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 (";
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 $resql = $this->db->query($sql);
2394 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price_extrafields";
2395 $sql .=
" WHERE fk_object = ".((int) $rowid);
2396 $resql = $this->db->query($sql);
2398 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price";
2399 $sql .=
" WHERE rowid = ".((int) $rowid);
2400 $resql = $this->db->query($sql);
2404 $this->error = $this->db->lasterror();
2424 $sql .=
" pl.rowid as log_rowid,";
2425 $sql .=
" pl.datec,";
2426 $sql .=
" pl.price,";
2427 $sql .=
" pl.quantity,";
2428 $sql .=
" pl.fk_user,";
2429 $sql .=
" pl.multicurrency_code,";
2430 $sql .=
" pl.multicurrency_price,";
2432 $sql .=
" pp.fk_soc as supplier_id,";
2433 $sql .=
" pp.ref_fourn as supplier_ref,";
2434 $sql .=
" pp.entity as entity";
2436 $sql .=
" FROM " . $this->db->prefix() .
"product_fournisseur_price_log as pl";
2437 $sql .=
" INNER JOIN " . $this->db->prefix() .
"product_fournisseur_price as pp ON pl.fk_product_fournisseur = pp.rowid";
2439 $sql .=
" WHERE pp.fk_product = " . ((int) $id);
2440 $sql .=
" AND pp.entity IN (" .
getEntity(
'product') .
")";
2441 $sql .=
" ORDER BY pl.datec DESC";
2443 $resql = $this->db->query($sql);
2445 while ($obj = $this->db->fetch_object($resql)) {
2446 if (is_string($obj->datec)) {
2447 $obj->datec = strtotime($obj->datec);
2451 $this->db->free($resql);
2453 $this->error = $this->db->lasterror();
2468 public function getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp = 0)
2470 global $hookmanager, $action;
2473 if (is_object($hookmanager)) {
2474 $parameters = array(
'thirdparty_seller' => $thirdparty_seller,
'thirdparty_buyer' => $thirdparty_buyer,
'pqp' => $pqp);
2476 $reshook = $hookmanager->executeHooks(
'getSellPrice', $parameters, $this, $action);
2478 return $hookmanager->resArray;
2483 $tva_tx =
get_default_tva($thirdparty_seller, $thirdparty_buyer, $this->
id);
2484 $tva_npr =
get_default_npr($thirdparty_seller, $thirdparty_buyer, $this->
id);
2485 if (empty($tva_tx)) {
2489 $pu_ht = $this->price;
2490 $pu_ttc = $this->price_ttc;
2491 $price_min = $this->price_min;
2492 $price_min_ttc = $this->price_min_ttc;
2493 $price_base_type = (empty($this->price_base_type) ?
'HT' : $this->price_base_type);
2497 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2501 $filter = array(
't.fk_product' => (
string) $this->
id,
't.fk_soc' => (
string) $thirdparty_buyer->id);
2504 $pricebycustomerexist =
false;
2505 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2507 if (count($prodcustprice->lines) > 0) {
2508 $date_now = (int) floor(
dol_now() / 86400) * 86400;
2509 foreach ($prodcustprice->lines as $k => $custprice_line) {
2510 if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
2511 $pricebycustomerexist =
true;
2512 $pu_ht =
price($custprice_line->price);
2513 $price_min =
price($custprice_line->price_min);
2514 $price_min_ttc =
price($custprice_line->price_min_ttc);
2515 $pu_ttc =
price($custprice_line->price_ttc);
2516 $price_base_type = $custprice_line->price_base_type;
2517 $tva_tx = $custprice_line->tva_tx;
2518 if ($custprice_line->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2519 $tva_tx .=
' (' . $custprice_line->default_vat_code .
')';
2521 $tva_npr = $custprice_line->recuperableonly;
2522 if (empty($tva_tx)) {
2531 if (!$pricebycustomerexist && !empty($thirdparty_buyer->price_level)) {
2532 $pu_ht = isset($this->multiprices[$thirdparty_buyer->price_level]) ? $this->multiprices[$thirdparty_buyer->price_level] : 0;
2533 $pu_ttc = isset($this->multiprices_ttc[$thirdparty_buyer->price_level]) ? $this->multiprices_ttc[$thirdparty_buyer->price_level] : 0;
2534 $price_min = isset($this->multiprices_min[$thirdparty_buyer->price_level]) ? $this->multiprices_min[$thirdparty_buyer->price_level] : 0;
2535 $price_min_ttc = isset($this->multiprices_min_ttc[$thirdparty_buyer->price_level]) ? $this->multiprices_min_ttc[$thirdparty_buyer->price_level] : 0;
2536 $price_base_type = isset($this->multiprices_base_type[$thirdparty_buyer->price_level]) ? $this->multiprices_base_type[$thirdparty_buyer->price_level] :
'HT';
2539 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2540 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2542 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2543 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2545 if (empty($tva_tx)) {
2550 } elseif (
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !empty($thirdparty_buyer->price_level)) {
2551 $pu_ht = isset($this->multiprices[$thirdparty_buyer->price_level]) ? $this->multiprices[$thirdparty_buyer->price_level] : 0;
2552 $pu_ttc = isset($this->multiprices_ttc[$thirdparty_buyer->price_level]) ? $this->multiprices_ttc[$thirdparty_buyer->price_level] : 0;
2553 $price_min = isset($this->multiprices_min[$thirdparty_buyer->price_level]) ? $this->multiprices_min[$thirdparty_buyer->price_level] : 0;
2554 $price_min_ttc = isset($this->multiprices_min_ttc[$thirdparty_buyer->price_level]) ? $this->multiprices_min_ttc[$thirdparty_buyer->price_level] : 0;
2555 $price_base_type = isset($this->multiprices_base_type[$thirdparty_buyer->price_level]) ? $this->multiprices_base_type[$thirdparty_buyer->price_level] :
'HT';
2558 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2559 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2561 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2562 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2564 if (empty($tva_tx)) {
2570 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2574 $filter = array(
't.fk_product' => (
string) $this->
id,
't.fk_soc' => (
string) $thirdparty_buyer->id);
2576 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2578 if (count($prodcustprice->lines) > 0) {
2579 $date_now = (int) floor(
dol_now() / 86400) * 86400;
2580 foreach ($prodcustprice->lines as $k => $custprice_line) {
2581 if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
2582 $pu_ht =
price($custprice_line->price);
2583 $price_min =
price($custprice_line->price_min);
2584 $price_min_ttc =
price($custprice_line->price_min_ttc);
2585 $pu_ttc =
price($custprice_line->price_ttc);
2586 $price_base_type = $custprice_line->price_base_type;
2587 $tva_tx = $custprice_line->tva_tx;
2588 if ($custprice_line->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2589 $tva_tx .=
' (' . $custprice_line->default_vat_code .
')';
2591 $tva_npr = $custprice_line->recuperableonly;
2592 if (empty($tva_tx)) {
2602 if (!empty($this->prices_by_qty[0])) {
2605 foreach ($this->prices_by_qty_list[0] as $priceforthequantityarray) {
2606 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2610 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2611 $pu_ht = $priceforthequantityarray[
'unitprice'];
2613 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2620 if (!empty($this->prices_by_qty[$thirdparty_buyer->price_level])) {
2623 foreach ($this->prices_by_qty_list[$thirdparty_buyer->price_level] as $priceforthequantityarray) {
2624 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2628 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2629 $pu_ht = $priceforthequantityarray[
'unitprice'];
2631 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2638 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);
2655 public function get_buyprice($prodfournprice, $qty, $product_id = 0, $fourn_ref =
'', $fk_soc = 0)
2658 global $action, $hookmanager;
2661 if (is_object($hookmanager)) {
2662 $parameters = array(
2663 'prodfournprice' => $prodfournprice,
2665 'product_id' => $product_id,
2666 'fourn_ref' => $fourn_ref,
2667 'fk_soc' => $fk_soc,
2670 $reshook = $hookmanager->executeHooks(
'getBuyPrice', $parameters, $this, $action);
2672 return $hookmanager->resArray;
2679 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2680 $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,";
2681 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2682 $sql .=
" pfp.packaging";
2683 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2684 $sql .=
" WHERE pfp.rowid = ".((int) $prodfournprice);
2686 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2688 $sql .=
" ORDER BY pfp.quantity DESC";
2690 dol_syslog(get_class($this).
"::get_buyprice first search by prodfournprice/qty", LOG_DEBUG);
2691 $resql = $this->db->query($sql);
2693 $obj = $this->db->fetch_object($resql);
2694 if ($obj && $obj->quantity > 0) {
2695 if (
isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2697 $prod_supplier->product_fourn_price_id = $obj->rowid;
2698 $prod_supplier->id = $obj->fk_product;
2699 $prod_supplier->fourn_qty = $obj->quantity;
2700 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2701 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2703 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2705 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2706 if ($price_result >= 0) {
2707 $obj->price = $price_result;
2710 $this->product_fourn_price_id = $obj->rowid;
2711 $this->buyprice = $obj->price;
2712 $this->fourn_pu = $obj->price / $obj->quantity;
2713 $this->fourn_price_base_type =
'HT';
2714 $this->fourn_socid = $obj->fk_soc;
2715 $this->ref_fourn = $obj->ref_supplier;
2716 $this->ref_supplier = $obj->ref_supplier;
2717 $this->desc_supplier = $obj->desc_supplier;
2718 $this->remise_percent = $obj->remise_percent;
2719 $this->vatrate_supplier = $obj->tva_tx;
2720 $this->default_vat_code_supplier = $obj->default_vat_code;
2721 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2722 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2723 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2724 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2725 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2727 $this->packaging = (float) $obj->packaging;
2733 $this->fourn_qty = $obj->quantity;
2734 $result = $obj->fk_product;
2738 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2739 $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,";
2740 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2741 $sql .=
" pfp.packaging";
2742 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2743 $sql .=
" WHERE 1 = 1";
2744 if ($product_id > 0) {
2745 $sql .=
" AND pfp.fk_product = ".((int) $product_id);
2747 if ($fourn_ref !=
'none') {
2748 $sql .=
" AND pfp.ref_fourn = '".$this->db->escape($fourn_ref).
"'";
2751 $sql .=
" AND pfp.fk_soc = ".((int) $fk_soc);
2754 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2756 $sql .=
" ORDER BY pfp.quantity DESC";
2759 dol_syslog(get_class($this).
"::get_buyprice second search from qty/ref/product_id", LOG_DEBUG);
2760 $resql = $this->db->query($sql);
2762 $obj = $this->db->fetch_object($resql);
2763 if ($obj && $obj->quantity > 0) {
2764 if (
isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2766 $prod_supplier->product_fourn_price_id = $obj->rowid;
2767 $prod_supplier->id = $obj->fk_product;
2768 $prod_supplier->fourn_qty = $obj->quantity;
2769 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2770 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2772 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2774 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2775 if ($price_result >= 0) {
2776 $obj->price = $price_result;
2779 $this->product_fourn_price_id = $obj->rowid;
2780 $this->buyprice = $obj->price;
2781 $this->fourn_qty = $obj->quantity;
2782 $this->fourn_pu = $obj->price / $obj->quantity;
2783 $this->fourn_price_base_type =
'HT';
2784 $this->fourn_socid = $obj->fk_soc;
2785 $this->ref_fourn = $obj->ref_supplier;
2786 $this->ref_supplier = $obj->ref_supplier;
2787 $this->desc_supplier = $obj->desc_supplier;
2788 $this->remise_percent = $obj->remise_percent;
2789 $this->vatrate_supplier = $obj->tva_tx;
2790 $this->default_vat_code_supplier = $obj->default_vat_code;
2791 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2792 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2793 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2794 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2795 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2797 $this->packaging = (float) $obj->packaging;
2801 $this->fourn_qty = $obj->quantity;
2802 $result = $obj->fk_product;
2808 $this->error = $this->db->lasterror();
2813 $this->error = $this->db->lasterror();
2837 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)
2843 dol_syslog(get_class($this).
"::update_price id=".$id.
" newprice=".$newprice.
" newpricebase=".$newpricebase.
" newminprice=".$newminprice.
" level=".$level.
" npr=".$newnpr.
" newdefaultvatcode=".$newdefaultvatcode);
2846 if (empty($this->tva_tx)) {
2847 $this->tva_tx = 0.0;
2849 if (empty($newnpr)) {
2852 if (empty($newminprice)) {
2857 if ($newvat ===
null || $newvat ==
'') {
2858 $newvat = (float) $this->tva_tx;
2861 $localtaxtype1 =
'';
2862 $localtaxtype2 =
'';
2867 return $this->
generateMultiprices($user, $newprice, $newpricebase, $newvat, $newnpr, $newpbq);
2870 if (!empty($newminprice) && ($newminprice > $newprice)) {
2871 $this->error =
'ErrorPriceCantBeLowerThanMinPrice';
2875 if ($newprice === 0 || $newprice !==
'') {
2876 if ($newpricebase ==
'TTC') {
2877 $price_ttc = (float)
price2num($newprice,
'MU');
2878 $price = (float)
price2num($newprice) / (1 + ((float) $newvat / 100));
2879 $price = (float)
price2num($price,
'MU');
2881 if ((
string) $newminprice !=
'0') {
2882 $price_min_ttc = (float)
price2num($newminprice,
'MU');
2883 $price_min = (float)
price2num($newminprice) / (1 + ($newvat / 100));
2884 $price_min = (float)
price2num($price_min,
'MU');
2887 $price_min_ttc = 0.0;
2890 $price = (float)
price2num($newprice,
'MU');
2891 $price_ttc = ($newnpr != 1) ? (
float)
price2num($newprice) * (1 + ($newvat / 100)) : $price;
2892 $price_ttc = (float)
price2num($price_ttc,
'MU');
2894 if ((
string) $newminprice !=
'0') {
2895 $price_min = (float)
price2num($newminprice,
'MU');
2896 $price_min_ttc = (float)
price2num($newminprice) * (1 + ($newvat / 100));
2897 $price_min_ttc = (float)
price2num($price_min_ttc,
'MU');
2901 $price_min_ttc = 0.0;
2905 if (count($localtaxes_array) > 0) {
2906 $localtaxtype1 = $localtaxes_array[
'0'];
2907 $localtax1 = $localtaxes_array[
'1'];
2908 $localtaxtype2 = $localtaxes_array[
'2'];
2909 $localtax2 = $localtaxes_array[
'3'];
2912 if (!empty($newdefaultvatcode)) {
2915 $sql =
"SELECT t.rowid, t.code, t.recuperableonly as tva_npr, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
2916 $sql .=
" FROM ".MAIN_DB_PREFIX.
"c_tva as t, ".MAIN_DB_PREFIX.
"c_country as c";
2917 $sql .=
" WHERE t.fk_pays = c.rowid AND c.code = '".$this->db->escape(
$mysoc->country_code).
"'";
2918 $sql .=
" AND t.taux = ".((float) $newdefaultvatcode).
" AND t.active = 1";
2919 $sql .=
" AND t.code = '".$this->db->escape($newdefaultvatcode).
"'";
2920 $resql = $this->db->query($sql);
2922 $obj = $this->db->fetch_object($resql);
2924 $npr = $obj->tva_npr;
2925 $localtax1 = $obj->localtax1;
2926 $localtax2 = $obj->localtax2;
2927 $localtaxtype1 = $obj->localtax1_type;
2928 $localtaxtype2 = $obj->localtax2_type;
2933 $localtaxtype1 =
'0';
2935 $localtaxtype2 =
'0';
2939 if (empty($localtax1)) {
2942 if (empty($localtax2)) {
2950 $sql =
"UPDATE ".$this->db->prefix().
"product SET";
2951 $sql .=
" price_base_type = '".$this->db->escape($newpricebase).
"',";
2952 $sql .=
" price = ".(float) $price.
",";
2953 $sql .=
" price_ttc = ".(float) $price_ttc.
",";
2954 $sql .=
" price_min = ".(float) $price_min.
",";
2955 $sql .=
" price_min_ttc = ".(float) $price_min_ttc.
",";
2956 $sql .=
" localtax1_tx = ".($localtax1 >= 0 ? (float) $localtax1 :
'NULL').
",";
2957 $sql .=
" localtax2_tx = ".($localtax2 >= 0 ? (float) $localtax2 :
'NULL').
",";
2958 $sql .=
" localtax1_type = ".($localtaxtype1 !=
'' ?
"'".$this->db->escape($localtaxtype1).
"'" :
"'0'").
",";
2959 $sql .=
" localtax2_type = ".($localtaxtype2 !=
'' ?
"'".$this->db->escape($localtaxtype2).
"'" :
"'0'").
",";
2960 $sql .=
" default_vat_code = ".($newdefaultvatcode ?
"'".$this->db->escape($newdefaultvatcode).
"'" :
"null").
",";
2961 $sql .=
" price_label = ".(!empty($price_label) ?
"'".$this->db->escape($price_label).
"'" :
"null").
",";
2962 $sql .=
" tva_tx = ".(float)
price2num($newvat).
",";
2963 $sql .=
" recuperableonly = '".$this->db->escape((
string) $newnpr).
"'";
2964 $sql .=
" WHERE rowid = ".((int) $id);
2966 dol_syslog(get_class($this).
"::update_price", LOG_DEBUG);
2967 $resql = $this->db->query($sql);
2969 $this->multiprices[$level] = $price;
2970 $this->multiprices_ttc[$level] = $price_ttc;
2971 $this->multiprices_min[$level] = $price_min;
2972 $this->multiprices_min_ttc[$level] = $price_min_ttc;
2973 $this->multiprices_base_type[$level] = $newpricebase;
2974 $this->multiprices_default_vat_code[$level] = $newdefaultvatcode;
2975 $this->multiprices_tva_tx[$level] = $newvat;
2976 $this->multiprices_recuperableonly[$level] = $newnpr;
2978 $this->
price = $price;
2979 $this->price_label = $price_label;
2980 $this->price_ttc = $price_ttc;
2981 $this->price_min = $price_min;
2982 $this->price_min_ttc = $price_min_ttc;
2983 $this->price_base_type = $newpricebase;
2984 $this->default_vat_code = $newdefaultvatcode;
2985 $this->tva_tx = $newvat;
2986 $this->tva_npr = $newnpr;
2989 $this->localtax1_tx = $localtax1;
2990 $this->localtax2_tx = $localtax2;
2991 $this->localtax1_type = $localtaxtype1;
2992 $this->localtax2_type = $localtaxtype2;
2995 $this->price_by_qty = $newpbq;
2999 if (!empty(array_diff_assoc($newPriceData, $lastPriceData)) || (!
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3003 $this->level = $level;
3007 $result = $this->call_trigger(
'PRODUCT_PRICE_MODIFY', $user);
3009 $this->db->rollback();
3015 $this->db->commit();
3017 $this->db->rollback();
3018 $this->error = $this->db->lasterror();
3037 $this->fk_price_expression = $expression_id;
3039 return $this->
update($this->
id, $user);
3054 public function fetch($id = 0, $ref =
'', $ref_ext =
'', $barcode =
'', $ignore_expression = 0, $ignore_price_load = 0, $ignore_lang_load = 0)
3056 include_once DOL_DOCUMENT_ROOT.
'/core/lib/company.lib.php';
3060 dol_syslog(get_class($this).
"::fetch id=".$id.
" ref=".$ref.
" ref_ext=".$ref_ext);
3063 if (!$id && !$ref && !$ref_ext && !$barcode) {
3064 $this->error =
'ErrorWrongParameters';
3065 dol_syslog(get_class($this).
"::fetch ".$this->error, LOG_ERR);
3069 $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,";
3070 $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,";
3071 $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,";
3072 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.last_main_doc,";
3073 $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,";
3075 $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,";
3077 $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,";
3082 $separatedEntityPMP =
false;
3083 $separatedStock =
false;
3084 $visibleWarehousesEntities =
$conf->entity;
3087 $checkPMPPerEntity = $this->db->query(
"SELECT pmp FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = ".((int) $id).
" AND entity = ".(
int)
$conf->entity);
3088 if ($this->db->num_rows($checkPMPPerEntity) > 0) {
3089 $separatedEntityPMP =
true;
3093 $separatedStock =
true;
3094 if (isset($mc->sharings[
'stock']) && !empty($mc->sharings[
'stock'])) {
3095 $visibleWarehousesEntities .=
"," . implode(
",", $mc->sharings[
'stock']);
3098 if ($separatedEntityPMP) {
3099 $sql .=
" ppe.pmp,";
3103 $sql .=
" p.datec, GREATEST(p.tms, pef.tms) AS tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.sell_or_eat_by_mandatory, p.batch_mask, p.fk_unit,";
3104 $sql .=
" p.fk_price_expression, p.price_autogen, p.stockable_product, p.model_pdf,";
3105 $sql .=
" p.price_label,";
3106 if ($separatedStock) {
3107 $sql .=
" SUM(sp.reel) as stock";
3111 $sql .=
" FROM ".$this->db->prefix().
"product as p";
3112 $sql .=
" LEFT JOIN ".$this->db->prefix().
"product_extrafields as pef ON pef.fk_object=p.rowid";
3114 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int)
$conf->entity);
3116 if ($separatedStock) {
3117 $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).
"))";
3121 $sql .=
" WHERE p.rowid = ".((int) $id);
3123 $sql .=
" WHERE p.entity IN (".getEntity($this->element).
")";
3125 $sql .=
" AND p.ref = '".$this->db->escape($ref).
"'";
3126 } elseif ($ref_ext) {
3127 $sql .=
" AND p.ref_ext = '".$this->db->escape($ref_ext).
"'";
3128 } elseif ($barcode) {
3129 $sql .=
" AND p.barcode = '".$this->db->escape($barcode).
"'";
3132 if ($separatedStock) {
3133 $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,";
3134 $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,";
3135 $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,";
3136 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
3137 $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,";
3139 $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,";
3141 $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,";
3143 if ($separatedEntityPMP) {
3144 $sql .=
" ppe.pmp,";
3148 $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,";
3149 $sql .=
" p.fk_price_expression, p.price_autogen, p.stockable_product, p.model_pdf,";
3150 $sql .=
" p.price_label";
3157 $resql = $this->db->query($sql);
3159 unset($this->oldcopy);
3161 if ($this->db->num_rows($resql) > 0) {
3162 $obj = $this->db->fetch_object($resql);
3164 $this->
id = $obj->rowid;
3165 $this->
ref = $obj->ref;
3166 $this->ref_ext = $obj->ref_ext;
3167 $this->label = $obj->label;
3169 $this->url = $obj->url;
3170 $this->note_public = $obj->note_public;
3171 $this->note_private = $obj->note_private;
3172 $this->note = $obj->note_private;
3174 $this->
type = $obj->fk_product_type;
3175 $this->price_label = $obj->price_label;
3176 $this->
status = $obj->tosell;
3177 $this->status_buy = $obj->tobuy;
3178 $this->status_batch = $obj->tobatch;
3179 $this->sell_or_eat_by_mandatory = $obj->sell_or_eat_by_mandatory;
3180 $this->batch_mask = $obj->batch_mask;
3182 $this->customcode = $obj->customcode;
3183 $this->country_id = $obj->fk_country;
3184 $this->country_code =
getCountry($this->country_id,
'2', $this->db);
3185 $this->state_id = $obj->fk_state;
3186 $this->lifetime = $obj->lifetime;
3187 $this->qc_frequency = $obj->qc_frequency;
3188 $this->
price = $obj->price;
3189 $this->price_ttc = $obj->price_ttc;
3190 $this->price_min = $obj->price_min;
3191 $this->price_min_ttc = $obj->price_min_ttc;
3192 $this->price_base_type = (empty($obj->price_base_type) ?
'HT' : $obj->price_base_type);
3193 $this->cost_price = isset($obj->cost_price) ? (float) $obj->cost_price :
null;
3194 $this->default_vat_code = $obj->default_vat_code;
3195 $this->tva_tx = $obj->tva_tx;
3197 $this->tva_npr = $obj->tva_npr;
3199 $this->localtax1_tx = $obj->localtax1_tx;
3200 $this->localtax2_tx = $obj->localtax2_tx;
3201 $this->localtax1_type = $obj->localtax1_type;
3202 $this->localtax2_type = $obj->localtax2_type;
3204 $this->finished = $obj->finished;
3205 $this->fk_default_bom = $obj->fk_default_bom;
3207 $this->duration = $obj->duration;
3209 preg_match(
'/([\d.]+)(\w+)/', $obj->duration, $matches);
3210 $this->duration_value = !empty($matches[1]) ? (float) $matches[1] : 0;
3211 $this->duration_unit = !empty($matches[2]) ? (
string) $matches[2] :
null;
3212 $this->canvas = $obj->canvas;
3213 $this->net_measure = $obj->net_measure;
3214 $this->net_measure_units = $obj->net_measure_units;
3215 $this->weight = $obj->weight;
3216 $this->weight_units = (is_null($obj->weight_units) ? 0 : $obj->weight_units);
3217 $this->length = $obj->length;
3218 $this->length_units = (is_null($obj->length_units) ? 0 : $obj->length_units);
3219 $this->width = $obj->width;
3220 $this->width_units = (is_null($obj->width_units) ? 0 : $obj->width_units);
3221 $this->height = $obj->height;
3222 $this->height_units = (is_null($obj->height_units) ? 0 : $obj->height_units);
3224 $this->surface = $obj->surface;
3225 $this->surface_units = (is_null($obj->surface_units) ? 0 : $obj->surface_units);
3226 $this->volume = $obj->volume;
3227 $this->volume_units = (is_null($obj->volume_units) ? 0 : $obj->volume_units);
3228 $this->barcode = $obj->barcode;
3229 $this->barcode_type = $obj->fk_barcode_type;
3231 $this->accountancy_code_buy = $obj->accountancy_code_buy;
3232 $this->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra;
3233 $this->accountancy_code_buy_export = $obj->accountancy_code_buy_export;
3234 $this->accountancy_code_sell = $obj->accountancy_code_sell;
3235 $this->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra;
3236 $this->accountancy_code_sell_export = $obj->accountancy_code_sell_export;
3238 $this->fk_default_warehouse = $obj->fk_default_warehouse;
3239 $this->fk_default_workstation = $obj->fk_default_workstation;
3240 $this->seuil_stock_alerte = $obj->seuil_stock_alerte;
3241 $this->desiredstock = $obj->desiredstock;
3242 $this->stock_reel = $obj->stock;
3243 $this->stockable_product = $obj->stockable_product;
3244 $this->pmp = $obj->pmp;
3246 $this->date_creation = $this->db->jdate($obj->datec);
3247 $this->date_modification = $this->db->jdate($obj->tms);
3249 $this->import_key = $obj->import_key;
3250 $this->entity = $obj->entity;
3252 $this->ref_ext = $obj->ref_ext;
3253 $this->fk_price_expression = $obj->fk_price_expression;
3254 $this->fk_unit = $obj->fk_unit;
3255 $this->price_autogen = $obj->price_autogen;
3256 $this->model_pdf = $obj->model_pdf;
3257 $this->last_main_doc = $obj->last_main_doc;
3259 $this->mandatory_period = $obj->mandatory_period;
3262 $this->packaging = (float) $obj->packaging;
3265 $this->db->free($resql);
3277 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
3278 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3279 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3280 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3281 $sql .=
" ,price_label";
3282 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3283 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3284 $sql .=
" AND price_level=".((int) $i);
3285 $sql .=
" AND fk_product = ".((int) $this->
id);
3286 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3288 $resql = $this->db->query($sql);
3290 $result = $this->db->fetch_array($resql);
3292 $this->multiprices[$i] = $result ? $result[
"price"] :
null;
3293 $this->multiprices_ttc[$i] = $result ? $result[
"price_ttc"] :
null;
3294 $this->multiprices_min[$i] = $result ? $result[
"price_min"] :
null;
3295 $this->multiprices_min_ttc[$i] = $result ? $result[
"price_min_ttc"] :
null;
3296 $this->multiprices_base_type[$i] = $result ? $result[
"price_base_type"] :
null;
3298 $this->multiprices_tva_tx[$i] = $result ? $result[
"tva_tx"].(!empty($result[
'default_vat_code']) ?
' ('.$result[
'default_vat_code'].
')' :
'') :
null;
3299 $this->multiprices_recuperableonly[$i] = $result ? $result[
"recuperableonly"] :
null;
3338 $this->error = $this->db->lasterror;
3344 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY') && empty($ignore_price_load)) {
3345 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3346 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid";
3347 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3348 $sql .=
" WHERE fk_product = ".((int) $this->
id);
3349 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3352 $resql = $this->db->query($sql);
3354 $result = $this->db->fetch_array($resql);
3358 $this->prices_by_qty[0] = $result[
"price_by_qty"];
3359 $this->prices_by_qty_id[0] = $result[
"rowid"];
3361 if ($this->prices_by_qty[0] == 1) {
3362 $sql =
"SELECT rowid,price, unitprice, quantity, remise_percent, remise, remise, price_base_type";
3363 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3364 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[0]);
3365 $sql .=
" ORDER BY quantity ASC";
3367 $resql = $this->db->query($sql);
3369 $resultat = array();
3371 while ($result = $this->db->fetch_array($resql)) {
3372 $resultat[$ii] = array();
3373 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3374 $resultat[$ii][
"price"] = $result[
"price"];
3375 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3376 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3377 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3379 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3382 $this->prices_by_qty_list[0] = $resultat;
3384 $this->error = $this->db->lasterror;
3390 $this->error = $this->db->lasterror;
3393 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') && empty($ignore_price_load)) {
3394 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
3395 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3396 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3397 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3398 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3399 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3400 $sql .=
" AND price_level=".((int) $i);
3401 $sql .=
" AND fk_product = ".((int) $this->
id);
3402 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3404 $resql = $this->db->query($sql);
3406 $this->error = $this->db->lasterror;
3409 $result = $this->db->fetch_array($resql);
3410 $this->multiprices[$i] = (!empty($result[
"price"]) ? $result[
"price"] : 0);
3411 $this->multiprices_ttc[$i] = (!empty($result[
"price_ttc"]) ? $result[
"price_ttc"] : 0);
3412 $this->multiprices_min[$i] = (!empty($result[
"price_min"]) ? $result[
"price_min"] : 0);
3413 $this->multiprices_min_ttc[$i] = (!empty($result[
"price_min_ttc"]) ? $result[
"price_min_ttc"] : 0);
3414 $this->multiprices_base_type[$i] = (!empty($result[
"price_base_type"]) ? $result[
"price_base_type"] :
'');
3416 $this->multiprices_tva_tx[$i] = (!empty($result[
"tva_tx"]) ? $result[
"tva_tx"] : 0);
3417 $this->multiprices_recuperableonly[$i] = (!empty($result[
"recuperableonly"]) ? $result[
"recuperableonly"] : 0);
3420 $this->prices_by_qty[$i] = (!empty($result[
"price_by_qty"]) ? $result[
"price_by_qty"] : 0);
3421 $this->prices_by_qty_id[$i] = (!empty($result[
"rowid"]) ? $result[
"rowid"] : 0);
3423 if ($this->prices_by_qty[$i] == 1) {
3424 $sql =
"SELECT rowid, price, unitprice, quantity, remise_percent, remise, price_base_type";
3425 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3426 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[$i]);
3427 $sql .=
" ORDER BY quantity ASC";
3429 $resql = $this->db->query($sql);
3431 $resultat = array();
3433 while ($result = $this->db->fetch_array($resql)) {
3434 $resultat[$ii] = array();
3435 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3436 $resultat[$ii][
"price"] = $result[
"price"];
3437 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3438 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3439 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3440 $resultat[$ii][
"remise"] = $result[
"remise"];
3441 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3444 $this->prices_by_qty_list[$i] = $resultat;
3446 $this->error = $this->db->lasterror;
3454 if (
isModEnabled(
'dynamicprices') && !empty($this->fk_price_expression) && empty($ignore_expression)) {
3455 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
3457 $price_result = $priceparser->parseProduct($this);
3458 if ($price_result >= 0) {
3459 $this->
price = $price_result;
3461 $this->price_ttc = (float)
price2num($this->
price) * (1 + ($this->tva_tx / 100));
3462 $this->price_ttc = (float)
price2num($this->price_ttc,
'MU');
3468 $this->stock_warehouse = array();
3475 $this->error = $this->db->lasterror();
3490 global $user, $hookmanager, $action;
3494 foreach (array(
'toconsume',
'consumed',
'toproduce',
'produced') as $role) {
3495 $this->stats_mo[
'customers_'.$role] = 0;
3496 $this->stats_mo[
'nb_'.$role] = 0;
3497 $this->stats_mo[
'qty_'.$role] = 0;
3499 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3500 $sql .=
" SUM(mp.qty) as qty";
3501 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as c";
3502 $sql .=
" INNER JOIN ".$this->db->prefix().
"mrp_production as mp ON mp.fk_mo=c.rowid";
3503 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3504 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3507 $sql .=
" c.entity IN (".getEntity(
'mo').
")";
3509 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3510 $sql .=
" AND mp.role ='".$this->db->escape($role).
"'";
3512 $sql .=
" AND c.fk_soc = ".((int) $socid);
3515 $result = $this->db->query($sql);
3517 $obj = $this->db->fetch_object($result);
3518 $this->stats_mo[
'customers_'.$role] = $obj->nb_customers ? $obj->nb_customers : 0;
3519 $this->stats_mo[
'nb_'.$role] = $obj->nb ? $obj->nb : 0;
3520 $this->stats_mo[
'qty_'.$role] = $obj->qty ?
price2num($obj->qty,
'MS') : 0;
3522 $this->error = $this->db->error();
3527 if (!empty($error)) {
3531 $parameters = array(
'socid' => $socid);
3532 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3534 $this->stats_mo = $hookmanager->resArray[
'stats_mo'];
3550 global $hookmanager, $action;
3554 $this->stats_bom[
'nb_toproduce'] = 0;
3555 $this->stats_bom[
'nb_toconsume'] = 0;
3556 $this->stats_bom[
'qty_toproduce'] = 0;
3557 $this->stats_bom[
'qty_toconsume'] = 0;
3559 $sql =
"SELECT COUNT(DISTINCT b.rowid) as nb_toproduce,";
3560 $sql .=
" SUM(b.qty) as qty_toproduce";
3561 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3562 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom = b.rowid";
3564 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3565 $sql .=
" AND b.fk_product =".((int) $this->
id);
3566 $sql .=
" GROUP BY b.rowid";
3568 $result = $this->db->query($sql);
3570 $obj = $this->db->fetch_object($result);
3571 $this->stats_bom[
'nb_toproduce'] = !empty($obj->nb_toproduce) ? $obj->nb_toproduce : 0;
3572 $this->stats_bom[
'qty_toproduce'] = !empty($obj->qty_toproduce) ?
price2num($obj->qty_toproduce) : 0;
3574 $this->error = $this->db->error();
3578 $sql =
"SELECT COUNT(DISTINCT bl.rowid) as nb_toconsume,";
3579 $sql .=
" SUM(bl.qty) as qty_toconsume";
3580 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3581 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
3583 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3584 $sql .=
" AND bl.fk_product =".((int) $this->
id);
3586 $result = $this->db->query($sql);
3588 $obj = $this->db->fetch_object($result);
3589 $this->stats_bom[
'nb_toconsume'] = !empty($obj->nb_toconsume) ? $obj->nb_toconsume : 0;
3590 $this->stats_bom[
'qty_toconsume'] = !empty($obj->qty_toconsume) ?
price2num($obj->qty_toconsume) : 0;
3592 $this->error = $this->db->error();
3596 if (!empty($error)) {
3600 $parameters = array(
'socid' => $socid);
3601 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3603 $this->stats_bom = $hookmanager->resArray[
'stats_bom'];
3619 global $user, $hookmanager, $action;
3621 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_customers, COUNT(DISTINCT p.rowid) as nb,";
3622 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3623 $sql .=
" FROM ".$this->db->prefix().
"propaldet as pd";
3624 $sql .=
", ".$this->db->prefix().
"propal as p";
3625 $sql .=
", ".$this->db->prefix().
"societe as s";
3626 $sql .=
" WHERE p.rowid = pd.fk_propal";
3627 $sql .=
" AND p.fk_soc = s.rowid";
3628 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
3629 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3630 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3631 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $user->id);
3635 $sql .=
" AND p.fk_soc = ".((int) $socid);
3638 $parameters = array(
'socid' => $socid,
'type_element' =>
'propal');
3639 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3640 $sql .= $hookmanager->resPrint;
3641 $result = $this->db->query($sql);
3643 $obj = $this->db->fetch_object($result);
3644 $this->stats_propale[
'customers'] = (int) $obj->nb_customers;
3645 $this->stats_propale[
'nb'] = (int) $obj->nb;
3646 $this->stats_propale[
'rows'] = (int) $obj->nb_rows;
3647 $this->stats_propale[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
3652 if (is_array($TFather) && !empty($TFather)) {
3653 foreach ($TFather as &$fatherData) {
3654 $pFather =
new Product($this->db);
3655 $pFather->id = (int) $fatherData[
'id'];
3656 $qtyCoef = $fatherData[
'qty'];
3658 if ($fatherData[
'incdec']) {
3659 $pFather->load_stats_propale($socid);
3661 if (!empty($pFather->stats_propale)) {
3662 $this->stats_propale[
'customers'] += $pFather->stats_propale[
'customers'];
3663 $this->stats_propale[
'nb'] += $pFather->stats_propale[
'nb'];
3664 $this->stats_propale[
'rows'] += $pFather->stats_propale[
'rows'];
3665 $this->stats_propale[
'qty'] += $pFather->stats_propale[
'qty'] * $qtyCoef;
3672 $parameters = array(
'socid' => $socid);
3673 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerProposal', $parameters, $this, $action);
3675 $this->stats_propale = $hookmanager->resArray[
'stats_propale'];
3680 $this->error = $this->db->error();
3696 global $user, $hookmanager, $action;
3698 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_suppliers, COUNT(DISTINCT p.rowid) as nb,";
3699 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3700 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as pd";
3701 $sql .=
", ".$this->db->prefix().
"supplier_proposal as p";
3702 $sql .=
", ".$this->db->prefix().
"societe as s";
3703 $sql .=
" WHERE p.rowid = pd.fk_supplier_proposal";
3704 $sql .=
" AND p.fk_soc = s.rowid";
3705 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
3706 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3707 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3708 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $user->id);
3712 $sql .=
" AND p.fk_soc = ".((int) $socid);
3715 $result = $this->db->query($sql);
3717 $obj = $this->db->fetch_object($result);
3718 $this->stats_proposal_supplier[
'suppliers'] = $obj->nb_suppliers;
3719 $this->stats_proposal_supplier[
'nb'] = $obj->nb;
3720 $this->stats_proposal_supplier[
'rows'] = $obj->nb_rows;
3721 $this->stats_proposal_supplier[
'qty'] = $obj->qty ? $obj->qty : 0;
3723 $parameters = array(
'socid' => $socid);
3724 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierProposal', $parameters, $this, $action);
3726 $this->stats_proposal_supplier = $hookmanager->resArray[
'stats_proposal_supplier'];
3731 $this->error = $this->db->error();
3749 global $user, $hookmanager, $action;
3752 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3753 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3754 $sql .=
" FROM ".$this->db->prefix().
"commandedet as cd";
3755 $sql .=
", ".$this->db->prefix().
"commande as c";
3756 $sql .=
", ".$this->db->prefix().
"societe as s";
3757 $sql .=
" WHERE c.rowid = cd.fk_commande";
3758 $sql .=
" AND c.fk_soc = s.rowid";
3759 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'commande').
")";
3760 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3761 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3762 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3765 $sql .=
" AND c.fk_soc = ".((int) $socid);
3767 if ($filtrestatut !=
'') {
3768 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3771 $parameters = array(
'socid' => $socid,
'type_element' =>
'order');
3772 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3773 $sql .= $hookmanager->resPrint;
3774 $result = $this->db->query($sql);
3776 $obj = $this->db->fetch_object($result);
3777 $this->stats_commande[
'customers'] = (int) $obj->nb_customers;
3778 $this->stats_commande[
'nb'] = (int) $obj->nb;
3779 $this->stats_commande[
'rows'] = (int) $obj->nb_rows;
3780 $this->stats_commande[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
3785 if (is_array($TFather) && !empty($TFather)) {
3786 foreach ($TFather as &$fatherData) {
3787 $pFather =
new Product($this->db);
3788 $pFather->id = $fatherData[
'id'];
3789 $qtyCoef = $fatherData[
'qty'];
3791 if ($fatherData[
'incdec']) {
3792 $pFather->load_stats_commande($socid, $filtrestatut);
3794 $this->stats_commande[
'customers'] += $pFather->stats_commande[
'customers'];
3795 $this->stats_commande[
'nb'] += $pFather->stats_commande[
'nb'];
3796 $this->stats_commande[
'rows'] += $pFather->stats_commande[
'rows'];
3797 $this->stats_commande[
'qty'] += $pFather->stats_commande[
'qty'] * $qtyCoef;
3810 $sql =
"SELECT SUM(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3811 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3813 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture' AND sourcetype = 'commande' ";
3814 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3815 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3816 $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)";
3820 $sql .=
"SELECT SUM(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3821 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3822 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_source = f.rowid AND el.targettype = 'commande' AND sourcetype = 'facture' ";
3823 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_target = c.rowid";
3824 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3825 $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)";
3827 $parameters = array(
'socid' => $socid,
'type_element' =>
'order');
3828 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3829 $sql .= $hookmanager->resPrint;
3830 $resql = $this->db->query($sql);
3832 while ($obj = $this->db->fetch_object($resql)) {
3833 $adeduire += (float) $obj->count;
3837 $this->stats_commande[
'qty'] -= $adeduire;
3840 include_once DOL_DOCUMENT_ROOT.
'/compta/facture/class/facture.class.php';
3844 $sql =
"SELECT sum(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3845 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3847 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture' AND sourcetype = 'commande' ";
3848 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3849 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3850 $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)";
3852 $sql .=
" UNION ALL ";
3854 $sql .=
"SELECT sum(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3855 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3856 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_source = f.rowid AND el.targettype = 'commande' AND sourcetype = 'facture' ";
3857 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_target = c.rowid";
3858 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3859 $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 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3863 $parameters = array(
'socid' => $socid,
'type_element' =>
'order');
3864 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3865 $sql .= $hookmanager->resPrint;
3866 $resql = $this->db->query($sql);
3868 while ($obj = $this->db->fetch_object($resql)) {
3869 $adeduire += (float) $obj->count;
3872 $this->error = $this->db->error();
3876 $this->stats_commande[
'qty'] -= $adeduire;
3880 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3881 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerOrder', $parameters, $this, $action);
3883 $this->stats_commande = $hookmanager->resArray[
'stats_commande'];
3887 $this->error = $this->db->error();
3905 global $user, $hookmanager, $action;
3907 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_suppliers, COUNT(DISTINCT c.rowid) as nb,";
3908 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3909 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as cd";
3910 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as c";
3911 $sql .=
", ".$this->db->prefix().
"societe as s";
3912 $sql .=
" WHERE c.rowid = cd.fk_commande";
3913 $sql .=
" AND c.fk_soc = s.rowid";
3914 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3915 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3916 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3917 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3920 $sql .=
" AND c.fk_soc = ".((int) $socid);
3922 if ($filtrestatut !=
'') {
3923 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3925 if (!empty($dateofvirtualstock)) {
3926 $sql .=
" AND c.date_livraison <= '".$this->db->idate($dateofvirtualstock).
"'";
3929 $result = $this->db->query($sql);
3931 $obj = $this->db->fetch_object($result);
3932 $this->stats_commande_fournisseur[
'suppliers'] = $obj->nb_suppliers;
3933 $this->stats_commande_fournisseur[
'nb'] = $obj->nb;
3934 $this->stats_commande_fournisseur[
'rows'] = $obj->nb_rows;
3935 $this->stats_commande_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
3937 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3938 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierOrder', $parameters, $this, $action);
3940 $this->stats_commande_fournisseur = $hookmanager->resArray[
'stats_commande_fournisseur'];
3945 $this->error = $this->db->error().
' sql='.$sql;
3960 public function load_stats_sending($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $filterShipmentStatus =
'')
3963 global $user, $hookmanager, $action;
3965 $sql =
"SELECT COUNT(DISTINCT e.fk_soc) as nb_customers, COUNT(DISTINCT e.rowid) as nb,";
3966 $sql .=
" COUNT(ed.rowid) as nb_rows, SUM(ed.qty) as qty";
3967 $sql .=
" FROM ".$this->db->prefix().
"expeditiondet as ed";
3968 $sql .=
", ".$this->db->prefix().
"commandedet as cd";
3969 $sql .=
", ".$this->db->prefix().
"commande as c";
3970 $sql .=
", ".$this->db->prefix().
"expedition as e";
3971 $sql .=
", ".$this->db->prefix().
"societe as s";
3972 $sql .=
" WHERE e.rowid = ed.fk_expedition";
3973 $sql .=
" AND c.rowid = cd.fk_commande";
3974 $sql .=
" AND e.fk_soc = s.rowid";
3975 $sql .=
" AND e.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'expedition').
")";
3976 $sql .=
" AND ed.fk_elementdet = cd.rowid";
3977 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3978 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3979 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = e.fk_soc AND sc.fk_user = ".((int) $user->id);
3982 $sql .=
" AND e.fk_soc = ".((int) $socid);
3984 if ($filtrestatut !=
'') {
3985 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3987 if (!empty($filterShipmentStatus)) {
3988 $sql .=
" AND e.fk_statut IN (".$this->db->sanitize($filterShipmentStatus).
")";
3991 $result = $this->db->query($sql);
3993 $obj = $this->db->fetch_object($result);
3994 $this->stats_expedition[
'customers'] = (int) $obj->nb_customers;
3995 $this->stats_expedition[
'nb'] = (int) $obj->nb;
3996 $this->stats_expedition[
'rows'] = (int) $obj->nb_rows;
3997 $this->stats_expedition[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
4002 if (is_array($TFather) && !empty($TFather)) {
4003 foreach ($TFather as &$fatherData) {
4004 $pFather =
new Product($this->db);
4005 $pFather->id = $fatherData[
'id'];
4006 $qtyCoef = $fatherData[
'qty'];
4008 if ($fatherData[
'incdec']) {
4009 $pFather->load_stats_sending($socid, $filtrestatut, $forVirtualStock);
4011 if (!empty($pFather->stats_expedition)) {
4012 $this->stats_expedition[
'customers'] += $pFather->stats_expedition[
'customers'];
4013 $this->stats_expedition[
'nb'] += $pFather->stats_expedition[
'nb'];
4014 $this->stats_expedition[
'rows'] += $pFather->stats_expedition[
'rows'];
4015 $this->stats_expedition[
'qty'] += $pFather->stats_expedition[
'qty'] * $qtyCoef;
4022 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock,
'filterShipmentStatus' => $filterShipmentStatus);
4023 $reshook = $hookmanager->executeHooks(
'loadStatsSending', $parameters, $this, $action);
4025 $this->stats_expedition = $hookmanager->resArray[
'stats_expedition'];
4030 $this->error = $this->db->error();
4045 public function load_stats_reception($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null)
4048 global $user, $hookmanager, $action;
4050 $sql =
"SELECT COUNT(DISTINCT cf.fk_soc) as nb_suppliers, COUNT(DISTINCT cf.rowid) as nb,";
4051 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4052 $sql .=
" FROM ".$this->db->prefix().
"receptiondet_batch as fd";
4053 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as cf";
4054 $sql .=
", ".$this->db->prefix().
"societe as s";
4055 $sql .=
" WHERE cf.rowid = fd.fk_element";
4056 $sql .=
" AND cf.fk_soc = s.rowid";
4057 $sql .=
" AND cf.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
4058 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4059 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
4060 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = cf.fk_soc AND sc.fk_user = ".((int) $user->id);
4063 $sql .=
" AND cf.fk_soc = ".((int) $socid);
4065 if ($filtrestatut !=
'') {
4066 $sql .=
" AND cf.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
4068 if (!empty($dateofvirtualstock)) {
4069 $sql .=
" AND fd.datec <= '".$this->db->idate($dateofvirtualstock).
"'";
4072 $result = $this->db->query($sql);
4074 $obj = $this->db->fetch_object($result);
4075 $this->stats_reception[
'suppliers'] = $obj->nb_suppliers;
4076 $this->stats_reception[
'nb'] = $obj->nb;
4077 $this->stats_reception[
'rows'] = $obj->nb_rows;
4078 $this->stats_reception[
'qty'] = $obj->qty ? $obj->qty : 0;
4080 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
4081 $reshook = $hookmanager->executeHooks(
'loadStatsReception', $parameters, $this, $action);
4083 $this->stats_reception = $hookmanager->resArray[
'stats_reception'];
4088 $this->error = $this->db->error();
4104 public function load_stats_inproduction($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null, $warehouseid = 0)
4107 global $user, $hookmanager, $action;
4111 $sql =
"SELECT COUNT(DISTINCT m.fk_soc) as nb_customers, COUNT(DISTINCT m.rowid) as nb,";
4112 $sql .=
" COUNT(mp.rowid) as nb_rows, SUM(mp.qty) as qty, role";
4113 $sql .=
" FROM ".$this->db->prefix().
"mrp_production as mp";
4114 $sql .=
", ".$this->db->prefix().
"mrp_mo as m";
4115 $sql .=
" LEFT JOIN ".$this->db->prefix().
"societe as s ON s.rowid = m.fk_soc";
4116 $sql .=
" WHERE m.rowid = mp.fk_mo";
4117 $sql .=
" AND m.entity IN (".getEntity(($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE')) ?
'stock' :
'mrp').
")";
4118 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
4119 $sql .=
" AND (mp.disable_stock_change IN (0) OR mp.disable_stock_change IS NULL)";
4120 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
4121 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = m.fk_soc AND sc.fk_user = ".((int) $user->id);
4124 $sql .=
" AND m.fk_soc = ".((int) $socid);
4126 if ($filtrestatut !=
'') {
4127 $sql .=
" AND m.status IN (".$this->db->sanitize($filtrestatut).
")";
4129 if (!empty($dateofvirtualstock)) {
4130 $sql .=
" AND m.date_valid <= '".$this->db->idate($dateofvirtualstock).
"'";
4132 if (!$serviceStockIsEnabled) {
4133 $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))";
4135 if (!empty($warehouseid)) {
4136 $sql .=
" AND m.fk_warehouse = ".((int) $warehouseid);
4138 $sql .=
" GROUP BY role";
4141 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
4143 $this->stats_mrptoconsume[
'customers'] = 0;
4144 $this->stats_mrptoconsume[
'nb'] = 0;
4145 $this->stats_mrptoconsume[
'rows'] = 0;
4146 $this->stats_mrptoconsume[
'qty'] = 0.0;
4147 $this->stats_mrptoproduce[
'customers'] = 0;
4148 $this->stats_mrptoproduce[
'nb'] = 0;
4149 $this->stats_mrptoproduce[
'rows'] = 0;
4150 $this->stats_mrptoproduce[
'qty'] = 0.0;
4153 $result = $this->db->query($sql);
4155 while ($obj = $this->db->fetch_object($result)) {
4156 if ($obj->role ==
'toconsume' && empty($warehouseid)) {
4157 $this->stats_mrptoconsume[
'customers'] += (int) $obj->nb_customers;
4158 $this->stats_mrptoconsume[
'nb'] += (int) $obj->nb;
4159 $this->stats_mrptoconsume[
'rows'] += (int) $obj->nb_rows;
4160 $this->stats_mrptoconsume[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4162 if ($obj->role ==
'consumed' && empty($warehouseid)) {
4166 $this->stats_mrptoconsume[
'qty'] -= ($obj->qty ? (float) $obj->qty : 0.0);
4168 if ($obj->role ==
'toproduce') {
4170 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4172 $this->stats_mrptoproduce[
'customers'] += (int) $obj->nb_customers;
4173 $this->stats_mrptoproduce[
'nb'] += (int) $obj->nb;
4174 $this->stats_mrptoproduce[
'rows'] += (int) $obj->nb_rows;
4175 $this->stats_mrptoproduce[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4178 if ($obj->role ==
'produced') {
4183 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
4185 $this->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
4192 if ($this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] < 0) {
4193 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
4196 if ($this->stats_mrptoconsume[
'qty'] < 0) {
4197 $this->stats_mrptoconsume[
'qty'] = 0;
4199 if ($this->stats_mrptoproduce[
'qty'] < 0) {
4200 $this->stats_mrptoproduce[
'qty'] = 0;
4204 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
4205 $reshook = $hookmanager->executeHooks(
'loadStatsInProduction', $parameters, $this, $action);
4207 $this->stats_mrptoproduce = $hookmanager->resArray[
'stats_mrptoproduce'];
4212 $this->error = $this->db->error();
4227 global $user, $hookmanager, $action;
4229 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
4230 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
4231 $sql .=
" FROM ".$this->db->prefix().
"contratdet as cd";
4232 $sql .=
", ".$this->db->prefix().
"contrat as c";
4233 $sql .=
", ".$this->db->prefix().
"societe as s";
4234 $sql .=
" WHERE c.rowid = cd.fk_contrat";
4235 $sql .=
" AND c.fk_soc = s.rowid";
4236 $sql .=
" AND c.entity IN (".getEntity(
'contract').
")";
4237 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
4238 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4239 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
4243 $sql .=
" AND c.fk_soc = ".((int) $socid);
4246 $result = $this->db->query($sql);
4248 $obj = $this->db->fetch_object($result);
4249 $this->stats_contrat[
'customers'] = (int) $obj->nb_customers;
4250 $this->stats_contrat[
'nb'] = (int) $obj->nb;
4251 $this->stats_contrat[
'rows'] = (int) $obj->nb_rows;
4252 $this->stats_contrat[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
4257 if (is_array($TFather) && !empty($TFather)) {
4258 foreach ($TFather as &$fatherData) {
4259 $pFather =
new Product($this->db);
4260 $pFather->id = $fatherData[
'id'];
4261 $qtyCoef = $fatherData[
'qty'];
4263 if ($fatherData[
'incdec']) {
4264 $pFather->load_stats_contrat($socid);
4266 if (!empty($pFather->stats_contrat)) {
4267 $this->stats_contrat[
'customers'] += $pFather->stats_contrat[
'customers'];
4268 $this->stats_contrat[
'nb'] += $pFather->stats_contrat[
'nb'];
4269 $this->stats_contrat[
'rows'] += $pFather->stats_contrat[
'rows'];
4270 $this->stats_contrat[
'qty'] += $pFather->stats_contrat[
'qty'] * $qtyCoef;
4277 $parameters = array(
'socid' => $socid);
4278 $reshook = $hookmanager->executeHooks(
'loadStatsContract', $parameters, $this, $action);
4280 $this->stats_contrat = $hookmanager->resArray[
'stats_contrat'];
4285 $this->error = $this->db->error().
' sql='.$sql;
4300 global $user, $hookmanager, $action;
4302 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4303 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(".$this->db->ifsql(
'f.type != 2',
'fd.qty',
'fd.qty * -1').
") as qty";
4304 $sql .=
" FROM ".$this->db->prefix().
"facturedet as fd";
4305 $sql .=
", ".$this->db->prefix().
"facture as f";
4306 $sql .=
", ".$this->db->prefix().
"societe as s";
4307 $sql .=
" WHERE f.rowid = fd.fk_facture";
4308 $sql .=
" AND f.fk_soc = s.rowid";
4309 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4310 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4311 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4312 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4316 $sql .=
" AND f.fk_soc = ".((int) $socid);
4319 $result = $this->db->query($sql);
4321 $obj = $this->db->fetch_object($result);
4322 $this->stats_facture[
'customers'] = (int) $obj->nb_customers;
4323 $this->stats_facture[
'nb'] = (int) $obj->nb;
4324 $this->stats_facture[
'rows'] = (int) $obj->nb_rows;
4325 $this->stats_facture[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
4330 if (is_array($TFather) && !empty($TFather)) {
4331 foreach ($TFather as &$fatherData) {
4332 $pFather =
new Product($this->db);
4333 $pFather->id = $fatherData[
'id'];
4334 $qtyCoef = $fatherData[
'qty'];
4336 if ($fatherData[
'incdec']) {
4337 $pFather->load_stats_facture($socid);
4339 if (!empty($pFather->stats_facture)) {
4340 $this->stats_facture[
'customers'] += $pFather->stats_facture[
'customers'];
4341 $this->stats_facture[
'nb'] += $pFather->stats_facture[
'nb'];
4342 $this->stats_facture[
'rows'] += $pFather->stats_facture[
'rows'];
4343 $this->stats_facture[
'qty'] += $pFather->stats_facture[
'qty'] * $qtyCoef;
4350 $parameters = array(
'socid' => $socid);
4351 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoice', $parameters, $this, $action);
4353 $this->stats_facture = $hookmanager->resArray[
'stats_facture'];
4358 $this->error = $this->db->error();
4374 global $user, $hookmanager, $action;
4376 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4377 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4378 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facturedet_rec as fd";
4379 $sql .=
", ".MAIN_DB_PREFIX.
"facture_rec as f";
4380 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
4381 $sql .=
" WHERE f.rowid = fd.fk_facture";
4382 $sql .=
" AND f.fk_soc = s.rowid";
4383 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4384 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4385 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4386 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4390 $sql .=
" AND f.fk_soc = ".((int) $socid);
4393 $result = $this->db->query($sql);
4395 $obj = $this->db->fetch_object($result);
4396 $this->stats_facturerec[
'customers'] = (int) $obj->nb_customers;
4397 $this->stats_facturerec[
'nb'] = (int) $obj->nb;
4398 $this->stats_facturerec[
'rows'] = (int) $obj->nb_rows;
4399 $this->stats_facturerec[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4404 if (is_array($TFather) && !empty($TFather)) {
4405 foreach ($TFather as &$fatherData) {
4406 $pFather =
new Product($this->db);
4407 $pFather->id = $fatherData[
'id'];
4408 $qtyCoef = $fatherData[
'qty'];
4410 if ($fatherData[
'incdec']) {
4411 $pFather->load_stats_facture($socid);
4413 $this->stats_facturerec[
'customers'] += $pFather->stats_facturerec[
'customers'];
4414 $this->stats_facturerec[
'nb'] += $pFather->stats_facturerec[
'nb'];
4415 $this->stats_facturerec[
'rows'] += $pFather->stats_facturerec[
'rows'];
4416 $this->stats_facturerec[
'qty'] += $pFather->stats_facturerec[
'qty'] * $qtyCoef;
4422 $parameters = array(
'socid' => $socid);
4423 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoiceRec', $parameters, $this, $action);
4425 $this->stats_facturerec = $hookmanager->resArray[
'stats_facturerec'];
4430 $this->error = $this->db->error();
4445 global $user, $hookmanager, $action;
4447 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
4448 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4449 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as fd";
4450 $sql .=
", ".$this->db->prefix().
"facture_fourn as f";
4451 $sql .=
", ".$this->db->prefix().
"societe as s";
4452 $sql .=
" WHERE f.rowid = fd.fk_facture_fourn";
4453 $sql .=
" AND f.fk_soc = s.rowid";
4454 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4455 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4456 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4457 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4461 $sql .=
" AND f.fk_soc = ".((int) $socid);
4464 $result = $this->db->query($sql);
4466 $obj = $this->db->fetch_object($result);
4467 $this->stats_facture_fournisseur[
'suppliers'] = (int) $obj->nb_suppliers;
4468 $this->stats_facture_fournisseur[
'nb'] = (int) $obj->nb;
4469 $this->stats_facture_fournisseur[
'rows'] = (int) $obj->nb_rows;
4470 $this->stats_facture_fournisseur[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4472 $parameters = array(
'socid' => $socid);
4473 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoice', $parameters, $this, $action);
4475 $this->stats_facture_fournisseur = $hookmanager->resArray[
'stats_facture_fournisseur'];
4480 $this->error = $this->db->error();
4495 global $user, $hookmanager, $action;
4497 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
4498 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4499 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facture_fourn_det_rec as fd";
4500 $sql .=
", ".MAIN_DB_PREFIX.
"facture_fourn_rec as f";
4501 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
4502 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4503 $sql .=
", ".MAIN_DB_PREFIX.
"societe_commerciaux as sc";
4505 $sql .=
" WHERE f.rowid = fd.fk_facture";
4506 $sql .=
" AND f.fk_soc = s.rowid";
4507 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4508 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4509 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4510 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4514 $sql .=
" AND f.fk_soc = ".((int) $socid);
4517 $result = $this->db->query($sql);
4519 $obj = $this->db->fetch_object($result);
4520 $this->stats_facturefournrec[
'suppliers'] = (int) $obj->nb_suppliers;
4521 $this->stats_facturefournrec[
'nb'] = (int) $obj->nb;
4522 $this->stats_facturefournrec[
'rows'] = (int) $obj->nb_rows;
4523 $this->stats_facturefournrec[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4525 $parameters = array(
'socid' => $socid);
4526 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoiceRec', $parameters, $this, $action);
4528 $this->stats_facturefournrec = $hookmanager->resArray[
'stats_facturefournrec'];
4533 $this->error = $this->db->error();
4552 $resql = $this->db->query($sql);
4554 $num = $this->db->num_rows($resql);
4557 $arr = $this->db->fetch_array($resql);
4558 if (is_array($arr)) {
4559 $keyfortab = (
string) $arr[1];
4561 $keyfortab = substr($keyfortab, -2);
4564 if ($mode ==
'byunit') {
4565 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[0];
4566 } elseif ($mode ==
'bynumber') {
4567 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4568 } elseif ($mode ==
'byamount') {
4569 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4578 $this->error = $this->db->error().
' sql='.$sql;
4585 } elseif ($year == -1) {
4594 for ($j = 0; $j < 12; $j++) {
4596 $idx = ucfirst(
dol_trunc(
dol_print_date(
dol_mktime(12, 0, 0, $month, 1, 1970),
"%b"), 1,
'right',
'UTF-8', 1));
4599 $result[$j] = array($idx, isset($tab[$year.$month]) ? $tab[$year.$month] : 0);
4602 $month =
"0".($month - 1);
4604 $month = substr($month, 1);
4612 return array_reverse($result);
4627 public function get_nb_vente($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4632 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4633 if ($mode ==
'bynumber') {
4634 $sql .=
", count(DISTINCT f.rowid)";
4636 $sql .=
", sum(d.total_ht) as total_ht";
4637 $sql .=
" FROM ".$this->db->prefix().
"facturedet as d, ".$this->db->prefix().
"facture as f, ".$this->db->prefix().
"societe as s";
4638 if ($filteronproducttype >= 0) {
4639 $sql .=
", ".$this->db->prefix().
"product as p";
4641 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4642 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4644 $sql .=
" WHERE f.rowid = d.fk_facture";
4645 if ($this->
id > 0) {
4646 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4648 $sql .=
" AND d.fk_product > 0";
4650 if ($filteronproducttype >= 0) {
4651 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4653 $sql .=
" AND f.fk_soc = s.rowid";
4654 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4655 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4656 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4659 $sql .=
" AND f.fk_soc = $socid";
4661 $sql .= $morefilter;
4662 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4663 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4665 return $this->
_get_stats($sql, $mode, $year);
4680 public function get_nb_achat($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4685 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4686 if ($mode ==
'bynumber') {
4687 $sql .=
", count(DISTINCT f.rowid)";
4689 $sql .=
", sum(d.total_ht) as total_ht";
4690 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as d, ".$this->db->prefix().
"facture_fourn as f, ".$this->db->prefix().
"societe as s";
4691 if ($filteronproducttype >= 0) {
4692 $sql .=
", ".$this->db->prefix().
"product as p";
4694 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4695 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4697 $sql .=
" WHERE f.rowid = d.fk_facture_fourn";
4698 if ($this->
id > 0) {
4699 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4701 $sql .=
" AND d.fk_product > 0";
4703 if ($filteronproducttype >= 0) {
4704 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4706 $sql .=
" AND f.fk_soc = s.rowid";
4707 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4708 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4709 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4712 $sql .=
" AND f.fk_soc = $socid";
4714 $sql .= $morefilter;
4715 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4716 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4718 return $this->
_get_stats($sql, $mode, $year);
4732 public function get_nb_propal($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4735 global $user, $hookmanager;
4737 $sql =
"SELECT sum(d.qty) as qty, date_format(p.datep, '%Y%m')";
4738 if ($mode ==
'bynumber') {
4739 $sql .=
", count(DISTINCT p.rowid)";
4741 $sql .=
", sum(d.total_ht) as total_ht";
4742 $sql .=
" FROM ".$this->db->prefix().
"propaldet as d, ".$this->db->prefix().
"propal as p, ".$this->db->prefix().
"societe as s";
4743 if ($filteronproducttype >= 0) {
4744 $sql .=
", ".$this->db->prefix().
"product as prod";
4746 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4747 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4749 $sql .=
" WHERE p.rowid = d.fk_propal";
4750 if ($this->
id > 0) {
4751 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4753 $sql .=
" AND d.fk_product > 0";
4755 if ($filteronproducttype >= 0) {
4756 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4758 $sql .=
" AND p.fk_soc = s.rowid";
4759 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
4760 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4761 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4764 $sql .=
" AND p.fk_soc = ".((int) $socid);
4766 $sql .= $morefilter;
4767 $parameters = array(
'socid' => $user->socid);
4768 $hookmanager->executeHooks(
'productGetNbPropal', $parameters, $this);
4769 $sql .= $hookmanager->resPrint;
4770 $sql .=
" GROUP BY date_format(p.datep,'%Y%m')";
4771 $sql .=
" ORDER BY date_format(p.datep,'%Y%m') DESC";
4772 return $this->
_get_stats($sql, $mode, $year);
4791 $sql =
"SELECT sum(d.qty) as qty, date_format(p.date_valid, '%Y%m')";
4792 if ($mode ==
'bynumber') {
4793 $sql .=
", count(DISTINCT p.rowid)";
4795 $sql .=
", sum(d.total_ht) as total_ht";
4796 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as d, ".$this->db->prefix().
"supplier_proposal as p, ".$this->db->prefix().
"societe as s";
4797 if ($filteronproducttype >= 0) {
4798 $sql .=
", ".$this->db->prefix().
"product as prod";
4800 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4801 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4803 $sql .=
" WHERE p.rowid = d.fk_supplier_proposal";
4804 if ($this->
id > 0) {
4805 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4807 $sql .=
" AND d.fk_product > 0";
4809 if ($filteronproducttype >= 0) {
4810 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4812 $sql .=
" AND p.fk_soc = s.rowid";
4813 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
4814 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4815 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4818 $sql .=
" AND p.fk_soc = ".((int) $socid);
4820 $sql .= $morefilter;
4821 $sql .=
" GROUP BY date_format(p.date_valid,'%Y%m')";
4822 $sql .=
" ORDER BY date_format(p.date_valid,'%Y%m') DESC";
4824 return $this->
_get_stats($sql, $mode, $year);
4838 public function get_nb_order($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4841 global $user, $hookmanager;
4843 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4844 if ($mode ==
'bynumber') {
4845 $sql .=
", count(DISTINCT c.rowid)";
4847 $sql .=
", sum(d.total_ht) as total_ht";
4848 $sql .=
" FROM ".$this->db->prefix().
"commandedet as d, ".$this->db->prefix().
"commande as c, ".$this->db->prefix().
"societe as s";
4849 if ($filteronproducttype >= 0) {
4850 $sql .=
", ".$this->db->prefix().
"product as p";
4852 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4853 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4855 $sql .=
" WHERE c.rowid = d.fk_commande";
4856 if ($this->
id > 0) {
4857 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4859 $sql .=
" AND d.fk_product > 0";
4861 if ($filteronproducttype >= 0) {
4862 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4864 $sql .=
" AND c.fk_soc = s.rowid";
4865 $sql .=
" AND c.entity IN (".getEntity(
'commande').
")";
4866 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4867 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4870 $sql .=
" AND c.fk_soc = ".((int) $socid);
4872 $sql .= $morefilter;
4873 $parameters = array(
'socid' => $user->socid);
4874 $hookmanager->executeHooks(
'productGetNbOrder', $parameters, $this);
4875 $sql .= $hookmanager->resPrint;
4876 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4877 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4879 return $this->
_get_stats($sql, $mode, $year);
4898 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4899 if ($mode ==
'bynumber') {
4900 $sql .=
", count(DISTINCT c.rowid)";
4902 $sql .=
", sum(d.total_ht) as total_ht";
4903 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as d, ".$this->db->prefix().
"commande_fournisseur as c, ".$this->db->prefix().
"societe as s";
4904 if ($filteronproducttype >= 0) {
4905 $sql .=
", ".$this->db->prefix().
"product as p";
4907 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4908 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4910 $sql .=
" WHERE c.rowid = d.fk_commande";
4911 if ($this->
id > 0) {
4912 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4914 $sql .=
" AND d.fk_product > 0";
4916 if ($filteronproducttype >= 0) {
4917 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4919 $sql .=
" AND c.fk_soc = s.rowid";
4920 $sql .=
" AND c.entity IN (".getEntity(
'supplier_order').
")";
4921 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4922 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4925 $sql .=
" AND c.fk_soc = ".((int) $socid);
4927 $sql .= $morefilter;
4928 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4929 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4931 return $this->
_get_stats($sql, $mode, $year);
4945 public function get_nb_contract($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4950 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_contrat, '%Y%m')";
4951 if ($mode ==
'bynumber') {
4952 $sql .=
", count(DISTINCT c.rowid)";
4954 $sql .=
", sum(d.total_ht) as total_ht";
4955 $sql .=
" FROM ".$this->db->prefix().
"contratdet as d, ".$this->db->prefix().
"contrat as c, ".$this->db->prefix().
"societe as s";
4956 if ($filteronproducttype >= 0) {
4957 $sql .=
", ".$this->db->prefix().
"product as p";
4959 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4960 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4962 $sql .=
" WHERE c.entity IN (".getEntity(
'contract').
")";
4963 $sql .=
" AND c.rowid = d.fk_contrat";
4965 if ($this->
id > 0) {
4966 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4968 $sql .=
" AND d.fk_product > 0";
4970 if ($filteronproducttype >= 0) {
4971 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4973 $sql .=
" AND c.fk_soc = s.rowid";
4975 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4976 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4979 $sql .=
" AND c.fk_soc = ".((int) $socid);
4981 $sql .= $morefilter;
4982 $sql .=
" GROUP BY date_format(c.date_contrat,'%Y%m')";
4983 $sql .=
" ORDER BY date_format(c.date_contrat,'%Y%m') DESC";
4985 return $this->
_get_stats($sql, $mode, $year);
4999 public function get_nb_mos($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
5004 $sql =
"SELECT sum(d.qty), date_format(d.date_valid, '%Y%m')";
5005 if ($mode ==
'bynumber') {
5006 $sql .=
", count(DISTINCT d.rowid)";
5008 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as d LEFT JOIN ".$this->db->prefix().
"societe as s ON d.fk_soc = s.rowid";
5009 if ($filteronproducttype >= 0) {
5010 $sql .=
", ".$this->db->prefix().
"product as p";
5012 if (!$user->hasRight(
'societe',
'client',
'voir')) {
5013 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
5016 $sql .=
" WHERE d.entity IN (".getEntity(
'mo').
")";
5017 $sql .=
" AND d.status > 0";
5019 if ($this->
id > 0) {
5020 $sql .=
" AND d.fk_product = ".((int) $this->
id);
5022 $sql .=
" AND d.fk_product > 0";
5024 if ($filteronproducttype >= 0) {
5025 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
5028 if (!$user->hasRight(
'societe',
'client',
'voir')) {
5029 $sql .=
" AND d.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
5032 $sql .=
" AND d.fk_soc = ".((int) $socid);
5034 $sql .= $morefilter;
5035 $sql .=
" GROUP BY date_format(d.date_valid,'%Y%m')";
5036 $sql .=
" ORDER BY date_format(d.date_valid,'%Y%m') DESC";
5038 return $this->
_get_stats($sql, $mode, $year);
5058 if (!is_numeric($id_pere)) {
5061 if (!is_numeric($id_fils)) {
5064 if (!is_numeric($incdec)) {
5074 $sql =
"SELECT fk_product_pere from ".$this->db->prefix().
"product_association";
5075 $sql .=
" WHERE fk_product_pere = ".((int) $id_fils).
" AND fk_product_fils = ".((int) $id_pere);
5076 if (!$this->db->query($sql)) {
5081 $sql =
"SELECT MAX(rang) as max_rank FROM ".$this->db->prefix().
"product_association";
5082 $sql .=
" WHERE fk_product_pere = ".((int) $id_pere);
5083 $resql = $this->db->query($sql);
5085 $obj = $this->db->fetch_object($resql);
5086 $rank = $obj->max_rank + 1;
5088 $sql =
"INSERT INTO ".$this->db->prefix().
"product_association(fk_product_pere,fk_product_fils,qty,incdec,rang)";
5089 $sql .=
" VALUES (".((int) $id_pere).
", ".((int) $id_fils).
", ".
price2num($qty,
'MS').
", ".((int) $incdec).
", ".((int) $rank).
")";
5090 if (! $this->db->query($sql)) {
5096 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_ADD', $user);
5098 $this->error = $this->db->lasterror();
5099 dol_syslog(get_class($this).
'::addSubproduct error='.$this->error, LOG_ERR);
5131 if (!is_numeric($id_pere)) {
5134 if (!is_numeric($id_fils)) {
5137 if (!is_numeric($incdec)) {
5140 if (!is_numeric($qty)) {
5144 $sql =
'UPDATE '.$this->db->prefix().
'product_association SET ';
5145 $sql .=
'qty = '.price2num($qty,
'MS');
5146 $sql .=
',incdec = '.((int) $incdec);
5147 $sql .=
' WHERE fk_product_pere = '.((int) $id_pere).
' AND fk_product_fils = '.((int) $id_fils);
5149 if (!$this->db->query($sql)) {
5155 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_UPDATE', $user);
5157 $this->error = $this->db->lasterror();
5158 dol_syslog(get_class($this).
'::updateSubproduct error='.$this->error, LOG_ERR);
5182 if (!is_numeric($fk_parent)) {
5185 if (!is_numeric($fk_child)) {
5189 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
5190 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5191 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
5193 dol_syslog(get_class($this).
'::del_sousproduit', LOG_DEBUG);
5194 if (!$this->db->query($sql)) {
5200 $sqlrank =
"SELECT rowid, rang FROM ".$this->db->prefix().
"product_association";
5201 $sqlrank .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5202 $sqlrank .=
" ORDER BY rang";
5203 $resqlrank = $this->db->query($sqlrank);
5206 while ($objrank = $this->db->fetch_object($resqlrank)) {
5208 $sql =
"UPDATE ".$this->db->prefix().
"product_association";
5209 $sql .=
" SET rang = ".((int) $cpt);
5210 $sql .=
" WHERE rowid = ".((int) $objrank->rowid);
5211 if (! $this->db->query($sql)) {
5220 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_DELETE', $user);
5222 $this->error = $this->db->lasterror();
5223 dol_syslog(get_class($this).
'::delSubproduct error='.$this->error, LOG_ERR);
5243 $sql =
"SELECT fk_product_pere, qty, incdec";
5244 $sql .=
" FROM ".$this->db->prefix().
"product_association";
5245 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5246 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
5248 $result = $this->db->query($sql);
5250 $num = $this->db->num_rows($result);
5253 $obj = $this->db->fetch_object($result);
5255 $this->is_sousproduit_qty = $obj->qty;
5256 $this->is_sousproduit_incdec = $obj->incdec;
5287 dol_syslog(get_class($this).
"::add_fournisseur id_fourn = ".$id_fourn.
" ref_fourn=".$ref_fourn.
" quantity=".$quantity, LOG_DEBUG);
5294 $sql =
"SELECT rowid, fk_product";
5295 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5296 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5297 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5298 $sql .=
" AND fk_product <> ".((int) $this->
id);
5299 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5301 $resql = $this->db->query($sql);
5303 $obj = $this->db->fetch_object($resql);
5306 $this->product_id_already_linked = $obj->fk_product;
5309 $this->db->free($resql);
5313 $sql =
"SELECT rowid";
5314 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5315 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5317 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5319 $sql .=
" AND (ref_fourn = '' OR ref_fourn IS NULL)";
5321 $sql .=
" AND quantity = ".((float) $quantity);
5322 $sql .=
" AND fk_product = ".((int) $this->
id);
5323 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5325 $resql = $this->db->query($sql);
5327 $obj = $this->db->fetch_object($resql);
5331 $sql =
"INSERT INTO ".$this->db->prefix().
"product_fournisseur_price(";
5334 $sql .=
", fk_product";
5336 $sql .=
", ref_fourn";
5337 $sql .=
", quantity";
5338 $sql .=
", fk_user";
5340 $sql .=
") VALUES (";
5341 $sql .=
"'".$this->db->idate($now).
"'";
5342 $sql .=
", ".((int)
$conf->entity);
5343 $sql .=
", ".((int) $this->
id);
5344 $sql .=
", ".((int) $id_fourn);
5345 $sql .=
", '".$this->db->escape($ref_fourn).
"'";
5346 $sql .=
", ".((float) $quantity);
5347 $sql .=
", ".((int) $user->id);
5351 if ($this->db->query($sql)) {
5352 $this->product_fourn_price_id = $this->db->last_insert_id($this->db->prefix().
"product_fournisseur_price");
5355 $this->error = $this->db->lasterror();
5360 $this->product_fourn_price_id = $obj->rowid;
5364 $this->error = $this->db->lasterror();
5383 $sql =
"SELECT DISTINCT p.fk_soc";
5384 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as p";
5385 $sql .=
" WHERE p.fk_product = ".((int) $this->
id);
5386 $sql .=
" AND p.entity = ".((int)
$conf->entity);
5388 $result = $this->db->query($sql);
5390 $num = $this->db->num_rows($result);
5393 $obj = $this->db->fetch_object($result);
5394 $list[$i] = $obj->fk_soc;
5420 $sql =
"INSERT INTO ".$this->db->prefix().
"product_price (";
5422 $sql .=
", fk_product";
5423 $sql .=
", date_price";
5424 $sql .=
", price_level";
5426 $sql .=
", price_ttc";
5427 $sql .=
", price_min";
5428 $sql .=
", price_min_ttc";
5429 $sql .=
", price_base_type";
5430 $sql .=
", price_label";
5431 $sql .=
", default_vat_code";
5433 $sql .=
", recuperableonly";
5434 $sql .=
", localtax1_tx";
5435 $sql .=
", localtax1_type";
5436 $sql .=
", localtax2_tx";
5437 $sql .=
", localtax2_type";
5438 $sql .=
", fk_user_author";
5440 $sql .=
", price_by_qty";
5441 $sql .=
", fk_price_expression";
5442 $sql .=
", fk_multicurrency";
5443 $sql .=
", multicurrency_code";
5444 $sql .=
", multicurrency_tx";
5445 $sql .=
", multicurrency_price";
5446 $sql .=
", multicurrency_price_ttc";
5450 $sql .=
", ".((int) $toId);
5451 $sql .=
", '".$this->db->idate($now).
"'";
5452 $sql .=
", price_level";
5454 $sql .=
", price_ttc";
5455 $sql .=
", price_min";
5456 $sql .=
", price_min_ttc";
5457 $sql .=
", price_base_type";
5458 $sql .=
", price_label";
5459 $sql .=
", default_vat_code";
5461 $sql .=
", recuperableonly";
5462 $sql .=
", localtax1_tx";
5463 $sql .=
", localtax1_type";
5464 $sql .=
", localtax2_tx";
5465 $sql .=
", localtax2_type";
5466 $sql .=
", ".((int) $user->id);
5468 $sql .=
", price_by_qty";
5469 $sql .=
", fk_price_expression";
5470 $sql .=
", fk_multicurrency";
5471 $sql .=
", multicurrency_code";
5472 $sql .=
", multicurrency_tx";
5473 $sql .=
", multicurrency_price";
5474 $sql .=
", multicurrency_price_ttc";
5475 $sql .=
" FROM ".$this->db->prefix().
"product_price ps";
5476 $sql .=
" WHERE fk_product = ".((int) $fromId);
5477 $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)";
5478 $sql .=
" ORDER BY date_price DESC";
5481 $resql = $this->db->query($sql);
5483 $this->db->rollback();
5487 $this->db->commit();
5504 $sql =
'INSERT INTO '.$this->db->prefix().
'product_association (fk_product_pere, fk_product_fils, qty, incdec)';
5505 $sql .=
" SELECT ".((int) $toId).
", fk_product_fils, qty, incdec FROM ".$this->db->prefix().
"product_association";
5506 $sql .=
" WHERE fk_product_pere = ".((int) $fromId);
5508 dol_syslog(get_class($this).
'::clone_association', LOG_DEBUG);
5509 if (!$this->db->query($sql)) {
5510 $this->db->rollback();
5514 $this->db->commit();
5547 $sql =
"INSERT ".$this->db->prefix().
"product_fournisseur_price (";
5548 $sql .=
" datec, fk_product, fk_soc, price, quantity, fk_user, tva_tx)";
5549 $sql .=
" SELECT '".$this->db->idate($now).
"', ".((int) $toId).
", fk_soc, price, quantity, fk_user, tva_tx";
5550 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5551 $sql .=
" WHERE fk_product = ".((int) $fromId);
5553 dol_syslog(get_class($this).
'::clone_fournisseurs', LOG_DEBUG);
5554 $resql = $this->db->query($sql);
5556 $this->db->rollback();
5559 $this->db->commit();
5577 public function fetch_prod_arbo(
$prod, $compl_path =
'', $multiply = 1, $level = 1, $id_parent = 0, $ignore_stock_load = 0)
5582 if ($multiply < 1) {
5583 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);
5588 foreach (
$prod as $id_product => $desc_pere) {
5589 if (is_array($desc_pere)) {
5590 $id = (!empty($desc_pere[0]) ? $desc_pere[0] :
'');
5591 $nb = (!empty($desc_pere[1]) ? $desc_pere[1] :
'');
5592 $type = (!empty($desc_pere[2]) ? $desc_pere[2] :
'');
5593 $label = (!empty($desc_pere[3]) ? $desc_pere[3] :
'');
5594 $incdec = (!empty($desc_pere[4]) ? $desc_pere[4] : 0);
5597 if (is_null($tmpproduct)) {
5598 $tmpproduct =
new Product($this->db);
5600 $tmpproduct->fetch($id);
5602 if (empty($ignore_stock_load) && ($tmpproduct->isProduct() ||
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES'))) {
5603 $tmpproduct->load_stock(
'nobatch,novirtual');
5606 $this->res[] = array(
5608 'id_parent' => $id_parent,
5609 'ref' => $tmpproduct->ref,
5611 'nb_total' => $nb * $multiply,
5612 'stock' => $tmpproduct->stock_reel,
5613 'stock_alert' => $tmpproduct->seuil_stock_alerte,
5615 'fullpath' => $compl_path.$label,
5617 'desiredstock' => $tmpproduct->desiredstock,
5619 'incdec' => $incdec,
5620 'entity' => $tmpproduct->entity
5624 if (isset($desc_pere[
'childs']) && is_array($desc_pere[
'childs'])) {
5625 if (!is_int($desc_pere[1] * $multiply)) {
5626 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);
5630 $this->
fetch_prod_arbo($desc_pere[
'childs'], $compl_path.$desc_pere[3].
" -> ", (
int) ceil($desc_pere[1] * $multiply), $level + 1, $id, $ignore_stock_load);
5648 $this->res = array();
5649 if (isset($this->sousprods) && is_array($this->sousprods)) {
5650 foreach ($this->sousprods as $prod_name => $desc_product) {
5651 if (is_array($desc_product)) {
5652 $this->
fetch_prod_arbo($desc_product,
"", $multiply, 1, $this->
id, $ignore_stock_load);
5671 $sql =
"SELECT COUNT(pa.rowid) as nb";
5672 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa";
5674 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id).
" OR pa.fk_product_pere = ".((int) $this->
id);
5675 } elseif ($mode == -1) {
5676 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id);
5677 } elseif ($mode == 1) {
5678 $sql .=
" WHERE pa.fk_product_pere = ".((int) $this->
id);
5681 $resql = $this->db->query($sql);
5683 $obj = $this->db->fetch_object($resql);
5685 $nb = (int) $obj->nb;
5705 $sql =
"SELECT count(rowid) as nb FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_parent = ".((int) $this->
id);
5706 $sql .=
" AND entity IN (".getEntity(
'product').
")";
5708 $resql = $this->db->query($sql);
5710 $obj = $this->db->fetch_object($resql);
5712 $nb = (int) $obj->nb;
5728 $sql =
"SELECT rowid FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_child = ".((int) $this->
id).
" AND entity IN (".
getEntity(
'product').
")";
5730 $query = $this->db->query($sql);
5733 if (!$this->db->num_rows($query)) {
5754 $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";
5755 $sql .=
", p.tosell as status, p.tobuy as status_buy";
5756 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa,";
5757 $sql .=
" ".$this->db->prefix().
"product as p";
5758 $sql .=
" WHERE p.rowid = pa.fk_product_pere";
5759 $sql .=
" AND pa.fk_product_fils = ".((int) $this->
id);
5761 $res = $this->db->query($sql);
5764 while ($record = $this->db->fetch_array($res)) {
5766 $prods[$record[
'id']] = array();
5767 $prods[$record[
'id']][
'id'] = $record[
'rowid'];
5768 $prods[$record[
'id']][
'ref'] = $record[
'ref'];
5769 $prods[$record[
'id']][
'label'] = $record[
'label'];
5770 $prods[$record[
'id']][
'qty'] = $record[
'qty'];
5771 $prods[$record[
'id']][
'incdec'] = $record[
'incdec'];
5772 $prods[$record[
'id']][
'fk_product_type'] = $record[
'fk_product_type'];
5773 $prods[$record[
'id']][
'entity'] = $record[
'entity'];
5774 $prods[$record[
'id']][
'status'] = $record[
'status'];
5775 $prods[$record[
'id']][
'status_buy'] = $record[
'status_buy'];
5794 public function getChildsArbo($id, $firstlevelonly = 0, $level = 1, $parents = array())
5800 $sql =
"SELECT p.rowid, p.ref, p.label as label, p.fk_product_type,";
5801 $sql .=
" pa.qty as qty, pa.fk_product_fils as id, pa.incdec,";
5802 $sql .=
" pa.rowid as fk_association, pa.rang";
5803 $sql .=
" FROM ".$this->db->prefix().
"product as p,";
5804 $sql .=
" ".$this->db->prefix().
"product_association as pa";
5805 $sql .=
" WHERE p.rowid = pa.fk_product_fils";
5806 $sql .=
" AND pa.fk_product_pere = ".((int) $id);
5807 $sql .=
" AND pa.fk_product_fils <> ".((int) $id);
5808 $sql .=
" ORDER BY pa.rang";
5810 dol_syslog(get_class($this).
'::getChildsArbo id='.$id.
' level='.$level.
' parents='.(is_array($parents) ? implode(
',', $parents) : $parents), LOG_DEBUG);
5817 $res = $this->db->query($sql);
5820 if ($this->db->num_rows($res) > 0) {
5824 while ($rec = $this->db->fetch_array($res)) {
5825 if (in_array($rec[
'id'], $parents)) {
5826 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);
5830 $prods[$rec[
'rowid']] = array(
5833 2 => $rec[
'fk_product_type'],
5834 3 => $this->db->escape($rec[
'label']),
5835 4 => $rec[
'incdec'],
5837 6 => $rec[
'fk_association'],
5842 if (empty($firstlevelonly)) {
5843 $listofchilds = $this->
getChildsArbo($rec[
'rowid'], 0, $level + 1, $parents);
5844 foreach ($listofchilds as $keyChild => $valueChild) {
5845 $prods[$rec[
'rowid']][
'childs'][$keyChild] = $valueChild;
5869 foreach ($this->
getChildsArbo($this->
id) as $keyChild => $valueChild) {
5870 $parent[$this->label][$keyChild] = $valueChild;
5872 foreach ($parent as $key => $value) {
5873 $this->sousprods[$key] = $value;
5886 global
$conf, $langs, $user;
5888 $langs->loadLangs(array(
'products',
'other'));
5891 $nofetch = !empty($params[
'nofetch']);
5894 return [
'optimize' => $langs->trans(
"ShowProduct")];
5898 $permissiontoreadproduct = 0;
5899 if ($this->
type == self::TYPE_PRODUCT && $user->hasRight(
'product',
'read')) {
5900 $permissiontoreadproduct = 1;
5902 if ($this->
type == self::TYPE_SERVICE && $user->hasRight(
'service',
'read')) {
5903 $permissiontoreadproduct = 1;
5906 if (!empty($this->entity) && $permissiontoreadproduct) {
5907 $tmpphoto = $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 80, 0, 0, 0, 0,
'1');
5908 if ($this->nbphoto > 0) {
5909 $datas[
'photo'] =
'<div class="photointooltip floatright">'.
"\n" . $tmpphoto .
'</div>';
5914 $datas[
'picto'] =
img_picto(
'',
'product').
' <u class="paddingrightonly">'.$langs->trans(
"Product").
'</u>';
5916 $datas[
'picto'] =
img_picto(
'',
'service').
' <u class="paddingrightonly">'.$langs->trans(
"Service").
'</u>';
5918 if (isset($this->
status) && isset($this->status_buy)) {
5919 $datas[
'status'] =
' '.$this->getLibStatut(5, 0) .
' '.$this->getLibStatut(5, 1);
5922 if (!empty($this->
ref)) {
5923 $datas[
'ref'] =
'<br><b>'.$langs->trans(
'ProductRef').
':</b> '.$this->ref;
5925 if (!empty($this->label)) {
5926 $datas[
'label'] =
'<br><b>'.$langs->trans(
'ProductLabel').
':</b> '.$this->label.
'<br>';
5929 if ($permissiontoreadproduct) {
5934 $datas[
'stockmanaged'] =
"<br><b>".$langs->trans(
"StockableProduct").
'</b>: '.
yn($this->
isStockManaged());
5938 $langs->load(
"productbatch");
5939 $datas[
'batchstatus'] =
"<br><b>".$langs->trans(
"ManageLotSerial").
'</b>: '.$this->
getLibStatut(0, 2);
5940 if ($this->status_batch) {
5941 $datas[
'batchdlc'] =
"<br><b>".$langs->trans(
"BatchSellOrEatByMandatoryList", $langs->transnoentitiesnoconv(
"SellByDate"), $langs->transnoentitiesnoconv(
"EatByDate")).
'</b>: '.$this->
getSellOrEatByMandatoryLabel();
5946 $datas[
'barcode'] =
'<br><b>'.$langs->trans(
'BarCode').
':</b> '.$this->barcode;
5950 if ($this->weight) {
5951 $datas[
'weight'] =
"<br><b>".$langs->trans(
"Weight").
'</b>: '.$this->weight.
' '.
measuringUnitString(0,
"weight", $this->weight_units);
5954 if ($this->length) {
5955 $labelsize .=
"<b>".$langs->trans(
"Length").
'</b>: '.$this->length.
' '.
measuringUnitString(0,
'size', $this->length_units);
5958 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Width").
'</b>: '.$this->width.
' '.
measuringUnitString(0,
'size', $this->width_units);
5960 if ($this->height) {
5961 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Height").
'</b>: '.$this->height.
' '.
measuringUnitString(0,
'size', $this->height_units);
5964 $datas[
'size'] =
"<br>".$labelsize;
5967 $labelsurfacevolume =
"";
5968 if ($this->surface) {
5969 $labelsurfacevolume .=
"<b>".$langs->trans(
"Surface").
'</b>: '.$this->surface.
' '.
measuringUnitString(0,
'surface', $this->surface_units);
5971 if ($this->volume) {
5972 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Volume").
'</b>: '.$this->volume.
' '.
measuringUnitString(0,
'volume', $this->volume_units);
5974 if ($labelsurfacevolume) {
5975 $datas[
'surface'] =
"<br>" . $labelsurfacevolume;
5978 if ($this->
isService() && !empty($this->duration_value)) {
5980 $datas[
'duration'] =
'<br><b>'.$langs->trans(
"Duration").
':</b> '.$this->duration_value;
5981 if ($this->duration_value > 1) {
5982 $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"));
5983 } elseif ($this->duration_value > 0) {
5984 $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"));
5986 $datas[
'duration'] .= (!empty($this->duration_unit) && isset($dur[$this->duration_unit]) ?
" ".$langs->trans($dur[$this->duration_unit]) :
'');
5988 if (empty($user->socid)) {
5989 if ($this->
isStockManaged() && isset($this->pmp) && $this->pmp) {
5990 $datas[
'pmp'] =
"<br><b>".$langs->trans(
"PMPValue").
'</b>: '.
price($this->pmp, 0,
'', 1, -1, -1,
$conf->currency);
5994 if ($this->
status && isset($this->accountancy_code_sell)) {
5995 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5996 $selllabel =
'<br>';
5997 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellCode').
':</b> '.
length_accountg($this->accountancy_code_sell);
5998 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellIntraCode').
':</b> '.
length_accountg($this->accountancy_code_sell_intra);
5999 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellExportCode').
':</b> '.
length_accountg($this->accountancy_code_sell_export);
6000 $datas[
'accountancysell'] = $selllabel;
6002 if ($this->status_buy && isset($this->accountancy_code_buy)) {
6003 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
6005 if (empty($this->
status)) {
6006 $buylabel .=
'<br>';
6008 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyCode').
':</b> '.
length_accountg($this->accountancy_code_buy);
6009 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyIntraCode').
':</b> '.
length_accountg($this->accountancy_code_buy_intra);
6010 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyExportCode').
':</b> '.
length_accountg($this->accountancy_code_buy_export);
6011 $datas[
'accountancybuy'] = $buylabel;
6017 require_once DOL_DOCUMENT_ROOT .
'/categories/class/categorie.class.php';
6018 $form =
new Form($this->db);
6019 $datas[
'categories'] =
'<br>' . $form->showCategories($this->
id, Categorie::TYPE_PRODUCT, 1);
6039 public function getNomUrl($withpicto = 0, $option =
'', $maxlength = 0, $save_lastsearch_value = -1, $notooltip = 0, $morecss =
'', $add_label = 0, $sep =
' - ')
6041 global $langs, $hookmanager;
6043 include_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
6049 $newref =
dol_trunc($newref, $maxlength,
'middle');
6053 'objecttype' => ($this->
type == 1 ?
'service' :
'product'),
6054 'option' => $option,
6057 $classfortooltip =
'classfortooltip';
6060 $classfortooltip =
'classforajaxtooltip';
6061 $dataparams =
' data-params="'.dol_escape_htmltag(json_encode($params)).
'"';
6068 if (empty($notooltip)) {
6070 $label = $langs->trans(
"ShowProduct");
6071 $linkclose .=
' alt="'.dol_escape_htmltag($label, 1, 1).
'"';
6073 $linkclose .= ($label ?
' title="'.dol_escape_htmltag($label, 1, 1).
'"' :
' title="tocomplete"');
6074 $linkclose .= $dataparams.
' class="nowraponall '.$classfortooltip.($morecss ?
' '.$morecss :
'').
'"';
6076 $linkclose =
' class="nowraponall'.($morecss ?
' '.$morecss :
'').
'"';
6079 if ($option ==
'supplier' || $option ==
'category') {
6080 $url = DOL_URL_ROOT.
'/product/price_suppliers.php?id='.$this->id;
6081 } elseif ($option ==
'stock') {
6082 $url = DOL_URL_ROOT.
'/product/stock/product.php?id='.$this->id;
6083 } elseif ($option ==
'composition') {
6084 $url = DOL_URL_ROOT.
'/product/composition/card.php?id='.$this->id;
6086 $url = DOL_URL_ROOT.
'/product/card.php?id='.$this->id;
6089 if ($option !==
'nolink') {
6091 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
6092 if ($save_lastsearch_value == -1 && isset($_SERVER[
"PHP_SELF"]) && preg_match(
'/list\.php/', $_SERVER[
"PHP_SELF"])) {
6093 $add_save_lastsearch_values = 1;
6095 if ($add_save_lastsearch_values) {
6096 $url .=
'&save_lastsearch_values=1';
6100 $linkstart =
'<a href="'.$url.
'"';
6101 $linkstart .= $linkclose.
'>';
6104 $result .= $linkstart;
6107 $result .= (
img_object(($notooltip ?
'' : $label),
'product',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
6110 $result .= (
img_object(($notooltip ?
'' : $label),
'service',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
6113 $result .=
'<span class="aaa">'.dol_escape_htmltag($newref).
'</span>';
6114 $result .= $linkend;
6115 if ($withpicto != 2) {
6116 $result .= (($add_label && $this->label) ? $sep.dol_trunc($this->label, ($add_label > 1 ? $add_label : 0)) :
'');
6120 $hookmanager->initHooks(array(
'productdao'));
6121 $parameters = array(
'id' => $this->
id,
'getnomurl' => &$result,
'label' => &$label);
6122 $reshook = $hookmanager->executeHooks(
'getNomUrl', $parameters, $this, $action);
6124 $result = $hookmanager->resPrint;
6126 $result .= $hookmanager->resPrint;
6143 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
6147 $langs->load(
"products");
6148 $outputlangs->load(
"products");
6155 $modelpath =
"core/modules/product/doc/";
6157 return $this->
commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
6173 return $this->
LibStatut($this->status_buy, $mode, $type);
6175 return $this->
LibStatut($this->status_batch, $mode, $type);
6178 return $this->
LibStatut($this->status_buy, $mode, $type);
6196 $labelStatus = $labelStatusShort =
'';
6198 $langs->load(
'products');
6200 $langs->load(
"productbatch");
6206 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial')));
6207 return dolGetStatus($label);
6209 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort')));
6210 return dolGetStatus($label);
6214 return dolGetStatus($langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch'),
'',
'', empty($status) ?
'status5' :
'status4', 3,
'dot');
6220 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'));
6224 $statuttrans = empty($status) ?
'status5' :
'status4';
6229 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSellShort');
6230 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSell');
6231 } elseif ($type == 1) {
6232 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuyShort');
6233 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuy');
6234 } elseif ($type == 2) {
6235 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch');
6236 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort');
6238 } elseif ($status == 1) {
6241 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSellShort');
6242 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSell');
6243 } elseif ($type == 1) {
6244 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBuyShort');
6245 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBuy');
6246 } elseif ($type == 2) {
6247 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBatch');
6248 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort');
6250 } elseif ($type == 2 && $status == 2) {
6251 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSerial');
6252 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort');
6256 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'),
'',
'',
'status0', 0);
6258 return dolGetStatus($labelStatus, $labelStatusShort,
'', $statuttrans, $mode);
6272 $langs->load(
'products');
6275 if (isset($this->finished) && $this->finished >= 0) {
6276 $sql =
"SELECT label, code FROM ".$this->db->prefix().
"c_product_nature where code = ".((int) $this->finished).
" AND active=1";
6277 $resql = $this->db->query($sql);
6279 $this->error = $this->db->error().
' sql='.$sql;
6280 dol_syslog(__METHOD__.
' Error '.$this->error, LOG_ERR);
6282 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
6283 $label = $langs->trans($res[
'label']);
6285 $this->db->free($resql);
6309 public function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label =
'', $price = 0, $inventorycode =
'', $origin_element =
'', $origin_id =
null, $disablestockchangeforsubproduct = 0, $extrafields =
null)
6315 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6318 $nbpiece = (float) $nbpiece;
6323 $nbpiece = abs($nbpiece);
6330 $movementstock->setOrigin($origin_element, (
int) $origin_id);
6331 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'',
'',
'',
'',
false, 0, $disablestockchangeforsubproduct);
6335 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6336 $movementstock->array_options = $array_options;
6337 $movementstock->insertExtraFields();
6339 $this->db->commit();
6344 $this->db->rollback();
6373 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)
6379 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6382 $nbpiece = (float) $nbpiece;
6387 $nbpiece = abs($nbpiece);
6395 $movementstock->setOrigin($origin_element, (
int) $origin_id);
6396 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'', $dlc, $dluo, $lot,
false, 0, $disablestockchangeforsubproduct, 0, $force_update_batch);
6400 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6401 $movementstock->array_options = $array_options;
6402 $movementstock->insertExtraFields();
6404 $this->db->commit();
6407 $this->error = $movementstock->error;
6408 $this->errors = $movementstock->errors;
6410 $this->db->rollback();
6430 public function load_stock($option =
'', $includedraftpoforvirtual =
null, $dateofvirtualstock =
null)
6433 $this->stock_reel = 0;
6434 $this->stock_warehouse = array();
6435 $this->stock_theorique = 0;
6438 $warehouseStatus = array();
6439 if (preg_match(
'/warehouseclosed/', $option)) {
6442 if (preg_match(
'/warehouseopen/', $option)) {
6445 if (preg_match(
'/warehouseinternal/', $option)) {
6453 $sql =
"SELECT ps.rowid, ps.reel, ps.fk_entrepot";
6454 $sql .=
" FROM ".$this->db->prefix().
"product_stock as ps";
6455 $sql .=
", ".$this->db->prefix().
"entrepot as w";
6456 $sql .=
" WHERE w.entity IN (".getEntity(
'stock').
")";
6457 $sql .=
" AND w.rowid = ps.fk_entrepot";
6458 $sql .=
" AND ps.fk_product = ".((int) $this->
id);
6459 if (count($warehouseStatus)) {
6460 $sql .=
" AND w.statut IN (".$this->db->sanitize(implode(
',', $warehouseStatus)).
")";
6463 $sql .=
" ORDER BY ps.reel ".(getDolGlobalString(
'DO_NOT_TRY_TO_DEFRAGMENT_STOCKS_WAREHOUSE') ?
'DESC' :
'ASC');
6465 dol_syslog(get_class($this).
"::load_stock", LOG_DEBUG);
6466 $result = $this->db->query($sql);
6468 $num = $this->db->num_rows($result);
6472 $row = $this->db->fetch_object($result);
6473 $this->stock_warehouse[$row->fk_entrepot] =
new stdClass();
6474 $this->stock_warehouse[$row->fk_entrepot]->real = $row->reel;
6475 $this->stock_warehouse[$row->fk_entrepot]->id = $row->rowid;
6476 if ((!preg_match(
'/nobatch/', $option)) && $this->
hasbatch()) {
6477 $this->stock_warehouse[$row->fk_entrepot]->detail_batch =
Productbatch::findAll($this->db, $row->rowid, 1, $this->id);
6479 $this->stock_reel += $row->reel;
6482 $this->stock_reel = (float)
price2num($this->stock_reel,
'MS');
6484 $this->db->free($result);
6486 if (!preg_match(
'/novirtual/', $option)) {
6492 $this->error = $this->db->lasterror();
6511 global $hookmanager, $action;
6513 $stock_commande_client = 0;
6514 $stock_commande_fournisseur = 0;
6515 $stock_sending_client = 0;
6516 $stock_reception_fournisseur = 0;
6517 $stock_inproduction = 0;
6526 $stock_commande_client = $this->stats_commande[
'qty'];
6529 require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expedition.class.php';
6530 $filterShipmentStatus =
'';
6540 $stock_sending_client = $this->stats_expedition[
'qty'];
6544 $filterStatus =
getDolGlobalString(
'SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK',
'3,4');
6545 if (isset($includedraftpoforvirtual)) {
6546 $filterStatus =
'0,1,2,'.$filterStatus;
6552 $stock_commande_fournisseur = $this->stats_commande_fournisseur[
'qty'];
6556 $filterStatus =
'4';
6557 if (isset($includedraftpoforvirtual)) {
6558 $filterStatus =
'0,'.$filterStatus;
6564 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
6572 $stock_inproduction = $this->stats_mrptoproduce[
'qty'] - $this->stats_mrptoconsume[
'qty'];
6575 $this->stock_theorique = $this->stock_reel + $stock_inproduction;
6579 $weBillOrderOrShipmentReception =
getDolGlobalString(
'STOCK_DO_WE_BILL_ORDER_OR_SHIPMENTECEPTION_FOR_VIRTUALSTOCK',
'order');
6583 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6587 $result = $tmpnewprod->load_stats_commande(0,
'0', 1);
6588 $this->stock_theorique += $tmpnewprod->stats_commande[
'qty'];
6590 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6591 $this->stock_theorique -= $stock_commande_client;
6592 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6593 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6598 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6600 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6602 if (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER_INCLUDE_DRAFT')) {
6604 $result = $tmpnewprod->load_stats_commande_fournisseur(0,
'0', 1);
6605 $this->stock_theorique += $this->stats_commande_fournisseur[
'qty'];
6607 $this->stock_theorique -= $stock_reception_fournisseur;
6608 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6609 $this->stock_theorique += $stock_commande_fournisseur;
6610 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6611 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6614 $parameters = array(
'id' => $this->
id,
'includedraftpoforvirtual' => $includedraftpoforvirtual);
6616 $reshook = $hookmanager->executeHooks(
'loadvirtualstock', $parameters, $this, $action);
6618 $this->stock_theorique = $hookmanager->resArray[
'stock_theorique'];
6619 } elseif ($reshook == 0 && isset($hookmanager->resArray[
'stock_stats_hook'])) {
6620 $this->stock_theorique += $hookmanager->resArray[
'stock_stats_hook'];
6624 if (!empty($this->stock_warehouse) &&
getDolGlobalString(
'STOCK_ALLOW_VIRTUAL_STOCK_PER_WAREHOUSE')) {
6625 foreach ($this->stock_warehouse as $warehouseid => $stockwarehouse) {
6633 if ($this->fk_default_warehouse == $warehouseid) {
6634 $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']);
6636 $this->stock_warehouse[$warehouseid]->virtual = $this->stock_warehouse[$warehouseid]->real + $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'];
6653 $this->stock_warehouse = array();
6658 if (count($prods_arbo) > 0) {
6659 $productCachedList = array();
6660 $stockByComponentList = array();
6662 foreach ($prods_arbo as $componentArr) {
6663 $componentId = $componentArr[
'id'];
6665 if ($componentArr[
'incdec'] == 1) {
6666 if (!isset($productCachedList[$componentId])) {
6667 $componentStatic =
new self($this->db);
6668 $componentStatic->fetch($componentId);
6670 $childrenNb = $componentStatic->hasFatherOrChild(1);
6671 if ($childrenNb == 0) {
6672 $componentStatic->load_stock(
'nobatch,novirtual');
6673 if (!isset($stockByComponentList[$componentId])) {
6674 $stockByComponentList[$componentId] = array(
6678 $stockByComponentList[$componentId][
'qty_need'] += $componentArr[
'nb_total'];
6680 $productCachedList[$componentId] = $componentStatic;
6685 if (!empty($stockByComponentList)) {
6686 foreach ($stockByComponentList as $componentId => $stockByComponentArr) {
6687 if (!isset($productCachedList[$componentId])) {
6688 $componentStatic =
new self($this->db);
6689 $componentStatic->fetch($componentId);
6690 $componentStatic->load_stock(
'nobatch,novirtual');
6691 $productCachedList[$componentId] = $componentStatic;
6693 $component = $productCachedList[$componentId];
6696 if ($component->stock_reel < $stockByComponentArr[
'qty_need']) {
6699 $this->error =
'Not enough component [id='.$componentId.
'] in stock, real='.$component->stock_reel.
' and need='.$stockByComponentArr[
'qty_need'];
6700 $this->errors[] = $this->error;
6701 dol_syslog(__METHOD__.
' : '.$this->error, LOG_ERR);
6703 if (!empty($component->stock_warehouse)) {
6704 foreach ($component->stock_warehouse as $warehouseId => $warehouseObj) {
6705 $kitWarehouseAvailable =
new stdClass();
6706 $kitWarehouseAvailable->id = $warehouseObj->id;
6707 $kitWarehouseAvailable->real = $qtyWish;
6708 $this->stock_warehouse[$warehouseId] = $kitWarehouseAvailable;
6717 } elseif (
getDolGlobalInt(
'PRODUIT_SOUSPRODUITS_ALSO_ENABLE_PARENT_STOCK_MOVE') && empty($productCachedList)) {
6741 $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";
6742 $sql .=
" WHERE pb.fk_product_stock = ps.rowid AND ps.fk_product = ".((int) $this->
id).
" AND pb.batch = '".$this->db->escape($batch).
"'";
6743 $sql .=
" GROUP BY pb.batch, pb.eatby, pb.sellby";
6744 dol_syslog(get_class($this).
"::loadBatchInfo load first entry found for lot/serial = ".$batch, LOG_DEBUG);
6745 $resql = $this->db->query($sql);
6747 $num = $this->db->num_rows($resql);
6750 $obj = $this->db->fetch_object($resql);
6751 $result[] = array(
'batch' => $batch,
'eatby' => $this->db->jdate($obj->eatby),
'sellby' => $this->db->jdate($obj->sellby),
'qty' => $obj->qty);
6757 $this->db->rollback();
6774 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6780 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos";
6782 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product').dol_sanitizeFileName($this->
ref);
6787 $dir_osencoded = $dir;
6789 if (is_dir($dir_osencoded)) {
6790 $originImage = $dir.
'/'.$file[
'name'];
6801 if (is_numeric($result) && $result > 0) {
6818 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6819 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6823 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos/";
6825 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product');
6829 if (file_exists($dir_osencoded)) {
6830 $handle = opendir($dir_osencoded);
6831 if (is_resource($handle)) {
6832 while (($file = readdir($handle)) !==
false) {
6834 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6857 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6858 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6864 $handle = @opendir($dir_osencoded);
6865 if (is_resource($handle)) {
6866 while (($file = readdir($handle)) !==
false) {
6868 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6875 $photo_vignette =
'';
6877 if (preg_match(
'/('.$this->regeximgext.
')$/i', $photo, $regs)) {
6878 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $photo).
'_small'.$regs[0];
6881 $dirthumb = $dir.
'thumbs/';
6885 $obj[
'photo'] = $photo;
6886 if ($photo_vignette &&
dol_is_file($dirthumb.$photo_vignette)) {
6887 $obj[
'photo_vignette'] =
'thumbs/'.$photo_vignette;
6889 $obj[
'photo_vignette'] =
"";
6892 $tabobj[$nbphoto - 1] = $obj;
6895 if ($nbmax && $nbphoto >= $nbmax) {
6917 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6918 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6920 $dir = dirname($file).
'/';
6921 $dirthumb = $dir.
'/thumbs/';
6922 $filename = preg_replace(
'/'.preg_quote($dir,
'/').
'/i',
'', $file);
6928 if (preg_match(
'/('.$this->regeximgext.
')$/i', $filename, $regs)) {
6929 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_small'.$regs[0];
6930 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6934 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_mini'.$regs[0];
6935 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6952 $infoImg = getimagesize($file_osencoded);
6953 $this->imgWidth = $infoImg[0];
6954 $this->imgHeight = $infoImg[1];
6964 global $hookmanager;
6966 $this->nb = array();
6968 $sql =
"SELECT count(p.rowid) as nb, fk_product_type";
6969 $sql .=
" FROM ".$this->db->prefix().
"product as p";
6970 $sql .=
' WHERE p.entity IN ('.getEntity($this->element, 1).
')';
6972 if (is_object($hookmanager)) {
6973 $parameters = array();
6974 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
6975 $sql .= $hookmanager->resPrint;
6977 $sql .=
' GROUP BY fk_product_type';
6979 $resql = $this->db->query($sql);
6981 while ($obj = $this->db->fetch_object($resql)) {
6982 if ($obj->fk_product_type == 1) {
6983 $this->nb[
"services"] = $obj->nb;
6985 $this->nb[
"products"] = $obj->nb;
6988 $this->db->free($resql);
6992 $this->error = $this->db->error();
7034 return $this->mandatory_period == 1;
7044 return $this->status_batch > 0;
7064 $dirsociete = array_merge(array(
'/core/modules/barcode/'),
$conf->modules_parts[
'barcode']);
7065 foreach ($dirsociete as $dirroot) {
7073 '@phan-var-force ModeleNumRefBarCode $mod';
7075 $result = $mod->getNextValue(
$object, $type);
7077 dol_syslog(get_class($this).
"::get_barcode barcode=".$result.
" module=".$var);
7094 $this->specimen = 1;
7096 $this->
ref =
'PRODUCT_SPEC';
7097 $this->label =
'PRODUCT SPECIMEN';
7098 $this->
description =
'This is description of this product specimen that was created the '.dol_print_date($now,
'dayhourlog').
'.';
7099 $this->specimen = 1;
7100 $this->country_id = 1;
7102 $this->status_buy = 1;
7104 $this->sell_or_eat_by_mandatory = 0;
7105 $this->note_private =
'This is a comment (private)';
7106 $this->note_public =
'This is a comment (public)';
7107 $this->date_creation = $now;
7108 $this->date_modification = $now;
7111 $this->weight_units = 3;
7114 $this->length_units = 1;
7116 $this->width_units = 0;
7117 $this->height =
null;
7118 $this->height_units =
null;
7120 $this->surface = 30;
7121 $this->surface_units = 0;
7122 $this->volume = 300;
7123 $this->volume_units = 0;
7125 $this->barcode = -1;
7143 if (empty($this->fk_unit)) {
7146 if (empty($outputlangs)) {
7147 $outputlangs = $langs;
7150 $outputlangs->load(
'products');
7153 $sql =
"SELECT code, label, short_label FROM ".$this->db->prefix().
"c_units where rowid = ".((int) $this->fk_unit);
7155 $resql = $this->db->query($sql);
7157 $this->error = $this->db->error();
7158 dol_syslog(get_class($this).
"::getLabelOfUnit Error ".$this->error, LOG_ERR);
7160 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
7161 if ($type ==
'short') {
7163 $label = $outputlangs->transnoentitiesnoconv($res[
'short_label']);
7165 $label = $outputlangs->trans($res[
'short_label']);
7167 } elseif ($type ==
'code') {
7168 $label = $res[
'code'];
7170 if ($outputlangs->trans(
'unit'.$res[
'code']) ==
'unit'.$res[
'code']) {
7172 $label = $res[
'label'];
7176 $label = $outputlangs->transnoentitiesnoconv(
'unit'.$res[
'code']);
7178 $label = $outputlangs->trans(
'unit'.$res[
'code']);
7183 $this->db->free($resql);
7197 $maxpricesupplier = 0;
7200 include_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.product.class.php';
7202 $product_fourn_list = $product_fourn->list_product_fournisseur_price($this->
id,
'',
'');
7204 if (is_array($product_fourn_list) && count($product_fourn_list) > 0) {
7205 foreach ($product_fourn_list as $productfourn) {
7206 if ($productfourn->fourn_unitprice > $maxpricesupplier) {
7207 $maxpricesupplier = $productfourn->fourn_unitprice;
7215 return $maxpricesupplier;
7231 require_once DOL_DOCUMENT_ROOT.
'/categories/class/categorie.class.php';
7232 return parent::setCategoriesCommon($categories, Categorie::TYPE_PRODUCT);
7246 'product_customer_price',
7247 'product_customer_price_log'
7266 $sql =
"SELECT rowid, level, fk_level, var_percent, var_min_percent FROM ".$this->db->prefix().
"product_pricerules";
7267 $query = $this->db->query($sql);
7271 while ($result = $this->db->fetch_object($query)) {
7272 $rules[$result->level] = $result;
7281 for ($i = 1; $i <= $nbofproducts; $i++) {
7282 $price = $baseprice;
7283 $price_min = $baseprice;
7287 if ($i > 1 && isset($rules[$i]->var_percent) && $rules[$i]->var_percent) {
7288 $price = $prices[$rules[$i]->fk_level] * (1 + ($rules[$i]->var_percent / 100));
7291 $prices[$i] = $price;
7294 if (isset($rules[$i]->var_min_percent) && $rules[$i]->var_min_percent) {
7295 $price_min = $price * (1 - ($rules[$i]->var_min_percent / 100));
7299 $check_amount = (($price == $this->multiprices[$i]) && ($price_min == $this->multiprices_min[$i]));
7300 $check_type = ($baseprice == $this->multiprices_base_type[$i]);
7302 if ($check_amount && $check_type) {
7306 if ($this->
updatePrice($price, $price_type, $user, $price_vat, $price_min, $i, $npr, $psq, 1) < 0) {
7324 return $user->rights->produit;
7326 return $user->rights->service;
7338 $sql =
"SELECT p.rowid, p.ref, p.datec as date_creation, GREATEST(p.tms, pef.tms) as date_modification,";
7339 $sql .=
" p.fk_user_author, p.fk_user_modif";
7340 $sql .=
" FROM ".$this->db->prefix().$this->table_element.
" as p";
7341 $sql .=
" LEFT JOIN ".$this->db->prefix().$this->table_element.
"_extrafields as pef ON pef.fk_object=p.rowid";
7342 $sql .=
" WHERE p.rowid = ".((int) $id);
7344 $result = $this->db->query($sql);
7346 if ($this->db->num_rows($result)) {
7347 $obj = $this->db->fetch_object($result);
7349 $this->
id = $obj->rowid;
7350 $this->
ref = $obj->ref;
7352 $this->user_creation_id = $obj->fk_user_author;
7353 $this->user_modification_id = $obj->fk_user_modif;
7355 $this->date_creation = $this->db->jdate($obj->date_creation);
7356 $this->date_modification = $this->db->jdate($obj->date_modification);
7359 $this->db->free($result);
7373 if (empty($this->duration_value)) {
7374 $this->errors[] =
'ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
7377 if ($this->duration_unit ==
's') {
7378 $prodDurationHours = 1. / 3600;
7379 } elseif ($this->duration_unit ==
'i' || $this->duration_unit ==
'mn' || $this->duration_unit ==
'min') {
7380 $prodDurationHours = 1. / 60;
7381 } elseif ($this->duration_unit ==
'h') {
7382 $prodDurationHours = 1.;
7383 } elseif ($this->duration_unit ==
'd') {
7384 $prodDurationHours = 24.;
7385 } elseif ($this->duration_unit ==
'w') {
7386 $prodDurationHours = 24. * 7;
7387 } elseif ($this->duration_unit ==
'm') {
7388 $prodDurationHours = 24. * 30;
7389 } elseif ($this->duration_unit ==
'y') {
7390 $prodDurationHours = 24. * 365;
7392 $prodDurationHours = 0.0;
7394 $prodDurationHours *= $this->duration_value;
7396 return $prodDurationHours;
7409 global $langs,
$conf;
7411 $selected = (empty($arraydata[
'selected']) ? 0 : $arraydata[
'selected']);
7413 $return =
'<div class="box-flex-item box-flex-grow-zero">';
7414 $return .=
'<div class="info-box info-box-sm">';
7415 $return .=
'<div class="info-box-img">';
7417 if ($this->entity !==
null && $this->
is_photo_available($conf->product->multidir_output[$this->entity])) {
7418 $label .= $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 120, 160, 0, 0, 0,
'',
'photoref photokanban');
7428 $return .=
'</div>';
7429 $return .=
'<div class="info-box-content">';
7430 $return .=
'<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">' . $this->
getNomUrl() .
'</span>';
7431 if ($selected >= 0) {
7432 $return .=
'<input id="cb'.$this->id.
'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->
id.
'"'.($selected ?
' checked="checked"' :
'').
'>';
7434 $return .=
'<br><span class="info-box-label opacitymedium inline-block tdoverflowmax150 valignmiddle" title="'.dol_escape_htmltag($this->label).
'">'.
dol_escape_htmltag($this->label).
'</span>';
7435 if ($this->price_base_type ==
'TTC') {
7436 $return .=
'<br><span class="info-box-status amount">'.price($this->price_ttc).
' '.$langs->trans(
"TTC").
'</span>';
7439 $return .=
'<br><span class="info-box-status amount">'.price($this->
price).
' '.$langs->trans(
"HT").
'</span>';
7444 $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>';
7449 $return .=
'<div class="info-box-status inline-block valignmiddle">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7451 $return .=
'<div class="info-box-status inline-block valignmiddle marginleftonly paddingleft">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7453 $return .=
'</div>';
7454 $return .=
'</div>';
7455 $return .=
'</div>';
7466 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.
info($id)
Load information for tab info.
correct_stock($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $inventorycode='', $origin_element='', $origin_id=null, $disablestockchangeforsubproduct=0, $extrafields=null)
Adjust stock in a warehouse for product.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
Create a document onto disk according to template module.
static getSellOrEatByMandatoryList()
Get the array of labels of Sell by or Eat by all mandatory flags for each status.
getChildsArbo($id, $firstlevelonly=0, $level=1, $parents=array())
Return children of product $id.
load_virtual_stock($includedraftpoforvirtual=null, $dateofvirtualstock=null)
Load value ->stock_theorique of a product.
load_stats_propale($socid=0)
Charge tableau des stats propale pour le produit/service.
get_barcode($object, $type='')
Get a barcode from the module to generate barcode values.
setAccountancyCode($type, $value)
Sets an accountancy code for a product.
load_stats_facture($socid=0)
Charge tableau des stats facture pour le produit/service.
setCategories($categories)
Sets object to supplied categories.
load_stats_reception($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null)
Charge tableau des stats réception fournisseur pour le produit/service.
get_nb_propal($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in proposals in which product is included.
update($id, $user, $notrigger=0, $action='update', $updatetype=false)
Update a record into database.
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.
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.
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]]]',...