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);
4524 return array_reverse($result);
4539 public function get_nb_vente($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4544 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4545 if ($mode ==
'bynumber') {
4546 $sql .=
", count(DISTINCT f.rowid)";
4548 $sql .=
", sum(d.total_ht) as total_ht";
4549 $sql .=
" FROM ".$this->db->prefix().
"facturedet as d, ".$this->db->prefix().
"facture as f, ".$this->db->prefix().
"societe as s";
4550 if ($filteronproducttype >= 0) {
4551 $sql .=
", ".$this->db->prefix().
"product as p";
4553 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4554 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4556 $sql .=
" WHERE f.rowid = d.fk_facture";
4557 if ($this->
id > 0) {
4558 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4560 $sql .=
" AND d.fk_product > 0";
4562 if ($filteronproducttype >= 0) {
4563 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4565 $sql .=
" AND f.fk_soc = s.rowid";
4566 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4567 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4568 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4571 $sql .=
" AND f.fk_soc = $socid";
4573 $sql .= $morefilter;
4574 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4575 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4577 return $this->
_get_stats($sql, $mode, $year);
4592 public function get_nb_achat($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4597 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4598 if ($mode ==
'bynumber') {
4599 $sql .=
", count(DISTINCT f.rowid)";
4601 $sql .=
", sum(d.total_ht) as total_ht";
4602 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as d, ".$this->db->prefix().
"facture_fourn as f, ".$this->db->prefix().
"societe as s";
4603 if ($filteronproducttype >= 0) {
4604 $sql .=
", ".$this->db->prefix().
"product as p";
4606 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4607 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4609 $sql .=
" WHERE f.rowid = d.fk_facture_fourn";
4610 if ($this->
id > 0) {
4611 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4613 $sql .=
" AND d.fk_product > 0";
4615 if ($filteronproducttype >= 0) {
4616 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4618 $sql .=
" AND f.fk_soc = s.rowid";
4619 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4620 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4621 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4624 $sql .=
" AND f.fk_soc = $socid";
4626 $sql .= $morefilter;
4627 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4628 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4630 return $this->
_get_stats($sql, $mode, $year);
4644 public function get_nb_propal($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4647 global $user, $hookmanager;
4649 $sql =
"SELECT sum(d.qty) as qty, date_format(p.datep, '%Y%m')";
4650 if ($mode ==
'bynumber') {
4651 $sql .=
", count(DISTINCT p.rowid)";
4653 $sql .=
", sum(d.total_ht) as total_ht";
4654 $sql .=
" FROM ".$this->db->prefix().
"propaldet as d, ".$this->db->prefix().
"propal as p, ".$this->db->prefix().
"societe as s";
4655 if ($filteronproducttype >= 0) {
4656 $sql .=
", ".$this->db->prefix().
"product as prod";
4658 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4659 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4661 $sql .=
" WHERE p.rowid = d.fk_propal";
4662 if ($this->
id > 0) {
4663 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4665 $sql .=
" AND d.fk_product > 0";
4667 if ($filteronproducttype >= 0) {
4668 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4670 $sql .=
" AND p.fk_soc = s.rowid";
4671 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
4672 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4673 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4676 $sql .=
" AND p.fk_soc = ".((int) $socid);
4678 $sql .= $morefilter;
4679 $parameters = array(
'socid' => $user->socid);
4680 $hookmanager->executeHooks(
'productGetNbPropal', $parameters, $this);
4681 $sql .= $hookmanager->resPrint;
4682 $sql .=
" GROUP BY date_format(p.datep,'%Y%m')";
4683 $sql .=
" ORDER BY date_format(p.datep,'%Y%m') DESC";
4684 return $this->
_get_stats($sql, $mode, $year);
4703 $sql =
"SELECT sum(d.qty) as qty, date_format(p.date_valid, '%Y%m')";
4704 if ($mode ==
'bynumber') {
4705 $sql .=
", count(DISTINCT p.rowid)";
4707 $sql .=
", sum(d.total_ht) as total_ht";
4708 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as d, ".$this->db->prefix().
"supplier_proposal as p, ".$this->db->prefix().
"societe as s";
4709 if ($filteronproducttype >= 0) {
4710 $sql .=
", ".$this->db->prefix().
"product as prod";
4712 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4713 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4715 $sql .=
" WHERE p.rowid = d.fk_supplier_proposal";
4716 if ($this->
id > 0) {
4717 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4719 $sql .=
" AND d.fk_product > 0";
4721 if ($filteronproducttype >= 0) {
4722 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4724 $sql .=
" AND p.fk_soc = s.rowid";
4725 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
4726 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4727 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4730 $sql .=
" AND p.fk_soc = ".((int) $socid);
4732 $sql .= $morefilter;
4733 $sql .=
" GROUP BY date_format(p.date_valid,'%Y%m')";
4734 $sql .=
" ORDER BY date_format(p.date_valid,'%Y%m') DESC";
4736 return $this->
_get_stats($sql, $mode, $year);
4750 public function get_nb_order($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4753 global $user, $hookmanager;
4755 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4756 if ($mode ==
'bynumber') {
4757 $sql .=
", count(DISTINCT c.rowid)";
4759 $sql .=
", sum(d.total_ht) as total_ht";
4760 $sql .=
" FROM ".$this->db->prefix().
"commandedet as d, ".$this->db->prefix().
"commande as c, ".$this->db->prefix().
"societe as s";
4761 if ($filteronproducttype >= 0) {
4762 $sql .=
", ".$this->db->prefix().
"product as p";
4764 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4765 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4767 $sql .=
" WHERE c.rowid = d.fk_commande";
4768 if ($this->
id > 0) {
4769 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4771 $sql .=
" AND d.fk_product > 0";
4773 if ($filteronproducttype >= 0) {
4774 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4776 $sql .=
" AND c.fk_soc = s.rowid";
4777 $sql .=
" AND c.entity IN (".getEntity(
'commande').
")";
4778 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4779 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4782 $sql .=
" AND c.fk_soc = ".((int) $socid);
4784 $sql .= $morefilter;
4785 $parameters = array(
'socid' => $user->socid);
4786 $hookmanager->executeHooks(
'productGetNbOrder', $parameters, $this);
4787 $sql .= $hookmanager->resPrint;
4788 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4789 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4791 return $this->
_get_stats($sql, $mode, $year);
4810 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4811 if ($mode ==
'bynumber') {
4812 $sql .=
", count(DISTINCT c.rowid)";
4814 $sql .=
", sum(d.total_ht) as total_ht";
4815 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as d, ".$this->db->prefix().
"commande_fournisseur as c, ".$this->db->prefix().
"societe as s";
4816 if ($filteronproducttype >= 0) {
4817 $sql .=
", ".$this->db->prefix().
"product as p";
4819 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4820 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4822 $sql .=
" WHERE c.rowid = d.fk_commande";
4823 if ($this->
id > 0) {
4824 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4826 $sql .=
" AND d.fk_product > 0";
4828 if ($filteronproducttype >= 0) {
4829 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4831 $sql .=
" AND c.fk_soc = s.rowid";
4832 $sql .=
" AND c.entity IN (".getEntity(
'supplier_order').
")";
4833 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4834 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4837 $sql .=
" AND c.fk_soc = ".((int) $socid);
4839 $sql .= $morefilter;
4840 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4841 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4843 return $this->
_get_stats($sql, $mode, $year);
4857 public function get_nb_contract($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4862 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_contrat, '%Y%m')";
4863 if ($mode ==
'bynumber') {
4864 $sql .=
", count(DISTINCT c.rowid)";
4866 $sql .=
", sum(d.total_ht) as total_ht";
4867 $sql .=
" FROM ".$this->db->prefix().
"contratdet as d, ".$this->db->prefix().
"contrat as c, ".$this->db->prefix().
"societe as s";
4868 if ($filteronproducttype >= 0) {
4869 $sql .=
", ".$this->db->prefix().
"product as p";
4871 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4872 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4874 $sql .=
" WHERE c.entity IN (".getEntity(
'contract').
")";
4875 $sql .=
" AND c.rowid = d.fk_contrat";
4877 if ($this->
id > 0) {
4878 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4880 $sql .=
" AND d.fk_product > 0";
4882 if ($filteronproducttype >= 0) {
4883 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4885 $sql .=
" AND c.fk_soc = s.rowid";
4887 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4888 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4891 $sql .=
" AND c.fk_soc = ".((int) $socid);
4893 $sql .= $morefilter;
4894 $sql .=
" GROUP BY date_format(c.date_contrat,'%Y%m')";
4895 $sql .=
" ORDER BY date_format(c.date_contrat,'%Y%m') DESC";
4897 return $this->
_get_stats($sql, $mode, $year);
4911 public function get_nb_mos($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4916 $sql =
"SELECT sum(d.qty), date_format(d.date_valid, '%Y%m')";
4917 if ($mode ==
'bynumber') {
4918 $sql .=
", count(DISTINCT d.rowid)";
4920 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as d LEFT JOIN ".$this->db->prefix().
"societe as s ON d.fk_soc = s.rowid";
4921 if ($filteronproducttype >= 0) {
4922 $sql .=
", ".$this->db->prefix().
"product as p";
4924 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4925 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4928 $sql .=
" WHERE d.entity IN (".getEntity(
'mo').
")";
4929 $sql .=
" AND d.status > 0";
4931 if ($this->
id > 0) {
4932 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4934 $sql .=
" AND d.fk_product > 0";
4936 if ($filteronproducttype >= 0) {
4937 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4940 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4941 $sql .=
" AND d.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4944 $sql .=
" AND d.fk_soc = ".((int) $socid);
4946 $sql .= $morefilter;
4947 $sql .=
" GROUP BY date_format(d.date_valid,'%Y%m')";
4948 $sql .=
" ORDER BY date_format(d.date_valid,'%Y%m') DESC";
4950 return $this->
_get_stats($sql, $mode, $year);
4970 if (!is_numeric($id_pere)) {
4973 if (!is_numeric($id_fils)) {
4976 if (!is_numeric($incdec)) {
4986 $sql =
"SELECT fk_product_pere from ".$this->db->prefix().
"product_association";
4987 $sql .=
" WHERE fk_product_pere = ".((int) $id_fils).
" AND fk_product_fils = ".((int) $id_pere);
4988 if (!$this->db->query($sql)) {
4993 $sql =
"SELECT MAX(rang) as max_rank FROM ".$this->db->prefix().
"product_association";
4994 $sql .=
" WHERE fk_product_pere = ".((int) $id_pere);
4995 $resql = $this->db->query($sql);
4997 $obj = $this->db->fetch_object($resql);
4998 $rank = $obj->max_rank + 1;
5000 $sql =
"INSERT INTO ".$this->db->prefix().
"product_association(fk_product_pere,fk_product_fils,qty,incdec,rang)";
5001 $sql .=
" VALUES (".((int) $id_pere).
", ".((int) $id_fils).
", ".
price2num($qty,
'MS').
", ".((int) $incdec).
", ".((int) $rank).
")";
5002 if (! $this->db->query($sql)) {
5008 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_ADD', $user);
5010 $this->error = $this->db->lasterror();
5011 dol_syslog(get_class($this).
'::addSubproduct error='.$this->error, LOG_ERR);
5043 if (!is_numeric($id_pere)) {
5046 if (!is_numeric($id_fils)) {
5049 if (!is_numeric($incdec)) {
5052 if (!is_numeric($qty)) {
5056 $sql =
'UPDATE '.$this->db->prefix().
'product_association SET ';
5057 $sql .=
'qty = '.price2num($qty,
'MS');
5058 $sql .=
',incdec = '.((int) $incdec);
5059 $sql .=
' WHERE fk_product_pere = '.((int) $id_pere).
' AND fk_product_fils = '.((int) $id_fils);
5061 if (!$this->db->query($sql)) {
5067 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_UPDATE', $user);
5069 $this->error = $this->db->lasterror();
5070 dol_syslog(get_class($this).
'::updateSubproduct error='.$this->error, LOG_ERR);
5094 if (!is_numeric($fk_parent)) {
5097 if (!is_numeric($fk_child)) {
5101 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
5102 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5103 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
5105 dol_syslog(get_class($this).
'::del_sousproduit', LOG_DEBUG);
5106 if (!$this->db->query($sql)) {
5112 $sqlrank =
"SELECT rowid, rang FROM ".$this->db->prefix().
"product_association";
5113 $sqlrank .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5114 $sqlrank .=
" ORDER BY rang";
5115 $resqlrank = $this->db->query($sqlrank);
5118 while ($objrank = $this->db->fetch_object($resqlrank)) {
5120 $sql =
"UPDATE ".$this->db->prefix().
"product_association";
5121 $sql .=
" SET rang = ".((int) $cpt);
5122 $sql .=
" WHERE rowid = ".((int) $objrank->rowid);
5123 if (! $this->db->query($sql)) {
5132 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_DELETE', $user);
5134 $this->error = $this->db->lasterror();
5135 dol_syslog(get_class($this).
'::delSubproduct error='.$this->error, LOG_ERR);
5155 $sql =
"SELECT fk_product_pere, qty, incdec";
5156 $sql .=
" FROM ".$this->db->prefix().
"product_association";
5157 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5158 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
5160 $result = $this->db->query($sql);
5162 $num = $this->db->num_rows($result);
5165 $obj = $this->db->fetch_object($result);
5167 $this->is_sousproduit_qty = $obj->qty;
5168 $this->is_sousproduit_incdec = $obj->incdec;
5199 dol_syslog(get_class($this).
"::add_fournisseur id_fourn = ".$id_fourn.
" ref_fourn=".$ref_fourn.
" quantity=".$quantity, LOG_DEBUG);
5206 $sql =
"SELECT rowid, fk_product";
5207 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5208 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5209 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5210 $sql .=
" AND fk_product <> ".((int) $this->
id);
5211 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5213 $resql = $this->db->query($sql);
5215 $obj = $this->db->fetch_object($resql);
5218 $this->product_id_already_linked = $obj->fk_product;
5221 $this->db->free($resql);
5225 $sql =
"SELECT rowid";
5226 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5227 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5229 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5231 $sql .=
" AND (ref_fourn = '' OR ref_fourn IS NULL)";
5233 $sql .=
" AND quantity = ".((float) $quantity);
5234 $sql .=
" AND fk_product = ".((int) $this->
id);
5235 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5237 $resql = $this->db->query($sql);
5239 $obj = $this->db->fetch_object($resql);
5243 $sql =
"INSERT INTO ".$this->db->prefix().
"product_fournisseur_price(";
5246 $sql .=
", fk_product";
5248 $sql .=
", ref_fourn";
5249 $sql .=
", quantity";
5250 $sql .=
", fk_user";
5252 $sql .=
") VALUES (";
5253 $sql .=
"'".$this->db->idate($now).
"'";
5254 $sql .=
", ".((int) $conf->entity);
5255 $sql .=
", ".((int) $this->
id);
5256 $sql .=
", ".((int) $id_fourn);
5257 $sql .=
", '".$this->db->escape($ref_fourn).
"'";
5258 $sql .=
", ".((float) $quantity);
5259 $sql .=
", ".((int) $user->id);
5263 if ($this->db->query($sql)) {
5264 $this->product_fourn_price_id = $this->db->last_insert_id($this->db->prefix().
"product_fournisseur_price");
5267 $this->error = $this->db->lasterror();
5272 $this->product_fourn_price_id = $obj->rowid;
5276 $this->error = $this->db->lasterror();
5295 $sql =
"SELECT DISTINCT p.fk_soc";
5296 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as p";
5297 $sql .=
" WHERE p.fk_product = ".((int) $this->
id);
5298 $sql .=
" AND p.entity = ".((int) $conf->entity);
5300 $result = $this->db->query($sql);
5302 $num = $this->db->num_rows($result);
5305 $obj = $this->db->fetch_object($result);
5306 $list[$i] = $obj->fk_soc;
5332 $sql =
"INSERT INTO ".$this->db->prefix().
"product_price (";
5334 $sql .=
", fk_product";
5335 $sql .=
", date_price";
5336 $sql .=
", price_level";
5338 $sql .=
", price_ttc";
5339 $sql .=
", price_min";
5340 $sql .=
", price_min_ttc";
5341 $sql .=
", price_base_type";
5342 $sql .=
", price_label";
5343 $sql .=
", default_vat_code";
5345 $sql .=
", recuperableonly";
5346 $sql .=
", localtax1_tx";
5347 $sql .=
", localtax1_type";
5348 $sql .=
", localtax2_tx";
5349 $sql .=
", localtax2_type";
5350 $sql .=
", fk_user_author";
5352 $sql .=
", price_by_qty";
5353 $sql .=
", fk_price_expression";
5354 $sql .=
", fk_multicurrency";
5355 $sql .=
", multicurrency_code";
5356 $sql .=
", multicurrency_tx";
5357 $sql .=
", multicurrency_price";
5358 $sql .=
", multicurrency_price_ttc";
5362 $sql .=
", ".((int) $toId);
5363 $sql .=
", '".$this->db->idate($now).
"'";
5364 $sql .=
", price_level";
5366 $sql .=
", price_ttc";
5367 $sql .=
", price_min";
5368 $sql .=
", price_min_ttc";
5369 $sql .=
", price_base_type";
5370 $sql .=
", price_label";
5371 $sql .=
", default_vat_code";
5373 $sql .=
", recuperableonly";
5374 $sql .=
", localtax1_tx";
5375 $sql .=
", localtax1_type";
5376 $sql .=
", localtax2_tx";
5377 $sql .=
", localtax2_type";
5378 $sql .=
", ".((int) $user->id);
5380 $sql .=
", price_by_qty";
5381 $sql .=
", fk_price_expression";
5382 $sql .=
", fk_multicurrency";
5383 $sql .=
", multicurrency_code";
5384 $sql .=
", multicurrency_tx";
5385 $sql .=
", multicurrency_price";
5386 $sql .=
", multicurrency_price_ttc";
5387 $sql .=
" FROM ".$this->db->prefix().
"product_price ps";
5388 $sql .=
" WHERE fk_product = ".((int) $fromId);
5389 $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)";
5390 $sql .=
" ORDER BY date_price DESC";
5393 $resql = $this->db->query($sql);
5395 $this->db->rollback();
5399 $this->db->commit();
5416 $sql =
'INSERT INTO '.$this->db->prefix().
'product_association (fk_product_pere, fk_product_fils, qty, incdec)';
5417 $sql .=
" SELECT ".((int) $toId).
", fk_product_fils, qty, incdec FROM ".$this->db->prefix().
"product_association";
5418 $sql .=
" WHERE fk_product_pere = ".((int) $fromId);
5420 dol_syslog(get_class($this).
'::clone_association', LOG_DEBUG);
5421 if (!$this->db->query($sql)) {
5422 $this->db->rollback();
5426 $this->db->commit();
5459 $sql =
"INSERT ".$this->db->prefix().
"product_fournisseur_price (";
5460 $sql .=
" datec, fk_product, fk_soc, price, quantity, fk_user, tva_tx)";
5461 $sql .=
" SELECT '".$this->db->idate($now).
"', ".((int) $toId).
", fk_soc, price, quantity, fk_user, tva_tx";
5462 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5463 $sql .=
" WHERE fk_product = ".((int) $fromId);
5465 dol_syslog(get_class($this).
'::clone_fournisseurs', LOG_DEBUG);
5466 $resql = $this->db->query($sql);
5468 $this->db->rollback();
5471 $this->db->commit();
5489 public function fetch_prod_arbo($prod, $compl_path =
'', $multiply = 1, $level = 1, $id_parent = 0, $ignore_stock_load = 0)
5494 if ($multiply < 1) {
5495 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);
5500 foreach ($prod as $id_product => $desc_pere) {
5501 if (is_array($desc_pere)) {
5502 $id = (!empty($desc_pere[0]) ? $desc_pere[0] :
'');
5503 $nb = (!empty($desc_pere[1]) ? $desc_pere[1] :
'');
5504 $type = (!empty($desc_pere[2]) ? $desc_pere[2] :
'');
5505 $label = (!empty($desc_pere[3]) ? $desc_pere[3] :
'');
5506 $incdec = (!empty($desc_pere[4]) ? $desc_pere[4] : 0);
5509 if (is_null($tmpproduct)) {
5510 $tmpproduct =
new Product($this->db);
5512 $tmpproduct->fetch($id);
5514 if (empty($ignore_stock_load) && ($tmpproduct->isProduct() ||
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES'))) {
5515 $tmpproduct->load_stock(
'nobatch,novirtual');
5518 $this->res[] = array(
5520 'id_parent' => $id_parent,
5521 'ref' => $tmpproduct->ref,
5523 'nb_total' => $nb * $multiply,
5524 'stock' => $tmpproduct->stock_reel,
5525 'stock_alert' => $tmpproduct->seuil_stock_alerte,
5527 'fullpath' => $compl_path.$label,
5529 'desiredstock' => $tmpproduct->desiredstock,
5531 'incdec' => $incdec,
5532 'entity' => $tmpproduct->entity
5536 if (isset($desc_pere[
'childs']) && is_array($desc_pere[
'childs'])) {
5537 if (!is_int($desc_pere[1] * $multiply)) {
5538 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);
5542 $this->
fetch_prod_arbo($desc_pere[
'childs'], $compl_path.$desc_pere[3].
" -> ", (
int) ceil($desc_pere[1] * $multiply), $level + 1, $id, $ignore_stock_load);
5560 $this->res = array();
5561 if (isset($this->sousprods) && is_array($this->sousprods)) {
5562 foreach ($this->sousprods as $prod_name => $desc_product) {
5563 if (is_array($desc_product)) {
5564 $this->
fetch_prod_arbo($desc_product,
"", $multiply, 1, $this->
id, $ignore_stock_load);
5583 $sql =
"SELECT COUNT(pa.rowid) as nb";
5584 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa";
5586 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id).
" OR pa.fk_product_pere = ".((int) $this->
id);
5587 } elseif ($mode == -1) {
5588 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id);
5589 } elseif ($mode == 1) {
5590 $sql .=
" WHERE pa.fk_product_pere = ".((int) $this->
id);
5593 $resql = $this->db->query($sql);
5595 $obj = $this->db->fetch_object($resql);
5597 $nb = (int) $obj->nb;
5617 $sql =
"SELECT count(rowid) as nb FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_parent = ".((int) $this->
id);
5618 $sql .=
" AND entity IN (".getEntity(
'product').
")";
5620 $resql = $this->db->query($sql);
5622 $obj = $this->db->fetch_object($resql);
5624 $nb = (int) $obj->nb;
5640 $sql =
"SELECT rowid FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_child = ".((int) $this->
id).
" AND entity IN (".
getEntity(
'product').
")";
5642 $query = $this->db->query($sql);
5645 if (!$this->db->num_rows($query)) {
5666 $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";
5667 $sql .=
", p.tosell as status, p.tobuy as status_buy";
5668 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa,";
5669 $sql .=
" ".$this->db->prefix().
"product as p";
5670 $sql .=
" WHERE p.rowid = pa.fk_product_pere";
5671 $sql .=
" AND pa.fk_product_fils = ".((int) $this->
id);
5673 $res = $this->db->query($sql);
5676 while ($record = $this->db->fetch_array($res)) {
5678 $prods[$record[
'id']] = array();
5679 $prods[$record[
'id']][
'id'] = $record[
'rowid'];
5680 $prods[$record[
'id']][
'ref'] = $record[
'ref'];
5681 $prods[$record[
'id']][
'label'] = $record[
'label'];
5682 $prods[$record[
'id']][
'qty'] = $record[
'qty'];
5683 $prods[$record[
'id']][
'incdec'] = $record[
'incdec'];
5684 $prods[$record[
'id']][
'fk_product_type'] = $record[
'fk_product_type'];
5685 $prods[$record[
'id']][
'entity'] = $record[
'entity'];
5686 $prods[$record[
'id']][
'status'] = $record[
'status'];
5687 $prods[$record[
'id']][
'status_buy'] = $record[
'status_buy'];
5706 public function getChildsArbo($id, $firstlevelonly = 0, $level = 1, $parents = array())
5712 $sql =
"SELECT p.rowid, p.ref, p.label as label, p.fk_product_type,";
5713 $sql .=
" pa.qty as qty, pa.fk_product_fils as id, pa.incdec,";
5714 $sql .=
" pa.rowid as fk_association, pa.rang";
5715 $sql .=
" FROM ".$this->db->prefix().
"product as p,";
5716 $sql .=
" ".$this->db->prefix().
"product_association as pa";
5717 $sql .=
" WHERE p.rowid = pa.fk_product_fils";
5718 $sql .=
" AND pa.fk_product_pere = ".((int) $id);
5719 $sql .=
" AND pa.fk_product_fils <> ".((int) $id);
5720 $sql .=
" ORDER BY pa.rang";
5722 dol_syslog(get_class($this).
'::getChildsArbo id='.$id.
' level='.$level.
' parents='.(is_array($parents) ? implode(
',', $parents) : $parents), LOG_DEBUG);
5729 $res = $this->db->query($sql);
5732 if ($this->db->num_rows($res) > 0) {
5736 while ($rec = $this->db->fetch_array($res)) {
5737 if (in_array($rec[
'id'], $parents)) {
5738 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);
5742 $prods[$rec[
'rowid']] = array(
5745 2 => $rec[
'fk_product_type'],
5746 3 => $this->db->escape($rec[
'label']),
5747 4 => $rec[
'incdec'],
5749 6 => $rec[
'fk_association'],
5754 if (empty($firstlevelonly)) {
5755 $listofchilds = $this->
getChildsArbo($rec[
'rowid'], 0, $level + 1, $parents);
5756 foreach ($listofchilds as $keyChild => $valueChild) {
5757 $prods[$rec[
'rowid']][
'childs'][$keyChild] = $valueChild;
5781 foreach ($this->
getChildsArbo($this->
id) as $keyChild => $valueChild) {
5782 $parent[$this->label][$keyChild] = $valueChild;
5784 foreach ($parent as $key => $value) {
5785 $this->sousprods[$key] = $value;
5798 global $conf, $langs, $user;
5800 $langs->loadLangs(array(
'products',
'other'));
5803 $nofetch = !empty($params[
'nofetch']);
5806 return [
'optimize' => $langs->trans(
"ShowProduct")];
5810 $permissiontoreadproduct = 0;
5811 if ($this->
type == self::TYPE_PRODUCT && $user->hasRight(
'product',
'read')) {
5812 $permissiontoreadproduct = 1;
5814 if ($this->
type == self::TYPE_SERVICE && $user->hasRight(
'service',
'read')) {
5815 $permissiontoreadproduct = 1;
5818 if (!empty($this->entity) && $permissiontoreadproduct) {
5819 $tmpphoto = $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 80, 0, 0, 0, 0,
'1');
5820 if ($this->nbphoto > 0) {
5821 $datas[
'photo'] =
'<div class="photointooltip floatright">'.
"\n" . $tmpphoto .
'</div>';
5826 $datas[
'picto'] =
img_picto(
'',
'product').
' <u class="paddingrightonly">'.$langs->trans(
"Product").
'</u>';
5828 $datas[
'picto'] =
img_picto(
'',
'service').
' <u class="paddingrightonly">'.$langs->trans(
"Service").
'</u>';
5830 if (isset($this->
status) && isset($this->status_buy)) {
5831 $datas[
'status'] =
' '.$this->getLibStatut(5, 0) .
' '.$this->getLibStatut(5, 1);
5834 if (!empty($this->
ref)) {
5835 $datas[
'ref'] =
'<br><b>'.$langs->trans(
'ProductRef').
':</b> '.$this->ref;
5837 if (!empty($this->label)) {
5838 $datas[
'label'] =
'<br><b>'.$langs->trans(
'ProductLabel').
':</b> '.$this->label.
'<br>';
5841 if ($permissiontoreadproduct) {
5846 $datas[
'stockmanaged'] =
"<br><b>".$langs->trans(
"StockableProduct").
'</b>: '.
yn($this->
isStockManaged());
5850 $langs->load(
"productbatch");
5851 $datas[
'batchstatus'] =
"<br><b>".$langs->trans(
"ManageLotSerial").
'</b>: '.$this->
getLibStatut(0, 2);
5852 if ($this->status_batch) {
5853 $datas[
'batchdlc'] =
"<br><b>".$langs->trans(
"BatchSellOrEatByMandatoryList", $langs->transnoentitiesnoconv(
"SellByDate"), $langs->transnoentitiesnoconv(
"EatByDate")).
'</b>: '.$this->
getSellOrEatByMandatoryLabel();
5858 $datas[
'barcode'] =
'<br><b>'.$langs->trans(
'BarCode').
':</b> '.$this->barcode;
5862 if ($this->weight) {
5863 $datas[
'weight'] =
"<br><b>".$langs->trans(
"Weight").
'</b>: '.$this->weight.
' '.
measuringUnitString(0,
"weight", $this->weight_units);
5866 if ($this->length) {
5867 $labelsize .=
"<b>".$langs->trans(
"Length").
'</b>: '.$this->length.
' '.
measuringUnitString(0,
'size', $this->length_units);
5870 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Width").
'</b>: '.$this->width.
' '.
measuringUnitString(0,
'size', $this->width_units);
5872 if ($this->height) {
5873 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Height").
'</b>: '.$this->height.
' '.
measuringUnitString(0,
'size', $this->height_units);
5876 $datas[
'size'] =
"<br>".$labelsize;
5879 $labelsurfacevolume =
"";
5880 if ($this->surface) {
5881 $labelsurfacevolume .=
"<b>".$langs->trans(
"Surface").
'</b>: '.$this->surface.
' '.
measuringUnitString(0,
'surface', $this->surface_units);
5883 if ($this->volume) {
5884 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Volume").
'</b>: '.$this->volume.
' '.
measuringUnitString(0,
'volume', $this->volume_units);
5886 if ($labelsurfacevolume) {
5887 $datas[
'surface'] =
"<br>" . $labelsurfacevolume;
5890 if ($this->
isService() && !empty($this->duration_value)) {
5892 $datas[
'duration'] =
'<br><b>'.$langs->trans(
"Duration").
':</b> '.$this->duration_value;
5893 if ($this->duration_value > 1) {
5894 $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"));
5895 } elseif ($this->duration_value > 0) {
5896 $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"));
5898 $datas[
'duration'] .= (!empty($this->duration_unit) && isset($dur[$this->duration_unit]) ?
" ".$langs->trans($dur[$this->duration_unit]) :
'');
5900 if (empty($user->socid)) {
5901 if ($this->
isStockManaged() && isset($this->pmp) && $this->pmp) {
5902 $datas[
'pmp'] =
"<br><b>".$langs->trans(
"PMPValue").
'</b>: '.
price($this->pmp, 0,
'', 1, -1, -1, $conf->currency);
5906 if ($this->
status && isset($this->accountancy_code_sell)) {
5907 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5908 $selllabel =
'<br>';
5909 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellCode').
':</b> '.
length_accountg($this->accountancy_code_sell);
5910 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellIntraCode').
':</b> '.
length_accountg($this->accountancy_code_sell_intra);
5911 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellExportCode').
':</b> '.
length_accountg($this->accountancy_code_sell_export);
5912 $datas[
'accountancysell'] = $selllabel;
5914 if ($this->status_buy && isset($this->accountancy_code_buy)) {
5915 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5917 if (empty($this->
status)) {
5918 $buylabel .=
'<br>';
5920 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyCode').
':</b> '.
length_accountg($this->accountancy_code_buy);
5921 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyIntraCode').
':</b> '.
length_accountg($this->accountancy_code_buy_intra);
5922 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyExportCode').
':</b> '.
length_accountg($this->accountancy_code_buy_export);
5923 $datas[
'accountancybuy'] = $buylabel;
5929 require_once DOL_DOCUMENT_ROOT .
'/categories/class/categorie.class.php';
5930 $form =
new Form($this->db);
5931 $datas[
'categories'] =
'<br>' . $form->showCategories($this->
id, Categorie::TYPE_PRODUCT, 1);
5951 public function getNomUrl($withpicto = 0, $option =
'', $maxlength = 0, $save_lastsearch_value = -1, $notooltip = 0, $morecss =
'', $add_label = 0, $sep =
' - ')
5953 global $langs, $hookmanager;
5955 include_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
5959 $newref = (string) $this->
ref;
5961 $newref =
dol_trunc($newref, $maxlength,
'middle');
5965 'objecttype' => ($this->
type == 1 ?
'service' :
'product'),
5966 'option' => $option,
5969 $classfortooltip =
'classfortooltip';
5972 $classfortooltip =
'classforajaxtooltip';
5973 $dataparams =
' data-params="'.dol_escape_htmltag(json_encode($params)).
'"';
5980 if (empty($notooltip)) {
5982 $label = $langs->trans(
"ShowProduct");
5983 $linkclose .=
' alt="'.dol_escape_htmltag($label, 1, 1).
'"';
5985 $linkclose .= ($label ?
' title="'.dol_escape_htmltag($label, 1, 1).
'"' :
' title="tocomplete"');
5986 $linkclose .= $dataparams.
' class="nowraponall '.$classfortooltip.($morecss ?
' '.$morecss :
'').
'"';
5988 $linkclose =
' class="nowraponall'.($morecss ?
' '.$morecss :
'').
'"';
5991 if ($option ==
'supplier' || $option ==
'category') {
5992 $url = DOL_URL_ROOT.
'/product/price_suppliers.php?id='.$this->id;
5993 } elseif ($option ==
'stock') {
5994 $url = DOL_URL_ROOT.
'/product/stock/product.php?id='.$this->id;
5995 } elseif ($option ==
'composition') {
5996 $url = DOL_URL_ROOT.
'/product/composition/card.php?id='.$this->id;
5998 $url = DOL_URL_ROOT.
'/product/card.php?id='.$this->id;
6001 if ($option !==
'nolink') {
6003 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
6004 if ($save_lastsearch_value == -1 && isset($_SERVER[
"PHP_SELF"]) && preg_match(
'/list\.php/', $_SERVER[
"PHP_SELF"])) {
6005 $add_save_lastsearch_values = 1;
6007 if ($add_save_lastsearch_values) {
6008 $url .=
'&save_lastsearch_values=1';
6012 $linkstart =
'<a href="'.$url.
'"';
6013 $linkstart .= $linkclose.
'>';
6016 $result .= $linkstart;
6019 $result .= (
img_object(($notooltip ?
'' : $label),
'product',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
6022 $result .= (
img_object(($notooltip ?
'' : $label),
'service',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
6025 $result .=
'<span class="aaa">'.dol_escape_htmltag($newref).
'</span>';
6026 $result .= $linkend;
6027 if ($withpicto != 2) {
6028 $result .= (($add_label && $this->label) ? $sep.dol_trunc($this->label, ($add_label > 1 ? $add_label : 0)) :
'');
6032 $hookmanager->initHooks(array(
'productdao'));
6033 $parameters = array(
'id' => $this->
id,
'getnomurl' => &$result,
'label' => &$label);
6034 $reshook = $hookmanager->executeHooks(
'getNomUrl', $parameters, $this, $action);
6036 $result = $hookmanager->resPrint;
6038 $result .= $hookmanager->resPrint;
6055 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
6059 $langs->load(
"products");
6060 $outputlangs->load(
"products");
6067 $modelpath =
"core/modules/product/doc/";
6069 return $this->
commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
6085 return $this->
LibStatut($this->status_buy, $mode, $type);
6087 return $this->
LibStatut($this->status_batch, $mode, $type);
6090 return $this->
LibStatut($this->status_buy, $mode, $type);
6108 $labelStatus = $labelStatusShort =
'';
6110 $langs->load(
'products');
6112 $langs->load(
"productbatch");
6118 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial')));
6121 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort')));
6126 return dolGetStatus($langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch'),
'',
'', empty($status) ?
'status5' :
'status4', 3,
'dot');
6132 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'));
6136 $statuttrans = empty($status) ?
'status5' :
'status4';
6141 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSellShort');
6142 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSell');
6143 } elseif ($type == 1) {
6144 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuyShort');
6145 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuy');
6146 } elseif ($type == 2) {
6147 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch');
6148 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort');
6150 } elseif ($status == 1) {
6153 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSellShort');
6154 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSell');
6155 } elseif ($type == 1) {
6156 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBuyShort');
6157 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBuy');
6158 } elseif ($type == 2) {
6159 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBatch');
6160 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort');
6162 } elseif ($type == 2 && $status == 2) {
6163 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSerial');
6164 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort');
6168 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'),
'',
'',
'status0', 0);
6170 return dolGetStatus($labelStatus, $labelStatusShort,
'', $statuttrans, $mode);
6184 $langs->load(
'products');
6187 if (isset($this->finished) && $this->finished >= 0) {
6188 $sql =
"SELECT label, code FROM ".$this->db->prefix().
"c_product_nature where code = ".((int) $this->finished).
" AND active=1";
6189 $resql = $this->db->query($sql);
6191 $this->error = $this->db->error().
' sql='.$sql;
6192 dol_syslog(__METHOD__.
' Error '.$this->error, LOG_ERR);
6194 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
6195 $label = $langs->trans($res[
'label']);
6197 $this->db->free($resql);
6221 public function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label =
'', $price = 0, $inventorycode =
'', $origin_element =
'', $origin_id =
null, $disablestockchangeforsubproduct = 0, $extrafields =
null)
6227 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6230 $nbpiece = (float) $nbpiece;
6235 $nbpiece = abs($nbpiece);
6242 $movementstock->setOrigin($origin_element, (
int) $origin_id);
6243 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'',
'',
'',
'',
false, 0, $disablestockchangeforsubproduct);
6247 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6248 $movementstock->array_options = $array_options;
6249 $movementstock->insertExtraFields();
6251 $this->db->commit();
6256 $this->db->rollback();
6285 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)
6291 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6294 $nbpiece = (float) $nbpiece;
6299 $nbpiece = abs($nbpiece);
6307 $movementstock->setOrigin($origin_element, (
int) $origin_id);
6308 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'', $dlc, $dluo, $lot,
false, 0, $disablestockchangeforsubproduct, 0, $force_update_batch);
6312 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6313 $movementstock->array_options = $array_options;
6314 $movementstock->insertExtraFields();
6316 $this->db->commit();
6319 $this->error = $movementstock->error;
6320 $this->errors = $movementstock->errors;
6322 $this->db->rollback();
6342 public function load_stock($option =
'', $includedraftpoforvirtual =
null, $dateofvirtualstock =
null)
6345 $this->stock_reel = 0;
6346 $this->stock_warehouse = array();
6347 $this->stock_theorique = 0;
6350 $warehouseStatus = array();
6351 if (preg_match(
'/warehouseclosed/', $option)) {
6354 if (preg_match(
'/warehouseopen/', $option)) {
6357 if (preg_match(
'/warehouseinternal/', $option)) {
6365 $sql =
"SELECT ps.rowid, ps.reel, ps.fk_entrepot";
6366 $sql .=
" FROM ".$this->db->prefix().
"product_stock as ps";
6367 $sql .=
", ".$this->db->prefix().
"entrepot as w";
6368 $sql .=
" WHERE w.entity IN (".getEntity(
'stock').
")";
6369 $sql .=
" AND w.rowid = ps.fk_entrepot";
6370 $sql .=
" AND ps.fk_product = ".((int) $this->
id);
6371 if (count($warehouseStatus)) {
6372 $sql .=
" AND w.statut IN (".$this->db->sanitize(implode(
',', $warehouseStatus)).
")";
6375 $sql .=
" ORDER BY ps.reel ".(getDolGlobalString(
'DO_NOT_TRY_TO_DEFRAGMENT_STOCKS_WAREHOUSE') ?
'DESC' :
'ASC');
6377 dol_syslog(get_class($this).
"::load_stock", LOG_DEBUG);
6378 $result = $this->db->query($sql);
6380 $num = $this->db->num_rows($result);
6384 $row = $this->db->fetch_object($result);
6385 $this->stock_warehouse[$row->fk_entrepot] =
new stdClass();
6386 $this->stock_warehouse[$row->fk_entrepot]->real = $row->reel;
6387 $this->stock_warehouse[$row->fk_entrepot]->id = $row->rowid;
6388 if ((!preg_match(
'/nobatch/', $option)) && $this->
hasbatch()) {
6389 $this->stock_warehouse[$row->fk_entrepot]->detail_batch =
Productbatch::findAll($this->db, $row->rowid, 1, $this->id);
6391 $this->stock_reel += $row->reel;
6394 $this->stock_reel = (float)
price2num($this->stock_reel,
'MS');
6396 $this->db->free($result);
6398 if (!preg_match(
'/novirtual/', $option)) {
6404 $this->error = $this->db->lasterror();
6423 global $hookmanager, $action;
6425 $stock_commande_client = 0;
6426 $stock_commande_fournisseur = 0;
6427 $stock_sending_client = 0;
6428 $stock_reception_fournisseur = 0;
6429 $stock_inproduction = 0;
6438 $stock_commande_client = $this->stats_commande[
'qty'];
6441 require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expedition.class.php';
6442 $filterShipmentStatus =
'';
6452 $stock_sending_client = $this->stats_expedition[
'qty'];
6456 $filterStatus =
getDolGlobalString(
'SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK',
'3,4');
6457 if (isset($includedraftpoforvirtual)) {
6458 $filterStatus =
'0,1,2,'.$filterStatus;
6464 $stock_commande_fournisseur = $this->stats_commande_fournisseur[
'qty'];
6468 $filterStatus =
'4';
6469 if (isset($includedraftpoforvirtual)) {
6470 $filterStatus =
'0,'.$filterStatus;
6476 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
6484 $stock_inproduction = $this->stats_mrptoproduce[
'qty'] - $this->stats_mrptoconsume[
'qty'];
6487 $this->stock_theorique = $this->stock_reel + $stock_inproduction;
6491 $weBillOrderOrShipmentReception =
getDolGlobalString(
'STOCK_DO_WE_BILL_ORDER_OR_SHIPMENTECEPTION_FOR_VIRTUALSTOCK',
'order');
6495 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6499 $result = $tmpnewprod->load_stats_commande(0,
'0', 1);
6500 $this->stock_theorique += $tmpnewprod->stats_commande[
'qty'];
6502 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6503 $this->stock_theorique -= $stock_commande_client;
6504 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6505 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6510 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6512 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6514 if (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER_INCLUDE_DRAFT')) {
6516 $result = $tmpnewprod->load_stats_commande_fournisseur(0,
'0', 1);
6517 $this->stock_theorique += $this->stats_commande_fournisseur[
'qty'];
6519 $this->stock_theorique -= $stock_reception_fournisseur;
6520 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6521 $this->stock_theorique += $stock_commande_fournisseur;
6522 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6523 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6526 $parameters = array(
'id' => $this->
id,
'includedraftpoforvirtual' => $includedraftpoforvirtual);
6528 $reshook = $hookmanager->executeHooks(
'loadvirtualstock', $parameters, $this, $action);
6530 $this->stock_theorique = $hookmanager->resArray[
'stock_theorique'];
6531 } elseif ($reshook == 0 && isset($hookmanager->resArray[
'stock_stats_hook'])) {
6532 $this->stock_theorique += $hookmanager->resArray[
'stock_stats_hook'];
6536 if (!empty($this->stock_warehouse) &&
getDolGlobalString(
'STOCK_ALLOW_VIRTUAL_STOCK_PER_WAREHOUSE')) {
6537 foreach ($this->stock_warehouse as $warehouseid => $stockwarehouse) {
6545 if ($this->fk_default_warehouse == $warehouseid) {
6546 $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']);
6548 $this->stock_warehouse[$warehouseid]->virtual = $this->stock_warehouse[$warehouseid]->real + $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'];
6565 $this->stock_warehouse = array();
6570 if (count($prods_arbo) > 0) {
6571 $productCachedList = array();
6572 $stockByComponentList = array();
6574 foreach ($prods_arbo as $componentArr) {
6575 $componentId = $componentArr[
'id'];
6577 if ($componentArr[
'incdec'] == 1) {
6578 if (!isset($productCachedList[$componentId])) {
6579 $componentStatic =
new self($this->db);
6580 $componentStatic->fetch($componentId);
6582 $childrenNb = $componentStatic->hasFatherOrChild(1);
6583 if ($childrenNb == 0) {
6584 $componentStatic->load_stock(
'nobatch,novirtual');
6585 if (!isset($stockByComponentList[$componentId])) {
6586 $stockByComponentList[$componentId] = array(
6590 $stockByComponentList[$componentId][
'qty_need'] += $componentArr[
'nb_total'];
6592 $productCachedList[$componentId] = $componentStatic;
6597 if (!empty($stockByComponentList)) {
6598 foreach ($stockByComponentList as $componentId => $stockByComponentArr) {
6599 if (!isset($productCachedList[$componentId])) {
6600 $componentStatic =
new self($this->db);
6601 $componentStatic->fetch($componentId);
6602 $componentStatic->load_stock(
'nobatch,novirtual');
6603 $productCachedList[$componentId] = $componentStatic;
6605 $component = $productCachedList[$componentId];
6608 if ($component->stock_reel < $stockByComponentArr[
'qty_need']) {
6611 $this->error =
'Not enough component [id='.$componentId.
'] in stock, real='.$component->stock_reel.
' and need='.$stockByComponentArr[
'qty_need'];
6612 $this->errors[] = $this->error;
6613 dol_syslog(__METHOD__.
' : '.$this->error, LOG_ERR);
6615 if (!empty($component->stock_warehouse)) {
6616 foreach ($component->stock_warehouse as $warehouseId => $warehouseObj) {
6617 $kitWarehouseAvailable =
new stdClass();
6618 $kitWarehouseAvailable->id = $warehouseObj->id;
6619 $kitWarehouseAvailable->real = $qtyWish;
6620 $this->stock_warehouse[$warehouseId] = $kitWarehouseAvailable;
6629 } elseif (
getDolGlobalInt(
'PRODUIT_SOUSPRODUITS_ALSO_ENABLE_PARENT_STOCK_MOVE') && empty($productCachedList)) {
6653 $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";
6654 $sql .=
" WHERE pb.fk_product_stock = ps.rowid AND ps.fk_product = ".((int) $this->
id).
" AND pb.batch = '".$this->db->escape($batch).
"'";
6655 $sql .=
" GROUP BY pb.batch, pb.eatby, pb.sellby";
6656 dol_syslog(get_class($this).
"::loadBatchInfo load first entry found for lot/serial = ".$batch, LOG_DEBUG);
6657 $resql = $this->db->query($sql);
6659 $num = $this->db->num_rows($resql);
6662 $obj = $this->db->fetch_object($resql);
6663 $result[] = array(
'batch' => $batch,
'eatby' => $this->db->jdate($obj->eatby),
'sellby' => $this->db->jdate($obj->sellby),
'qty' => $obj->qty);
6669 $this->db->rollback();
6686 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6692 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos";
6694 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product').dol_sanitizeFileName($this->
ref);
6699 $dir_osencoded = $dir;
6701 if (is_dir($dir_osencoded)) {
6702 $originImage = $dir.
'/'.$file[
'name'];
6713 if (is_numeric($result) && $result > 0) {
6730 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6731 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6735 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos/";
6737 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product');
6741 if (file_exists($dir_osencoded)) {
6742 $handle = opendir($dir_osencoded);
6743 if (is_resource($handle)) {
6744 while (($file = readdir($handle)) !==
false) {
6746 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6769 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6770 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6776 $handle = @opendir($dir_osencoded);
6777 if (is_resource($handle)) {
6778 while (($file = readdir($handle)) !==
false) {
6780 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6787 $photo_vignette =
'';
6789 if (preg_match(
'/('.$this->regeximgext.
')$/i', $photo, $regs)) {
6790 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $photo).
'_small'.$regs[0];
6793 $dirthumb = $dir.
'thumbs/';
6797 $obj[
'photo'] = $photo;
6798 if ($photo_vignette &&
dol_is_file($dirthumb.$photo_vignette)) {
6799 $obj[
'photo_vignette'] =
'thumbs/'.$photo_vignette;
6801 $obj[
'photo_vignette'] =
"";
6804 $tabobj[$nbphoto - 1] = $obj;
6807 if ($nbmax && $nbphoto >= $nbmax) {
6829 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6830 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6832 $dir = dirname($file).
'/';
6833 $dirthumb = $dir.
'/thumbs/';
6834 $filename = preg_replace(
'/'.preg_quote($dir,
'/').
'/i',
'', $file);
6840 if (preg_match(
'/('.$this->regeximgext.
')$/i', $filename, $regs)) {
6841 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_small'.$regs[0];
6842 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6846 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_mini'.$regs[0];
6847 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6864 $infoImg = getimagesize($file_osencoded);
6865 $this->imgWidth = $infoImg[0];
6866 $this->imgHeight = $infoImg[1];
6876 global $hookmanager;
6878 $this->nb = array();
6880 $sql =
"SELECT count(p.rowid) as nb, fk_product_type";
6881 $sql .=
" FROM ".$this->db->prefix().
"product as p";
6882 $sql .=
' WHERE p.entity IN ('.getEntity($this->element, 1).
')';
6884 if (is_object($hookmanager)) {
6885 $parameters = array();
6886 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
6887 $sql .= $hookmanager->resPrint;
6889 $sql .=
' GROUP BY fk_product_type';
6891 $resql = $this->db->query($sql);
6893 while ($obj = $this->db->fetch_object($resql)) {
6894 if ($obj->fk_product_type == 1) {
6895 $this->nb[
"services"] = $obj->nb;
6897 $this->nb[
"products"] = $obj->nb;
6900 $this->db->free($resql);
6904 $this->error = $this->db->error();
6946 return $this->mandatory_period == 1;
6956 return $this->status_batch > 0;
6976 $dirsociete = array_merge(array(
'/core/modules/barcode/'), $conf->modules_parts[
'barcode']);
6977 foreach ($dirsociete as $dirroot) {
6985 '@phan-var-force ModeleNumRefBarCode $mod';
6987 $result = $mod->getNextValue(
$object, $type);
6989 dol_syslog(get_class($this).
"::get_barcode barcode=".$result.
" module=".$var);
7006 $this->specimen = 1;
7008 $this->
ref =
'PRODUCT_SPEC';
7009 $this->label =
'PRODUCT SPECIMEN';
7010 $this->
description =
'This is description of this product specimen that was created the '.dol_print_date($now,
'dayhourlog').
'.';
7011 $this->specimen = 1;
7012 $this->country_id = 1;
7014 $this->status_buy = 1;
7016 $this->sell_or_eat_by_mandatory = 0;
7017 $this->note_private =
'This is a comment (private)';
7018 $this->note_public =
'This is a comment (public)';
7019 $this->date_creation = $now;
7020 $this->date_modification = $now;
7023 $this->weight_units = 3;
7026 $this->length_units = 1;
7028 $this->width_units = 0;
7029 $this->height =
null;
7030 $this->height_units =
null;
7032 $this->surface = 30;
7033 $this->surface_units = 0;
7034 $this->volume = 300;
7035 $this->volume_units = 0;
7037 $this->barcode = -1;
7055 if (empty($this->fk_unit)) {
7058 if (empty($outputlangs)) {
7059 $outputlangs = $langs;
7062 $outputlangs->load(
'products');
7065 $sql =
"SELECT code, label, short_label FROM ".$this->db->prefix().
"c_units where rowid = ".((int) $this->fk_unit);
7067 $resql = $this->db->query($sql);
7069 $this->error = $this->db->error();
7070 dol_syslog(get_class($this).
"::getLabelOfUnit Error ".$this->error, LOG_ERR);
7072 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
7073 if ($type ==
'short') {
7075 $label = $outputlangs->transnoentitiesnoconv($res[
'short_label']);
7077 $label = $outputlangs->trans($res[
'short_label']);
7079 } elseif ($type ==
'code') {
7080 $label = $res[
'code'];
7082 if ($outputlangs->trans(
'unit'.$res[
'code']) ==
'unit'.$res[
'code']) {
7084 $label = $res[
'label'];
7088 $label = $outputlangs->transnoentitiesnoconv(
'unit'.$res[
'code']);
7090 $label = $outputlangs->trans(
'unit'.$res[
'code']);
7095 $this->db->free($resql);
7109 $maxpricesupplier = 0;
7112 include_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.product.class.php';
7114 $product_fourn_list = $product_fourn->list_product_fournisseur_price($this->
id,
'',
'');
7116 if (is_array($product_fourn_list) && count($product_fourn_list) > 0) {
7117 foreach ($product_fourn_list as $productfourn) {
7118 if ($productfourn->fourn_unitprice > $maxpricesupplier) {
7119 $maxpricesupplier = $productfourn->fourn_unitprice;
7127 return $maxpricesupplier;
7143 require_once DOL_DOCUMENT_ROOT.
'/categories/class/categorie.class.php';
7144 return parent::setCategoriesCommon($categories, Categorie::TYPE_PRODUCT);
7158 $sql =
" DELETE FROM ".$dbs->prefix().
"product_customer_price";
7159 $sql .=
" WHERE fk_soc = ".(int) $origin_id;
7160 $sql .=
" AND fk_product IN (SELECT fk_product FROM (SELECT fk_product FROM ".$dbs->prefix().
"product_customer_price WHERE fk_soc = ".(int) $dest_id.
") AS tmp)";
7163 if (!$dbs->
query($sql)) {
7168 'product_customer_price',
7169 'product_customer_price_log'
7188 $sql =
"SELECT rowid, level, fk_level, var_percent, var_min_percent FROM ".$this->db->prefix().
"product_pricerules";
7189 $query = $this->db->query($sql);
7193 while ($result = $this->db->fetch_object($query)) {
7194 $rules[$result->level] = $result;
7203 for ($i = 1; $i <= $nbofproducts; $i++) {
7204 $price = $baseprice;
7205 $price_min = $baseprice;
7209 if ($i > 1 && isset($rules[$i]->var_percent) && $rules[$i]->var_percent) {
7210 $price = $prices[$rules[$i]->fk_level] * (1 + ($rules[$i]->var_percent / 100));
7213 $prices[$i] = $price;
7216 if (isset($rules[$i]->var_min_percent) && $rules[$i]->var_min_percent) {
7217 $price_min = $price * (1 - ($rules[$i]->var_min_percent / 100));
7221 $check_amount = (($price == $this->multiprices[$i]) && ($price_min == $this->multiprices_min[$i]));
7222 $check_type = ($baseprice == $this->multiprices_base_type[$i]);
7224 if ($check_amount && $check_type) {
7228 if ($this->
updatePrice($price, $price_type, $user, $price_vat, $price_min, $i, $npr, $psq, 1) < 0) {
7246 return $user->rights->produit;
7248 return $user->rights->service;
7260 $sql =
"SELECT p.rowid, p.ref, p.datec as date_creation, GREATEST(p.tms, pef.tms) as date_modification,";
7261 $sql .=
" p.fk_user_author, p.fk_user_modif";
7262 $sql .=
" FROM ".$this->db->prefix().$this->table_element.
" as p";
7263 $sql .=
" LEFT JOIN ".$this->db->prefix().$this->table_element.
"_extrafields as pef ON pef.fk_object=p.rowid";
7264 $sql .=
" WHERE p.rowid = ".((int) $id);
7266 $result = $this->db->query($sql);
7268 if ($this->db->num_rows($result)) {
7269 $obj = $this->db->fetch_object($result);
7271 $this->
id = $obj->rowid;
7272 $this->
ref = $obj->ref;
7274 $this->user_creation_id = $obj->fk_user_author;
7275 $this->user_modification_id = $obj->fk_user_modif;
7277 $this->date_creation = $this->db->jdate($obj->date_creation);
7278 $this->date_modification = $this->db->jdate($obj->date_modification);
7281 $this->db->free($result);
7295 if (empty($this->duration_value)) {
7296 $this->errors[] =
'ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
7299 if ($this->duration_unit ==
's') {
7300 $prodDurationHours = 1. / 3600;
7301 } elseif ($this->duration_unit ==
'i' || $this->duration_unit ==
'mn' || $this->duration_unit ==
'min') {
7302 $prodDurationHours = 1. / 60;
7303 } elseif ($this->duration_unit ==
'h') {
7304 $prodDurationHours = 1.;
7305 } elseif ($this->duration_unit ==
'd') {
7306 $prodDurationHours = 24.;
7307 } elseif ($this->duration_unit ==
'w') {
7308 $prodDurationHours = 24. * 7;
7309 } elseif ($this->duration_unit ==
'm') {
7310 $prodDurationHours = 24. * 30;
7311 } elseif ($this->duration_unit ==
'y') {
7312 $prodDurationHours = 24. * 365;
7314 $prodDurationHours = 0.0;
7316 $prodDurationHours *= $this->duration_value;
7318 return $prodDurationHours;
7331 global $langs, $conf;
7333 $selected = (empty($arraydata[
'selected']) ? 0 : $arraydata[
'selected']);
7335 $return =
'<div class="box-flex-item box-flex-grow-zero">';
7336 $return .=
'<div class="info-box info-box-sm">';
7337 $return .=
'<div class="info-box-img">';
7339 if ($this->entity !==
null && $this->
is_photo_available($conf->product->multidir_output[$this->entity])) {
7340 $label .= $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 120, 160, 0, 0, 0,
'',
'photoref photokanban');
7350 $return .=
'</div>';
7351 $return .=
'<div class="info-box-content">';
7352 $return .=
'<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">' . $this->
getNomUrl() .
'</span>';
7353 if ($selected >= 0) {
7354 $return .=
'<input id="cb'.$this->id.
'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->
id.
'"'.($selected ?
' checked="checked"' :
'').
'>';
7356 $return .=
'<br><span class="info-box-label opacitymedium inline-block tdoverflowmax150 valignmiddle" title="'.dol_escape_htmltag($this->label).
'">'.
dol_escape_htmltag($this->label).
'</span>';
7357 if ($this->price_base_type ==
'TTC') {
7358 $return .=
'<br><span class="info-box-status amount">'.price($this->price_ttc).
' '.$langs->trans(
"TTC").
'</span>';
7361 $return .=
'<br><span class="info-box-status amount">'.price($this->
price).
' '.$langs->trans(
"HT").
'</span>';
7366 $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>';
7371 $return .=
'<div class="info-box-status inline-block valignmiddle">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7373 $return .=
'<div class="info-box-status inline-block valignmiddle marginleftonly paddingleft">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7375 $return .=
'</div>';
7376 $return .=
'</div>';
7377 $return .=
'</div>';
7388 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.
query($query, $usesavepoint=0, $type='auto', $result_mode=0)
Execute a SQL request and return the resultset.
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]]]',...