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;
65 public $TRIGGER_PREFIX =
'PRODUCT';
70 public $element =
'product';
75 public $table_element =
'product';
80 public $fk_element =
'fk_product';
85 protected $childtables = array(
86 'supplier_proposaldet' => array(
'name' =>
'SupplierProposal',
'parent' =>
'supplier_proposal',
'parentkey' =>
'fk_supplier_proposal'),
87 'propaldet' => array(
'name' =>
'Proposal',
'parent' =>
'propal',
'parentkey' =>
'fk_propal'),
88 'commandedet' => array(
'name' =>
'Order',
'parent' =>
'commande',
'parentkey' =>
'fk_commande'),
89 'facturedet' => array(
'name' =>
'Invoice',
'parent' =>
'facture',
'parentkey' =>
'fk_facture'),
90 'contratdet' => array(
'name' =>
'Contract',
'parent' =>
'contrat',
'parentkey' =>
'fk_contrat'),
91 'facture_fourn_det' => array(
'name' =>
'SupplierInvoice',
'parent' =>
'facture_fourn',
'parentkey' =>
'fk_facture_fourn'),
92 'commande_fournisseurdet' => array(
'name' =>
'SupplierOrder',
'parent' =>
'commande_fournisseur',
'parentkey' =>
'fk_commande'),
93 'mrp_production' => array(
'name' =>
'Mo',
'parent' =>
'mrp_mo',
'parentkey' =>
'fk_mo',
'enabled' =>
'isModEnabled("mrp")'),
94 'bom_bom' => array(
'name' =>
'BOM',
'enabled' =>
'isModEnabled("bom")'),
95 'bom_bomline' => array(
'name' =>
'BOMLine',
'parent' =>
'bom_bom',
'parentkey' =>
'fk_bom',
'enabled' =>
'isModEnabled("bom")'),
103 public $picto =
'product';
114 public $regeximgext =
'\.gif|\.jpg|\.jpeg|\.png|\.bmp|\.webp|\.xpm|\.xbm';
161 public $price_formated;
173 public $price_ttc_formated;
187 public $price_min_ttc;
193 public $price_base_type;
203 public $multiprices = array();
207 public $multiprices_ttc = array();
211 public $multiprices_base_type = array();
215 public $multiprices_default_vat_code = array();
219 public $multiprices_min = array();
223 public $multiprices_min_ttc = array();
227 public $multiprices_tva_tx = array();
231 public $multiprices_recuperableonly = array();
237 public $price_by_qty;
241 public $prices_by_qty = array();
245 public $prices_by_qty_id = array();
249 public $prices_by_qty_list = array();
259 public $multilangs = array();
264 public $default_vat_code;
279 public $remise_percent;
284 public $localtax1_tx;
288 public $localtax2_tx;
292 public $localtax1_type;
296 public $localtax2_type;
303 public $desc_supplier;
307 public $vatrate_supplier;
311 public $default_vat_code_supplier;
316 public $fourn_multicurrency_price;
321 public $fourn_multicurrency_unitprice;
325 public $fourn_multicurrency_tx;
329 public $fourn_multicurrency_id;
333 public $fourn_multicurrency_code;
355 public $qc_frequency;
362 public $stock_reel = 0;
369 public $stock_theorique;
390 public $seuil_stock_alerte = 0;
395 public $desiredstock = 0;
400 public $duration_value;
404 public $duration_unit;
413 public $fk_default_workstation;
435 public $status_buy = 0;
457 public $fk_default_bom;
464 public $product_fourn_price_id;
486 public $status_batch = 0;
493 public $sell_or_eat_by_mandatory = 0;
500 public $batch_mask =
'';
525 public $weight_units;
533 public $length_units;
549 public $height_units;
557 public $surface_units;
565 public $volume_units;
574 public $net_measure_units;
579 public $accountancy_code_sell;
583 public $accountancy_code_sell_intra;
587 public $accountancy_code_sell_export;
591 public $accountancy_code_buy;
595 public $accountancy_code_buy_intra;
599 public $accountancy_code_buy_export;
609 public $barcode_type;
614 public $barcode_type_code;
619 public $stats_propale = array();
624 public $stats_commande = array();
629 public $stats_contrat = array();
634 public $stats_facture = array();
639 public $stats_proposal_supplier = array();
644 public $stats_commande_fournisseur = array();
649 public $stats_expedition = array();
654 public $stats_reception = array();
659 public $stats_mo = array();
664 public $stats_bom = array();
669 public $stats_mrptoconsume = array();
674 public $stats_mrptoproduce = array();
679 public $stats_facturerec = array();
684 public $stats_facture_fournisseur = array();
689 public $stats_facturefournrec = array();
704 public $product_fourn_id;
710 public $product_id_already_linked;
721 public $stock_warehouse = array();
726 public $fk_default_warehouse;
731 public $fk_price_expression;
749 public $fourn_price_base_type;
766 public $ref_supplier;
780 public $price_autogen = 0;
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((
string) $this->accountancy_code_buy);
1050 $this->accountancy_code_buy_intra = trim((
string) $this->accountancy_code_buy_intra);
1051 $this->accountancy_code_buy_export = trim((
string) $this->accountancy_code_buy_export);
1052 $this->accountancy_code_sell = trim((
string) $this->accountancy_code_sell);
1053 $this->accountancy_code_sell_intra = trim((
string) $this->accountancy_code_sell_intra);
1054 $this->accountancy_code_sell_export = trim((
string) $this->accountancy_code_sell_export);
1060 require_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
1061 $this->accountancy_code_buy =
clean_account($this->accountancy_code_buy);
1062 $this->accountancy_code_buy_intra =
clean_account($this->accountancy_code_buy_intra);
1063 $this->accountancy_code_buy_export =
clean_account($this->accountancy_code_buy_export);
1064 $this->accountancy_code_sell =
clean_account($this->accountancy_code_sell);
1065 $this->accountancy_code_sell_intra =
clean_account($this->accountancy_code_sell_intra);
1066 $this->accountancy_code_sell_export =
clean_account($this->accountancy_code_sell_export);
1070 $this->barcode = trim($this->barcode);
1071 $this->mandatory_period = empty($this->mandatory_period) ? 0 : $this->mandatory_period;
1073 if (empty($this->label)) {
1074 $langs->load(
'errors');
1075 $this->errors[] = $langs->trans(
'ErrorMandatoryParametersNotProvided');
1079 if (empty($this->
ref) || $this->
ref ==
'auto') {
1081 $module =
getDolGlobalString(
'PRODUCT_CODEPRODUCT_ADDON',
'mod_codeproduct_leopard');
1082 if ($module !=
'mod_codeproduct_leopard') {
1083 if (substr($module, 0, 16) ==
'mod_codeproduct_' && substr($module, -3) ==
'php') {
1084 $module = substr($module, 0,
dol_strlen($module) - 4);
1087 $modCodeProduct =
new $module();
1088 '@phan-var-force ModeleProductCode $modCodeProduct';
1089 if (!empty($modCodeProduct->code_auto)) {
1090 $this->
ref = $modCodeProduct->getNextValue($this, $this->
type);
1092 unset($modCodeProduct);
1095 if (empty($this->
ref)) {
1096 $this->error =
'ProductModuleNotSetupForAutoRef';
1101 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);
1105 if (empty($this->date_creation)) {
1106 $this->date_creation = $now;
1112 if ($this->barcode ==
'-1' || $this->barcode ==
'auto') {
1113 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1118 $result = $this->
verify();
1121 $sql =
"SELECT count(*) as nb";
1122 $sql .=
" FROM ".$this->db->prefix().
"product";
1123 $sql .=
" WHERE entity IN (".getEntity(
'product').
")";
1124 $sql .=
" AND ref = '".$this->db->escape($this->
ref).
"'";
1126 $result = $this->db->query($sql);
1128 $obj = $this->db->fetch_object($result);
1129 if ($obj->nb == 0) {
1131 $sql =
"INSERT INTO ".$this->db->prefix().
"product (";
1135 $sql .=
", ref_ext";
1136 $sql .=
", price_min";
1137 $sql .=
", price_min_ttc";
1139 $sql .=
", fk_user_author";
1140 $sql .=
", fk_product_type";
1142 $sql .=
", price_ttc";
1143 $sql .=
", price_base_type";
1144 $sql .=
", price_label";
1148 $sql .=
", accountancy_code_buy";
1149 $sql .=
", accountancy_code_buy_intra";
1150 $sql .=
", accountancy_code_buy_export";
1151 $sql .=
", accountancy_code_sell";
1152 $sql .=
", accountancy_code_sell_intra";
1153 $sql .=
", accountancy_code_sell_export";
1156 $sql .=
", finished";
1157 $sql .=
", tobatch";
1158 $sql .=
", sell_or_eat_by_mandatory";
1159 $sql .=
", batch_mask";
1160 $sql .=
", fk_unit";
1161 $sql .=
", mandatory_period";
1162 $sql .=
", stockable_product";
1163 if (!empty($this->default_vat_code)) {
1164 $sql .=
", default_vat_code";
1166 $sql .=
") VALUES (";
1167 $sql .=
"'".$this->db->idate($this->date_creation).
"'";
1168 $sql .=
", ".(!empty($this->entity) ? (int) $this->entity : (int) $conf->entity);
1169 $sql .=
", '".$this->db->escape($this->
ref).
"'";
1170 $sql .=
", ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1171 $sql .=
", ".price2num($price_min_ht);
1172 $sql .=
", ".price2num($price_min_ttc);
1173 $sql .=
", ".(!empty($this->label) ?
"'".$this->db->escape($this->label).
"'" :
"null");
1174 $sql .=
", ".((int) $user->id);
1175 $sql .=
", ".((int) $this->
type);
1176 $sql .=
", ".price2num($price_ht,
'MT');
1177 $sql .=
", ".price2num($price_ttc,
'MT');
1178 $sql .=
", '".$this->db->escape($this->price_base_type).
"'";
1179 $sql .=
", ".(!empty($this->price_label) ?
"'".$this->db->escape($this->price_label).
"'" :
"null");
1180 $sql .=
", ".((int) $this->
status);
1181 $sql .=
", ".((int) $this->status_buy);
1183 $sql .=
", '".$this->db->escape($this->accountancy_code_buy).
"'";
1184 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_intra).
"'";
1185 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_export).
"'";
1186 $sql .=
", '".$this->db->escape($this->accountancy_code_sell).
"'";
1187 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_intra).
"'";
1188 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_export).
"'";
1190 $sql .=
", '".$this->db->escape($this->canvas).
"'";
1191 $sql .=
", ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
'NULL' : (int) $this->finished);
1192 $sql .=
", ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : ((int) $this->status_batch));
1193 $sql .=
", ".((empty($this->sell_or_eat_by_mandatory) || $this->sell_or_eat_by_mandatory < 0) ? 0 : ((int) $this->sell_or_eat_by_mandatory));
1194 $sql .=
", '".$this->db->escape($this->batch_mask).
"'";
1195 $sql .=
", ".($this->fk_unit > 0 ? ((int) $this->fk_unit) :
'NULL');
1196 $sql .=
", '".$this->db->escape((
string) $this->mandatory_period).
"'";
1197 $sql .=
", ".((int) $this->stockable_product);
1198 if (!empty($this->default_vat_code)) {
1199 $sql .=
", '".$this->db->escape($this->default_vat_code).
"'";
1202 dol_syslog(get_class($this).
"::Create", LOG_DEBUG);
1204 $result = $this->db->query($sql);
1206 $id = $this->db->last_insert_id($this->db->prefix().
"product");
1210 $this->
price = $price_ht;
1211 $this->price_ttc = $price_ttc;
1212 $this->price_min = $price_min_ht;
1213 $this->price_min_ttc = $price_min_ttc;
1217 if ($this->
update($id, $user, 1,
'add') <= 0) {
1222 $this->error = $this->db->lasterror();
1227 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " .((int) $this->id) .
" AND entity = " . ((
int) $conf->entity));
1229 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1230 $sql .=
" fk_product";
1232 $sql .=
", accountancy_code_buy";
1233 $sql .=
", accountancy_code_buy_intra";
1234 $sql .=
", accountancy_code_buy_export";
1235 $sql .=
", accountancy_code_sell";
1236 $sql .=
", accountancy_code_sell_intra";
1237 $sql .=
", accountancy_code_sell_export";
1238 $sql .=
") VALUES (";
1240 $sql .=
", " . ((int) $conf->entity);
1241 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1242 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1243 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1244 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1245 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1246 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1248 $result = $this->db->query($sql);
1251 $this->error =
'ErrorFailedToInsertAccountancyForEntity';
1256 $this->error =
'ErrorFailedToGetInsertedId';
1260 $this->error = $this->db->lasterror();
1264 $langs->load(
"products");
1266 $this->error =
"ErrorProductAlreadyExists";
1267 dol_syslog(get_class($this).
"::Create fails, ref ".$this->
ref.
" already exists");
1271 $this->error = $this->db->lasterror();
1274 if (!$error && !$notrigger) {
1276 $result = $this->call_trigger(
'PRODUCT_CREATE', $user);
1284 $this->db->commit();
1287 $this->db->rollback();
1291 $this->db->rollback();
1292 dol_syslog(get_class($this).
"::Create fails verify ".implode(
',', $this->errors), LOG_WARNING);
1308 $this->errors = array();
1311 $this->
ref = trim($this->
ref);
1314 $this->errors[] =
'ErrorBadRef';
1318 $arrayofnonnegativevalue = array(
'weight' =>
'Weight',
'width' =>
'Width',
'height' =>
'Height',
'length' =>
'Length',
'surface' =>
'Surface',
'volume' =>
'Volume');
1319 foreach ($arrayofnonnegativevalue as $key => $value) {
1320 if (property_exists($this, $key) && !empty($this->$key) && ($this->$key < 0)) {
1321 $langs->loadLangs(array(
"main",
"other"));
1322 $this->error = $langs->trans(
"FieldCannotBeNegative", $langs->transnoentitiesnoconv($value));
1323 $this->errors[] = $this->error;
1328 $rescode = $this->
check_barcode($this->barcode, $this->barcode_type_code);
1330 if ($rescode == -1) {
1331 $this->errors[] =
'ErrorBadBarCodeSyntax';
1332 } elseif ($rescode == -2) {
1333 $this->errors[] =
'ErrorBarCodeRequired';
1334 } elseif ($rescode == -3) {
1336 $this->errors[] =
'ErrorBarCodeAlreadyUsed';
1364 $dirsociete = array_merge(array(
'/core/modules/barcode/'), $conf->modules_parts[
'barcode']);
1365 foreach ($dirsociete as $dirroot) {
1372 $mod =
new $module();
1373 '@phan-var-force ModeleNumRefBarCode $mod';
1375 dol_syslog(get_class($this).
"::check_barcode value=".$valuetotest.
" type=".$typefortest.
" module=".$module);
1376 $result = $mod->verif($this->db, $valuetotest, $this, 0, $typefortest);
1394 public function update($id, $user, $notrigger = 0, $action =
'update', $updatetype =
false)
1396 global $langs, $conf, $hookmanager;
1401 if (!$this->label) {
1402 $this->label =
'MISSING LABEL';
1407 $this->
ref = trim($this->
ref);
1411 $this->label = trim($this->label);
1413 $this->note_private = (isset($this->note_private) ? trim($this->note_private) :
null);
1414 $this->note_public = (isset($this->note_public) ? trim($this->note_public) :
null);
1415 $this->net_measure =
price2num($this->net_measure);
1416 $this->net_measure_units = (!is_numeric($this->net_measure_units) ? null : (int) $this->net_measure_units);
1417 $this->weight =
price2num($this->weight);
1418 $this->weight_units = (!is_numeric($this->weight_units) ? null : (int) $this->weight_units);
1419 $this->length =
price2num($this->length);
1420 $this->length_units = (!is_numeric($this->length_units) ? null : (int) $this->length_units);
1422 $this->width_units = (!is_numeric($this->width_units) ? null : (int) $this->width_units);
1423 $this->height =
price2num($this->height);
1424 $this->height_units = (!is_numeric($this->height_units) ? null : (int) $this->height_units);
1425 $this->surface =
price2num($this->surface);
1426 $this->surface_units = (!is_numeric($this->surface_units) ? null : (int) $this->surface_units);
1427 $this->volume =
price2num($this->volume);
1428 $this->volume_units = (!is_numeric($this->volume_units) ? null : (int) $this->volume_units);
1431 if (is_numeric($this->length_units)) {
1432 $this->width_units = $this->length_units;
1434 if (is_numeric($this->length_units)) {
1435 $this->height_units = $this->length_units;
1439 if (empty($this->surface) && !empty($this->length) && !empty($this->width) && $this->length_units == $this->width_units) {
1440 $this->surface = (float) $this->length * (
float) $this->width;
1443 if (empty($this->volume) && !empty($this->surface) && !empty($this->height) && $this->length_units == $this->height_units) {
1444 $this->volume = $this->surface * (float) $this->height;
1448 if (empty($this->tva_tx)) {
1451 if (empty($this->tva_npr)) {
1454 if (empty($this->localtax1_tx)) {
1455 $this->localtax1_tx = 0;
1457 if (empty($this->localtax2_tx)) {
1458 $this->localtax2_tx = 0;
1460 if (empty($this->localtax1_type)) {
1461 $this->localtax1_type =
'0';
1463 if (empty($this->localtax2_type)) {
1464 $this->localtax2_type =
'0';
1466 if (empty($this->
status)) {
1469 if (empty($this->status_buy)) {
1470 $this->status_buy = 0;
1473 if (empty($this->country_id)) {
1474 $this->country_id = 0;
1476 if (empty($this->country_id) && !empty($this->country_code)) {
1477 $country_id =
getCountry($this->country_code,
'3');
1478 $this->country_id = is_int($country_id) ? $country_id : 0;
1481 if (empty($this->state_id)) {
1482 $this->state_id = 0;
1485 if (empty($this->stockable_product)) {
1486 $this->stockable_product = 0;
1490 if ($this->barcode ==
'-1' || $this->barcode ==
'auto') {
1491 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1495 $this->barcode = (empty($this->barcode) ?
'' : trim($this->barcode));
1497 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
1498 $this->accountancy_code_buy_intra = (!empty($this->accountancy_code_buy_intra) ? trim($this->accountancy_code_buy_intra) :
'');
1499 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
1500 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
1501 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
1502 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
1508 require_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
1509 $this->accountancy_code_buy =
clean_account($this->accountancy_code_buy);
1510 $this->accountancy_code_buy_intra =
clean_account($this->accountancy_code_buy_intra);
1511 $this->accountancy_code_buy_export =
clean_account($this->accountancy_code_buy_export);
1512 $this->accountancy_code_sell =
clean_account($this->accountancy_code_sell);
1513 $this->accountancy_code_sell_intra =
clean_account($this->accountancy_code_sell_intra);
1514 $this->accountancy_code_sell_export =
clean_account($this->accountancy_code_sell_export);
1521 if ($action !=
'add') {
1522 $result = $this->
verify();
1534 if (is_null($this->oldcopy) || (is_object($this->oldcopy) && empty($this->oldcopy->id)) || !($this->oldcopy instanceof
Product)) {
1539 if ($this->
hasbatch() && !$this->oldcopy->hasbatch()) {
1541 $valueforundefinedlot =
'000000';
1546 dol_syslog(
"Flag batch of product id=".$this->
id.
" is set to ON, so we will create missing records into product_batch");
1549 foreach ($this->stock_warehouse as $idW => $ObjW) {
1551 foreach ($ObjW->detail_batch as $detail) {
1552 if ($detail->batch == $valueforundefinedlot || $detail->batch ==
'Undefined') {
1554 $sqlclean =
"DELETE FROM ".$this->db->prefix().
"product_batch WHERE batch in('Undefined', '".$this->db->escape($valueforundefinedlot).
"') AND fk_product_stock = ".((int) $ObjW->id);
1555 $result = $this->db->query($sqlclean);
1563 $qty_batch += $detail->qty;
1567 if ($ObjW->real != $qty_batch) {
1569 $ObjBatch->batch = $valueforundefinedlot;
1570 $ObjBatch->qty = ($ObjW->real - $qty_batch);
1571 $ObjBatch->fk_product_stock = (int) $ObjW->id;
1573 if ($ObjBatch->create($user, 1) < 0) {
1575 $this->errors = $ObjBatch->errors;
1580 if ($ObjLot->fetch(0, $this->id, $valueforundefinedlot) == 0) {
1581 $ObjLot->fk_product = $this->id;
1582 $ObjLot->entity = (int) $this->entity;
1583 $ObjLot->fk_user_creat = $user->id;
1584 $ObjLot->batch = $valueforundefinedlot;
1585 if ($ObjLot->create($user, 1) < 0) {
1587 $this->errors = $ObjLot->errors;
1595 $sql =
"UPDATE ".$this->db->prefix().
"product";
1596 $sql .=
" SET label = '".$this->db->escape($this->label).
"'";
1599 $sql .=
", fk_product_type = ".((int) $this->
type);
1602 $sql .=
", ref = '".$this->db->escape($this->
ref).
"'";
1603 $sql .=
", ref_ext = ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1604 $sql .=
", default_vat_code = ".($this->default_vat_code ?
"'".$this->db->escape($this->default_vat_code).
"'" :
"null");
1605 $sql .=
", tva_tx = ".((float) $this->tva_tx);
1606 $sql .=
", recuperableonly = ".((int) $this->tva_npr);
1607 $sql .=
", localtax1_tx = ".((float) $this->localtax1_tx);
1608 $sql .=
", localtax2_tx = ".((float) $this->localtax2_tx);
1609 $sql .=
", localtax1_type = ".($this->localtax1_type !=
'' ?
"'".$this->db->escape($this->localtax1_type).
"'" :
"'0'");
1610 $sql .=
", localtax2_type = ".($this->localtax2_type !=
'' ?
"'".$this->db->escape($this->localtax2_type).
"'" :
"'0'");
1612 $sql .=
", barcode = ".(empty($this->barcode) ?
"null" :
"'".$this->db->escape($this->barcode).
"'");
1613 $sql .=
", fk_barcode_type = ".(empty($this->barcode_type) ?
"null" : $this->db->escape((
string) $this->barcode_type));
1615 $sql .=
", tosell = ".(int) $this->
status;
1616 $sql .=
", tobuy = ".(int) $this->status_buy;
1617 $sql .=
", tobatch = ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : (int) $this->status_batch);
1618 $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);
1619 $sql .=
", batch_mask = '".$this->db->escape($this->batch_mask).
"'";
1621 $sql .=
", finished = ".((!isset($this->finished) || $this->finished < 0 || $this->finished ===
'') ?
"null" : (int) $this->finished);
1622 $sql .=
", fk_default_bom = ".((!isset($this->fk_default_bom) || $this->fk_default_bom < 0 || $this->fk_default_bom ==
'') ?
"null" : (int) $this->fk_default_bom);
1623 $sql .=
", net_measure = ".($this->net_measure !=
'' ?
"'".$this->db->escape($this->net_measure).
"'" :
'null');
1624 $sql .=
", net_measure_units = ".((string) $this->net_measure_units !=
'' ? ((
int) $this->net_measure_units) :
'null');
1625 $sql .=
", weight = ".($this->weight !=
'' ?
"'".$this->db->escape($this->weight).
"'" :
'null');
1626 $sql .=
", weight_units = ".((string) $this->weight_units !=
'' ? ((
int) $this->weight_units) :
'null');
1627 $sql .=
", length = ".($this->length !=
'' ?
"'".$this->db->escape($this->length).
"'" :
'null');
1628 $sql .=
", length_units = ".((string) $this->length_units !=
'' ? ((
int) $this->length_units) :
'null');
1629 $sql .=
", width= ".($this->width !=
'' ?
"'".$this->db->escape($this->width).
"'" :
'null');
1630 $sql .=
", width_units = ".((string) $this->width_units !=
'' ? ((
int) $this->width_units) :
'null');
1631 $sql .=
", height = ".($this->height !=
'' ?
"'".$this->db->escape($this->height).
"'" :
'null');
1632 $sql .=
", height_units = ".((string) $this->height_units !=
'' ? ((
int) $this->height_units) :
'null');
1633 $sql .=
", surface = ".($this->surface !=
'' ?
"'".$this->db->escape($this->surface).
"'" :
'null');
1634 $sql .=
", surface_units = ".((string) $this->surface_units !=
'' ? ((
int) $this->surface_units) :
'null');
1635 $sql .=
", volume = ".($this->volume !=
'' ?
"'".$this->db->escape($this->volume).
"'" :
'null');
1636 $sql .=
", volume_units = ".((string) $this->volume_units !=
'' ? ((
int) $this->volume_units) :
'null');
1637 $sql .=
", fk_default_warehouse = ".($this->fk_default_warehouse > 0 ? ((int) $this->fk_default_warehouse) :
'null');
1638 $sql .=
", fk_default_workstation = ".($this->fk_default_workstation > 0 ? ((int) $this->fk_default_workstation) :
'null');
1639 $sql .=
", seuil_stock_alerte = ".((isset($this->seuil_stock_alerte) && is_numeric($this->seuil_stock_alerte)) ? (
float) $this->seuil_stock_alerte :
'null');
1640 $sql .=
", description = '".$this->db->escape($this->
description).
"'";
1641 $sql .=
", url = ".($this->url ?
"'".$this->db->escape($this->url).
"'" :
'null');
1642 $sql .=
", customcode = '".$this->db->escape($this->customcode).
"'";
1643 $sql .=
", fk_country = ".($this->country_id > 0 ? (int) $this->country_id :
'null');
1644 $sql .=
", fk_state = ".($this->state_id > 0 ? (int) $this->state_id :
'null');
1645 $sql .=
", lifetime = ".($this->lifetime > 0 ? (int) $this->lifetime :
'null');
1646 $sql .=
", qc_frequency = ".($this->qc_frequency > 0 ? (int) $this->qc_frequency :
'null');
1647 $sql .=
", note = ".(isset($this->note_private) ?
"'".$this->db->escape($this->note_private).
"'" :
'null');
1648 $sql .=
", note_public = ".(isset($this->note_public) ?
"'".$this->db->escape($this->note_public).
"'" :
'null');
1649 $sql .=
", duration = '".$this->db->escape($this->duration_value.$this->duration_unit).
"'";
1651 $sql .=
", accountancy_code_buy = '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1652 $sql .=
", accountancy_code_buy_intra = '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1653 $sql .=
", accountancy_code_buy_export = '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1654 $sql .=
", accountancy_code_sell= '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1655 $sql .=
", accountancy_code_sell_intra= '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1656 $sql .=
", accountancy_code_sell_export= '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1658 $sql .=
", desiredstock = ".((isset($this->desiredstock) && is_numeric($this->desiredstock)) ? (
float) $this->desiredstock :
"null");
1659 $sql .=
", cost_price = ".($this->cost_price !=
'' ? ((float) $this->cost_price) :
'null');
1660 $sql .=
", fk_unit= ".(!$this->fk_unit ?
'NULL' : (int) $this->fk_unit);
1661 $sql .=
", price_autogen = ".(!$this->price_autogen ? 0 : 1);
1662 $sql .=
", fk_price_expression = ".($this->fk_price_expression != 0 ? (int) $this->fk_price_expression :
'NULL');
1663 $sql .=
", fk_user_modif = ".($user->id > 0 ? (int) $user->id :
'NULL');
1664 $sql .=
", mandatory_period = ".((int) $this->mandatory_period);
1665 $sql .=
", stockable_product = ".(int) $this->stockable_product;
1667 $sql .=
", packaging = ".(float) $this->packaging;
1671 $sql .=
" WHERE rowid = ".((int) $id);
1673 dol_syslog(get_class($this).
"::update", LOG_DEBUG);
1675 $resql = $this->db->query($sql);
1682 $this->db->rollback();
1691 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " . ((
int) $this->id) .
" AND entity = " . ((
int) $conf->entity));
1693 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1694 $sql .=
" fk_product";
1696 $sql .=
", accountancy_code_buy";
1697 $sql .=
", accountancy_code_buy_intra";
1698 $sql .=
", accountancy_code_buy_export";
1699 $sql .=
", accountancy_code_sell";
1700 $sql .=
", accountancy_code_sell_intra";
1701 $sql .=
", accountancy_code_sell_export";
1702 $sql .=
") VALUES (";
1703 $sql .= ((int) $this->
id);
1704 $sql .=
", " . ((int) $conf->entity);
1705 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1706 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1707 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1708 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1709 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1710 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1712 $result = $this->db->query($sql);
1715 $this->error =
'ErrorFailedToUpdateAccountancyForEntity';
1719 if (!$this->
hasbatch() && $this->oldcopy->hasbatch()) {
1721 $sql =
'SELECT pb.qty, ps.fk_entrepot, pb.batch FROM '.MAIN_DB_PREFIX.
'product_batch as pb';
1722 $sql .=
' INNER JOIN '.MAIN_DB_PREFIX.
'product_stock as ps ON (ps.rowid = pb.fk_product_stock)';
1723 $sql .=
' WHERE ps.fk_product = '.(int) $this->
id;
1725 $resql = $this->db->query($sql);
1729 while ($obj = $this->db->fetch_object($resql)) {
1731 $fk_entrepot = $obj->fk_entrepot;
1735 $batch = $obj->batch;
1738 $addOremove = $value > 0 ? 1 : 0;
1739 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1740 $res = $this->
correct_stock_batch($user, $fk_entrepot, abs($value), $addOremove, $label, $price, $dlc, $dluo, $batch, $inventorycode,
'',
null, 0,
null,
true);
1743 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1744 $res = $this->
correct_stock($user, $fk_entrepot, abs($value), (
int) empty($addOremove), $label, $price, $inventorycode,
'',
null, 0);
1763 if (!$error && !$notrigger) {
1765 $result = $this->call_trigger(
'PRODUCT_MODIFY', $user);
1772 if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) {
1774 if ($conf->product->dir_output) {
1777 if (file_exists($olddir)) {
1781 $res = @rename($olddir, $newdir);
1783 $langs->load(
"errors");
1784 $this->error = $langs->trans(
'ErrorFailToRenameDir', $olddir, $newdir);
1788 require_once DOL_DOCUMENT_ROOT .
'/ecm/class/ecmfiles.class.php';
1789 $ecmfiles =
new EcmFiles($this->db);
1790 $ecmfiles->updateAfterRename(
"produit/".
dol_sanitizeFileName($this->oldcopy->ref),
"produit/".dol_sanitizeFileName($this->ref));
1798 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1802 foreach ($comb->fetchAllByFkProductParent($this->id) as $currcomb) {
1803 $currcomb->updateProperties($this, $user);
1807 $this->db->commit();
1810 $this->db->rollback();
1814 if ($this->db->errno() ==
'DB_ERROR_RECORD_ALREADY_EXISTS') {
1815 $langs->load(
"errors");
1816 if (empty($conf->barcode->enabled) || empty($this->barcode)) {
1817 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductAlreadyExists", $this->
ref);
1819 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductBarCodeAlreadyExists", $this->barcode);
1821 $this->errors[] = $this->error;
1822 $this->db->rollback();
1825 $this->error = $langs->trans(
"Error").
" : ".$this->db->error().
" - ".$sql;
1826 $this->errors[] = $this->error;
1827 $this->db->rollback();
1832 $this->db->rollback();
1833 dol_syslog(get_class($this).
"::Update fails verify ".implode(
',', $this->errors), LOG_WARNING);
1845 public function delete(
User $user, $notrigger = 0)
1848 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
1853 if (empty($this->
id)) {
1854 $this->error =
"Object must be fetched before calling delete";
1857 if (($this->
isProduct() && !$user->
hasRight(
'produit',
'supprimer')) || ($this->isService() && !$user->hasRight(
'service',
'supprimer'))) {
1858 $this->error =
"ErrorForbidden";
1863 if (empty($objectisused)) {
1866 if (empty($notrigger)) {
1868 $result = $this->call_trigger(
'PRODUCT_DELETE', $user);
1877 $sql =
"DELETE FROM ".$this->db->prefix().
'product_batch';
1878 $sql .=
" WHERE fk_product_stock IN (";
1879 $sql .=
"SELECT rowid FROM ".$this->db->prefix().
'product_stock';
1880 $sql .=
" WHERE fk_product = ".((int) $this->
id).
")";
1882 $result = $this->db->query($sql);
1885 $this->errors[] = $this->db->lasterror();
1891 $elements = array(
'product_fournisseur_price',
'product_price',
'product_lang',
'categorie_product',
'product_stock',
'product_customer_price',
'product_lot');
1892 foreach ($elements as $table) {
1894 $sql =
"DELETE FROM ".$this->db->prefix().$table;
1895 $sql .=
" WHERE fk_product = ".(int) $this->
id;
1897 $result = $this->db->query($sql);
1900 $this->errors[] = $this->db->lasterror();
1907 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1908 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination2ValuePair.class.php';
1913 if ($prodcomb->deleteByFkProductParent($user, $this->id) < 0) {
1915 $this->errors[] =
'Error deleting combinations';
1919 if (!$error && ($prodcomb->fetchByFkProductChild($this->id) > 0) && ($prodcomb->delete($user) < 0)) {
1921 $this->errors[] =
'Error deleting child combination';
1927 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
1928 $sql .=
" WHERE fk_product_pere = ".(int) $this->
id.
" OR fk_product_fils = ".(
int) $this->id;
1930 $result = $this->db->query($sql);
1933 $this->errors[] = $this->db->lasterror();
1942 dol_syslog(get_class($this).
"::delete error -4 ".$this->error, LOG_ERR);
1948 $sqlz =
"DELETE FROM ".$this->db->prefix().
"product";
1949 $sqlz .=
" WHERE rowid = ".(int) $this->
id;
1951 $resultz = $this->db->query($sqlz);
1954 $this->errors[] = $this->db->lasterror();
1970 if ($conf->product->dir_output) {
1971 $dir = $conf->product->dir_output.
"/".$ref;
1972 if (file_exists($dir)) {
1975 $this->errors[] =
'ErrorFailToDeleteDir';
1983 $this->db->commit();
1986 foreach ($this->errors as $errmsg) {
1987 dol_syslog(get_class($this).
"::delete ".$errmsg, LOG_ERR);
1988 $this->error .= ($this->error ?
', '.$errmsg : $errmsg);
1990 $this->db->rollback();
1994 $this->error =
"ErrorRecordIsUsedCantDelete";
2008 $sellByLabel = $langs->trans(
'SellByDate');
2009 $eatByLabel = $langs->trans(
'EatByDate');
2011 self::SELL_OR_EAT_BY_MANDATORY_ID_NONE => $langs->trans(
'BatchSellOrEatByMandatoryNone'),
2012 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY => $sellByLabel,
2013 self::SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY => $eatByLabel,
2014 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT => $langs->trans(
'BatchSellOrEatByMandatoryAll', $sellByLabel, $eatByLabel),
2025 $sellOrEatByMandatoryLabel =
'';
2028 if (isset($sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory])) {
2029 $sellOrEatByMandatoryLabel = $sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory];
2032 return $sellOrEatByMandatoryLabel;
2045 $langs_available = $langs->get_available_languages(DOL_DOCUMENT_ROOT, 0, 2);
2046 $current_lang = $langs->getDefaultLang();
2048 foreach ($langs_available as $key => $value) {
2049 if ($key == $current_lang) {
2050 $sql =
"SELECT rowid";
2051 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2052 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2053 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
2055 $result = $this->db->query($sql);
2057 if ($this->db->num_rows($result)) {
2058 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
2060 $sql2 .=
" label='".$this->db->escape($this->label).
"',";
2061 $sql2 .=
" description='".$this->db->escape($this->
description).
"'";
2063 $sql2 .=
", note='".$this->db->escape($this->other).
"'";
2065 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
2067 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
2072 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->label).
"',";
2073 $sql2 .=
" '".$this->db->escape($this->
description).
"'";
2075 $sql2 .=
", '".$this->db->escape($this->other).
"'";
2079 dol_syslog(get_class($this).
'::setMultiLangs key = current_lang = '.$key);
2080 if (!$this->db->query($sql2)) {
2081 $this->error = $this->db->lasterror();
2084 } elseif (isset($this->multilangs[$key])) {
2085 if (empty($this->multilangs[$key][
"label"])) {
2086 $this->errors[] = $key .
' : ' . $langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Label"));
2090 $sql =
"SELECT rowid";
2091 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2092 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2093 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
2095 $result = $this->db->query($sql);
2097 if ($this->db->num_rows($result)) {
2098 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
2100 $sql2 .=
" label = '".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
2101 $sql2 .=
" description = '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
2104 $sql2 .=
", note = '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
2106 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
2108 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
2113 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
2114 $sql2 .=
" '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
2117 $sql2 .=
", '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
2123 if ($this->multilangs[
"$key"][
"label"] || $this->multilangs[
"$key"][
"description"]) {
2124 if (!$this->db->query($sql2)) {
2125 $this->error = $this->db->lasterror();
2135 $result = $this->call_trigger(
'PRODUCT_SET_MULTILANGS', $user);
2137 $this->error = $this->db->lasterror();
2155 $sql =
"DELETE FROM ".$this->db->prefix().
"product_lang";
2156 $sql .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($langtodelete).
"'";
2158 dol_syslog(get_class($this).
'::delMultiLangs', LOG_DEBUG);
2159 $result = $this->db->query($sql);
2162 $result = $this->call_trigger(
'PRODUCT_DEL_MULTILANGS', $user);
2164 $this->error = $this->db->lasterror();
2165 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
2169 unset($this->multilangs[$langtodelete]);
2172 $this->error = $this->db->lasterror();
2173 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
2194 if ($type ==
'buy') {
2195 $field =
'accountancy_code_buy';
2196 } elseif ($type ==
'buy_intra') {
2197 $field =
'accountancy_code_buy_intra';
2198 } elseif ($type ==
'buy_export') {
2199 $field =
'accountancy_code_buy_export';
2200 } elseif ($type ==
'sell') {
2201 $field =
'accountancy_code_sell';
2202 } elseif ($type ==
'sell_intra') {
2203 $field =
'accountancy_code_sell_intra';
2204 } elseif ($type ==
'sell_export') {
2205 $field =
'accountancy_code_sell_export';
2210 $sql =
"UPDATE ".$this->db->prefix().$this->table_element.
" SET ";
2211 $sql .=
"$field = '".$this->db->escape($value).
"'";
2212 $sql .=
" WHERE rowid = ".((int) $this->
id);
2215 $resql = $this->db->query($sql);
2219 $result = $this->call_trigger(
'PRODUCT_MODIFY', $user);
2226 $this->db->rollback();
2230 $this->$field = $value;
2232 $this->db->commit();
2235 $this->error = $this->db->lasterror();
2236 $this->db->rollback();
2250 $current_lang = $langs->getDefaultLang();
2252 $sql =
"SELECT lang, label, description, note as other";
2253 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2254 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2256 $result = $this->db->query($sql);
2258 while ($obj = $this->db->fetch_object($result)) {
2260 if ($obj->lang == $current_lang) {
2261 $this->label = $obj->label;
2263 $this->other = $obj->other;
2265 $this->multilangs[(string) $obj->lang][
"label"] = $obj->label;
2266 $this->multilangs[(string) $obj->lang][
"description"] = $obj->description;
2267 $this->multilangs[(string) $obj->lang][
"other"] = $obj->other;
2271 $this->error =
"Error: ".$this->db->lasterror().
" - ".$sql;
2284 $testExit = array(
'multiprices',
'multiprices_ttc',
'multiprices_base_type',
'multiprices_min',
'multiprices_min_ttc',
'multiprices_tva_tx',
'multiprices_recuperableonly');
2286 foreach ($testExit as $field) {
2287 if (!isset($this->$field)) {
2290 $tmparray = $this->$field;
2291 if (!isset($tmparray[$level])) {
2297 'level' => $level ? $level : 1,
2298 'multiprices' => (float) $this->multiprices[$level],
2299 'multiprices_ttc' => (
float) $this->multiprices_ttc[$level],
2300 'multiprices_base_type' => $this->multiprices_base_type[$level],
2301 'multiprices_min' => (float) $this->multiprices_min[$level],
2302 'multiprices_min_ttc' => (
float) $this->multiprices_min_ttc[$level],
2303 'multiprices_tva_tx' => (float) $this->multiprices_tva_tx[$level],
2304 'multiprices_recuperableonly' => (
float) $this->multiprices_recuperableonly[$level],
2327 if (empty($this->price_by_qty)) {
2328 $this->price_by_qty = 0;
2332 $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,";
2333 $sql .=
" localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, price_min,price_min_ttc,price_by_qty,entity,fk_price_expression) ";
2334 $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).
",";
2335 $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');
2338 dol_syslog(get_class($this).
"::_log_price", LOG_DEBUG);
2339 $resql = $this->db->query($sql);
2341 $this->error = $this->db->lasterror();
2361 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price_by_qty";
2362 $sql .=
" WHERE fk_product_price = ".((int) $rowid);
2363 $resql = $this->db->query($sql);
2365 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price";
2366 $sql .=
" WHERE rowid=".((int) $rowid);
2367 $resql = $this->db->query($sql);
2371 $this->error = $this->db->lasterror();
2386 public function getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp = 0)
2388 global $hookmanager, $action;
2391 if (is_object($hookmanager)) {
2392 $parameters = array(
'thirdparty_seller' => $thirdparty_seller,
'thirdparty_buyer' => $thirdparty_buyer,
'pqp' => $pqp);
2394 $reshook = $hookmanager->executeHooks(
'getSellPrice', $parameters, $this, $action);
2396 return $hookmanager->resArray;
2401 $tva_tx =
get_default_tva($thirdparty_seller, $thirdparty_buyer, $this->
id);
2402 $tva_npr =
get_default_npr($thirdparty_seller, $thirdparty_buyer, $this->
id);
2403 if (empty($tva_tx)) {
2407 $pu_ht = $this->price;
2408 $pu_ttc = $this->price_ttc;
2409 $price_min = $this->price_min;
2410 $price_min_ttc = $this->price_min_ttc;
2411 $price_base_type = $this->price_base_type;
2415 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2419 $filter = array(
't.fk_product' => (
string) $this->
id,
't.fk_soc' => (
string) $thirdparty_buyer->id);
2422 $pricebycustomerexist =
false;
2423 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2425 if (count($prodcustprice->lines) > 0) {
2426 $date_now = (int) floor(
dol_now() / 86400) * 86400;
2427 foreach ($prodcustprice->lines as $k => $custprice_line) {
2428 if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
2429 $pricebycustomerexist =
true;
2430 $pu_ht =
price($custprice_line->price);
2431 $price_min =
price($custprice_line->price_min);
2432 $price_min_ttc =
price($custprice_line->price_min_ttc);
2433 $pu_ttc =
price($custprice_line->price_ttc);
2434 $price_base_type = $custprice_line->price_base_type;
2435 $tva_tx = $custprice_line->tva_tx;
2436 if ($custprice_line->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2437 $tva_tx .=
' (' . $custprice_line->default_vat_code .
')';
2439 $tva_npr = $custprice_line->recuperableonly;
2440 if (empty($tva_tx)) {
2449 if (!$pricebycustomerexist && !empty($thirdparty_buyer->price_level)) {
2450 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
2451 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
2452 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
2453 $price_min_ttc = $this->multiprices_min_ttc[$thirdparty_buyer->price_level];
2454 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
2457 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2458 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2460 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2461 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2463 if (empty($tva_tx)) {
2468 } elseif (
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !empty($thirdparty_buyer->price_level)) {
2469 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
2470 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
2471 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
2472 $price_min_ttc = $this->multiprices_min_ttc[$thirdparty_buyer->price_level];
2473 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
2476 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2477 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2479 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2480 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2482 if (empty($tva_tx)) {
2488 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2492 $filter = array(
't.fk_product' => (
string) $this->
id,
't.fk_soc' => (
string) $thirdparty_buyer->id);
2494 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2496 if (count($prodcustprice->lines) > 0) {
2497 $date_now = (int) floor(
dol_now() / 86400) * 86400;
2498 foreach ($prodcustprice->lines as $k => $custprice_line) {
2499 if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
2500 $pu_ht =
price($custprice_line->price);
2501 $price_min =
price($custprice_line->price_min);
2502 $price_min_ttc =
price($custprice_line->price_min_ttc);
2503 $pu_ttc =
price($custprice_line->price_ttc);
2504 $price_base_type = $custprice_line->price_base_type;
2505 $tva_tx = $custprice_line->tva_tx;
2506 if ($custprice_line->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2507 $tva_tx .=
' (' . $custprice_line->default_vat_code .
')';
2509 $tva_npr = $custprice_line->recuperableonly;
2510 if (empty($tva_tx)) {
2520 if ($this->prices_by_qty[0]) {
2523 foreach ($this->prices_by_qty_list[0] as $priceforthequantityarray) {
2524 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2528 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2529 $pu_ht = $priceforthequantityarray[
'unitprice'];
2531 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2538 if ($this->prices_by_qty[$thirdparty_buyer->price_level]) {
2541 foreach ($this->prices_by_qty_list[$thirdparty_buyer->price_level] as $priceforthequantityarray) {
2542 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2546 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2547 $pu_ht = $priceforthequantityarray[
'unitprice'];
2549 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2556 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);
2573 public function get_buyprice($prodfournprice, $qty, $product_id = 0, $fourn_ref =
'', $fk_soc = 0)
2576 global $action, $hookmanager;
2579 if (is_object($hookmanager)) {
2580 $parameters = array(
2581 'prodfournprice' => $prodfournprice,
2583 'product_id' => $product_id,
2584 'fourn_ref' => $fourn_ref,
2585 'fk_soc' => $fk_soc,
2588 $reshook = $hookmanager->executeHooks(
'getBuyPrice', $parameters, $this, $action);
2590 return $hookmanager->resArray;
2597 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2598 $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,";
2599 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2600 $sql .=
" pfp.packaging";
2601 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2602 $sql .=
" WHERE pfp.rowid = ".((int) $prodfournprice);
2604 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2606 $sql .=
" ORDER BY pfp.quantity DESC";
2608 dol_syslog(get_class($this).
"::get_buyprice first search by prodfournprice/qty", LOG_DEBUG);
2609 $resql = $this->db->query($sql);
2611 $obj = $this->db->fetch_object($resql);
2612 if ($obj && $obj->quantity > 0) {
2613 if (
isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2615 $prod_supplier->product_fourn_price_id = $obj->rowid;
2616 $prod_supplier->id = $obj->fk_product;
2617 $prod_supplier->fourn_qty = $obj->quantity;
2618 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2619 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2621 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2623 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2624 if ($price_result >= 0) {
2625 $obj->price = $price_result;
2628 $this->product_fourn_price_id = $obj->rowid;
2629 $this->buyprice = $obj->price;
2630 $this->fourn_pu = $obj->price / $obj->quantity;
2631 $this->fourn_price_base_type =
'HT';
2632 $this->fourn_socid = $obj->fk_soc;
2633 $this->ref_fourn = $obj->ref_supplier;
2634 $this->ref_supplier = $obj->ref_supplier;
2635 $this->desc_supplier = $obj->desc_supplier;
2636 $this->remise_percent = $obj->remise_percent;
2637 $this->vatrate_supplier = $obj->tva_tx;
2638 $this->default_vat_code_supplier = $obj->default_vat_code;
2639 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2640 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2641 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2642 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2643 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2645 $this->packaging = (float) $obj->packaging;
2651 $this->fourn_qty = $obj->quantity;
2652 $result = $obj->fk_product;
2656 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2657 $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,";
2658 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2659 $sql .=
" pfp.packaging";
2660 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2661 $sql .=
" WHERE 1 = 1";
2662 if ($product_id > 0) {
2663 $sql .=
" AND pfp.fk_product = ".((int) $product_id);
2665 if ($fourn_ref !=
'none') {
2666 $sql .=
" AND pfp.ref_fourn = '".$this->db->escape($fourn_ref).
"'";
2669 $sql .=
" AND pfp.fk_soc = ".((int) $fk_soc);
2672 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2674 $sql .=
" ORDER BY pfp.quantity DESC";
2677 dol_syslog(get_class($this).
"::get_buyprice second search from qty/ref/product_id", LOG_DEBUG);
2678 $resql = $this->db->query($sql);
2680 $obj = $this->db->fetch_object($resql);
2681 if ($obj && $obj->quantity > 0) {
2682 if (
isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2684 $prod_supplier->product_fourn_price_id = $obj->rowid;
2685 $prod_supplier->id = $obj->fk_product;
2686 $prod_supplier->fourn_qty = $obj->quantity;
2687 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2688 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2690 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2692 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2693 if ($price_result >= 0) {
2694 $obj->price = $price_result;
2697 $this->product_fourn_price_id = $obj->rowid;
2698 $this->buyprice = $obj->price;
2699 $this->fourn_qty = $obj->quantity;
2700 $this->fourn_pu = $obj->price / $obj->quantity;
2701 $this->fourn_price_base_type =
'HT';
2702 $this->fourn_socid = $obj->fk_soc;
2703 $this->ref_fourn = $obj->ref_supplier;
2704 $this->ref_supplier = $obj->ref_supplier;
2705 $this->desc_supplier = $obj->desc_supplier;
2706 $this->remise_percent = $obj->remise_percent;
2707 $this->vatrate_supplier = $obj->tva_tx;
2708 $this->default_vat_code_supplier = $obj->default_vat_code;
2709 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2710 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2711 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2712 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2713 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2715 $this->packaging = (float) $obj->packaging;
2719 $this->fourn_qty = $obj->quantity;
2720 $result = $obj->fk_product;
2726 $this->error = $this->db->lasterror();
2731 $this->error = $this->db->lasterror();
2755 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)
2761 dol_syslog(get_class($this).
"::update_price id=".$id.
" newprice=".$newprice.
" newpricebase=".$newpricebase.
" newminprice=".$newminprice.
" level=".$level.
" npr=".$newnpr.
" newdefaultvatcode=".$newdefaultvatcode);
2764 if (empty($this->tva_tx)) {
2765 $this->tva_tx = 0.0;
2767 if (empty($newnpr)) {
2770 if (empty($newminprice)) {
2775 if ($newvat ===
null || $newvat ==
'') {
2776 $newvat = (float) $this->tva_tx;
2779 $localtaxtype1 =
'';
2780 $localtaxtype2 =
'';
2785 return $this->
generateMultiprices($user, $newprice, $newpricebase, $newvat, $newnpr, $newpbq);
2788 if (!empty($newminprice) && ($newminprice > $newprice)) {
2789 $this->error =
'ErrorPriceCantBeLowerThanMinPrice';
2793 if ($newprice === 0 || $newprice !==
'') {
2794 if ($newpricebase ==
'TTC') {
2795 $price_ttc = (float)
price2num($newprice,
'MU');
2796 $price = (float)
price2num($newprice) / (1 + ((float) $newvat / 100));
2797 $price = (float)
price2num($price,
'MU');
2799 if ((
string) $newminprice !=
'0') {
2800 $price_min_ttc = (float)
price2num($newminprice,
'MU');
2801 $price_min = (float)
price2num($newminprice) / (1 + ($newvat / 100));
2802 $price_min = (float)
price2num($price_min,
'MU');
2805 $price_min_ttc = 0.0;
2808 $price = (float)
price2num($newprice,
'MU');
2809 $price_ttc = ($newnpr != 1) ? (
float)
price2num($newprice) * (1 + ($newvat / 100)) : $price;
2810 $price_ttc = (float)
price2num($price_ttc,
'MU');
2812 if ((
string) $newminprice !=
'0') {
2813 $price_min = (float)
price2num($newminprice,
'MU');
2814 $price_min_ttc = (float)
price2num($newminprice) * (1 + ($newvat / 100));
2815 $price_min_ttc = (float)
price2num($price_min_ttc,
'MU');
2819 $price_min_ttc = 0.0;
2823 if (count($localtaxes_array) > 0) {
2824 $localtaxtype1 = $localtaxes_array[
'0'];
2825 $localtax1 = $localtaxes_array[
'1'];
2826 $localtaxtype2 = $localtaxes_array[
'2'];
2827 $localtax2 = $localtaxes_array[
'3'];
2830 if (!empty($newdefaultvatcode)) {
2833 $sql =
"SELECT t.rowid, t.code, t.recuperableonly as tva_npr, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
2834 $sql .=
" FROM ".MAIN_DB_PREFIX.
"c_tva as t, ".MAIN_DB_PREFIX.
"c_country as c";
2835 $sql .=
" WHERE t.fk_pays = c.rowid AND c.code = '".$this->db->escape(
$mysoc->country_code).
"'";
2836 $sql .=
" AND t.taux = ".((float) $newdefaultvatcode).
" AND t.active = 1";
2837 $sql .=
" AND t.code = '".$this->db->escape($newdefaultvatcode).
"'";
2838 $resql = $this->db->query($sql);
2840 $obj = $this->db->fetch_object($resql);
2842 $npr = $obj->tva_npr;
2843 $localtax1 = $obj->localtax1;
2844 $localtax2 = $obj->localtax2;
2845 $localtaxtype1 = $obj->localtax1_type;
2846 $localtaxtype2 = $obj->localtax2_type;
2851 $localtaxtype1 =
'0';
2853 $localtaxtype2 =
'0';
2857 if (empty($localtax1)) {
2860 if (empty($localtax2)) {
2868 $sql =
"UPDATE ".$this->db->prefix().
"product SET";
2869 $sql .=
" price_base_type = '".$this->db->escape($newpricebase).
"',";
2870 $sql .=
" price = ".(float) $price.
",";
2871 $sql .=
" price_ttc = ".(float) $price_ttc.
",";
2872 $sql .=
" price_min = ".(float) $price_min.
",";
2873 $sql .=
" price_min_ttc = ".(float) $price_min_ttc.
",";
2874 $sql .=
" localtax1_tx = ".($localtax1 >= 0 ? (float) $localtax1 :
'NULL').
",";
2875 $sql .=
" localtax2_tx = ".($localtax2 >= 0 ? (float) $localtax2 :
'NULL').
",";
2876 $sql .=
" localtax1_type = ".($localtaxtype1 !=
'' ?
"'".$this->db->escape($localtaxtype1).
"'" :
"'0'").
",";
2877 $sql .=
" localtax2_type = ".($localtaxtype2 !=
'' ?
"'".$this->db->escape($localtaxtype2).
"'" :
"'0'").
",";
2878 $sql .=
" default_vat_code = ".($newdefaultvatcode ?
"'".$this->db->escape($newdefaultvatcode).
"'" :
"null").
",";
2879 $sql .=
" price_label = ".(!empty($price_label) ?
"'".$this->db->escape($price_label).
"'" :
"null").
",";
2880 $sql .=
" tva_tx = ".(float)
price2num($newvat).
",";
2881 $sql .=
" recuperableonly = '".$this->db->escape((
string) $newnpr).
"'";
2882 $sql .=
" WHERE rowid = ".((int) $id);
2884 dol_syslog(get_class($this).
"::update_price", LOG_DEBUG);
2885 $resql = $this->db->query($sql);
2887 $this->multiprices[$level] = $price;
2888 $this->multiprices_ttc[$level] = $price_ttc;
2889 $this->multiprices_min[$level] = $price_min;
2890 $this->multiprices_min_ttc[$level] = $price_min_ttc;
2891 $this->multiprices_base_type[$level] = $newpricebase;
2892 $this->multiprices_default_vat_code[$level] = $newdefaultvatcode;
2893 $this->multiprices_tva_tx[$level] = $newvat;
2894 $this->multiprices_recuperableonly[$level] = $newnpr;
2896 $this->
price = $price;
2897 $this->price_label = $price_label;
2898 $this->price_ttc = $price_ttc;
2899 $this->price_min = $price_min;
2900 $this->price_min_ttc = $price_min_ttc;
2901 $this->price_base_type = $newpricebase;
2902 $this->default_vat_code = $newdefaultvatcode;
2903 $this->tva_tx = $newvat;
2904 $this->tva_npr = $newnpr;
2907 $this->localtax1_tx = $localtax1;
2908 $this->localtax2_tx = $localtax2;
2909 $this->localtax1_type = $localtaxtype1;
2910 $this->localtax2_type = $localtaxtype2;
2913 $this->price_by_qty = $newpbq;
2917 if (!empty(array_diff_assoc($newPriceData, $lastPriceData)) || (!
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
2921 $this->level = $level;
2925 $result = $this->call_trigger(
'PRODUCT_PRICE_MODIFY', $user);
2927 $this->db->rollback();
2933 $this->db->commit();
2935 $this->db->rollback();
2936 $this->error = $this->db->lasterror();
2955 $this->fk_price_expression = $expression_id;
2957 return $this->
update($this->
id, $user);
2972 public function fetch($id = 0, $ref =
'', $ref_ext =
'', $barcode =
'', $ignore_expression = 0, $ignore_price_load = 0, $ignore_lang_load = 0)
2974 include_once DOL_DOCUMENT_ROOT.
'/core/lib/company.lib.php';
2978 dol_syslog(get_class($this).
"::fetch id=".$id.
" ref=".$ref.
" ref_ext=".$ref_ext);
2981 if (!$id && !$ref && !$ref_ext && !$barcode) {
2982 $this->error =
'ErrorWrongParameters';
2983 dol_syslog(get_class($this).
"::fetch ".$this->error, LOG_ERR);
2987 $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,";
2988 $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,";
2989 $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,";
2990 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.last_main_doc,";
2991 $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,";
2993 $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,";
2995 $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,";
3000 $separatedEntityPMP =
false;
3001 $separatedStock =
false;
3002 $visibleWarehousesEntities = $conf->entity;
3005 $checkPMPPerEntity = $this->db->query(
"SELECT pmp FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = ".((int) $id).
" AND entity = ".(
int) $conf->entity);
3006 if ($this->db->num_rows($checkPMPPerEntity) > 0) {
3007 $separatedEntityPMP =
true;
3011 $separatedStock =
true;
3012 if (isset($mc->sharings[
'stock']) && !empty($mc->sharings[
'stock'])) {
3013 $visibleWarehousesEntities .=
"," . implode(
",", $mc->sharings[
'stock']);
3016 if ($separatedEntityPMP) {
3017 $sql .=
" ppe.pmp,";
3021 $sql .=
" p.datec, GREATEST(p.tms, pef.tms) AS tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.sell_or_eat_by_mandatory, p.batch_mask, p.fk_unit,";
3022 $sql .=
" p.fk_price_expression, p.price_autogen, p.stockable_product, p.model_pdf,";
3023 $sql .=
" p.price_label,";
3024 if ($separatedStock) {
3025 $sql .=
" SUM(sp.reel) as stock";
3029 $sql .=
" FROM ".$this->db->prefix().
"product as p";
3030 $sql .=
" LEFT JOIN ".$this->db->prefix().
"product_extrafields as pef ON pef.fk_object=p.rowid";
3032 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int) $conf->entity);
3034 if ($separatedStock) {
3035 $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).
"))";
3039 $sql .=
" WHERE p.rowid = ".((int) $id);
3041 $sql .=
" WHERE p.entity IN (".getEntity($this->element).
")";
3043 $sql .=
" AND p.ref = '".$this->db->escape($ref).
"'";
3044 } elseif ($ref_ext) {
3045 $sql .=
" AND p.ref_ext = '".$this->db->escape($ref_ext).
"'";
3046 } elseif ($barcode) {
3047 $sql .=
" AND p.barcode = '".$this->db->escape($barcode).
"'";
3050 if ($separatedStock) {
3051 $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,";
3052 $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,";
3053 $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,";
3054 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
3055 $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,";
3057 $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,";
3059 $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,";
3061 if ($separatedEntityPMP) {
3062 $sql .=
" ppe.pmp,";
3066 $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,";
3067 $sql .=
" p.fk_price_expression, p.price_autogen, p.stockable_product, p.model_pdf,";
3068 $sql .=
" p.price_label";
3075 $resql = $this->db->query($sql);
3077 unset($this->oldcopy);
3079 if ($this->db->num_rows($resql) > 0) {
3080 $obj = $this->db->fetch_object($resql);
3082 $this->
id = $obj->rowid;
3083 $this->
ref = $obj->ref;
3084 $this->ref_ext = $obj->ref_ext;
3085 $this->label = $obj->label;
3087 $this->url = $obj->url;
3088 $this->note_public = $obj->note_public;
3089 $this->note_private = $obj->note_private;
3090 $this->note = $obj->note_private;
3092 $this->
type = $obj->fk_product_type;
3093 $this->price_label = $obj->price_label;
3094 $this->
status = $obj->tosell;
3095 $this->status_buy = $obj->tobuy;
3096 $this->status_batch = $obj->tobatch;
3097 $this->sell_or_eat_by_mandatory = $obj->sell_or_eat_by_mandatory;
3098 $this->batch_mask = $obj->batch_mask;
3100 $this->customcode = $obj->customcode;
3101 $this->country_id = $obj->fk_country;
3102 $this->country_code =
getCountry($this->country_id,
'2', $this->db);
3103 $this->state_id = $obj->fk_state;
3104 $this->lifetime = $obj->lifetime;
3105 $this->qc_frequency = $obj->qc_frequency;
3106 $this->
price = $obj->price;
3107 $this->price_ttc = $obj->price_ttc;
3108 $this->price_min = $obj->price_min;
3109 $this->price_min_ttc = $obj->price_min_ttc;
3110 $this->price_base_type = $obj->price_base_type;
3111 $this->cost_price = isset($obj->cost_price) ? (float) $obj->cost_price :
null;
3112 $this->default_vat_code = $obj->default_vat_code;
3113 $this->tva_tx = $obj->tva_tx;
3115 $this->tva_npr = $obj->tva_npr;
3117 $this->localtax1_tx = $obj->localtax1_tx;
3118 $this->localtax2_tx = $obj->localtax2_tx;
3119 $this->localtax1_type = $obj->localtax1_type;
3120 $this->localtax2_type = $obj->localtax2_type;
3122 $this->finished = $obj->finished;
3123 $this->fk_default_bom = $obj->fk_default_bom;
3125 $this->duration = $obj->duration;
3127 preg_match(
'/([\d.]+)(\w+)/', $obj->duration, $matches);
3128 $this->duration_value = !empty($matches[1]) ? (float) $matches[1] : 0;
3129 $this->duration_unit = !empty($matches[2]) ? (string) $matches[2] :
null;
3130 $this->canvas = $obj->canvas;
3131 $this->net_measure = $obj->net_measure;
3132 $this->net_measure_units = $obj->net_measure_units;
3133 $this->weight = $obj->weight;
3134 $this->weight_units = (is_null($obj->weight_units) ? 0 : $obj->weight_units);
3135 $this->length = $obj->length;
3136 $this->length_units = (is_null($obj->length_units) ? 0 : $obj->length_units);
3137 $this->width = $obj->width;
3138 $this->width_units = (is_null($obj->width_units) ? 0 : $obj->width_units);
3139 $this->height = $obj->height;
3140 $this->height_units = (is_null($obj->height_units) ? 0 : $obj->height_units);
3142 $this->surface = $obj->surface;
3143 $this->surface_units = (is_null($obj->surface_units) ? 0 : $obj->surface_units);
3144 $this->volume = $obj->volume;
3145 $this->volume_units = (is_null($obj->volume_units) ? 0 : $obj->volume_units);
3146 $this->barcode = $obj->barcode;
3147 $this->barcode_type = $obj->fk_barcode_type;
3149 $this->accountancy_code_buy = $obj->accountancy_code_buy;
3150 $this->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra;
3151 $this->accountancy_code_buy_export = $obj->accountancy_code_buy_export;
3152 $this->accountancy_code_sell = $obj->accountancy_code_sell;
3153 $this->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra;
3154 $this->accountancy_code_sell_export = $obj->accountancy_code_sell_export;
3156 $this->fk_default_warehouse = $obj->fk_default_warehouse;
3157 $this->fk_default_workstation = $obj->fk_default_workstation;
3158 $this->seuil_stock_alerte = $obj->seuil_stock_alerte;
3159 $this->desiredstock = $obj->desiredstock;
3160 $this->stock_reel = $obj->stock;
3161 $this->stockable_product = $obj->stockable_product;
3162 $this->pmp = $obj->pmp;
3164 $this->date_creation = $this->db->jdate($obj->datec);
3165 $this->date_modification = $this->db->jdate($obj->tms);
3167 $this->import_key = $obj->import_key;
3168 $this->entity = $obj->entity;
3170 $this->ref_ext = $obj->ref_ext;
3171 $this->fk_price_expression = $obj->fk_price_expression;
3172 $this->fk_unit = $obj->fk_unit;
3173 $this->price_autogen = $obj->price_autogen;
3174 $this->model_pdf = $obj->model_pdf;
3175 $this->last_main_doc = $obj->last_main_doc;
3177 $this->mandatory_period = $obj->mandatory_period;
3180 $this->packaging = (float) $obj->packaging;
3183 $this->db->free($resql);
3195 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
3196 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3197 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3198 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3199 $sql .=
" ,price_label";
3200 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3201 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3202 $sql .=
" AND price_level=".((int) $i);
3203 $sql .=
" AND fk_product = ".((int) $this->
id);
3204 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3206 $resql = $this->db->query($sql);
3208 $result = $this->db->fetch_array($resql);
3210 $this->multiprices[$i] = $result ? $result[
"price"] :
null;
3211 $this->multiprices_ttc[$i] = $result ? $result[
"price_ttc"] :
null;
3212 $this->multiprices_min[$i] = $result ? $result[
"price_min"] :
null;
3213 $this->multiprices_min_ttc[$i] = $result ? $result[
"price_min_ttc"] :
null;
3214 $this->multiprices_base_type[$i] = $result ? $result[
"price_base_type"] :
null;
3216 $this->multiprices_tva_tx[$i] = $result ? $result[
"tva_tx"].(!empty($result[
'default_vat_code']) ?
' ('.$result[
'default_vat_code'].
')' :
'') :
null;
3217 $this->multiprices_recuperableonly[$i] = $result ? $result[
"recuperableonly"] :
null;
3256 $this->error = $this->db->lasterror;
3262 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY') && empty($ignore_price_load)) {
3263 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3264 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid";
3265 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3266 $sql .=
" WHERE fk_product = ".((int) $this->
id);
3267 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3270 $resql = $this->db->query($sql);
3272 $result = $this->db->fetch_array($resql);
3276 $this->prices_by_qty[0] = $result[
"price_by_qty"];
3277 $this->prices_by_qty_id[0] = $result[
"rowid"];
3279 if ($this->prices_by_qty[0] == 1) {
3280 $sql =
"SELECT rowid,price, unitprice, quantity, remise_percent, remise, remise, price_base_type";
3281 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3282 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[0]);
3283 $sql .=
" ORDER BY quantity ASC";
3285 $resql = $this->db->query($sql);
3287 $resultat = array();
3289 while ($result = $this->db->fetch_array($resql)) {
3290 $resultat[$ii] = array();
3291 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3292 $resultat[$ii][
"price"] = $result[
"price"];
3293 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3294 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3295 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3297 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3300 $this->prices_by_qty_list[0] = $resultat;
3302 $this->error = $this->db->lasterror;
3308 $this->error = $this->db->lasterror;
3311 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') && empty($ignore_price_load)) {
3312 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
3313 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3314 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3315 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3316 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3317 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3318 $sql .=
" AND price_level=".((int) $i);
3319 $sql .=
" AND fk_product = ".((int) $this->
id);
3320 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3322 $resql = $this->db->query($sql);
3324 $this->error = $this->db->lasterror;
3327 $result = $this->db->fetch_array($resql);
3328 $this->multiprices[$i] = (!empty($result[
"price"]) ? $result[
"price"] : 0);
3329 $this->multiprices_ttc[$i] = (!empty($result[
"price_ttc"]) ? $result[
"price_ttc"] : 0);
3330 $this->multiprices_min[$i] = (!empty($result[
"price_min"]) ? $result[
"price_min"] : 0);
3331 $this->multiprices_min_ttc[$i] = (!empty($result[
"price_min_ttc"]) ? $result[
"price_min_ttc"] : 0);
3332 $this->multiprices_base_type[$i] = (!empty($result[
"price_base_type"]) ? $result[
"price_base_type"] :
'');
3334 $this->multiprices_tva_tx[$i] = (!empty($result[
"tva_tx"]) ? $result[
"tva_tx"] : 0);
3335 $this->multiprices_recuperableonly[$i] = (!empty($result[
"recuperableonly"]) ? $result[
"recuperableonly"] : 0);
3338 $this->prices_by_qty[$i] = (!empty($result[
"price_by_qty"]) ? $result[
"price_by_qty"] : 0);
3339 $this->prices_by_qty_id[$i] = (!empty($result[
"rowid"]) ? $result[
"rowid"] : 0);
3341 if ($this->prices_by_qty[$i] == 1) {
3342 $sql =
"SELECT rowid, price, unitprice, quantity, remise_percent, remise, price_base_type";
3343 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3344 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[$i]);
3345 $sql .=
" ORDER BY quantity ASC";
3347 $resql = $this->db->query($sql);
3349 $resultat = array();
3351 while ($result = $this->db->fetch_array($resql)) {
3352 $resultat[$ii] = array();
3353 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3354 $resultat[$ii][
"price"] = $result[
"price"];
3355 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3356 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3357 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3358 $resultat[$ii][
"remise"] = $result[
"remise"];
3359 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3362 $this->prices_by_qty_list[$i] = $resultat;
3364 $this->error = $this->db->lasterror;
3372 if (
isModEnabled(
'dynamicprices') && !empty($this->fk_price_expression) && empty($ignore_expression)) {
3373 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
3375 $price_result = $priceparser->parseProduct($this);
3376 if ($price_result >= 0) {
3377 $this->
price = $price_result;
3379 $this->price_ttc = (float)
price2num($this->
price) * (1 + ($this->tva_tx / 100));
3380 $this->price_ttc = (float)
price2num($this->price_ttc,
'MU');
3386 $this->stock_warehouse = array();
3393 $this->error = $this->db->lasterror();
3408 global $user, $hookmanager, $action;
3412 foreach (array(
'toconsume',
'consumed',
'toproduce',
'produced') as $role) {
3413 $this->stats_mo[
'customers_'.$role] = 0;
3414 $this->stats_mo[
'nb_'.$role] = 0;
3415 $this->stats_mo[
'qty_'.$role] = 0;
3417 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3418 $sql .=
" SUM(mp.qty) as qty";
3419 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as c";
3420 $sql .=
" INNER JOIN ".$this->db->prefix().
"mrp_production as mp ON mp.fk_mo=c.rowid";
3421 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3422 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3425 $sql .=
" c.entity IN (".getEntity(
'mo').
")";
3427 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3428 $sql .=
" AND mp.role ='".$this->db->escape($role).
"'";
3430 $sql .=
" AND c.fk_soc = ".((int) $socid);
3433 $result = $this->db->query($sql);
3435 $obj = $this->db->fetch_object($result);
3436 $this->stats_mo[
'customers_'.$role] = $obj->nb_customers ? $obj->nb_customers : 0;
3437 $this->stats_mo[
'nb_'.$role] = $obj->nb ? $obj->nb : 0;
3438 $this->stats_mo[
'qty_'.$role] = $obj->qty ?
price2num($obj->qty,
'MS') : 0;
3440 $this->error = $this->db->error();
3445 if (!empty($error)) {
3449 $parameters = array(
'socid' => $socid);
3450 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3452 $this->stats_mo = $hookmanager->resArray[
'stats_mo'];
3468 global $hookmanager, $action;
3472 $this->stats_bom[
'nb_toproduce'] = 0;
3473 $this->stats_bom[
'nb_toconsume'] = 0;
3474 $this->stats_bom[
'qty_toproduce'] = 0;
3475 $this->stats_bom[
'qty_toconsume'] = 0;
3477 $sql =
"SELECT COUNT(DISTINCT b.rowid) as nb_toproduce,";
3478 $sql .=
" SUM(b.qty) as qty_toproduce";
3479 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3480 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom = b.rowid";
3482 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3483 $sql .=
" AND b.fk_product =".((int) $this->
id);
3484 $sql .=
" GROUP BY b.rowid";
3486 $result = $this->db->query($sql);
3488 $obj = $this->db->fetch_object($result);
3489 $this->stats_bom[
'nb_toproduce'] = !empty($obj->nb_toproduce) ? $obj->nb_toproduce : 0;
3490 $this->stats_bom[
'qty_toproduce'] = !empty($obj->qty_toproduce) ?
price2num($obj->qty_toproduce) : 0;
3492 $this->error = $this->db->error();
3496 $sql =
"SELECT COUNT(DISTINCT bl.rowid) as nb_toconsume,";
3497 $sql .=
" SUM(bl.qty) as qty_toconsume";
3498 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3499 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
3501 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3502 $sql .=
" AND bl.fk_product =".((int) $this->
id);
3504 $result = $this->db->query($sql);
3506 $obj = $this->db->fetch_object($result);
3507 $this->stats_bom[
'nb_toconsume'] = !empty($obj->nb_toconsume) ? $obj->nb_toconsume : 0;
3508 $this->stats_bom[
'qty_toconsume'] = !empty($obj->qty_toconsume) ?
price2num($obj->qty_toconsume) : 0;
3510 $this->error = $this->db->error();
3514 if (!empty($error)) {
3518 $parameters = array(
'socid' => $socid);
3519 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3521 $this->stats_bom = $hookmanager->resArray[
'stats_bom'];
3537 global $user, $hookmanager, $action;
3539 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_customers, COUNT(DISTINCT p.rowid) as nb,";
3540 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3541 $sql .=
" FROM ".$this->db->prefix().
"propaldet as pd";
3542 $sql .=
", ".$this->db->prefix().
"propal as p";
3543 $sql .=
", ".$this->db->prefix().
"societe as s";
3544 $sql .=
" WHERE p.rowid = pd.fk_propal";
3545 $sql .=
" AND p.fk_soc = s.rowid";
3546 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
3547 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3548 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3549 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $user->id);
3553 $sql .=
" AND p.fk_soc = ".((int) $socid);
3556 $parameters = array(
'socid' => $socid,
'type_element' =>
'propal');
3557 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3558 $sql .= $hookmanager->resPrint;
3559 $result = $this->db->query($sql);
3561 $obj = $this->db->fetch_object($result);
3562 $this->stats_propale[
'customers'] = $obj->nb_customers;
3563 $this->stats_propale[
'nb'] = $obj->nb;
3564 $this->stats_propale[
'rows'] = $obj->nb_rows;
3565 $this->stats_propale[
'qty'] = $obj->qty ? $obj->qty : 0;
3570 if (is_array($TFather) && !empty($TFather)) {
3571 foreach ($TFather as &$fatherData) {
3572 $pFather =
new Product($this->db);
3573 $pFather->id = $fatherData[
'id'];
3574 $qtyCoef = $fatherData[
'qty'];
3576 if ($fatherData[
'incdec']) {
3577 $pFather->load_stats_propale($socid);
3579 $this->stats_propale[
'customers'] += $pFather->stats_propale[
'customers'];
3580 $this->stats_propale[
'nb'] += $pFather->stats_propale[
'nb'];
3581 $this->stats_propale[
'rows'] += $pFather->stats_propale[
'rows'];
3582 $this->stats_propale[
'qty'] += $pFather->stats_propale[
'qty'] * $qtyCoef;
3588 $parameters = array(
'socid' => $socid);
3589 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerProposal', $parameters, $this, $action);
3591 $this->stats_propale = $hookmanager->resArray[
'stats_propale'];
3596 $this->error = $this->db->error();
3612 global $user, $hookmanager, $action;
3614 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_suppliers, COUNT(DISTINCT p.rowid) as nb,";
3615 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3616 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as pd";
3617 $sql .=
", ".$this->db->prefix().
"supplier_proposal as p";
3618 $sql .=
", ".$this->db->prefix().
"societe as s";
3619 $sql .=
" WHERE p.rowid = pd.fk_supplier_proposal";
3620 $sql .=
" AND p.fk_soc = s.rowid";
3621 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
3622 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3623 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3624 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $user->id);
3628 $sql .=
" AND p.fk_soc = ".((int) $socid);
3631 $result = $this->db->query($sql);
3633 $obj = $this->db->fetch_object($result);
3634 $this->stats_proposal_supplier[
'suppliers'] = $obj->nb_suppliers;
3635 $this->stats_proposal_supplier[
'nb'] = $obj->nb;
3636 $this->stats_proposal_supplier[
'rows'] = $obj->nb_rows;
3637 $this->stats_proposal_supplier[
'qty'] = $obj->qty ? $obj->qty : 0;
3639 $parameters = array(
'socid' => $socid);
3640 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierProposal', $parameters, $this, $action);
3642 $this->stats_proposal_supplier = $hookmanager->resArray[
'stats_proposal_supplier'];
3647 $this->error = $this->db->error();
3665 global $user, $hookmanager, $action;
3668 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3669 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3670 $sql .=
" FROM ".$this->db->prefix().
"commandedet as cd";
3671 $sql .=
", ".$this->db->prefix().
"commande as c";
3672 $sql .=
", ".$this->db->prefix().
"societe as s";
3673 $sql .=
" WHERE c.rowid = cd.fk_commande";
3674 $sql .=
" AND c.fk_soc = s.rowid";
3675 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'commande').
")";
3676 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3677 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3678 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3681 $sql .=
" AND c.fk_soc = ".((int) $socid);
3683 if ($filtrestatut !=
'') {
3684 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3687 $parameters = array(
'socid' => $socid,
'type_element' =>
'order');
3688 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3689 $sql .= $hookmanager->resPrint;
3690 $result = $this->db->query($sql);
3692 $obj = $this->db->fetch_object($result);
3693 $this->stats_commande[
'customers'] = $obj->nb_customers;
3694 $this->stats_commande[
'nb'] = $obj->nb;
3695 $this->stats_commande[
'rows'] = $obj->nb_rows;
3696 $this->stats_commande[
'qty'] = $obj->qty ? $obj->qty : 0;
3701 if (is_array($TFather) && !empty($TFather)) {
3702 foreach ($TFather as &$fatherData) {
3703 $pFather =
new Product($this->db);
3704 $pFather->id = $fatherData[
'id'];
3705 $qtyCoef = $fatherData[
'qty'];
3707 if ($fatherData[
'incdec']) {
3708 $pFather->load_stats_commande($socid, $filtrestatut);
3710 $this->stats_commande[
'customers'] += $pFather->stats_commande[
'customers'];
3711 $this->stats_commande[
'nb'] += $pFather->stats_commande[
'nb'];
3712 $this->stats_commande[
'rows'] += $pFather->stats_commande[
'rows'];
3713 $this->stats_commande[
'qty'] += $pFather->stats_commande[
'qty'] * $qtyCoef;
3726 $sql =
"SELECT SUM(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3727 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3729 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture' AND sourcetype = 'commande' ";
3730 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3731 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3732 $sql .=
" AND EXISTS (SELECT cd.fk_product FROM ".$this->db->prefix().
"commandedet as cd WHERE cd.fk_product = fd.fk_product AND cd.fk_commande = c.rowid)";
3736 $sql .=
"SELECT SUM(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3737 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3738 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_source = f.rowid AND el.targettype = 'commande' AND sourcetype = 'facture' ";
3739 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_target = c.rowid";
3740 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3741 $sql .=
" AND EXISTS (SELECT cd.fk_product FROM ".$this->db->prefix().
"commandedet as cd WHERE cd.fk_product = fd.fk_product AND cd.fk_commande = c.rowid)";
3743 $parameters = array(
'socid' => $socid,
'type_element' =>
'order');
3744 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3745 $sql .= $hookmanager->resPrint;
3746 $resql = $this->db->query($sql);
3748 while ($obj = $this->db->fetch_object($resql)) {
3749 $adeduire += $obj->count;
3753 $this->stats_commande[
'qty'] -= $adeduire;
3756 include_once DOL_DOCUMENT_ROOT.
'/compta/facture/class/facture.class.php';
3760 $sql =
"SELECT sum(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3761 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3763 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture' AND sourcetype = 'commande' ";
3764 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3765 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3766 $sql .=
" AND EXISTS (SELECT cd.fk_product FROM ".$this->db->prefix().
"commandedet as cd WHERE cd.fk_product = fd.fk_product AND cd.fk_commande = c.rowid)";
3768 $sql .=
" UNION ALL ";
3770 $sql .=
"SELECT sum(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3771 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3772 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_source = f.rowid AND el.targettype = 'commande' AND sourcetype = 'facture' ";
3773 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_target = c.rowid";
3774 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3775 $sql .=
" AND EXISTS (SELECT cd.fk_product FROM ".$this->db->prefix().
"commandedet as cd WHERE cd.fk_product = fd.fk_product AND cd.fk_commande = c.rowid)";
3777 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3779 $parameters = array(
'socid' => $socid,
'type_element' =>
'order');
3780 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3781 $sql .= $hookmanager->resPrint;
3782 $resql = $this->db->query($sql);
3784 while ($obj = $this->db->fetch_object($resql)) {
3785 $adeduire += $obj->count;
3788 $this->error = $this->db->error();
3792 $this->stats_commande[
'qty'] -= $adeduire;
3796 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3797 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerOrder', $parameters, $this, $action);
3799 $this->stats_commande = $hookmanager->resArray[
'stats_commande'];
3803 $this->error = $this->db->error();
3821 global $user, $hookmanager, $action;
3823 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_suppliers, COUNT(DISTINCT c.rowid) as nb,";
3824 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3825 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as cd";
3826 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as c";
3827 $sql .=
", ".$this->db->prefix().
"societe as s";
3828 $sql .=
" WHERE c.rowid = cd.fk_commande";
3829 $sql .=
" AND c.fk_soc = s.rowid";
3830 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3831 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3832 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3833 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3836 $sql .=
" AND c.fk_soc = ".((int) $socid);
3838 if ($filtrestatut !=
'') {
3839 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3841 if (!empty($dateofvirtualstock)) {
3842 $sql .=
" AND c.date_livraison <= '".$this->db->idate($dateofvirtualstock).
"'";
3845 $result = $this->db->query($sql);
3847 $obj = $this->db->fetch_object($result);
3848 $this->stats_commande_fournisseur[
'suppliers'] = $obj->nb_suppliers;
3849 $this->stats_commande_fournisseur[
'nb'] = $obj->nb;
3850 $this->stats_commande_fournisseur[
'rows'] = $obj->nb_rows;
3851 $this->stats_commande_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
3853 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3854 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierOrder', $parameters, $this, $action);
3856 $this->stats_commande_fournisseur = $hookmanager->resArray[
'stats_commande_fournisseur'];
3861 $this->error = $this->db->error().
' sql='.$sql;
3876 public function load_stats_sending($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $filterShipmentStatus =
'')
3879 global $user, $hookmanager, $action;
3881 $sql =
"SELECT COUNT(DISTINCT e.fk_soc) as nb_customers, COUNT(DISTINCT e.rowid) as nb,";
3882 $sql .=
" COUNT(ed.rowid) as nb_rows, SUM(ed.qty) as qty";
3883 $sql .=
" FROM ".$this->db->prefix().
"expeditiondet as ed";
3884 $sql .=
", ".$this->db->prefix().
"commandedet as cd";
3885 $sql .=
", ".$this->db->prefix().
"commande as c";
3886 $sql .=
", ".$this->db->prefix().
"expedition as e";
3887 $sql .=
", ".$this->db->prefix().
"societe as s";
3888 $sql .=
" WHERE e.rowid = ed.fk_expedition";
3889 $sql .=
" AND c.rowid = cd.fk_commande";
3890 $sql .=
" AND e.fk_soc = s.rowid";
3891 $sql .=
" AND e.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'expedition').
")";
3892 $sql .=
" AND ed.fk_elementdet = cd.rowid";
3893 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3894 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3895 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = e.fk_soc AND sc.fk_user = ".((int) $user->id);
3898 $sql .=
" AND e.fk_soc = ".((int) $socid);
3900 if ($filtrestatut !=
'') {
3901 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3903 if (!empty($filterShipmentStatus)) {
3904 $sql .=
" AND e.fk_statut IN (".$this->db->sanitize($filterShipmentStatus).
")";
3907 $result = $this->db->query($sql);
3909 $obj = $this->db->fetch_object($result);
3910 $this->stats_expedition[
'customers'] = $obj->nb_customers;
3911 $this->stats_expedition[
'nb'] = $obj->nb;
3912 $this->stats_expedition[
'rows'] = $obj->nb_rows;
3913 $this->stats_expedition[
'qty'] = $obj->qty ? $obj->qty : 0;
3918 if (is_array($TFather) && !empty($TFather)) {
3919 foreach ($TFather as &$fatherData) {
3920 $pFather =
new Product($this->db);
3921 $pFather->id = $fatherData[
'id'];
3922 $qtyCoef = $fatherData[
'qty'];
3924 if ($fatherData[
'incdec']) {
3925 $pFather->load_stats_sending($socid, $filtrestatut, $forVirtualStock);
3927 $this->stats_expedition[
'customers'] += $pFather->stats_expedition[
'customers'];
3928 $this->stats_expedition[
'nb'] += $pFather->stats_expedition[
'nb'];
3929 $this->stats_expedition[
'rows'] += $pFather->stats_expedition[
'rows'];
3930 $this->stats_expedition[
'qty'] += $pFather->stats_expedition[
'qty'] * $qtyCoef;
3936 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock,
'filterShipmentStatus' => $filterShipmentStatus);
3937 $reshook = $hookmanager->executeHooks(
'loadStatsSending', $parameters, $this, $action);
3939 $this->stats_expedition = $hookmanager->resArray[
'stats_expedition'];
3944 $this->error = $this->db->error();
3959 public function load_stats_reception($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null)
3962 global $user, $hookmanager, $action;
3964 $sql =
"SELECT COUNT(DISTINCT cf.fk_soc) as nb_suppliers, COUNT(DISTINCT cf.rowid) as nb,";
3965 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
3966 $sql .=
" FROM ".$this->db->prefix().
"receptiondet_batch as fd";
3967 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as cf";
3968 $sql .=
", ".$this->db->prefix().
"societe as s";
3969 $sql .=
" WHERE cf.rowid = fd.fk_element";
3970 $sql .=
" AND cf.fk_soc = s.rowid";
3971 $sql .=
" AND cf.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3972 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3973 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3974 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = cf.fk_soc AND sc.fk_user = ".((int) $user->id);
3977 $sql .=
" AND cf.fk_soc = ".((int) $socid);
3979 if ($filtrestatut !=
'') {
3980 $sql .=
" AND cf.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3982 if (!empty($dateofvirtualstock)) {
3983 $sql .=
" AND fd.datec <= '".$this->db->idate($dateofvirtualstock).
"'";
3986 $result = $this->db->query($sql);
3988 $obj = $this->db->fetch_object($result);
3989 $this->stats_reception[
'suppliers'] = $obj->nb_suppliers;
3990 $this->stats_reception[
'nb'] = $obj->nb;
3991 $this->stats_reception[
'rows'] = $obj->nb_rows;
3992 $this->stats_reception[
'qty'] = $obj->qty ? $obj->qty : 0;
3994 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3995 $reshook = $hookmanager->executeHooks(
'loadStatsReception', $parameters, $this, $action);
3997 $this->stats_reception = $hookmanager->resArray[
'stats_reception'];
4002 $this->error = $this->db->error();
4018 public function load_stats_inproduction($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null, $warehouseid = 0)
4021 global $user, $hookmanager, $action;
4025 $sql =
"SELECT COUNT(DISTINCT m.fk_soc) as nb_customers, COUNT(DISTINCT m.rowid) as nb,";
4026 $sql .=
" COUNT(mp.rowid) as nb_rows, SUM(mp.qty) as qty, role";
4027 $sql .=
" FROM ".$this->db->prefix().
"mrp_production as mp";
4028 $sql .=
", ".$this->db->prefix().
"mrp_mo as m";
4029 $sql .=
" LEFT JOIN ".$this->db->prefix().
"societe as s ON s.rowid = m.fk_soc";
4030 $sql .=
" WHERE m.rowid = mp.fk_mo";
4031 $sql .=
" AND m.entity IN (".getEntity(($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE')) ?
'stock' :
'mrp').
")";
4032 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
4033 $sql .=
" AND (mp.disable_stock_change IN (0) OR mp.disable_stock_change IS NULL)";
4034 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
4035 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = m.fk_soc AND sc.fk_user = ".((int) $user->id);
4038 $sql .=
" AND m.fk_soc = ".((int) $socid);
4040 if ($filtrestatut !=
'') {
4041 $sql .=
" AND m.status IN (".$this->db->sanitize($filtrestatut).
")";
4043 if (!empty($dateofvirtualstock)) {
4044 $sql .=
" AND m.date_valid <= '".$this->db->idate($dateofvirtualstock).
"'";
4046 if (!$serviceStockIsEnabled) {
4047 $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))";
4049 if (!empty($warehouseid)) {
4050 $sql .=
" AND m.fk_warehouse = ".((int) $warehouseid);
4052 $sql .=
" GROUP BY role";
4055 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
4057 $this->stats_mrptoconsume[
'customers'] = 0;
4058 $this->stats_mrptoconsume[
'nb'] = 0;
4059 $this->stats_mrptoconsume[
'rows'] = 0;
4060 $this->stats_mrptoconsume[
'qty'] = 0.0;
4061 $this->stats_mrptoproduce[
'customers'] = 0;
4062 $this->stats_mrptoproduce[
'nb'] = 0;
4063 $this->stats_mrptoproduce[
'rows'] = 0;
4064 $this->stats_mrptoproduce[
'qty'] = 0.0;
4067 $result = $this->db->query($sql);
4069 while ($obj = $this->db->fetch_object($result)) {
4070 if ($obj->role ==
'toconsume' && empty($warehouseid)) {
4071 $this->stats_mrptoconsume[
'customers'] += (int) $obj->nb_customers;
4072 $this->stats_mrptoconsume[
'nb'] += (int) $obj->nb;
4073 $this->stats_mrptoconsume[
'rows'] += (int) $obj->nb_rows;
4074 $this->stats_mrptoconsume[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4076 if ($obj->role ==
'consumed' && empty($warehouseid)) {
4080 $this->stats_mrptoconsume[
'qty'] -= ($obj->qty ? (float) $obj->qty : 0.0);
4082 if ($obj->role ==
'toproduce') {
4084 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4086 $this->stats_mrptoproduce[
'customers'] += (int) $obj->nb_customers;
4087 $this->stats_mrptoproduce[
'nb'] += (int) $obj->nb;
4088 $this->stats_mrptoproduce[
'rows'] += (int) $obj->nb_rows;
4089 $this->stats_mrptoproduce[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4092 if ($obj->role ==
'produced') {
4097 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
4099 $this->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
4106 if ($this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] < 0) {
4107 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
4110 if ($this->stats_mrptoconsume[
'qty'] < 0) {
4111 $this->stats_mrptoconsume[
'qty'] = 0;
4113 if ($this->stats_mrptoproduce[
'qty'] < 0) {
4114 $this->stats_mrptoproduce[
'qty'] = 0;
4118 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
4119 $reshook = $hookmanager->executeHooks(
'loadStatsInProduction', $parameters, $this, $action);
4121 $this->stats_mrptoproduce = $hookmanager->resArray[
'stats_mrptoproduce'];
4126 $this->error = $this->db->error();
4141 global $user, $hookmanager, $action;
4143 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
4144 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
4145 $sql .=
" FROM ".$this->db->prefix().
"contratdet as cd";
4146 $sql .=
", ".$this->db->prefix().
"contrat as c";
4147 $sql .=
", ".$this->db->prefix().
"societe as s";
4148 $sql .=
" WHERE c.rowid = cd.fk_contrat";
4149 $sql .=
" AND c.fk_soc = s.rowid";
4150 $sql .=
" AND c.entity IN (".getEntity(
'contract').
")";
4151 $sql .=
" AND cd.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 = c.fk_soc AND sc.fk_user = ".((int) $user->id);
4157 $sql .=
" AND c.fk_soc = ".((int) $socid);
4160 $result = $this->db->query($sql);
4162 $obj = $this->db->fetch_object($result);
4163 $this->stats_contrat[
'customers'] = $obj->nb_customers;
4164 $this->stats_contrat[
'nb'] = $obj->nb;
4165 $this->stats_contrat[
'rows'] = $obj->nb_rows;
4166 $this->stats_contrat[
'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_contrat($socid);
4180 $this->stats_contrat[
'customers'] += $pFather->stats_contrat[
'customers'];
4181 $this->stats_contrat[
'nb'] += $pFather->stats_contrat[
'nb'];
4182 $this->stats_contrat[
'rows'] += $pFather->stats_contrat[
'rows'];
4183 $this->stats_contrat[
'qty'] += $pFather->stats_contrat[
'qty'] * $qtyCoef;
4189 $parameters = array(
'socid' => $socid);
4190 $reshook = $hookmanager->executeHooks(
'loadStatsContract', $parameters, $this, $action);
4192 $this->stats_contrat = $hookmanager->resArray[
'stats_contrat'];
4197 $this->error = $this->db->error().
' sql='.$sql;
4212 global $user, $hookmanager, $action;
4214 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4215 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(".$this->db->ifsql(
'f.type != 2',
'fd.qty',
'fd.qty * -1').
") as qty";
4216 $sql .=
" FROM ".$this->db->prefix().
"facturedet as fd";
4217 $sql .=
", ".$this->db->prefix().
"facture as f";
4218 $sql .=
", ".$this->db->prefix().
"societe as s";
4219 $sql .=
" WHERE f.rowid = fd.fk_facture";
4220 $sql .=
" AND f.fk_soc = s.rowid";
4221 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4222 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4223 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4224 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4228 $sql .=
" AND f.fk_soc = ".((int) $socid);
4231 $result = $this->db->query($sql);
4233 $obj = $this->db->fetch_object($result);
4234 $this->stats_facture[
'customers'] = $obj->nb_customers;
4235 $this->stats_facture[
'nb'] = $obj->nb;
4236 $this->stats_facture[
'rows'] = $obj->nb_rows;
4237 $this->stats_facture[
'qty'] = $obj->qty ? $obj->qty : 0;
4242 if (is_array($TFather) && !empty($TFather)) {
4243 foreach ($TFather as &$fatherData) {
4244 $pFather =
new Product($this->db);
4245 $pFather->id = $fatherData[
'id'];
4246 $qtyCoef = $fatherData[
'qty'];
4248 if ($fatherData[
'incdec']) {
4249 $pFather->load_stats_facture($socid);
4251 $this->stats_facture[
'customers'] += $pFather->stats_facture[
'customers'];
4252 $this->stats_facture[
'nb'] += $pFather->stats_facture[
'nb'];
4253 $this->stats_facture[
'rows'] += $pFather->stats_facture[
'rows'];
4254 $this->stats_facture[
'qty'] += $pFather->stats_facture[
'qty'] * $qtyCoef;
4260 $parameters = array(
'socid' => $socid);
4261 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoice', $parameters, $this, $action);
4263 $this->stats_facture = $hookmanager->resArray[
'stats_facture'];
4268 $this->error = $this->db->error();
4284 global $user, $hookmanager, $action;
4286 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4287 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4288 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facturedet_rec as fd";
4289 $sql .=
", ".MAIN_DB_PREFIX.
"facture_rec as f";
4290 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
4291 $sql .=
" WHERE f.rowid = fd.fk_facture";
4292 $sql .=
" AND f.fk_soc = s.rowid";
4293 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
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_facturerec[
'customers'] = (int) $obj->nb_customers;
4307 $this->stats_facturerec[
'nb'] = (int) $obj->nb;
4308 $this->stats_facturerec[
'rows'] = (int) $obj->nb_rows;
4309 $this->stats_facturerec[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4314 if (is_array($TFather) && !empty($TFather)) {
4315 foreach ($TFather as &$fatherData) {
4316 $pFather =
new Product($this->db);
4317 $pFather->id = $fatherData[
'id'];
4318 $qtyCoef = $fatherData[
'qty'];
4320 if ($fatherData[
'incdec']) {
4321 $pFather->load_stats_facture($socid);
4323 $this->stats_facturerec[
'customers'] += $pFather->stats_facturerec[
'customers'];
4324 $this->stats_facturerec[
'nb'] += $pFather->stats_facturerec[
'nb'];
4325 $this->stats_facturerec[
'rows'] += $pFather->stats_facturerec[
'rows'];
4326 $this->stats_facturerec[
'qty'] += $pFather->stats_facturerec[
'qty'] * $qtyCoef;
4332 $parameters = array(
'socid' => $socid);
4333 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoiceRec', $parameters, $this, $action);
4335 $this->stats_facturerec = $hookmanager->resArray[
'stats_facturerec'];
4340 $this->error = $this->db->error();
4355 global $user, $hookmanager, $action;
4357 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
4358 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4359 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as fd";
4360 $sql .=
", ".$this->db->prefix().
"facture_fourn as f";
4361 $sql .=
", ".$this->db->prefix().
"societe as s";
4362 $sql .=
" WHERE f.rowid = fd.fk_facture_fourn";
4363 $sql .=
" AND f.fk_soc = s.rowid";
4364 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4365 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4366 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4367 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4371 $sql .=
" AND f.fk_soc = ".((int) $socid);
4374 $result = $this->db->query($sql);
4376 $obj = $this->db->fetch_object($result);
4377 $this->stats_facture_fournisseur[
'suppliers'] = (int) $obj->nb_suppliers;
4378 $this->stats_facture_fournisseur[
'nb'] = (int) $obj->nb;
4379 $this->stats_facture_fournisseur[
'rows'] = (int) $obj->nb_rows;
4380 $this->stats_facture_fournisseur[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4382 $parameters = array(
'socid' => $socid);
4383 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoice', $parameters, $this, $action);
4385 $this->stats_facture_fournisseur = $hookmanager->resArray[
'stats_facture_fournisseur'];
4390 $this->error = $this->db->error();
4405 global $user, $hookmanager, $action;
4407 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
4408 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4409 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facture_fourn_det_rec as fd";
4410 $sql .=
", ".MAIN_DB_PREFIX.
"facture_fourn_rec as f";
4411 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
4412 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4413 $sql .=
", ".MAIN_DB_PREFIX.
"societe_commerciaux as sc";
4415 $sql .=
" WHERE f.rowid = fd.fk_facture";
4416 $sql .=
" AND f.fk_soc = s.rowid";
4417 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4418 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4419 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4420 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4424 $sql .=
" AND f.fk_soc = ".((int) $socid);
4427 $result = $this->db->query($sql);
4429 $obj = $this->db->fetch_object($result);
4430 $this->stats_facturefournrec[
'suppliers'] = (int) $obj->nb_suppliers;
4431 $this->stats_facturefournrec[
'nb'] = (int) $obj->nb;
4432 $this->stats_facturefournrec[
'rows'] = (int) $obj->nb_rows;
4433 $this->stats_facturefournrec[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4435 $parameters = array(
'socid' => $socid);
4436 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoiceRec', $parameters, $this, $action);
4438 $this->stats_facturefournrec = $hookmanager->resArray[
'stats_facturefournrec'];
4443 $this->error = $this->db->error();
4462 $resql = $this->db->query($sql);
4464 $num = $this->db->num_rows($resql);
4467 $arr = $this->db->fetch_array($resql);
4468 if (is_array($arr)) {
4469 $keyfortab = (string) $arr[1];
4471 $keyfortab = substr($keyfortab, -2);
4474 if ($mode ==
'byunit') {
4475 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[0];
4476 } elseif ($mode ==
'bynumber') {
4477 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4478 } elseif ($mode ==
'byamount') {
4479 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4488 $this->error = $this->db->error().
' sql='.$sql;
4495 } elseif ($year == -1) {
4504 for ($j = 0; $j < 12; $j++) {
4506 $idx = ucfirst(
dol_trunc(
dol_print_date(
dol_mktime(12, 0, 0, $month, 1, 1970),
"%b"), 1,
'right',
'UTF-8', 1));
4509 $result[$j] = array($idx, isset($tab[$year.$month]) ? $tab[$year.$month] : 0);
4512 $month =
"0".($month - 1);
4514 $month = substr($month, 1);
4522 return array_reverse($result);
4537 public function get_nb_vente($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4542 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4543 if ($mode ==
'bynumber') {
4544 $sql .=
", count(DISTINCT f.rowid)";
4546 $sql .=
", sum(d.total_ht) as total_ht";
4547 $sql .=
" FROM ".$this->db->prefix().
"facturedet as d, ".$this->db->prefix().
"facture as f, ".$this->db->prefix().
"societe as s";
4548 if ($filteronproducttype >= 0) {
4549 $sql .=
", ".$this->db->prefix().
"product as p";
4551 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4552 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4554 $sql .=
" WHERE f.rowid = d.fk_facture";
4555 if ($this->
id > 0) {
4556 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4558 $sql .=
" AND d.fk_product > 0";
4560 if ($filteronproducttype >= 0) {
4561 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4563 $sql .=
" AND f.fk_soc = s.rowid";
4564 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4565 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4566 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4569 $sql .=
" AND f.fk_soc = $socid";
4571 $sql .= $morefilter;
4572 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4573 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4575 return $this->
_get_stats($sql, $mode, $year);
4590 public function get_nb_achat($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4595 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4596 if ($mode ==
'bynumber') {
4597 $sql .=
", count(DISTINCT f.rowid)";
4599 $sql .=
", sum(d.total_ht) as total_ht";
4600 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as d, ".$this->db->prefix().
"facture_fourn as f, ".$this->db->prefix().
"societe as s";
4601 if ($filteronproducttype >= 0) {
4602 $sql .=
", ".$this->db->prefix().
"product as p";
4604 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4605 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4607 $sql .=
" WHERE f.rowid = d.fk_facture_fourn";
4608 if ($this->
id > 0) {
4609 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4611 $sql .=
" AND d.fk_product > 0";
4613 if ($filteronproducttype >= 0) {
4614 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4616 $sql .=
" AND f.fk_soc = s.rowid";
4617 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4618 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4619 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4622 $sql .=
" AND f.fk_soc = $socid";
4624 $sql .= $morefilter;
4625 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4626 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4628 return $this->
_get_stats($sql, $mode, $year);
4642 public function get_nb_propal($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4645 global $user, $hookmanager;
4647 $sql =
"SELECT sum(d.qty) as qty, date_format(p.datep, '%Y%m')";
4648 if ($mode ==
'bynumber') {
4649 $sql .=
", count(DISTINCT p.rowid)";
4651 $sql .=
", sum(d.total_ht) as total_ht";
4652 $sql .=
" FROM ".$this->db->prefix().
"propaldet as d, ".$this->db->prefix().
"propal as p, ".$this->db->prefix().
"societe as s";
4653 if ($filteronproducttype >= 0) {
4654 $sql .=
", ".$this->db->prefix().
"product as prod";
4656 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4657 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4659 $sql .=
" WHERE p.rowid = d.fk_propal";
4660 if ($this->
id > 0) {
4661 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4663 $sql .=
" AND d.fk_product > 0";
4665 if ($filteronproducttype >= 0) {
4666 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4668 $sql .=
" AND p.fk_soc = s.rowid";
4669 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
4670 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4671 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4674 $sql .=
" AND p.fk_soc = ".((int) $socid);
4676 $sql .= $morefilter;
4677 $parameters = array(
'socid' => $user->socid);
4678 $hookmanager->executeHooks(
'productGetNbPropal', $parameters, $this);
4679 $sql .= $hookmanager->resPrint;
4680 $sql .=
" GROUP BY date_format(p.datep,'%Y%m')";
4681 $sql .=
" ORDER BY date_format(p.datep,'%Y%m') DESC";
4682 return $this->
_get_stats($sql, $mode, $year);
4701 $sql =
"SELECT sum(d.qty) as qty, date_format(p.date_valid, '%Y%m')";
4702 if ($mode ==
'bynumber') {
4703 $sql .=
", count(DISTINCT p.rowid)";
4705 $sql .=
", sum(d.total_ht) as total_ht";
4706 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as d, ".$this->db->prefix().
"supplier_proposal as p, ".$this->db->prefix().
"societe as s";
4707 if ($filteronproducttype >= 0) {
4708 $sql .=
", ".$this->db->prefix().
"product as prod";
4710 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4711 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4713 $sql .=
" WHERE p.rowid = d.fk_supplier_proposal";
4714 if ($this->
id > 0) {
4715 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4717 $sql .=
" AND d.fk_product > 0";
4719 if ($filteronproducttype >= 0) {
4720 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4722 $sql .=
" AND p.fk_soc = s.rowid";
4723 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
4724 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4725 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4728 $sql .=
" AND p.fk_soc = ".((int) $socid);
4730 $sql .= $morefilter;
4731 $sql .=
" GROUP BY date_format(p.date_valid,'%Y%m')";
4732 $sql .=
" ORDER BY date_format(p.date_valid,'%Y%m') DESC";
4734 return $this->
_get_stats($sql, $mode, $year);
4748 public function get_nb_order($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4751 global $user, $hookmanager;
4753 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4754 if ($mode ==
'bynumber') {
4755 $sql .=
", count(DISTINCT c.rowid)";
4757 $sql .=
", sum(d.total_ht) as total_ht";
4758 $sql .=
" FROM ".$this->db->prefix().
"commandedet as d, ".$this->db->prefix().
"commande as c, ".$this->db->prefix().
"societe as s";
4759 if ($filteronproducttype >= 0) {
4760 $sql .=
", ".$this->db->prefix().
"product as p";
4762 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4763 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4765 $sql .=
" WHERE c.rowid = d.fk_commande";
4766 if ($this->
id > 0) {
4767 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4769 $sql .=
" AND d.fk_product > 0";
4771 if ($filteronproducttype >= 0) {
4772 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4774 $sql .=
" AND c.fk_soc = s.rowid";
4775 $sql .=
" AND c.entity IN (".getEntity(
'commande').
")";
4776 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4777 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4780 $sql .=
" AND c.fk_soc = ".((int) $socid);
4782 $sql .= $morefilter;
4783 $parameters = array(
'socid' => $user->socid);
4784 $hookmanager->executeHooks(
'productGetNbOrder', $parameters, $this);
4785 $sql .= $hookmanager->resPrint;
4786 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4787 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4789 return $this->
_get_stats($sql, $mode, $year);
4808 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4809 if ($mode ==
'bynumber') {
4810 $sql .=
", count(DISTINCT c.rowid)";
4812 $sql .=
", sum(d.total_ht) as total_ht";
4813 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as d, ".$this->db->prefix().
"commande_fournisseur as c, ".$this->db->prefix().
"societe as s";
4814 if ($filteronproducttype >= 0) {
4815 $sql .=
", ".$this->db->prefix().
"product as p";
4817 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4818 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4820 $sql .=
" WHERE c.rowid = d.fk_commande";
4821 if ($this->
id > 0) {
4822 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4824 $sql .=
" AND d.fk_product > 0";
4826 if ($filteronproducttype >= 0) {
4827 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4829 $sql .=
" AND c.fk_soc = s.rowid";
4830 $sql .=
" AND c.entity IN (".getEntity(
'supplier_order').
")";
4831 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4832 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4835 $sql .=
" AND c.fk_soc = ".((int) $socid);
4837 $sql .= $morefilter;
4838 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4839 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4841 return $this->
_get_stats($sql, $mode, $year);
4855 public function get_nb_contract($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4860 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_contrat, '%Y%m')";
4861 if ($mode ==
'bynumber') {
4862 $sql .=
", count(DISTINCT c.rowid)";
4864 $sql .=
", sum(d.total_ht) as total_ht";
4865 $sql .=
" FROM ".$this->db->prefix().
"contratdet as d, ".$this->db->prefix().
"contrat as c, ".$this->db->prefix().
"societe as s";
4866 if ($filteronproducttype >= 0) {
4867 $sql .=
", ".$this->db->prefix().
"product as p";
4869 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4870 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4872 $sql .=
" WHERE c.entity IN (".getEntity(
'contract').
")";
4873 $sql .=
" AND c.rowid = d.fk_contrat";
4875 if ($this->
id > 0) {
4876 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4878 $sql .=
" AND d.fk_product > 0";
4880 if ($filteronproducttype >= 0) {
4881 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4883 $sql .=
" AND c.fk_soc = s.rowid";
4885 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4886 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4889 $sql .=
" AND c.fk_soc = ".((int) $socid);
4891 $sql .= $morefilter;
4892 $sql .=
" GROUP BY date_format(c.date_contrat,'%Y%m')";
4893 $sql .=
" ORDER BY date_format(c.date_contrat,'%Y%m') DESC";
4895 return $this->
_get_stats($sql, $mode, $year);
4909 public function get_nb_mos($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4914 $sql =
"SELECT sum(d.qty), date_format(d.date_valid, '%Y%m')";
4915 if ($mode ==
'bynumber') {
4916 $sql .=
", count(DISTINCT d.rowid)";
4918 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as d LEFT JOIN ".$this->db->prefix().
"societe as s ON d.fk_soc = s.rowid";
4919 if ($filteronproducttype >= 0) {
4920 $sql .=
", ".$this->db->prefix().
"product as p";
4922 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4923 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4926 $sql .=
" WHERE d.entity IN (".getEntity(
'mo').
")";
4927 $sql .=
" AND d.status > 0";
4929 if ($this->
id > 0) {
4930 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4932 $sql .=
" AND d.fk_product > 0";
4934 if ($filteronproducttype >= 0) {
4935 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4938 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4939 $sql .=
" AND d.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4942 $sql .=
" AND d.fk_soc = ".((int) $socid);
4944 $sql .= $morefilter;
4945 $sql .=
" GROUP BY date_format(d.date_valid,'%Y%m')";
4946 $sql .=
" ORDER BY date_format(d.date_valid,'%Y%m') DESC";
4948 return $this->
_get_stats($sql, $mode, $year);
4968 if (!is_numeric($id_pere)) {
4971 if (!is_numeric($id_fils)) {
4974 if (!is_numeric($incdec)) {
4984 $sql =
"SELECT fk_product_pere from ".$this->db->prefix().
"product_association";
4985 $sql .=
" WHERE fk_product_pere = ".((int) $id_fils).
" AND fk_product_fils = ".((int) $id_pere);
4986 if (!$this->db->query($sql)) {
4991 $sql =
"SELECT MAX(rang) as max_rank FROM ".$this->db->prefix().
"product_association";
4992 $sql .=
" WHERE fk_product_pere = ".((int) $id_pere);
4993 $resql = $this->db->query($sql);
4995 $obj = $this->db->fetch_object($resql);
4996 $rank = $obj->max_rank + 1;
4998 $sql =
"INSERT INTO ".$this->db->prefix().
"product_association(fk_product_pere,fk_product_fils,qty,incdec,rang)";
4999 $sql .=
" VALUES (".((int) $id_pere).
", ".((int) $id_fils).
", ".
price2num($qty,
'MS').
", ".((int) $incdec).
", ".((int) $rank).
")";
5000 if (! $this->db->query($sql)) {
5006 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_ADD', $user);
5008 $this->error = $this->db->lasterror();
5009 dol_syslog(get_class($this).
'::addSubproduct error='.$this->error, LOG_ERR);
5041 if (!is_numeric($id_pere)) {
5044 if (!is_numeric($id_fils)) {
5047 if (!is_numeric($incdec)) {
5050 if (!is_numeric($qty)) {
5054 $sql =
'UPDATE '.$this->db->prefix().
'product_association SET ';
5055 $sql .=
'qty = '.price2num($qty,
'MS');
5056 $sql .=
',incdec = '.((int) $incdec);
5057 $sql .=
' WHERE fk_product_pere = '.((int) $id_pere).
' AND fk_product_fils = '.((int) $id_fils);
5059 if (!$this->db->query($sql)) {
5065 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_UPDATE', $user);
5067 $this->error = $this->db->lasterror();
5068 dol_syslog(get_class($this).
'::updateSubproduct error='.$this->error, LOG_ERR);
5092 if (!is_numeric($fk_parent)) {
5095 if (!is_numeric($fk_child)) {
5099 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
5100 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5101 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
5103 dol_syslog(get_class($this).
'::del_sousproduit', LOG_DEBUG);
5104 if (!$this->db->query($sql)) {
5110 $sqlrank =
"SELECT rowid, rang FROM ".$this->db->prefix().
"product_association";
5111 $sqlrank .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5112 $sqlrank .=
" ORDER BY rang";
5113 $resqlrank = $this->db->query($sqlrank);
5116 while ($objrank = $this->db->fetch_object($resqlrank)) {
5118 $sql =
"UPDATE ".$this->db->prefix().
"product_association";
5119 $sql .=
" SET rang = ".((int) $cpt);
5120 $sql .=
" WHERE rowid = ".((int) $objrank->rowid);
5121 if (! $this->db->query($sql)) {
5130 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_DELETE', $user);
5132 $this->error = $this->db->lasterror();
5133 dol_syslog(get_class($this).
'::delSubproduct error='.$this->error, LOG_ERR);
5153 $sql =
"SELECT fk_product_pere, qty, incdec";
5154 $sql .=
" FROM ".$this->db->prefix().
"product_association";
5155 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5156 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
5158 $result = $this->db->query($sql);
5160 $num = $this->db->num_rows($result);
5163 $obj = $this->db->fetch_object($result);
5165 $this->is_sousproduit_qty = $obj->qty;
5166 $this->is_sousproduit_incdec = $obj->incdec;
5197 dol_syslog(get_class($this).
"::add_fournisseur id_fourn = ".$id_fourn.
" ref_fourn=".$ref_fourn.
" quantity=".$quantity, LOG_DEBUG);
5204 $sql =
"SELECT rowid, fk_product";
5205 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5206 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5207 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5208 $sql .=
" AND fk_product <> ".((int) $this->
id);
5209 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5211 $resql = $this->db->query($sql);
5213 $obj = $this->db->fetch_object($resql);
5216 $this->product_id_already_linked = $obj->fk_product;
5219 $this->db->free($resql);
5223 $sql =
"SELECT rowid";
5224 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5225 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5227 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5229 $sql .=
" AND (ref_fourn = '' OR ref_fourn IS NULL)";
5231 $sql .=
" AND quantity = ".((float) $quantity);
5232 $sql .=
" AND fk_product = ".((int) $this->
id);
5233 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5235 $resql = $this->db->query($sql);
5237 $obj = $this->db->fetch_object($resql);
5241 $sql =
"INSERT INTO ".$this->db->prefix().
"product_fournisseur_price(";
5244 $sql .=
", fk_product";
5246 $sql .=
", ref_fourn";
5247 $sql .=
", quantity";
5248 $sql .=
", fk_user";
5250 $sql .=
") VALUES (";
5251 $sql .=
"'".$this->db->idate($now).
"'";
5252 $sql .=
", ".((int) $conf->entity);
5253 $sql .=
", ".((int) $this->
id);
5254 $sql .=
", ".((int) $id_fourn);
5255 $sql .=
", '".$this->db->escape($ref_fourn).
"'";
5256 $sql .=
", ".((float) $quantity);
5257 $sql .=
", ".((int) $user->id);
5261 if ($this->db->query($sql)) {
5262 $this->product_fourn_price_id = $this->db->last_insert_id($this->db->prefix().
"product_fournisseur_price");
5265 $this->error = $this->db->lasterror();
5270 $this->product_fourn_price_id = $obj->rowid;
5274 $this->error = $this->db->lasterror();
5293 $sql =
"SELECT DISTINCT p.fk_soc";
5294 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as p";
5295 $sql .=
" WHERE p.fk_product = ".((int) $this->
id);
5296 $sql .=
" AND p.entity = ".((int) $conf->entity);
5298 $result = $this->db->query($sql);
5300 $num = $this->db->num_rows($result);
5303 $obj = $this->db->fetch_object($result);
5304 $list[$i] = $obj->fk_soc;
5330 $sql =
"INSERT INTO ".$this->db->prefix().
"product_price (";
5332 $sql .=
", fk_product";
5333 $sql .=
", date_price";
5334 $sql .=
", price_level";
5336 $sql .=
", price_ttc";
5337 $sql .=
", price_min";
5338 $sql .=
", price_min_ttc";
5339 $sql .=
", price_base_type";
5340 $sql .=
", price_label";
5341 $sql .=
", default_vat_code";
5343 $sql .=
", recuperableonly";
5344 $sql .=
", localtax1_tx";
5345 $sql .=
", localtax1_type";
5346 $sql .=
", localtax2_tx";
5347 $sql .=
", localtax2_type";
5348 $sql .=
", fk_user_author";
5350 $sql .=
", price_by_qty";
5351 $sql .=
", fk_price_expression";
5352 $sql .=
", fk_multicurrency";
5353 $sql .=
", multicurrency_code";
5354 $sql .=
", multicurrency_tx";
5355 $sql .=
", multicurrency_price";
5356 $sql .=
", multicurrency_price_ttc";
5360 $sql .=
", ".((int) $toId);
5361 $sql .=
", '".$this->db->idate($now).
"'";
5362 $sql .=
", price_level";
5364 $sql .=
", price_ttc";
5365 $sql .=
", price_min";
5366 $sql .=
", price_min_ttc";
5367 $sql .=
", price_base_type";
5368 $sql .=
", price_label";
5369 $sql .=
", default_vat_code";
5371 $sql .=
", recuperableonly";
5372 $sql .=
", localtax1_tx";
5373 $sql .=
", localtax1_type";
5374 $sql .=
", localtax2_tx";
5375 $sql .=
", localtax2_type";
5376 $sql .=
", ".((int) $user->id);
5378 $sql .=
", price_by_qty";
5379 $sql .=
", fk_price_expression";
5380 $sql .=
", fk_multicurrency";
5381 $sql .=
", multicurrency_code";
5382 $sql .=
", multicurrency_tx";
5383 $sql .=
", multicurrency_price";
5384 $sql .=
", multicurrency_price_ttc";
5385 $sql .=
" FROM ".$this->db->prefix().
"product_price ps";
5386 $sql .=
" WHERE fk_product = ".((int) $fromId);
5387 $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)";
5388 $sql .=
" ORDER BY date_price DESC";
5391 $resql = $this->db->query($sql);
5393 $this->db->rollback();
5397 $this->db->commit();
5414 $sql =
'INSERT INTO '.$this->db->prefix().
'product_association (fk_product_pere, fk_product_fils, qty, incdec)';
5415 $sql .=
" SELECT ".((int) $toId).
", fk_product_fils, qty, incdec FROM ".$this->db->prefix().
"product_association";
5416 $sql .=
" WHERE fk_product_pere = ".((int) $fromId);
5418 dol_syslog(get_class($this).
'::clone_association', LOG_DEBUG);
5419 if (!$this->db->query($sql)) {
5420 $this->db->rollback();
5424 $this->db->commit();
5457 $sql =
"INSERT ".$this->db->prefix().
"product_fournisseur_price (";
5458 $sql .=
" datec, fk_product, fk_soc, price, quantity, fk_user, tva_tx)";
5459 $sql .=
" SELECT '".$this->db->idate($now).
"', ".((int) $toId).
", fk_soc, price, quantity, fk_user, tva_tx";
5460 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5461 $sql .=
" WHERE fk_product = ".((int) $fromId);
5463 dol_syslog(get_class($this).
'::clone_fournisseurs', LOG_DEBUG);
5464 $resql = $this->db->query($sql);
5466 $this->db->rollback();
5469 $this->db->commit();
5487 public function fetch_prod_arbo($prod, $compl_path =
'', $multiply = 1, $level = 1, $id_parent = 0, $ignore_stock_load = 0)
5492 if ($multiply < 1) {
5493 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);
5498 foreach ($prod as $id_product => $desc_pere) {
5499 if (is_array($desc_pere)) {
5500 $id = (!empty($desc_pere[0]) ? $desc_pere[0] :
'');
5501 $nb = (!empty($desc_pere[1]) ? $desc_pere[1] :
'');
5502 $type = (!empty($desc_pere[2]) ? $desc_pere[2] :
'');
5503 $label = (!empty($desc_pere[3]) ? $desc_pere[3] :
'');
5504 $incdec = (!empty($desc_pere[4]) ? $desc_pere[4] : 0);
5507 if (is_null($tmpproduct)) {
5508 $tmpproduct =
new Product($this->db);
5510 $tmpproduct->fetch($id);
5512 if (empty($ignore_stock_load) && ($tmpproduct->isProduct() ||
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES'))) {
5513 $tmpproduct->load_stock(
'nobatch,novirtual');
5516 $this->res[] = array(
5518 'id_parent' => $id_parent,
5519 'ref' => $tmpproduct->ref,
5521 'nb_total' => $nb * $multiply,
5522 'stock' => $tmpproduct->stock_reel,
5523 'stock_alert' => $tmpproduct->seuil_stock_alerte,
5525 'fullpath' => $compl_path.$label,
5527 'desiredstock' => $tmpproduct->desiredstock,
5529 'incdec' => $incdec,
5530 'entity' => $tmpproduct->entity
5534 if (isset($desc_pere[
'childs']) && is_array($desc_pere[
'childs'])) {
5535 if (!is_int($desc_pere[1] * $multiply)) {
5536 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);
5540 $this->
fetch_prod_arbo($desc_pere[
'childs'], $compl_path.$desc_pere[3].
" -> ", (
int) ceil($desc_pere[1] * $multiply), $level + 1, $id, $ignore_stock_load);
5558 $this->res = array();
5559 if (isset($this->sousprods) && is_array($this->sousprods)) {
5560 foreach ($this->sousprods as $prod_name => $desc_product) {
5561 if (is_array($desc_product)) {
5562 $this->
fetch_prod_arbo($desc_product,
"", $multiply, 1, $this->
id, $ignore_stock_load);
5581 $sql =
"SELECT COUNT(pa.rowid) as nb";
5582 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa";
5584 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id).
" OR pa.fk_product_pere = ".((int) $this->
id);
5585 } elseif ($mode == -1) {
5586 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id);
5587 } elseif ($mode == 1) {
5588 $sql .=
" WHERE pa.fk_product_pere = ".((int) $this->
id);
5591 $resql = $this->db->query($sql);
5593 $obj = $this->db->fetch_object($resql);
5595 $nb = (int) $obj->nb;
5615 $sql =
"SELECT count(rowid) as nb FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_parent = ".((int) $this->
id);
5616 $sql .=
" AND entity IN (".getEntity(
'product').
")";
5618 $resql = $this->db->query($sql);
5620 $obj = $this->db->fetch_object($resql);
5622 $nb = (int) $obj->nb;
5638 $sql =
"SELECT rowid FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_child = ".((int) $this->
id).
" AND entity IN (".
getEntity(
'product').
")";
5640 $query = $this->db->query($sql);
5643 if (!$this->db->num_rows($query)) {
5664 $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";
5665 $sql .=
", p.tosell as status, p.tobuy as status_buy";
5666 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa,";
5667 $sql .=
" ".$this->db->prefix().
"product as p";
5668 $sql .=
" WHERE p.rowid = pa.fk_product_pere";
5669 $sql .=
" AND pa.fk_product_fils = ".((int) $this->
id);
5671 $res = $this->db->query($sql);
5674 while ($record = $this->db->fetch_array($res)) {
5676 $prods[$record[
'id']] = array();
5677 $prods[$record[
'id']][
'id'] = $record[
'rowid'];
5678 $prods[$record[
'id']][
'ref'] = $record[
'ref'];
5679 $prods[$record[
'id']][
'label'] = $record[
'label'];
5680 $prods[$record[
'id']][
'qty'] = $record[
'qty'];
5681 $prods[$record[
'id']][
'incdec'] = $record[
'incdec'];
5682 $prods[$record[
'id']][
'fk_product_type'] = $record[
'fk_product_type'];
5683 $prods[$record[
'id']][
'entity'] = $record[
'entity'];
5684 $prods[$record[
'id']][
'status'] = $record[
'status'];
5685 $prods[$record[
'id']][
'status_buy'] = $record[
'status_buy'];
5704 public function getChildsArbo($id, $firstlevelonly = 0, $level = 1, $parents = array())
5710 $sql =
"SELECT p.rowid, p.ref, p.label as label, p.fk_product_type,";
5711 $sql .=
" pa.qty as qty, pa.fk_product_fils as id, pa.incdec,";
5712 $sql .=
" pa.rowid as fk_association, pa.rang";
5713 $sql .=
" FROM ".$this->db->prefix().
"product as p,";
5714 $sql .=
" ".$this->db->prefix().
"product_association as pa";
5715 $sql .=
" WHERE p.rowid = pa.fk_product_fils";
5716 $sql .=
" AND pa.fk_product_pere = ".((int) $id);
5717 $sql .=
" AND pa.fk_product_fils <> ".((int) $id);
5718 $sql .=
" ORDER BY pa.rang";
5720 dol_syslog(get_class($this).
'::getChildsArbo id='.$id.
' level='.$level.
' parents='.(is_array($parents) ? implode(
',', $parents) : $parents), LOG_DEBUG);
5727 $res = $this->db->query($sql);
5730 if ($this->db->num_rows($res) > 0) {
5734 while ($rec = $this->db->fetch_array($res)) {
5735 if (in_array($rec[
'id'], $parents)) {
5736 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);
5740 $prods[$rec[
'rowid']] = array(
5743 2 => $rec[
'fk_product_type'],
5744 3 => $this->db->escape($rec[
'label']),
5745 4 => $rec[
'incdec'],
5747 6 => $rec[
'fk_association'],
5752 if (empty($firstlevelonly)) {
5753 $listofchilds = $this->
getChildsArbo($rec[
'rowid'], 0, $level + 1, $parents);
5754 foreach ($listofchilds as $keyChild => $valueChild) {
5755 $prods[$rec[
'rowid']][
'childs'][$keyChild] = $valueChild;
5779 foreach ($this->
getChildsArbo($this->
id) as $keyChild => $valueChild) {
5780 $parent[$this->label][$keyChild] = $valueChild;
5782 foreach ($parent as $key => $value) {
5783 $this->sousprods[$key] = $value;
5796 global $conf, $langs, $user;
5798 $langs->loadLangs(array(
'products',
'other'));
5801 $nofetch = !empty($params[
'nofetch']);
5804 return [
'optimize' => $langs->trans(
"ShowProduct")];
5808 $permissiontoreadproduct = 0;
5809 if ($this->
type == self::TYPE_PRODUCT && $user->hasRight(
'product',
'read')) {
5810 $permissiontoreadproduct = 1;
5812 if ($this->
type == self::TYPE_SERVICE && $user->hasRight(
'service',
'read')) {
5813 $permissiontoreadproduct = 1;
5816 if (!empty($this->entity) && $permissiontoreadproduct) {
5817 $tmpphoto = $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 80, 0, 0, 0, 0,
'1');
5818 if ($this->nbphoto > 0) {
5819 $datas[
'photo'] =
'<div class="photointooltip floatright">'.
"\n" . $tmpphoto .
'</div>';
5824 $datas[
'picto'] =
img_picto(
'',
'product').
' <u class="paddingrightonly">'.$langs->trans(
"Product").
'</u>';
5826 $datas[
'picto'] =
img_picto(
'',
'service').
' <u class="paddingrightonly">'.$langs->trans(
"Service").
'</u>';
5828 if (isset($this->
status) && isset($this->status_buy)) {
5829 $datas[
'status'] =
' '.$this->getLibStatut(5, 0) .
' '.$this->getLibStatut(5, 1);
5832 if (!empty($this->
ref)) {
5833 $datas[
'ref'] =
'<br><b>'.$langs->trans(
'ProductRef').
':</b> '.$this->ref;
5835 if (!empty($this->label)) {
5836 $datas[
'label'] =
'<br><b>'.$langs->trans(
'ProductLabel').
':</b> '.$this->label.
'<br>';
5839 if ($permissiontoreadproduct) {
5844 $datas[
'stockmanaged'] =
"<br><b>".$langs->trans(
"StockableProduct").
'</b>: '.
yn($this->
isStockManaged());
5848 $langs->load(
"productbatch");
5849 $datas[
'batchstatus'] =
"<br><b>".$langs->trans(
"ManageLotSerial").
'</b>: '.$this->
getLibStatut(0, 2);
5850 if ($this->status_batch) {
5851 $datas[
'batchdlc'] =
"<br><b>".$langs->trans(
"BatchSellOrEatByMandatoryList", $langs->transnoentitiesnoconv(
"SellByDate"), $langs->transnoentitiesnoconv(
"EatByDate")).
'</b>: '.$this->
getSellOrEatByMandatoryLabel();
5856 $datas[
'barcode'] =
'<br><b>'.$langs->trans(
'BarCode').
':</b> '.$this->barcode;
5860 if ($this->weight) {
5861 $datas[
'weight'] =
"<br><b>".$langs->trans(
"Weight").
'</b>: '.$this->weight.
' '.
measuringUnitString(0,
"weight", $this->weight_units);
5864 if ($this->length) {
5865 $labelsize .=
"<b>".$langs->trans(
"Length").
'</b>: '.$this->length.
' '.
measuringUnitString(0,
'size', $this->length_units);
5868 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Width").
'</b>: '.$this->width.
' '.
measuringUnitString(0,
'size', $this->width_units);
5870 if ($this->height) {
5871 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Height").
'</b>: '.$this->height.
' '.
measuringUnitString(0,
'size', $this->height_units);
5874 $datas[
'size'] =
"<br>".$labelsize;
5877 $labelsurfacevolume =
"";
5878 if ($this->surface) {
5879 $labelsurfacevolume .=
"<b>".$langs->trans(
"Surface").
'</b>: '.$this->surface.
' '.
measuringUnitString(0,
'surface', $this->surface_units);
5881 if ($this->volume) {
5882 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Volume").
'</b>: '.$this->volume.
' '.
measuringUnitString(0,
'volume', $this->volume_units);
5884 if ($labelsurfacevolume) {
5885 $datas[
'surface'] =
"<br>" . $labelsurfacevolume;
5888 if ($this->
isService() && !empty($this->duration_value)) {
5890 $datas[
'duration'] =
'<br><b>'.$langs->trans(
"Duration").
':</b> '.$this->duration_value;
5891 if ($this->duration_value > 1) {
5892 $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"));
5893 } elseif ($this->duration_value > 0) {
5894 $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"));
5896 $datas[
'duration'] .= (!empty($this->duration_unit) && isset($dur[$this->duration_unit]) ?
" ".$langs->trans($dur[$this->duration_unit]) :
'');
5898 if (empty($user->socid)) {
5899 if ($this->
isStockManaged() && isset($this->pmp) && $this->pmp) {
5900 $datas[
'pmp'] =
"<br><b>".$langs->trans(
"PMPValue").
'</b>: '.
price($this->pmp, 0,
'', 1, -1, -1, $conf->currency);
5904 if ($this->
status && isset($this->accountancy_code_sell)) {
5905 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5906 $selllabel =
'<br>';
5907 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellCode').
':</b> '.
length_accountg($this->accountancy_code_sell);
5908 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellIntraCode').
':</b> '.
length_accountg($this->accountancy_code_sell_intra);
5909 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellExportCode').
':</b> '.
length_accountg($this->accountancy_code_sell_export);
5910 $datas[
'accountancysell'] = $selllabel;
5912 if ($this->status_buy && isset($this->accountancy_code_buy)) {
5913 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5915 if (empty($this->
status)) {
5916 $buylabel .=
'<br>';
5918 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyCode').
':</b> '.
length_accountg($this->accountancy_code_buy);
5919 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyIntraCode').
':</b> '.
length_accountg($this->accountancy_code_buy_intra);
5920 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyExportCode').
':</b> '.
length_accountg($this->accountancy_code_buy_export);
5921 $datas[
'accountancybuy'] = $buylabel;
5927 require_once DOL_DOCUMENT_ROOT .
'/categories/class/categorie.class.php';
5928 $form =
new Form($this->db);
5929 $datas[
'categories'] =
'<br>' . $form->showCategories($this->
id, Categorie::TYPE_PRODUCT, 1);
5949 public function getNomUrl($withpicto = 0, $option =
'', $maxlength = 0, $save_lastsearch_value = -1, $notooltip = 0, $morecss =
'', $add_label = 0, $sep =
' - ')
5951 global $langs, $hookmanager;
5953 include_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
5957 $newref = (string) $this->
ref;
5959 $newref =
dol_trunc($newref, $maxlength,
'middle');
5963 'objecttype' => ($this->
type == 1 ?
'service' :
'product'),
5964 'option' => $option,
5967 $classfortooltip =
'classfortooltip';
5970 $classfortooltip =
'classforajaxtooltip';
5971 $dataparams =
' data-params="'.dol_escape_htmltag(json_encode($params)).
'"';
5978 if (empty($notooltip)) {
5980 $label = $langs->trans(
"ShowProduct");
5981 $linkclose .=
' alt="'.dol_escape_htmltag($label, 1, 1).
'"';
5983 $linkclose .= ($label ?
' title="'.dol_escape_htmltag($label, 1, 1).
'"' :
' title="tocomplete"');
5984 $linkclose .= $dataparams.
' class="nowraponall '.$classfortooltip.($morecss ?
' '.$morecss :
'').
'"';
5986 $linkclose =
' class="nowraponall'.($morecss ?
' '.$morecss :
'').
'"';
5989 if ($option ==
'supplier' || $option ==
'category') {
5990 $url = DOL_URL_ROOT.
'/product/price_suppliers.php?id='.$this->id;
5991 } elseif ($option ==
'stock') {
5992 $url = DOL_URL_ROOT.
'/product/stock/product.php?id='.$this->id;
5993 } elseif ($option ==
'composition') {
5994 $url = DOL_URL_ROOT.
'/product/composition/card.php?id='.$this->id;
5996 $url = DOL_URL_ROOT.
'/product/card.php?id='.$this->id;
5999 if ($option !==
'nolink') {
6001 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
6002 if ($save_lastsearch_value == -1 && isset($_SERVER[
"PHP_SELF"]) && preg_match(
'/list\.php/', $_SERVER[
"PHP_SELF"])) {
6003 $add_save_lastsearch_values = 1;
6005 if ($add_save_lastsearch_values) {
6006 $url .=
'&save_lastsearch_values=1';
6010 $linkstart =
'<a href="'.$url.
'"';
6011 $linkstart .= $linkclose.
'>';
6014 $result .= $linkstart;
6017 $result .= (
img_object(($notooltip ?
'' : $label),
'product',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
6020 $result .= (
img_object(($notooltip ?
'' : $label),
'service',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
6023 $result .=
'<span class="aaa">'.dol_escape_htmltag($newref).
'</span>';
6024 $result .= $linkend;
6025 if ($withpicto != 2) {
6026 $result .= (($add_label && $this->label) ? $sep.dol_trunc($this->label, ($add_label > 1 ? $add_label : 0)) :
'');
6030 $hookmanager->initHooks(array(
'productdao'));
6031 $parameters = array(
'id' => $this->
id,
'getnomurl' => &$result,
'label' => &$label);
6032 $reshook = $hookmanager->executeHooks(
'getNomUrl', $parameters, $this, $action);
6034 $result = $hookmanager->resPrint;
6036 $result .= $hookmanager->resPrint;
6053 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
6057 $langs->load(
"products");
6058 $outputlangs->load(
"products");
6065 $modelpath =
"core/modules/product/doc/";
6067 return $this->
commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
6083 return $this->
LibStatut($this->status_buy, $mode, $type);
6085 return $this->
LibStatut($this->status_batch, $mode, $type);
6088 return $this->
LibStatut($this->status_buy, $mode, $type);
6106 $labelStatus = $labelStatusShort =
'';
6108 $langs->load(
'products');
6110 $langs->load(
"productbatch");
6116 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial')));
6119 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort')));
6124 return dolGetStatus($langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch'),
'',
'', empty($status) ?
'status5' :
'status4', 3,
'dot');
6130 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'));
6134 $statuttrans = empty($status) ?
'status5' :
'status4';
6139 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSellShort');
6140 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSell');
6141 } elseif ($type == 1) {
6142 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuyShort');
6143 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuy');
6144 } elseif ($type == 2) {
6145 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch');
6146 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort');
6148 } elseif ($status == 1) {
6151 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSellShort');
6152 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSell');
6153 } elseif ($type == 1) {
6154 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBuyShort');
6155 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBuy');
6156 } elseif ($type == 2) {
6157 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBatch');
6158 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort');
6160 } elseif ($type == 2 && $status == 2) {
6161 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSerial');
6162 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort');
6166 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'),
'',
'',
'status0', 0);
6168 return dolGetStatus($labelStatus, $labelStatusShort,
'', $statuttrans, $mode);
6182 $langs->load(
'products');
6185 if (isset($this->finished) && $this->finished >= 0) {
6186 $sql =
"SELECT label, code FROM ".$this->db->prefix().
"c_product_nature where code = ".((int) $this->finished).
" AND active=1";
6187 $resql = $this->db->query($sql);
6189 $this->error = $this->db->error().
' sql='.$sql;
6190 dol_syslog(__METHOD__.
' Error '.$this->error, LOG_ERR);
6192 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
6193 $label = $langs->trans($res[
'label']);
6195 $this->db->free($resql);
6219 public function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label =
'', $price = 0, $inventorycode =
'', $origin_element =
'', $origin_id =
null, $disablestockchangeforsubproduct = 0, $extrafields =
null)
6225 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6228 $nbpiece = (float) $nbpiece;
6233 $nbpiece = abs($nbpiece);
6240 $movementstock->setOrigin($origin_element, (
int) $origin_id);
6241 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'',
'',
'',
'',
false, 0, $disablestockchangeforsubproduct);
6245 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6246 $movementstock->array_options = $array_options;
6247 $movementstock->insertExtraFields();
6249 $this->db->commit();
6254 $this->db->rollback();
6283 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)
6289 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6292 $nbpiece = (float) $nbpiece;
6297 $nbpiece = abs($nbpiece);
6305 $movementstock->setOrigin($origin_element, (
int) $origin_id);
6306 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'', $dlc, $dluo, $lot,
false, 0, $disablestockchangeforsubproduct, 0, $force_update_batch);
6310 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6311 $movementstock->array_options = $array_options;
6312 $movementstock->insertExtraFields();
6314 $this->db->commit();
6317 $this->error = $movementstock->error;
6318 $this->errors = $movementstock->errors;
6320 $this->db->rollback();
6340 public function load_stock($option =
'', $includedraftpoforvirtual =
null, $dateofvirtualstock =
null)
6343 $this->stock_reel = 0;
6344 $this->stock_warehouse = array();
6345 $this->stock_theorique = 0;
6348 $warehouseStatus = array();
6349 if (preg_match(
'/warehouseclosed/', $option)) {
6352 if (preg_match(
'/warehouseopen/', $option)) {
6355 if (preg_match(
'/warehouseinternal/', $option)) {
6363 $sql =
"SELECT ps.rowid, ps.reel, ps.fk_entrepot";
6364 $sql .=
" FROM ".$this->db->prefix().
"product_stock as ps";
6365 $sql .=
", ".$this->db->prefix().
"entrepot as w";
6366 $sql .=
" WHERE w.entity IN (".getEntity(
'stock').
")";
6367 $sql .=
" AND w.rowid = ps.fk_entrepot";
6368 $sql .=
" AND ps.fk_product = ".((int) $this->
id);
6369 if (count($warehouseStatus)) {
6370 $sql .=
" AND w.statut IN (".$this->db->sanitize(implode(
',', $warehouseStatus)).
")";
6373 $sql .=
" ORDER BY ps.reel ".(getDolGlobalString(
'DO_NOT_TRY_TO_DEFRAGMENT_STOCKS_WAREHOUSE') ?
'DESC' :
'ASC');
6375 dol_syslog(get_class($this).
"::load_stock", LOG_DEBUG);
6376 $result = $this->db->query($sql);
6378 $num = $this->db->num_rows($result);
6382 $row = $this->db->fetch_object($result);
6383 $this->stock_warehouse[$row->fk_entrepot] =
new stdClass();
6384 $this->stock_warehouse[$row->fk_entrepot]->real = $row->reel;
6385 $this->stock_warehouse[$row->fk_entrepot]->id = $row->rowid;
6386 if ((!preg_match(
'/nobatch/', $option)) && $this->
hasbatch()) {
6387 $this->stock_warehouse[$row->fk_entrepot]->detail_batch =
Productbatch::findAll($this->db, $row->rowid, 1, $this->id);
6389 $this->stock_reel += $row->reel;
6392 $this->stock_reel = (float)
price2num($this->stock_reel,
'MS');
6394 $this->db->free($result);
6396 if (!preg_match(
'/novirtual/', $option)) {
6402 $this->error = $this->db->lasterror();
6421 global $hookmanager, $action;
6423 $stock_commande_client = 0;
6424 $stock_commande_fournisseur = 0;
6425 $stock_sending_client = 0;
6426 $stock_reception_fournisseur = 0;
6427 $stock_inproduction = 0;
6436 $stock_commande_client = $this->stats_commande[
'qty'];
6439 require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expedition.class.php';
6440 $filterShipmentStatus =
'';
6450 $stock_sending_client = $this->stats_expedition[
'qty'];
6454 $filterStatus =
getDolGlobalString(
'SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK',
'3,4');
6455 if (isset($includedraftpoforvirtual)) {
6456 $filterStatus =
'0,1,2,'.$filterStatus;
6462 $stock_commande_fournisseur = $this->stats_commande_fournisseur[
'qty'];
6466 $filterStatus =
'4';
6467 if (isset($includedraftpoforvirtual)) {
6468 $filterStatus =
'0,'.$filterStatus;
6474 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
6482 $stock_inproduction = $this->stats_mrptoproduce[
'qty'] - $this->stats_mrptoconsume[
'qty'];
6485 $this->stock_theorique = $this->stock_reel + $stock_inproduction;
6489 $weBillOrderOrShipmentReception =
getDolGlobalString(
'STOCK_DO_WE_BILL_ORDER_OR_SHIPMENTECEPTION_FOR_VIRTUALSTOCK',
'order');
6493 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6497 $result = $tmpnewprod->load_stats_commande(0,
'0', 1);
6498 $this->stock_theorique += $tmpnewprod->stats_commande[
'qty'];
6500 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6501 $this->stock_theorique -= $stock_commande_client;
6502 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6503 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6508 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6510 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6512 if (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER_INCLUDE_DRAFT')) {
6514 $result = $tmpnewprod->load_stats_commande_fournisseur(0,
'0', 1);
6515 $this->stock_theorique += $this->stats_commande_fournisseur[
'qty'];
6517 $this->stock_theorique -= $stock_reception_fournisseur;
6518 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6519 $this->stock_theorique += $stock_commande_fournisseur;
6520 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6521 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6524 $parameters = array(
'id' => $this->
id,
'includedraftpoforvirtual' => $includedraftpoforvirtual);
6526 $reshook = $hookmanager->executeHooks(
'loadvirtualstock', $parameters, $this, $action);
6528 $this->stock_theorique = $hookmanager->resArray[
'stock_theorique'];
6529 } elseif ($reshook == 0 && isset($hookmanager->resArray[
'stock_stats_hook'])) {
6530 $this->stock_theorique += $hookmanager->resArray[
'stock_stats_hook'];
6534 if (!empty($this->stock_warehouse) &&
getDolGlobalString(
'STOCK_ALLOW_VIRTUAL_STOCK_PER_WAREHOUSE')) {
6535 foreach ($this->stock_warehouse as $warehouseid => $stockwarehouse) {
6543 if ($this->fk_default_warehouse == $warehouseid) {
6544 $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']);
6546 $this->stock_warehouse[$warehouseid]->virtual = $this->stock_warehouse[$warehouseid]->real + $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'];
6563 $this->stock_warehouse = array();
6568 if (count($prods_arbo) > 0) {
6569 $productCachedList = array();
6570 $stockByComponentList = array();
6572 foreach ($prods_arbo as $componentArr) {
6573 $componentId = $componentArr[
'id'];
6575 if ($componentArr[
'incdec'] == 1) {
6576 if (!isset($productCachedList[$componentId])) {
6577 $componentStatic =
new self($this->db);
6578 $componentStatic->fetch($componentId);
6580 $childrenNb = $componentStatic->hasFatherOrChild(1);
6581 if ($childrenNb == 0) {
6582 $componentStatic->load_stock(
'nobatch,novirtual');
6583 if (!isset($stockByComponentList[$componentId])) {
6584 $stockByComponentList[$componentId] = array(
6588 $stockByComponentList[$componentId][
'qty_need'] += $componentArr[
'nb_total'];
6590 $productCachedList[$componentId] = $componentStatic;
6595 if (!empty($stockByComponentList)) {
6596 foreach ($stockByComponentList as $componentId => $stockByComponentArr) {
6597 if (!isset($productCachedList[$componentId])) {
6598 $componentStatic =
new self($this->db);
6599 $componentStatic->fetch($componentId);
6600 $componentStatic->load_stock(
'nobatch,novirtual');
6601 $productCachedList[$componentId] = $componentStatic;
6603 $component = $productCachedList[$componentId];
6606 if ($component->stock_reel < $stockByComponentArr[
'qty_need']) {
6609 $this->error =
'Not enough component [id='.$componentId.
'] in stock, real='.$component->stock_reel.
' and need='.$stockByComponentArr[
'qty_need'];
6610 $this->errors[] = $this->error;
6611 dol_syslog(__METHOD__.
' : '.$this->error, LOG_ERR);
6613 if (!empty($component->stock_warehouse)) {
6614 foreach ($component->stock_warehouse as $warehouseId => $warehouseObj) {
6615 $kitWarehouseAvailable =
new stdClass();
6616 $kitWarehouseAvailable->id = $warehouseObj->id;
6617 $kitWarehouseAvailable->real = $qtyWish;
6618 $this->stock_warehouse[$warehouseId] = $kitWarehouseAvailable;
6627 } elseif (
getDolGlobalInt(
'PRODUIT_SOUSPRODUITS_ALSO_ENABLE_PARENT_STOCK_MOVE') && empty($productCachedList)) {
6651 $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";
6652 $sql .=
" WHERE pb.fk_product_stock = ps.rowid AND ps.fk_product = ".((int) $this->
id).
" AND pb.batch = '".$this->db->escape($batch).
"'";
6653 $sql .=
" GROUP BY pb.batch, pb.eatby, pb.sellby";
6654 dol_syslog(get_class($this).
"::loadBatchInfo load first entry found for lot/serial = ".$batch, LOG_DEBUG);
6655 $resql = $this->db->query($sql);
6657 $num = $this->db->num_rows($resql);
6660 $obj = $this->db->fetch_object($resql);
6661 $result[] = array(
'batch' => $batch,
'eatby' => $this->db->jdate($obj->eatby),
'sellby' => $this->db->jdate($obj->sellby),
'qty' => $obj->qty);
6667 $this->db->rollback();
6684 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6690 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos";
6692 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product').dol_sanitizeFileName($this->
ref);
6697 $dir_osencoded = $dir;
6699 if (is_dir($dir_osencoded)) {
6700 $originImage = $dir.
'/'.$file[
'name'];
6711 if (is_numeric($result) && $result > 0) {
6728 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6729 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6733 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos/";
6735 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product');
6739 if (file_exists($dir_osencoded)) {
6740 $handle = opendir($dir_osencoded);
6741 if (is_resource($handle)) {
6742 while (($file = readdir($handle)) !==
false) {
6744 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6767 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6768 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6774 $handle = @opendir($dir_osencoded);
6775 if (is_resource($handle)) {
6776 while (($file = readdir($handle)) !==
false) {
6778 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6785 $photo_vignette =
'';
6787 if (preg_match(
'/('.$this->regeximgext.
')$/i', $photo, $regs)) {
6788 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $photo).
'_small'.$regs[0];
6791 $dirthumb = $dir.
'thumbs/';
6795 $obj[
'photo'] = $photo;
6796 if ($photo_vignette &&
dol_is_file($dirthumb.$photo_vignette)) {
6797 $obj[
'photo_vignette'] =
'thumbs/'.$photo_vignette;
6799 $obj[
'photo_vignette'] =
"";
6802 $tabobj[$nbphoto - 1] = $obj;
6805 if ($nbmax && $nbphoto >= $nbmax) {
6827 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6828 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6830 $dir = dirname($file).
'/';
6831 $dirthumb = $dir.
'/thumbs/';
6832 $filename = preg_replace(
'/'.preg_quote($dir,
'/').
'/i',
'', $file);
6838 if (preg_match(
'/('.$this->regeximgext.
')$/i', $filename, $regs)) {
6839 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_small'.$regs[0];
6840 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6844 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_mini'.$regs[0];
6845 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6862 $infoImg = getimagesize($file_osencoded);
6863 $this->imgWidth = $infoImg[0];
6864 $this->imgHeight = $infoImg[1];
6874 global $hookmanager;
6876 $this->nb = array();
6878 $sql =
"SELECT count(p.rowid) as nb, fk_product_type";
6879 $sql .=
" FROM ".$this->db->prefix().
"product as p";
6880 $sql .=
' WHERE p.entity IN ('.getEntity($this->element, 1).
')';
6882 if (is_object($hookmanager)) {
6883 $parameters = array();
6884 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
6885 $sql .= $hookmanager->resPrint;
6887 $sql .=
' GROUP BY fk_product_type';
6889 $resql = $this->db->query($sql);
6891 while ($obj = $this->db->fetch_object($resql)) {
6892 if ($obj->fk_product_type == 1) {
6893 $this->nb[
"services"] = $obj->nb;
6895 $this->nb[
"products"] = $obj->nb;
6898 $this->db->free($resql);
6902 $this->error = $this->db->error();
6944 return $this->mandatory_period == 1;
6954 return $this->status_batch > 0;
6974 $dirsociete = array_merge(array(
'/core/modules/barcode/'), $conf->modules_parts[
'barcode']);
6975 foreach ($dirsociete as $dirroot) {
6983 '@phan-var-force ModeleNumRefBarCode $mod';
6985 $result = $mod->getNextValue(
$object, $type);
6987 dol_syslog(get_class($this).
"::get_barcode barcode=".$result.
" module=".$var);
7004 $this->specimen = 1;
7006 $this->
ref =
'PRODUCT_SPEC';
7007 $this->label =
'PRODUCT SPECIMEN';
7008 $this->
description =
'This is description of this product specimen that was created the '.dol_print_date($now,
'dayhourlog').
'.';
7009 $this->specimen = 1;
7010 $this->country_id = 1;
7012 $this->status_buy = 1;
7014 $this->sell_or_eat_by_mandatory = 0;
7015 $this->note_private =
'This is a comment (private)';
7016 $this->note_public =
'This is a comment (public)';
7017 $this->date_creation = $now;
7018 $this->date_modification = $now;
7021 $this->weight_units = 3;
7024 $this->length_units = 1;
7026 $this->width_units = 0;
7027 $this->height =
null;
7028 $this->height_units =
null;
7030 $this->surface = 30;
7031 $this->surface_units = 0;
7032 $this->volume = 300;
7033 $this->volume_units = 0;
7035 $this->barcode = -1;
7053 if (empty($this->fk_unit)) {
7056 if (empty($outputlangs)) {
7057 $outputlangs = $langs;
7060 $outputlangs->load(
'products');
7063 $sql =
"SELECT code, label, short_label FROM ".$this->db->prefix().
"c_units where rowid = ".((int) $this->fk_unit);
7065 $resql = $this->db->query($sql);
7067 $this->error = $this->db->error();
7068 dol_syslog(get_class($this).
"::getLabelOfUnit Error ".$this->error, LOG_ERR);
7070 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
7071 if ($type ==
'short') {
7073 $label = $outputlangs->transnoentitiesnoconv($res[
'short_label']);
7075 $label = $outputlangs->trans($res[
'short_label']);
7077 } elseif ($type ==
'code') {
7078 $label = $res[
'code'];
7080 if ($outputlangs->trans(
'unit'.$res[
'code']) ==
'unit'.$res[
'code']) {
7082 $label = $res[
'label'];
7086 $label = $outputlangs->transnoentitiesnoconv(
'unit'.$res[
'code']);
7088 $label = $outputlangs->trans(
'unit'.$res[
'code']);
7093 $this->db->free($resql);
7107 $maxpricesupplier = 0;
7110 include_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.product.class.php';
7112 $product_fourn_list = $product_fourn->list_product_fournisseur_price($this->
id,
'',
'');
7114 if (is_array($product_fourn_list) && count($product_fourn_list) > 0) {
7115 foreach ($product_fourn_list as $productfourn) {
7116 if ($productfourn->fourn_unitprice > $maxpricesupplier) {
7117 $maxpricesupplier = $productfourn->fourn_unitprice;
7125 return $maxpricesupplier;
7141 require_once DOL_DOCUMENT_ROOT.
'/categories/class/categorie.class.php';
7142 return parent::setCategoriesCommon($categories, Categorie::TYPE_PRODUCT);
7156 'product_customer_price',
7157 'product_customer_price_log'
7176 $sql =
"SELECT rowid, level, fk_level, var_percent, var_min_percent FROM ".$this->db->prefix().
"product_pricerules";
7177 $query = $this->db->query($sql);
7181 while ($result = $this->db->fetch_object($query)) {
7182 $rules[$result->level] = $result;
7191 for ($i = 1; $i <= $nbofproducts; $i++) {
7192 $price = $baseprice;
7193 $price_min = $baseprice;
7197 if ($i > 1 && isset($rules[$i]->var_percent) && $rules[$i]->var_percent) {
7198 $price = $prices[$rules[$i]->fk_level] * (1 + ($rules[$i]->var_percent / 100));
7201 $prices[$i] = $price;
7204 if (isset($rules[$i]->var_min_percent) && $rules[$i]->var_min_percent) {
7205 $price_min = $price * (1 - ($rules[$i]->var_min_percent / 100));
7209 $check_amount = (($price == $this->multiprices[$i]) && ($price_min == $this->multiprices_min[$i]));
7210 $check_type = ($baseprice == $this->multiprices_base_type[$i]);
7212 if ($check_amount && $check_type) {
7216 if ($this->
updatePrice($price, $price_type, $user, $price_vat, $price_min, $i, $npr, $psq, 1) < 0) {
7234 return $user->rights->produit;
7236 return $user->rights->service;
7248 $sql =
"SELECT p.rowid, p.ref, p.datec as date_creation, GREATEST(p.tms, pef.tms) as date_modification,";
7249 $sql .=
" p.fk_user_author, p.fk_user_modif";
7250 $sql .=
" FROM ".$this->db->prefix().$this->table_element.
" as p";
7251 $sql .=
" LEFT JOIN ".$this->db->prefix().$this->table_element.
"_extrafields as pef ON pef.fk_object=p.rowid";
7252 $sql .=
" WHERE p.rowid = ".((int) $id);
7254 $result = $this->db->query($sql);
7256 if ($this->db->num_rows($result)) {
7257 $obj = $this->db->fetch_object($result);
7259 $this->
id = $obj->rowid;
7260 $this->
ref = $obj->ref;
7262 $this->user_creation_id = $obj->fk_user_author;
7263 $this->user_modification_id = $obj->fk_user_modif;
7265 $this->date_creation = $this->db->jdate($obj->date_creation);
7266 $this->date_modification = $this->db->jdate($obj->date_modification);
7269 $this->db->free($result);
7283 if (empty($this->duration_value)) {
7284 $this->errors[] =
'ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
7287 if ($this->duration_unit ==
's') {
7288 $prodDurationHours = 1. / 3600;
7289 } elseif ($this->duration_unit ==
'i' || $this->duration_unit ==
'mn' || $this->duration_unit ==
'min') {
7290 $prodDurationHours = 1. / 60;
7291 } elseif ($this->duration_unit ==
'h') {
7292 $prodDurationHours = 1.;
7293 } elseif ($this->duration_unit ==
'd') {
7294 $prodDurationHours = 24.;
7295 } elseif ($this->duration_unit ==
'w') {
7296 $prodDurationHours = 24. * 7;
7297 } elseif ($this->duration_unit ==
'm') {
7298 $prodDurationHours = 24. * 30;
7299 } elseif ($this->duration_unit ==
'y') {
7300 $prodDurationHours = 24. * 365;
7302 $prodDurationHours = 0.0;
7304 $prodDurationHours *= $this->duration_value;
7306 return $prodDurationHours;
7319 global $langs, $conf;
7321 $selected = (empty($arraydata[
'selected']) ? 0 : $arraydata[
'selected']);
7323 $return =
'<div class="box-flex-item box-flex-grow-zero">';
7324 $return .=
'<div class="info-box info-box-sm">';
7325 $return .=
'<div class="info-box-img">';
7327 if ($this->entity !==
null && $this->
is_photo_available($conf->product->multidir_output[$this->entity])) {
7328 $label .= $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 120, 160, 0, 0, 0,
'',
'photoref photokanban');
7338 $return .=
'</div>';
7339 $return .=
'<div class="info-box-content">';
7340 $return .=
'<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">' . $this->
getNomUrl() .
'</span>';
7341 if ($selected >= 0) {
7342 $return .=
'<input id="cb'.$this->id.
'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->
id.
'"'.($selected ?
' checked="checked"' :
'').
'>';
7344 $return .=
'<br><span class="info-box-label opacitymedium inline-block tdoverflowmax150 valignmiddle" title="'.dol_escape_htmltag($this->label).
'">'.
dol_escape_htmltag($this->label).
'</span>';
7345 if ($this->price_base_type ==
'TTC') {
7346 $return .=
'<br><span class="info-box-status amount">'.price($this->price_ttc).
' '.$langs->trans(
"TTC").
'</span>';
7349 $return .=
'<br><span class="info-box-status amount">'.price($this->
price).
' '.$langs->trans(
"HT").
'</span>';
7354 $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>';
7359 $return .=
'<div class="info-box-status inline-block valignmiddle">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7361 $return .=
'<div class="info-box-status inline-block valignmiddle marginleftonly paddingleft">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7363 $return .=
'</div>';
7364 $return .=
'</div>';
7365 $return .=
'</div>';
7376 public $picto =
'service';
if(! $sortfield) if(! $sortorder) $object
length_accountg($account)
Return General accounting account with defined length (used for product and miscellaneous)
clean_account($account)
Return accounting account without zero on the right.
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.
setErrorsFromObject($object)
setErrorsFromObject
isObjectUsed($id=0, $entity=0)
Function to check if an object is used by others (by children).
deleteExtraFields()
Delete all extra fields values for the current object.
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
show_photos($modulepart, $sdir, $size=0, $nbmax=0, $nbbyrow=5, $showfilename=0, $showaction=0, $maxHeight=120, $maxWidth=160, $nolink=0, $overwritetitle=0, $usesharelink=0, $cache='', $addphotorefcss='photoref')
Show photos of an object (nbmax maximum), into several columns.
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
addThumbs($file, $quality=50)
Build thumb.
Class to manage Dolibarr database access.
Class to manage ECM files.
const STATUS_OPEN_INTERNAL
Warehouse open and only operations for stock transfers/corrections allowed (not for customer shipping...
const STATUS_OPEN_ALL
Warehouse open and any operations are allowed (customer shipping, supplier dispatch,...
const STATUS_CLOSED
Warehouse closed, inactive.
const STATUS_CLOSED
Closed status -> parcel was received by customer / end of process prev status : validated or shipment...
const STATUS_VALIDATED
Validated status -> parcel is ready to be sent prev status : draft next status : closed or shipment_i...
const STATUS_DRAFT
Draft status.
Class to manage stock movements.
Class to parse product price expressions.
Class ProductCombination Used to represent the relation between a product and one of its variants.
File of class to manage predefined price products or services by customer.
Class to manage predefined suppliers products.
Class to manage products or services.
static replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
get_nb_achat($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units or supplier invoices in which product is included.
getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp=0)
Return price of sell of a product for a seller/buyer/product.
__construct($db)
Constructor.
is_sousproduit($fk_parent, $fk_child)
Check if it is a sub-product into a kit.
const DISABLED_STOCK
Stockable product.
const SELL_OR_EAT_BY_MANDATORY_ID_NONE
Const sell or eat by mandatory id.
isStockManaged()
Return if the object is managed in stock.
setPriceExpression($expression_id)
Sets the supplier price expression.
getArrayForPriceCompare($level=0)
used to check if price have really change to avoid log pollution
get_arbo_each_prod($multiply=1, $ignore_stock_load=0)
Build the tree of subproducts and return it.
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.
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_now($mode='gmt')
Return date for now.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
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_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
yn($yesno, $format=1, $color=0)
Return yes or no in current language.
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
dol_clone($srcobject, $native=2)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
dol_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.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
utf8_check($str)
Check if a string is in UTF8.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_localtax($vatrate, $local, $thirdparty_buyer=null, $thirdparty_seller=null, $vatnpr=0)
Return localtax rate for a particular VAT rate, when selling a product with vat $vatrate,...
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
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.
measuring_units_squared($unitscale)
Transform a given unit scale into the square of that unit, if known.
measuringUnitString($unitid, $measuring_style='', $unitscale=null, $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
measuring_units_cubed($unit)
Transform a given unit scale into the cube of that unit, if known.
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...