43require_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
44require_once DOL_DOCUMENT_ROOT.
'/core/class/commonobject.class.php';
45require_once DOL_DOCUMENT_ROOT.
'/product/class/productbatch.class.php';
46require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/productlot.class.php';
47require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/entrepot.class.php';
58 const SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY = 1;
59 const SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY = 2;
60 const SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT = 3;
66 public $TRIGGER_PREFIX =
'PRODUCT';
71 public $element =
'product';
76 public $table_element =
'product';
81 public $fk_element =
'fk_product';
86 protected $childtables = array(
87 'supplier_proposaldet' => array(
'name' =>
'SupplierProposal',
'parent' =>
'supplier_proposal',
'parentkey' =>
'fk_supplier_proposal'),
88 'propaldet' => array(
'name' =>
'Proposal',
'parent' =>
'propal',
'parentkey' =>
'fk_propal'),
89 'commandedet' => array(
'name' =>
'Order',
'parent' =>
'commande',
'parentkey' =>
'fk_commande'),
90 'facturedet' => array(
'name' =>
'Invoice',
'parent' =>
'facture',
'parentkey' =>
'fk_facture'),
91 'contratdet' => array(
'name' =>
'Contract',
'parent' =>
'contrat',
'parentkey' =>
'fk_contrat'),
92 'facture_fourn_det' => array(
'name' =>
'SupplierInvoice',
'parent' =>
'facture_fourn',
'parentkey' =>
'fk_facture_fourn'),
93 'commande_fournisseurdet' => array(
'name' =>
'SupplierOrder',
'parent' =>
'commande_fournisseur',
'parentkey' =>
'fk_commande'),
94 'mrp_production' => array(
'name' =>
'Mo',
'parent' =>
'mrp_mo',
'parentkey' =>
'fk_mo',
'enabled' =>
'isModEnabled("mrp")'),
95 'bom_bom' => array(
'name' =>
'BOM',
'enabled' =>
'isModEnabled("bom")'),
96 'bom_bomline' => array(
'name' =>
'BOMLine',
'parent' =>
'bom_bom',
'parentkey' =>
'fk_bom',
'enabled' =>
'isModEnabled("bom")'),
104 public $picto =
'product';
115 public $regeximgext =
'\.gif|\.jpg|\.jpeg|\.png|\.bmp|\.webp|\.xpm|\.xbm|\.avif';
169 public $price_formated;
181 public $price_ttc_formated;
195 public $price_min_ttc;
201 public $price_base_type;
211 public $multiprices = array();
215 public $multiprices_ttc = array();
219 public $multiprices_base_type = array();
223 public $multiprices_default_vat_code = array();
227 public $multiprices_min = array();
231 public $multiprices_min_ttc = array();
235 public $multiprices_tva_tx = array();
239 public $multiprices_recuperableonly = array();
245 public $price_by_qty;
249 public $prices_by_qty = array();
253 public $prices_by_qty_id = array();
257 public $prices_by_qty_list = array();
267 public $multilangs = array();
272 public $default_vat_code;
287 public $remise_percent;
292 public $localtax1_tx;
296 public $localtax2_tx;
300 public $localtax1_type;
304 public $localtax2_type;
311 public $desc_supplier;
315 public $vatrate_supplier;
319 public $default_vat_code_supplier;
324 public $fourn_multicurrency_price;
329 public $fourn_multicurrency_unitprice;
333 public $fourn_multicurrency_tx;
337 public $fourn_multicurrency_id;
341 public $fourn_multicurrency_code;
363 public $qc_frequency;
370 public $stock_reel = 0;
377 public $stock_theorique;
398 public $seuil_stock_alerte = 0;
403 public $desiredstock = 0;
408 public $duration_value;
412 public $duration_unit;
421 public $fk_default_workstation;
443 public $status_buy = 0;
465 public $fk_default_bom;
472 public $product_fourn_price_id;
494 public $status_batch = 0;
501 public $sell_or_eat_by_mandatory = 0;
508 public $batch_mask =
'';
533 public $weight_units;
541 public $length_units;
557 public $height_units;
565 public $surface_units;
573 public $volume_units;
582 public $net_measure_units;
587 public $accountancy_code_sell;
591 public $accountancy_code_sell_intra;
595 public $accountancy_code_sell_export;
599 public $accountancy_code_buy;
603 public $accountancy_code_buy_intra;
607 public $accountancy_code_buy_export;
617 public $barcode_type;
622 public $barcode_type_code;
627 public $stats_propale = array();
632 public $stats_commande = array();
637 public $stats_contrat = array();
642 public $stats_facture = array();
647 public $stats_proposal_supplier = array();
652 public $stats_commande_fournisseur = array();
657 public $stats_expedition = array();
662 public $stats_reception = array();
667 public $stats_mo = array();
672 public $stats_bom = array();
677 public $stats_mrptoconsume = array();
682 public $stats_mrptoproduce = array();
687 public $stats_facturerec = array();
692 public $stats_facture_fournisseur = array();
697 public $stats_facturefournrec = array();
712 public $product_fourn_id;
718 public $product_id_already_linked;
729 public $stock_warehouse = array();
734 public $fk_default_warehouse;
739 public $fk_price_expression;
757 public $fourn_price_base_type;
774 public $ref_supplier;
788 public $price_autogen = 0;
795 public $sousprods = array();
808 public $is_object_used;
819 public $is_sousproduit_qty;
831 public $is_sousproduit_incdec;
836 public $mandatory_period;
843 public $stockable_product = 1;
873 public $fields = array(
874 'rowid' => array(
'type' =>
'integer',
'label' =>
'TechnicalID',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'index' => 1,
'position' => 1,
'comment' =>
'Id'),
875 'ref' => array(
'type' =>
'varchar(128)',
'label' =>
'Ref',
'enabled' => 1,
'visible' => 1,
'notnull' => 1,
'showoncombobox' => 1,
'index' => 1,
'position' => 10,
'searchall' => 1,
'comment' =>
'Reference of object'),
876 'entity' => array(
'type' =>
'integer',
'label' =>
'Entity',
'enabled' => 1,
'visible' => 0,
'default' =>
'1',
'notnull' => 1,
'index' => 1,
'position' => 5),
877 'label' => array(
'type' =>
'varchar(255)',
'label' =>
'Label',
'enabled' => 1,
'visible' => 1,
'notnull' => 1,
'showoncombobox' => 2,
'position' => 15,
'csslist' =>
'tdoverflowmax250'),
878 'barcode' => array(
'type' =>
'varchar(255)',
'label' =>
'Barcode',
'enabled' =>
'isModEnabled("barcode")',
'position' => 20,
'visible' => -1,
'showoncombobox' => 3,
'cssview' =>
'tdwordbreak',
'csslist' =>
'tdoverflowmax125'),
879 'fk_barcode_type' => array(
'type' =>
'integer',
'label' =>
'BarcodeType',
'enabled' => 1,
'position' => 21,
'notnull' => 0,
'visible' => -1,),
880 'note_public' => array(
'type' =>
'html',
'label' =>
'NotePublic',
'enabled' => 1,
'visible' => 0,
'position' => 61),
881 'note' => array(
'type' =>
'html',
'label' =>
'NotePrivate',
'enabled' => 1,
'visible' => 0,
'position' => 62),
882 'datec' => array(
'type' =>
'datetime',
'label' =>
'DateCreation',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 500),
883 'tms' => array(
'type' =>
'timestamp',
'label' =>
'DateModification',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 501),
885 'fk_user_author' => array(
'type' =>
'integer:User:user/class/user.class.php',
'label' =>
'UserAuthor',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 510,
'foreignkey' =>
'llx_user.rowid'),
886 'fk_user_modif' => array(
'type' =>
'integer:User:user/class/user.class.php',
'label' =>
'UserModif',
'enabled' => 1,
'visible' => -2,
'notnull' => -1,
'position' => 511),
888 'localtax1_tx' => array(
'type' =>
'double(6,3)',
'label' =>
'Localtax1tx',
'enabled' => 1,
'position' => 150,
'notnull' => 0,
'visible' => -1,),
889 'localtax1_type' => array(
'type' =>
'varchar(10)',
'label' =>
'Localtax1type',
'enabled' => 1,
'position' => 155,
'notnull' => 1,
'visible' => -1,),
890 'localtax2_tx' => array(
'type' =>
'double(6,3)',
'label' =>
'Localtax2tx',
'enabled' => 1,
'position' => 160,
'notnull' => 0,
'visible' => -1,),
891 'localtax2_type' => array(
'type' =>
'varchar(10)',
'label' =>
'Localtax2type',
'enabled' => 1,
'position' => 165,
'notnull' => 1,
'visible' => -1,),
892 'last_main_doc' => array(
'type' =>
'varchar(255)',
'label' =>
'LastMainDoc',
'enabled' => 1,
'visible' => -1,
'position' => 170),
893 'import_key' => array(
'type' =>
'varchar(14)',
'label' =>
'ImportId',
'enabled' => 1,
'visible' => -2,
'notnull' => -1,
'index' => 0,
'position' => 1000),
896 'mandatory_period' => array(
'type' =>
'integer',
'label' =>
'mandatoryperiod',
'enabled' => 1,
'visible' => -1,
'notnull' => 1,
'default' =>
'0',
'index' => 1,
'position' => 1000),
897 'stockable_product' => array(
'type' =>
'integer',
'label' =>
'stockable_product',
'enabled' => 1,
'visible' => 1,
'default' =>
'1',
'notnull' => 1,
'index' => 1,
'position' => 502),
913 const ENABLED_STOCK = 1;
924 $this->ismultientitymanaged = 1;
925 $this->isextrafieldmanaged = 1;
938 $this->
ref = trim($this->
ref);
966 public function create($user, $notrigger = 0)
968 global
$conf, $langs;
974 $this->
ref = trim($this->
ref);
978 $this->label = trim($this->label);
979 $this->price_ttc = (float)
price2num($this->price_ttc);
981 $this->price_min_ttc = (float)
price2num($this->price_min_ttc);
982 $this->price_min = (float)
price2num($this->price_min);
983 $this->price_label = trim($this->price_label);
984 if (empty($this->tva_tx)) {
987 if (empty($this->tva_npr)) {
991 if (empty($this->localtax1_tx)) {
992 $this->localtax1_tx = 0;
994 if (empty($this->localtax2_tx)) {
995 $this->localtax2_tx = 0;
997 if (empty($this->localtax1_type)) {
998 $this->localtax1_type =
'0';
1000 if (empty($this->localtax2_type)) {
1001 $this->localtax2_type =
'0';
1004 if (empty($this->price_base_type) &&
getDolGlobalString(
'PRODUCT_PRICE_BASE_TYPE')) {
1007 if (empty($this->
price)) {
1010 if (empty($this->price_min)) {
1011 $this->price_min = 0;
1014 if (empty($this->price_by_qty)) {
1015 $this->price_by_qty = 0;
1018 if (empty($this->
status)) {
1021 if (empty($this->status_buy)) {
1022 $this->status_buy = 0;
1024 if (empty($this->stockable_product)) {
1025 $this->stockable_product = 0;
1034 if ($this->price_base_type ==
'TTC' && $this->price_ttc > 0) {
1035 $price_ttc =
price2num($this->price_ttc,
'MU');
1036 $price_ht =
price2num($this->price_ttc / (1 + ($this->tva_tx / 100)),
'MU');
1040 if ($this->price_base_type !=
'TTC' && $this->
price > 0) {
1042 $price_ttc =
price2num($this->
price * (1 + ($this->tva_tx / 100)),
'MU');
1046 if (($this->price_min_ttc > 0) && ($this->price_base_type ==
'TTC')) {
1047 $price_min_ttc =
price2num($this->price_min_ttc,
'MU');
1048 $price_min_ht =
price2num($this->price_min_ttc / (1 + ($this->tva_tx / 100)),
'MU');
1052 if (($this->price_min > 0) && ($this->price_base_type !=
'TTC')) {
1053 $price_min_ht =
price2num($this->price_min,
'MU');
1054 $price_min_ttc =
price2num($this->price_min * (1 + ($this->tva_tx / 100)),
'MU');
1057 $this->accountancy_code_buy = trim((
string) $this->accountancy_code_buy);
1058 $this->accountancy_code_buy_intra = trim((
string) $this->accountancy_code_buy_intra);
1059 $this->accountancy_code_buy_export = trim((
string) $this->accountancy_code_buy_export);
1060 $this->accountancy_code_sell = trim((
string) $this->accountancy_code_sell);
1061 $this->accountancy_code_sell_intra = trim((
string) $this->accountancy_code_sell_intra);
1062 $this->accountancy_code_sell_export = trim((
string) $this->accountancy_code_sell_export);
1068 require_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
1069 $this->accountancy_code_buy =
clean_account($this->accountancy_code_buy);
1070 $this->accountancy_code_buy_intra =
clean_account($this->accountancy_code_buy_intra);
1071 $this->accountancy_code_buy_export =
clean_account($this->accountancy_code_buy_export);
1072 $this->accountancy_code_sell =
clean_account($this->accountancy_code_sell);
1073 $this->accountancy_code_sell_intra =
clean_account($this->accountancy_code_sell_intra);
1074 $this->accountancy_code_sell_export =
clean_account($this->accountancy_code_sell_export);
1078 $this->barcode = trim($this->barcode);
1079 $this->mandatory_period = empty($this->mandatory_period) ? 0 : $this->mandatory_period;
1081 if (empty($this->label)) {
1082 $langs->load(
'errors');
1083 $this->errors[] = $langs->trans(
'ErrorMandatoryParametersNotProvided');
1087 if (empty($this->
ref) || $this->
ref ==
'auto') {
1089 $module =
getDolGlobalString(
'PRODUCT_CODEPRODUCT_ADDON',
'mod_codeproduct_leopard');
1090 if ($module !=
'mod_codeproduct_leopard') {
1091 if (substr($module, 0, 16) ==
'mod_codeproduct_' && substr($module, -3) ==
'php') {
1092 $module = substr($module, 0,
dol_strlen($module) - 4);
1095 $modCodeProduct =
new $module();
1096 '@phan-var-force ModeleProductCode $modCodeProduct';
1097 if (!empty($modCodeProduct->code_auto)) {
1098 $this->
ref = $modCodeProduct->getNextValue($this, $this->
type);
1100 unset($modCodeProduct);
1103 if (empty($this->
ref)) {
1104 $this->error =
'ProductModuleNotSetupForAutoRef';
1109 dol_syslog(get_class($this).
"::create ref=".$this->
ref.
" price=".$this->price.
" price_ttc=".$this->price_ttc.
" tva_tx=".$this->tva_tx.
" price_base_type=".$this->price_base_type, LOG_DEBUG);
1113 if (empty($this->date_creation)) {
1114 $this->date_creation = $now;
1120 if ($this->barcode ==
'-1' || $this->barcode ==
'auto') {
1121 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1126 $result = $this->
verify();
1129 $sql =
"SELECT count(*) as nb";
1130 $sql .=
" FROM ".$this->db->prefix().
"product";
1131 $sql .=
" WHERE entity IN (".getEntity(
'product').
")";
1132 $sql .=
" AND ref = '".$this->db->escape($this->
ref).
"'";
1134 $result = $this->db->query($sql);
1136 $obj = $this->db->fetch_object($result);
1137 if ($obj->nb == 0) {
1139 $sql =
"INSERT INTO ".$this->db->prefix().
"product (";
1143 $sql .=
", ref_ext";
1144 $sql .=
", price_min";
1145 $sql .=
", price_min_ttc";
1147 $sql .=
", fk_user_author";
1148 $sql .=
", fk_product_type";
1150 $sql .=
", price_ttc";
1151 $sql .=
", price_base_type";
1152 $sql .=
", price_label";
1156 $sql .=
", accountancy_code_buy";
1157 $sql .=
", accountancy_code_buy_intra";
1158 $sql .=
", accountancy_code_buy_export";
1159 $sql .=
", accountancy_code_sell";
1160 $sql .=
", accountancy_code_sell_intra";
1161 $sql .=
", accountancy_code_sell_export";
1164 $sql .=
", finished";
1165 $sql .=
", tobatch";
1166 $sql .=
", sell_or_eat_by_mandatory";
1167 $sql .=
", batch_mask";
1168 $sql .=
", fk_unit";
1169 $sql .=
", mandatory_period";
1170 $sql .=
", stockable_product";
1171 if (!empty($this->default_vat_code)) {
1172 $sql .=
", default_vat_code";
1174 $sql .=
") VALUES (";
1175 $sql .=
"'".$this->db->idate($this->date_creation).
"'";
1176 $sql .=
", ".(!empty($this->entity) ? (int) $this->entity : (int)
$conf->entity);
1177 $sql .=
", '".$this->db->escape($this->
ref).
"'";
1178 $sql .=
", ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1179 $sql .=
", ".price2num($price_min_ht);
1180 $sql .=
", ".price2num($price_min_ttc);
1181 $sql .=
", ".(!empty($this->label) ?
"'".$this->db->escape($this->label).
"'" :
"null");
1182 $sql .=
", ".((int) $user->id);
1183 $sql .=
", ".((int) $this->
type);
1184 $sql .=
", ".price2num($price_ht,
'MT');
1185 $sql .=
", ".price2num($price_ttc,
'MT');
1186 $sql .=
", '".$this->db->escape($this->price_base_type).
"'";
1187 $sql .=
", ".(!empty($this->price_label) ?
"'".$this->db->escape($this->price_label).
"'" :
"null");
1188 $sql .=
", ".((int) $this->
status);
1189 $sql .=
", ".((int) $this->status_buy);
1191 $sql .=
", '".$this->db->escape($this->accountancy_code_buy).
"'";
1192 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_intra).
"'";
1193 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_export).
"'";
1194 $sql .=
", '".$this->db->escape($this->accountancy_code_sell).
"'";
1195 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_intra).
"'";
1196 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_export).
"'";
1198 $sql .=
", '".$this->db->escape($this->canvas).
"'";
1199 $sql .=
", ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
'NULL' : (int) $this->finished);
1200 $sql .=
", ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : ((int) $this->status_batch));
1201 $sql .=
", ".((empty($this->sell_or_eat_by_mandatory) || $this->sell_or_eat_by_mandatory < 0) ? 0 : ((int) $this->sell_or_eat_by_mandatory));
1202 $sql .=
", '".$this->db->escape($this->batch_mask).
"'";
1203 $sql .=
", ".($this->fk_unit > 0 ? ((int) $this->fk_unit) :
'NULL');
1204 $sql .=
", '".$this->db->escape((
string) $this->mandatory_period).
"'";
1205 $sql .=
", ".((int) $this->stockable_product);
1206 if (!empty($this->default_vat_code)) {
1207 $sql .=
", '".$this->db->escape($this->default_vat_code).
"'";
1210 dol_syslog(get_class($this).
"::Create", LOG_DEBUG);
1212 $result = $this->db->query($sql);
1214 $id = $this->db->last_insert_id($this->db->prefix().
"product");
1218 $this->
price = $price_ht;
1219 $this->price_ttc = $price_ttc;
1220 $this->price_min = $price_min_ht;
1221 $this->price_min_ttc = $price_min_ttc;
1225 if ($this->
update($id, $user, 1,
'add') <= 0) {
1230 $this->error = $this->db->lasterror();
1235 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " .((int) $this->id) .
" AND entity = " . ((
int)
$conf->entity));
1237 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1238 $sql .=
" fk_product";
1240 $sql .=
", accountancy_code_buy";
1241 $sql .=
", accountancy_code_buy_intra";
1242 $sql .=
", accountancy_code_buy_export";
1243 $sql .=
", accountancy_code_sell";
1244 $sql .=
", accountancy_code_sell_intra";
1245 $sql .=
", accountancy_code_sell_export";
1246 $sql .=
") VALUES (";
1247 $sql .= ((int) $this->
id);
1248 $sql .=
", " . ((int)
$conf->entity);
1249 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1250 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1251 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1252 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1253 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1254 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1256 $result = $this->db->query($sql);
1259 $this->error =
'ErrorFailedToInsertAccountancyForEntity';
1264 $this->error =
'ErrorFailedToGetInsertedId';
1268 $this->error = $this->db->lasterror();
1272 $langs->load(
"products");
1274 $this->error =
"ErrorProductAlreadyExists";
1275 dol_syslog(get_class($this).
"::Create fails, ref ".$this->
ref.
" already exists");
1279 $this->error = $this->db->lasterror();
1282 if (!$error && !$notrigger) {
1284 $result = $this->call_trigger(
'PRODUCT_CREATE', $user);
1292 $this->db->commit();
1295 $this->db->rollback();
1299 $this->db->rollback();
1300 dol_syslog(get_class($this).
"::Create fails verify ".implode(
',', $this->errors), LOG_WARNING);
1316 $this->errors = array();
1319 $this->
ref = trim($this->
ref);
1322 $this->errors[] =
'ErrorBadRef';
1326 $arrayofnonnegativevalue = array(
'weight' =>
'Weight',
'width' =>
'Width',
'height' =>
'Height',
'length' =>
'Length',
'surface' =>
'Surface',
'volume' =>
'Volume');
1327 foreach ($arrayofnonnegativevalue as $key => $value) {
1328 if (property_exists($this, $key) && !empty($this->$key) && ($this->$key < 0)) {
1329 $langs->loadLangs(array(
"main",
"other"));
1330 $this->error = $langs->trans(
"FieldCannotBeNegative", $langs->transnoentitiesnoconv($value));
1331 $this->errors[] = $this->error;
1336 $rescode = $this->check_barcode($this->barcode, $this->barcode_type_code);
1338 if ($rescode == -1) {
1339 $this->errors[] =
'ErrorBadBarCodeSyntax';
1340 } elseif ($rescode == -2) {
1341 $this->errors[] =
'ErrorBarCodeRequired';
1342 } elseif ($rescode == -3) {
1344 $this->errors[] =
'ErrorBarCodeAlreadyUsed';
1364 public function check_barcode($valuetotest, $typefortest)
1372 $dirsociete = array_merge(array(
'/core/modules/barcode/'),
$conf->modules_parts[
'barcode']);
1373 foreach ($dirsociete as $dirroot) {
1380 $mod =
new $module();
1381 '@phan-var-force ModeleNumRefBarCode $mod';
1384 dol_syslog(get_class($this).
"::check_barcode value=".$valuetotest.
" type=".$typefortest.
" module=".$module);
1385 $result = $mod->verif($this->db, $valuetotest, $this, 0, $typefortest);
1403 public function update($id, $user, $notrigger = 0, $action =
'update', $updatetype =
false)
1405 global $langs,
$conf, $hookmanager;
1410 if (!$this->label) {
1411 $this->label =
'MISSING LABEL';
1416 $this->
ref = trim($this->
ref);
1420 $this->label = trim($this->label);
1422 $this->note_private = (isset($this->note_private) ? trim($this->note_private) :
null);
1423 $this->note_public = (isset($this->note_public) ? trim($this->note_public) :
null);
1424 $this->net_measure =
price2num($this->net_measure);
1425 $this->net_measure_units = (!is_numeric($this->net_measure_units) ? null : (int) $this->net_measure_units);
1426 $this->weight =
price2num($this->weight);
1427 $this->weight_units = (!is_numeric($this->weight_units) ? null : (int) $this->weight_units);
1428 $this->length =
price2num($this->length);
1429 $this->length_units = (!is_numeric($this->length_units) ? null : (int) $this->length_units);
1431 $this->width_units = (!is_numeric($this->width_units) ? null : (int) $this->width_units);
1432 $this->height =
price2num($this->height);
1433 $this->height_units = (!is_numeric($this->height_units) ? null : (int) $this->height_units);
1434 $this->surface =
price2num($this->surface);
1435 $this->surface_units = (!is_numeric($this->surface_units) ? null : (int) $this->surface_units);
1436 $this->volume =
price2num($this->volume);
1437 $this->volume_units = (!is_numeric($this->volume_units) ? null : (int) $this->volume_units);
1440 if (is_numeric($this->length_units)) {
1441 $this->width_units = $this->length_units;
1443 if (is_numeric($this->length_units)) {
1444 $this->height_units = $this->length_units;
1448 if (empty($this->surface) && !empty($this->length) && !empty($this->width) && $this->length_units == $this->width_units) {
1449 $this->surface = (float) $this->length * (
float) $this->width;
1452 if (empty($this->volume) && !empty($this->surface) && !empty($this->height) && $this->length_units == $this->height_units) {
1453 $this->volume = $this->surface * (float) $this->height;
1457 if (empty($this->tva_tx)) {
1460 if (empty($this->tva_npr)) {
1463 if (empty($this->localtax1_tx)) {
1464 $this->localtax1_tx = 0;
1466 if (empty($this->localtax2_tx)) {
1467 $this->localtax2_tx = 0;
1469 if (empty($this->localtax1_type)) {
1470 $this->localtax1_type =
'0';
1472 if (empty($this->localtax2_type)) {
1473 $this->localtax2_type =
'0';
1475 if (empty($this->
status)) {
1478 if (empty($this->status_buy)) {
1479 $this->status_buy = 0;
1482 if (empty($this->country_id)) {
1483 $this->country_id = 0;
1485 if (empty($this->country_id) && !empty($this->country_code)) {
1486 $country_id =
getCountry($this->country_code,
'3');
1487 $this->country_id = is_int($country_id) ? $country_id : 0;
1490 if (empty($this->state_id)) {
1491 $this->state_id = 0;
1494 if (empty($this->stockable_product)) {
1495 $this->stockable_product = 0;
1499 if ($this->barcode ==
'-1' || $this->barcode ==
'auto') {
1500 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1504 $this->barcode = (empty($this->barcode) ?
'' : trim($this->barcode));
1506 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
1507 $this->accountancy_code_buy_intra = (!empty($this->accountancy_code_buy_intra) ? trim($this->accountancy_code_buy_intra) :
'');
1508 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
1509 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
1510 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
1511 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
1517 require_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
1518 $this->accountancy_code_buy =
clean_account($this->accountancy_code_buy);
1519 $this->accountancy_code_buy_intra =
clean_account($this->accountancy_code_buy_intra);
1520 $this->accountancy_code_buy_export =
clean_account($this->accountancy_code_buy_export);
1521 $this->accountancy_code_sell =
clean_account($this->accountancy_code_sell);
1522 $this->accountancy_code_sell_intra =
clean_account($this->accountancy_code_sell_intra);
1523 $this->accountancy_code_sell_export =
clean_account($this->accountancy_code_sell_export);
1530 if ($action !=
'add') {
1531 $result = $this->
verify();
1543 if (is_null($this->oldcopy) || (is_object($this->oldcopy) && empty($this->oldcopy->id)) || !($this->oldcopy instanceof
Product)) {
1548 if ($this->
hasbatch() && !$this->oldcopy->hasbatch()) {
1550 $valueforundefinedlot =
'000000';
1555 dol_syslog(
"Flag batch of product id=".$this->
id.
" is set to ON, so we will create missing records into product_batch");
1558 foreach ($this->stock_warehouse as $idW => $ObjW) {
1560 foreach ($ObjW->detail_batch as $detail) {
1561 if ($detail->batch == $valueforundefinedlot || $detail->batch ==
'Undefined') {
1563 $sqlclean =
"DELETE FROM ".$this->db->prefix().
"product_batch WHERE batch in('Undefined', '".$this->db->escape($valueforundefinedlot).
"') AND fk_product_stock = ".((int) $ObjW->id);
1564 $result = $this->db->query($sqlclean);
1572 $qty_batch += $detail->qty;
1576 if ($ObjW->real != $qty_batch) {
1578 $ObjBatch->batch = $valueforundefinedlot;
1579 $ObjBatch->qty = ($ObjW->real - $qty_batch);
1580 $ObjBatch->fk_product_stock = (int) $ObjW->id;
1582 if ($ObjBatch->create($user, 1) < 0) {
1584 $this->errors = $ObjBatch->errors;
1589 if ($ObjLot->fetch(0, $this->id, $valueforundefinedlot) == 0) {
1590 $ObjLot->fk_product = $this->id;
1591 $ObjLot->entity = (int) $this->entity;
1592 $ObjLot->fk_user_creat = $user->id;
1593 $ObjLot->batch = $valueforundefinedlot;
1594 if ($ObjLot->create($user, 1) < 0) {
1596 $this->errors = $ObjLot->errors;
1604 $sql =
"UPDATE ".$this->db->prefix().
"product";
1605 $sql .=
" SET label = '".$this->db->escape($this->label).
"'";
1608 $sql .=
", fk_product_type = ".((int) $this->
type);
1611 $sql .=
", ref = '".$this->db->escape($this->
ref).
"'";
1612 $sql .=
", ref_ext = ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1613 $sql .=
", default_vat_code = ".($this->default_vat_code ?
"'".$this->db->escape($this->default_vat_code).
"'" :
"null");
1614 $sql .=
", tva_tx = ".((float) $this->tva_tx);
1615 $sql .=
", recuperableonly = ".((int) $this->tva_npr);
1616 $sql .=
", localtax1_tx = ".((float) $this->localtax1_tx);
1617 $sql .=
", localtax2_tx = ".((float) $this->localtax2_tx);
1618 $sql .=
", localtax1_type = ".($this->localtax1_type !=
'' ?
"'".$this->db->escape($this->localtax1_type).
"'" :
"'0'");
1619 $sql .=
", localtax2_type = ".($this->localtax2_type !=
'' ?
"'".$this->db->escape($this->localtax2_type).
"'" :
"'0'");
1621 $sql .=
", barcode = ".(empty($this->barcode) ?
"null" :
"'".$this->db->escape($this->barcode).
"'");
1622 $sql .=
", fk_barcode_type = ".(empty($this->barcode_type) ?
"null" : $this->db->escape((
string) $this->barcode_type));
1624 $sql .=
", tosell = ".(int) $this->
status;
1625 $sql .=
", tobuy = ".(int) $this->status_buy;
1626 $sql .=
", tobatch = ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : (int) $this->status_batch);
1627 $sql .=
", sell_or_eat_by_mandatory = ".((empty($this->sell_or_eat_by_mandatory) || $this->sell_or_eat_by_mandatory < 0) ? 0 : (int) $this->sell_or_eat_by_mandatory);
1628 $sql .=
", batch_mask = '".$this->db->escape($this->batch_mask).
"'";
1630 $sql .=
", finished = ".((!isset($this->finished) || $this->finished < 0 || $this->finished ===
'') ?
"null" : (int) $this->finished);
1631 $sql .=
", fk_default_bom = ".((!isset($this->fk_default_bom) || $this->fk_default_bom < 0 || $this->fk_default_bom ==
'') ?
"null" : (int) $this->fk_default_bom);
1632 $sql .=
", net_measure = ".($this->net_measure !=
'' ?
"'".$this->db->escape($this->net_measure).
"'" :
'null');
1633 $sql .=
", net_measure_units = ".((string) $this->net_measure_units !=
'' ? ((
int) $this->net_measure_units) :
'null');
1634 $sql .=
", weight = ".($this->weight !=
'' ?
"'".$this->db->escape($this->weight).
"'" :
'null');
1635 $sql .=
", weight_units = ".((string) $this->weight_units !=
'' ? ((
int) $this->weight_units) :
'null');
1636 $sql .=
", length = ".($this->length !=
'' ?
"'".$this->db->escape($this->length).
"'" :
'null');
1637 $sql .=
", length_units = ".((string) $this->length_units !=
'' ? ((
int) $this->length_units) :
'null');
1638 $sql .=
", width= ".($this->width !=
'' ?
"'".$this->db->escape($this->width).
"'" :
'null');
1639 $sql .=
", width_units = ".((string) $this->width_units !=
'' ? ((
int) $this->width_units) :
'null');
1640 $sql .=
", height = ".($this->height !=
'' ?
"'".$this->db->escape($this->height).
"'" :
'null');
1641 $sql .=
", height_units = ".((string) $this->height_units !=
'' ? ((
int) $this->height_units) :
'null');
1642 $sql .=
", surface = ".($this->surface !=
'' ?
"'".$this->db->escape($this->surface).
"'" :
'null');
1643 $sql .=
", surface_units = ".((string) $this->surface_units !=
'' ? ((
int) $this->surface_units) :
'null');
1644 $sql .=
", volume = ".($this->volume !=
'' ?
"'".$this->db->escape($this->volume).
"'" :
'null');
1645 $sql .=
", volume_units = ".((string) $this->volume_units !=
'' ? ((
int) $this->volume_units) :
'null');
1646 $sql .=
", fk_default_warehouse = ".($this->fk_default_warehouse > 0 ? ((int) $this->fk_default_warehouse) :
'null');
1647 $sql .=
", fk_default_workstation = ".($this->fk_default_workstation > 0 ? ((int) $this->fk_default_workstation) :
'null');
1648 $sql .=
", seuil_stock_alerte = ".((isset($this->seuil_stock_alerte) && is_numeric($this->seuil_stock_alerte)) ? (
float) $this->seuil_stock_alerte :
'null');
1649 $sql .=
", description = '".$this->db->escape($this->
description).
"'";
1650 $sql .=
", url = ".($this->url ?
"'".$this->db->escape($this->url).
"'" :
'null');
1651 $sql .=
", customcode = '".$this->db->escape($this->customcode).
"'";
1652 $sql .=
", fk_country = ".($this->country_id > 0 ? (int) $this->country_id :
'null');
1653 $sql .=
", fk_state = ".($this->state_id > 0 ? (int) $this->state_id :
'null');
1654 $sql .=
", lifetime = ".($this->lifetime > 0 ? (int) $this->lifetime :
'null');
1655 $sql .=
", qc_frequency = ".($this->qc_frequency > 0 ? (int) $this->qc_frequency :
'null');
1656 $sql .=
", note = ".(isset($this->note_private) ?
"'".$this->db->escape($this->note_private).
"'" :
'null');
1657 $sql .=
", note_public = ".(isset($this->note_public) ?
"'".$this->db->escape($this->note_public).
"'" :
'null');
1658 $sql .=
", duration = '".$this->db->escape($this->duration_value.$this->duration_unit).
"'";
1660 $sql .=
", accountancy_code_buy = '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1661 $sql .=
", accountancy_code_buy_intra = '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1662 $sql .=
", accountancy_code_buy_export = '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1663 $sql .=
", accountancy_code_sell= '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1664 $sql .=
", accountancy_code_sell_intra= '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1665 $sql .=
", accountancy_code_sell_export= '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1667 $sql .=
", desiredstock = ".((isset($this->desiredstock) && is_numeric($this->desiredstock)) ? (
float) $this->desiredstock :
"null");
1668 $sql .=
", cost_price = ".($this->cost_price !=
'' ? ((float) $this->cost_price) :
'null');
1669 $sql .=
", fk_unit= ".(!$this->fk_unit ?
'NULL' : (int) $this->fk_unit);
1670 $sql .=
", price_autogen = ".(!$this->price_autogen ? 0 : 1);
1671 $sql .=
", fk_price_expression = ".($this->fk_price_expression != 0 ? (int) $this->fk_price_expression :
'NULL');
1672 $sql .=
", fk_user_modif = ".($user->id > 0 ? (int) $user->id :
'NULL');
1673 $sql .=
", mandatory_period = ".((int) $this->mandatory_period);
1674 $sql .=
", stockable_product = ".(int) $this->stockable_product;
1676 $sql .=
", packaging = ".(float) $this->packaging;
1680 $sql .=
" WHERE rowid = ".((int) $id);
1682 dol_syslog(get_class($this).
"::update", LOG_DEBUG);
1684 $resql = $this->db->query($sql);
1691 $this->db->rollback();
1700 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " . ((
int) $this->id) .
" AND entity = " . ((
int)
$conf->entity));
1702 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1703 $sql .=
" fk_product";
1705 $sql .=
", accountancy_code_buy";
1706 $sql .=
", accountancy_code_buy_intra";
1707 $sql .=
", accountancy_code_buy_export";
1708 $sql .=
", accountancy_code_sell";
1709 $sql .=
", accountancy_code_sell_intra";
1710 $sql .=
", accountancy_code_sell_export";
1711 $sql .=
") VALUES (";
1712 $sql .= ((int) $this->
id);
1713 $sql .=
", " . ((int)
$conf->entity);
1714 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1715 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1716 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1717 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1718 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1719 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1721 $result = $this->db->query($sql);
1724 $this->error =
'ErrorFailedToUpdateAccountancyForEntity';
1728 if (!$this->
hasbatch() && $this->oldcopy->hasbatch()) {
1730 $sql =
'SELECT pb.qty, ps.fk_entrepot, pb.batch FROM '.MAIN_DB_PREFIX.
'product_batch as pb';
1731 $sql .=
' INNER JOIN '.MAIN_DB_PREFIX.
'product_stock as ps ON (ps.rowid = pb.fk_product_stock)';
1732 $sql .=
' WHERE ps.fk_product = '.(int) $this->
id;
1734 $resql = $this->db->query($sql);
1738 while ($obj = $this->db->fetch_object($resql)) {
1740 $fk_entrepot = $obj->fk_entrepot;
1744 $batch = $obj->batch;
1747 $addOremove = $value > 0 ? 1 : 0;
1748 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1749 $res = $this->
correct_stock_batch($user, $fk_entrepot, abs($value), $addOremove, $label, $price, $dlc, $dluo, $batch, $inventorycode,
'',
null, 0,
null,
true);
1752 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1753 $res = $this->
correct_stock($user, $fk_entrepot, abs($value), (
int) empty($addOremove), $label, $price, $inventorycode,
'',
null, 0);
1772 if (!$error && !$notrigger) {
1774 $result = $this->call_trigger(
'PRODUCT_MODIFY', $user);
1781 if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) {
1783 if (
$conf->product->dir_output) {
1786 if (file_exists($olddir)) {
1790 $res = @rename($olddir, $newdir);
1792 $langs->load(
"errors");
1793 $this->error = $langs->trans(
'ErrorFailToRenameDir', $olddir, $newdir);
1797 require_once DOL_DOCUMENT_ROOT .
'/ecm/class/ecmfiles.class.php';
1798 $ecmfiles =
new EcmFiles($this->db);
1799 $ecmfiles->updateAfterRename(
"produit/".
dol_sanitizeFileName($this->oldcopy->ref),
"produit/".dol_sanitizeFileName($this->ref));
1807 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1811 foreach ($comb->fetchAllByFkProductParent($this->id) as $currcomb) {
1812 $currcomb->updateProperties($this, $user);
1816 $this->db->commit();
1819 $this->db->rollback();
1823 if ($this->db->errno() ==
'DB_ERROR_RECORD_ALREADY_EXISTS') {
1824 $langs->load(
"errors");
1825 if (empty(
$conf->barcode->enabled) || empty($this->barcode)) {
1826 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductAlreadyExists", $this->
ref);
1828 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductBarCodeAlreadyExists", $this->barcode);
1830 $this->errors[] = $this->error;
1831 $this->db->rollback();
1834 $this->error = $langs->trans(
"Error").
" : ".$this->db->error().
" - ".$sql;
1835 $this->errors[] = $this->error;
1836 $this->db->rollback();
1841 $this->db->rollback();
1842 dol_syslog(get_class($this).
"::Update fails verify ".implode(
',', $this->errors), LOG_WARNING);
1854 public function delete(
User $user, $notrigger = 0)
1857 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
1862 if (empty($this->
id)) {
1863 $this->error =
"Object must be fetched before calling delete";
1866 if (($this->
isProduct() && !$user->
hasRight(
'produit',
'supprimer')) || ($this->isService() && !$user->hasRight(
'service',
'supprimer'))) {
1867 $this->error =
"ErrorForbidden";
1872 if (empty($objectisused)) {
1875 if (empty($notrigger)) {
1877 $result = $this->call_trigger(
'PRODUCT_DELETE', $user);
1886 $sql =
"DELETE FROM ".$this->db->prefix().
'product_batch';
1887 $sql .=
" WHERE fk_product_stock IN (";
1888 $sql .=
"SELECT rowid FROM ".$this->db->prefix().
'product_stock';
1889 $sql .=
" WHERE fk_product = ".((int) $this->
id).
")";
1891 $result = $this->db->query($sql);
1894 $this->errors[] = $this->db->lasterror();
1900 $sql =
"DELETE FROM " . $this->db->prefix() .
"product_fournisseur_price_log";
1901 $sql .=
" WHERE fk_product_fournisseur IN (";
1902 $sql .=
" SELECT rowid FROM " . $this->db->prefix() .
"product_fournisseur_price";
1903 $sql .=
" WHERE fk_product = " . ((int) $this->
id);
1906 $resql = $this->db->query($sql);
1909 $this->errors[] = $this->db->lasterror();
1915 $elements = array(
'product_fournisseur_price',
'product_price',
'product_lang',
'categorie_product',
'product_stock',
'product_customer_price',
'product_lot');
1916 foreach ($elements as $table) {
1918 $sql =
"DELETE FROM ".$this->db->prefix().$table;
1919 $sql .=
" WHERE fk_product = ".(int) $this->
id;
1921 $result = $this->db->query($sql);
1924 $this->errors[] = $this->db->lasterror();
1931 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1932 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination2ValuePair.class.php';
1937 if ($prodcomb->deleteByFkProductParent($user, $this->id) < 0) {
1939 $this->errors[] =
'Error deleting combinations';
1943 if (!$error && ($prodcomb->fetchByFkProductChild($this->id) > 0) && ($prodcomb->delete($user) < 0)) {
1945 $this->errors[] =
'Error deleting child combination';
1951 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
1952 $sql .=
" WHERE fk_product_pere = ".(int) $this->
id.
" OR fk_product_fils = ".(
int) $this->id;
1954 $result = $this->db->query($sql);
1957 $this->errors[] = $this->db->lasterror();
1966 dol_syslog(get_class($this).
"::delete error -4 ".$this->error, LOG_ERR);
1972 $sqlz =
"DELETE FROM ".$this->db->prefix().
"product";
1973 $sqlz .=
" WHERE rowid = ".(int) $this->
id;
1975 $resultz = $this->db->query($sqlz);
1978 $this->errors[] = $this->db->lasterror();
1994 if ($conf->product->dir_output) {
1995 $dir =
$conf->product->dir_output.
"/".$ref;
1996 if (file_exists($dir)) {
1999 $this->errors[] =
'ErrorFailToDeleteDir';
2007 $this->db->commit();
2010 foreach ($this->errors as $errmsg) {
2011 dol_syslog(get_class($this).
"::delete ".$errmsg, LOG_ERR);
2012 $this->error .= ($this->error ?
', '.$errmsg : $errmsg);
2014 $this->db->rollback();
2018 $this->error =
"ErrorRecordIsUsedCantDelete";
2032 $sellByLabel = $langs->trans(
'SellByDate');
2033 $eatByLabel = $langs->trans(
'EatByDate');
2035 self::SELL_OR_EAT_BY_MANDATORY_ID_NONE => $langs->trans(
'BatchSellOrEatByMandatoryNone'),
2036 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY => $sellByLabel,
2037 self::SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY => $eatByLabel,
2038 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT => $langs->trans(
'BatchSellOrEatByMandatoryAll', $sellByLabel, $eatByLabel),
2049 $sellOrEatByMandatoryLabel =
'';
2052 if (isset($sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory])) {
2053 $sellOrEatByMandatoryLabel = $sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory];
2056 return $sellOrEatByMandatoryLabel;
2070 $langs_available = $langs->get_available_languages(DOL_DOCUMENT_ROOT, 0, 2);
2071 $current_lang = $langs->getDefaultLang();
2073 foreach ($langs_available as $key => $value) {
2074 if ($key == $current_lang) {
2075 $sql =
"SELECT rowid";
2076 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2077 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2078 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
2080 $result = $this->db->query($sql);
2082 if ($this->db->num_rows($result)) {
2083 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
2085 $sql2 .=
" label='".$this->db->escape($this->label).
"',";
2086 $sql2 .=
" description='".$this->db->escape($this->
description).
"'";
2088 $sql2 .=
", note='".$this->db->escape($this->other).
"'";
2090 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
2092 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
2097 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->label).
"',";
2098 $sql2 .=
" '".$this->db->escape($this->
description).
"'";
2100 $sql2 .=
", '".$this->db->escape($this->other).
"'";
2104 dol_syslog(get_class($this).
'::setMultiLangs key = current_lang = '.$key);
2105 if (!$this->db->query($sql2)) {
2106 $this->error = $this->db->lasterror();
2109 } elseif (isset($this->multilangs[$key])) {
2110 if (empty($this->multilangs[$key][
"label"])) {
2111 $this->errors[] = $key .
' : ' . $langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Label"));
2115 $sql =
"SELECT rowid";
2116 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2117 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2118 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
2120 $result = $this->db->query($sql);
2122 if ($this->db->num_rows($result)) {
2123 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
2125 $sql2 .=
" label = '".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
2126 $sql2 .=
" description = '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
2129 $sql2 .=
", note = '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
2131 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
2133 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
2138 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
2139 $sql2 .=
" '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
2142 $sql2 .=
", '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
2148 if ($this->multilangs[
"$key"][
"label"] || $this->multilangs[
"$key"][
"description"]) {
2149 if (!$this->db->query($sql2)) {
2150 $this->error = $this->db->lasterror();
2159 if (empty($notrigger)) {
2161 $result = $this->call_trigger(
'PRODUCT_SET_MULTILANGS', $user);
2163 $this->error = $this->db->lasterror();
2183 $sql =
"DELETE FROM ".$this->db->prefix().
"product_lang";
2184 $sql .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($langtodelete).
"'";
2186 dol_syslog(get_class($this).
'::delMultiLangs', LOG_DEBUG);
2187 $result = $this->db->query($sql);
2189 if (empty($notrigger)) {
2191 $result = $this->call_trigger(
'PRODUCT_DEL_MULTILANGS', $user);
2193 $this->error = $this->db->lasterror();
2194 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
2199 unset($this->multilangs[$langtodelete]);
2202 $this->error = $this->db->lasterror();
2203 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
2224 if ($type ==
'buy') {
2225 $field =
'accountancy_code_buy';
2226 } elseif ($type ==
'buy_intra') {
2227 $field =
'accountancy_code_buy_intra';
2228 } elseif ($type ==
'buy_export') {
2229 $field =
'accountancy_code_buy_export';
2230 } elseif ($type ==
'sell') {
2231 $field =
'accountancy_code_sell';
2232 } elseif ($type ==
'sell_intra') {
2233 $field =
'accountancy_code_sell_intra';
2234 } elseif ($type ==
'sell_export') {
2235 $field =
'accountancy_code_sell_export';
2240 $sql =
"UPDATE ".$this->db->prefix().$this->table_element.
" SET ";
2241 $sql .=
"$field = '".$this->db->escape($value).
"'";
2242 $sql .=
" WHERE rowid = ".((int) $this->
id);
2245 $resql = $this->db->query($sql);
2249 $result = $this->call_trigger(
'PRODUCT_MODIFY', $user);
2256 $this->db->rollback();
2260 $this->$field = $value;
2262 $this->db->commit();
2265 $this->error = $this->db->lasterror();
2266 $this->db->rollback();
2280 $current_lang = $langs->getDefaultLang();
2282 $sql =
"SELECT lang, label, description, note as other";
2283 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2284 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2286 $result = $this->db->query($sql);
2288 while ($obj = $this->db->fetch_object($result)) {
2290 if ($obj->lang == $current_lang) {
2291 $this->label = $obj->label;
2293 $this->other = $obj->other;
2295 $this->multilangs[(
string) $obj->lang][
"label"] = $obj->label;
2296 $this->multilangs[(
string) $obj->lang][
"description"] = $obj->description;
2297 $this->multilangs[(
string) $obj->lang][
"other"] = $obj->other;
2301 $this->error =
"Error: ".$this->db->lasterror().
" - ".$sql;
2314 $testExit = array(
'multiprices',
'multiprices_ttc',
'multiprices_base_type',
'multiprices_min',
'multiprices_min_ttc',
'multiprices_tva_tx',
'multiprices_recuperableonly');
2316 foreach ($testExit as $field) {
2317 if (!isset($this->$field)) {
2320 $tmparray = $this->$field;
2321 if (!isset($tmparray[$level])) {
2327 'level' => $level ? $level : 1,
2328 'multiprices' => (float) $this->multiprices[$level],
2329 'multiprices_ttc' => (
float) $this->multiprices_ttc[$level],
2330 'multiprices_base_type' => $this->multiprices_base_type[$level],
2331 'multiprices_min' => (float) $this->multiprices_min[$level],
2332 'multiprices_min_ttc' => (
float) $this->multiprices_min_ttc[$level],
2333 'multiprices_tva_tx' => (float) $this->multiprices_tva_tx[$level],
2334 'multiprices_recuperableonly' => (
float) $this->multiprices_recuperableonly[$level],
2357 if (empty($this->price_by_qty)) {
2358 $this->price_by_qty = 0;
2362 $sql =
"INSERT INTO ".$this->db->prefix().
"product_price(price_level,date_price, fk_product, fk_user_author, price_label, price, price_ttc, price_base_type,tosell, tva_tx, default_vat_code, recuperableonly,";
2363 $sql .=
" localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, price_min,price_min_ttc,price_by_qty,entity,fk_price_expression) ";
2364 $sql .=
" VALUES(".($level ? ((int) $level) : 1).
", '".$this->db->idate($now).
"', ".((int) $this->
id).
", ".((int) $user->id).
", ".(empty($this->price_label) ?
"null" :
"'".$this->db->escape($this->price_label).
"'").
",";
2365 $sql .=
" ".((float)
price2num($this->
price)).
", ".((
float)
price2num($this->price_ttc)).
",'".$this->db->escape($this->price_base_type).
"',".((int) $this->
status).
", ".((float)
price2num($this->tva_tx)).
",";
2366 $sql .=
" ".($this->default_vat_code ? (
"'".$this->db->escape($this->default_vat_code).
"'") :
"null").
", ".((
int) $this->tva_npr).
",";
2367 $sql .=
" ".price2num($this->localtax1_tx).
", ".
price2num($this->localtax2_tx).
", '".$this->db->escape($this->localtax1_type).
"', '".$this->db->escape($this->localtax2_type).
"', ".
price2num($this->price_min).
", ".
price2num($this->price_min_ttc).
", ".
price2num($this->price_by_qty).
", ".((int)
$conf->entity).
",".($this->fk_price_expression > 0 ? ((int) $this->fk_price_expression) :
'null');
2370 dol_syslog(get_class($this).
"::_log_price", LOG_DEBUG);
2371 $resql = $this->db->query($sql);
2373 $this->error = $this->db->lasterror();
2393 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price_by_qty";
2394 $sql .=
" WHERE fk_product_price = ".((int) $rowid);
2395 $resql = $this->db->query($sql);
2397 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price_extrafields";
2398 $sql .=
" WHERE fk_object = ".((int) $rowid);
2399 $resql = $this->db->query($sql);
2401 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price";
2402 $sql .=
" WHERE rowid = ".((int) $rowid);
2403 $resql = $this->db->query($sql);
2407 $this->error = $this->db->lasterror();
2427 $sql .=
" pl.rowid as log_rowid,";
2428 $sql .=
" pl.datec,";
2429 $sql .=
" pl.price,";
2430 $sql .=
" pl.quantity,";
2431 $sql .=
" pl.fk_user,";
2432 $sql .=
" pl.multicurrency_code,";
2433 $sql .=
" pl.multicurrency_price,";
2435 $sql .=
" pp.fk_soc as supplier_id,";
2436 $sql .=
" pp.ref_fourn as supplier_ref,";
2437 $sql .=
" pp.entity as entity";
2439 $sql .=
" FROM " . $this->db->prefix() .
"product_fournisseur_price_log as pl";
2440 $sql .=
" INNER JOIN " . $this->db->prefix() .
"product_fournisseur_price as pp ON pl.fk_product_fournisseur = pp.rowid";
2442 $sql .=
" WHERE pp.fk_product = " . ((int) $id);
2443 $sql .=
" AND pp.entity IN (" .
getEntity(
'product') .
")";
2444 $sql .=
" ORDER BY pl.datec DESC";
2446 $resql = $this->db->query($sql);
2448 while ($obj = $this->db->fetch_object($resql)) {
2449 if (is_string($obj->datec)) {
2450 $obj->datec = strtotime($obj->datec);
2454 $this->db->free($resql);
2456 $this->error = $this->db->lasterror();
2471 public function getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp = 0)
2473 global $hookmanager, $action;
2476 if (is_object($hookmanager)) {
2477 $parameters = array(
'thirdparty_seller' => $thirdparty_seller,
'thirdparty_buyer' => $thirdparty_buyer,
'pqp' => $pqp);
2479 $reshook = $hookmanager->executeHooks(
'getSellPrice', $parameters, $this, $action);
2481 return $hookmanager->resArray;
2486 $tva_tx =
get_default_tva($thirdparty_seller, $thirdparty_buyer, $this->
id);
2487 $tva_npr =
get_default_npr($thirdparty_seller, $thirdparty_buyer, $this->
id);
2488 if (empty($tva_tx)) {
2492 $pu_ht = $this->price;
2493 $pu_ttc = $this->price_ttc;
2494 $price_min = $this->price_min;
2495 $price_min_ttc = $this->price_min_ttc;
2496 $price_base_type = (empty($this->price_base_type) ?
'HT' : $this->price_base_type);
2500 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2504 $filter = array(
't.fk_product' => (
string) $this->
id,
't.fk_soc' => (
string) $thirdparty_buyer->id);
2507 $pricebycustomerexist =
false;
2508 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2510 if (count($prodcustprice->lines) > 0) {
2511 $date_now = (int) floor(
dol_now() / 86400) * 86400;
2512 foreach ($prodcustprice->lines as $k => $custprice_line) {
2513 if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
2514 $pricebycustomerexist =
true;
2515 $pu_ht =
price($custprice_line->price);
2516 $price_min =
price($custprice_line->price_min);
2517 $price_min_ttc =
price($custprice_line->price_min_ttc);
2518 $pu_ttc =
price($custprice_line->price_ttc);
2519 $price_base_type = $custprice_line->price_base_type;
2520 $tva_tx = $custprice_line->tva_tx;
2521 if ($custprice_line->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2522 $tva_tx .=
' (' . $custprice_line->default_vat_code .
')';
2524 $tva_npr = $custprice_line->recuperableonly;
2525 if (empty($tva_tx)) {
2534 if (!$pricebycustomerexist && !empty($thirdparty_buyer->price_level)) {
2535 $pu_ht = isset($this->multiprices[$thirdparty_buyer->price_level]) ? $this->multiprices[$thirdparty_buyer->price_level] : 0;
2536 $pu_ttc = isset($this->multiprices_ttc[$thirdparty_buyer->price_level]) ? $this->multiprices_ttc[$thirdparty_buyer->price_level] : 0;
2537 $price_min = isset($this->multiprices_min[$thirdparty_buyer->price_level]) ? $this->multiprices_min[$thirdparty_buyer->price_level] : 0;
2538 $price_min_ttc = isset($this->multiprices_min_ttc[$thirdparty_buyer->price_level]) ? $this->multiprices_min_ttc[$thirdparty_buyer->price_level] : 0;
2539 $price_base_type = isset($this->multiprices_base_type[$thirdparty_buyer->price_level]) ? $this->multiprices_base_type[$thirdparty_buyer->price_level] :
'HT';
2542 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2543 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2545 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2546 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2548 if (empty($tva_tx)) {
2553 } elseif (
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !empty($thirdparty_buyer->price_level)) {
2554 $pu_ht = isset($this->multiprices[$thirdparty_buyer->price_level]) ? $this->multiprices[$thirdparty_buyer->price_level] : 0;
2555 $pu_ttc = isset($this->multiprices_ttc[$thirdparty_buyer->price_level]) ? $this->multiprices_ttc[$thirdparty_buyer->price_level] : 0;
2556 $price_min = isset($this->multiprices_min[$thirdparty_buyer->price_level]) ? $this->multiprices_min[$thirdparty_buyer->price_level] : 0;
2557 $price_min_ttc = isset($this->multiprices_min_ttc[$thirdparty_buyer->price_level]) ? $this->multiprices_min_ttc[$thirdparty_buyer->price_level] : 0;
2558 $price_base_type = isset($this->multiprices_base_type[$thirdparty_buyer->price_level]) ? $this->multiprices_base_type[$thirdparty_buyer->price_level] :
'HT';
2561 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2562 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2564 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2565 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2567 if (empty($tva_tx)) {
2573 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2577 $filter = array(
't.fk_product' => (
string) $this->
id,
't.fk_soc' => (
string) $thirdparty_buyer->id);
2579 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2581 if (count($prodcustprice->lines) > 0) {
2582 $date_now = (int) floor(
dol_now() / 86400) * 86400;
2583 foreach ($prodcustprice->lines as $k => $custprice_line) {
2584 if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
2585 $pu_ht =
price($custprice_line->price);
2586 $price_min =
price($custprice_line->price_min);
2587 $price_min_ttc =
price($custprice_line->price_min_ttc);
2588 $pu_ttc =
price($custprice_line->price_ttc);
2589 $price_base_type = $custprice_line->price_base_type;
2590 $tva_tx = $custprice_line->tva_tx;
2591 if ($custprice_line->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2592 $tva_tx .=
' (' . $custprice_line->default_vat_code .
')';
2594 $tva_npr = $custprice_line->recuperableonly;
2595 if (empty($tva_tx)) {
2605 if (!empty($this->prices_by_qty[0])) {
2608 foreach ($this->prices_by_qty_list[0] as $priceforthequantityarray) {
2609 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2613 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2614 $pu_ht = $priceforthequantityarray[
'unitprice'];
2616 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2623 if (!empty($this->prices_by_qty[$thirdparty_buyer->price_level])) {
2626 foreach ($this->prices_by_qty_list[$thirdparty_buyer->price_level] as $priceforthequantityarray) {
2627 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2631 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2632 $pu_ht = $priceforthequantityarray[
'unitprice'];
2634 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2641 return array(
'pu_ht' => $pu_ht,
'pu_ttc' => $pu_ttc,
'price_min' => $price_min,
'price_min_ttc' => $price_min_ttc,
'price_base_type' => $price_base_type,
'tva_tx' => $tva_tx,
'tva_npr' => $tva_npr);
2658 public function get_buyprice($prodfournprice, $qty, $product_id = 0, $fourn_ref =
'', $fk_soc = 0)
2661 global $action, $hookmanager;
2664 if (is_object($hookmanager)) {
2665 $parameters = array(
2666 'prodfournprice' => $prodfournprice,
2668 'product_id' => $product_id,
2669 'fourn_ref' => $fourn_ref,
2670 'fk_soc' => $fk_soc,
2673 $reshook = $hookmanager->executeHooks(
'getBuyPrice', $parameters, $this, $action);
2675 return $hookmanager->resArray;
2682 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2683 $sql .=
" pfp.fk_product, pfp.ref_fourn as ref_supplier, pfp.desc_fourn as desc_supplier, pfp.tva_tx, pfp.default_vat_code, pfp.fk_supplier_price_expression,";
2684 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2685 $sql .=
" pfp.packaging";
2686 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2687 $sql .=
" WHERE pfp.rowid = ".((int) $prodfournprice);
2689 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2691 $sql .=
" ORDER BY pfp.quantity DESC";
2693 dol_syslog(get_class($this).
"::get_buyprice first search by prodfournprice/qty", LOG_DEBUG);
2694 $resql = $this->db->query($sql);
2696 $obj = $this->db->fetch_object($resql);
2697 if ($obj && $obj->quantity > 0) {
2698 if (
isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2700 $prod_supplier->product_fourn_price_id = $obj->rowid;
2701 $prod_supplier->id = $obj->fk_product;
2702 $prod_supplier->fourn_qty = $obj->quantity;
2703 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2704 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2706 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2708 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2709 if ($price_result >= 0) {
2710 $obj->price = $price_result;
2713 $this->product_fourn_price_id = $obj->rowid;
2714 $this->buyprice = $obj->price;
2715 $this->fourn_pu = $obj->price / $obj->quantity;
2716 $this->fourn_price_base_type =
'HT';
2717 $this->fourn_socid = $obj->fk_soc;
2718 $this->ref_fourn = $obj->ref_supplier;
2719 $this->ref_supplier = $obj->ref_supplier;
2720 $this->desc_supplier = $obj->desc_supplier;
2721 $this->remise_percent = $obj->remise_percent;
2722 $this->vatrate_supplier = $obj->tva_tx;
2723 $this->default_vat_code_supplier = $obj->default_vat_code;
2724 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2725 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2726 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2727 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2728 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2730 $this->packaging = (float) $obj->packaging;
2736 $this->fourn_qty = $obj->quantity;
2737 $result = $obj->fk_product;
2741 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2742 $sql .=
" pfp.fk_product, pfp.ref_fourn as ref_supplier, pfp.desc_fourn as desc_supplier, pfp.tva_tx, pfp.default_vat_code, pfp.fk_supplier_price_expression,";
2743 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2744 $sql .=
" pfp.packaging";
2745 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2746 $sql .=
" WHERE 1 = 1";
2747 if ($product_id > 0) {
2748 $sql .=
" AND pfp.fk_product = ".((int) $product_id);
2750 if ($fourn_ref !=
'none') {
2751 $sql .=
" AND pfp.ref_fourn = '".$this->db->escape($fourn_ref).
"'";
2754 $sql .=
" AND pfp.fk_soc = ".((int) $fk_soc);
2757 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2759 $sql .=
" ORDER BY pfp.quantity DESC";
2762 dol_syslog(get_class($this).
"::get_buyprice second search from qty/ref/product_id", LOG_DEBUG);
2763 $resql = $this->db->query($sql);
2765 $obj = $this->db->fetch_object($resql);
2766 if ($obj && $obj->quantity > 0) {
2767 if (
isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2769 $prod_supplier->product_fourn_price_id = $obj->rowid;
2770 $prod_supplier->id = $obj->fk_product;
2771 $prod_supplier->fourn_qty = $obj->quantity;
2772 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2773 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2775 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2777 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2778 if ($price_result >= 0) {
2779 $obj->price = $price_result;
2782 $this->product_fourn_price_id = $obj->rowid;
2783 $this->buyprice = $obj->price;
2784 $this->fourn_qty = $obj->quantity;
2785 $this->fourn_pu = $obj->price / $obj->quantity;
2786 $this->fourn_price_base_type =
'HT';
2787 $this->fourn_socid = $obj->fk_soc;
2788 $this->ref_fourn = $obj->ref_supplier;
2789 $this->ref_supplier = $obj->ref_supplier;
2790 $this->desc_supplier = $obj->desc_supplier;
2791 $this->remise_percent = $obj->remise_percent;
2792 $this->vatrate_supplier = $obj->tva_tx;
2793 $this->default_vat_code_supplier = $obj->default_vat_code;
2794 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2795 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2796 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2797 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2798 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2800 $this->packaging = (float) $obj->packaging;
2804 $this->fourn_qty = $obj->quantity;
2805 $result = $obj->fk_product;
2811 $this->error = $this->db->lasterror();
2816 $this->error = $this->db->lasterror();
2840 public function updatePrice($newprice, $newpricebase, $user, $newvat =
null, $newminprice = 0, $level = 0, $newnpr = 0, $newpbq = 0, $ignore_autogen = 0, $localtaxes_array = array(), $newdefaultvatcode =
'', $price_label =
'', $notrigger = 0)
2846 dol_syslog(get_class($this).
"::update_price id=".$id.
" newprice=".$newprice.
" newpricebase=".$newpricebase.
" newminprice=".$newminprice.
" level=".$level.
" npr=".$newnpr.
" newdefaultvatcode=".$newdefaultvatcode);
2849 if (empty($this->tva_tx)) {
2850 $this->tva_tx = 0.0;
2852 if (empty($newnpr)) {
2855 if (empty($newminprice)) {
2860 if ($newvat ===
null || $newvat ==
'') {
2861 $newvat = (float) $this->tva_tx;
2864 $localtaxtype1 =
'';
2865 $localtaxtype2 =
'';
2870 return $this->
generateMultiprices($user, $newprice, $newpricebase, $newvat, $newnpr, $newpbq);
2873 if (!empty($newminprice) && ($newminprice > $newprice)) {
2874 $this->error =
'ErrorPriceCantBeLowerThanMinPrice';
2878 if ($newprice === 0 || $newprice !==
'') {
2879 if ($newpricebase ==
'TTC') {
2880 $price_ttc = (float)
price2num($newprice,
'MU');
2881 $price = (float)
price2num($newprice) / (1 + ((float) $newvat / 100));
2882 $price = (float)
price2num($price,
'MU');
2884 if ((
string) $newminprice !=
'0') {
2885 $price_min_ttc = (float)
price2num($newminprice,
'MU');
2886 $price_min = (float)
price2num($newminprice) / (1 + ($newvat / 100));
2887 $price_min = (float)
price2num($price_min,
'MU');
2890 $price_min_ttc = 0.0;
2893 $price = (float)
price2num($newprice,
'MU');
2894 $price_ttc = ($newnpr != 1) ? (
float)
price2num($newprice) * (1 + ($newvat / 100)) : $price;
2895 $price_ttc = (float)
price2num($price_ttc,
'MU');
2897 if ((
string) $newminprice !=
'0') {
2898 $price_min = (float)
price2num($newminprice,
'MU');
2899 $price_min_ttc = (float)
price2num($newminprice) * (1 + ($newvat / 100));
2900 $price_min_ttc = (float)
price2num($price_min_ttc,
'MU');
2904 $price_min_ttc = 0.0;
2908 if (count($localtaxes_array) > 0) {
2909 $localtaxtype1 = $localtaxes_array[
'0'];
2910 $localtax1 = $localtaxes_array[
'1'];
2911 $localtaxtype2 = $localtaxes_array[
'2'];
2912 $localtax2 = $localtaxes_array[
'3'];
2915 if (!empty($newdefaultvatcode)) {
2918 $sql =
"SELECT t.rowid, t.code, t.recuperableonly as tva_npr, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
2919 $sql .=
" FROM ".MAIN_DB_PREFIX.
"c_tva as t, ".MAIN_DB_PREFIX.
"c_country as c";
2920 $sql .=
" WHERE t.fk_pays = c.rowid AND c.code = '".$this->db->escape(
$mysoc->country_code).
"'";
2921 $sql .=
" AND t.taux = ".((float) $newdefaultvatcode).
" AND t.active = 1";
2922 $sql .=
" AND t.code = '".$this->db->escape($newdefaultvatcode).
"'";
2923 $resql = $this->db->query($sql);
2925 $obj = $this->db->fetch_object($resql);
2927 $npr = $obj->tva_npr;
2928 $localtax1 = $obj->localtax1;
2929 $localtax2 = $obj->localtax2;
2930 $localtaxtype1 = $obj->localtax1_type;
2931 $localtaxtype2 = $obj->localtax2_type;
2936 $localtaxtype1 =
'0';
2938 $localtaxtype2 =
'0';
2942 if (empty($localtax1)) {
2945 if (empty($localtax2)) {
2954 $updatedefaultprice = (empty($level) || $level == 1);
2958 $sql =
"UPDATE ".$this->db->prefix().
"product SET";
2959 if ($updatedefaultprice) {
2960 $sql .=
" price_base_type = '".$this->db->escape($newpricebase).
"',";
2961 $sql .=
" price = ".(float) $price.
",";
2962 $sql .=
" price_ttc = ".(float) $price_ttc.
",";
2963 $sql .=
" price_min = ".(float) $price_min.
",";
2964 $sql .=
" price_min_ttc = ".(float) $price_min_ttc.
",";
2965 $sql .=
" price_label = ".(!empty($price_label) ?
"'".$this->db->escape($price_label).
"'" :
"null").
",";
2967 $sql .=
" localtax1_tx = ".($localtax1 >= 0 ? (float) $localtax1 :
'NULL').
",";
2968 $sql .=
" localtax2_tx = ".($localtax2 >= 0 ? (float) $localtax2 :
'NULL').
",";
2969 $sql .=
" localtax1_type = ".($localtaxtype1 !=
'' ?
"'".$this->db->escape($localtaxtype1).
"'" :
"'0'").
",";
2970 $sql .=
" localtax2_type = ".($localtaxtype2 !=
'' ?
"'".$this->db->escape($localtaxtype2).
"'" :
"'0'").
",";
2971 $sql .=
" default_vat_code = ".($newdefaultvatcode ?
"'".$this->db->escape($newdefaultvatcode).
"'" :
"null").
",";
2972 $sql .=
" tva_tx = ".(float)
price2num($newvat).
",";
2973 $sql .=
" recuperableonly = '".$this->db->escape((
string) $newnpr).
"'";
2974 $sql .=
" WHERE rowid = ".((int) $id);
2976 dol_syslog(get_class($this).
"::update_price", LOG_DEBUG);
2977 $resql = $this->db->query($sql);
2979 $this->multiprices[$level] = $price;
2980 $this->multiprices_ttc[$level] = $price_ttc;
2981 $this->multiprices_min[$level] = $price_min;
2982 $this->multiprices_min_ttc[$level] = $price_min_ttc;
2983 $this->multiprices_base_type[$level] = $newpricebase;
2984 $this->multiprices_default_vat_code[$level] = $newdefaultvatcode;
2985 $this->multiprices_tva_tx[$level] = $newvat;
2986 $this->multiprices_recuperableonly[$level] = $newnpr;
2990 $savdefaultprice = array($this->
price, $this->price_label, $this->price_ttc, $this->price_min, $this->price_min_ttc, $this->price_base_type);
2992 $this->
price = $price;
2993 $this->price_label = $price_label;
2994 $this->price_ttc = $price_ttc;
2995 $this->price_min = $price_min;
2996 $this->price_min_ttc = $price_min_ttc;
2997 $this->price_base_type = $newpricebase;
2998 $this->default_vat_code = $newdefaultvatcode;
2999 $this->tva_tx = $newvat;
3000 $this->tva_npr = $newnpr;
3003 $this->localtax1_tx = $localtax1;
3004 $this->localtax2_tx = $localtax2;
3005 $this->localtax1_type = $localtaxtype1;
3006 $this->localtax2_type = $localtaxtype2;
3009 $this->price_by_qty = $newpbq;
3013 if (!empty(array_diff_assoc($newPriceData, $lastPriceData)) || (!
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3017 if (!$updatedefaultprice) {
3019 list($this->
price, $this->price_label, $this->price_ttc, $this->price_min, $this->price_min_ttc, $this->price_base_type) = $savdefaultprice;
3022 $this->level = $level;
3026 $result = $this->call_trigger(
'PRODUCT_PRICE_MODIFY', $user);
3028 $this->db->rollback();
3034 $this->db->commit();
3036 $this->db->rollback();
3037 $this->error = $this->db->lasterror();
3056 $this->fk_price_expression = $expression_id;
3058 return $this->
update($this->
id, $user);
3073 public function fetch($id = 0, $ref =
'', $ref_ext =
'', $barcode =
'', $ignore_expression = 0, $ignore_price_load = 0, $ignore_lang_load = 0)
3075 include_once DOL_DOCUMENT_ROOT.
'/core/lib/company.lib.php';
3079 dol_syslog(get_class($this).
"::fetch id=".$id.
" ref=".$ref.
" ref_ext=".$ref_ext);
3082 if (!$id && !$ref && !$ref_ext && !$barcode) {
3083 $this->error =
'ErrorWrongParameters';
3084 dol_syslog(get_class($this).
"::fetch ".$this->error, LOG_ERR);
3088 $sql =
"SELECT p.rowid, p.ref, p.ref_ext, p.label, p.description, p.url, p.note_public, p.note as note_private, p.customcode, p.fk_country, p.fk_state, p.lifetime, p.qc_frequency, p.price, p.price_ttc,";
3089 $sql .=
" p.price_min, p.price_min_ttc, p.price_base_type, p.cost_price, p.default_vat_code, p.tva_tx, p.recuperableonly as tva_npr, p.localtax1_tx, p.localtax2_tx, p.localtax1_type, p.localtax2_type, p.tosell,";
3090 $sql .=
" p.tobuy, p.fk_product_type, p.duration, p.fk_default_warehouse, p.fk_default_workstation, p.seuil_stock_alerte, p.canvas, p.net_measure, p.net_measure_units, p.weight, p.weight_units,";
3091 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.last_main_doc,";
3092 $sql .=
" p.surface, p.surface_units, p.volume, p.volume_units, p.barcode, p.fk_barcode_type, p.finished, p.fk_default_bom, p.mandatory_period, p.packaging,";
3094 $sql .=
" p.accountancy_code_buy, p.accountancy_code_buy_intra, p.accountancy_code_buy_export, p.accountancy_code_sell, p.accountancy_code_sell_intra, p.accountancy_code_sell_export,";
3096 $sql .=
" ppe.accountancy_code_buy, ppe.accountancy_code_buy_intra, ppe.accountancy_code_buy_export, ppe.accountancy_code_sell, ppe.accountancy_code_sell_intra, ppe.accountancy_code_sell_export,";
3101 $separatedEntityPMP =
false;
3102 $separatedStock =
false;
3103 $visibleWarehousesEntities =
$conf->entity;
3106 $checkPMPPerEntity = $this->db->query(
"SELECT pmp FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = ".((int) $id).
" AND entity = ".(
int)
$conf->entity);
3107 if ($this->db->num_rows($checkPMPPerEntity) > 0) {
3108 $separatedEntityPMP =
true;
3112 $separatedStock =
true;
3113 if (isset($mc->sharings[
'stock']) && !empty($mc->sharings[
'stock'])) {
3114 $visibleWarehousesEntities .=
"," . implode(
",", $mc->sharings[
'stock']);
3117 if ($separatedEntityPMP) {
3118 $sql .=
" ppe.pmp,";
3122 $sql .=
" p.datec, GREATEST(p.tms, pef.tms) AS tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.sell_or_eat_by_mandatory, p.batch_mask, p.fk_unit,";
3123 $sql .=
" p.fk_price_expression, p.price_autogen, p.stockable_product, p.model_pdf,";
3124 $sql .=
" p.price_label,";
3125 if ($separatedStock) {
3126 $sql .=
" SUM(sp.reel) as stock";
3130 $sql .=
" FROM ".$this->db->prefix().
"product as p";
3131 $sql .=
" LEFT JOIN ".$this->db->prefix().
"product_extrafields as pef ON pef.fk_object=p.rowid";
3133 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int)
$conf->entity);
3135 if ($separatedStock) {
3136 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"product_stock as sp ON sp.fk_product = p.rowid AND sp.fk_entrepot IN (SELECT rowid FROM ".$this->db->prefix().
"entrepot WHERE entity IN (".$this->db->sanitize($visibleWarehousesEntities).
"))";
3140 $sql .=
" WHERE p.rowid = ".((int) $id);
3142 $sql .=
" WHERE p.entity IN (".getEntity($this->element).
")";
3144 $sql .=
" AND p.ref = '".$this->db->escape($ref).
"'";
3145 } elseif ($ref_ext) {
3146 $sql .=
" AND p.ref_ext = '".$this->db->escape($ref_ext).
"'";
3147 } elseif ($barcode) {
3148 $sql .=
" AND p.barcode = '".$this->db->escape($barcode).
"'";
3151 if ($separatedStock) {
3152 $sql .=
" GROUP BY p.rowid, p.ref, p.ref_ext, p.label, p.description, p.url, p.note_public, p.note, p.customcode, p.fk_country, p.fk_state, p.lifetime, p.qc_frequency, p.price, p.price_ttc,";
3153 $sql .=
" p.price_min, p.price_min_ttc, p.price_base_type, p.cost_price, p.default_vat_code, p.tva_tx, p.recuperableonly, p.localtax1_tx, p.localtax2_tx, p.localtax1_type, p.localtax2_type, p.tosell,";
3154 $sql .=
" p.tobuy, p.fk_product_type, p.duration, p.fk_default_warehouse, p.fk_default_workstation, p.seuil_stock_alerte, p.canvas, p.net_measure, p.net_measure_units, p.weight, p.weight_units,";
3155 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
3156 $sql .=
" p.surface, p.surface_units, p.volume, p.volume_units, p.barcode, p.fk_barcode_type, p.finished, p.fk_default_bom, p.mandatory_period, p.packaging,";
3158 $sql .=
" p.accountancy_code_buy, p.accountancy_code_buy_intra, p.accountancy_code_buy_export, p.accountancy_code_sell, p.accountancy_code_sell_intra, p.accountancy_code_sell_export,";
3160 $sql .=
" ppe.accountancy_code_buy, ppe.accountancy_code_buy_intra, ppe.accountancy_code_buy_export, ppe.accountancy_code_sell, ppe.accountancy_code_sell_intra, ppe.accountancy_code_sell_export,";
3162 if ($separatedEntityPMP) {
3163 $sql .=
" ppe.pmp,";
3167 $sql .=
" p.datec, p.tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.sell_or_eat_by_mandatory, p.batch_mask, p.fk_unit,";
3168 $sql .=
" p.fk_price_expression, p.price_autogen, p.stockable_product, p.model_pdf,";
3169 $sql .=
" p.price_label";
3176 $resql = $this->db->query($sql);
3178 unset($this->oldcopy);
3180 if ($this->db->num_rows($resql) > 0) {
3181 $obj = $this->db->fetch_object($resql);
3183 $this->
id = $obj->rowid;
3184 $this->
ref = $obj->ref;
3185 $this->ref_ext = $obj->ref_ext;
3186 $this->label = $obj->label;
3188 $this->url = $obj->url;
3189 $this->note_public = $obj->note_public;
3190 $this->note_private = $obj->note_private;
3191 $this->note = $obj->note_private;
3193 $this->
type = $obj->fk_product_type;
3194 $this->price_label = $obj->price_label;
3195 $this->
status = $obj->tosell;
3196 $this->status_buy = $obj->tobuy;
3197 $this->status_batch = $obj->tobatch;
3198 $this->sell_or_eat_by_mandatory = $obj->sell_or_eat_by_mandatory;
3199 $this->batch_mask = $obj->batch_mask;
3201 $this->customcode = $obj->customcode;
3202 $this->country_id = $obj->fk_country;
3203 $this->country_code =
getCountry($this->country_id,
'2', $this->db);
3204 $this->state_id = $obj->fk_state;
3205 $this->lifetime = $obj->lifetime;
3206 $this->qc_frequency = $obj->qc_frequency;
3207 $this->
price = $obj->price;
3208 $this->price_ttc = $obj->price_ttc;
3209 $this->price_min = $obj->price_min;
3210 $this->price_min_ttc = $obj->price_min_ttc;
3211 $this->price_base_type = (empty($obj->price_base_type) ?
'HT' : $obj->price_base_type);
3212 $this->cost_price = isset($obj->cost_price) ? (float) $obj->cost_price :
null;
3213 $this->default_vat_code = $obj->default_vat_code;
3214 $this->tva_tx = $obj->tva_tx;
3216 $this->tva_npr = $obj->tva_npr;
3218 $this->localtax1_tx = $obj->localtax1_tx;
3219 $this->localtax2_tx = $obj->localtax2_tx;
3220 $this->localtax1_type = $obj->localtax1_type;
3221 $this->localtax2_type = $obj->localtax2_type;
3223 $this->finished = $obj->finished;
3224 $this->fk_default_bom = $obj->fk_default_bom;
3226 $this->duration = $obj->duration;
3228 preg_match(
'/([\d.]+)(\w+)/', $obj->duration, $matches);
3229 $this->duration_value = !empty($matches[1]) ? (float) $matches[1] : 0;
3230 $this->duration_unit = !empty($matches[2]) ? (
string) $matches[2] :
null;
3231 $this->canvas = $obj->canvas;
3232 $this->net_measure = $obj->net_measure;
3233 $this->net_measure_units = $obj->net_measure_units;
3234 $this->weight = $obj->weight;
3235 $this->weight_units = (is_null($obj->weight_units) ? 0 : $obj->weight_units);
3236 $this->length = $obj->length;
3237 $this->length_units = (is_null($obj->length_units) ? 0 : $obj->length_units);
3238 $this->width = $obj->width;
3239 $this->width_units = (is_null($obj->width_units) ? 0 : $obj->width_units);
3240 $this->height = $obj->height;
3241 $this->height_units = (is_null($obj->height_units) ? 0 : $obj->height_units);
3243 $this->surface = $obj->surface;
3244 $this->surface_units = (is_null($obj->surface_units) ? 0 : $obj->surface_units);
3245 $this->volume = $obj->volume;
3246 $this->volume_units = (is_null($obj->volume_units) ? 0 : $obj->volume_units);
3247 $this->barcode = $obj->barcode;
3248 $this->barcode_type = $obj->fk_barcode_type;
3250 $this->accountancy_code_buy = $obj->accountancy_code_buy;
3251 $this->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra;
3252 $this->accountancy_code_buy_export = $obj->accountancy_code_buy_export;
3253 $this->accountancy_code_sell = $obj->accountancy_code_sell;
3254 $this->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra;
3255 $this->accountancy_code_sell_export = $obj->accountancy_code_sell_export;
3257 $this->fk_default_warehouse = $obj->fk_default_warehouse;
3258 $this->fk_default_workstation = $obj->fk_default_workstation;
3259 $this->seuil_stock_alerte = $obj->seuil_stock_alerte;
3260 $this->desiredstock = $obj->desiredstock;
3261 $this->stock_reel = $obj->stock;
3262 $this->stockable_product = $obj->stockable_product;
3263 $this->pmp = $obj->pmp;
3265 $this->date_creation = $this->db->jdate($obj->datec);
3266 $this->date_modification = $this->db->jdate($obj->tms);
3268 $this->import_key = $obj->import_key;
3269 $this->entity = $obj->entity;
3271 $this->ref_ext = $obj->ref_ext;
3272 $this->fk_price_expression = $obj->fk_price_expression;
3273 $this->fk_unit = $obj->fk_unit;
3274 $this->price_autogen = $obj->price_autogen;
3275 $this->model_pdf = $obj->model_pdf;
3276 $this->last_main_doc = $obj->last_main_doc;
3278 $this->mandatory_period = $obj->mandatory_period;
3281 $this->packaging = (float) $obj->packaging;
3284 $this->db->free($resql);
3296 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
3297 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3298 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3299 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3300 $sql .=
" ,price_label";
3301 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3302 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3303 $sql .=
" AND price_level=".((int) $i);
3304 $sql .=
" AND fk_product = ".((int) $this->
id);
3305 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3307 $resql = $this->db->query($sql);
3309 $result = $this->db->fetch_array($resql);
3311 $this->multiprices[$i] = $result ? $result[
"price"] :
null;
3312 $this->multiprices_ttc[$i] = $result ? $result[
"price_ttc"] :
null;
3313 $this->multiprices_min[$i] = $result ? $result[
"price_min"] :
null;
3314 $this->multiprices_min_ttc[$i] = $result ? $result[
"price_min_ttc"] :
null;
3315 $this->multiprices_base_type[$i] = $result ? $result[
"price_base_type"] :
null;
3317 $this->multiprices_tva_tx[$i] = $result ? $result[
"tva_tx"].(!empty($result[
'default_vat_code']) ?
' ('.$result[
'default_vat_code'].
')' :
'') :
null;
3318 $this->multiprices_recuperableonly[$i] = $result ? $result[
"recuperableonly"] :
null;
3357 $this->error = $this->db->lasterror;
3363 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY') && empty($ignore_price_load)) {
3364 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3365 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid";
3366 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3367 $sql .=
" WHERE fk_product = ".((int) $this->
id);
3368 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3371 $resql = $this->db->query($sql);
3373 $result = $this->db->fetch_array($resql);
3377 $this->prices_by_qty[0] = $result[
"price_by_qty"];
3378 $this->prices_by_qty_id[0] = $result[
"rowid"];
3380 if ($this->prices_by_qty[0] == 1) {
3381 $sql =
"SELECT rowid,price, unitprice, quantity, remise_percent, remise, remise, price_base_type";
3382 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3383 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[0]);
3384 $sql .=
" ORDER BY quantity ASC";
3386 $resql = $this->db->query($sql);
3388 $resultat = array();
3390 while ($result = $this->db->fetch_array($resql)) {
3391 $resultat[$ii] = array();
3392 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3393 $resultat[$ii][
"price"] = $result[
"price"];
3394 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3395 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3396 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3398 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3401 $this->prices_by_qty_list[0] = $resultat;
3403 $this->error = $this->db->lasterror;
3409 $this->error = $this->db->lasterror;
3412 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') && empty($ignore_price_load)) {
3413 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
3414 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3415 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3416 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3417 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3418 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3419 $sql .=
" AND price_level=".((int) $i);
3420 $sql .=
" AND fk_product = ".((int) $this->
id);
3421 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3423 $resql = $this->db->query($sql);
3425 $this->error = $this->db->lasterror;
3428 $result = $this->db->fetch_array($resql);
3429 $this->multiprices[$i] = (!empty($result[
"price"]) ? $result[
"price"] : 0);
3430 $this->multiprices_ttc[$i] = (!empty($result[
"price_ttc"]) ? $result[
"price_ttc"] : 0);
3431 $this->multiprices_min[$i] = (!empty($result[
"price_min"]) ? $result[
"price_min"] : 0);
3432 $this->multiprices_min_ttc[$i] = (!empty($result[
"price_min_ttc"]) ? $result[
"price_min_ttc"] : 0);
3433 $this->multiprices_base_type[$i] = (!empty($result[
"price_base_type"]) ? $result[
"price_base_type"] :
'');
3435 $this->multiprices_tva_tx[$i] = (!empty($result[
"tva_tx"]) ? $result[
"tva_tx"] : 0);
3436 $this->multiprices_recuperableonly[$i] = (!empty($result[
"recuperableonly"]) ? $result[
"recuperableonly"] : 0);
3439 $this->prices_by_qty[$i] = (!empty($result[
"price_by_qty"]) ? $result[
"price_by_qty"] : 0);
3440 $this->prices_by_qty_id[$i] = (!empty($result[
"rowid"]) ? $result[
"rowid"] : 0);
3442 if ($this->prices_by_qty[$i] == 1) {
3443 $sql =
"SELECT rowid, price, unitprice, quantity, remise_percent, remise, price_base_type";
3444 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3445 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[$i]);
3446 $sql .=
" ORDER BY quantity ASC";
3448 $resql = $this->db->query($sql);
3450 $resultat = array();
3452 while ($result = $this->db->fetch_array($resql)) {
3453 $resultat[$ii] = array();
3454 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3455 $resultat[$ii][
"price"] = $result[
"price"];
3456 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3457 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3458 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3459 $resultat[$ii][
"remise"] = $result[
"remise"];
3460 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3463 $this->prices_by_qty_list[$i] = $resultat;
3465 $this->error = $this->db->lasterror;
3473 if (
isModEnabled(
'dynamicprices') && !empty($this->fk_price_expression) && empty($ignore_expression)) {
3474 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
3476 $price_result = $priceparser->parseProduct($this);
3477 if ($price_result >= 0) {
3478 $this->
price = $price_result;
3480 $this->price_ttc = (float)
price2num($this->
price) * (1 + ($this->tva_tx / 100));
3481 $this->price_ttc = (float)
price2num($this->price_ttc,
'MU');
3487 $this->stock_warehouse = array();
3494 $this->error = $this->db->lasterror();
3509 global $user, $hookmanager, $action;
3513 foreach (array(
'toconsume',
'consumed',
'toproduce',
'produced') as $role) {
3514 $this->stats_mo[
'customers_'.$role] = 0;
3515 $this->stats_mo[
'nb_'.$role] = 0;
3516 $this->stats_mo[
'qty_'.$role] = 0;
3518 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3519 $sql .=
" SUM(mp.qty) as qty";
3520 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as c";
3521 $sql .=
" INNER JOIN ".$this->db->prefix().
"mrp_production as mp ON mp.fk_mo=c.rowid";
3522 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3523 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3526 $sql .=
" c.entity IN (".getEntity(
'mo').
")";
3528 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3529 $sql .=
" AND mp.role ='".$this->db->escape($role).
"'";
3531 $sql .=
" AND c.fk_soc = ".((int) $socid);
3534 $result = $this->db->query($sql);
3536 $obj = $this->db->fetch_object($result);
3537 $this->stats_mo[
'customers_'.$role] = $obj->nb_customers ? $obj->nb_customers : 0;
3538 $this->stats_mo[
'nb_'.$role] = $obj->nb ? $obj->nb : 0;
3539 $this->stats_mo[
'qty_'.$role] = $obj->qty ?
price2num($obj->qty,
'MS') : 0;
3541 $this->error = $this->db->error();
3546 if (!empty($error)) {
3550 $parameters = array(
'socid' => $socid);
3551 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3553 $this->stats_mo = $hookmanager->resArray[
'stats_mo'];
3569 global $hookmanager, $action;
3573 $this->stats_bom[
'nb_toproduce'] = 0;
3574 $this->stats_bom[
'nb_toconsume'] = 0;
3575 $this->stats_bom[
'qty_toproduce'] = 0;
3576 $this->stats_bom[
'qty_toconsume'] = 0;
3578 $sql =
"SELECT COUNT(DISTINCT b.rowid) as nb_toproduce,";
3579 $sql .=
" SUM(b.qty) as qty_toproduce";
3580 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3581 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom = b.rowid";
3583 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3584 $sql .=
" AND b.fk_product =".((int) $this->
id);
3585 $sql .=
" GROUP BY b.rowid";
3587 $result = $this->db->query($sql);
3589 $obj = $this->db->fetch_object($result);
3590 $this->stats_bom[
'nb_toproduce'] = !empty($obj->nb_toproduce) ? $obj->nb_toproduce : 0;
3591 $this->stats_bom[
'qty_toproduce'] = !empty($obj->qty_toproduce) ?
price2num($obj->qty_toproduce) : 0;
3593 $this->error = $this->db->error();
3597 $sql =
"SELECT COUNT(DISTINCT bl.rowid) as nb_toconsume,";
3598 $sql .=
" SUM(bl.qty) as qty_toconsume";
3599 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3600 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
3602 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3603 $sql .=
" AND bl.fk_product =".((int) $this->
id);
3605 $result = $this->db->query($sql);
3607 $obj = $this->db->fetch_object($result);
3608 $this->stats_bom[
'nb_toconsume'] = !empty($obj->nb_toconsume) ? $obj->nb_toconsume : 0;
3609 $this->stats_bom[
'qty_toconsume'] = !empty($obj->qty_toconsume) ?
price2num($obj->qty_toconsume) : 0;
3611 $this->error = $this->db->error();
3615 if (!empty($error)) {
3619 $parameters = array(
'socid' => $socid);
3620 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3622 $this->stats_bom = $hookmanager->resArray[
'stats_bom'];
3638 global $user, $hookmanager, $action;
3640 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_customers, COUNT(DISTINCT p.rowid) as nb,";
3641 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3642 $sql .=
" FROM ".$this->db->prefix().
"propaldet as pd";
3643 $sql .=
", ".$this->db->prefix().
"propal as p";
3644 $sql .=
", ".$this->db->prefix().
"societe as s";
3645 $sql .=
" WHERE p.rowid = pd.fk_propal";
3646 $sql .=
" AND p.fk_soc = s.rowid";
3647 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
3648 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3649 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3650 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $user->id);
3654 $sql .=
" AND p.fk_soc = ".((int) $socid);
3657 $parameters = array(
'socid' => $socid,
'type_element' =>
'propal');
3658 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3659 $sql .= $hookmanager->resPrint;
3660 $result = $this->db->query($sql);
3662 $obj = $this->db->fetch_object($result);
3663 $this->stats_propale[
'customers'] = (int) $obj->nb_customers;
3664 $this->stats_propale[
'nb'] = (int) $obj->nb;
3665 $this->stats_propale[
'rows'] = (int) $obj->nb_rows;
3666 $this->stats_propale[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
3671 if (is_array($TFather) && !empty($TFather)) {
3672 foreach ($TFather as &$fatherData) {
3673 $pFather =
new Product($this->db);
3674 $pFather->id = (int) $fatherData[
'id'];
3675 $qtyCoef = $fatherData[
'qty'];
3677 if ($fatherData[
'incdec']) {
3678 $pFather->load_stats_propale($socid);
3680 if (!empty($pFather->stats_propale)) {
3681 $this->stats_propale[
'customers'] += $pFather->stats_propale[
'customers'];
3682 $this->stats_propale[
'nb'] += $pFather->stats_propale[
'nb'];
3683 $this->stats_propale[
'rows'] += $pFather->stats_propale[
'rows'];
3684 $this->stats_propale[
'qty'] += $pFather->stats_propale[
'qty'] * $qtyCoef;
3691 $parameters = array(
'socid' => $socid);
3692 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerProposal', $parameters, $this, $action);
3694 $this->stats_propale = $hookmanager->resArray[
'stats_propale'];
3699 $this->error = $this->db->error();
3715 global $user, $hookmanager, $action;
3717 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_suppliers, COUNT(DISTINCT p.rowid) as nb,";
3718 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3719 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as pd";
3720 $sql .=
", ".$this->db->prefix().
"supplier_proposal as p";
3721 $sql .=
", ".$this->db->prefix().
"societe as s";
3722 $sql .=
" WHERE p.rowid = pd.fk_supplier_proposal";
3723 $sql .=
" AND p.fk_soc = s.rowid";
3724 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
3725 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3726 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3727 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $user->id);
3731 $sql .=
" AND p.fk_soc = ".((int) $socid);
3734 $result = $this->db->query($sql);
3736 $obj = $this->db->fetch_object($result);
3737 $this->stats_proposal_supplier[
'suppliers'] = $obj->nb_suppliers;
3738 $this->stats_proposal_supplier[
'nb'] = $obj->nb;
3739 $this->stats_proposal_supplier[
'rows'] = $obj->nb_rows;
3740 $this->stats_proposal_supplier[
'qty'] = $obj->qty ? $obj->qty : 0;
3742 $parameters = array(
'socid' => $socid);
3743 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierProposal', $parameters, $this, $action);
3745 $this->stats_proposal_supplier = $hookmanager->resArray[
'stats_proposal_supplier'];
3750 $this->error = $this->db->error();
3768 global $user, $hookmanager, $action;
3771 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3772 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3773 $sql .=
" FROM ".$this->db->prefix().
"commandedet as cd";
3774 $sql .=
", ".$this->db->prefix().
"commande as c";
3775 $sql .=
", ".$this->db->prefix().
"societe as s";
3776 $sql .=
" WHERE c.rowid = cd.fk_commande";
3777 $sql .=
" AND c.fk_soc = s.rowid";
3778 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'commande').
")";
3779 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3780 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3781 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3784 $sql .=
" AND c.fk_soc = ".((int) $socid);
3786 if ($filtrestatut !=
'') {
3787 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3790 $parameters = array(
'socid' => $socid,
'type_element' =>
'order');
3791 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3792 $sql .= $hookmanager->resPrint;
3793 $result = $this->db->query($sql);
3795 $obj = $this->db->fetch_object($result);
3796 $this->stats_commande[
'customers'] = (int) $obj->nb_customers;
3797 $this->stats_commande[
'nb'] = (int) $obj->nb;
3798 $this->stats_commande[
'rows'] = (int) $obj->nb_rows;
3799 $this->stats_commande[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
3804 if (is_array($TFather) && !empty($TFather)) {
3805 foreach ($TFather as &$fatherData) {
3806 $pFather =
new Product($this->db);
3807 $pFather->id = $fatherData[
'id'];
3808 $qtyCoef = $fatherData[
'qty'];
3810 if ($fatherData[
'incdec']) {
3811 $pFather->load_stats_commande($socid, $filtrestatut);
3813 $this->stats_commande[
'customers'] += $pFather->stats_commande[
'customers'];
3814 $this->stats_commande[
'nb'] += $pFather->stats_commande[
'nb'];
3815 $this->stats_commande[
'rows'] += $pFather->stats_commande[
'rows'];
3816 $this->stats_commande[
'qty'] += $pFather->stats_commande[
'qty'] * $qtyCoef;
3829 $sql =
"SELECT SUM(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3830 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3832 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture' AND sourcetype = 'commande' ";
3833 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3834 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3835 $sql .=
" AND EXISTS (SELECT cd.fk_product FROM ".$this->db->prefix().
"commandedet as cd WHERE cd.fk_product = fd.fk_product AND cd.fk_commande = c.rowid)";
3839 $sql .=
"SELECT SUM(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3840 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3841 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_source = f.rowid AND el.targettype = 'commande' AND sourcetype = 'facture' ";
3842 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_target = c.rowid";
3843 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3844 $sql .=
" AND EXISTS (SELECT cd.fk_product FROM ".$this->db->prefix().
"commandedet as cd WHERE cd.fk_product = fd.fk_product AND cd.fk_commande = c.rowid)";
3846 $parameters = array(
'socid' => $socid,
'type_element' =>
'order');
3847 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3848 $sql .= $hookmanager->resPrint;
3849 $resql = $this->db->query($sql);
3851 while ($obj = $this->db->fetch_object($resql)) {
3852 $adeduire += (float) $obj->count;
3856 $this->stats_commande[
'qty'] -= $adeduire;
3859 include_once DOL_DOCUMENT_ROOT.
'/compta/facture/class/facture.class.php';
3863 $sql =
"SELECT sum(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3864 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3866 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture' AND sourcetype = 'commande' ";
3867 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3868 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3869 $sql .=
" AND EXISTS (SELECT cd.fk_product FROM ".$this->db->prefix().
"commandedet as cd WHERE cd.fk_product = fd.fk_product AND cd.fk_commande = c.rowid)";
3871 $sql .=
" UNION ALL ";
3873 $sql .=
"SELECT sum(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3874 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3875 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_source = f.rowid AND el.targettype = 'commande' AND sourcetype = 'facture' ";
3876 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_target = c.rowid";
3877 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3878 $sql .=
" AND EXISTS (SELECT cd.fk_product FROM ".$this->db->prefix().
"commandedet as cd WHERE cd.fk_product = fd.fk_product AND cd.fk_commande = c.rowid)";
3880 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3882 $parameters = array(
'socid' => $socid,
'type_element' =>
'order');
3883 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3884 $sql .= $hookmanager->resPrint;
3885 $resql = $this->db->query($sql);
3887 while ($obj = $this->db->fetch_object($resql)) {
3888 $adeduire += (float) $obj->count;
3891 $this->error = $this->db->error();
3895 $this->stats_commande[
'qty'] -= $adeduire;
3899 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3900 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerOrder', $parameters, $this, $action);
3902 $this->stats_commande = $hookmanager->resArray[
'stats_commande'];
3906 $this->error = $this->db->error();
3924 global $user, $hookmanager, $action;
3926 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_suppliers, COUNT(DISTINCT c.rowid) as nb,";
3927 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3928 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as cd";
3929 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as c";
3930 $sql .=
", ".$this->db->prefix().
"societe as s";
3931 $sql .=
" WHERE c.rowid = cd.fk_commande";
3932 $sql .=
" AND c.fk_soc = s.rowid";
3933 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3934 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3935 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3936 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3939 $sql .=
" AND c.fk_soc = ".((int) $socid);
3941 if ($filtrestatut !=
'') {
3942 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3944 if (!empty($dateofvirtualstock)) {
3945 $sql .=
" AND c.date_livraison <= '".$this->db->idate($dateofvirtualstock).
"'";
3948 $result = $this->db->query($sql);
3950 $obj = $this->db->fetch_object($result);
3951 $this->stats_commande_fournisseur[
'suppliers'] = $obj->nb_suppliers;
3952 $this->stats_commande_fournisseur[
'nb'] = $obj->nb;
3953 $this->stats_commande_fournisseur[
'rows'] = $obj->nb_rows;
3954 $this->stats_commande_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
3956 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3957 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierOrder', $parameters, $this, $action);
3959 $this->stats_commande_fournisseur = $hookmanager->resArray[
'stats_commande_fournisseur'];
3964 $this->error = $this->db->error().
' sql='.$sql;
3979 public function load_stats_sending($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $filterShipmentStatus =
'')
3982 global $user, $hookmanager, $action;
3984 $sql =
"SELECT COUNT(DISTINCT e.fk_soc) as nb_customers, COUNT(DISTINCT e.rowid) as nb,";
3985 $sql .=
" COUNT(ed.rowid) as nb_rows, SUM(ed.qty) as qty";
3986 $sql .=
" FROM ".$this->db->prefix().
"expeditiondet as ed";
3987 $sql .=
", ".$this->db->prefix().
"commandedet as cd";
3988 $sql .=
", ".$this->db->prefix().
"commande as c";
3989 $sql .=
", ".$this->db->prefix().
"expedition as e";
3990 $sql .=
", ".$this->db->prefix().
"societe as s";
3991 $sql .=
" WHERE e.rowid = ed.fk_expedition";
3992 $sql .=
" AND c.rowid = cd.fk_commande";
3993 $sql .=
" AND e.fk_soc = s.rowid";
3994 $sql .=
" AND e.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'expedition').
")";
3995 $sql .=
" AND ed.fk_elementdet = cd.rowid";
3996 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3997 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3998 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = e.fk_soc AND sc.fk_user = ".((int) $user->id);
4001 $sql .=
" AND e.fk_soc = ".((int) $socid);
4003 if ($filtrestatut !=
'') {
4004 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
4006 if (!empty($filterShipmentStatus)) {
4007 $sql .=
" AND e.fk_statut IN (".$this->db->sanitize($filterShipmentStatus).
")";
4010 $result = $this->db->query($sql);
4012 $obj = $this->db->fetch_object($result);
4013 $this->stats_expedition[
'customers'] = (int) $obj->nb_customers;
4014 $this->stats_expedition[
'nb'] = (int) $obj->nb;
4015 $this->stats_expedition[
'rows'] = (int) $obj->nb_rows;
4016 $this->stats_expedition[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
4021 if (is_array($TFather) && !empty($TFather)) {
4022 foreach ($TFather as &$fatherData) {
4023 $pFather =
new Product($this->db);
4024 $pFather->id = $fatherData[
'id'];
4025 $qtyCoef = $fatherData[
'qty'];
4027 if ($fatherData[
'incdec']) {
4028 $pFather->load_stats_sending($socid, $filtrestatut, $forVirtualStock);
4030 if (!empty($pFather->stats_expedition)) {
4031 $this->stats_expedition[
'customers'] += $pFather->stats_expedition[
'customers'];
4032 $this->stats_expedition[
'nb'] += $pFather->stats_expedition[
'nb'];
4033 $this->stats_expedition[
'rows'] += $pFather->stats_expedition[
'rows'];
4034 $this->stats_expedition[
'qty'] += $pFather->stats_expedition[
'qty'] * $qtyCoef;
4041 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock,
'filterShipmentStatus' => $filterShipmentStatus);
4042 $reshook = $hookmanager->executeHooks(
'loadStatsSending', $parameters, $this, $action);
4044 $this->stats_expedition = $hookmanager->resArray[
'stats_expedition'];
4049 $this->error = $this->db->error();
4064 public function load_stats_reception($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null)
4067 global $user, $hookmanager, $action;
4069 $sql =
"SELECT COUNT(DISTINCT cf.fk_soc) as nb_suppliers, COUNT(DISTINCT cf.rowid) as nb,";
4070 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4071 $sql .=
" FROM ".$this->db->prefix().
"receptiondet_batch as fd";
4072 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as cf";
4073 $sql .=
", ".$this->db->prefix().
"societe as s";
4074 $sql .=
" WHERE cf.rowid = fd.fk_element";
4075 $sql .=
" AND cf.fk_soc = s.rowid";
4076 $sql .=
" AND cf.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
4077 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4078 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
4079 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = cf.fk_soc AND sc.fk_user = ".((int) $user->id);
4082 $sql .=
" AND cf.fk_soc = ".((int) $socid);
4084 if ($filtrestatut !=
'') {
4085 $sql .=
" AND cf.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
4087 if (!empty($dateofvirtualstock)) {
4088 $sql .=
" AND fd.datec <= '".$this->db->idate($dateofvirtualstock).
"'";
4091 $result = $this->db->query($sql);
4093 $obj = $this->db->fetch_object($result);
4094 $this->stats_reception[
'suppliers'] = $obj->nb_suppliers;
4095 $this->stats_reception[
'nb'] = $obj->nb;
4096 $this->stats_reception[
'rows'] = $obj->nb_rows;
4097 $this->stats_reception[
'qty'] = $obj->qty ? $obj->qty : 0;
4099 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
4100 $reshook = $hookmanager->executeHooks(
'loadStatsReception', $parameters, $this, $action);
4102 $this->stats_reception = $hookmanager->resArray[
'stats_reception'];
4107 $this->error = $this->db->error();
4123 public function load_stats_inproduction($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null, $warehouseid = 0)
4126 global $user, $hookmanager, $action;
4130 $sql =
"SELECT COUNT(DISTINCT m.fk_soc) as nb_customers, COUNT(DISTINCT m.rowid) as nb,";
4131 $sql .=
" COUNT(mp.rowid) as nb_rows, SUM(mp.qty) as qty, role";
4132 $sql .=
" FROM ".$this->db->prefix().
"mrp_production as mp";
4133 $sql .=
", ".$this->db->prefix().
"mrp_mo as m";
4134 $sql .=
" LEFT JOIN ".$this->db->prefix().
"societe as s ON s.rowid = m.fk_soc";
4135 $sql .=
" WHERE m.rowid = mp.fk_mo";
4136 $sql .=
" AND m.entity IN (".getEntity(($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE')) ?
'stock' :
'mrp').
")";
4137 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
4138 $sql .=
" AND (mp.disable_stock_change IN (0) OR mp.disable_stock_change IS NULL)";
4139 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
4140 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = m.fk_soc AND sc.fk_user = ".((int) $user->id);
4143 $sql .=
" AND m.fk_soc = ".((int) $socid);
4145 if ($filtrestatut !=
'') {
4146 $sql .=
" AND m.status IN (".$this->db->sanitize($filtrestatut).
")";
4148 if (!empty($dateofvirtualstock)) {
4149 $sql .=
" AND m.date_valid <= '".$this->db->idate($dateofvirtualstock).
"'";
4151 if (!$serviceStockIsEnabled) {
4152 $sql .=
"AND EXISTS (SELECT p.rowid FROM ".$this->db->prefix().
"product AS p WHERE p.rowid = ".((int) $this->
id).
" AND p.fk_product_type IN (0))";
4154 if (!empty($warehouseid)) {
4155 $sql .=
" AND m.fk_warehouse = ".((int) $warehouseid);
4157 $sql .=
" GROUP BY role";
4160 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
4162 $this->stats_mrptoconsume[
'customers'] = 0;
4163 $this->stats_mrptoconsume[
'nb'] = 0;
4164 $this->stats_mrptoconsume[
'rows'] = 0;
4165 $this->stats_mrptoconsume[
'qty'] = 0.0;
4166 $this->stats_mrptoproduce[
'customers'] = 0;
4167 $this->stats_mrptoproduce[
'nb'] = 0;
4168 $this->stats_mrptoproduce[
'rows'] = 0;
4169 $this->stats_mrptoproduce[
'qty'] = 0.0;
4172 $result = $this->db->query($sql);
4174 while ($obj = $this->db->fetch_object($result)) {
4175 if ($obj->role ==
'toconsume' && empty($warehouseid)) {
4176 $this->stats_mrptoconsume[
'customers'] += (int) $obj->nb_customers;
4177 $this->stats_mrptoconsume[
'nb'] += (int) $obj->nb;
4178 $this->stats_mrptoconsume[
'rows'] += (int) $obj->nb_rows;
4179 $this->stats_mrptoconsume[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4181 if ($obj->role ==
'consumed' && empty($warehouseid)) {
4185 $this->stats_mrptoconsume[
'qty'] -= ($obj->qty ? (float) $obj->qty : 0.0);
4187 if ($obj->role ==
'toproduce') {
4189 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4191 $this->stats_mrptoproduce[
'customers'] += (int) $obj->nb_customers;
4192 $this->stats_mrptoproduce[
'nb'] += (int) $obj->nb;
4193 $this->stats_mrptoproduce[
'rows'] += (int) $obj->nb_rows;
4194 $this->stats_mrptoproduce[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4197 if ($obj->role ==
'produced') {
4202 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
4204 $this->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
4211 if ($this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] < 0) {
4212 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
4215 if ($this->stats_mrptoconsume[
'qty'] < 0) {
4216 $this->stats_mrptoconsume[
'qty'] = 0;
4218 if ($this->stats_mrptoproduce[
'qty'] < 0) {
4219 $this->stats_mrptoproduce[
'qty'] = 0;
4223 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
4224 $reshook = $hookmanager->executeHooks(
'loadStatsInProduction', $parameters, $this, $action);
4226 $this->stats_mrptoproduce = $hookmanager->resArray[
'stats_mrptoproduce'];
4231 $this->error = $this->db->error();
4246 global $user, $hookmanager, $action;
4248 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
4249 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
4250 $sql .=
" FROM ".$this->db->prefix().
"contratdet as cd";
4251 $sql .=
", ".$this->db->prefix().
"contrat as c";
4252 $sql .=
", ".$this->db->prefix().
"societe as s";
4253 $sql .=
" WHERE c.rowid = cd.fk_contrat";
4254 $sql .=
" AND c.fk_soc = s.rowid";
4255 $sql .=
" AND c.entity IN (".getEntity(
'contract').
")";
4256 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
4257 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4258 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
4262 $sql .=
" AND c.fk_soc = ".((int) $socid);
4265 $result = $this->db->query($sql);
4267 $obj = $this->db->fetch_object($result);
4268 $this->stats_contrat[
'customers'] = (int) $obj->nb_customers;
4269 $this->stats_contrat[
'nb'] = (int) $obj->nb;
4270 $this->stats_contrat[
'rows'] = (int) $obj->nb_rows;
4271 $this->stats_contrat[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
4276 if (is_array($TFather) && !empty($TFather)) {
4277 foreach ($TFather as &$fatherData) {
4278 $pFather =
new Product($this->db);
4279 $pFather->id = $fatherData[
'id'];
4280 $qtyCoef = $fatherData[
'qty'];
4282 if ($fatherData[
'incdec']) {
4283 $pFather->load_stats_contrat($socid);
4285 if (!empty($pFather->stats_contrat)) {
4286 $this->stats_contrat[
'customers'] += $pFather->stats_contrat[
'customers'];
4287 $this->stats_contrat[
'nb'] += $pFather->stats_contrat[
'nb'];
4288 $this->stats_contrat[
'rows'] += $pFather->stats_contrat[
'rows'];
4289 $this->stats_contrat[
'qty'] += $pFather->stats_contrat[
'qty'] * $qtyCoef;
4296 $parameters = array(
'socid' => $socid);
4297 $reshook = $hookmanager->executeHooks(
'loadStatsContract', $parameters, $this, $action);
4299 $this->stats_contrat = $hookmanager->resArray[
'stats_contrat'];
4304 $this->error = $this->db->error().
' sql='.$sql;
4319 global $user, $hookmanager, $action;
4321 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4322 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(".$this->db->ifsql(
'f.type != 2',
'fd.qty',
'fd.qty * -1').
") as qty";
4323 $sql .=
" FROM ".$this->db->prefix().
"facturedet as fd";
4324 $sql .=
", ".$this->db->prefix().
"facture as f";
4325 $sql .=
", ".$this->db->prefix().
"societe as s";
4326 $sql .=
" WHERE f.rowid = fd.fk_facture";
4327 $sql .=
" AND f.fk_soc = s.rowid";
4328 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4329 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4330 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4331 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4335 $sql .=
" AND f.fk_soc = ".((int) $socid);
4338 $result = $this->db->query($sql);
4340 $obj = $this->db->fetch_object($result);
4341 $this->stats_facture[
'customers'] = (int) $obj->nb_customers;
4342 $this->stats_facture[
'nb'] = (int) $obj->nb;
4343 $this->stats_facture[
'rows'] = (int) $obj->nb_rows;
4344 $this->stats_facture[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
4349 if (is_array($TFather) && !empty($TFather)) {
4350 foreach ($TFather as &$fatherData) {
4351 $pFather =
new Product($this->db);
4352 $pFather->id = $fatherData[
'id'];
4353 $qtyCoef = $fatherData[
'qty'];
4355 if ($fatherData[
'incdec']) {
4356 $pFather->load_stats_facture($socid);
4358 if (!empty($pFather->stats_facture)) {
4359 $this->stats_facture[
'customers'] += $pFather->stats_facture[
'customers'];
4360 $this->stats_facture[
'nb'] += $pFather->stats_facture[
'nb'];
4361 $this->stats_facture[
'rows'] += $pFather->stats_facture[
'rows'];
4362 $this->stats_facture[
'qty'] += $pFather->stats_facture[
'qty'] * $qtyCoef;
4369 $parameters = array(
'socid' => $socid);
4370 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoice', $parameters, $this, $action);
4372 $this->stats_facture = $hookmanager->resArray[
'stats_facture'];
4377 $this->error = $this->db->error();
4393 global $user, $hookmanager, $action;
4395 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4396 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4397 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facturedet_rec as fd";
4398 $sql .=
", ".MAIN_DB_PREFIX.
"facture_rec as f";
4399 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
4400 $sql .=
" WHERE f.rowid = fd.fk_facture";
4401 $sql .=
" AND f.fk_soc = s.rowid";
4402 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4403 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4404 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4405 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4409 $sql .=
" AND f.fk_soc = ".((int) $socid);
4412 $result = $this->db->query($sql);
4414 $obj = $this->db->fetch_object($result);
4415 $this->stats_facturerec[
'customers'] = (int) $obj->nb_customers;
4416 $this->stats_facturerec[
'nb'] = (int) $obj->nb;
4417 $this->stats_facturerec[
'rows'] = (int) $obj->nb_rows;
4418 $this->stats_facturerec[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4423 if (is_array($TFather) && !empty($TFather)) {
4424 foreach ($TFather as &$fatherData) {
4425 $pFather =
new Product($this->db);
4426 $pFather->id = $fatherData[
'id'];
4427 $qtyCoef = $fatherData[
'qty'];
4429 if ($fatherData[
'incdec']) {
4430 $pFather->load_stats_facture($socid);
4432 $this->stats_facturerec[
'customers'] += $pFather->stats_facturerec[
'customers'];
4433 $this->stats_facturerec[
'nb'] += $pFather->stats_facturerec[
'nb'];
4434 $this->stats_facturerec[
'rows'] += $pFather->stats_facturerec[
'rows'];
4435 $this->stats_facturerec[
'qty'] += $pFather->stats_facturerec[
'qty'] * $qtyCoef;
4441 $parameters = array(
'socid' => $socid);
4442 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoiceRec', $parameters, $this, $action);
4444 $this->stats_facturerec = $hookmanager->resArray[
'stats_facturerec'];
4449 $this->error = $this->db->error();
4464 global $user, $hookmanager, $action;
4466 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
4467 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4468 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as fd";
4469 $sql .=
", ".$this->db->prefix().
"facture_fourn as f";
4470 $sql .=
", ".$this->db->prefix().
"societe as s";
4471 $sql .=
" WHERE f.rowid = fd.fk_facture_fourn";
4472 $sql .=
" AND f.fk_soc = s.rowid";
4473 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4474 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4475 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4476 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4480 $sql .=
" AND f.fk_soc = ".((int) $socid);
4483 $result = $this->db->query($sql);
4485 $obj = $this->db->fetch_object($result);
4486 $this->stats_facture_fournisseur[
'suppliers'] = (int) $obj->nb_suppliers;
4487 $this->stats_facture_fournisseur[
'nb'] = (int) $obj->nb;
4488 $this->stats_facture_fournisseur[
'rows'] = (int) $obj->nb_rows;
4489 $this->stats_facture_fournisseur[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4491 $parameters = array(
'socid' => $socid);
4492 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoice', $parameters, $this, $action);
4494 $this->stats_facture_fournisseur = $hookmanager->resArray[
'stats_facture_fournisseur'];
4499 $this->error = $this->db->error();
4514 global $user, $hookmanager, $action;
4516 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
4517 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4518 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facture_fourn_det_rec as fd";
4519 $sql .=
", ".MAIN_DB_PREFIX.
"facture_fourn_rec as f";
4520 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
4521 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4522 $sql .=
", ".MAIN_DB_PREFIX.
"societe_commerciaux as sc";
4524 $sql .=
" WHERE f.rowid = fd.fk_facture";
4525 $sql .=
" AND f.fk_soc = s.rowid";
4526 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4527 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4528 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4529 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4533 $sql .=
" AND f.fk_soc = ".((int) $socid);
4536 $result = $this->db->query($sql);
4538 $obj = $this->db->fetch_object($result);
4539 $this->stats_facturefournrec[
'suppliers'] = (int) $obj->nb_suppliers;
4540 $this->stats_facturefournrec[
'nb'] = (int) $obj->nb;
4541 $this->stats_facturefournrec[
'rows'] = (int) $obj->nb_rows;
4542 $this->stats_facturefournrec[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4544 $parameters = array(
'socid' => $socid);
4545 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoiceRec', $parameters, $this, $action);
4547 $this->stats_facturefournrec = $hookmanager->resArray[
'stats_facturefournrec'];
4552 $this->error = $this->db->error();
4571 $resql = $this->db->query($sql);
4573 $num = $this->db->num_rows($resql);
4576 $arr = $this->db->fetch_array($resql);
4577 if (is_array($arr)) {
4578 $keyfortab = (
string) $arr[1];
4580 $keyfortab = substr($keyfortab, -2);
4583 if ($mode ==
'byunit') {
4584 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[0];
4585 } elseif ($mode ==
'bynumber') {
4586 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4587 } elseif ($mode ==
'byamount') {
4588 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4597 $this->error = $this->db->error().
' sql='.$sql;
4604 } elseif ($year == -1) {
4613 for ($j = 0; $j < 12; $j++) {
4615 $idx = ucfirst(
dol_trunc(
dol_print_date(
dol_mktime(12, 0, 0, $month, 1, 1970),
"%b"), 1,
'right',
'UTF-8', 1));
4618 $result[$j] = array($idx, isset($tab[$year.$month]) ? $tab[$year.$month] : 0);
4621 $month =
"0".($month - 1);
4623 $month = substr($month, 1);
4631 return array_reverse($result);
4646 public function get_nb_vente($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4651 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4652 if ($mode ==
'bynumber') {
4653 $sql .=
", count(DISTINCT f.rowid)";
4655 $sql .=
", sum(d.total_ht) as total_ht";
4656 $sql .=
" FROM ".$this->db->prefix().
"facturedet as d, ".$this->db->prefix().
"facture as f, ".$this->db->prefix().
"societe as s";
4657 if ($filteronproducttype >= 0) {
4658 $sql .=
", ".$this->db->prefix().
"product as p";
4660 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4661 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4663 $sql .=
" WHERE f.rowid = d.fk_facture";
4664 if ($this->
id > 0) {
4665 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4667 $sql .=
" AND d.fk_product > 0";
4669 if ($filteronproducttype >= 0) {
4670 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4672 $sql .=
" AND f.fk_soc = s.rowid";
4673 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4674 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4675 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4678 $sql .=
" AND f.fk_soc = ".((int) $socid);
4680 $sql .= $morefilter;
4681 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4682 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4684 return $this->
_get_stats($sql, $mode, $year);
4699 public function get_nb_achat($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4704 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4705 if ($mode ==
'bynumber') {
4706 $sql .=
", count(DISTINCT f.rowid)";
4708 $sql .=
", sum(d.total_ht) as total_ht";
4709 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as d, ".$this->db->prefix().
"facture_fourn as f, ".$this->db->prefix().
"societe as s";
4710 if ($filteronproducttype >= 0) {
4711 $sql .=
", ".$this->db->prefix().
"product as p";
4713 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4714 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4716 $sql .=
" WHERE f.rowid = d.fk_facture_fourn";
4717 if ($this->
id > 0) {
4718 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4720 $sql .=
" AND d.fk_product > 0";
4722 if ($filteronproducttype >= 0) {
4723 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4725 $sql .=
" AND f.fk_soc = s.rowid";
4726 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4727 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4728 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4731 $sql .=
" AND f.fk_soc = ".((int) $socid);
4733 $sql .= $morefilter;
4734 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4735 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4737 return $this->
_get_stats($sql, $mode, $year);
4751 public function get_nb_propal($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4754 global $user, $hookmanager;
4756 $sql =
"SELECT sum(d.qty) as qty, date_format(p.datep, '%Y%m')";
4757 if ($mode ==
'bynumber') {
4758 $sql .=
", count(DISTINCT p.rowid)";
4760 $sql .=
", sum(d.total_ht) as total_ht";
4761 $sql .=
" FROM ".$this->db->prefix().
"propaldet as d, ".$this->db->prefix().
"propal as p, ".$this->db->prefix().
"societe as s";
4762 if ($filteronproducttype >= 0) {
4763 $sql .=
", ".$this->db->prefix().
"product as prod";
4765 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4766 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4768 $sql .=
" WHERE p.rowid = d.fk_propal";
4769 if ($this->
id > 0) {
4770 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4772 $sql .=
" AND d.fk_product > 0";
4774 if ($filteronproducttype >= 0) {
4775 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4777 $sql .=
" AND p.fk_soc = s.rowid";
4778 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
4779 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4780 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4783 $sql .=
" AND p.fk_soc = ".((int) $socid);
4785 $sql .= $morefilter;
4786 $parameters = array(
'socid' => $user->socid);
4787 $hookmanager->executeHooks(
'productGetNbPropal', $parameters, $this);
4788 $sql .= $hookmanager->resPrint;
4789 $sql .=
" GROUP BY date_format(p.datep,'%Y%m')";
4790 $sql .=
" ORDER BY date_format(p.datep,'%Y%m') DESC";
4791 return $this->
_get_stats($sql, $mode, $year);
4810 $sql =
"SELECT sum(d.qty) as qty, date_format(p.date_valid, '%Y%m')";
4811 if ($mode ==
'bynumber') {
4812 $sql .=
", count(DISTINCT p.rowid)";
4814 $sql .=
", sum(d.total_ht) as total_ht";
4815 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as d, ".$this->db->prefix().
"supplier_proposal as p, ".$this->db->prefix().
"societe as s";
4816 if ($filteronproducttype >= 0) {
4817 $sql .=
", ".$this->db->prefix().
"product as prod";
4819 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4820 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4822 $sql .=
" WHERE p.rowid = d.fk_supplier_proposal";
4823 if ($this->
id > 0) {
4824 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4826 $sql .=
" AND d.fk_product > 0";
4828 if ($filteronproducttype >= 0) {
4829 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4831 $sql .=
" AND p.fk_soc = s.rowid";
4832 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
4833 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4834 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4837 $sql .=
" AND p.fk_soc = ".((int) $socid);
4839 $sql .= $morefilter;
4840 $sql .=
" GROUP BY date_format(p.date_valid,'%Y%m')";
4841 $sql .=
" ORDER BY date_format(p.date_valid,'%Y%m') DESC";
4843 return $this->
_get_stats($sql, $mode, $year);
4857 public function get_nb_order($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4860 global $user, $hookmanager;
4862 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4863 if ($mode ==
'bynumber') {
4864 $sql .=
", count(DISTINCT c.rowid)";
4866 $sql .=
", sum(d.total_ht) as total_ht";
4867 $sql .=
" FROM ".$this->db->prefix().
"commandedet as d, ".$this->db->prefix().
"commande as c, ".$this->db->prefix().
"societe as s";
4868 if ($filteronproducttype >= 0) {
4869 $sql .=
", ".$this->db->prefix().
"product as p";
4871 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4872 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4874 $sql .=
" WHERE c.rowid = d.fk_commande";
4875 if ($this->
id > 0) {
4876 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4878 $sql .=
" AND d.fk_product > 0";
4880 if ($filteronproducttype >= 0) {
4881 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4883 $sql .=
" AND c.fk_soc = s.rowid";
4884 $sql .=
" AND c.entity IN (".getEntity(
'commande').
")";
4885 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4886 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4889 $sql .=
" AND c.fk_soc = ".((int) $socid);
4891 $sql .= $morefilter;
4892 $parameters = array(
'socid' => $user->socid);
4893 $hookmanager->executeHooks(
'productGetNbOrder', $parameters, $this);
4894 $sql .= $hookmanager->resPrint;
4895 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4896 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4898 return $this->
_get_stats($sql, $mode, $year);
4917 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4918 if ($mode ==
'bynumber') {
4919 $sql .=
", count(DISTINCT c.rowid)";
4921 $sql .=
", sum(d.total_ht) as total_ht";
4922 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as d, ".$this->db->prefix().
"commande_fournisseur as c, ".$this->db->prefix().
"societe as s";
4923 if ($filteronproducttype >= 0) {
4924 $sql .=
", ".$this->db->prefix().
"product as p";
4926 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4927 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4929 $sql .=
" WHERE c.rowid = d.fk_commande";
4930 if ($this->
id > 0) {
4931 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4933 $sql .=
" AND d.fk_product > 0";
4935 if ($filteronproducttype >= 0) {
4936 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4938 $sql .=
" AND c.fk_soc = s.rowid";
4939 $sql .=
" AND c.entity IN (".getEntity(
'supplier_order').
")";
4940 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4941 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4944 $sql .=
" AND c.fk_soc = ".((int) $socid);
4946 $sql .= $morefilter;
4947 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4948 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4950 return $this->
_get_stats($sql, $mode, $year);
4964 public function get_nb_contract($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4969 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_contrat, '%Y%m')";
4970 if ($mode ==
'bynumber') {
4971 $sql .=
", count(DISTINCT c.rowid)";
4973 $sql .=
", sum(d.total_ht) as total_ht";
4974 $sql .=
" FROM ".$this->db->prefix().
"contratdet as d, ".$this->db->prefix().
"contrat as c, ".$this->db->prefix().
"societe as s";
4975 if ($filteronproducttype >= 0) {
4976 $sql .=
", ".$this->db->prefix().
"product as p";
4978 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4979 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4981 $sql .=
" WHERE c.entity IN (".getEntity(
'contract').
")";
4982 $sql .=
" AND c.rowid = d.fk_contrat";
4984 if ($this->
id > 0) {
4985 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4987 $sql .=
" AND d.fk_product > 0";
4989 if ($filteronproducttype >= 0) {
4990 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4992 $sql .=
" AND c.fk_soc = s.rowid";
4994 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4995 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4998 $sql .=
" AND c.fk_soc = ".((int) $socid);
5000 $sql .= $morefilter;
5001 $sql .=
" GROUP BY date_format(c.date_contrat,'%Y%m')";
5002 $sql .=
" ORDER BY date_format(c.date_contrat,'%Y%m') DESC";
5004 return $this->
_get_stats($sql, $mode, $year);
5018 public function get_nb_mos($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
5023 $sql =
"SELECT sum(d.qty), date_format(d.date_valid, '%Y%m')";
5024 if ($mode ==
'bynumber') {
5025 $sql .=
", count(DISTINCT d.rowid)";
5027 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as d LEFT JOIN ".$this->db->prefix().
"societe as s ON d.fk_soc = s.rowid";
5028 if ($filteronproducttype >= 0) {
5029 $sql .=
", ".$this->db->prefix().
"product as p";
5031 if (!$user->hasRight(
'societe',
'client',
'voir')) {
5032 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
5035 $sql .=
" WHERE d.entity IN (".getEntity(
'mo').
")";
5036 $sql .=
" AND d.status > 0";
5038 if ($this->
id > 0) {
5039 $sql .=
" AND d.fk_product = ".((int) $this->
id);
5041 $sql .=
" AND d.fk_product > 0";
5043 if ($filteronproducttype >= 0) {
5044 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
5047 if (!$user->hasRight(
'societe',
'client',
'voir')) {
5048 $sql .=
" AND d.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
5051 $sql .=
" AND d.fk_soc = ".((int) $socid);
5053 $sql .= $morefilter;
5054 $sql .=
" GROUP BY date_format(d.date_valid,'%Y%m')";
5055 $sql .=
" ORDER BY date_format(d.date_valid,'%Y%m') DESC";
5057 return $this->
_get_stats($sql, $mode, $year);
5077 if (!is_numeric($id_pere)) {
5080 if (!is_numeric($id_fils)) {
5083 if (!is_numeric($incdec)) {
5093 $sql =
"SELECT fk_product_pere from ".$this->db->prefix().
"product_association";
5094 $sql .=
" WHERE fk_product_pere = ".((int) $id_fils).
" AND fk_product_fils = ".((int) $id_pere);
5095 if (!$this->db->query($sql)) {
5100 $sql =
"SELECT MAX(rang) as max_rank FROM ".$this->db->prefix().
"product_association";
5101 $sql .=
" WHERE fk_product_pere = ".((int) $id_pere);
5102 $resql = $this->db->query($sql);
5104 $obj = $this->db->fetch_object($resql);
5105 $rank = $obj->max_rank + 1;
5107 $sql =
"INSERT INTO ".$this->db->prefix().
"product_association(fk_product_pere,fk_product_fils,qty,incdec,rang)";
5108 $sql .=
" VALUES (".((int) $id_pere).
", ".((int) $id_fils).
", ".
price2num($qty,
'MS').
", ".((int) $incdec).
", ".((int) $rank).
")";
5109 if (! $this->db->query($sql)) {
5115 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_ADD', $user);
5117 $this->error = $this->db->lasterror();
5118 dol_syslog(get_class($this).
'::addSubproduct error='.$this->error, LOG_ERR);
5150 if (!is_numeric($id_pere)) {
5153 if (!is_numeric($id_fils)) {
5156 if (!is_numeric($incdec)) {
5159 if (!is_numeric($qty)) {
5163 $sql =
'UPDATE '.$this->db->prefix().
'product_association SET ';
5164 $sql .=
'qty = '.price2num($qty,
'MS');
5165 $sql .=
',incdec = '.((int) $incdec);
5166 $sql .=
' WHERE fk_product_pere = '.((int) $id_pere).
' AND fk_product_fils = '.((int) $id_fils);
5168 if (!$this->db->query($sql)) {
5174 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_UPDATE', $user);
5176 $this->error = $this->db->lasterror();
5177 dol_syslog(get_class($this).
'::updateSubproduct error='.$this->error, LOG_ERR);
5201 if (!is_numeric($fk_parent)) {
5204 if (!is_numeric($fk_child)) {
5208 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
5209 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5210 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
5212 dol_syslog(get_class($this).
'::del_sousproduit', LOG_DEBUG);
5213 if (!$this->db->query($sql)) {
5219 $sqlrank =
"SELECT rowid, rang FROM ".$this->db->prefix().
"product_association";
5220 $sqlrank .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5221 $sqlrank .=
" ORDER BY rang";
5222 $resqlrank = $this->db->query($sqlrank);
5225 while ($objrank = $this->db->fetch_object($resqlrank)) {
5227 $sql =
"UPDATE ".$this->db->prefix().
"product_association";
5228 $sql .=
" SET rang = ".((int) $cpt);
5229 $sql .=
" WHERE rowid = ".((int) $objrank->rowid);
5230 if (! $this->db->query($sql)) {
5239 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_DELETE', $user);
5241 $this->error = $this->db->lasterror();
5242 dol_syslog(get_class($this).
'::delSubproduct error='.$this->error, LOG_ERR);
5262 $sql =
"SELECT fk_product_pere, qty, incdec";
5263 $sql .=
" FROM ".$this->db->prefix().
"product_association";
5264 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5265 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
5267 $result = $this->db->query($sql);
5269 $num = $this->db->num_rows($result);
5272 $obj = $this->db->fetch_object($result);
5274 $this->is_sousproduit_qty = $obj->qty;
5275 $this->is_sousproduit_incdec = $obj->incdec;
5306 dol_syslog(get_class($this).
"::add_fournisseur id_fourn = ".$id_fourn.
" ref_fourn=".$ref_fourn.
" quantity=".$quantity, LOG_DEBUG);
5313 $sql =
"SELECT rowid, fk_product";
5314 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5315 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5316 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5317 $sql .=
" AND fk_product <> ".((int) $this->
id);
5318 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5320 $resql = $this->db->query($sql);
5322 $obj = $this->db->fetch_object($resql);
5325 $this->product_id_already_linked = $obj->fk_product;
5328 $this->db->free($resql);
5332 $sql =
"SELECT rowid";
5333 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5334 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5336 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5338 $sql .=
" AND (ref_fourn = '' OR ref_fourn IS NULL)";
5340 $sql .=
" AND quantity = ".((float) $quantity);
5341 $sql .=
" AND fk_product = ".((int) $this->
id);
5342 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5344 $resql = $this->db->query($sql);
5346 $obj = $this->db->fetch_object($resql);
5350 $sql =
"INSERT INTO ".$this->db->prefix().
"product_fournisseur_price(";
5353 $sql .=
", fk_product";
5355 $sql .=
", ref_fourn";
5356 $sql .=
", quantity";
5357 $sql .=
", fk_user";
5359 $sql .=
") VALUES (";
5360 $sql .=
"'".$this->db->idate($now).
"'";
5361 $sql .=
", ".((int)
$conf->entity);
5362 $sql .=
", ".((int) $this->
id);
5363 $sql .=
", ".((int) $id_fourn);
5364 $sql .=
", '".$this->db->escape($ref_fourn).
"'";
5365 $sql .=
", ".((float) $quantity);
5366 $sql .=
", ".((int) $user->id);
5370 if ($this->db->query($sql)) {
5371 $this->product_fourn_price_id = $this->db->last_insert_id($this->db->prefix().
"product_fournisseur_price");
5374 $this->error = $this->db->lasterror();
5379 $this->product_fourn_price_id = $obj->rowid;
5383 $this->error = $this->db->lasterror();
5402 $sql =
"SELECT DISTINCT p.fk_soc";
5403 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as p";
5404 $sql .=
" WHERE p.fk_product = ".((int) $this->
id);
5405 $sql .=
" AND p.entity = ".((int)
$conf->entity);
5407 $result = $this->db->query($sql);
5409 $num = $this->db->num_rows($result);
5412 $obj = $this->db->fetch_object($result);
5413 $list[$i] = $obj->fk_soc;
5439 $sql =
"INSERT INTO ".$this->db->prefix().
"product_price (";
5441 $sql .=
", fk_product";
5442 $sql .=
", date_price";
5443 $sql .=
", price_level";
5445 $sql .=
", price_ttc";
5446 $sql .=
", price_min";
5447 $sql .=
", price_min_ttc";
5448 $sql .=
", price_base_type";
5449 $sql .=
", price_label";
5450 $sql .=
", default_vat_code";
5452 $sql .=
", recuperableonly";
5453 $sql .=
", localtax1_tx";
5454 $sql .=
", localtax1_type";
5455 $sql .=
", localtax2_tx";
5456 $sql .=
", localtax2_type";
5457 $sql .=
", fk_user_author";
5459 $sql .=
", price_by_qty";
5460 $sql .=
", fk_price_expression";
5461 $sql .=
", fk_multicurrency";
5462 $sql .=
", multicurrency_code";
5463 $sql .=
", multicurrency_tx";
5464 $sql .=
", multicurrency_price";
5465 $sql .=
", multicurrency_price_ttc";
5469 $sql .=
", ".((int) $toId);
5470 $sql .=
", '".$this->db->idate($now).
"'";
5471 $sql .=
", price_level";
5473 $sql .=
", price_ttc";
5474 $sql .=
", price_min";
5475 $sql .=
", price_min_ttc";
5476 $sql .=
", price_base_type";
5477 $sql .=
", price_label";
5478 $sql .=
", default_vat_code";
5480 $sql .=
", recuperableonly";
5481 $sql .=
", localtax1_tx";
5482 $sql .=
", localtax1_type";
5483 $sql .=
", localtax2_tx";
5484 $sql .=
", localtax2_type";
5485 $sql .=
", ".((int) $user->id);
5487 $sql .=
", price_by_qty";
5488 $sql .=
", fk_price_expression";
5489 $sql .=
", fk_multicurrency";
5490 $sql .=
", multicurrency_code";
5491 $sql .=
", multicurrency_tx";
5492 $sql .=
", multicurrency_price";
5493 $sql .=
", multicurrency_price_ttc";
5494 $sql .=
" FROM ".$this->db->prefix().
"product_price ps";
5495 $sql .=
" WHERE fk_product = ".((int) $fromId);
5496 $sql .=
" AND date_price IN (SELECT MAX(pd.date_price) FROM ".$this->db->prefix().
"product_price pd WHERE pd.fk_product = ".((int) $fromId).
" AND pd.price_level = ps.price_level)";
5497 $sql .=
" ORDER BY date_price DESC";
5500 $resql = $this->db->query($sql);
5502 $this->db->rollback();
5506 $this->db->commit();
5523 $sql =
'INSERT INTO '.$this->db->prefix().
'product_association (fk_product_pere, fk_product_fils, qty, incdec)';
5524 $sql .=
" SELECT ".((int) $toId).
", fk_product_fils, qty, incdec FROM ".$this->db->prefix().
"product_association";
5525 $sql .=
" WHERE fk_product_pere = ".((int) $fromId);
5527 dol_syslog(get_class($this).
'::clone_association', LOG_DEBUG);
5528 if (!$this->db->query($sql)) {
5529 $this->db->rollback();
5533 $this->db->commit();
5566 $sql =
"INSERT ".$this->db->prefix().
"product_fournisseur_price (";
5567 $sql .=
" datec, fk_product, fk_soc, price, quantity, fk_user, tva_tx)";
5568 $sql .=
" SELECT '".$this->db->idate($now).
"', ".((int) $toId).
", fk_soc, price, quantity, fk_user, tva_tx";
5569 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5570 $sql .=
" WHERE fk_product = ".((int) $fromId);
5572 dol_syslog(get_class($this).
'::clone_fournisseurs', LOG_DEBUG);
5573 $resql = $this->db->query($sql);
5575 $this->db->rollback();
5578 $this->db->commit();
5596 public function fetch_prod_arbo(
$prod, $compl_path =
'', $multiply = 1, $level = 1, $id_parent = 0, $ignore_stock_load = 0)
5601 if ($multiply < 1) {
5602 dol_syslog(get_class($this).
'::'.__FUNCTION__.
' Product quantity rounded up to 1 from '.$multiply.
'. May result in unexpected end quantity for product children of '.$id_parent, LOG_WARNING);
5606 foreach (
$prod as $id_product => $desc_pere) {
5607 if (is_array($desc_pere)) {
5608 $id = (!empty($desc_pere[0]) ? $desc_pere[0] :
'');
5609 $nb = (!empty($desc_pere[1]) ? $desc_pere[1] :
'');
5610 $type = (!empty($desc_pere[2]) ? $desc_pere[2] :
'');
5611 $label = (!empty($desc_pere[3]) ? $desc_pere[3] :
'');
5612 $incdec = (!empty($desc_pere[4]) ? $desc_pere[4] : 0);
5615 if (is_null($tmpproduct)) {
5616 $tmpproduct =
new Product($this->db);
5618 $tmpproduct->fetch($id);
5620 if (empty($ignore_stock_load) && ($tmpproduct->isProduct() ||
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES'))) {
5621 $tmpproduct->load_stock(
'nobatch,novirtual');
5624 $this->res[] = array(
5626 'id_parent' => $id_parent,
5627 'ref' => $tmpproduct->ref,
5629 'nb_total' => $nb * $multiply,
5630 'stock' => $tmpproduct->stock_reel,
5631 'stock_alert' => $tmpproduct->seuil_stock_alerte,
5633 'fullpath' => $compl_path.$label,
5635 'desiredstock' => $tmpproduct->desiredstock,
5637 'incdec' => $incdec,
5638 'entity' => $tmpproduct->entity
5642 if (isset($desc_pere[
'childs']) && is_array($desc_pere[
'childs'])) {
5643 if (!is_int($desc_pere[1] * $multiply)) {
5644 dol_syslog(get_class($this).
'::'.__FUNCTION__.
' Source product quantity and multiplier may result in unexpected end quantity for '.$label.
'/'.$multiply.
' Child product:'.json_encode($desc_pere), LOG_WARNING);
5648 $this->
fetch_prod_arbo($desc_pere[
'childs'], $compl_path.$desc_pere[3].
" -> ", (
int) ceil($desc_pere[1] * $multiply), $level + 1, $id, $ignore_stock_load);
5666 $this->res = array();
5667 if (isset($this->sousprods) && is_array($this->sousprods)) {
5668 foreach ($this->sousprods as $prod_name => $desc_product) {
5669 if (is_array($desc_product)) {
5670 $this->
fetch_prod_arbo($desc_product,
"", $multiply, 1, $this->
id, $ignore_stock_load);
5688 $sql =
"SELECT COUNT(pa.rowid) as nb";
5689 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa";
5691 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id).
" OR pa.fk_product_pere = ".((int) $this->
id);
5692 } elseif ($mode == -1) {
5693 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id);
5694 } elseif ($mode == 1) {
5695 $sql .=
" WHERE pa.fk_product_pere = ".((int) $this->
id);
5698 $resql = $this->db->query($sql);
5700 $obj = $this->db->fetch_object($resql);
5702 $nb = (int) $obj->nb;
5722 $sql =
"SELECT count(rowid) as nb FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_parent = ".((int) $this->
id);
5723 $sql .=
" AND entity IN (".getEntity(
'product').
")";
5725 $resql = $this->db->query($sql);
5727 $obj = $this->db->fetch_object($resql);
5729 $nb = (int) $obj->nb;
5745 $sql =
"SELECT rowid FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_child = ".((int) $this->
id).
" AND entity IN (".
getEntity(
'product').
")";
5747 $query = $this->db->query($sql);
5750 if (!$this->db->num_rows($query)) {
5771 $sql =
"SELECT p.rowid, p.label as label, p.ref as ref, pa.fk_product_pere as id, p.fk_product_type, pa.qty, pa.incdec, p.entity";
5772 $sql .=
", p.tosell as status, p.tobuy as status_buy";
5773 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa,";
5774 $sql .=
" ".$this->db->prefix().
"product as p";
5775 $sql .=
" WHERE p.rowid = pa.fk_product_pere";
5776 $sql .=
" AND pa.fk_product_fils = ".((int) $this->
id);
5778 $res = $this->db->query($sql);
5781 while ($record = $this->db->fetch_array($res)) {
5783 $prods[$record[
'id']] = array();
5784 $prods[$record[
'id']][
'id'] = $record[
'rowid'];
5785 $prods[$record[
'id']][
'ref'] = $record[
'ref'];
5786 $prods[$record[
'id']][
'label'] = $record[
'label'];
5787 $prods[$record[
'id']][
'qty'] = $record[
'qty'];
5788 $prods[$record[
'id']][
'incdec'] = $record[
'incdec'];
5789 $prods[$record[
'id']][
'fk_product_type'] = $record[
'fk_product_type'];
5790 $prods[$record[
'id']][
'entity'] = $record[
'entity'];
5791 $prods[$record[
'id']][
'status'] = $record[
'status'];
5792 $prods[$record[
'id']][
'status_buy'] = $record[
'status_buy'];
5811 public function getChildsArbo($id, $firstlevelonly = 0, $level = 1, $parents = array())
5817 $sql =
"SELECT p.rowid, p.ref, p.label as label, p.fk_product_type,";
5818 $sql .=
" pa.qty as qty, pa.fk_product_fils as id, pa.incdec,";
5819 $sql .=
" pa.rowid as fk_association, pa.rang";
5820 $sql .=
" FROM ".$this->db->prefix().
"product as p,";
5821 $sql .=
" ".$this->db->prefix().
"product_association as pa";
5822 $sql .=
" WHERE p.rowid = pa.fk_product_fils";
5823 $sql .=
" AND pa.fk_product_pere = ".((int) $id);
5824 $sql .=
" AND pa.fk_product_fils <> ".((int) $id);
5825 $sql .=
" ORDER BY pa.rang";
5827 dol_syslog(get_class($this).
'::getChildsArbo id='.$id.
' level='.$level.
' parents='.(is_array($parents) ? implode(
',', $parents) : $parents), LOG_DEBUG);
5834 $res = $this->db->query($sql);
5837 if ($this->db->num_rows($res) > 0) {
5841 while ($rec = $this->db->fetch_array($res)) {
5842 if (in_array($rec[
'id'], $parents)) {
5843 dol_syslog(get_class($this).
'::getChildsArbo the product id='.$rec[
'rowid'].
' was already found at a higher level in tree. We discard to avoid infinite loop', LOG_WARNING);
5847 $prods[$rec[
'rowid']] = array(
5850 2 => $rec[
'fk_product_type'],
5851 3 => $this->db->escape($rec[
'label']),
5852 4 => $rec[
'incdec'],
5854 6 => $rec[
'fk_association'],
5859 if (empty($firstlevelonly)) {
5860 $listofchilds = $this->
getChildsArbo($rec[
'rowid'], 0, $level + 1, $parents);
5861 foreach ($listofchilds as $keyChild => $valueChild) {
5862 $prods[$rec[
'rowid']][
'childs'][$keyChild] = $valueChild;
5886 foreach ($this->
getChildsArbo($this->
id) as $keyChild => $valueChild) {
5887 $parent[$this->label][$keyChild] = $valueChild;
5889 foreach ($parent as $key => $value) {
5890 $this->sousprods[$key] = $value;
5903 global
$conf, $langs, $user;
5905 $langs->loadLangs(array(
'products',
'other'));
5908 $nofetch = !empty($params[
'nofetch']);
5911 return [
'optimize' => $langs->trans(
"ShowProduct")];
5915 $permissiontoreadproduct = 0;
5916 if ($this->
type == self::TYPE_PRODUCT && $user->hasRight(
'product',
'read')) {
5917 $permissiontoreadproduct = 1;
5919 if ($this->
type == self::TYPE_SERVICE && $user->hasRight(
'service',
'read')) {
5920 $permissiontoreadproduct = 1;
5923 if (!empty($this->entity) && $permissiontoreadproduct) {
5924 $tmpphoto = $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 80, 0, 0, 0, 0,
'1');
5925 if ($this->nbphoto > 0) {
5926 $datas[
'photo'] =
'<div class="photointooltip floatright">'.
"\n" . $tmpphoto .
'</div>';
5931 $datas[
'picto'] =
img_picto(
'',
'product').
' <u class="paddingrightonly">'.$langs->trans(
"Product").
'</u>';
5933 $datas[
'picto'] =
img_picto(
'',
'service').
' <u class="paddingrightonly">'.$langs->trans(
"Service").
'</u>';
5935 if (isset($this->
status) && isset($this->status_buy)) {
5936 $datas[
'status'] =
' '.$this->getLibStatut(5, 0) .
' '.$this->getLibStatut(5, 1);
5939 if (!empty($this->
ref)) {
5940 $datas[
'ref'] =
'<br><b>'.$langs->trans(
'ProductRef').
':</b> '.$this->ref;
5942 if (!empty($this->label)) {
5943 $datas[
'label'] =
'<br><b>'.$langs->trans(
'ProductLabel').
':</b> '.$this->label.
'<br>';
5946 if ($permissiontoreadproduct) {
5951 $datas[
'stockmanaged'] =
"<br><b>".$langs->trans(
"StockableProduct").
'</b>: '.
yn($this->
isStockManaged());
5955 $langs->load(
"productbatch");
5956 $datas[
'batchstatus'] =
"<br><b>".$langs->trans(
"ManageLotSerial").
'</b>: '.$this->
getLibStatut(0, 2);
5957 if ($this->status_batch) {
5958 $datas[
'batchdlc'] =
"<br><b>".$langs->trans(
"BatchSellOrEatByMandatoryList", $langs->transnoentitiesnoconv(
"SellByDate"), $langs->transnoentitiesnoconv(
"EatByDate")).
'</b>: '.$this->
getSellOrEatByMandatoryLabel();
5963 $datas[
'barcode'] =
'<br><b>'.$langs->trans(
'BarCode').
':</b> '.$this->barcode;
5967 if ($this->weight) {
5968 $datas[
'weight'] =
"<br><b>".$langs->trans(
"Weight").
'</b>: '.$this->weight.
' '.
measuringUnitString(0,
"weight", $this->weight_units);
5971 if ($this->length) {
5972 $labelsize .=
"<b>".$langs->trans(
"Length").
'</b>: '.$this->length.
' '.
measuringUnitString(0,
'size', $this->length_units);
5975 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Width").
'</b>: '.$this->width.
' '.
measuringUnitString(0,
'size', $this->width_units);
5977 if ($this->height) {
5978 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Height").
'</b>: '.$this->height.
' '.
measuringUnitString(0,
'size', $this->height_units);
5981 $datas[
'size'] =
"<br>".$labelsize;
5984 $labelsurfacevolume =
"";
5985 if ($this->surface) {
5986 $labelsurfacevolume .=
"<b>".$langs->trans(
"Surface").
'</b>: '.$this->surface.
' '.
measuringUnitString(0,
'surface', $this->surface_units);
5988 if ($this->volume) {
5989 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Volume").
'</b>: '.$this->volume.
' '.
measuringUnitString(0,
'volume', $this->volume_units);
5991 if ($labelsurfacevolume) {
5992 $datas[
'surface'] =
"<br>" . $labelsurfacevolume;
5995 if ($this->
isService() && !empty($this->duration_value)) {
5997 $datas[
'duration'] =
'<br><b>'.$langs->trans(
"Duration").
':</b> '.$this->duration_value;
5998 if ($this->duration_value > 1) {
5999 $dur = array(
"i" => $langs->trans(
"Minutes"),
"h" => $langs->trans(
"Hours"),
"d" => $langs->trans(
"Days"),
"w" => $langs->trans(
"Weeks"),
"m" => $langs->trans(
"Months"),
"y" => $langs->trans(
"Years"));
6000 } elseif ($this->duration_value > 0) {
6001 $dur = array(
"i" => $langs->trans(
"Minute"),
"h" => $langs->trans(
"Hour"),
"d" => $langs->trans(
"Day"),
"w" => $langs->trans(
"Week"),
"m" => $langs->trans(
"Month"),
"y" => $langs->trans(
"Year"));
6003 $datas[
'duration'] .= (!empty($this->duration_unit) && isset($dur[$this->duration_unit]) ?
" ".$langs->trans($dur[$this->duration_unit]) :
'');
6005 if (empty($user->socid)) {
6006 if ($this->
isStockManaged() && isset($this->pmp) && $this->pmp) {
6007 $datas[
'pmp'] =
"<br><b>".$langs->trans(
"PMPValue").
'</b>: '.
price($this->pmp, 0,
'', 1, -1, -1,
$conf->currency);
6011 if ($this->
status && isset($this->accountancy_code_sell)) {
6012 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
6013 $selllabel =
'<br>';
6014 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellCode').
':</b> '.
length_accountg($this->accountancy_code_sell);
6015 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellIntraCode').
':</b> '.
length_accountg($this->accountancy_code_sell_intra);
6016 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellExportCode').
':</b> '.
length_accountg($this->accountancy_code_sell_export);
6017 $datas[
'accountancysell'] = $selllabel;
6019 if ($this->status_buy && isset($this->accountancy_code_buy)) {
6020 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
6022 if (empty($this->
status)) {
6023 $buylabel .=
'<br>';
6025 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyCode').
':</b> '.
length_accountg($this->accountancy_code_buy);
6026 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyIntraCode').
':</b> '.
length_accountg($this->accountancy_code_buy_intra);
6027 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyExportCode').
':</b> '.
length_accountg($this->accountancy_code_buy_export);
6028 $datas[
'accountancybuy'] = $buylabel;
6034 require_once DOL_DOCUMENT_ROOT .
'/categories/class/categorie.class.php';
6035 $form =
new Form($this->db);
6036 $datas[
'categories'] =
'<br>' . $form->showCategories($this->
id, Categorie::TYPE_PRODUCT, 1);
6056 public function getNomUrl($withpicto = 0, $option =
'', $maxlength = 0, $save_lastsearch_value = -1, $notooltip = 0, $morecss =
'', $add_label = 0, $sep =
' - ')
6058 global $langs, $hookmanager;
6060 include_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
6066 $newref =
dol_trunc($newref, $maxlength,
'middle');
6070 'objecttype' => ($this->
type == 1 ?
'service' :
'product'),
6071 'option' => $option,
6074 $classfortooltip =
'classfortooltip';
6077 $classfortooltip =
'classforajaxtooltip';
6078 $dataparams =
' data-params="'.dol_escape_htmltag(json_encode($params)).
'"';
6085 if (empty($notooltip)) {
6087 $label = $langs->trans(
"ShowProduct");
6088 $linkclose .=
' alt="'.dol_escape_htmltag($label, 1, 1).
'"';
6090 $linkclose .= ($label ?
' title="'.dol_escape_htmltag($label, 1, 1).
'"' :
' title="tocomplete"');
6091 $linkclose .= $dataparams.
' class="nowraponall '.$classfortooltip.($morecss ?
' '.$morecss :
'').
'"';
6093 $linkclose =
' class="nowraponall'.($morecss ?
' '.$morecss :
'').
'"';
6096 if ($option ==
'supplier' || $option ==
'category') {
6097 $url = DOL_URL_ROOT.
'/product/price_suppliers.php?id='.$this->id;
6098 } elseif ($option ==
'stock') {
6099 $url = DOL_URL_ROOT.
'/product/stock/product.php?id='.$this->id;
6100 } elseif ($option ==
'composition') {
6101 $url = DOL_URL_ROOT.
'/product/composition/card.php?id='.$this->id;
6103 $url = DOL_URL_ROOT.
'/product/card.php?id='.$this->id;
6106 if ($option !==
'nolink') {
6108 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
6109 if ($save_lastsearch_value == -1 && isset($_SERVER[
"PHP_SELF"]) && preg_match(
'/list\.php/', $_SERVER[
"PHP_SELF"])) {
6110 $add_save_lastsearch_values = 1;
6112 if ($add_save_lastsearch_values) {
6113 $url .=
'&save_lastsearch_values=1';
6117 $linkstart =
'<a href="'.$url.
'"';
6118 $linkstart .= $linkclose.
'>';
6121 $result .= $linkstart;
6124 $result .= (
img_object(($notooltip ?
'' : $label),
'product',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
6127 $result .= (
img_object(($notooltip ?
'' : $label),
'service',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
6130 $result .=
'<span class="aaa">'.dol_escape_htmltag($newref).
'</span>';
6131 $result .= $linkend;
6132 if ($withpicto != 2) {
6133 $result .= (($add_label && $this->label) ? $sep.dol_trunc($this->label, ($add_label > 1 ? $add_label : 0)) :
'');
6137 $hookmanager->initHooks(array(
'productdao'));
6138 $parameters = array(
'id' => $this->
id,
'getnomurl' => &$result,
'label' => &$label);
6139 $reshook = $hookmanager->executeHooks(
'getNomUrl', $parameters, $this, $action);
6141 $result = $hookmanager->resPrint;
6143 $result .= $hookmanager->resPrint;
6160 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
6164 $langs->load(
"products");
6165 $outputlangs->load(
"products");
6171 if (!empty($this->model_pdf)) {
6172 $modele = $this->model_pdf;
6178 if (empty($modele)) {
6181 $modelpath =
"core/modules/product/doc/";
6182 return $this->
commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
6199 return $this->
LibStatut($this->status_buy, $mode, $type);
6201 return $this->
LibStatut($this->status_batch, $mode, $type);
6204 return $this->
LibStatut($this->status_buy, $mode, $type);
6222 $labelStatus = $labelStatusShort =
'';
6224 $langs->load(
'products');
6226 $langs->load(
"productbatch");
6232 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial')));
6235 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort')));
6240 return dolGetStatus($langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch'),
'',
'', empty($status) ?
'status5' :
'status4', 3,
'dot');
6246 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'));
6250 $statuttrans = empty($status) ?
'status5' :
'status4';
6255 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSellShort');
6256 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSell');
6257 } elseif ($type == 1) {
6258 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuyShort');
6259 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuy');
6260 } elseif ($type == 2) {
6261 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch');
6262 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort');
6264 } elseif ($status == 1) {
6267 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSellShort');
6268 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSell');
6269 } elseif ($type == 1) {
6270 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBuyShort');
6271 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBuy');
6272 } elseif ($type == 2) {
6273 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBatch');
6274 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort');
6276 } elseif ($type == 2 && $status == 2) {
6277 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSerial');
6278 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort');
6282 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'),
'',
'',
'status0', 0);
6284 return dolGetStatus($labelStatus, $labelStatusShort,
'', $statuttrans, $mode);
6298 $langs->load(
'products');
6301 if (isset($this->finished) && $this->finished >= 0) {
6302 $sql =
"SELECT label, code FROM ".$this->db->prefix().
"c_product_nature where code = ".((int) $this->finished).
" AND active=1";
6303 $resql = $this->db->query($sql);
6305 $this->error = $this->db->error().
' sql='.$sql;
6306 dol_syslog(__METHOD__.
' Error '.$this->error, LOG_ERR);
6308 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
6309 $label = $langs->trans($res[
'label']);
6311 $this->db->free($resql);
6335 public function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label =
'', $price = 0, $inventorycode =
'', $origin_element =
'', $origin_id =
null, $disablestockchangeforsubproduct = 0, $extrafields =
null)
6341 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6344 $nbpiece = (float) $nbpiece;
6349 $nbpiece = abs($nbpiece);
6356 $movementstock->setOrigin($origin_element, (
int) $origin_id);
6357 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'',
'',
'',
'',
false, 0, $disablestockchangeforsubproduct);
6361 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6362 $movementstock->array_options = $array_options;
6363 $movementstock->insertExtraFields();
6365 $this->db->commit();
6370 $this->db->rollback();
6399 public function correct_stock_batch($user, $id_entrepot, $nbpiece, $movement, $label =
'', $price = 0, $dlc =
'', $dluo =
'', $lot =
'', $inventorycode =
'', $origin_element =
'', $origin_id =
null, $disablestockchangeforsubproduct = 0, $extrafields =
null, $force_update_batch =
false)
6405 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6408 $nbpiece = (float) $nbpiece;
6413 $nbpiece = abs($nbpiece);
6421 $movementstock->setOrigin($origin_element, (
int) $origin_id);
6422 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'', $dlc, $dluo, $lot,
false, 0, $disablestockchangeforsubproduct, 0, $force_update_batch);
6426 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6427 $movementstock->array_options = $array_options;
6428 $movementstock->insertExtraFields();
6430 $this->db->commit();
6433 $this->error = $movementstock->error;
6434 $this->errors = $movementstock->errors;
6436 $this->db->rollback();
6456 public function load_stock($option =
'', $includedraftpoforvirtual =
null, $dateofvirtualstock =
null)
6459 $this->stock_reel = 0;
6460 $this->stock_warehouse = array();
6461 $this->stock_theorique = 0;
6464 $warehouseStatus = array();
6465 if (preg_match(
'/warehouseclosed/', $option)) {
6468 if (preg_match(
'/warehouseopen/', $option)) {
6471 if (preg_match(
'/warehouseinternal/', $option)) {
6479 $sql =
"SELECT ps.rowid, ps.reel, ps.fk_entrepot";
6480 $sql .=
" FROM ".$this->db->prefix().
"product_stock as ps";
6481 $sql .=
", ".$this->db->prefix().
"entrepot as w";
6482 $sql .=
" WHERE w.entity IN (".getEntity(
'stock').
")";
6483 $sql .=
" AND w.rowid = ps.fk_entrepot";
6484 $sql .=
" AND ps.fk_product = ".((int) $this->
id);
6485 if (count($warehouseStatus)) {
6486 $sql .=
" AND w.statut IN (".$this->db->sanitize(implode(
',', $warehouseStatus)).
")";
6489 $sql .=
" ORDER BY ps.reel ".(getDolGlobalString(
'DO_NOT_TRY_TO_DEFRAGMENT_STOCKS_WAREHOUSE') ?
'DESC' :
'ASC');
6491 dol_syslog(get_class($this).
"::load_stock", LOG_DEBUG);
6492 $result = $this->db->query($sql);
6494 $num = $this->db->num_rows($result);
6498 $row = $this->db->fetch_object($result);
6499 $this->stock_warehouse[$row->fk_entrepot] =
new stdClass();
6500 $this->stock_warehouse[$row->fk_entrepot]->real = $row->reel;
6501 $this->stock_warehouse[$row->fk_entrepot]->id = $row->rowid;
6502 if ((!preg_match(
'/nobatch/', $option)) && $this->
hasbatch()) {
6503 $this->stock_warehouse[$row->fk_entrepot]->detail_batch =
Productbatch::findAll($this->db, $row->rowid, 1, $this->id);
6505 $this->stock_reel += $row->reel;
6508 $this->stock_reel = (float)
price2num($this->stock_reel,
'MS');
6510 $this->db->free($result);
6512 if (!preg_match(
'/novirtual/', $option)) {
6518 $this->error = $this->db->lasterror();
6537 global $hookmanager, $action;
6539 $stock_commande_client = 0;
6540 $stock_commande_fournisseur = 0;
6541 $stock_sending_client = 0;
6542 $stock_reception_fournisseur = 0;
6543 $stock_inproduction = 0;
6552 $stock_commande_client = $this->stats_commande[
'qty'];
6555 require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expedition.class.php';
6556 $filterShipmentStatus =
'';
6566 $stock_sending_client = $this->stats_expedition[
'qty'];
6570 $filterStatus =
getDolGlobalString(
'SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK',
'3,4');
6571 if (isset($includedraftpoforvirtual)) {
6572 $filterStatus =
'0,1,2,'.$filterStatus;
6578 $stock_commande_fournisseur = $this->stats_commande_fournisseur[
'qty'];
6582 $filterStatus =
'4';
6583 if (isset($includedraftpoforvirtual)) {
6584 $filterStatus =
'0,'.$filterStatus;
6590 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
6599 $stock_inproduction = $this->stats_mrptoproduce[
'qty'] - $this->stats_mrptoconsume[
'qty'];
6602 $this->stock_theorique = $this->stock_reel + $stock_inproduction;
6606 $weBillOrderOrShipmentReception =
getDolGlobalString(
'STOCK_DO_WE_BILL_ORDER_OR_SHIPMENTECEPTION_FOR_VIRTUALSTOCK',
'order');
6610 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6614 $result = $tmpnewprod->load_stats_commande(0,
'0', 1);
6615 $this->stock_theorique += $tmpnewprod->stats_commande[
'qty'];
6617 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6618 $this->stock_theorique -= $stock_commande_client;
6619 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6620 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6625 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6627 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6629 if (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER_INCLUDE_DRAFT')) {
6631 $result = $tmpnewprod->load_stats_commande_fournisseur(0,
'0', 1);
6632 $this->stock_theorique += $this->stats_commande_fournisseur[
'qty'];
6634 $this->stock_theorique -= $stock_reception_fournisseur;
6635 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6636 $this->stock_theorique += $stock_commande_fournisseur;
6637 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6638 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6641 $parameters = array(
'id' => $this->
id,
'includedraftpoforvirtual' => $includedraftpoforvirtual);
6643 $reshook = $hookmanager->executeHooks(
'loadvirtualstock', $parameters, $this, $action);
6645 $this->stock_theorique = $hookmanager->resArray[
'stock_theorique'];
6646 } elseif ($reshook == 0 && isset($hookmanager->resArray[
'stock_stats_hook'])) {
6647 $this->stock_theorique += $hookmanager->resArray[
'stock_stats_hook'];
6651 if (!empty($this->stock_warehouse) &&
getDolGlobalString(
'STOCK_ALLOW_VIRTUAL_STOCK_PER_WAREHOUSE')) {
6652 foreach ($this->stock_warehouse as $warehouseid => $stockwarehouse) {
6660 if ($this->fk_default_warehouse == $warehouseid) {
6661 $this->stock_warehouse[$warehouseid]->virtual = $this->stock_warehouse[$warehouseid]->real + $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] + $this->stats_commande_fournisseur[
'qty'] - ($this->stats_commande[
'qty'] + $this->stats_mrptoconsume[
'qty']);
6663 $this->stock_warehouse[$warehouseid]->virtual = $this->stock_warehouse[$warehouseid]->real + $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'];
6680 $this->stock_warehouse = array();
6685 if (count($prods_arbo) > 0) {
6686 $productCachedList = array();
6687 $stockByComponentList = array();
6689 foreach ($prods_arbo as $componentArr) {
6690 $componentId = $componentArr[
'id'];
6692 if ($componentArr[
'incdec'] == 1) {
6693 if (!isset($productCachedList[$componentId])) {
6694 $componentStatic =
new self($this->db);
6695 $componentStatic->fetch($componentId);
6697 $childrenNb = $componentStatic->hasFatherOrChild(1);
6698 if ($childrenNb == 0) {
6699 $componentStatic->load_stock(
'nobatch,novirtual');
6700 if (!isset($stockByComponentList[$componentId])) {
6701 $stockByComponentList[$componentId] = array(
6705 $stockByComponentList[$componentId][
'qty_need'] += $componentArr[
'nb_total'];
6707 $productCachedList[$componentId] = $componentStatic;
6712 if (!empty($stockByComponentList)) {
6713 foreach ($stockByComponentList as $componentId => $stockByComponentArr) {
6714 if (!isset($productCachedList[$componentId])) {
6715 $componentStatic =
new self($this->db);
6716 $componentStatic->fetch($componentId);
6717 $componentStatic->load_stock(
'nobatch,novirtual');
6718 $productCachedList[$componentId] = $componentStatic;
6720 $component = $productCachedList[$componentId];
6723 if ($component->stock_reel < $stockByComponentArr[
'qty_need']) {
6726 $this->error =
'Not enough component [id='.$componentId.
'] in stock, real='.$component->stock_reel.
' and need='.$stockByComponentArr[
'qty_need'];
6727 $this->errors[] = $this->error;
6728 dol_syslog(__METHOD__.
' : '.$this->error, LOG_ERR);
6730 if (!empty($component->stock_warehouse)) {
6731 foreach ($component->stock_warehouse as $warehouseId => $warehouseObj) {
6732 $kitWarehouseAvailable =
new stdClass();
6733 $kitWarehouseAvailable->id = $warehouseObj->id;
6734 $kitWarehouseAvailable->real = $qtyWish;
6735 $this->stock_warehouse[$warehouseId] = $kitWarehouseAvailable;
6744 } elseif (
getDolGlobalInt(
'PRODUIT_SOUSPRODUITS_ALSO_ENABLE_PARENT_STOCK_MOVE') && empty($productCachedList)) {
6768 $sql =
"SELECT pb.batch, pb.eatby, pb.sellby, SUM(pb.qty) AS qty FROM ".$this->db->prefix().
"product_batch as pb, ".$this->db->prefix().
"product_stock as ps";
6769 $sql .=
" WHERE pb.fk_product_stock = ps.rowid AND ps.fk_product = ".((int) $this->
id).
" AND pb.batch = '".$this->db->escape($batch).
"'";
6770 $sql .=
" GROUP BY pb.batch, pb.eatby, pb.sellby";
6771 dol_syslog(get_class($this).
"::loadBatchInfo load first entry found for lot/serial = ".$batch, LOG_DEBUG);
6772 $resql = $this->db->query($sql);
6774 $num = $this->db->num_rows($resql);
6777 $obj = $this->db->fetch_object($resql);
6778 $result[] = array(
'batch' => $batch,
'eatby' => $this->db->jdate($obj->eatby),
'sellby' => $this->db->jdate($obj->sellby),
'qty' => $obj->qty);
6784 $this->db->rollback();
6801 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6807 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos";
6809 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product').dol_sanitizeFileName($this->
ref);
6814 $dir_osencoded = $dir;
6816 if (is_dir($dir_osencoded)) {
6817 $originImage = $dir.
'/'.$file[
'name'];
6828 if (is_numeric($result) && $result > 0) {
6845 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6846 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6850 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos/";
6852 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product');
6856 if (file_exists($dir_osencoded)) {
6857 $handle = opendir($dir_osencoded);
6858 if (is_resource($handle)) {
6859 while (($file = readdir($handle)) !==
false) {
6861 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6884 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6885 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6891 $handle = @opendir($dir_osencoded);
6892 if (is_resource($handle)) {
6893 while (($file = readdir($handle)) !==
false) {
6895 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6902 $photo_vignette =
'';
6904 if (preg_match(
'/('.$this->regeximgext.
')$/i', $photo, $regs)) {
6905 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $photo).
'_small'.$regs[0];
6908 $dirthumb = $dir.
'thumbs/';
6912 $obj[
'photo'] = $photo;
6913 if ($photo_vignette &&
dol_is_file($dirthumb.$photo_vignette)) {
6914 $obj[
'photo_vignette'] =
'thumbs/'.$photo_vignette;
6916 $obj[
'photo_vignette'] =
"";
6919 $tabobj[$nbphoto - 1] = $obj;
6922 if ($nbmax && $nbphoto >= $nbmax) {
6944 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6945 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6947 $dir = dirname($file).
'/';
6948 $dirthumb = $dir.
'/thumbs/';
6949 $filename = preg_replace(
'/'.preg_quote($dir,
'/').
'/i',
'', $file);
6955 if (preg_match(
'/('.$this->regeximgext.
')$/i', $filename, $regs)) {
6956 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_small'.$regs[0];
6957 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6961 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_mini'.$regs[0];
6962 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6979 $infoImg = getimagesize($file_osencoded);
6980 $this->imgWidth = $infoImg[0];
6981 $this->imgHeight = $infoImg[1];
6991 global $hookmanager;
6993 $this->nb = array();
6995 $sql =
"SELECT count(p.rowid) as nb, fk_product_type";
6996 $sql .=
" FROM ".$this->db->prefix().
"product as p";
6997 $sql .=
' WHERE p.entity IN ('.getEntity($this->element, 1).
')';
6999 if (is_object($hookmanager)) {
7000 $parameters = array();
7001 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
7002 $sql .= $hookmanager->resPrint;
7004 $sql .=
' GROUP BY fk_product_type';
7006 $resql = $this->db->query($sql);
7008 while ($obj = $this->db->fetch_object($resql)) {
7009 if ($obj->fk_product_type == 1) {
7010 $this->nb[
"services"] = $obj->nb;
7012 $this->nb[
"products"] = $obj->nb;
7015 $this->db->free($resql);
7019 $this->error = $this->db->error();
7061 return $this->mandatory_period == 1;
7071 return $this->status_batch > 0;
7091 $dirsociete = array_merge(array(
'/core/modules/barcode/'),
$conf->modules_parts[
'barcode']);
7092 foreach ($dirsociete as $dirroot) {
7100 '@phan-var-force ModeleNumRefBarCode $mod';
7102 $result = $mod->getNextValue(
$object, $type);
7104 dol_syslog(get_class($this).
"::get_barcode barcode=".$result.
" module=".$var);
7121 $this->specimen = 1;
7123 $this->
ref =
'PRODUCT_SPEC';
7124 $this->label =
'PRODUCT SPECIMEN';
7125 $this->
description =
'This is description of this product specimen that was created the '.dol_print_date($now,
'dayhourlog').
'.';
7126 $this->specimen = 1;
7127 $this->country_id = 1;
7129 $this->status_buy = 1;
7131 $this->sell_or_eat_by_mandatory = 0;
7132 $this->note_private =
'This is a comment (private)';
7133 $this->note_public =
'This is a comment (public)';
7134 $this->date_creation = $now;
7135 $this->date_modification = $now;
7138 $this->weight_units = 3;
7141 $this->length_units = 1;
7143 $this->width_units = 0;
7144 $this->height =
null;
7145 $this->height_units =
null;
7147 $this->surface = 30;
7148 $this->surface_units = 0;
7149 $this->volume = 300;
7150 $this->volume_units = 0;
7152 $this->barcode = -1;
7170 if (empty($this->fk_unit)) {
7173 if (empty($outputlangs)) {
7174 $outputlangs = $langs;
7177 $outputlangs->load(
'products');
7180 $sql =
"SELECT code, label, short_label FROM ".$this->db->prefix().
"c_units where rowid = ".((int) $this->fk_unit);
7182 $resql = $this->db->query($sql);
7184 $this->error = $this->db->error();
7185 dol_syslog(get_class($this).
"::getLabelOfUnit Error ".$this->error, LOG_ERR);
7187 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
7188 if ($type ==
'short') {
7190 $label = $outputlangs->transnoentitiesnoconv($res[
'short_label']);
7192 $label = $outputlangs->trans($res[
'short_label']);
7194 } elseif ($type ==
'code') {
7195 $label = $res[
'code'];
7197 if ($outputlangs->trans(
'unit'.$res[
'code']) ==
'unit'.$res[
'code']) {
7199 $label = $res[
'label'];
7203 $label = $outputlangs->transnoentitiesnoconv(
'unit'.$res[
'code']);
7205 $label = $outputlangs->trans(
'unit'.$res[
'code']);
7210 $this->db->free($resql);
7224 $maxpricesupplier = 0;
7227 include_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.product.class.php';
7229 $product_fourn_list = $product_fourn->list_product_fournisseur_price($this->
id,
'',
'');
7231 if (is_array($product_fourn_list) && count($product_fourn_list) > 0) {
7232 foreach ($product_fourn_list as $productfourn) {
7233 if ($productfourn->fourn_unitprice > $maxpricesupplier) {
7234 $maxpricesupplier = $productfourn->fourn_unitprice;
7242 return $maxpricesupplier;
7258 require_once DOL_DOCUMENT_ROOT.
'/categories/class/categorie.class.php';
7259 return parent::setCategoriesCommon($categories, Categorie::TYPE_PRODUCT);
7273 $sql =
" DELETE FROM ".$dbs->prefix().
"product_customer_price";
7274 $sql .=
" WHERE fk_soc = ".(int) $origin_id;
7275 $sql .=
" AND fk_product IN (SELECT fk_product FROM (SELECT fk_product FROM ".$dbs->prefix().
"product_customer_price WHERE fk_soc = ".(int) $dest_id.
") AS tmp)";
7278 if (!$dbs->
query($sql)) {
7283 'product_customer_price',
7284 'product_customer_price_log'
7303 $sql =
"SELECT rowid, level, fk_level, var_percent, var_min_percent FROM ".$this->db->prefix().
"product_pricerules";
7304 $query = $this->db->query($sql);
7308 while ($result = $this->db->fetch_object($query)) {
7309 $rules[$result->level] = $result;
7318 for ($i = 1; $i <= $nbofproducts; $i++) {
7319 $price = $baseprice;
7320 $price_min = $baseprice;
7324 if ($i > 1 && isset($rules[$i]->var_percent) && $rules[$i]->var_percent) {
7325 $price = $prices[$rules[$i]->fk_level] * (1 + ($rules[$i]->var_percent / 100));
7328 $prices[$i] = $price;
7331 if (isset($rules[$i]->var_min_percent) && $rules[$i]->var_min_percent) {
7332 $price_min = $price * (1 - ($rules[$i]->var_min_percent / 100));
7336 $check_amount = (($price == $this->multiprices[$i]) && ($price_min == $this->multiprices_min[$i]));
7337 $check_type = ($baseprice == $this->multiprices_base_type[$i]);
7339 if ($check_amount && $check_type) {
7343 if ($this->
updatePrice($price, $price_type, $user, $price_vat, $price_min, $i, $npr, $psq, 1) < 0) {
7361 return $user->rights->produit;
7363 return $user->rights->service;
7375 $sql =
"SELECT p.rowid, p.ref, p.datec as date_creation, GREATEST(p.tms, pef.tms) as date_modification,";
7376 $sql .=
" p.fk_user_author, p.fk_user_modif";
7377 $sql .=
" FROM ".$this->db->prefix().$this->table_element.
" as p";
7378 $sql .=
" LEFT JOIN ".$this->db->prefix().$this->table_element.
"_extrafields as pef ON pef.fk_object=p.rowid";
7379 $sql .=
" WHERE p.rowid = ".((int) $id);
7381 $result = $this->db->query($sql);
7383 if ($this->db->num_rows($result)) {
7384 $obj = $this->db->fetch_object($result);
7386 $this->
id = $obj->rowid;
7387 $this->
ref = $obj->ref;
7389 $this->user_creation_id = $obj->fk_user_author;
7390 $this->user_modification_id = $obj->fk_user_modif;
7392 $this->date_creation = $this->db->jdate($obj->date_creation);
7393 $this->date_modification = $this->db->jdate($obj->date_modification);
7396 $this->db->free($result);
7410 if (empty($this->duration_value)) {
7411 $this->errors[] =
'ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
7414 if ($this->duration_unit ==
's') {
7415 $prodDurationHours = 1. / 3600;
7416 } elseif ($this->duration_unit ==
'i' || $this->duration_unit ==
'mn' || $this->duration_unit ==
'min') {
7417 $prodDurationHours = 1. / 60;
7418 } elseif ($this->duration_unit ==
'h') {
7419 $prodDurationHours = 1.;
7420 } elseif ($this->duration_unit ==
'd') {
7421 $prodDurationHours = 24.;
7422 } elseif ($this->duration_unit ==
'w') {
7423 $prodDurationHours = 24. * 7;
7424 } elseif ($this->duration_unit ==
'm') {
7425 $prodDurationHours = 24. * 30;
7426 } elseif ($this->duration_unit ==
'y') {
7427 $prodDurationHours = 24. * 365;
7429 $prodDurationHours = 0.0;
7431 $prodDurationHours *= $this->duration_value;
7433 return $prodDurationHours;
7446 global $langs,
$conf;
7448 $selected = (empty($arraydata[
'selected']) ? 0 : $arraydata[
'selected']);
7450 $return =
'<div class="box-flex-item box-flex-grow-zero">';
7451 $return .=
'<div class="info-box info-box-sm">';
7452 $return .=
'<div class="info-box-img">';
7454 if ($this->entity !==
null && $this->
is_photo_available($conf->product->multidir_output[$this->entity])) {
7455 $label .= $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 120, 160, 0, 0, 0,
'',
'photoref photokanban');
7465 $return .=
'</div>';
7466 $return .=
'<div class="info-box-content">';
7467 $return .=
'<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">' . $this->
getNomUrl() .
'</span>';
7468 if ($selected >= 0) {
7469 $return .=
'<input id="cb'.$this->id.
'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->
id.
'"'.($selected ?
' checked="checked"' :
'').
'>';
7471 $return .=
'<br><span class="info-box-label opacitymedium inline-block tdoverflowmax150 valignmiddle" title="'.dol_escape_htmltag($this->label).
'">'.
dol_escape_htmltag($this->label).
'</span>';
7472 if ($this->price_base_type ==
'TTC') {
7473 $return .=
'<br><span class="info-box-status amount">'.price($this->price_ttc).
' '.$langs->trans(
"TTC").
'</span>';
7476 $return .=
'<br><span class="info-box-status amount">'.price($this->
price).
' '.$langs->trans(
"HT").
'</span>';
7481 $return .=
'<br><div class="info-box-status opacitymedium inline-block valignmiddle">'.img_picto($langs->trans(
'PhysicalStock'),
'stock').
'</div><div class="inline-block valignmiddle paddingleft" title="'.$langs->trans(
'PhysicalStock').
'">'.$this->stock_reel.
'</div>';
7486 $return .=
'<div class="info-box-status inline-block valignmiddle">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7488 $return .=
'<div class="info-box-status inline-block valignmiddle marginleftonly paddingleft">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7490 $return .=
'</div>';
7491 $return .=
'</div>';
7492 $return .=
'</div>';
7503 public $picto =
'service';
if(! $sortfield) if(! $sortorder) $object
length_accountg($account)
Return General accounting account with defined length (used for product and miscellaneous)
clean_account($account)
Return accounting account without zero on the right.
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
deleteEcmFiles($mode=0)
Delete related files of object in database.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
setErrorsFromObject($object)
setErrorsFromObject
isObjectUsed($id=0, $entity=0)
Function to check if an object is used by others (by children).
deleteExtraFields()
Delete all extra fields values for the current object.
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
show_photos($modulepart, $sdir, $size=0, $nbmax=0, $nbbyrow=5, $showfilename=0, $showaction=0, $maxHeight=120, $maxWidth=160, $nolink=0, $overwritetitle=0, $usesharelink=0, $cache='', $addphotorefcss='photoref')
Show photos of an object (nbmax maximum), into several columns.
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
addThumbs($file, $quality=50)
Build thumb.
Class to manage Dolibarr database access.
Class to manage ECM files.
const STATUS_OPEN_INTERNAL
Warehouse open and only operations for stock transfers/corrections allowed (not for customer shipping...
const STATUS_OPEN_ALL
Warehouse open and any operations are allowed (customer shipping, supplier dispatch,...
const STATUS_CLOSED
Warehouse closed, inactive.
const STATUS_CLOSED
Closed status -> parcel was received by customer / end of process prev status : validated or shipment...
const STATUS_VALIDATED
Validated status -> parcel is ready to be sent prev status : draft next status : closed or shipment_i...
const STATUS_DRAFT
Draft status.
Class to manage stock movements.
Class to parse product price expressions.
Class ProductCombination Used to represent the relation between a product and one of its variants.
File of class to manage predefined price products or services by customer.
Class to manage predefined suppliers products.
Class to manage products or services.
static replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
get_nb_achat($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units or supplier invoices in which product is included.
getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp=0)
Return price of sell of a product for a seller/buyer/product.
__construct($db)
Constructor.
is_sousproduit($fk_parent, $fk_child)
Check if it is a sub-product into a kit.
const DISABLED_STOCK
Stockable product.
const SELL_OR_EAT_BY_MANDATORY_ID_NONE
Const sell or eat by mandatory id.
isStockManaged()
Return if the object is managed in stock.
setPriceExpression($expression_id)
Sets the supplier price expression.
getArrayForPriceCompare($level=0)
used to check if price have really change to avoid log pollution
get_arbo_each_prod($multiply=1, $ignore_stock_load=0)
Build the tree of subproducts and return it.
list_suppliers()
Return list of suppliers providing the product or service.
load_stats_mo($socid=0)
Charge tableau des stats OF pour le produit/service.
isVariant()
Return if loaded product is a variant.
updatePrice($newprice, $newpricebase, $user, $newvat=null, $newminprice=0, $level=0, $newnpr=0, $newpbq=0, $ignore_autogen=0, $localtaxes_array=array(), $newdefaultvatcode='', $price_label='', $notrigger=0)
Modify customer price of a product/Service for a given level.
hasVariants()
Return if a product has variants or not.
load_stats_proposal_supplier($socid=0)
Charge tableau des stats propale pour le produit/service.
getLibFinished()
Retour label of nature of product.
add_sousproduit($id_pere, $id_fils, $qty, $incdec=1, $notrigger=0)
Link a product/service to a parent product/service.
add_fournisseur($user, $id_fourn, $ref_fourn, $quantity)
Add a supplier price for the product.
setMultiLangs($user, $notrigger=0)
Update or add a translation for a product.
hasFatherOrChild($mode=0)
Count all parent and children products for current product (first level only)
load_stats_facturerec($socid=0)
Load array of statistics for recurring invoice for product/service.
get_nb_propalsupplier($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in proposals in which product is included.
load_stats_facturefournrec($socid=0)
Load array of statistics for recurring supplier invoice for product/service.
get_nb_contract($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
load_stats_facture_fournisseur($socid=0)
Load array of statistics for vendor invoice for product/service.
get_nb_ordersupplier($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
getMultiLangs()
Load array this->multilangs.
get_nb_mos($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
clone_associations($fromId, $toId)
Clone links between products.
create($user, $notrigger=0)
Insert product into database.
load_stats_contrat($socid=0)
Charge tableau des stats contrat pour le produit/service.
isService()
Return if the object is a service.
getRights()
Returns the rights used for this class.
loadBatchInfo($batch)
Load existing information about a serial.
load_stock($option='', $includedraftpoforvirtual=null, $dateofvirtualstock=null)
Load information about stock of a product into ->stock_reel, ->stock_warehouse[] (including stock_war...
getProductDurationHours()
Return the duration of a service in hours (for a service based on duration fields)
get_buyprice($prodfournprice, $qty, $product_id=0, $fourn_ref='', $fk_soc=0)
Read price used by a provider.
clone_fournisseurs($fromId, $toId)
Copies the suppliers and supplier pricing of a product/service onto another one.
const TYPE_PRODUCT
Regular product.
fetchAllPriceLogs($id)
Get all price change logs for a product, enriched with supplier info.
add_photo($sdir, $file)
Move an uploaded file described into $file array into target directory $sdir.
log_price_delete($user, $rowid)
Delete a price line.
info($id)
Load information for tab info.
correct_stock($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $inventorycode='', $origin_element='', $origin_id=null, $disablestockchangeforsubproduct=0, $extrafields=null)
Adjust stock in a warehouse for product.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
Create a document onto disk according to template module.
static getSellOrEatByMandatoryList()
Get the array of labels of Sell by or Eat by all mandatory flags for each status.
getChildsArbo($id, $firstlevelonly=0, $level=1, $parents=array())
Return children of product $id.
load_virtual_stock($includedraftpoforvirtual=null, $dateofvirtualstock=null)
Load value ->stock_theorique of a product.
load_stats_propale($socid=0)
Charge tableau des stats propale pour le produit/service.
get_barcode($object, $type='')
Get a barcode from the module to generate barcode values.
setAccountancyCode($type, $value)
Sets an accountancy code for a product.
load_stats_facture($socid=0)
Charge tableau des stats facture pour le produit/service.
setCategories($categories)
Sets object to supplied categories.
load_stats_reception($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null)
Loads supplier reception statistics table for given product or service.
get_nb_propal($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in proposals in which product is included.
update($id, $user, $notrigger=0, $action='update', $updatetype=false)
Update a record into database.
correct_stock_batch($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $dlc='', $dluo='', $lot='', $inventorycode='', $origin_element='', $origin_id=null, $disablestockchangeforsubproduct=0, $extrafields=null, $force_update_batch=false)
Adjust stock in a warehouse for product with batch number.
load_stats_bom($socid=0)
Charge tableau des stats OF pour le produit/service.
hasbatch()
Return if the object has a batch management.
del_sousproduit($fk_parent, $fk_child, $notrigger=0)
Remove a link between a subproduct and a parent product/service.
fetch($id=0, $ref='', $ref_ext='', $barcode='', $ignore_expression=0, $ignore_price_load=0, $ignore_lang_load=0)
Load a product in memory from database.
update_sousproduit($id_pere, $id_fils, $qty, $incdec=1, $notrigger=0)
Modify composed product.
load_stats_commande($socid=0, $filtrestatut='', $forVirtualStock=0)
Charge tableau des stats commande client pour le produit/service.
delete_photo($file)
Delete a photo and its thumbs.
fetch_prod_arbo($prod, $compl_path='', $multiply=1, $level=1, $id_parent=0, $ignore_stock_load=0)
Function recursive, used only by get_arbo_each_prod(), to build tree of subproducts into ->res Define...
getKanbanView($option='', $arraydata=null)
Return clickable link of object (with eventually picto)
getLibStatut($mode=0, $type=0)
Return label of status of object.
load_stats_sending($socid=0, $filtrestatut='', $forVirtualStock=0, $filterShipmentStatus='')
Charge tableau des stats expedition client pour le produit/service.
clone_price($fromId, $toId)
Recopie les prix d'un produit/service sur un autre.
load_stats_inproduction($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null, $warehouseid=0)
Charge tableau des stats production pour le produit/service.
delMultiLangs($langtodelete, $user, $notrigger=0)
Delete a language for this product.
check()
Check that ref and label are ok.
initAsSpecimen()
Initialise an instance with random values.
liste_photos($dir, $nbmax=0)
Return an array with all photos of product found on disk.
loadStateBoard()
Load indicators this->nb for the dashboard.
getFather()
Return all parent products for current product (first level only)
getNomUrl($withpicto=0, $option='', $maxlength=0, $save_lastsearch_value=-1, $notooltip=0, $morecss='', $add_label=0, $sep=' - ')
Return clickable link of object (with eventually picto)
getSellOrEatByMandatoryLabel()
Get the label for sell by or eat by mandatory flag of the current product.
verify()
Check properties of product are ok (like name, barcode, ...).
get_nb_order($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
loadStockForVirtualProduct($option='', $qtyWish=1)
Load stock for components of virtual product (first level only)
min_recommended_price()
Return minimum product recommended price.
_log_price($user, $level=0)
Insert a track that we changed a customer price.
getLabelOfUnit($type='long', $outputlangs=null, $noentities=0)
Reads the units dictionary to return the translation code of a unit (if type='code'),...
_get_stats($sql, $mode, $year=0)
Return an array formatted for showing graphs.
load_stats_commande_fournisseur($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null)
Charge tableau des stats commande fournisseur pour le produit/service.
isMandatoryPeriod()
Return if the object has a constraint on mandatory_period.
isProduct()
Return if the object is a product.
generateMultiprices(User $user, $baseprice, $price_type, $price_vat, $npr, $psq)
Generates prices for a product based on product multiprice generation rules.
LibStatut($status, $mode=0, $type=0)
Return label of a given status.
const TYPE_SERVICE
Service.
is_photo_available($sdir)
Return if at least one photo is available.
get_image_size($file)
Load size of image file.
get_nb_vente($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units or customers invoices in which product is included.
getTooltipContentArray($params)
getTooltipContentArray
Class to manage products or services.
Manage record for batch number management.
static findAll($dbs, $fk_product_stock, $with_qty=0, $fk_product=0)
Return all batch detail records for a given product and warehouse.
Class with list of lots and properties.
Class to manage Dolibarr users.
hasRight($module, $permlevel1, $permlevel2='')
Return if a user has a permission.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0, $level=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
dol_is_file($pathoffile)
Return if path is a file.
dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $nohook=0, $keyforsourcefile='addedfile', $upload_dir='', $mode=0)
Check validity of a file upload from an GUI page, and move it to its final destination.
dol_now($mode='gmt')
Return date for now.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
dolGetFirstLineOfText($text, $nboflines=1, $charset='UTF-8')
Return first line of text.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='', $keepspaces=0)
Clean a string from all punctuation characters to use it as a ref or login.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
dol_clone($srcobject, $native=2)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '...' if string larger than length.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
utf8_check($str)
Check if a string is in UTF8.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_localtax($vatrate, $local, $thirdparty_buyer=null, $thirdparty_seller=null, $vatnpr=0)
Return localtax rate for a particular VAT rate, when selling a product with vat $vatrate,...
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
yn($yesno, $format=1, $color=0)
Return yes or no in current language.
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
query($query, $usesavepoint=0, $type='auto', $result_mode=0)
Execute a SQL request and return the resultset.
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
measuring_units_squared($unitscale)
Transform a given unit scale into the square of that unit, if known.
measuringUnitString($unitid, $measuring_style='', $unitscale=null, $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
measuring_units_cubed($unit)
Transform a given unit scale into the cube of that unit, if known.
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...