42require_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
43require_once DOL_DOCUMENT_ROOT.
'/core/class/commonobject.class.php';
44require_once DOL_DOCUMENT_ROOT.
'/product/class/productbatch.class.php';
45require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/productlot.class.php';
46require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/entrepot.class.php';
57 const SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY = 1;
58 const SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY = 2;
59 const SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT = 3;
64 public $element =
'product';
69 public $table_element =
'product';
74 public $fk_element =
'fk_product';
79 protected $childtables = array(
80 'supplier_proposaldet' => array(
'name' =>
'SupplierProposal',
'parent' =>
'supplier_proposal',
'parentkey' =>
'fk_supplier_proposal'),
81 'propaldet' => array(
'name' =>
'Proposal',
'parent' =>
'propal',
'parentkey' =>
'fk_propal'),
82 'commandedet' => array(
'name' =>
'Order',
'parent' =>
'commande',
'parentkey' =>
'fk_commande'),
83 'facturedet' => array(
'name' =>
'Invoice',
'parent' =>
'facture',
'parentkey' =>
'fk_facture'),
84 'contratdet' => array(
'name' =>
'Contract',
'parent' =>
'contrat',
'parentkey' =>
'fk_contrat'),
85 'facture_fourn_det' => array(
'name' =>
'SupplierInvoice',
'parent' =>
'facture_fourn',
'parentkey' =>
'fk_facture_fourn'),
86 'commande_fournisseurdet' => array(
'name' =>
'SupplierOrder',
'parent' =>
'commande_fournisseur',
'parentkey' =>
'fk_commande'),
87 'mrp_production' => array(
'name' =>
'Mo',
'parent' =>
'mrp_mo',
'parentkey' =>
'fk_mo',
'enabled' =>
'isModEnabled("mrp")'),
88 'bom_bom' => array(
'name' =>
'BOM',
'enabled' =>
'isModEnabled("bom")'),
89 'bom_bomline' => array(
'name' =>
'BOMLine',
'parent' =>
'bom_bom',
'parentkey' =>
'fk_bom',
'enabled' =>
'isModEnabled("bom")'),
97 public $picto =
'product';
108 public $regeximgext =
'\.gif|\.jpg|\.jpeg|\.png|\.bmp|\.webp|\.xpm|\.xbm';
155 public $price_formated;
167 public $price_ttc_formated;
181 public $price_min_ttc;
187 public $price_base_type;
197 public $multiprices = array();
201 public $multiprices_ttc = array();
205 public $multiprices_base_type = array();
209 public $multiprices_default_vat_code = array();
213 public $multiprices_min = array();
217 public $multiprices_min_ttc = array();
221 public $multiprices_tva_tx = array();
225 public $multiprices_recuperableonly = array();
231 public $price_by_qty;
235 public $prices_by_qty = array();
239 public $prices_by_qty_id = array();
243 public $prices_by_qty_list = array();
253 public $multilangs = array();
258 public $default_vat_code;
273 public $remise_percent;
278 public $localtax1_tx;
282 public $localtax2_tx;
286 public $localtax1_type;
290 public $localtax2_type;
297 public $desc_supplier;
301 public $vatrate_supplier;
305 public $default_vat_code_supplier;
310 public $fourn_multicurrency_price;
314 public $fourn_multicurrency_unitprice;
318 public $fourn_multicurrency_tx;
322 public $fourn_multicurrency_id;
326 public $fourn_multicurrency_code;
348 public $qc_frequency;
355 public $stock_reel = 0;
362 public $stock_theorique;
383 public $seuil_stock_alerte = 0;
388 public $desiredstock = 0;
393 public $duration_value;
397 public $duration_unit;
406 public $fk_default_workstation;
428 public $status_buy = 0;
450 public $fk_default_bom;
457 public $product_fourn_price_id;
479 public $status_batch = 0;
486 public $sell_or_eat_by_mandatory = 0;
493 public $batch_mask =
'';
518 public $weight_units;
526 public $length_units;
542 public $height_units;
550 public $surface_units;
558 public $volume_units;
567 public $net_measure_units;
572 public $accountancy_code_sell;
576 public $accountancy_code_sell_intra;
580 public $accountancy_code_sell_export;
584 public $accountancy_code_buy;
588 public $accountancy_code_buy_intra;
592 public $accountancy_code_buy_export;
602 public $barcode_type;
607 public $barcode_type_code;
612 public $stats_propale = array();
617 public $stats_commande = array();
622 public $stats_contrat = array();
627 public $stats_facture = array();
632 public $stats_proposal_supplier = array();
637 public $stats_commande_fournisseur = array();
642 public $stats_expedition = array();
647 public $stats_reception = array();
652 public $stats_mo = array();
657 public $stats_bom = array();
662 public $stats_mrptoconsume = array();
667 public $stats_mrptoproduce = array();
672 public $stats_facturerec = array();
677 public $stats_facture_fournisseur = array();
682 public $stats_facturefournrec = array();
697 public $product_fourn_id;
703 public $product_id_already_linked;
714 public $stock_warehouse = array();
719 public $fk_default_warehouse;
724 public $fk_price_expression;
742 public $fourn_price_base_type;
759 public $ref_supplier;
773 public $price_autogen = 0;
780 public $supplierprices;
787 public $sousprods = array();
800 public $is_object_used;
811 public $is_sousproduit_qty;
823 public $is_sousproduit_incdec;
828 public $mandatory_period;
835 public $stockable_product = 1;
865 public $fields = array(
866 'rowid' => array(
'type' =>
'integer',
'label' =>
'TechnicalID',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'index' => 1,
'position' => 1,
'comment' =>
'Id'),
867 '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'),
868 'entity' => array(
'type' =>
'integer',
'label' =>
'Entity',
'enabled' => 1,
'visible' => 0,
'default' =>
'1',
'notnull' => 1,
'index' => 1,
'position' => 5),
869 'label' => array(
'type' =>
'varchar(255)',
'label' =>
'Label',
'enabled' => 1,
'visible' => 1,
'notnull' => 1,
'showoncombobox' => 2,
'position' => 15,
'csslist' =>
'tdoverflowmax250'),
870 'barcode' => array(
'type' =>
'varchar(255)',
'label' =>
'Barcode',
'enabled' =>
'isModEnabled("barcode")',
'position' => 20,
'visible' => -1,
'showoncombobox' => 3,
'cssview' =>
'tdwordbreak',
'csslist' =>
'tdoverflowmax125'),
871 'fk_barcode_type' => array(
'type' =>
'integer',
'label' =>
'BarcodeType',
'enabled' => 1,
'position' => 21,
'notnull' => 0,
'visible' => -1,),
872 'note_public' => array(
'type' =>
'html',
'label' =>
'NotePublic',
'enabled' => 1,
'visible' => 0,
'position' => 61),
873 'note' => array(
'type' =>
'html',
'label' =>
'NotePrivate',
'enabled' => 1,
'visible' => 0,
'position' => 62),
874 'datec' => array(
'type' =>
'datetime',
'label' =>
'DateCreation',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 500),
875 'tms' => array(
'type' =>
'timestamp',
'label' =>
'DateModification',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 501),
877 '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'),
878 'fk_user_modif' => array(
'type' =>
'integer:User:user/class/user.class.php',
'label' =>
'UserModif',
'enabled' => 1,
'visible' => -2,
'notnull' => -1,
'position' => 511),
880 'localtax1_tx' => array(
'type' =>
'double(6,3)',
'label' =>
'Localtax1tx',
'enabled' => 1,
'position' => 150,
'notnull' => 0,
'visible' => -1,),
881 'localtax1_type' => array(
'type' =>
'varchar(10)',
'label' =>
'Localtax1type',
'enabled' => 1,
'position' => 155,
'notnull' => 1,
'visible' => -1,),
882 'localtax2_tx' => array(
'type' =>
'double(6,3)',
'label' =>
'Localtax2tx',
'enabled' => 1,
'position' => 160,
'notnull' => 0,
'visible' => -1,),
883 'localtax2_type' => array(
'type' =>
'varchar(10)',
'label' =>
'Localtax2type',
'enabled' => 1,
'position' => 165,
'notnull' => 1,
'visible' => -1,),
884 'last_main_doc' => array(
'type' =>
'varchar(255)',
'label' =>
'LastMainDoc',
'enabled' => 1,
'visible' => -1,
'position' => 170),
885 'import_key' => array(
'type' =>
'varchar(14)',
'label' =>
'ImportId',
'enabled' => 1,
'visible' => -2,
'notnull' => -1,
'index' => 0,
'position' => 1000),
888 'mandatory_period' => array(
'type' =>
'integer',
'label' =>
'mandatoryperiod',
'enabled' => 1,
'visible' => -1,
'notnull' => 1,
'default' =>
'0',
'index' => 1,
'position' => 1000),
889 'stockable_product' =>array(
'type' =>
'integer',
'label' =>
'stockable_product',
'enabled' => 1,
'visible' => 1,
'default' =>
'1',
'notnull' => 1,
'index' => 1,
'position' => 502),
905 const ENABLED_STOCK = 1;
916 $this->ismultientitymanaged = 1;
917 $this->isextrafieldmanaged = 1;
930 $this->
ref = trim($this->
ref);
958 public function create($user, $notrigger = 0)
960 global
$conf, $langs;
966 $this->
ref = trim($this->
ref);
970 $this->label = trim($this->label);
971 $this->price_ttc = (float)
price2num($this->price_ttc);
973 $this->price_min_ttc = (float)
price2num($this->price_min_ttc);
974 $this->price_min = (float)
price2num($this->price_min);
975 $this->price_label = trim($this->price_label);
976 if (empty($this->tva_tx)) {
979 if (empty($this->tva_npr)) {
983 if (empty($this->localtax1_tx)) {
984 $this->localtax1_tx = 0;
986 if (empty($this->localtax2_tx)) {
987 $this->localtax2_tx = 0;
989 if (empty($this->localtax1_type)) {
990 $this->localtax1_type =
'0';
992 if (empty($this->localtax2_type)) {
993 $this->localtax2_type =
'0';
999 if (empty($this->
price)) {
1002 if (empty($this->price_min)) {
1003 $this->price_min = 0;
1006 if (empty($this->price_by_qty)) {
1007 $this->price_by_qty = 0;
1010 if (empty($this->
status)) {
1013 if (empty($this->status_buy)) {
1014 $this->status_buy = 0;
1016 if (empty($this->stockable_product)) {
1017 $this->stockable_product = 0;
1026 if ($this->price_base_type ==
'TTC' && $this->price_ttc > 0) {
1027 $price_ttc =
price2num($this->price_ttc,
'MU');
1028 $price_ht =
price2num($this->price_ttc / (1 + ($this->tva_tx / 100)),
'MU');
1032 if ($this->price_base_type !=
'TTC' && $this->
price > 0) {
1034 $price_ttc =
price2num($this->
price * (1 + ($this->tva_tx / 100)),
'MU');
1038 if (($this->price_min_ttc > 0) && ($this->price_base_type ==
'TTC')) {
1039 $price_min_ttc =
price2num($this->price_min_ttc,
'MU');
1040 $price_min_ht =
price2num($this->price_min_ttc / (1 + ($this->tva_tx / 100)),
'MU');
1044 if (($this->price_min > 0) && ($this->price_base_type !=
'TTC')) {
1045 $price_min_ht =
price2num($this->price_min,
'MU');
1046 $price_min_ttc =
price2num($this->price_min * (1 + ($this->tva_tx / 100)),
'MU');
1049 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
1050 $this->accountancy_code_buy_intra = trim($this->accountancy_code_buy_intra);
1051 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
1052 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
1053 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
1054 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
1057 $this->barcode = trim($this->barcode);
1058 $this->mandatory_period = empty($this->mandatory_period) ? 0 : $this->mandatory_period;
1060 if (empty($this->label)) {
1061 $langs->load(
'errors');
1062 $this->errors[] = $langs->trans(
'ErrorMandatoryParametersNotProvided');
1066 if (empty($this->
ref) || $this->
ref ==
'auto') {
1068 $module =
getDolGlobalString(
'PRODUCT_CODEPRODUCT_ADDON',
'mod_codeproduct_leopard');
1069 if ($module !=
'mod_codeproduct_leopard') {
1070 if (substr($module, 0, 16) ==
'mod_codeproduct_' && substr($module, -3) ==
'php') {
1071 $module = substr($module, 0,
dol_strlen($module) - 4);
1074 $modCodeProduct =
new $module();
1075 '@phan-var-force ModeleProductCode $modCodeProduct';
1076 if (!empty($modCodeProduct->code_auto)) {
1077 $this->
ref = $modCodeProduct->getNextValue($this, $this->
type);
1079 unset($modCodeProduct);
1082 if (empty($this->
ref)) {
1083 $this->error =
'ProductModuleNotSetupForAutoRef';
1088 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);
1092 if (empty($this->date_creation)) {
1093 $this->date_creation = $now;
1099 if ($this->barcode ==
'-1' || $this->barcode ==
'auto') {
1100 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1105 $result = $this->
verify();
1108 $sql =
"SELECT count(*) as nb";
1109 $sql .=
" FROM ".$this->db->prefix().
"product";
1110 $sql .=
" WHERE entity IN (".getEntity(
'product').
")";
1111 $sql .=
" AND ref = '".$this->db->escape($this->
ref).
"'";
1113 $result = $this->db->query($sql);
1115 $obj = $this->db->fetch_object($result);
1116 if ($obj->nb == 0) {
1118 $sql =
"INSERT INTO ".$this->db->prefix().
"product (";
1122 $sql .=
", ref_ext";
1123 $sql .=
", price_min";
1124 $sql .=
", price_min_ttc";
1126 $sql .=
", fk_user_author";
1127 $sql .=
", fk_product_type";
1129 $sql .=
", price_ttc";
1130 $sql .=
", price_base_type";
1131 $sql .=
", price_label";
1135 $sql .=
", accountancy_code_buy";
1136 $sql .=
", accountancy_code_buy_intra";
1137 $sql .=
", accountancy_code_buy_export";
1138 $sql .=
", accountancy_code_sell";
1139 $sql .=
", accountancy_code_sell_intra";
1140 $sql .=
", accountancy_code_sell_export";
1143 $sql .=
", finished";
1144 $sql .=
", tobatch";
1145 $sql .=
", sell_or_eat_by_mandatory";
1146 $sql .=
", batch_mask";
1147 $sql .=
", fk_unit";
1148 $sql .=
", mandatory_period";
1149 $sql .=
", stockable_product";
1150 if (!empty($this->default_vat_code)) $sql.=
", default_vat_code";
1151 $sql .=
") VALUES (";
1152 $sql .=
"'".$this->db->idate($this->date_creation).
"'";
1153 $sql .=
", ".(!empty($this->entity) ? (int) $this->entity : (int)
$conf->entity);
1154 $sql .=
", '".$this->db->escape($this->
ref).
"'";
1155 $sql .=
", ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1156 $sql .=
", ".price2num($price_min_ht);
1157 $sql .=
", ".price2num($price_min_ttc);
1158 $sql .=
", ".(!empty($this->label) ?
"'".$this->db->escape($this->label).
"'" :
"null");
1159 $sql .=
", ".((int) $user->id);
1160 $sql .=
", ".((int) $this->
type);
1161 $sql .=
", ".price2num($price_ht,
'MT');
1162 $sql .=
", ".price2num($price_ttc,
'MT');
1163 $sql .=
", '".$this->db->escape($this->price_base_type).
"'";
1164 $sql .=
", ".(!empty($this->price_label) ?
"'".$this->db->escape($this->price_label).
"'" :
"null");
1165 $sql .=
", ".((int) $this->
status);
1166 $sql .=
", ".((int) $this->status_buy);
1168 $sql .=
", '".$this->db->escape($this->accountancy_code_buy).
"'";
1169 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_intra).
"'";
1170 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_export).
"'";
1171 $sql .=
", '".$this->db->escape($this->accountancy_code_sell).
"'";
1172 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_intra).
"'";
1173 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_export).
"'";
1175 $sql .=
", '".$this->db->escape($this->canvas).
"'";
1176 $sql .=
", ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
'NULL' : (int) $this->finished);
1177 $sql .=
", ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : ((int) $this->status_batch));
1178 $sql .=
", ".((empty($this->sell_or_eat_by_mandatory) || $this->sell_or_eat_by_mandatory < 0) ? 0 : ((int) $this->sell_or_eat_by_mandatory));
1179 $sql .=
", '".$this->db->escape($this->batch_mask).
"'";
1180 $sql .=
", ".($this->fk_unit > 0 ? ((int) $this->fk_unit) :
'NULL');
1181 $sql .=
", '".$this->db->escape((
string) $this->mandatory_period).
"'";
1182 $sql .=
", ".((int) $this->stockable_product);
1183 if (!empty($this->default_vat_code)) $sql.=
", '".$this->db->escape($this->default_vat_code).
"'";
1185 dol_syslog(get_class($this).
"::Create", LOG_DEBUG);
1187 $result = $this->db->query($sql);
1189 $id = $this->db->last_insert_id($this->db->prefix().
"product");
1193 $this->
price = $price_ht;
1194 $this->price_ttc = $price_ttc;
1195 $this->price_min = $price_min_ht;
1196 $this->price_min_ttc = $price_min_ttc;
1200 if ($this->
update($id, $user, 1,
'add') <= 0) {
1205 $this->error = $this->db->lasterror();
1210 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " .((int) $this->id) .
" AND entity = " . ((
int)
$conf->entity));
1212 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1213 $sql .=
" fk_product";
1215 $sql .=
", accountancy_code_buy";
1216 $sql .=
", accountancy_code_buy_intra";
1217 $sql .=
", accountancy_code_buy_export";
1218 $sql .=
", accountancy_code_sell";
1219 $sql .=
", accountancy_code_sell_intra";
1220 $sql .=
", accountancy_code_sell_export";
1221 $sql .=
") VALUES (";
1223 $sql .=
", " . ((int)
$conf->entity);
1224 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1225 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1226 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1227 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1228 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1229 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1231 $result = $this->db->query($sql);
1234 $this->error =
'ErrorFailedToInsertAccountancyForEntity';
1239 $this->error =
'ErrorFailedToGetInsertedId';
1243 $this->error = $this->db->lasterror();
1247 $langs->load(
"products");
1249 $this->error =
"ErrorProductAlreadyExists";
1250 dol_syslog(get_class($this).
"::Create fails, ref ".$this->
ref.
" already exists");
1254 $this->error = $this->db->lasterror();
1257 if (!$error && !$notrigger) {
1259 $result = $this->
call_trigger(
'PRODUCT_CREATE', $user);
1267 $this->db->commit();
1270 $this->db->rollback();
1274 $this->db->rollback();
1275 dol_syslog(get_class($this).
"::Create fails verify ".implode(
',', $this->errors), LOG_WARNING);
1291 $this->errors = array();
1294 $this->
ref = trim($this->
ref);
1297 $this->errors[] =
'ErrorBadRef';
1301 $arrayofnonnegativevalue = array(
'weight' =>
'Weight',
'width' =>
'Width',
'height' =>
'Height',
'length' =>
'Length',
'surface' =>
'Surface',
'volume' =>
'Volume');
1302 foreach ($arrayofnonnegativevalue as $key => $value) {
1303 if (property_exists($this, $key) && !empty($this->$key) && ($this->$key < 0)) {
1304 $langs->loadLangs(array(
"main",
"other"));
1305 $this->error = $langs->trans(
"FieldCannotBeNegative", $langs->transnoentitiesnoconv($value));
1306 $this->errors[] = $this->error;
1311 $rescode = $this->
check_barcode($this->barcode, $this->barcode_type_code);
1313 if ($rescode == -1) {
1314 $this->errors[] =
'ErrorBadBarCodeSyntax';
1315 } elseif ($rescode == -2) {
1316 $this->errors[] =
'ErrorBarCodeRequired';
1317 } elseif ($rescode == -3) {
1319 $this->errors[] =
'ErrorBarCodeAlreadyUsed';
1347 $dirsociete = array_merge(array(
'/core/modules/barcode/'),
$conf->modules_parts[
'barcode']);
1348 foreach ($dirsociete as $dirroot) {
1355 $mod =
new $module();
1356 '@phan-var-force ModeleNumRefBarCode $mod';
1358 dol_syslog(get_class($this).
"::check_barcode value=".$valuetotest.
" type=".$typefortest.
" module=".$module);
1359 $result = $mod->verif($this->db, $valuetotest, $this, 0, $typefortest);
1377 public function update($id, $user, $notrigger = 0, $action =
'update', $updatetype =
false)
1379 global $langs,
$conf, $hookmanager;
1384 if (!$this->label) {
1385 $this->label =
'MISSING LABEL';
1390 $this->
ref = trim($this->
ref);
1394 $this->label = trim($this->label);
1396 $this->note_private = (isset($this->note_private) ? trim($this->note_private) :
null);
1397 $this->note_public = (isset($this->note_public) ? trim($this->note_public) :
null);
1398 $this->net_measure =
price2num($this->net_measure);
1399 $this->net_measure_units = (!is_numeric($this->net_measure_units) ? null : (int) $this->net_measure_units);
1400 $this->weight =
price2num($this->weight);
1401 $this->weight_units = (!is_numeric($this->weight_units) ? null : (int) $this->weight_units);
1402 $this->length =
price2num($this->length);
1403 $this->length_units = (!is_numeric($this->length_units) ? null : (int) $this->length_units);
1405 $this->width_units = (!is_numeric($this->width_units) ? null : (int) $this->width_units);
1406 $this->height =
price2num($this->height);
1407 $this->height_units = (!is_numeric($this->height_units) ? null : (int) $this->height_units);
1408 $this->surface =
price2num($this->surface);
1409 $this->surface_units = (!is_numeric($this->surface_units) ? null : (int) $this->surface_units);
1410 $this->volume =
price2num($this->volume);
1411 $this->volume_units = (!is_numeric($this->volume_units) ? null : (int) $this->volume_units);
1414 if (is_numeric($this->length_units)) {
1415 $this->width_units = $this->length_units;
1417 if (is_numeric($this->length_units)) {
1418 $this->height_units = $this->length_units;
1422 if (empty($this->surface) && !empty($this->length) && !empty($this->width) && $this->length_units == $this->width_units) {
1423 $this->surface = (float) $this->length * (
float) $this->width;
1426 if (empty($this->volume) && !empty($this->surface) && !empty($this->height) && $this->length_units == $this->height_units) {
1427 $this->volume = $this->surface * (float) $this->height;
1431 if (empty($this->tva_tx)) {
1434 if (empty($this->tva_npr)) {
1437 if (empty($this->localtax1_tx)) {
1438 $this->localtax1_tx = 0;
1440 if (empty($this->localtax2_tx)) {
1441 $this->localtax2_tx = 0;
1443 if (empty($this->localtax1_type)) {
1444 $this->localtax1_type =
'0';
1446 if (empty($this->localtax2_type)) {
1447 $this->localtax2_type =
'0';
1449 if (empty($this->
status)) {
1452 if (empty($this->status_buy)) {
1453 $this->status_buy = 0;
1456 if (empty($this->country_id)) {
1457 $this->country_id = 0;
1459 if (empty($this->country_id) && !empty($this->country_code)) {
1460 $country_id =
getCountry($this->country_code,
'3');
1461 $this->country_id = is_int($country_id) ? $country_id : 0;
1464 if (empty($this->state_id)) {
1465 $this->state_id = 0;
1468 if (empty($this->stockable_product)) {
1469 $this->stockable_product = 0;
1473 $this->barcode = (empty($this->barcode) ?
'' : trim($this->barcode));
1475 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
1476 $this->accountancy_code_buy_intra = (!empty($this->accountancy_code_buy_intra) ? trim($this->accountancy_code_buy_intra) :
'');
1477 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
1478 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
1479 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
1480 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
1486 if ($action !=
'add') {
1487 $result = $this->
verify();
1496 if (is_null($this->oldcopy) || (is_object($this->oldcopy) && empty($this->oldcopy->id))) {
1501 if ($this->
hasbatch() && !$this->oldcopy->hasbatch()) {
1503 $valueforundefinedlot =
'000000';
1508 dol_syslog(
"Flag batch of product id=".$this->
id.
" is set to ON, so we will create missing records into product_batch");
1511 foreach ($this->stock_warehouse as $idW => $ObjW) {
1513 foreach ($ObjW->detail_batch as $detail) {
1514 if ($detail->batch == $valueforundefinedlot || $detail->batch ==
'Undefined') {
1516 $sqlclean =
"DELETE FROM ".$this->db->prefix().
"product_batch WHERE batch in('Undefined', '".$this->db->escape($valueforundefinedlot).
"') AND fk_product_stock = ".((int) $ObjW->id);
1517 $result = $this->db->query($sqlclean);
1525 $qty_batch += $detail->qty;
1529 if ($ObjW->real != $qty_batch) {
1531 $ObjBatch->batch = $valueforundefinedlot;
1532 $ObjBatch->qty = ($ObjW->real - $qty_batch);
1533 $ObjBatch->fk_product_stock = (int) $ObjW->id;
1535 if ($ObjBatch->create($user, 1) < 0) {
1537 $this->errors = $ObjBatch->errors;
1542 if ($ObjLot->fetch(0, $this->id, $valueforundefinedlot) == 0) {
1543 $ObjLot->fk_product = $this->id;
1544 $ObjLot->entity = (int) $this->entity;
1545 $ObjLot->fk_user_creat = $user->id;
1546 $ObjLot->batch = $valueforundefinedlot;
1547 if ($ObjLot->create($user, 1) < 0) {
1549 $this->errors = $ObjLot->errors;
1558 if ($this->barcode == -1) {
1559 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1562 $sql =
"UPDATE ".$this->db->prefix().
"product";
1563 $sql .=
" SET label = '".$this->db->escape($this->label).
"'";
1566 $sql .=
", fk_product_type = ".((int) $this->
type);
1569 $sql .=
", ref = '".$this->db->escape($this->
ref).
"'";
1570 $sql .=
", ref_ext = ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1571 $sql .=
", default_vat_code = ".($this->default_vat_code ?
"'".$this->db->escape($this->default_vat_code).
"'" :
"null");
1572 $sql .=
", tva_tx = ".((float) $this->tva_tx);
1573 $sql .=
", recuperableonly = ".((int) $this->tva_npr);
1574 $sql .=
", localtax1_tx = ".((float) $this->localtax1_tx);
1575 $sql .=
", localtax2_tx = ".((float) $this->localtax2_tx);
1576 $sql .=
", localtax1_type = ".($this->localtax1_type !=
'' ?
"'".$this->db->escape($this->localtax1_type).
"'" :
"'0'");
1577 $sql .=
", localtax2_type = ".($this->localtax2_type !=
'' ?
"'".$this->db->escape($this->localtax2_type).
"'" :
"'0'");
1579 $sql .=
", barcode = ".(empty($this->barcode) ?
"null" :
"'".$this->db->escape($this->barcode).
"'");
1580 $sql .=
", fk_barcode_type = ".(empty($this->barcode_type) ?
"null" : $this->db->escape((
string) $this->barcode_type));
1582 $sql .=
", tosell = ".(int) $this->
status;
1583 $sql .=
", tobuy = ".(int) $this->status_buy;
1584 $sql .=
", tobatch = ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : (int) $this->status_batch);
1585 $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);
1586 $sql .=
", batch_mask = '".$this->db->escape($this->batch_mask).
"'";
1588 $sql .=
", finished = ".((!isset($this->finished) || $this->finished < 0 || $this->finished ===
'') ?
"null" : (int) $this->finished);
1589 $sql .=
", fk_default_bom = ".((!isset($this->fk_default_bom) || $this->fk_default_bom < 0 || $this->fk_default_bom ==
'') ?
"null" : (int) $this->fk_default_bom);
1590 $sql .=
", net_measure = ".($this->net_measure !=
'' ?
"'".$this->db->escape($this->net_measure).
"'" :
'null');
1591 $sql .=
", net_measure_units = ".((string) $this->net_measure_units !=
'' ? ((
int) $this->net_measure_units) :
'null');
1592 $sql .=
", weight = ".($this->weight !=
'' ?
"'".$this->db->escape($this->weight).
"'" :
'null');
1593 $sql .=
", weight_units = ".((string) $this->weight_units !=
'' ? ((
int) $this->weight_units) :
'null');
1594 $sql .=
", length = ".($this->length !=
'' ?
"'".$this->db->escape($this->length).
"'" :
'null');
1595 $sql .=
", length_units = ".((string) $this->length_units !=
'' ? ((
int) $this->length_units) :
'null');
1596 $sql .=
", width= ".($this->width !=
'' ?
"'".$this->db->escape($this->width).
"'" :
'null');
1597 $sql .=
", width_units = ".((string) $this->width_units !=
'' ? ((
int) $this->width_units) :
'null');
1598 $sql .=
", height = ".($this->height !=
'' ?
"'".$this->db->escape($this->height).
"'" :
'null');
1599 $sql .=
", height_units = ".((string) $this->height_units !=
'' ? ((
int) $this->height_units) :
'null');
1600 $sql .=
", surface = ".($this->surface !=
'' ?
"'".$this->db->escape($this->surface).
"'" :
'null');
1601 $sql .=
", surface_units = ".((string) $this->surface_units !=
'' ? ((
int) $this->surface_units) :
'null');
1602 $sql .=
", volume = ".($this->volume !=
'' ?
"'".$this->db->escape($this->volume).
"'" :
'null');
1603 $sql .=
", volume_units = ".((string) $this->volume_units !=
'' ? ((
int) $this->volume_units) :
'null');
1604 $sql .=
", fk_default_warehouse = ".($this->fk_default_warehouse > 0 ? ((int) $this->fk_default_warehouse) :
'null');
1605 $sql .=
", fk_default_workstation = ".($this->fk_default_workstation > 0 ? ((int) $this->fk_default_workstation) :
'null');
1606 $sql .=
", seuil_stock_alerte = ".((isset($this->seuil_stock_alerte) && is_numeric($this->seuil_stock_alerte)) ? (
float) $this->seuil_stock_alerte :
'null');
1607 $sql .=
", description = '".$this->db->escape($this->
description).
"'";
1608 $sql .=
", url = ".($this->url ?
"'".$this->db->escape($this->url).
"'" :
'null');
1609 $sql .=
", customcode = '".$this->db->escape($this->customcode).
"'";
1610 $sql .=
", fk_country = ".($this->country_id > 0 ? (int) $this->country_id :
'null');
1611 $sql .=
", fk_state = ".($this->state_id > 0 ? (int) $this->state_id :
'null');
1612 $sql .=
", lifetime = ".($this->lifetime > 0 ? (int) $this->lifetime :
'null');
1613 $sql .=
", qc_frequency = ".($this->qc_frequency > 0 ? (int) $this->qc_frequency :
'null');
1614 $sql .=
", note = ".(isset($this->note_private) ?
"'".$this->db->escape($this->note_private).
"'" :
'null');
1615 $sql .=
", note_public = ".(isset($this->note_public) ?
"'".$this->db->escape($this->note_public).
"'" :
'null');
1616 $sql .=
", duration = '".$this->db->escape($this->duration_value.$this->duration_unit).
"'";
1618 $sql .=
", accountancy_code_buy = '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1619 $sql .=
", accountancy_code_buy_intra = '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1620 $sql .=
", accountancy_code_buy_export = '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1621 $sql .=
", accountancy_code_sell= '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1622 $sql .=
", accountancy_code_sell_intra= '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1623 $sql .=
", accountancy_code_sell_export= '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1625 $sql .=
", desiredstock = ".((isset($this->desiredstock) && is_numeric($this->desiredstock)) ? (
float) $this->desiredstock :
"null");
1626 $sql .=
", cost_price = ".($this->cost_price !=
'' ? ((float) $this->cost_price) :
'null');
1627 $sql .=
", fk_unit= ".(!$this->fk_unit ?
'NULL' : (int) $this->fk_unit);
1628 $sql .=
", price_autogen = ".(!$this->price_autogen ? 0 : 1);
1629 $sql .=
", fk_price_expression = ".($this->fk_price_expression != 0 ? (int) $this->fk_price_expression :
'NULL');
1630 $sql .=
", fk_user_modif = ".($user->id > 0 ? (int) $user->id :
'NULL');
1631 $sql .=
", mandatory_period = ".((int) $this->mandatory_period);
1632 $sql .=
", stockable_product = ".(int) $this->stockable_product;
1634 $sql .=
", packaging = ".(float) $this->packaging;
1638 $sql .=
" WHERE rowid = ".((int) $id);
1640 dol_syslog(get_class($this).
"::update", LOG_DEBUG);
1642 $resql = $this->db->query($sql);
1649 $this->db->rollback();
1658 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " . ((
int) $this->id) .
" AND entity = " . ((
int)
$conf->entity));
1660 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1661 $sql .=
" fk_product";
1663 $sql .=
", accountancy_code_buy";
1664 $sql .=
", accountancy_code_buy_intra";
1665 $sql .=
", accountancy_code_buy_export";
1666 $sql .=
", accountancy_code_sell";
1667 $sql .=
", accountancy_code_sell_intra";
1668 $sql .=
", accountancy_code_sell_export";
1669 $sql .=
") VALUES (";
1670 $sql .= ((int) $this->
id);
1671 $sql .=
", " . ((int)
$conf->entity);
1672 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1673 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1674 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1675 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1676 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1677 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1679 $result = $this->db->query($sql);
1682 $this->error =
'ErrorFailedToUpdateAccountancyForEntity';
1686 if (!$this->
hasbatch() && $this->oldcopy->hasbatch()) {
1688 $sql =
'SELECT pb.qty, ps.fk_entrepot, pb.batch FROM '.MAIN_DB_PREFIX.
'product_batch as pb';
1689 $sql .=
' INNER JOIN '.MAIN_DB_PREFIX.
'product_stock as ps ON (ps.rowid = pb.fk_product_stock)';
1690 $sql .=
' WHERE ps.fk_product = '.(int) $this->
id;
1692 $resql = $this->db->query($sql);
1696 while ($obj = $this->db->fetch_object($resql)) {
1698 $fk_entrepot = $obj->fk_entrepot;
1702 $batch = $obj->batch;
1705 $addOremove = $value > 0 ? 1 : 0;
1706 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1707 $res = $this->
correct_stock_batch($user, $fk_entrepot, abs($value), $addOremove, $label, $price, $dlc, $dluo, $batch, $inventorycode,
'',
null, 0,
null,
true);
1710 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1711 $res = $this->
correct_stock($user, $fk_entrepot, abs($value), (
int) empty($addOremove), $label, $price, $inventorycode,
'',
null, 0);
1730 if (!$error && !$notrigger) {
1732 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
1739 if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) {
1741 if (
$conf->product->dir_output) {
1744 if (file_exists($olddir)) {
1748 $res = @rename($olddir, $newdir);
1750 $langs->load(
"errors");
1751 $this->error = $langs->trans(
'ErrorFailToRenameDir', $olddir, $newdir);
1755 require_once DOL_DOCUMENT_ROOT .
'/ecm/class/ecmfiles.class.php';
1756 $ecmfiles =
new EcmFiles($this->db);
1757 $ecmfiles->updateAfterRename(
"produit/".
dol_sanitizeFileName($this->oldcopy->ref),
"produit/".dol_sanitizeFileName($this->ref));
1764 if (isModEnabled(
'variants')) {
1765 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1769 foreach ($comb->fetchAllByFkProductParent($this->id) as $currcomb) {
1770 $currcomb->updateProperties($this, $user);
1774 $this->db->commit();
1777 $this->db->rollback();
1781 if ($this->db->errno() ==
'DB_ERROR_RECORD_ALREADY_EXISTS') {
1782 $langs->load(
"errors");
1783 if (empty(
$conf->barcode->enabled) || empty($this->barcode)) {
1784 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductAlreadyExists", $this->
ref);
1786 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductBarCodeAlreadyExists", $this->barcode);
1788 $this->errors[] = $this->error;
1789 $this->db->rollback();
1792 $this->error = $langs->trans(
"Error").
" : ".$this->db->error().
" - ".$sql;
1793 $this->errors[] = $this->error;
1794 $this->db->rollback();
1799 $this->db->rollback();
1800 dol_syslog(get_class($this).
"::Update fails verify ".implode(
',', $this->errors), LOG_WARNING);
1812 public function delete(
User $user, $notrigger = 0)
1815 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
1820 if (empty($this->
id)) {
1821 $this->error =
"Object must be fetched before calling delete";
1824 if (($this->
isProduct() && !$user->
hasRight(
'produit',
'supprimer')) || ($this->isService() && !$user->hasRight(
'service',
'supprimer'))) {
1825 $this->error =
"ErrorForbidden";
1830 if (empty($objectisused)) {
1833 if (!$error && empty($notrigger)) {
1835 $result = $this->
call_trigger(
'PRODUCT_DELETE', $user);
1844 $sql =
"DELETE FROM ".$this->db->prefix().
'product_batch';
1845 $sql .=
" WHERE fk_product_stock IN (";
1846 $sql .=
"SELECT rowid FROM ".$this->db->prefix().
'product_stock';
1847 $sql .=
" WHERE fk_product = ".((int) $this->
id).
")";
1849 $result = $this->db->query($sql);
1852 $this->errors[] = $this->db->lasterror();
1858 $elements = array(
'product_fournisseur_price',
'product_price',
'product_lang',
'categorie_product',
'product_stock',
'product_customer_price',
'product_lot');
1859 foreach ($elements as $table) {
1861 $sql =
"DELETE FROM ".$this->db->prefix().$table;
1862 $sql .=
" WHERE fk_product = ".(int) $this->
id;
1864 $result = $this->db->query($sql);
1867 $this->errors[] = $this->db->lasterror();
1874 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1875 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination2ValuePair.class.php';
1880 if ($prodcomb->deleteByFkProductParent($user, $this->id) < 0) {
1882 $this->errors[] =
'Error deleting combinations';
1886 if (!$error && ($prodcomb->fetchByFkProductChild($this->id) > 0) && ($prodcomb->delete($user) < 0)) {
1888 $this->errors[] =
'Error deleting child combination';
1894 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
1895 $sql .=
" WHERE fk_product_pere = ".(int) $this->
id.
" OR fk_product_fils = ".(
int) $this->id;
1897 $result = $this->db->query($sql);
1900 $this->errors[] = $this->db->lasterror();
1909 dol_syslog(get_class($this).
"::delete error -4 ".$this->error, LOG_ERR);
1915 $sqlz =
"DELETE FROM ".$this->db->prefix().
"product";
1916 $sqlz .=
" WHERE rowid = ".(int) $this->
id;
1918 $resultz = $this->db->query($sqlz);
1921 $this->errors[] = $this->db->lasterror();
1937 if ($conf->product->dir_output) {
1938 $dir =
$conf->product->dir_output.
"/".$ref;
1939 if (file_exists($dir)) {
1942 $this->errors[] =
'ErrorFailToDeleteDir';
1950 $this->db->commit();
1953 foreach ($this->errors as $errmsg) {
1954 dol_syslog(get_class($this).
"::delete ".$errmsg, LOG_ERR);
1955 $this->error .= ($this->error ?
', '.$errmsg : $errmsg);
1957 $this->db->rollback();
1961 $this->error =
"ErrorRecordIsUsedCantDelete";
1975 $sellByLabel = $langs->trans(
'SellByDate');
1976 $eatByLabel = $langs->trans(
'EatByDate');
1978 self::SELL_OR_EAT_BY_MANDATORY_ID_NONE => $langs->trans(
'BatchSellOrEatByMandatoryNone'),
1979 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY => $sellByLabel,
1980 self::SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY => $eatByLabel,
1981 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT => $langs->trans(
'BatchSellOrEatByMandatoryAll', $sellByLabel, $eatByLabel),
1992 $sellOrEatByMandatoryLabel =
'';
1995 if (isset($sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory])) {
1996 $sellOrEatByMandatoryLabel = $sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory];
1999 return $sellOrEatByMandatoryLabel;
2012 $langs_available = $langs->get_available_languages(DOL_DOCUMENT_ROOT, 0, 2);
2013 $current_lang = $langs->getDefaultLang();
2015 foreach ($langs_available as $key => $value) {
2016 if ($key == $current_lang) {
2017 $sql =
"SELECT rowid";
2018 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2019 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2020 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
2022 $result = $this->db->query($sql);
2024 if ($this->db->num_rows($result)) {
2025 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
2027 $sql2 .=
" label='".$this->db->escape($this->label).
"',";
2028 $sql2 .=
" description='".$this->db->escape($this->
description).
"'";
2030 $sql2 .=
", note='".$this->db->escape($this->other).
"'";
2032 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
2034 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
2039 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->label).
"',";
2040 $sql2 .=
" '".$this->db->escape($this->
description).
"'";
2042 $sql2 .=
", '".$this->db->escape($this->other).
"'";
2046 dol_syslog(get_class($this).
'::setMultiLangs key = current_lang = '.$key);
2047 if (!$this->db->query($sql2)) {
2048 $this->error = $this->db->lasterror();
2051 } elseif (isset($this->multilangs[$key])) {
2052 if (empty($this->multilangs[$key][
"label"])) {
2053 $this->errors[] = $key .
' : ' . $langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Label"));
2057 $sql =
"SELECT rowid";
2058 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2059 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2060 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
2062 $result = $this->db->query($sql);
2064 if ($this->db->num_rows($result)) {
2065 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
2067 $sql2 .=
" label = '".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
2068 $sql2 .=
" description = '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
2071 $sql2 .=
", note = '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
2073 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
2075 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
2080 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
2081 $sql2 .=
" '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
2084 $sql2 .=
", '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
2090 if ($this->multilangs[
"$key"][
"label"] || $this->multilangs[
"$key"][
"description"]) {
2091 if (!$this->db->query($sql2)) {
2092 $this->error = $this->db->lasterror();
2102 $result = $this->
call_trigger(
'PRODUCT_SET_MULTILANGS', $user);
2104 $this->error = $this->db->lasterror();
2122 $sql =
"DELETE FROM ".$this->db->prefix().
"product_lang";
2123 $sql .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($langtodelete).
"'";
2125 dol_syslog(get_class($this).
'::delMultiLangs', LOG_DEBUG);
2126 $result = $this->db->query($sql);
2129 $result = $this->
call_trigger(
'PRODUCT_DEL_MULTILANGS', $user);
2131 $this->error = $this->db->lasterror();
2132 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
2136 unset($this->multilangs[$langtodelete]);
2139 $this->error = $this->db->lasterror();
2140 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
2161 if ($type ==
'buy') {
2162 $field =
'accountancy_code_buy';
2163 } elseif ($type ==
'buy_intra') {
2164 $field =
'accountancy_code_buy_intra';
2165 } elseif ($type ==
'buy_export') {
2166 $field =
'accountancy_code_buy_export';
2167 } elseif ($type ==
'sell') {
2168 $field =
'accountancy_code_sell';
2169 } elseif ($type ==
'sell_intra') {
2170 $field =
'accountancy_code_sell_intra';
2171 } elseif ($type ==
'sell_export') {
2172 $field =
'accountancy_code_sell_export';
2177 $sql =
"UPDATE ".$this->db->prefix().$this->table_element.
" SET ";
2178 $sql .=
"$field = '".$this->db->escape($value).
"'";
2179 $sql .=
" WHERE rowid = ".((int) $this->
id);
2182 $resql = $this->db->query($sql);
2186 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
2193 $this->db->rollback();
2197 $this->$field = $value;
2199 $this->db->commit();
2202 $this->error = $this->db->lasterror();
2203 $this->db->rollback();
2217 $current_lang = $langs->getDefaultLang();
2219 $sql =
"SELECT lang, label, description, note as other";
2220 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2221 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2223 $result = $this->db->query($sql);
2225 while ($obj = $this->db->fetch_object($result)) {
2227 if ($obj->lang == $current_lang) {
2228 $this->label = $obj->label;
2230 $this->other = $obj->other;
2232 $this->multilangs[(string) $obj->lang][
"label"] = $obj->label;
2233 $this->multilangs[(string) $obj->lang][
"description"] = $obj->description;
2234 $this->multilangs[(string) $obj->lang][
"other"] = $obj->other;
2238 $this->error =
"Error: ".$this->db->lasterror().
" - ".$sql;
2251 $testExit = array(
'multiprices',
'multiprices_ttc',
'multiprices_base_type',
'multiprices_min',
'multiprices_min_ttc',
'multiprices_tva_tx',
'multiprices_recuperableonly');
2253 foreach ($testExit as $field) {
2254 if (!isset($this->$field)) {
2257 $tmparray = $this->$field;
2258 if (!isset($tmparray[$level])) {
2264 'level' => $level ? $level : 1,
2265 'multiprices' => (float) $this->multiprices[$level],
2266 'multiprices_ttc' => (
float) $this->multiprices_ttc[$level],
2267 'multiprices_base_type' => $this->multiprices_base_type[$level],
2268 'multiprices_min' => (float) $this->multiprices_min[$level],
2269 'multiprices_min_ttc' => (
float) $this->multiprices_min_ttc[$level],
2270 'multiprices_tva_tx' => (float) $this->multiprices_tva_tx[$level],
2271 'multiprices_recuperableonly' => (
float) $this->multiprices_recuperableonly[$level],
2294 if (empty($this->price_by_qty)) {
2295 $this->price_by_qty = 0;
2299 $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,";
2300 $sql .=
" localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, price_min,price_min_ttc,price_by_qty,entity,fk_price_expression) ";
2301 $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).
"'").
", ".((float)
price2num($this->
price)).
", ".((
float)
price2num($this->price_ttc)).
",'".$this->db->escape($this->price_base_type).
"',".((int) $this->
status).
", ".((float)
price2num($this->tva_tx)).
", ".($this->default_vat_code ? (
"'".$this->db->escape($this->default_vat_code).
"'") :
"null").
", ".((
int) $this->tva_npr).
",";
2302 $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');
2305 dol_syslog(get_class($this).
"::_log_price", LOG_DEBUG);
2306 $resql = $this->db->query($sql);
2308 $this->error = $this->db->lasterror();
2328 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price_by_qty";
2329 $sql .=
" WHERE fk_product_price = ".((int) $rowid);
2330 $resql = $this->db->query($sql);
2332 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price";
2333 $sql .=
" WHERE rowid=".((int) $rowid);
2334 $resql = $this->db->query($sql);
2338 $this->error = $this->db->lasterror();
2353 public function getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp = 0)
2355 global $hookmanager, $action;
2358 if (is_object($hookmanager)) {
2359 $parameters = array(
'thirdparty_seller' => $thirdparty_seller,
'thirdparty_buyer' => $thirdparty_buyer,
'pqp' => $pqp);
2361 $reshook = $hookmanager->executeHooks(
'getSellPrice', $parameters, $this, $action);
2363 return $hookmanager->resArray;
2368 $tva_tx =
get_default_tva($thirdparty_seller, $thirdparty_buyer, $this->
id);
2369 $tva_npr =
get_default_npr($thirdparty_seller, $thirdparty_buyer, $this->
id);
2370 if (empty($tva_tx)) {
2374 $pu_ht = $this->price;
2375 $pu_ttc = $this->price_ttc;
2376 $price_min = $this->price_min;
2377 $price_min_ttc = $this->price_min_ttc;
2378 $price_base_type = $this->price_base_type;
2382 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2386 $filter = array(
't.fk_product' => (
string) $this->
id,
't.fk_soc' => (
string) $thirdparty_buyer->id);
2389 $pricebycustomerexist =
false;
2390 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2392 if (count($prodcustprice->lines) > 0) {
2393 $date_now = (int) floor(
dol_now() / 86400) * 86400;
2394 foreach ($prodcustprice->lines as $k => $custprice_line) {
2395 if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
2396 $pricebycustomerexist =
true;
2397 $pu_ht =
price($custprice_line->price);
2398 $price_min =
price($custprice_line->price_min);
2399 $price_min_ttc =
price($custprice_line->price_min_ttc);
2400 $pu_ttc =
price($custprice_line->price_ttc);
2401 $price_base_type = $custprice_line->price_base_type;
2402 $tva_tx = $custprice_line->tva_tx;
2403 if ($custprice_line->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2404 $tva_tx .=
' (' . $custprice_line->default_vat_code .
')';
2406 $tva_npr = $custprice_line->recuperableonly;
2407 if (empty($tva_tx)) {
2416 if (!$pricebycustomerexist && !empty($thirdparty_buyer->price_level)) {
2417 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
2418 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
2419 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
2420 $price_min_ttc = $this->multiprices_min_ttc[$thirdparty_buyer->price_level];
2421 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
2424 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2425 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2427 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2428 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2430 if (empty($tva_tx)) {
2435 } elseif (
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !empty($thirdparty_buyer->price_level)) {
2436 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
2437 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
2438 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
2439 $price_min_ttc = $this->multiprices_min_ttc[$thirdparty_buyer->price_level];
2440 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
2442 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2443 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2445 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2446 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2448 if (empty($tva_tx)) {
2454 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2458 $filter = array(
't.fk_product' => (
string) $this->
id,
't.fk_soc' => (
string) $thirdparty_buyer->id);
2460 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2462 if (count($prodcustprice->lines) > 0) {
2463 $date_now = (int) floor(
dol_now() / 86400) * 86400;
2464 foreach ($prodcustprice->lines as $k => $custprice_line) {
2465 if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
2466 $pu_ht =
price($custprice_line->price);
2467 $price_min =
price($custprice_line->price_min);
2468 $price_min_ttc =
price($custprice_line->price_min_ttc);
2469 $pu_ttc =
price($custprice_line->price_ttc);
2470 $price_base_type = $custprice_line->price_base_type;
2471 $tva_tx = $custprice_line->tva_tx;
2472 if ($custprice_line->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2473 $tva_tx .=
' (' . $custprice_line->default_vat_code .
')';
2475 $tva_npr = $custprice_line->recuperableonly;
2476 if (empty($tva_tx)) {
2486 if ($this->prices_by_qty[0]) {
2489 foreach ($this->prices_by_qty_list[0] as $priceforthequantityarray) {
2490 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2494 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2495 $pu_ht = $priceforthequantityarray[
'unitprice'];
2497 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2504 if ($this->prices_by_qty[$thirdparty_buyer->price_level]) {
2507 foreach ($this->prices_by_qty_list[$thirdparty_buyer->price_level] as $priceforthequantityarray) {
2508 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2512 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2513 $pu_ht = $priceforthequantityarray[
'unitprice'];
2515 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2522 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);
2539 public function get_buyprice($prodfournprice, $qty, $product_id = 0, $fourn_ref =
'', $fk_soc = 0)
2542 global $action, $hookmanager;
2545 if (is_object($hookmanager)) {
2546 $parameters = array(
2547 'prodfournprice' => $prodfournprice,
2549 'product_id' => $product_id,
2550 'fourn_ref' => $fourn_ref,
2551 'fk_soc' => $fk_soc,
2554 $reshook = $hookmanager->executeHooks(
'getBuyPrice', $parameters, $this, $action);
2556 return $hookmanager->resArray;
2563 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2564 $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,";
2565 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2566 $sql .=
" pfp.packaging";
2567 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2568 $sql .=
" WHERE pfp.rowid = ".((int) $prodfournprice);
2570 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2572 $sql .=
" ORDER BY pfp.quantity DESC";
2574 dol_syslog(get_class($this).
"::get_buyprice first search by prodfournprice/qty", LOG_DEBUG);
2575 $resql = $this->db->query($sql);
2577 $obj = $this->db->fetch_object($resql);
2578 if ($obj && $obj->quantity > 0) {
2579 if (isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2581 $prod_supplier->product_fourn_price_id = $obj->rowid;
2582 $prod_supplier->id = $obj->fk_product;
2583 $prod_supplier->fourn_qty = $obj->quantity;
2584 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2585 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2587 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2589 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2590 if ($price_result >= 0) {
2591 $obj->price = $price_result;
2594 $this->product_fourn_price_id = $obj->rowid;
2595 $this->buyprice = $obj->price;
2596 $this->fourn_pu = $obj->price / $obj->quantity;
2597 $this->fourn_price_base_type =
'HT';
2598 $this->fourn_socid = $obj->fk_soc;
2599 $this->ref_fourn = $obj->ref_supplier;
2600 $this->ref_supplier = $obj->ref_supplier;
2601 $this->desc_supplier = $obj->desc_supplier;
2602 $this->remise_percent = $obj->remise_percent;
2603 $this->vatrate_supplier = $obj->tva_tx;
2604 $this->default_vat_code_supplier = $obj->default_vat_code;
2605 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2606 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2607 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2608 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2609 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2611 $this->packaging = (float) $obj->packaging;
2613 $result = $obj->fk_product;
2617 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2618 $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,";
2619 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2620 $sql .=
" pfp.packaging";
2621 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2622 $sql .=
" WHERE 1 = 1";
2623 if ($product_id > 0) {
2624 $sql .=
" AND pfp.fk_product = ".((int) $product_id);
2626 if ($fourn_ref !=
'none') {
2627 $sql .=
" AND pfp.ref_fourn = '".$this->db->escape($fourn_ref).
"'";
2630 $sql .=
" AND pfp.fk_soc = ".((int) $fk_soc);
2633 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2635 $sql .=
" ORDER BY pfp.quantity DESC";
2638 dol_syslog(get_class($this).
"::get_buyprice second search from qty/ref/product_id", LOG_DEBUG);
2639 $resql = $this->db->query($sql);
2641 $obj = $this->db->fetch_object($resql);
2642 if ($obj && $obj->quantity > 0) {
2643 if (isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2645 $prod_supplier->product_fourn_price_id = $obj->rowid;
2646 $prod_supplier->id = $obj->fk_product;
2647 $prod_supplier->fourn_qty = $obj->quantity;
2648 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2649 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2651 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2653 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2654 if ($price_result >= 0) {
2655 $obj->price = $price_result;
2658 $this->product_fourn_price_id = $obj->rowid;
2659 $this->buyprice = $obj->price;
2660 $this->fourn_qty = $obj->quantity;
2661 $this->fourn_pu = $obj->price / $obj->quantity;
2662 $this->fourn_price_base_type =
'HT';
2663 $this->fourn_socid = $obj->fk_soc;
2664 $this->ref_fourn = $obj->ref_supplier;
2665 $this->ref_supplier = $obj->ref_supplier;
2666 $this->desc_supplier = $obj->desc_supplier;
2667 $this->remise_percent = $obj->remise_percent;
2668 $this->vatrate_supplier = $obj->tva_tx;
2669 $this->default_vat_code_supplier = $obj->default_vat_code;
2670 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2671 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2672 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2673 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2674 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2676 $this->packaging = (float) $obj->packaging;
2678 $result = $obj->fk_product;
2684 $this->error = $this->db->lasterror();
2689 $this->error = $this->db->lasterror();
2713 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)
2719 dol_syslog(get_class($this).
"::update_price id=".$id.
" newprice=".$newprice.
" newpricebase=".$newpricebase.
" newminprice=".$newminprice.
" level=".$level.
" npr=".$newnpr.
" newdefaultvatcode=".$newdefaultvatcode);
2722 if (empty($this->tva_tx)) {
2723 $this->tva_tx = 0.0;
2725 if (empty($newnpr)) {
2728 if (empty($newminprice)) {
2733 if ($newvat ===
null || $newvat ==
'') {
2734 $newvat = (float) $this->tva_tx;
2737 $localtaxtype1 =
'';
2738 $localtaxtype2 =
'';
2743 return $this->
generateMultiprices($user, $newprice, $newpricebase, $newvat, $newnpr, $newpbq);
2746 if (!empty($newminprice) && ($newminprice > $newprice)) {
2747 $this->error =
'ErrorPriceCantBeLowerThanMinPrice';
2751 if ($newprice === 0 || $newprice !==
'') {
2752 if ($newpricebase ==
'TTC') {
2753 $price_ttc = (float)
price2num($newprice,
'MU');
2754 $price = (float)
price2num($newprice) / (1 + ((float) $newvat / 100));
2755 $price = (float)
price2num($price,
'MU');
2757 if ((
string) $newminprice !=
'0') {
2758 $price_min_ttc = (float)
price2num($newminprice,
'MU');
2759 $price_min = (float)
price2num($newminprice) / (1 + ($newvat / 100));
2760 $price_min = (float)
price2num($price_min,
'MU');
2763 $price_min_ttc = 0.0;
2766 $price = (float)
price2num($newprice,
'MU');
2767 $price_ttc = ($newnpr != 1) ? (
float)
price2num($newprice) * (1 + ($newvat / 100)) : $price;
2768 $price_ttc = (float)
price2num($price_ttc,
'MU');
2770 if ((
string) $newminprice !=
'0') {
2771 $price_min = (float)
price2num($newminprice,
'MU');
2772 $price_min_ttc = (float)
price2num($newminprice) * (1 + ($newvat / 100));
2773 $price_min_ttc = (float)
price2num($price_min_ttc,
'MU');
2777 $price_min_ttc = 0.0;
2781 if (count($localtaxes_array) > 0) {
2782 $localtaxtype1 = $localtaxes_array[
'0'];
2783 $localtax1 = $localtaxes_array[
'1'];
2784 $localtaxtype2 = $localtaxes_array[
'2'];
2785 $localtax2 = $localtaxes_array[
'3'];
2788 if (!empty($newdefaultvatcode)) {
2791 $sql =
"SELECT t.rowid, t.code, t.recuperableonly as tva_npr, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
2792 $sql .=
" FROM ".MAIN_DB_PREFIX.
"c_tva as t, ".MAIN_DB_PREFIX.
"c_country as c";
2793 $sql .=
" WHERE t.fk_pays = c.rowid AND c.code = '".$this->db->escape($mysoc->country_code).
"'";
2794 $sql .=
" AND t.taux = ".((float) $newdefaultvatcode).
" AND t.active = 1";
2795 $sql .=
" AND t.code = '".$this->db->escape($newdefaultvatcode).
"'";
2796 $resql = $this->db->query($sql);
2798 $obj = $this->db->fetch_object($resql);
2800 $npr = $obj->tva_npr;
2801 $localtax1 = $obj->localtax1;
2802 $localtax2 = $obj->localtax2;
2803 $localtaxtype1 = $obj->localtax1_type;
2804 $localtaxtype2 = $obj->localtax2_type;
2809 $localtaxtype1 =
'0';
2811 $localtaxtype2 =
'0';
2815 if (empty($localtax1)) {
2818 if (empty($localtax2)) {
2826 $sql =
"UPDATE ".$this->db->prefix().
"product SET";
2827 $sql .=
" price_base_type = '".$this->db->escape($newpricebase).
"',";
2828 $sql .=
" price = ".(float) $price.
",";
2829 $sql .=
" price_ttc = ".(float) $price_ttc.
",";
2830 $sql .=
" price_min = ".(float) $price_min.
",";
2831 $sql .=
" price_min_ttc = ".(float) $price_min_ttc.
",";
2832 $sql .=
" localtax1_tx = ".($localtax1 >= 0 ? (float) $localtax1 :
'NULL').
",";
2833 $sql .=
" localtax2_tx = ".($localtax2 >= 0 ? (float) $localtax2 :
'NULL').
",";
2834 $sql .=
" localtax1_type = ".($localtaxtype1 !=
'' ?
"'".$this->db->escape($localtaxtype1).
"'" :
"'0'").
",";
2835 $sql .=
" localtax2_type = ".($localtaxtype2 !=
'' ?
"'".$this->db->escape($localtaxtype2).
"'" :
"'0'").
",";
2836 $sql .=
" default_vat_code = ".($newdefaultvatcode ?
"'".$this->db->escape($newdefaultvatcode).
"'" :
"null").
",";
2837 $sql .=
" price_label = ".(!empty($price_label) ?
"'".$this->db->escape($price_label).
"'" :
"null").
",";
2838 $sql .=
" tva_tx = ".(float)
price2num($newvat).
",";
2839 $sql .=
" recuperableonly = '".$this->db->escape((
string) $newnpr).
"'";
2840 $sql .=
" WHERE rowid = ".((int) $id);
2842 dol_syslog(get_class($this).
"::update_price", LOG_DEBUG);
2843 $resql = $this->db->query($sql);
2845 $this->multiprices[$level] = $price;
2846 $this->multiprices_ttc[$level] = $price_ttc;
2847 $this->multiprices_min[$level] = $price_min;
2848 $this->multiprices_min_ttc[$level] = $price_min_ttc;
2849 $this->multiprices_base_type[$level] = $newpricebase;
2850 $this->multiprices_default_vat_code[$level] = $newdefaultvatcode;
2851 $this->multiprices_tva_tx[$level] = $newvat;
2852 $this->multiprices_recuperableonly[$level] = $newnpr;
2854 $this->
price = $price;
2855 $this->price_label = $price_label;
2856 $this->price_ttc = $price_ttc;
2857 $this->price_min = $price_min;
2858 $this->price_min_ttc = $price_min_ttc;
2859 $this->price_base_type = $newpricebase;
2860 $this->default_vat_code = $newdefaultvatcode;
2861 $this->tva_tx = $newvat;
2862 $this->tva_npr = $newnpr;
2865 $this->localtax1_tx = $localtax1;
2866 $this->localtax2_tx = $localtax2;
2867 $this->localtax1_type = $localtaxtype1;
2868 $this->localtax2_type = $localtaxtype2;
2871 $this->price_by_qty = $newpbq;
2875 if (!empty(array_diff_assoc($newPriceData, $lastPriceData)) || !
getDolGlobalString(
'PRODUIT_MULTIPRICES')) {
2879 $this->level = $level;
2883 $result = $this->
call_trigger(
'PRODUCT_PRICE_MODIFY', $user);
2885 $this->db->rollback();
2891 $this->db->commit();
2893 $this->db->rollback();
2894 $this->error = $this->db->lasterror();
2913 $this->fk_price_expression = $expression_id;
2915 return $this->
update($this->
id, $user);
2930 public function fetch($id = 0, $ref =
'', $ref_ext =
'', $barcode =
'', $ignore_expression = 0, $ignore_price_load = 0, $ignore_lang_load = 0)
2932 include_once DOL_DOCUMENT_ROOT.
'/core/lib/company.lib.php';
2936 dol_syslog(get_class($this).
"::fetch id=".$id.
" ref=".$ref.
" ref_ext=".$ref_ext);
2939 if (!$id && !$ref && !$ref_ext && !$barcode) {
2940 $this->error =
'ErrorWrongParameters';
2941 dol_syslog(get_class($this).
"::fetch ".$this->error, LOG_ERR);
2945 $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,";
2946 $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,";
2947 $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,";
2948 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.last_main_doc,";
2949 $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,";
2951 $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,";
2953 $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,";
2958 $separatedEntityPMP =
false;
2959 $separatedStock =
false;
2960 $visibleWarehousesEntities =
$conf->entity;
2963 $checkPMPPerEntity = $this->db->query(
"SELECT pmp FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = ".((int) $id).
" AND entity = ".(
int)
$conf->entity);
2964 if ($this->db->num_rows($checkPMPPerEntity) > 0) {
2965 $separatedEntityPMP =
true;
2969 $separatedStock =
true;
2970 if (isset($mc->sharings[
'stock']) && !empty($mc->sharings[
'stock'])) {
2971 $visibleWarehousesEntities .=
"," . implode(
",", $mc->sharings[
'stock']);
2974 if ($separatedEntityPMP) {
2975 $sql .=
" ppe.pmp,";
2979 $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,";
2980 $sql .=
" p.fk_price_expression, p.price_autogen, p.stockable_product, p.model_pdf,";
2981 $sql .=
" p.price_label,";
2982 if ($separatedStock) {
2983 $sql .=
" SUM(sp.reel) as stock";
2987 $sql .=
" FROM ".$this->db->prefix().
"product as p";
2989 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int)
$conf->entity);
2991 if ($separatedStock) {
2992 $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).
"))";
2996 $sql .=
" WHERE p.rowid = ".((int) $id);
2998 $sql .=
" WHERE p.entity IN (".getEntity($this->element).
")";
3000 $sql .=
" AND p.ref = '".$this->db->escape($ref).
"'";
3001 } elseif ($ref_ext) {
3002 $sql .=
" AND p.ref_ext = '".$this->db->escape($ref_ext).
"'";
3003 } elseif ($barcode) {
3004 $sql .=
" AND p.barcode = '".$this->db->escape($barcode).
"'";
3007 if ($separatedStock) {
3008 $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,";
3009 $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,";
3010 $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,";
3011 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
3012 $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,";
3014 $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,";
3016 $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,";
3018 if ($separatedEntityPMP) {
3019 $sql .=
" ppe.pmp,";
3023 $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,";
3024 $sql .=
" p.fk_price_expression, p.price_autogen, p.stockable_product, p.model_pdf,";
3025 $sql .=
" p.price_label";
3026 if (!$separatedStock) {
3027 $sql .=
", p.stock";
3031 $resql = $this->db->query($sql);
3033 unset($this->oldcopy);
3035 if ($this->db->num_rows($resql) > 0) {
3036 $obj = $this->db->fetch_object($resql);
3038 $this->
id = $obj->rowid;
3039 $this->
ref = $obj->ref;
3040 $this->ref_ext = $obj->ref_ext;
3041 $this->label = $obj->label;
3043 $this->url = $obj->url;
3044 $this->note_public = $obj->note_public;
3045 $this->note_private = $obj->note_private;
3046 $this->note = $obj->note_private;
3048 $this->
type = $obj->fk_product_type;
3049 $this->price_label = $obj->price_label;
3050 $this->
status = $obj->tosell;
3051 $this->status_buy = $obj->tobuy;
3052 $this->status_batch = $obj->tobatch;
3053 $this->sell_or_eat_by_mandatory = $obj->sell_or_eat_by_mandatory;
3054 $this->batch_mask = $obj->batch_mask;
3056 $this->customcode = $obj->customcode;
3057 $this->country_id = $obj->fk_country;
3058 $this->country_code =
getCountry($this->country_id,
'2', $this->db);
3059 $this->state_id = $obj->fk_state;
3060 $this->lifetime = $obj->lifetime;
3061 $this->qc_frequency = $obj->qc_frequency;
3062 $this->
price = $obj->price;
3063 $this->price_ttc = $obj->price_ttc;
3064 $this->price_min = $obj->price_min;
3065 $this->price_min_ttc = $obj->price_min_ttc;
3066 $this->price_base_type = $obj->price_base_type;
3067 $this->cost_price = isset($obj->cost_price) ? (float) $obj->cost_price :
null;
3068 $this->default_vat_code = $obj->default_vat_code;
3069 $this->tva_tx = $obj->tva_tx;
3071 $this->tva_npr = $obj->tva_npr;
3073 $this->localtax1_tx = $obj->localtax1_tx;
3074 $this->localtax2_tx = $obj->localtax2_tx;
3075 $this->localtax1_type = $obj->localtax1_type;
3076 $this->localtax2_type = $obj->localtax2_type;
3078 $this->finished = $obj->finished;
3079 $this->fk_default_bom = $obj->fk_default_bom;
3081 $this->duration = $obj->duration;
3083 preg_match(
'/([\d.]+)(\w+)/', $obj->duration, $matches);
3084 $this->duration_value = !empty($matches[1]) ? (float) $matches[1] : 0;
3085 $this->duration_unit = !empty($matches[2]) ? (string) $matches[2] :
null;
3086 $this->canvas = $obj->canvas;
3087 $this->net_measure = $obj->net_measure;
3088 $this->net_measure_units = $obj->net_measure_units;
3089 $this->weight = $obj->weight;
3090 $this->weight_units = (is_null($obj->weight_units) ? 0 : $obj->weight_units);
3091 $this->length = $obj->length;
3092 $this->length_units = (is_null($obj->length_units) ? 0 : $obj->length_units);
3093 $this->width = $obj->width;
3094 $this->width_units = (is_null($obj->width_units) ? 0 : $obj->width_units);
3095 $this->height = $obj->height;
3096 $this->height_units = (is_null($obj->height_units) ? 0 : $obj->height_units);
3098 $this->surface = $obj->surface;
3099 $this->surface_units = (is_null($obj->surface_units) ? 0 : $obj->surface_units);
3100 $this->volume = $obj->volume;
3101 $this->volume_units = (is_null($obj->volume_units) ? 0 : $obj->volume_units);
3102 $this->barcode = $obj->barcode;
3103 $this->barcode_type = $obj->fk_barcode_type;
3105 $this->accountancy_code_buy = $obj->accountancy_code_buy;
3106 $this->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra;
3107 $this->accountancy_code_buy_export = $obj->accountancy_code_buy_export;
3108 $this->accountancy_code_sell = $obj->accountancy_code_sell;
3109 $this->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra;
3110 $this->accountancy_code_sell_export = $obj->accountancy_code_sell_export;
3112 $this->fk_default_warehouse = $obj->fk_default_warehouse;
3113 $this->fk_default_workstation = $obj->fk_default_workstation;
3114 $this->seuil_stock_alerte = $obj->seuil_stock_alerte;
3115 $this->desiredstock = $obj->desiredstock;
3116 $this->stock_reel = $obj->stock;
3117 $this->stockable_product = $obj->stockable_product;
3118 $this->pmp = $obj->pmp;
3120 $this->date_creation = $this->db->jdate($obj->datec);
3121 $this->date_modification = $this->db->jdate($obj->tms);
3123 $this->import_key = $obj->import_key;
3124 $this->entity = $obj->entity;
3126 $this->ref_ext = $obj->ref_ext;
3127 $this->fk_price_expression = $obj->fk_price_expression;
3128 $this->fk_unit = $obj->fk_unit;
3129 $this->price_autogen = $obj->price_autogen;
3130 $this->model_pdf = $obj->model_pdf;
3131 $this->last_main_doc = $obj->last_main_doc;
3133 $this->mandatory_period = $obj->mandatory_period;
3136 $this->packaging = (float) $obj->packaging;
3139 $this->db->free($resql);
3151 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
3152 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3153 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3154 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3155 $sql .=
" ,price_label";
3156 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3157 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3158 $sql .=
" AND price_level=".((int) $i);
3159 $sql .=
" AND fk_product = ".((int) $this->
id);
3160 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3162 $resql = $this->db->query($sql);
3164 $result = $this->db->fetch_array($resql);
3166 $this->multiprices[$i] = $result ? $result[
"price"] :
null;
3167 $this->multiprices_ttc[$i] = $result ? $result[
"price_ttc"] :
null;
3168 $this->multiprices_min[$i] = $result ? $result[
"price_min"] :
null;
3169 $this->multiprices_min_ttc[$i] = $result ? $result[
"price_min_ttc"] :
null;
3170 $this->multiprices_base_type[$i] = $result ? $result[
"price_base_type"] :
null;
3172 $this->multiprices_tva_tx[$i] = $result ? $result[
"tva_tx"].(!empty($result[
'default_vat_code']) ?
' ('.$result[
'default_vat_code'].
')' :
'') :
null;
3173 $this->multiprices_recuperableonly[$i] = $result ? $result[
"recuperableonly"] :
null;
3212 $this->error = $this->db->lasterror;
3218 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY') && empty($ignore_price_load)) {
3219 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3220 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid";
3221 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3222 $sql .=
" WHERE fk_product = ".((int) $this->
id);
3223 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3226 $resql = $this->db->query($sql);
3228 $result = $this->db->fetch_array($resql);
3232 $this->prices_by_qty[0] = $result[
"price_by_qty"];
3233 $this->prices_by_qty_id[0] = $result[
"rowid"];
3235 if ($this->prices_by_qty[0] == 1) {
3236 $sql =
"SELECT rowid,price, unitprice, quantity, remise_percent, remise, remise, price_base_type";
3237 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3238 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[0]);
3239 $sql .=
" ORDER BY quantity ASC";
3241 $resql = $this->db->query($sql);
3243 $resultat = array();
3245 while ($result = $this->db->fetch_array($resql)) {
3246 $resultat[$ii] = array();
3247 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3248 $resultat[$ii][
"price"] = $result[
"price"];
3249 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3250 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3251 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3253 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3256 $this->prices_by_qty_list[0] = $resultat;
3258 $this->error = $this->db->lasterror;
3264 $this->error = $this->db->lasterror;
3267 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') && empty($ignore_price_load)) {
3268 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
3269 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3270 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3271 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3272 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3273 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3274 $sql .=
" AND price_level=".((int) $i);
3275 $sql .=
" AND fk_product = ".((int) $this->
id);
3276 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3278 $resql = $this->db->query($sql);
3280 $this->error = $this->db->lasterror;
3283 $result = $this->db->fetch_array($resql);
3284 $this->multiprices[$i] = (!empty($result[
"price"]) ? $result[
"price"] : 0);
3285 $this->multiprices_ttc[$i] = (!empty($result[
"price_ttc"]) ? $result[
"price_ttc"] : 0);
3286 $this->multiprices_min[$i] = (!empty($result[
"price_min"]) ? $result[
"price_min"] : 0);
3287 $this->multiprices_min_ttc[$i] = (!empty($result[
"price_min_ttc"]) ? $result[
"price_min_ttc"] : 0);
3288 $this->multiprices_base_type[$i] = (!empty($result[
"price_base_type"]) ? $result[
"price_base_type"] :
'');
3290 $this->multiprices_tva_tx[$i] = (!empty($result[
"tva_tx"]) ? $result[
"tva_tx"] : 0);
3291 $this->multiprices_recuperableonly[$i] = (!empty($result[
"recuperableonly"]) ? $result[
"recuperableonly"] : 0);
3294 $this->prices_by_qty[$i] = (!empty($result[
"price_by_qty"]) ? $result[
"price_by_qty"] : 0);
3295 $this->prices_by_qty_id[$i] = (!empty($result[
"rowid"]) ? $result[
"rowid"] : 0);
3297 if ($this->prices_by_qty[$i] == 1) {
3298 $sql =
"SELECT rowid, price, unitprice, quantity, remise_percent, remise, price_base_type";
3299 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3300 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[$i]);
3301 $sql .=
" ORDER BY quantity ASC";
3303 $resql = $this->db->query($sql);
3305 $resultat = array();
3307 while ($result = $this->db->fetch_array($resql)) {
3308 $resultat[$ii] = array();
3309 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3310 $resultat[$ii][
"price"] = $result[
"price"];
3311 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3312 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3313 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3314 $resultat[$ii][
"remise"] = $result[
"remise"];
3315 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3318 $this->prices_by_qty_list[$i] = $resultat;
3320 $this->error = $this->db->lasterror;
3328 if (isModEnabled(
'dynamicprices') && !empty($this->fk_price_expression) && empty($ignore_expression)) {
3329 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
3331 $price_result = $priceparser->parseProduct($this);
3332 if ($price_result >= 0) {
3333 $this->
price = $price_result;
3335 $this->price_ttc = (float)
price2num($this->
price) * (1 + ($this->tva_tx / 100));
3336 $this->price_ttc = (float)
price2num($this->price_ttc,
'MU');
3342 $this->stock_warehouse = array();
3349 $this->error = $this->db->lasterror();
3364 global $user, $hookmanager, $action;
3368 foreach (array(
'toconsume',
'consumed',
'toproduce',
'produced') as $role) {
3369 $this->stats_mo[
'customers_'.$role] = 0;
3370 $this->stats_mo[
'nb_'.$role] = 0;
3371 $this->stats_mo[
'qty_'.$role] = 0;
3373 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3374 $sql .=
" SUM(mp.qty) as qty";
3375 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as c";
3376 $sql .=
" INNER JOIN ".$this->db->prefix().
"mrp_production as mp ON mp.fk_mo=c.rowid";
3377 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3378 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3381 $sql .=
" c.entity IN (".getEntity(
'mo').
")";
3383 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3384 $sql .=
" AND mp.role ='".$this->db->escape($role).
"'";
3386 $sql .=
" AND c.fk_soc = ".((int) $socid);
3389 $result = $this->db->query($sql);
3391 $obj = $this->db->fetch_object($result);
3392 $this->stats_mo[
'customers_'.$role] = $obj->nb_customers ? $obj->nb_customers : 0;
3393 $this->stats_mo[
'nb_'.$role] = $obj->nb ? $obj->nb : 0;
3394 $this->stats_mo[
'qty_'.$role] = $obj->qty ?
price2num($obj->qty,
'MS') : 0;
3396 $this->error = $this->db->error();
3401 if (!empty($error)) {
3405 $parameters = array(
'socid' => $socid);
3406 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3408 $this->stats_mo = $hookmanager->resArray[
'stats_mo'];
3424 global $hookmanager, $action;
3428 $this->stats_bom[
'nb_toproduce'] = 0;
3429 $this->stats_bom[
'nb_toconsume'] = 0;
3430 $this->stats_bom[
'qty_toproduce'] = 0;
3431 $this->stats_bom[
'qty_toconsume'] = 0;
3433 $sql =
"SELECT COUNT(DISTINCT b.rowid) as nb_toproduce,";
3434 $sql .=
" SUM(b.qty) as qty_toproduce";
3435 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3436 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom = b.rowid";
3438 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3439 $sql .=
" AND b.fk_product =".((int) $this->
id);
3440 $sql .=
" GROUP BY b.rowid";
3442 $result = $this->db->query($sql);
3444 $obj = $this->db->fetch_object($result);
3445 $this->stats_bom[
'nb_toproduce'] = !empty($obj->nb_toproduce) ? $obj->nb_toproduce : 0;
3446 $this->stats_bom[
'qty_toproduce'] = !empty($obj->qty_toproduce) ?
price2num($obj->qty_toproduce) : 0;
3448 $this->error = $this->db->error();
3452 $sql =
"SELECT COUNT(DISTINCT bl.rowid) as nb_toconsume,";
3453 $sql .=
" SUM(bl.qty) as qty_toconsume";
3454 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3455 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
3457 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3458 $sql .=
" AND bl.fk_product =".((int) $this->
id);
3460 $result = $this->db->query($sql);
3462 $obj = $this->db->fetch_object($result);
3463 $this->stats_bom[
'nb_toconsume'] = !empty($obj->nb_toconsume) ? $obj->nb_toconsume : 0;
3464 $this->stats_bom[
'qty_toconsume'] = !empty($obj->qty_toconsume) ?
price2num($obj->qty_toconsume) : 0;
3466 $this->error = $this->db->error();
3470 if (!empty($error)) {
3474 $parameters = array(
'socid' => $socid);
3475 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3477 $this->stats_bom = $hookmanager->resArray[
'stats_bom'];
3493 global $user, $hookmanager, $action;
3495 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_customers, COUNT(DISTINCT p.rowid) as nb,";
3496 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3497 $sql .=
" FROM ".$this->db->prefix().
"propaldet as pd";
3498 $sql .=
", ".$this->db->prefix().
"propal as p";
3499 $sql .=
", ".$this->db->prefix().
"societe as s";
3500 $sql .=
" WHERE p.rowid = pd.fk_propal";
3501 $sql .=
" AND p.fk_soc = s.rowid";
3502 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
3503 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3504 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3505 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $user->id);
3509 $sql .=
" AND p.fk_soc = ".((int) $socid);
3512 $result = $this->db->query($sql);
3514 $obj = $this->db->fetch_object($result);
3515 $this->stats_propale[
'customers'] = $obj->nb_customers;
3516 $this->stats_propale[
'nb'] = $obj->nb;
3517 $this->stats_propale[
'rows'] = $obj->nb_rows;
3518 $this->stats_propale[
'qty'] = $obj->qty ? $obj->qty : 0;
3523 if (is_array($TFather) && !empty($TFather)) {
3524 foreach ($TFather as &$fatherData) {
3525 $pFather =
new Product($this->db);
3526 $pFather->id = $fatherData[
'id'];
3527 $qtyCoef = $fatherData[
'qty'];
3529 if ($fatherData[
'incdec']) {
3530 $pFather->load_stats_propale($socid);
3532 $this->stats_propale[
'customers'] += $pFather->stats_propale[
'customers'];
3533 $this->stats_propale[
'nb'] += $pFather->stats_propale[
'nb'];
3534 $this->stats_propale[
'rows'] += $pFather->stats_propale[
'rows'];
3535 $this->stats_propale[
'qty'] += $pFather->stats_propale[
'qty'] * $qtyCoef;
3541 $parameters = array(
'socid' => $socid);
3542 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerProposal', $parameters, $this, $action);
3544 $this->stats_propale = $hookmanager->resArray[
'stats_propale'];
3549 $this->error = $this->db->error();
3565 global $user, $hookmanager, $action;
3567 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_suppliers, COUNT(DISTINCT p.rowid) as nb,";
3568 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3569 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as pd";
3570 $sql .=
", ".$this->db->prefix().
"supplier_proposal as p";
3571 $sql .=
", ".$this->db->prefix().
"societe as s";
3572 $sql .=
" WHERE p.rowid = pd.fk_supplier_proposal";
3573 $sql .=
" AND p.fk_soc = s.rowid";
3574 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
3575 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3576 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3577 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $user->id);
3581 $sql .=
" AND p.fk_soc = ".((int) $socid);
3584 $result = $this->db->query($sql);
3586 $obj = $this->db->fetch_object($result);
3587 $this->stats_proposal_supplier[
'suppliers'] = $obj->nb_suppliers;
3588 $this->stats_proposal_supplier[
'nb'] = $obj->nb;
3589 $this->stats_proposal_supplier[
'rows'] = $obj->nb_rows;
3590 $this->stats_proposal_supplier[
'qty'] = $obj->qty ? $obj->qty : 0;
3592 $parameters = array(
'socid' => $socid);
3593 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierProposal', $parameters, $this, $action);
3595 $this->stats_proposal_supplier = $hookmanager->resArray[
'stats_proposal_supplier'];
3600 $this->error = $this->db->error();
3618 global $user, $hookmanager, $action;
3620 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3621 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3622 $sql .=
" FROM ".$this->db->prefix().
"commandedet as cd";
3623 $sql .=
", ".$this->db->prefix().
"commande as c";
3624 $sql .=
", ".$this->db->prefix().
"societe as s";
3625 $sql .=
" WHERE c.rowid = cd.fk_commande";
3626 $sql .=
" AND c.fk_soc = s.rowid";
3627 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'commande').
")";
3628 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3629 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3630 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3633 $sql .=
" AND c.fk_soc = ".((int) $socid);
3635 if ($filtrestatut !=
'') {
3636 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3639 $result = $this->db->query($sql);
3641 $obj = $this->db->fetch_object($result);
3642 $this->stats_commande[
'customers'] = $obj->nb_customers;
3643 $this->stats_commande[
'nb'] = $obj->nb;
3644 $this->stats_commande[
'rows'] = $obj->nb_rows;
3645 $this->stats_commande[
'qty'] = $obj->qty ? $obj->qty : 0;
3650 if (is_array($TFather) && !empty($TFather)) {
3651 foreach ($TFather as &$fatherData) {
3652 $pFather =
new Product($this->db);
3653 $pFather->id = $fatherData[
'id'];
3654 $qtyCoef = $fatherData[
'qty'];
3656 if ($fatherData[
'incdec']) {
3657 $pFather->load_stats_commande($socid, $filtrestatut);
3659 $this->stats_commande[
'customers'] += $pFather->stats_commande[
'customers'];
3660 $this->stats_commande[
'nb'] += $pFather->stats_commande[
'nb'];
3661 $this->stats_commande[
'rows'] += $pFather->stats_commande[
'rows'];
3662 $this->stats_commande[
'qty'] += $pFather->stats_commande[
'qty'] * $qtyCoef;
3674 $sql =
"SELECT SUM(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3675 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3676 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON ((el.fk_target = f.rowid AND el.targettype = 'facture' AND sourcetype = 'commande') OR (el.fk_source = f.rowid AND el.targettype = 'commande' AND sourcetype = 'facture'))";
3677 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3678 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3680 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3681 $resql = $this->db->query($sql);
3683 if ($this->db->num_rows($resql) > 0) {
3684 $obj = $this->db->fetch_object($resql);
3685 $adeduire += $obj->count;
3689 $this->stats_commande[
'qty'] -= $adeduire;
3692 include_once DOL_DOCUMENT_ROOT.
'/compta/facture/class/facture.class.php';
3696 $sql =
"SELECT sum(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count";
3697 $sql .=
" FROM " . $this->db->prefix() .
"facturedet as fd";
3698 $sql .=
" JOIN " . $this->db->prefix() .
"facture as f ON fd.fk_facture = f.rowid";
3699 $sql .=
" JOIN " . $this->db->prefix() .
"element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture' AND el.sourcetype = 'commande'";
3700 $sql .=
" JOIN " . $this->db->prefix() .
"commande as c ON el.fk_source = c.rowid";
3701 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3702 $sql .=
" UNION ALL";
3703 $sql .=
" SELECT sum(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count";
3704 $sql .=
" FROM " . $this->db->prefix() .
"facturedet as fd";
3705 $sql .=
" JOIN " . $this->db->prefix() .
"facture as f ON fd.fk_facture = f.rowid";
3706 $sql .=
" JOIN " . $this->db->prefix() .
"element_element as el ON el.fk_source = f.rowid AND el.targettype = 'commande' AND el.sourcetype = 'facture'";
3707 $sql .=
" JOIN " . $this->db->prefix() .
"commande as c ON el.fk_source = c.rowid";
3708 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product =".((int) $this->
id);
3709 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3710 $resql = $this->db->query($sql);
3712 if ($this->db->num_rows($resql) > 0) {
3713 $obj = $this->db->fetch_object($resql);
3714 $adeduire += $obj->count;
3717 $this->error = $this->db->error();
3721 $this->stats_commande[
'qty'] -= $adeduire;
3725 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3726 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerOrder', $parameters, $this, $action);
3728 $this->stats_commande = $hookmanager->resArray[
'stats_commande'];
3732 $this->error = $this->db->error();
3750 global $user, $hookmanager, $action;
3752 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_suppliers, COUNT(DISTINCT c.rowid) as nb,";
3753 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3754 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as cd";
3755 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as c";
3756 $sql .=
", ".$this->db->prefix().
"societe as s";
3757 $sql .=
" WHERE c.rowid = cd.fk_commande";
3758 $sql .=
" AND c.fk_soc = s.rowid";
3759 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3760 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3761 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3762 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3765 $sql .=
" AND c.fk_soc = ".((int) $socid);
3767 if ($filtrestatut !=
'') {
3768 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3770 if (!empty($dateofvirtualstock)) {
3771 $sql .=
" AND c.date_livraison <= '".$this->db->idate($dateofvirtualstock).
"'";
3774 $result = $this->db->query($sql);
3776 $obj = $this->db->fetch_object($result);
3777 $this->stats_commande_fournisseur[
'suppliers'] = $obj->nb_suppliers;
3778 $this->stats_commande_fournisseur[
'nb'] = $obj->nb;
3779 $this->stats_commande_fournisseur[
'rows'] = $obj->nb_rows;
3780 $this->stats_commande_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
3782 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3783 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierOrder', $parameters, $this, $action);
3785 $this->stats_commande_fournisseur = $hookmanager->resArray[
'stats_commande_fournisseur'];
3790 $this->error = $this->db->error().
' sql='.$sql;
3805 public function load_stats_sending($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $filterShipmentStatus =
'')
3808 global $user, $hookmanager, $action;
3810 $sql =
"SELECT COUNT(DISTINCT e.fk_soc) as nb_customers, COUNT(DISTINCT e.rowid) as nb,";
3811 $sql .=
" COUNT(ed.rowid) as nb_rows, SUM(ed.qty) as qty";
3812 $sql .=
" FROM ".$this->db->prefix().
"expeditiondet as ed";
3813 $sql .=
", ".$this->db->prefix().
"commandedet as cd";
3814 $sql .=
", ".$this->db->prefix().
"commande as c";
3815 $sql .=
", ".$this->db->prefix().
"expedition as e";
3816 $sql .=
", ".$this->db->prefix().
"societe as s";
3817 $sql .=
" WHERE e.rowid = ed.fk_expedition";
3818 $sql .=
" AND c.rowid = cd.fk_commande";
3819 $sql .=
" AND e.fk_soc = s.rowid";
3820 $sql .=
" AND e.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'expedition').
")";
3821 $sql .=
" AND ed.fk_elementdet = cd.rowid";
3822 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3823 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3824 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = e.fk_soc AND sc.fk_user = ".((int) $user->id);
3827 $sql .=
" AND e.fk_soc = ".((int) $socid);
3829 if ($filtrestatut !=
'') {
3830 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3832 if (!empty($filterShipmentStatus)) {
3833 $sql .=
" AND e.fk_statut IN (".$this->db->sanitize($filterShipmentStatus).
")";
3836 $result = $this->db->query($sql);
3838 $obj = $this->db->fetch_object($result);
3839 $this->stats_expedition[
'customers'] = $obj->nb_customers;
3840 $this->stats_expedition[
'nb'] = $obj->nb;
3841 $this->stats_expedition[
'rows'] = $obj->nb_rows;
3842 $this->stats_expedition[
'qty'] = $obj->qty ? $obj->qty : 0;
3847 if (is_array($TFather) && !empty($TFather)) {
3848 foreach ($TFather as &$fatherData) {
3849 $pFather =
new Product($this->db);
3850 $pFather->id = $fatherData[
'id'];
3851 $qtyCoef = $fatherData[
'qty'];
3853 if ($fatherData[
'incdec']) {
3854 $pFather->load_stats_sending($socid, $filtrestatut, $forVirtualStock);
3856 $this->stats_expedition[
'customers'] += $pFather->stats_expedition[
'customers'];
3857 $this->stats_expedition[
'nb'] += $pFather->stats_expedition[
'nb'];
3858 $this->stats_expedition[
'rows'] += $pFather->stats_expedition[
'rows'];
3859 $this->stats_expedition[
'qty'] += $pFather->stats_expedition[
'qty'] * $qtyCoef;
3865 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock,
'filterShipmentStatus' => $filterShipmentStatus);
3866 $reshook = $hookmanager->executeHooks(
'loadStatsSending', $parameters, $this, $action);
3868 $this->stats_expedition = $hookmanager->resArray[
'stats_expedition'];
3873 $this->error = $this->db->error();
3888 public function load_stats_reception($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null)
3891 global $user, $hookmanager, $action;
3893 $sql =
"SELECT COUNT(DISTINCT cf.fk_soc) as nb_suppliers, COUNT(DISTINCT cf.rowid) as nb,";
3894 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
3895 $sql .=
" FROM ".$this->db->prefix().
"receptiondet_batch as fd";
3896 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as cf";
3897 $sql .=
", ".$this->db->prefix().
"societe as s";
3898 $sql .=
" WHERE cf.rowid = fd.fk_element";
3899 $sql .=
" AND cf.fk_soc = s.rowid";
3900 $sql .=
" AND cf.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3901 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3902 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3903 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = cf.fk_soc AND sc.fk_user = ".((int) $user->id);
3906 $sql .=
" AND cf.fk_soc = ".((int) $socid);
3908 if ($filtrestatut !=
'') {
3909 $sql .=
" AND cf.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3911 if (!empty($dateofvirtualstock)) {
3912 $sql .=
" AND fd.datec <= '".$this->db->idate($dateofvirtualstock).
"'";
3915 $result = $this->db->query($sql);
3917 $obj = $this->db->fetch_object($result);
3918 $this->stats_reception[
'suppliers'] = $obj->nb_suppliers;
3919 $this->stats_reception[
'nb'] = $obj->nb;
3920 $this->stats_reception[
'rows'] = $obj->nb_rows;
3921 $this->stats_reception[
'qty'] = $obj->qty ? $obj->qty : 0;
3923 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3924 $reshook = $hookmanager->executeHooks(
'loadStatsReception', $parameters, $this, $action);
3926 $this->stats_reception = $hookmanager->resArray[
'stats_reception'];
3931 $this->error = $this->db->error();
3947 public function load_stats_inproduction($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null, $warehouseid = 0)
3950 global $user, $hookmanager, $action;
3952 $serviceStockIsEnabled = isModEnabled(
"service") &&
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES');
3954 $sql =
"SELECT COUNT(DISTINCT m.fk_soc) as nb_customers, COUNT(DISTINCT m.rowid) as nb,";
3955 $sql .=
" COUNT(mp.rowid) as nb_rows, SUM(mp.qty) as qty, role";
3956 $sql .=
" FROM ".$this->db->prefix().
"mrp_production as mp";
3957 $sql .=
", ".$this->db->prefix().
"mrp_mo as m";
3958 $sql .=
" LEFT JOIN ".$this->db->prefix().
"societe as s ON s.rowid = m.fk_soc";
3959 $sql .=
" WHERE m.rowid = mp.fk_mo";
3960 $sql .=
" AND m.entity IN (".getEntity(($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE')) ?
'stock' :
'mrp').
")";
3961 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3962 $sql .=
" AND (mp.disable_stock_change IN (0) OR mp.disable_stock_change IS NULL)";
3963 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3964 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = m.fk_soc AND sc.fk_user = ".((int) $user->id);
3967 $sql .=
" AND m.fk_soc = ".((int) $socid);
3969 if ($filtrestatut !=
'') {
3970 $sql .=
" AND m.status IN (".$this->db->sanitize($filtrestatut).
")";
3972 if (!empty($dateofvirtualstock)) {
3973 $sql .=
" AND m.date_valid <= '".$this->db->idate($dateofvirtualstock).
"'";
3975 if (!$serviceStockIsEnabled) {
3976 $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))";
3978 if (!empty($warehouseid)) {
3979 $sql .=
" AND m.fk_warehouse = ".((int) $warehouseid);
3981 $sql .=
" GROUP BY role";
3984 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
3986 $this->stats_mrptoconsume[
'customers'] = 0;
3987 $this->stats_mrptoconsume[
'nb'] = 0;
3988 $this->stats_mrptoconsume[
'rows'] = 0;
3989 $this->stats_mrptoconsume[
'qty'] = 0.0;
3990 $this->stats_mrptoproduce[
'customers'] = 0;
3991 $this->stats_mrptoproduce[
'nb'] = 0;
3992 $this->stats_mrptoproduce[
'rows'] = 0;
3993 $this->stats_mrptoproduce[
'qty'] = 0.0;
3996 $result = $this->db->query($sql);
3998 while ($obj = $this->db->fetch_object($result)) {
3999 if ($obj->role ==
'toconsume' && empty($warehouseid)) {
4000 $this->stats_mrptoconsume[
'customers'] += (int) $obj->nb_customers;
4001 $this->stats_mrptoconsume[
'nb'] += (int) $obj->nb;
4002 $this->stats_mrptoconsume[
'rows'] += (int) $obj->nb_rows;
4003 $this->stats_mrptoconsume[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4005 if ($obj->role ==
'consumed' && empty($warehouseid)) {
4009 $this->stats_mrptoconsume[
'qty'] -= ($obj->qty ? (float) $obj->qty : 0.0);
4011 if ($obj->role ==
'toproduce') {
4013 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4015 $this->stats_mrptoproduce[
'customers'] += (int) $obj->nb_customers;
4016 $this->stats_mrptoproduce[
'nb'] += (int) $obj->nb;
4017 $this->stats_mrptoproduce[
'rows'] += (int) $obj->nb_rows;
4018 $this->stats_mrptoproduce[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4021 if ($obj->role ==
'produced') {
4026 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
4028 $this->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
4035 if ($this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] < 0) {
4036 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
4039 if ($this->stats_mrptoconsume[
'qty'] < 0) {
4040 $this->stats_mrptoconsume[
'qty'] = 0;
4042 if ($this->stats_mrptoproduce[
'qty'] < 0) {
4043 $this->stats_mrptoproduce[
'qty'] = 0;
4047 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
4048 $reshook = $hookmanager->executeHooks(
'loadStatsInProduction', $parameters, $this, $action);
4050 $this->stats_mrptoproduce = $hookmanager->resArray[
'stats_mrptoproduce'];
4055 $this->error = $this->db->error();
4070 global $user, $hookmanager, $action;
4072 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
4073 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
4074 $sql .=
" FROM ".$this->db->prefix().
"contratdet as cd";
4075 $sql .=
", ".$this->db->prefix().
"contrat as c";
4076 $sql .=
", ".$this->db->prefix().
"societe as s";
4077 $sql .=
" WHERE c.rowid = cd.fk_contrat";
4078 $sql .=
" AND c.fk_soc = s.rowid";
4079 $sql .=
" AND c.entity IN (".getEntity(
'contract').
")";
4080 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
4081 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4082 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
4086 $sql .=
" AND c.fk_soc = ".((int) $socid);
4089 $result = $this->db->query($sql);
4091 $obj = $this->db->fetch_object($result);
4092 $this->stats_contrat[
'customers'] = $obj->nb_customers;
4093 $this->stats_contrat[
'nb'] = $obj->nb;
4094 $this->stats_contrat[
'rows'] = $obj->nb_rows;
4095 $this->stats_contrat[
'qty'] = $obj->qty ? $obj->qty : 0;
4100 if (is_array($TFather) && !empty($TFather)) {
4101 foreach ($TFather as &$fatherData) {
4102 $pFather =
new Product($this->db);
4103 $pFather->id = $fatherData[
'id'];
4104 $qtyCoef = $fatherData[
'qty'];
4106 if ($fatherData[
'incdec']) {
4107 $pFather->load_stats_contrat($socid);
4109 $this->stats_contrat[
'customers'] += $pFather->stats_contrat[
'customers'];
4110 $this->stats_contrat[
'nb'] += $pFather->stats_contrat[
'nb'];
4111 $this->stats_contrat[
'rows'] += $pFather->stats_contrat[
'rows'];
4112 $this->stats_contrat[
'qty'] += $pFather->stats_contrat[
'qty'] * $qtyCoef;
4118 $parameters = array(
'socid' => $socid);
4119 $reshook = $hookmanager->executeHooks(
'loadStatsContract', $parameters, $this, $action);
4121 $this->stats_contrat = $hookmanager->resArray[
'stats_contrat'];
4126 $this->error = $this->db->error().
' sql='.$sql;
4141 global $user, $hookmanager, $action;
4143 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4144 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(".$this->db->ifsql(
'f.type != 2',
'fd.qty',
'fd.qty * -1').
") as qty";
4145 $sql .=
" FROM ".$this->db->prefix().
"facturedet as fd";
4146 $sql .=
", ".$this->db->prefix().
"facture as f";
4147 $sql .=
", ".$this->db->prefix().
"societe as s";
4148 $sql .=
" WHERE f.rowid = fd.fk_facture";
4149 $sql .=
" AND f.fk_soc = s.rowid";
4150 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4151 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4152 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4153 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4157 $sql .=
" AND f.fk_soc = ".((int) $socid);
4160 $result = $this->db->query($sql);
4162 $obj = $this->db->fetch_object($result);
4163 $this->stats_facture[
'customers'] = $obj->nb_customers;
4164 $this->stats_facture[
'nb'] = $obj->nb;
4165 $this->stats_facture[
'rows'] = $obj->nb_rows;
4166 $this->stats_facture[
'qty'] = $obj->qty ? $obj->qty : 0;
4171 if (is_array($TFather) && !empty($TFather)) {
4172 foreach ($TFather as &$fatherData) {
4173 $pFather =
new Product($this->db);
4174 $pFather->id = $fatherData[
'id'];
4175 $qtyCoef = $fatherData[
'qty'];
4177 if ($fatherData[
'incdec']) {
4178 $pFather->load_stats_facture($socid);
4180 $this->stats_facture[
'customers'] += $pFather->stats_facture[
'customers'];
4181 $this->stats_facture[
'nb'] += $pFather->stats_facture[
'nb'];
4182 $this->stats_facture[
'rows'] += $pFather->stats_facture[
'rows'];
4183 $this->stats_facture[
'qty'] += $pFather->stats_facture[
'qty'] * $qtyCoef;
4189 $parameters = array(
'socid' => $socid);
4190 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoice', $parameters, $this, $action);
4192 $this->stats_facture = $hookmanager->resArray[
'stats_facture'];
4197 $this->error = $this->db->error();
4213 global $user, $hookmanager, $action;
4215 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4216 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4217 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facturedet_rec as fd";
4218 $sql .=
", ".MAIN_DB_PREFIX.
"facture_rec as f";
4219 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
4220 $sql .=
" WHERE f.rowid = fd.fk_facture";
4221 $sql .=
" AND f.fk_soc = s.rowid";
4222 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4223 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4224 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4225 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4229 $sql .=
" AND f.fk_soc = ".((int) $socid);
4232 $result = $this->db->query($sql);
4234 $obj = $this->db->fetch_object($result);
4235 $this->stats_facturerec[
'customers'] = (int) $obj->nb_customers;
4236 $this->stats_facturerec[
'nb'] = (int) $obj->nb;
4237 $this->stats_facturerec[
'rows'] = (int) $obj->nb_rows;
4238 $this->stats_facturerec[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4243 if (is_array($TFather) && !empty($TFather)) {
4244 foreach ($TFather as &$fatherData) {
4245 $pFather =
new Product($this->db);
4246 $pFather->id = $fatherData[
'id'];
4247 $qtyCoef = $fatherData[
'qty'];
4249 if ($fatherData[
'incdec']) {
4250 $pFather->load_stats_facture($socid);
4252 $this->stats_facturerec[
'customers'] += $pFather->stats_facturerec[
'customers'];
4253 $this->stats_facturerec[
'nb'] += $pFather->stats_facturerec[
'nb'];
4254 $this->stats_facturerec[
'rows'] += $pFather->stats_facturerec[
'rows'];
4255 $this->stats_facturerec[
'qty'] += $pFather->stats_facturerec[
'qty'] * $qtyCoef;
4261 $parameters = array(
'socid' => $socid);
4262 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoiceRec', $parameters, $this, $action);
4264 $this->stats_facturerec = $hookmanager->resArray[
'stats_facturerec'];
4269 $this->error = $this->db->error();
4284 global $user, $hookmanager, $action;
4286 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
4287 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4288 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as fd";
4289 $sql .=
", ".$this->db->prefix().
"facture_fourn as f";
4290 $sql .=
", ".$this->db->prefix().
"societe as s";
4291 $sql .=
" WHERE f.rowid = fd.fk_facture_fourn";
4292 $sql .=
" AND f.fk_soc = s.rowid";
4293 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4294 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4295 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4296 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4300 $sql .=
" AND f.fk_soc = ".((int) $socid);
4303 $result = $this->db->query($sql);
4305 $obj = $this->db->fetch_object($result);
4306 $this->stats_facture_fournisseur[
'suppliers'] = (int) $obj->nb_suppliers;
4307 $this->stats_facture_fournisseur[
'nb'] = (int) $obj->nb;
4308 $this->stats_facture_fournisseur[
'rows'] = (int) $obj->nb_rows;
4309 $this->stats_facture_fournisseur[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4311 $parameters = array(
'socid' => $socid);
4312 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoice', $parameters, $this, $action);
4314 $this->stats_facture_fournisseur = $hookmanager->resArray[
'stats_facture_fournisseur'];
4319 $this->error = $this->db->error();
4334 global $user, $hookmanager, $action;
4336 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
4337 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4338 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facture_fourn_det_rec as fd";
4339 $sql .=
", ".MAIN_DB_PREFIX.
"facture_fourn_rec as f";
4340 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
4341 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4342 $sql .=
", ".MAIN_DB_PREFIX.
"societe_commerciaux as sc";
4344 $sql .=
" WHERE f.rowid = fd.fk_facture";
4345 $sql .=
" AND f.fk_soc = s.rowid";
4346 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4347 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4348 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4349 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4353 $sql .=
" AND f.fk_soc = ".((int) $socid);
4356 $result = $this->db->query($sql);
4358 $obj = $this->db->fetch_object($result);
4359 $this->stats_facturefournrec[
'suppliers'] = (int) $obj->nb_suppliers;
4360 $this->stats_facturefournrec[
'nb'] = (int) $obj->nb;
4361 $this->stats_facturefournrec[
'rows'] = (int) $obj->nb_rows;
4362 $this->stats_facturefournrec[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4364 $parameters = array(
'socid' => $socid);
4365 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoiceRec', $parameters, $this, $action);
4367 $this->stats_facturefournrec = $hookmanager->resArray[
'stats_facturefournrec'];
4372 $this->error = $this->db->error();
4391 $resql = $this->db->query($sql);
4393 $num = $this->db->num_rows($resql);
4396 $arr = $this->db->fetch_array($resql);
4397 if (is_array($arr)) {
4398 $keyfortab = (string) $arr[1];
4400 $keyfortab = substr($keyfortab, -2);
4403 if ($mode ==
'byunit') {
4404 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[0];
4405 } elseif ($mode ==
'bynumber') {
4406 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4407 } elseif ($mode ==
'byamount') {
4408 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4417 $this->error = $this->db->error().
' sql='.$sql;
4424 } elseif ($year == -1) {
4433 for ($j = 0; $j < 12; $j++) {
4435 $idx = ucfirst(
dol_trunc(
dol_print_date(
dol_mktime(12, 0, 0, $month, 1, 1970),
"%b"), 1,
'right',
'UTF-8', 1));
4438 $result[$j] = array($idx, isset($tab[$year.$month]) ? $tab[$year.$month] : 0);
4441 $month =
"0".($month - 1);
4443 $month = substr($month, 1);
4451 return array_reverse($result);
4466 public function get_nb_vente($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4471 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4472 if ($mode ==
'bynumber') {
4473 $sql .=
", count(DISTINCT f.rowid)";
4475 $sql .=
", sum(d.total_ht) as total_ht";
4476 $sql .=
" FROM ".$this->db->prefix().
"facturedet as d, ".$this->db->prefix().
"facture as f, ".$this->db->prefix().
"societe as s";
4477 if ($filteronproducttype >= 0) {
4478 $sql .=
", ".$this->db->prefix().
"product as p";
4480 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4481 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4483 $sql .=
" WHERE f.rowid = d.fk_facture";
4484 if ($this->
id > 0) {
4485 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4487 $sql .=
" AND d.fk_product > 0";
4489 if ($filteronproducttype >= 0) {
4490 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4492 $sql .=
" AND f.fk_soc = s.rowid";
4493 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4494 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4495 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4498 $sql .=
" AND f.fk_soc = $socid";
4500 $sql .= $morefilter;
4501 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4502 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4504 return $this->
_get_stats($sql, $mode, $year);
4519 public function get_nb_achat($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4524 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4525 if ($mode ==
'bynumber') {
4526 $sql .=
", count(DISTINCT f.rowid)";
4528 $sql .=
", sum(d.total_ht) as total_ht";
4529 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as d, ".$this->db->prefix().
"facture_fourn as f, ".$this->db->prefix().
"societe as s";
4530 if ($filteronproducttype >= 0) {
4531 $sql .=
", ".$this->db->prefix().
"product as p";
4533 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4534 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4536 $sql .=
" WHERE f.rowid = d.fk_facture_fourn";
4537 if ($this->
id > 0) {
4538 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4540 $sql .=
" AND d.fk_product > 0";
4542 if ($filteronproducttype >= 0) {
4543 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4545 $sql .=
" AND f.fk_soc = s.rowid";
4546 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4547 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4548 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4551 $sql .=
" AND f.fk_soc = $socid";
4553 $sql .= $morefilter;
4554 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4555 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4557 return $this->
_get_stats($sql, $mode, $year);
4571 public function get_nb_propal($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4576 $sql =
"SELECT sum(d.qty) as qty, date_format(p.datep, '%Y%m')";
4577 if ($mode ==
'bynumber') {
4578 $sql .=
", count(DISTINCT p.rowid)";
4580 $sql .=
", sum(d.total_ht) as total_ht";
4581 $sql .=
" FROM ".$this->db->prefix().
"propaldet as d, ".$this->db->prefix().
"propal as p, ".$this->db->prefix().
"societe as s";
4582 if ($filteronproducttype >= 0) {
4583 $sql .=
", ".$this->db->prefix().
"product as prod";
4585 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4586 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4588 $sql .=
" WHERE p.rowid = d.fk_propal";
4589 if ($this->
id > 0) {
4590 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4592 $sql .=
" AND d.fk_product > 0";
4594 if ($filteronproducttype >= 0) {
4595 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4597 $sql .=
" AND p.fk_soc = s.rowid";
4598 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
4599 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4600 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4603 $sql .=
" AND p.fk_soc = ".((int) $socid);
4605 $sql .= $morefilter;
4606 $sql .=
" GROUP BY date_format(p.datep,'%Y%m')";
4607 $sql .=
" ORDER BY date_format(p.datep,'%Y%m') DESC";
4609 return $this->
_get_stats($sql, $mode, $year);
4628 $sql =
"SELECT sum(d.qty) as qty, date_format(p.date_valid, '%Y%m')";
4629 if ($mode ==
'bynumber') {
4630 $sql .=
", count(DISTINCT p.rowid)";
4632 $sql .=
", sum(d.total_ht) as total_ht";
4633 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as d, ".$this->db->prefix().
"supplier_proposal as p, ".$this->db->prefix().
"societe as s";
4634 if ($filteronproducttype >= 0) {
4635 $sql .=
", ".$this->db->prefix().
"product as prod";
4637 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4638 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4640 $sql .=
" WHERE p.rowid = d.fk_supplier_proposal";
4641 if ($this->
id > 0) {
4642 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4644 $sql .=
" AND d.fk_product > 0";
4646 if ($filteronproducttype >= 0) {
4647 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4649 $sql .=
" AND p.fk_soc = s.rowid";
4650 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
4651 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4652 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4655 $sql .=
" AND p.fk_soc = ".((int) $socid);
4657 $sql .= $morefilter;
4658 $sql .=
" GROUP BY date_format(p.date_valid,'%Y%m')";
4659 $sql .=
" ORDER BY date_format(p.date_valid,'%Y%m') DESC";
4661 return $this->
_get_stats($sql, $mode, $year);
4675 public function get_nb_order($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4680 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4681 if ($mode ==
'bynumber') {
4682 $sql .=
", count(DISTINCT c.rowid)";
4684 $sql .=
", sum(d.total_ht) as total_ht";
4685 $sql .=
" FROM ".$this->db->prefix().
"commandedet as d, ".$this->db->prefix().
"commande as c, ".$this->db->prefix().
"societe as s";
4686 if ($filteronproducttype >= 0) {
4687 $sql .=
", ".$this->db->prefix().
"product as p";
4689 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4690 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4692 $sql .=
" WHERE c.rowid = d.fk_commande";
4693 if ($this->
id > 0) {
4694 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4696 $sql .=
" AND d.fk_product > 0";
4698 if ($filteronproducttype >= 0) {
4699 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4701 $sql .=
" AND c.fk_soc = s.rowid";
4702 $sql .=
" AND c.entity IN (".getEntity(
'commande').
")";
4703 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4704 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4707 $sql .=
" AND c.fk_soc = ".((int) $socid);
4709 $sql .= $morefilter;
4710 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4711 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4713 return $this->
_get_stats($sql, $mode, $year);
4732 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4733 if ($mode ==
'bynumber') {
4734 $sql .=
", count(DISTINCT c.rowid)";
4736 $sql .=
", sum(d.total_ht) as total_ht";
4737 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as d, ".$this->db->prefix().
"commande_fournisseur as c, ".$this->db->prefix().
"societe as s";
4738 if ($filteronproducttype >= 0) {
4739 $sql .=
", ".$this->db->prefix().
"product as p";
4741 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4742 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4744 $sql .=
" WHERE c.rowid = d.fk_commande";
4745 if ($this->
id > 0) {
4746 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4748 $sql .=
" AND d.fk_product > 0";
4750 if ($filteronproducttype >= 0) {
4751 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4753 $sql .=
" AND c.fk_soc = s.rowid";
4754 $sql .=
" AND c.entity IN (".getEntity(
'supplier_order').
")";
4755 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4756 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4759 $sql .=
" AND c.fk_soc = ".((int) $socid);
4761 $sql .= $morefilter;
4762 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4763 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4765 return $this->
_get_stats($sql, $mode, $year);
4779 public function get_nb_contract($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4784 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_contrat, '%Y%m')";
4785 if ($mode ==
'bynumber') {
4786 $sql .=
", count(DISTINCT c.rowid)";
4788 $sql .=
", sum(d.total_ht) as total_ht";
4789 $sql .=
" FROM ".$this->db->prefix().
"contratdet as d, ".$this->db->prefix().
"contrat as c, ".$this->db->prefix().
"societe as s";
4790 if ($filteronproducttype >= 0) {
4791 $sql .=
", ".$this->db->prefix().
"product as p";
4793 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4794 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4796 $sql .=
" WHERE c.entity IN (".getEntity(
'contract').
")";
4797 $sql .=
" AND c.rowid = d.fk_contrat";
4799 if ($this->
id > 0) {
4800 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4802 $sql .=
" AND d.fk_product > 0";
4804 if ($filteronproducttype >= 0) {
4805 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4807 $sql .=
" AND c.fk_soc = s.rowid";
4809 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4810 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4813 $sql .=
" AND c.fk_soc = ".((int) $socid);
4815 $sql .= $morefilter;
4816 $sql .=
" GROUP BY date_format(c.date_contrat,'%Y%m')";
4817 $sql .=
" ORDER BY date_format(c.date_contrat,'%Y%m') DESC";
4819 return $this->
_get_stats($sql, $mode, $year);
4833 public function get_nb_mos($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4838 $sql =
"SELECT sum(d.qty), date_format(d.date_valid, '%Y%m')";
4839 if ($mode ==
'bynumber') {
4840 $sql .=
", count(DISTINCT d.rowid)";
4842 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as d LEFT JOIN ".$this->db->prefix().
"societe as s ON d.fk_soc = s.rowid";
4843 if ($filteronproducttype >= 0) {
4844 $sql .=
", ".$this->db->prefix().
"product as p";
4846 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4847 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4850 $sql .=
" WHERE d.entity IN (".getEntity(
'mo').
")";
4851 $sql .=
" AND d.status > 0";
4853 if ($this->
id > 0) {
4854 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4856 $sql .=
" AND d.fk_product > 0";
4858 if ($filteronproducttype >= 0) {
4859 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4862 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4863 $sql .=
" AND d.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4866 $sql .=
" AND d.fk_soc = ".((int) $socid);
4868 $sql .= $morefilter;
4869 $sql .=
" GROUP BY date_format(d.date_valid,'%Y%m')";
4870 $sql .=
" ORDER BY date_format(d.date_valid,'%Y%m') DESC";
4872 return $this->
_get_stats($sql, $mode, $year);
4892 if (!is_numeric($id_pere)) {
4895 if (!is_numeric($id_fils)) {
4898 if (!is_numeric($incdec)) {
4908 $sql =
"SELECT fk_product_pere from ".$this->db->prefix().
"product_association";
4909 $sql .=
" WHERE fk_product_pere = ".((int) $id_fils).
" AND fk_product_fils = ".((int) $id_pere);
4910 if (!$this->db->query($sql)) {
4915 $sql =
"SELECT MAX(rang) as max_rank FROM ".$this->db->prefix().
"product_association";
4916 $sql .=
" WHERE fk_product_pere = ".((int) $id_pere);
4917 $resql = $this->db->query($sql);
4919 $obj = $this->db->fetch_object($resql);
4920 $rank = $obj->max_rank + 1;
4922 $sql =
"INSERT INTO ".$this->db->prefix().
"product_association(fk_product_pere,fk_product_fils,qty,incdec,rang)";
4923 $sql .=
" VALUES (".((int) $id_pere).
", ".((int) $id_fils).
", ".
price2num($qty,
'MS').
", ".((int) $incdec).
", ".((int) $rank).
")";
4924 if (! $this->db->query($sql)) {
4930 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_ADD', $user);
4932 $this->error = $this->db->lasterror();
4933 dol_syslog(get_class($this).
'::addSubproduct error='.$this->error, LOG_ERR);
4965 if (!is_numeric($id_pere)) {
4968 if (!is_numeric($id_fils)) {
4971 if (!is_numeric($incdec)) {
4974 if (!is_numeric($qty)) {
4978 $sql =
'UPDATE '.$this->db->prefix().
'product_association SET ';
4979 $sql .=
'qty = '.price2num($qty,
'MS');
4980 $sql .=
',incdec = '.((int) $incdec);
4981 $sql .=
' WHERE fk_product_pere = '.((int) $id_pere).
' AND fk_product_fils = '.((int) $id_fils);
4983 if (!$this->db->query($sql)) {
4989 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_UPDATE', $user);
4991 $this->error = $this->db->lasterror();
4992 dol_syslog(get_class($this).
'::updateSubproduct error='.$this->error, LOG_ERR);
5016 if (!is_numeric($fk_parent)) {
5019 if (!is_numeric($fk_child)) {
5023 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
5024 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5025 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
5027 dol_syslog(get_class($this).
'::del_sousproduit', LOG_DEBUG);
5028 if (!$this->db->query($sql)) {
5034 $sqlrank =
"SELECT rowid, rang FROM ".$this->db->prefix().
"product_association";
5035 $sqlrank .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5036 $sqlrank .=
" ORDER BY rang";
5037 $resqlrank = $this->db->query($sqlrank);
5040 while ($objrank = $this->db->fetch_object($resqlrank)) {
5042 $sql =
"UPDATE ".$this->db->prefix().
"product_association";
5043 $sql .=
" SET rang = ".((int) $cpt);
5044 $sql .=
" WHERE rowid = ".((int) $objrank->rowid);
5045 if (! $this->db->query($sql)) {
5054 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_DELETE', $user);
5056 $this->error = $this->db->lasterror();
5057 dol_syslog(get_class($this).
'::delSubproduct error='.$this->error, LOG_ERR);
5077 $sql =
"SELECT fk_product_pere, qty, incdec";
5078 $sql .=
" FROM ".$this->db->prefix().
"product_association";
5079 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5080 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
5082 $result = $this->db->query($sql);
5084 $num = $this->db->num_rows($result);
5087 $obj = $this->db->fetch_object($result);
5089 $this->is_sousproduit_qty = $obj->qty;
5090 $this->is_sousproduit_incdec = $obj->incdec;
5121 dol_syslog(get_class($this).
"::add_fournisseur id_fourn = ".$id_fourn.
" ref_fourn=".$ref_fourn.
" quantity=".$quantity, LOG_DEBUG);
5128 $sql =
"SELECT rowid, fk_product";
5129 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5130 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5131 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5132 $sql .=
" AND fk_product <> ".((int) $this->
id);
5133 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5135 $resql = $this->db->query($sql);
5137 $obj = $this->db->fetch_object($resql);
5140 $this->product_id_already_linked = $obj->fk_product;
5143 $this->db->free($resql);
5147 $sql =
"SELECT rowid";
5148 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5149 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5151 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5153 $sql .=
" AND (ref_fourn = '' OR ref_fourn IS NULL)";
5155 $sql .=
" AND quantity = ".((float) $quantity);
5156 $sql .=
" AND fk_product = ".((int) $this->
id);
5157 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5159 $resql = $this->db->query($sql);
5161 $obj = $this->db->fetch_object($resql);
5165 $sql =
"INSERT INTO ".$this->db->prefix().
"product_fournisseur_price(";
5168 $sql .=
", fk_product";
5170 $sql .=
", ref_fourn";
5171 $sql .=
", quantity";
5172 $sql .=
", fk_user";
5174 $sql .=
") VALUES (";
5175 $sql .=
"'".$this->db->idate($now).
"'";
5176 $sql .=
", ".((int)
$conf->entity);
5177 $sql .=
", ".((int) $this->
id);
5178 $sql .=
", ".((int) $id_fourn);
5179 $sql .=
", '".$this->db->escape($ref_fourn).
"'";
5180 $sql .=
", ".((float) $quantity);
5181 $sql .=
", ".((int) $user->id);
5185 if ($this->db->query($sql)) {
5186 $this->product_fourn_price_id = $this->db->last_insert_id($this->db->prefix().
"product_fournisseur_price");
5189 $this->error = $this->db->lasterror();
5194 $this->product_fourn_price_id = $obj->rowid;
5198 $this->error = $this->db->lasterror();
5217 $sql =
"SELECT DISTINCT p.fk_soc";
5218 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as p";
5219 $sql .=
" WHERE p.fk_product = ".((int) $this->
id);
5220 $sql .=
" AND p.entity = ".((int)
$conf->entity);
5222 $result = $this->db->query($sql);
5224 $num = $this->db->num_rows($result);
5227 $obj = $this->db->fetch_object($result);
5228 $list[$i] = $obj->fk_soc;
5253 $sql =
"INSERT INTO ".$this->db->prefix().
"product_price (";
5255 $sql .=
", fk_product";
5256 $sql .=
", date_price";
5257 $sql .=
", price_level";
5259 $sql .=
", price_ttc";
5260 $sql .=
", price_min";
5261 $sql .=
", price_min_ttc";
5262 $sql .=
", price_base_type";
5263 $sql .=
", price_label";
5264 $sql .=
", default_vat_code";
5266 $sql .=
", recuperableonly";
5267 $sql .=
", localtax1_tx";
5268 $sql .=
", localtax1_type";
5269 $sql .=
", localtax2_tx";
5270 $sql .=
", localtax2_type";
5271 $sql .=
", fk_user_author";
5273 $sql .=
", price_by_qty";
5274 $sql .=
", fk_price_expression";
5275 $sql .=
", fk_multicurrency";
5276 $sql .=
", multicurrency_code";
5277 $sql .=
", multicurrency_tx";
5278 $sql .=
", multicurrency_price";
5279 $sql .=
", multicurrency_price_ttc";
5283 $sql .=
", ".((int) $toId);
5284 $sql .=
", '".$this->db->idate($now).
"'";
5285 $sql .=
", price_level";
5287 $sql .=
", price_ttc";
5288 $sql .=
", price_min";
5289 $sql .=
", price_min_ttc";
5290 $sql .=
", price_base_type";
5291 $sql .=
", price_label";
5292 $sql .=
", default_vat_code";
5294 $sql .=
", recuperableonly";
5295 $sql .=
", localtax1_tx";
5296 $sql .=
", localtax1_type";
5297 $sql .=
", localtax2_tx";
5298 $sql .=
", localtax2_type";
5299 $sql .=
", ".((int) $user->id);
5301 $sql .=
", price_by_qty";
5302 $sql .=
", fk_price_expression";
5303 $sql .=
", fk_multicurrency";
5304 $sql .=
", multicurrency_code";
5305 $sql .=
", multicurrency_tx";
5306 $sql .=
", multicurrency_price";
5307 $sql .=
", multicurrency_price_ttc";
5308 $sql .=
" FROM ".$this->db->prefix().
"product_price ps";
5309 $sql .=
" WHERE fk_product = ".((int) $fromId);
5310 $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)";
5311 $sql .=
" ORDER BY date_price DESC";
5314 $resql = $this->db->query($sql);
5316 $this->db->rollback();
5320 $this->db->commit();
5337 $sql =
'INSERT INTO '.$this->db->prefix().
'product_association (fk_product_pere, fk_product_fils, qty, incdec)';
5338 $sql .=
" SELECT ".((int) $toId).
", fk_product_fils, qty, incdec FROM ".$this->db->prefix().
"product_association";
5339 $sql .=
" WHERE fk_product_pere = ".((int) $fromId);
5341 dol_syslog(get_class($this).
'::clone_association', LOG_DEBUG);
5342 if (!$this->db->query($sql)) {
5343 $this->db->rollback();
5347 $this->db->commit();
5380 $sql =
"INSERT ".$this->db->prefix().
"product_fournisseur_price (";
5381 $sql .=
" datec, fk_product, fk_soc, price, quantity, fk_user, tva_tx)";
5382 $sql .=
" SELECT '".$this->db->idate($now).
"', ".((int) $toId).
", fk_soc, price, quantity, fk_user, tva_tx";
5383 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5384 $sql .=
" WHERE fk_product = ".((int) $fromId);
5386 dol_syslog(get_class($this).
'::clone_fournisseurs', LOG_DEBUG);
5387 $resql = $this->db->query($sql);
5389 $this->db->rollback();
5392 $this->db->commit();
5410 public function fetch_prod_arbo($prod, $compl_path =
'', $multiply = 1, $level = 1, $id_parent = 0, $ignore_stock_load = 0)
5415 if ($multiply < 1) {
5416 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);
5421 foreach ($prod as $id_product => $desc_pere) {
5422 if (is_array($desc_pere)) {
5423 $id = (!empty($desc_pere[0]) ? $desc_pere[0] :
'');
5424 $nb = (!empty($desc_pere[1]) ? $desc_pere[1] :
'');
5425 $type = (!empty($desc_pere[2]) ? $desc_pere[2] :
'');
5426 $label = (!empty($desc_pere[3]) ? $desc_pere[3] :
'');
5427 $incdec = (!empty($desc_pere[4]) ? $desc_pere[4] : 0);
5430 if (is_null($tmpproduct)) {
5431 $tmpproduct =
new Product($this->db);
5433 $tmpproduct->fetch($id);
5435 if (empty($ignore_stock_load) && ($tmpproduct->isProduct() ||
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES'))) {
5436 $tmpproduct->load_stock(
'nobatch,novirtual');
5439 $this->res[] = array(
5441 'id_parent' => $id_parent,
5442 'ref' => $tmpproduct->ref,
5444 'nb_total' => $nb * $multiply,
5445 'stock' => $tmpproduct->stock_reel,
5446 'stock_alert' => $tmpproduct->seuil_stock_alerte,
5448 'fullpath' => $compl_path.$label,
5450 'desiredstock' => $tmpproduct->desiredstock,
5452 'incdec' => $incdec,
5453 'entity' => $tmpproduct->entity
5457 if (isset($desc_pere[
'childs']) && is_array($desc_pere[
'childs'])) {
5458 if (!is_int($desc_pere[1] * $multiply)) {
5459 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);
5463 $this->
fetch_prod_arbo($desc_pere[
'childs'], $compl_path.$desc_pere[3].
" -> ", (
int) ceil($desc_pere[1] * $multiply), $level + 1, $id, $ignore_stock_load);
5481 $this->res = array();
5482 if (isset($this->sousprods) && is_array($this->sousprods)) {
5483 foreach ($this->sousprods as $prod_name => $desc_product) {
5484 if (is_array($desc_product)) {
5485 $this->
fetch_prod_arbo($desc_product,
"", $multiply, 1, $this->
id, $ignore_stock_load);
5504 $sql =
"SELECT COUNT(pa.rowid) as nb";
5505 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa";
5507 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id).
" OR pa.fk_product_pere = ".((int) $this->
id);
5508 } elseif ($mode == -1) {
5509 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id);
5510 } elseif ($mode == 1) {
5511 $sql .=
" WHERE pa.fk_product_pere = ".((int) $this->
id);
5514 $resql = $this->db->query($sql);
5516 $obj = $this->db->fetch_object($resql);
5535 $sql =
"SELECT count(rowid) as nb FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_parent = ".((int) $this->
id);
5536 $sql .=
" AND entity IN (".getEntity(
'product').
")";
5538 $resql = $this->db->query($sql);
5540 $obj = $this->db->fetch_object($resql);
5557 if (isModEnabled(
'variants')) {
5558 $sql =
"SELECT rowid FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_child = ".((int) $this->
id).
" AND entity IN (".
getEntity(
'product').
")";
5560 $query = $this->db->query($sql);
5563 if (!$this->db->num_rows($query)) {
5584 $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";
5585 $sql .=
", p.tosell as status, p.tobuy as status_buy";
5586 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa,";
5587 $sql .=
" ".$this->db->prefix().
"product as p";
5588 $sql .=
" WHERE p.rowid = pa.fk_product_pere";
5589 $sql .=
" AND pa.fk_product_fils = ".((int) $this->
id);
5591 $res = $this->db->query($sql);
5594 while ($record = $this->db->fetch_array($res)) {
5596 $prods[$record[
'id']] = array();
5597 $prods[$record[
'id']][
'id'] = $record[
'rowid'];
5598 $prods[$record[
'id']][
'ref'] = $record[
'ref'];
5599 $prods[$record[
'id']][
'label'] = $record[
'label'];
5600 $prods[$record[
'id']][
'qty'] = $record[
'qty'];
5601 $prods[$record[
'id']][
'incdec'] = $record[
'incdec'];
5602 $prods[$record[
'id']][
'fk_product_type'] = $record[
'fk_product_type'];
5603 $prods[$record[
'id']][
'entity'] = $record[
'entity'];
5604 $prods[$record[
'id']][
'status'] = $record[
'status'];
5605 $prods[$record[
'id']][
'status_buy'] = $record[
'status_buy'];
5624 public function getChildsArbo($id, $firstlevelonly = 0, $level = 1, $parents = array())
5630 $sql =
"SELECT p.rowid, p.ref, p.label as label, p.fk_product_type,";
5631 $sql .=
" pa.qty as qty, pa.fk_product_fils as id, pa.incdec,";
5632 $sql .=
" pa.rowid as fk_association, pa.rang";
5633 $sql .=
" FROM ".$this->db->prefix().
"product as p,";
5634 $sql .=
" ".$this->db->prefix().
"product_association as pa";
5635 $sql .=
" WHERE p.rowid = pa.fk_product_fils";
5636 $sql .=
" AND pa.fk_product_pere = ".((int) $id);
5637 $sql .=
" AND pa.fk_product_fils <> ".((int) $id);
5638 $sql .=
" ORDER BY pa.rang";
5640 dol_syslog(get_class($this).
'::getChildsArbo id='.$id.
' level='.$level.
' parents='.(is_array($parents) ? implode(
',', $parents) : $parents), LOG_DEBUG);
5647 $res = $this->db->query($sql);
5650 if ($this->db->num_rows($res) > 0) {
5654 while ($rec = $this->db->fetch_array($res)) {
5655 if (in_array($rec[
'id'], $parents)) {
5656 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);
5660 $prods[$rec[
'rowid']] = array(
5663 2 => $rec[
'fk_product_type'],
5664 3 => $this->db->escape($rec[
'label']),
5665 4 => $rec[
'incdec'],
5667 6 => $rec[
'fk_association'],
5672 if (empty($firstlevelonly)) {
5673 $listofchilds = $this->
getChildsArbo($rec[
'rowid'], 0, $level + 1, $parents);
5674 foreach ($listofchilds as $keyChild => $valueChild) {
5675 $prods[$rec[
'rowid']][
'childs'][$keyChild] = $valueChild;
5699 foreach ($this->
getChildsArbo($this->
id) as $keyChild => $valueChild) {
5700 $parent[$this->label][$keyChild] = $valueChild;
5702 foreach ($parent as $key => $value) {
5703 $this->sousprods[$key] = $value;
5716 global
$conf, $langs, $user;
5718 $langs->loadLangs(array(
'products',
'other'));
5721 $nofetch = !empty($params[
'nofetch']);
5724 return [
'optimize' => $langs->trans(
"ShowProduct")];
5728 $permissiontoreadproduct = 0;
5729 if ($this->
type == self::TYPE_PRODUCT && $user->hasRight(
'product',
'read')) {
5730 $permissiontoreadproduct = 1;
5732 if ($this->
type == self::TYPE_SERVICE && $user->hasRight(
'service',
'read')) {
5733 $permissiontoreadproduct = 1;
5736 if (!empty($this->entity) && $permissiontoreadproduct) {
5737 $tmpphoto = $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 80, 0, 0, 0, 0,
'1');
5738 if ($this->nbphoto > 0) {
5739 $datas[
'photo'] =
'<div class="photointooltip floatright">'.
"\n" . $tmpphoto .
'</div>';
5744 $datas[
'picto'] =
img_picto(
'',
'product').
' <u class="paddingrightonly">'.$langs->trans(
"Product").
'</u>';
5746 $datas[
'picto'] =
img_picto(
'',
'service').
' <u class="paddingrightonly">'.$langs->trans(
"Service").
'</u>';
5748 if (isset($this->
status) && isset($this->status_buy)) {
5749 $datas[
'status'] =
' '.$this->getLibStatut(5, 0) .
' '.$this->getLibStatut(5, 1);
5752 if (!empty($this->
ref)) {
5753 $datas[
'ref'] =
'<br><b>'.$langs->trans(
'ProductRef').
':</b> '.$this->ref;
5755 if (!empty($this->label)) {
5756 $datas[
'label'] =
'<br><b>'.$langs->trans(
'ProductLabel').
':</b> '.$this->label;
5759 if ($permissiontoreadproduct) {
5764 if (isModEnabled(
'productbatch')) {
5765 $langs->load(
"productbatch");
5766 $datas[
'batchstatus'] =
"<br><b>".$langs->trans(
"ManageLotSerial").
'</b>: '.$this->
getLibStatut(0, 2);
5767 if ($this->status_batch) {
5768 $datas[
'batchdlc'] =
"<br><b>".$langs->trans(
"BatchSellOrEatByMandatoryList", $langs->transnoentitiesnoconv(
"SellByDate"), $langs->transnoentitiesnoconv(
"EatByDate")).
'</b>: '.$this->
getSellOrEatByMandatoryLabel();
5772 if (isModEnabled(
'barcode')) {
5773 $datas[
'barcode'] =
'<br><b>'.$langs->trans(
'BarCode').
':</b> '.$this->barcode;
5777 if ($this->weight) {
5778 $datas[
'weight'] =
"<br><b>".$langs->trans(
"Weight").
'</b>: '.$this->weight.
' '.
measuringUnitString(0,
"weight", $this->weight_units);
5781 if ($this->length) {
5782 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Length").
'</b>: '.$this->length.
' '.
measuringUnitString(0,
'size', $this->length_units);
5785 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Width").
'</b>: '.$this->width.
' '.
measuringUnitString(0,
'size', $this->width_units);
5787 if ($this->height) {
5788 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Height").
'</b>: '.$this->height.
' '.
measuringUnitString(0,
'size', $this->height_units);
5791 $datas[
'size'] =
"<br>".$labelsize;
5794 $labelsurfacevolume =
"";
5795 if ($this->surface) {
5796 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Surface").
'</b>: '.$this->surface.
' '.
measuringUnitString(0,
'surface', $this->surface_units);
5798 if ($this->volume) {
5799 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Volume").
'</b>: '.$this->volume.
' '.
measuringUnitString(0,
'volume', $this->volume_units);
5801 if ($labelsurfacevolume) {
5802 $datas[
'surface'] =
"<br>" . $labelsurfacevolume;
5805 if ($this->
isService() && !empty($this->duration_value)) {
5807 $datas[
'duration'] =
'<br><b>'.$langs->trans(
"Duration").
':</b> '.$this->duration_value;
5808 if ($this->duration_value > 1) {
5809 $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"));
5810 } elseif ($this->duration_value > 0) {
5811 $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"));
5813 $datas[
'duration'] .= (!empty($this->duration_unit) && isset($dur[$this->duration_unit]) ?
" ".$langs->trans($dur[$this->duration_unit]) :
'');
5815 if (empty($user->socid)) {
5816 if ($this->
isStockManaged() && !empty($this->pmp) && $this->pmp) {
5817 $datas[
'pmp'] =
"<br><b>".$langs->trans(
"PMPValue").
'</b>: '.
price($this->pmp, 0,
'', 1, -1, -1,
$conf->currency);
5820 if (isModEnabled(
'accounting')) {
5821 if ($this->
status && isset($this->accountancy_code_sell)) {
5822 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5823 $selllabel =
'<br>';
5824 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellCode').
':</b> '.
length_accountg($this->accountancy_code_sell);
5825 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellIntraCode').
':</b> '.
length_accountg($this->accountancy_code_sell_intra);
5826 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellExportCode').
':</b> '.
length_accountg($this->accountancy_code_sell_export);
5827 $datas[
'accountancysell'] = $selllabel;
5829 if ($this->status_buy && isset($this->accountancy_code_buy)) {
5830 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5832 if (empty($this->
status)) {
5833 $buylabel .=
'<br>';
5835 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyCode').
':</b> '.
length_accountg($this->accountancy_code_buy);
5836 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyIntraCode').
':</b> '.
length_accountg($this->accountancy_code_buy_intra);
5837 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyExportCode').
':</b> '.
length_accountg($this->accountancy_code_buy_export);
5838 $datas[
'accountancybuy'] = $buylabel;
5843 if (isModEnabled(
'category') && !$nofetch) {
5844 require_once DOL_DOCUMENT_ROOT .
'/categories/class/categorie.class.php';
5845 $form =
new Form($this->db);
5846 $datas[
'categories'] =
'<br>' . $form->showCategories($this->
id, Categorie::TYPE_PRODUCT, 1);
5866 public function getNomUrl($withpicto = 0, $option =
'', $maxlength = 0, $save_lastsearch_value = -1, $notooltip = 0, $morecss =
'', $add_label = 0, $sep =
' - ')
5868 global $langs, $hookmanager;
5870 include_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
5874 $newref = $this->ref;
5876 $newref =
dol_trunc($newref, $maxlength,
'middle');
5880 'objecttype' => ($this->
type == 1 ?
'service' :
'product'),
5881 'option' => $option,
5884 $classfortooltip =
'classfortooltip';
5887 $classfortooltip =
'classforajaxtooltip';
5888 $dataparams =
' data-params="'.dol_escape_htmltag(json_encode($params)).
'"';
5895 if (empty($notooltip)) {
5897 $label = $langs->trans(
"ShowProduct");
5898 $linkclose .=
' alt="'.dol_escape_htmltag($label, 1, 1).
'"';
5900 $linkclose .= ($label ?
' title="'.dol_escape_htmltag($label, 1, 1).
'"' :
' title="tocomplete"');
5901 $linkclose .= $dataparams.
' class="nowraponall '.$classfortooltip.($morecss ?
' '.$morecss :
'').
'"';
5903 $linkclose =
' class="nowraponall'.($morecss ?
' '.$morecss :
'').
'"';
5906 if ($option ==
'supplier' || $option ==
'category') {
5907 $url = DOL_URL_ROOT.
'/product/price_suppliers.php?id='.$this->id;
5908 } elseif ($option ==
'stock') {
5909 $url = DOL_URL_ROOT.
'/product/stock/product.php?id='.$this->id;
5910 } elseif ($option ==
'composition') {
5911 $url = DOL_URL_ROOT.
'/product/composition/card.php?id='.$this->id;
5913 $url = DOL_URL_ROOT.
'/product/card.php?id='.$this->id;
5916 if ($option !==
'nolink') {
5918 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
5919 if ($save_lastsearch_value == -1 && isset($_SERVER[
"PHP_SELF"]) && preg_match(
'/list\.php/', $_SERVER[
"PHP_SELF"])) {
5920 $add_save_lastsearch_values = 1;
5922 if ($add_save_lastsearch_values) {
5923 $url .=
'&save_lastsearch_values=1';
5927 $linkstart =
'<a href="'.$url.
'"';
5928 $linkstart .= $linkclose.
'>';
5931 $result .= $linkstart;
5934 $result .= (
img_object(($notooltip ?
'' : $label),
'product',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
5937 $result .= (
img_object(($notooltip ?
'' : $label),
'service',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
5940 $result .=
'<span class="aaa">'.dol_escape_htmltag($newref).
'</span>';
5941 $result .= $linkend;
5942 if ($withpicto != 2) {
5943 $result .= (($add_label && $this->label) ? $sep.dol_trunc($this->label, ($add_label > 1 ? $add_label : 0)) :
'');
5947 $hookmanager->initHooks(array(
'productdao'));
5948 $parameters = array(
'id' => $this->
id,
'getnomurl' => &$result,
'label' => &$label);
5949 $reshook = $hookmanager->executeHooks(
'getNomUrl', $parameters, $this, $action);
5951 $result = $hookmanager->resPrint;
5953 $result .= $hookmanager->resPrint;
5970 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
5974 $langs->load(
"products");
5975 $outputlangs->load(
"products");
5982 $modelpath =
"core/modules/product/doc/";
5984 return $this->
commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
6000 return $this->
LibStatut($this->status_buy, $mode, $type);
6002 return $this->
LibStatut($this->status_batch, $mode, $type);
6005 return $this->
LibStatut($this->status_buy, $mode, $type);
6023 $labelStatus = $labelStatusShort =
'';
6025 $langs->load(
'products');
6026 if (isModEnabled(
'productbatch')) {
6027 $langs->load(
"productbatch");
6033 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial')));
6036 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort')));
6041 return dolGetStatus($langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch'),
'',
'', empty($status) ?
'status5' :
'status4', 3,
'dot');
6047 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'));
6051 $statuttrans = empty($status) ?
'status5' :
'status4';
6056 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSellShort');
6057 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSell');
6058 } elseif ($type == 1) {
6059 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuyShort');
6060 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuy');
6061 } elseif ($type == 2) {
6062 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch');
6063 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort');
6065 } elseif ($status == 1) {
6068 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSellShort');
6069 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSell');
6070 } elseif ($type == 1) {
6071 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBuyShort');
6072 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBuy');
6073 } elseif ($type == 2) {
6074 $labelStatus = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial'));
6075 $labelStatusShort = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort'));
6077 } elseif ($type == 2 && $status == 2) {
6078 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSerial');
6079 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort');
6083 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'),
'',
'',
'status0', 0);
6085 return dolGetStatus($labelStatus, $labelStatusShort,
'', $statuttrans, $mode);
6099 $langs->load(
'products');
6102 if (isset($this->finished) && $this->finished >= 0) {
6103 $sql =
"SELECT label, code FROM ".$this->db->prefix().
"c_product_nature where code = ".((int) $this->finished).
" AND active=1";
6104 $resql = $this->db->query($sql);
6106 $this->error = $this->db->error().
' sql='.$sql;
6107 dol_syslog(__METHOD__.
' Error '.$this->error, LOG_ERR);
6109 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
6110 $label = $langs->trans($res[
'label']);
6112 $this->db->free($resql);
6136 public function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label =
'', $price = 0, $inventorycode =
'', $origin_element =
'', $origin_id =
null, $disablestockchangeforsubproduct = 0, $extrafields =
null)
6142 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6145 $nbpiece = (float) $nbpiece;
6150 $nbpiece = abs($nbpiece);
6157 $movementstock->setOrigin($origin_element, (
int) $origin_id);
6158 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'',
'',
'',
'',
false, 0, $disablestockchangeforsubproduct);
6162 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6163 $movementstock->array_options = $array_options;
6164 $movementstock->insertExtraFields();
6166 $this->db->commit();
6169 $this->error = $movementstock->error;
6170 $this->errors = $movementstock->errors;
6172 $this->db->rollback();
6201 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)
6207 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6210 $nbpiece = (float) $nbpiece;
6215 $nbpiece = abs($nbpiece);
6223 $movementstock->setOrigin($origin_element, (
int) $origin_id);
6224 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'', $dlc, $dluo, $lot,
false, 0, $disablestockchangeforsubproduct, 0, $force_update_batch);
6228 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6229 $movementstock->array_options = $array_options;
6230 $movementstock->insertExtraFields();
6232 $this->db->commit();
6235 $this->error = $movementstock->error;
6236 $this->errors = $movementstock->errors;
6238 $this->db->rollback();
6258 public function load_stock($option =
'', $includedraftpoforvirtual =
null, $dateofvirtualstock =
null)
6261 $this->stock_reel = 0;
6262 $this->stock_warehouse = array();
6263 $this->stock_theorique = 0;
6266 $warehouseStatus = array();
6267 if (preg_match(
'/warehouseclosed/', $option)) {
6270 if (preg_match(
'/warehouseopen/', $option)) {
6273 if (preg_match(
'/warehouseinternal/', $option)) {
6281 $sql =
"SELECT ps.rowid, ps.reel, ps.fk_entrepot";
6282 $sql .=
" FROM ".$this->db->prefix().
"product_stock as ps";
6283 $sql .=
", ".$this->db->prefix().
"entrepot as w";
6284 $sql .=
" WHERE w.entity IN (".getEntity(
'stock').
")";
6285 $sql .=
" AND w.rowid = ps.fk_entrepot";
6286 $sql .=
" AND ps.fk_product = ".((int) $this->
id);
6287 if (count($warehouseStatus)) {
6288 $sql .=
" AND w.statut IN (".$this->db->sanitize(implode(
',', $warehouseStatus)).
")";
6291 $sql .=
" ORDER BY ps.reel ".(getDolGlobalString(
'DO_NOT_TRY_TO_DEFRAGMENT_STOCKS_WAREHOUSE') ?
'DESC' :
'ASC');
6293 dol_syslog(get_class($this).
"::load_stock", LOG_DEBUG);
6294 $result = $this->db->query($sql);
6296 $num = $this->db->num_rows($result);
6300 $row = $this->db->fetch_object($result);
6301 $this->stock_warehouse[$row->fk_entrepot] =
new stdClass();
6302 $this->stock_warehouse[$row->fk_entrepot]->real = $row->reel;
6303 $this->stock_warehouse[$row->fk_entrepot]->id = $row->rowid;
6304 if ((!preg_match(
'/nobatch/', $option)) && $this->
hasbatch()) {
6305 $this->stock_warehouse[$row->fk_entrepot]->detail_batch =
Productbatch::findAll($this->db, $row->rowid, 1, $this->id);
6307 $this->stock_reel += $row->reel;
6310 $this->stock_reel = (float)
price2num($this->stock_reel,
'MS');
6312 $this->db->free($result);
6314 if (!preg_match(
'/novirtual/', $option)) {
6320 $this->error = $this->db->lasterror();
6339 global $hookmanager, $action;
6341 $stock_commande_client = 0;
6342 $stock_commande_fournisseur = 0;
6343 $stock_sending_client = 0;
6344 $stock_reception_fournisseur = 0;
6345 $stock_inproduction = 0;
6349 if (isModEnabled(
'order')) {
6354 $stock_commande_client = $this->stats_commande[
'qty'];
6356 if (isModEnabled(
"shipping")) {
6357 require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expedition.class.php';
6358 $filterShipmentStatus =
'';
6368 $stock_sending_client = $this->stats_expedition[
'qty'];
6371 if (isModEnabled(
"supplier_order")) {
6372 $filterStatus =
getDolGlobalString(
'SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK',
'3,4');
6373 if (isset($includedraftpoforvirtual)) {
6374 $filterStatus =
'0,1,2,'.$filterStatus;
6380 $stock_commande_fournisseur = $this->stats_commande_fournisseur[
'qty'];
6383 if (isModEnabled(
"supplier_order") || isModEnabled(
"supplier_invoice")) {
6384 $filterStatus =
'4';
6385 if (isset($includedraftpoforvirtual)) {
6386 $filterStatus =
'0,'.$filterStatus;
6392 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
6395 if (isModEnabled(
'mrp')) {
6400 $stock_inproduction = $this->stats_mrptoproduce[
'qty'] - $this->stats_mrptoconsume[
'qty'];
6403 $this->stock_theorique = $this->stock_reel + $stock_inproduction;
6407 $weBillOrderOrShipmentReception =
getDolGlobalString(
'STOCK_DO_WE_BILL_ORDER_OR_SHIPMENTECEPTION_FOR_VIRTUALSTOCK',
'order');
6411 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6415 $result = $tmpnewprod->load_stats_commande(0,
'0', 1);
6416 $this->stock_theorique += $tmpnewprod->stats_commande[
'qty'];
6418 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6419 $this->stock_theorique -= $stock_commande_client;
6420 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6421 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6426 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6428 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6430 if (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER_INCLUDE_DRAFT')) {
6432 $result = $tmpnewprod->load_stats_commande_fournisseur(0,
'0', 1);
6433 $this->stock_theorique += $this->stats_commande_fournisseur[
'qty'];
6435 $this->stock_theorique -= $stock_reception_fournisseur;
6436 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6437 $this->stock_theorique += $stock_commande_fournisseur;
6438 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6439 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6442 $parameters = array(
'id' => $this->
id,
'includedraftpoforvirtual' => $includedraftpoforvirtual);
6444 $reshook = $hookmanager->executeHooks(
'loadvirtualstock', $parameters, $this, $action);
6446 $this->stock_theorique = $hookmanager->resArray[
'stock_theorique'];
6447 } elseif ($reshook == 0 && isset($hookmanager->resArray[
'stock_stats_hook'])) {
6448 $this->stock_theorique += $hookmanager->resArray[
'stock_stats_hook'];
6452 if (!empty($this->stock_warehouse) &&
getDolGlobalString(
'STOCK_ALLOW_VIRTUAL_STOCK_PER_WAREHOUSE')) {
6453 foreach ($this->stock_warehouse as $warehouseid => $stockwarehouse) {
6454 if (isModEnabled(
'mrp')) {
6461 if ($this->fk_default_warehouse == $warehouseid) {
6462 $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']);
6464 $this->stock_warehouse[$warehouseid]->virtual = $this->stock_warehouse[$warehouseid]->real + $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'];
6481 $this->stock_warehouse = array();
6486 if (count($prods_arbo) > 0) {
6487 $productCachedList = array();
6488 $stockByComponentList = array();
6490 foreach ($prods_arbo as $componentArr) {
6491 $componentId = $componentArr[
'id'];
6493 if ($componentArr[
'incdec'] == 1) {
6494 if (!isset($productCachedList[$componentId])) {
6495 $componentStatic =
new self($this->db);
6496 $componentStatic->fetch($componentId);
6498 $childrenNb = $componentStatic->hasFatherOrChild(1);
6499 if ($childrenNb == 0) {
6500 $componentStatic->load_stock(
'nobatch,novirtual');
6501 if (!isset($stockByComponentList[$componentId])) {
6502 $stockByComponentList[$componentId] = array(
6506 $stockByComponentList[$componentId][
'qty_need'] += $componentArr[
'nb_total'];
6508 $productCachedList[$componentId] = $componentStatic;
6513 if (!empty($stockByComponentList)) {
6514 foreach ($stockByComponentList as $componentId => $stockByComponentArr) {
6515 if (!isset($productCachedList[$componentId])) {
6516 $componentStatic =
new self($this->db);
6517 $componentStatic->fetch($componentId);
6518 $componentStatic->load_stock(
'nobatch,novirtual');
6519 $productCachedList[$componentId] = $componentStatic;
6521 $component = $productCachedList[$componentId];
6524 if ($component->stock_reel < $stockByComponentArr[
'qty_need']) {
6527 $this->error =
'Not enough component [id='.$componentId.
'] in stock, real='.$component->stock_reel.
' and need='.$stockByComponentArr[
'qty_need'];
6528 $this->errors[] = $this->error;
6529 dol_syslog(__METHOD__.
' : '.$this->error, LOG_ERR);
6531 if (!empty($component->stock_warehouse)) {
6532 foreach ($component->stock_warehouse as $warehouseId => $warehouseObj) {
6533 $kitWarehouseAvailable =
new stdClass();
6534 $kitWarehouseAvailable->id = $warehouseObj->id;
6535 $kitWarehouseAvailable->real = $qtyWish;
6536 $this->stock_warehouse[$warehouseId] = $kitWarehouseAvailable;
6566 $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";
6567 $sql .=
" WHERE pb.fk_product_stock = ps.rowid AND ps.fk_product = ".((int) $this->
id).
" AND pb.batch = '".$this->db->escape($batch).
"'";
6568 $sql .=
" GROUP BY pb.batch, pb.eatby, pb.sellby";
6569 dol_syslog(get_class($this).
"::loadBatchInfo load first entry found for lot/serial = ".$batch, LOG_DEBUG);
6570 $resql = $this->db->query($sql);
6572 $num = $this->db->num_rows($resql);
6575 $obj = $this->db->fetch_object($resql);
6576 $result[] = array(
'batch' => $batch,
'eatby' => $this->db->jdate($obj->eatby),
'sellby' => $this->db->jdate($obj->sellby),
'qty' => $obj->qty);
6582 $this->db->rollback();
6599 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6605 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos";
6607 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product').dol_sanitizeFileName($this->
ref);
6612 $dir_osencoded = $dir;
6614 if (is_dir($dir_osencoded)) {
6615 $originImage = $dir.
'/'.$file[
'name'];
6626 if (is_numeric($result) && $result > 0) {
6643 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6644 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6648 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos/";
6650 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product');
6654 if (file_exists($dir_osencoded)) {
6655 $handle = opendir($dir_osencoded);
6656 if (is_resource($handle)) {
6657 while (($file = readdir($handle)) !==
false) {
6659 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6682 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6683 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6689 $handle = @opendir($dir_osencoded);
6690 if (is_resource($handle)) {
6691 while (($file = readdir($handle)) !==
false) {
6693 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6700 $photo_vignette =
'';
6702 if (preg_match(
'/('.$this->regeximgext.
')$/i', $photo, $regs)) {
6703 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $photo).
'_small'.$regs[0];
6706 $dirthumb = $dir.
'thumbs/';
6710 $obj[
'photo'] = $photo;
6711 if ($photo_vignette &&
dol_is_file($dirthumb.$photo_vignette)) {
6712 $obj[
'photo_vignette'] =
'thumbs/'.$photo_vignette;
6714 $obj[
'photo_vignette'] =
"";
6717 $tabobj[$nbphoto - 1] = $obj;
6720 if ($nbmax && $nbphoto >= $nbmax) {
6742 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6743 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6745 $dir = dirname($file).
'/';
6746 $dirthumb = $dir.
'/thumbs/';
6747 $filename = preg_replace(
'/'.preg_quote($dir,
'/').
'/i',
'', $file);
6753 if (preg_match(
'/('.$this->regeximgext.
')$/i', $filename, $regs)) {
6754 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_small'.$regs[0];
6755 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6759 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_mini'.$regs[0];
6760 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6777 $infoImg = getimagesize($file_osencoded);
6778 $this->imgWidth = $infoImg[0];
6779 $this->imgHeight = $infoImg[1];
6789 global $hookmanager;
6791 $this->nb = array();
6793 $sql =
"SELECT count(p.rowid) as nb, fk_product_type";
6794 $sql .=
" FROM ".$this->db->prefix().
"product as p";
6795 $sql .=
' WHERE p.entity IN ('.getEntity($this->element, 1).
')';
6797 if (is_object($hookmanager)) {
6798 $parameters = array();
6799 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
6800 $sql .= $hookmanager->resPrint;
6802 $sql .=
' GROUP BY fk_product_type';
6804 $resql = $this->db->query($sql);
6806 while ($obj = $this->db->fetch_object($resql)) {
6807 if ($obj->fk_product_type == 1) {
6808 $this->nb[
"services"] = $obj->nb;
6810 $this->nb[
"products"] = $obj->nb;
6813 $this->db->free($resql);
6817 $this->error = $this->db->error();
6859 return $this->mandatory_period == 1;
6869 return $this->status_batch > 0;
6889 $dirsociete = array_merge(array(
'/core/modules/barcode/'),
$conf->modules_parts[
'barcode']);
6890 foreach ($dirsociete as $dirroot) {
6898 '@phan-var-force ModeleNumRefBarCode $mod';
6900 $result = $mod->getNextValue(
$object, $type);
6902 dol_syslog(get_class($this).
"::get_barcode barcode=".$result.
" module=".$var);
6919 $this->specimen = 1;
6921 $this->
ref =
'PRODUCT_SPEC';
6922 $this->label =
'PRODUCT SPECIMEN';
6923 $this->
description =
'This is description of this product specimen that was created the '.dol_print_date($now,
'dayhourlog').
'.';
6924 $this->specimen = 1;
6925 $this->country_id = 1;
6927 $this->status_buy = 1;
6929 $this->sell_or_eat_by_mandatory = 0;
6930 $this->note_private =
'This is a comment (private)';
6931 $this->note_public =
'This is a comment (public)';
6932 $this->date_creation = $now;
6933 $this->date_modification = $now;
6936 $this->weight_units = 3;
6939 $this->length_units = 1;
6941 $this->width_units = 0;
6942 $this->height =
null;
6943 $this->height_units =
null;
6945 $this->surface = 30;
6946 $this->surface_units = 0;
6947 $this->volume = 300;
6948 $this->volume_units = 0;
6950 $this->barcode = -1;
6968 if (empty($this->fk_unit)) {
6971 if (empty($outputlangs)) {
6972 $outputlangs = $langs;
6975 $outputlangs->load(
'products');
6978 $sql =
"SELECT code, label, short_label FROM ".$this->db->prefix().
"c_units where rowid = ".((int) $this->fk_unit);
6980 $resql = $this->db->query($sql);
6982 $this->error = $this->db->error();
6983 dol_syslog(get_class($this).
"::getLabelOfUnit Error ".$this->error, LOG_ERR);
6985 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
6986 if ($type ==
'short') {
6988 $label = $outputlangs->transnoentitiesnoconv($res[
'short_label']);
6990 $label = $outputlangs->trans($res[
'short_label']);
6992 } elseif ($type ==
'code') {
6993 $label = $res[
'code'];
6995 if ($outputlangs->trans(
'unit'.$res[
'code']) ==
'unit'.$res[
'code']) {
6997 $label = $res[
'label'];
7001 $label = $outputlangs->transnoentitiesnoconv(
'unit'.$res[
'code']);
7003 $label = $outputlangs->trans(
'unit'.$res[
'code']);
7008 $this->db->free($resql);
7022 $maxpricesupplier = 0;
7025 include_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.product.class.php';
7027 $product_fourn_list = $product_fourn->list_product_fournisseur_price($this->
id,
'',
'');
7029 if (is_array($product_fourn_list) && count($product_fourn_list) > 0) {
7030 foreach ($product_fourn_list as $productfourn) {
7031 if ($productfourn->fourn_unitprice > $maxpricesupplier) {
7032 $maxpricesupplier = $productfourn->fourn_unitprice;
7040 return $maxpricesupplier;
7056 require_once DOL_DOCUMENT_ROOT.
'/categories/class/categorie.class.php';
7057 return parent::setCategoriesCommon($categories, Categorie::TYPE_PRODUCT);
7071 'product_customer_price',
7072 'product_customer_price_log'
7091 $sql =
"SELECT rowid, level, fk_level, var_percent, var_min_percent FROM ".$this->db->prefix().
"product_pricerules";
7092 $query = $this->db->query($sql);
7096 while ($result = $this->db->fetch_object($query)) {
7097 $rules[$result->level] = $result;
7106 for ($i = 1; $i <= $nbofproducts; $i++) {
7107 $price = $baseprice;
7108 $price_min = $baseprice;
7112 if ($i > 1 && isset($rules[$i]->var_percent) && $rules[$i]->var_percent) {
7113 $price = $prices[$rules[$i]->fk_level] * (1 + ($rules[$i]->var_percent / 100));
7116 $prices[$i] = $price;
7119 if (isset($rules[$i]->var_min_percent) && $rules[$i]->var_min_percent) {
7120 $price_min = $price * (1 - ($rules[$i]->var_min_percent / 100));
7124 $check_amount = (($price == $this->multiprices[$i]) && ($price_min == $this->multiprices_min[$i]));
7125 $check_type = ($baseprice == $this->multiprices_base_type[$i]);
7127 if ($check_amount && $check_type) {
7131 if ($this->
updatePrice($price, $price_type, $user, $price_vat, $price_min, $i, $npr, $psq, 1) < 0) {
7149 return $user->rights->produit;
7151 return $user->rights->service;
7163 $sql =
"SELECT p.rowid, p.ref, p.datec as date_creation, p.tms as date_modification,";
7164 $sql .=
" p.fk_user_author, p.fk_user_modif";
7165 $sql .=
" FROM ".$this->db->prefix().$this->table_element.
" as p";
7166 $sql .=
" WHERE p.rowid = ".((int) $id);
7168 $result = $this->db->query($sql);
7170 if ($this->db->num_rows($result)) {
7171 $obj = $this->db->fetch_object($result);
7173 $this->
id = $obj->rowid;
7174 $this->
ref = $obj->ref;
7176 $this->user_creation_id = $obj->fk_user_author;
7177 $this->user_modification_id = $obj->fk_user_modif;
7179 $this->date_creation = $this->db->jdate($obj->date_creation);
7180 $this->date_modification = $this->db->jdate($obj->date_modification);
7183 $this->db->free($result);
7197 if (empty($this->duration_value)) {
7198 $this->errors[] =
'ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
7201 if ($this->duration_unit ==
's') {
7202 $prodDurationHours = 1. / 3600;
7203 } elseif ($this->duration_unit ==
'i' || $this->duration_unit ==
'mn' || $this->duration_unit ==
'min') {
7204 $prodDurationHours = 1. / 60;
7205 } elseif ($this->duration_unit ==
'h') {
7206 $prodDurationHours = 1.;
7207 } elseif ($this->duration_unit ==
'd') {
7208 $prodDurationHours = 24.;
7209 } elseif ($this->duration_unit ==
'w') {
7210 $prodDurationHours = 24. * 7;
7211 } elseif ($this->duration_unit ==
'm') {
7212 $prodDurationHours = 24. * 30;
7213 } elseif ($this->duration_unit ==
'y') {
7214 $prodDurationHours = 24. * 365;
7216 $prodDurationHours = 0.0;
7218 $prodDurationHours *= $this->duration_value;
7220 return $prodDurationHours;
7233 global $langs,
$conf;
7235 $selected = (empty($arraydata[
'selected']) ? 0 : $arraydata[
'selected']);
7237 $return =
'<div class="box-flex-item box-flex-grow-zero">';
7238 $return .=
'<div class="info-box info-box-sm">';
7239 $return .=
'<div class="info-box-img">';
7242 $label .= $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 120, 160, 0, 0, 0,
'',
'photoref photokanban');
7252 $return .=
'</div>';
7253 $return .=
'<div class="info-box-content">';
7254 $return .=
'<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this,
'getNomUrl') ? $this->
getNomUrl() : $this->ref).
'</span>';
7255 if ($selected >= 0) {
7256 $return .=
'<input id="cb'.$this->id.
'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->
id.
'"'.($selected ?
' checked="checked"' :
'').
'>';
7258 if (property_exists($this,
'label')) {
7259 $return .=
'<br><span class="info-box-label opacitymedium inline-block tdoverflowmax150 valignmiddle" title="'.dol_escape_htmltag($this->label).
'">'.
dol_escape_htmltag($this->label).
'</span>';
7261 if (property_exists($this,
'price') && property_exists($this,
'price_ttc')) {
7262 if ($this->price_base_type ==
'TTC') {
7263 $return .=
'<br><span class="info-box-status amount">'.price($this->price_ttc).
' '.$langs->trans(
"TTC").
'</span>';
7266 $return .=
'<br><span class="info-box-status amount">'.price($this->
price).
' '.$langs->trans(
"HT").
'</span>';
7271 if (property_exists($this,
'stock_reel') && $this->
isProduct()) {
7272 $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>';
7275 if (method_exists($this,
'getLibStatut')) {
7277 $return .=
'<br><div class="info-box-status inline-block valignmiddle">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7279 $return .=
'<div class="info-box-status inline-block valignmiddle marginleftonly paddingleft">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7282 $return .=
'</div>';
7283 $return .=
'</div>';
7284 $return .=
'</div>';
7297 if (!is_numeric($limit)) {
7301 $sql =
"SELECT p.rowid, p.ref, p.label, p.description, p.entity, ef.filename
7302 FROM ".MAIN_DB_PREFIX.
"product AS p
7303 JOIN ".MAIN_DB_PREFIX.
"ecm_files AS ef ON p.rowid = ef.src_object_id
7304 WHERE ef.entity IN (".
getEntity(
'product').
")
7305 AND (ef.filename LIKE '%.png' OR ef.filename LIKE '%.jpeg' OR ef.filename LIKE '%.svg')
7306 GROUP BY p.rowid, p.ref, p.label, p.description, p.entity, ef.filename
7307 ORDER BY p.datec ASC
7308 LIMIT " . ((int) $limit);
7310 $resql = $this->db->query($sql);
7311 $products = array();
7314 while ($obj = $this->db->fetch_object($resql)) {
7315 $products[] = array(
7316 'rowid' => $obj->rowid,
7318 'label' => $obj->label,
7319 'description' => $obj->description,
7320 'entity' => $obj->entity,
7321 'filename' => $obj->filename
7327 if (empty($products)) {
7340 public $picto =
'service';
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
length_accountg($account)
Return General accounting account with defined length (used for product and miscellaneous)
Parent class of all other business classes (invoices, contracts, proposals, orders,...
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.
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.
call_trigger($triggerName, $user)
Call trigger based on this instance.
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.
check_barcode($valuetotest, $typefortest)
Check barcode.
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.
delMultiLangs($langtodelete, $user)
Delete a language for this product.
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.
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)
Recopie les fournisseurs et prix fournisseurs d'un produit/service sur un autre.
const TYPE_PRODUCT
Regular product.
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.
getProductsToPreviewInEmail($limit)
Retrieve and display products.
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)
Charge tableau des stats réception fournisseur pour le produit/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.
setMultiLangs($user)
Update or add a translation for a product.
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.
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_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...
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)
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.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
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.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
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)
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
dol_clone($object, $native=2)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
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.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0)
Clean a string to use it as a file name.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
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, 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)
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.
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
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