42require_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
43require_once DOL_DOCUMENT_ROOT.
'/core/class/commonobject.class.php';
44require_once DOL_DOCUMENT_ROOT.
'/product/class/productbatch.class.php';
45require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/productlot.class.php';
46require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/entrepot.class.php';
57 const SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY = 1;
58 const SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY = 2;
59 const SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT = 3;
65 public $TRIGGER_PREFIX =
'PRODUCT';
70 public $element =
'product';
75 public $table_element =
'product';
80 public $fk_element =
'fk_product';
85 protected $childtables = array(
86 'supplier_proposaldet' => array(
'name' =>
'SupplierProposal',
'parent' =>
'supplier_proposal',
'parentkey' =>
'fk_supplier_proposal'),
87 'propaldet' => array(
'name' =>
'Proposal',
'parent' =>
'propal',
'parentkey' =>
'fk_propal'),
88 'commandedet' => array(
'name' =>
'Order',
'parent' =>
'commande',
'parentkey' =>
'fk_commande'),
89 'facturedet' => array(
'name' =>
'Invoice',
'parent' =>
'facture',
'parentkey' =>
'fk_facture'),
90 'contratdet' => array(
'name' =>
'Contract',
'parent' =>
'contrat',
'parentkey' =>
'fk_contrat'),
91 'facture_fourn_det' => array(
'name' =>
'SupplierInvoice',
'parent' =>
'facture_fourn',
'parentkey' =>
'fk_facture_fourn'),
92 'commande_fournisseurdet' => array(
'name' =>
'SupplierOrder',
'parent' =>
'commande_fournisseur',
'parentkey' =>
'fk_commande'),
93 'mrp_production' => array(
'name' =>
'Mo',
'parent' =>
'mrp_mo',
'parentkey' =>
'fk_mo',
'enabled' =>
'isModEnabled("mrp")'),
94 'bom_bom' => array(
'name' =>
'BOM',
'enabled' =>
'isModEnabled("bom")'),
95 'bom_bomline' => array(
'name' =>
'BOMLine',
'parent' =>
'bom_bom',
'parentkey' =>
'fk_bom',
'enabled' =>
'isModEnabled("bom")'),
103 public $picto =
'product';
114 public $regeximgext =
'\.gif|\.jpg|\.jpeg|\.png|\.bmp|\.webp|\.xpm|\.xbm|\.avif';
168 public $price_formated;
180 public $price_ttc_formated;
194 public $price_min_ttc;
200 public $price_base_type;
210 public $multiprices = array();
214 public $multiprices_ttc = array();
218 public $multiprices_base_type = array();
222 public $multiprices_default_vat_code = array();
226 public $multiprices_min = array();
230 public $multiprices_min_ttc = array();
234 public $multiprices_tva_tx = array();
238 public $multiprices_recuperableonly = array();
244 public $price_by_qty;
248 public $prices_by_qty = array();
252 public $prices_by_qty_id = array();
256 public $prices_by_qty_list = array();
266 public $multilangs = array();
271 public $default_vat_code;
286 public $remise_percent;
291 public $localtax1_tx;
295 public $localtax2_tx;
299 public $localtax1_type;
303 public $localtax2_type;
310 public $desc_supplier;
314 public $vatrate_supplier;
318 public $default_vat_code_supplier;
323 public $fourn_multicurrency_price;
328 public $fourn_multicurrency_unitprice;
332 public $fourn_multicurrency_tx;
336 public $fourn_multicurrency_id;
340 public $fourn_multicurrency_code;
362 public $qc_frequency;
369 public $stock_reel = 0;
376 public $stock_theorique;
397 public $seuil_stock_alerte = 0;
402 public $desiredstock = 0;
407 public $duration_value;
411 public $duration_unit;
420 public $fk_default_workstation;
442 public $status_buy = 0;
464 public $fk_default_bom;
471 public $product_fourn_price_id;
493 public $status_batch = 0;
500 public $sell_or_eat_by_mandatory = 0;
507 public $batch_mask =
'';
532 public $weight_units;
540 public $length_units;
556 public $height_units;
564 public $surface_units;
572 public $volume_units;
581 public $net_measure_units;
586 public $accountancy_code_sell;
590 public $accountancy_code_sell_intra;
594 public $accountancy_code_sell_export;
598 public $accountancy_code_buy;
602 public $accountancy_code_buy_intra;
606 public $accountancy_code_buy_export;
616 public $barcode_type;
621 public $barcode_type_code;
626 public $stats_propale = array();
631 public $stats_commande = array();
636 public $stats_contrat = array();
641 public $stats_facture = array();
646 public $stats_proposal_supplier = array();
651 public $stats_commande_fournisseur = array();
656 public $stats_expedition = array();
661 public $stats_reception = array();
666 public $stats_mo = array();
671 public $stats_bom = array();
676 public $stats_mrptoconsume = array();
681 public $stats_mrptoproduce = array();
686 public $stats_facturerec = array();
691 public $stats_facture_fournisseur = array();
696 public $stats_facturefournrec = array();
711 public $product_fourn_id;
717 public $product_id_already_linked;
728 public $stock_warehouse = array();
733 public $fk_default_warehouse;
738 public $fk_price_expression;
756 public $fourn_price_base_type;
773 public $ref_supplier;
787 public $price_autogen = 0;
794 public $sousprods = array();
807 public $is_object_used;
818 public $is_sousproduit_qty;
830 public $is_sousproduit_incdec;
835 public $mandatory_period;
842 public $stockable_product = 1;
872 public $fields = array(
873 'rowid' => array(
'type' =>
'integer',
'label' =>
'TechnicalID',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'index' => 1,
'position' => 1,
'comment' =>
'Id'),
874 'ref' => array(
'type' =>
'varchar(128)',
'label' =>
'Ref',
'enabled' => 1,
'visible' => 1,
'notnull' => 1,
'showoncombobox' => 1,
'index' => 1,
'position' => 10,
'searchall' => 1,
'comment' =>
'Reference of object'),
875 'entity' => array(
'type' =>
'integer',
'label' =>
'Entity',
'enabled' => 1,
'visible' => 0,
'default' =>
'1',
'notnull' => 1,
'index' => 1,
'position' => 5),
876 'label' => array(
'type' =>
'varchar(255)',
'label' =>
'Label',
'enabled' => 1,
'visible' => 1,
'notnull' => 1,
'showoncombobox' => 2,
'position' => 15,
'csslist' =>
'tdoverflowmax250'),
877 'barcode' => array(
'type' =>
'varchar(255)',
'label' =>
'Barcode',
'enabled' =>
'isModEnabled("barcode")',
'position' => 20,
'visible' => -1,
'showoncombobox' => 3,
'cssview' =>
'tdwordbreak',
'csslist' =>
'tdoverflowmax125'),
878 'fk_barcode_type' => array(
'type' =>
'integer',
'label' =>
'BarcodeType',
'enabled' => 1,
'position' => 21,
'notnull' => 0,
'visible' => -1,),
879 'note_public' => array(
'type' =>
'html',
'label' =>
'NotePublic',
'enabled' => 1,
'visible' => 0,
'position' => 61),
880 'note' => array(
'type' =>
'html',
'label' =>
'NotePrivate',
'enabled' => 1,
'visible' => 0,
'position' => 62),
881 'datec' => array(
'type' =>
'datetime',
'label' =>
'DateCreation',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 500),
882 'tms' => array(
'type' =>
'timestamp',
'label' =>
'DateModification',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 501),
884 'fk_user_author' => array(
'type' =>
'integer:User:user/class/user.class.php',
'label' =>
'UserAuthor',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 510,
'foreignkey' =>
'llx_user.rowid'),
885 'fk_user_modif' => array(
'type' =>
'integer:User:user/class/user.class.php',
'label' =>
'UserModif',
'enabled' => 1,
'visible' => -2,
'notnull' => -1,
'position' => 511),
887 'localtax1_tx' => array(
'type' =>
'double(6,3)',
'label' =>
'Localtax1tx',
'enabled' => 1,
'position' => 150,
'notnull' => 0,
'visible' => -1,),
888 'localtax1_type' => array(
'type' =>
'varchar(10)',
'label' =>
'Localtax1type',
'enabled' => 1,
'position' => 155,
'notnull' => 1,
'visible' => -1,),
889 'localtax2_tx' => array(
'type' =>
'double(6,3)',
'label' =>
'Localtax2tx',
'enabled' => 1,
'position' => 160,
'notnull' => 0,
'visible' => -1,),
890 'localtax2_type' => array(
'type' =>
'varchar(10)',
'label' =>
'Localtax2type',
'enabled' => 1,
'position' => 165,
'notnull' => 1,
'visible' => -1,),
891 'last_main_doc' => array(
'type' =>
'varchar(255)',
'label' =>
'LastMainDoc',
'enabled' => 1,
'visible' => -1,
'position' => 170),
892 'import_key' => array(
'type' =>
'varchar(14)',
'label' =>
'ImportId',
'enabled' => 1,
'visible' => -2,
'notnull' => -1,
'index' => 0,
'position' => 1000),
895 'mandatory_period' => array(
'type' =>
'integer',
'label' =>
'mandatoryperiod',
'enabled' => 1,
'visible' => -1,
'notnull' => 1,
'default' =>
'0',
'index' => 1,
'position' => 1000),
896 'stockable_product' => array(
'type' =>
'integer',
'label' =>
'stockable_product',
'enabled' => 1,
'visible' => 1,
'default' =>
'1',
'notnull' => 1,
'index' => 1,
'position' => 502),
912 const ENABLED_STOCK = 1;
923 $this->ismultientitymanaged = 1;
924 $this->isextrafieldmanaged = 1;
937 $this->
ref = trim($this->
ref);
965 public function create($user, $notrigger = 0)
967 global
$conf, $langs;
973 $this->
ref = trim($this->
ref);
977 $this->label = trim($this->label);
978 $this->price_ttc = (float)
price2num($this->price_ttc);
980 $this->price_min_ttc = (float)
price2num($this->price_min_ttc);
981 $this->price_min = (float)
price2num($this->price_min);
982 $this->price_label = trim($this->price_label);
983 if (empty($this->tva_tx)) {
986 if (empty($this->tva_npr)) {
990 if (empty($this->localtax1_tx)) {
991 $this->localtax1_tx = 0;
993 if (empty($this->localtax2_tx)) {
994 $this->localtax2_tx = 0;
996 if (empty($this->localtax1_type)) {
997 $this->localtax1_type =
'0';
999 if (empty($this->localtax2_type)) {
1000 $this->localtax2_type =
'0';
1003 if (empty($this->price_base_type) &&
getDolGlobalString(
'PRODUCT_PRICE_BASE_TYPE')) {
1006 if (empty($this->
price)) {
1009 if (empty($this->price_min)) {
1010 $this->price_min = 0;
1013 if (empty($this->price_by_qty)) {
1014 $this->price_by_qty = 0;
1017 if (empty($this->
status)) {
1020 if (empty($this->status_buy)) {
1021 $this->status_buy = 0;
1023 if (empty($this->stockable_product)) {
1024 $this->stockable_product = 0;
1033 if ($this->price_base_type ==
'TTC' && $this->price_ttc > 0) {
1034 $price_ttc =
price2num($this->price_ttc,
'MU');
1035 $price_ht =
price2num($this->price_ttc / (1 + ($this->tva_tx / 100)),
'MU');
1039 if ($this->price_base_type !=
'TTC' && $this->
price > 0) {
1041 $price_ttc =
price2num($this->
price * (1 + ($this->tva_tx / 100)),
'MU');
1045 if (($this->price_min_ttc > 0) && ($this->price_base_type ==
'TTC')) {
1046 $price_min_ttc =
price2num($this->price_min_ttc,
'MU');
1047 $price_min_ht =
price2num($this->price_min_ttc / (1 + ($this->tva_tx / 100)),
'MU');
1051 if (($this->price_min > 0) && ($this->price_base_type !=
'TTC')) {
1052 $price_min_ht =
price2num($this->price_min,
'MU');
1053 $price_min_ttc =
price2num($this->price_min * (1 + ($this->tva_tx / 100)),
'MU');
1056 $this->accountancy_code_buy = trim((
string) $this->accountancy_code_buy);
1057 $this->accountancy_code_buy_intra = trim((
string) $this->accountancy_code_buy_intra);
1058 $this->accountancy_code_buy_export = trim((
string) $this->accountancy_code_buy_export);
1059 $this->accountancy_code_sell = trim((
string) $this->accountancy_code_sell);
1060 $this->accountancy_code_sell_intra = trim((
string) $this->accountancy_code_sell_intra);
1061 $this->accountancy_code_sell_export = trim((
string) $this->accountancy_code_sell_export);
1067 require_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
1068 $this->accountancy_code_buy =
clean_account($this->accountancy_code_buy);
1069 $this->accountancy_code_buy_intra =
clean_account($this->accountancy_code_buy_intra);
1070 $this->accountancy_code_buy_export =
clean_account($this->accountancy_code_buy_export);
1071 $this->accountancy_code_sell =
clean_account($this->accountancy_code_sell);
1072 $this->accountancy_code_sell_intra =
clean_account($this->accountancy_code_sell_intra);
1073 $this->accountancy_code_sell_export =
clean_account($this->accountancy_code_sell_export);
1077 $this->barcode = trim($this->barcode);
1078 $this->mandatory_period = empty($this->mandatory_period) ? 0 : $this->mandatory_period;
1080 if (empty($this->label)) {
1081 $langs->load(
'errors');
1082 $this->errors[] = $langs->trans(
'ErrorMandatoryParametersNotProvided');
1086 if (empty($this->
ref) || $this->
ref ==
'auto') {
1088 $module =
getDolGlobalString(
'PRODUCT_CODEPRODUCT_ADDON',
'mod_codeproduct_leopard');
1089 if ($module !=
'mod_codeproduct_leopard') {
1090 if (substr($module, 0, 16) ==
'mod_codeproduct_' && substr($module, -3) ==
'php') {
1091 $module = substr($module, 0,
dol_strlen($module) - 4);
1094 $modCodeProduct =
new $module();
1095 '@phan-var-force ModeleProductCode $modCodeProduct';
1096 if (!empty($modCodeProduct->code_auto)) {
1097 $this->
ref = $modCodeProduct->getNextValue($this, $this->
type);
1099 unset($modCodeProduct);
1102 if (empty($this->
ref)) {
1103 $this->error =
'ProductModuleNotSetupForAutoRef';
1108 dol_syslog(get_class($this).
"::create ref=".$this->
ref.
" price=".$this->price.
" price_ttc=".$this->price_ttc.
" tva_tx=".$this->tva_tx.
" price_base_type=".$this->price_base_type, LOG_DEBUG);
1112 if (empty($this->date_creation)) {
1113 $this->date_creation = $now;
1119 if ($this->barcode ==
'-1' || $this->barcode ==
'auto') {
1120 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1125 $result = $this->
verify();
1128 $sql =
"SELECT count(*) as nb";
1129 $sql .=
" FROM ".$this->db->prefix().
"product";
1130 $sql .=
" WHERE entity IN (".getEntity(
'product').
")";
1131 $sql .=
" AND ref = '".$this->db->escape($this->
ref).
"'";
1133 $result = $this->db->query($sql);
1135 $obj = $this->db->fetch_object($result);
1136 if ($obj->nb == 0) {
1138 $sql =
"INSERT INTO ".$this->db->prefix().
"product (";
1142 $sql .=
", ref_ext";
1143 $sql .=
", price_min";
1144 $sql .=
", price_min_ttc";
1146 $sql .=
", fk_user_author";
1147 $sql .=
", fk_product_type";
1149 $sql .=
", price_ttc";
1150 $sql .=
", price_base_type";
1151 $sql .=
", price_label";
1155 $sql .=
", accountancy_code_buy";
1156 $sql .=
", accountancy_code_buy_intra";
1157 $sql .=
", accountancy_code_buy_export";
1158 $sql .=
", accountancy_code_sell";
1159 $sql .=
", accountancy_code_sell_intra";
1160 $sql .=
", accountancy_code_sell_export";
1163 $sql .=
", finished";
1164 $sql .=
", tobatch";
1165 $sql .=
", sell_or_eat_by_mandatory";
1166 $sql .=
", batch_mask";
1167 $sql .=
", fk_unit";
1168 $sql .=
", mandatory_period";
1169 $sql .=
", stockable_product";
1170 if (!empty($this->default_vat_code)) {
1171 $sql .=
", default_vat_code";
1173 $sql .=
") VALUES (";
1174 $sql .=
"'".$this->db->idate($this->date_creation).
"'";
1175 $sql .=
", ".(!empty($this->entity) ? (int) $this->entity : (int)
$conf->entity);
1176 $sql .=
", '".$this->db->escape($this->
ref).
"'";
1177 $sql .=
", ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1178 $sql .=
", ".price2num($price_min_ht);
1179 $sql .=
", ".price2num($price_min_ttc);
1180 $sql .=
", ".(!empty($this->label) ?
"'".$this->db->escape($this->label).
"'" :
"null");
1181 $sql .=
", ".((int) $user->id);
1182 $sql .=
", ".((int) $this->
type);
1183 $sql .=
", ".price2num($price_ht,
'MT');
1184 $sql .=
", ".price2num($price_ttc,
'MT');
1185 $sql .=
", '".$this->db->escape($this->price_base_type).
"'";
1186 $sql .=
", ".(!empty($this->price_label) ?
"'".$this->db->escape($this->price_label).
"'" :
"null");
1187 $sql .=
", ".((int) $this->
status);
1188 $sql .=
", ".((int) $this->status_buy);
1190 $sql .=
", '".$this->db->escape($this->accountancy_code_buy).
"'";
1191 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_intra).
"'";
1192 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_export).
"'";
1193 $sql .=
", '".$this->db->escape($this->accountancy_code_sell).
"'";
1194 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_intra).
"'";
1195 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_export).
"'";
1197 $sql .=
", '".$this->db->escape($this->canvas).
"'";
1198 $sql .=
", ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
'NULL' : (int) $this->finished);
1199 $sql .=
", ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : ((int) $this->status_batch));
1200 $sql .=
", ".((empty($this->sell_or_eat_by_mandatory) || $this->sell_or_eat_by_mandatory < 0) ? 0 : ((int) $this->sell_or_eat_by_mandatory));
1201 $sql .=
", '".$this->db->escape($this->batch_mask).
"'";
1202 $sql .=
", ".($this->fk_unit > 0 ? ((int) $this->fk_unit) :
'NULL');
1203 $sql .=
", '".$this->db->escape((
string) $this->mandatory_period).
"'";
1204 $sql .=
", ".((int) $this->stockable_product);
1205 if (!empty($this->default_vat_code)) {
1206 $sql .=
", '".$this->db->escape($this->default_vat_code).
"'";
1209 dol_syslog(get_class($this).
"::Create", LOG_DEBUG);
1211 $result = $this->db->query($sql);
1213 $id = $this->db->last_insert_id($this->db->prefix().
"product");
1217 $this->
price = $price_ht;
1218 $this->price_ttc = $price_ttc;
1219 $this->price_min = $price_min_ht;
1220 $this->price_min_ttc = $price_min_ttc;
1224 if ($this->
update($id, $user, 1,
'add') <= 0) {
1229 $this->error = $this->db->lasterror();
1234 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " .((int) $this->id) .
" AND entity = " . ((
int)
$conf->entity));
1236 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1237 $sql .=
" fk_product";
1239 $sql .=
", accountancy_code_buy";
1240 $sql .=
", accountancy_code_buy_intra";
1241 $sql .=
", accountancy_code_buy_export";
1242 $sql .=
", accountancy_code_sell";
1243 $sql .=
", accountancy_code_sell_intra";
1244 $sql .=
", accountancy_code_sell_export";
1245 $sql .=
") VALUES (";
1246 $sql .= ((int) $this->
id);
1247 $sql .=
", " . ((int)
$conf->entity);
1248 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1249 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1250 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1251 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1252 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1253 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1255 $result = $this->db->query($sql);
1258 $this->error =
'ErrorFailedToInsertAccountancyForEntity';
1263 $this->error =
'ErrorFailedToGetInsertedId';
1267 $this->error = $this->db->lasterror();
1271 $langs->load(
"products");
1273 $this->error =
"ErrorProductAlreadyExists";
1274 dol_syslog(get_class($this).
"::Create fails, ref ".$this->
ref.
" already exists");
1278 $this->error = $this->db->lasterror();
1281 if (!$error && !$notrigger) {
1283 $result = $this->call_trigger(
'PRODUCT_CREATE', $user);
1291 $this->db->commit();
1294 $this->db->rollback();
1298 $this->db->rollback();
1299 dol_syslog(get_class($this).
"::Create fails verify ".implode(
',', $this->errors), LOG_WARNING);
1315 $this->errors = array();
1318 $this->
ref = trim($this->
ref);
1321 $this->errors[] =
'ErrorBadRef';
1325 $arrayofnonnegativevalue = array(
'weight' =>
'Weight',
'width' =>
'Width',
'height' =>
'Height',
'length' =>
'Length',
'surface' =>
'Surface',
'volume' =>
'Volume');
1326 foreach ($arrayofnonnegativevalue as $key => $value) {
1327 if (property_exists($this, $key) && !empty($this->$key) && ($this->$key < 0)) {
1328 $langs->loadLangs(array(
"main",
"other"));
1329 $this->error = $langs->trans(
"FieldCannotBeNegative", $langs->transnoentitiesnoconv($value));
1330 $this->errors[] = $this->error;
1335 $rescode = $this->check_barcode($this->barcode, $this->barcode_type_code);
1337 if ($rescode == -1) {
1338 $this->errors[] =
'ErrorBadBarCodeSyntax';
1339 } elseif ($rescode == -2) {
1340 $this->errors[] =
'ErrorBarCodeRequired';
1341 } elseif ($rescode == -3) {
1343 $this->errors[] =
'ErrorBarCodeAlreadyUsed';
1363 public function check_barcode($valuetotest, $typefortest)
1371 $dirsociete = array_merge(array(
'/core/modules/barcode/'),
$conf->modules_parts[
'barcode']);
1372 foreach ($dirsociete as $dirroot) {
1379 $mod =
new $module();
1380 '@phan-var-force ModeleNumRefBarCode $mod';
1383 dol_syslog(get_class($this).
"::check_barcode value=".$valuetotest.
" type=".$typefortest.
" module=".$module);
1384 $result = $mod->verif($this->db, $valuetotest, $this, 0, $typefortest);
1402 public function update($id, $user, $notrigger = 0, $action =
'update', $updatetype =
false)
1404 global $langs,
$conf, $hookmanager;
1409 if (!$this->label) {
1410 $this->label =
'MISSING LABEL';
1415 $this->
ref = trim($this->
ref);
1419 $this->label = trim($this->label);
1421 $this->note_private = (isset($this->note_private) ? trim($this->note_private) :
null);
1422 $this->note_public = (isset($this->note_public) ? trim($this->note_public) :
null);
1423 $this->net_measure =
price2num($this->net_measure);
1424 $this->net_measure_units = (!is_numeric($this->net_measure_units) ? null : (int) $this->net_measure_units);
1425 $this->weight =
price2num($this->weight);
1426 $this->weight_units = (!is_numeric($this->weight_units) ? null : (int) $this->weight_units);
1427 $this->length =
price2num($this->length);
1428 $this->length_units = (!is_numeric($this->length_units) ? null : (int) $this->length_units);
1430 $this->width_units = (!is_numeric($this->width_units) ? null : (int) $this->width_units);
1431 $this->height =
price2num($this->height);
1432 $this->height_units = (!is_numeric($this->height_units) ? null : (int) $this->height_units);
1433 $this->surface =
price2num($this->surface);
1434 $this->surface_units = (!is_numeric($this->surface_units) ? null : (int) $this->surface_units);
1435 $this->volume =
price2num($this->volume);
1436 $this->volume_units = (!is_numeric($this->volume_units) ? null : (int) $this->volume_units);
1439 if (is_numeric($this->length_units)) {
1440 $this->width_units = $this->length_units;
1442 if (is_numeric($this->length_units)) {
1443 $this->height_units = $this->length_units;
1447 if (empty($this->surface) && !empty($this->length) && !empty($this->width) && $this->length_units == $this->width_units) {
1448 $this->surface = (float) $this->length * (
float) $this->width;
1451 if (empty($this->volume) && !empty($this->surface) && !empty($this->height) && $this->length_units == $this->height_units) {
1452 $this->volume = $this->surface * (float) $this->height;
1456 if (empty($this->tva_tx)) {
1459 if (empty($this->tva_npr)) {
1462 if (empty($this->localtax1_tx)) {
1463 $this->localtax1_tx = 0;
1465 if (empty($this->localtax2_tx)) {
1466 $this->localtax2_tx = 0;
1468 if (empty($this->localtax1_type)) {
1469 $this->localtax1_type =
'0';
1471 if (empty($this->localtax2_type)) {
1472 $this->localtax2_type =
'0';
1474 if (empty($this->
status)) {
1477 if (empty($this->status_buy)) {
1478 $this->status_buy = 0;
1481 if (empty($this->country_id)) {
1482 $this->country_id = 0;
1484 if (empty($this->country_id) && !empty($this->country_code)) {
1485 $country_id =
getCountry($this->country_code,
'3');
1486 $this->country_id = is_int($country_id) ? $country_id : 0;
1489 if (empty($this->state_id)) {
1490 $this->state_id = 0;
1493 if (empty($this->stockable_product)) {
1494 $this->stockable_product = 0;
1498 if ($this->barcode ==
'-1' || $this->barcode ==
'auto') {
1499 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1503 $this->barcode = (empty($this->barcode) ?
'' : trim($this->barcode));
1505 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
1506 $this->accountancy_code_buy_intra = (!empty($this->accountancy_code_buy_intra) ? trim($this->accountancy_code_buy_intra) :
'');
1507 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
1508 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
1509 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
1510 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
1516 require_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
1517 $this->accountancy_code_buy =
clean_account($this->accountancy_code_buy);
1518 $this->accountancy_code_buy_intra =
clean_account($this->accountancy_code_buy_intra);
1519 $this->accountancy_code_buy_export =
clean_account($this->accountancy_code_buy_export);
1520 $this->accountancy_code_sell =
clean_account($this->accountancy_code_sell);
1521 $this->accountancy_code_sell_intra =
clean_account($this->accountancy_code_sell_intra);
1522 $this->accountancy_code_sell_export =
clean_account($this->accountancy_code_sell_export);
1529 if ($action !=
'add') {
1530 $result = $this->
verify();
1542 if (is_null($this->oldcopy) || (is_object($this->oldcopy) && empty($this->oldcopy->id)) || !($this->oldcopy instanceof
Product)) {
1547 if ($this->
hasbatch() && !$this->oldcopy->hasbatch()) {
1549 $valueforundefinedlot =
'000000';
1554 dol_syslog(
"Flag batch of product id=".$this->
id.
" is set to ON, so we will create missing records into product_batch");
1557 foreach ($this->stock_warehouse as $idW => $ObjW) {
1559 foreach ($ObjW->detail_batch as $detail) {
1560 if ($detail->batch == $valueforundefinedlot || $detail->batch ==
'Undefined') {
1562 $sqlclean =
"DELETE FROM ".$this->db->prefix().
"product_batch WHERE batch in('Undefined', '".$this->db->escape($valueforundefinedlot).
"') AND fk_product_stock = ".((int) $ObjW->id);
1563 $result = $this->db->query($sqlclean);
1571 $qty_batch += $detail->qty;
1575 if ($ObjW->real != $qty_batch) {
1577 $ObjBatch->batch = $valueforundefinedlot;
1578 $ObjBatch->qty = ($ObjW->real - $qty_batch);
1579 $ObjBatch->fk_product_stock = (int) $ObjW->id;
1581 if ($ObjBatch->create($user, 1) < 0) {
1583 $this->errors = $ObjBatch->errors;
1588 if ($ObjLot->fetch(0, $this->id, $valueforundefinedlot) == 0) {
1589 $ObjLot->fk_product = $this->id;
1590 $ObjLot->entity = (int) $this->entity;
1591 $ObjLot->fk_user_creat = $user->id;
1592 $ObjLot->batch = $valueforundefinedlot;
1593 if ($ObjLot->create($user, 1) < 0) {
1595 $this->errors = $ObjLot->errors;
1603 $sql =
"UPDATE ".$this->db->prefix().
"product";
1604 $sql .=
" SET label = '".$this->db->escape($this->label).
"'";
1607 $sql .=
", fk_product_type = ".((int) $this->
type);
1610 $sql .=
", ref = '".$this->db->escape($this->
ref).
"'";
1611 $sql .=
", ref_ext = ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1612 $sql .=
", default_vat_code = ".($this->default_vat_code ?
"'".$this->db->escape($this->default_vat_code).
"'" :
"null");
1613 $sql .=
", tva_tx = ".((float) $this->tva_tx);
1614 $sql .=
", recuperableonly = ".((int) $this->tva_npr);
1615 $sql .=
", localtax1_tx = ".((float) $this->localtax1_tx);
1616 $sql .=
", localtax2_tx = ".((float) $this->localtax2_tx);
1617 $sql .=
", localtax1_type = ".($this->localtax1_type !=
'' ?
"'".$this->db->escape($this->localtax1_type).
"'" :
"'0'");
1618 $sql .=
", localtax2_type = ".($this->localtax2_type !=
'' ?
"'".$this->db->escape($this->localtax2_type).
"'" :
"'0'");
1620 $sql .=
", barcode = ".(empty($this->barcode) ?
"null" :
"'".$this->db->escape($this->barcode).
"'");
1621 $sql .=
", fk_barcode_type = ".(empty($this->barcode_type) ?
"null" : $this->db->escape((
string) $this->barcode_type));
1623 $sql .=
", tosell = ".(int) $this->
status;
1624 $sql .=
", tobuy = ".(int) $this->status_buy;
1625 $sql .=
", tobatch = ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : (int) $this->status_batch);
1626 $sql .=
", sell_or_eat_by_mandatory = ".((empty($this->sell_or_eat_by_mandatory) || $this->sell_or_eat_by_mandatory < 0) ? 0 : (int) $this->sell_or_eat_by_mandatory);
1627 $sql .=
", batch_mask = '".$this->db->escape($this->batch_mask).
"'";
1629 $sql .=
", finished = ".((!isset($this->finished) || $this->finished < 0 || $this->finished ===
'') ?
"null" : (int) $this->finished);
1630 $sql .=
", fk_default_bom = ".((!isset($this->fk_default_bom) || $this->fk_default_bom < 0 || $this->fk_default_bom ==
'') ?
"null" : (int) $this->fk_default_bom);
1631 $sql .=
", net_measure = ".($this->net_measure !=
'' ?
"'".$this->db->escape($this->net_measure).
"'" :
'null');
1632 $sql .=
", net_measure_units = ".((string) $this->net_measure_units !=
'' ? ((
int) $this->net_measure_units) :
'null');
1633 $sql .=
", weight = ".($this->weight !=
'' ?
"'".$this->db->escape($this->weight).
"'" :
'null');
1634 $sql .=
", weight_units = ".((string) $this->weight_units !=
'' ? ((
int) $this->weight_units) :
'null');
1635 $sql .=
", length = ".($this->length !=
'' ?
"'".$this->db->escape($this->length).
"'" :
'null');
1636 $sql .=
", length_units = ".((string) $this->length_units !=
'' ? ((
int) $this->length_units) :
'null');
1637 $sql .=
", width= ".($this->width !=
'' ?
"'".$this->db->escape($this->width).
"'" :
'null');
1638 $sql .=
", width_units = ".((string) $this->width_units !=
'' ? ((
int) $this->width_units) :
'null');
1639 $sql .=
", height = ".($this->height !=
'' ?
"'".$this->db->escape($this->height).
"'" :
'null');
1640 $sql .=
", height_units = ".((string) $this->height_units !=
'' ? ((
int) $this->height_units) :
'null');
1641 $sql .=
", surface = ".($this->surface !=
'' ?
"'".$this->db->escape($this->surface).
"'" :
'null');
1642 $sql .=
", surface_units = ".((string) $this->surface_units !=
'' ? ((
int) $this->surface_units) :
'null');
1643 $sql .=
", volume = ".($this->volume !=
'' ?
"'".$this->db->escape($this->volume).
"'" :
'null');
1644 $sql .=
", volume_units = ".((string) $this->volume_units !=
'' ? ((
int) $this->volume_units) :
'null');
1645 $sql .=
", fk_default_warehouse = ".($this->fk_default_warehouse > 0 ? ((int) $this->fk_default_warehouse) :
'null');
1646 $sql .=
", fk_default_workstation = ".($this->fk_default_workstation > 0 ? ((int) $this->fk_default_workstation) :
'null');
1647 $sql .=
", seuil_stock_alerte = ".((isset($this->seuil_stock_alerte) && is_numeric($this->seuil_stock_alerte)) ? (
float) $this->seuil_stock_alerte :
'null');
1648 $sql .=
", description = '".$this->db->escape($this->
description).
"'";
1649 $sql .=
", url = ".($this->url ?
"'".$this->db->escape($this->url).
"'" :
'null');
1650 $sql .=
", customcode = '".$this->db->escape($this->customcode).
"'";
1651 $sql .=
", fk_country = ".($this->country_id > 0 ? (int) $this->country_id :
'null');
1652 $sql .=
", fk_state = ".($this->state_id > 0 ? (int) $this->state_id :
'null');
1653 $sql .=
", lifetime = ".($this->lifetime > 0 ? (int) $this->lifetime :
'null');
1654 $sql .=
", qc_frequency = ".($this->qc_frequency > 0 ? (int) $this->qc_frequency :
'null');
1655 $sql .=
", note = ".(isset($this->note_private) ?
"'".$this->db->escape($this->note_private).
"'" :
'null');
1656 $sql .=
", note_public = ".(isset($this->note_public) ?
"'".$this->db->escape($this->note_public).
"'" :
'null');
1657 $sql .=
", duration = '".$this->db->escape($this->duration_value.$this->duration_unit).
"'";
1659 $sql .=
", accountancy_code_buy = '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1660 $sql .=
", accountancy_code_buy_intra = '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1661 $sql .=
", accountancy_code_buy_export = '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1662 $sql .=
", accountancy_code_sell= '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1663 $sql .=
", accountancy_code_sell_intra= '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1664 $sql .=
", accountancy_code_sell_export= '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1666 $sql .=
", desiredstock = ".((isset($this->desiredstock) && is_numeric($this->desiredstock)) ? (
float) $this->desiredstock :
"null");
1667 $sql .=
", cost_price = ".($this->cost_price !=
'' ? ((float) $this->cost_price) :
'null');
1668 $sql .=
", fk_unit= ".(!$this->fk_unit ?
'NULL' : (int) $this->fk_unit);
1669 $sql .=
", price_autogen = ".(!$this->price_autogen ? 0 : 1);
1670 $sql .=
", fk_price_expression = ".($this->fk_price_expression != 0 ? (int) $this->fk_price_expression :
'NULL');
1671 $sql .=
", fk_user_modif = ".($user->id > 0 ? (int) $user->id :
'NULL');
1672 $sql .=
", mandatory_period = ".((int) $this->mandatory_period);
1673 $sql .=
", stockable_product = ".(int) $this->stockable_product;
1675 $sql .=
", packaging = ".(float) $this->packaging;
1679 $sql .=
" WHERE rowid = ".((int) $id);
1681 dol_syslog(get_class($this).
"::update", LOG_DEBUG);
1683 $resql = $this->db->query($sql);
1690 $this->db->rollback();
1699 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " . ((
int) $this->id) .
" AND entity = " . ((
int)
$conf->entity));
1701 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1702 $sql .=
" fk_product";
1704 $sql .=
", accountancy_code_buy";
1705 $sql .=
", accountancy_code_buy_intra";
1706 $sql .=
", accountancy_code_buy_export";
1707 $sql .=
", accountancy_code_sell";
1708 $sql .=
", accountancy_code_sell_intra";
1709 $sql .=
", accountancy_code_sell_export";
1710 $sql .=
") VALUES (";
1711 $sql .= ((int) $this->
id);
1712 $sql .=
", " . ((int)
$conf->entity);
1713 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1714 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1715 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1716 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1717 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1718 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1720 $result = $this->db->query($sql);
1723 $this->error =
'ErrorFailedToUpdateAccountancyForEntity';
1727 if (!$this->
hasbatch() && $this->oldcopy->hasbatch()) {
1729 $sql =
'SELECT pb.qty, ps.fk_entrepot, pb.batch FROM '.MAIN_DB_PREFIX.
'product_batch as pb';
1730 $sql .=
' INNER JOIN '.MAIN_DB_PREFIX.
'product_stock as ps ON (ps.rowid = pb.fk_product_stock)';
1731 $sql .=
' WHERE ps.fk_product = '.(int) $this->
id;
1733 $resql = $this->db->query($sql);
1737 while ($obj = $this->db->fetch_object($resql)) {
1739 $fk_entrepot = $obj->fk_entrepot;
1743 $batch = $obj->batch;
1746 $addOremove = $value > 0 ? 1 : 0;
1747 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1748 $res = $this->
correct_stock_batch($user, $fk_entrepot, abs($value), $addOremove, $label, $price, $dlc, $dluo, $batch, $inventorycode,
'',
null, 0,
null,
true);
1751 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1752 $res = $this->
correct_stock($user, $fk_entrepot, abs($value), (
int) empty($addOremove), $label, $price, $inventorycode,
'',
null, 0);
1771 if (!$error && !$notrigger) {
1773 $result = $this->call_trigger(
'PRODUCT_MODIFY', $user);
1780 if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) {
1782 if (
$conf->product->dir_output) {
1785 if (file_exists($olddir)) {
1789 $res = @rename($olddir, $newdir);
1791 $langs->load(
"errors");
1792 $this->error = $langs->trans(
'ErrorFailToRenameDir', $olddir, $newdir);
1796 require_once DOL_DOCUMENT_ROOT .
'/ecm/class/ecmfiles.class.php';
1797 $ecmfiles =
new EcmFiles($this->db);
1798 $ecmfiles->updateAfterRename(
"produit/".
dol_sanitizeFileName($this->oldcopy->ref),
"produit/".dol_sanitizeFileName($this->ref));
1806 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1810 foreach ($comb->fetchAllByFkProductParent($this->id) as $currcomb) {
1811 $currcomb->updateProperties($this, $user);
1815 $this->db->commit();
1818 $this->db->rollback();
1822 if ($this->db->errno() ==
'DB_ERROR_RECORD_ALREADY_EXISTS') {
1823 $langs->load(
"errors");
1824 if (empty(
$conf->barcode->enabled) || empty($this->barcode)) {
1825 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductAlreadyExists", $this->
ref);
1827 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductBarCodeAlreadyExists", $this->barcode);
1829 $this->errors[] = $this->error;
1830 $this->db->rollback();
1833 $this->error = $langs->trans(
"Error").
" : ".$this->db->error().
" - ".$sql;
1834 $this->errors[] = $this->error;
1835 $this->db->rollback();
1840 $this->db->rollback();
1841 dol_syslog(get_class($this).
"::Update fails verify ".implode(
',', $this->errors), LOG_WARNING);
1853 public function delete(
User $user, $notrigger = 0)
1856 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
1861 if (empty($this->
id)) {
1862 $this->error =
"Object must be fetched before calling delete";
1865 if (($this->
isProduct() && !$user->
hasRight(
'produit',
'supprimer')) || ($this->isService() && !$user->hasRight(
'service',
'supprimer'))) {
1866 $this->error =
"ErrorForbidden";
1871 if (empty($objectisused)) {
1874 if (empty($notrigger)) {
1876 $result = $this->call_trigger(
'PRODUCT_DELETE', $user);
1885 $sql =
"DELETE FROM ".$this->db->prefix().
'product_batch';
1886 $sql .=
" WHERE fk_product_stock IN (";
1887 $sql .=
"SELECT rowid FROM ".$this->db->prefix().
'product_stock';
1888 $sql .=
" WHERE fk_product = ".((int) $this->
id).
")";
1890 $result = $this->db->query($sql);
1893 $this->errors[] = $this->db->lasterror();
1899 $sql =
"DELETE FROM " . $this->db->prefix() .
"product_fournisseur_price_log";
1900 $sql .=
" WHERE fk_product_fournisseur IN (";
1901 $sql .=
" SELECT rowid FROM " . $this->db->prefix() .
"product_fournisseur_price";
1902 $sql .=
" WHERE fk_product = " . ((int) $this->
id);
1905 $resql = $this->db->query($sql);
1908 $this->errors[] = $this->db->lasterror();
1914 $elements = array(
'product_fournisseur_price',
'product_price',
'product_lang',
'categorie_product',
'product_stock',
'product_customer_price',
'product_lot');
1915 foreach ($elements as $table) {
1917 $sql =
"DELETE FROM ".$this->db->prefix().$table;
1918 $sql .=
" WHERE fk_product = ".(int) $this->
id;
1920 $result = $this->db->query($sql);
1923 $this->errors[] = $this->db->lasterror();
1930 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1931 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination2ValuePair.class.php';
1936 if ($prodcomb->deleteByFkProductParent($user, $this->id) < 0) {
1938 $this->errors[] =
'Error deleting combinations';
1942 if (!$error && ($prodcomb->fetchByFkProductChild($this->id) > 0) && ($prodcomb->delete($user) < 0)) {
1944 $this->errors[] =
'Error deleting child combination';
1950 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
1951 $sql .=
" WHERE fk_product_pere = ".(int) $this->
id.
" OR fk_product_fils = ".(
int) $this->id;
1953 $result = $this->db->query($sql);
1956 $this->errors[] = $this->db->lasterror();
1965 dol_syslog(get_class($this).
"::delete error -4 ".$this->error, LOG_ERR);
1971 $sqlz =
"DELETE FROM ".$this->db->prefix().
"product";
1972 $sqlz .=
" WHERE rowid = ".(int) $this->
id;
1974 $resultz = $this->db->query($sqlz);
1977 $this->errors[] = $this->db->lasterror();
1993 if ($conf->product->dir_output) {
1994 $dir =
$conf->product->dir_output.
"/".$ref;
1995 if (file_exists($dir)) {
1998 $this->errors[] =
'ErrorFailToDeleteDir';
2006 $this->db->commit();
2009 foreach ($this->errors as $errmsg) {
2010 dol_syslog(get_class($this).
"::delete ".$errmsg, LOG_ERR);
2011 $this->error .= ($this->error ?
', '.$errmsg : $errmsg);
2013 $this->db->rollback();
2017 $this->error =
"ErrorRecordIsUsedCantDelete";
2031 $sellByLabel = $langs->trans(
'SellByDate');
2032 $eatByLabel = $langs->trans(
'EatByDate');
2034 self::SELL_OR_EAT_BY_MANDATORY_ID_NONE => $langs->trans(
'BatchSellOrEatByMandatoryNone'),
2035 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY => $sellByLabel,
2036 self::SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY => $eatByLabel,
2037 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT => $langs->trans(
'BatchSellOrEatByMandatoryAll', $sellByLabel, $eatByLabel),
2048 $sellOrEatByMandatoryLabel =
'';
2051 if (isset($sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory])) {
2052 $sellOrEatByMandatoryLabel = $sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory];
2055 return $sellOrEatByMandatoryLabel;
2069 $langs_available = $langs->get_available_languages(DOL_DOCUMENT_ROOT, 0, 2);
2070 $current_lang = $langs->getDefaultLang();
2072 foreach ($langs_available as $key => $value) {
2073 if ($key == $current_lang) {
2074 $sql =
"SELECT rowid";
2075 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2076 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2077 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
2079 $result = $this->db->query($sql);
2081 if ($this->db->num_rows($result)) {
2082 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
2084 $sql2 .=
" label='".$this->db->escape($this->label).
"',";
2085 $sql2 .=
" description='".$this->db->escape($this->
description).
"'";
2087 $sql2 .=
", note='".$this->db->escape($this->other).
"'";
2089 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
2091 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
2096 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->label).
"',";
2097 $sql2 .=
" '".$this->db->escape($this->
description).
"'";
2099 $sql2 .=
", '".$this->db->escape($this->other).
"'";
2103 dol_syslog(get_class($this).
'::setMultiLangs key = current_lang = '.$key);
2104 if (!$this->db->query($sql2)) {
2105 $this->error = $this->db->lasterror();
2108 } elseif (isset($this->multilangs[$key])) {
2109 if (empty($this->multilangs[$key][
"label"])) {
2110 $this->errors[] = $key .
' : ' . $langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Label"));
2114 $sql =
"SELECT rowid";
2115 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2116 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2117 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
2119 $result = $this->db->query($sql);
2121 if ($this->db->num_rows($result)) {
2122 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
2124 $sql2 .=
" label = '".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
2125 $sql2 .=
" description = '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
2128 $sql2 .=
", note = '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
2130 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
2132 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
2137 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
2138 $sql2 .=
" '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
2141 $sql2 .=
", '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
2147 if ($this->multilangs[
"$key"][
"label"] || $this->multilangs[
"$key"][
"description"]) {
2148 if (!$this->db->query($sql2)) {
2149 $this->error = $this->db->lasterror();
2158 if (empty($notrigger)) {
2160 $result = $this->call_trigger(
'PRODUCT_SET_MULTILANGS', $user);
2162 $this->error = $this->db->lasterror();
2182 $sql =
"DELETE FROM ".$this->db->prefix().
"product_lang";
2183 $sql .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($langtodelete).
"'";
2185 dol_syslog(get_class($this).
'::delMultiLangs', LOG_DEBUG);
2186 $result = $this->db->query($sql);
2188 if (empty($notrigger)) {
2190 $result = $this->call_trigger(
'PRODUCT_DEL_MULTILANGS', $user);
2192 $this->error = $this->db->lasterror();
2193 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
2198 unset($this->multilangs[$langtodelete]);
2201 $this->error = $this->db->lasterror();
2202 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
2223 if ($type ==
'buy') {
2224 $field =
'accountancy_code_buy';
2225 } elseif ($type ==
'buy_intra') {
2226 $field =
'accountancy_code_buy_intra';
2227 } elseif ($type ==
'buy_export') {
2228 $field =
'accountancy_code_buy_export';
2229 } elseif ($type ==
'sell') {
2230 $field =
'accountancy_code_sell';
2231 } elseif ($type ==
'sell_intra') {
2232 $field =
'accountancy_code_sell_intra';
2233 } elseif ($type ==
'sell_export') {
2234 $field =
'accountancy_code_sell_export';
2239 $sql =
"UPDATE ".$this->db->prefix().$this->table_element.
" SET ";
2240 $sql .=
"$field = '".$this->db->escape($value).
"'";
2241 $sql .=
" WHERE rowid = ".((int) $this->
id);
2244 $resql = $this->db->query($sql);
2248 $result = $this->call_trigger(
'PRODUCT_MODIFY', $user);
2255 $this->db->rollback();
2259 $this->$field = $value;
2261 $this->db->commit();
2264 $this->error = $this->db->lasterror();
2265 $this->db->rollback();
2279 $current_lang = $langs->getDefaultLang();
2281 $sql =
"SELECT lang, label, description, note as other";
2282 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2283 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2285 $result = $this->db->query($sql);
2287 while ($obj = $this->db->fetch_object($result)) {
2289 if ($obj->lang == $current_lang) {
2290 $this->label = $obj->label;
2292 $this->other = $obj->other;
2294 $this->multilangs[(
string) $obj->lang][
"label"] = $obj->label;
2295 $this->multilangs[(
string) $obj->lang][
"description"] = $obj->description;
2296 $this->multilangs[(
string) $obj->lang][
"other"] = $obj->other;
2300 $this->error =
"Error: ".$this->db->lasterror().
" - ".$sql;
2313 $testExit = array(
'multiprices',
'multiprices_ttc',
'multiprices_base_type',
'multiprices_min',
'multiprices_min_ttc',
'multiprices_tva_tx',
'multiprices_recuperableonly');
2315 foreach ($testExit as $field) {
2316 if (!isset($this->$field)) {
2319 $tmparray = $this->$field;
2320 if (!isset($tmparray[$level])) {
2326 'level' => $level ? $level : 1,
2327 'multiprices' => (float) $this->multiprices[$level],
2328 'multiprices_ttc' => (
float) $this->multiprices_ttc[$level],
2329 'multiprices_base_type' => $this->multiprices_base_type[$level],
2330 'multiprices_min' => (float) $this->multiprices_min[$level],
2331 'multiprices_min_ttc' => (
float) $this->multiprices_min_ttc[$level],
2332 'multiprices_tva_tx' => (float) $this->multiprices_tva_tx[$level],
2333 'multiprices_recuperableonly' => (
float) $this->multiprices_recuperableonly[$level],
2356 if (empty($this->price_by_qty)) {
2357 $this->price_by_qty = 0;
2361 $sql =
"INSERT INTO ".$this->db->prefix().
"product_price(price_level,date_price, fk_product, fk_user_author, price_label, price, price_ttc, price_base_type,tosell, tva_tx, default_vat_code, recuperableonly,";
2362 $sql .=
" localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, price_min,price_min_ttc,price_by_qty,entity,fk_price_expression) ";
2363 $sql .=
" VALUES(".($level ? ((int) $level) : 1).
", '".$this->db->idate($now).
"', ".((int) $this->
id).
", ".((int) $user->id).
", ".(empty($this->price_label) ?
"null" :
"'".$this->db->escape($this->price_label).
"'").
", ".((float)
price2num($this->
price)).
", ".((
float)
price2num($this->price_ttc)).
",'".$this->db->escape($this->price_base_type).
"',".((int) $this->
status).
", ".((float)
price2num($this->tva_tx)).
", ".($this->default_vat_code ? (
"'".$this->db->escape($this->default_vat_code).
"'") :
"null").
", ".((
int) $this->tva_npr).
",";
2364 $sql .=
" ".price2num($this->localtax1_tx).
", ".
price2num($this->localtax2_tx).
", '".$this->db->escape($this->localtax1_type).
"', '".$this->db->escape($this->localtax2_type).
"', ".
price2num($this->price_min).
", ".
price2num($this->price_min_ttc).
", ".
price2num($this->price_by_qty).
", ".((int)
$conf->entity).
",".($this->fk_price_expression > 0 ? ((int) $this->fk_price_expression) :
'null');
2367 dol_syslog(get_class($this).
"::_log_price", LOG_DEBUG);
2368 $resql = $this->db->query($sql);
2370 $this->error = $this->db->lasterror();
2390 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price_by_qty";
2391 $sql .=
" WHERE fk_product_price = ".((int) $rowid);
2392 $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)) {
2951 $updatedefaultprice = (empty($level) || $level == 1);
2955 $sql =
"UPDATE ".$this->db->prefix().
"product SET";
2956 if ($updatedefaultprice) {
2957 $sql .=
" price_base_type = '".$this->db->escape($newpricebase).
"',";
2958 $sql .=
" price = ".(float) $price.
",";
2959 $sql .=
" price_ttc = ".(float) $price_ttc.
",";
2960 $sql .=
" price_min = ".(float) $price_min.
",";
2961 $sql .=
" price_min_ttc = ".(float) $price_min_ttc.
",";
2962 $sql .=
" price_label = ".(!empty($price_label) ?
"'".$this->db->escape($price_label).
"'" :
"null").
",";
2964 $sql .=
" localtax1_tx = ".($localtax1 >= 0 ? (float) $localtax1 :
'NULL').
",";
2965 $sql .=
" localtax2_tx = ".($localtax2 >= 0 ? (float) $localtax2 :
'NULL').
",";
2966 $sql .=
" localtax1_type = ".($localtaxtype1 !=
'' ?
"'".$this->db->escape($localtaxtype1).
"'" :
"'0'").
",";
2967 $sql .=
" localtax2_type = ".($localtaxtype2 !=
'' ?
"'".$this->db->escape($localtaxtype2).
"'" :
"'0'").
",";
2968 $sql .=
" default_vat_code = ".($newdefaultvatcode ?
"'".$this->db->escape($newdefaultvatcode).
"'" :
"null").
",";
2969 $sql .=
" tva_tx = ".(float)
price2num($newvat).
",";
2970 $sql .=
" recuperableonly = '".$this->db->escape((
string) $newnpr).
"'";
2971 $sql .=
" WHERE rowid = ".((int) $id);
2973 dol_syslog(get_class($this).
"::update_price", LOG_DEBUG);
2974 $resql = $this->db->query($sql);
2976 $this->multiprices[$level] = $price;
2977 $this->multiprices_ttc[$level] = $price_ttc;
2978 $this->multiprices_min[$level] = $price_min;
2979 $this->multiprices_min_ttc[$level] = $price_min_ttc;
2980 $this->multiprices_base_type[$level] = $newpricebase;
2981 $this->multiprices_default_vat_code[$level] = $newdefaultvatcode;
2982 $this->multiprices_tva_tx[$level] = $newvat;
2983 $this->multiprices_recuperableonly[$level] = $newnpr;
2987 $savdefaultprice = array($this->
price, $this->price_label, $this->price_ttc, $this->price_min, $this->price_min_ttc, $this->price_base_type);
2989 $this->
price = $price;
2990 $this->price_label = $price_label;
2991 $this->price_ttc = $price_ttc;
2992 $this->price_min = $price_min;
2993 $this->price_min_ttc = $price_min_ttc;
2994 $this->price_base_type = $newpricebase;
2995 $this->default_vat_code = $newdefaultvatcode;
2996 $this->tva_tx = $newvat;
2997 $this->tva_npr = $newnpr;
3000 $this->localtax1_tx = $localtax1;
3001 $this->localtax2_tx = $localtax2;
3002 $this->localtax1_type = $localtaxtype1;
3003 $this->localtax2_type = $localtaxtype2;
3006 $this->price_by_qty = $newpbq;
3010 if (!empty(array_diff_assoc($newPriceData, $lastPriceData)) || (!
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3014 if (!$updatedefaultprice) {
3016 list($this->
price, $this->price_label, $this->price_ttc, $this->price_min, $this->price_min_ttc, $this->price_base_type) = $savdefaultprice;
3019 $this->level = $level;
3023 $result = $this->call_trigger(
'PRODUCT_PRICE_MODIFY', $user);
3025 $this->db->rollback();
3031 $this->db->commit();
3033 $this->db->rollback();
3034 $this->error = $this->db->lasterror();
3053 $this->fk_price_expression = $expression_id;
3055 return $this->
update($this->
id, $user);
3070 public function fetch($id = 0, $ref =
'', $ref_ext =
'', $barcode =
'', $ignore_expression = 0, $ignore_price_load = 0, $ignore_lang_load = 0)
3072 include_once DOL_DOCUMENT_ROOT.
'/core/lib/company.lib.php';
3076 dol_syslog(get_class($this).
"::fetch id=".$id.
" ref=".$ref.
" ref_ext=".$ref_ext);
3079 if (!$id && !$ref && !$ref_ext && !$barcode) {
3080 $this->error =
'ErrorWrongParameters';
3081 dol_syslog(get_class($this).
"::fetch ".$this->error, LOG_ERR);
3085 $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,";
3086 $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,";
3087 $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,";
3088 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.last_main_doc,";
3089 $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,";
3091 $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,";
3093 $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,";
3098 $separatedEntityPMP =
false;
3099 $separatedStock =
false;
3100 $visibleWarehousesEntities =
$conf->entity;
3103 $checkPMPPerEntity = $this->db->query(
"SELECT pmp FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = ".((int) $id).
" AND entity = ".(
int)
$conf->entity);
3104 if ($this->db->num_rows($checkPMPPerEntity) > 0) {
3105 $separatedEntityPMP =
true;
3109 $separatedStock =
true;
3110 if (isset($mc->sharings[
'stock']) && !empty($mc->sharings[
'stock'])) {
3111 $visibleWarehousesEntities .=
"," . implode(
",", $mc->sharings[
'stock']);
3114 if ($separatedEntityPMP) {
3115 $sql .=
" ppe.pmp,";
3119 $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,";
3120 $sql .=
" p.fk_price_expression, p.price_autogen, p.stockable_product, p.model_pdf,";
3121 $sql .=
" p.price_label,";
3122 if ($separatedStock) {
3123 $sql .=
" SUM(sp.reel) as stock";
3127 $sql .=
" FROM ".$this->db->prefix().
"product as p";
3128 $sql .=
" LEFT JOIN ".$this->db->prefix().
"product_extrafields as pef ON pef.fk_object=p.rowid";
3130 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int)
$conf->entity);
3132 if ($separatedStock) {
3133 $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).
"))";
3137 $sql .=
" WHERE p.rowid = ".((int) $id);
3139 $sql .=
" WHERE p.entity IN (".getEntity($this->element).
")";
3141 $sql .=
" AND p.ref = '".$this->db->escape($ref).
"'";
3142 } elseif ($ref_ext) {
3143 $sql .=
" AND p.ref_ext = '".$this->db->escape($ref_ext).
"'";
3144 } elseif ($barcode) {
3145 $sql .=
" AND p.barcode = '".$this->db->escape($barcode).
"'";
3148 if ($separatedStock) {
3149 $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,";
3150 $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,";
3151 $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,";
3152 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
3153 $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,";
3155 $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,";
3157 $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,";
3159 if ($separatedEntityPMP) {
3160 $sql .=
" ppe.pmp,";
3164 $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,";
3165 $sql .=
" p.fk_price_expression, p.price_autogen, p.stockable_product, p.model_pdf,";
3166 $sql .=
" p.price_label";
3173 $resql = $this->db->query($sql);
3175 unset($this->oldcopy);
3177 if ($this->db->num_rows($resql) > 0) {
3178 $obj = $this->db->fetch_object($resql);
3180 $this->
id = $obj->rowid;
3181 $this->
ref = $obj->ref;
3182 $this->ref_ext = $obj->ref_ext;
3183 $this->label = $obj->label;
3185 $this->url = $obj->url;
3186 $this->note_public = $obj->note_public;
3187 $this->note_private = $obj->note_private;
3188 $this->note = $obj->note_private;
3190 $this->
type = $obj->fk_product_type;
3191 $this->price_label = $obj->price_label;
3192 $this->
status = $obj->tosell;
3193 $this->status_buy = $obj->tobuy;
3194 $this->status_batch = $obj->tobatch;
3195 $this->sell_or_eat_by_mandatory = $obj->sell_or_eat_by_mandatory;
3196 $this->batch_mask = $obj->batch_mask;
3198 $this->customcode = $obj->customcode;
3199 $this->country_id = $obj->fk_country;
3200 $this->country_code =
getCountry($this->country_id,
'2', $this->db);
3201 $this->state_id = $obj->fk_state;
3202 $this->lifetime = $obj->lifetime;
3203 $this->qc_frequency = $obj->qc_frequency;
3204 $this->
price = $obj->price;
3205 $this->price_ttc = $obj->price_ttc;
3206 $this->price_min = $obj->price_min;
3207 $this->price_min_ttc = $obj->price_min_ttc;
3208 $this->price_base_type = (empty($obj->price_base_type) ?
'HT' : $obj->price_base_type);
3209 $this->cost_price = isset($obj->cost_price) ? (float) $obj->cost_price :
null;
3210 $this->default_vat_code = $obj->default_vat_code;
3211 $this->tva_tx = $obj->tva_tx;
3213 $this->tva_npr = $obj->tva_npr;
3215 $this->localtax1_tx = $obj->localtax1_tx;
3216 $this->localtax2_tx = $obj->localtax2_tx;
3217 $this->localtax1_type = $obj->localtax1_type;
3218 $this->localtax2_type = $obj->localtax2_type;
3220 $this->finished = $obj->finished;
3221 $this->fk_default_bom = $obj->fk_default_bom;
3223 $this->duration = $obj->duration;
3225 preg_match(
'/([\d.]+)(\w+)/', $obj->duration, $matches);
3226 $this->duration_value = !empty($matches[1]) ? (float) $matches[1] : 0;
3227 $this->duration_unit = !empty($matches[2]) ? (
string) $matches[2] :
null;
3228 $this->canvas = $obj->canvas;
3229 $this->net_measure = $obj->net_measure;
3230 $this->net_measure_units = $obj->net_measure_units;
3231 $this->weight = $obj->weight;
3232 $this->weight_units = (is_null($obj->weight_units) ? 0 : $obj->weight_units);
3233 $this->length = $obj->length;
3234 $this->length_units = (is_null($obj->length_units) ? 0 : $obj->length_units);
3235 $this->width = $obj->width;
3236 $this->width_units = (is_null($obj->width_units) ? 0 : $obj->width_units);
3237 $this->height = $obj->height;
3238 $this->height_units = (is_null($obj->height_units) ? 0 : $obj->height_units);
3240 $this->surface = $obj->surface;
3241 $this->surface_units = (is_null($obj->surface_units) ? 0 : $obj->surface_units);
3242 $this->volume = $obj->volume;
3243 $this->volume_units = (is_null($obj->volume_units) ? 0 : $obj->volume_units);
3244 $this->barcode = $obj->barcode;
3245 $this->barcode_type = $obj->fk_barcode_type;
3247 $this->accountancy_code_buy = $obj->accountancy_code_buy;
3248 $this->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra;
3249 $this->accountancy_code_buy_export = $obj->accountancy_code_buy_export;
3250 $this->accountancy_code_sell = $obj->accountancy_code_sell;
3251 $this->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra;
3252 $this->accountancy_code_sell_export = $obj->accountancy_code_sell_export;
3254 $this->fk_default_warehouse = $obj->fk_default_warehouse;
3255 $this->fk_default_workstation = $obj->fk_default_workstation;
3256 $this->seuil_stock_alerte = $obj->seuil_stock_alerte;
3257 $this->desiredstock = $obj->desiredstock;
3258 $this->stock_reel = $obj->stock;
3259 $this->stockable_product = $obj->stockable_product;
3260 $this->pmp = $obj->pmp;
3262 $this->date_creation = $this->db->jdate($obj->datec);
3263 $this->date_modification = $this->db->jdate($obj->tms);
3265 $this->import_key = $obj->import_key;
3266 $this->entity = $obj->entity;
3268 $this->ref_ext = $obj->ref_ext;
3269 $this->fk_price_expression = $obj->fk_price_expression;
3270 $this->fk_unit = $obj->fk_unit;
3271 $this->price_autogen = $obj->price_autogen;
3272 $this->model_pdf = $obj->model_pdf;
3273 $this->last_main_doc = $obj->last_main_doc;
3275 $this->mandatory_period = $obj->mandatory_period;
3278 $this->packaging = (float) $obj->packaging;
3281 $this->db->free($resql);
3293 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
3294 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3295 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3296 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3297 $sql .=
" ,price_label";
3298 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3299 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3300 $sql .=
" AND price_level=".((int) $i);
3301 $sql .=
" AND fk_product = ".((int) $this->
id);
3302 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3304 $resql = $this->db->query($sql);
3306 $result = $this->db->fetch_array($resql);
3308 $this->multiprices[$i] = $result ? $result[
"price"] :
null;
3309 $this->multiprices_ttc[$i] = $result ? $result[
"price_ttc"] :
null;
3310 $this->multiprices_min[$i] = $result ? $result[
"price_min"] :
null;
3311 $this->multiprices_min_ttc[$i] = $result ? $result[
"price_min_ttc"] :
null;
3312 $this->multiprices_base_type[$i] = $result ? $result[
"price_base_type"] :
null;
3314 $this->multiprices_tva_tx[$i] = $result ? $result[
"tva_tx"].(!empty($result[
'default_vat_code']) ?
' ('.$result[
'default_vat_code'].
')' :
'') :
null;
3315 $this->multiprices_recuperableonly[$i] = $result ? $result[
"recuperableonly"] :
null;
3354 $this->error = $this->db->lasterror;
3360 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY') && empty($ignore_price_load)) {
3361 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3362 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid";
3363 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3364 $sql .=
" WHERE fk_product = ".((int) $this->
id);
3365 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3368 $resql = $this->db->query($sql);
3370 $result = $this->db->fetch_array($resql);
3374 $this->prices_by_qty[0] = $result[
"price_by_qty"];
3375 $this->prices_by_qty_id[0] = $result[
"rowid"];
3377 if ($this->prices_by_qty[0] == 1) {
3378 $sql =
"SELECT rowid,price, unitprice, quantity, remise_percent, remise, remise, price_base_type";
3379 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3380 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[0]);
3381 $sql .=
" ORDER BY quantity ASC";
3383 $resql = $this->db->query($sql);
3385 $resultat = array();
3387 while ($result = $this->db->fetch_array($resql)) {
3388 $resultat[$ii] = array();
3389 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3390 $resultat[$ii][
"price"] = $result[
"price"];
3391 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3392 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3393 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3395 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3398 $this->prices_by_qty_list[0] = $resultat;
3400 $this->error = $this->db->lasterror;
3406 $this->error = $this->db->lasterror;
3409 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') && empty($ignore_price_load)) {
3410 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
3411 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3412 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3413 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3414 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3415 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3416 $sql .=
" AND price_level=".((int) $i);
3417 $sql .=
" AND fk_product = ".((int) $this->
id);
3418 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3420 $resql = $this->db->query($sql);
3422 $this->error = $this->db->lasterror;
3425 $result = $this->db->fetch_array($resql);
3426 $this->multiprices[$i] = (!empty($result[
"price"]) ? $result[
"price"] : 0);
3427 $this->multiprices_ttc[$i] = (!empty($result[
"price_ttc"]) ? $result[
"price_ttc"] : 0);
3428 $this->multiprices_min[$i] = (!empty($result[
"price_min"]) ? $result[
"price_min"] : 0);
3429 $this->multiprices_min_ttc[$i] = (!empty($result[
"price_min_ttc"]) ? $result[
"price_min_ttc"] : 0);
3430 $this->multiprices_base_type[$i] = (!empty($result[
"price_base_type"]) ? $result[
"price_base_type"] :
'');
3432 $this->multiprices_tva_tx[$i] = (!empty($result[
"tva_tx"]) ? $result[
"tva_tx"] : 0);
3433 $this->multiprices_recuperableonly[$i] = (!empty($result[
"recuperableonly"]) ? $result[
"recuperableonly"] : 0);
3436 $this->prices_by_qty[$i] = (!empty($result[
"price_by_qty"]) ? $result[
"price_by_qty"] : 0);
3437 $this->prices_by_qty_id[$i] = (!empty($result[
"rowid"]) ? $result[
"rowid"] : 0);
3439 if ($this->prices_by_qty[$i] == 1) {
3440 $sql =
"SELECT rowid, price, unitprice, quantity, remise_percent, remise, price_base_type";
3441 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3442 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[$i]);
3443 $sql .=
" ORDER BY quantity ASC";
3445 $resql = $this->db->query($sql);
3447 $resultat = array();
3449 while ($result = $this->db->fetch_array($resql)) {
3450 $resultat[$ii] = array();
3451 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3452 $resultat[$ii][
"price"] = $result[
"price"];
3453 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3454 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3455 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3456 $resultat[$ii][
"remise"] = $result[
"remise"];
3457 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3460 $this->prices_by_qty_list[$i] = $resultat;
3462 $this->error = $this->db->lasterror;
3470 if (
isModEnabled(
'dynamicprices') && !empty($this->fk_price_expression) && empty($ignore_expression)) {
3471 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
3473 $price_result = $priceparser->parseProduct($this);
3474 if ($price_result >= 0) {
3475 $this->
price = $price_result;
3477 $this->price_ttc = (float)
price2num($this->
price) * (1 + ($this->tva_tx / 100));
3478 $this->price_ttc = (float)
price2num($this->price_ttc,
'MU');
3484 $this->stock_warehouse = array();
3491 $this->error = $this->db->lasterror();
3506 global $user, $hookmanager, $action;
3510 foreach (array(
'toconsume',
'consumed',
'toproduce',
'produced') as $role) {
3511 $this->stats_mo[
'customers_'.$role] = 0;
3512 $this->stats_mo[
'nb_'.$role] = 0;
3513 $this->stats_mo[
'qty_'.$role] = 0;
3515 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3516 $sql .=
" SUM(mp.qty) as qty";
3517 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as c";
3518 $sql .=
" INNER JOIN ".$this->db->prefix().
"mrp_production as mp ON mp.fk_mo=c.rowid";
3519 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3520 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3523 $sql .=
" c.entity IN (".getEntity(
'mo').
")";
3525 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3526 $sql .=
" AND mp.role ='".$this->db->escape($role).
"'";
3528 $sql .=
" AND c.fk_soc = ".((int) $socid);
3531 $result = $this->db->query($sql);
3533 $obj = $this->db->fetch_object($result);
3534 $this->stats_mo[
'customers_'.$role] = $obj->nb_customers ? $obj->nb_customers : 0;
3535 $this->stats_mo[
'nb_'.$role] = $obj->nb ? $obj->nb : 0;
3536 $this->stats_mo[
'qty_'.$role] = $obj->qty ?
price2num($obj->qty,
'MS') : 0;
3538 $this->error = $this->db->error();
3543 if (!empty($error)) {
3547 $parameters = array(
'socid' => $socid);
3548 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3550 $this->stats_mo = $hookmanager->resArray[
'stats_mo'];
3566 global $hookmanager, $action;
3570 $this->stats_bom[
'nb_toproduce'] = 0;
3571 $this->stats_bom[
'nb_toconsume'] = 0;
3572 $this->stats_bom[
'qty_toproduce'] = 0;
3573 $this->stats_bom[
'qty_toconsume'] = 0;
3575 $sql =
"SELECT COUNT(DISTINCT b.rowid) as nb_toproduce,";
3576 $sql .=
" SUM(b.qty) as qty_toproduce";
3577 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3578 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom = b.rowid";
3580 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3581 $sql .=
" AND b.fk_product =".((int) $this->
id);
3582 $sql .=
" GROUP BY b.rowid";
3584 $result = $this->db->query($sql);
3586 $obj = $this->db->fetch_object($result);
3587 $this->stats_bom[
'nb_toproduce'] = !empty($obj->nb_toproduce) ? $obj->nb_toproduce : 0;
3588 $this->stats_bom[
'qty_toproduce'] = !empty($obj->qty_toproduce) ?
price2num($obj->qty_toproduce) : 0;
3590 $this->error = $this->db->error();
3594 $sql =
"SELECT COUNT(DISTINCT bl.rowid) as nb_toconsume,";
3595 $sql .=
" SUM(bl.qty) as qty_toconsume";
3596 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3597 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
3599 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3600 $sql .=
" AND bl.fk_product =".((int) $this->
id);
3602 $result = $this->db->query($sql);
3604 $obj = $this->db->fetch_object($result);
3605 $this->stats_bom[
'nb_toconsume'] = !empty($obj->nb_toconsume) ? $obj->nb_toconsume : 0;
3606 $this->stats_bom[
'qty_toconsume'] = !empty($obj->qty_toconsume) ?
price2num($obj->qty_toconsume) : 0;
3608 $this->error = $this->db->error();
3612 if (!empty($error)) {
3616 $parameters = array(
'socid' => $socid);
3617 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3619 $this->stats_bom = $hookmanager->resArray[
'stats_bom'];
3635 global $user, $hookmanager, $action;
3637 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_customers, COUNT(DISTINCT p.rowid) as nb,";
3638 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3639 $sql .=
" FROM ".$this->db->prefix().
"propaldet as pd";
3640 $sql .=
", ".$this->db->prefix().
"propal as p";
3641 $sql .=
", ".$this->db->prefix().
"societe as s";
3642 $sql .=
" WHERE p.rowid = pd.fk_propal";
3643 $sql .=
" AND p.fk_soc = s.rowid";
3644 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
3645 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3646 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3647 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $user->id);
3651 $sql .=
" AND p.fk_soc = ".((int) $socid);
3654 $parameters = array(
'socid' => $socid,
'type_element' =>
'propal');
3655 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3656 $sql .= $hookmanager->resPrint;
3657 $result = $this->db->query($sql);
3659 $obj = $this->db->fetch_object($result);
3660 $this->stats_propale[
'customers'] = (int) $obj->nb_customers;
3661 $this->stats_propale[
'nb'] = (int) $obj->nb;
3662 $this->stats_propale[
'rows'] = (int) $obj->nb_rows;
3663 $this->stats_propale[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
3668 if (is_array($TFather) && !empty($TFather)) {
3669 foreach ($TFather as &$fatherData) {
3670 $pFather =
new Product($this->db);
3671 $pFather->id = (int) $fatherData[
'id'];
3672 $qtyCoef = $fatherData[
'qty'];
3674 if ($fatherData[
'incdec']) {
3675 $pFather->load_stats_propale($socid);
3677 if (!empty($pFather->stats_propale)) {
3678 $this->stats_propale[
'customers'] += $pFather->stats_propale[
'customers'];
3679 $this->stats_propale[
'nb'] += $pFather->stats_propale[
'nb'];
3680 $this->stats_propale[
'rows'] += $pFather->stats_propale[
'rows'];
3681 $this->stats_propale[
'qty'] += $pFather->stats_propale[
'qty'] * $qtyCoef;
3688 $parameters = array(
'socid' => $socid);
3689 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerProposal', $parameters, $this, $action);
3691 $this->stats_propale = $hookmanager->resArray[
'stats_propale'];
3696 $this->error = $this->db->error();
3712 global $user, $hookmanager, $action;
3714 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_suppliers, COUNT(DISTINCT p.rowid) as nb,";
3715 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3716 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as pd";
3717 $sql .=
", ".$this->db->prefix().
"supplier_proposal as p";
3718 $sql .=
", ".$this->db->prefix().
"societe as s";
3719 $sql .=
" WHERE p.rowid = pd.fk_supplier_proposal";
3720 $sql .=
" AND p.fk_soc = s.rowid";
3721 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
3722 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3723 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3724 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $user->id);
3728 $sql .=
" AND p.fk_soc = ".((int) $socid);
3731 $result = $this->db->query($sql);
3733 $obj = $this->db->fetch_object($result);
3734 $this->stats_proposal_supplier[
'suppliers'] = $obj->nb_suppliers;
3735 $this->stats_proposal_supplier[
'nb'] = $obj->nb;
3736 $this->stats_proposal_supplier[
'rows'] = $obj->nb_rows;
3737 $this->stats_proposal_supplier[
'qty'] = $obj->qty ? $obj->qty : 0;
3739 $parameters = array(
'socid' => $socid);
3740 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierProposal', $parameters, $this, $action);
3742 $this->stats_proposal_supplier = $hookmanager->resArray[
'stats_proposal_supplier'];
3747 $this->error = $this->db->error();
3765 global $user, $hookmanager, $action;
3768 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3769 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3770 $sql .=
" FROM ".$this->db->prefix().
"commandedet as cd";
3771 $sql .=
", ".$this->db->prefix().
"commande as c";
3772 $sql .=
", ".$this->db->prefix().
"societe as s";
3773 $sql .=
" WHERE c.rowid = cd.fk_commande";
3774 $sql .=
" AND c.fk_soc = s.rowid";
3775 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'commande').
")";
3776 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3777 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3778 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3781 $sql .=
" AND c.fk_soc = ".((int) $socid);
3783 if ($filtrestatut !=
'') {
3784 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3787 $parameters = array(
'socid' => $socid,
'type_element' =>
'order');
3788 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3789 $sql .= $hookmanager->resPrint;
3790 $result = $this->db->query($sql);
3792 $obj = $this->db->fetch_object($result);
3793 $this->stats_commande[
'customers'] = (int) $obj->nb_customers;
3794 $this->stats_commande[
'nb'] = (int) $obj->nb;
3795 $this->stats_commande[
'rows'] = (int) $obj->nb_rows;
3796 $this->stats_commande[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
3801 if (is_array($TFather) && !empty($TFather)) {
3802 foreach ($TFather as &$fatherData) {
3803 $pFather =
new Product($this->db);
3804 $pFather->id = $fatherData[
'id'];
3805 $qtyCoef = $fatherData[
'qty'];
3807 if ($fatherData[
'incdec']) {
3808 $pFather->load_stats_commande($socid, $filtrestatut);
3810 $this->stats_commande[
'customers'] += $pFather->stats_commande[
'customers'];
3811 $this->stats_commande[
'nb'] += $pFather->stats_commande[
'nb'];
3812 $this->stats_commande[
'rows'] += $pFather->stats_commande[
'rows'];
3813 $this->stats_commande[
'qty'] += $pFather->stats_commande[
'qty'] * $qtyCoef;
3826 $sql =
"SELECT SUM(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3827 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3829 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture' AND sourcetype = 'commande' ";
3830 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3831 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3832 $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)";
3836 $sql .=
"SELECT SUM(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3837 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3838 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_source = f.rowid AND el.targettype = 'commande' AND sourcetype = 'facture' ";
3839 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_target = c.rowid";
3840 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3841 $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)";
3843 $parameters = array(
'socid' => $socid,
'type_element' =>
'order');
3844 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3845 $sql .= $hookmanager->resPrint;
3846 $resql = $this->db->query($sql);
3848 while ($obj = $this->db->fetch_object($resql)) {
3849 $adeduire += (float) $obj->count;
3853 $this->stats_commande[
'qty'] -= $adeduire;
3856 include_once DOL_DOCUMENT_ROOT.
'/compta/facture/class/facture.class.php';
3860 $sql =
"SELECT sum(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3861 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3863 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture' AND sourcetype = 'commande' ";
3864 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3865 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3866 $sql .=
" AND EXISTS (SELECT cd.fk_product FROM ".$this->db->prefix().
"commandedet as cd WHERE cd.fk_product = fd.fk_product AND cd.fk_commande = c.rowid)";
3868 $sql .=
" UNION ALL ";
3870 $sql .=
"SELECT sum(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3871 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3872 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_source = f.rowid AND el.targettype = 'commande' AND sourcetype = 'facture' ";
3873 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_target = c.rowid";
3874 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3875 $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)";
3877 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3879 $parameters = array(
'socid' => $socid,
'type_element' =>
'order');
3880 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3881 $sql .= $hookmanager->resPrint;
3882 $resql = $this->db->query($sql);
3884 while ($obj = $this->db->fetch_object($resql)) {
3885 $adeduire += (float) $obj->count;
3888 $this->error = $this->db->error();
3892 $this->stats_commande[
'qty'] -= $adeduire;
3896 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3897 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerOrder', $parameters, $this, $action);
3899 $this->stats_commande = $hookmanager->resArray[
'stats_commande'];
3903 $this->error = $this->db->error();
3921 global $user, $hookmanager, $action;
3923 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_suppliers, COUNT(DISTINCT c.rowid) as nb,";
3924 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3925 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as cd";
3926 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as c";
3927 $sql .=
", ".$this->db->prefix().
"societe as s";
3928 $sql .=
" WHERE c.rowid = cd.fk_commande";
3929 $sql .=
" AND c.fk_soc = s.rowid";
3930 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3931 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3932 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3933 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3936 $sql .=
" AND c.fk_soc = ".((int) $socid);
3938 if ($filtrestatut !=
'') {
3939 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3941 if (!empty($dateofvirtualstock)) {
3942 $sql .=
" AND c.date_livraison <= '".$this->db->idate($dateofvirtualstock).
"'";
3945 $result = $this->db->query($sql);
3947 $obj = $this->db->fetch_object($result);
3948 $this->stats_commande_fournisseur[
'suppliers'] = $obj->nb_suppliers;
3949 $this->stats_commande_fournisseur[
'nb'] = $obj->nb;
3950 $this->stats_commande_fournisseur[
'rows'] = $obj->nb_rows;
3951 $this->stats_commande_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
3953 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3954 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierOrder', $parameters, $this, $action);
3956 $this->stats_commande_fournisseur = $hookmanager->resArray[
'stats_commande_fournisseur'];
3961 $this->error = $this->db->error().
' sql='.$sql;
3976 public function load_stats_sending($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $filterShipmentStatus =
'')
3979 global $user, $hookmanager, $action;
3981 $sql =
"SELECT COUNT(DISTINCT e.fk_soc) as nb_customers, COUNT(DISTINCT e.rowid) as nb,";
3982 $sql .=
" COUNT(ed.rowid) as nb_rows, SUM(ed.qty) as qty";
3983 $sql .=
" FROM ".$this->db->prefix().
"expeditiondet as ed";
3984 $sql .=
", ".$this->db->prefix().
"commandedet as cd";
3985 $sql .=
", ".$this->db->prefix().
"commande as c";
3986 $sql .=
", ".$this->db->prefix().
"expedition as e";
3987 $sql .=
", ".$this->db->prefix().
"societe as s";
3988 $sql .=
" WHERE e.rowid = ed.fk_expedition";
3989 $sql .=
" AND c.rowid = cd.fk_commande";
3990 $sql .=
" AND e.fk_soc = s.rowid";
3991 $sql .=
" AND e.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'expedition').
")";
3992 $sql .=
" AND ed.fk_elementdet = cd.rowid";
3993 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3994 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3995 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = e.fk_soc AND sc.fk_user = ".((int) $user->id);
3998 $sql .=
" AND e.fk_soc = ".((int) $socid);
4000 if ($filtrestatut !=
'') {
4001 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
4003 if (!empty($filterShipmentStatus)) {
4004 $sql .=
" AND e.fk_statut IN (".$this->db->sanitize($filterShipmentStatus).
")";
4007 $result = $this->db->query($sql);
4009 $obj = $this->db->fetch_object($result);
4010 $this->stats_expedition[
'customers'] = (int) $obj->nb_customers;
4011 $this->stats_expedition[
'nb'] = (int) $obj->nb;
4012 $this->stats_expedition[
'rows'] = (int) $obj->nb_rows;
4013 $this->stats_expedition[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
4018 if (is_array($TFather) && !empty($TFather)) {
4019 foreach ($TFather as &$fatherData) {
4020 $pFather =
new Product($this->db);
4021 $pFather->id = $fatherData[
'id'];
4022 $qtyCoef = $fatherData[
'qty'];
4024 if ($fatherData[
'incdec']) {
4025 $pFather->load_stats_sending($socid, $filtrestatut, $forVirtualStock);
4027 if (!empty($pFather->stats_expedition)) {
4028 $this->stats_expedition[
'customers'] += $pFather->stats_expedition[
'customers'];
4029 $this->stats_expedition[
'nb'] += $pFather->stats_expedition[
'nb'];
4030 $this->stats_expedition[
'rows'] += $pFather->stats_expedition[
'rows'];
4031 $this->stats_expedition[
'qty'] += $pFather->stats_expedition[
'qty'] * $qtyCoef;
4038 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock,
'filterShipmentStatus' => $filterShipmentStatus);
4039 $reshook = $hookmanager->executeHooks(
'loadStatsSending', $parameters, $this, $action);
4041 $this->stats_expedition = $hookmanager->resArray[
'stats_expedition'];
4046 $this->error = $this->db->error();
4061 public function load_stats_reception($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null)
4064 global $user, $hookmanager, $action;
4066 $sql =
"SELECT COUNT(DISTINCT cf.fk_soc) as nb_suppliers, COUNT(DISTINCT cf.rowid) as nb,";
4067 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4068 $sql .=
" FROM ".$this->db->prefix().
"receptiondet_batch as fd";
4069 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as cf";
4070 $sql .=
", ".$this->db->prefix().
"societe as s";
4071 $sql .=
" WHERE cf.rowid = fd.fk_element";
4072 $sql .=
" AND cf.fk_soc = s.rowid";
4073 $sql .=
" AND cf.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
4074 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4075 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
4076 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = cf.fk_soc AND sc.fk_user = ".((int) $user->id);
4079 $sql .=
" AND cf.fk_soc = ".((int) $socid);
4081 if ($filtrestatut !=
'') {
4082 $sql .=
" AND cf.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
4084 if (!empty($dateofvirtualstock)) {
4085 $sql .=
" AND fd.datec <= '".$this->db->idate($dateofvirtualstock).
"'";
4088 $result = $this->db->query($sql);
4090 $obj = $this->db->fetch_object($result);
4091 $this->stats_reception[
'suppliers'] = $obj->nb_suppliers;
4092 $this->stats_reception[
'nb'] = $obj->nb;
4093 $this->stats_reception[
'rows'] = $obj->nb_rows;
4094 $this->stats_reception[
'qty'] = $obj->qty ? $obj->qty : 0;
4096 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
4097 $reshook = $hookmanager->executeHooks(
'loadStatsReception', $parameters, $this, $action);
4099 $this->stats_reception = $hookmanager->resArray[
'stats_reception'];
4104 $this->error = $this->db->error();
4120 public function load_stats_inproduction($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null, $warehouseid = 0)
4123 global $user, $hookmanager, $action;
4127 $sql =
"SELECT COUNT(DISTINCT m.fk_soc) as nb_customers, COUNT(DISTINCT m.rowid) as nb,";
4128 $sql .=
" COUNT(mp.rowid) as nb_rows, SUM(mp.qty) as qty, role";
4129 $sql .=
" FROM ".$this->db->prefix().
"mrp_production as mp";
4130 $sql .=
", ".$this->db->prefix().
"mrp_mo as m";
4131 $sql .=
" LEFT JOIN ".$this->db->prefix().
"societe as s ON s.rowid = m.fk_soc";
4132 $sql .=
" WHERE m.rowid = mp.fk_mo";
4133 $sql .=
" AND m.entity IN (".getEntity(($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE')) ?
'stock' :
'mrp').
")";
4134 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
4135 $sql .=
" AND (mp.disable_stock_change IN (0) OR mp.disable_stock_change IS NULL)";
4136 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
4137 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = m.fk_soc AND sc.fk_user = ".((int) $user->id);
4140 $sql .=
" AND m.fk_soc = ".((int) $socid);
4142 if ($filtrestatut !=
'') {
4143 $sql .=
" AND m.status IN (".$this->db->sanitize($filtrestatut).
")";
4145 if (!empty($dateofvirtualstock)) {
4146 $sql .=
" AND m.date_valid <= '".$this->db->idate($dateofvirtualstock).
"'";
4148 if (!$serviceStockIsEnabled) {
4149 $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))";
4151 if (!empty($warehouseid)) {
4152 $sql .=
" AND m.fk_warehouse = ".((int) $warehouseid);
4154 $sql .=
" GROUP BY role";
4157 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
4159 $this->stats_mrptoconsume[
'customers'] = 0;
4160 $this->stats_mrptoconsume[
'nb'] = 0;
4161 $this->stats_mrptoconsume[
'rows'] = 0;
4162 $this->stats_mrptoconsume[
'qty'] = 0.0;
4163 $this->stats_mrptoproduce[
'customers'] = 0;
4164 $this->stats_mrptoproduce[
'nb'] = 0;
4165 $this->stats_mrptoproduce[
'rows'] = 0;
4166 $this->stats_mrptoproduce[
'qty'] = 0.0;
4169 $result = $this->db->query($sql);
4171 while ($obj = $this->db->fetch_object($result)) {
4172 if ($obj->role ==
'toconsume' && empty($warehouseid)) {
4173 $this->stats_mrptoconsume[
'customers'] += (int) $obj->nb_customers;
4174 $this->stats_mrptoconsume[
'nb'] += (int) $obj->nb;
4175 $this->stats_mrptoconsume[
'rows'] += (int) $obj->nb_rows;
4176 $this->stats_mrptoconsume[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4178 if ($obj->role ==
'consumed' && empty($warehouseid)) {
4182 $this->stats_mrptoconsume[
'qty'] -= ($obj->qty ? (float) $obj->qty : 0.0);
4184 if ($obj->role ==
'toproduce') {
4186 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4188 $this->stats_mrptoproduce[
'customers'] += (int) $obj->nb_customers;
4189 $this->stats_mrptoproduce[
'nb'] += (int) $obj->nb;
4190 $this->stats_mrptoproduce[
'rows'] += (int) $obj->nb_rows;
4191 $this->stats_mrptoproduce[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4194 if ($obj->role ==
'produced') {
4199 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
4201 $this->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
4208 if ($this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] < 0) {
4209 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
4212 if ($this->stats_mrptoconsume[
'qty'] < 0) {
4213 $this->stats_mrptoconsume[
'qty'] = 0;
4215 if ($this->stats_mrptoproduce[
'qty'] < 0) {
4216 $this->stats_mrptoproduce[
'qty'] = 0;
4220 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
4221 $reshook = $hookmanager->executeHooks(
'loadStatsInProduction', $parameters, $this, $action);
4223 $this->stats_mrptoproduce = $hookmanager->resArray[
'stats_mrptoproduce'];
4228 $this->error = $this->db->error();
4243 global $user, $hookmanager, $action;
4245 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
4246 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
4247 $sql .=
" FROM ".$this->db->prefix().
"contratdet as cd";
4248 $sql .=
", ".$this->db->prefix().
"contrat as c";
4249 $sql .=
", ".$this->db->prefix().
"societe as s";
4250 $sql .=
" WHERE c.rowid = cd.fk_contrat";
4251 $sql .=
" AND c.fk_soc = s.rowid";
4252 $sql .=
" AND c.entity IN (".getEntity(
'contract').
")";
4253 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
4254 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4255 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
4259 $sql .=
" AND c.fk_soc = ".((int) $socid);
4262 $result = $this->db->query($sql);
4264 $obj = $this->db->fetch_object($result);
4265 $this->stats_contrat[
'customers'] = (int) $obj->nb_customers;
4266 $this->stats_contrat[
'nb'] = (int) $obj->nb;
4267 $this->stats_contrat[
'rows'] = (int) $obj->nb_rows;
4268 $this->stats_contrat[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
4273 if (is_array($TFather) && !empty($TFather)) {
4274 foreach ($TFather as &$fatherData) {
4275 $pFather =
new Product($this->db);
4276 $pFather->id = $fatherData[
'id'];
4277 $qtyCoef = $fatherData[
'qty'];
4279 if ($fatherData[
'incdec']) {
4280 $pFather->load_stats_contrat($socid);
4282 if (!empty($pFather->stats_contrat)) {
4283 $this->stats_contrat[
'customers'] += $pFather->stats_contrat[
'customers'];
4284 $this->stats_contrat[
'nb'] += $pFather->stats_contrat[
'nb'];
4285 $this->stats_contrat[
'rows'] += $pFather->stats_contrat[
'rows'];
4286 $this->stats_contrat[
'qty'] += $pFather->stats_contrat[
'qty'] * $qtyCoef;
4293 $parameters = array(
'socid' => $socid);
4294 $reshook = $hookmanager->executeHooks(
'loadStatsContract', $parameters, $this, $action);
4296 $this->stats_contrat = $hookmanager->resArray[
'stats_contrat'];
4301 $this->error = $this->db->error().
' sql='.$sql;
4316 global $user, $hookmanager, $action;
4318 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4319 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(".$this->db->ifsql(
'f.type != 2',
'fd.qty',
'fd.qty * -1').
") as qty";
4320 $sql .=
" FROM ".$this->db->prefix().
"facturedet as fd";
4321 $sql .=
", ".$this->db->prefix().
"facture as f";
4322 $sql .=
", ".$this->db->prefix().
"societe as s";
4323 $sql .=
" WHERE f.rowid = fd.fk_facture";
4324 $sql .=
" AND f.fk_soc = s.rowid";
4325 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4326 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4327 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4328 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4332 $sql .=
" AND f.fk_soc = ".((int) $socid);
4335 $result = $this->db->query($sql);
4337 $obj = $this->db->fetch_object($result);
4338 $this->stats_facture[
'customers'] = (int) $obj->nb_customers;
4339 $this->stats_facture[
'nb'] = (int) $obj->nb;
4340 $this->stats_facture[
'rows'] = (int) $obj->nb_rows;
4341 $this->stats_facture[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
4346 if (is_array($TFather) && !empty($TFather)) {
4347 foreach ($TFather as &$fatherData) {
4348 $pFather =
new Product($this->db);
4349 $pFather->id = $fatherData[
'id'];
4350 $qtyCoef = $fatherData[
'qty'];
4352 if ($fatherData[
'incdec']) {
4353 $pFather->load_stats_facture($socid);
4355 if (!empty($pFather->stats_facture)) {
4356 $this->stats_facture[
'customers'] += $pFather->stats_facture[
'customers'];
4357 $this->stats_facture[
'nb'] += $pFather->stats_facture[
'nb'];
4358 $this->stats_facture[
'rows'] += $pFather->stats_facture[
'rows'];
4359 $this->stats_facture[
'qty'] += $pFather->stats_facture[
'qty'] * $qtyCoef;
4366 $parameters = array(
'socid' => $socid);
4367 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoice', $parameters, $this, $action);
4369 $this->stats_facture = $hookmanager->resArray[
'stats_facture'];
4374 $this->error = $this->db->error();
4390 global $user, $hookmanager, $action;
4392 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4393 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4394 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facturedet_rec as fd";
4395 $sql .=
", ".MAIN_DB_PREFIX.
"facture_rec as f";
4396 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
4397 $sql .=
" WHERE f.rowid = fd.fk_facture";
4398 $sql .=
" AND f.fk_soc = s.rowid";
4399 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4400 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4401 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4402 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4406 $sql .=
" AND f.fk_soc = ".((int) $socid);
4409 $result = $this->db->query($sql);
4411 $obj = $this->db->fetch_object($result);
4412 $this->stats_facturerec[
'customers'] = (int) $obj->nb_customers;
4413 $this->stats_facturerec[
'nb'] = (int) $obj->nb;
4414 $this->stats_facturerec[
'rows'] = (int) $obj->nb_rows;
4415 $this->stats_facturerec[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4420 if (is_array($TFather) && !empty($TFather)) {
4421 foreach ($TFather as &$fatherData) {
4422 $pFather =
new Product($this->db);
4423 $pFather->id = $fatherData[
'id'];
4424 $qtyCoef = $fatherData[
'qty'];
4426 if ($fatherData[
'incdec']) {
4427 $pFather->load_stats_facture($socid);
4429 $this->stats_facturerec[
'customers'] += $pFather->stats_facturerec[
'customers'];
4430 $this->stats_facturerec[
'nb'] += $pFather->stats_facturerec[
'nb'];
4431 $this->stats_facturerec[
'rows'] += $pFather->stats_facturerec[
'rows'];
4432 $this->stats_facturerec[
'qty'] += $pFather->stats_facturerec[
'qty'] * $qtyCoef;
4438 $parameters = array(
'socid' => $socid);
4439 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoiceRec', $parameters, $this, $action);
4441 $this->stats_facturerec = $hookmanager->resArray[
'stats_facturerec'];
4446 $this->error = $this->db->error();
4461 global $user, $hookmanager, $action;
4463 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
4464 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4465 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as fd";
4466 $sql .=
", ".$this->db->prefix().
"facture_fourn as f";
4467 $sql .=
", ".$this->db->prefix().
"societe as s";
4468 $sql .=
" WHERE f.rowid = fd.fk_facture_fourn";
4469 $sql .=
" AND f.fk_soc = s.rowid";
4470 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4471 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4472 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4473 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4477 $sql .=
" AND f.fk_soc = ".((int) $socid);
4480 $result = $this->db->query($sql);
4482 $obj = $this->db->fetch_object($result);
4483 $this->stats_facture_fournisseur[
'suppliers'] = (int) $obj->nb_suppliers;
4484 $this->stats_facture_fournisseur[
'nb'] = (int) $obj->nb;
4485 $this->stats_facture_fournisseur[
'rows'] = (int) $obj->nb_rows;
4486 $this->stats_facture_fournisseur[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4488 $parameters = array(
'socid' => $socid);
4489 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoice', $parameters, $this, $action);
4491 $this->stats_facture_fournisseur = $hookmanager->resArray[
'stats_facture_fournisseur'];
4496 $this->error = $this->db->error();
4511 global $user, $hookmanager, $action;
4513 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
4514 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4515 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facture_fourn_det_rec as fd";
4516 $sql .=
", ".MAIN_DB_PREFIX.
"facture_fourn_rec as f";
4517 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
4518 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4519 $sql .=
", ".MAIN_DB_PREFIX.
"societe_commerciaux as sc";
4521 $sql .=
" WHERE f.rowid = fd.fk_facture";
4522 $sql .=
" AND f.fk_soc = s.rowid";
4523 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4524 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4525 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4526 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4530 $sql .=
" AND f.fk_soc = ".((int) $socid);
4533 $result = $this->db->query($sql);
4535 $obj = $this->db->fetch_object($result);
4536 $this->stats_facturefournrec[
'suppliers'] = (int) $obj->nb_suppliers;
4537 $this->stats_facturefournrec[
'nb'] = (int) $obj->nb;
4538 $this->stats_facturefournrec[
'rows'] = (int) $obj->nb_rows;
4539 $this->stats_facturefournrec[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4541 $parameters = array(
'socid' => $socid);
4542 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoiceRec', $parameters, $this, $action);
4544 $this->stats_facturefournrec = $hookmanager->resArray[
'stats_facturefournrec'];
4549 $this->error = $this->db->error();
4568 $resql = $this->db->query($sql);
4570 $num = $this->db->num_rows($resql);
4573 $arr = $this->db->fetch_array($resql);
4574 if (is_array($arr)) {
4575 $keyfortab = (
string) $arr[1];
4577 $keyfortab = substr($keyfortab, -2);
4580 if ($mode ==
'byunit') {
4581 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[0];
4582 } elseif ($mode ==
'bynumber') {
4583 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4584 } elseif ($mode ==
'byamount') {
4585 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4594 $this->error = $this->db->error().
' sql='.$sql;
4601 } elseif ($year == -1) {
4610 for ($j = 0; $j < 12; $j++) {
4612 $idx = ucfirst(
dol_trunc(
dol_print_date(
dol_mktime(12, 0, 0, $month, 1, 1970),
"%b"), 1,
'right',
'UTF-8', 1));
4615 $result[$j] = array($idx, isset($tab[$year.$month]) ? $tab[$year.$month] : 0);
4618 $month =
"0".($month - 1);
4620 $month = substr($month, 1);
4630 return array_reverse($result);
4645 public function get_nb_vente($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4650 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4651 if ($mode ==
'bynumber') {
4652 $sql .=
", count(DISTINCT f.rowid)";
4654 $sql .=
", sum(d.total_ht) as total_ht";
4655 $sql .=
" FROM ".$this->db->prefix().
"facturedet as d, ".$this->db->prefix().
"facture as f, ".$this->db->prefix().
"societe as s";
4656 if ($filteronproducttype >= 0) {
4657 $sql .=
", ".$this->db->prefix().
"product as p";
4659 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4660 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4662 $sql .=
" WHERE f.rowid = d.fk_facture";
4663 if ($this->
id > 0) {
4664 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4666 $sql .=
" AND d.fk_product > 0";
4668 if ($filteronproducttype >= 0) {
4669 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4671 $sql .=
" AND f.fk_soc = s.rowid";
4672 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4673 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4674 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4677 $sql .=
" AND f.fk_soc = ".((int) $socid);
4679 $sql .= $morefilter;
4680 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4681 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4683 return $this->
_get_stats($sql, $mode, $year);
4698 public function get_nb_achat($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4703 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4704 if ($mode ==
'bynumber') {
4705 $sql .=
", count(DISTINCT f.rowid)";
4707 $sql .=
", sum(d.total_ht) as total_ht";
4708 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as d, ".$this->db->prefix().
"facture_fourn as f, ".$this->db->prefix().
"societe as s";
4709 if ($filteronproducttype >= 0) {
4710 $sql .=
", ".$this->db->prefix().
"product as p";
4712 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4713 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4715 $sql .=
" WHERE f.rowid = d.fk_facture_fourn";
4716 if ($this->
id > 0) {
4717 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4719 $sql .=
" AND d.fk_product > 0";
4721 if ($filteronproducttype >= 0) {
4722 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4724 $sql .=
" AND f.fk_soc = s.rowid";
4725 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4726 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4727 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4730 $sql .=
" AND f.fk_soc = ".((int) $socid);
4732 $sql .= $morefilter;
4733 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4734 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4736 return $this->
_get_stats($sql, $mode, $year);
4750 public function get_nb_propal($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4753 global $user, $hookmanager;
4755 $sql =
"SELECT sum(d.qty) as qty, date_format(p.datep, '%Y%m')";
4756 if ($mode ==
'bynumber') {
4757 $sql .=
", count(DISTINCT p.rowid)";
4759 $sql .=
", sum(d.total_ht) as total_ht";
4760 $sql .=
" FROM ".$this->db->prefix().
"propaldet as d, ".$this->db->prefix().
"propal as p, ".$this->db->prefix().
"societe as s";
4761 if ($filteronproducttype >= 0) {
4762 $sql .=
", ".$this->db->prefix().
"product as prod";
4764 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4765 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4767 $sql .=
" WHERE p.rowid = d.fk_propal";
4768 if ($this->
id > 0) {
4769 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4771 $sql .=
" AND d.fk_product > 0";
4773 if ($filteronproducttype >= 0) {
4774 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4776 $sql .=
" AND p.fk_soc = s.rowid";
4777 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
4778 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4779 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4782 $sql .=
" AND p.fk_soc = ".((int) $socid);
4784 $sql .= $morefilter;
4785 $parameters = array(
'socid' => $user->socid);
4786 $hookmanager->executeHooks(
'productGetNbPropal', $parameters, $this);
4787 $sql .= $hookmanager->resPrint;
4788 $sql .=
" GROUP BY date_format(p.datep,'%Y%m')";
4789 $sql .=
" ORDER BY date_format(p.datep,'%Y%m') DESC";
4790 return $this->
_get_stats($sql, $mode, $year);
4809 $sql =
"SELECT sum(d.qty) as qty, date_format(p.date_valid, '%Y%m')";
4810 if ($mode ==
'bynumber') {
4811 $sql .=
", count(DISTINCT p.rowid)";
4813 $sql .=
", sum(d.total_ht) as total_ht";
4814 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as d, ".$this->db->prefix().
"supplier_proposal as p, ".$this->db->prefix().
"societe as s";
4815 if ($filteronproducttype >= 0) {
4816 $sql .=
", ".$this->db->prefix().
"product as prod";
4818 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4819 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4821 $sql .=
" WHERE p.rowid = d.fk_supplier_proposal";
4822 if ($this->
id > 0) {
4823 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4825 $sql .=
" AND d.fk_product > 0";
4827 if ($filteronproducttype >= 0) {
4828 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4830 $sql .=
" AND p.fk_soc = s.rowid";
4831 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
4832 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4833 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4836 $sql .=
" AND p.fk_soc = ".((int) $socid);
4838 $sql .= $morefilter;
4839 $sql .=
" GROUP BY date_format(p.date_valid,'%Y%m')";
4840 $sql .=
" ORDER BY date_format(p.date_valid,'%Y%m') DESC";
4842 return $this->
_get_stats($sql, $mode, $year);
4856 public function get_nb_order($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4859 global $user, $hookmanager;
4861 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4862 if ($mode ==
'bynumber') {
4863 $sql .=
", count(DISTINCT c.rowid)";
4865 $sql .=
", sum(d.total_ht) as total_ht";
4866 $sql .=
" FROM ".$this->db->prefix().
"commandedet as d, ".$this->db->prefix().
"commande as c, ".$this->db->prefix().
"societe as s";
4867 if ($filteronproducttype >= 0) {
4868 $sql .=
", ".$this->db->prefix().
"product as p";
4870 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4871 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4873 $sql .=
" WHERE c.rowid = d.fk_commande";
4874 if ($this->
id > 0) {
4875 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4877 $sql .=
" AND d.fk_product > 0";
4879 if ($filteronproducttype >= 0) {
4880 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4882 $sql .=
" AND c.fk_soc = s.rowid";
4883 $sql .=
" AND c.entity IN (".getEntity(
'commande').
")";
4884 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4885 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4888 $sql .=
" AND c.fk_soc = ".((int) $socid);
4890 $sql .= $morefilter;
4891 $parameters = array(
'socid' => $user->socid);
4892 $hookmanager->executeHooks(
'productGetNbOrder', $parameters, $this);
4893 $sql .= $hookmanager->resPrint;
4894 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4895 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4897 return $this->
_get_stats($sql, $mode, $year);
4916 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4917 if ($mode ==
'bynumber') {
4918 $sql .=
", count(DISTINCT c.rowid)";
4920 $sql .=
", sum(d.total_ht) as total_ht";
4921 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as d, ".$this->db->prefix().
"commande_fournisseur as c, ".$this->db->prefix().
"societe as s";
4922 if ($filteronproducttype >= 0) {
4923 $sql .=
", ".$this->db->prefix().
"product as p";
4925 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4926 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4928 $sql .=
" WHERE c.rowid = d.fk_commande";
4929 if ($this->
id > 0) {
4930 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4932 $sql .=
" AND d.fk_product > 0";
4934 if ($filteronproducttype >= 0) {
4935 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4937 $sql .=
" AND c.fk_soc = s.rowid";
4938 $sql .=
" AND c.entity IN (".getEntity(
'supplier_order').
")";
4939 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4940 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4943 $sql .=
" AND c.fk_soc = ".((int) $socid);
4945 $sql .= $morefilter;
4946 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4947 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4949 return $this->
_get_stats($sql, $mode, $year);
4963 public function get_nb_contract($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4968 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_contrat, '%Y%m')";
4969 if ($mode ==
'bynumber') {
4970 $sql .=
", count(DISTINCT c.rowid)";
4972 $sql .=
", sum(d.total_ht) as total_ht";
4973 $sql .=
" FROM ".$this->db->prefix().
"contratdet as d, ".$this->db->prefix().
"contrat as c, ".$this->db->prefix().
"societe as s";
4974 if ($filteronproducttype >= 0) {
4975 $sql .=
", ".$this->db->prefix().
"product as p";
4977 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4978 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4980 $sql .=
" WHERE c.entity IN (".getEntity(
'contract').
")";
4981 $sql .=
" AND c.rowid = d.fk_contrat";
4983 if ($this->
id > 0) {
4984 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4986 $sql .=
" AND d.fk_product > 0";
4988 if ($filteronproducttype >= 0) {
4989 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4991 $sql .=
" AND c.fk_soc = s.rowid";
4993 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4994 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4997 $sql .=
" AND c.fk_soc = ".((int) $socid);
4999 $sql .= $morefilter;
5000 $sql .=
" GROUP BY date_format(c.date_contrat,'%Y%m')";
5001 $sql .=
" ORDER BY date_format(c.date_contrat,'%Y%m') DESC";
5003 return $this->
_get_stats($sql, $mode, $year);
5017 public function get_nb_mos($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
5022 $sql =
"SELECT sum(d.qty), date_format(d.date_valid, '%Y%m')";
5023 if ($mode ==
'bynumber') {
5024 $sql .=
", count(DISTINCT d.rowid)";
5026 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as d LEFT JOIN ".$this->db->prefix().
"societe as s ON d.fk_soc = s.rowid";
5027 if ($filteronproducttype >= 0) {
5028 $sql .=
", ".$this->db->prefix().
"product as p";
5030 if (!$user->hasRight(
'societe',
'client',
'voir')) {
5031 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
5034 $sql .=
" WHERE d.entity IN (".getEntity(
'mo').
")";
5035 $sql .=
" AND d.status > 0";
5037 if ($this->
id > 0) {
5038 $sql .=
" AND d.fk_product = ".((int) $this->
id);
5040 $sql .=
" AND d.fk_product > 0";
5042 if ($filteronproducttype >= 0) {
5043 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
5046 if (!$user->hasRight(
'societe',
'client',
'voir')) {
5047 $sql .=
" AND d.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
5050 $sql .=
" AND d.fk_soc = ".((int) $socid);
5052 $sql .= $morefilter;
5053 $sql .=
" GROUP BY date_format(d.date_valid,'%Y%m')";
5054 $sql .=
" ORDER BY date_format(d.date_valid,'%Y%m') DESC";
5056 return $this->
_get_stats($sql, $mode, $year);
5076 if (!is_numeric($id_pere)) {
5079 if (!is_numeric($id_fils)) {
5082 if (!is_numeric($incdec)) {
5092 $sql =
"SELECT fk_product_pere from ".$this->db->prefix().
"product_association";
5093 $sql .=
" WHERE fk_product_pere = ".((int) $id_fils).
" AND fk_product_fils = ".((int) $id_pere);
5094 if (!$this->db->query($sql)) {
5099 $sql =
"SELECT MAX(rang) as max_rank FROM ".$this->db->prefix().
"product_association";
5100 $sql .=
" WHERE fk_product_pere = ".((int) $id_pere);
5101 $resql = $this->db->query($sql);
5103 $obj = $this->db->fetch_object($resql);
5104 $rank = $obj->max_rank + 1;
5106 $sql =
"INSERT INTO ".$this->db->prefix().
"product_association(fk_product_pere,fk_product_fils,qty,incdec,rang)";
5107 $sql .=
" VALUES (".((int) $id_pere).
", ".((int) $id_fils).
", ".
price2num($qty,
'MS').
", ".((int) $incdec).
", ".((int) $rank).
")";
5108 if (! $this->db->query($sql)) {
5114 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_ADD', $user);
5116 $this->error = $this->db->lasterror();
5117 dol_syslog(get_class($this).
'::addSubproduct error='.$this->error, LOG_ERR);
5149 if (!is_numeric($id_pere)) {
5152 if (!is_numeric($id_fils)) {
5155 if (!is_numeric($incdec)) {
5158 if (!is_numeric($qty)) {
5162 $sql =
'UPDATE '.$this->db->prefix().
'product_association SET ';
5163 $sql .=
'qty = '.price2num($qty,
'MS');
5164 $sql .=
',incdec = '.((int) $incdec);
5165 $sql .=
' WHERE fk_product_pere = '.((int) $id_pere).
' AND fk_product_fils = '.((int) $id_fils);
5167 if (!$this->db->query($sql)) {
5173 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_UPDATE', $user);
5175 $this->error = $this->db->lasterror();
5176 dol_syslog(get_class($this).
'::updateSubproduct error='.$this->error, LOG_ERR);
5200 if (!is_numeric($fk_parent)) {
5203 if (!is_numeric($fk_child)) {
5207 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
5208 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5209 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
5211 dol_syslog(get_class($this).
'::del_sousproduit', LOG_DEBUG);
5212 if (!$this->db->query($sql)) {
5218 $sqlrank =
"SELECT rowid, rang FROM ".$this->db->prefix().
"product_association";
5219 $sqlrank .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5220 $sqlrank .=
" ORDER BY rang";
5221 $resqlrank = $this->db->query($sqlrank);
5224 while ($objrank = $this->db->fetch_object($resqlrank)) {
5226 $sql =
"UPDATE ".$this->db->prefix().
"product_association";
5227 $sql .=
" SET rang = ".((int) $cpt);
5228 $sql .=
" WHERE rowid = ".((int) $objrank->rowid);
5229 if (! $this->db->query($sql)) {
5238 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_DELETE', $user);
5240 $this->error = $this->db->lasterror();
5241 dol_syslog(get_class($this).
'::delSubproduct error='.$this->error, LOG_ERR);
5261 $sql =
"SELECT fk_product_pere, qty, incdec";
5262 $sql .=
" FROM ".$this->db->prefix().
"product_association";
5263 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5264 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
5266 $result = $this->db->query($sql);
5268 $num = $this->db->num_rows($result);
5271 $obj = $this->db->fetch_object($result);
5273 $this->is_sousproduit_qty = $obj->qty;
5274 $this->is_sousproduit_incdec = $obj->incdec;
5305 dol_syslog(get_class($this).
"::add_fournisseur id_fourn = ".$id_fourn.
" ref_fourn=".$ref_fourn.
" quantity=".$quantity, LOG_DEBUG);
5312 $sql =
"SELECT rowid, fk_product";
5313 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5314 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5315 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5316 $sql .=
" AND fk_product <> ".((int) $this->
id);
5317 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5319 $resql = $this->db->query($sql);
5321 $obj = $this->db->fetch_object($resql);
5324 $this->product_id_already_linked = $obj->fk_product;
5327 $this->db->free($resql);
5331 $sql =
"SELECT rowid";
5332 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5333 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5335 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5337 $sql .=
" AND (ref_fourn = '' OR ref_fourn IS NULL)";
5339 $sql .=
" AND quantity = ".((float) $quantity);
5340 $sql .=
" AND fk_product = ".((int) $this->
id);
5341 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5343 $resql = $this->db->query($sql);
5345 $obj = $this->db->fetch_object($resql);
5349 $sql =
"INSERT INTO ".$this->db->prefix().
"product_fournisseur_price(";
5352 $sql .=
", fk_product";
5354 $sql .=
", ref_fourn";
5355 $sql .=
", quantity";
5356 $sql .=
", fk_user";
5358 $sql .=
") VALUES (";
5359 $sql .=
"'".$this->db->idate($now).
"'";
5360 $sql .=
", ".((int)
$conf->entity);
5361 $sql .=
", ".((int) $this->
id);
5362 $sql .=
", ".((int) $id_fourn);
5363 $sql .=
", '".$this->db->escape($ref_fourn).
"'";
5364 $sql .=
", ".((float) $quantity);
5365 $sql .=
", ".((int) $user->id);
5369 if ($this->db->query($sql)) {
5370 $this->product_fourn_price_id = $this->db->last_insert_id($this->db->prefix().
"product_fournisseur_price");
5373 $this->error = $this->db->lasterror();
5378 $this->product_fourn_price_id = $obj->rowid;
5382 $this->error = $this->db->lasterror();
5401 $sql =
"SELECT DISTINCT p.fk_soc";
5402 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as p";
5403 $sql .=
" WHERE p.fk_product = ".((int) $this->
id);
5404 $sql .=
" AND p.entity = ".((int)
$conf->entity);
5406 $result = $this->db->query($sql);
5408 $num = $this->db->num_rows($result);
5411 $obj = $this->db->fetch_object($result);
5412 $list[$i] = $obj->fk_soc;
5438 $sql =
"INSERT INTO ".$this->db->prefix().
"product_price (";
5440 $sql .=
", fk_product";
5441 $sql .=
", date_price";
5442 $sql .=
", price_level";
5444 $sql .=
", price_ttc";
5445 $sql .=
", price_min";
5446 $sql .=
", price_min_ttc";
5447 $sql .=
", price_base_type";
5448 $sql .=
", price_label";
5449 $sql .=
", default_vat_code";
5451 $sql .=
", recuperableonly";
5452 $sql .=
", localtax1_tx";
5453 $sql .=
", localtax1_type";
5454 $sql .=
", localtax2_tx";
5455 $sql .=
", localtax2_type";
5456 $sql .=
", fk_user_author";
5458 $sql .=
", price_by_qty";
5459 $sql .=
", fk_price_expression";
5460 $sql .=
", fk_multicurrency";
5461 $sql .=
", multicurrency_code";
5462 $sql .=
", multicurrency_tx";
5463 $sql .=
", multicurrency_price";
5464 $sql .=
", multicurrency_price_ttc";
5468 $sql .=
", ".((int) $toId);
5469 $sql .=
", '".$this->db->idate($now).
"'";
5470 $sql .=
", price_level";
5472 $sql .=
", price_ttc";
5473 $sql .=
", price_min";
5474 $sql .=
", price_min_ttc";
5475 $sql .=
", price_base_type";
5476 $sql .=
", price_label";
5477 $sql .=
", default_vat_code";
5479 $sql .=
", recuperableonly";
5480 $sql .=
", localtax1_tx";
5481 $sql .=
", localtax1_type";
5482 $sql .=
", localtax2_tx";
5483 $sql .=
", localtax2_type";
5484 $sql .=
", ".((int) $user->id);
5486 $sql .=
", price_by_qty";
5487 $sql .=
", fk_price_expression";
5488 $sql .=
", fk_multicurrency";
5489 $sql .=
", multicurrency_code";
5490 $sql .=
", multicurrency_tx";
5491 $sql .=
", multicurrency_price";
5492 $sql .=
", multicurrency_price_ttc";
5493 $sql .=
" FROM ".$this->db->prefix().
"product_price ps";
5494 $sql .=
" WHERE fk_product = ".((int) $fromId);
5495 $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)";
5496 $sql .=
" ORDER BY date_price DESC";
5499 $resql = $this->db->query($sql);
5501 $this->db->rollback();
5505 $this->db->commit();
5522 $sql =
'INSERT INTO '.$this->db->prefix().
'product_association (fk_product_pere, fk_product_fils, qty, incdec)';
5523 $sql .=
" SELECT ".((int) $toId).
", fk_product_fils, qty, incdec FROM ".$this->db->prefix().
"product_association";
5524 $sql .=
" WHERE fk_product_pere = ".((int) $fromId);
5526 dol_syslog(get_class($this).
'::clone_association', LOG_DEBUG);
5527 if (!$this->db->query($sql)) {
5528 $this->db->rollback();
5532 $this->db->commit();
5565 $sql =
"INSERT ".$this->db->prefix().
"product_fournisseur_price (";
5566 $sql .=
" datec, fk_product, fk_soc, price, quantity, fk_user, tva_tx)";
5567 $sql .=
" SELECT '".$this->db->idate($now).
"', ".((int) $toId).
", fk_soc, price, quantity, fk_user, tva_tx";
5568 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5569 $sql .=
" WHERE fk_product = ".((int) $fromId);
5571 dol_syslog(get_class($this).
'::clone_fournisseurs', LOG_DEBUG);
5572 $resql = $this->db->query($sql);
5574 $this->db->rollback();
5577 $this->db->commit();
5595 public function fetch_prod_arbo(
$prod, $compl_path =
'', $multiply = 1, $level = 1, $id_parent = 0, $ignore_stock_load = 0)
5600 if ($multiply < 1) {
5601 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);
5606 foreach (
$prod as $id_product => $desc_pere) {
5607 if (is_array($desc_pere)) {
5608 $id = (!empty($desc_pere[0]) ? $desc_pere[0] :
'');
5609 $nb = (!empty($desc_pere[1]) ? $desc_pere[1] :
'');
5610 $type = (!empty($desc_pere[2]) ? $desc_pere[2] :
'');
5611 $label = (!empty($desc_pere[3]) ? $desc_pere[3] :
'');
5612 $incdec = (!empty($desc_pere[4]) ? $desc_pere[4] : 0);
5615 if (is_null($tmpproduct)) {
5616 $tmpproduct =
new Product($this->db);
5618 $tmpproduct->fetch($id);
5620 if (empty($ignore_stock_load) && ($tmpproduct->isProduct() ||
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES'))) {
5621 $tmpproduct->load_stock(
'nobatch,novirtual');
5624 $this->res[] = array(
5626 'id_parent' => $id_parent,
5627 'ref' => $tmpproduct->ref,
5629 'nb_total' => $nb * $multiply,
5630 'stock' => $tmpproduct->stock_reel,
5631 'stock_alert' => $tmpproduct->seuil_stock_alerte,
5633 'fullpath' => $compl_path.$label,
5635 'desiredstock' => $tmpproduct->desiredstock,
5637 'incdec' => $incdec,
5638 'entity' => $tmpproduct->entity
5642 if (isset($desc_pere[
'childs']) && is_array($desc_pere[
'childs'])) {
5643 if (!is_int($desc_pere[1] * $multiply)) {
5644 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);
5648 $this->
fetch_prod_arbo($desc_pere[
'childs'], $compl_path.$desc_pere[3].
" -> ", (
int) ceil($desc_pere[1] * $multiply), $level + 1, $id, $ignore_stock_load);
5666 $this->res = array();
5667 if (isset($this->sousprods) && is_array($this->sousprods)) {
5668 foreach ($this->sousprods as $prod_name => $desc_product) {
5669 if (is_array($desc_product)) {
5670 $this->
fetch_prod_arbo($desc_product,
"", $multiply, 1, $this->
id, $ignore_stock_load);
5689 $sql =
"SELECT COUNT(pa.rowid) as nb";
5690 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa";
5692 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id).
" OR pa.fk_product_pere = ".((int) $this->
id);
5693 } elseif ($mode == -1) {
5694 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id);
5695 } elseif ($mode == 1) {
5696 $sql .=
" WHERE pa.fk_product_pere = ".((int) $this->
id);
5699 $resql = $this->db->query($sql);
5701 $obj = $this->db->fetch_object($resql);
5703 $nb = (int) $obj->nb;
5723 $sql =
"SELECT count(rowid) as nb FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_parent = ".((int) $this->
id);
5724 $sql .=
" AND entity IN (".getEntity(
'product').
")";
5726 $resql = $this->db->query($sql);
5728 $obj = $this->db->fetch_object($resql);
5730 $nb = (int) $obj->nb;
5746 $sql =
"SELECT rowid FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_child = ".((int) $this->
id).
" AND entity IN (".
getEntity(
'product').
")";
5748 $query = $this->db->query($sql);
5751 if (!$this->db->num_rows($query)) {
5772 $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";
5773 $sql .=
", p.tosell as status, p.tobuy as status_buy";
5774 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa,";
5775 $sql .=
" ".$this->db->prefix().
"product as p";
5776 $sql .=
" WHERE p.rowid = pa.fk_product_pere";
5777 $sql .=
" AND pa.fk_product_fils = ".((int) $this->
id);
5779 $res = $this->db->query($sql);
5782 while ($record = $this->db->fetch_array($res)) {
5784 $prods[$record[
'id']] = array();
5785 $prods[$record[
'id']][
'id'] = $record[
'rowid'];
5786 $prods[$record[
'id']][
'ref'] = $record[
'ref'];
5787 $prods[$record[
'id']][
'label'] = $record[
'label'];
5788 $prods[$record[
'id']][
'qty'] = $record[
'qty'];
5789 $prods[$record[
'id']][
'incdec'] = $record[
'incdec'];
5790 $prods[$record[
'id']][
'fk_product_type'] = $record[
'fk_product_type'];
5791 $prods[$record[
'id']][
'entity'] = $record[
'entity'];
5792 $prods[$record[
'id']][
'status'] = $record[
'status'];
5793 $prods[$record[
'id']][
'status_buy'] = $record[
'status_buy'];
5812 public function getChildsArbo($id, $firstlevelonly = 0, $level = 1, $parents = array())
5818 $sql =
"SELECT p.rowid, p.ref, p.label as label, p.fk_product_type,";
5819 $sql .=
" pa.qty as qty, pa.fk_product_fils as id, pa.incdec,";
5820 $sql .=
" pa.rowid as fk_association, pa.rang";
5821 $sql .=
" FROM ".$this->db->prefix().
"product as p,";
5822 $sql .=
" ".$this->db->prefix().
"product_association as pa";
5823 $sql .=
" WHERE p.rowid = pa.fk_product_fils";
5824 $sql .=
" AND pa.fk_product_pere = ".((int) $id);
5825 $sql .=
" AND pa.fk_product_fils <> ".((int) $id);
5826 $sql .=
" ORDER BY pa.rang";
5828 dol_syslog(get_class($this).
'::getChildsArbo id='.$id.
' level='.$level.
' parents='.(is_array($parents) ? implode(
',', $parents) : $parents), LOG_DEBUG);
5835 $res = $this->db->query($sql);
5838 if ($this->db->num_rows($res) > 0) {
5842 while ($rec = $this->db->fetch_array($res)) {
5843 if (in_array($rec[
'id'], $parents)) {
5844 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);
5848 $prods[$rec[
'rowid']] = array(
5851 2 => $rec[
'fk_product_type'],
5852 3 => $this->db->escape($rec[
'label']),
5853 4 => $rec[
'incdec'],
5855 6 => $rec[
'fk_association'],
5860 if (empty($firstlevelonly)) {
5861 $listofchilds = $this->
getChildsArbo($rec[
'rowid'], 0, $level + 1, $parents);
5862 foreach ($listofchilds as $keyChild => $valueChild) {
5863 $prods[$rec[
'rowid']][
'childs'][$keyChild] = $valueChild;
5887 foreach ($this->
getChildsArbo($this->
id) as $keyChild => $valueChild) {
5888 $parent[$this->label][$keyChild] = $valueChild;
5890 foreach ($parent as $key => $value) {
5891 $this->sousprods[$key] = $value;
5904 global
$conf, $langs, $user;
5906 $langs->loadLangs(array(
'products',
'other'));
5909 $nofetch = !empty($params[
'nofetch']);
5912 return [
'optimize' => $langs->trans(
"ShowProduct")];
5916 $permissiontoreadproduct = 0;
5917 if ($this->
type == self::TYPE_PRODUCT && $user->hasRight(
'product',
'read')) {
5918 $permissiontoreadproduct = 1;
5920 if ($this->
type == self::TYPE_SERVICE && $user->hasRight(
'service',
'read')) {
5921 $permissiontoreadproduct = 1;
5924 if (!empty($this->entity) && $permissiontoreadproduct) {
5925 $tmpphoto = $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 80, 0, 0, 0, 0,
'1');
5926 if ($this->nbphoto > 0) {
5927 $datas[
'photo'] =
'<div class="photointooltip floatright">'.
"\n" . $tmpphoto .
'</div>';
5932 $datas[
'picto'] =
img_picto(
'',
'product').
' <u class="paddingrightonly">'.$langs->trans(
"Product").
'</u>';
5934 $datas[
'picto'] =
img_picto(
'',
'service').
' <u class="paddingrightonly">'.$langs->trans(
"Service").
'</u>';
5936 if (isset($this->
status) && isset($this->status_buy)) {
5937 $datas[
'status'] =
' '.$this->getLibStatut(5, 0) .
' '.$this->getLibStatut(5, 1);
5940 if (!empty($this->
ref)) {
5941 $datas[
'ref'] =
'<br><b>'.$langs->trans(
'ProductRef').
':</b> '.$this->ref;
5943 if (!empty($this->label)) {
5944 $datas[
'label'] =
'<br><b>'.$langs->trans(
'ProductLabel').
':</b> '.$this->label.
'<br>';
5947 if ($permissiontoreadproduct) {
5952 $datas[
'stockmanaged'] =
"<br><b>".$langs->trans(
"StockableProduct").
'</b>: '.
yn($this->
isStockManaged());
5956 $langs->load(
"productbatch");
5957 $datas[
'batchstatus'] =
"<br><b>".$langs->trans(
"ManageLotSerial").
'</b>: '.$this->
getLibStatut(0, 2);
5958 if ($this->status_batch) {
5959 $datas[
'batchdlc'] =
"<br><b>".$langs->trans(
"BatchSellOrEatByMandatoryList", $langs->transnoentitiesnoconv(
"SellByDate"), $langs->transnoentitiesnoconv(
"EatByDate")).
'</b>: '.$this->
getSellOrEatByMandatoryLabel();
5964 $datas[
'barcode'] =
'<br><b>'.$langs->trans(
'BarCode').
':</b> '.$this->barcode;
5968 if ($this->weight) {
5969 $datas[
'weight'] =
"<br><b>".$langs->trans(
"Weight").
'</b>: '.$this->weight.
' '.
measuringUnitString(0,
"weight", $this->weight_units);
5972 if ($this->length) {
5973 $labelsize .=
"<b>".$langs->trans(
"Length").
'</b>: '.$this->length.
' '.
measuringUnitString(0,
'size', $this->length_units);
5976 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Width").
'</b>: '.$this->width.
' '.
measuringUnitString(0,
'size', $this->width_units);
5978 if ($this->height) {
5979 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Height").
'</b>: '.$this->height.
' '.
measuringUnitString(0,
'size', $this->height_units);
5982 $datas[
'size'] =
"<br>".$labelsize;
5985 $labelsurfacevolume =
"";
5986 if ($this->surface) {
5987 $labelsurfacevolume .=
"<b>".$langs->trans(
"Surface").
'</b>: '.$this->surface.
' '.
measuringUnitString(0,
'surface', $this->surface_units);
5989 if ($this->volume) {
5990 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Volume").
'</b>: '.$this->volume.
' '.
measuringUnitString(0,
'volume', $this->volume_units);
5992 if ($labelsurfacevolume) {
5993 $datas[
'surface'] =
"<br>" . $labelsurfacevolume;
5996 if ($this->
isService() && !empty($this->duration_value)) {
5998 $datas[
'duration'] =
'<br><b>'.$langs->trans(
"Duration").
':</b> '.$this->duration_value;
5999 if ($this->duration_value > 1) {
6000 $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"));
6001 } elseif ($this->duration_value > 0) {
6002 $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"));
6004 $datas[
'duration'] .= (!empty($this->duration_unit) && isset($dur[$this->duration_unit]) ?
" ".$langs->trans($dur[$this->duration_unit]) :
'');
6006 if (empty($user->socid)) {
6007 if ($this->
isStockManaged() && isset($this->pmp) && $this->pmp) {
6008 $datas[
'pmp'] =
"<br><b>".$langs->trans(
"PMPValue").
'</b>: '.
price($this->pmp, 0,
'', 1, -1, -1,
$conf->currency);
6012 if ($this->
status && isset($this->accountancy_code_sell)) {
6013 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
6014 $selllabel =
'<br>';
6015 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellCode').
':</b> '.
length_accountg($this->accountancy_code_sell);
6016 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellIntraCode').
':</b> '.
length_accountg($this->accountancy_code_sell_intra);
6017 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellExportCode').
':</b> '.
length_accountg($this->accountancy_code_sell_export);
6018 $datas[
'accountancysell'] = $selllabel;
6020 if ($this->status_buy && isset($this->accountancy_code_buy)) {
6021 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
6023 if (empty($this->
status)) {
6024 $buylabel .=
'<br>';
6026 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyCode').
':</b> '.
length_accountg($this->accountancy_code_buy);
6027 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyIntraCode').
':</b> '.
length_accountg($this->accountancy_code_buy_intra);
6028 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyExportCode').
':</b> '.
length_accountg($this->accountancy_code_buy_export);
6029 $datas[
'accountancybuy'] = $buylabel;
6035 require_once DOL_DOCUMENT_ROOT .
'/categories/class/categorie.class.php';
6036 $form =
new Form($this->db);
6037 $datas[
'categories'] =
'<br>' . $form->showCategories($this->
id, Categorie::TYPE_PRODUCT, 1);
6057 public function getNomUrl($withpicto = 0, $option =
'', $maxlength = 0, $save_lastsearch_value = -1, $notooltip = 0, $morecss =
'', $add_label = 0, $sep =
' - ')
6059 global $langs, $hookmanager;
6061 include_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
6067 $newref =
dol_trunc($newref, $maxlength,
'middle');
6071 'objecttype' => ($this->
type == 1 ?
'service' :
'product'),
6072 'option' => $option,
6075 $classfortooltip =
'classfortooltip';
6078 $classfortooltip =
'classforajaxtooltip';
6079 $dataparams =
' data-params="'.dol_escape_htmltag(json_encode($params)).
'"';
6086 if (empty($notooltip)) {
6088 $label = $langs->trans(
"ShowProduct");
6089 $linkclose .=
' alt="'.dol_escape_htmltag($label, 1, 1).
'"';
6091 $linkclose .= ($label ?
' title="'.dol_escape_htmltag($label, 1, 1).
'"' :
' title="tocomplete"');
6092 $linkclose .= $dataparams.
' class="nowraponall '.$classfortooltip.($morecss ?
' '.$morecss :
'').
'"';
6094 $linkclose =
' class="nowraponall'.($morecss ?
' '.$morecss :
'').
'"';
6097 if ($option ==
'supplier' || $option ==
'category') {
6098 $url = DOL_URL_ROOT.
'/product/price_suppliers.php?id='.$this->id;
6099 } elseif ($option ==
'stock') {
6100 $url = DOL_URL_ROOT.
'/product/stock/product.php?id='.$this->id;
6101 } elseif ($option ==
'composition') {
6102 $url = DOL_URL_ROOT.
'/product/composition/card.php?id='.$this->id;
6104 $url = DOL_URL_ROOT.
'/product/card.php?id='.$this->id;
6107 if ($option !==
'nolink') {
6109 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
6110 if ($save_lastsearch_value == -1 && isset($_SERVER[
"PHP_SELF"]) && preg_match(
'/list\.php/', $_SERVER[
"PHP_SELF"])) {
6111 $add_save_lastsearch_values = 1;
6113 if ($add_save_lastsearch_values) {
6114 $url .=
'&save_lastsearch_values=1';
6118 $linkstart =
'<a href="'.$url.
'"';
6119 $linkstart .= $linkclose.
'>';
6122 $result .= $linkstart;
6125 $result .= (
img_object(($notooltip ?
'' : $label),
'product',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
6128 $result .= (
img_object(($notooltip ?
'' : $label),
'service',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
6131 $result .=
'<span class="aaa">'.dol_escape_htmltag($newref).
'</span>';
6132 $result .= $linkend;
6133 if ($withpicto != 2) {
6134 $result .= (($add_label && $this->label) ? $sep.dol_trunc($this->label, ($add_label > 1 ? $add_label : 0)) :
'');
6138 $hookmanager->initHooks(array(
'productdao'));
6139 $parameters = array(
'id' => $this->
id,
'getnomurl' => &$result,
'label' => &$label);
6140 $reshook = $hookmanager->executeHooks(
'getNomUrl', $parameters, $this, $action);
6142 $result = $hookmanager->resPrint;
6144 $result .= $hookmanager->resPrint;
6161 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
6165 $langs->load(
"products");
6166 $outputlangs->load(
"products");
6171 if (!empty($this->model_pdf)) {
6172 $modele = $this->model_pdf;
6178 if (empty($modele)) {
6181 $modelpath =
"core/modules/product/doc/";
6182 return $this->
commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
6199 return $this->
LibStatut($this->status_buy, $mode, $type);
6201 return $this->
LibStatut($this->status_batch, $mode, $type);
6204 return $this->
LibStatut($this->status_buy, $mode, $type);
6222 $labelStatus = $labelStatusShort =
'';
6224 $langs->load(
'products');
6226 $langs->load(
"productbatch");
6232 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial')));
6235 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort')));
6240 return dolGetStatus($langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch'),
'',
'', empty($status) ?
'status5' :
'status4', 3,
'dot');
6246 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'));
6250 $statuttrans = empty($status) ?
'status5' :
'status4';
6255 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSellShort');
6256 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSell');
6257 } elseif ($type == 1) {
6258 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuyShort');
6259 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuy');
6260 } elseif ($type == 2) {
6261 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch');
6262 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort');
6264 } elseif ($status == 1) {
6267 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSellShort');
6268 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSell');
6269 } elseif ($type == 1) {
6270 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBuyShort');
6271 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBuy');
6272 } elseif ($type == 2) {
6273 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBatch');
6274 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort');
6276 } elseif ($type == 2 && $status == 2) {
6277 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSerial');
6278 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort');
6282 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'),
'',
'',
'status0', 0);
6284 return dolGetStatus($labelStatus, $labelStatusShort,
'', $statuttrans, $mode);
6298 $langs->load(
'products');
6301 if (isset($this->finished) && $this->finished >= 0) {
6302 $sql =
"SELECT label, code FROM ".$this->db->prefix().
"c_product_nature where code = ".((int) $this->finished).
" AND active=1";
6303 $resql = $this->db->query($sql);
6305 $this->error = $this->db->error().
' sql='.$sql;
6306 dol_syslog(__METHOD__.
' Error '.$this->error, LOG_ERR);
6308 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
6309 $label = $langs->trans($res[
'label']);
6311 $this->db->free($resql);
6335 public function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label =
'', $price = 0, $inventorycode =
'', $origin_element =
'', $origin_id =
null, $disablestockchangeforsubproduct = 0, $extrafields =
null)
6341 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6344 $nbpiece = (float) $nbpiece;
6349 $nbpiece = abs($nbpiece);
6356 $movementstock->setOrigin($origin_element, (
int) $origin_id);
6357 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'',
'',
'',
'',
false, 0, $disablestockchangeforsubproduct);
6361 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6362 $movementstock->array_options = $array_options;
6363 $movementstock->insertExtraFields();
6365 $this->db->commit();
6370 $this->db->rollback();
6399 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)
6405 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6408 $nbpiece = (float) $nbpiece;
6413 $nbpiece = abs($nbpiece);
6421 $movementstock->setOrigin($origin_element, (
int) $origin_id);
6422 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'', $dlc, $dluo, $lot,
false, 0, $disablestockchangeforsubproduct, 0, $force_update_batch);
6426 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6427 $movementstock->array_options = $array_options;
6428 $movementstock->insertExtraFields();
6430 $this->db->commit();
6433 $this->error = $movementstock->error;
6434 $this->errors = $movementstock->errors;
6436 $this->db->rollback();
6456 public function load_stock($option =
'', $includedraftpoforvirtual =
null, $dateofvirtualstock =
null)
6459 $this->stock_reel = 0;
6460 $this->stock_warehouse = array();
6461 $this->stock_theorique = 0;
6464 $warehouseStatus = array();
6465 if (preg_match(
'/warehouseclosed/', $option)) {
6468 if (preg_match(
'/warehouseopen/', $option)) {
6471 if (preg_match(
'/warehouseinternal/', $option)) {
6479 $sql =
"SELECT ps.rowid, ps.reel, ps.fk_entrepot";
6480 $sql .=
" FROM ".$this->db->prefix().
"product_stock as ps";
6481 $sql .=
", ".$this->db->prefix().
"entrepot as w";
6482 $sql .=
" WHERE w.entity IN (".getEntity(
'stock').
")";
6483 $sql .=
" AND w.rowid = ps.fk_entrepot";
6484 $sql .=
" AND ps.fk_product = ".((int) $this->
id);
6485 if (count($warehouseStatus)) {
6486 $sql .=
" AND w.statut IN (".$this->db->sanitize(implode(
',', $warehouseStatus)).
")";
6489 $sql .=
" ORDER BY ps.reel ".(getDolGlobalString(
'DO_NOT_TRY_TO_DEFRAGMENT_STOCKS_WAREHOUSE') ?
'DESC' :
'ASC');
6491 dol_syslog(get_class($this).
"::load_stock", LOG_DEBUG);
6492 $result = $this->db->query($sql);
6494 $num = $this->db->num_rows($result);
6498 $row = $this->db->fetch_object($result);
6499 $this->stock_warehouse[$row->fk_entrepot] =
new stdClass();
6500 $this->stock_warehouse[$row->fk_entrepot]->real = $row->reel;
6501 $this->stock_warehouse[$row->fk_entrepot]->id = $row->rowid;
6502 if ((!preg_match(
'/nobatch/', $option)) && $this->
hasbatch()) {
6503 $this->stock_warehouse[$row->fk_entrepot]->detail_batch =
Productbatch::findAll($this->db, $row->rowid, 1, $this->id);
6505 $this->stock_reel += $row->reel;
6508 $this->stock_reel = (float)
price2num($this->stock_reel,
'MS');
6510 $this->db->free($result);
6512 if (!preg_match(
'/novirtual/', $option)) {
6518 $this->error = $this->db->lasterror();
6537 global $hookmanager, $action;
6539 $stock_commande_client = 0;
6540 $stock_commande_fournisseur = 0;
6541 $stock_sending_client = 0;
6542 $stock_reception_fournisseur = 0;
6543 $stock_inproduction = 0;
6552 $stock_commande_client = $this->stats_commande[
'qty'];
6555 require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expedition.class.php';
6556 $filterShipmentStatus =
'';
6566 $stock_sending_client = $this->stats_expedition[
'qty'];
6570 $filterStatus =
getDolGlobalString(
'SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK',
'3,4');
6571 if (isset($includedraftpoforvirtual)) {
6572 $filterStatus =
'0,1,2,'.$filterStatus;
6578 $stock_commande_fournisseur = $this->stats_commande_fournisseur[
'qty'];
6582 $filterStatus =
'4';
6583 if (isset($includedraftpoforvirtual)) {
6584 $filterStatus =
'0,'.$filterStatus;
6590 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
6598 $stock_inproduction = $this->stats_mrptoproduce[
'qty'] - $this->stats_mrptoconsume[
'qty'];
6601 $this->stock_theorique = $this->stock_reel + $stock_inproduction;
6605 $weBillOrderOrShipmentReception =
getDolGlobalString(
'STOCK_DO_WE_BILL_ORDER_OR_SHIPMENTECEPTION_FOR_VIRTUALSTOCK',
'order');
6609 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6613 $result = $tmpnewprod->load_stats_commande(0,
'0', 1);
6614 $this->stock_theorique += $tmpnewprod->stats_commande[
'qty'];
6616 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6617 $this->stock_theorique -= $stock_commande_client;
6618 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6619 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6624 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6626 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6628 if (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER_INCLUDE_DRAFT')) {
6630 $result = $tmpnewprod->load_stats_commande_fournisseur(0,
'0', 1);
6631 $this->stock_theorique += $this->stats_commande_fournisseur[
'qty'];
6633 $this->stock_theorique -= $stock_reception_fournisseur;
6634 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6635 $this->stock_theorique += $stock_commande_fournisseur;
6636 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6637 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6640 $parameters = array(
'id' => $this->
id,
'includedraftpoforvirtual' => $includedraftpoforvirtual);
6642 $reshook = $hookmanager->executeHooks(
'loadvirtualstock', $parameters, $this, $action);
6644 $this->stock_theorique = $hookmanager->resArray[
'stock_theorique'];
6645 } elseif ($reshook == 0 && isset($hookmanager->resArray[
'stock_stats_hook'])) {
6646 $this->stock_theorique += $hookmanager->resArray[
'stock_stats_hook'];
6650 if (!empty($this->stock_warehouse) &&
getDolGlobalString(
'STOCK_ALLOW_VIRTUAL_STOCK_PER_WAREHOUSE')) {
6651 foreach ($this->stock_warehouse as $warehouseid => $stockwarehouse) {
6659 if ($this->fk_default_warehouse == $warehouseid) {
6660 $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']);
6662 $this->stock_warehouse[$warehouseid]->virtual = $this->stock_warehouse[$warehouseid]->real + $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'];
6679 $this->stock_warehouse = array();
6684 if (count($prods_arbo) > 0) {
6685 $productCachedList = array();
6686 $stockByComponentList = array();
6688 foreach ($prods_arbo as $componentArr) {
6689 $componentId = $componentArr[
'id'];
6691 if ($componentArr[
'incdec'] == 1) {
6692 if (!isset($productCachedList[$componentId])) {
6693 $componentStatic =
new self($this->db);
6694 $componentStatic->fetch($componentId);
6696 $childrenNb = $componentStatic->hasFatherOrChild(1);
6697 if ($childrenNb == 0) {
6698 $componentStatic->load_stock(
'nobatch,novirtual');
6699 if (!isset($stockByComponentList[$componentId])) {
6700 $stockByComponentList[$componentId] = array(
6704 $stockByComponentList[$componentId][
'qty_need'] += $componentArr[
'nb_total'];
6706 $productCachedList[$componentId] = $componentStatic;
6711 if (!empty($stockByComponentList)) {
6712 foreach ($stockByComponentList as $componentId => $stockByComponentArr) {
6713 if (!isset($productCachedList[$componentId])) {
6714 $componentStatic =
new self($this->db);
6715 $componentStatic->fetch($componentId);
6716 $componentStatic->load_stock(
'nobatch,novirtual');
6717 $productCachedList[$componentId] = $componentStatic;
6719 $component = $productCachedList[$componentId];
6722 if ($component->stock_reel < $stockByComponentArr[
'qty_need']) {
6725 $this->error =
'Not enough component [id='.$componentId.
'] in stock, real='.$component->stock_reel.
' and need='.$stockByComponentArr[
'qty_need'];
6726 $this->errors[] = $this->error;
6727 dol_syslog(__METHOD__.
' : '.$this->error, LOG_ERR);
6729 if (!empty($component->stock_warehouse)) {
6730 foreach ($component->stock_warehouse as $warehouseId => $warehouseObj) {
6731 $kitWarehouseAvailable =
new stdClass();
6732 $kitWarehouseAvailable->id = $warehouseObj->id;
6733 $kitWarehouseAvailable->real = $qtyWish;
6734 $this->stock_warehouse[$warehouseId] = $kitWarehouseAvailable;
6743 } elseif (
getDolGlobalInt(
'PRODUIT_SOUSPRODUITS_ALSO_ENABLE_PARENT_STOCK_MOVE') && empty($productCachedList)) {
6767 $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";
6768 $sql .=
" WHERE pb.fk_product_stock = ps.rowid AND ps.fk_product = ".((int) $this->
id).
" AND pb.batch = '".$this->db->escape($batch).
"'";
6769 $sql .=
" GROUP BY pb.batch, pb.eatby, pb.sellby";
6770 dol_syslog(get_class($this).
"::loadBatchInfo load first entry found for lot/serial = ".$batch, LOG_DEBUG);
6771 $resql = $this->db->query($sql);
6773 $num = $this->db->num_rows($resql);
6776 $obj = $this->db->fetch_object($resql);
6777 $result[] = array(
'batch' => $batch,
'eatby' => $this->db->jdate($obj->eatby),
'sellby' => $this->db->jdate($obj->sellby),
'qty' => $obj->qty);
6783 $this->db->rollback();
6800 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6806 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos";
6808 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product').dol_sanitizeFileName($this->
ref);
6813 $dir_osencoded = $dir;
6815 if (is_dir($dir_osencoded)) {
6816 $originImage = $dir.
'/'.$file[
'name'];
6827 if (is_numeric($result) && $result > 0) {
6844 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6845 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6849 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos/";
6851 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product');
6855 if (file_exists($dir_osencoded)) {
6856 $handle = opendir($dir_osencoded);
6857 if (is_resource($handle)) {
6858 while (($file = readdir($handle)) !==
false) {
6860 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6883 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6884 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6890 $handle = @opendir($dir_osencoded);
6891 if (is_resource($handle)) {
6892 while (($file = readdir($handle)) !==
false) {
6894 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6901 $photo_vignette =
'';
6903 if (preg_match(
'/('.$this->regeximgext.
')$/i', $photo, $regs)) {
6904 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $photo).
'_small'.$regs[0];
6907 $dirthumb = $dir.
'thumbs/';
6911 $obj[
'photo'] = $photo;
6912 if ($photo_vignette &&
dol_is_file($dirthumb.$photo_vignette)) {
6913 $obj[
'photo_vignette'] =
'thumbs/'.$photo_vignette;
6915 $obj[
'photo_vignette'] =
"";
6918 $tabobj[$nbphoto - 1] = $obj;
6921 if ($nbmax && $nbphoto >= $nbmax) {
6943 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6944 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6946 $dir = dirname($file).
'/';
6947 $dirthumb = $dir.
'/thumbs/';
6948 $filename = preg_replace(
'/'.preg_quote($dir,
'/').
'/i',
'', $file);
6954 if (preg_match(
'/('.$this->regeximgext.
')$/i', $filename, $regs)) {
6955 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_small'.$regs[0];
6956 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6960 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_mini'.$regs[0];
6961 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6978 $infoImg = getimagesize($file_osencoded);
6979 $this->imgWidth = $infoImg[0];
6980 $this->imgHeight = $infoImg[1];
6990 global $hookmanager;
6992 $this->nb = array();
6994 $sql =
"SELECT count(p.rowid) as nb, fk_product_type";
6995 $sql .=
" FROM ".$this->db->prefix().
"product as p";
6996 $sql .=
' WHERE p.entity IN ('.getEntity($this->element, 1).
')';
6998 if (is_object($hookmanager)) {
6999 $parameters = array();
7000 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
7001 $sql .= $hookmanager->resPrint;
7003 $sql .=
' GROUP BY fk_product_type';
7005 $resql = $this->db->query($sql);
7007 while ($obj = $this->db->fetch_object($resql)) {
7008 if ($obj->fk_product_type == 1) {
7009 $this->nb[
"services"] = $obj->nb;
7011 $this->nb[
"products"] = $obj->nb;
7014 $this->db->free($resql);
7018 $this->error = $this->db->error();
7060 return $this->mandatory_period == 1;
7070 return $this->status_batch > 0;
7090 $dirsociete = array_merge(array(
'/core/modules/barcode/'),
$conf->modules_parts[
'barcode']);
7091 foreach ($dirsociete as $dirroot) {
7099 '@phan-var-force ModeleNumRefBarCode $mod';
7101 $result = $mod->getNextValue(
$object, $type);
7103 dol_syslog(get_class($this).
"::get_barcode barcode=".$result.
" module=".$var);
7120 $this->specimen = 1;
7122 $this->
ref =
'PRODUCT_SPEC';
7123 $this->label =
'PRODUCT SPECIMEN';
7124 $this->
description =
'This is description of this product specimen that was created the '.dol_print_date($now,
'dayhourlog').
'.';
7125 $this->specimen = 1;
7126 $this->country_id = 1;
7128 $this->status_buy = 1;
7130 $this->sell_or_eat_by_mandatory = 0;
7131 $this->note_private =
'This is a comment (private)';
7132 $this->note_public =
'This is a comment (public)';
7133 $this->date_creation = $now;
7134 $this->date_modification = $now;
7137 $this->weight_units = 3;
7140 $this->length_units = 1;
7142 $this->width_units = 0;
7143 $this->height =
null;
7144 $this->height_units =
null;
7146 $this->surface = 30;
7147 $this->surface_units = 0;
7148 $this->volume = 300;
7149 $this->volume_units = 0;
7151 $this->barcode = -1;
7169 if (empty($this->fk_unit)) {
7172 if (empty($outputlangs)) {
7173 $outputlangs = $langs;
7176 $outputlangs->load(
'products');
7179 $sql =
"SELECT code, label, short_label FROM ".$this->db->prefix().
"c_units where rowid = ".((int) $this->fk_unit);
7181 $resql = $this->db->query($sql);
7183 $this->error = $this->db->error();
7184 dol_syslog(get_class($this).
"::getLabelOfUnit Error ".$this->error, LOG_ERR);
7186 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
7187 if ($type ==
'short') {
7189 $label = $outputlangs->transnoentitiesnoconv($res[
'short_label']);
7191 $label = $outputlangs->trans($res[
'short_label']);
7193 } elseif ($type ==
'code') {
7194 $label = $res[
'code'];
7196 if ($outputlangs->trans(
'unit'.$res[
'code']) ==
'unit'.$res[
'code']) {
7198 $label = $res[
'label'];
7202 $label = $outputlangs->transnoentitiesnoconv(
'unit'.$res[
'code']);
7204 $label = $outputlangs->trans(
'unit'.$res[
'code']);
7209 $this->db->free($resql);
7223 $maxpricesupplier = 0;
7226 include_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.product.class.php';
7228 $product_fourn_list = $product_fourn->list_product_fournisseur_price($this->
id,
'',
'');
7230 if (is_array($product_fourn_list) && count($product_fourn_list) > 0) {
7231 foreach ($product_fourn_list as $productfourn) {
7232 if ($productfourn->fourn_unitprice > $maxpricesupplier) {
7233 $maxpricesupplier = $productfourn->fourn_unitprice;
7241 return $maxpricesupplier;
7257 require_once DOL_DOCUMENT_ROOT.
'/categories/class/categorie.class.php';
7258 return parent::setCategoriesCommon($categories, Categorie::TYPE_PRODUCT);
7272 $sql =
" DELETE FROM ".$dbs->prefix().
"product_customer_price";
7273 $sql .=
" WHERE fk_soc = ".(int) $origin_id;
7274 $sql .=
" AND fk_product IN (SELECT fk_product FROM (SELECT fk_product FROM ".$dbs->prefix().
"product_customer_price WHERE fk_soc = ".(int) $dest_id.
") AS tmp)";
7277 if (!$dbs->
query($sql)) {
7282 'product_customer_price',
7283 'product_customer_price_log'
7302 $sql =
"SELECT rowid, level, fk_level, var_percent, var_min_percent FROM ".$this->db->prefix().
"product_pricerules";
7303 $query = $this->db->query($sql);
7307 while ($result = $this->db->fetch_object($query)) {
7308 $rules[$result->level] = $result;
7317 for ($i = 1; $i <= $nbofproducts; $i++) {
7318 $price = $baseprice;
7319 $price_min = $baseprice;
7323 if ($i > 1 && isset($rules[$i]->var_percent) && $rules[$i]->var_percent) {
7324 $price = $prices[$rules[$i]->fk_level] * (1 + ($rules[$i]->var_percent / 100));
7327 $prices[$i] = $price;
7330 if (isset($rules[$i]->var_min_percent) && $rules[$i]->var_min_percent) {
7331 $price_min = $price * (1 - ($rules[$i]->var_min_percent / 100));
7335 $check_amount = (($price == $this->multiprices[$i]) && ($price_min == $this->multiprices_min[$i]));
7336 $check_type = ($baseprice == $this->multiprices_base_type[$i]);
7338 if ($check_amount && $check_type) {
7342 if ($this->
updatePrice($price, $price_type, $user, $price_vat, $price_min, $i, $npr, $psq, 1) < 0) {
7360 return $user->rights->produit;
7362 return $user->rights->service;
7374 $sql =
"SELECT p.rowid, p.ref, p.datec as date_creation, GREATEST(p.tms, pef.tms) as date_modification,";
7375 $sql .=
" p.fk_user_author, p.fk_user_modif";
7376 $sql .=
" FROM ".$this->db->prefix().$this->table_element.
" as p";
7377 $sql .=
" LEFT JOIN ".$this->db->prefix().$this->table_element.
"_extrafields as pef ON pef.fk_object=p.rowid";
7378 $sql .=
" WHERE p.rowid = ".((int) $id);
7380 $result = $this->db->query($sql);
7382 if ($this->db->num_rows($result)) {
7383 $obj = $this->db->fetch_object($result);
7385 $this->
id = $obj->rowid;
7386 $this->
ref = $obj->ref;
7388 $this->user_creation_id = $obj->fk_user_author;
7389 $this->user_modification_id = $obj->fk_user_modif;
7391 $this->date_creation = $this->db->jdate($obj->date_creation);
7392 $this->date_modification = $this->db->jdate($obj->date_modification);
7395 $this->db->free($result);
7409 if (empty($this->duration_value)) {
7410 $this->errors[] =
'ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
7413 if ($this->duration_unit ==
's') {
7414 $prodDurationHours = 1. / 3600;
7415 } elseif ($this->duration_unit ==
'i' || $this->duration_unit ==
'mn' || $this->duration_unit ==
'min') {
7416 $prodDurationHours = 1. / 60;
7417 } elseif ($this->duration_unit ==
'h') {
7418 $prodDurationHours = 1.;
7419 } elseif ($this->duration_unit ==
'd') {
7420 $prodDurationHours = 24.;
7421 } elseif ($this->duration_unit ==
'w') {
7422 $prodDurationHours = 24. * 7;
7423 } elseif ($this->duration_unit ==
'm') {
7424 $prodDurationHours = 24. * 30;
7425 } elseif ($this->duration_unit ==
'y') {
7426 $prodDurationHours = 24. * 365;
7428 $prodDurationHours = 0.0;
7430 $prodDurationHours *= $this->duration_value;
7432 return $prodDurationHours;
7445 global $langs,
$conf;
7447 $selected = (empty($arraydata[
'selected']) ? 0 : $arraydata[
'selected']);
7449 $return =
'<div class="box-flex-item box-flex-grow-zero">';
7450 $return .=
'<div class="info-box info-box-sm">';
7451 $return .=
'<div class="info-box-img">';
7453 if ($this->entity !==
null && $this->
is_photo_available($conf->product->multidir_output[$this->entity])) {
7454 $label .= $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 120, 160, 0, 0, 0,
'',
'photoref photokanban');
7464 $return .=
'</div>';
7465 $return .=
'<div class="info-box-content">';
7466 $return .=
'<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">' . $this->
getNomUrl() .
'</span>';
7467 if ($selected >= 0) {
7468 $return .=
'<input id="cb'.$this->id.
'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->
id.
'"'.($selected ?
' checked="checked"' :
'').
'>';
7470 $return .=
'<br><span class="info-box-label opacitymedium inline-block tdoverflowmax150 valignmiddle" title="'.dol_escape_htmltag($this->label).
'">'.
dol_escape_htmltag($this->label).
'</span>';
7471 if ($this->price_base_type ==
'TTC') {
7472 $return .=
'<br><span class="info-box-status amount">'.price($this->price_ttc).
' '.$langs->trans(
"TTC").
'</span>';
7475 $return .=
'<br><span class="info-box-status amount">'.price($this->
price).
' '.$langs->trans(
"HT").
'</span>';
7480 $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>';
7485 $return .=
'<div class="info-box-status inline-block valignmiddle">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7487 $return .=
'<div class="info-box-status inline-block valignmiddle marginleftonly paddingleft">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7489 $return .=
'</div>';
7490 $return .=
'</div>';
7491 $return .=
'</div>';
7502 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)
Loads supplier reception statistics table for given product or service.
get_nb_propal($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in proposals in which product is included.
update($id, $user, $notrigger=0, $action='update', $updatetype=false)
Update a record into database.
correct_stock_batch($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $dlc='', $dluo='', $lot='', $inventorycode='', $origin_element='', $origin_id=null, $disablestockchangeforsubproduct=0, $extrafields=null, $force_update_batch=false)
Adjust stock in a warehouse for product with batch number.
load_stats_bom($socid=0)
Charge tableau des stats OF pour le produit/service.
hasbatch()
Return if the object has a batch management.
del_sousproduit($fk_parent, $fk_child, $notrigger=0)
Remove a link between a subproduct and a parent product/service.
fetch($id=0, $ref='', $ref_ext='', $barcode='', $ignore_expression=0, $ignore_price_load=0, $ignore_lang_load=0)
Load a product in memory from database.
update_sousproduit($id_pere, $id_fils, $qty, $incdec=1, $notrigger=0)
Modify composed product.
load_stats_commande($socid=0, $filtrestatut='', $forVirtualStock=0)
Charge tableau des stats commande client pour le produit/service.
delete_photo($file)
Delete a photo and its thumbs.
fetch_prod_arbo($prod, $compl_path='', $multiply=1, $level=1, $id_parent=0, $ignore_stock_load=0)
Function recursive, used only by get_arbo_each_prod(), to build tree of subproducts into ->res Define...
getKanbanView($option='', $arraydata=null)
Return clickable link of object (with eventually picto)
getLibStatut($mode=0, $type=0)
Return label of status of object.
load_stats_sending($socid=0, $filtrestatut='', $forVirtualStock=0, $filterShipmentStatus='')
Charge tableau des stats expedition client pour le produit/service.
clone_price($fromId, $toId)
Recopie les prix d'un produit/service sur un autre.
load_stats_inproduction($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null, $warehouseid=0)
Charge tableau des stats production pour le produit/service.
delMultiLangs($langtodelete, $user, $notrigger=0)
Delete a language for this product.
check()
Check that ref and label are ok.
initAsSpecimen()
Initialise an instance with random values.
liste_photos($dir, $nbmax=0)
Return an array with all photos of product found on disk.
loadStateBoard()
Load indicators this->nb for the dashboard.
getFather()
Return all parent products for current product (first level only)
getNomUrl($withpicto=0, $option='', $maxlength=0, $save_lastsearch_value=-1, $notooltip=0, $morecss='', $add_label=0, $sep=' - ')
Return clickable link of object (with eventually picto)
getSellOrEatByMandatoryLabel()
Get the label for sell by or eat by mandatory flag of the current product.
verify()
Check properties of product are ok (like name, barcode, ...).
get_nb_order($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
loadStockForVirtualProduct($option='', $qtyWish=1)
Load stock for components of virtual product (first level only)
min_recommended_price()
Return minimum product recommended price.
_log_price($user, $level=0)
Insert a track that we changed a customer price.
getLabelOfUnit($type='long', $outputlangs=null, $noentities=0)
Reads the units dictionary to return the translation code of a unit (if type='code'),...
_get_stats($sql, $mode, $year=0)
Return an array formatted for showing graphs.
load_stats_commande_fournisseur($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null)
Charge tableau des stats commande fournisseur pour le produit/service.
isMandatoryPeriod()
Return if the object has a constraint on mandatory_period.
isProduct()
Return if the object is a product.
generateMultiprices(User $user, $baseprice, $price_type, $price_vat, $npr, $psq)
Generates prices for a product based on product multiprice generation rules.
LibStatut($status, $mode=0, $type=0)
Return label of a given status.
const TYPE_SERVICE
Service.
is_photo_available($sdir)
Return if at least one photo is available.
get_image_size($file)
Load size of image file.
get_nb_vente($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units or customers invoices in which product is included.
getTooltipContentArray($params)
getTooltipContentArray
Class to manage products or services.
Manage record for batch number management.
static findAll($dbs, $fk_product_stock, $with_qty=0, $fk_product=0)
Return all batch detail records for a given product and warehouse.
Class with list of lots and properties.
Class to manage Dolibarr users.
hasRight($module, $permlevel1, $permlevel2='')
Return if a user has a permission.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0, $level=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
dol_is_file($pathoffile)
Return if path is a file.
dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $nohook=0, $keyforsourcefile='addedfile', $upload_dir='', $mode=0)
Check validity of a file upload from an GUI page, and move it to its final destination.
dol_now($mode='gmt')
Return date for now.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
dolGetFirstLineOfText($text, $nboflines=1, $charset='UTF-8')
Return first line of text.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='', $keepspaces=0)
Clean a string from all punctuation characters to use it as a ref or login.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
yn($yesno, $format=1, $color=0)
Return yes or no in current language.
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
dol_clone($srcobject, $native=2)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '...' if string larger than length.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
utf8_check($str)
Check if a string is in UTF8.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_localtax($vatrate, $local, $thirdparty_buyer=null, $thirdparty_seller=null, $vatnpr=0)
Return localtax rate for a particular VAT rate, when selling a product with vat $vatrate,...
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
query($query, $usesavepoint=0, $type='auto', $result_mode=0)
Execute a SQL request and return the resultset.
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
buildzip.php
measuring_units_squared($unitscale)
Transform a given unit scale into the square of that unit, if known.
measuringUnitString($unitid, $measuring_style='', $unitscale=null, $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
measuring_units_cubed($unit)
Transform a given unit scale into the cube of that unit, if known.
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...