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 $sql .=
" AND fk_product_price IN (SELECT pp.rowid FROM ".$this->db->prefix().
"product_price as pp WHERE pp.fk_product = ".((int) $this->
id).
")";
2364 $resql = $this->db->query($sql);
2366 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price";
2367 $sql .=
" WHERE rowid = ".((int) $rowid);
2368 $sql .=
" AND fk_product = ".((int) $this->
id);
2369 $resql = $this->db->query($sql);
2373 $this->error = $this->db->lasterror();
2388 public function getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp = 0)
2390 global $hookmanager, $action;
2393 if (is_object($hookmanager)) {
2394 $parameters = array(
'thirdparty_seller' => $thirdparty_seller,
'thirdparty_buyer' => $thirdparty_buyer,
'pqp' => $pqp);
2396 $reshook = $hookmanager->executeHooks(
'getSellPrice', $parameters, $this, $action);
2398 return $hookmanager->resArray;
2403 $tva_tx =
get_default_tva($thirdparty_seller, $thirdparty_buyer, $this->
id);
2404 $tva_npr =
get_default_npr($thirdparty_seller, $thirdparty_buyer, $this->
id);
2405 if (empty($tva_tx)) {
2409 $pu_ht = $this->price;
2410 $pu_ttc = $this->price_ttc;
2411 $price_min = $this->price_min;
2412 $price_min_ttc = $this->price_min_ttc;
2413 $price_base_type = $this->price_base_type;
2417 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2421 $filter = array(
't.fk_product' => (
string) $this->
id,
't.fk_soc' => (
string) $thirdparty_buyer->id);
2424 $pricebycustomerexist =
false;
2425 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2427 if (count($prodcustprice->lines) > 0) {
2428 $date_now = (int) floor(
dol_now() / 86400) * 86400;
2429 foreach ($prodcustprice->lines as $k => $custprice_line) {
2430 if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
2431 $pricebycustomerexist =
true;
2432 $pu_ht =
price($custprice_line->price);
2433 $price_min =
price($custprice_line->price_min);
2434 $price_min_ttc =
price($custprice_line->price_min_ttc);
2435 $pu_ttc =
price($custprice_line->price_ttc);
2436 $price_base_type = $custprice_line->price_base_type;
2437 $tva_tx = $custprice_line->tva_tx;
2438 if ($custprice_line->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2439 $tva_tx .=
' (' . $custprice_line->default_vat_code .
')';
2441 $tva_npr = $custprice_line->recuperableonly;
2442 if (empty($tva_tx)) {
2451 if (!$pricebycustomerexist && !empty($thirdparty_buyer->price_level)) {
2452 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
2453 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
2454 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
2455 $price_min_ttc = $this->multiprices_min_ttc[$thirdparty_buyer->price_level];
2456 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
2459 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2460 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2462 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2463 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2465 if (empty($tva_tx)) {
2470 } elseif (
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !empty($thirdparty_buyer->price_level)) {
2471 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
2472 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
2473 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
2474 $price_min_ttc = $this->multiprices_min_ttc[$thirdparty_buyer->price_level];
2475 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
2478 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2479 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2481 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2482 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2484 if (empty($tva_tx)) {
2490 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2494 $filter = array(
't.fk_product' => (
string) $this->
id,
't.fk_soc' => (
string) $thirdparty_buyer->id);
2496 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2498 if (count($prodcustprice->lines) > 0) {
2499 $date_now = (int) floor(
dol_now() / 86400) * 86400;
2500 foreach ($prodcustprice->lines as $k => $custprice_line) {
2501 if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
2502 $pu_ht =
price($custprice_line->price);
2503 $price_min =
price($custprice_line->price_min);
2504 $price_min_ttc =
price($custprice_line->price_min_ttc);
2505 $pu_ttc =
price($custprice_line->price_ttc);
2506 $price_base_type = $custprice_line->price_base_type;
2507 $tva_tx = $custprice_line->tva_tx;
2508 if ($custprice_line->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2509 $tva_tx .=
' (' . $custprice_line->default_vat_code .
')';
2511 $tva_npr = $custprice_line->recuperableonly;
2512 if (empty($tva_tx)) {
2522 if ($this->prices_by_qty[0]) {
2525 foreach ($this->prices_by_qty_list[0] as $priceforthequantityarray) {
2526 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2530 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2531 $pu_ht = $priceforthequantityarray[
'unitprice'];
2533 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2540 if ($this->prices_by_qty[$thirdparty_buyer->price_level]) {
2543 foreach ($this->prices_by_qty_list[$thirdparty_buyer->price_level] as $priceforthequantityarray) {
2544 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2548 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2549 $pu_ht = $priceforthequantityarray[
'unitprice'];
2551 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2558 $localtax1 =
get_localtax((
string) $tva_tx, 1, $thirdparty_buyer, $thirdparty_seller, $tva_npr);
2559 $localtax2 =
get_localtax((
string) $tva_tx, 2, $thirdparty_buyer, $thirdparty_seller, $tva_npr);
2561 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,
'localtax1' => $localtax1,
'localtax2' => $localtax2);
2578 public function get_buyprice($prodfournprice, $qty, $product_id = 0, $fourn_ref =
'', $fk_soc = 0)
2581 global $action, $hookmanager;
2584 if (is_object($hookmanager)) {
2585 $parameters = array(
2586 'prodfournprice' => $prodfournprice,
2588 'product_id' => $product_id,
2589 'fourn_ref' => $fourn_ref,
2590 'fk_soc' => $fk_soc,
2593 $reshook = $hookmanager->executeHooks(
'getBuyPrice', $parameters, $this, $action);
2595 return $hookmanager->resArray;
2602 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2603 $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,";
2604 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2605 $sql .=
" pfp.packaging";
2606 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2607 $sql .=
" WHERE pfp.rowid = ".((int) $prodfournprice);
2609 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2611 $sql .=
" ORDER BY pfp.quantity DESC";
2613 dol_syslog(get_class($this).
"::get_buyprice first search by prodfournprice/qty", LOG_DEBUG);
2614 $resql = $this->db->query($sql);
2616 $obj = $this->db->fetch_object($resql);
2617 if ($obj && $obj->quantity > 0) {
2618 if (
isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2620 $prod_supplier->product_fourn_price_id = $obj->rowid;
2621 $prod_supplier->id = $obj->fk_product;
2622 $prod_supplier->fourn_qty = $obj->quantity;
2623 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2624 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2626 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2628 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2629 if ($price_result >= 0) {
2630 $obj->price = $price_result;
2633 $this->product_fourn_price_id = $obj->rowid;
2634 $this->buyprice = $obj->price;
2635 $this->fourn_pu = $obj->price / $obj->quantity;
2636 $this->fourn_price_base_type =
'HT';
2637 $this->fourn_socid = $obj->fk_soc;
2638 $this->ref_fourn = $obj->ref_supplier;
2639 $this->ref_supplier = $obj->ref_supplier;
2640 $this->desc_supplier = $obj->desc_supplier;
2641 $this->remise_percent = $obj->remise_percent;
2642 $this->vatrate_supplier = $obj->tva_tx;
2643 $this->default_vat_code_supplier = $obj->default_vat_code;
2644 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2645 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2646 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2647 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2648 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2650 $this->packaging = (float) $obj->packaging;
2656 $this->fourn_qty = $obj->quantity;
2657 $result = $obj->fk_product;
2661 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2662 $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,";
2663 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2664 $sql .=
" pfp.packaging";
2665 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2666 $sql .=
" WHERE 1 = 1";
2667 if ($product_id > 0) {
2668 $sql .=
" AND pfp.fk_product = ".((int) $product_id);
2670 if ($fourn_ref !=
'none') {
2671 $sql .=
" AND pfp.ref_fourn = '".$this->db->escape($fourn_ref).
"'";
2674 $sql .=
" AND pfp.fk_soc = ".((int) $fk_soc);
2677 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2679 $sql .=
" ORDER BY pfp.quantity DESC";
2682 dol_syslog(get_class($this).
"::get_buyprice second search from qty/ref/product_id", LOG_DEBUG);
2683 $resql = $this->db->query($sql);
2685 $obj = $this->db->fetch_object($resql);
2686 if ($obj && $obj->quantity > 0) {
2687 if (
isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2689 $prod_supplier->product_fourn_price_id = $obj->rowid;
2690 $prod_supplier->id = $obj->fk_product;
2691 $prod_supplier->fourn_qty = $obj->quantity;
2692 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2693 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2695 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2697 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2698 if ($price_result >= 0) {
2699 $obj->price = $price_result;
2702 $this->product_fourn_price_id = $obj->rowid;
2703 $this->buyprice = $obj->price;
2704 $this->fourn_qty = $obj->quantity;
2705 $this->fourn_pu = $obj->price / $obj->quantity;
2706 $this->fourn_price_base_type =
'HT';
2707 $this->fourn_socid = $obj->fk_soc;
2708 $this->ref_fourn = $obj->ref_supplier;
2709 $this->ref_supplier = $obj->ref_supplier;
2710 $this->desc_supplier = $obj->desc_supplier;
2711 $this->remise_percent = $obj->remise_percent;
2712 $this->vatrate_supplier = $obj->tva_tx;
2713 $this->default_vat_code_supplier = $obj->default_vat_code;
2714 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2715 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2716 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2717 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2718 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2720 $this->packaging = (float) $obj->packaging;
2724 $this->fourn_qty = $obj->quantity;
2725 $result = $obj->fk_product;
2731 $this->error = $this->db->lasterror();
2736 $this->error = $this->db->lasterror();
2760 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)
2766 dol_syslog(get_class($this).
"::update_price id=".$id.
" newprice=".$newprice.
" newpricebase=".$newpricebase.
" newminprice=".$newminprice.
" level=".$level.
" npr=".$newnpr.
" newdefaultvatcode=".$newdefaultvatcode);
2769 if (empty($this->tva_tx)) {
2770 $this->tva_tx = 0.0;
2772 if (empty($newnpr)) {
2775 if (empty($newminprice)) {
2780 if ($newvat ===
null || $newvat ==
'') {
2781 $newvat = (float) $this->tva_tx;
2784 $localtaxtype1 =
'';
2785 $localtaxtype2 =
'';
2790 return $this->
generateMultiprices($user, $newprice, $newpricebase, $newvat, $newnpr, $newpbq);
2793 if (!empty($newminprice) && ($newminprice > $newprice)) {
2794 $this->error =
'ErrorPriceCantBeLowerThanMinPrice';
2798 if ($newprice === 0 || $newprice !==
'') {
2799 if ($newpricebase ==
'TTC') {
2800 $price_ttc = (float)
price2num($newprice,
'MU');
2801 $price = (float)
price2num($newprice) / (1 + ((float) $newvat / 100));
2802 $price = (float)
price2num($price,
'MU');
2804 if ((
string) $newminprice !=
'0') {
2805 $price_min_ttc = (float)
price2num($newminprice,
'MU');
2806 $price_min = (float)
price2num($newminprice) / (1 + ($newvat / 100));
2807 $price_min = (float)
price2num($price_min,
'MU');
2810 $price_min_ttc = 0.0;
2813 $price = (float)
price2num($newprice,
'MU');
2814 $price_ttc = ($newnpr != 1) ? (
float)
price2num($newprice) * (1 + ($newvat / 100)) : $price;
2815 $price_ttc = (float)
price2num($price_ttc,
'MU');
2817 if ((
string) $newminprice !=
'0') {
2818 $price_min = (float)
price2num($newminprice,
'MU');
2819 $price_min_ttc = (float)
price2num($newminprice) * (1 + ($newvat / 100));
2820 $price_min_ttc = (float)
price2num($price_min_ttc,
'MU');
2824 $price_min_ttc = 0.0;
2828 if (count($localtaxes_array) > 0) {
2829 $localtaxtype1 = $localtaxes_array[
'0'];
2830 $localtax1 = $localtaxes_array[
'1'];
2831 $localtaxtype2 = $localtaxes_array[
'2'];
2832 $localtax2 = $localtaxes_array[
'3'];
2835 if (!empty($newdefaultvatcode)) {
2838 $sql =
"SELECT t.rowid, t.code, t.recuperableonly as tva_npr, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
2839 $sql .=
" FROM ".MAIN_DB_PREFIX.
"c_tva as t, ".MAIN_DB_PREFIX.
"c_country as c";
2840 $sql .=
" WHERE t.fk_pays = c.rowid AND c.code = '".$this->db->escape(
$mysoc->country_code).
"'";
2841 $sql .=
" AND t.taux = ".((float) $newdefaultvatcode).
" AND t.active = 1";
2842 $sql .=
" AND t.code = '".$this->db->escape($newdefaultvatcode).
"'";
2843 $resql = $this->db->query($sql);
2845 $obj = $this->db->fetch_object($resql);
2847 $npr = $obj->tva_npr;
2848 $localtax1 = $obj->localtax1;
2849 $localtax2 = $obj->localtax2;
2850 $localtaxtype1 = $obj->localtax1_type;
2851 $localtaxtype2 = $obj->localtax2_type;
2856 $localtaxtype1 =
'0';
2858 $localtaxtype2 =
'0';
2862 if (empty($localtax1)) {
2865 if (empty($localtax2)) {
2873 $sql =
"UPDATE ".$this->db->prefix().
"product SET";
2874 $sql .=
" price_base_type = '".$this->db->escape($newpricebase).
"',";
2875 $sql .=
" price = ".(float) $price.
",";
2876 $sql .=
" price_ttc = ".(float) $price_ttc.
",";
2877 $sql .=
" price_min = ".(float) $price_min.
",";
2878 $sql .=
" price_min_ttc = ".(float) $price_min_ttc.
",";
2879 $sql .=
" localtax1_tx = ".($localtax1 >= 0 ? (float) $localtax1 :
'NULL').
",";
2880 $sql .=
" localtax2_tx = ".($localtax2 >= 0 ? (float) $localtax2 :
'NULL').
",";
2881 $sql .=
" localtax1_type = ".($localtaxtype1 !=
'' ?
"'".$this->db->escape($localtaxtype1).
"'" :
"'0'").
",";
2882 $sql .=
" localtax2_type = ".($localtaxtype2 !=
'' ?
"'".$this->db->escape($localtaxtype2).
"'" :
"'0'").
",";
2883 $sql .=
" default_vat_code = ".($newdefaultvatcode ?
"'".$this->db->escape($newdefaultvatcode).
"'" :
"null").
",";
2884 $sql .=
" price_label = ".(!empty($price_label) ?
"'".$this->db->escape($price_label).
"'" :
"null").
",";
2885 $sql .=
" tva_tx = ".(float)
price2num($newvat).
",";
2886 $sql .=
" recuperableonly = '".$this->db->escape((
string) $newnpr).
"'";
2887 $sql .=
" WHERE rowid = ".((int) $id);
2889 dol_syslog(get_class($this).
"::update_price", LOG_DEBUG);
2890 $resql = $this->db->query($sql);
2892 $this->multiprices[$level] = $price;
2893 $this->multiprices_ttc[$level] = $price_ttc;
2894 $this->multiprices_min[$level] = $price_min;
2895 $this->multiprices_min_ttc[$level] = $price_min_ttc;
2896 $this->multiprices_base_type[$level] = $newpricebase;
2897 $this->multiprices_default_vat_code[$level] = $newdefaultvatcode;
2898 $this->multiprices_tva_tx[$level] = $newvat;
2899 $this->multiprices_recuperableonly[$level] = $newnpr;
2901 $this->
price = $price;
2902 $this->price_label = $price_label;
2903 $this->price_ttc = $price_ttc;
2904 $this->price_min = $price_min;
2905 $this->price_min_ttc = $price_min_ttc;
2906 $this->price_base_type = $newpricebase;
2907 $this->default_vat_code = $newdefaultvatcode;
2908 $this->tva_tx = $newvat;
2909 $this->tva_npr = $newnpr;
2912 $this->localtax1_tx = $localtax1;
2913 $this->localtax2_tx = $localtax2;
2914 $this->localtax1_type = $localtaxtype1;
2915 $this->localtax2_type = $localtaxtype2;
2918 $this->price_by_qty = $newpbq;
2922 if (!empty(array_diff_assoc($newPriceData, $lastPriceData)) || (!
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
2926 $this->level = $level;
2930 $result = $this->call_trigger(
'PRODUCT_PRICE_MODIFY', $user);
2932 $this->db->rollback();
2938 $this->db->commit();
2940 $this->db->rollback();
2941 $this->error = $this->db->lasterror();
2960 $this->fk_price_expression = $expression_id;
2962 return $this->
update($this->
id, $user);
2977 public function fetch($id = 0, $ref =
'', $ref_ext =
'', $barcode =
'', $ignore_expression = 0, $ignore_price_load = 0, $ignore_lang_load = 0)
2979 include_once DOL_DOCUMENT_ROOT.
'/core/lib/company.lib.php';
2983 dol_syslog(get_class($this).
"::fetch id=".$id.
" ref=".$ref.
" ref_ext=".$ref_ext);
2986 if (!$id && !$ref && !$ref_ext && !$barcode) {
2987 $this->error =
'ErrorWrongParameters';
2988 dol_syslog(get_class($this).
"::fetch ".$this->error, LOG_ERR);
2992 $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,";
2993 $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,";
2994 $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,";
2995 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.last_main_doc,";
2996 $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,";
2998 $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,";
3000 $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,";
3005 $separatedEntityPMP =
false;
3006 $separatedStock =
false;
3007 $visibleWarehousesEntities = $conf->entity;
3010 $checkPMPPerEntity = $this->db->query(
"SELECT pmp FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = ".((int) $id).
" AND entity = ".(
int) $conf->entity);
3011 if ($this->db->num_rows($checkPMPPerEntity) > 0) {
3012 $separatedEntityPMP =
true;
3016 $separatedStock =
true;
3017 if (isset($mc->sharings[
'stock']) && !empty($mc->sharings[
'stock'])) {
3018 $visibleWarehousesEntities .=
"," . implode(
",", $mc->sharings[
'stock']);
3021 if ($separatedEntityPMP) {
3022 $sql .=
" ppe.pmp,";
3026 $sql .=
" p.datec, GREATEST(p.tms, COALESCE(pef.tms, p.tms)) AS tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.sell_or_eat_by_mandatory, p.batch_mask, p.fk_unit,";
3027 $sql .=
" p.fk_price_expression, p.price_autogen, p.stockable_product, p.model_pdf,";
3028 $sql .=
" p.price_label,";
3029 if ($separatedStock) {
3030 $sql .=
" SUM(sp.reel) as stock";
3034 $sql .=
" FROM ".$this->db->prefix().
"product as p";
3035 $sql .=
" LEFT JOIN ".$this->db->prefix().
"product_extrafields as pef ON pef.fk_object=p.rowid";
3037 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int) $conf->entity);
3039 if ($separatedStock) {
3040 $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).
"))";
3044 $sql .=
" WHERE p.rowid = ".((int) $id);
3046 $sql .=
" WHERE p.entity IN (".getEntity($this->element).
")";
3048 $sql .=
" AND p.ref = '".$this->db->escape($ref).
"'";
3049 } elseif ($ref_ext) {
3050 $sql .=
" AND p.ref_ext = '".$this->db->escape($ref_ext).
"'";
3051 } elseif ($barcode) {
3052 $sql .=
" AND p.barcode = '".$this->db->escape($barcode).
"'";
3055 if ($separatedStock) {
3056 $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,";
3057 $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,";
3058 $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,";
3059 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
3060 $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,";
3062 $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,";
3064 $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,";
3066 if ($separatedEntityPMP) {
3067 $sql .=
" ppe.pmp,";
3071 $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,";
3072 $sql .=
" p.fk_price_expression, p.price_autogen, p.stockable_product, p.model_pdf,";
3073 $sql .=
" p.price_label";
3080 $resql = $this->db->query($sql);
3082 unset($this->oldcopy);
3084 if ($this->db->num_rows($resql) > 0) {
3085 $obj = $this->db->fetch_object($resql);
3087 $this->
id = $obj->rowid;
3088 $this->
ref = $obj->ref;
3089 $this->ref_ext = $obj->ref_ext;
3090 $this->label = $obj->label;
3092 $this->url = $obj->url;
3093 $this->note_public = $obj->note_public;
3094 $this->note_private = $obj->note_private;
3095 $this->note = $obj->note_private;
3097 $this->
type = $obj->fk_product_type;
3098 $this->price_label = $obj->price_label;
3099 $this->
status = $obj->tosell;
3100 $this->status_buy = $obj->tobuy;
3101 $this->status_batch = $obj->tobatch;
3102 $this->sell_or_eat_by_mandatory = $obj->sell_or_eat_by_mandatory;
3103 $this->batch_mask = $obj->batch_mask;
3105 $this->customcode = $obj->customcode;
3106 $this->country_id = $obj->fk_country;
3107 $this->country_code =
getCountry($this->country_id,
'2', $this->db);
3108 $this->state_id = $obj->fk_state;
3109 $this->lifetime = $obj->lifetime;
3110 $this->qc_frequency = $obj->qc_frequency;
3111 $this->
price = $obj->price;
3112 $this->price_ttc = $obj->price_ttc;
3113 $this->price_min = $obj->price_min;
3114 $this->price_min_ttc = $obj->price_min_ttc;
3115 $this->price_base_type = $obj->price_base_type;
3116 $this->cost_price = isset($obj->cost_price) ? (float) $obj->cost_price :
null;
3117 $this->default_vat_code = $obj->default_vat_code;
3118 $this->tva_tx = $obj->tva_tx;
3120 $this->tva_npr = $obj->tva_npr;
3122 $this->localtax1_tx = $obj->localtax1_tx;
3123 $this->localtax2_tx = $obj->localtax2_tx;
3124 $this->localtax1_type = $obj->localtax1_type;
3125 $this->localtax2_type = $obj->localtax2_type;
3127 $this->finished = $obj->finished;
3128 $this->fk_default_bom = $obj->fk_default_bom;
3130 $this->duration = $obj->duration;
3132 preg_match(
'/([\d.]+)(\w+)/', $obj->duration, $matches);
3133 $this->duration_value = !empty($matches[1]) ? (float) $matches[1] : 0;
3134 $this->duration_unit = !empty($matches[2]) ? (string) $matches[2] :
null;
3135 $this->canvas = $obj->canvas;
3136 $this->net_measure = $obj->net_measure;
3137 $this->net_measure_units = $obj->net_measure_units;
3138 $this->weight = $obj->weight;
3139 $this->weight_units = (is_null($obj->weight_units) ? 0 : $obj->weight_units);
3140 $this->length = $obj->length;
3141 $this->length_units = (is_null($obj->length_units) ? 0 : $obj->length_units);
3142 $this->width = $obj->width;
3143 $this->width_units = (is_null($obj->width_units) ? 0 : $obj->width_units);
3144 $this->height = $obj->height;
3145 $this->height_units = (is_null($obj->height_units) ? 0 : $obj->height_units);
3147 $this->surface = $obj->surface;
3148 $this->surface_units = (is_null($obj->surface_units) ? 0 : $obj->surface_units);
3149 $this->volume = $obj->volume;
3150 $this->volume_units = (is_null($obj->volume_units) ? 0 : $obj->volume_units);
3151 $this->barcode = $obj->barcode;
3152 $this->barcode_type = $obj->fk_barcode_type;
3154 $this->accountancy_code_buy = $obj->accountancy_code_buy;
3155 $this->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra;
3156 $this->accountancy_code_buy_export = $obj->accountancy_code_buy_export;
3157 $this->accountancy_code_sell = $obj->accountancy_code_sell;
3158 $this->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra;
3159 $this->accountancy_code_sell_export = $obj->accountancy_code_sell_export;
3161 $this->fk_default_warehouse = $obj->fk_default_warehouse;
3162 $this->fk_default_workstation = $obj->fk_default_workstation;
3163 $this->seuil_stock_alerte = $obj->seuil_stock_alerte;
3164 $this->desiredstock = $obj->desiredstock;
3165 $this->stock_reel = $obj->stock;
3166 $this->stockable_product = $obj->stockable_product;
3167 $this->pmp = $obj->pmp;
3169 $this->date_creation = $this->db->jdate($obj->datec);
3170 $this->date_modification = $this->db->jdate($obj->tms);
3172 $this->import_key = $obj->import_key;
3173 $this->entity = $obj->entity;
3175 $this->ref_ext = $obj->ref_ext;
3176 $this->fk_price_expression = $obj->fk_price_expression;
3177 $this->fk_unit = $obj->fk_unit;
3178 $this->price_autogen = $obj->price_autogen;
3179 $this->model_pdf = $obj->model_pdf;
3180 $this->last_main_doc = $obj->last_main_doc;
3182 $this->mandatory_period = $obj->mandatory_period;
3185 $this->packaging = (float) $obj->packaging;
3188 $this->db->free($resql);
3200 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
3201 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3202 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3203 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3204 $sql .=
" ,price_label";
3205 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3206 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3207 $sql .=
" AND price_level=".((int) $i);
3208 $sql .=
" AND fk_product = ".((int) $this->
id);
3209 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3211 $resql = $this->db->query($sql);
3213 $result = $this->db->fetch_array($resql);
3215 $this->multiprices[$i] = $result ? $result[
"price"] :
null;
3216 $this->multiprices_ttc[$i] = $result ? $result[
"price_ttc"] :
null;
3217 $this->multiprices_min[$i] = $result ? $result[
"price_min"] :
null;
3218 $this->multiprices_min_ttc[$i] = $result ? $result[
"price_min_ttc"] :
null;
3219 $this->multiprices_base_type[$i] = $result ? $result[
"price_base_type"] :
null;
3221 $this->multiprices_tva_tx[$i] = $result ? $result[
"tva_tx"].(!empty($result[
'default_vat_code']) ?
' ('.$result[
'default_vat_code'].
')' :
'') :
null;
3222 $this->multiprices_recuperableonly[$i] = $result ? $result[
"recuperableonly"] :
null;
3261 $this->error = $this->db->lasterror;
3267 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY') && empty($ignore_price_load)) {
3268 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3269 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid";
3270 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3271 $sql .=
" WHERE fk_product = ".((int) $this->
id);
3272 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3275 $resql = $this->db->query($sql);
3277 $result = $this->db->fetch_array($resql);
3281 $this->prices_by_qty[0] = $result[
"price_by_qty"];
3282 $this->prices_by_qty_id[0] = $result[
"rowid"];
3284 if ($this->prices_by_qty[0] == 1) {
3285 $sql =
"SELECT rowid,price, unitprice, quantity, remise_percent, remise, remise, price_base_type";
3286 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3287 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[0]);
3288 $sql .=
" ORDER BY quantity ASC";
3290 $resql = $this->db->query($sql);
3292 $resultat = array();
3294 while ($result = $this->db->fetch_array($resql)) {
3295 $resultat[$ii] = array();
3296 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3297 $resultat[$ii][
"price"] = $result[
"price"];
3298 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3299 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3300 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3302 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3305 $this->prices_by_qty_list[0] = $resultat;
3307 $this->error = $this->db->lasterror;
3313 $this->error = $this->db->lasterror;
3316 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') && empty($ignore_price_load)) {
3317 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
3318 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3319 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3320 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3321 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3322 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3323 $sql .=
" AND price_level=".((int) $i);
3324 $sql .=
" AND fk_product = ".((int) $this->
id);
3325 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3327 $resql = $this->db->query($sql);
3329 $this->error = $this->db->lasterror;
3332 $result = $this->db->fetch_array($resql);
3333 $this->multiprices[$i] = (!empty($result[
"price"]) ? $result[
"price"] : 0);
3334 $this->multiprices_ttc[$i] = (!empty($result[
"price_ttc"]) ? $result[
"price_ttc"] : 0);
3335 $this->multiprices_min[$i] = (!empty($result[
"price_min"]) ? $result[
"price_min"] : 0);
3336 $this->multiprices_min_ttc[$i] = (!empty($result[
"price_min_ttc"]) ? $result[
"price_min_ttc"] : 0);
3337 $this->multiprices_base_type[$i] = (!empty($result[
"price_base_type"]) ? $result[
"price_base_type"] :
'');
3339 $this->multiprices_tva_tx[$i] = (!empty($result[
"tva_tx"]) ? $result[
"tva_tx"] : 0);
3340 $this->multiprices_recuperableonly[$i] = (!empty($result[
"recuperableonly"]) ? $result[
"recuperableonly"] : 0);
3343 $this->prices_by_qty[$i] = (!empty($result[
"price_by_qty"]) ? $result[
"price_by_qty"] : 0);
3344 $this->prices_by_qty_id[$i] = (!empty($result[
"rowid"]) ? $result[
"rowid"] : 0);
3346 if ($this->prices_by_qty[$i] == 1) {
3347 $sql =
"SELECT rowid, price, unitprice, quantity, remise_percent, remise, price_base_type";
3348 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3349 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[$i]);
3350 $sql .=
" ORDER BY quantity ASC";
3352 $resql = $this->db->query($sql);
3354 $resultat = array();
3356 while ($result = $this->db->fetch_array($resql)) {
3357 $resultat[$ii] = array();
3358 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3359 $resultat[$ii][
"price"] = $result[
"price"];
3360 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3361 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3362 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3363 $resultat[$ii][
"remise"] = $result[
"remise"];
3364 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3367 $this->prices_by_qty_list[$i] = $resultat;
3369 $this->error = $this->db->lasterror;
3377 if (
isModEnabled(
'dynamicprices') && !empty($this->fk_price_expression) && empty($ignore_expression)) {
3378 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
3380 $price_result = $priceparser->parseProduct($this);
3381 if ($price_result >= 0) {
3382 $this->
price = $price_result;
3384 $this->price_ttc = (float)
price2num($this->
price) * (1 + ($this->tva_tx / 100));
3385 $this->price_ttc = (float)
price2num($this->price_ttc,
'MU');
3391 $this->stock_warehouse = array();
3398 $this->error = $this->db->lasterror();
3413 global $user, $hookmanager, $action;
3417 foreach (array(
'toconsume',
'consumed',
'toproduce',
'produced') as $role) {
3418 $this->stats_mo[
'customers_'.$role] = 0;
3419 $this->stats_mo[
'nb_'.$role] = 0;
3420 $this->stats_mo[
'qty_'.$role] = 0;
3422 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3423 $sql .=
" SUM(mp.qty) as qty";
3424 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as c";
3425 $sql .=
" INNER JOIN ".$this->db->prefix().
"mrp_production as mp ON mp.fk_mo=c.rowid";
3426 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3427 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3430 $sql .=
" c.entity IN (".getEntity(
'mo').
")";
3432 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3433 $sql .=
" AND mp.role ='".$this->db->escape($role).
"'";
3435 $sql .=
" AND c.fk_soc = ".((int) $socid);
3438 $result = $this->db->query($sql);
3440 $obj = $this->db->fetch_object($result);
3441 $this->stats_mo[
'customers_'.$role] = $obj->nb_customers ? $obj->nb_customers : 0;
3442 $this->stats_mo[
'nb_'.$role] = $obj->nb ? $obj->nb : 0;
3443 $this->stats_mo[
'qty_'.$role] = $obj->qty ?
price2num($obj->qty,
'MS') : 0;
3445 $this->error = $this->db->error();
3450 if (!empty($error)) {
3454 $parameters = array(
'socid' => $socid);
3455 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3457 $this->stats_mo = $hookmanager->resArray[
'stats_mo'];
3473 global $hookmanager, $action;
3477 $this->stats_bom[
'nb_toproduce'] = 0;
3478 $this->stats_bom[
'nb_toconsume'] = 0;
3479 $this->stats_bom[
'qty_toproduce'] = 0;
3480 $this->stats_bom[
'qty_toconsume'] = 0;
3482 $sql =
"SELECT COUNT(DISTINCT b.rowid) as nb_toproduce,";
3483 $sql .=
" SUM(b.qty) as qty_toproduce";
3484 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3485 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom = b.rowid";
3487 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3488 $sql .=
" AND b.fk_product =".((int) $this->
id);
3489 $sql .=
" GROUP BY b.rowid";
3491 $result = $this->db->query($sql);
3493 $obj = $this->db->fetch_object($result);
3494 $this->stats_bom[
'nb_toproduce'] = !empty($obj->nb_toproduce) ? $obj->nb_toproduce : 0;
3495 $this->stats_bom[
'qty_toproduce'] = !empty($obj->qty_toproduce) ?
price2num($obj->qty_toproduce) : 0;
3497 $this->error = $this->db->error();
3501 $sql =
"SELECT COUNT(DISTINCT bl.rowid) as nb_toconsume,";
3502 $sql .=
" SUM(bl.qty) as qty_toconsume";
3503 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3504 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
3506 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3507 $sql .=
" AND bl.fk_product =".((int) $this->
id);
3509 $result = $this->db->query($sql);
3511 $obj = $this->db->fetch_object($result);
3512 $this->stats_bom[
'nb_toconsume'] = !empty($obj->nb_toconsume) ? $obj->nb_toconsume : 0;
3513 $this->stats_bom[
'qty_toconsume'] = !empty($obj->qty_toconsume) ?
price2num($obj->qty_toconsume) : 0;
3515 $this->error = $this->db->error();
3519 if (!empty($error)) {
3523 $parameters = array(
'socid' => $socid);
3524 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3526 $this->stats_bom = $hookmanager->resArray[
'stats_bom'];
3542 global $user, $hookmanager, $action;
3544 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_customers, COUNT(DISTINCT p.rowid) as nb,";
3545 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3546 $sql .=
" FROM ".$this->db->prefix().
"propaldet as pd";
3547 $sql .=
", ".$this->db->prefix().
"propal as p";
3548 $sql .=
", ".$this->db->prefix().
"societe as s";
3549 $sql .=
" WHERE p.rowid = pd.fk_propal";
3550 $sql .=
" AND p.fk_soc = s.rowid";
3551 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
3552 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3553 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3554 $sql .=
" AND EXISTS (SELECT 1 FROM ".$this->db->prefix().
"societe_commerciaux as sc WHERE sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $user->id).
")";
3558 $sql .=
" AND p.fk_soc = ".((int) $socid);
3561 $parameters = array(
'socid' => $socid,
'type_element' =>
'propal');
3562 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3563 $sql .= $hookmanager->resPrint;
3564 $result = $this->db->query($sql);
3566 $obj = $this->db->fetch_object($result);
3567 $this->stats_propale[
'customers'] = $obj->nb_customers;
3568 $this->stats_propale[
'nb'] = $obj->nb;
3569 $this->stats_propale[
'rows'] = $obj->nb_rows;
3570 $this->stats_propale[
'qty'] = $obj->qty ? $obj->qty : 0;
3575 if (is_array($TFather) && !empty($TFather)) {
3576 foreach ($TFather as &$fatherData) {
3577 $pFather =
new Product($this->db);
3578 $pFather->id = $fatherData[
'id'];
3579 $qtyCoef = $fatherData[
'qty'];
3581 if ($fatherData[
'incdec']) {
3582 $pFather->load_stats_propale($socid);
3584 $this->stats_propale[
'customers'] += $pFather->stats_propale[
'customers'];
3585 $this->stats_propale[
'nb'] += $pFather->stats_propale[
'nb'];
3586 $this->stats_propale[
'rows'] += $pFather->stats_propale[
'rows'];
3587 $this->stats_propale[
'qty'] += $pFather->stats_propale[
'qty'] * $qtyCoef;
3593 $parameters = array(
'socid' => $socid);
3594 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerProposal', $parameters, $this, $action);
3596 $this->stats_propale = $hookmanager->resArray[
'stats_propale'];
3601 $this->error = $this->db->error();
3617 global $user, $hookmanager, $action;
3619 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_suppliers, COUNT(DISTINCT p.rowid) as nb,";
3620 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3621 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as pd";
3622 $sql .=
", ".$this->db->prefix().
"supplier_proposal as p";
3623 $sql .=
", ".$this->db->prefix().
"societe as s";
3624 $sql .=
" WHERE p.rowid = pd.fk_supplier_proposal";
3625 $sql .=
" AND p.fk_soc = s.rowid";
3626 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
3627 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3628 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3629 $sql .=
" AND EXISTS (SELECT 1 FROM ".$this->db->prefix().
"societe_commerciaux as sc WHERE sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $user->id).
")";
3633 $sql .=
" AND p.fk_soc = ".((int) $socid);
3636 $result = $this->db->query($sql);
3638 $obj = $this->db->fetch_object($result);
3639 $this->stats_proposal_supplier[
'suppliers'] = $obj->nb_suppliers;
3640 $this->stats_proposal_supplier[
'nb'] = $obj->nb;
3641 $this->stats_proposal_supplier[
'rows'] = $obj->nb_rows;
3642 $this->stats_proposal_supplier[
'qty'] = $obj->qty ? $obj->qty : 0;
3644 $parameters = array(
'socid' => $socid);
3645 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierProposal', $parameters, $this, $action);
3647 $this->stats_proposal_supplier = $hookmanager->resArray[
'stats_proposal_supplier'];
3652 $this->error = $this->db->error();
3670 global $user, $hookmanager, $action;
3673 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3674 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3675 $sql .=
" FROM ".$this->db->prefix().
"commandedet as cd";
3676 $sql .=
", ".$this->db->prefix().
"commande as c";
3677 $sql .=
", ".$this->db->prefix().
"societe as s";
3678 $sql .=
" WHERE c.rowid = cd.fk_commande";
3679 $sql .=
" AND c.fk_soc = s.rowid";
3680 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'commande').
")";
3681 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3682 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3683 $sql .=
" AND EXISTS (SELECT 1 FROM ".$this->db->prefix().
"societe_commerciaux as sc WHERE sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id).
")";
3686 $sql .=
" AND c.fk_soc = ".((int) $socid);
3688 if ($filtrestatut !=
'') {
3689 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3692 $parameters = array(
'socid' => $socid,
'type_element' =>
'order');
3693 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3694 $sql .= $hookmanager->resPrint;
3695 $result = $this->db->query($sql);
3697 $obj = $this->db->fetch_object($result);
3698 $this->stats_commande[
'customers'] = $obj->nb_customers;
3699 $this->stats_commande[
'nb'] = $obj->nb;
3700 $this->stats_commande[
'rows'] = $obj->nb_rows;
3701 $this->stats_commande[
'qty'] = $obj->qty ? $obj->qty : 0;
3706 if (is_array($TFather) && !empty($TFather)) {
3707 foreach ($TFather as &$fatherData) {
3708 $pFather =
new Product($this->db);
3709 $pFather->id = $fatherData[
'id'];
3710 $qtyCoef = $fatherData[
'qty'];
3712 if ($fatherData[
'incdec']) {
3713 $pFather->load_stats_commande($socid, $filtrestatut);
3715 $this->stats_commande[
'customers'] += $pFather->stats_commande[
'customers'];
3716 $this->stats_commande[
'nb'] += $pFather->stats_commande[
'nb'];
3717 $this->stats_commande[
'rows'] += $pFather->stats_commande[
'rows'];
3718 $this->stats_commande[
'qty'] += $pFather->stats_commande[
'qty'] * $qtyCoef;
3731 $sql =
"SELECT SUM(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3732 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3734 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture' AND sourcetype = 'commande' ";
3735 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3736 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3737 $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)";
3741 $sql .=
"SELECT SUM(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3742 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3743 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_source = f.rowid AND el.targettype = 'commande' AND sourcetype = 'facture' ";
3744 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_target = c.rowid";
3745 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3746 $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)";
3748 $parameters = array(
'socid' => $socid,
'type_element' =>
'order');
3749 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3750 $sql .= $hookmanager->resPrint;
3751 $resql = $this->db->query($sql);
3753 while ($obj = $this->db->fetch_object($resql)) {
3754 $adeduire += $obj->count;
3758 $this->stats_commande[
'qty'] -= $adeduire;
3761 include_once DOL_DOCUMENT_ROOT.
'/compta/facture/class/facture.class.php';
3765 $sql =
"SELECT sum(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3766 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3768 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture' AND sourcetype = 'commande' ";
3769 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3770 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3771 $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)";
3773 $sql .=
" UNION ALL ";
3775 $sql .=
"SELECT sum(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3776 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3777 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_source = f.rowid AND el.targettype = 'commande' AND sourcetype = 'facture' ";
3778 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_target = c.rowid";
3779 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3780 $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)";
3782 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3784 $parameters = array(
'socid' => $socid,
'type_element' =>
'order');
3785 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3786 $sql .= $hookmanager->resPrint;
3787 $resql = $this->db->query($sql);
3789 while ($obj = $this->db->fetch_object($resql)) {
3790 $adeduire += $obj->count;
3793 $this->error = $this->db->error();
3797 $this->stats_commande[
'qty'] -= $adeduire;
3801 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3802 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerOrder', $parameters, $this, $action);
3804 $this->stats_commande = $hookmanager->resArray[
'stats_commande'];
3808 $this->error = $this->db->error();
3826 global $user, $hookmanager, $action;
3828 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_suppliers, COUNT(DISTINCT c.rowid) as nb,";
3829 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3830 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as cd";
3831 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as c";
3832 $sql .=
", ".$this->db->prefix().
"societe as s";
3833 $sql .=
" WHERE c.rowid = cd.fk_commande";
3834 $sql .=
" AND c.fk_soc = s.rowid";
3835 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3836 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3837 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3838 $sql .=
" AND EXISTS (SELECT 1 FROM ".$this->db->prefix().
"societe_commerciaux as sc WHERE sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id).
")";
3841 $sql .=
" AND c.fk_soc = ".((int) $socid);
3843 if ($filtrestatut !=
'') {
3844 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3846 if (!empty($dateofvirtualstock)) {
3847 $sql .=
" AND c.date_livraison <= '".$this->db->idate($dateofvirtualstock).
"'";
3850 $result = $this->db->query($sql);
3852 $obj = $this->db->fetch_object($result);
3853 $this->stats_commande_fournisseur[
'suppliers'] = $obj->nb_suppliers;
3854 $this->stats_commande_fournisseur[
'nb'] = $obj->nb;
3855 $this->stats_commande_fournisseur[
'rows'] = $obj->nb_rows;
3856 $this->stats_commande_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
3858 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3859 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierOrder', $parameters, $this, $action);
3861 $this->stats_commande_fournisseur = $hookmanager->resArray[
'stats_commande_fournisseur'];
3866 $this->error = $this->db->error().
' sql='.$sql;
3881 public function load_stats_sending($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $filterShipmentStatus =
'')
3884 global $user, $hookmanager, $action;
3886 $sql =
"SELECT COUNT(DISTINCT e.fk_soc) as nb_customers, COUNT(DISTINCT e.rowid) as nb,";
3887 $sql .=
" COUNT(ed.rowid) as nb_rows, SUM(ed.qty) as qty";
3888 $sql .=
" FROM ".$this->db->prefix().
"expeditiondet as ed";
3889 $sql .=
", ".$this->db->prefix().
"commandedet as cd";
3890 $sql .=
", ".$this->db->prefix().
"commande as c";
3891 $sql .=
", ".$this->db->prefix().
"expedition as e";
3892 $sql .=
", ".$this->db->prefix().
"societe as s";
3893 $sql .=
" WHERE e.rowid = ed.fk_expedition";
3894 $sql .=
" AND c.rowid = cd.fk_commande";
3895 $sql .=
" AND e.fk_soc = s.rowid";
3896 $sql .=
" AND e.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'expedition').
")";
3897 $sql .=
" AND ed.fk_elementdet = cd.rowid";
3898 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3899 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3900 $sql .=
" AND EXISTS (SELECT 1 FROM ".$this->db->prefix().
"societe_commerciaux as sc WHERE sc.fk_soc = e.fk_soc AND sc.fk_user = ".((int) $user->id).
")";
3903 $sql .=
" AND e.fk_soc = ".((int) $socid);
3905 if ($filtrestatut !=
'') {
3906 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3908 if (!empty($filterShipmentStatus)) {
3909 $sql .=
" AND e.fk_statut IN (".$this->db->sanitize($filterShipmentStatus).
")";
3912 $result = $this->db->query($sql);
3914 $obj = $this->db->fetch_object($result);
3915 $this->stats_expedition[
'customers'] = $obj->nb_customers;
3916 $this->stats_expedition[
'nb'] = $obj->nb;
3917 $this->stats_expedition[
'rows'] = $obj->nb_rows;
3918 $this->stats_expedition[
'qty'] = $obj->qty ? $obj->qty : 0;
3923 if (is_array($TFather) && !empty($TFather)) {
3924 foreach ($TFather as &$fatherData) {
3925 $pFather =
new Product($this->db);
3926 $pFather->id = $fatherData[
'id'];
3927 $qtyCoef = $fatherData[
'qty'];
3929 if ($fatherData[
'incdec']) {
3930 $pFather->load_stats_sending($socid, $filtrestatut, $forVirtualStock);
3932 $this->stats_expedition[
'customers'] += $pFather->stats_expedition[
'customers'];
3933 $this->stats_expedition[
'nb'] += $pFather->stats_expedition[
'nb'];
3934 $this->stats_expedition[
'rows'] += $pFather->stats_expedition[
'rows'];
3935 $this->stats_expedition[
'qty'] += $pFather->stats_expedition[
'qty'] * $qtyCoef;
3941 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock,
'filterShipmentStatus' => $filterShipmentStatus);
3942 $reshook = $hookmanager->executeHooks(
'loadStatsSending', $parameters, $this, $action);
3944 $this->stats_expedition = $hookmanager->resArray[
'stats_expedition'];
3949 $this->error = $this->db->error();
3964 public function load_stats_reception($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null)
3967 global $user, $hookmanager, $action;
3969 $sql =
"SELECT COUNT(DISTINCT cf.fk_soc) as nb_suppliers, COUNT(DISTINCT cf.rowid) as nb,";
3970 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
3971 $sql .=
" FROM ".$this->db->prefix().
"receptiondet_batch as fd";
3972 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as cf";
3973 $sql .=
", ".$this->db->prefix().
"societe as s";
3974 $sql .=
" WHERE cf.rowid = fd.fk_element";
3975 $sql .=
" AND cf.fk_soc = s.rowid";
3976 $sql .=
" AND cf.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3977 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3978 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3979 $sql .=
" AND EXISTS (SELECT 1 FROM ".$this->db->prefix().
"societe_commerciaux as sc WHERE sc.fk_soc = cf.fk_soc AND sc.fk_user = ".((int) $user->id).
")";
3982 $sql .=
" AND cf.fk_soc = ".((int) $socid);
3984 if ($filtrestatut !=
'') {
3985 $sql .=
" AND cf.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3987 if (!empty($dateofvirtualstock)) {
3988 $sql .=
" AND fd.datec <= '".$this->db->idate($dateofvirtualstock).
"'";
3991 $result = $this->db->query($sql);
3993 $obj = $this->db->fetch_object($result);
3994 $this->stats_reception[
'suppliers'] = $obj->nb_suppliers;
3995 $this->stats_reception[
'nb'] = $obj->nb;
3996 $this->stats_reception[
'rows'] = $obj->nb_rows;
3997 $this->stats_reception[
'qty'] = $obj->qty ? $obj->qty : 0;
3999 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
4000 $reshook = $hookmanager->executeHooks(
'loadStatsReception', $parameters, $this, $action);
4002 $this->stats_reception = $hookmanager->resArray[
'stats_reception'];
4007 $this->error = $this->db->error();
4023 public function load_stats_inproduction($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null, $warehouseid = 0)
4026 global $user, $hookmanager, $action;
4030 $sql =
"SELECT COUNT(DISTINCT m.fk_soc) as nb_customers, COUNT(DISTINCT m.rowid) as nb,";
4031 $sql .=
" COUNT(mp.rowid) as nb_rows, SUM(mp.qty) as qty, role";
4032 $sql .=
" FROM ".$this->db->prefix().
"mrp_production as mp";
4033 $sql .=
", ".$this->db->prefix().
"mrp_mo as m";
4034 $sql .=
" LEFT JOIN ".$this->db->prefix().
"societe as s ON s.rowid = m.fk_soc";
4035 $sql .=
" WHERE m.rowid = mp.fk_mo";
4036 $sql .=
" AND m.entity IN (".getEntity(($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE')) ?
'stock' :
'mrp').
")";
4037 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
4038 $sql .=
" AND (mp.disable_stock_change IN (0) OR mp.disable_stock_change IS NULL)";
4039 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
4040 $sql .=
" AND EXISTS (SELECT 1 FROM ".$this->db->prefix().
"societe_commerciaux as sc WHERE sc.fk_soc = m.fk_soc AND sc.fk_user = ".((int) $user->id).
")";
4043 $sql .=
" AND m.fk_soc = ".((int) $socid);
4045 if ($filtrestatut !=
'') {
4046 $sql .=
" AND m.status IN (".$this->db->sanitize($filtrestatut).
")";
4048 if (!empty($dateofvirtualstock)) {
4049 $sql .=
" AND m.date_valid <= '".$this->db->idate($dateofvirtualstock).
"'";
4051 if (!$serviceStockIsEnabled) {
4052 $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))";
4054 if (!empty($warehouseid)) {
4055 $sql .=
" AND m.fk_warehouse = ".((int) $warehouseid);
4057 $sql .=
" GROUP BY role";
4060 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
4062 $this->stats_mrptoconsume[
'customers'] = 0;
4063 $this->stats_mrptoconsume[
'nb'] = 0;
4064 $this->stats_mrptoconsume[
'rows'] = 0;
4065 $this->stats_mrptoconsume[
'qty'] = 0.0;
4066 $this->stats_mrptoproduce[
'customers'] = 0;
4067 $this->stats_mrptoproduce[
'nb'] = 0;
4068 $this->stats_mrptoproduce[
'rows'] = 0;
4069 $this->stats_mrptoproduce[
'qty'] = 0.0;
4072 $result = $this->db->query($sql);
4074 while ($obj = $this->db->fetch_object($result)) {
4075 if ($obj->role ==
'toconsume' && empty($warehouseid)) {
4076 $this->stats_mrptoconsume[
'customers'] += (int) $obj->nb_customers;
4077 $this->stats_mrptoconsume[
'nb'] += (int) $obj->nb;
4078 $this->stats_mrptoconsume[
'rows'] += (int) $obj->nb_rows;
4079 $this->stats_mrptoconsume[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4081 if ($obj->role ==
'consumed' && empty($warehouseid)) {
4085 $this->stats_mrptoconsume[
'qty'] -= ($obj->qty ? (float) $obj->qty : 0.0);
4087 if ($obj->role ==
'toproduce') {
4089 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4091 $this->stats_mrptoproduce[
'customers'] += (int) $obj->nb_customers;
4092 $this->stats_mrptoproduce[
'nb'] += (int) $obj->nb;
4093 $this->stats_mrptoproduce[
'rows'] += (int) $obj->nb_rows;
4094 $this->stats_mrptoproduce[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4097 if ($obj->role ==
'produced') {
4102 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
4104 $this->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
4111 if ($this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] < 0) {
4112 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
4115 if ($this->stats_mrptoconsume[
'qty'] < 0) {
4116 $this->stats_mrptoconsume[
'qty'] = 0;
4118 if ($this->stats_mrptoproduce[
'qty'] < 0) {
4119 $this->stats_mrptoproduce[
'qty'] = 0;
4123 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
4124 $reshook = $hookmanager->executeHooks(
'loadStatsInProduction', $parameters, $this, $action);
4126 $this->stats_mrptoproduce = $hookmanager->resArray[
'stats_mrptoproduce'];
4131 $this->error = $this->db->error();
4146 global $user, $hookmanager, $action;
4148 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
4149 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
4150 $sql .=
" FROM ".$this->db->prefix().
"contratdet as cd";
4151 $sql .=
", ".$this->db->prefix().
"contrat as c";
4152 $sql .=
", ".$this->db->prefix().
"societe as s";
4153 $sql .=
" WHERE c.rowid = cd.fk_contrat";
4154 $sql .=
" AND c.fk_soc = s.rowid";
4155 $sql .=
" AND c.entity IN (".getEntity(
'contract').
")";
4156 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
4157 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4158 $sql .=
" AND EXISTS (SELECT 1 FROM ".$this->db->prefix().
"societe_commerciaux as sc WHERE sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id).
")";
4162 $sql .=
" AND c.fk_soc = ".((int) $socid);
4165 $result = $this->db->query($sql);
4167 $obj = $this->db->fetch_object($result);
4168 $this->stats_contrat[
'customers'] = $obj->nb_customers;
4169 $this->stats_contrat[
'nb'] = $obj->nb;
4170 $this->stats_contrat[
'rows'] = $obj->nb_rows;
4171 $this->stats_contrat[
'qty'] = $obj->qty ? $obj->qty : 0;
4176 if (is_array($TFather) && !empty($TFather)) {
4177 foreach ($TFather as &$fatherData) {
4178 $pFather =
new Product($this->db);
4179 $pFather->id = $fatherData[
'id'];
4180 $qtyCoef = $fatherData[
'qty'];
4182 if ($fatherData[
'incdec']) {
4183 $pFather->load_stats_contrat($socid);
4185 $this->stats_contrat[
'customers'] += $pFather->stats_contrat[
'customers'];
4186 $this->stats_contrat[
'nb'] += $pFather->stats_contrat[
'nb'];
4187 $this->stats_contrat[
'rows'] += $pFather->stats_contrat[
'rows'];
4188 $this->stats_contrat[
'qty'] += $pFather->stats_contrat[
'qty'] * $qtyCoef;
4194 $parameters = array(
'socid' => $socid);
4195 $reshook = $hookmanager->executeHooks(
'loadStatsContract', $parameters, $this, $action);
4197 $this->stats_contrat = $hookmanager->resArray[
'stats_contrat'];
4202 $this->error = $this->db->error().
' sql='.$sql;
4217 global $user, $hookmanager, $action;
4219 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4220 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(".$this->db->ifsql(
'f.type != 2',
'fd.qty',
'fd.qty * -1').
") as qty";
4221 $sql .=
" FROM ".$this->db->prefix().
"facturedet as fd";
4222 $sql .=
", ".$this->db->prefix().
"facture as f";
4223 $sql .=
", ".$this->db->prefix().
"societe as s";
4224 $sql .=
" WHERE f.rowid = fd.fk_facture";
4225 $sql .=
" AND f.fk_soc = s.rowid";
4226 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4227 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4228 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4229 $sql .=
" AND EXISTS (SELECT 1 FROM ".$this->db->prefix().
"societe_commerciaux as sc WHERE sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id).
")";
4233 $sql .=
" AND f.fk_soc = ".((int) $socid);
4236 $result = $this->db->query($sql);
4238 $obj = $this->db->fetch_object($result);
4239 $this->stats_facture[
'customers'] = $obj->nb_customers;
4240 $this->stats_facture[
'nb'] = $obj->nb;
4241 $this->stats_facture[
'rows'] = $obj->nb_rows;
4242 $this->stats_facture[
'qty'] = $obj->qty ? $obj->qty : 0;
4247 if (is_array($TFather) && !empty($TFather)) {
4248 foreach ($TFather as &$fatherData) {
4249 $pFather =
new Product($this->db);
4250 $pFather->id = $fatherData[
'id'];
4251 $qtyCoef = $fatherData[
'qty'];
4253 if ($fatherData[
'incdec']) {
4254 $pFather->load_stats_facture($socid);
4256 $this->stats_facture[
'customers'] += $pFather->stats_facture[
'customers'];
4257 $this->stats_facture[
'nb'] += $pFather->stats_facture[
'nb'];
4258 $this->stats_facture[
'rows'] += $pFather->stats_facture[
'rows'];
4259 $this->stats_facture[
'qty'] += $pFather->stats_facture[
'qty'] * $qtyCoef;
4265 $parameters = array(
'socid' => $socid);
4266 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoice', $parameters, $this, $action);
4268 $this->stats_facture = $hookmanager->resArray[
'stats_facture'];
4273 $this->error = $this->db->error();
4289 global $user, $hookmanager, $action;
4291 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4292 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4293 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facturedet_rec as fd";
4294 $sql .=
", ".MAIN_DB_PREFIX.
"facture_rec as f";
4295 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
4296 $sql .=
" WHERE f.rowid = fd.fk_facture";
4297 $sql .=
" AND f.fk_soc = s.rowid";
4298 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4299 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4300 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4301 $sql .=
" AND EXISTS (SELECT 1 FROM ".$this->db->prefix().
"societe_commerciaux as sc WHERE sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id).
")";
4305 $sql .=
" AND f.fk_soc = ".((int) $socid);
4308 $result = $this->db->query($sql);
4310 $obj = $this->db->fetch_object($result);
4311 $this->stats_facturerec[
'customers'] = (int) $obj->nb_customers;
4312 $this->stats_facturerec[
'nb'] = (int) $obj->nb;
4313 $this->stats_facturerec[
'rows'] = (int) $obj->nb_rows;
4314 $this->stats_facturerec[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4319 if (is_array($TFather) && !empty($TFather)) {
4320 foreach ($TFather as &$fatherData) {
4321 $pFather =
new Product($this->db);
4322 $pFather->id = $fatherData[
'id'];
4323 $qtyCoef = $fatherData[
'qty'];
4325 if ($fatherData[
'incdec']) {
4326 $pFather->load_stats_facture($socid);
4328 $this->stats_facturerec[
'customers'] += $pFather->stats_facturerec[
'customers'];
4329 $this->stats_facturerec[
'nb'] += $pFather->stats_facturerec[
'nb'];
4330 $this->stats_facturerec[
'rows'] += $pFather->stats_facturerec[
'rows'];
4331 $this->stats_facturerec[
'qty'] += $pFather->stats_facturerec[
'qty'] * $qtyCoef;
4337 $parameters = array(
'socid' => $socid);
4338 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoiceRec', $parameters, $this, $action);
4340 $this->stats_facturerec = $hookmanager->resArray[
'stats_facturerec'];
4345 $this->error = $this->db->error();
4360 global $user, $hookmanager, $action;
4362 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
4363 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4364 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as fd";
4365 $sql .=
", ".$this->db->prefix().
"facture_fourn as f";
4366 $sql .=
", ".$this->db->prefix().
"societe as s";
4367 $sql .=
" WHERE f.rowid = fd.fk_facture_fourn";
4368 $sql .=
" AND f.fk_soc = s.rowid";
4369 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4370 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4371 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4372 $sql .=
" AND EXISTS (SELECT 1 FROM ".$this->db->prefix().
"societe_commerciaux as sc WHERE sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id).
")";
4376 $sql .=
" AND f.fk_soc = ".((int) $socid);
4379 $result = $this->db->query($sql);
4381 $obj = $this->db->fetch_object($result);
4382 $this->stats_facture_fournisseur[
'suppliers'] = (int) $obj->nb_suppliers;
4383 $this->stats_facture_fournisseur[
'nb'] = (int) $obj->nb;
4384 $this->stats_facture_fournisseur[
'rows'] = (int) $obj->nb_rows;
4385 $this->stats_facture_fournisseur[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4387 $parameters = array(
'socid' => $socid);
4388 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoice', $parameters, $this, $action);
4390 $this->stats_facture_fournisseur = $hookmanager->resArray[
'stats_facture_fournisseur'];
4395 $this->error = $this->db->error();
4410 global $user, $hookmanager, $action;
4412 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
4413 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4414 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facture_fourn_det_rec as fd";
4415 $sql .=
", ".MAIN_DB_PREFIX.
"facture_fourn_rec as f";
4416 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
4417 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4418 $sql .=
", ".MAIN_DB_PREFIX.
"societe_commerciaux as sc";
4420 $sql .=
" WHERE f.rowid = fd.fk_facture";
4421 $sql .=
" AND f.fk_soc = s.rowid";
4422 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4423 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4424 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4425 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4429 $sql .=
" AND f.fk_soc = ".((int) $socid);
4432 $result = $this->db->query($sql);
4434 $obj = $this->db->fetch_object($result);
4435 $this->stats_facturefournrec[
'suppliers'] = (int) $obj->nb_suppliers;
4436 $this->stats_facturefournrec[
'nb'] = (int) $obj->nb;
4437 $this->stats_facturefournrec[
'rows'] = (int) $obj->nb_rows;
4438 $this->stats_facturefournrec[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4440 $parameters = array(
'socid' => $socid);
4441 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoiceRec', $parameters, $this, $action);
4443 $this->stats_facturefournrec = $hookmanager->resArray[
'stats_facturefournrec'];
4448 $this->error = $this->db->error();
4467 $resql = $this->db->query($sql);
4469 $num = $this->db->num_rows($resql);
4472 $arr = $this->db->fetch_array($resql);
4473 if (is_array($arr)) {
4474 $keyfortab = (string) $arr[1];
4476 $keyfortab = substr($keyfortab, -2);
4479 if ($mode ==
'byunit') {
4480 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[0];
4481 } elseif ($mode ==
'bynumber') {
4482 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4483 } elseif ($mode ==
'byamount') {
4484 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4493 $this->error = $this->db->error().
' sql='.$sql;
4500 } elseif ($year == -1) {
4509 for ($j = 0; $j < 12; $j++) {
4511 $idx = ucfirst(
dol_trunc(
dol_print_date(
dol_mktime(12, 0, 0, $month, 1, 1970),
"%b"), 1,
'right',
'UTF-8', 1));
4514 $result[$j] = array($idx, isset($tab[$year.$month]) ? $tab[$year.$month] : 0);
4517 $month =
"0".($month - 1);
4519 $month = substr($month, 1);
4529 return array_reverse($result);
4544 public function get_nb_vente($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4549 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4550 if ($mode ==
'bynumber') {
4551 $sql .=
", count(DISTINCT f.rowid)";
4553 $sql .=
", sum(d.total_ht) as total_ht";
4554 $sql .=
" FROM ".$this->db->prefix().
"facturedet as d, ".$this->db->prefix().
"facture as f, ".$this->db->prefix().
"societe as s";
4555 if ($filteronproducttype >= 0) {
4556 $sql .=
", ".$this->db->prefix().
"product as p";
4558 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4559 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4561 $sql .=
" WHERE f.rowid = d.fk_facture";
4562 if ($this->
id > 0) {
4563 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4565 $sql .=
" AND d.fk_product > 0";
4567 if ($filteronproducttype >= 0) {
4568 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4570 $sql .=
" AND f.fk_soc = s.rowid";
4571 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4572 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4573 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4576 $sql .=
" AND f.fk_soc = $socid";
4578 $sql .= $morefilter;
4579 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4580 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4582 return $this->
_get_stats($sql, $mode, $year);
4597 public function get_nb_achat($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4602 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4603 if ($mode ==
'bynumber') {
4604 $sql .=
", count(DISTINCT f.rowid)";
4606 $sql .=
", sum(d.total_ht) as total_ht";
4607 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as d, ".$this->db->prefix().
"facture_fourn as f, ".$this->db->prefix().
"societe as s";
4608 if ($filteronproducttype >= 0) {
4609 $sql .=
", ".$this->db->prefix().
"product as p";
4611 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4612 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4614 $sql .=
" WHERE f.rowid = d.fk_facture_fourn";
4615 if ($this->
id > 0) {
4616 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4618 $sql .=
" AND d.fk_product > 0";
4620 if ($filteronproducttype >= 0) {
4621 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4623 $sql .=
" AND f.fk_soc = s.rowid";
4624 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4625 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4626 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4629 $sql .=
" AND f.fk_soc = $socid";
4631 $sql .= $morefilter;
4632 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4633 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4635 return $this->
_get_stats($sql, $mode, $year);
4649 public function get_nb_propal($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4652 global $user, $hookmanager;
4654 $sql =
"SELECT sum(d.qty) as qty, date_format(p.datep, '%Y%m')";
4655 if ($mode ==
'bynumber') {
4656 $sql .=
", count(DISTINCT p.rowid)";
4658 $sql .=
", sum(d.total_ht) as total_ht";
4659 $sql .=
" FROM ".$this->db->prefix().
"propaldet as d, ".$this->db->prefix().
"propal as p, ".$this->db->prefix().
"societe as s";
4660 if ($filteronproducttype >= 0) {
4661 $sql .=
", ".$this->db->prefix().
"product as prod";
4663 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4664 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4666 $sql .=
" WHERE p.rowid = d.fk_propal";
4667 if ($this->
id > 0) {
4668 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4670 $sql .=
" AND d.fk_product > 0";
4672 if ($filteronproducttype >= 0) {
4673 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4675 $sql .=
" AND p.fk_soc = s.rowid";
4676 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
4677 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4678 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4681 $sql .=
" AND p.fk_soc = ".((int) $socid);
4683 $sql .= $morefilter;
4684 $parameters = array(
'socid' => $user->socid);
4685 $hookmanager->executeHooks(
'productGetNbPropal', $parameters, $this);
4686 $sql .= $hookmanager->resPrint;
4687 $sql .=
" GROUP BY date_format(p.datep,'%Y%m')";
4688 $sql .=
" ORDER BY date_format(p.datep,'%Y%m') DESC";
4689 return $this->
_get_stats($sql, $mode, $year);
4708 $sql =
"SELECT sum(d.qty) as qty, date_format(p.date_valid, '%Y%m')";
4709 if ($mode ==
'bynumber') {
4710 $sql .=
", count(DISTINCT p.rowid)";
4712 $sql .=
", sum(d.total_ht) as total_ht";
4713 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as d, ".$this->db->prefix().
"supplier_proposal as p, ".$this->db->prefix().
"societe as s";
4714 if ($filteronproducttype >= 0) {
4715 $sql .=
", ".$this->db->prefix().
"product as prod";
4717 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4718 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4720 $sql .=
" WHERE p.rowid = d.fk_supplier_proposal";
4721 if ($this->
id > 0) {
4722 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4724 $sql .=
" AND d.fk_product > 0";
4726 if ($filteronproducttype >= 0) {
4727 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4729 $sql .=
" AND p.fk_soc = s.rowid";
4730 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
4731 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4732 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4735 $sql .=
" AND p.fk_soc = ".((int) $socid);
4737 $sql .= $morefilter;
4738 $sql .=
" GROUP BY date_format(p.date_valid,'%Y%m')";
4739 $sql .=
" ORDER BY date_format(p.date_valid,'%Y%m') DESC";
4741 return $this->
_get_stats($sql, $mode, $year);
4755 public function get_nb_order($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4758 global $user, $hookmanager;
4760 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4761 if ($mode ==
'bynumber') {
4762 $sql .=
", count(DISTINCT c.rowid)";
4764 $sql .=
", sum(d.total_ht) as total_ht";
4765 $sql .=
" FROM ".$this->db->prefix().
"commandedet as d, ".$this->db->prefix().
"commande as c, ".$this->db->prefix().
"societe as s";
4766 if ($filteronproducttype >= 0) {
4767 $sql .=
", ".$this->db->prefix().
"product as p";
4769 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4770 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4772 $sql .=
" WHERE c.rowid = d.fk_commande";
4773 if ($this->
id > 0) {
4774 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4776 $sql .=
" AND d.fk_product > 0";
4778 if ($filteronproducttype >= 0) {
4779 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4781 $sql .=
" AND c.fk_soc = s.rowid";
4782 $sql .=
" AND c.entity IN (".getEntity(
'commande').
")";
4783 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4784 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4787 $sql .=
" AND c.fk_soc = ".((int) $socid);
4789 $sql .= $morefilter;
4790 $parameters = array(
'socid' => $user->socid);
4791 $hookmanager->executeHooks(
'productGetNbOrder', $parameters, $this);
4792 $sql .= $hookmanager->resPrint;
4793 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4794 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4796 return $this->
_get_stats($sql, $mode, $year);
4815 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4816 if ($mode ==
'bynumber') {
4817 $sql .=
", count(DISTINCT c.rowid)";
4819 $sql .=
", sum(d.total_ht) as total_ht";
4820 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as d, ".$this->db->prefix().
"commande_fournisseur as c, ".$this->db->prefix().
"societe as s";
4821 if ($filteronproducttype >= 0) {
4822 $sql .=
", ".$this->db->prefix().
"product as p";
4824 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4825 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4827 $sql .=
" WHERE c.rowid = d.fk_commande";
4828 if ($this->
id > 0) {
4829 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4831 $sql .=
" AND d.fk_product > 0";
4833 if ($filteronproducttype >= 0) {
4834 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4836 $sql .=
" AND c.fk_soc = s.rowid";
4837 $sql .=
" AND c.entity IN (".getEntity(
'supplier_order').
")";
4838 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4839 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4842 $sql .=
" AND c.fk_soc = ".((int) $socid);
4844 $sql .= $morefilter;
4845 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4846 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4848 return $this->
_get_stats($sql, $mode, $year);
4862 public function get_nb_contract($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4867 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_contrat, '%Y%m')";
4868 if ($mode ==
'bynumber') {
4869 $sql .=
", count(DISTINCT c.rowid)";
4871 $sql .=
", sum(d.total_ht) as total_ht";
4872 $sql .=
" FROM ".$this->db->prefix().
"contratdet as d, ".$this->db->prefix().
"contrat as c, ".$this->db->prefix().
"societe as s";
4873 if ($filteronproducttype >= 0) {
4874 $sql .=
", ".$this->db->prefix().
"product as p";
4876 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4877 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4879 $sql .=
" WHERE c.entity IN (".getEntity(
'contract').
")";
4880 $sql .=
" AND c.rowid = d.fk_contrat";
4882 if ($this->
id > 0) {
4883 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4885 $sql .=
" AND d.fk_product > 0";
4887 if ($filteronproducttype >= 0) {
4888 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4890 $sql .=
" AND c.fk_soc = s.rowid";
4892 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4893 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4896 $sql .=
" AND c.fk_soc = ".((int) $socid);
4898 $sql .= $morefilter;
4899 $sql .=
" GROUP BY date_format(c.date_contrat,'%Y%m')";
4900 $sql .=
" ORDER BY date_format(c.date_contrat,'%Y%m') DESC";
4902 return $this->
_get_stats($sql, $mode, $year);
4916 public function get_nb_mos($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4921 $sql =
"SELECT sum(d.qty), date_format(d.date_valid, '%Y%m')";
4922 if ($mode ==
'bynumber') {
4923 $sql .=
", count(DISTINCT d.rowid)";
4925 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as d LEFT JOIN ".$this->db->prefix().
"societe as s ON d.fk_soc = s.rowid";
4926 if ($filteronproducttype >= 0) {
4927 $sql .=
", ".$this->db->prefix().
"product as p";
4929 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4930 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4933 $sql .=
" WHERE d.entity IN (".getEntity(
'mo').
")";
4934 $sql .=
" AND d.status > 0";
4936 if ($this->
id > 0) {
4937 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4939 $sql .=
" AND d.fk_product > 0";
4941 if ($filteronproducttype >= 0) {
4942 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4945 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4946 $sql .=
" AND d.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4949 $sql .=
" AND d.fk_soc = ".((int) $socid);
4951 $sql .= $morefilter;
4952 $sql .=
" GROUP BY date_format(d.date_valid,'%Y%m')";
4953 $sql .=
" ORDER BY date_format(d.date_valid,'%Y%m') DESC";
4955 return $this->
_get_stats($sql, $mode, $year);
4975 if (!is_numeric($id_pere)) {
4978 if (!is_numeric($id_fils)) {
4981 if (!is_numeric($incdec)) {
4991 $sql =
"SELECT fk_product_pere from ".$this->db->prefix().
"product_association";
4992 $sql .=
" WHERE fk_product_pere = ".((int) $id_fils).
" AND fk_product_fils = ".((int) $id_pere);
4993 if (!$this->db->query($sql)) {
4998 $sql =
"SELECT MAX(rang) as max_rank FROM ".$this->db->prefix().
"product_association";
4999 $sql .=
" WHERE fk_product_pere = ".((int) $id_pere);
5000 $resql = $this->db->query($sql);
5002 $obj = $this->db->fetch_object($resql);
5003 $rank = $obj->max_rank + 1;
5005 $sql =
"INSERT INTO ".$this->db->prefix().
"product_association(fk_product_pere,fk_product_fils,qty,incdec,rang)";
5006 $sql .=
" VALUES (".((int) $id_pere).
", ".((int) $id_fils).
", ".
price2num($qty,
'MS').
", ".((int) $incdec).
", ".((int) $rank).
")";
5007 if (! $this->db->query($sql)) {
5013 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_ADD', $user);
5015 $this->error = $this->db->lasterror();
5016 dol_syslog(get_class($this).
'::addSubproduct error='.$this->error, LOG_ERR);
5048 if (!is_numeric($id_pere)) {
5051 if (!is_numeric($id_fils)) {
5054 if (!is_numeric($incdec)) {
5057 if (!is_numeric($qty)) {
5061 $sql =
'UPDATE '.$this->db->prefix().
'product_association SET ';
5062 $sql .=
'qty = '.price2num($qty,
'MS');
5063 $sql .=
',incdec = '.((int) $incdec);
5064 $sql .=
' WHERE fk_product_pere = '.((int) $id_pere).
' AND fk_product_fils = '.((int) $id_fils);
5066 if (!$this->db->query($sql)) {
5072 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_UPDATE', $user);
5074 $this->error = $this->db->lasterror();
5075 dol_syslog(get_class($this).
'::updateSubproduct error='.$this->error, LOG_ERR);
5099 if (!is_numeric($fk_parent)) {
5102 if (!is_numeric($fk_child)) {
5106 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
5107 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5108 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
5110 dol_syslog(get_class($this).
'::del_sousproduit', LOG_DEBUG);
5111 if (!$this->db->query($sql)) {
5117 $sqlrank =
"SELECT rowid, rang FROM ".$this->db->prefix().
"product_association";
5118 $sqlrank .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5119 $sqlrank .=
" ORDER BY rang";
5120 $resqlrank = $this->db->query($sqlrank);
5123 while ($objrank = $this->db->fetch_object($resqlrank)) {
5125 $sql =
"UPDATE ".$this->db->prefix().
"product_association";
5126 $sql .=
" SET rang = ".((int) $cpt);
5127 $sql .=
" WHERE rowid = ".((int) $objrank->rowid);
5128 if (! $this->db->query($sql)) {
5137 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_DELETE', $user);
5139 $this->error = $this->db->lasterror();
5140 dol_syslog(get_class($this).
'::delSubproduct error='.$this->error, LOG_ERR);
5160 $sql =
"SELECT fk_product_pere, qty, incdec";
5161 $sql .=
" FROM ".$this->db->prefix().
"product_association";
5162 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5163 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
5165 $result = $this->db->query($sql);
5167 $num = $this->db->num_rows($result);
5170 $obj = $this->db->fetch_object($result);
5172 $this->is_sousproduit_qty = $obj->qty;
5173 $this->is_sousproduit_incdec = $obj->incdec;
5204 dol_syslog(get_class($this).
"::add_fournisseur id_fourn = ".$id_fourn.
" ref_fourn=".$ref_fourn.
" quantity=".$quantity, LOG_DEBUG);
5211 $sql =
"SELECT rowid, fk_product";
5212 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5213 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5214 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5215 $sql .=
" AND fk_product <> ".((int) $this->
id);
5216 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5218 $resql = $this->db->query($sql);
5220 $obj = $this->db->fetch_object($resql);
5223 $this->product_id_already_linked = $obj->fk_product;
5226 $this->db->free($resql);
5230 $sql =
"SELECT rowid";
5231 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5232 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5234 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5236 $sql .=
" AND (ref_fourn = '' OR ref_fourn IS NULL)";
5238 $sql .=
" AND quantity = ".((float) $quantity);
5239 $sql .=
" AND fk_product = ".((int) $this->
id);
5240 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5242 $resql = $this->db->query($sql);
5244 $obj = $this->db->fetch_object($resql);
5248 $sql =
"INSERT INTO ".$this->db->prefix().
"product_fournisseur_price(";
5251 $sql .=
", fk_product";
5253 $sql .=
", ref_fourn";
5254 $sql .=
", quantity";
5255 $sql .=
", fk_user";
5257 $sql .=
") VALUES (";
5258 $sql .=
"'".$this->db->idate($now).
"'";
5259 $sql .=
", ".((int) $conf->entity);
5260 $sql .=
", ".((int) $this->
id);
5261 $sql .=
", ".((int) $id_fourn);
5262 $sql .=
", '".$this->db->escape($ref_fourn).
"'";
5263 $sql .=
", ".((float) $quantity);
5264 $sql .=
", ".((int) $user->id);
5268 if ($this->db->query($sql)) {
5269 $this->product_fourn_price_id = $this->db->last_insert_id($this->db->prefix().
"product_fournisseur_price");
5272 $this->error = $this->db->lasterror();
5277 $this->product_fourn_price_id = $obj->rowid;
5281 $this->error = $this->db->lasterror();
5300 $sql =
"SELECT DISTINCT p.fk_soc";
5301 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as p";
5302 $sql .=
" WHERE p.fk_product = ".((int) $this->
id);
5303 $sql .=
" AND p.entity = ".((int) $conf->entity);
5305 $result = $this->db->query($sql);
5307 $num = $this->db->num_rows($result);
5310 $obj = $this->db->fetch_object($result);
5311 $list[$i] = $obj->fk_soc;
5337 $sql =
"INSERT INTO ".$this->db->prefix().
"product_price (";
5339 $sql .=
", fk_product";
5340 $sql .=
", date_price";
5341 $sql .=
", price_level";
5343 $sql .=
", price_ttc";
5344 $sql .=
", price_min";
5345 $sql .=
", price_min_ttc";
5346 $sql .=
", price_base_type";
5347 $sql .=
", price_label";
5348 $sql .=
", default_vat_code";
5350 $sql .=
", recuperableonly";
5351 $sql .=
", localtax1_tx";
5352 $sql .=
", localtax1_type";
5353 $sql .=
", localtax2_tx";
5354 $sql .=
", localtax2_type";
5355 $sql .=
", fk_user_author";
5357 $sql .=
", price_by_qty";
5358 $sql .=
", fk_price_expression";
5359 $sql .=
", fk_multicurrency";
5360 $sql .=
", multicurrency_code";
5361 $sql .=
", multicurrency_tx";
5362 $sql .=
", multicurrency_price";
5363 $sql .=
", multicurrency_price_ttc";
5367 $sql .=
", ".((int) $toId);
5368 $sql .=
", '".$this->db->idate($now).
"'";
5369 $sql .=
", price_level";
5371 $sql .=
", price_ttc";
5372 $sql .=
", price_min";
5373 $sql .=
", price_min_ttc";
5374 $sql .=
", price_base_type";
5375 $sql .=
", price_label";
5376 $sql .=
", default_vat_code";
5378 $sql .=
", recuperableonly";
5379 $sql .=
", localtax1_tx";
5380 $sql .=
", localtax1_type";
5381 $sql .=
", localtax2_tx";
5382 $sql .=
", localtax2_type";
5383 $sql .=
", ".((int) $user->id);
5385 $sql .=
", price_by_qty";
5386 $sql .=
", fk_price_expression";
5387 $sql .=
", fk_multicurrency";
5388 $sql .=
", multicurrency_code";
5389 $sql .=
", multicurrency_tx";
5390 $sql .=
", multicurrency_price";
5391 $sql .=
", multicurrency_price_ttc";
5392 $sql .=
" FROM ".$this->db->prefix().
"product_price ps";
5393 $sql .=
" WHERE fk_product = ".((int) $fromId);
5394 $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)";
5395 $sql .=
" ORDER BY date_price DESC";
5398 $resql = $this->db->query($sql);
5400 $this->db->rollback();
5404 $this->db->commit();
5421 $sql =
'INSERT INTO '.$this->db->prefix().
'product_association (fk_product_pere, fk_product_fils, qty, incdec)';
5422 $sql .=
" SELECT ".((int) $toId).
", fk_product_fils, qty, incdec FROM ".$this->db->prefix().
"product_association";
5423 $sql .=
" WHERE fk_product_pere = ".((int) $fromId);
5425 dol_syslog(get_class($this).
'::clone_association', LOG_DEBUG);
5426 if (!$this->db->query($sql)) {
5427 $this->db->rollback();
5431 $this->db->commit();
5464 $sql =
"INSERT ".$this->db->prefix().
"product_fournisseur_price (";
5465 $sql .=
" datec, fk_product, fk_soc, price, quantity, fk_user, tva_tx)";
5466 $sql .=
" SELECT '".$this->db->idate($now).
"', ".((int) $toId).
", fk_soc, price, quantity, fk_user, tva_tx";
5467 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5468 $sql .=
" WHERE fk_product = ".((int) $fromId);
5470 dol_syslog(get_class($this).
'::clone_fournisseurs', LOG_DEBUG);
5471 $resql = $this->db->query($sql);
5473 $this->db->rollback();
5476 $this->db->commit();
5494 public function fetch_prod_arbo($prod, $compl_path =
'', $multiply = 1, $level = 1, $id_parent = 0, $ignore_stock_load = 0)
5499 if ($multiply < 1) {
5500 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);
5505 foreach ($prod as $id_product => $desc_pere) {
5506 if (is_array($desc_pere)) {
5507 $id = (!empty($desc_pere[0]) ? $desc_pere[0] :
'');
5508 $nb = (!empty($desc_pere[1]) ? $desc_pere[1] :
'');
5509 $type = (!empty($desc_pere[2]) ? $desc_pere[2] :
'');
5510 $label = (!empty($desc_pere[3]) ? $desc_pere[3] :
'');
5511 $incdec = (!empty($desc_pere[4]) ? $desc_pere[4] : 0);
5514 if (is_null($tmpproduct)) {
5515 $tmpproduct =
new Product($this->db);
5517 $tmpproduct->fetch($id);
5519 if (empty($ignore_stock_load) && ($tmpproduct->isProduct() ||
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES'))) {
5520 $tmpproduct->load_stock(
'nobatch,novirtual');
5523 $this->res[] = array(
5525 'id_parent' => $id_parent,
5526 'ref' => $tmpproduct->ref,
5528 'nb_total' => $nb * $multiply,
5529 'stock' => $tmpproduct->stock_reel,
5530 'stock_alert' => $tmpproduct->seuil_stock_alerte,
5532 'fullpath' => $compl_path.$label,
5534 'desiredstock' => $tmpproduct->desiredstock,
5536 'incdec' => $incdec,
5537 'entity' => $tmpproduct->entity
5541 if (isset($desc_pere[
'childs']) && is_array($desc_pere[
'childs'])) {
5542 if (!is_int($desc_pere[1] * $multiply)) {
5543 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);
5547 $this->
fetch_prod_arbo($desc_pere[
'childs'], $compl_path.$desc_pere[3].
" -> ", (
int) ceil($desc_pere[1] * $multiply), $level + 1, $id, $ignore_stock_load);
5565 $this->res = array();
5566 if (isset($this->sousprods) && is_array($this->sousprods)) {
5567 foreach ($this->sousprods as $prod_name => $desc_product) {
5568 if (is_array($desc_product)) {
5569 $this->
fetch_prod_arbo($desc_product,
"", $multiply, 1, $this->
id, $ignore_stock_load);
5588 $sql =
"SELECT COUNT(pa.rowid) as nb";
5589 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa";
5591 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id).
" OR pa.fk_product_pere = ".((int) $this->
id);
5592 } elseif ($mode == -1) {
5593 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id);
5594 } elseif ($mode == 1) {
5595 $sql .=
" WHERE pa.fk_product_pere = ".((int) $this->
id);
5598 $resql = $this->db->query($sql);
5600 $obj = $this->db->fetch_object($resql);
5602 $nb = (int) $obj->nb;
5622 $sql =
"SELECT count(rowid) as nb FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_parent = ".((int) $this->
id);
5623 $sql .=
" AND entity IN (".getEntity(
'product').
")";
5625 $resql = $this->db->query($sql);
5627 $obj = $this->db->fetch_object($resql);
5629 $nb = (int) $obj->nb;
5645 $sql =
"SELECT rowid FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_child = ".((int) $this->
id).
" AND entity IN (".
getEntity(
'product').
")";
5647 $query = $this->db->query($sql);
5650 if (!$this->db->num_rows($query)) {
5671 $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";
5672 $sql .=
", p.tosell as status, p.tobuy as status_buy";
5673 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa,";
5674 $sql .=
" ".$this->db->prefix().
"product as p";
5675 $sql .=
" WHERE p.rowid = pa.fk_product_pere";
5676 $sql .=
" AND pa.fk_product_fils = ".((int) $this->
id);
5678 $res = $this->db->query($sql);
5681 while ($record = $this->db->fetch_array($res)) {
5683 $prods[$record[
'id']] = array();
5684 $prods[$record[
'id']][
'id'] = $record[
'rowid'];
5685 $prods[$record[
'id']][
'ref'] = $record[
'ref'];
5686 $prods[$record[
'id']][
'label'] = $record[
'label'];
5687 $prods[$record[
'id']][
'qty'] = $record[
'qty'];
5688 $prods[$record[
'id']][
'incdec'] = $record[
'incdec'];
5689 $prods[$record[
'id']][
'fk_product_type'] = $record[
'fk_product_type'];
5690 $prods[$record[
'id']][
'entity'] = $record[
'entity'];
5691 $prods[$record[
'id']][
'status'] = $record[
'status'];
5692 $prods[$record[
'id']][
'status_buy'] = $record[
'status_buy'];
5711 public function getChildsArbo($id, $firstlevelonly = 0, $level = 1, $parents = array())
5717 $sql =
"SELECT p.rowid, p.ref, p.label as label, p.fk_product_type,";
5718 $sql .=
" pa.qty as qty, pa.fk_product_fils as id, pa.incdec,";
5719 $sql .=
" pa.rowid as fk_association, pa.rang";
5720 $sql .=
" FROM ".$this->db->prefix().
"product as p,";
5721 $sql .=
" ".$this->db->prefix().
"product_association as pa";
5722 $sql .=
" WHERE p.rowid = pa.fk_product_fils";
5723 $sql .=
" AND pa.fk_product_pere = ".((int) $id);
5724 $sql .=
" AND pa.fk_product_fils <> ".((int) $id);
5725 $sql .=
" ORDER BY pa.rang";
5727 dol_syslog(get_class($this).
'::getChildsArbo id='.$id.
' level='.$level.
' parents='.(is_array($parents) ? implode(
',', $parents) : $parents), LOG_DEBUG);
5734 $res = $this->db->query($sql);
5737 if ($this->db->num_rows($res) > 0) {
5741 while ($rec = $this->db->fetch_array($res)) {
5742 if (in_array($rec[
'id'], $parents)) {
5743 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);
5747 $prods[$rec[
'rowid']] = array(
5750 2 => $rec[
'fk_product_type'],
5751 3 => $this->db->escape($rec[
'label']),
5752 4 => $rec[
'incdec'],
5754 6 => $rec[
'fk_association'],
5759 if (empty($firstlevelonly)) {
5760 $listofchilds = $this->
getChildsArbo($rec[
'rowid'], 0, $level + 1, $parents);
5761 foreach ($listofchilds as $keyChild => $valueChild) {
5762 $prods[$rec[
'rowid']][
'childs'][$keyChild] = $valueChild;
5786 foreach ($this->
getChildsArbo($this->
id) as $keyChild => $valueChild) {
5787 $parent[$this->label][$keyChild] = $valueChild;
5789 foreach ($parent as $key => $value) {
5790 $this->sousprods[$key] = $value;
5803 global $conf, $langs, $user;
5805 $langs->loadLangs(array(
'products',
'other'));
5808 $nofetch = !empty($params[
'nofetch']);
5811 return [
'optimize' => $langs->trans(
"ShowProduct")];
5815 $permissiontoreadproduct = 0;
5816 if ($this->
type == self::TYPE_PRODUCT && $user->hasRight(
'product',
'read')) {
5817 $permissiontoreadproduct = 1;
5819 if ($this->
type == self::TYPE_SERVICE && $user->hasRight(
'service',
'read')) {
5820 $permissiontoreadproduct = 1;
5823 if (!empty($this->entity) && $permissiontoreadproduct) {
5824 $tmpphoto = $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 80, 0, 0, 0, 0,
'1');
5825 if ($this->nbphoto > 0) {
5826 $datas[
'photo'] =
'<div class="photointooltip floatright">'.
"\n" . $tmpphoto .
'</div>';
5831 $datas[
'picto'] =
img_picto(
'',
'product').
' <u class="paddingrightonly">'.$langs->trans(
"Product").
'</u>';
5833 $datas[
'picto'] =
img_picto(
'',
'service').
' <u class="paddingrightonly">'.$langs->trans(
"Service").
'</u>';
5835 if (isset($this->
status) && isset($this->status_buy)) {
5836 $datas[
'status'] =
' '.$this->getLibStatut(5, 0) .
' '.$this->getLibStatut(5, 1);
5839 if (!empty($this->
ref)) {
5840 $datas[
'ref'] =
'<br><b>'.$langs->trans(
'ProductRef').
':</b> '.$this->ref;
5842 if (!empty($this->label)) {
5843 $datas[
'label'] =
'<br><b>'.$langs->trans(
'ProductLabel').
':</b> '.$this->label.
'<br>';
5846 if ($permissiontoreadproduct) {
5851 $datas[
'stockmanaged'] =
"<br><b>".$langs->trans(
"StockableProduct").
'</b>: '.
yn($this->
isStockManaged());
5855 $langs->load(
"productbatch");
5856 $datas[
'batchstatus'] =
"<br><b>".$langs->trans(
"ManageLotSerial").
'</b>: '.$this->
getLibStatut(0, 2);
5857 if ($this->status_batch) {
5858 $datas[
'batchdlc'] =
"<br><b>".$langs->trans(
"BatchSellOrEatByMandatoryList", $langs->transnoentitiesnoconv(
"SellByDate"), $langs->transnoentitiesnoconv(
"EatByDate")).
'</b>: '.$this->
getSellOrEatByMandatoryLabel();
5863 $datas[
'barcode'] =
'<br><b>'.$langs->trans(
'BarCode').
':</b> '.$this->barcode;
5867 if ($this->weight) {
5868 $datas[
'weight'] =
"<br><b>".$langs->trans(
"Weight").
'</b>: '.$this->weight.
' '.
measuringUnitString(0,
"weight", $this->weight_units);
5871 if ($this->length) {
5872 $labelsize .=
"<b>".$langs->trans(
"Length").
'</b>: '.$this->length.
' '.
measuringUnitString(0,
'size', $this->length_units);
5875 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Width").
'</b>: '.$this->width.
' '.
measuringUnitString(0,
'size', $this->width_units);
5877 if ($this->height) {
5878 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Height").
'</b>: '.$this->height.
' '.
measuringUnitString(0,
'size', $this->height_units);
5881 $datas[
'size'] =
"<br>".$labelsize;
5884 $labelsurfacevolume =
"";
5885 if ($this->surface) {
5886 $labelsurfacevolume .=
"<b>".$langs->trans(
"Surface").
'</b>: '.$this->surface.
' '.
measuringUnitString(0,
'surface', $this->surface_units);
5888 if ($this->volume) {
5889 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Volume").
'</b>: '.$this->volume.
' '.
measuringUnitString(0,
'volume', $this->volume_units);
5891 if ($labelsurfacevolume) {
5892 $datas[
'surface'] =
"<br>" . $labelsurfacevolume;
5895 if ($this->
isService() && !empty($this->duration_value)) {
5897 $datas[
'duration'] =
'<br><b>'.$langs->trans(
"Duration").
':</b> '.$this->duration_value;
5898 if ($this->duration_value > 1) {
5899 $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"));
5900 } elseif ($this->duration_value > 0) {
5901 $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"));
5903 $datas[
'duration'] .= (!empty($this->duration_unit) && isset($dur[$this->duration_unit]) ?
" ".$langs->trans($dur[$this->duration_unit]) :
'');
5905 if (empty($user->socid)) {
5906 if ($this->
isStockManaged() && isset($this->pmp) && $this->pmp) {
5907 $datas[
'pmp'] =
"<br><b>".$langs->trans(
"PMPValue").
'</b>: '.
price($this->pmp, 0,
'', 1, -1, -1, $conf->currency);
5911 if ($this->
status && isset($this->accountancy_code_sell)) {
5912 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5913 $selllabel =
'<br>';
5914 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellCode').
':</b> '.
length_accountg($this->accountancy_code_sell);
5915 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellIntraCode').
':</b> '.
length_accountg($this->accountancy_code_sell_intra);
5916 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellExportCode').
':</b> '.
length_accountg($this->accountancy_code_sell_export);
5917 $datas[
'accountancysell'] = $selllabel;
5919 if ($this->status_buy && isset($this->accountancy_code_buy)) {
5920 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5922 if (empty($this->
status)) {
5923 $buylabel .=
'<br>';
5925 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyCode').
':</b> '.
length_accountg($this->accountancy_code_buy);
5926 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyIntraCode').
':</b> '.
length_accountg($this->accountancy_code_buy_intra);
5927 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyExportCode').
':</b> '.
length_accountg($this->accountancy_code_buy_export);
5928 $datas[
'accountancybuy'] = $buylabel;
5934 require_once DOL_DOCUMENT_ROOT .
'/categories/class/categorie.class.php';
5935 $form =
new Form($this->db);
5936 $datas[
'categories'] =
'<br>' . $form->showCategories($this->
id, Categorie::TYPE_PRODUCT, 1);
5956 public function getNomUrl($withpicto = 0, $option =
'', $maxlength = 0, $save_lastsearch_value = -1, $notooltip = 0, $morecss =
'', $add_label = 0, $sep =
' - ')
5958 global $langs, $hookmanager;
5960 include_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
5964 $newref = (string) $this->
ref;
5966 $newref =
dol_trunc($newref, $maxlength,
'middle');
5970 'objecttype' => ($this->
type == 1 ?
'service' :
'product'),
5971 'option' => $option,
5974 $classfortooltip =
'classfortooltip';
5977 $classfortooltip =
'classforajaxtooltip';
5978 $dataparams =
' data-params="'.dol_escape_htmltag(json_encode($params)).
'"';
5985 if (empty($notooltip)) {
5987 $label = $langs->trans(
"ShowProduct");
5988 $linkclose .=
' alt="'.dol_escape_htmltag($label, 1, 1).
'"';
5990 $linkclose .= ($label ?
' title="'.dol_escape_htmltag($label, 1, 1).
'"' :
' title="tocomplete"');
5991 $linkclose .= $dataparams.
' class="nowraponall '.$classfortooltip.($morecss ?
' '.$morecss :
'').
'"';
5993 $linkclose =
' class="nowraponall'.($morecss ?
' '.$morecss :
'').
'"';
5996 if ($option ==
'supplier' || $option ==
'category') {
5997 $url = DOL_URL_ROOT.
'/product/price_suppliers.php?id='.$this->id;
5998 } elseif ($option ==
'stock') {
5999 $url = DOL_URL_ROOT.
'/product/stock/product.php?id='.$this->id;
6000 } elseif ($option ==
'composition') {
6001 $url = DOL_URL_ROOT.
'/product/composition/card.php?id='.$this->id;
6003 $url = DOL_URL_ROOT.
'/product/card.php?id='.$this->id;
6006 if ($option !==
'nolink') {
6008 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
6009 if ($save_lastsearch_value == -1 && isset($_SERVER[
"PHP_SELF"]) && preg_match(
'/list\.php/', $_SERVER[
"PHP_SELF"])) {
6010 $add_save_lastsearch_values = 1;
6012 if ($add_save_lastsearch_values) {
6013 $url .=
'&save_lastsearch_values=1';
6017 $linkstart =
'<a href="'.$url.
'"';
6018 $linkstart .= $linkclose.
'>';
6021 $result .= $linkstart;
6024 $result .= (
img_object(($notooltip ?
'' : $label),
'product',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
6027 $result .= (
img_object(($notooltip ?
'' : $label),
'service',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
6030 $result .=
'<span class="aaa">'.dol_escape_htmltag($newref).
'</span>';
6031 $result .= $linkend;
6032 if ($withpicto != 2) {
6033 $result .= (($add_label && $this->label) ? $sep.dol_trunc($this->label, ($add_label > 1 ? $add_label : 0)) :
'');
6037 $hookmanager->initHooks(array(
'productdao'));
6038 $parameters = array(
'id' => $this->
id,
'getnomurl' => &$result,
'label' => &$label);
6039 $reshook = $hookmanager->executeHooks(
'getNomUrl', $parameters, $this, $action);
6041 $result = $hookmanager->resPrint;
6043 $result .= $hookmanager->resPrint;
6060 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
6064 $langs->load(
"products");
6065 $outputlangs->load(
"products");
6072 $modelpath =
"core/modules/product/doc/";
6074 return $this->
commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
6090 return $this->
LibStatut($this->status_buy, $mode, $type);
6092 return $this->
LibStatut($this->status_batch, $mode, $type);
6095 return $this->
LibStatut($this->status_buy, $mode, $type);
6113 $labelStatus = $labelStatusShort =
'';
6115 $langs->load(
'products');
6117 $langs->load(
"productbatch");
6123 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial')));
6126 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort')));
6131 return dolGetStatus($langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch'),
'',
'', empty($status) ?
'status5' :
'status4', 3,
'dot');
6137 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'));
6141 $statuttrans = empty($status) ?
'status5' :
'status4';
6146 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSellShort');
6147 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSell');
6148 } elseif ($type == 1) {
6149 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuyShort');
6150 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuy');
6151 } elseif ($type == 2) {
6152 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch');
6153 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort');
6155 } elseif ($status == 1) {
6158 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSellShort');
6159 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSell');
6160 } elseif ($type == 1) {
6161 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBuyShort');
6162 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBuy');
6163 } elseif ($type == 2) {
6164 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBatch');
6165 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort');
6167 } elseif ($type == 2 && $status == 2) {
6168 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSerial');
6169 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort');
6173 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'),
'',
'',
'status0', 0);
6175 return dolGetStatus($labelStatus, $labelStatusShort,
'', $statuttrans, $mode);
6189 $langs->load(
'products');
6192 if (isset($this->finished) && $this->finished >= 0) {
6193 $sql =
"SELECT label, code FROM ".$this->db->prefix().
"c_product_nature where code = ".((int) $this->finished).
" AND active=1";
6194 $resql = $this->db->query($sql);
6196 $this->error = $this->db->error().
' sql='.$sql;
6197 dol_syslog(__METHOD__.
' Error '.$this->error, LOG_ERR);
6199 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
6200 $label = $langs->trans($res[
'label']);
6202 $this->db->free($resql);
6226 public function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label =
'', $price = 0, $inventorycode =
'', $origin_element =
'', $origin_id =
null, $disablestockchangeforsubproduct = 0, $extrafields =
null)
6232 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6235 $nbpiece = (float) $nbpiece;
6240 $nbpiece = abs($nbpiece);
6247 $movementstock->setOrigin($origin_element, (
int) $origin_id);
6248 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'',
'',
'',
'',
false, 0, $disablestockchangeforsubproduct);
6252 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6253 $movementstock->array_options = $array_options;
6254 $movementstock->insertExtraFields();
6256 $this->db->commit();
6261 $this->db->rollback();
6290 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)
6296 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6299 $nbpiece = (float) $nbpiece;
6304 $nbpiece = abs($nbpiece);
6312 $movementstock->setOrigin($origin_element, (
int) $origin_id);
6313 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'', $dlc, $dluo, $lot,
false, 0, $disablestockchangeforsubproduct, 0, $force_update_batch);
6317 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6318 $movementstock->array_options = $array_options;
6319 $movementstock->insertExtraFields();
6321 $this->db->commit();
6324 $this->error = $movementstock->error;
6325 $this->errors = $movementstock->errors;
6327 $this->db->rollback();
6347 public function load_stock($option =
'', $includedraftpoforvirtual =
null, $dateofvirtualstock =
null)
6350 $this->stock_reel = 0;
6351 $this->stock_warehouse = array();
6352 $this->stock_theorique = 0;
6355 $warehouseStatus = array();
6356 if (preg_match(
'/warehouseclosed/', $option)) {
6359 if (preg_match(
'/warehouseopen/', $option)) {
6362 if (preg_match(
'/warehouseinternal/', $option)) {
6370 $sql =
"SELECT ps.rowid, ps.reel, ps.fk_entrepot";
6371 $sql .=
" FROM ".$this->db->prefix().
"product_stock as ps";
6372 $sql .=
", ".$this->db->prefix().
"entrepot as w";
6373 $sql .=
" WHERE w.entity IN (".getEntity(
'stock').
")";
6374 $sql .=
" AND w.rowid = ps.fk_entrepot";
6375 $sql .=
" AND ps.fk_product = ".((int) $this->
id);
6376 if (count($warehouseStatus)) {
6377 $sql .=
" AND w.statut IN (".$this->db->sanitize(implode(
',', $warehouseStatus)).
")";
6380 $sql .=
" ORDER BY ps.reel ".(getDolGlobalString(
'DO_NOT_TRY_TO_DEFRAGMENT_STOCKS_WAREHOUSE') ?
'DESC' :
'ASC');
6382 dol_syslog(get_class($this).
"::load_stock", LOG_DEBUG);
6383 $result = $this->db->query($sql);
6385 $num = $this->db->num_rows($result);
6389 $row = $this->db->fetch_object($result);
6390 $this->stock_warehouse[$row->fk_entrepot] =
new stdClass();
6391 $this->stock_warehouse[$row->fk_entrepot]->real = $row->reel;
6392 $this->stock_warehouse[$row->fk_entrepot]->id = $row->rowid;
6393 if ((!preg_match(
'/nobatch/', $option)) && $this->
hasbatch()) {
6394 $this->stock_warehouse[$row->fk_entrepot]->detail_batch =
Productbatch::findAll($this->db, $row->rowid, 1, $this->id);
6396 $this->stock_reel += $row->reel;
6399 $this->stock_reel = (float)
price2num($this->stock_reel,
'MS');
6401 $this->db->free($result);
6403 if (!preg_match(
'/novirtual/', $option)) {
6409 $this->error = $this->db->lasterror();
6428 global $hookmanager, $action;
6430 $stock_commande_client = 0;
6431 $stock_commande_fournisseur = 0;
6432 $stock_sending_client = 0;
6433 $stock_reception_fournisseur = 0;
6434 $stock_inproduction = 0;
6443 $stock_commande_client = $this->stats_commande[
'qty'];
6446 require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expedition.class.php';
6447 $filterShipmentStatus =
'';
6457 $stock_sending_client = $this->stats_expedition[
'qty'];
6461 $filterStatus =
getDolGlobalString(
'SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK',
'3,4');
6462 if (isset($includedraftpoforvirtual)) {
6463 $filterStatus =
'0,1,2,'.$filterStatus;
6469 $stock_commande_fournisseur = $this->stats_commande_fournisseur[
'qty'];
6473 $filterStatus =
'4';
6474 if (isset($includedraftpoforvirtual)) {
6475 $filterStatus =
'0,'.$filterStatus;
6481 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
6489 $stock_inproduction = $this->stats_mrptoproduce[
'qty'] - $this->stats_mrptoconsume[
'qty'];
6492 $this->stock_theorique = $this->stock_reel + $stock_inproduction;
6496 $weBillOrderOrShipmentReception =
getDolGlobalString(
'STOCK_DO_WE_BILL_ORDER_OR_SHIPMENTECEPTION_FOR_VIRTUALSTOCK',
'order');
6500 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6504 $result = $tmpnewprod->load_stats_commande(0,
'0', 1);
6505 $this->stock_theorique += $tmpnewprod->stats_commande[
'qty'];
6507 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6508 $this->stock_theorique -= $stock_commande_client;
6509 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6510 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6515 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6517 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6519 if (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER_INCLUDE_DRAFT')) {
6521 $result = $tmpnewprod->load_stats_commande_fournisseur(0,
'0', 1);
6522 $this->stock_theorique += $this->stats_commande_fournisseur[
'qty'];
6524 $this->stock_theorique -= $stock_reception_fournisseur;
6525 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6526 $this->stock_theorique += $stock_commande_fournisseur;
6527 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6528 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6531 $parameters = array(
'id' => $this->
id,
'includedraftpoforvirtual' => $includedraftpoforvirtual);
6533 $reshook = $hookmanager->executeHooks(
'loadvirtualstock', $parameters, $this, $action);
6535 $this->stock_theorique = $hookmanager->resArray[
'stock_theorique'];
6536 } elseif ($reshook == 0 && isset($hookmanager->resArray[
'stock_stats_hook'])) {
6537 $this->stock_theorique += $hookmanager->resArray[
'stock_stats_hook'];
6541 if (!empty($this->stock_warehouse) &&
getDolGlobalString(
'STOCK_ALLOW_VIRTUAL_STOCK_PER_WAREHOUSE')) {
6542 foreach ($this->stock_warehouse as $warehouseid => $stockwarehouse) {
6550 if ($this->fk_default_warehouse == $warehouseid) {
6551 $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']);
6553 $this->stock_warehouse[$warehouseid]->virtual = $this->stock_warehouse[$warehouseid]->real + $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'];
6570 $this->stock_warehouse = array();
6575 if (count($prods_arbo) > 0) {
6576 $productCachedList = array();
6577 $stockByComponentList = array();
6579 foreach ($prods_arbo as $componentArr) {
6580 $componentId = $componentArr[
'id'];
6582 if ($componentArr[
'incdec'] == 1) {
6583 if (!isset($productCachedList[$componentId])) {
6584 $componentStatic =
new self($this->db);
6585 $componentStatic->fetch($componentId);
6587 $childrenNb = $componentStatic->hasFatherOrChild(1);
6588 if ($childrenNb == 0) {
6589 $componentStatic->load_stock(
'nobatch,novirtual');
6590 if (!isset($stockByComponentList[$componentId])) {
6591 $stockByComponentList[$componentId] = array(
6595 $stockByComponentList[$componentId][
'qty_need'] += $componentArr[
'nb_total'];
6597 $productCachedList[$componentId] = $componentStatic;
6602 if (!empty($stockByComponentList)) {
6603 foreach ($stockByComponentList as $componentId => $stockByComponentArr) {
6604 if (!isset($productCachedList[$componentId])) {
6605 $componentStatic =
new self($this->db);
6606 $componentStatic->fetch($componentId);
6607 $componentStatic->load_stock(
'nobatch,novirtual');
6608 $productCachedList[$componentId] = $componentStatic;
6610 $component = $productCachedList[$componentId];
6613 if ($component->stock_reel < $stockByComponentArr[
'qty_need']) {
6616 $this->error =
'Not enough component [id='.$componentId.
'] in stock, real='.$component->stock_reel.
' and need='.$stockByComponentArr[
'qty_need'];
6617 $this->errors[] = $this->error;
6618 dol_syslog(__METHOD__.
' : '.$this->error, LOG_ERR);
6620 if (!empty($component->stock_warehouse)) {
6621 foreach ($component->stock_warehouse as $warehouseId => $warehouseObj) {
6622 $kitWarehouseAvailable =
new stdClass();
6623 $kitWarehouseAvailable->id = $warehouseObj->id;
6624 $kitWarehouseAvailable->real = $qtyWish;
6625 $this->stock_warehouse[$warehouseId] = $kitWarehouseAvailable;
6634 } elseif (
getDolGlobalInt(
'PRODUIT_SOUSPRODUITS_ALSO_ENABLE_PARENT_STOCK_MOVE') && empty($productCachedList)) {
6658 $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";
6659 $sql .=
" WHERE pb.fk_product_stock = ps.rowid AND ps.fk_product = ".((int) $this->
id).
" AND pb.batch = '".$this->db->escape($batch).
"'";
6660 $sql .=
" GROUP BY pb.batch, pb.eatby, pb.sellby";
6661 dol_syslog(get_class($this).
"::loadBatchInfo load first entry found for lot/serial = ".$batch, LOG_DEBUG);
6662 $resql = $this->db->query($sql);
6664 $num = $this->db->num_rows($resql);
6667 $obj = $this->db->fetch_object($resql);
6668 $result[] = array(
'batch' => $batch,
'eatby' => $this->db->jdate($obj->eatby),
'sellby' => $this->db->jdate($obj->sellby),
'qty' => $obj->qty);
6674 $this->db->rollback();
6691 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6697 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos";
6699 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product').dol_sanitizeFileName($this->
ref);
6704 $dir_osencoded = $dir;
6706 if (is_dir($dir_osencoded)) {
6707 $originImage = $dir.
'/'.$file[
'name'];
6718 if (is_numeric($result) && $result > 0) {
6735 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6736 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6740 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos/";
6742 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product');
6746 if (file_exists($dir_osencoded)) {
6747 $handle = opendir($dir_osencoded);
6748 if (is_resource($handle)) {
6749 while (($file = readdir($handle)) !==
false) {
6751 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6774 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6775 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6781 $handle = @opendir($dir_osencoded);
6782 if (is_resource($handle)) {
6783 while (($file = readdir($handle)) !==
false) {
6785 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6792 $photo_vignette =
'';
6794 if (preg_match(
'/('.$this->regeximgext.
')$/i', $photo, $regs)) {
6795 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $photo).
'_small'.$regs[0];
6798 $dirthumb = $dir.
'thumbs/';
6802 $obj[
'photo'] = $photo;
6803 if ($photo_vignette &&
dol_is_file($dirthumb.$photo_vignette)) {
6804 $obj[
'photo_vignette'] =
'thumbs/'.$photo_vignette;
6806 $obj[
'photo_vignette'] =
"";
6809 $tabobj[$nbphoto - 1] = $obj;
6812 if ($nbmax && $nbphoto >= $nbmax) {
6834 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6835 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6837 $dir = dirname($file).
'/';
6838 $dirthumb = $dir.
'/thumbs/';
6839 $filename = preg_replace(
'/'.preg_quote($dir,
'/').
'/i',
'', $file);
6845 if (preg_match(
'/('.$this->regeximgext.
')$/i', $filename, $regs)) {
6846 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_small'.$regs[0];
6847 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6851 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_mini'.$regs[0];
6852 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6869 $infoImg = getimagesize($file_osencoded);
6870 $this->imgWidth = $infoImg[0];
6871 $this->imgHeight = $infoImg[1];
6881 global $hookmanager;
6883 $this->nb = array();
6885 $sql =
"SELECT count(p.rowid) as nb, fk_product_type";
6886 $sql .=
" FROM ".$this->db->prefix().
"product as p";
6887 $sql .=
' WHERE p.entity IN ('.getEntity($this->element, 1).
')';
6889 if (is_object($hookmanager)) {
6890 $parameters = array();
6891 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
6892 $sql .= $hookmanager->resPrint;
6894 $sql .=
' GROUP BY fk_product_type';
6896 $resql = $this->db->query($sql);
6898 while ($obj = $this->db->fetch_object($resql)) {
6899 if ($obj->fk_product_type == 1) {
6900 $this->nb[
"services"] = $obj->nb;
6902 $this->nb[
"products"] = $obj->nb;
6905 $this->db->free($resql);
6909 $this->error = $this->db->error();
6951 return $this->mandatory_period == 1;
6961 return $this->status_batch > 0;
6981 $dirsociete = array_merge(array(
'/core/modules/barcode/'), $conf->modules_parts[
'barcode']);
6982 foreach ($dirsociete as $dirroot) {
6990 '@phan-var-force ModeleNumRefBarCode $mod';
6992 $result = $mod->getNextValue(
$object, $type);
6994 dol_syslog(get_class($this).
"::get_barcode barcode=".$result.
" module=".$var);
7011 $this->specimen = 1;
7013 $this->
ref =
'PRODUCT_SPEC';
7014 $this->label =
'PRODUCT SPECIMEN';
7015 $this->
description =
'This is description of this product specimen that was created the '.dol_print_date($now,
'dayhourlog').
'.';
7016 $this->specimen = 1;
7017 $this->country_id = 1;
7019 $this->status_buy = 1;
7021 $this->sell_or_eat_by_mandatory = 0;
7022 $this->note_private =
'This is a comment (private)';
7023 $this->note_public =
'This is a comment (public)';
7024 $this->date_creation = $now;
7025 $this->date_modification = $now;
7028 $this->weight_units = 3;
7031 $this->length_units = 1;
7033 $this->width_units = 0;
7034 $this->height =
null;
7035 $this->height_units =
null;
7037 $this->surface = 30;
7038 $this->surface_units = 0;
7039 $this->volume = 300;
7040 $this->volume_units = 0;
7042 $this->barcode = -1;
7060 if (empty($this->fk_unit)) {
7063 if (empty($outputlangs)) {
7064 $outputlangs = $langs;
7067 $outputlangs->load(
'products');
7070 $sql =
"SELECT code, label, short_label FROM ".$this->db->prefix().
"c_units where rowid = ".((int) $this->fk_unit);
7072 $resql = $this->db->query($sql);
7074 $this->error = $this->db->error();
7075 dol_syslog(get_class($this).
"::getLabelOfUnit Error ".$this->error, LOG_ERR);
7077 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
7078 if ($type ==
'short') {
7080 $label = $outputlangs->transnoentitiesnoconv($res[
'short_label']);
7082 $label = $outputlangs->trans($res[
'short_label']);
7084 } elseif ($type ==
'code') {
7085 $label = $res[
'code'];
7087 if ($outputlangs->trans(
'unit'.$res[
'code']) ==
'unit'.$res[
'code']) {
7089 $label = $res[
'label'];
7093 $label = $outputlangs->transnoentitiesnoconv(
'unit'.$res[
'code']);
7095 $label = $outputlangs->trans(
'unit'.$res[
'code']);
7100 $this->db->free($resql);
7114 $maxpricesupplier = 0;
7117 include_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.product.class.php';
7119 $product_fourn_list = $product_fourn->list_product_fournisseur_price($this->
id,
'',
'');
7121 if (is_array($product_fourn_list) && count($product_fourn_list) > 0) {
7122 foreach ($product_fourn_list as $productfourn) {
7123 if ($productfourn->fourn_unitprice > $maxpricesupplier) {
7124 $maxpricesupplier = $productfourn->fourn_unitprice;
7132 return $maxpricesupplier;
7148 require_once DOL_DOCUMENT_ROOT.
'/categories/class/categorie.class.php';
7149 return parent::setCategoriesCommon($categories, Categorie::TYPE_PRODUCT);
7163 $sql =
" DELETE FROM ".$dbs->prefix().
"product_customer_price";
7164 $sql .=
" WHERE fk_soc = ".(int) $origin_id;
7165 $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)";
7168 if (!$dbs->
query($sql)) {
7173 'product_customer_price',
7174 'product_customer_price_log'
7193 $sql =
"SELECT rowid, level, fk_level, var_percent, var_min_percent FROM ".$this->db->prefix().
"product_pricerules";
7194 $query = $this->db->query($sql);
7198 while ($result = $this->db->fetch_object($query)) {
7199 $rules[$result->level] = $result;
7208 for ($i = 1; $i <= $nbofproducts; $i++) {
7209 $price = $baseprice;
7210 $price_min = $baseprice;
7214 if ($i > 1 && isset($rules[$i]->var_percent) && $rules[$i]->var_percent) {
7215 $price = $prices[$rules[$i]->fk_level] * (1 + ($rules[$i]->var_percent / 100));
7218 $prices[$i] = $price;
7221 if (isset($rules[$i]->var_min_percent) && $rules[$i]->var_min_percent) {
7222 $price_min = $price * (1 - ($rules[$i]->var_min_percent / 100));
7226 $check_amount = (($price == $this->multiprices[$i]) && ($price_min == $this->multiprices_min[$i]));
7227 $check_type = ($baseprice == $this->multiprices_base_type[$i]);
7229 if ($check_amount && $check_type) {
7233 if ($this->
updatePrice($price, $price_type, $user, $price_vat, $price_min, $i, $npr, $psq, 1) < 0) {
7251 return $user->rights->produit;
7253 return $user->rights->service;
7265 $sql =
"SELECT p.rowid, p.ref, p.datec as date_creation, GREATEST(p.tms, COALESCE(pef.tms, p.tms)) as date_modification,";
7266 $sql .=
" p.fk_user_author, p.fk_user_modif";
7267 $sql .=
" FROM ".$this->db->prefix().$this->table_element.
" as p";
7268 $sql .=
" LEFT JOIN ".$this->db->prefix().$this->table_element.
"_extrafields as pef ON pef.fk_object=p.rowid";
7269 $sql .=
" WHERE p.rowid = ".((int) $id);
7271 $result = $this->db->query($sql);
7273 if ($this->db->num_rows($result)) {
7274 $obj = $this->db->fetch_object($result);
7276 $this->
id = $obj->rowid;
7277 $this->
ref = $obj->ref;
7279 $this->user_creation_id = $obj->fk_user_author;
7280 $this->user_modification_id = $obj->fk_user_modif;
7282 $this->date_creation = $this->db->jdate($obj->date_creation);
7283 $this->date_modification = $this->db->jdate($obj->date_modification);
7286 $this->db->free($result);
7300 if (empty($this->duration_value)) {
7301 $this->errors[] =
'ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
7304 if ($this->duration_unit ==
's') {
7305 $prodDurationHours = 1. / 3600;
7306 } elseif ($this->duration_unit ==
'i' || $this->duration_unit ==
'mn' || $this->duration_unit ==
'min') {
7307 $prodDurationHours = 1. / 60;
7308 } elseif ($this->duration_unit ==
'h') {
7309 $prodDurationHours = 1.;
7310 } elseif ($this->duration_unit ==
'd') {
7311 $prodDurationHours = 24.;
7312 } elseif ($this->duration_unit ==
'w') {
7313 $prodDurationHours = 24. * 7;
7314 } elseif ($this->duration_unit ==
'm') {
7315 $prodDurationHours = 24. * 30;
7316 } elseif ($this->duration_unit ==
'y') {
7317 $prodDurationHours = 24. * 365;
7321 $this->errors[] =
'ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
7324 $prodDurationHours *= $this->duration_value;
7326 return $prodDurationHours;
7339 global $langs, $conf;
7341 $selected = (empty($arraydata[
'selected']) ? 0 : $arraydata[
'selected']);
7343 $return =
'<div class="box-flex-item box-flex-grow-zero">';
7344 $return .=
'<div class="info-box info-box-sm">';
7345 $return .=
'<div class="info-box-img">';
7347 if ($this->entity !==
null && $this->
is_photo_available($conf->product->multidir_output[$this->entity])) {
7348 $label .= $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 120, 160, 0, 0, 0,
'',
'photoref photokanban');
7358 $return .=
'</div>';
7359 $return .=
'<div class="info-box-content">';
7360 $return .=
'<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">' . $this->
getNomUrl() .
'</span>';
7361 if ($selected >= 0) {
7362 $return .=
'<input id="cb'.$this->id.
'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->
id.
'"'.($selected ?
' checked="checked"' :
'').
'>';
7364 $return .=
'<br><span class="info-box-label opacitymedium inline-block tdoverflowmax150 valignmiddle" title="'.dol_escape_htmltag($this->label).
'">'.
dol_escape_htmltag($this->label).
'</span>';
7365 if ($this->price_base_type ==
'TTC') {
7366 $return .=
'<br><span class="info-box-status amount">'.price($this->price_ttc).
' '.$langs->trans(
"TTC").
'</span>';
7369 $return .=
'<br><span class="info-box-status amount">'.price($this->
price).
' '.$langs->trans(
"HT").
'</span>';
7374 $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>';
7379 $return .=
'<div class="info-box-status inline-block valignmiddle">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7381 $return .=
'<div class="info-box-status inline-block valignmiddle marginleftonly paddingleft">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7383 $return .=
'</div>';
7384 $return .=
'</div>';
7385 $return .=
'</div>';
7396 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 of this product.
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]]]',...