42require_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
43require_once DOL_DOCUMENT_ROOT.
'/core/class/commonobject.class.php';
44require_once DOL_DOCUMENT_ROOT.
'/product/class/productbatch.class.php';
45require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/productlot.class.php';
46require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/entrepot.class.php';
57 const SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY = 1;
58 const SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY = 2;
59 const SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT = 3;
65 public $TRIGGER_PREFIX =
'PRODUCT';
70 public $element =
'product';
75 public $table_element =
'product';
80 public $fk_element =
'fk_product';
85 protected $childtables = array(
86 'supplier_proposaldet' => array(
'name' =>
'SupplierProposal',
'parent' =>
'supplier_proposal',
'parentkey' =>
'fk_supplier_proposal'),
87 'propaldet' => array(
'name' =>
'Proposal',
'parent' =>
'propal',
'parentkey' =>
'fk_propal'),
88 'commandedet' => array(
'name' =>
'Order',
'parent' =>
'commande',
'parentkey' =>
'fk_commande'),
89 'facturedet' => array(
'name' =>
'Invoice',
'parent' =>
'facture',
'parentkey' =>
'fk_facture'),
90 'contratdet' => array(
'name' =>
'Contract',
'parent' =>
'contrat',
'parentkey' =>
'fk_contrat'),
91 'facture_fourn_det' => array(
'name' =>
'SupplierInvoice',
'parent' =>
'facture_fourn',
'parentkey' =>
'fk_facture_fourn'),
92 'commande_fournisseurdet' => array(
'name' =>
'SupplierOrder',
'parent' =>
'commande_fournisseur',
'parentkey' =>
'fk_commande'),
93 'mrp_production' => array(
'name' =>
'Mo',
'parent' =>
'mrp_mo',
'parentkey' =>
'fk_mo',
'enabled' =>
'isModEnabled("mrp")'),
94 'bom_bom' => array(
'name' =>
'BOM',
'enabled' =>
'isModEnabled("bom")'),
95 'bom_bomline' => array(
'name' =>
'BOMLine',
'parent' =>
'bom_bom',
'parentkey' =>
'fk_bom',
'enabled' =>
'isModEnabled("bom")'),
103 public $picto =
'product';
114 public $regeximgext =
'\.gif|\.jpg|\.jpeg|\.png|\.bmp|\.webp|\.xpm|\.xbm|\.avif';
168 public $price_formated;
180 public $price_ttc_formated;
194 public $price_min_ttc;
200 public $price_base_type;
210 public $multiprices = array();
214 public $multiprices_ttc = array();
218 public $multiprices_base_type = array();
222 public $multiprices_default_vat_code = array();
226 public $multiprices_min = array();
230 public $multiprices_min_ttc = array();
234 public $multiprices_tva_tx = array();
238 public $multiprices_recuperableonly = array();
244 public $price_by_qty;
248 public $prices_by_qty = array();
252 public $prices_by_qty_id = array();
256 public $prices_by_qty_list = array();
266 public $multilangs = array();
271 public $default_vat_code;
286 public $remise_percent;
291 public $localtax1_tx;
295 public $localtax2_tx;
299 public $localtax1_type;
303 public $localtax2_type;
310 public $desc_supplier;
314 public $vatrate_supplier;
318 public $default_vat_code_supplier;
323 public $fourn_multicurrency_price;
328 public $fourn_multicurrency_unitprice;
332 public $fourn_multicurrency_tx;
336 public $fourn_multicurrency_id;
340 public $fourn_multicurrency_code;
362 public $qc_frequency;
369 public $stock_reel = 0;
376 public $stock_theorique;
397 public $seuil_stock_alerte = 0;
402 public $desiredstock = 0;
407 public $duration_value;
411 public $duration_unit;
420 public $fk_default_workstation;
442 public $status_buy = 0;
464 public $fk_default_bom;
471 public $product_fourn_price_id;
493 public $status_batch = 0;
500 public $sell_or_eat_by_mandatory = 0;
507 public $batch_mask =
'';
532 public $weight_units;
540 public $length_units;
556 public $height_units;
564 public $surface_units;
572 public $volume_units;
581 public $net_measure_units;
586 public $accountancy_code_sell;
590 public $accountancy_code_sell_intra;
594 public $accountancy_code_sell_export;
598 public $accountancy_code_buy;
602 public $accountancy_code_buy_intra;
606 public $accountancy_code_buy_export;
616 public $barcode_type;
621 public $barcode_type_code;
626 public $stats_propale = array();
631 public $stats_commande = array();
636 public $stats_contrat = array();
641 public $stats_facture = array();
646 public $stats_proposal_supplier = array();
651 public $stats_commande_fournisseur = array();
656 public $stats_expedition = array();
661 public $stats_reception = array();
666 public $stats_mo = array();
671 public $stats_bom = array();
676 public $stats_mrptoconsume = array();
681 public $stats_mrptoproduce = array();
686 public $stats_facturerec = array();
691 public $stats_facture_fournisseur = array();
696 public $stats_facturefournrec = array();
711 public $product_fourn_id;
717 public $product_id_already_linked;
728 public $stock_warehouse = array();
733 public $fk_default_warehouse;
738 public $fk_price_expression;
756 public $fourn_price_base_type;
773 public $ref_supplier;
787 public $price_autogen = 0;
794 public $sousprods = array();
807 public $is_object_used;
818 public $is_sousproduit_qty;
830 public $is_sousproduit_incdec;
835 public $mandatory_period;
842 public $stockable_product = 1;
872 public $fields = array(
873 'rowid' => array(
'type' =>
'integer',
'label' =>
'TechnicalID',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'index' => 1,
'position' => 1,
'comment' =>
'Id'),
874 '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'),
875 'entity' => array(
'type' =>
'integer',
'label' =>
'Entity',
'enabled' => 1,
'visible' => 0,
'default' =>
'1',
'notnull' => 1,
'index' => 1,
'position' => 5),
876 'label' => array(
'type' =>
'varchar(255)',
'label' =>
'Label',
'enabled' => 1,
'visible' => 1,
'notnull' => 1,
'showoncombobox' => 2,
'position' => 15,
'csslist' =>
'tdoverflowmax250'),
877 'barcode' => array(
'type' =>
'varchar(255)',
'label' =>
'Barcode',
'enabled' =>
'isModEnabled("barcode")',
'position' => 20,
'visible' => -1,
'showoncombobox' => 3,
'cssview' =>
'tdwordbreak',
'csslist' =>
'tdoverflowmax125'),
878 'fk_barcode_type' => array(
'type' =>
'integer',
'label' =>
'BarcodeType',
'enabled' => 1,
'position' => 21,
'notnull' => 0,
'visible' => -1,),
879 'note_public' => array(
'type' =>
'html',
'label' =>
'NotePublic',
'enabled' => 1,
'visible' => 0,
'position' => 61),
880 'note' => array(
'type' =>
'html',
'label' =>
'NotePrivate',
'enabled' => 1,
'visible' => 0,
'position' => 62),
881 'datec' => array(
'type' =>
'datetime',
'label' =>
'DateCreation',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 500),
882 'tms' => array(
'type' =>
'timestamp',
'label' =>
'DateModification',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 501),
884 'fk_user_author' => array(
'type' =>
'integer:User:user/class/user.class.php',
'label' =>
'UserAuthor',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 510,
'foreignkey' =>
'llx_user.rowid'),
885 'fk_user_modif' => array(
'type' =>
'integer:User:user/class/user.class.php',
'label' =>
'UserModif',
'enabled' => 1,
'visible' => -2,
'notnull' => -1,
'position' => 511),
887 'localtax1_tx' => array(
'type' =>
'double(6,3)',
'label' =>
'Localtax1tx',
'enabled' => 1,
'position' => 150,
'notnull' => 0,
'visible' => -1,),
888 'localtax1_type' => array(
'type' =>
'varchar(10)',
'label' =>
'Localtax1type',
'enabled' => 1,
'position' => 155,
'notnull' => 1,
'visible' => -1,),
889 'localtax2_tx' => array(
'type' =>
'double(6,3)',
'label' =>
'Localtax2tx',
'enabled' => 1,
'position' => 160,
'notnull' => 0,
'visible' => -1,),
890 'localtax2_type' => array(
'type' =>
'varchar(10)',
'label' =>
'Localtax2type',
'enabled' => 1,
'position' => 165,
'notnull' => 1,
'visible' => -1,),
891 'last_main_doc' => array(
'type' =>
'varchar(255)',
'label' =>
'LastMainDoc',
'enabled' => 1,
'visible' => -1,
'position' => 170),
892 'import_key' => array(
'type' =>
'varchar(14)',
'label' =>
'ImportId',
'enabled' => 1,
'visible' => -2,
'notnull' => -1,
'index' => 0,
'position' => 1000),
895 'mandatory_period' => array(
'type' =>
'integer',
'label' =>
'mandatoryperiod',
'enabled' => 1,
'visible' => -1,
'notnull' => 1,
'default' =>
'0',
'index' => 1,
'position' => 1000),
896 'stockable_product' => array(
'type' =>
'integer',
'label' =>
'stockable_product',
'enabled' => 1,
'visible' => 1,
'default' =>
'1',
'notnull' => 1,
'index' => 1,
'position' => 502),
912 const ENABLED_STOCK = 1;
923 $this->ismultientitymanaged = 1;
924 $this->isextrafieldmanaged = 1;
937 $this->
ref = trim($this->
ref);
965 public function create($user, $notrigger = 0)
967 global
$conf, $langs;
973 $this->
ref = trim($this->
ref);
977 $this->label = trim($this->label);
978 $this->price_ttc = (float)
price2num($this->price_ttc);
980 $this->price_min_ttc = (float)
price2num($this->price_min_ttc);
981 $this->price_min = (float)
price2num($this->price_min);
982 $this->price_label = trim($this->price_label);
983 if (empty($this->tva_tx)) {
986 if (empty($this->tva_npr)) {
990 if (empty($this->localtax1_tx)) {
991 $this->localtax1_tx = 0;
993 if (empty($this->localtax2_tx)) {
994 $this->localtax2_tx = 0;
996 if (empty($this->localtax1_type)) {
997 $this->localtax1_type =
'0';
999 if (empty($this->localtax2_type)) {
1000 $this->localtax2_type =
'0';
1003 if (empty($this->price_base_type) &&
getDolGlobalString(
'PRODUCT_PRICE_BASE_TYPE')) {
1006 if (empty($this->
price)) {
1009 if (empty($this->price_min)) {
1010 $this->price_min = 0;
1013 if (empty($this->price_by_qty)) {
1014 $this->price_by_qty = 0;
1017 if (empty($this->
status)) {
1020 if (empty($this->status_buy)) {
1021 $this->status_buy = 0;
1023 if (empty($this->stockable_product)) {
1024 $this->stockable_product = 0;
1033 if ($this->price_base_type ==
'TTC' && $this->price_ttc > 0) {
1034 $price_ttc =
price2num($this->price_ttc,
'MU');
1035 $price_ht =
price2num($this->price_ttc / (1 + ($this->tva_tx / 100)),
'MU');
1039 if ($this->price_base_type !=
'TTC' && $this->
price > 0) {
1041 $price_ttc =
price2num($this->
price * (1 + ($this->tva_tx / 100)),
'MU');
1045 if (($this->price_min_ttc > 0) && ($this->price_base_type ==
'TTC')) {
1046 $price_min_ttc =
price2num($this->price_min_ttc,
'MU');
1047 $price_min_ht =
price2num($this->price_min_ttc / (1 + ($this->tva_tx / 100)),
'MU');
1051 if (($this->price_min > 0) && ($this->price_base_type !=
'TTC')) {
1052 $price_min_ht =
price2num($this->price_min,
'MU');
1053 $price_min_ttc =
price2num($this->price_min * (1 + ($this->tva_tx / 100)),
'MU');
1056 $this->accountancy_code_buy = trim((
string) $this->accountancy_code_buy);
1057 $this->accountancy_code_buy_intra = trim((
string) $this->accountancy_code_buy_intra);
1058 $this->accountancy_code_buy_export = trim((
string) $this->accountancy_code_buy_export);
1059 $this->accountancy_code_sell = trim((
string) $this->accountancy_code_sell);
1060 $this->accountancy_code_sell_intra = trim((
string) $this->accountancy_code_sell_intra);
1061 $this->accountancy_code_sell_export = trim((
string) $this->accountancy_code_sell_export);
1067 require_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
1068 $this->accountancy_code_buy =
clean_account($this->accountancy_code_buy);
1069 $this->accountancy_code_buy_intra =
clean_account($this->accountancy_code_buy_intra);
1070 $this->accountancy_code_buy_export =
clean_account($this->accountancy_code_buy_export);
1071 $this->accountancy_code_sell =
clean_account($this->accountancy_code_sell);
1072 $this->accountancy_code_sell_intra =
clean_account($this->accountancy_code_sell_intra);
1073 $this->accountancy_code_sell_export =
clean_account($this->accountancy_code_sell_export);
1077 $this->barcode = trim($this->barcode);
1078 $this->mandatory_period = empty($this->mandatory_period) ? 0 : $this->mandatory_period;
1080 if (empty($this->label)) {
1081 $langs->load(
'errors');
1082 $this->errors[] = $langs->trans(
'ErrorMandatoryParametersNotProvided');
1086 if (empty($this->
ref) || $this->
ref ==
'auto') {
1088 $module =
getDolGlobalString(
'PRODUCT_CODEPRODUCT_ADDON',
'mod_codeproduct_leopard');
1089 if ($module !=
'mod_codeproduct_leopard') {
1090 if (substr($module, 0, 16) ==
'mod_codeproduct_' && substr($module, -3) ==
'php') {
1091 $module = substr($module, 0,
dol_strlen($module) - 4);
1094 $modCodeProduct =
new $module();
1095 '@phan-var-force ModeleProductCode $modCodeProduct';
1096 if (!empty($modCodeProduct->code_auto)) {
1097 $this->
ref = $modCodeProduct->getNextValue($this, $this->
type);
1099 unset($modCodeProduct);
1102 if (empty($this->
ref)) {
1103 $this->error =
'ProductModuleNotSetupForAutoRef';
1108 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);
1112 if (empty($this->date_creation)) {
1113 $this->date_creation = $now;
1119 if ($this->barcode ==
'-1' || $this->barcode ==
'auto') {
1120 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1125 $result = $this->
verify();
1128 $sql =
"SELECT count(*) as nb";
1129 $sql .=
" FROM ".$this->db->prefix().
"product";
1130 $sql .=
" WHERE entity IN (".getEntity(
'product').
")";
1131 $sql .=
" AND ref = '".$this->db->escape($this->
ref).
"'";
1133 $result = $this->db->query($sql);
1135 $obj = $this->db->fetch_object($result);
1136 if ($obj->nb == 0) {
1138 $sql =
"INSERT INTO ".$this->db->prefix().
"product (";
1142 $sql .=
", ref_ext";
1143 $sql .=
", price_min";
1144 $sql .=
", price_min_ttc";
1146 $sql .=
", fk_user_author";
1147 $sql .=
", fk_product_type";
1149 $sql .=
", price_ttc";
1150 $sql .=
", price_base_type";
1151 $sql .=
", price_label";
1155 $sql .=
", accountancy_code_buy";
1156 $sql .=
", accountancy_code_buy_intra";
1157 $sql .=
", accountancy_code_buy_export";
1158 $sql .=
", accountancy_code_sell";
1159 $sql .=
", accountancy_code_sell_intra";
1160 $sql .=
", accountancy_code_sell_export";
1163 $sql .=
", finished";
1164 $sql .=
", tobatch";
1165 $sql .=
", sell_or_eat_by_mandatory";
1166 $sql .=
", batch_mask";
1167 $sql .=
", fk_unit";
1168 $sql .=
", mandatory_period";
1169 $sql .=
", stockable_product";
1170 if (!empty($this->default_vat_code)) {
1171 $sql .=
", default_vat_code";
1173 $sql .=
") VALUES (";
1174 $sql .=
"'".$this->db->idate($this->date_creation).
"'";
1175 $sql .=
", ".(!empty($this->entity) ? (int) $this->entity : (int)
$conf->entity);
1176 $sql .=
", '".$this->db->escape($this->
ref).
"'";
1177 $sql .=
", ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1178 $sql .=
", ".price2num($price_min_ht);
1179 $sql .=
", ".price2num($price_min_ttc);
1180 $sql .=
", ".(!empty($this->label) ?
"'".$this->db->escape($this->label).
"'" :
"null");
1181 $sql .=
", ".((int) $user->id);
1182 $sql .=
", ".((int) $this->
type);
1183 $sql .=
", ".price2num($price_ht,
'MT');
1184 $sql .=
", ".price2num($price_ttc,
'MT');
1185 $sql .=
", '".$this->db->escape($this->price_base_type).
"'";
1186 $sql .=
", ".(!empty($this->price_label) ?
"'".$this->db->escape($this->price_label).
"'" :
"null");
1187 $sql .=
", ".((int) $this->
status);
1188 $sql .=
", ".((int) $this->status_buy);
1190 $sql .=
", '".$this->db->escape($this->accountancy_code_buy).
"'";
1191 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_intra).
"'";
1192 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_export).
"'";
1193 $sql .=
", '".$this->db->escape($this->accountancy_code_sell).
"'";
1194 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_intra).
"'";
1195 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_export).
"'";
1197 $sql .=
", '".$this->db->escape($this->canvas).
"'";
1198 $sql .=
", ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
'NULL' : (int) $this->finished);
1199 $sql .=
", ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : ((int) $this->status_batch));
1200 $sql .=
", ".((empty($this->sell_or_eat_by_mandatory) || $this->sell_or_eat_by_mandatory < 0) ? 0 : ((int) $this->sell_or_eat_by_mandatory));
1201 $sql .=
", '".$this->db->escape($this->batch_mask).
"'";
1202 $sql .=
", ".($this->fk_unit > 0 ? ((int) $this->fk_unit) :
'NULL');
1203 $sql .=
", '".$this->db->escape((
string) $this->mandatory_period).
"'";
1204 $sql .=
", ".((int) $this->stockable_product);
1205 if (!empty($this->default_vat_code)) {
1206 $sql .=
", '".$this->db->escape($this->default_vat_code).
"'";
1209 dol_syslog(get_class($this).
"::Create", LOG_DEBUG);
1211 $result = $this->db->query($sql);
1213 $id = $this->db->last_insert_id($this->db->prefix().
"product");
1217 $this->
price = $price_ht;
1218 $this->price_ttc = $price_ttc;
1219 $this->price_min = $price_min_ht;
1220 $this->price_min_ttc = $price_min_ttc;
1224 if ($this->
update($id, $user, 1,
'add') <= 0) {
1229 $this->error = $this->db->lasterror();
1234 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " .((int) $this->id) .
" AND entity = " . ((
int)
$conf->entity));
1236 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1237 $sql .=
" fk_product";
1239 $sql .=
", accountancy_code_buy";
1240 $sql .=
", accountancy_code_buy_intra";
1241 $sql .=
", accountancy_code_buy_export";
1242 $sql .=
", accountancy_code_sell";
1243 $sql .=
", accountancy_code_sell_intra";
1244 $sql .=
", accountancy_code_sell_export";
1245 $sql .=
") VALUES (";
1246 $sql .= ((int) $this->
id);
1247 $sql .=
", " . ((int)
$conf->entity);
1248 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1249 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1250 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1251 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1252 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1253 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1255 $result = $this->db->query($sql);
1258 $this->error =
'ErrorFailedToInsertAccountancyForEntity';
1263 $this->error =
'ErrorFailedToGetInsertedId';
1267 $this->error = $this->db->lasterror();
1271 $langs->load(
"products");
1273 $this->error =
"ErrorProductAlreadyExists";
1274 dol_syslog(get_class($this).
"::Create fails, ref ".$this->
ref.
" already exists");
1278 $this->error = $this->db->lasterror();
1281 if (!$error && !$notrigger) {
1283 $result = $this->call_trigger(
'PRODUCT_CREATE', $user);
1291 $this->db->commit();
1294 $this->db->rollback();
1298 $this->db->rollback();
1299 dol_syslog(get_class($this).
"::Create fails verify ".implode(
',', $this->errors), LOG_WARNING);
1315 $this->errors = array();
1318 $this->
ref = trim($this->
ref);
1321 $this->errors[] =
'ErrorBadRef';
1325 $arrayofnonnegativevalue = array(
'weight' =>
'Weight',
'width' =>
'Width',
'height' =>
'Height',
'length' =>
'Length',
'surface' =>
'Surface',
'volume' =>
'Volume');
1326 foreach ($arrayofnonnegativevalue as $key => $value) {
1327 if (property_exists($this, $key) && !empty($this->$key) && ($this->$key < 0)) {
1328 $langs->loadLangs(array(
"main",
"other"));
1329 $this->error = $langs->trans(
"FieldCannotBeNegative", $langs->transnoentitiesnoconv($value));
1330 $this->errors[] = $this->error;
1335 $rescode = $this->check_barcode($this->barcode, $this->barcode_type_code);
1337 if ($rescode == -1) {
1338 $this->errors[] =
'ErrorBadBarCodeSyntax';
1339 } elseif ($rescode == -2) {
1340 $this->errors[] =
'ErrorBarCodeRequired';
1341 } elseif ($rescode == -3) {
1343 $this->errors[] =
'ErrorBarCodeAlreadyUsed';
1363 public function check_barcode($valuetotest, $typefortest)
1371 $dirsociete = array_merge(array(
'/core/modules/barcode/'),
$conf->modules_parts[
'barcode']);
1372 foreach ($dirsociete as $dirroot) {
1379 $mod =
new $module();
1380 '@phan-var-force ModeleNumRefBarCode $mod';
1383 dol_syslog(get_class($this).
"::check_barcode value=".$valuetotest.
" type=".$typefortest.
" module=".$module);
1384 $result = $mod->verif($this->db, $valuetotest, $this, 0, $typefortest);
1402 public function update($id, $user, $notrigger = 0, $action =
'update', $updatetype =
false)
1404 global $langs,
$conf, $hookmanager;
1409 if (!$this->label) {
1410 $this->label =
'MISSING LABEL';
1415 $this->
ref = trim($this->
ref);
1419 $this->label = trim($this->label);
1421 $this->note_private = (isset($this->note_private) ? trim($this->note_private) :
null);
1422 $this->note_public = (isset($this->note_public) ? trim($this->note_public) :
null);
1423 $this->net_measure =
price2num($this->net_measure);
1424 $this->net_measure_units = (!is_numeric($this->net_measure_units) ? null : (int) $this->net_measure_units);
1425 $this->weight =
price2num($this->weight);
1426 $this->weight_units = (!is_numeric($this->weight_units) ? null : (int) $this->weight_units);
1427 $this->length =
price2num($this->length);
1428 $this->length_units = (!is_numeric($this->length_units) ? null : (int) $this->length_units);
1430 $this->width_units = (!is_numeric($this->width_units) ? null : (int) $this->width_units);
1431 $this->height =
price2num($this->height);
1432 $this->height_units = (!is_numeric($this->height_units) ? null : (int) $this->height_units);
1433 $this->surface =
price2num($this->surface);
1434 $this->surface_units = (!is_numeric($this->surface_units) ? null : (int) $this->surface_units);
1435 $this->volume =
price2num($this->volume);
1436 $this->volume_units = (!is_numeric($this->volume_units) ? null : (int) $this->volume_units);
1439 if (is_numeric($this->length_units)) {
1440 $this->width_units = $this->length_units;
1442 if (is_numeric($this->length_units)) {
1443 $this->height_units = $this->length_units;
1447 if (empty($this->surface) && !empty($this->length) && !empty($this->width) && $this->length_units == $this->width_units) {
1448 $this->surface = (float) $this->length * (
float) $this->width;
1451 if (empty($this->volume) && !empty($this->surface) && !empty($this->height) && $this->length_units == $this->height_units) {
1452 $this->volume = $this->surface * (float) $this->height;
1456 if (empty($this->tva_tx)) {
1459 if (empty($this->tva_npr)) {
1462 if (empty($this->localtax1_tx)) {
1463 $this->localtax1_tx = 0;
1465 if (empty($this->localtax2_tx)) {
1466 $this->localtax2_tx = 0;
1468 if (empty($this->localtax1_type)) {
1469 $this->localtax1_type =
'0';
1471 if (empty($this->localtax2_type)) {
1472 $this->localtax2_type =
'0';
1474 if (empty($this->
status)) {
1477 if (empty($this->status_buy)) {
1478 $this->status_buy = 0;
1481 if (empty($this->country_id)) {
1482 $this->country_id = 0;
1484 if (empty($this->country_id) && !empty($this->country_code)) {
1485 $country_id =
getCountry($this->country_code,
'3');
1486 $this->country_id = is_int($country_id) ? $country_id : 0;
1489 if (empty($this->state_id)) {
1490 $this->state_id = 0;
1493 if (empty($this->stockable_product)) {
1494 $this->stockable_product = 0;
1498 if ($this->barcode ==
'-1' || $this->barcode ==
'auto') {
1499 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1503 $this->barcode = (empty($this->barcode) ?
'' : trim($this->barcode));
1505 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
1506 $this->accountancy_code_buy_intra = (!empty($this->accountancy_code_buy_intra) ? trim($this->accountancy_code_buy_intra) :
'');
1507 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
1508 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
1509 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
1510 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
1516 require_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
1517 $this->accountancy_code_buy =
clean_account($this->accountancy_code_buy);
1518 $this->accountancy_code_buy_intra =
clean_account($this->accountancy_code_buy_intra);
1519 $this->accountancy_code_buy_export =
clean_account($this->accountancy_code_buy_export);
1520 $this->accountancy_code_sell =
clean_account($this->accountancy_code_sell);
1521 $this->accountancy_code_sell_intra =
clean_account($this->accountancy_code_sell_intra);
1522 $this->accountancy_code_sell_export =
clean_account($this->accountancy_code_sell_export);
1529 if ($action !=
'add') {
1530 $result = $this->
verify();
1542 if (is_null($this->oldcopy) || (is_object($this->oldcopy) && empty($this->oldcopy->id)) || !($this->oldcopy instanceof
Product)) {
1547 if ($this->
hasbatch() && !$this->oldcopy->hasbatch()) {
1549 $valueforundefinedlot =
'000000';
1554 dol_syslog(
"Flag batch of product id=".$this->
id.
" is set to ON, so we will create missing records into product_batch");
1557 foreach ($this->stock_warehouse as $idW => $ObjW) {
1559 foreach ($ObjW->detail_batch as $detail) {
1560 if ($detail->batch == $valueforundefinedlot || $detail->batch ==
'Undefined') {
1562 $sqlclean =
"DELETE FROM ".$this->db->prefix().
"product_batch WHERE batch in('Undefined', '".$this->db->escape($valueforundefinedlot).
"') AND fk_product_stock = ".((int) $ObjW->id);
1563 $result = $this->db->query($sqlclean);
1571 $qty_batch += $detail->qty;
1575 if ($ObjW->real != $qty_batch) {
1577 $ObjBatch->batch = $valueforundefinedlot;
1578 $ObjBatch->qty = ($ObjW->real - $qty_batch);
1579 $ObjBatch->fk_product_stock = (int) $ObjW->id;
1581 if ($ObjBatch->create($user, 1) < 0) {
1583 $this->errors = $ObjBatch->errors;
1588 if ($ObjLot->fetch(0, $this->id, $valueforundefinedlot) == 0) {
1589 $ObjLot->fk_product = $this->id;
1590 $ObjLot->entity = (int) $this->entity;
1591 $ObjLot->fk_user_creat = $user->id;
1592 $ObjLot->batch = $valueforundefinedlot;
1593 if ($ObjLot->create($user, 1) < 0) {
1595 $this->errors = $ObjLot->errors;
1603 $sql =
"UPDATE ".$this->db->prefix().
"product";
1604 $sql .=
" SET label = '".$this->db->escape($this->label).
"'";
1607 $sql .=
", fk_product_type = ".((int) $this->
type);
1610 $sql .=
", ref = '".$this->db->escape($this->
ref).
"'";
1611 $sql .=
", ref_ext = ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1612 $sql .=
", default_vat_code = ".($this->default_vat_code ?
"'".$this->db->escape($this->default_vat_code).
"'" :
"null");
1613 $sql .=
", tva_tx = ".((float) $this->tva_tx);
1614 $sql .=
", recuperableonly = ".((int) $this->tva_npr);
1615 $sql .=
", localtax1_tx = ".((float) $this->localtax1_tx);
1616 $sql .=
", localtax2_tx = ".((float) $this->localtax2_tx);
1617 $sql .=
", localtax1_type = ".($this->localtax1_type !=
'' ?
"'".$this->db->escape($this->localtax1_type).
"'" :
"'0'");
1618 $sql .=
", localtax2_type = ".($this->localtax2_type !=
'' ?
"'".$this->db->escape($this->localtax2_type).
"'" :
"'0'");
1620 $sql .=
", barcode = ".(empty($this->barcode) ?
"null" :
"'".$this->db->escape($this->barcode).
"'");
1621 $sql .=
", fk_barcode_type = ".(empty($this->barcode_type) ?
"null" : $this->db->escape((
string) $this->barcode_type));
1623 $sql .=
", tosell = ".(int) $this->
status;
1624 $sql .=
", tobuy = ".(int) $this->status_buy;
1625 $sql .=
", tobatch = ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : (int) $this->status_batch);
1626 $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);
1627 $sql .=
", batch_mask = '".$this->db->escape($this->batch_mask).
"'";
1629 $sql .=
", finished = ".((!isset($this->finished) || $this->finished < 0 || $this->finished ===
'') ?
"null" : (int) $this->finished);
1630 $sql .=
", fk_default_bom = ".((!isset($this->fk_default_bom) || $this->fk_default_bom < 0 || $this->fk_default_bom ==
'') ?
"null" : (int) $this->fk_default_bom);
1631 $sql .=
", net_measure = ".($this->net_measure !=
'' ?
"'".$this->db->escape($this->net_measure).
"'" :
'null');
1632 $sql .=
", net_measure_units = ".((string) $this->net_measure_units !=
'' ? ((
int) $this->net_measure_units) :
'null');
1633 $sql .=
", weight = ".($this->weight !=
'' ?
"'".$this->db->escape($this->weight).
"'" :
'null');
1634 $sql .=
", weight_units = ".((string) $this->weight_units !=
'' ? ((
int) $this->weight_units) :
'null');
1635 $sql .=
", length = ".($this->length !=
'' ?
"'".$this->db->escape($this->length).
"'" :
'null');
1636 $sql .=
", length_units = ".((string) $this->length_units !=
'' ? ((
int) $this->length_units) :
'null');
1637 $sql .=
", width= ".($this->width !=
'' ?
"'".$this->db->escape($this->width).
"'" :
'null');
1638 $sql .=
", width_units = ".((string) $this->width_units !=
'' ? ((
int) $this->width_units) :
'null');
1639 $sql .=
", height = ".($this->height !=
'' ?
"'".$this->db->escape($this->height).
"'" :
'null');
1640 $sql .=
", height_units = ".((string) $this->height_units !=
'' ? ((
int) $this->height_units) :
'null');
1641 $sql .=
", surface = ".($this->surface !=
'' ?
"'".$this->db->escape($this->surface).
"'" :
'null');
1642 $sql .=
", surface_units = ".((string) $this->surface_units !=
'' ? ((
int) $this->surface_units) :
'null');
1643 $sql .=
", volume = ".($this->volume !=
'' ?
"'".$this->db->escape($this->volume).
"'" :
'null');
1644 $sql .=
", volume_units = ".((string) $this->volume_units !=
'' ? ((
int) $this->volume_units) :
'null');
1645 $sql .=
", fk_default_warehouse = ".($this->fk_default_warehouse > 0 ? ((int) $this->fk_default_warehouse) :
'null');
1646 $sql .=
", fk_default_workstation = ".($this->fk_default_workstation > 0 ? ((int) $this->fk_default_workstation) :
'null');
1647 $sql .=
", seuil_stock_alerte = ".((isset($this->seuil_stock_alerte) && is_numeric($this->seuil_stock_alerte)) ? (
float) $this->seuil_stock_alerte :
'null');
1648 $sql .=
", description = '".$this->db->escape($this->
description).
"'";
1649 $sql .=
", url = ".($this->url ?
"'".$this->db->escape($this->url).
"'" :
'null');
1650 $sql .=
", customcode = '".$this->db->escape($this->customcode).
"'";
1651 $sql .=
", fk_country = ".($this->country_id > 0 ? (int) $this->country_id :
'null');
1652 $sql .=
", fk_state = ".($this->state_id > 0 ? (int) $this->state_id :
'null');
1653 $sql .=
", lifetime = ".($this->lifetime > 0 ? (int) $this->lifetime :
'null');
1654 $sql .=
", qc_frequency = ".($this->qc_frequency > 0 ? (int) $this->qc_frequency :
'null');
1655 $sql .=
", note = ".(isset($this->note_private) ?
"'".$this->db->escape($this->note_private).
"'" :
'null');
1656 $sql .=
", note_public = ".(isset($this->note_public) ?
"'".$this->db->escape($this->note_public).
"'" :
'null');
1657 $sql .=
", duration = '".$this->db->escape($this->duration_value.$this->duration_unit).
"'";
1659 $sql .=
", accountancy_code_buy = '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1660 $sql .=
", accountancy_code_buy_intra = '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1661 $sql .=
", accountancy_code_buy_export = '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1662 $sql .=
", accountancy_code_sell= '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1663 $sql .=
", accountancy_code_sell_intra= '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1664 $sql .=
", accountancy_code_sell_export= '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1666 $sql .=
", desiredstock = ".((isset($this->desiredstock) && is_numeric($this->desiredstock)) ? (
float) $this->desiredstock :
"null");
1667 $sql .=
", cost_price = ".($this->cost_price !=
'' ? ((float) $this->cost_price) :
'null');
1668 $sql .=
", fk_unit= ".(!$this->fk_unit ?
'NULL' : (int) $this->fk_unit);
1669 $sql .=
", price_autogen = ".(!$this->price_autogen ? 0 : 1);
1670 $sql .=
", fk_price_expression = ".($this->fk_price_expression != 0 ? (int) $this->fk_price_expression :
'NULL');
1671 $sql .=
", fk_user_modif = ".($user->id > 0 ? (int) $user->id :
'NULL');
1672 $sql .=
", mandatory_period = ".((int) $this->mandatory_period);
1673 $sql .=
", stockable_product = ".(int) $this->stockable_product;
1675 $sql .=
", packaging = ".(float) $this->packaging;
1679 $sql .=
" WHERE rowid = ".((int) $id);
1681 dol_syslog(get_class($this).
"::update", LOG_DEBUG);
1683 $resql = $this->db->query($sql);
1690 $this->db->rollback();
1699 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " . ((
int) $this->id) .
" AND entity = " . ((
int)
$conf->entity));
1701 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1702 $sql .=
" fk_product";
1704 $sql .=
", accountancy_code_buy";
1705 $sql .=
", accountancy_code_buy_intra";
1706 $sql .=
", accountancy_code_buy_export";
1707 $sql .=
", accountancy_code_sell";
1708 $sql .=
", accountancy_code_sell_intra";
1709 $sql .=
", accountancy_code_sell_export";
1710 $sql .=
") VALUES (";
1711 $sql .= ((int) $this->
id);
1712 $sql .=
", " . ((int)
$conf->entity);
1713 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1714 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1715 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1716 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1717 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1718 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1720 $result = $this->db->query($sql);
1723 $this->error =
'ErrorFailedToUpdateAccountancyForEntity';
1727 if (!$this->
hasbatch() && $this->oldcopy->hasbatch()) {
1729 $sql =
'SELECT pb.qty, ps.fk_entrepot, pb.batch FROM '.MAIN_DB_PREFIX.
'product_batch as pb';
1730 $sql .=
' INNER JOIN '.MAIN_DB_PREFIX.
'product_stock as ps ON (ps.rowid = pb.fk_product_stock)';
1731 $sql .=
' WHERE ps.fk_product = '.(int) $this->
id;
1733 $resql = $this->db->query($sql);
1737 while ($obj = $this->db->fetch_object($resql)) {
1739 $fk_entrepot = $obj->fk_entrepot;
1743 $batch = $obj->batch;
1746 $addOremove = $value > 0 ? 1 : 0;
1747 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1748 $res = $this->
correct_stock_batch($user, $fk_entrepot, abs($value), $addOremove, $label, $price, $dlc, $dluo, $batch, $inventorycode,
'',
null, 0,
null,
true);
1751 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1752 $res = $this->
correct_stock($user, $fk_entrepot, abs($value), (
int) empty($addOremove), $label, $price, $inventorycode,
'',
null, 0);
1771 if (!$error && !$notrigger) {
1773 $result = $this->call_trigger(
'PRODUCT_MODIFY', $user);
1780 if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) {
1782 if (
$conf->product->dir_output) {
1785 if (file_exists($olddir)) {
1789 $res = @rename($olddir, $newdir);
1791 $langs->load(
"errors");
1792 $this->error = $langs->trans(
'ErrorFailToRenameDir', $olddir, $newdir);
1796 require_once DOL_DOCUMENT_ROOT .
'/ecm/class/ecmfiles.class.php';
1797 $ecmfiles =
new EcmFiles($this->db);
1798 $ecmfiles->updateAfterRename(
"produit/".
dol_sanitizeFileName($this->oldcopy->ref),
"produit/".dol_sanitizeFileName($this->ref));
1806 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1810 foreach ($comb->fetchAllByFkProductParent($this->id) as $currcomb) {
1811 $currcomb->updateProperties($this, $user);
1815 $this->db->commit();
1818 $this->db->rollback();
1822 if ($this->db->errno() ==
'DB_ERROR_RECORD_ALREADY_EXISTS') {
1823 $langs->load(
"errors");
1824 if (empty(
$conf->barcode->enabled) || empty($this->barcode)) {
1825 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductAlreadyExists", $this->
ref);
1827 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductBarCodeAlreadyExists", $this->barcode);
1829 $this->errors[] = $this->error;
1830 $this->db->rollback();
1833 $this->error = $langs->trans(
"Error").
" : ".$this->db->error().
" - ".$sql;
1834 $this->errors[] = $this->error;
1835 $this->db->rollback();
1840 $this->db->rollback();
1841 dol_syslog(get_class($this).
"::Update fails verify ".implode(
',', $this->errors), LOG_WARNING);
1853 public function delete(
User $user, $notrigger = 0)
1856 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
1861 if (empty($this->
id)) {
1862 $this->error =
"Object must be fetched before calling delete";
1865 if (($this->
isProduct() && !$user->
hasRight(
'produit',
'supprimer')) || ($this->isService() && !$user->hasRight(
'service',
'supprimer'))) {
1866 $this->error =
"ErrorForbidden";
1871 if (empty($objectisused)) {
1874 if (empty($notrigger)) {
1876 $result = $this->call_trigger(
'PRODUCT_DELETE', $user);
1885 $sql =
"DELETE FROM ".$this->db->prefix().
'product_batch';
1886 $sql .=
" WHERE fk_product_stock IN (";
1887 $sql .=
"SELECT rowid FROM ".$this->db->prefix().
'product_stock';
1888 $sql .=
" WHERE fk_product = ".((int) $this->
id).
")";
1890 $result = $this->db->query($sql);
1893 $this->errors[] = $this->db->lasterror();
1899 $sql =
"DELETE FROM " . $this->db->prefix() .
"product_fournisseur_price_log";
1900 $sql .=
" WHERE fk_product_fournisseur IN (";
1901 $sql .=
" SELECT rowid FROM " . $this->db->prefix() .
"product_fournisseur_price";
1902 $sql .=
" WHERE fk_product = " . ((int) $this->
id);
1905 $resql = $this->db->query($sql);
1908 $this->errors[] = $this->db->lasterror();
1914 $elements = array(
'product_fournisseur_price',
'product_price',
'product_lang',
'categorie_product',
'product_stock',
'product_customer_price',
'product_lot');
1915 foreach ($elements as $table) {
1917 $sql =
"DELETE FROM ".$this->db->prefix().$table;
1918 $sql .=
" WHERE fk_product = ".(int) $this->
id;
1920 $result = $this->db->query($sql);
1923 $this->errors[] = $this->db->lasterror();
1930 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1931 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination2ValuePair.class.php';
1936 if ($prodcomb->deleteByFkProductParent($user, $this->id) < 0) {
1938 $this->errors[] =
'Error deleting combinations';
1942 if (!$error && ($prodcomb->fetchByFkProductChild($this->id) > 0) && ($prodcomb->delete($user) < 0)) {
1944 $this->errors[] =
'Error deleting child combination';
1950 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
1951 $sql .=
" WHERE fk_product_pere = ".(int) $this->
id.
" OR fk_product_fils = ".(
int) $this->id;
1953 $result = $this->db->query($sql);
1956 $this->errors[] = $this->db->lasterror();
1965 dol_syslog(get_class($this).
"::delete error -4 ".$this->error, LOG_ERR);
1971 $sqlz =
"DELETE FROM ".$this->db->prefix().
"product";
1972 $sqlz .=
" WHERE rowid = ".(int) $this->
id;
1974 $resultz = $this->db->query($sqlz);
1977 $this->errors[] = $this->db->lasterror();
1993 if ($conf->product->dir_output) {
1994 $dir =
$conf->product->dir_output.
"/".$ref;
1995 if (file_exists($dir)) {
1998 $this->errors[] =
'ErrorFailToDeleteDir';
2006 $this->db->commit();
2009 foreach ($this->errors as $errmsg) {
2010 dol_syslog(get_class($this).
"::delete ".$errmsg, LOG_ERR);
2011 $this->error .= ($this->error ?
', '.$errmsg : $errmsg);
2013 $this->db->rollback();
2017 $this->error =
"ErrorRecordIsUsedCantDelete";
2031 $sellByLabel = $langs->trans(
'SellByDate');
2032 $eatByLabel = $langs->trans(
'EatByDate');
2034 self::SELL_OR_EAT_BY_MANDATORY_ID_NONE => $langs->trans(
'BatchSellOrEatByMandatoryNone'),
2035 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY => $sellByLabel,
2036 self::SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY => $eatByLabel,
2037 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT => $langs->trans(
'BatchSellOrEatByMandatoryAll', $sellByLabel, $eatByLabel),
2048 $sellOrEatByMandatoryLabel =
'';
2051 if (isset($sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory])) {
2052 $sellOrEatByMandatoryLabel = $sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory];
2055 return $sellOrEatByMandatoryLabel;
2069 $langs_available = $langs->get_available_languages(DOL_DOCUMENT_ROOT, 0, 2);
2070 $current_lang = $langs->getDefaultLang();
2072 foreach ($langs_available as $key => $value) {
2073 if ($key == $current_lang) {
2074 $sql =
"SELECT rowid";
2075 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2076 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2077 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
2079 $result = $this->db->query($sql);
2081 if ($this->db->num_rows($result)) {
2082 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
2084 $sql2 .=
" label='".$this->db->escape($this->label).
"',";
2085 $sql2 .=
" description='".$this->db->escape($this->
description).
"'";
2087 $sql2 .=
", note='".$this->db->escape($this->other).
"'";
2089 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
2091 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
2096 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->label).
"',";
2097 $sql2 .=
" '".$this->db->escape($this->
description).
"'";
2099 $sql2 .=
", '".$this->db->escape($this->other).
"'";
2103 dol_syslog(get_class($this).
'::setMultiLangs key = current_lang = '.$key);
2104 if (!$this->db->query($sql2)) {
2105 $this->error = $this->db->lasterror();
2108 } elseif (isset($this->multilangs[$key])) {
2109 if (empty($this->multilangs[$key][
"label"])) {
2110 $this->errors[] = $key .
' : ' . $langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Label"));
2114 $sql =
"SELECT rowid";
2115 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2116 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2117 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
2119 $result = $this->db->query($sql);
2121 if ($this->db->num_rows($result)) {
2122 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
2124 $sql2 .=
" label = '".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
2125 $sql2 .=
" description = '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
2128 $sql2 .=
", note = '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
2130 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
2132 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
2137 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
2138 $sql2 .=
" '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
2141 $sql2 .=
", '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
2147 if ($this->multilangs[
"$key"][
"label"] || $this->multilangs[
"$key"][
"description"]) {
2148 if (!$this->db->query($sql2)) {
2149 $this->error = $this->db->lasterror();
2158 if (empty($notrigger)) {
2160 $result = $this->call_trigger(
'PRODUCT_SET_MULTILANGS', $user);
2162 $this->error = $this->db->lasterror();
2182 $sql =
"DELETE FROM ".$this->db->prefix().
"product_lang";
2183 $sql .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($langtodelete).
"'";
2185 dol_syslog(get_class($this).
'::delMultiLangs', LOG_DEBUG);
2186 $result = $this->db->query($sql);
2188 if (empty($notrigger)) {
2190 $result = $this->call_trigger(
'PRODUCT_DEL_MULTILANGS', $user);
2192 $this->error = $this->db->lasterror();
2193 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
2198 unset($this->multilangs[$langtodelete]);
2201 $this->error = $this->db->lasterror();
2202 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
2223 if ($type ==
'buy') {
2224 $field =
'accountancy_code_buy';
2225 } elseif ($type ==
'buy_intra') {
2226 $field =
'accountancy_code_buy_intra';
2227 } elseif ($type ==
'buy_export') {
2228 $field =
'accountancy_code_buy_export';
2229 } elseif ($type ==
'sell') {
2230 $field =
'accountancy_code_sell';
2231 } elseif ($type ==
'sell_intra') {
2232 $field =
'accountancy_code_sell_intra';
2233 } elseif ($type ==
'sell_export') {
2234 $field =
'accountancy_code_sell_export';
2239 $sql =
"UPDATE ".$this->db->prefix().$this->table_element.
" SET ";
2240 $sql .=
"$field = '".$this->db->escape($value).
"'";
2241 $sql .=
" WHERE rowid = ".((int) $this->
id);
2244 $resql = $this->db->query($sql);
2248 $result = $this->call_trigger(
'PRODUCT_MODIFY', $user);
2255 $this->db->rollback();
2259 $this->$field = $value;
2261 $this->db->commit();
2264 $this->error = $this->db->lasterror();
2265 $this->db->rollback();
2279 $current_lang = $langs->getDefaultLang();
2281 $sql =
"SELECT lang, label, description, note as other";
2282 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2283 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2285 $result = $this->db->query($sql);
2287 while ($obj = $this->db->fetch_object($result)) {
2289 if ($obj->lang == $current_lang) {
2290 $this->label = $obj->label;
2292 $this->other = $obj->other;
2294 $this->multilangs[(
string) $obj->lang][
"label"] = $obj->label;
2295 $this->multilangs[(
string) $obj->lang][
"description"] = $obj->description;
2296 $this->multilangs[(
string) $obj->lang][
"other"] = $obj->other;
2300 $this->error =
"Error: ".$this->db->lasterror().
" - ".$sql;
2313 $testExit = array(
'multiprices',
'multiprices_ttc',
'multiprices_base_type',
'multiprices_min',
'multiprices_min_ttc',
'multiprices_tva_tx',
'multiprices_recuperableonly');
2315 foreach ($testExit as $field) {
2316 if (!isset($this->$field)) {
2319 $tmparray = $this->$field;
2320 if (!isset($tmparray[$level])) {
2326 'level' => $level ? $level : 1,
2327 'multiprices' => (float) $this->multiprices[$level],
2328 'multiprices_ttc' => (
float) $this->multiprices_ttc[$level],
2329 'multiprices_base_type' => $this->multiprices_base_type[$level],
2330 'multiprices_min' => (float) $this->multiprices_min[$level],
2331 'multiprices_min_ttc' => (
float) $this->multiprices_min_ttc[$level],
2332 'multiprices_tva_tx' => (float) $this->multiprices_tva_tx[$level],
2333 'multiprices_recuperableonly' => (
float) $this->multiprices_recuperableonly[$level],
2356 if (empty($this->price_by_qty)) {
2357 $this->price_by_qty = 0;
2361 $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,";
2362 $sql .=
" localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, price_min,price_min_ttc,price_by_qty,entity,fk_price_expression) ";
2363 $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).
",";
2364 $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');
2367 dol_syslog(get_class($this).
"::_log_price", LOG_DEBUG);
2368 $resql = $this->db->query($sql);
2370 $this->error = $this->db->lasterror();
2390 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price_by_qty";
2391 $sql .=
" WHERE fk_product_price = ".((int) $rowid);
2392 $sql .=
" AND fk_product_price IN (SELECT pp.rowid FROM ".$this->db->prefix().
"product_price as pp WHERE pp.fk_product = ".((int) $this->
id).
")";
2393 $resql = $this->db->query($sql);
2395 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price_extrafields";
2396 $sql .=
" WHERE fk_object = ".((int) $rowid);
2397 $resql = $this->db->query($sql);
2399 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price";
2400 $sql .=
" WHERE rowid = ".((int) $rowid);
2401 $sql .=
" AND fk_product = ".((int) $this->
id);
2402 $resql = $this->db->query($sql);
2406 $this->error = $this->db->lasterror();
2426 $sql .=
" pl.rowid as log_rowid,";
2427 $sql .=
" pl.datec,";
2428 $sql .=
" pl.price,";
2429 $sql .=
" pl.quantity,";
2430 $sql .=
" pl.fk_user,";
2431 $sql .=
" pl.multicurrency_code,";
2432 $sql .=
" pl.multicurrency_price,";
2434 $sql .=
" pp.fk_soc as supplier_id,";
2435 $sql .=
" pp.ref_fourn as supplier_ref,";
2436 $sql .=
" pp.entity as entity";
2438 $sql .=
" FROM " . $this->db->prefix() .
"product_fournisseur_price_log as pl";
2439 $sql .=
" INNER JOIN " . $this->db->prefix() .
"product_fournisseur_price as pp ON pl.fk_product_fournisseur = pp.rowid";
2441 $sql .=
" WHERE pp.fk_product = " . ((int) $id);
2442 $sql .=
" AND pp.entity IN (" .
getEntity(
'product') .
")";
2443 $sql .=
" ORDER BY pl.datec DESC";
2445 $resql = $this->db->query($sql);
2447 while ($obj = $this->db->fetch_object($resql)) {
2448 if (is_string($obj->datec)) {
2449 $obj->datec = strtotime($obj->datec);
2453 $this->db->free($resql);
2455 $this->error = $this->db->lasterror();
2470 public function getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp = 0)
2472 global $hookmanager, $action;
2475 if (is_object($hookmanager)) {
2476 $parameters = array(
'thirdparty_seller' => $thirdparty_seller,
'thirdparty_buyer' => $thirdparty_buyer,
'pqp' => $pqp);
2478 $reshook = $hookmanager->executeHooks(
'getSellPrice', $parameters, $this, $action);
2480 return $hookmanager->resArray;
2485 $tva_tx =
get_default_tva($thirdparty_seller, $thirdparty_buyer, $this->
id);
2486 $tva_npr =
get_default_npr($thirdparty_seller, $thirdparty_buyer, $this->
id);
2487 if (empty($tva_tx)) {
2491 $pu_ht = $this->price;
2492 $pu_ttc = $this->price_ttc;
2493 $price_min = $this->price_min;
2494 $price_min_ttc = $this->price_min_ttc;
2495 $price_base_type = (empty($this->price_base_type) ?
'HT' : $this->price_base_type);
2499 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2503 $filter = array(
't.fk_product' => (
string) $this->
id,
't.fk_soc' => (
string) $thirdparty_buyer->id);
2506 $pricebycustomerexist =
false;
2507 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2509 if (count($prodcustprice->lines) > 0) {
2510 $date_now = (int) floor(
dol_now() / 86400) * 86400;
2511 foreach ($prodcustprice->lines as $k => $custprice_line) {
2512 if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
2513 $pricebycustomerexist =
true;
2514 $pu_ht =
price($custprice_line->price);
2515 $price_min =
price($custprice_line->price_min);
2516 $price_min_ttc =
price($custprice_line->price_min_ttc);
2517 $pu_ttc =
price($custprice_line->price_ttc);
2518 $price_base_type = $custprice_line->price_base_type;
2519 $tva_tx = $custprice_line->tva_tx;
2520 if ($custprice_line->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2521 $tva_tx .=
' (' . $custprice_line->default_vat_code .
')';
2523 $tva_npr = $custprice_line->recuperableonly;
2524 if (empty($tva_tx)) {
2533 if (!$pricebycustomerexist && !empty($thirdparty_buyer->price_level)) {
2534 $pu_ht = isset($this->multiprices[$thirdparty_buyer->price_level]) ? $this->multiprices[$thirdparty_buyer->price_level] : 0;
2535 $pu_ttc = isset($this->multiprices_ttc[$thirdparty_buyer->price_level]) ? $this->multiprices_ttc[$thirdparty_buyer->price_level] : 0;
2536 $price_min = isset($this->multiprices_min[$thirdparty_buyer->price_level]) ? $this->multiprices_min[$thirdparty_buyer->price_level] : 0;
2537 $price_min_ttc = isset($this->multiprices_min_ttc[$thirdparty_buyer->price_level]) ? $this->multiprices_min_ttc[$thirdparty_buyer->price_level] : 0;
2538 $price_base_type = isset($this->multiprices_base_type[$thirdparty_buyer->price_level]) ? $this->multiprices_base_type[$thirdparty_buyer->price_level] :
'HT';
2541 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2542 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2544 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2545 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2547 if (empty($tva_tx)) {
2552 } elseif (
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !empty($thirdparty_buyer->price_level)) {
2553 $pu_ht = isset($this->multiprices[$thirdparty_buyer->price_level]) ? $this->multiprices[$thirdparty_buyer->price_level] : 0;
2554 $pu_ttc = isset($this->multiprices_ttc[$thirdparty_buyer->price_level]) ? $this->multiprices_ttc[$thirdparty_buyer->price_level] : 0;
2555 $price_min = isset($this->multiprices_min[$thirdparty_buyer->price_level]) ? $this->multiprices_min[$thirdparty_buyer->price_level] : 0;
2556 $price_min_ttc = isset($this->multiprices_min_ttc[$thirdparty_buyer->price_level]) ? $this->multiprices_min_ttc[$thirdparty_buyer->price_level] : 0;
2557 $price_base_type = isset($this->multiprices_base_type[$thirdparty_buyer->price_level]) ? $this->multiprices_base_type[$thirdparty_buyer->price_level] :
'HT';
2560 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2561 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2563 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2564 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2566 if (empty($tva_tx)) {
2572 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2576 $filter = array(
't.fk_product' => (
string) $this->
id,
't.fk_soc' => (
string) $thirdparty_buyer->id);
2578 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2580 if (count($prodcustprice->lines) > 0) {
2581 $date_now = (int) floor(
dol_now() / 86400) * 86400;
2582 foreach ($prodcustprice->lines as $k => $custprice_line) {
2583 if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
2584 $pu_ht =
price($custprice_line->price);
2585 $price_min =
price($custprice_line->price_min);
2586 $price_min_ttc =
price($custprice_line->price_min_ttc);
2587 $pu_ttc =
price($custprice_line->price_ttc);
2588 $price_base_type = $custprice_line->price_base_type;
2589 $tva_tx = $custprice_line->tva_tx;
2590 if ($custprice_line->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2591 $tva_tx .=
' (' . $custprice_line->default_vat_code .
')';
2593 $tva_npr = $custprice_line->recuperableonly;
2594 if (empty($tva_tx)) {
2604 if (!empty($this->prices_by_qty[0])) {
2607 foreach ($this->prices_by_qty_list[0] as $priceforthequantityarray) {
2608 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2612 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2613 $pu_ht = $priceforthequantityarray[
'unitprice'];
2615 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2622 if (!empty($thirdparty_buyer->price_level)) {
2624 $pu_ht = isset($this->multiprices[$thirdparty_buyer->price_level]) ? $this->multiprices[$thirdparty_buyer->price_level] : 0;
2625 $pu_ttc = isset($this->multiprices_ttc[$thirdparty_buyer->price_level]) ? $this->multiprices_ttc[$thirdparty_buyer->price_level] : 0;
2626 $price_min = isset($this->multiprices_min[$thirdparty_buyer->price_level]) ? $this->multiprices_min[$thirdparty_buyer->price_level] : 0;
2627 $price_min_ttc = isset($this->multiprices_min_ttc[$thirdparty_buyer->price_level]) ? $this->multiprices_min_ttc[$thirdparty_buyer->price_level] : 0;
2628 $price_base_type = empty($this->multiprices_base_type[$thirdparty_buyer->price_level]) ?
'HT' : $this->multiprices_base_type[$thirdparty_buyer->price_level];
2631 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2632 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2634 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2635 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2637 if (empty($tva_tx)) {
2642 if (!empty($thirdparty_buyer->price_level) && !empty($this->prices_by_qty[$thirdparty_buyer->price_level])) {
2645 foreach ($this->prices_by_qty_list[$thirdparty_buyer->price_level] as $priceforthequantityarray) {
2646 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2650 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2651 $pu_ht = $priceforthequantityarray[
'unitprice'];
2653 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2660 $localtax1 =
get_localtax((
string) $tva_tx, 1, $thirdparty_buyer, $thirdparty_seller, $tva_npr);
2661 $localtax2 =
get_localtax((
string) $tva_tx, 2, $thirdparty_buyer, $thirdparty_seller, $tva_npr);
2663 return array(
'pu_ht' => $pu_ht,
'pu_ttc' => $pu_ttc,
'price_min' => $price_min,
'price_min_ttc' => $price_min_ttc,
'price_base_type' => $price_base_type,
'tva_tx' => $tva_tx,
'tva_npr' => $tva_npr,
'localtax1' => $localtax1,
'localtax2' => $localtax2);
2680 public function get_buyprice($prodfournprice, $qty, $product_id = 0, $fourn_ref =
'', $fk_soc = 0)
2683 global $action, $hookmanager;
2686 if (is_object($hookmanager)) {
2687 $parameters = array(
2688 'prodfournprice' => $prodfournprice,
2690 'product_id' => $product_id,
2691 'fourn_ref' => $fourn_ref,
2692 'fk_soc' => $fk_soc,
2695 $reshook = $hookmanager->executeHooks(
'getBuyPrice', $parameters, $this, $action);
2697 return $hookmanager->resArray;
2704 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2705 $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,";
2706 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2707 $sql .=
" pfp.packaging";
2708 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2709 $sql .=
" WHERE pfp.rowid = ".((int) $prodfournprice);
2711 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2713 $sql .=
" ORDER BY pfp.quantity DESC";
2715 dol_syslog(get_class($this).
"::get_buyprice first search by prodfournprice/qty", LOG_DEBUG);
2716 $resql = $this->db->query($sql);
2718 $obj = $this->db->fetch_object($resql);
2719 if ($obj && $obj->quantity > 0) {
2720 if (
isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2722 $prod_supplier->product_fourn_price_id = $obj->rowid;
2723 $prod_supplier->id = $obj->fk_product;
2724 $prod_supplier->fourn_qty = $obj->quantity;
2725 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2726 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2728 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2730 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2731 if ($price_result >= 0) {
2732 $obj->price = $price_result;
2735 $this->product_fourn_price_id = $obj->rowid;
2736 $this->buyprice = $obj->price;
2737 $this->fourn_pu = $obj->price / $obj->quantity;
2738 $this->fourn_price_base_type =
'HT';
2739 $this->fourn_socid = $obj->fk_soc;
2740 $this->ref_fourn = $obj->ref_supplier;
2741 $this->ref_supplier = $obj->ref_supplier;
2742 $this->desc_supplier = $obj->desc_supplier;
2743 $this->remise_percent = $obj->remise_percent;
2744 $this->vatrate_supplier = $obj->tva_tx;
2745 $this->default_vat_code_supplier = $obj->default_vat_code;
2746 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2747 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2748 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2749 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2750 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2752 $this->packaging = (float) $obj->packaging;
2758 $this->fourn_qty = $obj->quantity;
2759 $result = $obj->fk_product;
2763 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2764 $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,";
2765 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2766 $sql .=
" pfp.packaging";
2767 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2768 $sql .=
" WHERE 1 = 1";
2769 if ($product_id > 0) {
2770 $sql .=
" AND pfp.fk_product = ".((int) $product_id);
2772 if ($fourn_ref !=
'none') {
2773 $sql .=
" AND pfp.ref_fourn = '".$this->db->escape($fourn_ref).
"'";
2776 $sql .=
" AND pfp.fk_soc = ".((int) $fk_soc);
2779 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2781 $sql .=
" ORDER BY pfp.quantity DESC";
2784 dol_syslog(get_class($this).
"::get_buyprice second search from qty/ref/product_id", LOG_DEBUG);
2785 $resql = $this->db->query($sql);
2787 $obj = $this->db->fetch_object($resql);
2788 if ($obj && $obj->quantity > 0) {
2789 if (
isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2791 $prod_supplier->product_fourn_price_id = $obj->rowid;
2792 $prod_supplier->id = $obj->fk_product;
2793 $prod_supplier->fourn_qty = $obj->quantity;
2794 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2795 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2797 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2799 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2800 if ($price_result >= 0) {
2801 $obj->price = $price_result;
2804 $this->product_fourn_price_id = $obj->rowid;
2805 $this->buyprice = $obj->price;
2806 $this->fourn_qty = $obj->quantity;
2807 $this->fourn_pu = $obj->price / $obj->quantity;
2808 $this->fourn_price_base_type =
'HT';
2809 $this->fourn_socid = $obj->fk_soc;
2810 $this->ref_fourn = $obj->ref_supplier;
2811 $this->ref_supplier = $obj->ref_supplier;
2812 $this->desc_supplier = $obj->desc_supplier;
2813 $this->remise_percent = $obj->remise_percent;
2814 $this->vatrate_supplier = $obj->tva_tx;
2815 $this->default_vat_code_supplier = $obj->default_vat_code;
2816 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2817 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2818 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2819 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2820 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2822 $this->packaging = (float) $obj->packaging;
2826 $this->fourn_qty = $obj->quantity;
2827 $result = $obj->fk_product;
2833 $this->error = $this->db->lasterror();
2838 $this->error = $this->db->lasterror();
2862 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)
2868 dol_syslog(get_class($this).
"::update_price id=".$id.
" newprice=".$newprice.
" newpricebase=".$newpricebase.
" newminprice=".$newminprice.
" level=".$level.
" npr=".$newnpr.
" newdefaultvatcode=".$newdefaultvatcode);
2871 if (empty($this->tva_tx)) {
2872 $this->tva_tx = 0.0;
2874 if (empty($newnpr)) {
2877 if (empty($newminprice)) {
2882 if ($newvat ===
null || $newvat ==
'') {
2883 $newvat = (float) $this->tva_tx;
2886 $localtaxtype1 =
'';
2887 $localtaxtype2 =
'';
2892 return $this->
generateMultiprices($user, $newprice, $newpricebase, $newvat, $newnpr, $newpbq);
2895 if (!empty($newminprice) && ($newminprice > $newprice)) {
2896 $this->error =
'ErrorPriceCantBeLowerThanMinPrice';
2900 if ($newprice === 0 || $newprice !==
'') {
2901 if ($newpricebase ==
'TTC') {
2902 $price_ttc = (float)
price2num($newprice,
'MU');
2903 $price = (float)
price2num($newprice) / (1 + ((float) $newvat / 100));
2904 $price = (float)
price2num($price,
'MU');
2906 if ((
string) $newminprice !=
'0') {
2907 $price_min_ttc = (float)
price2num($newminprice,
'MU');
2908 $price_min = (float)
price2num($newminprice) / (1 + ($newvat / 100));
2909 $price_min = (float)
price2num($price_min,
'MU');
2912 $price_min_ttc = 0.0;
2915 $price = (float)
price2num($newprice,
'MU');
2916 $price_ttc = ($newnpr != 1) ? (
float)
price2num($newprice) * (1 + ($newvat / 100)) : $price;
2917 $price_ttc = (float)
price2num($price_ttc,
'MU');
2919 if ((
string) $newminprice !=
'0') {
2920 $price_min = (float)
price2num($newminprice,
'MU');
2921 $price_min_ttc = (float)
price2num($newminprice) * (1 + ($newvat / 100));
2922 $price_min_ttc = (float)
price2num($price_min_ttc,
'MU');
2926 $price_min_ttc = 0.0;
2930 if (count($localtaxes_array) > 0) {
2931 $localtaxtype1 = $localtaxes_array[
'0'];
2932 $localtax1 = $localtaxes_array[
'1'];
2933 $localtaxtype2 = $localtaxes_array[
'2'];
2934 $localtax2 = $localtaxes_array[
'3'];
2937 if (!empty($newdefaultvatcode)) {
2940 $sql =
"SELECT t.rowid, t.code, t.recuperableonly as tva_npr, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
2941 $sql .=
" FROM ".MAIN_DB_PREFIX.
"c_tva as t, ".MAIN_DB_PREFIX.
"c_country as c";
2942 $sql .=
" WHERE t.fk_pays = c.rowid AND c.code = '".$this->db->escape(
$mysoc->country_code).
"'";
2943 $sql .=
" AND t.taux = ".((float) $newdefaultvatcode).
" AND t.active = 1";
2944 $sql .=
" AND t.code = '".$this->db->escape($newdefaultvatcode).
"'";
2945 $resql = $this->db->query($sql);
2947 $obj = $this->db->fetch_object($resql);
2949 $npr = $obj->tva_npr;
2950 $localtax1 = $obj->localtax1;
2951 $localtax2 = $obj->localtax2;
2952 $localtaxtype1 = $obj->localtax1_type;
2953 $localtaxtype2 = $obj->localtax2_type;
2958 $localtaxtype1 =
'0';
2960 $localtaxtype2 =
'0';
2964 if (empty($localtax1)) {
2967 if (empty($localtax2)) {
2976 $updatedefaultprice = (empty($level) || $level == 1);
2980 $sql =
"UPDATE ".$this->db->prefix().
"product SET";
2981 if ($updatedefaultprice) {
2982 $sql .=
" price_base_type = '".$this->db->escape($newpricebase).
"',";
2983 $sql .=
" price = ".(float) $price.
",";
2984 $sql .=
" price_ttc = ".(float) $price_ttc.
",";
2985 $sql .=
" price_min = ".(float) $price_min.
",";
2986 $sql .=
" price_min_ttc = ".(float) $price_min_ttc.
",";
2987 $sql .=
" price_label = ".(!empty($price_label) ?
"'".$this->db->escape($price_label).
"'" :
"null").
",";
2989 $sql .=
" localtax1_tx = ".($localtax1 >= 0 ? (float) $localtax1 :
'NULL').
",";
2990 $sql .=
" localtax2_tx = ".($localtax2 >= 0 ? (float) $localtax2 :
'NULL').
",";
2991 $sql .=
" localtax1_type = ".($localtaxtype1 !=
'' ?
"'".$this->db->escape($localtaxtype1).
"'" :
"'0'").
",";
2992 $sql .=
" localtax2_type = ".($localtaxtype2 !=
'' ?
"'".$this->db->escape($localtaxtype2).
"'" :
"'0'").
",";
2993 $sql .=
" default_vat_code = ".($newdefaultvatcode ?
"'".$this->db->escape($newdefaultvatcode).
"'" :
"null").
",";
2994 $sql .=
" tva_tx = ".(float)
price2num($newvat).
",";
2995 $sql .=
" recuperableonly = '".$this->db->escape((
string) $newnpr).
"'";
2996 $sql .=
" WHERE rowid = ".((int) $id);
2998 dol_syslog(get_class($this).
"::update_price", LOG_DEBUG);
2999 $resql = $this->db->query($sql);
3001 $this->multiprices[$level] = $price;
3002 $this->multiprices_ttc[$level] = $price_ttc;
3003 $this->multiprices_min[$level] = $price_min;
3004 $this->multiprices_min_ttc[$level] = $price_min_ttc;
3005 $this->multiprices_base_type[$level] = $newpricebase;
3006 $this->multiprices_default_vat_code[$level] = $newdefaultvatcode;
3007 $this->multiprices_tva_tx[$level] = $newvat;
3008 $this->multiprices_recuperableonly[$level] = $newnpr;
3012 $savdefaultprice = array($this->
price, $this->price_label, $this->price_ttc, $this->price_min, $this->price_min_ttc, $this->price_base_type);
3014 $this->
price = $price;
3015 $this->price_label = $price_label;
3016 $this->price_ttc = $price_ttc;
3017 $this->price_min = $price_min;
3018 $this->price_min_ttc = $price_min_ttc;
3019 $this->price_base_type = $newpricebase;
3020 $this->default_vat_code = $newdefaultvatcode;
3021 $this->tva_tx = $newvat;
3022 $this->tva_npr = $newnpr;
3025 $this->localtax1_tx = $localtax1;
3026 $this->localtax2_tx = $localtax2;
3027 $this->localtax1_type = $localtaxtype1;
3028 $this->localtax2_type = $localtaxtype2;
3031 $this->price_by_qty = $newpbq;
3035 if (!empty(array_diff_assoc($newPriceData, $lastPriceData)) || (!
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3039 if (!$updatedefaultprice) {
3041 list($this->
price, $this->price_label, $this->price_ttc, $this->price_min, $this->price_min_ttc, $this->price_base_type) = $savdefaultprice;
3044 $this->level = $level;
3048 $result = $this->call_trigger(
'PRODUCT_PRICE_MODIFY', $user);
3050 $this->db->rollback();
3056 $this->db->commit();
3058 $this->db->rollback();
3059 $this->error = $this->db->lasterror();
3078 $this->fk_price_expression = $expression_id;
3080 return $this->
update($this->
id, $user);
3095 public function fetch($id = 0, $ref =
'', $ref_ext =
'', $barcode =
'', $ignore_expression = 0, $ignore_price_load = 0, $ignore_lang_load = 0)
3097 include_once DOL_DOCUMENT_ROOT.
'/core/lib/company.lib.php';
3101 dol_syslog(get_class($this).
"::fetch id=".$id.
" ref=".$ref.
" ref_ext=".$ref_ext);
3104 if (!$id && !$ref && !$ref_ext && !$barcode) {
3105 $this->error =
'ErrorWrongParameters';
3106 dol_syslog(get_class($this).
"::fetch ".$this->error, LOG_ERR);
3110 $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,";
3111 $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,";
3112 $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,";
3113 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.last_main_doc,";
3114 $sql .=
" p.surface, p.surface_units, p.volume, p.volume_units, p.barcode, p.fk_barcode_type, p.finished, p.fk_default_bom, p.mandatory_period, p.packaging,";
3116 $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,";
3118 $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,";
3123 $separatedEntityPMP =
false;
3124 $separatedStock =
false;
3125 $visibleWarehousesEntities =
$conf->entity;
3128 $checkPMPPerEntity = $this->db->query(
"SELECT pmp FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = ".((int) $id).
" AND entity = ".(
int)
$conf->entity);
3129 if ($this->db->num_rows($checkPMPPerEntity) > 0) {
3130 $separatedEntityPMP =
true;
3134 $separatedStock =
true;
3135 if (isset($mc->sharings[
'stock']) && !empty($mc->sharings[
'stock'])) {
3136 $visibleWarehousesEntities .=
"," . implode(
",", $mc->sharings[
'stock']);
3139 if ($separatedEntityPMP) {
3140 $sql .=
" ppe.pmp,";
3144 $sql .=
" p.datec, GREATEST(p.tms, COALESCE(pef.tms, p.tms)) AS tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.sell_or_eat_by_mandatory, p.batch_mask, p.fk_unit,";
3145 $sql .=
" p.fk_price_expression, p.price_autogen, p.stockable_product, p.model_pdf,";
3146 $sql .=
" p.price_label,";
3147 if ($separatedStock) {
3148 $sql .=
" SUM(sp.reel) as stock";
3152 $sql .=
" FROM ".$this->db->prefix().
"product as p";
3153 $sql .=
" LEFT JOIN ".$this->db->prefix().
"product_extrafields as pef ON pef.fk_object=p.rowid";
3155 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int)
$conf->entity);
3157 if ($separatedStock) {
3158 $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).
"))";
3162 $sql .=
" WHERE p.rowid = ".((int) $id);
3164 $sql .=
" WHERE p.entity IN (".getEntity($this->element).
")";
3166 $sql .=
" AND p.ref = '".$this->db->escape($ref).
"'";
3167 } elseif ($ref_ext) {
3168 $sql .=
" AND p.ref_ext = '".$this->db->escape($ref_ext).
"'";
3169 } elseif ($barcode) {
3170 $sql .=
" AND p.barcode = '".$this->db->escape($barcode).
"'";
3173 if ($separatedStock) {
3174 $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,";
3175 $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,";
3176 $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,";
3177 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
3178 $sql .=
" p.surface, p.surface_units, p.volume, p.volume_units, p.barcode, p.fk_barcode_type, p.finished, p.fk_default_bom, p.mandatory_period, p.packaging,";
3180 $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,";
3182 $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,";
3184 if ($separatedEntityPMP) {
3185 $sql .=
" ppe.pmp,";
3189 $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,";
3190 $sql .=
" p.fk_price_expression, p.price_autogen, p.stockable_product, p.model_pdf,";
3191 $sql .=
" p.price_label";
3198 $resql = $this->db->query($sql);
3200 unset($this->oldcopy);
3202 if ($this->db->num_rows($resql) > 0) {
3203 $obj = $this->db->fetch_object($resql);
3205 $this->
id = $obj->rowid;
3206 $this->
ref = $obj->ref;
3207 $this->ref_ext = $obj->ref_ext;
3208 $this->label = $obj->label;
3210 $this->url = $obj->url;
3211 $this->note_public = $obj->note_public;
3212 $this->note_private = $obj->note_private;
3213 $this->note = $obj->note_private;
3215 $this->
type = $obj->fk_product_type;
3216 $this->price_label = $obj->price_label;
3217 $this->
status = $obj->tosell;
3218 $this->status_buy = $obj->tobuy;
3219 $this->status_batch = $obj->tobatch;
3220 $this->sell_or_eat_by_mandatory = $obj->sell_or_eat_by_mandatory;
3221 $this->batch_mask = $obj->batch_mask;
3223 $this->customcode = $obj->customcode;
3224 $this->country_id = $obj->fk_country;
3225 $this->country_code =
getCountry($this->country_id,
'2', $this->db);
3226 $this->state_id = $obj->fk_state;
3227 $this->lifetime = $obj->lifetime;
3228 $this->qc_frequency = $obj->qc_frequency;
3229 $this->
price = $obj->price;
3230 $this->price_ttc = $obj->price_ttc;
3231 $this->price_min = $obj->price_min;
3232 $this->price_min_ttc = $obj->price_min_ttc;
3233 $this->price_base_type = (empty($obj->price_base_type) ?
'HT' : $obj->price_base_type);
3234 $this->cost_price = isset($obj->cost_price) ? (float) $obj->cost_price :
null;
3235 $this->default_vat_code = $obj->default_vat_code;
3236 $this->tva_tx = $obj->tva_tx;
3238 $this->tva_npr = $obj->tva_npr;
3240 $this->localtax1_tx = $obj->localtax1_tx;
3241 $this->localtax2_tx = $obj->localtax2_tx;
3242 $this->localtax1_type = $obj->localtax1_type;
3243 $this->localtax2_type = $obj->localtax2_type;
3245 $this->finished = $obj->finished;
3246 $this->fk_default_bom = $obj->fk_default_bom;
3248 $this->duration = $obj->duration;
3250 preg_match(
'/([\d.]+)(\w+)/', $obj->duration, $matches);
3251 $this->duration_value = !empty($matches[1]) ? (float) $matches[1] : 0;
3252 $this->duration_unit = !empty($matches[2]) ? (
string) $matches[2] :
null;
3253 $this->canvas = $obj->canvas;
3254 $this->net_measure = $obj->net_measure;
3255 $this->net_measure_units = $obj->net_measure_units;
3256 $this->weight = $obj->weight;
3257 $this->weight_units = (is_null($obj->weight_units) ? 0 : $obj->weight_units);
3258 $this->length = $obj->length;
3259 $this->length_units = (is_null($obj->length_units) ? 0 : $obj->length_units);
3260 $this->width = $obj->width;
3261 $this->width_units = (is_null($obj->width_units) ? 0 : $obj->width_units);
3262 $this->height = $obj->height;
3263 $this->height_units = (is_null($obj->height_units) ? 0 : $obj->height_units);
3265 $this->surface = $obj->surface;
3266 $this->surface_units = (is_null($obj->surface_units) ? 0 : $obj->surface_units);
3267 $this->volume = $obj->volume;
3268 $this->volume_units = (is_null($obj->volume_units) ? 0 : $obj->volume_units);
3269 $this->barcode = $obj->barcode;
3270 $this->barcode_type = $obj->fk_barcode_type;
3272 $this->accountancy_code_buy = $obj->accountancy_code_buy;
3273 $this->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra;
3274 $this->accountancy_code_buy_export = $obj->accountancy_code_buy_export;
3275 $this->accountancy_code_sell = $obj->accountancy_code_sell;
3276 $this->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra;
3277 $this->accountancy_code_sell_export = $obj->accountancy_code_sell_export;
3279 $this->fk_default_warehouse = $obj->fk_default_warehouse;
3280 $this->fk_default_workstation = $obj->fk_default_workstation;
3281 $this->seuil_stock_alerte = $obj->seuil_stock_alerte;
3282 $this->desiredstock = $obj->desiredstock;
3283 $this->stock_reel = $obj->stock;
3284 $this->stockable_product = $obj->stockable_product;
3285 $this->pmp = $obj->pmp;
3287 $this->date_creation = $this->db->jdate($obj->datec);
3288 $this->date_modification = $this->db->jdate($obj->tms);
3290 $this->import_key = $obj->import_key;
3291 $this->entity = $obj->entity;
3293 $this->ref_ext = $obj->ref_ext;
3294 $this->fk_price_expression = $obj->fk_price_expression;
3295 $this->fk_unit = $obj->fk_unit;
3296 $this->price_autogen = $obj->price_autogen;
3297 $this->model_pdf = $obj->model_pdf;
3298 $this->last_main_doc = $obj->last_main_doc;
3300 $this->mandatory_period = $obj->mandatory_period;
3303 $this->packaging = (float) $obj->packaging;
3306 $this->db->free($resql);
3318 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
3319 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3320 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3321 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3322 $sql .=
" ,price_label";
3323 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3324 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3325 $sql .=
" AND price_level=".((int) $i);
3326 $sql .=
" AND fk_product = ".((int) $this->
id);
3327 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3329 $resql = $this->db->query($sql);
3331 $result = $this->db->fetch_array($resql);
3333 $this->multiprices[$i] = $result ? $result[
"price"] :
null;
3334 $this->multiprices_ttc[$i] = $result ? $result[
"price_ttc"] :
null;
3335 $this->multiprices_min[$i] = $result ? $result[
"price_min"] :
null;
3336 $this->multiprices_min_ttc[$i] = $result ? $result[
"price_min_ttc"] :
null;
3337 $this->multiprices_base_type[$i] = $result ? $result[
"price_base_type"] :
null;
3339 $this->multiprices_tva_tx[$i] = $result ? $result[
"tva_tx"].(!empty($result[
'default_vat_code']) ?
' ('.$result[
'default_vat_code'].
')' :
'') :
null;
3340 $this->multiprices_recuperableonly[$i] = $result ? $result[
"recuperableonly"] :
null;
3379 $this->error = $this->db->lasterror;
3385 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY') && empty($ignore_price_load)) {
3386 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3387 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid";
3388 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3389 $sql .=
" WHERE fk_product = ".((int) $this->
id);
3390 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3393 $resql = $this->db->query($sql);
3395 $result = $this->db->fetch_array($resql);
3399 $this->prices_by_qty[0] = $result[
"price_by_qty"];
3400 $this->prices_by_qty_id[0] = $result[
"rowid"];
3402 if ($this->prices_by_qty[0] == 1) {
3403 $sql =
"SELECT rowid,price, unitprice, quantity, remise_percent, remise, remise, price_base_type";
3404 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3405 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[0]);
3406 $sql .=
" ORDER BY quantity ASC";
3408 $resql = $this->db->query($sql);
3410 $resultat = array();
3412 while ($result = $this->db->fetch_array($resql)) {
3413 $resultat[$ii] = array();
3414 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3415 $resultat[$ii][
"price"] = $result[
"price"];
3416 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3417 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3418 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3420 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3423 $this->prices_by_qty_list[0] = $resultat;
3425 $this->error = $this->db->lasterror;
3431 $this->error = $this->db->lasterror;
3434 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') && empty($ignore_price_load)) {
3435 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
3436 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3437 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3438 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3439 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3440 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3441 $sql .=
" AND price_level=".((int) $i);
3442 $sql .=
" AND fk_product = ".((int) $this->
id);
3443 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3445 $resql = $this->db->query($sql);
3447 $this->error = $this->db->lasterror;
3450 $result = $this->db->fetch_array($resql);
3451 $this->multiprices[$i] = (!empty($result[
"price"]) ? $result[
"price"] : 0);
3452 $this->multiprices_ttc[$i] = (!empty($result[
"price_ttc"]) ? $result[
"price_ttc"] : 0);
3453 $this->multiprices_min[$i] = (!empty($result[
"price_min"]) ? $result[
"price_min"] : 0);
3454 $this->multiprices_min_ttc[$i] = (!empty($result[
"price_min_ttc"]) ? $result[
"price_min_ttc"] : 0);
3455 $this->multiprices_base_type[$i] = (!empty($result[
"price_base_type"]) ? $result[
"price_base_type"] :
'');
3457 $this->multiprices_tva_tx[$i] = (!empty($result[
"tva_tx"]) ? $result[
"tva_tx"] : 0);
3458 $this->multiprices_recuperableonly[$i] = (!empty($result[
"recuperableonly"]) ? $result[
"recuperableonly"] : 0);
3461 $this->prices_by_qty[$i] = (!empty($result[
"price_by_qty"]) ? $result[
"price_by_qty"] : 0);
3462 $this->prices_by_qty_id[$i] = (!empty($result[
"rowid"]) ? $result[
"rowid"] : 0);
3464 if ($this->prices_by_qty[$i] == 1) {
3465 $sql =
"SELECT rowid, price, unitprice, quantity, remise_percent, remise, price_base_type";
3466 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3467 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[$i]);
3468 $sql .=
" ORDER BY quantity ASC";
3470 $resql = $this->db->query($sql);
3472 $resultat = array();
3474 while ($result = $this->db->fetch_array($resql)) {
3475 $resultat[$ii] = array();
3476 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3477 $resultat[$ii][
"price"] = $result[
"price"];
3478 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3479 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3480 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3481 $resultat[$ii][
"remise"] = $result[
"remise"];
3482 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3485 $this->prices_by_qty_list[$i] = $resultat;
3487 $this->error = $this->db->lasterror;
3495 if (
isModEnabled(
'dynamicprices') && !empty($this->fk_price_expression) && empty($ignore_expression)) {
3496 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
3498 $price_result = $priceparser->parseProduct($this);
3499 if ($price_result >= 0) {
3500 $this->
price = $price_result;
3502 $this->price_ttc = (float)
price2num($this->
price) * (1 + ($this->tva_tx / 100));
3503 $this->price_ttc = (float)
price2num($this->price_ttc,
'MU');
3509 $this->stock_warehouse = array();
3516 $this->error = $this->db->lasterror();
3531 global $user, $hookmanager, $action;
3535 foreach (array(
'toconsume',
'consumed',
'toproduce',
'produced') as $role) {
3536 $this->stats_mo[
'customers_'.$role] = 0;
3537 $this->stats_mo[
'nb_'.$role] = 0;
3538 $this->stats_mo[
'qty_'.$role] = 0;
3540 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3541 $sql .=
" SUM(mp.qty) as qty";
3542 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as c";
3543 $sql .=
" INNER JOIN ".$this->db->prefix().
"mrp_production as mp ON mp.fk_mo=c.rowid";
3544 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3545 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3548 $sql .=
" c.entity IN (".getEntity(
'mo').
")";
3550 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3551 $sql .=
" AND mp.role ='".$this->db->escape($role).
"'";
3553 $sql .=
" AND c.fk_soc = ".((int) $socid);
3556 $result = $this->db->query($sql);
3558 $obj = $this->db->fetch_object($result);
3559 $this->stats_mo[
'customers_'.$role] = $obj->nb_customers ? $obj->nb_customers : 0;
3560 $this->stats_mo[
'nb_'.$role] = $obj->nb ? $obj->nb : 0;
3561 $this->stats_mo[
'qty_'.$role] = $obj->qty ?
price2num($obj->qty,
'MS') : 0;
3563 $this->error = $this->db->error();
3568 if (!empty($error)) {
3572 $parameters = array(
'socid' => $socid);
3573 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3575 $this->stats_mo = $hookmanager->resArray[
'stats_mo'];
3591 global $hookmanager, $action;
3595 $this->stats_bom[
'nb_toproduce'] = 0;
3596 $this->stats_bom[
'nb_toconsume'] = 0;
3597 $this->stats_bom[
'qty_toproduce'] = 0;
3598 $this->stats_bom[
'qty_toconsume'] = 0;
3600 $sql =
"SELECT COUNT(DISTINCT b.rowid) as nb_toproduce,";
3601 $sql .=
" SUM(b.qty) as qty_toproduce";
3602 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3603 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom = b.rowid";
3605 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3606 $sql .=
" AND b.fk_product =".((int) $this->
id);
3607 $sql .=
" GROUP BY b.rowid";
3609 $result = $this->db->query($sql);
3611 $obj = $this->db->fetch_object($result);
3612 $this->stats_bom[
'nb_toproduce'] = !empty($obj->nb_toproduce) ? $obj->nb_toproduce : 0;
3613 $this->stats_bom[
'qty_toproduce'] = !empty($obj->qty_toproduce) ?
price2num($obj->qty_toproduce) : 0;
3615 $this->error = $this->db->error();
3619 $sql =
"SELECT COUNT(DISTINCT bl.rowid) as nb_toconsume,";
3620 $sql .=
" SUM(bl.qty) as qty_toconsume";
3621 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3622 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
3624 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3625 $sql .=
" AND bl.fk_product =".((int) $this->
id);
3627 $result = $this->db->query($sql);
3629 $obj = $this->db->fetch_object($result);
3630 $this->stats_bom[
'nb_toconsume'] = !empty($obj->nb_toconsume) ? $obj->nb_toconsume : 0;
3631 $this->stats_bom[
'qty_toconsume'] = !empty($obj->qty_toconsume) ?
price2num($obj->qty_toconsume) : 0;
3633 $this->error = $this->db->error();
3637 if (!empty($error)) {
3641 $parameters = array(
'socid' => $socid);
3642 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3644 $this->stats_bom = $hookmanager->resArray[
'stats_bom'];
3660 global $user, $hookmanager, $action;
3662 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_customers, COUNT(DISTINCT p.rowid) as nb,";
3663 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3664 $sql .=
" FROM ".$this->db->prefix().
"propaldet as pd";
3665 $sql .=
", ".$this->db->prefix().
"propal as p";
3666 $sql .=
", ".$this->db->prefix().
"societe as s";
3667 $sql .=
" WHERE p.rowid = pd.fk_propal";
3668 $sql .=
" AND p.fk_soc = s.rowid";
3669 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
3670 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3671 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3672 $sql .=
" AND EXISTS (SELECT 1 FROM ".$this->db->prefix().
"societe_commerciaux as sc WHERE sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $user->id).
")";
3676 $sql .=
" AND p.fk_soc = ".((int) $socid);
3679 $parameters = array(
'socid' => $socid,
'type_element' =>
'propal');
3680 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3681 $sql .= $hookmanager->resPrint;
3682 $result = $this->db->query($sql);
3684 $obj = $this->db->fetch_object($result);
3685 $this->stats_propale[
'customers'] = (int) $obj->nb_customers;
3686 $this->stats_propale[
'nb'] = (int) $obj->nb;
3687 $this->stats_propale[
'rows'] = (int) $obj->nb_rows;
3688 $this->stats_propale[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
3693 if (is_array($TFather) && !empty($TFather)) {
3694 foreach ($TFather as &$fatherData) {
3695 $pFather =
new Product($this->db);
3696 $pFather->id = (int) $fatherData[
'id'];
3697 $qtyCoef = $fatherData[
'qty'];
3699 if ($fatherData[
'incdec']) {
3700 $pFather->load_stats_propale($socid);
3702 if (!empty($pFather->stats_propale)) {
3703 $this->stats_propale[
'customers'] += $pFather->stats_propale[
'customers'];
3704 $this->stats_propale[
'nb'] += $pFather->stats_propale[
'nb'];
3705 $this->stats_propale[
'rows'] += $pFather->stats_propale[
'rows'];
3706 $this->stats_propale[
'qty'] += $pFather->stats_propale[
'qty'] * $qtyCoef;
3713 $parameters = array(
'socid' => $socid);
3714 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerProposal', $parameters, $this, $action);
3716 $this->stats_propale = $hookmanager->resArray[
'stats_propale'];
3721 $this->error = $this->db->error();
3737 global $user, $hookmanager, $action;
3739 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_suppliers, COUNT(DISTINCT p.rowid) as nb,";
3740 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3741 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as pd";
3742 $sql .=
", ".$this->db->prefix().
"supplier_proposal as p";
3743 $sql .=
", ".$this->db->prefix().
"societe as s";
3744 $sql .=
" WHERE p.rowid = pd.fk_supplier_proposal";
3745 $sql .=
" AND p.fk_soc = s.rowid";
3746 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
3747 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3748 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3749 $sql .=
" AND EXISTS (SELECT 1 FROM ".$this->db->prefix().
"societe_commerciaux as sc WHERE sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $user->id).
")";
3753 $sql .=
" AND p.fk_soc = ".((int) $socid);
3756 $result = $this->db->query($sql);
3758 $obj = $this->db->fetch_object($result);
3759 $this->stats_proposal_supplier[
'suppliers'] = $obj->nb_suppliers;
3760 $this->stats_proposal_supplier[
'nb'] = $obj->nb;
3761 $this->stats_proposal_supplier[
'rows'] = $obj->nb_rows;
3762 $this->stats_proposal_supplier[
'qty'] = $obj->qty ? $obj->qty : 0;
3764 $parameters = array(
'socid' => $socid);
3765 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierProposal', $parameters, $this, $action);
3767 $this->stats_proposal_supplier = $hookmanager->resArray[
'stats_proposal_supplier'];
3772 $this->error = $this->db->error();
3790 global $user, $hookmanager, $action;
3793 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3794 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3795 $sql .=
" FROM ".$this->db->prefix().
"commandedet as cd";
3796 $sql .=
", ".$this->db->prefix().
"commande as c";
3797 $sql .=
", ".$this->db->prefix().
"societe as s";
3798 $sql .=
" WHERE c.rowid = cd.fk_commande";
3799 $sql .=
" AND c.fk_soc = s.rowid";
3800 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'commande').
")";
3801 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3802 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3803 $sql .=
" AND EXISTS (SELECT 1 FROM ".$this->db->prefix().
"societe_commerciaux as sc WHERE sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id).
")";
3806 $sql .=
" AND c.fk_soc = ".((int) $socid);
3808 if ($filtrestatut !=
'') {
3809 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3812 $parameters = array(
'socid' => $socid,
'type_element' =>
'order');
3813 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3814 $sql .= $hookmanager->resPrint;
3815 $result = $this->db->query($sql);
3817 $obj = $this->db->fetch_object($result);
3818 $this->stats_commande[
'customers'] = (int) $obj->nb_customers;
3819 $this->stats_commande[
'nb'] = (int) $obj->nb;
3820 $this->stats_commande[
'rows'] = (int) $obj->nb_rows;
3821 $this->stats_commande[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
3826 if (is_array($TFather) && !empty($TFather)) {
3827 foreach ($TFather as &$fatherData) {
3828 $pFather =
new Product($this->db);
3829 $pFather->id = $fatherData[
'id'];
3830 $qtyCoef = $fatherData[
'qty'];
3832 if ($fatherData[
'incdec']) {
3833 $pFather->load_stats_commande($socid, $filtrestatut);
3835 $this->stats_commande[
'customers'] += $pFather->stats_commande[
'customers'];
3836 $this->stats_commande[
'nb'] += $pFather->stats_commande[
'nb'];
3837 $this->stats_commande[
'rows'] += $pFather->stats_commande[
'rows'];
3838 $this->stats_commande[
'qty'] += $pFather->stats_commande[
'qty'] * $qtyCoef;
3851 $sql =
"SELECT SUM(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3852 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3854 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture' AND sourcetype = 'commande' ";
3855 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3856 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3857 $sql .=
" AND EXISTS (SELECT cd.fk_product FROM ".$this->db->prefix().
"commandedet as cd WHERE cd.fk_product = fd.fk_product AND cd.fk_commande = c.rowid)";
3861 $sql .=
"SELECT SUM(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3862 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3863 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_source = f.rowid AND el.targettype = 'commande' AND sourcetype = 'facture' ";
3864 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_target = c.rowid";
3865 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3866 $sql .=
" AND EXISTS (SELECT cd.fk_product FROM ".$this->db->prefix().
"commandedet as cd WHERE cd.fk_product = fd.fk_product AND cd.fk_commande = c.rowid)";
3868 $parameters = array(
'socid' => $socid,
'type_element' =>
'order');
3869 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3870 $sql .= $hookmanager->resPrint;
3871 $resql = $this->db->query($sql);
3873 while ($obj = $this->db->fetch_object($resql)) {
3874 $adeduire += (float) $obj->count;
3878 $this->stats_commande[
'qty'] -= $adeduire;
3881 include_once DOL_DOCUMENT_ROOT.
'/compta/facture/class/facture.class.php';
3885 $sql =
"SELECT sum(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3886 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3888 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture' AND sourcetype = 'commande' ";
3889 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3890 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3891 $sql .=
" AND EXISTS (SELECT cd.fk_product FROM ".$this->db->prefix().
"commandedet as cd WHERE cd.fk_product = fd.fk_product AND cd.fk_commande = c.rowid)";
3893 $sql .=
" UNION ALL ";
3895 $sql .=
"SELECT sum(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3896 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3897 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_source = f.rowid AND el.targettype = 'commande' AND sourcetype = 'facture' ";
3898 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_target = c.rowid";
3899 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3900 $sql .=
" AND EXISTS (SELECT cd.fk_product FROM ".$this->db->prefix().
"commandedet as cd WHERE cd.fk_product = fd.fk_product AND cd.fk_commande = c.rowid)";
3902 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3904 $parameters = array(
'socid' => $socid,
'type_element' =>
'order');
3905 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3906 $sql .= $hookmanager->resPrint;
3907 $resql = $this->db->query($sql);
3909 while ($obj = $this->db->fetch_object($resql)) {
3910 $adeduire += (float) $obj->count;
3913 $this->error = $this->db->error();
3917 $this->stats_commande[
'qty'] -= $adeduire;
3921 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3922 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerOrder', $parameters, $this, $action);
3924 $this->stats_commande = $hookmanager->resArray[
'stats_commande'];
3928 $this->error = $this->db->error();
3946 global $user, $hookmanager, $action;
3948 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_suppliers, COUNT(DISTINCT c.rowid) as nb,";
3949 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3950 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as cd";
3951 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as c";
3952 $sql .=
", ".$this->db->prefix().
"societe as s";
3953 $sql .=
" WHERE c.rowid = cd.fk_commande";
3954 $sql .=
" AND c.fk_soc = s.rowid";
3955 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3956 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3957 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3958 $sql .=
" AND EXISTS (SELECT 1 FROM ".$this->db->prefix().
"societe_commerciaux as sc WHERE sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id).
")";
3961 $sql .=
" AND c.fk_soc = ".((int) $socid);
3963 if ($filtrestatut !=
'') {
3964 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3966 if (!empty($dateofvirtualstock)) {
3967 $sql .=
" AND c.date_livraison <= '".$this->db->idate($dateofvirtualstock).
"'";
3970 $result = $this->db->query($sql);
3972 $obj = $this->db->fetch_object($result);
3973 $this->stats_commande_fournisseur[
'suppliers'] = $obj->nb_suppliers;
3974 $this->stats_commande_fournisseur[
'nb'] = $obj->nb;
3975 $this->stats_commande_fournisseur[
'rows'] = $obj->nb_rows;
3976 $this->stats_commande_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
3978 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3979 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierOrder', $parameters, $this, $action);
3981 $this->stats_commande_fournisseur = $hookmanager->resArray[
'stats_commande_fournisseur'];
3986 $this->error = $this->db->error().
' sql='.$sql;
4001 public function load_stats_sending($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $filterShipmentStatus =
'')
4004 global $user, $hookmanager, $action;
4006 $sql =
"SELECT COUNT(DISTINCT e.fk_soc) as nb_customers, COUNT(DISTINCT e.rowid) as nb,";
4007 $sql .=
" COUNT(ed.rowid) as nb_rows, SUM(ed.qty) as qty";
4008 $sql .=
" FROM ".$this->db->prefix().
"expeditiondet as ed";
4009 $sql .=
", ".$this->db->prefix().
"commandedet as cd";
4010 $sql .=
", ".$this->db->prefix().
"commande as c";
4011 $sql .=
", ".$this->db->prefix().
"expedition as e";
4012 $sql .=
", ".$this->db->prefix().
"societe as s";
4013 $sql .=
" WHERE e.rowid = ed.fk_expedition";
4014 $sql .=
" AND c.rowid = cd.fk_commande";
4015 $sql .=
" AND e.fk_soc = s.rowid";
4016 $sql .=
" AND e.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'expedition').
")";
4017 $sql .=
" AND ed.fk_elementdet = cd.rowid";
4018 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
4019 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
4020 $sql .=
" AND EXISTS (SELECT 1 FROM ".$this->db->prefix().
"societe_commerciaux as sc WHERE sc.fk_soc = e.fk_soc AND sc.fk_user = ".((int) $user->id).
")";
4023 $sql .=
" AND e.fk_soc = ".((int) $socid);
4025 if ($filtrestatut !=
'') {
4026 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
4028 if (!empty($filterShipmentStatus)) {
4029 $sql .=
" AND e.fk_statut IN (".$this->db->sanitize($filterShipmentStatus).
")";
4032 $result = $this->db->query($sql);
4034 $obj = $this->db->fetch_object($result);
4035 $this->stats_expedition[
'customers'] = (int) $obj->nb_customers;
4036 $this->stats_expedition[
'nb'] = (int) $obj->nb;
4037 $this->stats_expedition[
'rows'] = (int) $obj->nb_rows;
4038 $this->stats_expedition[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
4043 if (is_array($TFather) && !empty($TFather)) {
4044 foreach ($TFather as &$fatherData) {
4045 $pFather =
new Product($this->db);
4046 $pFather->id = $fatherData[
'id'];
4047 $qtyCoef = $fatherData[
'qty'];
4049 if ($fatherData[
'incdec']) {
4050 $pFather->load_stats_sending($socid, $filtrestatut, $forVirtualStock);
4052 if (!empty($pFather->stats_expedition)) {
4053 $this->stats_expedition[
'customers'] += $pFather->stats_expedition[
'customers'];
4054 $this->stats_expedition[
'nb'] += $pFather->stats_expedition[
'nb'];
4055 $this->stats_expedition[
'rows'] += $pFather->stats_expedition[
'rows'];
4056 $this->stats_expedition[
'qty'] += $pFather->stats_expedition[
'qty'] * $qtyCoef;
4063 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock,
'filterShipmentStatus' => $filterShipmentStatus);
4064 $reshook = $hookmanager->executeHooks(
'loadStatsSending', $parameters, $this, $action);
4066 $this->stats_expedition = $hookmanager->resArray[
'stats_expedition'];
4071 $this->error = $this->db->error();
4086 public function load_stats_reception($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null)
4089 global $user, $hookmanager, $action;
4091 $sql =
"SELECT COUNT(DISTINCT cf.fk_soc) as nb_suppliers, COUNT(DISTINCT cf.rowid) as nb,";
4092 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4093 $sql .=
" FROM ".$this->db->prefix().
"receptiondet_batch as fd";
4094 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as cf";
4095 $sql .=
", ".$this->db->prefix().
"societe as s";
4096 $sql .=
" WHERE cf.rowid = fd.fk_element";
4097 $sql .=
" AND cf.fk_soc = s.rowid";
4098 $sql .=
" AND cf.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
4099 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4100 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
4101 $sql .=
" AND EXISTS (SELECT 1 FROM ".$this->db->prefix().
"societe_commerciaux as sc WHERE sc.fk_soc = cf.fk_soc AND sc.fk_user = ".((int) $user->id).
")";
4104 $sql .=
" AND cf.fk_soc = ".((int) $socid);
4106 if ($filtrestatut !=
'') {
4107 $sql .=
" AND cf.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
4109 if (!empty($dateofvirtualstock)) {
4110 $sql .=
" AND fd.datec <= '".$this->db->idate($dateofvirtualstock).
"'";
4113 $result = $this->db->query($sql);
4115 $obj = $this->db->fetch_object($result);
4116 $this->stats_reception[
'suppliers'] = $obj->nb_suppliers;
4117 $this->stats_reception[
'nb'] = $obj->nb;
4118 $this->stats_reception[
'rows'] = $obj->nb_rows;
4119 $this->stats_reception[
'qty'] = $obj->qty ? $obj->qty : 0;
4121 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
4122 $reshook = $hookmanager->executeHooks(
'loadStatsReception', $parameters, $this, $action);
4124 $this->stats_reception = $hookmanager->resArray[
'stats_reception'];
4129 $this->error = $this->db->error();
4145 public function load_stats_inproduction($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null, $warehouseid = 0)
4148 global $user, $hookmanager, $action;
4152 $sql =
"SELECT COUNT(DISTINCT m.fk_soc) as nb_customers, COUNT(DISTINCT m.rowid) as nb,";
4153 $sql .=
" COUNT(mp.rowid) as nb_rows, SUM(mp.qty) as qty, role";
4154 $sql .=
" FROM ".$this->db->prefix().
"mrp_production as mp";
4155 $sql .=
", ".$this->db->prefix().
"mrp_mo as m";
4156 $sql .=
" LEFT JOIN ".$this->db->prefix().
"societe as s ON s.rowid = m.fk_soc";
4157 $sql .=
" WHERE m.rowid = mp.fk_mo";
4158 $sql .=
" AND m.entity IN (".getEntity(($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE')) ?
'stock' :
'mrp').
")";
4159 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
4160 $sql .=
" AND (mp.disable_stock_change IN (0) OR mp.disable_stock_change IS NULL)";
4161 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
4162 $sql .=
" AND EXISTS (SELECT 1 FROM ".$this->db->prefix().
"societe_commerciaux as sc WHERE sc.fk_soc = m.fk_soc AND sc.fk_user = ".((int) $user->id).
")";
4165 $sql .=
" AND m.fk_soc = ".((int) $socid);
4167 if ($filtrestatut !=
'') {
4168 $sql .=
" AND m.status IN (".$this->db->sanitize($filtrestatut).
")";
4170 if (!empty($dateofvirtualstock)) {
4171 $sql .=
" AND m.date_valid <= '".$this->db->idate($dateofvirtualstock).
"'";
4173 if (!$serviceStockIsEnabled) {
4174 $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))";
4176 if (!empty($warehouseid)) {
4177 $sql .=
" AND m.fk_warehouse = ".((int) $warehouseid);
4179 $sql .=
" GROUP BY role";
4182 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
4184 $this->stats_mrptoconsume[
'customers'] = 0;
4185 $this->stats_mrptoconsume[
'nb'] = 0;
4186 $this->stats_mrptoconsume[
'rows'] = 0;
4187 $this->stats_mrptoconsume[
'qty'] = 0.0;
4188 $this->stats_mrptoproduce[
'customers'] = 0;
4189 $this->stats_mrptoproduce[
'nb'] = 0;
4190 $this->stats_mrptoproduce[
'rows'] = 0;
4191 $this->stats_mrptoproduce[
'qty'] = 0.0;
4194 $result = $this->db->query($sql);
4196 while ($obj = $this->db->fetch_object($result)) {
4197 if ($obj->role ==
'toconsume' && empty($warehouseid)) {
4198 $this->stats_mrptoconsume[
'customers'] += (int) $obj->nb_customers;
4199 $this->stats_mrptoconsume[
'nb'] += (int) $obj->nb;
4200 $this->stats_mrptoconsume[
'rows'] += (int) $obj->nb_rows;
4201 $this->stats_mrptoconsume[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4203 if ($obj->role ==
'consumed' && empty($warehouseid)) {
4207 $this->stats_mrptoconsume[
'qty'] -= ($obj->qty ? (float) $obj->qty : 0.0);
4209 if ($obj->role ==
'toproduce') {
4211 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4213 $this->stats_mrptoproduce[
'customers'] += (int) $obj->nb_customers;
4214 $this->stats_mrptoproduce[
'nb'] += (int) $obj->nb;
4215 $this->stats_mrptoproduce[
'rows'] += (int) $obj->nb_rows;
4216 $this->stats_mrptoproduce[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4219 if ($obj->role ==
'produced') {
4224 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
4226 $this->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
4233 if ($this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] < 0) {
4234 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
4237 if ($this->stats_mrptoconsume[
'qty'] < 0) {
4238 $this->stats_mrptoconsume[
'qty'] = 0;
4240 if ($this->stats_mrptoproduce[
'qty'] < 0) {
4241 $this->stats_mrptoproduce[
'qty'] = 0;
4245 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
4246 $reshook = $hookmanager->executeHooks(
'loadStatsInProduction', $parameters, $this, $action);
4248 $this->stats_mrptoproduce = $hookmanager->resArray[
'stats_mrptoproduce'];
4253 $this->error = $this->db->error();
4268 global $user, $hookmanager, $action;
4270 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
4271 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
4272 $sql .=
" FROM ".$this->db->prefix().
"contratdet as cd";
4273 $sql .=
", ".$this->db->prefix().
"contrat as c";
4274 $sql .=
", ".$this->db->prefix().
"societe as s";
4275 $sql .=
" WHERE c.rowid = cd.fk_contrat";
4276 $sql .=
" AND c.fk_soc = s.rowid";
4277 $sql .=
" AND c.entity IN (".getEntity(
'contract').
")";
4278 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
4279 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4280 $sql .=
" AND EXISTS (SELECT 1 FROM ".$this->db->prefix().
"societe_commerciaux as sc WHERE sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id).
")";
4284 $sql .=
" AND c.fk_soc = ".((int) $socid);
4287 $result = $this->db->query($sql);
4289 $obj = $this->db->fetch_object($result);
4290 $this->stats_contrat[
'customers'] = (int) $obj->nb_customers;
4291 $this->stats_contrat[
'nb'] = (int) $obj->nb;
4292 $this->stats_contrat[
'rows'] = (int) $obj->nb_rows;
4293 $this->stats_contrat[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
4298 if (is_array($TFather) && !empty($TFather)) {
4299 foreach ($TFather as &$fatherData) {
4300 $pFather =
new Product($this->db);
4301 $pFather->id = $fatherData[
'id'];
4302 $qtyCoef = $fatherData[
'qty'];
4304 if ($fatherData[
'incdec']) {
4305 $pFather->load_stats_contrat($socid);
4307 if (!empty($pFather->stats_contrat)) {
4308 $this->stats_contrat[
'customers'] += $pFather->stats_contrat[
'customers'];
4309 $this->stats_contrat[
'nb'] += $pFather->stats_contrat[
'nb'];
4310 $this->stats_contrat[
'rows'] += $pFather->stats_contrat[
'rows'];
4311 $this->stats_contrat[
'qty'] += $pFather->stats_contrat[
'qty'] * $qtyCoef;
4318 $parameters = array(
'socid' => $socid);
4319 $reshook = $hookmanager->executeHooks(
'loadStatsContract', $parameters, $this, $action);
4321 $this->stats_contrat = $hookmanager->resArray[
'stats_contrat'];
4326 $this->error = $this->db->error().
' sql='.$sql;
4341 global $user, $hookmanager, $action;
4343 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4344 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(".$this->db->ifsql(
'f.type != 2',
'fd.qty',
'fd.qty * -1').
") as qty";
4345 $sql .=
" FROM ".$this->db->prefix().
"facturedet as fd";
4346 $sql .=
", ".$this->db->prefix().
"facture as f";
4347 $sql .=
", ".$this->db->prefix().
"societe as s";
4348 $sql .=
" WHERE f.rowid = fd.fk_facture";
4349 $sql .=
" AND f.fk_soc = s.rowid";
4350 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4351 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4352 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4353 $sql .=
" AND EXISTS (SELECT 1 FROM ".$this->db->prefix().
"societe_commerciaux as sc WHERE sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id).
")";
4357 $sql .=
" AND f.fk_soc = ".((int) $socid);
4360 $result = $this->db->query($sql);
4362 $obj = $this->db->fetch_object($result);
4363 $this->stats_facture[
'customers'] = (int) $obj->nb_customers;
4364 $this->stats_facture[
'nb'] = (int) $obj->nb;
4365 $this->stats_facture[
'rows'] = (int) $obj->nb_rows;
4366 $this->stats_facture[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
4371 if (is_array($TFather) && !empty($TFather)) {
4372 foreach ($TFather as &$fatherData) {
4373 $pFather =
new Product($this->db);
4374 $pFather->id = $fatherData[
'id'];
4375 $qtyCoef = $fatherData[
'qty'];
4377 if ($fatherData[
'incdec']) {
4378 $pFather->load_stats_facture($socid);
4380 if (!empty($pFather->stats_facture)) {
4381 $this->stats_facture[
'customers'] += $pFather->stats_facture[
'customers'];
4382 $this->stats_facture[
'nb'] += $pFather->stats_facture[
'nb'];
4383 $this->stats_facture[
'rows'] += $pFather->stats_facture[
'rows'];
4384 $this->stats_facture[
'qty'] += $pFather->stats_facture[
'qty'] * $qtyCoef;
4391 $parameters = array(
'socid' => $socid);
4392 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoice', $parameters, $this, $action);
4394 $this->stats_facture = $hookmanager->resArray[
'stats_facture'];
4399 $this->error = $this->db->error();
4415 global $user, $hookmanager, $action;
4417 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4418 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4419 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facturedet_rec as fd";
4420 $sql .=
", ".MAIN_DB_PREFIX.
"facture_rec as f";
4421 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
4422 $sql .=
" WHERE f.rowid = fd.fk_facture";
4423 $sql .=
" AND f.fk_soc = s.rowid";
4424 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4425 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4426 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4427 $sql .=
" AND EXISTS (SELECT 1 FROM ".$this->db->prefix().
"societe_commerciaux as sc WHERE sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id).
")";
4431 $sql .=
" AND f.fk_soc = ".((int) $socid);
4434 $result = $this->db->query($sql);
4436 $obj = $this->db->fetch_object($result);
4437 $this->stats_facturerec[
'customers'] = (int) $obj->nb_customers;
4438 $this->stats_facturerec[
'nb'] = (int) $obj->nb;
4439 $this->stats_facturerec[
'rows'] = (int) $obj->nb_rows;
4440 $this->stats_facturerec[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4445 if (is_array($TFather) && !empty($TFather)) {
4446 foreach ($TFather as &$fatherData) {
4447 $pFather =
new Product($this->db);
4448 $pFather->id = $fatherData[
'id'];
4449 $qtyCoef = $fatherData[
'qty'];
4451 if ($fatherData[
'incdec']) {
4452 $pFather->load_stats_facture($socid);
4454 $this->stats_facturerec[
'customers'] += $pFather->stats_facturerec[
'customers'];
4455 $this->stats_facturerec[
'nb'] += $pFather->stats_facturerec[
'nb'];
4456 $this->stats_facturerec[
'rows'] += $pFather->stats_facturerec[
'rows'];
4457 $this->stats_facturerec[
'qty'] += $pFather->stats_facturerec[
'qty'] * $qtyCoef;
4463 $parameters = array(
'socid' => $socid);
4464 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoiceRec', $parameters, $this, $action);
4466 $this->stats_facturerec = $hookmanager->resArray[
'stats_facturerec'];
4471 $this->error = $this->db->error();
4486 global $user, $hookmanager, $action;
4488 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
4489 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4490 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as fd";
4491 $sql .=
", ".$this->db->prefix().
"facture_fourn as f";
4492 $sql .=
", ".$this->db->prefix().
"societe as s";
4493 $sql .=
" WHERE f.rowid = fd.fk_facture_fourn";
4494 $sql .=
" AND f.fk_soc = s.rowid";
4495 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4496 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4497 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4498 $sql .=
" AND EXISTS (SELECT 1 FROM ".$this->db->prefix().
"societe_commerciaux as sc WHERE sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id).
")";
4502 $sql .=
" AND f.fk_soc = ".((int) $socid);
4505 $result = $this->db->query($sql);
4507 $obj = $this->db->fetch_object($result);
4508 $this->stats_facture_fournisseur[
'suppliers'] = (int) $obj->nb_suppliers;
4509 $this->stats_facture_fournisseur[
'nb'] = (int) $obj->nb;
4510 $this->stats_facture_fournisseur[
'rows'] = (int) $obj->nb_rows;
4511 $this->stats_facture_fournisseur[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4513 $parameters = array(
'socid' => $socid);
4514 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoice', $parameters, $this, $action);
4516 $this->stats_facture_fournisseur = $hookmanager->resArray[
'stats_facture_fournisseur'];
4521 $this->error = $this->db->error();
4536 global $user, $hookmanager, $action;
4538 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
4539 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4540 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facture_fourn_det_rec as fd";
4541 $sql .=
", ".MAIN_DB_PREFIX.
"facture_fourn_rec as f";
4542 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
4543 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4544 $sql .=
", ".MAIN_DB_PREFIX.
"societe_commerciaux as sc";
4546 $sql .=
" WHERE f.rowid = fd.fk_facture";
4547 $sql .=
" AND f.fk_soc = s.rowid";
4548 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4549 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4550 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4551 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4555 $sql .=
" AND f.fk_soc = ".((int) $socid);
4558 $result = $this->db->query($sql);
4560 $obj = $this->db->fetch_object($result);
4561 $this->stats_facturefournrec[
'suppliers'] = (int) $obj->nb_suppliers;
4562 $this->stats_facturefournrec[
'nb'] = (int) $obj->nb;
4563 $this->stats_facturefournrec[
'rows'] = (int) $obj->nb_rows;
4564 $this->stats_facturefournrec[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4566 $parameters = array(
'socid' => $socid);
4567 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoiceRec', $parameters, $this, $action);
4569 $this->stats_facturefournrec = $hookmanager->resArray[
'stats_facturefournrec'];
4574 $this->error = $this->db->error();
4593 $resql = $this->db->query($sql);
4595 $num = $this->db->num_rows($resql);
4598 $arr = $this->db->fetch_array($resql);
4599 if (is_array($arr)) {
4600 $keyfortab = (
string) $arr[1];
4602 $keyfortab = substr($keyfortab, -2);
4605 if ($mode ==
'byunit') {
4606 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[0];
4607 } elseif ($mode ==
'bynumber') {
4608 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4609 } elseif ($mode ==
'byamount') {
4610 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4619 $this->error = $this->db->error().
' sql='.$sql;
4626 } elseif ($year == -1) {
4635 for ($j = 0; $j < 12; $j++) {
4637 $idx = ucfirst(
dol_trunc(
dol_print_date(
dol_mktime(12, 0, 0, $month, 1, 1970),
"%b"), 1,
'right',
'UTF-8', 1));
4640 $result[$j] = array($idx, isset($tab[$year.$month]) ? $tab[$year.$month] : 0);
4643 $month =
"0".($month - 1);
4645 $month = substr($month, 1);
4655 return array_reverse($result);
4670 public function get_nb_vente($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4675 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4676 if ($mode ==
'bynumber') {
4677 $sql .=
", count(DISTINCT f.rowid)";
4679 $sql .=
", sum(d.total_ht) as total_ht";
4680 $sql .=
" FROM ".$this->db->prefix().
"facturedet as d, ".$this->db->prefix().
"facture as f, ".$this->db->prefix().
"societe as s";
4681 if ($filteronproducttype >= 0) {
4682 $sql .=
", ".$this->db->prefix().
"product as p";
4684 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4685 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4687 $sql .=
" WHERE f.rowid = d.fk_facture";
4688 if ($this->
id > 0) {
4689 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4691 $sql .=
" AND d.fk_product > 0";
4693 if ($filteronproducttype >= 0) {
4694 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4696 $sql .=
" AND f.fk_soc = s.rowid";
4697 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4698 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4699 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4702 $sql .=
" AND f.fk_soc = ".((int) $socid);
4704 $sql .= $morefilter;
4705 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4706 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4708 return $this->
_get_stats($sql, $mode, $year);
4723 public function get_nb_achat($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4728 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4729 if ($mode ==
'bynumber') {
4730 $sql .=
", count(DISTINCT f.rowid)";
4732 $sql .=
", sum(d.total_ht) as total_ht";
4733 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as d, ".$this->db->prefix().
"facture_fourn as f, ".$this->db->prefix().
"societe as s";
4734 if ($filteronproducttype >= 0) {
4735 $sql .=
", ".$this->db->prefix().
"product as p";
4737 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4738 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4740 $sql .=
" WHERE f.rowid = d.fk_facture_fourn";
4741 if ($this->
id > 0) {
4742 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4744 $sql .=
" AND d.fk_product > 0";
4746 if ($filteronproducttype >= 0) {
4747 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4749 $sql .=
" AND f.fk_soc = s.rowid";
4750 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4751 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4752 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4755 $sql .=
" AND f.fk_soc = ".((int) $socid);
4757 $sql .= $morefilter;
4758 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4759 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4761 return $this->
_get_stats($sql, $mode, $year);
4775 public function get_nb_propal($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4778 global $user, $hookmanager;
4780 $sql =
"SELECT sum(d.qty) as qty, date_format(p.datep, '%Y%m')";
4781 if ($mode ==
'bynumber') {
4782 $sql .=
", count(DISTINCT p.rowid)";
4784 $sql .=
", sum(d.total_ht) as total_ht";
4785 $sql .=
" FROM ".$this->db->prefix().
"propaldet as d, ".$this->db->prefix().
"propal as p, ".$this->db->prefix().
"societe as s";
4786 if ($filteronproducttype >= 0) {
4787 $sql .=
", ".$this->db->prefix().
"product as prod";
4789 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4790 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4792 $sql .=
" WHERE p.rowid = d.fk_propal";
4793 if ($this->
id > 0) {
4794 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4796 $sql .=
" AND d.fk_product > 0";
4798 if ($filteronproducttype >= 0) {
4799 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4801 $sql .=
" AND p.fk_soc = s.rowid";
4802 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
4803 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4804 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4807 $sql .=
" AND p.fk_soc = ".((int) $socid);
4809 $sql .= $morefilter;
4810 $parameters = array(
'socid' => $user->socid);
4811 $hookmanager->executeHooks(
'productGetNbPropal', $parameters, $this);
4812 $sql .= $hookmanager->resPrint;
4813 $sql .=
" GROUP BY date_format(p.datep,'%Y%m')";
4814 $sql .=
" ORDER BY date_format(p.datep,'%Y%m') DESC";
4815 return $this->
_get_stats($sql, $mode, $year);
4834 $sql =
"SELECT sum(d.qty) as qty, date_format(p.date_valid, '%Y%m')";
4835 if ($mode ==
'bynumber') {
4836 $sql .=
", count(DISTINCT p.rowid)";
4838 $sql .=
", sum(d.total_ht) as total_ht";
4839 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as d, ".$this->db->prefix().
"supplier_proposal as p, ".$this->db->prefix().
"societe as s";
4840 if ($filteronproducttype >= 0) {
4841 $sql .=
", ".$this->db->prefix().
"product as prod";
4843 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4844 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4846 $sql .=
" WHERE p.rowid = d.fk_supplier_proposal";
4847 if ($this->
id > 0) {
4848 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4850 $sql .=
" AND d.fk_product > 0";
4852 if ($filteronproducttype >= 0) {
4853 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4855 $sql .=
" AND p.fk_soc = s.rowid";
4856 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
4857 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4858 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4861 $sql .=
" AND p.fk_soc = ".((int) $socid);
4863 $sql .= $morefilter;
4864 $sql .=
" GROUP BY date_format(p.date_valid,'%Y%m')";
4865 $sql .=
" ORDER BY date_format(p.date_valid,'%Y%m') DESC";
4867 return $this->
_get_stats($sql, $mode, $year);
4881 public function get_nb_order($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4884 global $user, $hookmanager;
4886 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4887 if ($mode ==
'bynumber') {
4888 $sql .=
", count(DISTINCT c.rowid)";
4890 $sql .=
", sum(d.total_ht) as total_ht";
4891 $sql .=
" FROM ".$this->db->prefix().
"commandedet as d, ".$this->db->prefix().
"commande as c, ".$this->db->prefix().
"societe as s";
4892 if ($filteronproducttype >= 0) {
4893 $sql .=
", ".$this->db->prefix().
"product as p";
4895 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4896 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4898 $sql .=
" WHERE c.rowid = d.fk_commande";
4899 if ($this->
id > 0) {
4900 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4902 $sql .=
" AND d.fk_product > 0";
4904 if ($filteronproducttype >= 0) {
4905 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4907 $sql .=
" AND c.fk_soc = s.rowid";
4908 $sql .=
" AND c.entity IN (".getEntity(
'commande').
")";
4909 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4910 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4913 $sql .=
" AND c.fk_soc = ".((int) $socid);
4915 $sql .= $morefilter;
4916 $parameters = array(
'socid' => $user->socid);
4917 $hookmanager->executeHooks(
'productGetNbOrder', $parameters, $this);
4918 $sql .= $hookmanager->resPrint;
4919 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4920 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4922 return $this->
_get_stats($sql, $mode, $year);
4941 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4942 if ($mode ==
'bynumber') {
4943 $sql .=
", count(DISTINCT c.rowid)";
4945 $sql .=
", sum(d.total_ht) as total_ht";
4946 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as d, ".$this->db->prefix().
"commande_fournisseur as c, ".$this->db->prefix().
"societe as s";
4947 if ($filteronproducttype >= 0) {
4948 $sql .=
", ".$this->db->prefix().
"product as p";
4950 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4951 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4953 $sql .=
" WHERE c.rowid = d.fk_commande";
4954 if ($this->
id > 0) {
4955 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4957 $sql .=
" AND d.fk_product > 0";
4959 if ($filteronproducttype >= 0) {
4960 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4962 $sql .=
" AND c.fk_soc = s.rowid";
4963 $sql .=
" AND c.entity IN (".getEntity(
'supplier_order').
")";
4964 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4965 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4968 $sql .=
" AND c.fk_soc = ".((int) $socid);
4970 $sql .= $morefilter;
4971 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4972 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4974 return $this->
_get_stats($sql, $mode, $year);
4988 public function get_nb_contract($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4993 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_contrat, '%Y%m')";
4994 if ($mode ==
'bynumber') {
4995 $sql .=
", count(DISTINCT c.rowid)";
4997 $sql .=
", sum(d.total_ht) as total_ht";
4998 $sql .=
" FROM ".$this->db->prefix().
"contratdet as d, ".$this->db->prefix().
"contrat as c, ".$this->db->prefix().
"societe as s";
4999 if ($filteronproducttype >= 0) {
5000 $sql .=
", ".$this->db->prefix().
"product as p";
5002 if (!$user->hasRight(
'societe',
'client',
'voir')) {
5003 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
5005 $sql .=
" WHERE c.entity IN (".getEntity(
'contract').
")";
5006 $sql .=
" AND c.rowid = d.fk_contrat";
5008 if ($this->
id > 0) {
5009 $sql .=
" AND d.fk_product = ".((int) $this->
id);
5011 $sql .=
" AND d.fk_product > 0";
5013 if ($filteronproducttype >= 0) {
5014 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
5016 $sql .=
" AND c.fk_soc = s.rowid";
5018 if (!$user->hasRight(
'societe',
'client',
'voir')) {
5019 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
5022 $sql .=
" AND c.fk_soc = ".((int) $socid);
5024 $sql .= $morefilter;
5025 $sql .=
" GROUP BY date_format(c.date_contrat,'%Y%m')";
5026 $sql .=
" ORDER BY date_format(c.date_contrat,'%Y%m') DESC";
5028 return $this->
_get_stats($sql, $mode, $year);
5042 public function get_nb_mos($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
5047 $sql =
"SELECT sum(d.qty), date_format(d.date_valid, '%Y%m')";
5048 if ($mode ==
'bynumber') {
5049 $sql .=
", count(DISTINCT d.rowid)";
5051 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as d LEFT JOIN ".$this->db->prefix().
"societe as s ON d.fk_soc = s.rowid";
5052 if ($filteronproducttype >= 0) {
5053 $sql .=
", ".$this->db->prefix().
"product as p";
5055 if (!$user->hasRight(
'societe',
'client',
'voir')) {
5056 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
5059 $sql .=
" WHERE d.entity IN (".getEntity(
'mo').
")";
5060 $sql .=
" AND d.status > 0";
5062 if ($this->
id > 0) {
5063 $sql .=
" AND d.fk_product = ".((int) $this->
id);
5065 $sql .=
" AND d.fk_product > 0";
5067 if ($filteronproducttype >= 0) {
5068 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
5071 if (!$user->hasRight(
'societe',
'client',
'voir')) {
5072 $sql .=
" AND d.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
5075 $sql .=
" AND d.fk_soc = ".((int) $socid);
5077 $sql .= $morefilter;
5078 $sql .=
" GROUP BY date_format(d.date_valid,'%Y%m')";
5079 $sql .=
" ORDER BY date_format(d.date_valid,'%Y%m') DESC";
5081 return $this->
_get_stats($sql, $mode, $year);
5101 if (!is_numeric($id_pere)) {
5104 if (!is_numeric($id_fils)) {
5107 if (!is_numeric($incdec)) {
5117 $sql =
"SELECT fk_product_pere from ".$this->db->prefix().
"product_association";
5118 $sql .=
" WHERE fk_product_pere = ".((int) $id_fils).
" AND fk_product_fils = ".((int) $id_pere);
5119 if (!$this->db->query($sql)) {
5124 $sql =
"SELECT MAX(rang) as max_rank FROM ".$this->db->prefix().
"product_association";
5125 $sql .=
" WHERE fk_product_pere = ".((int) $id_pere);
5126 $resql = $this->db->query($sql);
5128 $obj = $this->db->fetch_object($resql);
5129 $rank = $obj->max_rank + 1;
5131 $sql =
"INSERT INTO ".$this->db->prefix().
"product_association(fk_product_pere,fk_product_fils,qty,incdec,rang)";
5132 $sql .=
" VALUES (".((int) $id_pere).
", ".((int) $id_fils).
", ".
price2num($qty,
'MS').
", ".((int) $incdec).
", ".((int) $rank).
")";
5133 if (! $this->db->query($sql)) {
5139 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_ADD', $user);
5141 $this->error = $this->db->lasterror();
5142 dol_syslog(get_class($this).
'::addSubproduct error='.$this->error, LOG_ERR);
5174 if (!is_numeric($id_pere)) {
5177 if (!is_numeric($id_fils)) {
5180 if (!is_numeric($incdec)) {
5183 if (!is_numeric($qty)) {
5187 $sql =
'UPDATE '.$this->db->prefix().
'product_association SET ';
5188 $sql .=
'qty = '.price2num($qty,
'MS');
5189 $sql .=
',incdec = '.((int) $incdec);
5190 $sql .=
' WHERE fk_product_pere = '.((int) $id_pere).
' AND fk_product_fils = '.((int) $id_fils);
5192 if (!$this->db->query($sql)) {
5198 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_UPDATE', $user);
5200 $this->error = $this->db->lasterror();
5201 dol_syslog(get_class($this).
'::updateSubproduct error='.$this->error, LOG_ERR);
5225 if (!is_numeric($fk_parent)) {
5228 if (!is_numeric($fk_child)) {
5232 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
5233 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5234 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
5236 dol_syslog(get_class($this).
'::del_sousproduit', LOG_DEBUG);
5237 if (!$this->db->query($sql)) {
5243 $sqlrank =
"SELECT rowid, rang FROM ".$this->db->prefix().
"product_association";
5244 $sqlrank .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5245 $sqlrank .=
" ORDER BY rang";
5246 $resqlrank = $this->db->query($sqlrank);
5249 while ($objrank = $this->db->fetch_object($resqlrank)) {
5251 $sql =
"UPDATE ".$this->db->prefix().
"product_association";
5252 $sql .=
" SET rang = ".((int) $cpt);
5253 $sql .=
" WHERE rowid = ".((int) $objrank->rowid);
5254 if (! $this->db->query($sql)) {
5263 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_DELETE', $user);
5265 $this->error = $this->db->lasterror();
5266 dol_syslog(get_class($this).
'::delSubproduct error='.$this->error, LOG_ERR);
5286 $sql =
"SELECT fk_product_pere, qty, incdec";
5287 $sql .=
" FROM ".$this->db->prefix().
"product_association";
5288 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5289 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
5291 $result = $this->db->query($sql);
5293 $num = $this->db->num_rows($result);
5296 $obj = $this->db->fetch_object($result);
5298 $this->is_sousproduit_qty = $obj->qty;
5299 $this->is_sousproduit_incdec = $obj->incdec;
5330 dol_syslog(get_class($this).
"::add_fournisseur id_fourn = ".$id_fourn.
" ref_fourn=".$ref_fourn.
" quantity=".$quantity, LOG_DEBUG);
5337 $sql =
"SELECT rowid, fk_product";
5338 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5339 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5340 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5341 $sql .=
" AND fk_product <> ".((int) $this->
id);
5342 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5344 $resql = $this->db->query($sql);
5346 $obj = $this->db->fetch_object($resql);
5349 $this->product_id_already_linked = $obj->fk_product;
5352 $this->db->free($resql);
5356 $sql =
"SELECT rowid";
5357 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5358 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5360 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5362 $sql .=
" AND (ref_fourn = '' OR ref_fourn IS NULL)";
5364 $sql .=
" AND quantity = ".((float) $quantity);
5365 $sql .=
" AND fk_product = ".((int) $this->
id);
5366 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5368 $resql = $this->db->query($sql);
5370 $obj = $this->db->fetch_object($resql);
5374 $sql =
"INSERT INTO ".$this->db->prefix().
"product_fournisseur_price(";
5377 $sql .=
", fk_product";
5379 $sql .=
", ref_fourn";
5380 $sql .=
", quantity";
5381 $sql .=
", fk_user";
5383 $sql .=
") VALUES (";
5384 $sql .=
"'".$this->db->idate($now).
"'";
5385 $sql .=
", ".((int)
$conf->entity);
5386 $sql .=
", ".((int) $this->
id);
5387 $sql .=
", ".((int) $id_fourn);
5388 $sql .=
", '".$this->db->escape($ref_fourn).
"'";
5389 $sql .=
", ".((float) $quantity);
5390 $sql .=
", ".((int) $user->id);
5394 if ($this->db->query($sql)) {
5395 $this->product_fourn_price_id = $this->db->last_insert_id($this->db->prefix().
"product_fournisseur_price");
5398 $this->error = $this->db->lasterror();
5403 $this->product_fourn_price_id = $obj->rowid;
5407 $this->error = $this->db->lasterror();
5426 $sql =
"SELECT DISTINCT p.fk_soc";
5427 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as p";
5428 $sql .=
" WHERE p.fk_product = ".((int) $this->
id);
5429 $sql .=
" AND p.entity = ".((int)
$conf->entity);
5431 $result = $this->db->query($sql);
5433 $num = $this->db->num_rows($result);
5436 $obj = $this->db->fetch_object($result);
5437 $list[$i] = $obj->fk_soc;
5463 $sql =
"INSERT INTO ".$this->db->prefix().
"product_price (";
5465 $sql .=
", fk_product";
5466 $sql .=
", date_price";
5467 $sql .=
", price_level";
5469 $sql .=
", price_ttc";
5470 $sql .=
", price_min";
5471 $sql .=
", price_min_ttc";
5472 $sql .=
", price_base_type";
5473 $sql .=
", price_label";
5474 $sql .=
", default_vat_code";
5476 $sql .=
", recuperableonly";
5477 $sql .=
", localtax1_tx";
5478 $sql .=
", localtax1_type";
5479 $sql .=
", localtax2_tx";
5480 $sql .=
", localtax2_type";
5481 $sql .=
", fk_user_author";
5483 $sql .=
", price_by_qty";
5484 $sql .=
", fk_price_expression";
5485 $sql .=
", fk_multicurrency";
5486 $sql .=
", multicurrency_code";
5487 $sql .=
", multicurrency_tx";
5488 $sql .=
", multicurrency_price";
5489 $sql .=
", multicurrency_price_ttc";
5493 $sql .=
", ".((int) $toId);
5494 $sql .=
", '".$this->db->idate($now).
"'";
5495 $sql .=
", price_level";
5497 $sql .=
", price_ttc";
5498 $sql .=
", price_min";
5499 $sql .=
", price_min_ttc";
5500 $sql .=
", price_base_type";
5501 $sql .=
", price_label";
5502 $sql .=
", default_vat_code";
5504 $sql .=
", recuperableonly";
5505 $sql .=
", localtax1_tx";
5506 $sql .=
", localtax1_type";
5507 $sql .=
", localtax2_tx";
5508 $sql .=
", localtax2_type";
5509 $sql .=
", ".((int) $user->id);
5511 $sql .=
", price_by_qty";
5512 $sql .=
", fk_price_expression";
5513 $sql .=
", fk_multicurrency";
5514 $sql .=
", multicurrency_code";
5515 $sql .=
", multicurrency_tx";
5516 $sql .=
", multicurrency_price";
5517 $sql .=
", multicurrency_price_ttc";
5518 $sql .=
" FROM ".$this->db->prefix().
"product_price ps";
5519 $sql .=
" WHERE fk_product = ".((int) $fromId);
5520 $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)";
5521 $sql .=
" ORDER BY date_price DESC";
5524 $resql = $this->db->query($sql);
5526 $this->db->rollback();
5530 $this->db->commit();
5547 $sql =
'INSERT INTO '.$this->db->prefix().
'product_association (fk_product_pere, fk_product_fils, qty, incdec)';
5548 $sql .=
" SELECT ".((int) $toId).
", fk_product_fils, qty, incdec FROM ".$this->db->prefix().
"product_association";
5549 $sql .=
" WHERE fk_product_pere = ".((int) $fromId);
5551 dol_syslog(get_class($this).
'::clone_association', LOG_DEBUG);
5552 if (!$this->db->query($sql)) {
5553 $this->db->rollback();
5557 $this->db->commit();
5590 $sql =
"INSERT ".$this->db->prefix().
"product_fournisseur_price (";
5591 $sql .=
" datec, fk_product, fk_soc, price, quantity, fk_user, tva_tx)";
5592 $sql .=
" SELECT '".$this->db->idate($now).
"', ".((int) $toId).
", fk_soc, price, quantity, fk_user, tva_tx";
5593 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5594 $sql .=
" WHERE fk_product = ".((int) $fromId);
5596 dol_syslog(get_class($this).
'::clone_fournisseurs', LOG_DEBUG);
5597 $resql = $this->db->query($sql);
5599 $this->db->rollback();
5602 $this->db->commit();
5620 public function fetch_prod_arbo(
$prod, $compl_path =
'', $multiply = 1, $level = 1, $id_parent = 0, $ignore_stock_load = 0)
5625 if ($multiply < 1) {
5626 dol_syslog(get_class($this).
'::'.__FUNCTION__.
' Product quantity rounded up to 1 from '.$multiply.
'. May result in unexpected end quantity for product children of '.$id_parent, LOG_WARNING);
5631 foreach (
$prod as $id_product => $desc_pere) {
5632 if (is_array($desc_pere)) {
5633 $id = (!empty($desc_pere[0]) ? $desc_pere[0] :
'');
5634 $nb = (!empty($desc_pere[1]) ? $desc_pere[1] :
'');
5635 $type = (!empty($desc_pere[2]) ? $desc_pere[2] :
'');
5636 $label = (!empty($desc_pere[3]) ? $desc_pere[3] :
'');
5637 $incdec = (!empty($desc_pere[4]) ? $desc_pere[4] : 0);
5640 if (is_null($tmpproduct)) {
5641 $tmpproduct =
new Product($this->db);
5643 $tmpproduct->fetch($id);
5645 if (empty($ignore_stock_load) && ($tmpproduct->isProduct() ||
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES'))) {
5646 $tmpproduct->load_stock(
'nobatch,novirtual');
5649 $this->res[] = array(
5651 'id_parent' => $id_parent,
5652 'ref' => $tmpproduct->ref,
5654 'nb_total' => $nb * $multiply,
5655 'stock' => $tmpproduct->stock_reel,
5656 'stock_alert' => $tmpproduct->seuil_stock_alerte,
5658 'fullpath' => $compl_path.$label,
5660 'desiredstock' => $tmpproduct->desiredstock,
5662 'incdec' => $incdec,
5663 'entity' => $tmpproduct->entity
5667 if (isset($desc_pere[
'childs']) && is_array($desc_pere[
'childs'])) {
5668 if (!is_int($desc_pere[1] * $multiply)) {
5669 dol_syslog(get_class($this).
'::'.__FUNCTION__.
' Source product quantity and multiplier may result in unexpected end quantity for '.$label.
'/'.$multiply.
' Child product:'.json_encode($desc_pere), LOG_WARNING);
5673 $this->
fetch_prod_arbo($desc_pere[
'childs'], $compl_path.$desc_pere[3].
" -> ", (
int) ceil($desc_pere[1] * $multiply), $level + 1, $id, $ignore_stock_load);
5691 $this->res = array();
5692 if (isset($this->sousprods) && is_array($this->sousprods)) {
5693 foreach ($this->sousprods as $prod_name => $desc_product) {
5694 if (is_array($desc_product)) {
5695 $this->
fetch_prod_arbo($desc_product,
"", $multiply, 1, $this->
id, $ignore_stock_load);
5714 $sql =
"SELECT COUNT(pa.rowid) as nb";
5715 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa";
5717 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id).
" OR pa.fk_product_pere = ".((int) $this->
id);
5718 } elseif ($mode == -1) {
5719 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id);
5720 } elseif ($mode == 1) {
5721 $sql .=
" WHERE pa.fk_product_pere = ".((int) $this->
id);
5724 $resql = $this->db->query($sql);
5726 $obj = $this->db->fetch_object($resql);
5728 $nb = (int) $obj->nb;
5748 $sql =
"SELECT count(rowid) as nb FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_parent = ".((int) $this->
id);
5749 $sql .=
" AND entity IN (".getEntity(
'product').
")";
5751 $resql = $this->db->query($sql);
5753 $obj = $this->db->fetch_object($resql);
5755 $nb = (int) $obj->nb;
5771 $sql =
"SELECT rowid FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_child = ".((int) $this->
id).
" AND entity IN (".
getEntity(
'product').
")";
5773 $query = $this->db->query($sql);
5776 if (!$this->db->num_rows($query)) {
5797 $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";
5798 $sql .=
", p.tosell as status, p.tobuy as status_buy";
5799 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa,";
5800 $sql .=
" ".$this->db->prefix().
"product as p";
5801 $sql .=
" WHERE p.rowid = pa.fk_product_pere";
5802 $sql .=
" AND pa.fk_product_fils = ".((int) $this->
id);
5804 $res = $this->db->query($sql);
5807 while ($record = $this->db->fetch_array($res)) {
5809 $prods[$record[
'id']] = array();
5810 $prods[$record[
'id']][
'id'] = $record[
'rowid'];
5811 $prods[$record[
'id']][
'ref'] = $record[
'ref'];
5812 $prods[$record[
'id']][
'label'] = $record[
'label'];
5813 $prods[$record[
'id']][
'qty'] = $record[
'qty'];
5814 $prods[$record[
'id']][
'incdec'] = $record[
'incdec'];
5815 $prods[$record[
'id']][
'fk_product_type'] = $record[
'fk_product_type'];
5816 $prods[$record[
'id']][
'entity'] = $record[
'entity'];
5817 $prods[$record[
'id']][
'status'] = $record[
'status'];
5818 $prods[$record[
'id']][
'status_buy'] = $record[
'status_buy'];
5837 public function getChildsArbo($id, $firstlevelonly = 0, $level = 1, $parents = array())
5843 $sql =
"SELECT p.rowid, p.ref, p.label as label, p.fk_product_type,";
5844 $sql .=
" pa.qty as qty, pa.fk_product_fils as id, pa.incdec,";
5845 $sql .=
" pa.rowid as fk_association, pa.rang";
5846 $sql .=
" FROM ".$this->db->prefix().
"product as p,";
5847 $sql .=
" ".$this->db->prefix().
"product_association as pa";
5848 $sql .=
" WHERE p.rowid = pa.fk_product_fils";
5849 $sql .=
" AND pa.fk_product_pere = ".((int) $id);
5850 $sql .=
" AND pa.fk_product_fils <> ".((int) $id);
5851 $sql .=
" ORDER BY pa.rang";
5853 dol_syslog(get_class($this).
'::getChildsArbo id='.$id.
' level='.$level.
' parents='.(is_array($parents) ? implode(
',', $parents) : $parents), LOG_DEBUG);
5860 $res = $this->db->query($sql);
5863 if ($this->db->num_rows($res) > 0) {
5867 while ($rec = $this->db->fetch_array($res)) {
5868 if (in_array($rec[
'id'], $parents)) {
5869 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);
5873 $prods[$rec[
'rowid']] = array(
5876 2 => $rec[
'fk_product_type'],
5877 3 => $this->db->escape($rec[
'label']),
5878 4 => $rec[
'incdec'],
5880 6 => $rec[
'fk_association'],
5885 if (empty($firstlevelonly)) {
5886 $listofchilds = $this->
getChildsArbo($rec[
'rowid'], 0, $level + 1, $parents);
5887 foreach ($listofchilds as $keyChild => $valueChild) {
5888 $prods[$rec[
'rowid']][
'childs'][$keyChild] = $valueChild;
5912 foreach ($this->
getChildsArbo($this->
id) as $keyChild => $valueChild) {
5913 $parent[$this->label][$keyChild] = $valueChild;
5915 foreach ($parent as $key => $value) {
5916 $this->sousprods[$key] = $value;
5929 global
$conf, $langs, $user;
5931 $langs->loadLangs(array(
'products',
'other'));
5934 $nofetch = !empty($params[
'nofetch']);
5937 return [
'optimize' => $langs->trans(
"ShowProduct")];
5941 $permissiontoreadproduct = 0;
5942 if ($this->
type == self::TYPE_PRODUCT && $user->hasRight(
'product',
'read')) {
5943 $permissiontoreadproduct = 1;
5945 if ($this->
type == self::TYPE_SERVICE && $user->hasRight(
'service',
'read')) {
5946 $permissiontoreadproduct = 1;
5949 if (!empty($this->entity) && $permissiontoreadproduct) {
5950 $tmpphoto = $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 80, 0, 0, 0, 0,
'1');
5951 if ($this->nbphoto > 0) {
5952 $datas[
'photo'] =
'<div class="photointooltip floatright">'.
"\n" . $tmpphoto .
'</div>';
5957 $datas[
'picto'] =
img_picto(
'',
'product').
' <u class="paddingrightonly">'.$langs->trans(
"Product").
'</u>';
5959 $datas[
'picto'] =
img_picto(
'',
'service').
' <u class="paddingrightonly">'.$langs->trans(
"Service").
'</u>';
5961 if (isset($this->
status) && isset($this->status_buy)) {
5962 $datas[
'status'] =
' '.$this->getLibStatut(5, 0) .
' '.$this->getLibStatut(5, 1);
5965 if (!empty($this->
ref)) {
5966 $datas[
'ref'] =
'<br><b>'.$langs->trans(
'ProductRef').
':</b> '.$this->ref;
5968 if (!empty($this->label)) {
5969 $datas[
'label'] =
'<br><b>'.$langs->trans(
'ProductLabel').
':</b> '.$this->label.
'<br>';
5972 if ($permissiontoreadproduct) {
5977 $datas[
'stockmanaged'] =
"<br><b>".$langs->trans(
"StockableProduct").
'</b>: '.
yn($this->
isStockManaged());
5981 $langs->load(
"productbatch");
5982 $datas[
'batchstatus'] =
"<br><b>".$langs->trans(
"ManageLotSerial").
'</b>: '.$this->
getLibStatut(0, 2);
5983 if ($this->status_batch) {
5984 $datas[
'batchdlc'] =
"<br><b>".$langs->trans(
"BatchSellOrEatByMandatoryList", $langs->transnoentitiesnoconv(
"SellByDate"), $langs->transnoentitiesnoconv(
"EatByDate")).
'</b>: '.$this->
getSellOrEatByMandatoryLabel();
5989 $datas[
'barcode'] =
'<br><b>'.$langs->trans(
'BarCode').
':</b> '.$this->barcode;
5993 if ($this->weight) {
5994 $datas[
'weight'] =
"<br><b>".$langs->trans(
"Weight").
'</b>: '.$this->weight.
' '.
measuringUnitString(0,
"weight", $this->weight_units);
5997 if ($this->length) {
5998 $labelsize .=
"<b>".$langs->trans(
"Length").
'</b>: '.$this->length.
' '.
measuringUnitString(0,
'size', $this->length_units);
6001 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Width").
'</b>: '.$this->width.
' '.
measuringUnitString(0,
'size', $this->width_units);
6003 if ($this->height) {
6004 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Height").
'</b>: '.$this->height.
' '.
measuringUnitString(0,
'size', $this->height_units);
6007 $datas[
'size'] =
"<br>".$labelsize;
6010 $labelsurfacevolume =
"";
6011 if ($this->surface) {
6012 $labelsurfacevolume .=
"<b>".$langs->trans(
"Surface").
'</b>: '.$this->surface.
' '.
measuringUnitString(0,
'surface', $this->surface_units);
6014 if ($this->volume) {
6015 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Volume").
'</b>: '.$this->volume.
' '.
measuringUnitString(0,
'volume', $this->volume_units);
6017 if ($labelsurfacevolume) {
6018 $datas[
'surface'] =
"<br>" . $labelsurfacevolume;
6021 if ($this->
isService() && !empty($this->duration_value)) {
6023 $datas[
'duration'] =
'<br><b>'.$langs->trans(
"Duration").
':</b> '.$this->duration_value;
6024 if ($this->duration_value > 1) {
6025 $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"));
6026 } elseif ($this->duration_value > 0) {
6027 $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"));
6029 $datas[
'duration'] .= (!empty($this->duration_unit) && isset($dur[$this->duration_unit]) ?
" ".$langs->trans($dur[$this->duration_unit]) :
'');
6031 if (empty($user->socid)) {
6032 if ($this->
isStockManaged() && isset($this->pmp) && $this->pmp) {
6033 $datas[
'pmp'] =
"<br><b>".$langs->trans(
"PMPValue").
'</b>: '.
price($this->pmp, 0,
'', 1, -1, -1,
$conf->currency);
6037 if ($this->
status && isset($this->accountancy_code_sell)) {
6038 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
6039 $selllabel =
'<br>';
6040 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellCode').
':</b> '.
length_accountg($this->accountancy_code_sell);
6041 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellIntraCode').
':</b> '.
length_accountg($this->accountancy_code_sell_intra);
6042 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellExportCode').
':</b> '.
length_accountg($this->accountancy_code_sell_export);
6043 $datas[
'accountancysell'] = $selllabel;
6045 if ($this->status_buy && isset($this->accountancy_code_buy)) {
6046 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
6048 if (empty($this->
status)) {
6049 $buylabel .=
'<br>';
6051 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyCode').
':</b> '.
length_accountg($this->accountancy_code_buy);
6052 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyIntraCode').
':</b> '.
length_accountg($this->accountancy_code_buy_intra);
6053 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyExportCode').
':</b> '.
length_accountg($this->accountancy_code_buy_export);
6054 $datas[
'accountancybuy'] = $buylabel;
6060 require_once DOL_DOCUMENT_ROOT .
'/categories/class/categorie.class.php';
6061 $form =
new Form($this->db);
6062 $datas[
'categories'] =
'<br>' . $form->showCategories($this->
id, Categorie::TYPE_PRODUCT, 1);
6082 public function getNomUrl($withpicto = 0, $option =
'', $maxlength = 0, $save_lastsearch_value = -1, $notooltip = 0, $morecss =
'', $add_label = 0, $sep =
' - ')
6084 global $langs, $hookmanager;
6086 include_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
6092 $newref =
dol_trunc($newref, $maxlength,
'middle');
6096 'objecttype' => ($this->
type == 1 ?
'service' :
'product'),
6097 'option' => $option,
6100 $classfortooltip =
'classfortooltip';
6103 $classfortooltip =
'classforajaxtooltip';
6104 $dataparams =
' data-params="'.dol_escape_htmltag(json_encode($params)).
'"';
6111 if (empty($notooltip)) {
6113 $label = $langs->trans(
"ShowProduct");
6114 $linkclose .=
' alt="'.dol_escape_htmltag($label, 1, 1).
'"';
6116 $linkclose .= ($label ?
' title="'.dol_escape_htmltag($label, 1, 1).
'"' :
' title="tocomplete"');
6117 $linkclose .= $dataparams.
' class="nowraponall '.$classfortooltip.($morecss ?
' '.$morecss :
'').
'"';
6119 $linkclose =
' class="nowraponall'.($morecss ?
' '.$morecss :
'').
'"';
6122 if ($option ==
'supplier' || $option ==
'category') {
6123 $url = DOL_URL_ROOT.
'/product/price_suppliers.php?id='.$this->id;
6124 } elseif ($option ==
'stock') {
6125 $url = DOL_URL_ROOT.
'/product/stock/product.php?id='.$this->id;
6126 } elseif ($option ==
'composition') {
6127 $url = DOL_URL_ROOT.
'/product/composition/card.php?id='.$this->id;
6129 $url = DOL_URL_ROOT.
'/product/card.php?id='.$this->id;
6132 if ($option !==
'nolink') {
6134 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
6135 if ($save_lastsearch_value == -1 && isset($_SERVER[
"PHP_SELF"]) && preg_match(
'/list\.php/', $_SERVER[
"PHP_SELF"])) {
6136 $add_save_lastsearch_values = 1;
6138 if ($add_save_lastsearch_values) {
6139 $url .=
'&save_lastsearch_values=1';
6143 $linkstart =
'<a href="'.$url.
'"';
6144 $linkstart .= $linkclose.
'>';
6147 $result .= $linkstart;
6150 $result .= (
img_object(($notooltip ?
'' : $label),
'product',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
6153 $result .= (
img_object(($notooltip ?
'' : $label),
'service',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
6156 $result .=
'<span class="aaa">'.dol_escape_htmltag($newref).
'</span>';
6157 $result .= $linkend;
6158 if ($withpicto != 2) {
6159 $result .= (($add_label && $this->label) ? $sep.dol_trunc($this->label, ($add_label > 1 ? $add_label : 0)) :
'');
6163 $hookmanager->initHooks(array(
'productdao'));
6164 $parameters = array(
'id' => $this->
id,
'getnomurl' => &$result,
'label' => &$label);
6165 $reshook = $hookmanager->executeHooks(
'getNomUrl', $parameters, $this, $action);
6167 $result = $hookmanager->resPrint;
6169 $result .= $hookmanager->resPrint;
6186 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
6190 $langs->load(
"products");
6191 $outputlangs->load(
"products");
6196 if (!empty($this->model_pdf)) {
6197 $modele = $this->model_pdf;
6203 if (empty($modele)) {
6206 $modelpath =
"core/modules/product/doc/";
6207 return $this->
commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
6224 return $this->
LibStatut($this->status_buy, $mode, $type);
6226 return $this->
LibStatut($this->status_batch, $mode, $type);
6229 return $this->
LibStatut($this->status_buy, $mode, $type);
6247 $labelStatus = $labelStatusShort =
'';
6249 $langs->load(
'products');
6251 $langs->load(
"productbatch");
6257 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial')));
6260 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort')));
6265 return dolGetStatus($langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch'),
'',
'', empty($status) ?
'status5' :
'status4', 3,
'dot');
6271 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'));
6275 $statuttrans = empty($status) ?
'status5' :
'status4';
6280 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSellShort');
6281 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSell');
6282 } elseif ($type == 1) {
6283 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuyShort');
6284 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuy');
6285 } elseif ($type == 2) {
6286 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch');
6287 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort');
6289 } elseif ($status == 1) {
6292 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSellShort');
6293 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSell');
6294 } elseif ($type == 1) {
6295 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBuyShort');
6296 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBuy');
6297 } elseif ($type == 2) {
6298 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBatch');
6299 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort');
6301 } elseif ($type == 2 && $status == 2) {
6302 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSerial');
6303 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort');
6307 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'),
'',
'',
'status0', 0);
6309 return dolGetStatus($labelStatus, $labelStatusShort,
'', $statuttrans, $mode);
6323 $langs->load(
'products');
6326 if (isset($this->finished) && $this->finished >= 0) {
6327 $sql =
"SELECT label, code FROM ".$this->db->prefix().
"c_product_nature where code = ".((int) $this->finished).
" AND active=1";
6328 $resql = $this->db->query($sql);
6330 $this->error = $this->db->error().
' sql='.$sql;
6331 dol_syslog(__METHOD__.
' Error '.$this->error, LOG_ERR);
6333 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
6334 $label = $langs->trans($res[
'label']);
6336 $this->db->free($resql);
6360 public function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label =
'', $price = 0, $inventorycode =
'', $origin_element =
'', $origin_id =
null, $disablestockchangeforsubproduct = 0, $extrafields =
null)
6366 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6369 $nbpiece = (float) $nbpiece;
6374 $nbpiece = abs($nbpiece);
6381 $movementstock->setOrigin($origin_element, (
int) $origin_id);
6382 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'',
'',
'',
'',
false, 0, $disablestockchangeforsubproduct);
6386 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6387 $movementstock->array_options = $array_options;
6388 $movementstock->insertExtraFields();
6390 $this->db->commit();
6395 $this->db->rollback();
6424 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)
6430 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6433 $nbpiece = (float) $nbpiece;
6438 $nbpiece = abs($nbpiece);
6446 $movementstock->setOrigin($origin_element, (
int) $origin_id);
6447 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'', $dlc, $dluo, $lot,
false, 0, $disablestockchangeforsubproduct, 0, $force_update_batch);
6451 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6452 $movementstock->array_options = $array_options;
6453 $movementstock->insertExtraFields();
6455 $this->db->commit();
6458 $this->error = $movementstock->error;
6459 $this->errors = $movementstock->errors;
6461 $this->db->rollback();
6481 public function load_stock($option =
'', $includedraftpoforvirtual =
null, $dateofvirtualstock =
null)
6484 $this->stock_reel = 0;
6485 $this->stock_warehouse = array();
6486 $this->stock_theorique = 0;
6489 $warehouseStatus = array();
6490 if (preg_match(
'/warehouseclosed/', $option)) {
6493 if (preg_match(
'/warehouseopen/', $option)) {
6496 if (preg_match(
'/warehouseinternal/', $option)) {
6504 $sql =
"SELECT ps.rowid, ps.reel, ps.fk_entrepot";
6505 $sql .=
" FROM ".$this->db->prefix().
"product_stock as ps";
6506 $sql .=
", ".$this->db->prefix().
"entrepot as w";
6507 $sql .=
" WHERE w.entity IN (".getEntity(
'stock').
")";
6508 $sql .=
" AND w.rowid = ps.fk_entrepot";
6509 $sql .=
" AND ps.fk_product = ".((int) $this->
id);
6510 if (count($warehouseStatus)) {
6511 $sql .=
" AND w.statut IN (".$this->db->sanitize(implode(
',', $warehouseStatus)).
")";
6514 $sql .=
" ORDER BY ps.reel ".(getDolGlobalString(
'DO_NOT_TRY_TO_DEFRAGMENT_STOCKS_WAREHOUSE') ?
'DESC' :
'ASC');
6516 dol_syslog(get_class($this).
"::load_stock", LOG_DEBUG);
6517 $result = $this->db->query($sql);
6519 $num = $this->db->num_rows($result);
6523 $row = $this->db->fetch_object($result);
6524 $this->stock_warehouse[$row->fk_entrepot] =
new stdClass();
6525 $this->stock_warehouse[$row->fk_entrepot]->real = $row->reel;
6526 $this->stock_warehouse[$row->fk_entrepot]->id = $row->rowid;
6527 if ((!preg_match(
'/nobatch/', $option)) && $this->
hasbatch()) {
6528 $this->stock_warehouse[$row->fk_entrepot]->detail_batch =
Productbatch::findAll($this->db, $row->rowid, 1, $this->id);
6530 $this->stock_reel += $row->reel;
6533 $this->stock_reel = (float)
price2num($this->stock_reel,
'MS');
6535 $this->db->free($result);
6537 if (!preg_match(
'/novirtual/', $option)) {
6543 $this->error = $this->db->lasterror();
6562 global $hookmanager, $action;
6564 $stock_commande_client = 0;
6565 $stock_commande_fournisseur = 0;
6566 $stock_sending_client = 0;
6567 $stock_reception_fournisseur = 0;
6568 $stock_inproduction = 0;
6577 $stock_commande_client = $this->stats_commande[
'qty'];
6580 require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expedition.class.php';
6581 $filterShipmentStatus =
'';
6591 $stock_sending_client = $this->stats_expedition[
'qty'];
6595 $filterStatus =
getDolGlobalString(
'SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK',
'3,4');
6596 if (isset($includedraftpoforvirtual)) {
6597 $filterStatus =
'0,1,2,'.$filterStatus;
6603 $stock_commande_fournisseur = $this->stats_commande_fournisseur[
'qty'];
6607 $filterStatus =
'4';
6608 if (isset($includedraftpoforvirtual)) {
6609 $filterStatus =
'0,'.$filterStatus;
6615 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
6623 $stock_inproduction = $this->stats_mrptoproduce[
'qty'] - $this->stats_mrptoconsume[
'qty'];
6626 $this->stock_theorique = $this->stock_reel + $stock_inproduction;
6630 $weBillOrderOrShipmentReception =
getDolGlobalString(
'STOCK_DO_WE_BILL_ORDER_OR_SHIPMENTECEPTION_FOR_VIRTUALSTOCK',
'order');
6634 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6638 $result = $tmpnewprod->load_stats_commande(0,
'0', 1);
6639 $this->stock_theorique += $tmpnewprod->stats_commande[
'qty'];
6641 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6642 $this->stock_theorique -= $stock_commande_client;
6643 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6644 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6649 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6651 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6653 if (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER_INCLUDE_DRAFT')) {
6655 $result = $tmpnewprod->load_stats_commande_fournisseur(0,
'0', 1);
6656 $this->stock_theorique += $this->stats_commande_fournisseur[
'qty'];
6658 $this->stock_theorique -= $stock_reception_fournisseur;
6659 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6660 $this->stock_theorique += $stock_commande_fournisseur;
6661 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6662 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6665 $parameters = array(
'id' => $this->
id,
'includedraftpoforvirtual' => $includedraftpoforvirtual);
6667 $reshook = $hookmanager->executeHooks(
'loadvirtualstock', $parameters, $this, $action);
6669 $this->stock_theorique = $hookmanager->resArray[
'stock_theorique'];
6670 } elseif ($reshook == 0 && isset($hookmanager->resArray[
'stock_stats_hook'])) {
6671 $this->stock_theorique += $hookmanager->resArray[
'stock_stats_hook'];
6675 if (!empty($this->stock_warehouse) &&
getDolGlobalString(
'STOCK_ALLOW_VIRTUAL_STOCK_PER_WAREHOUSE')) {
6676 foreach ($this->stock_warehouse as $warehouseid => $stockwarehouse) {
6684 if ($this->fk_default_warehouse == $warehouseid) {
6685 $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']);
6687 $this->stock_warehouse[$warehouseid]->virtual = $this->stock_warehouse[$warehouseid]->real + $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'];
6704 $this->stock_warehouse = array();
6709 if (count($prods_arbo) > 0) {
6710 $productCachedList = array();
6711 $stockByComponentList = array();
6713 foreach ($prods_arbo as $componentArr) {
6714 $componentId = $componentArr[
'id'];
6716 if ($componentArr[
'incdec'] == 1) {
6717 if (!isset($productCachedList[$componentId])) {
6718 $componentStatic =
new self($this->db);
6719 $componentStatic->fetch($componentId);
6721 $childrenNb = $componentStatic->hasFatherOrChild(1);
6722 if ($childrenNb == 0) {
6723 $componentStatic->load_stock(
'nobatch,novirtual');
6724 if (!isset($stockByComponentList[$componentId])) {
6725 $stockByComponentList[$componentId] = array(
6729 $stockByComponentList[$componentId][
'qty_need'] += $componentArr[
'nb_total'];
6731 $productCachedList[$componentId] = $componentStatic;
6736 if (!empty($stockByComponentList)) {
6737 foreach ($stockByComponentList as $componentId => $stockByComponentArr) {
6738 if (!isset($productCachedList[$componentId])) {
6739 $componentStatic =
new self($this->db);
6740 $componentStatic->fetch($componentId);
6741 $componentStatic->load_stock(
'nobatch,novirtual');
6742 $productCachedList[$componentId] = $componentStatic;
6744 $component = $productCachedList[$componentId];
6747 if ($component->stock_reel < $stockByComponentArr[
'qty_need']) {
6750 $this->error =
'Not enough component [id='.$componentId.
'] in stock, real='.$component->stock_reel.
' and need='.$stockByComponentArr[
'qty_need'];
6751 $this->errors[] = $this->error;
6752 dol_syslog(__METHOD__.
' : '.$this->error, LOG_ERR);
6754 if (!empty($component->stock_warehouse)) {
6755 foreach ($component->stock_warehouse as $warehouseId => $warehouseObj) {
6756 $kitWarehouseAvailable =
new stdClass();
6757 $kitWarehouseAvailable->id = $warehouseObj->id;
6758 $kitWarehouseAvailable->real = $qtyWish;
6759 $this->stock_warehouse[$warehouseId] = $kitWarehouseAvailable;
6768 } elseif (
getDolGlobalInt(
'PRODUIT_SOUSPRODUITS_ALSO_ENABLE_PARENT_STOCK_MOVE') && empty($productCachedList)) {
6792 $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";
6793 $sql .=
" WHERE pb.fk_product_stock = ps.rowid AND ps.fk_product = ".((int) $this->
id).
" AND pb.batch = '".$this->db->escape($batch).
"'";
6794 $sql .=
" GROUP BY pb.batch, pb.eatby, pb.sellby";
6795 dol_syslog(get_class($this).
"::loadBatchInfo load first entry found for lot/serial = ".$batch, LOG_DEBUG);
6796 $resql = $this->db->query($sql);
6798 $num = $this->db->num_rows($resql);
6801 $obj = $this->db->fetch_object($resql);
6802 $result[] = array(
'batch' => $batch,
'eatby' => $this->db->jdate($obj->eatby),
'sellby' => $this->db->jdate($obj->sellby),
'qty' => $obj->qty);
6808 $this->db->rollback();
6825 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6831 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos";
6833 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product').dol_sanitizeFileName($this->
ref);
6838 $dir_osencoded = $dir;
6840 if (is_dir($dir_osencoded)) {
6841 $originImage = $dir.
'/'.$file[
'name'];
6852 if (is_numeric($result) && $result > 0) {
6869 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6870 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6874 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos/";
6876 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product');
6880 if (file_exists($dir_osencoded)) {
6881 $handle = opendir($dir_osencoded);
6882 if (is_resource($handle)) {
6883 while (($file = readdir($handle)) !==
false) {
6885 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6908 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6909 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6915 $handle = @opendir($dir_osencoded);
6916 if (is_resource($handle)) {
6917 while (($file = readdir($handle)) !==
false) {
6919 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6926 $photo_vignette =
'';
6928 if (preg_match(
'/('.$this->regeximgext.
')$/i', $photo, $regs)) {
6929 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $photo).
'_small'.$regs[0];
6932 $dirthumb = $dir.
'thumbs/';
6936 $obj[
'photo'] = $photo;
6937 if ($photo_vignette &&
dol_is_file($dirthumb.$photo_vignette)) {
6938 $obj[
'photo_vignette'] =
'thumbs/'.$photo_vignette;
6940 $obj[
'photo_vignette'] =
"";
6943 $tabobj[$nbphoto - 1] = $obj;
6946 if ($nbmax && $nbphoto >= $nbmax) {
6968 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6969 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6971 $dir = dirname($file).
'/';
6972 $dirthumb = $dir.
'/thumbs/';
6973 $filename = preg_replace(
'/'.preg_quote($dir,
'/').
'/i',
'', $file);
6979 if (preg_match(
'/('.$this->regeximgext.
')$/i', $filename, $regs)) {
6980 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_small'.$regs[0];
6981 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6985 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_mini'.$regs[0];
6986 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
7003 $infoImg = getimagesize($file_osencoded);
7004 $this->imgWidth = $infoImg[0];
7005 $this->imgHeight = $infoImg[1];
7015 global $hookmanager;
7017 $this->nb = array();
7019 $sql =
"SELECT count(p.rowid) as nb, fk_product_type";
7020 $sql .=
" FROM ".$this->db->prefix().
"product as p";
7021 $sql .=
' WHERE p.entity IN ('.getEntity($this->element, 1).
')';
7023 if (is_object($hookmanager)) {
7024 $parameters = array();
7025 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
7026 $sql .= $hookmanager->resPrint;
7028 $sql .=
' GROUP BY fk_product_type';
7030 $resql = $this->db->query($sql);
7032 while ($obj = $this->db->fetch_object($resql)) {
7033 if ($obj->fk_product_type == 1) {
7034 $this->nb[
"services"] = $obj->nb;
7036 $this->nb[
"products"] = $obj->nb;
7039 $this->db->free($resql);
7043 $this->error = $this->db->error();
7085 return $this->mandatory_period == 1;
7095 return $this->status_batch > 0;
7115 $dirsociete = array_merge(array(
'/core/modules/barcode/'),
$conf->modules_parts[
'barcode']);
7116 foreach ($dirsociete as $dirroot) {
7124 '@phan-var-force ModeleNumRefBarCode $mod';
7126 $result = $mod->getNextValue(
$object, $type);
7128 dol_syslog(get_class($this).
"::get_barcode barcode=".$result.
" module=".$var);
7145 $this->specimen = 1;
7147 $this->
ref =
'PRODUCT_SPEC';
7148 $this->label =
'PRODUCT SPECIMEN';
7149 $this->
description =
'This is description of this product specimen that was created the '.dol_print_date($now,
'dayhourlog').
'.';
7150 $this->specimen = 1;
7151 $this->country_id = 1;
7153 $this->status_buy = 1;
7155 $this->sell_or_eat_by_mandatory = 0;
7156 $this->note_private =
'This is a comment (private)';
7157 $this->note_public =
'This is a comment (public)';
7158 $this->date_creation = $now;
7159 $this->date_modification = $now;
7162 $this->weight_units = 3;
7165 $this->length_units = 1;
7167 $this->width_units = 0;
7168 $this->height =
null;
7169 $this->height_units =
null;
7171 $this->surface = 30;
7172 $this->surface_units = 0;
7173 $this->volume = 300;
7174 $this->volume_units = 0;
7176 $this->barcode = -1;
7194 if (empty($this->fk_unit)) {
7197 if (empty($outputlangs)) {
7198 $outputlangs = $langs;
7201 $outputlangs->load(
'products');
7204 $sql =
"SELECT code, label, short_label FROM ".$this->db->prefix().
"c_units where rowid = ".((int) $this->fk_unit);
7206 $resql = $this->db->query($sql);
7208 $this->error = $this->db->error();
7209 dol_syslog(get_class($this).
"::getLabelOfUnit Error ".$this->error, LOG_ERR);
7211 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
7212 if ($type ==
'short') {
7214 $label = $outputlangs->transnoentitiesnoconv($res[
'short_label']);
7216 $label = $outputlangs->trans($res[
'short_label']);
7218 } elseif ($type ==
'code') {
7219 $label = $res[
'code'];
7221 if ($outputlangs->trans(
'unit'.$res[
'code']) ==
'unit'.$res[
'code']) {
7223 $label = $res[
'label'];
7227 $label = $outputlangs->transnoentitiesnoconv(
'unit'.$res[
'code']);
7229 $label = $outputlangs->trans(
'unit'.$res[
'code']);
7234 $this->db->free($resql);
7248 $maxpricesupplier = 0;
7251 include_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.product.class.php';
7253 $product_fourn_list = $product_fourn->list_product_fournisseur_price($this->
id,
'',
'');
7255 if (is_array($product_fourn_list) && count($product_fourn_list) > 0) {
7256 foreach ($product_fourn_list as $productfourn) {
7257 if ($productfourn->fourn_unitprice > $maxpricesupplier) {
7258 $maxpricesupplier = $productfourn->fourn_unitprice;
7266 return $maxpricesupplier;
7282 require_once DOL_DOCUMENT_ROOT.
'/categories/class/categorie.class.php';
7283 return parent::setCategoriesCommon($categories, Categorie::TYPE_PRODUCT);
7297 $sql =
" DELETE FROM ".$dbs->prefix().
"product_customer_price";
7298 $sql .=
" WHERE fk_soc = ".(int) $origin_id;
7299 $sql .=
" AND fk_product IN (SELECT fk_product FROM (SELECT fk_product FROM ".$dbs->prefix().
"product_customer_price WHERE fk_soc = ".(int) $dest_id.
") AS tmp)";
7302 if (!$dbs->
query($sql)) {
7307 'product_customer_price',
7308 'product_customer_price_log'
7327 $sql =
"SELECT rowid, level, fk_level, var_percent, var_min_percent FROM ".$this->db->prefix().
"product_pricerules";
7328 $query = $this->db->query($sql);
7332 while ($result = $this->db->fetch_object($query)) {
7333 $rules[$result->level] = $result;
7342 for ($i = 1; $i <= $nbofproducts; $i++) {
7343 $price = $baseprice;
7344 $price_min = $baseprice;
7348 if ($i > 1 && isset($rules[$i]->var_percent) && $rules[$i]->var_percent) {
7349 $price = $prices[$rules[$i]->fk_level] * (1 + ($rules[$i]->var_percent / 100));
7352 $prices[$i] = $price;
7355 if (isset($rules[$i]->var_min_percent) && $rules[$i]->var_min_percent) {
7356 $price_min = $price * (1 - ($rules[$i]->var_min_percent / 100));
7360 $check_amount = (($price == $this->multiprices[$i]) && ($price_min == $this->multiprices_min[$i]));
7361 $check_type = ($baseprice == $this->multiprices_base_type[$i]);
7363 if ($check_amount && $check_type) {
7367 if ($this->
updatePrice($price, $price_type, $user, $price_vat, $price_min, $i, $npr, $psq, 1) < 0) {
7385 return $user->rights->produit;
7387 return $user->rights->service;
7399 $sql =
"SELECT p.rowid, p.ref, p.datec as date_creation, GREATEST(p.tms, COALESCE(pef.tms, p.tms)) as date_modification,";
7400 $sql .=
" p.fk_user_author, p.fk_user_modif";
7401 $sql .=
" FROM ".$this->db->prefix().$this->table_element.
" as p";
7402 $sql .=
" LEFT JOIN ".$this->db->prefix().$this->table_element.
"_extrafields as pef ON pef.fk_object=p.rowid";
7403 $sql .=
" WHERE p.rowid = ".((int) $id);
7405 $result = $this->db->query($sql);
7407 if ($this->db->num_rows($result)) {
7408 $obj = $this->db->fetch_object($result);
7410 $this->
id = $obj->rowid;
7411 $this->
ref = $obj->ref;
7413 $this->user_creation_id = $obj->fk_user_author;
7414 $this->user_modification_id = $obj->fk_user_modif;
7416 $this->date_creation = $this->db->jdate($obj->date_creation);
7417 $this->date_modification = $this->db->jdate($obj->date_modification);
7420 $this->db->free($result);
7434 if (empty($this->duration_value)) {
7435 $this->errors[] =
'ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
7438 if ($this->duration_unit ==
's') {
7439 $prodDurationHours = 1. / 3600;
7440 } elseif ($this->duration_unit ==
'i' || $this->duration_unit ==
'mn' || $this->duration_unit ==
'min') {
7441 $prodDurationHours = 1. / 60;
7442 } elseif ($this->duration_unit ==
'h') {
7443 $prodDurationHours = 1.;
7444 } elseif ($this->duration_unit ==
'd') {
7445 $prodDurationHours = 24.;
7446 } elseif ($this->duration_unit ==
'w') {
7447 $prodDurationHours = 24. * 7;
7448 } elseif ($this->duration_unit ==
'm') {
7449 $prodDurationHours = 24. * 30;
7450 } elseif ($this->duration_unit ==
'y') {
7451 $prodDurationHours = 24. * 365;
7455 $this->errors[] =
'ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
7458 $prodDurationHours *= $this->duration_value;
7460 return $prodDurationHours;
7473 global $langs,
$conf;
7475 $selected = (empty($arraydata[
'selected']) ? 0 : $arraydata[
'selected']);
7477 $return =
'<div class="box-flex-item box-flex-grow-zero">';
7478 $return .=
'<div class="info-box info-box-sm">';
7479 $return .=
'<div class="info-box-img">';
7481 if ($this->entity !==
null && $this->
is_photo_available($conf->product->multidir_output[$this->entity])) {
7482 $label .= $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 120, 160, 0, 0, 0,
'',
'photoref photokanban');
7492 $return .=
'</div>';
7493 $return .=
'<div class="info-box-content">';
7494 $return .=
'<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">' . $this->
getNomUrl() .
'</span>';
7495 if ($selected >= 0) {
7496 $return .=
'<input id="cb'.$this->id.
'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->
id.
'"'.($selected ?
' checked="checked"' :
'').
'>';
7498 $return .=
'<br><span class="info-box-label opacitymedium inline-block tdoverflowmax150 valignmiddle" title="'.dol_escape_htmltag($this->label).
'">'.
dol_escape_htmltag($this->label).
'</span>';
7499 if ($this->price_base_type ==
'TTC') {
7500 $return .=
'<br><span class="info-box-status amount">'.price($this->price_ttc).
' '.$langs->trans(
"TTC").
'</span>';
7503 $return .=
'<br><span class="info-box-status amount">'.price($this->
price).
' '.$langs->trans(
"HT").
'</span>';
7508 $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>';
7513 $return .=
'<div class="info-box-status inline-block valignmiddle">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7515 $return .=
'<div class="info-box-status inline-block valignmiddle marginleftonly paddingleft">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7517 $return .=
'</div>';
7518 $return .=
'</div>';
7519 $return .=
'</div>';
7530 public $picto =
'service';
if(! $sortfield) if(! $sortorder) $object
length_accountg($account)
Return General accounting account with defined length (used for product and miscellaneous)
clean_account($account)
Return accounting account without zero on the right.
Parent class of all other business classes (invoices, contracts, proposals, orders,...
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
deleteEcmFiles($mode=0)
Delete related files of object in database.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
setErrorsFromObject($object)
setErrorsFromObject
isObjectUsed($id=0, $entity=0)
Function to check if an object is used by others (by children).
deleteExtraFields()
Delete all extra fields values for the current object.
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
show_photos($modulepart, $sdir, $size=0, $nbmax=0, $nbbyrow=5, $showfilename=0, $showaction=0, $maxHeight=120, $maxWidth=160, $nolink=0, $overwritetitle=0, $usesharelink=0, $cache='', $addphotorefcss='photoref')
Show photos of an object (nbmax maximum), into several columns.
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
addThumbs($file, $quality=50)
Build thumb.
Class to manage Dolibarr database access.
Class to manage ECM files.
const STATUS_OPEN_INTERNAL
Warehouse open and only operations for stock transfers/corrections allowed (not for customer shipping...
const STATUS_OPEN_ALL
Warehouse open and any operations are allowed (customer shipping, supplier dispatch,...
const STATUS_CLOSED
Warehouse closed, inactive.
const STATUS_CLOSED
Closed status -> parcel was received by customer / end of process prev status : validated or shipment...
const STATUS_VALIDATED
Validated status -> parcel is ready to be sent prev status : draft next status : closed or shipment_i...
const STATUS_DRAFT
Draft status.
Class to manage stock movements.
Class to parse product price expressions.
Class ProductCombination Used to represent the relation between a product and one of its variants.
File of class to manage predefined price products or services by customer.
Class to manage predefined suppliers products.
Class to manage products or services.
static replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
get_nb_achat($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units or supplier invoices in which product is included.
getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp=0)
Return price of sell of a product for a seller/buyer/product.
__construct($db)
Constructor.
is_sousproduit($fk_parent, $fk_child)
Check if it is a sub-product into a kit.
const DISABLED_STOCK
Stockable product.
const SELL_OR_EAT_BY_MANDATORY_ID_NONE
Const sell or eat by mandatory id.
isStockManaged()
Return if the object is managed in stock.
setPriceExpression($expression_id)
Sets the supplier price expression.
getArrayForPriceCompare($level=0)
used to check if price have really change to avoid log pollution
get_arbo_each_prod($multiply=1, $ignore_stock_load=0)
Build the tree of subproducts and return it.
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.
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.
setMultiLangs($user, $notrigger=0)
Update or add a translation for a product.
hasFatherOrChild($mode=0)
Count all parent and children products for current product (first level only)
load_stats_facturerec($socid=0)
Load array of statistics for recurring invoice for product/service.
get_nb_propalsupplier($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in proposals in which product is included.
load_stats_facturefournrec($socid=0)
Load array of statistics for recurring supplier invoice for product/service.
get_nb_contract($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
load_stats_facture_fournisseur($socid=0)
Load array of statistics for vendor invoice for product/service.
get_nb_ordersupplier($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
getMultiLangs()
Load array this->multilangs.
get_nb_mos($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
clone_associations($fromId, $toId)
Clone links between products.
create($user, $notrigger=0)
Insert product into database.
load_stats_contrat($socid=0)
Charge tableau des stats contrat pour le produit/service.
isService()
Return if the object is a service.
getRights()
Returns the rights used for this class.
loadBatchInfo($batch)
Load existing information about a serial.
load_stock($option='', $includedraftpoforvirtual=null, $dateofvirtualstock=null)
Load information about stock of a product into ->stock_reel, ->stock_warehouse[] (including stock_war...
getProductDurationHours()
Return the duration of a service in hours (for a service based on duration fields)
get_buyprice($prodfournprice, $qty, $product_id=0, $fourn_ref='', $fk_soc=0)
Read price used by a provider.
clone_fournisseurs($fromId, $toId)
Copies the suppliers and supplier pricing of a product/service onto another one.
const TYPE_PRODUCT
Regular product.
fetchAllPriceLogs($id)
Get all price change logs for a product, enriched with supplier info.
add_photo($sdir, $file)
Move an uploaded file described into $file array into target directory $sdir.
log_price_delete($user, $rowid)
Delete a price line of this product.
info($id)
Load information for tab info.
correct_stock($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $inventorycode='', $origin_element='', $origin_id=null, $disablestockchangeforsubproduct=0, $extrafields=null)
Adjust stock in a warehouse for product.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
Create a document onto disk according to template module.
static getSellOrEatByMandatoryList()
Get the array of labels of Sell by or Eat by all mandatory flags for each status.
getChildsArbo($id, $firstlevelonly=0, $level=1, $parents=array())
Return children of product $id.
load_virtual_stock($includedraftpoforvirtual=null, $dateofvirtualstock=null)
Load value ->stock_theorique of a product.
load_stats_propale($socid=0)
Charge tableau des stats propale pour le produit/service.
get_barcode($object, $type='')
Get a barcode from the module to generate barcode values.
setAccountancyCode($type, $value)
Sets an accountancy code for a product.
load_stats_facture($socid=0)
Charge tableau des stats facture pour le produit/service.
setCategories($categories)
Sets object to supplied categories.
load_stats_reception($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null)
Loads supplier reception statistics table for given product or 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.
correct_stock_batch($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $dlc='', $dluo='', $lot='', $inventorycode='', $origin_element='', $origin_id=null, $disablestockchangeforsubproduct=0, $extrafields=null, $force_update_batch=false)
Adjust stock in a warehouse for product with batch number.
load_stats_bom($socid=0)
Charge tableau des stats OF pour le produit/service.
hasbatch()
Return if the object has a batch management.
del_sousproduit($fk_parent, $fk_child, $notrigger=0)
Remove a link between a subproduct and a parent product/service.
fetch($id=0, $ref='', $ref_ext='', $barcode='', $ignore_expression=0, $ignore_price_load=0, $ignore_lang_load=0)
Load a product in memory from database.
update_sousproduit($id_pere, $id_fils, $qty, $incdec=1, $notrigger=0)
Modify composed product.
load_stats_commande($socid=0, $filtrestatut='', $forVirtualStock=0)
Charge tableau des stats commande client pour le produit/service.
delete_photo($file)
Delete a photo and its thumbs.
fetch_prod_arbo($prod, $compl_path='', $multiply=1, $level=1, $id_parent=0, $ignore_stock_load=0)
Function recursive, used only by get_arbo_each_prod(), to build tree of subproducts into ->res Define...
getKanbanView($option='', $arraydata=null)
Return clickable link of object (with eventually picto)
getLibStatut($mode=0, $type=0)
Return label of status of object.
load_stats_sending($socid=0, $filtrestatut='', $forVirtualStock=0, $filterShipmentStatus='')
Charge tableau des stats expedition client pour le produit/service.
clone_price($fromId, $toId)
Recopie les prix d'un produit/service sur un autre.
load_stats_inproduction($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null, $warehouseid=0)
Charge tableau des stats production pour le produit/service.
delMultiLangs($langtodelete, $user, $notrigger=0)
Delete a language for this product.
check()
Check that ref and label are ok.
initAsSpecimen()
Initialise an instance with random values.
liste_photos($dir, $nbmax=0)
Return an array with all photos of product found on disk.
loadStateBoard()
Load indicators this->nb for the dashboard.
getFather()
Return all parent products for current product (first level only)
getNomUrl($withpicto=0, $option='', $maxlength=0, $save_lastsearch_value=-1, $notooltip=0, $morecss='', $add_label=0, $sep=' - ')
Return clickable link of object (with eventually picto)
getSellOrEatByMandatoryLabel()
Get the label for sell by or eat by mandatory flag of the current product.
verify()
Check properties of product are ok (like name, barcode, ...).
get_nb_order($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
loadStockForVirtualProduct($option='', $qtyWish=1)
Load stock for components of virtual product (first level only)
min_recommended_price()
Return minimum product recommended price.
_log_price($user, $level=0)
Insert a track that we changed a customer price.
getLabelOfUnit($type='long', $outputlangs=null, $noentities=0)
Reads the units dictionary to return the translation code of a unit (if type='code'),...
_get_stats($sql, $mode, $year=0)
Return an array formatted for showing graphs.
load_stats_commande_fournisseur($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null)
Charge tableau des stats commande fournisseur pour le produit/service.
isMandatoryPeriod()
Return if the object has a constraint on mandatory_period.
isProduct()
Return if the object is a product.
generateMultiprices(User $user, $baseprice, $price_type, $price_vat, $npr, $psq)
Generates prices for a product based on product multiprice generation rules.
LibStatut($status, $mode=0, $type=0)
Return label of a given status.
const TYPE_SERVICE
Service.
is_photo_available($sdir)
Return if at least one photo is available.
get_image_size($file)
Load size of image file.
get_nb_vente($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units or customers invoices in which product is included.
getTooltipContentArray($params)
getTooltipContentArray
Class to manage products or services.
Manage record for batch number management.
static findAll($dbs, $fk_product_stock, $with_qty=0, $fk_product=0)
Return all batch detail records for a given product and warehouse.
Class with list of lots and properties.
Class to manage Dolibarr users.
hasRight($module, $permlevel1, $permlevel2='')
Return if a user has a permission.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0, $level=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
dol_is_file($pathoffile)
Return if path is a file.
dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $nohook=0, $keyforsourcefile='addedfile', $upload_dir='', $mode=0)
Check validity of a file upload from an GUI page, and move it to its final destination.
dol_now($mode='gmt')
Return date for now.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
dolGetFirstLineOfText($text, $nboflines=1, $charset='UTF-8')
Return first line of text.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='', $keepspaces=0)
Clean a string from all punctuation characters to use it as a ref or login.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
yn($yesno, $format=1, $color=0)
Return yes or no in current language.
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
dol_clone($srcobject, $native=2)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '...' if string larger than length.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
utf8_check($str)
Check if a string is in UTF8.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_localtax($vatrate, $local, $thirdparty_buyer=null, $thirdparty_seller=null, $vatnpr=0)
Return localtax rate for a particular VAT rate, when selling a product with vat $vatrate,...
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
query($query, $usesavepoint=0, $type='auto', $result_mode=0)
Execute a SQL request and return the resultset.
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
buildzip.php
measuring_units_squared($unitscale)
Transform a given unit scale into the square of that unit, if known.
measuringUnitString($unitid, $measuring_style='', $unitscale=null, $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
measuring_units_cubed($unit)
Transform a given unit scale into the cube of that unit, if known.
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...