40require_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
41require_once DOL_DOCUMENT_ROOT.
'/core/class/commonobject.class.php';
42require_once DOL_DOCUMENT_ROOT.
'/product/class/productbatch.class.php';
43require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/productlot.class.php';
44require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/entrepot.class.php';
55 const SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY = 1;
56 const SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY = 2;
57 const SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT = 3;
62 public $element =
'product';
67 public $table_element =
'product';
72 public $fk_element =
'fk_product';
77 protected $childtables = array(
78 'supplier_proposaldet' => array(
'name' =>
'SupplierProposal',
'parent' =>
'supplier_proposal',
'parentkey' =>
'fk_supplier_proposal'),
79 'propaldet' => array(
'name' =>
'Proposal',
'parent' =>
'propal',
'parentkey' =>
'fk_propal'),
80 'commandedet' => array(
'name' =>
'Order',
'parent' =>
'commande',
'parentkey' =>
'fk_commande'),
81 'facturedet' => array(
'name' =>
'Invoice',
'parent' =>
'facture',
'parentkey' =>
'fk_facture'),
82 'contratdet' => array(
'name' =>
'Contract',
'parent' =>
'contrat',
'parentkey' =>
'fk_contrat'),
83 'facture_fourn_det' => array(
'name' =>
'SupplierInvoice',
'parent' =>
'facture_fourn',
'parentkey' =>
'fk_facture_fourn'),
84 'commande_fournisseurdet' => array(
'name' =>
'SupplierOrder',
'parent' =>
'commande_fournisseur',
'parentkey' =>
'fk_commande'),
85 'mrp_production' => array(
'name' =>
'Mo',
'parent' =>
'mrp_mo',
'parentkey' =>
'fk_mo',
'enabled' =>
'isModEnabled("mrp")'),
86 'bom_bom' => array(
'name' =>
'BOM',
'enabled' =>
'isModEnabled("bom")'),
87 'bom_bomline' => array(
'name' =>
'BOMLine',
'parent' =>
'bom_bom',
'parentkey' =>
'fk_bom',
'enabled' =>
'isModEnabled("bom")'),
95 public $picto =
'product';
106 public $regeximgext =
'\.gif|\.jpg|\.jpeg|\.png|\.bmp|\.webp|\.xpm|\.xbm';
153 public $price_formated;
165 public $price_ttc_formated;
179 public $price_min_ttc;
185 public $price_base_type;
195 public $multiprices = array();
199 public $multiprices_ttc = array();
203 public $multiprices_base_type = array();
207 public $multiprices_default_vat_code = array();
211 public $multiprices_min = array();
215 public $multiprices_min_ttc = array();
219 public $multiprices_tva_tx = array();
223 public $multiprices_recuperableonly = array();
229 public $price_by_qty;
233 public $prices_by_qty = array();
237 public $prices_by_qty_id = array();
241 public $prices_by_qty_list = array();
251 public $multilangs = array();
256 public $default_vat_code;
271 public $remise_percent;
276 public $localtax1_tx;
280 public $localtax2_tx;
284 public $localtax1_type;
288 public $localtax2_type;
295 public $desc_supplier;
299 public $vatrate_supplier;
303 public $default_vat_code_supplier;
308 public $fourn_multicurrency_price;
312 public $fourn_multicurrency_unitprice;
316 public $fourn_multicurrency_tx;
320 public $fourn_multicurrency_id;
324 public $fourn_multicurrency_code;
346 public $qc_frequency;
353 public $stock_reel = 0;
360 public $stock_theorique;
381 public $seuil_stock_alerte = 0;
386 public $desiredstock = 0;
391 public $duration_value;
395 public $duration_unit;
404 public $fk_default_workstation;
426 public $status_buy = 0;
448 public $fk_default_bom;
455 public $product_fourn_price_id;
477 public $status_batch = 0;
484 public $sell_or_eat_by_mandatory = 0;
491 public $batch_mask =
'';
516 public $weight_units;
524 public $length_units;
540 public $height_units;
548 public $surface_units;
556 public $volume_units;
565 public $net_measure_units;
570 public $accountancy_code_sell;
574 public $accountancy_code_sell_intra;
578 public $accountancy_code_sell_export;
582 public $accountancy_code_buy;
586 public $accountancy_code_buy_intra;
590 public $accountancy_code_buy_export;
600 public $barcode_type;
605 public $barcode_type_code;
610 public $stats_propale = array();
615 public $stats_commande = array();
620 public $stats_contrat = array();
625 public $stats_facture = array();
630 public $stats_proposal_supplier = array();
635 public $stats_commande_fournisseur = array();
640 public $stats_expedition = array();
645 public $stats_reception = array();
650 public $stats_mo = array();
655 public $stats_bom = array();
660 public $stats_mrptoconsume = array();
665 public $stats_mrptoproduce = array();
670 public $stats_facturerec = array();
675 public $stats_facture_fournisseur = array();
690 public $product_fourn_id;
696 public $product_id_already_linked;
707 public $stock_warehouse = array();
712 public $fk_default_warehouse;
717 public $fk_price_expression;
735 public $fourn_price_base_type;
752 public $ref_supplier;
766 public $price_autogen = 0;
773 public $supplierprices;
780 public $sousprods = array();
793 public $is_object_used;
804 public $is_sousproduit_qty;
816 public $is_sousproduit_incdec;
821 public $mandatory_period;
852 public $fields = array(
853 'rowid' => array(
'type' =>
'integer',
'label' =>
'TechnicalID',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'index' => 1,
'position' => 1,
'comment' =>
'Id'),
854 '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'),
855 'entity' => array(
'type' =>
'integer',
'label' =>
'Entity',
'enabled' => 1,
'visible' => 0,
'default' =>
'1',
'notnull' => 1,
'index' => 1,
'position' => 5),
856 'label' => array(
'type' =>
'varchar(255)',
'label' =>
'Label',
'enabled' => 1,
'visible' => 1,
'notnull' => 1,
'showoncombobox' => 2,
'position' => 15,
'csslist' =>
'tdoverflowmax250'),
857 'barcode' => array(
'type' =>
'varchar(255)',
'label' =>
'Barcode',
'enabled' =>
'isModEnabled("barcode")',
'position' => 20,
'visible' => -1,
'showoncombobox' => 3,
'cssview' =>
'tdwordbreak',
'csslist' =>
'tdoverflowmax125'),
858 'fk_barcode_type' => array(
'type' =>
'integer',
'label' =>
'BarcodeType',
'enabled' => 1,
'position' => 21,
'notnull' => 0,
'visible' => -1,),
859 'note_public' => array(
'type' =>
'html',
'label' =>
'NotePublic',
'enabled' => 1,
'visible' => 0,
'position' => 61),
860 'note' => array(
'type' =>
'html',
'label' =>
'NotePrivate',
'enabled' => 1,
'visible' => 0,
'position' => 62),
861 'datec' => array(
'type' =>
'datetime',
'label' =>
'DateCreation',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 500),
862 'tms' => array(
'type' =>
'timestamp',
'label' =>
'DateModification',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 501),
864 'fk_user_author' => array(
'type' =>
'integer',
'label' =>
'UserAuthor',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 510,
'foreignkey' =>
'llx_user.rowid'),
865 'fk_user_modif' => array(
'type' =>
'integer',
'label' =>
'UserModif',
'enabled' => 1,
'visible' => -2,
'notnull' => -1,
'position' => 511),
867 'localtax1_tx' => array(
'type' =>
'double(6,3)',
'label' =>
'Localtax1tx',
'enabled' => 1,
'position' => 150,
'notnull' => 0,
'visible' => -1,),
868 'localtax1_type' => array(
'type' =>
'varchar(10)',
'label' =>
'Localtax1type',
'enabled' => 1,
'position' => 155,
'notnull' => 1,
'visible' => -1,),
869 'localtax2_tx' => array(
'type' =>
'double(6,3)',
'label' =>
'Localtax2tx',
'enabled' => 1,
'position' => 160,
'notnull' => 0,
'visible' => -1,),
870 'localtax2_type' => array(
'type' =>
'varchar(10)',
'label' =>
'Localtax2type',
'enabled' => 1,
'position' => 165,
'notnull' => 1,
'visible' => -1,),
871 'last_main_doc' => array(
'type' =>
'varchar(255)',
'label' =>
'LastMainDoc',
'enabled' => 1,
'visible' => -1,
'position' => 170),
872 'import_key' => array(
'type' =>
'varchar(14)',
'label' =>
'ImportId',
'enabled' => 1,
'visible' => -2,
'notnull' => -1,
'index' => 0,
'position' => 1000),
875 'mandatory_period' => array(
'type' =>
'integer',
'label' =>
'mandatoryperiod',
'enabled' => 1,
'visible' => -1,
'notnull' => 1,
'default' =>
'0',
'index' => 1,
'position' => 1000),
896 $this->ismultientitymanaged = 1;
897 $this->isextrafieldmanaged = 1;
910 $this->
ref = trim($this->
ref);
938 public function create($user, $notrigger = 0)
940 global
$conf, $langs;
946 $this->
ref = trim($this->
ref);
950 $this->label = trim($this->label);
951 $this->price_ttc = (float)
price2num($this->price_ttc);
953 $this->price_min_ttc = (float)
price2num($this->price_min_ttc);
954 $this->price_min = (float)
price2num($this->price_min);
955 $this->price_label = trim($this->price_label);
956 if (empty($this->tva_tx)) {
959 if (empty($this->tva_npr)) {
963 if (empty($this->localtax1_tx)) {
964 $this->localtax1_tx = 0;
966 if (empty($this->localtax2_tx)) {
967 $this->localtax2_tx = 0;
969 if (empty($this->localtax1_type)) {
970 $this->localtax1_type =
'0';
972 if (empty($this->localtax2_type)) {
973 $this->localtax2_type =
'0';
975 if (empty($this->
price)) {
978 if (empty($this->price_min)) {
979 $this->price_min = 0;
982 if (empty($this->price_by_qty)) {
983 $this->price_by_qty = 0;
986 if (empty($this->
status)) {
989 if (empty($this->status_buy)) {
990 $this->status_buy = 0;
999 if ($this->price_base_type ==
'TTC' && $this->price_ttc > 0) {
1000 $price_ttc =
price2num($this->price_ttc,
'MU');
1001 $price_ht =
price2num($this->price_ttc / (1 + ($this->tva_tx / 100)),
'MU');
1005 if ($this->price_base_type !=
'TTC' && $this->
price > 0) {
1007 $price_ttc =
price2num($this->
price * (1 + ($this->tva_tx / 100)),
'MU');
1011 if (($this->price_min_ttc > 0) && ($this->price_base_type ==
'TTC')) {
1012 $price_min_ttc =
price2num($this->price_min_ttc,
'MU');
1013 $price_min_ht =
price2num($this->price_min_ttc / (1 + ($this->tva_tx / 100)),
'MU');
1017 if (($this->price_min > 0) && ($this->price_base_type !=
'TTC')) {
1018 $price_min_ht =
price2num($this->price_min,
'MU');
1019 $price_min_ttc =
price2num($this->price_min * (1 + ($this->tva_tx / 100)),
'MU');
1022 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
1023 $this->accountancy_code_buy_intra = trim($this->accountancy_code_buy_intra);
1024 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
1025 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
1026 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
1027 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
1030 $this->barcode = trim($this->barcode);
1031 $this->mandatory_period = empty($this->mandatory_period) ? 0 : $this->mandatory_period;
1033 if (empty($this->label)) {
1034 $this->error =
'ErrorMandatoryParametersNotProvided';
1038 if (empty($this->
ref) || $this->
ref ==
'auto') {
1040 $module =
getDolGlobalString(
'PRODUCT_CODEPRODUCT_ADDON',
'mod_codeproduct_leopard');
1041 if ($module !=
'mod_codeproduct_leopard') {
1042 if (substr($module, 0, 16) ==
'mod_codeproduct_' && substr($module, -3) ==
'php') {
1043 $module = substr($module, 0,
dol_strlen($module) - 4);
1046 $modCodeProduct =
new $module();
1047 '@phan-var-force ModeleProductCode $modCodeProduct';
1048 if (!empty($modCodeProduct->code_auto)) {
1049 $this->
ref = $modCodeProduct->getNextValue($this, $this->
type);
1051 unset($modCodeProduct);
1054 if (empty($this->
ref)) {
1055 $this->error =
'ProductModuleNotSetupForAutoRef';
1060 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);
1064 if (empty($this->date_creation)) {
1065 $this->date_creation = $now;
1071 if ($this->barcode ==
'-1' || $this->barcode ==
'auto') {
1072 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1077 $result = $this->
verify();
1080 $sql =
"SELECT count(*) as nb";
1081 $sql .=
" FROM ".$this->db->prefix().
"product";
1082 $sql .=
" WHERE entity IN (".getEntity(
'product').
")";
1083 $sql .=
" AND ref = '".$this->db->escape($this->
ref).
"'";
1085 $result = $this->db->query($sql);
1087 $obj = $this->db->fetch_object($result);
1088 if ($obj->nb == 0) {
1090 $sql =
"INSERT INTO ".$this->db->prefix().
"product (";
1094 $sql .=
", ref_ext";
1095 $sql .=
", price_min";
1096 $sql .=
", price_min_ttc";
1098 $sql .=
", fk_user_author";
1099 $sql .=
", fk_product_type";
1101 $sql .=
", price_ttc";
1102 $sql .=
", price_base_type";
1103 $sql .=
", price_label";
1107 $sql .=
", accountancy_code_buy";
1108 $sql .=
", accountancy_code_buy_intra";
1109 $sql .=
", accountancy_code_buy_export";
1110 $sql .=
", accountancy_code_sell";
1111 $sql .=
", accountancy_code_sell_intra";
1112 $sql .=
", accountancy_code_sell_export";
1115 $sql .=
", finished";
1116 $sql .=
", tobatch";
1117 $sql .=
", sell_or_eat_by_mandatory";
1118 $sql .=
", batch_mask";
1119 $sql .=
", fk_unit";
1120 $sql .=
", mandatory_period";
1121 $sql .=
") VALUES (";
1122 $sql .=
"'".$this->db->idate($this->date_creation).
"'";
1123 $sql .=
", ".(!empty($this->entity) ? (int) $this->entity : (int)
$conf->entity);
1124 $sql .=
", '".$this->db->escape($this->
ref).
"'";
1125 $sql .=
", ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1126 $sql .=
", ".price2num($price_min_ht);
1127 $sql .=
", ".price2num($price_min_ttc);
1128 $sql .=
", ".(!empty($this->label) ?
"'".$this->db->escape($this->label).
"'" :
"null");
1129 $sql .=
", ".((int) $user->id);
1130 $sql .=
", ".((int) $this->
type);
1131 $sql .=
", ".price2num($price_ht,
'MT');
1132 $sql .=
", ".price2num($price_ttc,
'MT');
1133 $sql .=
", '".$this->db->escape($this->price_base_type).
"'";
1134 $sql .=
", ".(!empty($this->price_label) ?
"'".$this->db->escape($this->price_label).
"'" :
"null");
1135 $sql .=
", ".((int) $this->
status);
1136 $sql .=
", ".((int) $this->status_buy);
1138 $sql .=
", '".$this->db->escape($this->accountancy_code_buy).
"'";
1139 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_intra).
"'";
1140 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_export).
"'";
1141 $sql .=
", '".$this->db->escape($this->accountancy_code_sell).
"'";
1142 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_intra).
"'";
1143 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_export).
"'";
1145 $sql .=
", '".$this->db->escape($this->canvas).
"'";
1146 $sql .=
", ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
'NULL' : (int) $this->finished);
1147 $sql .=
", ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : ((int) $this->status_batch));
1148 $sql .=
", ".((empty($this->sell_or_eat_by_mandatory) || $this->sell_or_eat_by_mandatory < 0) ? 0 : ((int) $this->sell_or_eat_by_mandatory));
1149 $sql .=
", '".$this->db->escape($this->batch_mask).
"'";
1150 $sql .=
", ".($this->fk_unit > 0 ? ((int) $this->fk_unit) :
'NULL');
1151 $sql .=
", '".$this->db->escape($this->mandatory_period).
"'";
1154 dol_syslog(get_class($this).
"::Create", LOG_DEBUG);
1156 $result = $this->db->query($sql);
1158 $id = $this->db->last_insert_id($this->db->prefix().
"product");
1162 $this->
price = $price_ht;
1163 $this->price_ttc = $price_ttc;
1164 $this->price_min = $price_min_ht;
1165 $this->price_min_ttc = $price_min_ttc;
1169 if ($this->
update($id, $user, 1,
'add') <= 0) {
1174 $this->error = $this->db->lasterror();
1179 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " .((int) $this->id) .
" AND entity = " . ((
int)
$conf->entity));
1181 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1182 $sql .=
" fk_product";
1184 $sql .=
", accountancy_code_buy";
1185 $sql .=
", accountancy_code_buy_intra";
1186 $sql .=
", accountancy_code_buy_export";
1187 $sql .=
", accountancy_code_sell";
1188 $sql .=
", accountancy_code_sell_intra";
1189 $sql .=
", accountancy_code_sell_export";
1190 $sql .=
") VALUES (";
1192 $sql .=
", " . ((int)
$conf->entity);
1193 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1194 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1195 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1196 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1197 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1198 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1200 $result = $this->db->query($sql);
1203 $this->error =
'ErrorFailedToInsertAccountancyForEntity';
1208 $this->error =
'ErrorFailedToGetInsertedId';
1212 $this->error = $this->db->lasterror();
1216 $langs->load(
"products");
1218 $this->error =
"ErrorProductAlreadyExists";
1219 dol_syslog(get_class($this).
"::Create fails, ref ".$this->
ref.
" already exists");
1223 $this->error = $this->db->lasterror();
1226 if (!$error && !$notrigger) {
1228 $result = $this->
call_trigger(
'PRODUCT_CREATE', $user);
1236 $this->db->commit();
1239 $this->db->rollback();
1243 $this->db->rollback();
1244 dol_syslog(get_class($this).
"::Create fails verify ".implode(
',', $this->errors), LOG_WARNING);
1260 $this->errors = array();
1263 $this->
ref = trim($this->
ref);
1266 $this->errors[] =
'ErrorBadRef';
1270 $arrayofnonnegativevalue = array(
'weight' =>
'Weight',
'width' =>
'Width',
'height' =>
'Height',
'length' =>
'Length',
'surface' =>
'Surface',
'volume' =>
'Volume');
1271 foreach ($arrayofnonnegativevalue as $key => $value) {
1272 if (property_exists($this, $key) && !empty($this->$key) && ($this->$key < 0)) {
1273 $langs->loadLangs(array(
"main",
"other"));
1274 $this->error = $langs->trans(
"FieldCannotBeNegative", $langs->transnoentitiesnoconv($value));
1275 $this->errors[] = $this->error;
1280 $rescode = $this->
check_barcode($this->barcode, $this->barcode_type_code);
1282 if ($rescode == -1) {
1283 $this->errors[] =
'ErrorBadBarCodeSyntax';
1284 } elseif ($rescode == -2) {
1285 $this->errors[] =
'ErrorBarCodeRequired';
1286 } elseif ($rescode == -3) {
1288 $this->errors[] =
'ErrorBarCodeAlreadyUsed';
1316 $dirsociete = array_merge(array(
'/core/modules/barcode/'),
$conf->modules_parts[
'barcode']);
1317 foreach ($dirsociete as $dirroot) {
1324 $mod =
new $module();
1325 '@phan-var-force ModeleNumRefBarCode $mod';
1327 dol_syslog(get_class($this).
"::check_barcode value=".$valuetotest.
" type=".$typefortest.
" module=".$module);
1328 $result = $mod->verif($this->db, $valuetotest, $this, 0, $typefortest);
1346 public function update($id, $user, $notrigger = 0, $action =
'update', $updatetype =
false)
1348 global $langs,
$conf, $hookmanager;
1353 if (!$this->label) {
1354 $this->label =
'MISSING LABEL';
1359 $this->
ref = trim($this->
ref);
1363 $this->label = trim($this->label);
1365 $this->note_private = (isset($this->note_private) ? trim($this->note_private) :
null);
1366 $this->note_public = (isset($this->note_public) ? trim($this->note_public) :
null);
1367 $this->net_measure =
price2num($this->net_measure);
1368 $this->net_measure_units = (is_null($this->net_measure_units) ?
'' : trim((
string) $this->net_measure_units));
1369 $this->weight =
price2num($this->weight);
1370 $this->weight_units = (is_null($this->weight_units) ?
'' : trim((
string) $this->weight_units));
1371 $this->length =
price2num($this->length);
1372 $this->length_units = (is_null($this->length_units) ?
'' : trim((
string) $this->length_units));
1374 $this->width_units = (is_null($this->width_units) ?
'' : trim((
string) $this->width_units));
1375 $this->height =
price2num($this->height);
1376 $this->height_units = (is_null($this->height_units) ?
'' : trim((
string) $this->height_units));
1377 $this->surface =
price2num($this->surface);
1378 $this->surface_units = (is_null($this->surface_units) ?
'' : trim((
string) $this->surface_units));
1379 $this->volume =
price2num($this->volume);
1380 $this->volume_units = (is_null($this->volume_units) ?
'' : trim((
string) $this->volume_units));
1383 if (is_numeric($this->length_units)) {
1384 $this->width_units = $this->length_units;
1386 if (is_numeric($this->length_units)) {
1387 $this->height_units = $this->length_units;
1391 if (empty($this->surface) && !empty($this->length) && !empty($this->width) && $this->length_units == $this->width_units) {
1392 $this->surface = (float) $this->length * (
float) $this->width;
1395 if (empty($this->volume) && !empty($this->surface) && !empty($this->height) && $this->length_units == $this->height_units) {
1396 $this->volume = $this->surface * (float) $this->height;
1400 if (empty($this->tva_tx)) {
1403 if (empty($this->tva_npr)) {
1406 if (empty($this->localtax1_tx)) {
1407 $this->localtax1_tx = 0;
1409 if (empty($this->localtax2_tx)) {
1410 $this->localtax2_tx = 0;
1412 if (empty($this->localtax1_type)) {
1413 $this->localtax1_type =
'0';
1415 if (empty($this->localtax2_type)) {
1416 $this->localtax2_type =
'0';
1418 if (empty($this->
status)) {
1421 if (empty($this->status_buy)) {
1422 $this->status_buy = 0;
1425 if (empty($this->country_id)) {
1426 $this->country_id = 0;
1429 if (empty($this->state_id)) {
1430 $this->state_id = 0;
1434 $this->barcode = (empty($this->barcode) ?
'' : trim($this->barcode));
1436 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
1437 $this->accountancy_code_buy_intra = (!empty($this->accountancy_code_buy_intra) ? trim($this->accountancy_code_buy_intra) :
'');
1438 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
1439 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
1440 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
1441 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
1448 if ($action !=
'add') {
1449 $result = $this->
verify();
1457 if (is_null($this->oldcopy) || (is_object($this->oldcopy) && $this->oldcopy->isEmpty())) {
1462 if ($this->
hasbatch() && !$this->oldcopy->hasbatch()) {
1464 $valueforundefinedlot =
'000000';
1469 dol_syslog(
"Flag batch of product id=".$this->
id.
" is set to ON, so we will create missing records into product_batch");
1472 foreach ($this->stock_warehouse as $idW => $ObjW) {
1474 foreach ($ObjW->detail_batch as $detail) {
1475 if ($detail->batch == $valueforundefinedlot || $detail->batch ==
'Undefined') {
1477 $sqlclean =
"DELETE FROM ".$this->db->prefix().
"product_batch WHERE batch in('Undefined', '".$this->db->escape($valueforundefinedlot).
"') AND fk_product_stock = ".((int) $ObjW->id);
1478 $result = $this->db->query($sqlclean);
1486 $qty_batch += $detail->qty;
1490 if ($ObjW->real != $qty_batch) {
1492 $ObjBatch->batch = $valueforundefinedlot;
1493 $ObjBatch->qty = ($ObjW->real - $qty_batch);
1494 $ObjBatch->fk_product_stock = (int) $ObjW->id;
1496 if ($ObjBatch->create($user, 1) < 0) {
1498 $this->errors = $ObjBatch->errors;
1503 if ($ObjLot->fetch(0, $this->id, $valueforundefinedlot) == 0) {
1504 $ObjLot->fk_product = $this->id;
1505 $ObjLot->entity = $this->entity;
1506 $ObjLot->fk_user_creat = $user->id;
1507 $ObjLot->batch = $valueforundefinedlot;
1508 if ($ObjLot->create($user,
true) < 0) {
1510 $this->errors = $ObjLot->errors;
1519 if ($this->barcode == -1) {
1520 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1523 $sql =
"UPDATE ".$this->db->prefix().
"product";
1524 $sql .=
" SET label = '".$this->db->escape($this->label).
"'";
1527 $sql .=
", fk_product_type = ".((int) $this->
type);
1530 $sql .=
", ref = '".$this->db->escape($this->
ref).
"'";
1531 $sql .=
", ref_ext = ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1532 $sql .=
", default_vat_code = ".($this->default_vat_code ?
"'".$this->db->escape($this->default_vat_code).
"'" :
"null");
1533 $sql .=
", tva_tx = ".((float) $this->tva_tx);
1534 $sql .=
", recuperableonly = ".((int) $this->tva_npr);
1535 $sql .=
", localtax1_tx = ".((float) $this->localtax1_tx);
1536 $sql .=
", localtax2_tx = ".((float) $this->localtax2_tx);
1537 $sql .=
", localtax1_type = ".($this->localtax1_type !=
'' ?
"'".$this->db->escape($this->localtax1_type).
"'" :
"'0'");
1538 $sql .=
", localtax2_type = ".($this->localtax2_type !=
'' ?
"'".$this->db->escape($this->localtax2_type).
"'" :
"'0'");
1540 $sql .=
", barcode = ".(empty($this->barcode) ?
"null" :
"'".$this->db->escape($this->barcode).
"'");
1541 $sql .=
", fk_barcode_type = ".(empty($this->barcode_type) ?
"null" : $this->db->escape($this->barcode_type));
1543 $sql .=
", tosell = ".(int) $this->
status;
1544 $sql .=
", tobuy = ".(int) $this->status_buy;
1545 $sql .=
", tobatch = ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : (int) $this->status_batch);
1546 $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);
1547 $sql .=
", batch_mask = '".$this->db->escape($this->batch_mask).
"'";
1549 $sql .=
", finished = ".((!isset($this->finished) || $this->finished < 0 || $this->finished ===
'') ?
"null" : (int) $this->finished);
1550 $sql .=
", fk_default_bom = ".((!isset($this->fk_default_bom) || $this->fk_default_bom < 0 || $this->fk_default_bom ==
'') ?
"null" : (int) $this->fk_default_bom);
1551 $sql .=
", net_measure = ".($this->net_measure !=
'' ?
"'".$this->db->escape($this->net_measure).
"'" :
'null');
1552 $sql .=
", net_measure_units = ".($this->net_measure_units !=
'' ?
"'".$this->db->escape($this->net_measure_units).
"'" :
'null');
1553 $sql .=
", weight = ".($this->weight !=
'' ?
"'".$this->db->escape($this->weight).
"'" :
'null');
1554 $sql .=
", weight_units = ".($this->weight_units !=
'' ?
"'".$this->db->escape($this->weight_units).
"'" :
'null');
1555 $sql .=
", length = ".($this->length !=
'' ?
"'".$this->db->escape($this->length).
"'" :
'null');
1556 $sql .=
", length_units = ".($this->length_units !=
'' ?
"'".$this->db->escape($this->length_units).
"'" :
'null');
1557 $sql .=
", width= ".($this->width !=
'' ?
"'".$this->db->escape($this->width).
"'" :
'null');
1558 $sql .=
", width_units = ".($this->width_units !=
'' ?
"'".$this->db->escape($this->width_units).
"'" :
'null');
1559 $sql .=
", height = ".($this->height !=
'' ?
"'".$this->db->escape($this->height).
"'" :
'null');
1560 $sql .=
", height_units = ".($this->height_units !=
'' ?
"'".$this->db->escape($this->height_units).
"'" :
'null');
1561 $sql .=
", surface = ".($this->surface !=
'' ?
"'".$this->db->escape($this->surface).
"'" :
'null');
1562 $sql .=
", surface_units = ".($this->surface_units !=
'' ?
"'".$this->db->escape($this->surface_units).
"'" :
'null');
1563 $sql .=
", volume = ".($this->volume !=
'' ?
"'".$this->db->escape($this->volume).
"'" :
'null');
1564 $sql .=
", volume_units = ".($this->volume_units !=
'' ?
"'".$this->db->escape($this->volume_units).
"'" :
'null');
1565 $sql .=
", fk_default_warehouse = ".($this->fk_default_warehouse > 0 ? ((int) $this->fk_default_warehouse) :
'null');
1566 $sql .=
", fk_default_workstation = ".($this->fk_default_workstation > 0 ? ((int) $this->fk_default_workstation) :
'null');
1567 $sql .=
", seuil_stock_alerte = ".((isset($this->seuil_stock_alerte) && is_numeric($this->seuil_stock_alerte)) ? (
float) $this->seuil_stock_alerte :
'null');
1568 $sql .=
", description = '".$this->db->escape($this->
description).
"'";
1569 $sql .=
", url = ".($this->url ?
"'".$this->db->escape($this->url).
"'" :
'null');
1570 $sql .=
", customcode = '".$this->db->escape($this->customcode).
"'";
1571 $sql .=
", fk_country = ".($this->country_id > 0 ? (int) $this->country_id :
'null');
1572 $sql .=
", fk_state = ".($this->state_id > 0 ? (int) $this->state_id :
'null');
1573 $sql .=
", lifetime = ".($this->lifetime > 0 ? (int) $this->lifetime :
'null');
1574 $sql .=
", qc_frequency = ".($this->qc_frequency > 0 ? (int) $this->qc_frequency :
'null');
1575 $sql .=
", note = ".(isset($this->note_private) ?
"'".$this->db->escape($this->note_private).
"'" :
'null');
1576 $sql .=
", note_public = ".(isset($this->note_public) ?
"'".$this->db->escape($this->note_public).
"'" :
'null');
1577 $sql .=
", duration = '".$this->db->escape($this->duration_value.$this->duration_unit).
"'";
1579 $sql .=
", accountancy_code_buy = '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1580 $sql .=
", accountancy_code_buy_intra = '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1581 $sql .=
", accountancy_code_buy_export = '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1582 $sql .=
", accountancy_code_sell= '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1583 $sql .=
", accountancy_code_sell_intra= '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1584 $sql .=
", accountancy_code_sell_export= '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1586 $sql .=
", desiredstock = ".((isset($this->desiredstock) && is_numeric($this->desiredstock)) ? (
float) $this->desiredstock :
"null");
1587 $sql .=
", cost_price = ".($this->cost_price !=
'' ? ((float) $this->cost_price) :
'null');
1588 $sql .=
", fk_unit= ".(!$this->fk_unit ?
'NULL' : (int) $this->fk_unit);
1589 $sql .=
", price_autogen = ".(!$this->price_autogen ? 0 : 1);
1590 $sql .=
", fk_price_expression = ".($this->fk_price_expression != 0 ? (int) $this->fk_price_expression :
'NULL');
1591 $sql .=
", fk_user_modif = ".($user->id > 0 ? (int) $user->id :
'NULL');
1592 $sql .=
", mandatory_period = ".((int) $this->mandatory_period);
1594 $sql .=
" WHERE rowid = ".((int) $id);
1596 dol_syslog(get_class($this).
"::update", LOG_DEBUG);
1598 $resql = $this->db->query($sql);
1605 $this->db->rollback();
1614 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " . ((
int) $this->id) .
" AND entity = " . ((
int)
$conf->entity));
1616 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1617 $sql .=
" fk_product";
1619 $sql .=
", accountancy_code_buy";
1620 $sql .=
", accountancy_code_buy_intra";
1621 $sql .=
", accountancy_code_buy_export";
1622 $sql .=
", accountancy_code_sell";
1623 $sql .=
", accountancy_code_sell_intra";
1624 $sql .=
", accountancy_code_sell_export";
1625 $sql .=
") VALUES (";
1626 $sql .= ((int) $this->
id);
1627 $sql .=
", " . ((int)
$conf->entity);
1628 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1629 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1630 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1631 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1632 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1633 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1635 $result = $this->db->query($sql);
1638 $this->error =
'ErrorFailedToUpdateAccountancyForEntity';
1642 if (!$this->
hasbatch() && $this->oldcopy->hasbatch()) {
1644 $sql =
'SELECT pb.qty, ps.fk_entrepot, pb.batch FROM '.MAIN_DB_PREFIX.
'product_batch as pb';
1645 $sql .=
' INNER JOIN '.MAIN_DB_PREFIX.
'product_stock as ps ON (ps.rowid = pb.fk_product_stock)';
1646 $sql .=
' WHERE ps.fk_product = '.(int) $this->
id;
1648 $resql = $this->db->query($sql);
1652 while ($obj = $this->db->fetch_object($resql)) {
1654 $fk_entrepot = $obj->fk_entrepot;
1658 $batch = $obj->batch;
1661 $addOremove = $value > 0 ? 1 : 0;
1662 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1663 $res = $this->
correct_stock_batch($user, $fk_entrepot, abs($value), $addOremove, $label, $price, $dlc, $dluo, $batch, $inventorycode,
'',
null, 0,
null,
true);
1666 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1667 $res = $this->
correct_stock($user, $fk_entrepot, abs($value), (
int) empty($addOremove), $label, $price, $inventorycode,
'',
null, 0);
1686 if (!$error && !$notrigger) {
1688 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
1695 if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) {
1697 if (
$conf->product->dir_output) {
1700 if (file_exists($olddir)) {
1704 $res = @rename($olddir, $newdir);
1706 $langs->load(
"errors");
1707 $this->error = $langs->trans(
'ErrorFailToRenameDir', $olddir, $newdir);
1711 require_once DOL_DOCUMENT_ROOT .
'/ecm/class/ecmfiles.class.php';
1712 $ecmfiles =
new EcmFiles($this->db);
1713 $ecmfiles->updateAfterRename(
"produit/".
dol_sanitizeFileName($this->oldcopy->ref),
"produit/".dol_sanitizeFileName($this->ref));
1720 if (isModEnabled(
'variants')) {
1721 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1725 foreach ($comb->fetchAllByFkProductParent($this->id) as $currcomb) {
1726 $currcomb->updateProperties($this, $user);
1730 $this->db->commit();
1733 $this->db->rollback();
1737 if ($this->db->errno() ==
'DB_ERROR_RECORD_ALREADY_EXISTS') {
1738 $langs->load(
"errors");
1739 if (empty(
$conf->barcode->enabled) || empty($this->barcode)) {
1740 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductAlreadyExists", $this->
ref);
1742 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductBarCodeAlreadyExists", $this->barcode);
1744 $this->errors[] = $this->error;
1745 $this->db->rollback();
1748 $this->error = $langs->trans(
"Error").
" : ".$this->db->error().
" - ".$sql;
1749 $this->errors[] = $this->error;
1750 $this->db->rollback();
1755 $this->db->rollback();
1756 dol_syslog(get_class($this).
"::Update fails verify ".implode(
',', $this->errors), LOG_WARNING);
1768 public function delete(
User $user, $notrigger = 0)
1771 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
1776 if (empty($this->
id)) {
1777 $this->error =
"Object must be fetched before calling delete";
1780 if (($this->
isProduct() && !$user->
hasRight(
'produit',
'supprimer')) || ($this->isService() && !$user->hasRight(
'service',
'supprimer'))) {
1781 $this->error =
"ErrorForbidden";
1786 if (empty($objectisused)) {
1789 if (!$error && empty($notrigger)) {
1791 $result = $this->
call_trigger(
'PRODUCT_DELETE', $user);
1800 $sql =
"DELETE FROM ".$this->db->prefix().
'product_batch';
1801 $sql .=
" WHERE fk_product_stock IN (";
1802 $sql .=
"SELECT rowid FROM ".$this->db->prefix().
'product_stock';
1803 $sql .=
" WHERE fk_product = ".((int) $this->
id).
")";
1805 $result = $this->db->query($sql);
1808 $this->errors[] = $this->db->lasterror();
1814 $elements = array(
'product_fournisseur_price',
'product_price',
'product_lang',
'categorie_product',
'product_stock',
'product_customer_price',
'product_lot');
1815 foreach ($elements as $table) {
1817 $sql =
"DELETE FROM ".$this->db->prefix().$table;
1818 $sql .=
" WHERE fk_product = ".(int) $this->
id;
1820 $result = $this->db->query($sql);
1823 $this->errors[] = $this->db->lasterror();
1830 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1831 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination2ValuePair.class.php';
1836 if ($prodcomb->deleteByFkProductParent($user, $this->id) < 0) {
1838 $this->errors[] =
'Error deleting combinations';
1842 if (!$error && ($prodcomb->fetchByFkProductChild($this->id) > 0) && ($prodcomb->delete($user) < 0)) {
1844 $this->errors[] =
'Error deleting child combination';
1850 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
1851 $sql .=
" WHERE fk_product_pere = ".(int) $this->
id.
" OR fk_product_fils = ".(
int) $this->id;
1853 $result = $this->db->query($sql);
1856 $this->errors[] = $this->db->lasterror();
1865 dol_syslog(get_class($this).
"::delete error -4 ".$this->error, LOG_ERR);
1871 $sqlz =
"DELETE FROM ".$this->db->prefix().
"product";
1872 $sqlz .=
" WHERE rowid = ".(int) $this->
id;
1874 $resultz = $this->db->query($sqlz);
1877 $this->errors[] = $this->db->lasterror();
1893 if ($conf->product->dir_output) {
1894 $dir =
$conf->product->dir_output.
"/".$ref;
1895 if (file_exists($dir)) {
1898 $this->errors[] =
'ErrorFailToDeleteDir';
1906 $this->db->commit();
1909 foreach ($this->errors as $errmsg) {
1910 dol_syslog(get_class($this).
"::delete ".$errmsg, LOG_ERR);
1911 $this->error .= ($this->error ?
', '.$errmsg : $errmsg);
1913 $this->db->rollback();
1917 $this->error =
"ErrorRecordIsUsedCantDelete";
1931 $sellByLabel = $langs->trans(
'SellByDate');
1932 $eatByLabel = $langs->trans(
'EatByDate');
1934 self::SELL_OR_EAT_BY_MANDATORY_ID_NONE => $langs->trans(
'BatchSellOrEatByMandatoryNone'),
1935 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY => $sellByLabel,
1936 self::SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY => $eatByLabel,
1937 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT => $langs->trans(
'BatchSellOrEatByMandatoryAll', $sellByLabel, $eatByLabel),
1948 $sellOrEatByMandatoryLabel =
'';
1951 if (isset($sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory])) {
1952 $sellOrEatByMandatoryLabel = $sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory];
1955 return $sellOrEatByMandatoryLabel;
1968 $langs_available = $langs->get_available_languages(DOL_DOCUMENT_ROOT, 0, 2);
1969 $current_lang = $langs->getDefaultLang();
1971 foreach ($langs_available as $key => $value) {
1972 if ($key == $current_lang) {
1973 $sql =
"SELECT rowid";
1974 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1975 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1976 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
1978 $result = $this->db->query($sql);
1980 if ($this->db->num_rows($result)) {
1981 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
1983 $sql2 .=
" label='".$this->db->escape($this->label).
"',";
1984 $sql2 .=
" description='".$this->db->escape($this->
description).
"'";
1986 $sql2 .=
", note='".$this->db->escape($this->other).
"'";
1988 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
1990 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
1995 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->label).
"',";
1996 $sql2 .=
" '".$this->db->escape($this->
description).
"'";
1998 $sql2 .=
", '".$this->db->escape($this->other).
"'";
2002 dol_syslog(get_class($this).
'::setMultiLangs key = current_lang = '.$key);
2003 if (!$this->db->query($sql2)) {
2004 $this->error = $this->db->lasterror();
2007 } elseif (isset($this->multilangs[$key])) {
2008 if (empty($this->multilangs[$key][
"label"])) {
2009 $this->errors[] = $key .
' : ' . $langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Label"));
2013 $sql =
"SELECT rowid";
2014 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2015 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2016 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
2018 $result = $this->db->query($sql);
2020 if ($this->db->num_rows($result)) {
2021 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
2023 $sql2 .=
" label = '".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
2024 $sql2 .=
" description = '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
2027 $sql2 .=
", note = '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
2029 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
2031 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
2036 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
2037 $sql2 .=
" '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
2040 $sql2 .=
", '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
2046 if ($this->multilangs[
"$key"][
"label"] || $this->multilangs[
"$key"][
"description"]) {
2047 if (!$this->db->query($sql2)) {
2048 $this->error = $this->db->lasterror();
2058 $result = $this->
call_trigger(
'PRODUCT_SET_MULTILANGS', $user);
2060 $this->error = $this->db->lasterror();
2078 $sql =
"DELETE FROM ".$this->db->prefix().
"product_lang";
2079 $sql .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($langtodelete).
"'";
2081 dol_syslog(get_class($this).
'::delMultiLangs', LOG_DEBUG);
2082 $result = $this->db->query($sql);
2085 $result = $this->
call_trigger(
'PRODUCT_DEL_MULTILANGS', $user);
2087 $this->error = $this->db->lasterror();
2088 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
2094 $this->error = $this->db->lasterror();
2095 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
2116 if ($type ==
'buy') {
2117 $field =
'accountancy_code_buy';
2118 } elseif ($type ==
'buy_intra') {
2119 $field =
'accountancy_code_buy_intra';
2120 } elseif ($type ==
'buy_export') {
2121 $field =
'accountancy_code_buy_export';
2122 } elseif ($type ==
'sell') {
2123 $field =
'accountancy_code_sell';
2124 } elseif ($type ==
'sell_intra') {
2125 $field =
'accountancy_code_sell_intra';
2126 } elseif ($type ==
'sell_export') {
2127 $field =
'accountancy_code_sell_export';
2132 $sql =
"UPDATE ".$this->db->prefix().$this->table_element.
" SET ";
2133 $sql .=
"$field = '".$this->db->escape($value).
"'";
2134 $sql .=
" WHERE rowid = ".((int) $this->
id);
2137 $resql = $this->db->query($sql);
2141 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
2148 $this->db->rollback();
2152 $this->$field = $value;
2154 $this->db->commit();
2157 $this->error = $this->db->lasterror();
2158 $this->db->rollback();
2172 $current_lang = $langs->getDefaultLang();
2174 $sql =
"SELECT lang, label, description, note as other";
2175 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2176 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2178 $result = $this->db->query($sql);
2180 while ($obj = $this->db->fetch_object($result)) {
2182 if ($obj->lang == $current_lang) {
2183 $this->label = $obj->label;
2185 $this->other = $obj->other;
2187 $this->multilangs[(string) $obj->lang][
"label"] = $obj->label;
2188 $this->multilangs[(string) $obj->lang][
"description"] = $obj->description;
2189 $this->multilangs[(string) $obj->lang][
"other"] = $obj->other;
2193 $this->error =
"Error: ".$this->db->lasterror().
" - ".$sql;
2206 $testExit = array(
'multiprices',
'multiprices_ttc',
'multiprices_base_type',
'multiprices_min',
'multiprices_min_ttc',
'multiprices_tva_tx',
'multiprices_recuperableonly');
2208 foreach ($testExit as $field) {
2209 if (!isset($this->$field)) {
2212 $tmparray = $this->$field;
2213 if (!isset($tmparray[$level])) {
2219 'level' => $level ? $level : 1,
2220 'multiprices' => (float) $this->multiprices[$level],
2221 'multiprices_ttc' => (
float) $this->multiprices_ttc[$level],
2222 'multiprices_base_type' => $this->multiprices_base_type[$level],
2223 'multiprices_min' => (float) $this->multiprices_min[$level],
2224 'multiprices_min_ttc' => (
float) $this->multiprices_min_ttc[$level],
2225 'multiprices_tva_tx' => (float) $this->multiprices_tva_tx[$level],
2226 'multiprices_recuperableonly' => (
float) $this->multiprices_recuperableonly[$level],
2249 if (empty($this->price_by_qty)) {
2250 $this->price_by_qty = 0;
2254 $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,";
2255 $sql .=
" localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, price_min,price_min_ttc,price_by_qty,entity,fk_price_expression) ";
2256 $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).
",";
2257 $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');
2260 dol_syslog(get_class($this).
"::_log_price", LOG_DEBUG);
2261 $resql = $this->db->query($sql);
2263 $this->error = $this->db->lasterror();
2283 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price_by_qty";
2284 $sql .=
" WHERE fk_product_price = ".((int) $rowid);
2285 $resql = $this->db->query($sql);
2287 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price";
2288 $sql .=
" WHERE rowid=".((int) $rowid);
2289 $resql = $this->db->query($sql);
2293 $this->error = $this->db->lasterror();
2308 public function getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp = 0)
2310 global $hookmanager, $action;
2313 if (is_object($hookmanager)) {
2314 $parameters = array(
'thirdparty_seller' => $thirdparty_seller,
'thirdparty_buyer' => $thirdparty_buyer,
'pqp' => $pqp);
2316 $reshook = $hookmanager->executeHooks(
'getSellPrice', $parameters, $this, $action);
2318 return $hookmanager->resArray;
2323 $tva_tx =
get_default_tva($thirdparty_seller, $thirdparty_buyer, $this->
id);
2324 $tva_npr =
get_default_npr($thirdparty_seller, $thirdparty_buyer, $this->
id);
2325 if (empty($tva_tx)) {
2329 $pu_ht = $this->price;
2330 $pu_ttc = $this->price_ttc;
2331 $price_min = $this->price_min;
2332 $price_base_type = $this->price_base_type;
2336 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2340 $filter = array(
't.fk_product' => $this->
id,
't.fk_soc' => $thirdparty_buyer->id);
2343 $pricebycustomerexist =
false;
2344 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2346 if (count($prodcustprice->lines) > 0) {
2347 $pricebycustomerexist =
true;
2348 $pu_ht =
price($prodcustprice->lines[0]->price);
2349 $price_min =
price($prodcustprice->lines[0]->price_min);
2350 $pu_ttc =
price($prodcustprice->lines[0]->price_ttc);
2351 $price_base_type = $prodcustprice->lines[0]->price_base_type;
2352 $tva_tx = $prodcustprice->lines[0]->tva_tx;
2353 if ($prodcustprice->lines[0]->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2354 $tva_tx .=
' ('.$prodcustprice->lines[0]->default_vat_code.
')';
2356 $tva_npr = $prodcustprice->lines[0]->recuperableonly;
2357 if (empty($tva_tx)) {
2363 if (!$pricebycustomerexist && !empty($thirdparty_buyer->price_level)) {
2364 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
2365 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
2366 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
2367 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
2370 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2371 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2373 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2374 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2376 if (empty($tva_tx)) {
2381 } elseif (
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !empty($thirdparty_buyer->price_level)) {
2382 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
2383 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
2384 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
2385 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
2387 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2388 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2390 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2391 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2393 if (empty($tva_tx)) {
2399 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2403 $filter = array(
't.fk_product' => $this->
id,
't.fk_soc' => $thirdparty_buyer->id);
2405 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2407 if (count($prodcustprice->lines) > 0) {
2408 $pu_ht =
price($prodcustprice->lines[0]->price);
2409 $price_min =
price($prodcustprice->lines[0]->price_min);
2410 $pu_ttc =
price($prodcustprice->lines[0]->price_ttc);
2411 $price_base_type = $prodcustprice->lines[0]->price_base_type;
2412 $tva_tx = $prodcustprice->lines[0]->tva_tx;
2413 if ($prodcustprice->lines[0]->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2414 $tva_tx .=
' ('.$prodcustprice->lines[0]->default_vat_code.
')';
2416 $tva_npr = $prodcustprice->lines[0]->recuperableonly;
2417 if (empty($tva_tx)) {
2424 if ($this->prices_by_qty[0]) {
2427 foreach ($this->prices_by_qty_list[0] as $priceforthequantityarray) {
2428 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2432 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2433 $pu_ht = $priceforthequantityarray[
'unitprice'];
2435 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2442 if ($this->prices_by_qty[$thirdparty_buyer->price_level]) {
2445 foreach ($this->prices_by_qty_list[$thirdparty_buyer->price_level] as $priceforthequantityarray) {
2446 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2450 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2451 $pu_ht = $priceforthequantityarray[
'unitprice'];
2453 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2460 return array(
'pu_ht' => $pu_ht,
'pu_ttc' => $pu_ttc,
'price_min' => $price_min,
'price_base_type' => $price_base_type,
'tva_tx' => $tva_tx,
'tva_npr' => $tva_npr);
2477 public function get_buyprice($prodfournprice, $qty, $product_id = 0, $fourn_ref =
'', $fk_soc = 0)
2480 global $action, $hookmanager;
2483 if (is_object($hookmanager)) {
2484 $parameters = array(
2485 'prodfournprice' => $prodfournprice,
2487 'product_id' => $product_id,
2488 'fourn_ref' => $fourn_ref,
2489 'fk_soc' => $fk_soc,
2492 $reshook = $hookmanager->executeHooks(
'getBuyPrice', $parameters, $this, $action);
2494 return $hookmanager->resArray;
2501 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2502 $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,";
2503 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2504 $sql .=
" pfp.packaging";
2505 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2506 $sql .=
" WHERE pfp.rowid = ".((int) $prodfournprice);
2508 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2510 $sql .=
" ORDER BY pfp.quantity DESC";
2512 dol_syslog(get_class($this).
"::get_buyprice first search by prodfournprice/qty", LOG_DEBUG);
2513 $resql = $this->db->query($sql);
2515 $obj = $this->db->fetch_object($resql);
2516 if ($obj && $obj->quantity > 0) {
2517 if (isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2519 $prod_supplier->product_fourn_price_id = $obj->rowid;
2520 $prod_supplier->id = $obj->fk_product;
2521 $prod_supplier->fourn_qty = $obj->quantity;
2522 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2523 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2525 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2527 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2528 if ($price_result >= 0) {
2529 $obj->price = $price_result;
2532 $this->product_fourn_price_id = $obj->rowid;
2533 $this->buyprice = $obj->price;
2534 $this->fourn_pu = $obj->price / $obj->quantity;
2535 $this->fourn_price_base_type =
'HT';
2536 $this->fourn_socid = $obj->fk_soc;
2537 $this->ref_fourn = $obj->ref_supplier;
2538 $this->ref_supplier = $obj->ref_supplier;
2539 $this->desc_supplier = $obj->desc_supplier;
2540 $this->remise_percent = $obj->remise_percent;
2541 $this->vatrate_supplier = $obj->tva_tx;
2542 $this->default_vat_code_supplier = $obj->default_vat_code;
2543 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2544 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2545 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2546 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2547 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2549 $this->packaging = $obj->packaging;
2551 $result = $obj->fk_product;
2555 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2556 $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,";
2557 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2558 $sql .=
" pfp.packaging";
2559 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2560 $sql .=
" WHERE 1 = 1";
2561 if ($product_id > 0) {
2562 $sql .=
" AND pfp.fk_product = ".((int) $product_id);
2564 if ($fourn_ref !=
'none') {
2565 $sql .=
" AND pfp.ref_fourn = '".$this->db->escape($fourn_ref).
"'";
2568 $sql .=
" AND pfp.fk_soc = ".((int) $fk_soc);
2571 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2573 $sql .=
" ORDER BY pfp.quantity DESC";
2576 dol_syslog(get_class($this).
"::get_buyprice second search from qty/ref/product_id", LOG_DEBUG);
2577 $resql = $this->db->query($sql);
2579 $obj = $this->db->fetch_object($resql);
2580 if ($obj && $obj->quantity > 0) {
2581 if (isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2583 $prod_supplier->product_fourn_price_id = $obj->rowid;
2584 $prod_supplier->id = $obj->fk_product;
2585 $prod_supplier->fourn_qty = $obj->quantity;
2586 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2587 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2589 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2591 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2593 $obj->price = $price_result;
2596 $this->product_fourn_price_id = $obj->rowid;
2597 $this->buyprice = $obj->price;
2598 $this->fourn_qty = $obj->quantity;
2599 $this->fourn_pu = $obj->price / $obj->quantity;
2600 $this->fourn_price_base_type =
'HT';
2601 $this->fourn_socid = $obj->fk_soc;
2602 $this->ref_fourn = $obj->ref_supplier;
2603 $this->ref_supplier = $obj->ref_supplier;
2604 $this->desc_supplier = $obj->desc_supplier;
2605 $this->remise_percent = $obj->remise_percent;
2606 $this->vatrate_supplier = $obj->tva_tx;
2607 $this->default_vat_code_supplier = $obj->default_vat_code;
2608 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2609 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2610 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2611 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2612 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2614 $this->packaging = $obj->packaging;
2616 $result = $obj->fk_product;
2622 $this->error = $this->db->lasterror();
2627 $this->error = $this->db->lasterror();
2651 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)
2657 dol_syslog(get_class($this).
"::update_price id=".$id.
" newprice=".$newprice.
" newpricebase=".$newpricebase.
" newminprice=".$newminprice.
" level=".$level.
" npr=".$newnpr.
" newdefaultvatcode=".$newdefaultvatcode);
2660 if (empty($this->tva_tx)) {
2661 $this->tva_tx = 0.0;
2663 if (empty($newnpr)) {
2666 if (empty($newminprice)) {
2671 if ($newvat ===
null || $newvat ==
'') {
2672 $newvat = (float) $this->tva_tx;
2675 $localtaxtype1 =
'';
2676 $localtaxtype2 =
'';
2681 return $this->
generateMultiprices($user, $newprice, $newpricebase, $newvat, $newnpr, $newpbq);
2684 if (!empty($newminprice) && ($newminprice > $newprice)) {
2685 $this->error =
'ErrorPriceCantBeLowerThanMinPrice';
2689 if ($newprice === 0 || $newprice !==
'') {
2690 if ($newpricebase ==
'TTC') {
2691 $price_ttc = (float)
price2num($newprice,
'MU');
2692 $price = (float)
price2num($newprice) / (1 + ((float) $newvat / 100));
2693 $price = (float)
price2num($price,
'MU');
2695 if ((
string) $newminprice !=
'0') {
2696 $price_min_ttc = (float)
price2num($newminprice,
'MU');
2697 $price_min = (float)
price2num($newminprice) / (1 + ($newvat / 100));
2698 $price_min = (float)
price2num($price_min,
'MU');
2701 $price_min_ttc = 0.0;
2704 $price = (float)
price2num($newprice,
'MU');
2705 $price_ttc = ($newnpr != 1) ? (
float)
price2num($newprice) * (1 + ($newvat / 100)) : $price;
2706 $price_ttc = (float)
price2num($price_ttc,
'MU');
2708 if ((
string) $newminprice !=
'0') {
2709 $price_min = (float)
price2num($newminprice,
'MU');
2710 $price_min_ttc = (float)
price2num($newminprice) * (1 + ($newvat / 100));
2711 $price_min_ttc = (float)
price2num($price_min_ttc,
'MU');
2715 $price_min_ttc = 0.0;
2719 if (count($localtaxes_array) > 0) {
2720 $localtaxtype1 = $localtaxes_array[
'0'];
2721 $localtax1 = $localtaxes_array[
'1'];
2722 $localtaxtype2 = $localtaxes_array[
'2'];
2723 $localtax2 = $localtaxes_array[
'3'];
2726 if (!empty($newdefaultvatcode)) {
2729 $sql =
"SELECT t.rowid, t.code, t.recuperableonly as tva_npr, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
2730 $sql .=
" FROM ".MAIN_DB_PREFIX.
"c_tva as t, ".MAIN_DB_PREFIX.
"c_country as c";
2731 $sql .=
" WHERE t.fk_pays = c.rowid AND c.code = '".$this->db->escape($mysoc->country_code).
"'";
2732 $sql .=
" AND t.taux = ".((float) $newdefaultvatcode).
" AND t.active = 1";
2733 $sql .=
" AND t.code = '".$this->db->escape($newdefaultvatcode).
"'";
2734 $resql = $this->db->query($sql);
2736 $obj = $this->db->fetch_object($resql);
2738 $npr = $obj->tva_npr;
2739 $localtax1 = $obj->localtax1;
2740 $localtax2 = $obj->localtax2;
2741 $localtaxtype1 = $obj->localtax1_type;
2742 $localtaxtype2 = $obj->localtax2_type;
2747 $localtaxtype1 =
'0';
2749 $localtaxtype2 =
'0';
2753 if (empty($localtax1)) {
2756 if (empty($localtax2)) {
2764 $sql =
"UPDATE ".$this->db->prefix().
"product SET";
2765 $sql .=
" price_base_type = '".$this->db->escape($newpricebase).
"',";
2766 $sql .=
" price = ".(float) $price.
",";
2767 $sql .=
" price_ttc = ".(float) $price_ttc.
",";
2768 $sql .=
" price_min = ".(float) $price_min.
",";
2769 $sql .=
" price_min_ttc = ".(float) $price_min_ttc.
",";
2770 $sql .=
" localtax1_tx = ".($localtax1 >= 0 ? (float) $localtax1 :
'NULL').
",";
2771 $sql .=
" localtax2_tx = ".($localtax2 >= 0 ? (float) $localtax2 :
'NULL').
",";
2772 $sql .=
" localtax1_type = ".($localtaxtype1 !=
'' ?
"'".$this->db->escape($localtaxtype1).
"'" :
"'0'").
",";
2773 $sql .=
" localtax2_type = ".($localtaxtype2 !=
'' ?
"'".$this->db->escape($localtaxtype2).
"'" :
"'0'").
",";
2774 $sql .=
" default_vat_code = ".($newdefaultvatcode ?
"'".$this->db->escape($newdefaultvatcode).
"'" :
"null").
",";
2775 $sql .=
" price_label = ".(!empty($price_label) ?
"'".$this->db->escape($price_label).
"'" :
"null").
",";
2776 $sql .=
" tva_tx = ".(float)
price2num($newvat).
",";
2777 $sql .=
" recuperableonly = '".$this->db->escape($newnpr).
"'";
2778 $sql .=
" WHERE rowid = ".((int) $id);
2780 dol_syslog(get_class($this).
"::update_price", LOG_DEBUG);
2781 $resql = $this->db->query($sql);
2783 $this->multiprices[$level] = $price;
2784 $this->multiprices_ttc[$level] = $price_ttc;
2785 $this->multiprices_min[$level] = $price_min;
2786 $this->multiprices_min_ttc[$level] = $price_min_ttc;
2787 $this->multiprices_base_type[$level] = $newpricebase;
2788 $this->multiprices_default_vat_code[$level] = $newdefaultvatcode;
2789 $this->multiprices_tva_tx[$level] = $newvat;
2790 $this->multiprices_recuperableonly[$level] = $newnpr;
2792 $this->
price = $price;
2793 $this->price_label = $price_label;
2794 $this->price_ttc = $price_ttc;
2795 $this->price_min = $price_min;
2796 $this->price_min_ttc = $price_min_ttc;
2797 $this->price_base_type = $newpricebase;
2798 $this->default_vat_code = $newdefaultvatcode;
2799 $this->tva_tx = $newvat;
2800 $this->tva_npr = $newnpr;
2803 $this->localtax1_tx = $localtax1;
2804 $this->localtax2_tx = $localtax2;
2805 $this->localtax1_type = $localtaxtype1;
2806 $this->localtax2_type = $localtaxtype2;
2809 $this->price_by_qty = $newpbq;
2813 if (!empty(array_diff_assoc($newPriceData, $lastPriceData)) || !
getDolGlobalString(
'PRODUIT_MULTIPRICES')) {
2817 $this->level = $level;
2821 $result = $this->
call_trigger(
'PRODUCT_PRICE_MODIFY', $user);
2823 $this->db->rollback();
2829 $this->db->commit();
2831 $this->db->rollback();
2832 $this->error = $this->db->lasterror();
2851 $this->fk_price_expression = $expression_id;
2853 return $this->
update($this->
id, $user);
2868 public function fetch($id = 0, $ref =
'', $ref_ext =
'', $barcode =
'', $ignore_expression = 0, $ignore_price_load = 0, $ignore_lang_load = 0)
2870 include_once DOL_DOCUMENT_ROOT.
'/core/lib/company.lib.php';
2874 dol_syslog(get_class($this).
"::fetch id=".$id.
" ref=".$ref.
" ref_ext=".$ref_ext);
2877 if (!$id && !$ref && !$ref_ext && !$barcode) {
2878 $this->error =
'ErrorWrongParameters';
2879 dol_syslog(get_class($this).
"::fetch ".$this->error, LOG_ERR);
2883 $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,";
2884 $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,";
2885 $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,";
2886 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.last_main_doc,";
2887 $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,";
2889 $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,";
2891 $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,";
2896 $separatedEntityPMP =
false;
2897 $separatedStock =
false;
2898 $visibleWarehousesEntities =
$conf->entity;
2901 $checkPMPPerEntity = $this->db->query(
"SELECT pmp FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = ".((int) $id).
" AND entity = ".(
int)
$conf->entity);
2902 if ($this->db->num_rows($checkPMPPerEntity) > 0) {
2903 $separatedEntityPMP =
true;
2907 $separatedStock =
true;
2908 if (isset($mc->sharings[
'stock']) && !empty($mc->sharings[
'stock'])) {
2909 $visibleWarehousesEntities .=
"," . implode(
",", $mc->sharings[
'stock']);
2912 if ($separatedEntityPMP) {
2913 $sql .=
" ppe.pmp,";
2917 $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,";
2918 $sql .=
" p.fk_price_expression, p.price_autogen, p.model_pdf,";
2919 $sql .=
" p.price_label,";
2920 if ($separatedStock) {
2921 $sql .=
" SUM(sp.reel) as stock";
2925 $sql .=
" FROM ".$this->db->prefix().
"product as p";
2927 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int)
$conf->entity);
2929 if ($separatedStock) {
2930 $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).
"))";
2934 $sql .=
" WHERE p.rowid = ".((int) $id);
2936 $sql .=
" WHERE p.entity IN (".getEntity($this->element).
")";
2938 $sql .=
" AND p.ref = '".$this->db->escape($ref).
"'";
2939 } elseif ($ref_ext) {
2940 $sql .=
" AND p.ref_ext = '".$this->db->escape($ref_ext).
"'";
2941 } elseif ($barcode) {
2942 $sql .=
" AND p.barcode = '".$this->db->escape($barcode).
"'";
2945 if ($separatedStock) {
2946 $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,";
2947 $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,";
2948 $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,";
2949 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
2950 $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,";
2952 $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,";
2954 $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,";
2956 if ($separatedEntityPMP) {
2957 $sql .=
" ppe.pmp,";
2961 $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,";
2962 $sql .=
" p.fk_price_expression, p.price_autogen, p.model_pdf";
2963 $sql .=
" ,p.price_label";
2964 if (!$separatedStock) {
2965 $sql .=
", p.stock";
2969 $resql = $this->db->query($sql);
2971 unset($this->oldcopy);
2973 if ($this->db->num_rows($resql) > 0) {
2974 $obj = $this->db->fetch_object($resql);
2976 $this->
id = $obj->rowid;
2977 $this->
ref = $obj->ref;
2978 $this->ref_ext = $obj->ref_ext;
2979 $this->label = $obj->label;
2981 $this->url = $obj->url;
2982 $this->note_public = $obj->note_public;
2983 $this->note_private = $obj->note_private;
2984 $this->note = $obj->note_private;
2986 $this->
type = $obj->fk_product_type;
2987 $this->price_label = $obj->price_label;
2988 $this->
status = $obj->tosell;
2989 $this->status_buy = $obj->tobuy;
2990 $this->status_batch = $obj->tobatch;
2991 $this->sell_or_eat_by_mandatory = $obj->sell_or_eat_by_mandatory;
2992 $this->batch_mask = $obj->batch_mask;
2994 $this->customcode = $obj->customcode;
2995 $this->country_id = $obj->fk_country;
2996 $this->country_code =
getCountry($this->country_id,
'2', $this->db);
2997 $this->state_id = $obj->fk_state;
2998 $this->lifetime = $obj->lifetime;
2999 $this->qc_frequency = $obj->qc_frequency;
3000 $this->
price = $obj->price;
3001 $this->price_ttc = $obj->price_ttc;
3002 $this->price_min = $obj->price_min;
3003 $this->price_min_ttc = $obj->price_min_ttc;
3004 $this->price_base_type = $obj->price_base_type;
3005 $this->cost_price = isset($obj->cost_price) ? (float) $obj->cost_price :
null;
3006 $this->default_vat_code = $obj->default_vat_code;
3007 $this->tva_tx = $obj->tva_tx;
3009 $this->tva_npr = $obj->tva_npr;
3011 $this->localtax1_tx = $obj->localtax1_tx;
3012 $this->localtax2_tx = $obj->localtax2_tx;
3013 $this->localtax1_type = $obj->localtax1_type;
3014 $this->localtax2_type = $obj->localtax2_type;
3016 $this->finished = $obj->finished;
3017 $this->fk_default_bom = $obj->fk_default_bom;
3019 $this->duration = $obj->duration;
3021 preg_match(
'/(\d+)(\w+)/', $obj->duration, $matches);
3022 $this->duration_value = !empty($matches[1]) ? (int) $matches[1] : 0;
3023 $this->duration_unit = !empty($matches[2]) ? (string) $matches[2] :
null;
3024 $this->canvas = $obj->canvas;
3025 $this->net_measure = $obj->net_measure;
3026 $this->net_measure_units = $obj->net_measure_units;
3027 $this->weight = $obj->weight;
3028 $this->weight_units = (is_null($obj->weight_units) ? 0 : $obj->weight_units);
3029 $this->length = $obj->length;
3030 $this->length_units = (is_null($obj->length_units) ? 0 : $obj->length_units);
3031 $this->width = $obj->width;
3032 $this->width_units = (is_null($obj->width_units) ? 0 : $obj->width_units);
3033 $this->height = $obj->height;
3034 $this->height_units = (is_null($obj->height_units) ? 0 : $obj->height_units);
3036 $this->surface = $obj->surface;
3037 $this->surface_units = (is_null($obj->surface_units) ? 0 : $obj->surface_units);
3038 $this->volume = $obj->volume;
3039 $this->volume_units = (is_null($obj->volume_units) ? 0 : $obj->volume_units);
3040 $this->barcode = $obj->barcode;
3041 $this->barcode_type = $obj->fk_barcode_type;
3043 $this->accountancy_code_buy = $obj->accountancy_code_buy;
3044 $this->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra;
3045 $this->accountancy_code_buy_export = $obj->accountancy_code_buy_export;
3046 $this->accountancy_code_sell = $obj->accountancy_code_sell;
3047 $this->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra;
3048 $this->accountancy_code_sell_export = $obj->accountancy_code_sell_export;
3050 $this->fk_default_warehouse = $obj->fk_default_warehouse;
3051 $this->fk_default_workstation = $obj->fk_default_workstation;
3052 $this->seuil_stock_alerte = $obj->seuil_stock_alerte;
3053 $this->desiredstock = $obj->desiredstock;
3054 $this->stock_reel = $obj->stock;
3055 $this->pmp = $obj->pmp;
3057 $this->date_creation = $this->db->jdate($obj->datec);
3058 $this->date_modification = $this->db->jdate($obj->tms);
3060 $this->import_key = $obj->import_key;
3061 $this->entity = $obj->entity;
3063 $this->ref_ext = $obj->ref_ext;
3064 $this->fk_price_expression = $obj->fk_price_expression;
3065 $this->fk_unit = $obj->fk_unit;
3066 $this->price_autogen = $obj->price_autogen;
3067 $this->model_pdf = $obj->model_pdf;
3068 $this->last_main_doc = $obj->last_main_doc;
3070 $this->mandatory_period = $obj->mandatory_period;
3072 $this->db->free($resql);
3084 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
3085 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3086 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3087 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3088 $sql .=
" ,price_label";
3089 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3090 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3091 $sql .=
" AND price_level=".((int) $i);
3092 $sql .=
" AND fk_product = ".((int) $this->
id);
3093 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3095 $resql = $this->db->query($sql);
3097 $result = $this->db->fetch_array($resql);
3099 $this->multiprices[$i] = $result ? $result[
"price"] :
null;
3100 $this->multiprices_ttc[$i] = $result ? $result[
"price_ttc"] :
null;
3101 $this->multiprices_min[$i] = $result ? $result[
"price_min"] :
null;
3102 $this->multiprices_min_ttc[$i] = $result ? $result[
"price_min_ttc"] :
null;
3103 $this->multiprices_base_type[$i] = $result ? $result[
"price_base_type"] :
null;
3105 $this->multiprices_tva_tx[$i] = $result ? $result[
"tva_tx"].(!empty($result[
'default_vat_code']) ?
' ('.$result[
'default_vat_code'].
')' :
'') :
null;
3106 $this->multiprices_recuperableonly[$i] = $result ? $result[
"recuperableonly"] :
null;
3145 $this->error = $this->db->lasterror;
3151 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY') && empty($ignore_price_load)) {
3152 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3153 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid";
3154 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3155 $sql .=
" WHERE fk_product = ".((int) $this->
id);
3156 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3159 $resql = $this->db->query($sql);
3161 $result = $this->db->fetch_array($resql);
3165 $this->prices_by_qty[0] = $result[
"price_by_qty"];
3166 $this->prices_by_qty_id[0] = $result[
"rowid"];
3168 if ($this->prices_by_qty[0] == 1) {
3169 $sql =
"SELECT rowid,price, unitprice, quantity, remise_percent, remise, remise, price_base_type";
3170 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3171 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[0]);
3172 $sql .=
" ORDER BY quantity ASC";
3174 $resql = $this->db->query($sql);
3176 $resultat = array();
3178 while ($result = $this->db->fetch_array($resql)) {
3179 $resultat[$ii] = array();
3180 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3181 $resultat[$ii][
"price"] = $result[
"price"];
3182 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3183 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3184 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3186 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3189 $this->prices_by_qty_list[0] = $resultat;
3191 $this->error = $this->db->lasterror;
3197 $this->error = $this->db->lasterror;
3200 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') && empty($ignore_price_load)) {
3201 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
3202 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3203 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3204 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
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 $this->error = $this->db->lasterror;
3215 } elseif ($result = $this->db->fetch_array($resql)) {
3216 $this->multiprices[$i] = (!empty($result[
"price"]) ? $result[
"price"] : 0);
3217 $this->multiprices_ttc[$i] = (!empty($result[
"price_ttc"]) ? $result[
"price_ttc"] : 0);
3218 $this->multiprices_min[$i] = (!empty($result[
"price_min"]) ? $result[
"price_min"] : 0);
3219 $this->multiprices_min_ttc[$i] = (!empty($result[
"price_min_ttc"]) ? $result[
"price_min_ttc"] : 0);
3220 $this->multiprices_base_type[$i] = (!empty($result[
"price_base_type"]) ? $result[
"price_base_type"] :
'');
3222 $this->multiprices_tva_tx[$i] = (!empty($result[
"tva_tx"]) ? $result[
"tva_tx"] : 0);
3223 $this->multiprices_recuperableonly[$i] = (!empty($result[
"recuperableonly"]) ? $result[
"recuperableonly"] : 0);
3226 $this->prices_by_qty[$i] = (!empty($result[
"price_by_qty"]) ? $result[
"price_by_qty"] : 0);
3227 $this->prices_by_qty_id[$i] = (!empty($result[
"rowid"]) ? $result[
"rowid"] : 0);
3229 if ($this->prices_by_qty[$i] == 1) {
3230 $sql =
"SELECT rowid, price, unitprice, quantity, remise_percent, remise, price_base_type";
3231 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3232 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[$i]);
3233 $sql .=
" ORDER BY quantity ASC";
3235 $resql = $this->db->query($sql);
3237 $resultat = array();
3239 while ($result = $this->db->fetch_array($resql)) {
3240 $resultat[$ii] = array();
3241 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3242 $resultat[$ii][
"price"] = $result[
"price"];
3243 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3244 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3245 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3246 $resultat[$ii][
"remise"] = $result[
"remise"];
3247 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3250 $this->prices_by_qty_list[$i] = $resultat;
3252 $this->error = $this->db->lasterror;
3260 if (isModEnabled(
'dynamicprices') && !empty($this->fk_price_expression) && empty($ignore_expression)) {
3261 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
3263 $price_result = $priceparser->parseProduct($this);
3264 if ($price_result >= 0) {
3265 $this->
price = $price_result;
3267 $this->price_ttc = (float)
price2num($this->
price) * (1 + ($this->tva_tx / 100));
3268 $this->price_ttc = (float)
price2num($this->price_ttc,
'MU');
3274 $this->stock_warehouse = array();
3281 $this->error = $this->db->lasterror();
3296 global $user, $hookmanager, $action;
3300 foreach (array(
'toconsume',
'consumed',
'toproduce',
'produced') as $role) {
3301 $this->stats_mo[
'customers_'.$role] = 0;
3302 $this->stats_mo[
'nb_'.$role] = 0;
3303 $this->stats_mo[
'qty_'.$role] = 0;
3305 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3306 $sql .=
" SUM(mp.qty) as qty";
3307 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as c";
3308 $sql .=
" INNER JOIN ".$this->db->prefix().
"mrp_production as mp ON mp.fk_mo=c.rowid";
3309 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3310 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3313 $sql .=
" c.entity IN (".getEntity(
'mo').
")";
3315 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3316 $sql .=
" AND mp.role ='".$this->db->escape($role).
"'";
3318 $sql .=
" AND c.fk_soc = ".((int) $socid);
3321 $result = $this->db->query($sql);
3323 $obj = $this->db->fetch_object($result);
3324 $this->stats_mo[
'customers_'.$role] = $obj->nb_customers ? $obj->nb_customers : 0;
3325 $this->stats_mo[
'nb_'.$role] = $obj->nb ? $obj->nb : 0;
3326 $this->stats_mo[
'qty_'.$role] = $obj->qty ?
price2num($obj->qty,
'MS') : 0;
3328 $this->error = $this->db->error();
3333 if (!empty($error)) {
3337 $parameters = array(
'socid' => $socid);
3338 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3340 $this->stats_mo = $hookmanager->resArray[
'stats_mo'];
3356 global $hookmanager, $action;
3360 $this->stats_bom[
'nb_toproduce'] = 0;
3361 $this->stats_bom[
'nb_toconsume'] = 0;
3362 $this->stats_bom[
'qty_toproduce'] = 0;
3363 $this->stats_bom[
'qty_toconsume'] = 0;
3365 $sql =
"SELECT COUNT(DISTINCT b.rowid) as nb_toproduce,";
3366 $sql .=
" SUM(b.qty) as qty_toproduce";
3367 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3368 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom = b.rowid";
3370 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3371 $sql .=
" AND b.fk_product =".((int) $this->
id);
3372 $sql .=
" GROUP BY b.rowid";
3374 $result = $this->db->query($sql);
3376 $obj = $this->db->fetch_object($result);
3377 $this->stats_bom[
'nb_toproduce'] = !empty($obj->nb_toproduce) ? $obj->nb_toproduce : 0;
3378 $this->stats_bom[
'qty_toproduce'] = !empty($obj->qty_toproduce) ?
price2num($obj->qty_toproduce) : 0;
3380 $this->error = $this->db->error();
3384 $sql =
"SELECT COUNT(DISTINCT bl.rowid) as nb_toconsume,";
3385 $sql .=
" SUM(bl.qty) as qty_toconsume";
3386 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3387 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
3389 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3390 $sql .=
" AND bl.fk_product =".((int) $this->
id);
3392 $result = $this->db->query($sql);
3394 $obj = $this->db->fetch_object($result);
3395 $this->stats_bom[
'nb_toconsume'] = !empty($obj->nb_toconsume) ? $obj->nb_toconsume : 0;
3396 $this->stats_bom[
'qty_toconsume'] = !empty($obj->qty_toconsume) ?
price2num($obj->qty_toconsume) : 0;
3398 $this->error = $this->db->error();
3402 if (!empty($error)) {
3406 $parameters = array(
'socid' => $socid);
3407 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3409 $this->stats_bom = $hookmanager->resArray[
'stats_bom'];
3425 global $user, $hookmanager, $action;
3427 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_customers, COUNT(DISTINCT p.rowid) as nb,";
3428 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3429 $sql .=
" FROM ".$this->db->prefix().
"propaldet as pd";
3430 $sql .=
", ".$this->db->prefix().
"propal as p";
3431 $sql .=
", ".$this->db->prefix().
"societe as s";
3432 $sql .=
" WHERE p.rowid = pd.fk_propal";
3433 $sql .=
" AND p.fk_soc = s.rowid";
3434 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
3435 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3436 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3437 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $user->id);
3441 $sql .=
" AND p.fk_soc = ".((int) $socid);
3444 $result = $this->db->query($sql);
3446 $obj = $this->db->fetch_object($result);
3447 $this->stats_propale[
'customers'] = $obj->nb_customers;
3448 $this->stats_propale[
'nb'] = $obj->nb;
3449 $this->stats_propale[
'rows'] = $obj->nb_rows;
3450 $this->stats_propale[
'qty'] = $obj->qty ? $obj->qty : 0;
3455 if (is_array($TFather) && !empty($TFather)) {
3456 foreach ($TFather as &$fatherData) {
3457 $pFather =
new Product($this->db);
3458 $pFather->id = $fatherData[
'id'];
3459 $qtyCoef = $fatherData[
'qty'];
3461 if ($fatherData[
'incdec']) {
3462 $pFather->load_stats_propale($socid);
3464 $this->stats_propale[
'customers'] += $pFather->stats_propale[
'customers'];
3465 $this->stats_propale[
'nb'] += $pFather->stats_propale[
'nb'];
3466 $this->stats_propale[
'rows'] += $pFather->stats_propale[
'rows'];
3467 $this->stats_propale[
'qty'] += $pFather->stats_propale[
'qty'] * $qtyCoef;
3473 $parameters = array(
'socid' => $socid);
3474 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerProposal', $parameters, $this, $action);
3476 $this->stats_propale = $hookmanager->resArray[
'stats_propale'];
3481 $this->error = $this->db->error();
3497 global $user, $hookmanager, $action;
3499 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_suppliers, COUNT(DISTINCT p.rowid) as nb,";
3500 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3501 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as pd";
3502 $sql .=
", ".$this->db->prefix().
"supplier_proposal as p";
3503 $sql .=
", ".$this->db->prefix().
"societe as s";
3504 $sql .=
" WHERE p.rowid = pd.fk_supplier_proposal";
3505 $sql .=
" AND p.fk_soc = s.rowid";
3506 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
3507 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3508 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3509 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $user->id);
3513 $sql .=
" AND p.fk_soc = ".((int) $socid);
3516 $result = $this->db->query($sql);
3518 $obj = $this->db->fetch_object($result);
3519 $this->stats_proposal_supplier[
'suppliers'] = $obj->nb_suppliers;
3520 $this->stats_proposal_supplier[
'nb'] = $obj->nb;
3521 $this->stats_proposal_supplier[
'rows'] = $obj->nb_rows;
3522 $this->stats_proposal_supplier[
'qty'] = $obj->qty ? $obj->qty : 0;
3524 $parameters = array(
'socid' => $socid);
3525 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierProposal', $parameters, $this, $action);
3527 $this->stats_proposal_supplier = $hookmanager->resArray[
'stats_proposal_supplier'];
3532 $this->error = $this->db->error();
3550 global $user, $hookmanager, $action;
3552 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3553 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3554 $sql .=
" FROM ".$this->db->prefix().
"commandedet as cd";
3555 $sql .=
", ".$this->db->prefix().
"commande as c";
3556 $sql .=
", ".$this->db->prefix().
"societe as s";
3557 $sql .=
" WHERE c.rowid = cd.fk_commande";
3558 $sql .=
" AND c.fk_soc = s.rowid";
3559 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'commande').
")";
3560 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3561 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3562 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3565 $sql .=
" AND c.fk_soc = ".((int) $socid);
3567 if ($filtrestatut !=
'') {
3568 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3571 $result = $this->db->query($sql);
3573 $obj = $this->db->fetch_object($result);
3574 $this->stats_commande[
'customers'] = $obj->nb_customers;
3575 $this->stats_commande[
'nb'] = $obj->nb;
3576 $this->stats_commande[
'rows'] = $obj->nb_rows;
3577 $this->stats_commande[
'qty'] = $obj->qty ? $obj->qty : 0;
3582 if (is_array($TFather) && !empty($TFather)) {
3583 foreach ($TFather as &$fatherData) {
3584 $pFather =
new Product($this->db);
3585 $pFather->id = $fatherData[
'id'];
3586 $qtyCoef = $fatherData[
'qty'];
3588 if ($fatherData[
'incdec']) {
3589 $pFather->load_stats_commande($socid, $filtrestatut);
3591 $this->stats_commande[
'customers'] += $pFather->stats_commande[
'customers'];
3592 $this->stats_commande[
'nb'] += $pFather->stats_commande[
'nb'];
3593 $this->stats_commande[
'rows'] += $pFather->stats_commande[
'rows'];
3594 $this->stats_commande[
'qty'] += $pFather->stats_commande[
'qty'] * $qtyCoef;
3606 $sql =
"SELECT SUM(".$this->db->ifsql(
'f.type=2', -1, 1).
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3607 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3608 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON ((el.fk_target = f.rowid AND el.targettype = 'facture' AND sourcetype = 'commande') OR (el.fk_source = f.rowid AND el.targettype = 'commande' AND sourcetype = 'facture'))";
3609 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3610 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3612 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3613 $resql = $this->db->query($sql);
3615 if ($this->db->num_rows($resql) > 0) {
3616 $obj = $this->db->fetch_object($resql);
3617 $adeduire += $obj->count;
3621 $this->stats_commande[
'qty'] -= $adeduire;
3624 include_once DOL_DOCUMENT_ROOT.
'/compta/facture/class/facture.class.php';
3628 $sql =
"SELECT sum(".$this->db->ifsql(
'f.type=2', -1, 1).
" * fd.qty) as count FROM ".MAIN_DB_PREFIX.
"facturedet as fd ";
3629 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"facture as f ON fd.fk_facture = f.rowid";
3630 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"element_element as el ON ((el.fk_target = f.rowid AND el.targettype = 'facture' AND sourcetype = 'commande') OR (el.fk_source = f.rowid AND el.targettype = 'commande' AND sourcetype = 'facture'))";
3631 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"commande as c ON el.fk_source = c.rowid";
3632 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3634 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3635 $resql = $this->db->query($sql);
3637 if ($this->db->num_rows($resql) > 0) {
3638 $obj = $this->db->fetch_object($resql);
3639 $adeduire += $obj->count;
3642 $this->error = $this->db->error();
3646 $this->stats_commande[
'qty'] -= $adeduire;
3650 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3651 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerOrder', $parameters, $this, $action);
3653 $this->stats_commande = $hookmanager->resArray[
'stats_commande'];
3657 $this->error = $this->db->error();
3675 global $user, $hookmanager, $action;
3677 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_suppliers, COUNT(DISTINCT c.rowid) as nb,";
3678 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3679 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as cd";
3680 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as c";
3681 $sql .=
", ".$this->db->prefix().
"societe as s";
3682 $sql .=
" WHERE c.rowid = cd.fk_commande";
3683 $sql .=
" AND c.fk_soc = s.rowid";
3684 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3685 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3686 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3687 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3690 $sql .=
" AND c.fk_soc = ".((int) $socid);
3692 if ($filtrestatut !=
'') {
3693 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3695 if (!empty($dateofvirtualstock)) {
3696 $sql .=
" AND c.date_livraison <= '".$this->db->idate($dateofvirtualstock).
"'";
3699 $result = $this->db->query($sql);
3701 $obj = $this->db->fetch_object($result);
3702 $this->stats_commande_fournisseur[
'suppliers'] = $obj->nb_suppliers;
3703 $this->stats_commande_fournisseur[
'nb'] = $obj->nb;
3704 $this->stats_commande_fournisseur[
'rows'] = $obj->nb_rows;
3705 $this->stats_commande_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
3707 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3708 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierOrder', $parameters, $this, $action);
3710 $this->stats_commande_fournisseur = $hookmanager->resArray[
'stats_commande_fournisseur'];
3715 $this->error = $this->db->error().
' sql='.$sql;
3730 public function load_stats_sending($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $filterShipmentStatus =
'')
3733 global $user, $hookmanager, $action;
3735 $sql =
"SELECT COUNT(DISTINCT e.fk_soc) as nb_customers, COUNT(DISTINCT e.rowid) as nb,";
3736 $sql .=
" COUNT(ed.rowid) as nb_rows, SUM(ed.qty) as qty";
3737 $sql .=
" FROM ".$this->db->prefix().
"expeditiondet as ed";
3738 $sql .=
", ".$this->db->prefix().
"commandedet as cd";
3739 $sql .=
", ".$this->db->prefix().
"commande as c";
3740 $sql .=
", ".$this->db->prefix().
"expedition as e";
3741 $sql .=
", ".$this->db->prefix().
"societe as s";
3742 $sql .=
" WHERE e.rowid = ed.fk_expedition";
3743 $sql .=
" AND c.rowid = cd.fk_commande";
3744 $sql .=
" AND e.fk_soc = s.rowid";
3745 $sql .=
" AND e.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'expedition').
")";
3746 $sql .=
" AND ed.fk_elementdet = cd.rowid";
3747 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3748 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3749 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = e.fk_soc AND sc.fk_user = ".((int) $user->id);
3752 $sql .=
" AND e.fk_soc = ".((int) $socid);
3754 if ($filtrestatut !=
'') {
3755 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3757 if (!empty($filterShipmentStatus)) {
3758 $sql .=
" AND e.fk_statut IN (".$this->db->sanitize($filterShipmentStatus).
")";
3761 $result = $this->db->query($sql);
3763 $obj = $this->db->fetch_object($result);
3764 $this->stats_expedition[
'customers'] = $obj->nb_customers;
3765 $this->stats_expedition[
'nb'] = $obj->nb;
3766 $this->stats_expedition[
'rows'] = $obj->nb_rows;
3767 $this->stats_expedition[
'qty'] = $obj->qty ? $obj->qty : 0;
3772 if (is_array($TFather) && !empty($TFather)) {
3773 foreach ($TFather as &$fatherData) {
3774 $pFather =
new Product($this->db);
3775 $pFather->id = $fatherData[
'id'];
3776 $qtyCoef = $fatherData[
'qty'];
3778 if ($fatherData[
'incdec']) {
3779 $pFather->load_stats_sending($socid, $filtrestatut, $forVirtualStock);
3781 $this->stats_expedition[
'customers'] += $pFather->stats_expedition[
'customers'];
3782 $this->stats_expedition[
'nb'] += $pFather->stats_expedition[
'nb'];
3783 $this->stats_expedition[
'rows'] += $pFather->stats_expedition[
'rows'];
3784 $this->stats_expedition[
'qty'] += $pFather->stats_expedition[
'qty'] * $qtyCoef;
3790 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock,
'filterShipmentStatus' => $filterShipmentStatus);
3791 $reshook = $hookmanager->executeHooks(
'loadStatsSending', $parameters, $this, $action);
3793 $this->stats_expedition = $hookmanager->resArray[
'stats_expedition'];
3798 $this->error = $this->db->error();
3813 public function load_stats_reception($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null)
3816 global $user, $hookmanager, $action;
3818 $sql =
"SELECT COUNT(DISTINCT cf.fk_soc) as nb_suppliers, COUNT(DISTINCT cf.rowid) as nb,";
3819 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
3820 $sql .=
" FROM ".$this->db->prefix().
"receptiondet_batch as fd";
3821 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as cf";
3822 $sql .=
", ".$this->db->prefix().
"societe as s";
3823 $sql .=
" WHERE cf.rowid = fd.fk_element";
3824 $sql .=
" AND cf.fk_soc = s.rowid";
3825 $sql .=
" AND cf.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3826 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3827 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3828 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = cf.fk_soc AND sc.fk_user = ".((int) $user->id);
3831 $sql .=
" AND cf.fk_soc = ".((int) $socid);
3833 if ($filtrestatut !=
'') {
3834 $sql .=
" AND cf.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3836 if (!empty($dateofvirtualstock)) {
3837 $sql .=
" AND fd.datec <= '".$this->db->idate($dateofvirtualstock).
"'";
3840 $result = $this->db->query($sql);
3842 $obj = $this->db->fetch_object($result);
3843 $this->stats_reception[
'suppliers'] = $obj->nb_suppliers;
3844 $this->stats_reception[
'nb'] = $obj->nb;
3845 $this->stats_reception[
'rows'] = $obj->nb_rows;
3846 $this->stats_reception[
'qty'] = $obj->qty ? $obj->qty : 0;
3848 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3849 $reshook = $hookmanager->executeHooks(
'loadStatsReception', $parameters, $this, $action);
3851 $this->stats_reception = $hookmanager->resArray[
'stats_reception'];
3856 $this->error = $this->db->error();
3872 public function load_stats_inproduction($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null, $warehouseid = 0)
3875 global $user, $hookmanager, $action;
3877 $serviceStockIsEnabled = isModEnabled(
"service") &&
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES');
3879 $sql =
"SELECT COUNT(DISTINCT m.fk_soc) as nb_customers, COUNT(DISTINCT m.rowid) as nb,";
3880 $sql .=
" COUNT(mp.rowid) as nb_rows, SUM(mp.qty) as qty, role";
3881 $sql .=
" FROM ".$this->db->prefix().
"mrp_production as mp";
3882 $sql .=
", ".$this->db->prefix().
"mrp_mo as m";
3883 $sql .=
" LEFT JOIN ".$this->db->prefix().
"societe as s ON s.rowid = m.fk_soc";
3884 $sql .=
" WHERE m.rowid = mp.fk_mo";
3885 $sql .=
" AND m.entity IN (".getEntity(($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE')) ?
'stock' :
'mrp').
")";
3886 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3887 $sql .=
" AND (mp.disable_stock_change IN (0) OR mp.disable_stock_change IS NULL)";
3888 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3889 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = m.fk_soc AND sc.fk_user = ".((int) $user->id);
3892 $sql .=
" AND m.fk_soc = ".((int) $socid);
3894 if ($filtrestatut !=
'') {
3895 $sql .=
" AND m.status IN (".$this->db->sanitize($filtrestatut).
")";
3897 if (!empty($dateofvirtualstock)) {
3898 $sql .=
" AND m.date_valid <= '".$this->db->idate($dateofvirtualstock).
"'";
3900 if (!$serviceStockIsEnabled) {
3901 $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))";
3903 if (!empty($warehouseid)) {
3904 $sql .=
" AND m.fk_warehouse = ".((int) $warehouseid);
3906 $sql .=
" GROUP BY role";
3909 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
3911 $this->stats_mrptoconsume[
'customers'] = 0;
3912 $this->stats_mrptoconsume[
'nb'] = 0;
3913 $this->stats_mrptoconsume[
'rows'] = 0;
3914 $this->stats_mrptoconsume[
'qty'] = 0.0;
3915 $this->stats_mrptoproduce[
'customers'] = 0;
3916 $this->stats_mrptoproduce[
'nb'] = 0;
3917 $this->stats_mrptoproduce[
'rows'] = 0;
3918 $this->stats_mrptoproduce[
'qty'] = 0.0;
3921 $result = $this->db->query($sql);
3923 while ($obj = $this->db->fetch_object($result)) {
3924 if ($obj->role ==
'toconsume' && empty($warehouseid)) {
3925 $this->stats_mrptoconsume[
'customers'] += (int) $obj->nb_customers;
3926 $this->stats_mrptoconsume[
'nb'] += (int) $obj->nb;
3927 $this->stats_mrptoconsume[
'rows'] += (int) $obj->nb_rows;
3928 $this->stats_mrptoconsume[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
3930 if ($obj->role ==
'consumed' && empty($warehouseid)) {
3934 $this->stats_mrptoconsume[
'qty'] -= ($obj->qty ? (float) $obj->qty : 0.0);
3936 if ($obj->role ==
'toproduce') {
3938 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
3940 $this->stats_mrptoproduce[
'customers'] += (int) $obj->nb_customers;
3941 $this->stats_mrptoproduce[
'nb'] += (int) $obj->nb;
3942 $this->stats_mrptoproduce[
'rows'] += (int) $obj->nb_rows;
3943 $this->stats_mrptoproduce[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
3946 if ($obj->role ==
'produced') {
3951 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3953 $this->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3960 if ($this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] < 0) {
3961 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
3964 if ($this->stats_mrptoconsume[
'qty'] < 0) {
3965 $this->stats_mrptoconsume[
'qty'] = 0;
3967 if ($this->stats_mrptoproduce[
'qty'] < 0) {
3968 $this->stats_mrptoproduce[
'qty'] = 0;
3972 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3973 $reshook = $hookmanager->executeHooks(
'loadStatsInProduction', $parameters, $this, $action);
3975 $this->stats_mrptoproduce = $hookmanager->resArray[
'stats_mrptoproduce'];
3980 $this->error = $this->db->error();
3995 global $user, $hookmanager, $action;
3997 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3998 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3999 $sql .=
" FROM ".$this->db->prefix().
"contratdet as cd";
4000 $sql .=
", ".$this->db->prefix().
"contrat as c";
4001 $sql .=
", ".$this->db->prefix().
"societe as s";
4002 $sql .=
" WHERE c.rowid = cd.fk_contrat";
4003 $sql .=
" AND c.fk_soc = s.rowid";
4004 $sql .=
" AND c.entity IN (".getEntity(
'contract').
")";
4005 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
4006 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4007 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
4011 $sql .=
" AND c.fk_soc = ".((int) $socid);
4014 $result = $this->db->query($sql);
4016 $obj = $this->db->fetch_object($result);
4017 $this->stats_contrat[
'customers'] = $obj->nb_customers;
4018 $this->stats_contrat[
'nb'] = $obj->nb;
4019 $this->stats_contrat[
'rows'] = $obj->nb_rows;
4020 $this->stats_contrat[
'qty'] = $obj->qty ? $obj->qty : 0;
4025 if (is_array($TFather) && !empty($TFather)) {
4026 foreach ($TFather as &$fatherData) {
4027 $pFather =
new Product($this->db);
4028 $pFather->id = $fatherData[
'id'];
4029 $qtyCoef = $fatherData[
'qty'];
4031 if ($fatherData[
'incdec']) {
4032 $pFather->load_stats_contrat($socid);
4034 $this->stats_contrat[
'customers'] += $pFather->stats_contrat[
'customers'];
4035 $this->stats_contrat[
'nb'] += $pFather->stats_contrat[
'nb'];
4036 $this->stats_contrat[
'rows'] += $pFather->stats_contrat[
'rows'];
4037 $this->stats_contrat[
'qty'] += $pFather->stats_contrat[
'qty'] * $qtyCoef;
4043 $parameters = array(
'socid' => $socid);
4044 $reshook = $hookmanager->executeHooks(
'loadStatsContract', $parameters, $this, $action);
4046 $this->stats_contrat = $hookmanager->resArray[
'stats_contrat'];
4051 $this->error = $this->db->error().
' sql='.$sql;
4066 global $user, $hookmanager, $action;
4068 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4069 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(".$this->db->ifsql(
'f.type != 2',
'fd.qty',
'fd.qty * -1').
") as qty";
4070 $sql .=
" FROM ".$this->db->prefix().
"facturedet as fd";
4071 $sql .=
", ".$this->db->prefix().
"facture as f";
4072 $sql .=
", ".$this->db->prefix().
"societe as s";
4073 $sql .=
" WHERE f.rowid = fd.fk_facture";
4074 $sql .=
" AND f.fk_soc = s.rowid";
4075 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4076 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4077 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4078 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4082 $sql .=
" AND f.fk_soc = ".((int) $socid);
4085 $result = $this->db->query($sql);
4087 $obj = $this->db->fetch_object($result);
4088 $this->stats_facture[
'customers'] = $obj->nb_customers;
4089 $this->stats_facture[
'nb'] = $obj->nb;
4090 $this->stats_facture[
'rows'] = $obj->nb_rows;
4091 $this->stats_facture[
'qty'] = $obj->qty ? $obj->qty : 0;
4096 if (is_array($TFather) && !empty($TFather)) {
4097 foreach ($TFather as &$fatherData) {
4098 $pFather =
new Product($this->db);
4099 $pFather->id = $fatherData[
'id'];
4100 $qtyCoef = $fatherData[
'qty'];
4102 if ($fatherData[
'incdec']) {
4103 $pFather->load_stats_facture($socid);
4105 $this->stats_facture[
'customers'] += $pFather->stats_facture[
'customers'];
4106 $this->stats_facture[
'nb'] += $pFather->stats_facture[
'nb'];
4107 $this->stats_facture[
'rows'] += $pFather->stats_facture[
'rows'];
4108 $this->stats_facture[
'qty'] += $pFather->stats_facture[
'qty'] * $qtyCoef;
4114 $parameters = array(
'socid' => $socid);
4115 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoice', $parameters, $this, $action);
4117 $this->stats_facture = $hookmanager->resArray[
'stats_facture'];
4122 $this->error = $this->db->error();
4138 global $user, $hookmanager, $action;
4140 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4141 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4142 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facturedet_rec as fd";
4143 $sql .=
", ".MAIN_DB_PREFIX.
"facture_rec as f";
4144 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
4145 $sql .=
" WHERE f.rowid = fd.fk_facture";
4146 $sql .=
" AND f.fk_soc = s.rowid";
4147 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4148 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4149 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4150 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4154 $sql .=
" AND f.fk_soc = ".((int) $socid);
4157 $result = $this->db->query($sql);
4159 $obj = $this->db->fetch_object($result);
4160 $this->stats_facturerec[
'customers'] = (int) $obj->nb_customers;
4161 $this->stats_facturerec[
'nb'] = (int) $obj->nb;
4162 $this->stats_facturerec[
'rows'] = (int) $obj->nb_rows;
4163 $this->stats_facturerec[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4168 if (is_array($TFather) && !empty($TFather)) {
4169 foreach ($TFather as &$fatherData) {
4170 $pFather =
new Product($this->db);
4171 $pFather->id = $fatherData[
'id'];
4172 $qtyCoef = $fatherData[
'qty'];
4174 if ($fatherData[
'incdec']) {
4175 $pFather->load_stats_facture($socid);
4177 $this->stats_facturerec[
'customers'] += $pFather->stats_facturerec[
'customers'];
4178 $this->stats_facturerec[
'nb'] += $pFather->stats_facturerec[
'nb'];
4179 $this->stats_facturerec[
'rows'] += $pFather->stats_facturerec[
'rows'];
4180 $this->stats_facturerec[
'qty'] += $pFather->stats_facturerec[
'qty'] * $qtyCoef;
4186 $parameters = array(
'socid' => $socid);
4187 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoiceRec', $parameters, $this, $action);
4189 $this->stats_facturerec = $hookmanager->resArray[
'stats_facturerec'];
4194 $this->error = $this->db->error();
4209 global $user, $hookmanager, $action;
4211 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
4212 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4213 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as fd";
4214 $sql .=
", ".$this->db->prefix().
"facture_fourn as f";
4215 $sql .=
", ".$this->db->prefix().
"societe as s";
4216 $sql .=
" WHERE f.rowid = fd.fk_facture_fourn";
4217 $sql .=
" AND f.fk_soc = s.rowid";
4218 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4219 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4220 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4221 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4225 $sql .=
" AND f.fk_soc = ".((int) $socid);
4228 $result = $this->db->query($sql);
4230 $obj = $this->db->fetch_object($result);
4231 $this->stats_facture_fournisseur[
'suppliers'] = (int) $obj->nb_suppliers;
4232 $this->stats_facture_fournisseur[
'nb'] = (int) $obj->nb;
4233 $this->stats_facture_fournisseur[
'rows'] = (int) $obj->nb_rows;
4234 $this->stats_facture_fournisseur[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4236 $parameters = array(
'socid' => $socid);
4237 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoice', $parameters, $this, $action);
4239 $this->stats_facture_fournisseur = $hookmanager->resArray[
'stats_facture_fournisseur'];
4244 $this->error = $this->db->error();
4263 $resql = $this->db->query($sql);
4265 $num = $this->db->num_rows($resql);
4268 $arr = $this->db->fetch_array($resql);
4269 if (is_array($arr)) {
4270 $keyfortab = (string) $arr[1];
4272 $keyfortab = substr($keyfortab, -2);
4275 if ($mode ==
'byunit') {
4276 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[0];
4277 } elseif ($mode ==
'bynumber') {
4278 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4279 } elseif ($mode ==
'byamount') {
4280 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4289 $this->error = $this->db->error().
' sql='.$sql;
4296 } elseif ($year == -1) {
4305 for ($j = 0; $j < 12; $j++) {
4307 $idx = ucfirst(
dol_trunc(
dol_print_date(
dol_mktime(12, 0, 0, $month, 1, 1970),
"%b"), 1,
'right',
'UTF-8', 1));
4310 $result[$j] = array($idx, isset($tab[$year.$month]) ? $tab[$year.$month] : 0);
4313 $month =
"0".($month - 1);
4315 $month = substr($month, 1);
4323 return array_reverse($result);
4338 public function get_nb_vente($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4343 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4344 if ($mode ==
'bynumber') {
4345 $sql .=
", count(DISTINCT f.rowid)";
4347 $sql .=
", sum(d.total_ht) as total_ht";
4348 $sql .=
" FROM ".$this->db->prefix().
"facturedet as d, ".$this->db->prefix().
"facture as f, ".$this->db->prefix().
"societe as s";
4349 if ($filteronproducttype >= 0) {
4350 $sql .=
", ".$this->db->prefix().
"product as p";
4352 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4353 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4355 $sql .=
" WHERE f.rowid = d.fk_facture";
4356 if ($this->
id > 0) {
4357 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4359 $sql .=
" AND d.fk_product > 0";
4361 if ($filteronproducttype >= 0) {
4362 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4364 $sql .=
" AND f.fk_soc = s.rowid";
4365 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4366 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4367 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4370 $sql .=
" AND f.fk_soc = $socid";
4372 $sql .= $morefilter;
4373 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4374 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4376 return $this->
_get_stats($sql, $mode, $year);
4391 public function get_nb_achat($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4396 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4397 if ($mode ==
'bynumber') {
4398 $sql .=
", count(DISTINCT f.rowid)";
4400 $sql .=
", sum(d.total_ht) as total_ht";
4401 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as d, ".$this->db->prefix().
"facture_fourn as f, ".$this->db->prefix().
"societe as s";
4402 if ($filteronproducttype >= 0) {
4403 $sql .=
", ".$this->db->prefix().
"product as p";
4405 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4406 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4408 $sql .=
" WHERE f.rowid = d.fk_facture_fourn";
4409 if ($this->
id > 0) {
4410 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4412 $sql .=
" AND d.fk_product > 0";
4414 if ($filteronproducttype >= 0) {
4415 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4417 $sql .=
" AND f.fk_soc = s.rowid";
4418 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4419 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4420 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4423 $sql .=
" AND f.fk_soc = $socid";
4425 $sql .= $morefilter;
4426 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4427 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4429 return $this->
_get_stats($sql, $mode, $year);
4443 public function get_nb_propal($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4448 $sql =
"SELECT sum(d.qty) as qty, date_format(p.datep, '%Y%m')";
4449 if ($mode ==
'bynumber') {
4450 $sql .=
", count(DISTINCT p.rowid)";
4452 $sql .=
", sum(d.total_ht) as total_ht";
4453 $sql .=
" FROM ".$this->db->prefix().
"propaldet as d, ".$this->db->prefix().
"propal as p, ".$this->db->prefix().
"societe as s";
4454 if ($filteronproducttype >= 0) {
4455 $sql .=
", ".$this->db->prefix().
"product as prod";
4457 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4458 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4460 $sql .=
" WHERE p.rowid = d.fk_propal";
4461 if ($this->
id > 0) {
4462 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4464 $sql .=
" AND d.fk_product > 0";
4466 if ($filteronproducttype >= 0) {
4467 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4469 $sql .=
" AND p.fk_soc = s.rowid";
4470 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
4471 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4472 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4475 $sql .=
" AND p.fk_soc = ".((int) $socid);
4477 $sql .= $morefilter;
4478 $sql .=
" GROUP BY date_format(p.datep,'%Y%m')";
4479 $sql .=
" ORDER BY date_format(p.datep,'%Y%m') DESC";
4481 return $this->
_get_stats($sql, $mode, $year);
4500 $sql =
"SELECT sum(d.qty) as qty, date_format(p.date_valid, '%Y%m')";
4501 if ($mode ==
'bynumber') {
4502 $sql .=
", count(DISTINCT p.rowid)";
4504 $sql .=
", sum(d.total_ht) as total_ht";
4505 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as d, ".$this->db->prefix().
"supplier_proposal as p, ".$this->db->prefix().
"societe as s";
4506 if ($filteronproducttype >= 0) {
4507 $sql .=
", ".$this->db->prefix().
"product as prod";
4509 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4510 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4512 $sql .=
" WHERE p.rowid = d.fk_supplier_proposal";
4513 if ($this->
id > 0) {
4514 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4516 $sql .=
" AND d.fk_product > 0";
4518 if ($filteronproducttype >= 0) {
4519 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4521 $sql .=
" AND p.fk_soc = s.rowid";
4522 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
4523 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4524 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4527 $sql .=
" AND p.fk_soc = ".((int) $socid);
4529 $sql .= $morefilter;
4530 $sql .=
" GROUP BY date_format(p.date_valid,'%Y%m')";
4531 $sql .=
" ORDER BY date_format(p.date_valid,'%Y%m') DESC";
4533 return $this->
_get_stats($sql, $mode, $year);
4547 public function get_nb_order($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4552 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4553 if ($mode ==
'bynumber') {
4554 $sql .=
", count(DISTINCT c.rowid)";
4556 $sql .=
", sum(d.total_ht) as total_ht";
4557 $sql .=
" FROM ".$this->db->prefix().
"commandedet as d, ".$this->db->prefix().
"commande as c, ".$this->db->prefix().
"societe as s";
4558 if ($filteronproducttype >= 0) {
4559 $sql .=
", ".$this->db->prefix().
"product as p";
4561 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4562 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4564 $sql .=
" WHERE c.rowid = d.fk_commande";
4565 if ($this->
id > 0) {
4566 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4568 $sql .=
" AND d.fk_product > 0";
4570 if ($filteronproducttype >= 0) {
4571 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4573 $sql .=
" AND c.fk_soc = s.rowid";
4574 $sql .=
" AND c.entity IN (".getEntity(
'commande').
")";
4575 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4576 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4579 $sql .=
" AND c.fk_soc = ".((int) $socid);
4581 $sql .= $morefilter;
4582 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4583 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4585 return $this->
_get_stats($sql, $mode, $year);
4604 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4605 if ($mode ==
'bynumber') {
4606 $sql .=
", count(DISTINCT c.rowid)";
4608 $sql .=
", sum(d.total_ht) as total_ht";
4609 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as d, ".$this->db->prefix().
"commande_fournisseur as c, ".$this->db->prefix().
"societe as s";
4610 if ($filteronproducttype >= 0) {
4611 $sql .=
", ".$this->db->prefix().
"product as p";
4613 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4614 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4616 $sql .=
" WHERE c.rowid = d.fk_commande";
4617 if ($this->
id > 0) {
4618 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4620 $sql .=
" AND d.fk_product > 0";
4622 if ($filteronproducttype >= 0) {
4623 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4625 $sql .=
" AND c.fk_soc = s.rowid";
4626 $sql .=
" AND c.entity IN (".getEntity(
'supplier_order').
")";
4627 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4628 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4631 $sql .=
" AND c.fk_soc = ".((int) $socid);
4633 $sql .= $morefilter;
4634 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4635 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4637 return $this->
_get_stats($sql, $mode, $year);
4651 public function get_nb_contract($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4656 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_contrat, '%Y%m')";
4657 if ($mode ==
'bynumber') {
4658 $sql .=
", count(DISTINCT c.rowid)";
4660 $sql .=
", sum(d.total_ht) as total_ht";
4661 $sql .=
" FROM ".$this->db->prefix().
"contratdet as d, ".$this->db->prefix().
"contrat as c, ".$this->db->prefix().
"societe as s";
4662 if ($filteronproducttype >= 0) {
4663 $sql .=
", ".$this->db->prefix().
"product as p";
4665 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4666 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4668 $sql .=
" WHERE c.entity IN (".getEntity(
'contract').
")";
4669 $sql .=
" AND c.rowid = d.fk_contrat";
4671 if ($this->
id > 0) {
4672 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4674 $sql .=
" AND d.fk_product > 0";
4676 if ($filteronproducttype >= 0) {
4677 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4679 $sql .=
" AND c.fk_soc = s.rowid";
4681 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4682 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4685 $sql .=
" AND c.fk_soc = ".((int) $socid);
4687 $sql .= $morefilter;
4688 $sql .=
" GROUP BY date_format(c.date_contrat,'%Y%m')";
4689 $sql .=
" ORDER BY date_format(c.date_contrat,'%Y%m') DESC";
4691 return $this->
_get_stats($sql, $mode, $year);
4705 public function get_nb_mos($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4710 $sql =
"SELECT sum(d.qty), date_format(d.date_valid, '%Y%m')";
4711 if ($mode ==
'bynumber') {
4712 $sql .=
", count(DISTINCT d.rowid)";
4714 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as d LEFT JOIN ".$this->db->prefix().
"societe as s ON d.fk_soc = s.rowid";
4715 if ($filteronproducttype >= 0) {
4716 $sql .=
", ".$this->db->prefix().
"product as p";
4718 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4719 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4722 $sql .=
" WHERE d.entity IN (".getEntity(
'mo').
")";
4723 $sql .=
" AND d.status > 0";
4725 if ($this->
id > 0) {
4726 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4728 $sql .=
" AND d.fk_product > 0";
4730 if ($filteronproducttype >= 0) {
4731 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4734 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4735 $sql .=
" AND d.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4738 $sql .=
" AND d.fk_soc = ".((int) $socid);
4740 $sql .= $morefilter;
4741 $sql .=
" GROUP BY date_format(d.date_valid,'%Y%m')";
4742 $sql .=
" ORDER BY date_format(d.date_valid,'%Y%m') DESC";
4744 return $this->
_get_stats($sql, $mode, $year);
4764 if (!is_numeric($id_pere)) {
4767 if (!is_numeric($id_fils)) {
4770 if (!is_numeric($incdec)) {
4780 $sql =
"SELECT fk_product_pere from ".$this->db->prefix().
"product_association";
4781 $sql .=
" WHERE fk_product_pere = ".((int) $id_fils).
" AND fk_product_fils = ".((int) $id_pere);
4782 if (!$this->db->query($sql)) {
4787 $sql =
"SELECT MAX(rang) as max_rank FROM ".$this->db->prefix().
"product_association";
4788 $sql .=
" WHERE fk_product_pere = ".((int) $id_pere);
4789 $resql = $this->db->query($sql);
4791 $obj = $this->db->fetch_object($resql);
4792 $rank = $obj->max_rank + 1;
4794 $sql =
"INSERT INTO ".$this->db->prefix().
"product_association(fk_product_pere,fk_product_fils,qty,incdec,rang)";
4795 $sql .=
" VALUES (".((int) $id_pere).
", ".((int) $id_fils).
", ".
price2num($qty,
'MS').
", ".((int) $incdec).
", ".((int) $rank).
")";
4796 if (! $this->db->query($sql)) {
4802 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_ADD', $user);
4804 $this->error = $this->db->lasterror();
4805 dol_syslog(get_class($this).
'::addSubproduct error='.$this->error, LOG_ERR);
4837 if (!is_numeric($id_pere)) {
4840 if (!is_numeric($id_fils)) {
4843 if (!is_numeric($incdec)) {
4846 if (!is_numeric($qty)) {
4850 $sql =
'UPDATE '.$this->db->prefix().
'product_association SET ';
4851 $sql .=
'qty = '.price2num($qty,
'MS');
4852 $sql .=
',incdec = '.((int) $incdec);
4853 $sql .=
' WHERE fk_product_pere = '.((int) $id_pere).
' AND fk_product_fils = '.((int) $id_fils);
4855 if (!$this->db->query($sql)) {
4861 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_UPDATE', $user);
4863 $this->error = $this->db->lasterror();
4864 dol_syslog(get_class($this).
'::updateSubproduct error='.$this->error, LOG_ERR);
4888 if (!is_numeric($fk_parent)) {
4891 if (!is_numeric($fk_child)) {
4895 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
4896 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
4897 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
4899 dol_syslog(get_class($this).
'::del_sousproduit', LOG_DEBUG);
4900 if (!$this->db->query($sql)) {
4906 $sqlrank =
"SELECT rowid, rang FROM ".$this->db->prefix().
"product_association";
4907 $sqlrank .=
" WHERE fk_product_pere = ".((int) $fk_parent);
4908 $sqlrank .=
" ORDER BY rang";
4909 $resqlrank = $this->db->query($sqlrank);
4912 while ($objrank = $this->db->fetch_object($resqlrank)) {
4914 $sql =
"UPDATE ".$this->db->prefix().
"product_association";
4915 $sql .=
" SET rang = ".((int) $cpt);
4916 $sql .=
" WHERE rowid = ".((int) $objrank->rowid);
4917 if (! $this->db->query($sql)) {
4926 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_DELETE', $user);
4928 $this->error = $this->db->lasterror();
4929 dol_syslog(get_class($this).
'::delSubproduct error='.$this->error, LOG_ERR);
4949 $sql =
"SELECT fk_product_pere, qty, incdec";
4950 $sql .=
" FROM ".$this->db->prefix().
"product_association";
4951 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
4952 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
4954 $result = $this->db->query($sql);
4956 $num = $this->db->num_rows($result);
4959 $obj = $this->db->fetch_object($result);
4961 $this->is_sousproduit_qty = $obj->qty;
4962 $this->is_sousproduit_incdec = $obj->incdec;
4993 dol_syslog(get_class($this).
"::add_fournisseur id_fourn = ".$id_fourn.
" ref_fourn=".$ref_fourn.
" quantity=".$quantity, LOG_DEBUG);
5000 $sql =
"SELECT rowid, fk_product";
5001 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5002 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5003 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5004 $sql .=
" AND fk_product <> ".((int) $this->
id);
5005 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5007 $resql = $this->db->query($sql);
5009 $obj = $this->db->fetch_object($resql);
5012 $this->product_id_already_linked = $obj->fk_product;
5015 $this->db->free($resql);
5019 $sql =
"SELECT rowid";
5020 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5021 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5023 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5025 $sql .=
" AND (ref_fourn = '' OR ref_fourn IS NULL)";
5027 $sql .=
" AND quantity = ".((float) $quantity);
5028 $sql .=
" AND fk_product = ".((int) $this->
id);
5029 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5031 $resql = $this->db->query($sql);
5033 $obj = $this->db->fetch_object($resql);
5037 $sql =
"INSERT INTO ".$this->db->prefix().
"product_fournisseur_price(";
5040 $sql .=
", fk_product";
5042 $sql .=
", ref_fourn";
5043 $sql .=
", quantity";
5044 $sql .=
", fk_user";
5046 $sql .=
") VALUES (";
5047 $sql .=
"'".$this->db->idate($now).
"'";
5048 $sql .=
", ".((int)
$conf->entity);
5049 $sql .=
", ".((int) $this->
id);
5050 $sql .=
", ".((int) $id_fourn);
5051 $sql .=
", '".$this->db->escape($ref_fourn).
"'";
5052 $sql .=
", ".((float) $quantity);
5053 $sql .=
", ".((int) $user->id);
5057 if ($this->db->query($sql)) {
5058 $this->product_fourn_price_id = $this->db->last_insert_id($this->db->prefix().
"product_fournisseur_price");
5061 $this->error = $this->db->lasterror();
5066 $this->product_fourn_price_id = $obj->rowid;
5070 $this->error = $this->db->lasterror();
5089 $sql =
"SELECT DISTINCT p.fk_soc";
5090 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as p";
5091 $sql .=
" WHERE p.fk_product = ".((int) $this->
id);
5092 $sql .=
" AND p.entity = ".((int)
$conf->entity);
5094 $result = $this->db->query($sql);
5096 $num = $this->db->num_rows($result);
5099 $obj = $this->db->fetch_object($result);
5100 $list[$i] = $obj->fk_soc;
5125 $sql =
"INSERT INTO ".$this->db->prefix().
"product_price (";
5127 $sql .=
", fk_product";
5128 $sql .=
", date_price";
5129 $sql .=
", price_level";
5131 $sql .=
", price_ttc";
5132 $sql .=
", price_min";
5133 $sql .=
", price_min_ttc";
5134 $sql .=
", price_base_type";
5135 $sql .=
", price_label";
5136 $sql .=
", default_vat_code";
5138 $sql .=
", recuperableonly";
5139 $sql .=
", localtax1_tx";
5140 $sql .=
", localtax1_type";
5141 $sql .=
", localtax2_tx";
5142 $sql .=
", localtax2_type";
5143 $sql .=
", fk_user_author";
5145 $sql .=
", price_by_qty";
5146 $sql .=
", fk_price_expression";
5147 $sql .=
", fk_multicurrency";
5148 $sql .=
", multicurrency_code";
5149 $sql .=
", multicurrency_tx";
5150 $sql .=
", multicurrency_price";
5151 $sql .=
", multicurrency_price_ttc";
5156 $sql .=
", '".$this->db->idate($now).
"'";
5157 $sql .=
", price_level";
5159 $sql .=
", price_ttc";
5160 $sql .=
", price_min";
5161 $sql .=
", price_min_ttc";
5162 $sql .=
", price_base_type";
5163 $sql .=
", price_label";
5164 $sql .=
", default_vat_code";
5166 $sql .=
", recuperableonly";
5167 $sql .=
", localtax1_tx";
5168 $sql .=
", localtax1_type";
5169 $sql .=
", localtax2_tx";
5170 $sql .=
", localtax2_type";
5171 $sql .=
", ".$user->id;
5173 $sql .=
", price_by_qty";
5174 $sql .=
", fk_price_expression";
5175 $sql .=
", fk_multicurrency";
5176 $sql .=
", multicurrency_code";
5177 $sql .=
", multicurrency_tx";
5178 $sql .=
", multicurrency_price";
5179 $sql .=
", multicurrency_price_ttc";
5180 $sql .=
" FROM ".$this->db->prefix().
"product_price ps";
5181 $sql .=
" WHERE fk_product = ".((int) $fromId);
5182 $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)";
5183 $sql .=
" ORDER BY date_price DESC";
5186 $resql = $this->db->query($sql);
5188 $this->db->rollback();
5192 $this->db->commit();
5209 $sql =
'INSERT INTO '.$this->db->prefix().
'product_association (fk_product_pere, fk_product_fils, qty, incdec)';
5210 $sql .=
" SELECT ".$toId.
", fk_product_fils, qty, incdec FROM ".$this->db->prefix().
"product_association";
5211 $sql .=
" WHERE fk_product_pere = ".((int) $fromId);
5213 dol_syslog(get_class($this).
'::clone_association', LOG_DEBUG);
5214 if (!$this->db->query($sql)) {
5215 $this->db->rollback();
5219 $this->db->commit();
5252 $sql =
"INSERT ".$this->db->prefix().
"product_fournisseur_price (";
5253 $sql .=
" datec, fk_product, fk_soc, price, quantity, fk_user, tva_tx)";
5254 $sql .=
" SELECT '".$this->db->idate($now).
"', ".((int) $toId).
", fk_soc, price, quantity, fk_user, tva_tx";
5255 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5256 $sql .=
" WHERE fk_product = ".((int) $fromId);
5258 dol_syslog(get_class($this).
'::clone_fournisseurs', LOG_DEBUG);
5259 $resql = $this->db->query($sql);
5261 $this->db->rollback();
5264 $this->db->commit();
5282 public function fetch_prod_arbo($prod, $compl_path =
'', $multiply = 1, $level = 1, $id_parent = 0, $ignore_stock_load = 0)
5288 foreach ($prod as $id_product => $desc_pere) {
5289 if (is_array($desc_pere)) {
5290 $id = (!empty($desc_pere[0]) ? $desc_pere[0] :
'');
5291 $nb = (!empty($desc_pere[1]) ? $desc_pere[1] :
'');
5292 $type = (!empty($desc_pere[2]) ? $desc_pere[2] :
'');
5293 $label = (!empty($desc_pere[3]) ? $desc_pere[3] :
'');
5294 $incdec = (!empty($desc_pere[4]) ? $desc_pere[4] : 0);
5296 if ($multiply < 1) {
5301 if (is_null($tmpproduct)) {
5302 $tmpproduct =
new Product($this->db);
5304 $tmpproduct->fetch($id);
5306 if (empty($ignore_stock_load) && ($tmpproduct->isProduct() ||
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES'))) {
5307 $tmpproduct->load_stock(
'nobatch,novirtual');
5310 $this->res[] = array(
5312 'id_parent' => $id_parent,
5313 'ref' => $tmpproduct->ref,
5315 'nb_total' => $nb * $multiply,
5316 'stock' => $tmpproduct->stock_reel,
5317 'stock_alert' => $tmpproduct->seuil_stock_alerte,
5319 'fullpath' => $compl_path.$label,
5321 'desiredstock' => $tmpproduct->desiredstock,
5323 'incdec' => $incdec,
5324 'entity' => $tmpproduct->entity
5328 if (isset($desc_pere[
'childs']) && is_array($desc_pere[
'childs'])) {
5330 $this->
fetch_prod_arbo($desc_pere[
'childs'], $compl_path.$desc_pere[3].
" -> ", $desc_pere[1] * $multiply, $level + 1, $id, $ignore_stock_load);
5348 $this->res = array();
5349 if (isset($this->sousprods) && is_array($this->sousprods)) {
5350 foreach ($this->sousprods as $prod_name => $desc_product) {
5351 if (is_array($desc_product)) {
5352 $this->
fetch_prod_arbo($desc_product,
"", $multiply, 1, $this->
id, $ignore_stock_load);
5371 $sql =
"SELECT COUNT(pa.rowid) as nb";
5372 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa";
5374 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id).
" OR pa.fk_product_pere = ".((int) $this->
id);
5375 } elseif ($mode == -1) {
5376 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id);
5377 } elseif ($mode == 1) {
5378 $sql .=
" WHERE pa.fk_product_pere = ".((int) $this->
id);
5381 $resql = $this->db->query($sql);
5383 $obj = $this->db->fetch_object($resql);
5402 $sql =
"SELECT count(rowid) as nb FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_parent = ".((int) $this->
id);
5403 $sql .=
" AND entity IN (".getEntity(
'product').
")";
5405 $resql = $this->db->query($sql);
5407 $obj = $this->db->fetch_object($resql);
5424 if (isModEnabled(
'variants')) {
5425 $sql =
"SELECT rowid FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_child = ".((int) $this->
id).
" AND entity IN (".
getEntity(
'product').
")";
5427 $query = $this->db->query($sql);
5430 if (!$this->db->num_rows($query)) {
5451 $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";
5452 $sql .=
", p.tosell as status, p.tobuy as status_buy";
5453 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa,";
5454 $sql .=
" ".$this->db->prefix().
"product as p";
5455 $sql .=
" WHERE p.rowid = pa.fk_product_pere";
5456 $sql .=
" AND pa.fk_product_fils = ".((int) $this->
id);
5458 $res = $this->db->query($sql);
5461 while ($record = $this->db->fetch_array($res)) {
5463 $prods[$record[
'id']] = array();
5464 $prods[$record[
'id']][
'id'] = $record[
'rowid'];
5465 $prods[$record[
'id']][
'ref'] = $record[
'ref'];
5466 $prods[$record[
'id']][
'label'] = $record[
'label'];
5467 $prods[$record[
'id']][
'qty'] = $record[
'qty'];
5468 $prods[$record[
'id']][
'incdec'] = $record[
'incdec'];
5469 $prods[$record[
'id']][
'fk_product_type'] = $record[
'fk_product_type'];
5470 $prods[$record[
'id']][
'entity'] = $record[
'entity'];
5471 $prods[$record[
'id']][
'status'] = $record[
'status'];
5472 $prods[$record[
'id']][
'status_buy'] = $record[
'status_buy'];
5491 public function getChildsArbo($id, $firstlevelonly = 0, $level = 1, $parents = array())
5497 $sql =
"SELECT p.rowid, p.ref, p.label as label, p.fk_product_type,";
5498 $sql .=
" pa.qty as qty, pa.fk_product_fils as id, pa.incdec,";
5499 $sql .=
" pa.rowid as fk_association, pa.rang";
5500 $sql .=
" FROM ".$this->db->prefix().
"product as p,";
5501 $sql .=
" ".$this->db->prefix().
"product_association as pa";
5502 $sql .=
" WHERE p.rowid = pa.fk_product_fils";
5503 $sql .=
" AND pa.fk_product_pere = ".((int) $id);
5504 $sql .=
" AND pa.fk_product_fils <> ".((int) $id);
5505 $sql .=
" ORDER BY pa.rang";
5507 dol_syslog(get_class($this).
'::getChildsArbo id='.$id.
' level='.$level.
' parents='.(is_array($parents) ? implode(
',', $parents) : $parents), LOG_DEBUG);
5514 $res = $this->db->query($sql);
5517 if ($this->db->num_rows($res) > 0) {
5521 while ($rec = $this->db->fetch_array($res)) {
5522 if (in_array($rec[
'id'], $parents)) {
5523 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);
5527 $prods[$rec[
'rowid']] = array(
5530 2 => $rec[
'fk_product_type'],
5531 3 => $this->db->escape($rec[
'label']),
5532 4 => $rec[
'incdec'],
5534 6 => $rec[
'fk_association'],
5539 if (empty($firstlevelonly)) {
5540 $listofchilds = $this->
getChildsArbo($rec[
'rowid'], 0, $level + 1, $parents);
5541 foreach ($listofchilds as $keyChild => $valueChild) {
5542 $prods[$rec[
'rowid']][
'childs'][$keyChild] = $valueChild;
5566 foreach ($this->
getChildsArbo($this->
id) as $keyChild => $valueChild) {
5567 $parent[$this->label][$keyChild] = $valueChild;
5569 foreach ($parent as $key => $value) {
5570 $this->sousprods[$key] = $value;
5583 global
$conf, $langs, $user;
5585 $langs->loadLangs(array(
'products',
'other'));
5588 $nofetch = !empty($params[
'nofetch']);
5591 return [
'optimize' => $langs->trans(
"ShowProduct")];
5595 $permissiontoreadproduct = 0;
5596 if ($this->
type == self::TYPE_PRODUCT && $user->hasRight(
'product',
'read')) {
5597 $permissiontoreadproduct = 1;
5599 if ($this->
type == self::TYPE_SERVICE && $user->hasRight(
'service',
'read')) {
5600 $permissiontoreadproduct = 1;
5603 if (!empty($this->entity) && $permissiontoreadproduct) {
5604 $tmpphoto = $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 80, 0, 0, 0, 0,
'1');
5605 if ($this->nbphoto > 0) {
5606 $datas[
'photo'] =
'<div class="photointooltip floatright">'.
"\n" . $tmpphoto .
'</div>';
5611 $datas[
'picto'] =
img_picto(
'',
'product').
' <u class="paddingrightonly">'.$langs->trans(
"Product").
'</u>';
5613 $datas[
'picto'] =
img_picto(
'',
'service').
' <u class="paddingrightonly">'.$langs->trans(
"Service").
'</u>';
5615 if (isset($this->
status) && isset($this->status_buy)) {
5616 $datas[
'status'] =
' '.$this->getLibStatut(5, 0) .
' '.$this->getLibStatut(5, 1);
5619 if (!empty($this->
ref)) {
5620 $datas[
'ref'] =
'<br><b>'.$langs->trans(
'ProductRef').
':</b> '.$this->ref;
5622 if (!empty($this->label)) {
5623 $datas[
'label'] =
'<br><b>'.$langs->trans(
'ProductLabel').
':</b> '.$this->label;
5626 if ($permissiontoreadproduct) {
5631 if (isModEnabled(
'productbatch')) {
5632 $langs->load(
"productbatch");
5633 $datas[
'batchstatus'] =
"<br><b>".$langs->trans(
"ManageLotSerial").
'</b>: '.$this->
getLibStatut(0, 2);
5634 if ($this->status_batch) {
5635 $datas[
'batchdlc'] =
"<br><b>".$langs->trans(
"BatchSellOrEatByMandatoryList", $langs->transnoentitiesnoconv(
"SellByDate"), $langs->transnoentitiesnoconv(
"EatByDate")).
'</b>: '.$this->
getSellOrEatByMandatoryLabel();
5639 if (isModEnabled(
'barcode')) {
5640 $datas[
'barcode'] =
'<br><b>'.$langs->trans(
'BarCode').
':</b> '.$this->barcode;
5644 if ($this->weight) {
5645 $datas[
'weight'] =
"<br><b>".$langs->trans(
"Weight").
'</b>: '.$this->weight.
' '.
measuringUnitString(0,
"weight", $this->weight_units);
5648 if ($this->length) {
5649 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Length").
'</b>: '.$this->length.
' '.
measuringUnitString(0,
'size', $this->length_units);
5652 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Width").
'</b>: '.$this->width.
' '.
measuringUnitString(0,
'size', $this->width_units);
5654 if ($this->height) {
5655 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Height").
'</b>: '.$this->height.
' '.
measuringUnitString(0,
'size', $this->height_units);
5658 $datas[
'size'] =
"<br>".$labelsize;
5661 $labelsurfacevolume =
"";
5662 if ($this->surface) {
5663 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Surface").
'</b>: '.$this->surface.
' '.
measuringUnitString(0,
'surface', $this->surface_units);
5665 if ($this->volume) {
5666 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Volume").
'</b>: '.$this->volume.
' '.
measuringUnitString(0,
'volume', $this->volume_units);
5668 if ($labelsurfacevolume) {
5669 $datas[
'surface'] =
"<br>" . $labelsurfacevolume;
5672 if ($this->
isService() && !empty($this->duration_value)) {
5674 $datas[
'duration'] =
'<br><b>'.$langs->trans(
"Duration").
':</b> '.$this->duration_value;
5675 if ($this->duration_value > 1) {
5676 $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"));
5677 } elseif ($this->duration_value > 0) {
5678 $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"));
5680 $datas[
'duration'] .= (!empty($this->duration_unit) && isset($dur[$this->duration_unit]) ?
" ".$langs->trans($dur[$this->duration_unit]) :
'');
5682 if (empty($user->socid)) {
5683 if (!empty($this->pmp) && $this->pmp) {
5684 $datas[
'pmp'] =
"<br><b>".$langs->trans(
"PMPValue").
'</b>: '.
price($this->pmp, 0,
'', 1, -1, -1,
$conf->currency);
5687 if (isModEnabled(
'accounting')) {
5688 if ($this->
status && isset($this->accountancy_code_sell)) {
5689 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5690 $selllabel =
'<br>';
5691 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellCode').
':</b> '.
length_accountg($this->accountancy_code_sell);
5692 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellIntraCode').
':</b> '.
length_accountg($this->accountancy_code_sell_intra);
5693 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellExportCode').
':</b> '.
length_accountg($this->accountancy_code_sell_export);
5694 $datas[
'accountancysell'] = $selllabel;
5696 if ($this->status_buy && isset($this->accountancy_code_buy)) {
5697 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5699 if (empty($this->
status)) {
5700 $buylabel .=
'<br>';
5702 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyCode').
':</b> '.
length_accountg($this->accountancy_code_buy);
5703 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyIntraCode').
':</b> '.
length_accountg($this->accountancy_code_buy_intra);
5704 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyExportCode').
':</b> '.
length_accountg($this->accountancy_code_buy_export);
5705 $datas[
'accountancybuy'] = $buylabel;
5710 if (isModEnabled(
'category') && !$nofetch) {
5711 require_once DOL_DOCUMENT_ROOT .
'/categories/class/categorie.class.php';
5712 $form =
new Form($this->db);
5713 $datas[
'categories'] =
'<br>' . $form->showCategories($this->
id, Categorie::TYPE_PRODUCT, 1);
5733 public function getNomUrl($withpicto = 0, $option =
'', $maxlength = 0, $save_lastsearch_value = -1, $notooltip = 0, $morecss =
'', $add_label = 0, $sep =
' - ')
5735 global $langs, $hookmanager;
5737 include_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
5741 $newref = $this->ref;
5743 $newref =
dol_trunc($newref, $maxlength,
'middle');
5747 'objecttype' => ($this->
type == 1 ?
'service' :
'product'),
5748 'option' => $option,
5751 $classfortooltip =
'classfortooltip';
5754 $classfortooltip =
'classforajaxtooltip';
5755 $dataparams =
' data-params="'.dol_escape_htmltag(json_encode($params)).
'"';
5762 if (empty($notooltip)) {
5764 $label = $langs->trans(
"ShowProduct");
5765 $linkclose .=
' alt="'.dol_escape_htmltag($label, 1, 1).
'"';
5767 $linkclose .= ($label ?
' title="'.dol_escape_htmltag($label, 1, 1).
'"' :
' title="tocomplete"');
5768 $linkclose .= $dataparams.
' class="nowraponall '.$classfortooltip.($morecss ?
' '.$morecss :
'').
'"';
5770 $linkclose =
' class="nowraponall'.($morecss ?
' '.$morecss :
'').
'"';
5773 if ($option ==
'supplier' || $option ==
'category') {
5774 $url = DOL_URL_ROOT.
'/product/price_suppliers.php?id='.$this->id;
5775 } elseif ($option ==
'stock') {
5776 $url = DOL_URL_ROOT.
'/product/stock/product.php?id='.$this->id;
5777 } elseif ($option ==
'composition') {
5778 $url = DOL_URL_ROOT.
'/product/composition/card.php?id='.$this->id;
5780 $url = DOL_URL_ROOT.
'/product/card.php?id='.$this->id;
5783 if ($option !==
'nolink') {
5785 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
5786 if ($save_lastsearch_value == -1 && isset($_SERVER[
"PHP_SELF"]) && preg_match(
'/list\.php/', $_SERVER[
"PHP_SELF"])) {
5787 $add_save_lastsearch_values = 1;
5789 if ($add_save_lastsearch_values) {
5790 $url .=
'&save_lastsearch_values=1';
5794 $linkstart =
'<a href="'.$url.
'"';
5795 $linkstart .= $linkclose.
'>';
5798 $result .= $linkstart;
5801 $result .= (
img_object(($notooltip ?
'' : $label),
'product',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
5804 $result .= (
img_object(($notooltip ?
'' : $label),
'service',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
5807 $result .=
'<span class="aaa">'.dol_escape_htmltag($newref).
'</span>';
5808 $result .= $linkend;
5809 if ($withpicto != 2) {
5810 $result .= (($add_label && $this->label) ? $sep.dol_trunc($this->label, ($add_label > 1 ? $add_label : 0)) :
'');
5814 $hookmanager->initHooks(array(
'productdao'));
5815 $parameters = array(
'id' => $this->
id,
'getnomurl' => &$result,
'label' => &$label);
5816 $reshook = $hookmanager->executeHooks(
'getNomUrl', $parameters, $this, $action);
5818 $result = $hookmanager->resPrint;
5820 $result .= $hookmanager->resPrint;
5837 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
5841 $langs->load(
"products");
5842 $outputlangs->load(
"products");
5849 $modelpath =
"core/modules/product/doc/";
5851 return $this->
commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
5867 return $this->
LibStatut($this->status_buy, $mode, $type);
5869 return $this->
LibStatut($this->status_batch, $mode, $type);
5872 return $this->
LibStatut($this->status_buy, $mode, $type);
5890 $labelStatus = $labelStatusShort =
'';
5892 $langs->load(
'products');
5893 if (isModEnabled(
'productbatch')) {
5894 $langs->load(
"productbatch");
5900 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial')));
5903 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort')));
5908 return dolGetStatus($langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch'),
'',
'', empty($status) ?
'status5' :
'status4', 3,
'dot');
5914 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'));
5918 $statuttrans = empty($status) ?
'status5' :
'status4';
5923 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSellShort');
5924 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSell');
5925 } elseif ($type == 1) {
5926 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuyShort');
5927 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuy');
5928 } elseif ($type == 2) {
5929 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch');
5930 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort');
5932 } elseif ($status == 1) {
5935 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSellShort');
5936 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSell');
5937 } elseif ($type == 1) {
5938 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBuyShort');
5939 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBuy');
5940 } elseif ($type == 2) {
5941 $labelStatus = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial'));
5942 $labelStatusShort = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort'));
5944 } elseif ($type == 2 && $status == 2) {
5945 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSerial');
5946 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort');
5950 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'),
'',
'',
'status0', 0);
5952 return dolGetStatus($labelStatus, $labelStatusShort,
'', $statuttrans, $mode);
5966 $langs->load(
'products');
5969 if (isset($this->finished) && $this->finished >= 0) {
5970 $sql =
"SELECT label, code FROM ".$this->db->prefix().
"c_product_nature where code = ".((int) $this->finished).
" AND active=1";
5971 $resql = $this->db->query($sql);
5973 $this->error = $this->db->error().
' sql='.$sql;
5974 dol_syslog(__METHOD__.
' Error '.$this->error, LOG_ERR);
5976 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
5977 $label = $langs->trans($res[
'label']);
5979 $this->db->free($resql);
6003 public function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label =
'', $price = 0, $inventorycode =
'', $origin_element =
'', $origin_id =
null, $disablestockchangeforsubproduct = 0, $extrafields =
null)
6009 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6015 $nbpiece = abs($nbpiece);
6018 $op[0] =
"+".trim((
string) $nbpiece);
6019 $op[1] =
"-".trim((
string) $nbpiece);
6022 $movementstock->setOrigin($origin_element, $origin_id);
6023 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'',
'',
'',
'',
false, 0, $disablestockchangeforsubproduct);
6027 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6028 $movementstock->array_options = $array_options;
6029 $movementstock->insertExtraFields();
6031 $this->db->commit();
6034 $this->error = $movementstock->error;
6035 $this->errors = $movementstock->errors;
6037 $this->db->rollback();
6066 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)
6072 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6078 $nbpiece = abs($nbpiece);
6082 $op[0] =
"+".trim((
string) $nbpiece);
6083 $op[1] =
"-".trim((
string) $nbpiece);
6086 $movementstock->setOrigin($origin_element, $origin_id);
6087 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'', $dlc, $dluo, $lot,
false, 0, $disablestockchangeforsubproduct, 0, $force_update_batch);
6091 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6092 $movementstock->array_options = $array_options;
6093 $movementstock->insertExtraFields();
6095 $this->db->commit();
6098 $this->error = $movementstock->error;
6099 $this->errors = $movementstock->errors;
6101 $this->db->rollback();
6121 public function load_stock($option =
'', $includedraftpoforvirtual =
null, $dateofvirtualstock =
null)
6124 $this->stock_reel = 0;
6125 $this->stock_warehouse = array();
6126 $this->stock_theorique = 0;
6129 $warehouseStatus = array();
6130 if (preg_match(
'/warehouseclosed/', $option)) {
6133 if (preg_match(
'/warehouseopen/', $option)) {
6136 if (preg_match(
'/warehouseinternal/', $option)) {
6144 $sql =
"SELECT ps.rowid, ps.reel, ps.fk_entrepot";
6145 $sql .=
" FROM ".$this->db->prefix().
"product_stock as ps";
6146 $sql .=
", ".$this->db->prefix().
"entrepot as w";
6147 $sql .=
" WHERE w.entity IN (".getEntity(
'stock').
")";
6148 $sql .=
" AND w.rowid = ps.fk_entrepot";
6149 $sql .=
" AND ps.fk_product = ".((int) $this->
id);
6150 if (count($warehouseStatus)) {
6151 $sql .=
" AND w.statut IN (".$this->db->sanitize(implode(
',', $warehouseStatus)).
")";
6154 $sql .=
" ORDER BY ps.reel ".(getDolGlobalString(
'DO_NOT_TRY_TO_DEFRAGMENT_STOCKS_WAREHOUSE') ?
'DESC' :
'ASC');
6156 dol_syslog(get_class($this).
"::load_stock", LOG_DEBUG);
6157 $result = $this->db->query($sql);
6159 $num = $this->db->num_rows($result);
6163 $row = $this->db->fetch_object($result);
6164 $this->stock_warehouse[$row->fk_entrepot] =
new stdClass();
6165 $this->stock_warehouse[$row->fk_entrepot]->real = $row->reel;
6166 $this->stock_warehouse[$row->fk_entrepot]->id = $row->rowid;
6167 if ((!preg_match(
'/nobatch/', $option)) && $this->
hasbatch()) {
6168 $this->stock_warehouse[$row->fk_entrepot]->detail_batch =
Productbatch::findAll($this->db, $row->rowid, 1, $this->id);
6170 $this->stock_reel += $row->reel;
6173 $this->stock_reel = (float)
price2num($this->stock_reel,
'MS');
6175 $this->db->free($result);
6177 if (!preg_match(
'/novirtual/', $option)) {
6183 $this->error = $this->db->lasterror();
6202 global $hookmanager, $action;
6204 $stock_commande_client = 0;
6205 $stock_commande_fournisseur = 0;
6206 $stock_sending_client = 0;
6207 $stock_reception_fournisseur = 0;
6208 $stock_inproduction = 0;
6212 if (isModEnabled(
'order')) {
6217 $stock_commande_client = $this->stats_commande[
'qty'];
6219 if (isModEnabled(
"shipping")) {
6220 require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expedition.class.php';
6221 $filterShipmentStatus =
'';
6231 $stock_sending_client = $this->stats_expedition[
'qty'];
6234 if (isModEnabled(
"supplier_order")) {
6235 $filterStatus =
getDolGlobalString(
'SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK',
'3,4');
6236 if (isset($includedraftpoforvirtual)) {
6237 $filterStatus =
'0,1,2,'.$filterStatus;
6243 $stock_commande_fournisseur = $this->stats_commande_fournisseur[
'qty'];
6246 if (isModEnabled(
"supplier_order") || isModEnabled(
"supplier_invoice")) {
6247 $filterStatus =
'4';
6248 if (isset($includedraftpoforvirtual)) {
6249 $filterStatus =
'0,'.$filterStatus;
6255 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
6258 if (isModEnabled(
'mrp')) {
6263 $stock_inproduction = $this->stats_mrptoproduce[
'qty'] - $this->stats_mrptoconsume[
'qty'];
6266 $this->stock_theorique = $this->stock_reel + $stock_inproduction;
6270 $weBillOrderOrShipmentReception =
getDolGlobalString(
'STOCK_DO_WE_BILL_ORDER_OR_SHIPMENTECEPTION_FOR_VIRTUALSTOCK',
'order');
6274 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6278 $result = $tmpnewprod->load_stats_commande(0,
'0', 1);
6279 $this->stock_theorique += $tmpnewprod->stats_commande[
'qty'];
6281 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6282 $this->stock_theorique -= $stock_commande_client;
6283 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6284 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6289 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6291 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6293 if (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER_INCLUDE_DRAFT')) {
6295 $result = $tmpnewprod->load_stats_commande_fournisseur(0,
'0', 1);
6296 $this->stock_theorique += $this->stats_commande_fournisseur[
'qty'];
6298 $this->stock_theorique -= $stock_reception_fournisseur;
6299 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6300 $this->stock_theorique += $stock_commande_fournisseur;
6301 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6302 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6305 $parameters = array(
'id' => $this->
id,
'includedraftpoforvirtual' => $includedraftpoforvirtual);
6307 $reshook = $hookmanager->executeHooks(
'loadvirtualstock', $parameters, $this, $action);
6309 $this->stock_theorique = $hookmanager->resArray[
'stock_theorique'];
6310 } elseif ($reshook == 0 && isset($hookmanager->resArray[
'stock_stats_hook'])) {
6311 $this->stock_theorique += $hookmanager->resArray[
'stock_stats_hook'];
6315 if (!empty($this->stock_warehouse) &&
getDolGlobalString(
'STOCK_ALLOW_VIRTUAL_STOCK_PER_WAREHOUSE')) {
6316 foreach ($this->stock_warehouse as $warehouseid => $stockwarehouse) {
6317 if (isModEnabled(
'mrp')) {
6324 if ($this->fk_default_warehouse == $warehouseid) {
6325 $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']);
6327 $this->stock_warehouse[$warehouseid]->virtual = $this->stock_warehouse[$warehouseid]->real + $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'];
6347 $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";
6348 $sql .=
" WHERE pb.fk_product_stock = ps.rowid AND ps.fk_product = ".((int) $this->
id).
" AND pb.batch = '".$this->db->escape($batch).
"'";
6349 $sql .=
" GROUP BY pb.batch, pb.eatby, pb.sellby";
6350 dol_syslog(get_class($this).
"::loadBatchInfo load first entry found for lot/serial = ".$batch, LOG_DEBUG);
6351 $resql = $this->db->query($sql);
6353 $num = $this->db->num_rows($resql);
6356 $obj = $this->db->fetch_object($resql);
6357 $result[] = array(
'batch' => $batch,
'eatby' => $this->db->jdate($obj->eatby),
'sellby' => $this->db->jdate($obj->sellby),
'qty' => $obj->qty);
6363 $this->db->rollback();
6380 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6386 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos";
6388 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product').dol_sanitizeFileName($this->
ref);
6393 $dir_osencoded = $dir;
6395 if (is_dir($dir_osencoded)) {
6396 $originImage = $dir.
'/'.$file[
'name'];
6407 if (is_numeric($result) && $result > 0) {
6424 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6425 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6429 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos/";
6431 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product');
6435 if (file_exists($dir_osencoded)) {
6436 $handle = opendir($dir_osencoded);
6437 if (is_resource($handle)) {
6438 while (($file = readdir($handle)) !==
false) {
6440 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6463 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6464 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6470 $handle = @opendir($dir_osencoded);
6471 if (is_resource($handle)) {
6472 while (($file = readdir($handle)) !==
false) {
6474 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6481 $photo_vignette =
'';
6483 if (preg_match(
'/('.$this->regeximgext.
')$/i', $photo, $regs)) {
6484 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $photo).
'_small'.$regs[0];
6487 $dirthumb = $dir.
'thumbs/';
6491 $obj[
'photo'] = $photo;
6492 if ($photo_vignette &&
dol_is_file($dirthumb.$photo_vignette)) {
6493 $obj[
'photo_vignette'] =
'thumbs/'.$photo_vignette;
6495 $obj[
'photo_vignette'] =
"";
6498 $tabobj[$nbphoto - 1] = $obj;
6501 if ($nbmax && $nbphoto >= $nbmax) {
6523 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6524 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6526 $dir = dirname($file).
'/';
6527 $dirthumb = $dir.
'/thumbs/';
6528 $filename = preg_replace(
'/'.preg_quote($dir,
'/').
'/i',
'', $file);
6534 if (preg_match(
'/('.$this->regeximgext.
')$/i', $filename, $regs)) {
6535 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_small'.$regs[0];
6536 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6540 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_mini'.$regs[0];
6541 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6558 $infoImg = getimagesize($file_osencoded);
6559 $this->imgWidth = $infoImg[0];
6560 $this->imgHeight = $infoImg[1];
6570 global $hookmanager;
6572 $this->nb = array();
6574 $sql =
"SELECT count(p.rowid) as nb, fk_product_type";
6575 $sql .=
" FROM ".$this->db->prefix().
"product as p";
6576 $sql .=
' WHERE p.entity IN ('.getEntity($this->element, 1).
')';
6578 if (is_object($hookmanager)) {
6579 $parameters = array();
6580 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
6581 $sql .= $hookmanager->resPrint;
6583 $sql .=
' GROUP BY fk_product_type';
6585 $resql = $this->db->query($sql);
6587 while ($obj = $this->db->fetch_object($resql)) {
6588 if ($obj->fk_product_type == 1) {
6589 $this->nb[
"services"] = $obj->nb;
6591 $this->nb[
"products"] = $obj->nb;
6594 $this->db->free($resql);
6598 $this->error = $this->db->error();
6640 return $this->mandatory_period == 1;
6650 return $this->status_batch > 0;
6670 $dirsociete = array_merge(array(
'/core/modules/barcode/'),
$conf->modules_parts[
'barcode']);
6671 foreach ($dirsociete as $dirroot) {
6679 '@phan-var-force ModeleNumRefBarCode $mod';
6681 $result = $mod->getNextValue(
$object, $type);
6683 dol_syslog(get_class($this).
"::get_barcode barcode=".$result.
" module=".$var);
6700 $this->specimen = 1;
6702 $this->
ref =
'PRODUCT_SPEC';
6703 $this->label =
'PRODUCT SPECIMEN';
6704 $this->
description =
'This is description of this product specimen that was created the '.dol_print_date($now,
'dayhourlog').
'.';
6705 $this->specimen = 1;
6706 $this->country_id = 1;
6708 $this->status_buy = 1;
6710 $this->sell_or_eat_by_mandatory = 0;
6711 $this->note_private =
'This is a comment (private)';
6712 $this->note_public =
'This is a comment (public)';
6713 $this->date_creation = $now;
6714 $this->date_modification = $now;
6717 $this->weight_units = 3;
6720 $this->length_units = 1;
6722 $this->width_units = 0;
6723 $this->height =
null;
6724 $this->height_units =
null;
6726 $this->surface = 30;
6727 $this->surface_units = 0;
6728 $this->volume = 300;
6729 $this->volume_units = 0;
6731 $this->barcode = -1;
6746 if (!$this->fk_unit) {
6750 $langs->load(
'products');
6752 $label_type =
'label';
6753 if ($type ==
'short') {
6754 $label_type =
'short_label';
6757 $sql =
"SELECT ".$label_type.
", code from ".$this->db->prefix().
"c_units where rowid = ".((int) $this->fk_unit);
6759 $resql = $this->db->query($sql);
6761 $this->error = $this->db->error();
6762 dol_syslog(get_class($this).
"::getLabelOfUnit Error ".$this->error, LOG_ERR);
6764 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
6765 $label = ($label_type ==
'short_label' ? $res[$label_type] :
'unit'.$res[
'code']);
6767 $this->db->free($resql);
6781 $maxpricesupplier = 0;
6784 include_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.product.class.php';
6786 $product_fourn_list = $product_fourn->list_product_fournisseur_price($this->
id,
'',
'');
6788 if (is_array($product_fourn_list) && count($product_fourn_list) > 0) {
6789 foreach ($product_fourn_list as $productfourn) {
6790 if ($productfourn->fourn_unitprice > $maxpricesupplier) {
6791 $maxpricesupplier = $productfourn->fourn_unitprice;
6799 return $maxpricesupplier;
6815 require_once DOL_DOCUMENT_ROOT.
'/categories/class/categorie.class.php';
6816 return parent::setCategoriesCommon($categories, Categorie::TYPE_PRODUCT);
6830 'product_customer_price',
6831 'product_customer_price_log'
6850 $sql =
"SELECT rowid, level, fk_level, var_percent, var_min_percent FROM ".$this->db->prefix().
"product_pricerules";
6851 $query = $this->db->query($sql);
6855 while ($result = $this->db->fetch_object($query)) {
6856 $rules[$result->level] = $result;
6865 for ($i = 1; $i <= $nbofproducts; $i++) {
6866 $price = $baseprice;
6867 $price_min = $baseprice;
6871 if ($i > 1 && isset($rules[$i]->var_percent) && $rules[$i]->var_percent) {
6872 $price = $prices[$rules[$i]->fk_level] * (1 + ($rules[$i]->var_percent / 100));
6875 $prices[$i] = $price;
6878 if (isset($rules[$i]->var_min_percent) && $rules[$i]->var_min_percent) {
6879 $price_min = $price * (1 - ($rules[$i]->var_min_percent / 100));
6883 $check_amount = (($price == $this->multiprices[$i]) && ($price_min == $this->multiprices_min[$i]));
6884 $check_type = ($baseprice == $this->multiprices_base_type[$i]);
6886 if ($check_amount && $check_type) {
6890 if ($this->
updatePrice($price, $price_type, $user, $price_vat, $price_min, $i, $npr, $psq, 1) < 0) {
6908 return $user->rights->produit;
6910 return $user->rights->service;
6922 $sql =
"SELECT p.rowid, p.ref, p.datec as date_creation, p.tms as date_modification,";
6923 $sql .=
" p.fk_user_author, p.fk_user_modif";
6924 $sql .=
" FROM ".$this->db->prefix().$this->table_element.
" as p";
6925 $sql .=
" WHERE p.rowid = ".((int) $id);
6927 $result = $this->db->query($sql);
6929 if ($this->db->num_rows($result)) {
6930 $obj = $this->db->fetch_object($result);
6932 $this->
id = $obj->rowid;
6933 $this->
ref = $obj->ref;
6935 $this->user_creation_id = $obj->fk_user_author;
6936 $this->user_modification_id = $obj->fk_user_modif;
6938 $this->date_creation = $this->db->jdate($obj->date_creation);
6939 $this->date_modification = $this->db->jdate($obj->date_modification);
6942 $this->db->free($result);
6956 if (empty($this->duration_value)) {
6957 $this->errors[] =
'ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
6960 if ($this->duration_unit ==
's') {
6961 $prodDurationHours = 1. / 3600;
6962 } elseif ($this->duration_unit ==
'i' || $this->duration_unit ==
'mn' || $this->duration_unit ==
'min') {
6963 $prodDurationHours = 1. / 60;
6964 } elseif ($this->duration_unit ==
'h') {
6965 $prodDurationHours = 1.;
6966 } elseif ($this->duration_unit ==
'd') {
6967 $prodDurationHours = 24.;
6968 } elseif ($this->duration_unit ==
'w') {
6969 $prodDurationHours = 24. * 7;
6970 } elseif ($this->duration_unit ==
'm') {
6971 $prodDurationHours = 24. * 30;
6972 } elseif ($this->duration_unit ==
'y') {
6973 $prodDurationHours = 24. * 365;
6975 $prodDurationHours = 0.0;
6977 $prodDurationHours *= $this->duration_value;
6979 return $prodDurationHours;
6992 global $langs,
$conf;
6994 $selected = (empty($arraydata[
'selected']) ? 0 : $arraydata[
'selected']);
6996 $return =
'<div class="box-flex-item box-flex-grow-zero">';
6997 $return .=
'<div class="info-box info-box-sm">';
6998 $return .=
'<div class="info-box-img">';
7001 $label .= $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 120, 160, 0, 0, 0,
'',
'photoref photokanban');
7011 $return .=
'</div>';
7012 $return .=
'<div class="info-box-content">';
7013 $return .=
'<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this,
'getNomUrl') ? $this->
getNomUrl() : $this->ref).
'</span>';
7014 if ($selected >= 0) {
7015 $return .=
'<input id="cb'.$this->id.
'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->
id.
'"'.($selected ?
' checked="checked"' :
'').
'>';
7017 if (property_exists($this,
'label')) {
7018 $return .=
'<br><span class="info-box-label opacitymedium inline-block tdoverflowmax150 valignmiddle" title="'.dol_escape_htmltag($this->label).
'">'.
dol_escape_htmltag($this->label).
'</span>';
7020 if (property_exists($this,
'price') && property_exists($this,
'price_ttc')) {
7021 if ($this->price_base_type ==
'TTC') {
7022 $return .=
'<br><span class="info-box-status amount">'.price($this->price_ttc).
' '.$langs->trans(
"TTC").
'</span>';
7025 $return .=
'<br><span class="info-box-status amount">'.price($this->
price).
' '.$langs->trans(
"HT").
'</span>';
7030 if (property_exists($this,
'stock_reel') && $this->
isProduct()) {
7031 $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>';
7034 if (method_exists($this,
'getLibStatut')) {
7036 $return .=
'<br><div class="info-box-status inline-block valignmiddle">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7038 $return .=
'<div class="info-box-status inline-block valignmiddle marginleftonly paddingleft">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7041 $return .=
'</div>';
7042 $return .=
'</div>';
7043 $return .=
'</div>';
7056 if (!is_numeric($limit)) {
7060 $sql =
"SELECT p.rowid, p.ref, p.label, p.description, p.entity, ef.filename
7061 FROM ".MAIN_DB_PREFIX.
"product AS p
7062 JOIN ".MAIN_DB_PREFIX.
"ecm_files AS ef ON p.rowid = ef.src_object_id
7063 WHERE ef.entity IN (".
getEntity(
'product').
")
7064 AND (ef.filename LIKE '%.png' OR ef.filename LIKE '%.jpeg' OR ef.filename LIKE '%.svg')
7065 GROUP BY p.rowid, p.ref, p.label, p.description, p.entity, ef.filename
7066 ORDER BY p.datec ASC
7067 LIMIT " . ((int) $limit);
7069 $resql = $this->db->query($sql);
7070 $products = array();
7073 while ($obj = $this->db->fetch_object($resql)) {
7074 $products[] = array(
7075 'rowid' => $obj->rowid,
7077 'label' => $obj->label,
7078 'description' => $obj->description,
7079 'entity' => $obj->entity,
7080 'filename' => $obj->filename
7086 if (empty($products)) {
7099 public $picto =
'service';
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
length_accountg($account)
Return General accounting account with defined length (used for product and miscellaneous)
Parent class of all other business classes (invoices, contracts, proposals, orders,...
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
deleteEcmFiles($mode=0)
Delete related files of object in database.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
isObjectUsed($id=0, $entity=0)
Function to check if an object is used by others (by children).
deleteExtraFields()
Delete all extra fields values for the current object.
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
show_photos($modulepart, $sdir, $size=0, $nbmax=0, $nbbyrow=5, $showfilename=0, $showaction=0, $maxHeight=120, $maxWidth=160, $nolink=0, $overwritetitle=0, $usesharelink=0, $cache='', $addphotorefcss='photoref')
Show photos of an object (nbmax maximum), into several columns.
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
call_trigger($triggerName, $user)
Call trigger based on this instance.
addThumbs($file, $quality=50)
Build thumb.
Class to manage Dolibarr database access.
Class to manage ECM files.
const STATUS_OPEN_INTERNAL
Warehouse open and only operations for stock transfers/corrections allowed (not for customer shipping...
const STATUS_OPEN_ALL
Warehouse open and any operations are allowed (customer shipping, supplier dispatch,...
const STATUS_CLOSED
Warehouse closed, inactive.
const STATUS_CLOSED
Closed status -> parcel was received by customer / end of process prev status : validated or shipment...
const STATUS_VALIDATED
Validated status -> parcel is ready to be sent prev status : draft next status : closed or shipment_i...
const STATUS_DRAFT
Draft status.
Class to manage stock movements.
Class to parse product price expressions.
Class ProductCombination Used to represent the relation between a product and one of its variants.
File of class to manage predefined price products or services by customer.
Class to manage predefined suppliers products.
Class to manage products or services.
static replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
get_nb_achat($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units or supplier invoices in which product is included.
getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp=0)
Return price of sell of a product for a seller/buyer/product.
__construct($db)
Constructor.
is_sousproduit($fk_parent, $fk_child)
Check if it is a sub-product into a kit.
const 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.
getLabelOfUnit($type='long')
Returns the text label from units dictionary.
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)
Charge tableau des stats facture recurrentes pour le produit/service.
get_nb_propalsupplier($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in proposals in which product is included.
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)
Charge tableau des stats facture pour le produit/service.
get_nb_ordersupplier($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
getMultiLangs()
Load array this->multilangs.
get_nb_mos($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
clone_associations($fromId, $toId)
Clone links between products.
create($user, $notrigger=0)
Insert product into database.
load_stats_contrat($socid=0)
Charge tableau des stats contrat pour le produit/service.
isService()
Return if the object is a service.
getRights()
Returns the rights used for this class.
loadBatchInfo($batch)
Load existing information about a serial.
load_stock($option='', $includedraftpoforvirtual=null, $dateofvirtualstock=null)
Load information about stock of a product into ->stock_reel, ->stock_warehouse[] (including stock_war...
getProductDurationHours()
Return the duration of a service in hours (for a service based on duration fields)
get_buyprice($prodfournprice, $qty, $product_id=0, $fourn_ref='', $fk_soc=0)
Read price used by a provider.
clone_fournisseurs($fromId, $toId)
Recopie les fournisseurs et prix fournisseurs d'un produit/service sur un autre.
const TYPE_PRODUCT
Regular product.
add_photo($sdir, $file)
Move an uploaded file described into $file array into target directory $sdir.
log_price_delete($user, $rowid)
Delete a price line.
info($id)
Load information for tab info.
correct_stock($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $inventorycode='', $origin_element='', $origin_id=null, $disablestockchangeforsubproduct=0, $extrafields=null)
Adjust stock in a warehouse for product.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
Create a document onto disk according to template module.
static getSellOrEatByMandatoryList()
Get the array of labels of Sell by or Eat by all mandatory flags for each status.
getChildsArbo($id, $firstlevelonly=0, $level=1, $parents=array())
Return children of product $id.
load_virtual_stock($includedraftpoforvirtual=null, $dateofvirtualstock=null)
Load value ->stock_theorique of a product.
load_stats_propale($socid=0)
Charge tableau des stats propale pour le produit/service.
get_barcode($object, $type='')
Get a barcode from the module to generate barcode values.
setAccountancyCode($type, $value)
Sets an accountancy code for a product.
getProductsToPreviewInEmail($limit)
Retrieve and display products.
load_stats_facture($socid=0)
Charge tableau des stats facture pour le produit/service.
setCategories($categories)
Sets object to supplied categories.
load_stats_reception($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null)
Charge tableau des stats réception fournisseur pour le produit/service.
get_nb_propal($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in proposals in which product is included.
update($id, $user, $notrigger=0, $action='update', $updatetype=false)
Update a record into database.
setMultiLangs($user)
Update or add a translation for a product.
correct_stock_batch($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $dlc='', $dluo='', $lot='', $inventorycode='', $origin_element='', $origin_id=null, $disablestockchangeforsubproduct=0, $extrafields=null, $force_update_batch=false)
Adjust stock in a warehouse for product with batch number.
load_stats_bom($socid=0)
Charge tableau des stats OF pour le produit/service.
hasbatch()
Return if the object has a sell-by or eat-by date.
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.
min_recommended_price()
Return minimum product recommended price.
_log_price($user, $level=0)
Insert a track that we changed a customer price.
_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_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $nohook=0, $varfiles='addedfile', $upload_dir='')
Check validity of a file upload from an GUI page, and move it to its final destination.
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_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
dolGetFirstLineOfText($text, $nboflines=1, $charset='UTF-8')
Return first line of text.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='', $keepspaces=0)
Clean a string from all punctuation characters to use it as a ref or login.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
dol_clone($object, $native=2)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0)
Clean a string to use it as a file name.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
utf8_check($str)
Check if a string is in UTF8.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_localtax($vatrate, $local, $thirdparty_buyer=null, $thirdparty_seller=null, $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate,...
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
measuring_units_squared($unitscale)
Transform a given unit scale into the square of that unit, if known.
measuringUnitString($unitid, $measuring_style='', $unitscale='', $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:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type