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);
1033 require_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
1034 $this->accountancy_code_buy =
clean_account($this->accountancy_code_buy);
1035 $this->accountancy_code_buy_intra =
clean_account($this->accountancy_code_buy_intra);
1036 $this->accountancy_code_buy_export =
clean_account($this->accountancy_code_buy_export);
1037 $this->accountancy_code_sell =
clean_account($this->accountancy_code_sell);
1038 $this->accountancy_code_sell_intra =
clean_account($this->accountancy_code_sell_intra);
1039 $this->accountancy_code_sell_export =
clean_account($this->accountancy_code_sell_export);
1043 $this->barcode = trim($this->barcode);
1044 $this->mandatory_period = empty($this->mandatory_period) ? 0 : $this->mandatory_period;
1046 if (empty($this->label)) {
1047 $this->error =
'ErrorMandatoryParametersNotProvided';
1051 if (empty($this->
ref) || $this->
ref ==
'auto') {
1053 $module =
getDolGlobalString(
'PRODUCT_CODEPRODUCT_ADDON',
'mod_codeproduct_leopard');
1054 if ($module !=
'mod_codeproduct_leopard') {
1055 if (substr($module, 0, 16) ==
'mod_codeproduct_' && substr($module, -3) ==
'php') {
1056 $module = substr($module, 0,
dol_strlen($module) - 4);
1059 $modCodeProduct =
new $module();
1060 '@phan-var-force ModeleProductCode $modCodeProduct';
1061 if (!empty($modCodeProduct->code_auto)) {
1062 $this->
ref = $modCodeProduct->getNextValue($this, $this->
type);
1064 unset($modCodeProduct);
1067 if (empty($this->
ref)) {
1068 $this->error =
'ProductModuleNotSetupForAutoRef';
1073 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);
1077 if (empty($this->date_creation)) {
1078 $this->date_creation = $now;
1084 if ($this->barcode ==
'-1' || $this->barcode ==
'auto') {
1085 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1090 $result = $this->
verify();
1093 $sql =
"SELECT count(*) as nb";
1094 $sql .=
" FROM ".$this->db->prefix().
"product";
1095 $sql .=
" WHERE entity IN (".getEntity(
'product').
")";
1096 $sql .=
" AND ref = '".$this->db->escape($this->
ref).
"'";
1098 $result = $this->db->query($sql);
1100 $obj = $this->db->fetch_object($result);
1101 if ($obj->nb == 0) {
1103 $sql =
"INSERT INTO ".$this->db->prefix().
"product (";
1107 $sql .=
", ref_ext";
1108 $sql .=
", price_min";
1109 $sql .=
", price_min_ttc";
1111 $sql .=
", fk_user_author";
1112 $sql .=
", fk_product_type";
1114 $sql .=
", price_ttc";
1115 $sql .=
", price_base_type";
1116 $sql .=
", price_label";
1120 $sql .=
", accountancy_code_buy";
1121 $sql .=
", accountancy_code_buy_intra";
1122 $sql .=
", accountancy_code_buy_export";
1123 $sql .=
", accountancy_code_sell";
1124 $sql .=
", accountancy_code_sell_intra";
1125 $sql .=
", accountancy_code_sell_export";
1128 $sql .=
", finished";
1129 $sql .=
", tobatch";
1130 $sql .=
", sell_or_eat_by_mandatory";
1131 $sql .=
", batch_mask";
1132 $sql .=
", fk_unit";
1133 $sql .=
", mandatory_period";
1134 $sql .=
") VALUES (";
1135 $sql .=
"'".$this->db->idate($this->date_creation).
"'";
1136 $sql .=
", ".(!empty($this->entity) ? (int) $this->entity : (int)
$conf->entity);
1137 $sql .=
", '".$this->db->escape($this->
ref).
"'";
1138 $sql .=
", ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1139 $sql .=
", ".price2num($price_min_ht);
1140 $sql .=
", ".price2num($price_min_ttc);
1141 $sql .=
", ".(!empty($this->label) ?
"'".$this->db->escape($this->label).
"'" :
"null");
1142 $sql .=
", ".((int) $user->id);
1143 $sql .=
", ".((int) $this->
type);
1144 $sql .=
", ".price2num($price_ht,
'MT');
1145 $sql .=
", ".price2num($price_ttc,
'MT');
1146 $sql .=
", '".$this->db->escape($this->price_base_type).
"'";
1147 $sql .=
", ".(!empty($this->price_label) ?
"'".$this->db->escape($this->price_label).
"'" :
"null");
1148 $sql .=
", ".((int) $this->
status);
1149 $sql .=
", ".((int) $this->status_buy);
1151 $sql .=
", '".$this->db->escape($this->accountancy_code_buy).
"'";
1152 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_intra).
"'";
1153 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_export).
"'";
1154 $sql .=
", '".$this->db->escape($this->accountancy_code_sell).
"'";
1155 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_intra).
"'";
1156 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_export).
"'";
1158 $sql .=
", '".$this->db->escape($this->canvas).
"'";
1159 $sql .=
", ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
'NULL' : (int) $this->finished);
1160 $sql .=
", ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : ((int) $this->status_batch));
1161 $sql .=
", ".((empty($this->sell_or_eat_by_mandatory) || $this->sell_or_eat_by_mandatory < 0) ? 0 : ((int) $this->sell_or_eat_by_mandatory));
1162 $sql .=
", '".$this->db->escape($this->batch_mask).
"'";
1163 $sql .=
", ".($this->fk_unit > 0 ? ((int) $this->fk_unit) :
'NULL');
1164 $sql .=
", '".$this->db->escape($this->mandatory_period).
"'";
1167 dol_syslog(get_class($this).
"::Create", LOG_DEBUG);
1169 $result = $this->db->query($sql);
1171 $id = $this->db->last_insert_id($this->db->prefix().
"product");
1175 $this->
price = $price_ht;
1176 $this->price_ttc = $price_ttc;
1177 $this->price_min = $price_min_ht;
1178 $this->price_min_ttc = $price_min_ttc;
1182 if ($this->
update($id, $user, 1,
'add') <= 0) {
1187 $this->error = $this->db->lasterror();
1192 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " .((int) $this->id) .
" AND entity = " . ((
int)
$conf->entity));
1194 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1195 $sql .=
" fk_product";
1197 $sql .=
", accountancy_code_buy";
1198 $sql .=
", accountancy_code_buy_intra";
1199 $sql .=
", accountancy_code_buy_export";
1200 $sql .=
", accountancy_code_sell";
1201 $sql .=
", accountancy_code_sell_intra";
1202 $sql .=
", accountancy_code_sell_export";
1203 $sql .=
") VALUES (";
1205 $sql .=
", " . ((int)
$conf->entity);
1206 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1207 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1208 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1209 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1210 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1211 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1213 $result = $this->db->query($sql);
1216 $this->error =
'ErrorFailedToInsertAccountancyForEntity';
1221 $this->error =
'ErrorFailedToGetInsertedId';
1225 $this->error = $this->db->lasterror();
1229 $langs->load(
"products");
1231 $this->error =
"ErrorProductAlreadyExists";
1232 dol_syslog(get_class($this).
"::Create fails, ref ".$this->
ref.
" already exists");
1236 $this->error = $this->db->lasterror();
1239 if (!$error && !$notrigger) {
1241 $result = $this->
call_trigger(
'PRODUCT_CREATE', $user);
1249 $this->db->commit();
1252 $this->db->rollback();
1256 $this->db->rollback();
1257 dol_syslog(get_class($this).
"::Create fails verify ".implode(
',', $this->errors), LOG_WARNING);
1273 $this->errors = array();
1276 $this->
ref = trim($this->
ref);
1279 $this->errors[] =
'ErrorBadRef';
1283 $arrayofnonnegativevalue = array(
'weight' =>
'Weight',
'width' =>
'Width',
'height' =>
'Height',
'length' =>
'Length',
'surface' =>
'Surface',
'volume' =>
'Volume');
1284 foreach ($arrayofnonnegativevalue as $key => $value) {
1285 if (property_exists($this, $key) && !empty($this->$key) && ($this->$key < 0)) {
1286 $langs->loadLangs(array(
"main",
"other"));
1287 $this->error = $langs->trans(
"FieldCannotBeNegative", $langs->transnoentitiesnoconv($value));
1288 $this->errors[] = $this->error;
1293 $rescode = $this->
check_barcode($this->barcode, $this->barcode_type_code);
1295 if ($rescode == -1) {
1296 $this->errors[] =
'ErrorBadBarCodeSyntax';
1297 } elseif ($rescode == -2) {
1298 $this->errors[] =
'ErrorBarCodeRequired';
1299 } elseif ($rescode == -3) {
1301 $this->errors[] =
'ErrorBarCodeAlreadyUsed';
1329 $dirsociete = array_merge(array(
'/core/modules/barcode/'),
$conf->modules_parts[
'barcode']);
1330 foreach ($dirsociete as $dirroot) {
1337 $mod =
new $module();
1338 '@phan-var-force ModeleNumRefBarCode $mod';
1340 dol_syslog(get_class($this).
"::check_barcode value=".$valuetotest.
" type=".$typefortest.
" module=".$module);
1341 $result = $mod->verif($this->db, $valuetotest, $this, 0, $typefortest);
1359 public function update($id, $user, $notrigger = 0, $action =
'update', $updatetype =
false)
1361 global $langs,
$conf, $hookmanager;
1366 if (!$this->label) {
1367 $this->label =
'MISSING LABEL';
1372 $this->
ref = trim($this->
ref);
1376 $this->label = trim($this->label);
1378 $this->note_private = (isset($this->note_private) ? trim($this->note_private) :
null);
1379 $this->note_public = (isset($this->note_public) ? trim($this->note_public) :
null);
1380 $this->net_measure =
price2num($this->net_measure);
1381 $this->net_measure_units = (is_null($this->net_measure_units) ?
'' : trim((
string) $this->net_measure_units));
1382 $this->weight =
price2num($this->weight);
1383 $this->weight_units = (is_null($this->weight_units) ?
'' : trim((
string) $this->weight_units));
1384 $this->length =
price2num($this->length);
1385 $this->length_units = (is_null($this->length_units) ?
'' : trim((
string) $this->length_units));
1387 $this->width_units = (is_null($this->width_units) ?
'' : trim((
string) $this->width_units));
1388 $this->height =
price2num($this->height);
1389 $this->height_units = (is_null($this->height_units) ?
'' : trim((
string) $this->height_units));
1390 $this->surface =
price2num($this->surface);
1391 $this->surface_units = (is_null($this->surface_units) ?
'' : trim((
string) $this->surface_units));
1392 $this->volume =
price2num($this->volume);
1393 $this->volume_units = (is_null($this->volume_units) ?
'' : trim((
string) $this->volume_units));
1396 if (is_numeric($this->length_units)) {
1397 $this->width_units = $this->length_units;
1399 if (is_numeric($this->length_units)) {
1400 $this->height_units = $this->length_units;
1404 if (empty($this->surface) && !empty($this->length) && !empty($this->width) && $this->length_units == $this->width_units) {
1405 $this->surface = (float) $this->length * (
float) $this->width;
1408 if (empty($this->volume) && !empty($this->surface) && !empty($this->height) && $this->length_units == $this->height_units) {
1409 $this->volume = $this->surface * (float) $this->height;
1413 if (empty($this->tva_tx)) {
1416 if (empty($this->tva_npr)) {
1419 if (empty($this->localtax1_tx)) {
1420 $this->localtax1_tx = 0;
1422 if (empty($this->localtax2_tx)) {
1423 $this->localtax2_tx = 0;
1425 if (empty($this->localtax1_type)) {
1426 $this->localtax1_type =
'0';
1428 if (empty($this->localtax2_type)) {
1429 $this->localtax2_type =
'0';
1431 if (empty($this->
status)) {
1434 if (empty($this->status_buy)) {
1435 $this->status_buy = 0;
1438 if (empty($this->country_id)) {
1439 $this->country_id = 0;
1442 if (empty($this->state_id)) {
1443 $this->state_id = 0;
1447 $this->barcode = (empty($this->barcode) ?
'' : trim($this->barcode));
1449 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
1450 $this->accountancy_code_buy_intra = (!empty($this->accountancy_code_buy_intra) ? trim($this->accountancy_code_buy_intra) :
'');
1451 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
1452 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
1453 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
1454 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
1460 require_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
1461 $this->accountancy_code_buy =
clean_account($this->accountancy_code_buy);
1462 $this->accountancy_code_buy_intra =
clean_account($this->accountancy_code_buy_intra);
1463 $this->accountancy_code_buy_export =
clean_account($this->accountancy_code_buy_export);
1464 $this->accountancy_code_sell =
clean_account($this->accountancy_code_sell);
1465 $this->accountancy_code_sell_intra =
clean_account($this->accountancy_code_sell_intra);
1466 $this->accountancy_code_sell_export =
clean_account($this->accountancy_code_sell_export);
1474 if ($action !=
'add') {
1475 $result = $this->
verify();
1484 if (is_null($this->oldcopy) || (is_object($this->oldcopy) && empty($this->oldcopy->id))) {
1489 if ($this->
hasbatch() && !$this->oldcopy->hasbatch()) {
1491 $valueforundefinedlot =
'000000';
1496 dol_syslog(
"Flag batch of product id=".$this->
id.
" is set to ON, so we will create missing records into product_batch");
1499 foreach ($this->stock_warehouse as $idW => $ObjW) {
1501 foreach ($ObjW->detail_batch as $detail) {
1502 if ($detail->batch == $valueforundefinedlot || $detail->batch ==
'Undefined') {
1504 $sqlclean =
"DELETE FROM ".$this->db->prefix().
"product_batch WHERE batch in('Undefined', '".$this->db->escape($valueforundefinedlot).
"') AND fk_product_stock = ".((int) $ObjW->id);
1505 $result = $this->db->query($sqlclean);
1513 $qty_batch += $detail->qty;
1517 if ($ObjW->real != $qty_batch) {
1519 $ObjBatch->batch = $valueforundefinedlot;
1520 $ObjBatch->qty = ($ObjW->real - $qty_batch);
1521 $ObjBatch->fk_product_stock = (int) $ObjW->id;
1523 if ($ObjBatch->create($user, 1) < 0) {
1525 $this->errors = $ObjBatch->errors;
1530 if ($ObjLot->fetch(0, $this->id, $valueforundefinedlot) == 0) {
1531 $ObjLot->fk_product = $this->id;
1532 $ObjLot->entity = $this->entity;
1533 $ObjLot->fk_user_creat = $user->id;
1534 $ObjLot->batch = $valueforundefinedlot;
1535 if ($ObjLot->create($user,
true) < 0) {
1537 $this->errors = $ObjLot->errors;
1546 if ($this->barcode == -1) {
1547 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1550 $sql =
"UPDATE ".$this->db->prefix().
"product";
1551 $sql .=
" SET label = '".$this->db->escape($this->label).
"'";
1554 $sql .=
", fk_product_type = ".((int) $this->
type);
1557 $sql .=
", ref = '".$this->db->escape($this->
ref).
"'";
1558 $sql .=
", ref_ext = ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1559 $sql .=
", default_vat_code = ".($this->default_vat_code ?
"'".$this->db->escape($this->default_vat_code).
"'" :
"null");
1560 $sql .=
", tva_tx = ".((float) $this->tva_tx);
1561 $sql .=
", recuperableonly = ".((int) $this->tva_npr);
1562 $sql .=
", localtax1_tx = ".((float) $this->localtax1_tx);
1563 $sql .=
", localtax2_tx = ".((float) $this->localtax2_tx);
1564 $sql .=
", localtax1_type = ".($this->localtax1_type !=
'' ?
"'".$this->db->escape($this->localtax1_type).
"'" :
"'0'");
1565 $sql .=
", localtax2_type = ".($this->localtax2_type !=
'' ?
"'".$this->db->escape($this->localtax2_type).
"'" :
"'0'");
1567 $sql .=
", barcode = ".(empty($this->barcode) ?
"null" :
"'".$this->db->escape($this->barcode).
"'");
1568 $sql .=
", fk_barcode_type = ".(empty($this->barcode_type) ?
"null" : $this->db->escape($this->barcode_type));
1570 $sql .=
", tosell = ".(int) $this->
status;
1571 $sql .=
", tobuy = ".(int) $this->status_buy;
1572 $sql .=
", tobatch = ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : (int) $this->status_batch);
1573 $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);
1574 $sql .=
", batch_mask = '".$this->db->escape($this->batch_mask).
"'";
1576 $sql .=
", finished = ".((!isset($this->finished) || $this->finished < 0 || $this->finished ===
'') ?
"null" : (int) $this->finished);
1577 $sql .=
", fk_default_bom = ".((!isset($this->fk_default_bom) || $this->fk_default_bom < 0 || $this->fk_default_bom ==
'') ?
"null" : (int) $this->fk_default_bom);
1578 $sql .=
", net_measure = ".($this->net_measure !=
'' ?
"'".$this->db->escape($this->net_measure).
"'" :
'null');
1579 $sql .=
", net_measure_units = ".($this->net_measure_units !=
'' ?
"'".$this->db->escape($this->net_measure_units).
"'" :
'null');
1580 $sql .=
", weight = ".($this->weight !=
'' ?
"'".$this->db->escape($this->weight).
"'" :
'null');
1581 $sql .=
", weight_units = ".($this->weight_units !=
'' ?
"'".$this->db->escape($this->weight_units).
"'" :
'null');
1582 $sql .=
", length = ".($this->length !=
'' ?
"'".$this->db->escape($this->length).
"'" :
'null');
1583 $sql .=
", length_units = ".($this->length_units !=
'' ?
"'".$this->db->escape($this->length_units).
"'" :
'null');
1584 $sql .=
", width= ".($this->width !=
'' ?
"'".$this->db->escape($this->width).
"'" :
'null');
1585 $sql .=
", width_units = ".($this->width_units !=
'' ?
"'".$this->db->escape($this->width_units).
"'" :
'null');
1586 $sql .=
", height = ".($this->height !=
'' ?
"'".$this->db->escape($this->height).
"'" :
'null');
1587 $sql .=
", height_units = ".($this->height_units !=
'' ?
"'".$this->db->escape($this->height_units).
"'" :
'null');
1588 $sql .=
", surface = ".($this->surface !=
'' ?
"'".$this->db->escape($this->surface).
"'" :
'null');
1589 $sql .=
", surface_units = ".($this->surface_units !=
'' ?
"'".$this->db->escape($this->surface_units).
"'" :
'null');
1590 $sql .=
", volume = ".($this->volume !=
'' ?
"'".$this->db->escape($this->volume).
"'" :
'null');
1591 $sql .=
", volume_units = ".($this->volume_units !=
'' ?
"'".$this->db->escape($this->volume_units).
"'" :
'null');
1592 $sql .=
", fk_default_warehouse = ".($this->fk_default_warehouse > 0 ? ((int) $this->fk_default_warehouse) :
'null');
1593 $sql .=
", fk_default_workstation = ".($this->fk_default_workstation > 0 ? ((int) $this->fk_default_workstation) :
'null');
1594 $sql .=
", seuil_stock_alerte = ".((isset($this->seuil_stock_alerte) && is_numeric($this->seuil_stock_alerte)) ? (
float) $this->seuil_stock_alerte :
'null');
1595 $sql .=
", description = '".$this->db->escape($this->
description).
"'";
1596 $sql .=
", url = ".($this->url ?
"'".$this->db->escape($this->url).
"'" :
'null');
1597 $sql .=
", customcode = '".$this->db->escape($this->customcode).
"'";
1598 $sql .=
", fk_country = ".($this->country_id > 0 ? (int) $this->country_id :
'null');
1599 $sql .=
", fk_state = ".($this->state_id > 0 ? (int) $this->state_id :
'null');
1600 $sql .=
", lifetime = ".($this->lifetime > 0 ? (int) $this->lifetime :
'null');
1601 $sql .=
", qc_frequency = ".($this->qc_frequency > 0 ? (int) $this->qc_frequency :
'null');
1602 $sql .=
", note = ".(isset($this->note_private) ?
"'".$this->db->escape($this->note_private).
"'" :
'null');
1603 $sql .=
", note_public = ".(isset($this->note_public) ?
"'".$this->db->escape($this->note_public).
"'" :
'null');
1604 $sql .=
", duration = '".$this->db->escape($this->duration_value.$this->duration_unit).
"'";
1606 $sql .=
", accountancy_code_buy = '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1607 $sql .=
", accountancy_code_buy_intra = '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1608 $sql .=
", accountancy_code_buy_export = '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1609 $sql .=
", accountancy_code_sell= '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1610 $sql .=
", accountancy_code_sell_intra= '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1611 $sql .=
", accountancy_code_sell_export= '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1613 $sql .=
", desiredstock = ".((isset($this->desiredstock) && is_numeric($this->desiredstock)) ? (
float) $this->desiredstock :
"null");
1614 $sql .=
", cost_price = ".($this->cost_price !=
'' ? ((float) $this->cost_price) :
'null');
1615 $sql .=
", fk_unit= ".(!$this->fk_unit ?
'NULL' : (int) $this->fk_unit);
1616 $sql .=
", price_autogen = ".(!$this->price_autogen ? 0 : 1);
1617 $sql .=
", fk_price_expression = ".($this->fk_price_expression != 0 ? (int) $this->fk_price_expression :
'NULL');
1618 $sql .=
", fk_user_modif = ".($user->id > 0 ? (int) $user->id :
'NULL');
1619 $sql .=
", mandatory_period = ".((int) $this->mandatory_period);
1621 $sql .=
" WHERE rowid = ".((int) $id);
1623 dol_syslog(get_class($this).
"::update", LOG_DEBUG);
1625 $resql = $this->db->query($sql);
1632 $this->db->rollback();
1641 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " . ((
int) $this->id) .
" AND entity = " . ((
int)
$conf->entity));
1643 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1644 $sql .=
" fk_product";
1646 $sql .=
", accountancy_code_buy";
1647 $sql .=
", accountancy_code_buy_intra";
1648 $sql .=
", accountancy_code_buy_export";
1649 $sql .=
", accountancy_code_sell";
1650 $sql .=
", accountancy_code_sell_intra";
1651 $sql .=
", accountancy_code_sell_export";
1652 $sql .=
") VALUES (";
1653 $sql .= ((int) $this->
id);
1654 $sql .=
", " . ((int)
$conf->entity);
1655 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1656 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1657 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1658 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1659 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1660 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1662 $result = $this->db->query($sql);
1665 $this->error =
'ErrorFailedToUpdateAccountancyForEntity';
1669 if (!$this->
hasbatch() && $this->oldcopy->hasbatch()) {
1671 $sql =
'SELECT pb.qty, ps.fk_entrepot, pb.batch FROM '.MAIN_DB_PREFIX.
'product_batch as pb';
1672 $sql .=
' INNER JOIN '.MAIN_DB_PREFIX.
'product_stock as ps ON (ps.rowid = pb.fk_product_stock)';
1673 $sql .=
' WHERE ps.fk_product = '.(int) $this->
id;
1675 $resql = $this->db->query($sql);
1679 while ($obj = $this->db->fetch_object($resql)) {
1681 $fk_entrepot = $obj->fk_entrepot;
1685 $batch = $obj->batch;
1688 $addOremove = $value > 0 ? 1 : 0;
1689 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1690 $res = $this->
correct_stock_batch($user, $fk_entrepot, abs($value), $addOremove, $label, $price, $dlc, $dluo, $batch, $inventorycode,
'',
null, 0,
null,
true);
1693 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1694 $res = $this->
correct_stock($user, $fk_entrepot, abs($value), (
int) empty($addOremove), $label, $price, $inventorycode,
'',
null, 0);
1713 if (!$error && !$notrigger) {
1715 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
1722 if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) {
1724 if (
$conf->product->dir_output) {
1727 if (file_exists($olddir)) {
1731 $res = @rename($olddir, $newdir);
1733 $langs->load(
"errors");
1734 $this->error = $langs->trans(
'ErrorFailToRenameDir', $olddir, $newdir);
1738 require_once DOL_DOCUMENT_ROOT .
'/ecm/class/ecmfiles.class.php';
1739 $ecmfiles =
new EcmFiles($this->db);
1740 $ecmfiles->updateAfterRename(
"produit/".
dol_sanitizeFileName($this->oldcopy->ref),
"produit/".dol_sanitizeFileName($this->ref));
1747 if (isModEnabled(
'variants')) {
1748 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1752 foreach ($comb->fetchAllByFkProductParent($this->id) as $currcomb) {
1753 $currcomb->updateProperties($this, $user);
1757 $this->db->commit();
1760 $this->db->rollback();
1764 if ($this->db->errno() ==
'DB_ERROR_RECORD_ALREADY_EXISTS') {
1765 $langs->load(
"errors");
1766 if (empty(
$conf->barcode->enabled) || empty($this->barcode)) {
1767 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductAlreadyExists", $this->
ref);
1769 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductBarCodeAlreadyExists", $this->barcode);
1771 $this->errors[] = $this->error;
1772 $this->db->rollback();
1775 $this->error = $langs->trans(
"Error").
" : ".$this->db->error().
" - ".$sql;
1776 $this->errors[] = $this->error;
1777 $this->db->rollback();
1782 $this->db->rollback();
1783 dol_syslog(get_class($this).
"::Update fails verify ".implode(
',', $this->errors), LOG_WARNING);
1795 public function delete(
User $user, $notrigger = 0)
1798 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
1803 if (empty($this->
id)) {
1804 $this->error =
"Object must be fetched before calling delete";
1807 if (($this->
isProduct() && !$user->
hasRight(
'produit',
'supprimer')) || ($this->isService() && !$user->hasRight(
'service',
'supprimer'))) {
1808 $this->error =
"ErrorForbidden";
1813 if (empty($objectisused)) {
1816 if (!$error && empty($notrigger)) {
1818 $result = $this->
call_trigger(
'PRODUCT_DELETE', $user);
1827 $sql =
"DELETE FROM ".$this->db->prefix().
'product_batch';
1828 $sql .=
" WHERE fk_product_stock IN (";
1829 $sql .=
"SELECT rowid FROM ".$this->db->prefix().
'product_stock';
1830 $sql .=
" WHERE fk_product = ".((int) $this->
id).
")";
1832 $result = $this->db->query($sql);
1835 $this->errors[] = $this->db->lasterror();
1841 $elements = array(
'product_fournisseur_price',
'product_price',
'product_lang',
'categorie_product',
'product_stock',
'product_customer_price',
'product_lot');
1842 foreach ($elements as $table) {
1844 $sql =
"DELETE FROM ".$this->db->prefix().$table;
1845 $sql .=
" WHERE fk_product = ".(int) $this->
id;
1847 $result = $this->db->query($sql);
1850 $this->errors[] = $this->db->lasterror();
1857 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1858 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination2ValuePair.class.php';
1863 if ($prodcomb->deleteByFkProductParent($user, $this->id) < 0) {
1865 $this->errors[] =
'Error deleting combinations';
1869 if (!$error && ($prodcomb->fetchByFkProductChild($this->id) > 0) && ($prodcomb->delete($user) < 0)) {
1871 $this->errors[] =
'Error deleting child combination';
1877 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
1878 $sql .=
" WHERE fk_product_pere = ".(int) $this->
id.
" OR fk_product_fils = ".(
int) $this->id;
1880 $result = $this->db->query($sql);
1883 $this->errors[] = $this->db->lasterror();
1892 dol_syslog(get_class($this).
"::delete error -4 ".$this->error, LOG_ERR);
1898 $sqlz =
"DELETE FROM ".$this->db->prefix().
"product";
1899 $sqlz .=
" WHERE rowid = ".(int) $this->
id;
1901 $resultz = $this->db->query($sqlz);
1904 $this->errors[] = $this->db->lasterror();
1920 if ($conf->product->dir_output) {
1921 $dir =
$conf->product->dir_output.
"/".$ref;
1922 if (file_exists($dir)) {
1925 $this->errors[] =
'ErrorFailToDeleteDir';
1933 $this->db->commit();
1936 foreach ($this->errors as $errmsg) {
1937 dol_syslog(get_class($this).
"::delete ".$errmsg, LOG_ERR);
1938 $this->error .= ($this->error ?
', '.$errmsg : $errmsg);
1940 $this->db->rollback();
1944 $this->error =
"ErrorRecordIsUsedCantDelete";
1958 $sellByLabel = $langs->trans(
'SellByDate');
1959 $eatByLabel = $langs->trans(
'EatByDate');
1961 self::SELL_OR_EAT_BY_MANDATORY_ID_NONE => $langs->trans(
'BatchSellOrEatByMandatoryNone'),
1962 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY => $sellByLabel,
1963 self::SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY => $eatByLabel,
1964 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT => $langs->trans(
'BatchSellOrEatByMandatoryAll', $sellByLabel, $eatByLabel),
1975 $sellOrEatByMandatoryLabel =
'';
1978 if (isset($sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory])) {
1979 $sellOrEatByMandatoryLabel = $sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory];
1982 return $sellOrEatByMandatoryLabel;
1995 $langs_available = $langs->get_available_languages(DOL_DOCUMENT_ROOT, 0, 2);
1996 $current_lang = $langs->getDefaultLang();
1998 foreach ($langs_available as $key => $value) {
1999 if ($key == $current_lang) {
2000 $sql =
"SELECT rowid";
2001 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2002 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2003 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
2005 $result = $this->db->query($sql);
2007 if ($this->db->num_rows($result)) {
2008 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
2010 $sql2 .=
" label='".$this->db->escape($this->label).
"',";
2011 $sql2 .=
" description='".$this->db->escape($this->
description).
"'";
2013 $sql2 .=
", note='".$this->db->escape($this->other).
"'";
2015 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
2017 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
2022 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->label).
"',";
2023 $sql2 .=
" '".$this->db->escape($this->
description).
"'";
2025 $sql2 .=
", '".$this->db->escape($this->other).
"'";
2029 dol_syslog(get_class($this).
'::setMultiLangs key = current_lang = '.$key);
2030 if (!$this->db->query($sql2)) {
2031 $this->error = $this->db->lasterror();
2034 } elseif (isset($this->multilangs[$key])) {
2035 if (empty($this->multilangs[$key][
"label"])) {
2036 $this->errors[] = $key .
' : ' . $langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Label"));
2040 $sql =
"SELECT rowid";
2041 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2042 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2043 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
2045 $result = $this->db->query($sql);
2047 if ($this->db->num_rows($result)) {
2048 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
2050 $sql2 .=
" label = '".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
2051 $sql2 .=
" description = '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
2054 $sql2 .=
", note = '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
2056 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
2058 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
2063 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
2064 $sql2 .=
" '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
2067 $sql2 .=
", '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
2073 if ($this->multilangs[
"$key"][
"label"] || $this->multilangs[
"$key"][
"description"]) {
2074 if (!$this->db->query($sql2)) {
2075 $this->error = $this->db->lasterror();
2085 $result = $this->
call_trigger(
'PRODUCT_SET_MULTILANGS', $user);
2087 $this->error = $this->db->lasterror();
2105 $sql =
"DELETE FROM ".$this->db->prefix().
"product_lang";
2106 $sql .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($langtodelete).
"'";
2108 dol_syslog(get_class($this).
'::delMultiLangs', LOG_DEBUG);
2109 $result = $this->db->query($sql);
2112 $result = $this->
call_trigger(
'PRODUCT_DEL_MULTILANGS', $user);
2114 $this->error = $this->db->lasterror();
2115 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
2121 $this->error = $this->db->lasterror();
2122 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
2143 if ($type ==
'buy') {
2144 $field =
'accountancy_code_buy';
2145 } elseif ($type ==
'buy_intra') {
2146 $field =
'accountancy_code_buy_intra';
2147 } elseif ($type ==
'buy_export') {
2148 $field =
'accountancy_code_buy_export';
2149 } elseif ($type ==
'sell') {
2150 $field =
'accountancy_code_sell';
2151 } elseif ($type ==
'sell_intra') {
2152 $field =
'accountancy_code_sell_intra';
2153 } elseif ($type ==
'sell_export') {
2154 $field =
'accountancy_code_sell_export';
2159 $sql =
"UPDATE ".$this->db->prefix().$this->table_element.
" SET ";
2160 $sql .=
"$field = '".$this->db->escape($value).
"'";
2161 $sql .=
" WHERE rowid = ".((int) $this->
id);
2164 $resql = $this->db->query($sql);
2168 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
2175 $this->db->rollback();
2179 $this->$field = $value;
2181 $this->db->commit();
2184 $this->error = $this->db->lasterror();
2185 $this->db->rollback();
2199 $current_lang = $langs->getDefaultLang();
2201 $sql =
"SELECT lang, label, description, note as other";
2202 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2203 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2205 $result = $this->db->query($sql);
2207 while ($obj = $this->db->fetch_object($result)) {
2209 if ($obj->lang == $current_lang) {
2210 $this->label = $obj->label;
2212 $this->other = $obj->other;
2214 $this->multilangs[(string) $obj->lang][
"label"] = $obj->label;
2215 $this->multilangs[(string) $obj->lang][
"description"] = $obj->description;
2216 $this->multilangs[(string) $obj->lang][
"other"] = $obj->other;
2220 $this->error =
"Error: ".$this->db->lasterror().
" - ".$sql;
2233 $testExit = array(
'multiprices',
'multiprices_ttc',
'multiprices_base_type',
'multiprices_min',
'multiprices_min_ttc',
'multiprices_tva_tx',
'multiprices_recuperableonly');
2235 foreach ($testExit as $field) {
2236 if (!isset($this->$field)) {
2239 $tmparray = $this->$field;
2240 if (!isset($tmparray[$level])) {
2246 'level' => $level ? $level : 1,
2247 'multiprices' => (float) $this->multiprices[$level],
2248 'multiprices_ttc' => (
float) $this->multiprices_ttc[$level],
2249 'multiprices_base_type' => $this->multiprices_base_type[$level],
2250 'multiprices_min' => (float) $this->multiprices_min[$level],
2251 'multiprices_min_ttc' => (
float) $this->multiprices_min_ttc[$level],
2252 'multiprices_tva_tx' => (float) $this->multiprices_tva_tx[$level],
2253 'multiprices_recuperableonly' => (
float) $this->multiprices_recuperableonly[$level],
2276 if (empty($this->price_by_qty)) {
2277 $this->price_by_qty = 0;
2281 $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,";
2282 $sql .=
" localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, price_min,price_min_ttc,price_by_qty,entity,fk_price_expression) ";
2283 $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).
",";
2284 $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');
2287 dol_syslog(get_class($this).
"::_log_price", LOG_DEBUG);
2288 $resql = $this->db->query($sql);
2290 $this->error = $this->db->lasterror();
2310 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price_by_qty";
2311 $sql .=
" WHERE fk_product_price = ".((int) $rowid);
2312 $resql = $this->db->query($sql);
2314 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price";
2315 $sql .=
" WHERE rowid=".((int) $rowid);
2316 $resql = $this->db->query($sql);
2320 $this->error = $this->db->lasterror();
2335 public function getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp = 0)
2337 global $hookmanager, $action;
2340 if (is_object($hookmanager)) {
2341 $parameters = array(
'thirdparty_seller' => $thirdparty_seller,
'thirdparty_buyer' => $thirdparty_buyer,
'pqp' => $pqp);
2343 $reshook = $hookmanager->executeHooks(
'getSellPrice', $parameters, $this, $action);
2345 return $hookmanager->resArray;
2350 $tva_tx =
get_default_tva($thirdparty_seller, $thirdparty_buyer, $this->
id);
2351 $tva_npr =
get_default_npr($thirdparty_seller, $thirdparty_buyer, $this->
id);
2352 if (empty($tva_tx)) {
2356 $pu_ht = $this->price;
2357 $pu_ttc = $this->price_ttc;
2358 $price_min = $this->price_min;
2359 $price_base_type = $this->price_base_type;
2363 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2367 $filter = array(
't.fk_product' => $this->
id,
't.fk_soc' => $thirdparty_buyer->id);
2370 $pricebycustomerexist =
false;
2371 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2373 if (count($prodcustprice->lines) > 0) {
2374 $pricebycustomerexist =
true;
2375 $pu_ht =
price($prodcustprice->lines[0]->price);
2376 $price_min =
price($prodcustprice->lines[0]->price_min);
2377 $pu_ttc =
price($prodcustprice->lines[0]->price_ttc);
2378 $price_base_type = $prodcustprice->lines[0]->price_base_type;
2379 $tva_tx = $prodcustprice->lines[0]->tva_tx;
2380 if ($prodcustprice->lines[0]->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2381 $tva_tx .=
' ('.$prodcustprice->lines[0]->default_vat_code.
')';
2383 $tva_npr = $prodcustprice->lines[0]->recuperableonly;
2384 if (empty($tva_tx)) {
2390 if (!$pricebycustomerexist && !empty($thirdparty_buyer->price_level)) {
2391 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
2392 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
2393 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
2394 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
2397 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2398 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2400 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2401 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2403 if (empty($tva_tx)) {
2408 } elseif (
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !empty($thirdparty_buyer->price_level)) {
2409 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
2410 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
2411 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
2412 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
2414 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2415 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2417 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2418 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2420 if (empty($tva_tx)) {
2426 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2430 $filter = array(
't.fk_product' => $this->
id,
't.fk_soc' => $thirdparty_buyer->id);
2432 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2434 if (count($prodcustprice->lines) > 0) {
2435 $pu_ht =
price($prodcustprice->lines[0]->price);
2436 $price_min =
price($prodcustprice->lines[0]->price_min);
2437 $pu_ttc =
price($prodcustprice->lines[0]->price_ttc);
2438 $price_base_type = $prodcustprice->lines[0]->price_base_type;
2439 $tva_tx = $prodcustprice->lines[0]->tva_tx;
2440 if ($prodcustprice->lines[0]->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2441 $tva_tx .=
' ('.$prodcustprice->lines[0]->default_vat_code.
')';
2443 $tva_npr = $prodcustprice->lines[0]->recuperableonly;
2444 if (empty($tva_tx)) {
2451 if ($this->prices_by_qty[0]) {
2454 foreach ($this->prices_by_qty_list[0] as $priceforthequantityarray) {
2455 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2459 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2460 $pu_ht = $priceforthequantityarray[
'unitprice'];
2462 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2469 if ($this->prices_by_qty[$thirdparty_buyer->price_level]) {
2472 foreach ($this->prices_by_qty_list[$thirdparty_buyer->price_level] as $priceforthequantityarray) {
2473 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2477 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2478 $pu_ht = $priceforthequantityarray[
'unitprice'];
2480 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2487 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);
2504 public function get_buyprice($prodfournprice, $qty, $product_id = 0, $fourn_ref =
'', $fk_soc = 0)
2507 global $action, $hookmanager;
2510 if (is_object($hookmanager)) {
2511 $parameters = array(
2512 'prodfournprice' => $prodfournprice,
2514 'product_id' => $product_id,
2515 'fourn_ref' => $fourn_ref,
2516 'fk_soc' => $fk_soc,
2519 $reshook = $hookmanager->executeHooks(
'getBuyPrice', $parameters, $this, $action);
2521 return $hookmanager->resArray;
2528 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2529 $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,";
2530 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2531 $sql .=
" pfp.packaging";
2532 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2533 $sql .=
" WHERE pfp.rowid = ".((int) $prodfournprice);
2535 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2537 $sql .=
" ORDER BY pfp.quantity DESC";
2539 dol_syslog(get_class($this).
"::get_buyprice first search by prodfournprice/qty", LOG_DEBUG);
2540 $resql = $this->db->query($sql);
2542 $obj = $this->db->fetch_object($resql);
2543 if ($obj && $obj->quantity > 0) {
2544 if (isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2546 $prod_supplier->product_fourn_price_id = $obj->rowid;
2547 $prod_supplier->id = $obj->fk_product;
2548 $prod_supplier->fourn_qty = $obj->quantity;
2549 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2550 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2552 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2554 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2555 if ($price_result >= 0) {
2556 $obj->price = $price_result;
2559 $this->product_fourn_price_id = $obj->rowid;
2560 $this->buyprice = $obj->price;
2561 $this->fourn_pu = $obj->price / $obj->quantity;
2562 $this->fourn_price_base_type =
'HT';
2563 $this->fourn_socid = $obj->fk_soc;
2564 $this->ref_fourn = $obj->ref_supplier;
2565 $this->ref_supplier = $obj->ref_supplier;
2566 $this->desc_supplier = $obj->desc_supplier;
2567 $this->remise_percent = $obj->remise_percent;
2568 $this->vatrate_supplier = $obj->tva_tx;
2569 $this->default_vat_code_supplier = $obj->default_vat_code;
2570 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2571 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2572 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2573 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2574 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2576 $this->packaging = $obj->packaging;
2578 $result = $obj->fk_product;
2582 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2583 $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,";
2584 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2585 $sql .=
" pfp.packaging";
2586 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2587 $sql .=
" WHERE 1 = 1";
2588 if ($product_id > 0) {
2589 $sql .=
" AND pfp.fk_product = ".((int) $product_id);
2591 if ($fourn_ref !=
'none') {
2592 $sql .=
" AND pfp.ref_fourn = '".$this->db->escape($fourn_ref).
"'";
2595 $sql .=
" AND pfp.fk_soc = ".((int) $fk_soc);
2598 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2600 $sql .=
" ORDER BY pfp.quantity DESC";
2603 dol_syslog(get_class($this).
"::get_buyprice second search from qty/ref/product_id", LOG_DEBUG);
2604 $resql = $this->db->query($sql);
2606 $obj = $this->db->fetch_object($resql);
2607 if ($obj && $obj->quantity > 0) {
2608 if (isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2610 $prod_supplier->product_fourn_price_id = $obj->rowid;
2611 $prod_supplier->id = $obj->fk_product;
2612 $prod_supplier->fourn_qty = $obj->quantity;
2613 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2614 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2616 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2618 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2620 $obj->price = $price_result;
2623 $this->product_fourn_price_id = $obj->rowid;
2624 $this->buyprice = $obj->price;
2625 $this->fourn_qty = $obj->quantity;
2626 $this->fourn_pu = $obj->price / $obj->quantity;
2627 $this->fourn_price_base_type =
'HT';
2628 $this->fourn_socid = $obj->fk_soc;
2629 $this->ref_fourn = $obj->ref_supplier;
2630 $this->ref_supplier = $obj->ref_supplier;
2631 $this->desc_supplier = $obj->desc_supplier;
2632 $this->remise_percent = $obj->remise_percent;
2633 $this->vatrate_supplier = $obj->tva_tx;
2634 $this->default_vat_code_supplier = $obj->default_vat_code;
2635 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2636 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2637 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2638 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2639 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2641 $this->packaging = $obj->packaging;
2643 $result = $obj->fk_product;
2649 $this->error = $this->db->lasterror();
2654 $this->error = $this->db->lasterror();
2678 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)
2684 dol_syslog(get_class($this).
"::update_price id=".$id.
" newprice=".$newprice.
" newpricebase=".$newpricebase.
" newminprice=".$newminprice.
" level=".$level.
" npr=".$newnpr.
" newdefaultvatcode=".$newdefaultvatcode);
2687 if (empty($this->tva_tx)) {
2688 $this->tva_tx = 0.0;
2690 if (empty($newnpr)) {
2693 if (empty($newminprice)) {
2698 if ($newvat ===
null || $newvat ==
'') {
2699 $newvat = (float) $this->tva_tx;
2702 $localtaxtype1 =
'';
2703 $localtaxtype2 =
'';
2708 return $this->
generateMultiprices($user, $newprice, $newpricebase, $newvat, $newnpr, $newpbq);
2711 if (!empty($newminprice) && ($newminprice > $newprice)) {
2712 $this->error =
'ErrorPriceCantBeLowerThanMinPrice';
2716 if ($newprice === 0 || $newprice !==
'') {
2717 if ($newpricebase ==
'TTC') {
2718 $price_ttc = (float)
price2num($newprice,
'MU');
2719 $price = (float)
price2num($newprice) / (1 + ((float) $newvat / 100));
2720 $price = (float)
price2num($price,
'MU');
2722 if ((
string) $newminprice !=
'0') {
2723 $price_min_ttc = (float)
price2num($newminprice,
'MU');
2724 $price_min = (float)
price2num($newminprice) / (1 + ($newvat / 100));
2725 $price_min = (float)
price2num($price_min,
'MU');
2728 $price_min_ttc = 0.0;
2731 $price = (float)
price2num($newprice,
'MU');
2732 $price_ttc = ($newnpr != 1) ? (
float)
price2num($newprice) * (1 + ($newvat / 100)) : $price;
2733 $price_ttc = (float)
price2num($price_ttc,
'MU');
2735 if ((
string) $newminprice !=
'0') {
2736 $price_min = (float)
price2num($newminprice,
'MU');
2737 $price_min_ttc = (float)
price2num($newminprice) * (1 + ($newvat / 100));
2738 $price_min_ttc = (float)
price2num($price_min_ttc,
'MU');
2742 $price_min_ttc = 0.0;
2746 if (count($localtaxes_array) > 0) {
2747 $localtaxtype1 = $localtaxes_array[
'0'];
2748 $localtax1 = $localtaxes_array[
'1'];
2749 $localtaxtype2 = $localtaxes_array[
'2'];
2750 $localtax2 = $localtaxes_array[
'3'];
2753 if (!empty($newdefaultvatcode)) {
2756 $sql =
"SELECT t.rowid, t.code, t.recuperableonly as tva_npr, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
2757 $sql .=
" FROM ".MAIN_DB_PREFIX.
"c_tva as t, ".MAIN_DB_PREFIX.
"c_country as c";
2758 $sql .=
" WHERE t.fk_pays = c.rowid AND c.code = '".$this->db->escape($mysoc->country_code).
"'";
2759 $sql .=
" AND t.taux = ".((float) $newdefaultvatcode).
" AND t.active = 1";
2760 $sql .=
" AND t.code = '".$this->db->escape($newdefaultvatcode).
"'";
2761 $resql = $this->db->query($sql);
2763 $obj = $this->db->fetch_object($resql);
2765 $npr = $obj->tva_npr;
2766 $localtax1 = $obj->localtax1;
2767 $localtax2 = $obj->localtax2;
2768 $localtaxtype1 = $obj->localtax1_type;
2769 $localtaxtype2 = $obj->localtax2_type;
2774 $localtaxtype1 =
'0';
2776 $localtaxtype2 =
'0';
2780 if (empty($localtax1)) {
2783 if (empty($localtax2)) {
2791 $sql =
"UPDATE ".$this->db->prefix().
"product SET";
2792 $sql .=
" price_base_type = '".$this->db->escape($newpricebase).
"',";
2793 $sql .=
" price = ".(float) $price.
",";
2794 $sql .=
" price_ttc = ".(float) $price_ttc.
",";
2795 $sql .=
" price_min = ".(float) $price_min.
",";
2796 $sql .=
" price_min_ttc = ".(float) $price_min_ttc.
",";
2797 $sql .=
" localtax1_tx = ".($localtax1 >= 0 ? (float) $localtax1 :
'NULL').
",";
2798 $sql .=
" localtax2_tx = ".($localtax2 >= 0 ? (float) $localtax2 :
'NULL').
",";
2799 $sql .=
" localtax1_type = ".($localtaxtype1 !=
'' ?
"'".$this->db->escape($localtaxtype1).
"'" :
"'0'").
",";
2800 $sql .=
" localtax2_type = ".($localtaxtype2 !=
'' ?
"'".$this->db->escape($localtaxtype2).
"'" :
"'0'").
",";
2801 $sql .=
" default_vat_code = ".($newdefaultvatcode ?
"'".$this->db->escape($newdefaultvatcode).
"'" :
"null").
",";
2802 $sql .=
" price_label = ".(!empty($price_label) ?
"'".$this->db->escape($price_label).
"'" :
"null").
",";
2803 $sql .=
" tva_tx = ".(float)
price2num($newvat).
",";
2804 $sql .=
" recuperableonly = '".$this->db->escape($newnpr).
"'";
2805 $sql .=
" WHERE rowid = ".((int) $id);
2807 dol_syslog(get_class($this).
"::update_price", LOG_DEBUG);
2808 $resql = $this->db->query($sql);
2810 $this->multiprices[$level] = $price;
2811 $this->multiprices_ttc[$level] = $price_ttc;
2812 $this->multiprices_min[$level] = $price_min;
2813 $this->multiprices_min_ttc[$level] = $price_min_ttc;
2814 $this->multiprices_base_type[$level] = $newpricebase;
2815 $this->multiprices_default_vat_code[$level] = $newdefaultvatcode;
2816 $this->multiprices_tva_tx[$level] = $newvat;
2817 $this->multiprices_recuperableonly[$level] = $newnpr;
2819 $this->
price = $price;
2820 $this->price_label = $price_label;
2821 $this->price_ttc = $price_ttc;
2822 $this->price_min = $price_min;
2823 $this->price_min_ttc = $price_min_ttc;
2824 $this->price_base_type = $newpricebase;
2825 $this->default_vat_code = $newdefaultvatcode;
2826 $this->tva_tx = $newvat;
2827 $this->tva_npr = $newnpr;
2830 $this->localtax1_tx = $localtax1;
2831 $this->localtax2_tx = $localtax2;
2832 $this->localtax1_type = $localtaxtype1;
2833 $this->localtax2_type = $localtaxtype2;
2836 $this->price_by_qty = $newpbq;
2840 if (!empty(array_diff_assoc($newPriceData, $lastPriceData)) || !
getDolGlobalString(
'PRODUIT_MULTIPRICES')) {
2844 $this->level = $level;
2848 $result = $this->
call_trigger(
'PRODUCT_PRICE_MODIFY', $user);
2850 $this->db->rollback();
2856 $this->db->commit();
2858 $this->db->rollback();
2859 $this->error = $this->db->lasterror();
2878 $this->fk_price_expression = $expression_id;
2880 return $this->
update($this->
id, $user);
2895 public function fetch($id = 0, $ref =
'', $ref_ext =
'', $barcode =
'', $ignore_expression = 0, $ignore_price_load = 0, $ignore_lang_load = 0)
2897 include_once DOL_DOCUMENT_ROOT.
'/core/lib/company.lib.php';
2901 dol_syslog(get_class($this).
"::fetch id=".$id.
" ref=".$ref.
" ref_ext=".$ref_ext);
2904 if (!$id && !$ref && !$ref_ext && !$barcode) {
2905 $this->error =
'ErrorWrongParameters';
2906 dol_syslog(get_class($this).
"::fetch ".$this->error, LOG_ERR);
2910 $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,";
2911 $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,";
2912 $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,";
2913 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.last_main_doc,";
2914 $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,";
2916 $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,";
2918 $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,";
2923 $separatedEntityPMP =
false;
2924 $separatedStock =
false;
2925 $visibleWarehousesEntities =
$conf->entity;
2928 $checkPMPPerEntity = $this->db->query(
"SELECT pmp FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = ".((int) $id).
" AND entity = ".(
int)
$conf->entity);
2929 if ($this->db->num_rows($checkPMPPerEntity) > 0) {
2930 $separatedEntityPMP =
true;
2934 $separatedStock =
true;
2935 if (isset($mc->sharings[
'stock']) && !empty($mc->sharings[
'stock'])) {
2936 $visibleWarehousesEntities .=
"," . implode(
",", $mc->sharings[
'stock']);
2939 if ($separatedEntityPMP) {
2940 $sql .=
" ppe.pmp,";
2944 $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,";
2945 $sql .=
" p.fk_price_expression, p.price_autogen, p.model_pdf,";
2946 $sql .=
" p.price_label,";
2947 if ($separatedStock) {
2948 $sql .=
" SUM(sp.reel) as stock";
2952 $sql .=
" FROM ".$this->db->prefix().
"product as p";
2954 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int)
$conf->entity);
2956 if ($separatedStock) {
2957 $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).
"))";
2961 $sql .=
" WHERE p.rowid = ".((int) $id);
2963 $sql .=
" WHERE p.entity IN (".getEntity($this->element).
")";
2965 $sql .=
" AND p.ref = '".$this->db->escape($ref).
"'";
2966 } elseif ($ref_ext) {
2967 $sql .=
" AND p.ref_ext = '".$this->db->escape($ref_ext).
"'";
2968 } elseif ($barcode) {
2969 $sql .=
" AND p.barcode = '".$this->db->escape($barcode).
"'";
2972 if ($separatedStock) {
2973 $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,";
2974 $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,";
2975 $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,";
2976 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
2977 $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,";
2979 $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,";
2981 $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,";
2983 if ($separatedEntityPMP) {
2984 $sql .=
" ppe.pmp,";
2988 $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,";
2989 $sql .=
" p.fk_price_expression, p.price_autogen, p.model_pdf";
2990 $sql .=
" ,p.price_label";
2991 if (!$separatedStock) {
2992 $sql .=
", p.stock";
2996 $resql = $this->db->query($sql);
2998 unset($this->oldcopy);
3000 if ($this->db->num_rows($resql) > 0) {
3001 $obj = $this->db->fetch_object($resql);
3003 $this->
id = $obj->rowid;
3004 $this->
ref = $obj->ref;
3005 $this->ref_ext = $obj->ref_ext;
3006 $this->label = $obj->label;
3008 $this->url = $obj->url;
3009 $this->note_public = $obj->note_public;
3010 $this->note_private = $obj->note_private;
3011 $this->note = $obj->note_private;
3013 $this->
type = $obj->fk_product_type;
3014 $this->price_label = $obj->price_label;
3015 $this->
status = $obj->tosell;
3016 $this->status_buy = $obj->tobuy;
3017 $this->status_batch = $obj->tobatch;
3018 $this->sell_or_eat_by_mandatory = $obj->sell_or_eat_by_mandatory;
3019 $this->batch_mask = $obj->batch_mask;
3021 $this->customcode = $obj->customcode;
3022 $this->country_id = $obj->fk_country;
3023 $this->country_code =
getCountry($this->country_id,
'2', $this->db);
3024 $this->state_id = $obj->fk_state;
3025 $this->lifetime = $obj->lifetime;
3026 $this->qc_frequency = $obj->qc_frequency;
3027 $this->
price = $obj->price;
3028 $this->price_ttc = $obj->price_ttc;
3029 $this->price_min = $obj->price_min;
3030 $this->price_min_ttc = $obj->price_min_ttc;
3031 $this->price_base_type = $obj->price_base_type;
3032 $this->cost_price = isset($obj->cost_price) ? (float) $obj->cost_price :
null;
3033 $this->default_vat_code = $obj->default_vat_code;
3034 $this->tva_tx = $obj->tva_tx;
3036 $this->tva_npr = $obj->tva_npr;
3038 $this->localtax1_tx = $obj->localtax1_tx;
3039 $this->localtax2_tx = $obj->localtax2_tx;
3040 $this->localtax1_type = $obj->localtax1_type;
3041 $this->localtax2_type = $obj->localtax2_type;
3043 $this->finished = $obj->finished;
3044 $this->fk_default_bom = $obj->fk_default_bom;
3046 $this->duration = $obj->duration;
3048 preg_match(
'/([\d.]+)(\w+)/', $obj->duration, $matches);
3049 $this->duration_value = !empty($matches[1]) ? (float) $matches[1] : 0;
3050 $this->duration_unit = !empty($matches[2]) ? (string) $matches[2] :
null;
3051 $this->canvas = $obj->canvas;
3052 $this->net_measure = $obj->net_measure;
3053 $this->net_measure_units = $obj->net_measure_units;
3054 $this->weight = $obj->weight;
3055 $this->weight_units = (is_null($obj->weight_units) ? 0 : $obj->weight_units);
3056 $this->length = $obj->length;
3057 $this->length_units = (is_null($obj->length_units) ? 0 : $obj->length_units);
3058 $this->width = $obj->width;
3059 $this->width_units = (is_null($obj->width_units) ? 0 : $obj->width_units);
3060 $this->height = $obj->height;
3061 $this->height_units = (is_null($obj->height_units) ? 0 : $obj->height_units);
3063 $this->surface = $obj->surface;
3064 $this->surface_units = (is_null($obj->surface_units) ? 0 : $obj->surface_units);
3065 $this->volume = $obj->volume;
3066 $this->volume_units = (is_null($obj->volume_units) ? 0 : $obj->volume_units);
3067 $this->barcode = $obj->barcode;
3068 $this->barcode_type = $obj->fk_barcode_type;
3070 $this->accountancy_code_buy = $obj->accountancy_code_buy;
3071 $this->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra;
3072 $this->accountancy_code_buy_export = $obj->accountancy_code_buy_export;
3073 $this->accountancy_code_sell = $obj->accountancy_code_sell;
3074 $this->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra;
3075 $this->accountancy_code_sell_export = $obj->accountancy_code_sell_export;
3077 $this->fk_default_warehouse = $obj->fk_default_warehouse;
3078 $this->fk_default_workstation = $obj->fk_default_workstation;
3079 $this->seuil_stock_alerte = $obj->seuil_stock_alerte;
3080 $this->desiredstock = $obj->desiredstock;
3081 $this->stock_reel = $obj->stock;
3082 $this->pmp = $obj->pmp;
3084 $this->date_creation = $this->db->jdate($obj->datec);
3085 $this->date_modification = $this->db->jdate($obj->tms);
3087 $this->import_key = $obj->import_key;
3088 $this->entity = $obj->entity;
3090 $this->ref_ext = $obj->ref_ext;
3091 $this->fk_price_expression = $obj->fk_price_expression;
3092 $this->fk_unit = $obj->fk_unit;
3093 $this->price_autogen = $obj->price_autogen;
3094 $this->model_pdf = $obj->model_pdf;
3095 $this->last_main_doc = $obj->last_main_doc;
3097 $this->mandatory_period = $obj->mandatory_period;
3099 $this->db->free($resql);
3111 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
3112 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3113 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3114 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3115 $sql .=
" ,price_label";
3116 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3117 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3118 $sql .=
" AND price_level=".((int) $i);
3119 $sql .=
" AND fk_product = ".((int) $this->
id);
3120 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3122 $resql = $this->db->query($sql);
3124 $result = $this->db->fetch_array($resql);
3126 $this->multiprices[$i] = $result ? $result[
"price"] :
null;
3127 $this->multiprices_ttc[$i] = $result ? $result[
"price_ttc"] :
null;
3128 $this->multiprices_min[$i] = $result ? $result[
"price_min"] :
null;
3129 $this->multiprices_min_ttc[$i] = $result ? $result[
"price_min_ttc"] :
null;
3130 $this->multiprices_base_type[$i] = $result ? $result[
"price_base_type"] :
null;
3132 $this->multiprices_tva_tx[$i] = $result ? $result[
"tva_tx"].(!empty($result[
'default_vat_code']) ?
' ('.$result[
'default_vat_code'].
')' :
'') :
null;
3133 $this->multiprices_recuperableonly[$i] = $result ? $result[
"recuperableonly"] :
null;
3172 $this->error = $this->db->lasterror;
3178 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY') && empty($ignore_price_load)) {
3179 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3180 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid";
3181 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3182 $sql .=
" WHERE fk_product = ".((int) $this->
id);
3183 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3186 $resql = $this->db->query($sql);
3188 $result = $this->db->fetch_array($resql);
3192 $this->prices_by_qty[0] = $result[
"price_by_qty"];
3193 $this->prices_by_qty_id[0] = $result[
"rowid"];
3195 if ($this->prices_by_qty[0] == 1) {
3196 $sql =
"SELECT rowid,price, unitprice, quantity, remise_percent, remise, remise, price_base_type";
3197 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3198 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[0]);
3199 $sql .=
" ORDER BY quantity ASC";
3201 $resql = $this->db->query($sql);
3203 $resultat = array();
3205 while ($result = $this->db->fetch_array($resql)) {
3206 $resultat[$ii] = array();
3207 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3208 $resultat[$ii][
"price"] = $result[
"price"];
3209 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3210 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3211 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3213 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3216 $this->prices_by_qty_list[0] = $resultat;
3218 $this->error = $this->db->lasterror;
3224 $this->error = $this->db->lasterror;
3227 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') && empty($ignore_price_load)) {
3228 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
3229 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3230 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3231 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3232 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3233 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3234 $sql .=
" AND price_level=".((int) $i);
3235 $sql .=
" AND fk_product = ".((int) $this->
id);
3236 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3238 $resql = $this->db->query($sql);
3240 $this->error = $this->db->lasterror;
3242 } elseif ($result = $this->db->fetch_array($resql)) {
3243 $this->multiprices[$i] = (!empty($result[
"price"]) ? $result[
"price"] : 0);
3244 $this->multiprices_ttc[$i] = (!empty($result[
"price_ttc"]) ? $result[
"price_ttc"] : 0);
3245 $this->multiprices_min[$i] = (!empty($result[
"price_min"]) ? $result[
"price_min"] : 0);
3246 $this->multiprices_min_ttc[$i] = (!empty($result[
"price_min_ttc"]) ? $result[
"price_min_ttc"] : 0);
3247 $this->multiprices_base_type[$i] = (!empty($result[
"price_base_type"]) ? $result[
"price_base_type"] :
'');
3249 $this->multiprices_tva_tx[$i] = (!empty($result[
"tva_tx"]) ? $result[
"tva_tx"] : 0);
3250 $this->multiprices_recuperableonly[$i] = (!empty($result[
"recuperableonly"]) ? $result[
"recuperableonly"] : 0);
3253 $this->prices_by_qty[$i] = (!empty($result[
"price_by_qty"]) ? $result[
"price_by_qty"] : 0);
3254 $this->prices_by_qty_id[$i] = (!empty($result[
"rowid"]) ? $result[
"rowid"] : 0);
3256 if ($this->prices_by_qty[$i] == 1) {
3257 $sql =
"SELECT rowid, price, unitprice, quantity, remise_percent, remise, price_base_type";
3258 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3259 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[$i]);
3260 $sql .=
" ORDER BY quantity ASC";
3262 $resql = $this->db->query($sql);
3264 $resultat = array();
3266 while ($result = $this->db->fetch_array($resql)) {
3267 $resultat[$ii] = array();
3268 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3269 $resultat[$ii][
"price"] = $result[
"price"];
3270 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3271 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3272 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3273 $resultat[$ii][
"remise"] = $result[
"remise"];
3274 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3277 $this->prices_by_qty_list[$i] = $resultat;
3279 $this->error = $this->db->lasterror;
3287 if (isModEnabled(
'dynamicprices') && !empty($this->fk_price_expression) && empty($ignore_expression)) {
3288 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
3290 $price_result = $priceparser->parseProduct($this);
3291 if ($price_result >= 0) {
3292 $this->
price = $price_result;
3294 $this->price_ttc = (float)
price2num($this->
price) * (1 + ($this->tva_tx / 100));
3295 $this->price_ttc = (float)
price2num($this->price_ttc,
'MU');
3301 $this->stock_warehouse = array();
3308 $this->error = $this->db->lasterror();
3323 global $user, $hookmanager, $action;
3327 foreach (array(
'toconsume',
'consumed',
'toproduce',
'produced') as $role) {
3328 $this->stats_mo[
'customers_'.$role] = 0;
3329 $this->stats_mo[
'nb_'.$role] = 0;
3330 $this->stats_mo[
'qty_'.$role] = 0;
3332 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3333 $sql .=
" SUM(mp.qty) as qty";
3334 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as c";
3335 $sql .=
" INNER JOIN ".$this->db->prefix().
"mrp_production as mp ON mp.fk_mo=c.rowid";
3336 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3337 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3340 $sql .=
" c.entity IN (".getEntity(
'mo').
")";
3342 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3343 $sql .=
" AND mp.role ='".$this->db->escape($role).
"'";
3345 $sql .=
" AND c.fk_soc = ".((int) $socid);
3348 $result = $this->db->query($sql);
3350 $obj = $this->db->fetch_object($result);
3351 $this->stats_mo[
'customers_'.$role] = $obj->nb_customers ? $obj->nb_customers : 0;
3352 $this->stats_mo[
'nb_'.$role] = $obj->nb ? $obj->nb : 0;
3353 $this->stats_mo[
'qty_'.$role] = $obj->qty ?
price2num($obj->qty,
'MS') : 0;
3355 $this->error = $this->db->error();
3360 if (!empty($error)) {
3364 $parameters = array(
'socid' => $socid);
3365 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3367 $this->stats_mo = $hookmanager->resArray[
'stats_mo'];
3383 global $hookmanager, $action;
3387 $this->stats_bom[
'nb_toproduce'] = 0;
3388 $this->stats_bom[
'nb_toconsume'] = 0;
3389 $this->stats_bom[
'qty_toproduce'] = 0;
3390 $this->stats_bom[
'qty_toconsume'] = 0;
3392 $sql =
"SELECT COUNT(DISTINCT b.rowid) as nb_toproduce,";
3393 $sql .=
" SUM(b.qty) as qty_toproduce";
3394 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3395 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom = b.rowid";
3397 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3398 $sql .=
" AND b.fk_product =".((int) $this->
id);
3399 $sql .=
" GROUP BY b.rowid";
3401 $result = $this->db->query($sql);
3403 $obj = $this->db->fetch_object($result);
3404 $this->stats_bom[
'nb_toproduce'] = !empty($obj->nb_toproduce) ? $obj->nb_toproduce : 0;
3405 $this->stats_bom[
'qty_toproduce'] = !empty($obj->qty_toproduce) ?
price2num($obj->qty_toproduce) : 0;
3407 $this->error = $this->db->error();
3411 $sql =
"SELECT COUNT(DISTINCT bl.rowid) as nb_toconsume,";
3412 $sql .=
" SUM(bl.qty) as qty_toconsume";
3413 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3414 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
3416 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3417 $sql .=
" AND bl.fk_product =".((int) $this->
id);
3419 $result = $this->db->query($sql);
3421 $obj = $this->db->fetch_object($result);
3422 $this->stats_bom[
'nb_toconsume'] = !empty($obj->nb_toconsume) ? $obj->nb_toconsume : 0;
3423 $this->stats_bom[
'qty_toconsume'] = !empty($obj->qty_toconsume) ?
price2num($obj->qty_toconsume) : 0;
3425 $this->error = $this->db->error();
3429 if (!empty($error)) {
3433 $parameters = array(
'socid' => $socid);
3434 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3436 $this->stats_bom = $hookmanager->resArray[
'stats_bom'];
3452 global $user, $hookmanager, $action;
3454 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_customers, COUNT(DISTINCT p.rowid) as nb,";
3455 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3456 $sql .=
" FROM ".$this->db->prefix().
"propaldet as pd";
3457 $sql .=
", ".$this->db->prefix().
"propal as p";
3458 $sql .=
", ".$this->db->prefix().
"societe as s";
3459 $sql .=
" WHERE p.rowid = pd.fk_propal";
3460 $sql .=
" AND p.fk_soc = s.rowid";
3461 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
3462 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3463 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3464 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $user->id);
3468 $sql .=
" AND p.fk_soc = ".((int) $socid);
3471 $result = $this->db->query($sql);
3473 $obj = $this->db->fetch_object($result);
3474 $this->stats_propale[
'customers'] = $obj->nb_customers;
3475 $this->stats_propale[
'nb'] = $obj->nb;
3476 $this->stats_propale[
'rows'] = $obj->nb_rows;
3477 $this->stats_propale[
'qty'] = $obj->qty ? $obj->qty : 0;
3482 if (is_array($TFather) && !empty($TFather)) {
3483 foreach ($TFather as &$fatherData) {
3484 $pFather =
new Product($this->db);
3485 $pFather->id = $fatherData[
'id'];
3486 $qtyCoef = $fatherData[
'qty'];
3488 if ($fatherData[
'incdec']) {
3489 $pFather->load_stats_propale($socid);
3491 $this->stats_propale[
'customers'] += $pFather->stats_propale[
'customers'];
3492 $this->stats_propale[
'nb'] += $pFather->stats_propale[
'nb'];
3493 $this->stats_propale[
'rows'] += $pFather->stats_propale[
'rows'];
3494 $this->stats_propale[
'qty'] += $pFather->stats_propale[
'qty'] * $qtyCoef;
3500 $parameters = array(
'socid' => $socid);
3501 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerProposal', $parameters, $this, $action);
3503 $this->stats_propale = $hookmanager->resArray[
'stats_propale'];
3508 $this->error = $this->db->error();
3524 global $user, $hookmanager, $action;
3526 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_suppliers, COUNT(DISTINCT p.rowid) as nb,";
3527 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3528 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as pd";
3529 $sql .=
", ".$this->db->prefix().
"supplier_proposal as p";
3530 $sql .=
", ".$this->db->prefix().
"societe as s";
3531 $sql .=
" WHERE p.rowid = pd.fk_supplier_proposal";
3532 $sql .=
" AND p.fk_soc = s.rowid";
3533 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
3534 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3535 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3536 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $user->id);
3540 $sql .=
" AND p.fk_soc = ".((int) $socid);
3543 $result = $this->db->query($sql);
3545 $obj = $this->db->fetch_object($result);
3546 $this->stats_proposal_supplier[
'suppliers'] = $obj->nb_suppliers;
3547 $this->stats_proposal_supplier[
'nb'] = $obj->nb;
3548 $this->stats_proposal_supplier[
'rows'] = $obj->nb_rows;
3549 $this->stats_proposal_supplier[
'qty'] = $obj->qty ? $obj->qty : 0;
3551 $parameters = array(
'socid' => $socid);
3552 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierProposal', $parameters, $this, $action);
3554 $this->stats_proposal_supplier = $hookmanager->resArray[
'stats_proposal_supplier'];
3559 $this->error = $this->db->error();
3577 global $user, $hookmanager, $action;
3579 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3580 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3581 $sql .=
" FROM ".$this->db->prefix().
"commandedet as cd";
3582 $sql .=
", ".$this->db->prefix().
"commande as c";
3583 $sql .=
", ".$this->db->prefix().
"societe as s";
3584 $sql .=
" WHERE c.rowid = cd.fk_commande";
3585 $sql .=
" AND c.fk_soc = s.rowid";
3586 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'commande').
")";
3587 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3588 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3589 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3592 $sql .=
" AND c.fk_soc = ".((int) $socid);
3594 if ($filtrestatut !=
'') {
3595 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3598 $result = $this->db->query($sql);
3600 $obj = $this->db->fetch_object($result);
3601 $this->stats_commande[
'customers'] = $obj->nb_customers;
3602 $this->stats_commande[
'nb'] = $obj->nb;
3603 $this->stats_commande[
'rows'] = $obj->nb_rows;
3604 $this->stats_commande[
'qty'] = $obj->qty ? $obj->qty : 0;
3609 if (is_array($TFather) && !empty($TFather)) {
3610 foreach ($TFather as &$fatherData) {
3611 $pFather =
new Product($this->db);
3612 $pFather->id = $fatherData[
'id'];
3613 $qtyCoef = $fatherData[
'qty'];
3615 if ($fatherData[
'incdec']) {
3616 $pFather->load_stats_commande($socid, $filtrestatut);
3618 $this->stats_commande[
'customers'] += $pFather->stats_commande[
'customers'];
3619 $this->stats_commande[
'nb'] += $pFather->stats_commande[
'nb'];
3620 $this->stats_commande[
'rows'] += $pFather->stats_commande[
'rows'];
3621 $this->stats_commande[
'qty'] += $pFather->stats_commande[
'qty'] * $qtyCoef;
3633 $sql =
"SELECT SUM(".$this->db->ifsql(
'f.type=2', -1, 1).
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3634 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3635 $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'))";
3636 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3637 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3639 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3640 $resql = $this->db->query($sql);
3642 if ($this->db->num_rows($resql) > 0) {
3643 $obj = $this->db->fetch_object($resql);
3644 $adeduire += $obj->count;
3648 $this->stats_commande[
'qty'] -= $adeduire;
3651 include_once DOL_DOCUMENT_ROOT.
'/compta/facture/class/facture.class.php';
3655 $sql =
"SELECT sum(".$this->db->ifsql(
'f.type=2', -1, 1).
" * fd.qty) as count FROM ".MAIN_DB_PREFIX.
"facturedet as fd ";
3656 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"facture as f ON fd.fk_facture = f.rowid";
3657 $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'))";
3658 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"commande as c ON el.fk_source = c.rowid";
3659 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3661 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3662 $resql = $this->db->query($sql);
3664 if ($this->db->num_rows($resql) > 0) {
3665 $obj = $this->db->fetch_object($resql);
3666 $adeduire += $obj->count;
3669 $this->error = $this->db->error();
3673 $this->stats_commande[
'qty'] -= $adeduire;
3677 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3678 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerOrder', $parameters, $this, $action);
3680 $this->stats_commande = $hookmanager->resArray[
'stats_commande'];
3684 $this->error = $this->db->error();
3702 global $user, $hookmanager, $action;
3704 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_suppliers, COUNT(DISTINCT c.rowid) as nb,";
3705 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3706 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as cd";
3707 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as c";
3708 $sql .=
", ".$this->db->prefix().
"societe as s";
3709 $sql .=
" WHERE c.rowid = cd.fk_commande";
3710 $sql .=
" AND c.fk_soc = s.rowid";
3711 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3712 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3713 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3714 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3717 $sql .=
" AND c.fk_soc = ".((int) $socid);
3719 if ($filtrestatut !=
'') {
3720 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3722 if (!empty($dateofvirtualstock)) {
3723 $sql .=
" AND c.date_livraison <= '".$this->db->idate($dateofvirtualstock).
"'";
3726 $result = $this->db->query($sql);
3728 $obj = $this->db->fetch_object($result);
3729 $this->stats_commande_fournisseur[
'suppliers'] = $obj->nb_suppliers;
3730 $this->stats_commande_fournisseur[
'nb'] = $obj->nb;
3731 $this->stats_commande_fournisseur[
'rows'] = $obj->nb_rows;
3732 $this->stats_commande_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
3734 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3735 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierOrder', $parameters, $this, $action);
3737 $this->stats_commande_fournisseur = $hookmanager->resArray[
'stats_commande_fournisseur'];
3742 $this->error = $this->db->error().
' sql='.$sql;
3757 public function load_stats_sending($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $filterShipmentStatus =
'')
3760 global $user, $hookmanager, $action;
3762 $sql =
"SELECT COUNT(DISTINCT e.fk_soc) as nb_customers, COUNT(DISTINCT e.rowid) as nb,";
3763 $sql .=
" COUNT(ed.rowid) as nb_rows, SUM(ed.qty) as qty";
3764 $sql .=
" FROM ".$this->db->prefix().
"expeditiondet as ed";
3765 $sql .=
", ".$this->db->prefix().
"commandedet as cd";
3766 $sql .=
", ".$this->db->prefix().
"commande as c";
3767 $sql .=
", ".$this->db->prefix().
"expedition as e";
3768 $sql .=
", ".$this->db->prefix().
"societe as s";
3769 $sql .=
" WHERE e.rowid = ed.fk_expedition";
3770 $sql .=
" AND c.rowid = cd.fk_commande";
3771 $sql .=
" AND e.fk_soc = s.rowid";
3772 $sql .=
" AND e.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'expedition').
")";
3773 $sql .=
" AND ed.fk_elementdet = cd.rowid";
3774 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3775 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3776 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = e.fk_soc AND sc.fk_user = ".((int) $user->id);
3779 $sql .=
" AND e.fk_soc = ".((int) $socid);
3781 if ($filtrestatut !=
'') {
3782 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3784 if (!empty($filterShipmentStatus)) {
3785 $sql .=
" AND e.fk_statut IN (".$this->db->sanitize($filterShipmentStatus).
")";
3788 $result = $this->db->query($sql);
3790 $obj = $this->db->fetch_object($result);
3791 $this->stats_expedition[
'customers'] = $obj->nb_customers;
3792 $this->stats_expedition[
'nb'] = $obj->nb;
3793 $this->stats_expedition[
'rows'] = $obj->nb_rows;
3794 $this->stats_expedition[
'qty'] = $obj->qty ? $obj->qty : 0;
3799 if (is_array($TFather) && !empty($TFather)) {
3800 foreach ($TFather as &$fatherData) {
3801 $pFather =
new Product($this->db);
3802 $pFather->id = $fatherData[
'id'];
3803 $qtyCoef = $fatherData[
'qty'];
3805 if ($fatherData[
'incdec']) {
3806 $pFather->load_stats_sending($socid, $filtrestatut, $forVirtualStock);
3808 $this->stats_expedition[
'customers'] += $pFather->stats_expedition[
'customers'];
3809 $this->stats_expedition[
'nb'] += $pFather->stats_expedition[
'nb'];
3810 $this->stats_expedition[
'rows'] += $pFather->stats_expedition[
'rows'];
3811 $this->stats_expedition[
'qty'] += $pFather->stats_expedition[
'qty'] * $qtyCoef;
3817 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock,
'filterShipmentStatus' => $filterShipmentStatus);
3818 $reshook = $hookmanager->executeHooks(
'loadStatsSending', $parameters, $this, $action);
3820 $this->stats_expedition = $hookmanager->resArray[
'stats_expedition'];
3825 $this->error = $this->db->error();
3840 public function load_stats_reception($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null)
3843 global $user, $hookmanager, $action;
3845 $sql =
"SELECT COUNT(DISTINCT cf.fk_soc) as nb_suppliers, COUNT(DISTINCT cf.rowid) as nb,";
3846 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
3847 $sql .=
" FROM ".$this->db->prefix().
"receptiondet_batch as fd";
3848 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as cf";
3849 $sql .=
", ".$this->db->prefix().
"societe as s";
3850 $sql .=
" WHERE cf.rowid = fd.fk_element";
3851 $sql .=
" AND cf.fk_soc = s.rowid";
3852 $sql .=
" AND cf.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3853 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3854 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3855 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = cf.fk_soc AND sc.fk_user = ".((int) $user->id);
3858 $sql .=
" AND cf.fk_soc = ".((int) $socid);
3860 if ($filtrestatut !=
'') {
3861 $sql .=
" AND cf.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3863 if (!empty($dateofvirtualstock)) {
3864 $sql .=
" AND fd.datec <= '".$this->db->idate($dateofvirtualstock).
"'";
3867 $result = $this->db->query($sql);
3869 $obj = $this->db->fetch_object($result);
3870 $this->stats_reception[
'suppliers'] = $obj->nb_suppliers;
3871 $this->stats_reception[
'nb'] = $obj->nb;
3872 $this->stats_reception[
'rows'] = $obj->nb_rows;
3873 $this->stats_reception[
'qty'] = $obj->qty ? $obj->qty : 0;
3875 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3876 $reshook = $hookmanager->executeHooks(
'loadStatsReception', $parameters, $this, $action);
3878 $this->stats_reception = $hookmanager->resArray[
'stats_reception'];
3883 $this->error = $this->db->error();
3899 public function load_stats_inproduction($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null, $warehouseid = 0)
3902 global $user, $hookmanager, $action;
3904 $serviceStockIsEnabled = isModEnabled(
"service") &&
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES');
3906 $sql =
"SELECT COUNT(DISTINCT m.fk_soc) as nb_customers, COUNT(DISTINCT m.rowid) as nb,";
3907 $sql .=
" COUNT(mp.rowid) as nb_rows, SUM(mp.qty) as qty, role";
3908 $sql .=
" FROM ".$this->db->prefix().
"mrp_production as mp";
3909 $sql .=
", ".$this->db->prefix().
"mrp_mo as m";
3910 $sql .=
" LEFT JOIN ".$this->db->prefix().
"societe as s ON s.rowid = m.fk_soc";
3911 $sql .=
" WHERE m.rowid = mp.fk_mo";
3912 $sql .=
" AND m.entity IN (".getEntity(($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE')) ?
'stock' :
'mrp').
")";
3913 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3914 $sql .=
" AND (mp.disable_stock_change IN (0) OR mp.disable_stock_change IS NULL)";
3915 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3916 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = m.fk_soc AND sc.fk_user = ".((int) $user->id);
3919 $sql .=
" AND m.fk_soc = ".((int) $socid);
3921 if ($filtrestatut !=
'') {
3922 $sql .=
" AND m.status IN (".$this->db->sanitize($filtrestatut).
")";
3924 if (!empty($dateofvirtualstock)) {
3925 $sql .=
" AND m.date_valid <= '".$this->db->idate($dateofvirtualstock).
"'";
3927 if (!$serviceStockIsEnabled) {
3928 $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))";
3930 if (!empty($warehouseid)) {
3931 $sql .=
" AND m.fk_warehouse = ".((int) $warehouseid);
3933 $sql .=
" GROUP BY role";
3936 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
3938 $this->stats_mrptoconsume[
'customers'] = 0;
3939 $this->stats_mrptoconsume[
'nb'] = 0;
3940 $this->stats_mrptoconsume[
'rows'] = 0;
3941 $this->stats_mrptoconsume[
'qty'] = 0.0;
3942 $this->stats_mrptoproduce[
'customers'] = 0;
3943 $this->stats_mrptoproduce[
'nb'] = 0;
3944 $this->stats_mrptoproduce[
'rows'] = 0;
3945 $this->stats_mrptoproduce[
'qty'] = 0.0;
3948 $result = $this->db->query($sql);
3950 while ($obj = $this->db->fetch_object($result)) {
3951 if ($obj->role ==
'toconsume' && empty($warehouseid)) {
3952 $this->stats_mrptoconsume[
'customers'] += (int) $obj->nb_customers;
3953 $this->stats_mrptoconsume[
'nb'] += (int) $obj->nb;
3954 $this->stats_mrptoconsume[
'rows'] += (int) $obj->nb_rows;
3955 $this->stats_mrptoconsume[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
3957 if ($obj->role ==
'consumed' && empty($warehouseid)) {
3961 $this->stats_mrptoconsume[
'qty'] -= ($obj->qty ? (float) $obj->qty : 0.0);
3963 if ($obj->role ==
'toproduce') {
3965 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
3967 $this->stats_mrptoproduce[
'customers'] += (int) $obj->nb_customers;
3968 $this->stats_mrptoproduce[
'nb'] += (int) $obj->nb;
3969 $this->stats_mrptoproduce[
'rows'] += (int) $obj->nb_rows;
3970 $this->stats_mrptoproduce[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
3973 if ($obj->role ==
'produced') {
3978 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3980 $this->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3987 if ($this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] < 0) {
3988 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
3991 if ($this->stats_mrptoconsume[
'qty'] < 0) {
3992 $this->stats_mrptoconsume[
'qty'] = 0;
3994 if ($this->stats_mrptoproduce[
'qty'] < 0) {
3995 $this->stats_mrptoproduce[
'qty'] = 0;
3999 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
4000 $reshook = $hookmanager->executeHooks(
'loadStatsInProduction', $parameters, $this, $action);
4002 $this->stats_mrptoproduce = $hookmanager->resArray[
'stats_mrptoproduce'];
4007 $this->error = $this->db->error();
4022 global $user, $hookmanager, $action;
4024 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
4025 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
4026 $sql .=
" FROM ".$this->db->prefix().
"contratdet as cd";
4027 $sql .=
", ".$this->db->prefix().
"contrat as c";
4028 $sql .=
", ".$this->db->prefix().
"societe as s";
4029 $sql .=
" WHERE c.rowid = cd.fk_contrat";
4030 $sql .=
" AND c.fk_soc = s.rowid";
4031 $sql .=
" AND c.entity IN (".getEntity(
'contract').
")";
4032 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
4033 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4034 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
4038 $sql .=
" AND c.fk_soc = ".((int) $socid);
4041 $result = $this->db->query($sql);
4043 $obj = $this->db->fetch_object($result);
4044 $this->stats_contrat[
'customers'] = $obj->nb_customers;
4045 $this->stats_contrat[
'nb'] = $obj->nb;
4046 $this->stats_contrat[
'rows'] = $obj->nb_rows;
4047 $this->stats_contrat[
'qty'] = $obj->qty ? $obj->qty : 0;
4052 if (is_array($TFather) && !empty($TFather)) {
4053 foreach ($TFather as &$fatherData) {
4054 $pFather =
new Product($this->db);
4055 $pFather->id = $fatherData[
'id'];
4056 $qtyCoef = $fatherData[
'qty'];
4058 if ($fatherData[
'incdec']) {
4059 $pFather->load_stats_contrat($socid);
4061 $this->stats_contrat[
'customers'] += $pFather->stats_contrat[
'customers'];
4062 $this->stats_contrat[
'nb'] += $pFather->stats_contrat[
'nb'];
4063 $this->stats_contrat[
'rows'] += $pFather->stats_contrat[
'rows'];
4064 $this->stats_contrat[
'qty'] += $pFather->stats_contrat[
'qty'] * $qtyCoef;
4070 $parameters = array(
'socid' => $socid);
4071 $reshook = $hookmanager->executeHooks(
'loadStatsContract', $parameters, $this, $action);
4073 $this->stats_contrat = $hookmanager->resArray[
'stats_contrat'];
4078 $this->error = $this->db->error().
' sql='.$sql;
4093 global $user, $hookmanager, $action;
4095 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4096 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(".$this->db->ifsql(
'f.type != 2',
'fd.qty',
'fd.qty * -1').
") as qty";
4097 $sql .=
" FROM ".$this->db->prefix().
"facturedet as fd";
4098 $sql .=
", ".$this->db->prefix().
"facture as f";
4099 $sql .=
", ".$this->db->prefix().
"societe as s";
4100 $sql .=
" WHERE f.rowid = fd.fk_facture";
4101 $sql .=
" AND f.fk_soc = s.rowid";
4102 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4103 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4104 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4105 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4109 $sql .=
" AND f.fk_soc = ".((int) $socid);
4112 $result = $this->db->query($sql);
4114 $obj = $this->db->fetch_object($result);
4115 $this->stats_facture[
'customers'] = $obj->nb_customers;
4116 $this->stats_facture[
'nb'] = $obj->nb;
4117 $this->stats_facture[
'rows'] = $obj->nb_rows;
4118 $this->stats_facture[
'qty'] = $obj->qty ? $obj->qty : 0;
4123 if (is_array($TFather) && !empty($TFather)) {
4124 foreach ($TFather as &$fatherData) {
4125 $pFather =
new Product($this->db);
4126 $pFather->id = $fatherData[
'id'];
4127 $qtyCoef = $fatherData[
'qty'];
4129 if ($fatherData[
'incdec']) {
4130 $pFather->load_stats_facture($socid);
4132 $this->stats_facture[
'customers'] += $pFather->stats_facture[
'customers'];
4133 $this->stats_facture[
'nb'] += $pFather->stats_facture[
'nb'];
4134 $this->stats_facture[
'rows'] += $pFather->stats_facture[
'rows'];
4135 $this->stats_facture[
'qty'] += $pFather->stats_facture[
'qty'] * $qtyCoef;
4141 $parameters = array(
'socid' => $socid);
4142 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoice', $parameters, $this, $action);
4144 $this->stats_facture = $hookmanager->resArray[
'stats_facture'];
4149 $this->error = $this->db->error();
4165 global $user, $hookmanager, $action;
4167 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4168 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4169 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facturedet_rec as fd";
4170 $sql .=
", ".MAIN_DB_PREFIX.
"facture_rec as f";
4171 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
4172 $sql .=
" WHERE f.rowid = fd.fk_facture";
4173 $sql .=
" AND f.fk_soc = s.rowid";
4174 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4175 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4176 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4177 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4181 $sql .=
" AND f.fk_soc = ".((int) $socid);
4184 $result = $this->db->query($sql);
4186 $obj = $this->db->fetch_object($result);
4187 $this->stats_facturerec[
'customers'] = (int) $obj->nb_customers;
4188 $this->stats_facturerec[
'nb'] = (int) $obj->nb;
4189 $this->stats_facturerec[
'rows'] = (int) $obj->nb_rows;
4190 $this->stats_facturerec[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4195 if (is_array($TFather) && !empty($TFather)) {
4196 foreach ($TFather as &$fatherData) {
4197 $pFather =
new Product($this->db);
4198 $pFather->id = $fatherData[
'id'];
4199 $qtyCoef = $fatherData[
'qty'];
4201 if ($fatherData[
'incdec']) {
4202 $pFather->load_stats_facture($socid);
4204 $this->stats_facturerec[
'customers'] += $pFather->stats_facturerec[
'customers'];
4205 $this->stats_facturerec[
'nb'] += $pFather->stats_facturerec[
'nb'];
4206 $this->stats_facturerec[
'rows'] += $pFather->stats_facturerec[
'rows'];
4207 $this->stats_facturerec[
'qty'] += $pFather->stats_facturerec[
'qty'] * $qtyCoef;
4213 $parameters = array(
'socid' => $socid);
4214 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoiceRec', $parameters, $this, $action);
4216 $this->stats_facturerec = $hookmanager->resArray[
'stats_facturerec'];
4221 $this->error = $this->db->error();
4236 global $user, $hookmanager, $action;
4238 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
4239 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4240 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as fd";
4241 $sql .=
", ".$this->db->prefix().
"facture_fourn as f";
4242 $sql .=
", ".$this->db->prefix().
"societe as s";
4243 $sql .=
" WHERE f.rowid = fd.fk_facture_fourn";
4244 $sql .=
" AND f.fk_soc = s.rowid";
4245 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4246 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4247 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4248 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4252 $sql .=
" AND f.fk_soc = ".((int) $socid);
4255 $result = $this->db->query($sql);
4257 $obj = $this->db->fetch_object($result);
4258 $this->stats_facture_fournisseur[
'suppliers'] = (int) $obj->nb_suppliers;
4259 $this->stats_facture_fournisseur[
'nb'] = (int) $obj->nb;
4260 $this->stats_facture_fournisseur[
'rows'] = (int) $obj->nb_rows;
4261 $this->stats_facture_fournisseur[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4263 $parameters = array(
'socid' => $socid);
4264 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoice', $parameters, $this, $action);
4266 $this->stats_facture_fournisseur = $hookmanager->resArray[
'stats_facture_fournisseur'];
4271 $this->error = $this->db->error();
4290 $resql = $this->db->query($sql);
4292 $num = $this->db->num_rows($resql);
4295 $arr = $this->db->fetch_array($resql);
4296 if (is_array($arr)) {
4297 $keyfortab = (string) $arr[1];
4299 $keyfortab = substr($keyfortab, -2);
4302 if ($mode ==
'byunit') {
4303 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[0];
4304 } elseif ($mode ==
'bynumber') {
4305 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4306 } elseif ($mode ==
'byamount') {
4307 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4316 $this->error = $this->db->error().
' sql='.$sql;
4323 } elseif ($year == -1) {
4332 for ($j = 0; $j < 12; $j++) {
4334 $idx = ucfirst(
dol_trunc(
dol_print_date(
dol_mktime(12, 0, 0, $month, 1, 1970),
"%b"), 1,
'right',
'UTF-8', 1));
4337 $result[$j] = array($idx, isset($tab[$year.$month]) ? $tab[$year.$month] : 0);
4340 $month =
"0".($month - 1);
4342 $month = substr($month, 1);
4350 return array_reverse($result);
4365 public function get_nb_vente($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4370 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4371 if ($mode ==
'bynumber') {
4372 $sql .=
", count(DISTINCT f.rowid)";
4374 $sql .=
", sum(d.total_ht) as total_ht";
4375 $sql .=
" FROM ".$this->db->prefix().
"facturedet as d, ".$this->db->prefix().
"facture as f, ".$this->db->prefix().
"societe as s";
4376 if ($filteronproducttype >= 0) {
4377 $sql .=
", ".$this->db->prefix().
"product as p";
4379 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4380 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4382 $sql .=
" WHERE f.rowid = d.fk_facture";
4383 if ($this->
id > 0) {
4384 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4386 $sql .=
" AND d.fk_product > 0";
4388 if ($filteronproducttype >= 0) {
4389 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4391 $sql .=
" AND f.fk_soc = s.rowid";
4392 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4393 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4394 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4397 $sql .=
" AND f.fk_soc = $socid";
4399 $sql .= $morefilter;
4400 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4401 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4403 return $this->
_get_stats($sql, $mode, $year);
4418 public function get_nb_achat($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4423 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4424 if ($mode ==
'bynumber') {
4425 $sql .=
", count(DISTINCT f.rowid)";
4427 $sql .=
", sum(d.total_ht) as total_ht";
4428 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as d, ".$this->db->prefix().
"facture_fourn as f, ".$this->db->prefix().
"societe as s";
4429 if ($filteronproducttype >= 0) {
4430 $sql .=
", ".$this->db->prefix().
"product as p";
4432 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4433 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4435 $sql .=
" WHERE f.rowid = d.fk_facture_fourn";
4436 if ($this->
id > 0) {
4437 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4439 $sql .=
" AND d.fk_product > 0";
4441 if ($filteronproducttype >= 0) {
4442 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4444 $sql .=
" AND f.fk_soc = s.rowid";
4445 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4446 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4447 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4450 $sql .=
" AND f.fk_soc = $socid";
4452 $sql .= $morefilter;
4453 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4454 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4456 return $this->
_get_stats($sql, $mode, $year);
4470 public function get_nb_propal($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4475 $sql =
"SELECT sum(d.qty) as qty, date_format(p.datep, '%Y%m')";
4476 if ($mode ==
'bynumber') {
4477 $sql .=
", count(DISTINCT p.rowid)";
4479 $sql .=
", sum(d.total_ht) as total_ht";
4480 $sql .=
" FROM ".$this->db->prefix().
"propaldet as d, ".$this->db->prefix().
"propal as p, ".$this->db->prefix().
"societe as s";
4481 if ($filteronproducttype >= 0) {
4482 $sql .=
", ".$this->db->prefix().
"product as prod";
4484 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4485 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4487 $sql .=
" WHERE p.rowid = d.fk_propal";
4488 if ($this->
id > 0) {
4489 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4491 $sql .=
" AND d.fk_product > 0";
4493 if ($filteronproducttype >= 0) {
4494 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4496 $sql .=
" AND p.fk_soc = s.rowid";
4497 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
4498 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4499 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4502 $sql .=
" AND p.fk_soc = ".((int) $socid);
4504 $sql .= $morefilter;
4505 $sql .=
" GROUP BY date_format(p.datep,'%Y%m')";
4506 $sql .=
" ORDER BY date_format(p.datep,'%Y%m') DESC";
4508 return $this->
_get_stats($sql, $mode, $year);
4527 $sql =
"SELECT sum(d.qty) as qty, date_format(p.date_valid, '%Y%m')";
4528 if ($mode ==
'bynumber') {
4529 $sql .=
", count(DISTINCT p.rowid)";
4531 $sql .=
", sum(d.total_ht) as total_ht";
4532 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as d, ".$this->db->prefix().
"supplier_proposal as p, ".$this->db->prefix().
"societe as s";
4533 if ($filteronproducttype >= 0) {
4534 $sql .=
", ".$this->db->prefix().
"product as prod";
4536 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4537 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4539 $sql .=
" WHERE p.rowid = d.fk_supplier_proposal";
4540 if ($this->
id > 0) {
4541 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4543 $sql .=
" AND d.fk_product > 0";
4545 if ($filteronproducttype >= 0) {
4546 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4548 $sql .=
" AND p.fk_soc = s.rowid";
4549 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
4550 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4551 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4554 $sql .=
" AND p.fk_soc = ".((int) $socid);
4556 $sql .= $morefilter;
4557 $sql .=
" GROUP BY date_format(p.date_valid,'%Y%m')";
4558 $sql .=
" ORDER BY date_format(p.date_valid,'%Y%m') DESC";
4560 return $this->
_get_stats($sql, $mode, $year);
4574 public function get_nb_order($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4579 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4580 if ($mode ==
'bynumber') {
4581 $sql .=
", count(DISTINCT c.rowid)";
4583 $sql .=
", sum(d.total_ht) as total_ht";
4584 $sql .=
" FROM ".$this->db->prefix().
"commandedet as d, ".$this->db->prefix().
"commande as c, ".$this->db->prefix().
"societe as s";
4585 if ($filteronproducttype >= 0) {
4586 $sql .=
", ".$this->db->prefix().
"product as p";
4588 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4589 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4591 $sql .=
" WHERE c.rowid = d.fk_commande";
4592 if ($this->
id > 0) {
4593 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4595 $sql .=
" AND d.fk_product > 0";
4597 if ($filteronproducttype >= 0) {
4598 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4600 $sql .=
" AND c.fk_soc = s.rowid";
4601 $sql .=
" AND c.entity IN (".getEntity(
'commande').
")";
4602 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4603 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4606 $sql .=
" AND c.fk_soc = ".((int) $socid);
4608 $sql .= $morefilter;
4609 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4610 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4612 return $this->
_get_stats($sql, $mode, $year);
4631 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4632 if ($mode ==
'bynumber') {
4633 $sql .=
", count(DISTINCT c.rowid)";
4635 $sql .=
", sum(d.total_ht) as total_ht";
4636 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as d, ".$this->db->prefix().
"commande_fournisseur as c, ".$this->db->prefix().
"societe as s";
4637 if ($filteronproducttype >= 0) {
4638 $sql .=
", ".$this->db->prefix().
"product as p";
4640 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4641 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4643 $sql .=
" WHERE c.rowid = d.fk_commande";
4644 if ($this->
id > 0) {
4645 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4647 $sql .=
" AND d.fk_product > 0";
4649 if ($filteronproducttype >= 0) {
4650 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4652 $sql .=
" AND c.fk_soc = s.rowid";
4653 $sql .=
" AND c.entity IN (".getEntity(
'supplier_order').
")";
4654 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4655 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4658 $sql .=
" AND c.fk_soc = ".((int) $socid);
4660 $sql .= $morefilter;
4661 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4662 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4664 return $this->
_get_stats($sql, $mode, $year);
4678 public function get_nb_contract($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4683 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_contrat, '%Y%m')";
4684 if ($mode ==
'bynumber') {
4685 $sql .=
", count(DISTINCT c.rowid)";
4687 $sql .=
", sum(d.total_ht) as total_ht";
4688 $sql .=
" FROM ".$this->db->prefix().
"contratdet as d, ".$this->db->prefix().
"contrat as c, ".$this->db->prefix().
"societe as s";
4689 if ($filteronproducttype >= 0) {
4690 $sql .=
", ".$this->db->prefix().
"product as p";
4692 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4693 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4695 $sql .=
" WHERE c.entity IN (".getEntity(
'contract').
")";
4696 $sql .=
" AND c.rowid = d.fk_contrat";
4698 if ($this->
id > 0) {
4699 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4701 $sql .=
" AND d.fk_product > 0";
4703 if ($filteronproducttype >= 0) {
4704 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4706 $sql .=
" AND c.fk_soc = s.rowid";
4708 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4709 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4712 $sql .=
" AND c.fk_soc = ".((int) $socid);
4714 $sql .= $morefilter;
4715 $sql .=
" GROUP BY date_format(c.date_contrat,'%Y%m')";
4716 $sql .=
" ORDER BY date_format(c.date_contrat,'%Y%m') DESC";
4718 return $this->
_get_stats($sql, $mode, $year);
4732 public function get_nb_mos($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4737 $sql =
"SELECT sum(d.qty), date_format(d.date_valid, '%Y%m')";
4738 if ($mode ==
'bynumber') {
4739 $sql .=
", count(DISTINCT d.rowid)";
4741 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as d LEFT JOIN ".$this->db->prefix().
"societe as s ON d.fk_soc = s.rowid";
4742 if ($filteronproducttype >= 0) {
4743 $sql .=
", ".$this->db->prefix().
"product as p";
4745 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4746 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4749 $sql .=
" WHERE d.entity IN (".getEntity(
'mo').
")";
4750 $sql .=
" AND d.status > 0";
4752 if ($this->
id > 0) {
4753 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4755 $sql .=
" AND d.fk_product > 0";
4757 if ($filteronproducttype >= 0) {
4758 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4761 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4762 $sql .=
" AND d.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4765 $sql .=
" AND d.fk_soc = ".((int) $socid);
4767 $sql .= $morefilter;
4768 $sql .=
" GROUP BY date_format(d.date_valid,'%Y%m')";
4769 $sql .=
" ORDER BY date_format(d.date_valid,'%Y%m') DESC";
4771 return $this->
_get_stats($sql, $mode, $year);
4791 if (!is_numeric($id_pere)) {
4794 if (!is_numeric($id_fils)) {
4797 if (!is_numeric($incdec)) {
4807 $sql =
"SELECT fk_product_pere from ".$this->db->prefix().
"product_association";
4808 $sql .=
" WHERE fk_product_pere = ".((int) $id_fils).
" AND fk_product_fils = ".((int) $id_pere);
4809 if (!$this->db->query($sql)) {
4814 $sql =
"SELECT MAX(rang) as max_rank FROM ".$this->db->prefix().
"product_association";
4815 $sql .=
" WHERE fk_product_pere = ".((int) $id_pere);
4816 $resql = $this->db->query($sql);
4818 $obj = $this->db->fetch_object($resql);
4819 $rank = $obj->max_rank + 1;
4821 $sql =
"INSERT INTO ".$this->db->prefix().
"product_association(fk_product_pere,fk_product_fils,qty,incdec,rang)";
4822 $sql .=
" VALUES (".((int) $id_pere).
", ".((int) $id_fils).
", ".
price2num($qty,
'MS').
", ".((int) $incdec).
", ".((int) $rank).
")";
4823 if (! $this->db->query($sql)) {
4829 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_ADD', $user);
4831 $this->error = $this->db->lasterror();
4832 dol_syslog(get_class($this).
'::addSubproduct error='.$this->error, LOG_ERR);
4864 if (!is_numeric($id_pere)) {
4867 if (!is_numeric($id_fils)) {
4870 if (!is_numeric($incdec)) {
4873 if (!is_numeric($qty)) {
4877 $sql =
'UPDATE '.$this->db->prefix().
'product_association SET ';
4878 $sql .=
'qty = '.price2num($qty,
'MS');
4879 $sql .=
',incdec = '.((int) $incdec);
4880 $sql .=
' WHERE fk_product_pere = '.((int) $id_pere).
' AND fk_product_fils = '.((int) $id_fils);
4882 if (!$this->db->query($sql)) {
4888 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_UPDATE', $user);
4890 $this->error = $this->db->lasterror();
4891 dol_syslog(get_class($this).
'::updateSubproduct error='.$this->error, LOG_ERR);
4915 if (!is_numeric($fk_parent)) {
4918 if (!is_numeric($fk_child)) {
4922 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
4923 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
4924 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
4926 dol_syslog(get_class($this).
'::del_sousproduit', LOG_DEBUG);
4927 if (!$this->db->query($sql)) {
4933 $sqlrank =
"SELECT rowid, rang FROM ".$this->db->prefix().
"product_association";
4934 $sqlrank .=
" WHERE fk_product_pere = ".((int) $fk_parent);
4935 $sqlrank .=
" ORDER BY rang";
4936 $resqlrank = $this->db->query($sqlrank);
4939 while ($objrank = $this->db->fetch_object($resqlrank)) {
4941 $sql =
"UPDATE ".$this->db->prefix().
"product_association";
4942 $sql .=
" SET rang = ".((int) $cpt);
4943 $sql .=
" WHERE rowid = ".((int) $objrank->rowid);
4944 if (! $this->db->query($sql)) {
4953 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_DELETE', $user);
4955 $this->error = $this->db->lasterror();
4956 dol_syslog(get_class($this).
'::delSubproduct error='.$this->error, LOG_ERR);
4976 $sql =
"SELECT fk_product_pere, qty, incdec";
4977 $sql .=
" FROM ".$this->db->prefix().
"product_association";
4978 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
4979 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
4981 $result = $this->db->query($sql);
4983 $num = $this->db->num_rows($result);
4986 $obj = $this->db->fetch_object($result);
4988 $this->is_sousproduit_qty = $obj->qty;
4989 $this->is_sousproduit_incdec = $obj->incdec;
5020 dol_syslog(get_class($this).
"::add_fournisseur id_fourn = ".$id_fourn.
" ref_fourn=".$ref_fourn.
" quantity=".$quantity, LOG_DEBUG);
5027 $sql =
"SELECT rowid, fk_product";
5028 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5029 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5030 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5031 $sql .=
" AND fk_product <> ".((int) $this->
id);
5032 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5034 $resql = $this->db->query($sql);
5036 $obj = $this->db->fetch_object($resql);
5039 $this->product_id_already_linked = $obj->fk_product;
5042 $this->db->free($resql);
5046 $sql =
"SELECT rowid";
5047 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5048 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5050 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5052 $sql .=
" AND (ref_fourn = '' OR ref_fourn IS NULL)";
5054 $sql .=
" AND quantity = ".((float) $quantity);
5055 $sql .=
" AND fk_product = ".((int) $this->
id);
5056 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5058 $resql = $this->db->query($sql);
5060 $obj = $this->db->fetch_object($resql);
5064 $sql =
"INSERT INTO ".$this->db->prefix().
"product_fournisseur_price(";
5067 $sql .=
", fk_product";
5069 $sql .=
", ref_fourn";
5070 $sql .=
", quantity";
5071 $sql .=
", fk_user";
5073 $sql .=
") VALUES (";
5074 $sql .=
"'".$this->db->idate($now).
"'";
5075 $sql .=
", ".((int)
$conf->entity);
5076 $sql .=
", ".((int) $this->
id);
5077 $sql .=
", ".((int) $id_fourn);
5078 $sql .=
", '".$this->db->escape($ref_fourn).
"'";
5079 $sql .=
", ".((float) $quantity);
5080 $sql .=
", ".((int) $user->id);
5084 if ($this->db->query($sql)) {
5085 $this->product_fourn_price_id = $this->db->last_insert_id($this->db->prefix().
"product_fournisseur_price");
5088 $this->error = $this->db->lasterror();
5093 $this->product_fourn_price_id = $obj->rowid;
5097 $this->error = $this->db->lasterror();
5116 $sql =
"SELECT DISTINCT p.fk_soc";
5117 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as p";
5118 $sql .=
" WHERE p.fk_product = ".((int) $this->
id);
5119 $sql .=
" AND p.entity = ".((int)
$conf->entity);
5121 $result = $this->db->query($sql);
5123 $num = $this->db->num_rows($result);
5126 $obj = $this->db->fetch_object($result);
5127 $list[$i] = $obj->fk_soc;
5152 $sql =
"INSERT INTO ".$this->db->prefix().
"product_price (";
5154 $sql .=
", fk_product";
5155 $sql .=
", date_price";
5156 $sql .=
", price_level";
5158 $sql .=
", price_ttc";
5159 $sql .=
", price_min";
5160 $sql .=
", price_min_ttc";
5161 $sql .=
", price_base_type";
5162 $sql .=
", price_label";
5163 $sql .=
", default_vat_code";
5165 $sql .=
", recuperableonly";
5166 $sql .=
", localtax1_tx";
5167 $sql .=
", localtax1_type";
5168 $sql .=
", localtax2_tx";
5169 $sql .=
", localtax2_type";
5170 $sql .=
", fk_user_author";
5172 $sql .=
", price_by_qty";
5173 $sql .=
", fk_price_expression";
5174 $sql .=
", fk_multicurrency";
5175 $sql .=
", multicurrency_code";
5176 $sql .=
", multicurrency_tx";
5177 $sql .=
", multicurrency_price";
5178 $sql .=
", multicurrency_price_ttc";
5183 $sql .=
", '".$this->db->idate($now).
"'";
5184 $sql .=
", price_level";
5186 $sql .=
", price_ttc";
5187 $sql .=
", price_min";
5188 $sql .=
", price_min_ttc";
5189 $sql .=
", price_base_type";
5190 $sql .=
", price_label";
5191 $sql .=
", default_vat_code";
5193 $sql .=
", recuperableonly";
5194 $sql .=
", localtax1_tx";
5195 $sql .=
", localtax1_type";
5196 $sql .=
", localtax2_tx";
5197 $sql .=
", localtax2_type";
5198 $sql .=
", ".$user->id;
5200 $sql .=
", price_by_qty";
5201 $sql .=
", fk_price_expression";
5202 $sql .=
", fk_multicurrency";
5203 $sql .=
", multicurrency_code";
5204 $sql .=
", multicurrency_tx";
5205 $sql .=
", multicurrency_price";
5206 $sql .=
", multicurrency_price_ttc";
5207 $sql .=
" FROM ".$this->db->prefix().
"product_price ps";
5208 $sql .=
" WHERE fk_product = ".((int) $fromId);
5209 $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)";
5210 $sql .=
" ORDER BY date_price DESC";
5213 $resql = $this->db->query($sql);
5215 $this->db->rollback();
5219 $this->db->commit();
5236 $sql =
'INSERT INTO '.$this->db->prefix().
'product_association (fk_product_pere, fk_product_fils, qty, incdec)';
5237 $sql .=
" SELECT ".$toId.
", fk_product_fils, qty, incdec FROM ".$this->db->prefix().
"product_association";
5238 $sql .=
" WHERE fk_product_pere = ".((int) $fromId);
5240 dol_syslog(get_class($this).
'::clone_association', LOG_DEBUG);
5241 if (!$this->db->query($sql)) {
5242 $this->db->rollback();
5246 $this->db->commit();
5279 $sql =
"INSERT ".$this->db->prefix().
"product_fournisseur_price (";
5280 $sql .=
" datec, fk_product, fk_soc, price, quantity, fk_user, tva_tx)";
5281 $sql .=
" SELECT '".$this->db->idate($now).
"', ".((int) $toId).
", fk_soc, price, quantity, fk_user, tva_tx";
5282 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5283 $sql .=
" WHERE fk_product = ".((int) $fromId);
5285 dol_syslog(get_class($this).
'::clone_fournisseurs', LOG_DEBUG);
5286 $resql = $this->db->query($sql);
5288 $this->db->rollback();
5291 $this->db->commit();
5309 public function fetch_prod_arbo($prod, $compl_path =
'', $multiply = 1, $level = 1, $id_parent = 0, $ignore_stock_load = 0)
5315 foreach ($prod as $id_product => $desc_pere) {
5316 if (is_array($desc_pere)) {
5317 $id = (!empty($desc_pere[0]) ? $desc_pere[0] :
'');
5318 $nb = (!empty($desc_pere[1]) ? $desc_pere[1] :
'');
5319 $type = (!empty($desc_pere[2]) ? $desc_pere[2] :
'');
5320 $label = (!empty($desc_pere[3]) ? $desc_pere[3] :
'');
5321 $incdec = (!empty($desc_pere[4]) ? $desc_pere[4] : 0);
5323 if ($multiply < 1) {
5328 if (is_null($tmpproduct)) {
5329 $tmpproduct =
new Product($this->db);
5331 $tmpproduct->fetch($id);
5333 if (empty($ignore_stock_load) && ($tmpproduct->isProduct() ||
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES'))) {
5334 $tmpproduct->load_stock(
'nobatch,novirtual');
5337 $this->res[] = array(
5339 'id_parent' => $id_parent,
5340 'ref' => $tmpproduct->ref,
5342 'nb_total' => $nb * $multiply,
5343 'stock' => $tmpproduct->stock_reel,
5344 'stock_alert' => $tmpproduct->seuil_stock_alerte,
5346 'fullpath' => $compl_path.$label,
5348 'desiredstock' => $tmpproduct->desiredstock,
5350 'incdec' => $incdec,
5351 'entity' => $tmpproduct->entity
5355 if (isset($desc_pere[
'childs']) && is_array($desc_pere[
'childs'])) {
5357 $this->
fetch_prod_arbo($desc_pere[
'childs'], $compl_path.$desc_pere[3].
" -> ", $desc_pere[1] * $multiply, $level + 1, $id, $ignore_stock_load);
5375 $this->res = array();
5376 if (isset($this->sousprods) && is_array($this->sousprods)) {
5377 foreach ($this->sousprods as $prod_name => $desc_product) {
5378 if (is_array($desc_product)) {
5379 $this->
fetch_prod_arbo($desc_product,
"", $multiply, 1, $this->
id, $ignore_stock_load);
5398 $sql =
"SELECT COUNT(pa.rowid) as nb";
5399 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa";
5401 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id).
" OR pa.fk_product_pere = ".((int) $this->
id);
5402 } elseif ($mode == -1) {
5403 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id);
5404 } elseif ($mode == 1) {
5405 $sql .=
" WHERE pa.fk_product_pere = ".((int) $this->
id);
5408 $resql = $this->db->query($sql);
5410 $obj = $this->db->fetch_object($resql);
5429 $sql =
"SELECT count(rowid) as nb FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_parent = ".((int) $this->
id);
5430 $sql .=
" AND entity IN (".getEntity(
'product').
")";
5432 $resql = $this->db->query($sql);
5434 $obj = $this->db->fetch_object($resql);
5451 if (isModEnabled(
'variants')) {
5452 $sql =
"SELECT rowid FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_child = ".((int) $this->
id).
" AND entity IN (".
getEntity(
'product').
")";
5454 $query = $this->db->query($sql);
5457 if (!$this->db->num_rows($query)) {
5478 $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";
5479 $sql .=
", p.tosell as status, p.tobuy as status_buy";
5480 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa,";
5481 $sql .=
" ".$this->db->prefix().
"product as p";
5482 $sql .=
" WHERE p.rowid = pa.fk_product_pere";
5483 $sql .=
" AND pa.fk_product_fils = ".((int) $this->
id);
5485 $res = $this->db->query($sql);
5488 while ($record = $this->db->fetch_array($res)) {
5490 $prods[$record[
'id']] = array();
5491 $prods[$record[
'id']][
'id'] = $record[
'rowid'];
5492 $prods[$record[
'id']][
'ref'] = $record[
'ref'];
5493 $prods[$record[
'id']][
'label'] = $record[
'label'];
5494 $prods[$record[
'id']][
'qty'] = $record[
'qty'];
5495 $prods[$record[
'id']][
'incdec'] = $record[
'incdec'];
5496 $prods[$record[
'id']][
'fk_product_type'] = $record[
'fk_product_type'];
5497 $prods[$record[
'id']][
'entity'] = $record[
'entity'];
5498 $prods[$record[
'id']][
'status'] = $record[
'status'];
5499 $prods[$record[
'id']][
'status_buy'] = $record[
'status_buy'];
5518 public function getChildsArbo($id, $firstlevelonly = 0, $level = 1, $parents = array())
5524 $sql =
"SELECT p.rowid, p.ref, p.label as label, p.fk_product_type,";
5525 $sql .=
" pa.qty as qty, pa.fk_product_fils as id, pa.incdec,";
5526 $sql .=
" pa.rowid as fk_association, pa.rang";
5527 $sql .=
" FROM ".$this->db->prefix().
"product as p,";
5528 $sql .=
" ".$this->db->prefix().
"product_association as pa";
5529 $sql .=
" WHERE p.rowid = pa.fk_product_fils";
5530 $sql .=
" AND pa.fk_product_pere = ".((int) $id);
5531 $sql .=
" AND pa.fk_product_fils <> ".((int) $id);
5532 $sql .=
" ORDER BY pa.rang";
5534 dol_syslog(get_class($this).
'::getChildsArbo id='.$id.
' level='.$level.
' parents='.(is_array($parents) ? implode(
',', $parents) : $parents), LOG_DEBUG);
5541 $res = $this->db->query($sql);
5544 if ($this->db->num_rows($res) > 0) {
5548 while ($rec = $this->db->fetch_array($res)) {
5549 if (in_array($rec[
'id'], $parents)) {
5550 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);
5554 $prods[$rec[
'rowid']] = array(
5557 2 => $rec[
'fk_product_type'],
5558 3 => $this->db->escape($rec[
'label']),
5559 4 => $rec[
'incdec'],
5561 6 => $rec[
'fk_association'],
5566 if (empty($firstlevelonly)) {
5567 $listofchilds = $this->
getChildsArbo($rec[
'rowid'], 0, $level + 1, $parents);
5568 foreach ($listofchilds as $keyChild => $valueChild) {
5569 $prods[$rec[
'rowid']][
'childs'][$keyChild] = $valueChild;
5593 foreach ($this->
getChildsArbo($this->
id) as $keyChild => $valueChild) {
5594 $parent[$this->label][$keyChild] = $valueChild;
5596 foreach ($parent as $key => $value) {
5597 $this->sousprods[$key] = $value;
5610 global
$conf, $langs, $user;
5612 $langs->loadLangs(array(
'products',
'other'));
5615 $nofetch = !empty($params[
'nofetch']);
5618 return [
'optimize' => $langs->trans(
"ShowProduct")];
5622 $permissiontoreadproduct = 0;
5623 if ($this->
type == self::TYPE_PRODUCT && $user->hasRight(
'product',
'read')) {
5624 $permissiontoreadproduct = 1;
5626 if ($this->
type == self::TYPE_SERVICE && $user->hasRight(
'service',
'read')) {
5627 $permissiontoreadproduct = 1;
5630 if (!empty($this->entity) && $permissiontoreadproduct) {
5631 $tmpphoto = $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 80, 0, 0, 0, 0,
'1');
5632 if ($this->nbphoto > 0) {
5633 $datas[
'photo'] =
'<div class="photointooltip floatright">'.
"\n" . $tmpphoto .
'</div>';
5638 $datas[
'picto'] =
img_picto(
'',
'product').
' <u class="paddingrightonly">'.$langs->trans(
"Product").
'</u>';
5640 $datas[
'picto'] =
img_picto(
'',
'service').
' <u class="paddingrightonly">'.$langs->trans(
"Service").
'</u>';
5642 if (isset($this->
status) && isset($this->status_buy)) {
5643 $datas[
'status'] =
' '.$this->getLibStatut(5, 0) .
' '.$this->getLibStatut(5, 1);
5646 if (!empty($this->
ref)) {
5647 $datas[
'ref'] =
'<br><b>'.$langs->trans(
'ProductRef').
':</b> '.$this->ref;
5649 if (!empty($this->label)) {
5650 $datas[
'label'] =
'<br><b>'.$langs->trans(
'ProductLabel').
':</b> '.$this->label;
5653 if ($permissiontoreadproduct) {
5658 if (isModEnabled(
'productbatch')) {
5659 $langs->load(
"productbatch");
5660 $datas[
'batchstatus'] =
"<br><b>".$langs->trans(
"ManageLotSerial").
'</b>: '.$this->
getLibStatut(0, 2);
5661 if ($this->status_batch) {
5662 $datas[
'batchdlc'] =
"<br><b>".$langs->trans(
"BatchSellOrEatByMandatoryList", $langs->transnoentitiesnoconv(
"SellByDate"), $langs->transnoentitiesnoconv(
"EatByDate")).
'</b>: '.$this->
getSellOrEatByMandatoryLabel();
5666 if (isModEnabled(
'barcode')) {
5667 $datas[
'barcode'] =
'<br><b>'.$langs->trans(
'BarCode').
':</b> '.$this->barcode;
5671 if ($this->weight) {
5672 $datas[
'weight'] =
"<br><b>".$langs->trans(
"Weight").
'</b>: '.$this->weight.
' '.
measuringUnitString(0,
"weight", $this->weight_units);
5675 if ($this->length) {
5676 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Length").
'</b>: '.$this->length.
' '.
measuringUnitString(0,
'size', $this->length_units);
5679 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Width").
'</b>: '.$this->width.
' '.
measuringUnitString(0,
'size', $this->width_units);
5681 if ($this->height) {
5682 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Height").
'</b>: '.$this->height.
' '.
measuringUnitString(0,
'size', $this->height_units);
5685 $datas[
'size'] =
"<br>".$labelsize;
5688 $labelsurfacevolume =
"";
5689 if ($this->surface) {
5690 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Surface").
'</b>: '.$this->surface.
' '.
measuringUnitString(0,
'surface', $this->surface_units);
5692 if ($this->volume) {
5693 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Volume").
'</b>: '.$this->volume.
' '.
measuringUnitString(0,
'volume', $this->volume_units);
5695 if ($labelsurfacevolume) {
5696 $datas[
'surface'] =
"<br>" . $labelsurfacevolume;
5699 if ($this->
isService() && !empty($this->duration_value)) {
5701 $datas[
'duration'] =
'<br><b>'.$langs->trans(
"Duration").
':</b> '.$this->duration_value;
5702 if ($this->duration_value > 1) {
5703 $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"));
5704 } elseif ($this->duration_value > 0) {
5705 $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"));
5707 $datas[
'duration'] .= (!empty($this->duration_unit) && isset($dur[$this->duration_unit]) ?
" ".$langs->trans($dur[$this->duration_unit]) :
'');
5709 if (empty($user->socid)) {
5710 if (!empty($this->pmp) && $this->pmp) {
5711 $datas[
'pmp'] =
"<br><b>".$langs->trans(
"PMPValue").
'</b>: '.
price($this->pmp, 0,
'', 1, -1, -1,
$conf->currency);
5714 if (isModEnabled(
'accounting')) {
5715 if ($this->
status && isset($this->accountancy_code_sell)) {
5716 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5717 $selllabel =
'<br>';
5718 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellCode').
':</b> '.
length_accountg($this->accountancy_code_sell);
5719 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellIntraCode').
':</b> '.
length_accountg($this->accountancy_code_sell_intra);
5720 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellExportCode').
':</b> '.
length_accountg($this->accountancy_code_sell_export);
5721 $datas[
'accountancysell'] = $selllabel;
5723 if ($this->status_buy && isset($this->accountancy_code_buy)) {
5724 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5726 if (empty($this->
status)) {
5727 $buylabel .=
'<br>';
5729 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyCode').
':</b> '.
length_accountg($this->accountancy_code_buy);
5730 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyIntraCode').
':</b> '.
length_accountg($this->accountancy_code_buy_intra);
5731 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyExportCode').
':</b> '.
length_accountg($this->accountancy_code_buy_export);
5732 $datas[
'accountancybuy'] = $buylabel;
5737 if (isModEnabled(
'category') && !$nofetch) {
5738 require_once DOL_DOCUMENT_ROOT .
'/categories/class/categorie.class.php';
5739 $form =
new Form($this->db);
5740 $datas[
'categories'] =
'<br>' . $form->showCategories($this->
id, Categorie::TYPE_PRODUCT, 1);
5760 public function getNomUrl($withpicto = 0, $option =
'', $maxlength = 0, $save_lastsearch_value = -1, $notooltip = 0, $morecss =
'', $add_label = 0, $sep =
' - ')
5762 global $langs, $hookmanager;
5764 include_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
5768 $newref = $this->ref;
5770 $newref =
dol_trunc($newref, $maxlength,
'middle');
5774 'objecttype' => ($this->
type == 1 ?
'service' :
'product'),
5775 'option' => $option,
5778 $classfortooltip =
'classfortooltip';
5781 $classfortooltip =
'classforajaxtooltip';
5782 $dataparams =
' data-params="'.dol_escape_htmltag(json_encode($params)).
'"';
5789 if (empty($notooltip)) {
5791 $label = $langs->trans(
"ShowProduct");
5792 $linkclose .=
' alt="'.dol_escape_htmltag($label, 1, 1).
'"';
5794 $linkclose .= ($label ?
' title="'.dol_escape_htmltag($label, 1, 1).
'"' :
' title="tocomplete"');
5795 $linkclose .= $dataparams.
' class="nowraponall '.$classfortooltip.($morecss ?
' '.$morecss :
'').
'"';
5797 $linkclose =
' class="nowraponall'.($morecss ?
' '.$morecss :
'').
'"';
5800 if ($option ==
'supplier' || $option ==
'category') {
5801 $url = DOL_URL_ROOT.
'/product/price_suppliers.php?id='.$this->id;
5802 } elseif ($option ==
'stock') {
5803 $url = DOL_URL_ROOT.
'/product/stock/product.php?id='.$this->id;
5804 } elseif ($option ==
'composition') {
5805 $url = DOL_URL_ROOT.
'/product/composition/card.php?id='.$this->id;
5807 $url = DOL_URL_ROOT.
'/product/card.php?id='.$this->id;
5810 if ($option !==
'nolink') {
5812 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
5813 if ($save_lastsearch_value == -1 && isset($_SERVER[
"PHP_SELF"]) && preg_match(
'/list\.php/', $_SERVER[
"PHP_SELF"])) {
5814 $add_save_lastsearch_values = 1;
5816 if ($add_save_lastsearch_values) {
5817 $url .=
'&save_lastsearch_values=1';
5821 $linkstart =
'<a href="'.$url.
'"';
5822 $linkstart .= $linkclose.
'>';
5825 $result .= $linkstart;
5828 $result .= (
img_object(($notooltip ?
'' : $label),
'product',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
5831 $result .= (
img_object(($notooltip ?
'' : $label),
'service',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
5834 $result .=
'<span class="aaa">'.dol_escape_htmltag($newref).
'</span>';
5835 $result .= $linkend;
5836 if ($withpicto != 2) {
5837 $result .= (($add_label && $this->label) ? $sep.dol_trunc($this->label, ($add_label > 1 ? $add_label : 0)) :
'');
5841 $hookmanager->initHooks(array(
'productdao'));
5842 $parameters = array(
'id' => $this->
id,
'getnomurl' => &$result,
'label' => &$label);
5843 $reshook = $hookmanager->executeHooks(
'getNomUrl', $parameters, $this, $action);
5845 $result = $hookmanager->resPrint;
5847 $result .= $hookmanager->resPrint;
5864 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
5868 $langs->load(
"products");
5869 $outputlangs->load(
"products");
5876 $modelpath =
"core/modules/product/doc/";
5878 return $this->
commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
5894 return $this->
LibStatut($this->status_buy, $mode, $type);
5896 return $this->
LibStatut($this->status_batch, $mode, $type);
5899 return $this->
LibStatut($this->status_buy, $mode, $type);
5917 $labelStatus = $labelStatusShort =
'';
5919 $langs->load(
'products');
5920 if (isModEnabled(
'productbatch')) {
5921 $langs->load(
"productbatch");
5927 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial')));
5930 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort')));
5935 return dolGetStatus($langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch'),
'',
'', empty($status) ?
'status5' :
'status4', 3,
'dot');
5941 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'));
5945 $statuttrans = empty($status) ?
'status5' :
'status4';
5950 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSellShort');
5951 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSell');
5952 } elseif ($type == 1) {
5953 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuyShort');
5954 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuy');
5955 } elseif ($type == 2) {
5956 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch');
5957 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort');
5959 } elseif ($status == 1) {
5962 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSellShort');
5963 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSell');
5964 } elseif ($type == 1) {
5965 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBuyShort');
5966 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBuy');
5967 } elseif ($type == 2) {
5968 $labelStatus = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial'));
5969 $labelStatusShort = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort'));
5971 } elseif ($type == 2 && $status == 2) {
5972 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSerial');
5973 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort');
5977 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'),
'',
'',
'status0', 0);
5979 return dolGetStatus($labelStatus, $labelStatusShort,
'', $statuttrans, $mode);
5993 $langs->load(
'products');
5996 if (isset($this->finished) && $this->finished >= 0) {
5997 $sql =
"SELECT label, code FROM ".$this->db->prefix().
"c_product_nature where code = ".((int) $this->finished).
" AND active=1";
5998 $resql = $this->db->query($sql);
6000 $this->error = $this->db->error().
' sql='.$sql;
6001 dol_syslog(__METHOD__.
' Error '.$this->error, LOG_ERR);
6003 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
6004 $label = $langs->trans($res[
'label']);
6006 $this->db->free($resql);
6030 public function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label =
'', $price = 0, $inventorycode =
'', $origin_element =
'', $origin_id =
null, $disablestockchangeforsubproduct = 0, $extrafields =
null)
6036 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6042 $nbpiece = abs($nbpiece);
6045 $op[0] =
"+".trim((
string) $nbpiece);
6046 $op[1] =
"-".trim((
string) $nbpiece);
6049 $movementstock->setOrigin($origin_element, $origin_id);
6050 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'',
'',
'',
'',
false, 0, $disablestockchangeforsubproduct);
6054 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6055 $movementstock->array_options = $array_options;
6056 $movementstock->insertExtraFields();
6058 $this->db->commit();
6061 $this->error = $movementstock->error;
6062 $this->errors = $movementstock->errors;
6064 $this->db->rollback();
6093 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)
6099 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6105 $nbpiece = abs($nbpiece);
6109 $op[0] =
"+".trim((
string) $nbpiece);
6110 $op[1] =
"-".trim((
string) $nbpiece);
6113 $movementstock->setOrigin($origin_element, $origin_id);
6114 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'', $dlc, $dluo, $lot,
false, 0, $disablestockchangeforsubproduct, 0, $force_update_batch);
6118 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6119 $movementstock->array_options = $array_options;
6120 $movementstock->insertExtraFields();
6122 $this->db->commit();
6125 $this->error = $movementstock->error;
6126 $this->errors = $movementstock->errors;
6128 $this->db->rollback();
6148 public function load_stock($option =
'', $includedraftpoforvirtual =
null, $dateofvirtualstock =
null)
6151 $this->stock_reel = 0;
6152 $this->stock_warehouse = array();
6153 $this->stock_theorique = 0;
6156 $warehouseStatus = array();
6157 if (preg_match(
'/warehouseclosed/', $option)) {
6160 if (preg_match(
'/warehouseopen/', $option)) {
6163 if (preg_match(
'/warehouseinternal/', $option)) {
6171 $sql =
"SELECT ps.rowid, ps.reel, ps.fk_entrepot";
6172 $sql .=
" FROM ".$this->db->prefix().
"product_stock as ps";
6173 $sql .=
", ".$this->db->prefix().
"entrepot as w";
6174 $sql .=
" WHERE w.entity IN (".getEntity(
'stock').
")";
6175 $sql .=
" AND w.rowid = ps.fk_entrepot";
6176 $sql .=
" AND ps.fk_product = ".((int) $this->
id);
6177 if (count($warehouseStatus)) {
6178 $sql .=
" AND w.statut IN (".$this->db->sanitize(implode(
',', $warehouseStatus)).
")";
6181 $sql .=
" ORDER BY ps.reel ".(getDolGlobalString(
'DO_NOT_TRY_TO_DEFRAGMENT_STOCKS_WAREHOUSE') ?
'DESC' :
'ASC');
6183 dol_syslog(get_class($this).
"::load_stock", LOG_DEBUG);
6184 $result = $this->db->query($sql);
6186 $num = $this->db->num_rows($result);
6190 $row = $this->db->fetch_object($result);
6191 $this->stock_warehouse[$row->fk_entrepot] =
new stdClass();
6192 $this->stock_warehouse[$row->fk_entrepot]->real = $row->reel;
6193 $this->stock_warehouse[$row->fk_entrepot]->id = $row->rowid;
6194 if ((!preg_match(
'/nobatch/', $option)) && $this->
hasbatch()) {
6195 $this->stock_warehouse[$row->fk_entrepot]->detail_batch =
Productbatch::findAll($this->db, $row->rowid, 1, $this->id);
6197 $this->stock_reel += $row->reel;
6200 $this->stock_reel = (float)
price2num($this->stock_reel,
'MS');
6202 $this->db->free($result);
6204 if (!preg_match(
'/novirtual/', $option)) {
6210 $this->error = $this->db->lasterror();
6229 global $hookmanager, $action;
6231 $stock_commande_client = 0;
6232 $stock_commande_fournisseur = 0;
6233 $stock_sending_client = 0;
6234 $stock_reception_fournisseur = 0;
6235 $stock_inproduction = 0;
6239 if (isModEnabled(
'order')) {
6244 $stock_commande_client = $this->stats_commande[
'qty'];
6246 if (isModEnabled(
"shipping")) {
6247 require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expedition.class.php';
6248 $filterShipmentStatus =
'';
6258 $stock_sending_client = $this->stats_expedition[
'qty'];
6261 if (isModEnabled(
"supplier_order")) {
6262 $filterStatus =
getDolGlobalString(
'SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK',
'3,4');
6263 if (isset($includedraftpoforvirtual)) {
6264 $filterStatus =
'0,1,2,'.$filterStatus;
6270 $stock_commande_fournisseur = $this->stats_commande_fournisseur[
'qty'];
6273 if (isModEnabled(
"supplier_order") || isModEnabled(
"supplier_invoice")) {
6274 $filterStatus =
'4';
6275 if (isset($includedraftpoforvirtual)) {
6276 $filterStatus =
'0,'.$filterStatus;
6282 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
6285 if (isModEnabled(
'mrp')) {
6290 $stock_inproduction = $this->stats_mrptoproduce[
'qty'] - $this->stats_mrptoconsume[
'qty'];
6293 $this->stock_theorique = $this->stock_reel + $stock_inproduction;
6297 $weBillOrderOrShipmentReception =
getDolGlobalString(
'STOCK_DO_WE_BILL_ORDER_OR_SHIPMENTECEPTION_FOR_VIRTUALSTOCK',
'order');
6301 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6305 $result = $tmpnewprod->load_stats_commande(0,
'0', 1);
6306 $this->stock_theorique += $tmpnewprod->stats_commande[
'qty'];
6308 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6309 $this->stock_theorique -= $stock_commande_client;
6310 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6311 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6316 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6318 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6320 if (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER_INCLUDE_DRAFT')) {
6322 $result = $tmpnewprod->load_stats_commande_fournisseur(0,
'0', 1);
6323 $this->stock_theorique += $this->stats_commande_fournisseur[
'qty'];
6325 $this->stock_theorique -= $stock_reception_fournisseur;
6326 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6327 $this->stock_theorique += $stock_commande_fournisseur;
6328 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6329 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6332 $parameters = array(
'id' => $this->
id,
'includedraftpoforvirtual' => $includedraftpoforvirtual);
6334 $reshook = $hookmanager->executeHooks(
'loadvirtualstock', $parameters, $this, $action);
6336 $this->stock_theorique = $hookmanager->resArray[
'stock_theorique'];
6337 } elseif ($reshook == 0 && isset($hookmanager->resArray[
'stock_stats_hook'])) {
6338 $this->stock_theorique += $hookmanager->resArray[
'stock_stats_hook'];
6342 if (!empty($this->stock_warehouse) &&
getDolGlobalString(
'STOCK_ALLOW_VIRTUAL_STOCK_PER_WAREHOUSE')) {
6343 foreach ($this->stock_warehouse as $warehouseid => $stockwarehouse) {
6344 if (isModEnabled(
'mrp')) {
6351 if ($this->fk_default_warehouse == $warehouseid) {
6352 $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']);
6354 $this->stock_warehouse[$warehouseid]->virtual = $this->stock_warehouse[$warehouseid]->real + $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'];
6374 $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";
6375 $sql .=
" WHERE pb.fk_product_stock = ps.rowid AND ps.fk_product = ".((int) $this->
id).
" AND pb.batch = '".$this->db->escape($batch).
"'";
6376 $sql .=
" GROUP BY pb.batch, pb.eatby, pb.sellby";
6377 dol_syslog(get_class($this).
"::loadBatchInfo load first entry found for lot/serial = ".$batch, LOG_DEBUG);
6378 $resql = $this->db->query($sql);
6380 $num = $this->db->num_rows($resql);
6383 $obj = $this->db->fetch_object($resql);
6384 $result[] = array(
'batch' => $batch,
'eatby' => $this->db->jdate($obj->eatby),
'sellby' => $this->db->jdate($obj->sellby),
'qty' => $obj->qty);
6390 $this->db->rollback();
6407 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6413 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos";
6415 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product').dol_sanitizeFileName($this->
ref);
6420 $dir_osencoded = $dir;
6422 if (is_dir($dir_osencoded)) {
6423 $originImage = $dir.
'/'.$file[
'name'];
6434 if (is_numeric($result) && $result > 0) {
6451 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6452 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6456 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos/";
6458 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product');
6462 if (file_exists($dir_osencoded)) {
6463 $handle = opendir($dir_osencoded);
6464 if (is_resource($handle)) {
6465 while (($file = readdir($handle)) !==
false) {
6467 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6490 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6491 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6497 $handle = @opendir($dir_osencoded);
6498 if (is_resource($handle)) {
6499 while (($file = readdir($handle)) !==
false) {
6501 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6508 $photo_vignette =
'';
6510 if (preg_match(
'/('.$this->regeximgext.
')$/i', $photo, $regs)) {
6511 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $photo).
'_small'.$regs[0];
6514 $dirthumb = $dir.
'thumbs/';
6518 $obj[
'photo'] = $photo;
6519 if ($photo_vignette &&
dol_is_file($dirthumb.$photo_vignette)) {
6520 $obj[
'photo_vignette'] =
'thumbs/'.$photo_vignette;
6522 $obj[
'photo_vignette'] =
"";
6525 $tabobj[$nbphoto - 1] = $obj;
6528 if ($nbmax && $nbphoto >= $nbmax) {
6550 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6551 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6553 $dir = dirname($file).
'/';
6554 $dirthumb = $dir.
'/thumbs/';
6555 $filename = preg_replace(
'/'.preg_quote($dir,
'/').
'/i',
'', $file);
6561 if (preg_match(
'/('.$this->regeximgext.
')$/i', $filename, $regs)) {
6562 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_small'.$regs[0];
6563 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6567 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_mini'.$regs[0];
6568 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6585 $infoImg = getimagesize($file_osencoded);
6586 $this->imgWidth = $infoImg[0];
6587 $this->imgHeight = $infoImg[1];
6597 global $hookmanager;
6599 $this->nb = array();
6601 $sql =
"SELECT count(p.rowid) as nb, fk_product_type";
6602 $sql .=
" FROM ".$this->db->prefix().
"product as p";
6603 $sql .=
' WHERE p.entity IN ('.getEntity($this->element, 1).
')';
6605 if (is_object($hookmanager)) {
6606 $parameters = array();
6607 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
6608 $sql .= $hookmanager->resPrint;
6610 $sql .=
' GROUP BY fk_product_type';
6612 $resql = $this->db->query($sql);
6614 while ($obj = $this->db->fetch_object($resql)) {
6615 if ($obj->fk_product_type == 1) {
6616 $this->nb[
"services"] = $obj->nb;
6618 $this->nb[
"products"] = $obj->nb;
6621 $this->db->free($resql);
6625 $this->error = $this->db->error();
6667 return $this->mandatory_period == 1;
6677 return $this->status_batch > 0;
6697 $dirsociete = array_merge(array(
'/core/modules/barcode/'),
$conf->modules_parts[
'barcode']);
6698 foreach ($dirsociete as $dirroot) {
6706 '@phan-var-force ModeleNumRefBarCode $mod';
6708 $result = $mod->getNextValue(
$object, $type);
6710 dol_syslog(get_class($this).
"::get_barcode barcode=".$result.
" module=".$var);
6727 $this->specimen = 1;
6729 $this->
ref =
'PRODUCT_SPEC';
6730 $this->label =
'PRODUCT SPECIMEN';
6731 $this->
description =
'This is description of this product specimen that was created the '.dol_print_date($now,
'dayhourlog').
'.';
6732 $this->specimen = 1;
6733 $this->country_id = 1;
6735 $this->status_buy = 1;
6737 $this->sell_or_eat_by_mandatory = 0;
6738 $this->note_private =
'This is a comment (private)';
6739 $this->note_public =
'This is a comment (public)';
6740 $this->date_creation = $now;
6741 $this->date_modification = $now;
6744 $this->weight_units = 3;
6747 $this->length_units = 1;
6749 $this->width_units = 0;
6750 $this->height =
null;
6751 $this->height_units =
null;
6753 $this->surface = 30;
6754 $this->surface_units = 0;
6755 $this->volume = 300;
6756 $this->volume_units = 0;
6758 $this->barcode = -1;
6776 if (empty($this->fk_unit)) {
6779 if (empty($outputlangs)) {
6780 $outputlangs = $langs;
6783 $outputlangs->load(
'products');
6786 $sql =
"SELECT code, label, short_label FROM ".$this->db->prefix().
"c_units where rowid = ".((int) $this->fk_unit);
6788 $resql = $this->db->query($sql);
6790 $this->error = $this->db->error();
6791 dol_syslog(get_class($this).
"::getLabelOfUnit Error ".$this->error, LOG_ERR);
6793 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
6794 if ($type ==
'short') {
6796 $label = $outputlangs->transnoentitiesnoconv($res[
'short_label']);
6798 $label = $outputlangs->trans($res[
'short_label']);
6800 } elseif ($type ==
'code') {
6801 $label = $res[
'code'];
6803 if ($outputlangs->trans(
'unit'.$res[
'code']) ==
'unit'.$res[
'code']) {
6805 $label = $res[
'label'];
6809 $label = $outputlangs->transnoentitiesnoconv(
'unit'.$res[
'code']);
6811 $label = $outputlangs->trans(
'unit'.$res[
'code']);
6816 $this->db->free($resql);
6830 $maxpricesupplier = 0;
6833 include_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.product.class.php';
6835 $product_fourn_list = $product_fourn->list_product_fournisseur_price($this->
id,
'',
'');
6837 if (is_array($product_fourn_list) && count($product_fourn_list) > 0) {
6838 foreach ($product_fourn_list as $productfourn) {
6839 if ($productfourn->fourn_unitprice > $maxpricesupplier) {
6840 $maxpricesupplier = $productfourn->fourn_unitprice;
6848 return $maxpricesupplier;
6864 require_once DOL_DOCUMENT_ROOT.
'/categories/class/categorie.class.php';
6865 return parent::setCategoriesCommon($categories, Categorie::TYPE_PRODUCT);
6879 'product_customer_price',
6880 'product_customer_price_log'
6899 $sql =
"SELECT rowid, level, fk_level, var_percent, var_min_percent FROM ".$this->db->prefix().
"product_pricerules";
6900 $query = $this->db->query($sql);
6904 while ($result = $this->db->fetch_object($query)) {
6905 $rules[$result->level] = $result;
6914 for ($i = 1; $i <= $nbofproducts; $i++) {
6915 $price = $baseprice;
6916 $price_min = $baseprice;
6920 if ($i > 1 && isset($rules[$i]->var_percent) && $rules[$i]->var_percent) {
6921 $price = $prices[$rules[$i]->fk_level] * (1 + ($rules[$i]->var_percent / 100));
6924 $prices[$i] = $price;
6927 if (isset($rules[$i]->var_min_percent) && $rules[$i]->var_min_percent) {
6928 $price_min = $price * (1 - ($rules[$i]->var_min_percent / 100));
6932 $check_amount = (($price == $this->multiprices[$i]) && ($price_min == $this->multiprices_min[$i]));
6933 $check_type = ($baseprice == $this->multiprices_base_type[$i]);
6935 if ($check_amount && $check_type) {
6939 if ($this->
updatePrice($price, $price_type, $user, $price_vat, $price_min, $i, $npr, $psq, 1) < 0) {
6957 return $user->rights->produit;
6959 return $user->rights->service;
6971 $sql =
"SELECT p.rowid, p.ref, p.datec as date_creation, p.tms as date_modification,";
6972 $sql .=
" p.fk_user_author, p.fk_user_modif";
6973 $sql .=
" FROM ".$this->db->prefix().$this->table_element.
" as p";
6974 $sql .=
" WHERE p.rowid = ".((int) $id);
6976 $result = $this->db->query($sql);
6978 if ($this->db->num_rows($result)) {
6979 $obj = $this->db->fetch_object($result);
6981 $this->
id = $obj->rowid;
6982 $this->
ref = $obj->ref;
6984 $this->user_creation_id = $obj->fk_user_author;
6985 $this->user_modification_id = $obj->fk_user_modif;
6987 $this->date_creation = $this->db->jdate($obj->date_creation);
6988 $this->date_modification = $this->db->jdate($obj->date_modification);
6991 $this->db->free($result);
7005 if (empty($this->duration_value)) {
7006 $this->errors[] =
'ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
7009 if ($this->duration_unit ==
's') {
7010 $prodDurationHours = 1. / 3600;
7011 } elseif ($this->duration_unit ==
'i' || $this->duration_unit ==
'mn' || $this->duration_unit ==
'min') {
7012 $prodDurationHours = 1. / 60;
7013 } elseif ($this->duration_unit ==
'h') {
7014 $prodDurationHours = 1.;
7015 } elseif ($this->duration_unit ==
'd') {
7016 $prodDurationHours = 24.;
7017 } elseif ($this->duration_unit ==
'w') {
7018 $prodDurationHours = 24. * 7;
7019 } elseif ($this->duration_unit ==
'm') {
7020 $prodDurationHours = 24. * 30;
7021 } elseif ($this->duration_unit ==
'y') {
7022 $prodDurationHours = 24. * 365;
7024 $prodDurationHours = 0.0;
7026 $prodDurationHours *= $this->duration_value;
7028 return $prodDurationHours;
7041 global $langs,
$conf;
7043 $selected = (empty($arraydata[
'selected']) ? 0 : $arraydata[
'selected']);
7045 $return =
'<div class="box-flex-item box-flex-grow-zero">';
7046 $return .=
'<div class="info-box info-box-sm">';
7047 $return .=
'<div class="info-box-img">';
7050 $label .= $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 120, 160, 0, 0, 0,
'',
'photoref photokanban');
7060 $return .=
'</div>';
7061 $return .=
'<div class="info-box-content">';
7062 $return .=
'<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this,
'getNomUrl') ? $this->
getNomUrl() : $this->ref).
'</span>';
7063 if ($selected >= 0) {
7064 $return .=
'<input id="cb'.$this->id.
'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->
id.
'"'.($selected ?
' checked="checked"' :
'').
'>';
7066 if (property_exists($this,
'label')) {
7067 $return .=
'<br><span class="info-box-label opacitymedium inline-block tdoverflowmax150 valignmiddle" title="'.dol_escape_htmltag($this->label).
'">'.
dol_escape_htmltag($this->label).
'</span>';
7069 if (property_exists($this,
'price') && property_exists($this,
'price_ttc')) {
7070 if ($this->price_base_type ==
'TTC') {
7071 $return .=
'<br><span class="info-box-status amount">'.price($this->price_ttc).
' '.$langs->trans(
"TTC").
'</span>';
7074 $return .=
'<br><span class="info-box-status amount">'.price($this->
price).
' '.$langs->trans(
"HT").
'</span>';
7079 if (property_exists($this,
'stock_reel') && $this->
isProduct()) {
7080 $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>';
7083 if (method_exists($this,
'getLibStatut')) {
7085 $return .=
'<br><div class="info-box-status inline-block valignmiddle">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7087 $return .=
'<div class="info-box-status inline-block valignmiddle marginleftonly paddingleft">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7090 $return .=
'</div>';
7091 $return .=
'</div>';
7092 $return .=
'</div>';
7105 if (!is_numeric($limit)) {
7109 $sql =
"SELECT p.rowid, p.ref, p.label, p.description, p.entity, ef.filename
7110 FROM ".MAIN_DB_PREFIX.
"product AS p
7111 JOIN ".MAIN_DB_PREFIX.
"ecm_files AS ef ON p.rowid = ef.src_object_id
7112 WHERE ef.entity IN (".
getEntity(
'product').
")
7113 AND (ef.filename LIKE '%.png' OR ef.filename LIKE '%.jpeg' OR ef.filename LIKE '%.svg')
7114 GROUP BY p.rowid, p.ref, p.label, p.description, p.entity, ef.filename
7115 ORDER BY p.datec ASC
7116 LIMIT " . ((int) $limit);
7118 $resql = $this->db->query($sql);
7119 $products = array();
7122 while ($obj = $this->db->fetch_object($resql)) {
7123 $products[] = array(
7124 'rowid' => $obj->rowid,
7126 'label' => $obj->label,
7127 'description' => $obj->description,
7128 'entity' => $obj->entity,
7129 'filename' => $obj->filename
7135 if (empty($products)) {
7148 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)
clean_account($account)
Return accounting account without zero on the right.
Parent class of all other business classes (invoices, contracts, proposals, orders,...
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
deleteEcmFiles($mode=0)
Delete related files of object in database.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
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.
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.
getLabelOfUnit($type='long', $outputlangs=null, $noentities=0)
Reads the units dictionary to return the translation code of a unit (if type='code'),...
_get_stats($sql, $mode, $year=0)
Return an array formatted for showing graphs.
load_stats_commande_fournisseur($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null)
Charge tableau des stats commande fournisseur pour le produit/service.
isMandatoryPeriod()
Return if the object has a constraint on mandatory_period.
isProduct()
Return if the object is a product.
generateMultiprices(User $user, $baseprice, $price_type, $price_vat, $npr, $psq)
Generates prices for a product based on product multiprice generation rules.
LibStatut($status, $mode=0, $type=0)
Return label of a given status.
const TYPE_SERVICE
Service.
is_photo_available($sdir)
Return if at least one photo is available.
get_image_size($file)
Load size of image file.
get_nb_vente($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units or customers invoices in which product is included.
getTooltipContentArray($params)
getTooltipContentArray
Class to manage products or services.
Manage record for batch number management.
static findAll($dbs, $fk_product_stock, $with_qty=0, $fk_product=0)
Return all batch detail records for a given product and warehouse.
Class with list of lots and properties.
Class to manage Dolibarr users.
hasRight($module, $permlevel1, $permlevel2='')
Return if a user has a permission.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
dol_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