40require_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
41require_once DOL_DOCUMENT_ROOT.
'/core/class/commonobject.class.php';
42require_once DOL_DOCUMENT_ROOT.
'/product/class/productbatch.class.php';
43require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/productlot.class.php';
44require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/entrepot.class.php';
55 const SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY = 1;
56 const SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY = 2;
57 const SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT = 3;
62 public $element =
'product';
67 public $table_element =
'product';
72 public $fk_element =
'fk_product';
82 protected $childtables = array(
83 'supplier_proposaldet' => array(
'name' =>
'SupplierProposal',
'parent' =>
'supplier_proposal',
'parentkey' =>
'fk_supplier_proposal'),
84 'propaldet' => array(
'name' =>
'Proposal',
'parent' =>
'propal',
'parentkey' =>
'fk_propal'),
85 'commandedet' => array(
'name' =>
'Order',
'parent' =>
'commande',
'parentkey' =>
'fk_commande'),
86 'facturedet' => array(
'name' =>
'Invoice',
'parent' =>
'facture',
'parentkey' =>
'fk_facture'),
87 'contratdet' => array(
'name' =>
'Contract',
'parent' =>
'contrat',
'parentkey' =>
'fk_contrat'),
88 'facture_fourn_det' => array(
'name' =>
'SupplierInvoice',
'parent' =>
'facture_fourn',
'parentkey' =>
'fk_facture_fourn'),
89 'commande_fournisseurdet' => array(
'name' =>
'SupplierOrder',
'parent' =>
'commande_fournisseur',
'parentkey' =>
'fk_commande'),
90 'mrp_production' => array(
'name' =>
'Mo',
'parent' =>
'mrp_mo',
'parentkey' =>
'fk_mo' ),
91 'bom_bom' => array(
'name' =>
'BOM'),
92 'bom_bomline' => array(
'name' =>
'BOMLine',
'parent' =>
'bom_bom',
'parentkey' =>
'fk_bom'),
100 public $picto =
'product';
111 public $regeximgext =
'\.gif|\.jpg|\.jpeg|\.png|\.bmp|\.webp|\.xpm|\.xbm';
158 public $price_formated;
170 public $price_ttc_formated;
184 public $price_min_ttc;
190 public $price_base_type;
200 public $multiprices = array();
204 public $multiprices_ttc = array();
208 public $multiprices_base_type = array();
212 public $multiprices_default_vat_code = array();
216 public $multiprices_min = array();
220 public $multiprices_min_ttc = array();
224 public $multiprices_tva_tx = array();
228 public $multiprices_recuperableonly = array();
237 public $price_by_qty;
241 public $prices_by_qty = array();
245 public $prices_by_qty_id = array();
249 public $prices_by_qty_list = array();
259 public $multilangs = array();
264 public $default_vat_code;
279 public $remise_percent;
284 public $localtax1_tx;
288 public $localtax2_tx;
292 public $localtax1_type;
296 public $localtax2_type;
303 public $desc_supplier;
307 public $vatrate_supplier;
311 public $default_vat_code_supplier;
316 public $fourn_multicurrency_price;
320 public $fourn_multicurrency_unitprice;
324 public $fourn_multicurrency_tx;
328 public $fourn_multicurrency_id;
332 public $fourn_multicurrency_code;
354 public $qc_frequency;
361 public $stock_reel = 0;
368 public $stock_theorique;
387 public $seuil_stock_alerte = 0;
392 public $desiredstock = 0;
397 public $duration_value;
401 public $duration_unit;
410 public $fk_default_workstation;
432 public $status_buy = 0;
454 public $fk_default_bom;
461 public $product_fourn_price_id;
483 public $status_batch = 0;
490 public $sell_or_eat_by_mandatory = 0;
497 public $batch_mask =
'';
522 public $weight_units;
530 public $length_units;
546 public $height_units;
554 public $surface_units;
562 public $volume_units;
571 public $net_measure_units;
576 public $accountancy_code_sell;
580 public $accountancy_code_sell_intra;
584 public $accountancy_code_sell_export;
588 public $accountancy_code_buy;
592 public $accountancy_code_buy_intra;
596 public $accountancy_code_buy_export;
606 public $barcode_type;
611 public $barcode_type_code;
613 public $stats_propale = array();
614 public $stats_commande = array();
615 public $stats_contrat = array();
616 public $stats_facture = array();
617 public $stats_proposal_supplier = array();
618 public $stats_commande_fournisseur = array();
619 public $stats_expedition = array();
620 public $stats_reception = array();
621 public $stats_mo = array();
622 public $stats_bom = array();
623 public $stats_mrptoconsume = array();
624 public $stats_mrptoproduce = array();
625 public $stats_facturerec = array();
626 public $stats_facture_fournisseur = array();
641 public $product_fourn_id;
647 public $product_id_already_linked;
661 public $fk_default_warehouse;
666 public $fk_price_expression;
684 public $fourn_price_base_type;
701 public $ref_supplier;
715 public $price_autogen = 0;
722 public $supplierprices;
742 public $is_object_used;
753 public $is_sousproduit_qty;
765 public $is_sousproduit_incdec;
770 public $mandatory_period;
801 public $fields = array(
802 'rowid' => array(
'type' =>
'integer',
'label' =>
'TechnicalID',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'index' => 1,
'position' => 1,
'comment' =>
'Id'),
803 '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'),
804 'entity' => array(
'type' =>
'integer',
'label' =>
'Entity',
'enabled' => 1,
'visible' => 0,
'default' =>
'1',
'notnull' => 1,
'index' => 1,
'position' => 5),
805 'label' => array(
'type' =>
'varchar(255)',
'label' =>
'Label',
'enabled' => 1,
'visible' => 1,
'notnull' => 1,
'showoncombobox' => 2,
'position' => 15,
'csslist' =>
'tdoverflowmax250'),
806 'barcode' => array(
'type' =>
'varchar(255)',
'label' =>
'Barcode',
'enabled' =>
'isModEnabled("barcode")',
'position' => 20,
'visible' => -1,
'showoncombobox' => 3,
'cssview' =>
'tdwordbreak',
'csslist' =>
'tdoverflowmax125'),
807 'fk_barcode_type' => array(
'type' =>
'integer',
'label' =>
'BarcodeType',
'enabled' => 1,
'position' => 21,
'notnull' => 0,
'visible' => -1,),
808 'note_public' => array(
'type' =>
'html',
'label' =>
'NotePublic',
'enabled' => 1,
'visible' => 0,
'position' => 61),
809 'note' => array(
'type' =>
'html',
'label' =>
'NotePrivate',
'enabled' => 1,
'visible' => 0,
'position' => 62),
810 'datec' => array(
'type' =>
'datetime',
'label' =>
'DateCreation',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 500),
811 'tms' => array(
'type' =>
'timestamp',
'label' =>
'DateModification',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 501),
813 'fk_user_author' => array(
'type' =>
'integer',
'label' =>
'UserAuthor',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 510,
'foreignkey' =>
'llx_user.rowid'),
814 'fk_user_modif' => array(
'type' =>
'integer',
'label' =>
'UserModif',
'enabled' => 1,
'visible' => -2,
'notnull' => -1,
'position' => 511),
816 'localtax1_tx' => array(
'type' =>
'double(6,3)',
'label' =>
'Localtax1tx',
'enabled' => 1,
'position' => 150,
'notnull' => 0,
'visible' => -1,),
817 'localtax1_type' => array(
'type' =>
'varchar(10)',
'label' =>
'Localtax1type',
'enabled' => 1,
'position' => 155,
'notnull' => 1,
'visible' => -1,),
818 'localtax2_tx' => array(
'type' =>
'double(6,3)',
'label' =>
'Localtax2tx',
'enabled' => 1,
'position' => 160,
'notnull' => 0,
'visible' => -1,),
819 'localtax2_type' => array(
'type' =>
'varchar(10)',
'label' =>
'Localtax2type',
'enabled' => 1,
'position' => 165,
'notnull' => 1,
'visible' => -1,),
820 'last_main_doc' => array(
'type' =>
'varchar(255)',
'label' =>
'LastMainDoc',
'enabled' => 1,
'visible' => -1,
'position' => 170),
821 'import_key' => array(
'type' =>
'varchar(14)',
'label' =>
'ImportId',
'enabled' => 1,
'visible' => -2,
'notnull' => -1,
'index' => 0,
'position' => 1000),
824 'mandatory_period' => array(
'type' =>
'integer',
'label' =>
'mandatoryperiod',
'enabled' => 1,
'visible' => 1,
'notnull' => 1,
'default' =>
'0',
'index' => 1,
'position' => 1000),
845 $this->ismultientitymanaged = 1;
846 $this->isextrafieldmanaged = 1;
859 $this->
ref = trim($this->
ref);
887 public function create($user, $notrigger = 0)
889 global $conf, $langs;
895 $this->
ref = trim($this->
ref);
899 $this->label = trim($this->label);
900 $this->price_ttc = (float)
price2num($this->price_ttc);
902 $this->price_min_ttc = (float)
price2num($this->price_min_ttc);
903 $this->price_min = (float)
price2num($this->price_min);
904 $this->price_label = trim($this->price_label);
905 if (empty($this->tva_tx)) {
908 if (empty($this->tva_npr)) {
912 if (empty($this->localtax1_tx)) {
913 $this->localtax1_tx = 0;
915 if (empty($this->localtax2_tx)) {
916 $this->localtax2_tx = 0;
918 if (empty($this->localtax1_type)) {
919 $this->localtax1_type =
'0';
921 if (empty($this->localtax2_type)) {
922 $this->localtax2_type =
'0';
924 if (empty($this->
price)) {
927 if (empty($this->price_min)) {
928 $this->price_min = 0;
931 if (empty($this->price_by_qty)) {
932 $this->price_by_qty = 0;
935 if (empty($this->
status)) {
938 if (empty($this->status_buy)) {
939 $this->status_buy = 0;
948 if ($this->price_base_type ==
'TTC' && $this->price_ttc > 0) {
949 $price_ttc =
price2num($this->price_ttc,
'MU');
950 $price_ht =
price2num($this->price_ttc / (1 + ($this->tva_tx / 100)),
'MU');
954 if ($this->price_base_type !=
'TTC' && $this->
price > 0) {
956 $price_ttc =
price2num($this->
price * (1 + ($this->tva_tx / 100)),
'MU');
960 if (($this->price_min_ttc > 0) && ($this->price_base_type ==
'TTC')) {
961 $price_min_ttc =
price2num($this->price_min_ttc,
'MU');
962 $price_min_ht =
price2num($this->price_min_ttc / (1 + ($this->tva_tx / 100)),
'MU');
966 if (($this->price_min > 0) && ($this->price_base_type !=
'TTC')) {
967 $price_min_ht =
price2num($this->price_min,
'MU');
968 $price_min_ttc =
price2num($this->price_min * (1 + ($this->tva_tx / 100)),
'MU');
971 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
972 $this->accountancy_code_buy_intra = trim($this->accountancy_code_buy_intra);
973 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
974 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
975 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
976 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
979 $this->barcode = trim($this->barcode);
980 $this->mandatory_period = empty($this->mandatory_period) ? 0 : $this->mandatory_period;
982 if (empty($this->label)) {
983 $this->error =
'ErrorMandatoryParametersNotProvided';
987 if (empty($this->
ref) || $this->
ref ==
'auto') {
990 if ($module !=
'mod_codeproduct_leopard') {
991 if (substr($module, 0, 16) ==
'mod_codeproduct_' && substr($module, -3) ==
'php') {
992 $module = substr($module, 0,
dol_strlen($module) - 4);
995 $modCodeProduct =
new $module();
996 '@phan-var-force ModeleProductCode $modCodeProduct';
997 if (!empty($modCodeProduct->code_auto)) {
998 $this->
ref = $modCodeProduct->getNextValue($this, $this->
type);
1000 unset($modCodeProduct);
1003 if (empty($this->
ref)) {
1004 $this->error =
'ProductModuleNotSetupForAutoRef';
1009 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);
1013 if (empty($this->date_creation)) {
1014 $this->date_creation = $now;
1020 if ($this->barcode ==
'-1' || $this->barcode ==
'auto') {
1021 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1026 $result = $this->
verify();
1029 $sql =
"SELECT count(*) as nb";
1030 $sql .=
" FROM ".$this->db->prefix().
"product";
1031 $sql .=
" WHERE entity IN (".getEntity(
'product').
")";
1032 $sql .=
" AND ref = '".$this->db->escape($this->
ref).
"'";
1034 $result = $this->db->query($sql);
1036 $obj = $this->db->fetch_object($result);
1037 if ($obj->nb == 0) {
1039 $sql =
"INSERT INTO ".$this->db->prefix().
"product (";
1043 $sql .=
", ref_ext";
1044 $sql .=
", price_min";
1045 $sql .=
", price_min_ttc";
1047 $sql .=
", fk_user_author";
1048 $sql .=
", fk_product_type";
1050 $sql .=
", price_ttc";
1051 $sql .=
", price_base_type";
1052 $sql .=
", price_label";
1056 $sql .=
", accountancy_code_buy";
1057 $sql .=
", accountancy_code_buy_intra";
1058 $sql .=
", accountancy_code_buy_export";
1059 $sql .=
", accountancy_code_sell";
1060 $sql .=
", accountancy_code_sell_intra";
1061 $sql .=
", accountancy_code_sell_export";
1064 $sql .=
", finished";
1065 $sql .=
", tobatch";
1066 $sql .=
", sell_or_eat_by_mandatory";
1067 $sql .=
", batch_mask";
1068 $sql .=
", fk_unit";
1069 $sql .=
", mandatory_period";
1070 $sql .=
") VALUES (";
1071 $sql .=
"'".$this->db->idate($this->date_creation).
"'";
1072 $sql .=
", ".(!empty($this->entity) ? (int) $this->entity : (int) $conf->entity);
1073 $sql .=
", '".$this->db->escape($this->
ref).
"'";
1074 $sql .=
", ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1075 $sql .=
", ".price2num($price_min_ht);
1076 $sql .=
", ".price2num($price_min_ttc);
1077 $sql .=
", ".(!empty($this->label) ?
"'".$this->db->escape($this->label).
"'" :
"null");
1078 $sql .=
", ".((int) $user->id);
1079 $sql .=
", ".((int) $this->
type);
1080 $sql .=
", ".price2num($price_ht,
'MT');
1081 $sql .=
", ".price2num($price_ttc,
'MT');
1082 $sql .=
", '".$this->db->escape($this->price_base_type).
"'";
1083 $sql .=
", ".(!empty($this->price_label) ?
"'".$this->db->escape($this->price_label).
"'" :
"null");
1084 $sql .=
", ".((int) $this->
status);
1085 $sql .=
", ".((int) $this->status_buy);
1087 $sql .=
", '".$this->db->escape($this->accountancy_code_buy).
"'";
1088 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_intra).
"'";
1089 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_export).
"'";
1090 $sql .=
", '".$this->db->escape($this->accountancy_code_sell).
"'";
1091 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_intra).
"'";
1092 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_export).
"'";
1094 $sql .=
", '".$this->db->escape($this->canvas).
"'";
1095 $sql .=
", ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
'NULL' : (int) $this->finished);
1096 $sql .=
", ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : ((int) $this->status_batch));
1097 $sql .=
", ".((empty($this->sell_or_eat_by_mandatory) || $this->sell_or_eat_by_mandatory < 0) ? 0 : ((int) $this->sell_or_eat_by_mandatory));
1098 $sql .=
", '".$this->db->escape($this->batch_mask).
"'";
1099 $sql .=
", ".($this->fk_unit > 0 ? ((int) $this->fk_unit) :
'NULL');
1100 $sql .=
", '".$this->db->escape($this->mandatory_period).
"'";
1103 dol_syslog(get_class($this).
"::Create", LOG_DEBUG);
1105 $result = $this->db->query($sql);
1107 $id = $this->db->last_insert_id($this->db->prefix().
"product");
1111 $this->
price = $price_ht;
1112 $this->price_ttc = $price_ttc;
1113 $this->price_min = $price_min_ht;
1114 $this->price_min_ttc = $price_min_ttc;
1118 if ($this->
update($id, $user, 1,
'add') <= 0) {
1123 $this->error = $this->db->lasterror();
1128 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " .((int) $this->id) .
" AND entity = " . ((
int) $conf->entity));
1130 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1131 $sql .=
" fk_product";
1133 $sql .=
", accountancy_code_buy";
1134 $sql .=
", accountancy_code_buy_intra";
1135 $sql .=
", accountancy_code_buy_export";
1136 $sql .=
", accountancy_code_sell";
1137 $sql .=
", accountancy_code_sell_intra";
1138 $sql .=
", accountancy_code_sell_export";
1139 $sql .=
") VALUES (";
1141 $sql .=
", " . ((int) $conf->entity);
1142 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1143 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1144 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1145 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1146 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1147 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1149 $result = $this->db->query($sql);
1152 $this->error =
'ErrorFailedToInsertAccountancyForEntity';
1157 $this->error =
'ErrorFailedToGetInsertedId';
1161 $this->error = $this->db->lasterror();
1165 $langs->load(
"products");
1167 $this->error =
"ErrorProductAlreadyExists";
1168 dol_syslog(get_class($this).
"::Create fails, ref ".$this->
ref.
" already exists");
1172 $this->error = $this->db->lasterror();
1175 if (!$error && !$notrigger) {
1177 $result = $this->
call_trigger(
'PRODUCT_CREATE', $user);
1185 $this->db->commit();
1188 $this->db->rollback();
1192 $this->db->rollback();
1193 dol_syslog(get_class($this).
"::Create fails verify ".implode(
',', $this->errors), LOG_WARNING);
1209 $this->errors = array();
1212 $this->
ref = trim($this->
ref);
1215 $this->errors[] =
'ErrorBadRef';
1219 $arrayofnonnegativevalue = array(
'weight' =>
'Weight',
'width' =>
'Width',
'height' =>
'Height',
'length' =>
'Length',
'surface' =>
'Surface',
'volume' =>
'Volume');
1220 foreach ($arrayofnonnegativevalue as $key => $value) {
1221 if (property_exists($this, $key) && !empty($this->$key) && ($this->$key < 0)) {
1222 $langs->loadLangs(array(
"main",
"other"));
1223 $this->error = $langs->trans(
"FieldCannotBeNegative", $langs->transnoentitiesnoconv($value));
1224 $this->errors[] = $this->error;
1229 $rescode = $this->
check_barcode($this->barcode, $this->barcode_type_code);
1231 if ($rescode == -1) {
1232 $this->errors[] =
'ErrorBadBarCodeSyntax';
1233 } elseif ($rescode == -2) {
1234 $this->errors[] =
'ErrorBarCodeRequired';
1235 } elseif ($rescode == -3) {
1237 $this->errors[] =
'ErrorBarCodeAlreadyUsed';
1265 $dirsociete = array_merge(array(
'/core/modules/barcode/'), $conf->modules_parts[
'barcode']);
1266 foreach ($dirsociete as $dirroot) {
1273 $mod =
new $module();
1274 '@phan-var-force ModeleNumRefBarCode $mod';
1276 dol_syslog(get_class($this).
"::check_barcode value=".$valuetotest.
" type=".$typefortest.
" module=".$module);
1277 $result = $mod->verif($this->db, $valuetotest, $this, 0, $typefortest);
1295 public function update($id, $user, $notrigger = 0, $action =
'update', $updatetype =
false)
1297 global $langs, $conf, $hookmanager;
1302 if (!$this->label) {
1303 $this->label =
'MISSING LABEL';
1308 $this->
ref = trim($this->
ref);
1312 $this->label = trim($this->label);
1314 $this->note_private = (isset($this->note_private) ? trim($this->note_private) :
null);
1315 $this->note_public = (isset($this->note_public) ? trim($this->note_public) :
null);
1316 $this->net_measure =
price2num($this->net_measure);
1317 $this->net_measure_units = (empty($this->net_measure_units) ?
'' : trim((
string) $this->net_measure_units));
1318 $this->weight =
price2num($this->weight);
1319 $this->weight_units = (empty($this->weight_units) ?
'' : trim((
string) $this->weight_units));
1320 $this->length =
price2num($this->length);
1321 $this->length_units = (empty($this->length_units) ?
'' : trim((
string) $this->length_units));
1323 $this->width_units = (empty($this->width_units) ?
'' : trim((
string) $this->width_units));
1324 $this->height =
price2num($this->height);
1325 $this->height_units = (empty($this->height_units) ?
'' : trim((
string) $this->height_units));
1326 $this->surface =
price2num($this->surface);
1327 $this->surface_units = (empty($this->surface_units) ?
'' : trim((
string) $this->surface_units));
1328 $this->volume =
price2num($this->volume);
1329 $this->volume_units = (empty($this->volume_units) ?
'' : trim((
string) $this->volume_units));
1332 if (is_numeric($this->length_units)) {
1333 $this->width_units = $this->length_units;
1335 if (is_numeric($this->length_units)) {
1336 $this->height_units = $this->length_units;
1340 if (empty($this->surface) && !empty($this->length) && !empty($this->width) && $this->length_units == $this->width_units) {
1341 $this->surface = (float) $this->length * (
float) $this->width;
1344 if (empty($this->volume) && !empty($this->surface) && !empty($this->height) && $this->length_units == $this->height_units) {
1345 $this->volume = $this->surface * (float) $this->height;
1349 if (empty($this->tva_tx)) {
1352 if (empty($this->tva_npr)) {
1355 if (empty($this->localtax1_tx)) {
1356 $this->localtax1_tx = 0;
1358 if (empty($this->localtax2_tx)) {
1359 $this->localtax2_tx = 0;
1361 if (empty($this->localtax1_type)) {
1362 $this->localtax1_type =
'0';
1364 if (empty($this->localtax2_type)) {
1365 $this->localtax2_type =
'0';
1367 if (empty($this->
status)) {
1370 if (empty($this->status_buy)) {
1371 $this->status_buy = 0;
1374 if (empty($this->country_id)) {
1375 $this->country_id = 0;
1378 if (empty($this->state_id)) {
1379 $this->state_id = 0;
1383 $this->barcode = (empty($this->barcode) ?
'' : trim($this->barcode));
1385 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
1386 $this->accountancy_code_buy_intra = (!empty($this->accountancy_code_buy_intra) ? trim($this->accountancy_code_buy_intra) :
'');
1387 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
1388 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
1389 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
1390 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
1397 if ($action !=
'add') {
1398 $result = $this->
verify();
1406 if (is_null($this->oldcopy) || (is_object($this->oldcopy) && $this->oldcopy->isEmpty())) {
1411 if ($this->
hasbatch() && !$this->oldcopy->hasbatch()) {
1413 $valueforundefinedlot =
'000000';
1418 dol_syslog(
"Flag batch of product id=".$this->
id.
" is set to ON, so we will create missing records into product_batch");
1421 foreach ($this->stock_warehouse as $idW => $ObjW) {
1423 foreach ($ObjW->detail_batch as $detail) {
1424 if ($detail->batch == $valueforundefinedlot || $detail->batch ==
'Undefined') {
1426 $sqlclean =
"DELETE FROM ".$this->db->prefix().
"product_batch WHERE batch in('Undefined', '".$this->db->escape($valueforundefinedlot).
"') AND fk_product_stock = ".((int) $ObjW->id);
1427 $result = $this->db->query($sqlclean);
1435 $qty_batch += $detail->qty;
1439 if ($ObjW->real != $qty_batch) {
1441 $ObjBatch->batch = $valueforundefinedlot;
1442 $ObjBatch->qty = ($ObjW->real - $qty_batch);
1443 $ObjBatch->fk_product_stock = $ObjW->id;
1445 if ($ObjBatch->create($user, 1) < 0) {
1447 $this->errors = $ObjBatch->errors;
1452 if ($ObjLot->fetch(0, $this->id, $valueforundefinedlot) == 0) {
1453 $ObjLot->fk_product = $this->id;
1454 $ObjLot->entity = $this->entity;
1455 $ObjLot->fk_user_creat = $user->id;
1456 $ObjLot->batch = $valueforundefinedlot;
1457 if ($ObjLot->create($user,
true) < 0) {
1459 $this->errors = $ObjLot->errors;
1468 if ($this->barcode == -1) {
1469 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1472 $sql =
"UPDATE ".$this->db->prefix().
"product";
1473 $sql .=
" SET label = '".$this->db->escape($this->label).
"'";
1476 $sql .=
", fk_product_type = ".((int) $this->
type);
1479 $sql .=
", ref = '".$this->db->escape($this->
ref).
"'";
1480 $sql .=
", ref_ext = ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1481 $sql .=
", default_vat_code = ".($this->default_vat_code ?
"'".$this->db->escape($this->default_vat_code).
"'" :
"null");
1482 $sql .=
", tva_tx = ".((float) $this->tva_tx);
1483 $sql .=
", recuperableonly = ".((int) $this->tva_npr);
1484 $sql .=
", localtax1_tx = ".((float) $this->localtax1_tx);
1485 $sql .=
", localtax2_tx = ".((float) $this->localtax2_tx);
1486 $sql .=
", localtax1_type = ".($this->localtax1_type !=
'' ?
"'".$this->db->escape($this->localtax1_type).
"'" :
"'0'");
1487 $sql .=
", localtax2_type = ".($this->localtax2_type !=
'' ?
"'".$this->db->escape($this->localtax2_type).
"'" :
"'0'");
1489 $sql .=
", barcode = ".(empty($this->barcode) ?
"null" :
"'".$this->db->escape($this->barcode).
"'");
1490 $sql .=
", fk_barcode_type = ".(empty($this->barcode_type) ?
"null" : $this->db->escape($this->barcode_type));
1492 $sql .=
", tosell = ".(int) $this->
status;
1493 $sql .=
", tobuy = ".(int) $this->status_buy;
1494 $sql .=
", tobatch = ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : (int) $this->status_batch);
1495 $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);
1496 $sql .=
", batch_mask = '".$this->db->escape($this->batch_mask).
"'";
1498 $sql .=
", finished = ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
"null" : (int) $this->finished);
1499 $sql .=
", fk_default_bom = ".((!isset($this->fk_default_bom) || $this->fk_default_bom < 0 || $this->fk_default_bom ==
'') ?
"null" : (int) $this->fk_default_bom);
1500 $sql .=
", net_measure = ".($this->net_measure !=
'' ?
"'".$this->db->escape($this->net_measure).
"'" :
'null');
1501 $sql .=
", net_measure_units = ".($this->net_measure_units !=
'' ?
"'".$this->db->escape($this->net_measure_units).
"'" :
'null');
1502 $sql .=
", weight = ".($this->weight !=
'' ?
"'".$this->db->escape($this->weight).
"'" :
'null');
1503 $sql .=
", weight_units = ".($this->weight_units !=
'' ?
"'".$this->db->escape($this->weight_units).
"'" :
'null');
1504 $sql .=
", length = ".($this->length !=
'' ?
"'".$this->db->escape($this->length).
"'" :
'null');
1505 $sql .=
", length_units = ".($this->length_units !=
'' ?
"'".$this->db->escape($this->length_units).
"'" :
'null');
1506 $sql .=
", width= ".($this->width !=
'' ?
"'".$this->db->escape($this->width).
"'" :
'null');
1507 $sql .=
", width_units = ".($this->width_units !=
'' ?
"'".$this->db->escape($this->width_units).
"'" :
'null');
1508 $sql .=
", height = ".($this->height !=
'' ?
"'".$this->db->escape($this->height).
"'" :
'null');
1509 $sql .=
", height_units = ".($this->height_units !=
'' ?
"'".$this->db->escape($this->height_units).
"'" :
'null');
1510 $sql .=
", surface = ".($this->surface !=
'' ?
"'".$this->db->escape($this->surface).
"'" :
'null');
1511 $sql .=
", surface_units = ".($this->surface_units !=
'' ?
"'".$this->db->escape($this->surface_units).
"'" :
'null');
1512 $sql .=
", volume = ".($this->volume !=
'' ?
"'".$this->db->escape($this->volume).
"'" :
'null');
1513 $sql .=
", volume_units = ".($this->volume_units !=
'' ?
"'".$this->db->escape($this->volume_units).
"'" :
'null');
1514 $sql .=
", fk_default_warehouse = ".($this->fk_default_warehouse > 0 ? ((int) $this->fk_default_warehouse) :
'null');
1515 $sql .=
", fk_default_workstation = ".($this->fk_default_workstation > 0 ? ((int) $this->fk_default_workstation) :
'null');
1516 $sql .=
", seuil_stock_alerte = ".((isset($this->seuil_stock_alerte) && is_numeric($this->seuil_stock_alerte)) ? (
float) $this->seuil_stock_alerte :
'null');
1517 $sql .=
", description = '".$this->db->escape($this->
description).
"'";
1518 $sql .=
", url = ".($this->url ?
"'".$this->db->escape($this->url).
"'" :
'null');
1519 $sql .=
", customcode = '".$this->db->escape($this->customcode).
"'";
1520 $sql .=
", fk_country = ".($this->country_id > 0 ? (int) $this->country_id :
'null');
1521 $sql .=
", fk_state = ".($this->state_id > 0 ? (int) $this->state_id :
'null');
1522 $sql .=
", lifetime = ".($this->lifetime > 0 ? (int) $this->lifetime :
'null');
1523 $sql .=
", qc_frequency = ".($this->qc_frequency > 0 ? (int) $this->qc_frequency :
'null');
1524 $sql .=
", note = ".(isset($this->note_private) ?
"'".$this->db->escape($this->note_private).
"'" :
'null');
1525 $sql .=
", note_public = ".(isset($this->note_public) ?
"'".$this->db->escape($this->note_public).
"'" :
'null');
1526 $sql .=
", duration = '".$this->db->escape($this->duration_value.$this->duration_unit).
"'";
1528 $sql .=
", accountancy_code_buy = '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1529 $sql .=
", accountancy_code_buy_intra = '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1530 $sql .=
", accountancy_code_buy_export = '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1531 $sql .=
", accountancy_code_sell= '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1532 $sql .=
", accountancy_code_sell_intra= '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1533 $sql .=
", accountancy_code_sell_export= '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1535 $sql .=
", desiredstock = ".((isset($this->desiredstock) && is_numeric($this->desiredstock)) ? (
float) $this->desiredstock :
"null");
1536 $sql .=
", cost_price = ".($this->cost_price !=
'' ? $this->db->escape($this->cost_price) :
'null');
1537 $sql .=
", fk_unit= ".(!$this->fk_unit ?
'NULL' : (int) $this->fk_unit);
1538 $sql .=
", price_autogen = ".(!$this->price_autogen ? 0 : 1);
1539 $sql .=
", fk_price_expression = ".($this->fk_price_expression != 0 ? (int) $this->fk_price_expression :
'NULL');
1540 $sql .=
", fk_user_modif = ".($user->id > 0 ? $user->id :
'NULL');
1541 $sql .=
", mandatory_period = ".($this->mandatory_period);
1543 $sql .=
" WHERE rowid = ".((int) $id);
1545 dol_syslog(get_class($this).
"::update", LOG_DEBUG);
1547 $resql = $this->db->query($sql);
1554 $this->db->rollback();
1563 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " . ((
int) $this->id) .
" AND entity = " . ((
int) $conf->entity));
1565 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1566 $sql .=
" fk_product";
1568 $sql .=
", accountancy_code_buy";
1569 $sql .=
", accountancy_code_buy_intra";
1570 $sql .=
", accountancy_code_buy_export";
1571 $sql .=
", accountancy_code_sell";
1572 $sql .=
", accountancy_code_sell_intra";
1573 $sql .=
", accountancy_code_sell_export";
1574 $sql .=
") VALUES (";
1575 $sql .= ((int) $this->
id);
1576 $sql .=
", " . ((int) $conf->entity);
1577 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1578 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1579 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1580 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1581 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1582 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1584 $result = $this->db->query($sql);
1587 $this->error =
'ErrorFailedToUpdateAccountancyForEntity';
1591 if (!$this->
hasbatch() && $this->oldcopy->hasbatch()) {
1593 $sql =
'SELECT pb.qty, ps.fk_entrepot, pb.batch FROM '.MAIN_DB_PREFIX.
'product_batch as pb';
1594 $sql .=
' INNER JOIN '.MAIN_DB_PREFIX.
'product_stock as ps ON (ps.rowid = pb.fk_product_stock)';
1595 $sql .=
' WHERE ps.fk_product = '.(int) $this->
id;
1597 $resql = $this->db->query($sql);
1601 while ($obj = $this->db->fetch_object($resql)) {
1603 $fk_entrepot = $obj->fk_entrepot;
1607 $batch = $obj->batch;
1610 $addOremove = $value > 0 ? 1 : 0;
1611 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1612 $res = $this->
correct_stock_batch($user, $fk_entrepot, abs($value), $addOremove, $label, $price, $dlc, $dluo, $batch, $inventorycode,
'',
null, 0,
null,
true);
1615 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1616 $res = $this->
correct_stock($user, $fk_entrepot, abs($value), (
int) empty($addOremove), $label, $price, $inventorycode,
'',
null, 0);
1635 if (!$error && !$notrigger) {
1637 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
1644 if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) {
1646 if ($conf->product->dir_output) {
1649 if (file_exists($olddir)) {
1653 $res = @rename($olddir, $newdir);
1655 $langs->load(
"errors");
1656 $this->error = $langs->trans(
'ErrorFailToRenameDir', $olddir, $newdir);
1660 require_once DOL_DOCUMENT_ROOT .
'/ecm/class/ecmfiles.class.php';
1661 $ecmfiles =
new EcmFiles($this->db);
1662 $ecmfiles->updateAfterRename(
"produit/".
dol_sanitizeFileName($this->oldcopy->ref),
"produit/".dol_sanitizeFileName($this->ref));
1669 if (isModEnabled(
'variants')) {
1670 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1674 foreach ($comb->fetchAllByFkProductParent($this->id) as $currcomb) {
1675 $currcomb->updateProperties($this, $user);
1679 $this->db->commit();
1682 $this->db->rollback();
1686 if ($this->db->errno() ==
'DB_ERROR_RECORD_ALREADY_EXISTS') {
1687 $langs->load(
"errors");
1688 if (empty($conf->barcode->enabled) || empty($this->barcode)) {
1689 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductAlreadyExists", $this->
ref);
1691 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductBarCodeAlreadyExists", $this->barcode);
1693 $this->errors[] = $this->error;
1694 $this->db->rollback();
1697 $this->error = $langs->trans(
"Error").
" : ".$this->db->error().
" - ".$sql;
1698 $this->errors[] = $this->error;
1699 $this->db->rollback();
1704 $this->db->rollback();
1705 dol_syslog(get_class($this).
"::Update fails verify ".implode(
',', $this->errors), LOG_WARNING);
1717 public function delete(
User $user, $notrigger = 0)
1720 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
1725 if (empty($this->
id)) {
1726 $this->error =
"Object must be fetched before calling delete";
1729 if (($this->
isProduct() && !$user->
hasRight(
'produit',
'supprimer')) || ($this->isService() && !$user->hasRight(
'service',
'supprimer'))) {
1730 $this->error =
"ErrorForbidden";
1735 if (empty($objectisused)) {
1738 if (!$error && empty($notrigger)) {
1740 $result = $this->
call_trigger(
'PRODUCT_DELETE', $user);
1749 $sql =
"DELETE FROM ".$this->db->prefix().
'product_batch';
1750 $sql .=
" WHERE fk_product_stock IN (";
1751 $sql .=
"SELECT rowid FROM ".$this->db->prefix().
'product_stock';
1752 $sql .=
" WHERE fk_product = ".((int) $this->
id).
")";
1754 $result = $this->db->query($sql);
1757 $this->errors[] = $this->db->lasterror();
1763 $elements = array(
'product_fournisseur_price',
'product_price',
'product_lang',
'categorie_product',
'product_stock',
'product_customer_price',
'product_lot');
1764 foreach ($elements as $table) {
1766 $sql =
"DELETE FROM ".$this->db->prefix().$table;
1767 $sql .=
" WHERE fk_product = ".(int) $this->
id;
1769 $result = $this->db->query($sql);
1772 $this->errors[] = $this->db->lasterror();
1779 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1780 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination2ValuePair.class.php';
1785 if ($prodcomb->deleteByFkProductParent($user, $this->id) < 0) {
1787 $this->errors[] =
'Error deleting combinations';
1791 if (!$error && ($prodcomb->fetchByFkProductChild($this->id) > 0) && ($prodcomb->delete($user) < 0)) {
1793 $this->errors[] =
'Error deleting child combination';
1799 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
1800 $sql .=
" WHERE fk_product_pere = ".(int) $this->
id.
" OR fk_product_fils = ".(
int) $this->id;
1802 $result = $this->db->query($sql);
1805 $this->errors[] = $this->db->lasterror();
1814 dol_syslog(get_class($this).
"::delete error -4 ".$this->error, LOG_ERR);
1820 $sqlz =
"DELETE FROM ".$this->db->prefix().
"product";
1821 $sqlz .=
" WHERE rowid = ".(int) $this->
id;
1823 $resultz = $this->db->query($sqlz);
1826 $this->errors[] = $this->db->lasterror();
1842 if ($conf->product->dir_output) {
1843 $dir = $conf->product->dir_output.
"/".$ref;
1844 if (file_exists($dir)) {
1847 $this->errors[] =
'ErrorFailToDeleteDir';
1855 $this->db->commit();
1858 foreach ($this->errors as $errmsg) {
1859 dol_syslog(get_class($this).
"::delete ".$errmsg, LOG_ERR);
1860 $this->error .= ($this->error ?
', '.$errmsg : $errmsg);
1862 $this->db->rollback();
1866 $this->error =
"ErrorRecordIsUsedCantDelete";
1880 $sellByLabel = $langs->trans(
'SellByDate');
1881 $eatByLabel = $langs->trans(
'EatByDate');
1883 self::SELL_OR_EAT_BY_MANDATORY_ID_NONE => $langs->trans(
'BatchSellOrEatByMandatoryNone'),
1884 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY => $sellByLabel,
1885 self::SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY => $eatByLabel,
1886 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT => $langs->trans(
'BatchSellOrEatByMandatoryAll', $sellByLabel, $eatByLabel),
1897 $sellOrEatByMandatoryLabel =
'';
1900 if (isset($sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory])) {
1901 $sellOrEatByMandatoryLabel = $sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory];
1904 return $sellOrEatByMandatoryLabel;
1917 $langs_available = $langs->get_available_languages(DOL_DOCUMENT_ROOT, 0, 2);
1918 $current_lang = $langs->getDefaultLang();
1920 foreach ($langs_available as $key => $value) {
1921 if ($key == $current_lang) {
1922 $sql =
"SELECT rowid";
1923 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1924 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1925 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
1927 $result = $this->db->query($sql);
1929 if ($this->db->num_rows($result)) {
1930 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
1932 $sql2 .=
" label='".$this->db->escape($this->label).
"',";
1933 $sql2 .=
" description='".$this->db->escape($this->
description).
"'";
1935 $sql2 .=
", note='".$this->db->escape($this->other).
"'";
1937 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
1939 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
1944 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->label).
"',";
1945 $sql2 .=
" '".$this->db->escape($this->
description).
"'";
1947 $sql2 .=
", '".$this->db->escape($this->other).
"'";
1951 dol_syslog(get_class($this).
'::setMultiLangs key = current_lang = '.$key);
1952 if (!$this->db->query($sql2)) {
1953 $this->error = $this->db->lasterror();
1956 } elseif (isset($this->multilangs[$key])) {
1957 if (empty($this->multilangs[$key][
"label"])) {
1958 $this->errors[] = $key .
' : ' . $langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Label"));
1962 $sql =
"SELECT rowid";
1963 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1964 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1965 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
1967 $result = $this->db->query($sql);
1969 if ($this->db->num_rows($result)) {
1970 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
1972 $sql2 .=
" label = '".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
1973 $sql2 .=
" description = '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
1976 $sql2 .=
", note = '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
1978 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
1980 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
1985 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
1986 $sql2 .=
" '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
1989 $sql2 .=
", '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
1995 if ($this->multilangs[
"$key"][
"label"] || $this->multilangs[
"$key"][
"description"]) {
1996 if (!$this->db->query($sql2)) {
1997 $this->error = $this->db->lasterror();
2007 $result = $this->
call_trigger(
'PRODUCT_SET_MULTILANGS', $user);
2009 $this->error = $this->db->lasterror();
2027 $sql =
"DELETE FROM ".$this->db->prefix().
"product_lang";
2028 $sql .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($langtodelete).
"'";
2030 dol_syslog(get_class($this).
'::delMultiLangs', LOG_DEBUG);
2031 $result = $this->db->query($sql);
2034 $result = $this->
call_trigger(
'PRODUCT_DEL_MULTILANGS', $user);
2036 $this->error = $this->db->lasterror();
2037 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
2043 $this->error = $this->db->lasterror();
2044 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
2065 if ($type ==
'buy') {
2066 $field =
'accountancy_code_buy';
2067 } elseif ($type ==
'buy_intra') {
2068 $field =
'accountancy_code_buy_intra';
2069 } elseif ($type ==
'buy_export') {
2070 $field =
'accountancy_code_buy_export';
2071 } elseif ($type ==
'sell') {
2072 $field =
'accountancy_code_sell';
2073 } elseif ($type ==
'sell_intra') {
2074 $field =
'accountancy_code_sell_intra';
2075 } elseif ($type ==
'sell_export') {
2076 $field =
'accountancy_code_sell_export';
2081 $sql =
"UPDATE ".$this->db->prefix().$this->table_element.
" SET ";
2082 $sql .=
"$field = '".$this->db->escape($value).
"'";
2083 $sql .=
" WHERE rowid = ".((int) $this->
id);
2086 $resql = $this->db->query($sql);
2090 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
2097 $this->db->rollback();
2101 $this->$field = $value;
2103 $this->db->commit();
2106 $this->error = $this->db->lasterror();
2107 $this->db->rollback();
2121 $current_lang = $langs->getDefaultLang();
2123 $sql =
"SELECT lang, label, description, note as other";
2124 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2125 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2127 $result = $this->db->query($sql);
2129 while ($obj = $this->db->fetch_object($result)) {
2131 if ($obj->lang == $current_lang) {
2132 $this->label = $obj->label;
2134 $this->other = $obj->other;
2136 $this->multilangs[(string) $obj->lang][
"label"] = $obj->label;
2137 $this->multilangs[(string) $obj->lang][
"description"] = $obj->description;
2138 $this->multilangs[(string) $obj->lang][
"other"] = $obj->other;
2142 $this->error =
"Error: ".$this->db->lasterror().
" - ".$sql;
2155 $testExit = array(
'multiprices',
'multiprices_ttc',
'multiprices_base_type',
'multiprices_min',
'multiprices_min_ttc',
'multiprices_tva_tx',
'multiprices_recuperableonly');
2157 foreach ($testExit as $field) {
2158 if (!isset($this->$field)) {
2161 $tmparray = $this->$field;
2162 if (!isset($tmparray[$level])) {
2168 'level' => $level ? $level : 1,
2169 'multiprices' => (float) $this->multiprices[$level],
2170 'multiprices_ttc' => (
float) $this->multiprices_ttc[$level],
2171 'multiprices_base_type' => $this->multiprices_base_type[$level],
2172 'multiprices_min' => (float) $this->multiprices_min[$level],
2173 'multiprices_min_ttc' => (
float) $this->multiprices_min_ttc[$level],
2174 'multiprices_tva_tx' => (float) $this->multiprices_tva_tx[$level],
2175 'multiprices_recuperableonly' => (
float) $this->multiprices_recuperableonly[$level],
2198 if (empty($this->price_by_qty)) {
2199 $this->price_by_qty = 0;
2203 $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,";
2204 $sql .=
" localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, price_min,price_min_ttc,price_by_qty,entity,fk_price_expression) ";
2205 $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).
",";
2206 $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');
2209 dol_syslog(get_class($this).
"::_log_price", LOG_DEBUG);
2210 $resql = $this->db->query($sql);
2212 $this->error = $this->db->lasterror();
2232 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price_by_qty";
2233 $sql .=
" WHERE fk_product_price = ".((int) $rowid);
2234 $resql = $this->db->query($sql);
2236 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price";
2237 $sql .=
" WHERE rowid=".((int) $rowid);
2238 $resql = $this->db->query($sql);
2242 $this->error = $this->db->lasterror();
2257 public function getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp = 0)
2259 global $hookmanager, $action;
2262 if (is_object($hookmanager)) {
2263 $parameters = array(
'thirdparty_seller' => $thirdparty_seller,
'thirdparty_buyer' => $thirdparty_buyer,
'pqp' => $pqp);
2265 $reshook = $hookmanager->executeHooks(
'getSellPrice', $parameters, $this, $action);
2267 return $hookmanager->resArray;
2272 $tva_tx =
get_default_tva($thirdparty_seller, $thirdparty_buyer, $this->
id);
2273 $tva_npr =
get_default_npr($thirdparty_seller, $thirdparty_buyer, $this->
id);
2274 if (empty($tva_tx)) {
2278 $pu_ht = $this->price;
2279 $pu_ttc = $this->price_ttc;
2280 $price_min = $this->price_min;
2281 $price_base_type = $this->price_base_type;
2285 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2289 $filter = array(
't.fk_product' => $this->
id,
't.fk_soc' => $thirdparty_buyer->id);
2292 $pricebycustomerexist =
false;
2293 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2295 if (count($prodcustprice->lines) > 0) {
2296 $pricebycustomerexist =
true;
2297 $pu_ht =
price($prodcustprice->lines[0]->price);
2298 $price_min =
price($prodcustprice->lines[0]->price_min);
2299 $pu_ttc =
price($prodcustprice->lines[0]->price_ttc);
2300 $price_base_type = $prodcustprice->lines[0]->price_base_type;
2301 $tva_tx = $prodcustprice->lines[0]->tva_tx;
2302 if ($prodcustprice->lines[0]->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2303 $tva_tx .=
' ('.$prodcustprice->lines[0]->default_vat_code.
')';
2305 $tva_npr = $prodcustprice->lines[0]->recuperableonly;
2306 if (empty($tva_tx)) {
2312 if (!$pricebycustomerexist && !empty($thirdparty_buyer->price_level)) {
2313 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
2314 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
2315 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
2316 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
2319 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2320 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2322 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2323 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2325 if (empty($tva_tx)) {
2330 } elseif (
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !empty($thirdparty_buyer->price_level)) {
2331 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
2332 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
2333 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
2334 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
2336 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2337 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2339 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2340 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2342 if (empty($tva_tx)) {
2348 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2352 $filter = array(
't.fk_product' => $this->
id,
't.fk_soc' => $thirdparty_buyer->id);
2354 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2356 if (count($prodcustprice->lines) > 0) {
2357 $pu_ht =
price($prodcustprice->lines[0]->price);
2358 $price_min =
price($prodcustprice->lines[0]->price_min);
2359 $pu_ttc =
price($prodcustprice->lines[0]->price_ttc);
2360 $price_base_type = $prodcustprice->lines[0]->price_base_type;
2361 $tva_tx = $prodcustprice->lines[0]->tva_tx;
2362 if ($prodcustprice->lines[0]->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2363 $tva_tx .=
' ('.$prodcustprice->lines[0]->default_vat_code.
')';
2365 $tva_npr = $prodcustprice->lines[0]->recuperableonly;
2366 if (empty($tva_tx)) {
2373 if ($this->prices_by_qty[0]) {
2376 foreach ($this->prices_by_qty_list[0] as $priceforthequantityarray) {
2377 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2381 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2382 $pu_ht = $priceforthequantityarray[
'unitprice'];
2384 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2391 if ($this->prices_by_qty[$thirdparty_buyer->price_level]) {
2394 foreach ($this->prices_by_qty_list[$thirdparty_buyer->price_level] as $priceforthequantityarray) {
2395 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2399 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2400 $pu_ht = $priceforthequantityarray[
'unitprice'];
2402 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2409 return array(
'pu_ht' => $pu_ht,
'pu_ttc' => $pu_ttc,
'price_min' => $price_min,
'price_base_type' => $price_base_type,
'tva_tx' => $tva_tx,
'tva_npr' => $tva_npr);
2426 public function get_buyprice($prodfournprice, $qty, $product_id = 0, $fourn_ref =
'', $fk_soc = 0)
2429 global $action, $hookmanager;
2432 if (is_object($hookmanager)) {
2433 $parameters = array(
2434 'prodfournprice' => $prodfournprice,
2436 'product_id' => $product_id,
2437 'fourn_ref' => $fourn_ref,
2438 'fk_soc' => $fk_soc,
2441 $reshook = $hookmanager->executeHooks(
'getBuyPrice', $parameters, $this, $action);
2443 return $hookmanager->resArray;
2450 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2451 $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,";
2452 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2453 $sql .=
" pfp.packaging";
2454 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2455 $sql .=
" WHERE pfp.rowid = ".((int) $prodfournprice);
2457 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2459 $sql .=
" ORDER BY pfp.quantity DESC";
2461 dol_syslog(get_class($this).
"::get_buyprice first search by prodfournprice/qty", LOG_DEBUG);
2462 $resql = $this->db->query($sql);
2464 $obj = $this->db->fetch_object($resql);
2465 if ($obj && $obj->quantity > 0) {
2466 if (isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2468 $prod_supplier->product_fourn_price_id = $obj->rowid;
2469 $prod_supplier->id = $obj->fk_product;
2470 $prod_supplier->fourn_qty = $obj->quantity;
2471 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2472 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2474 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2476 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2477 if ($price_result >= 0) {
2478 $obj->price = $price_result;
2481 $this->product_fourn_price_id = $obj->rowid;
2482 $this->buyprice = $obj->price;
2483 $this->fourn_pu = $obj->price / $obj->quantity;
2484 $this->fourn_price_base_type =
'HT';
2485 $this->fourn_socid = $obj->fk_soc;
2486 $this->ref_fourn = $obj->ref_supplier;
2487 $this->ref_supplier = $obj->ref_supplier;
2488 $this->desc_supplier = $obj->desc_supplier;
2489 $this->remise_percent = $obj->remise_percent;
2490 $this->vatrate_supplier = $obj->tva_tx;
2491 $this->default_vat_code_supplier = $obj->default_vat_code;
2492 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2493 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2494 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2495 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2496 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2498 $this->packaging = $obj->packaging;
2500 $result = $obj->fk_product;
2504 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2505 $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,";
2506 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2507 $sql .=
" pfp.packaging";
2508 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2509 $sql .=
" WHERE 1 = 1";
2510 if ($product_id > 0) {
2511 $sql .=
" AND pfp.fk_product = ".((int) $product_id);
2513 if ($fourn_ref !=
'none') {
2514 $sql .=
" AND pfp.ref_fourn = '".$this->db->escape($fourn_ref).
"'";
2517 $sql .=
" AND pfp.fk_soc = ".((int) $fk_soc);
2520 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2522 $sql .=
" ORDER BY pfp.quantity DESC";
2525 dol_syslog(get_class($this).
"::get_buyprice second search from qty/ref/product_id", LOG_DEBUG);
2526 $resql = $this->db->query($sql);
2528 $obj = $this->db->fetch_object($resql);
2529 if ($obj && $obj->quantity > 0) {
2530 if (isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2532 $prod_supplier->product_fourn_price_id = $obj->rowid;
2533 $prod_supplier->id = $obj->fk_product;
2534 $prod_supplier->fourn_qty = $obj->quantity;
2535 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2536 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2538 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2540 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2542 $obj->price = $price_result;
2545 $this->product_fourn_price_id = $obj->rowid;
2546 $this->buyprice = $obj->price;
2547 $this->fourn_qty = $obj->quantity;
2548 $this->fourn_pu = $obj->price / $obj->quantity;
2549 $this->fourn_price_base_type =
'HT';
2550 $this->fourn_socid = $obj->fk_soc;
2551 $this->ref_fourn = $obj->ref_supplier;
2552 $this->ref_supplier = $obj->ref_supplier;
2553 $this->desc_supplier = $obj->desc_supplier;
2554 $this->remise_percent = $obj->remise_percent;
2555 $this->vatrate_supplier = $obj->tva_tx;
2556 $this->default_vat_code_supplier = $obj->default_vat_code;
2557 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2558 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2559 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2560 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2561 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2563 $this->packaging = $obj->packaging;
2565 $result = $obj->fk_product;
2571 $this->error = $this->db->lasterror();
2576 $this->error = $this->db->lasterror();
2600 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)
2606 dol_syslog(get_class($this).
"::update_price id=".$id.
" newprice=".$newprice.
" newpricebase=".$newpricebase.
" newminprice=".$newminprice.
" level=".$level.
" npr=".$newnpr.
" newdefaultvatcode=".$newdefaultvatcode);
2609 if (empty($this->tva_tx)) {
2612 if (empty($newnpr)) {
2615 if (empty($newminprice)) {
2620 if ($newvat ===
null || $newvat ==
'') {
2621 $newvat = $this->tva_tx;
2624 $localtaxtype1 =
'';
2625 $localtaxtype2 =
'';
2630 return $this->
generateMultiprices($user, $newprice, $newpricebase, $newvat, $newnpr, $newpbq);
2633 if (!empty($newminprice) && ($newminprice > $newprice)) {
2634 $this->error =
'ErrorPriceCantBeLowerThanMinPrice';
2638 if ($newprice === 0 || $newprice !==
'') {
2639 if ($newpricebase ==
'TTC') {
2640 $price_ttc =
price2num($newprice,
'MU');
2641 $price = (float)
price2num($newprice) / (1 + ((float) $newvat / 100));
2644 if ($newminprice !=
'' || $newminprice == 0) {
2645 $price_min_ttc =
price2num($newminprice,
'MU');
2646 $price_min = (float)
price2num($newminprice) / (1 + ($newvat / 100));
2647 $price_min =
price2num($price_min,
'MU');
2653 $price = (float)
price2num($newprice,
'MU');
2654 $price_ttc = ($newnpr != 1) ? (
float)
price2num($newprice) * (1 + ($newvat / 100)) : $price;
2655 $price_ttc = (float)
price2num($price_ttc,
'MU');
2657 if ($newminprice !==
'' || $newminprice == 0) {
2658 $price_min =
price2num($newminprice,
'MU');
2659 $price_min_ttc = (float)
price2num($newminprice) * (1 + ($newvat / 100));
2660 $price_min_ttc =
price2num($price_min_ttc,
'MU');
2668 if (count($localtaxes_array) > 0) {
2669 $localtaxtype1 = $localtaxes_array[
'0'];
2670 $localtax1 = $localtaxes_array[
'1'];
2671 $localtaxtype2 = $localtaxes_array[
'2'];
2672 $localtax2 = $localtaxes_array[
'3'];
2675 if (!empty($newdefaultvatcode)) {
2678 $sql =
"SELECT t.rowid, t.code, t.recuperableonly as tva_npr, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
2679 $sql .=
" FROM ".MAIN_DB_PREFIX.
"c_tva as t, ".MAIN_DB_PREFIX.
"c_country as c";
2680 $sql .=
" WHERE t.fk_pays = c.rowid AND c.code = '".$this->db->escape($mysoc->country_code).
"'";
2681 $sql .=
" AND t.taux = ".((float) $newdefaultvatcode).
" AND t.active = 1";
2682 $sql .=
" AND t.code = '".$this->db->escape($newdefaultvatcode).
"'";
2683 $resql = $this->db->query($sql);
2685 $obj = $this->db->fetch_object($resql);
2687 $npr = $obj->tva_npr;
2688 $localtax1 = $obj->localtax1;
2689 $localtax2 = $obj->localtax2;
2690 $localtaxtype1 = $obj->localtax1_type;
2691 $localtaxtype2 = $obj->localtax2_type;
2696 $localtaxtype1 =
'0';
2698 $localtaxtype2 =
'0';
2702 if (empty($localtax1)) {
2705 if (empty($localtax2)) {
2713 $sql =
"UPDATE ".$this->db->prefix().
"product SET";
2714 $sql .=
" price_base_type = '".$this->db->escape($newpricebase).
"',";
2715 $sql .=
" price = ".(float) $price.
",";
2716 $sql .=
" price_ttc = ".(float) $price_ttc.
",";
2717 $sql .=
" price_min = ".(float) $price_min.
",";
2718 $sql .=
" price_min_ttc = ".(float) $price_min_ttc.
",";
2719 $sql .=
" localtax1_tx = ".($localtax1 >= 0 ? (float) $localtax1 :
'NULL').
",";
2720 $sql .=
" localtax2_tx = ".($localtax2 >= 0 ? (float) $localtax2 :
'NULL').
",";
2721 $sql .=
" localtax1_type = ".($localtaxtype1 !=
'' ?
"'".$this->db->escape($localtaxtype1).
"'" :
"'0'").
",";
2722 $sql .=
" localtax2_type = ".($localtaxtype2 !=
'' ?
"'".$this->db->escape($localtaxtype2).
"'" :
"'0'").
",";
2723 $sql .=
" default_vat_code = ".($newdefaultvatcode ?
"'".$this->db->escape($newdefaultvatcode).
"'" :
"null").
",";
2724 $sql .=
" price_label = ".(!empty($price_label) ?
"'".$this->db->escape($price_label).
"'" :
"null").
",";
2725 $sql .=
" tva_tx = ".(float)
price2num($newvat).
",";
2726 $sql .=
" recuperableonly = '".$this->db->escape($newnpr).
"'";
2727 $sql .=
" WHERE rowid = ".((int) $id);
2729 dol_syslog(get_class($this).
"::update_price", LOG_DEBUG);
2730 $resql = $this->db->query($sql);
2732 $this->multiprices[$level] = $price;
2733 $this->multiprices_ttc[$level] = $price_ttc;
2734 $this->multiprices_min[$level] = $price_min;
2735 $this->multiprices_min_ttc[$level] = $price_min_ttc;
2736 $this->multiprices_base_type[$level] = $newpricebase;
2737 $this->multiprices_default_vat_code[$level] = $newdefaultvatcode;
2738 $this->multiprices_tva_tx[$level] = $newvat;
2739 $this->multiprices_recuperableonly[$level] = $newnpr;
2741 $this->
price = $price;
2742 $this->price_label = $price_label;
2743 $this->price_ttc = $price_ttc;
2744 $this->price_min = $price_min;
2745 $this->price_min_ttc = $price_min_ttc;
2746 $this->price_base_type = $newpricebase;
2747 $this->default_vat_code = $newdefaultvatcode;
2748 $this->tva_tx = $newvat;
2749 $this->tva_npr = $newnpr;
2752 $this->localtax1_tx = $localtax1;
2753 $this->localtax2_tx = $localtax2;
2754 $this->localtax1_type = $localtaxtype1;
2755 $this->localtax2_type = $localtaxtype2;
2758 $this->price_by_qty = $newpbq;
2762 if (!empty(array_diff_assoc($newPriceData, $lastPriceData)) || !
getDolGlobalString(
'PRODUIT_MULTIPRICES')) {
2766 $this->level = $level;
2770 $result = $this->
call_trigger(
'PRODUCT_PRICE_MODIFY', $user);
2772 $this->db->rollback();
2778 $this->db->commit();
2780 $this->db->rollback();
2781 $this->error = $this->db->lasterror();
2800 $this->fk_price_expression = $expression_id;
2802 return $this->
update($this->
id, $user);
2817 public function fetch($id = 0, $ref =
'', $ref_ext =
'', $barcode =
'', $ignore_expression = 0, $ignore_price_load = 0, $ignore_lang_load = 0)
2819 include_once DOL_DOCUMENT_ROOT.
'/core/lib/company.lib.php';
2823 dol_syslog(get_class($this).
"::fetch id=".$id.
" ref=".$ref.
" ref_ext=".$ref_ext);
2826 if (!$id && !$ref && !$ref_ext && !$barcode) {
2827 $this->error =
'ErrorWrongParameters';
2828 dol_syslog(get_class($this).
"::fetch ".$this->error, LOG_ERR);
2832 $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,";
2833 $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,";
2834 $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,";
2835 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.last_main_doc,";
2836 $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,";
2838 $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,";
2840 $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,";
2845 $separatedEntityPMP =
false;
2846 $separatedStock =
false;
2847 $visibleWarehousesEntities = $conf->entity;
2850 $checkPMPPerEntity = $this->db->query(
"SELECT pmp FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = ".((int) $id).
" AND entity = ".(
int) $conf->entity);
2851 if ($this->db->num_rows($checkPMPPerEntity) > 0) {
2852 $separatedEntityPMP =
true;
2856 $separatedStock =
true;
2857 if (isset($mc->sharings[
'stock']) && !empty($mc->sharings[
'stock'])) {
2858 $visibleWarehousesEntities .=
"," . implode(
",", $mc->sharings[
'stock']);
2861 if ($separatedEntityPMP) {
2862 $sql .=
" ppe.pmp,";
2866 $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,";
2867 $sql .=
" p.fk_price_expression, p.price_autogen, p.model_pdf,";
2868 $sql .=
" p.price_label,";
2869 if ($separatedStock) {
2870 $sql .=
" SUM(sp.reel) as stock";
2874 $sql .=
" FROM ".$this->db->prefix().
"product as p";
2876 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int) $conf->entity);
2878 if ($separatedStock) {
2879 $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).
"))";
2883 $sql .=
" WHERE p.rowid = ".((int) $id);
2885 $sql .=
" WHERE p.entity IN (".getEntity($this->element).
")";
2887 $sql .=
" AND p.ref = '".$this->db->escape($ref).
"'";
2888 } elseif ($ref_ext) {
2889 $sql .=
" AND p.ref_ext = '".$this->db->escape($ref_ext).
"'";
2890 } elseif ($barcode) {
2891 $sql .=
" AND p.barcode = '".$this->db->escape($barcode).
"'";
2894 if ($separatedStock) {
2895 $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,";
2896 $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,";
2897 $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,";
2898 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
2899 $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,";
2901 $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,";
2903 $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,";
2905 if ($separatedEntityPMP) {
2906 $sql .=
" ppe.pmp,";
2910 $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,";
2911 $sql .=
" p.fk_price_expression, p.price_autogen, p.model_pdf";
2912 $sql .=
" ,p.price_label";
2913 if (!$separatedStock) {
2914 $sql .=
", p.stock";
2918 $resql = $this->db->query($sql);
2920 unset($this->oldcopy);
2922 if ($this->db->num_rows($resql) > 0) {
2923 $obj = $this->db->fetch_object($resql);
2925 $this->
id = $obj->rowid;
2926 $this->
ref = $obj->ref;
2927 $this->ref_ext = $obj->ref_ext;
2928 $this->label = $obj->label;
2930 $this->url = $obj->url;
2931 $this->note_public = $obj->note_public;
2932 $this->note_private = $obj->note_private;
2933 $this->note = $obj->note_private;
2935 $this->
type = $obj->fk_product_type;
2936 $this->price_label = $obj->price_label;
2937 $this->
status = $obj->tosell;
2938 $this->status_buy = $obj->tobuy;
2939 $this->status_batch = $obj->tobatch;
2940 $this->sell_or_eat_by_mandatory = $obj->sell_or_eat_by_mandatory;
2941 $this->batch_mask = $obj->batch_mask;
2943 $this->customcode = $obj->customcode;
2944 $this->country_id = $obj->fk_country;
2945 $this->country_code =
getCountry($this->country_id,
'2', $this->db);
2946 $this->state_id = $obj->fk_state;
2947 $this->lifetime = $obj->lifetime;
2948 $this->qc_frequency = $obj->qc_frequency;
2949 $this->
price = $obj->price;
2950 $this->price_ttc = $obj->price_ttc;
2951 $this->price_min = $obj->price_min;
2952 $this->price_min_ttc = $obj->price_min_ttc;
2953 $this->price_base_type = $obj->price_base_type;
2954 $this->cost_price = $obj->cost_price;
2955 $this->default_vat_code = $obj->default_vat_code;
2956 $this->tva_tx = $obj->tva_tx;
2958 $this->tva_npr = $obj->tva_npr;
2960 $this->localtax1_tx = $obj->localtax1_tx;
2961 $this->localtax2_tx = $obj->localtax2_tx;
2962 $this->localtax1_type = $obj->localtax1_type;
2963 $this->localtax2_type = $obj->localtax2_type;
2965 $this->finished = $obj->finished;
2966 $this->fk_default_bom = $obj->fk_default_bom;
2968 $this->duration = $obj->duration;
2969 $this->duration_value = $obj->duration ? (int) (substr($obj->duration, 0,
dol_strlen($obj->duration) - 1)) : 0;
2970 $this->duration_unit = $obj->duration ? substr($obj->duration, -1) :
null;
2971 $this->canvas = $obj->canvas;
2972 $this->net_measure = $obj->net_measure;
2973 $this->net_measure_units = $obj->net_measure_units;
2974 $this->weight = $obj->weight;
2975 $this->weight_units = $obj->weight_units;
2976 $this->length = $obj->length;
2977 $this->length_units = $obj->length_units;
2978 $this->width = $obj->width;
2979 $this->width_units = $obj->width_units;
2980 $this->height = $obj->height;
2981 $this->height_units = $obj->height_units;
2983 $this->surface = $obj->surface;
2984 $this->surface_units = $obj->surface_units;
2985 $this->volume = $obj->volume;
2986 $this->volume_units = $obj->volume_units;
2987 $this->barcode = $obj->barcode;
2988 $this->barcode_type = $obj->fk_barcode_type;
2990 $this->accountancy_code_buy = $obj->accountancy_code_buy;
2991 $this->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra;
2992 $this->accountancy_code_buy_export = $obj->accountancy_code_buy_export;
2993 $this->accountancy_code_sell = $obj->accountancy_code_sell;
2994 $this->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra;
2995 $this->accountancy_code_sell_export = $obj->accountancy_code_sell_export;
2997 $this->fk_default_warehouse = $obj->fk_default_warehouse;
2998 $this->fk_default_workstation = $obj->fk_default_workstation;
2999 $this->seuil_stock_alerte = $obj->seuil_stock_alerte;
3000 $this->desiredstock = $obj->desiredstock;
3001 $this->stock_reel = $obj->stock;
3002 $this->pmp = $obj->pmp;
3004 $this->date_creation = $obj->datec;
3005 $this->date_modification = $obj->tms;
3006 $this->import_key = $obj->import_key;
3007 $this->entity = $obj->entity;
3009 $this->ref_ext = $obj->ref_ext;
3010 $this->fk_price_expression = $obj->fk_price_expression;
3011 $this->fk_unit = $obj->fk_unit;
3012 $this->price_autogen = $obj->price_autogen;
3013 $this->model_pdf = $obj->model_pdf;
3014 $this->last_main_doc = $obj->last_main_doc;
3016 $this->mandatory_period = $obj->mandatory_period;
3018 $this->db->free($resql);
3031 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3032 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3033 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3034 $sql .=
" ,price_label";
3035 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3036 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3037 $sql .=
" AND price_level=".((int) $i);
3038 $sql .=
" AND fk_product = ".((int) $this->
id);
3039 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3041 $resql = $this->db->query($sql);
3043 $result = $this->db->fetch_array($resql);
3045 $this->multiprices[$i] = $result ? $result[
"price"] :
null;
3046 $this->multiprices_ttc[$i] = $result ? $result[
"price_ttc"] :
null;
3047 $this->multiprices_min[$i] = $result ? $result[
"price_min"] :
null;
3048 $this->multiprices_min_ttc[$i] = $result ? $result[
"price_min_ttc"] :
null;
3049 $this->multiprices_base_type[$i] = $result ? $result[
"price_base_type"] :
null;
3051 $this->multiprices_tva_tx[$i] = $result ? $result[
"tva_tx"].($result ?
' ('.$result[
'default_vat_code'].
')' :
'') :
null;
3052 $this->multiprices_recuperableonly[$i] = $result ? $result[
"recuperableonly"] :
null;
3091 $this->error = $this->db->lasterror;
3097 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY') && empty($ignore_price_load)) {
3098 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3099 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid";
3100 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3101 $sql .=
" WHERE fk_product = ".((int) $this->
id);
3102 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3105 $resql = $this->db->query($sql);
3107 $result = $this->db->fetch_array($resql);
3111 $this->prices_by_qty[0] = $result[
"price_by_qty"];
3112 $this->prices_by_qty_id[0] = $result[
"rowid"];
3114 if ($this->prices_by_qty[0] == 1) {
3115 $sql =
"SELECT rowid,price, unitprice, quantity, remise_percent, remise, remise, price_base_type";
3116 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3117 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[0]);
3118 $sql .=
" ORDER BY quantity ASC";
3120 $resql = $this->db->query($sql);
3122 $resultat = array();
3124 while ($result = $this->db->fetch_array($resql)) {
3125 $resultat[$ii] = array();
3126 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3127 $resultat[$ii][
"price"] = $result[
"price"];
3128 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3129 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3130 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3132 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3135 $this->prices_by_qty_list[0] = $resultat;
3137 $this->error = $this->db->lasterror;
3143 $this->error = $this->db->lasterror;
3146 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') && empty($ignore_price_load)) {
3148 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3149 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3150 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3151 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3152 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3153 $sql .=
" AND price_level=".((int) $i);
3154 $sql .=
" AND fk_product = ".((int) $this->
id);
3155 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3157 $resql = $this->db->query($sql);
3159 $this->error = $this->db->lasterror;
3161 } elseif ($result = $this->db->fetch_array($resql)) {
3162 $this->multiprices[$i] = (!empty($result[
"price"]) ? $result[
"price"] : 0);
3163 $this->multiprices_ttc[$i] = (!empty($result[
"price_ttc"]) ? $result[
"price_ttc"] : 0);
3164 $this->multiprices_min[$i] = (!empty($result[
"price_min"]) ? $result[
"price_min"] : 0);
3165 $this->multiprices_min_ttc[$i] = (!empty($result[
"price_min_ttc"]) ? $result[
"price_min_ttc"] : 0);
3166 $this->multiprices_base_type[$i] = (!empty($result[
"price_base_type"]) ? $result[
"price_base_type"] :
'');
3168 $this->multiprices_tva_tx[$i] = (!empty($result[
"tva_tx"]) ? $result[
"tva_tx"] : 0);
3169 $this->multiprices_recuperableonly[$i] = (!empty($result[
"recuperableonly"]) ? $result[
"recuperableonly"] : 0);
3172 $this->prices_by_qty[$i] = (!empty($result[
"price_by_qty"]) ? $result[
"price_by_qty"] : 0);
3173 $this->prices_by_qty_id[$i] = (!empty($result[
"rowid"]) ? $result[
"rowid"] : 0);
3175 if ($this->prices_by_qty[$i] == 1) {
3176 $sql =
"SELECT rowid, price, unitprice, quantity, remise_percent, remise, price_base_type";
3177 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3178 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[$i]);
3179 $sql .=
" ORDER BY quantity ASC";
3181 $resql = $this->db->query($sql);
3183 $resultat = array();
3185 while ($result = $this->db->fetch_array($resql)) {
3186 $resultat[$ii] = array();
3187 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3188 $resultat[$ii][
"price"] = $result[
"price"];
3189 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3190 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3191 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3192 $resultat[$ii][
"remise"] = $result[
"remise"];
3193 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3196 $this->prices_by_qty_list[$i] = $resultat;
3198 $this->error = $this->db->lasterror;
3206 if (isModEnabled(
'dynamicprices') && !empty($this->fk_price_expression) && empty($ignore_expression)) {
3207 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
3209 $price_result = $priceparser->parseProduct($this);
3210 if ($price_result >= 0) {
3211 $this->
price = $price_result;
3213 $this->price_ttc = (float)
price2num($this->
price) * (1 + ($this->tva_tx / 100));
3214 $this->price_ttc = (float)
price2num($this->price_ttc,
'MU');
3220 $this->stock_warehouse = array();
3227 $this->error = $this->db->lasterror();
3242 global $user, $hookmanager, $action;
3246 foreach (array(
'toconsume',
'consumed',
'toproduce',
'produced') as $role) {
3247 $this->stats_mo[
'customers_'.$role] = 0;
3248 $this->stats_mo[
'nb_'.$role] = 0;
3249 $this->stats_mo[
'qty_'.$role] = 0;
3251 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3252 $sql .=
" SUM(mp.qty) as qty";
3253 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as c";
3254 $sql .=
" INNER JOIN ".$this->db->prefix().
"mrp_production as mp ON mp.fk_mo=c.rowid";
3255 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3256 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc=c.fk_soc AND sc.fk_user = ".((int) $user->id);
3259 $sql .=
" c.entity IN (".getEntity(
'mo').
")";
3261 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3262 $sql .=
" AND mp.role ='".$this->db->escape($role).
"'";
3264 $sql .=
" AND c.fk_soc = ".((int) $socid);
3267 $result = $this->db->query($sql);
3269 $obj = $this->db->fetch_object($result);
3270 $this->stats_mo[
'customers_'.$role] = $obj->nb_customers ? $obj->nb_customers : 0;
3271 $this->stats_mo[
'nb_'.$role] = $obj->nb ? $obj->nb : 0;
3272 $this->stats_mo[
'qty_'.$role] = $obj->qty ?
price2num($obj->qty,
'MS') : 0;
3274 $this->error = $this->db->error();
3279 if (!empty($error)) {
3283 $parameters = array(
'socid' => $socid);
3284 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3286 $this->stats_mo = $hookmanager->resArray[
'stats_mo'];
3302 global $hookmanager, $action;
3306 $this->stats_bom[
'nb_toproduce'] = 0;
3307 $this->stats_bom[
'nb_toconsume'] = 0;
3308 $this->stats_bom[
'qty_toproduce'] = 0;
3309 $this->stats_bom[
'qty_toconsume'] = 0;
3311 $sql =
"SELECT COUNT(DISTINCT b.rowid) as nb_toproduce,";
3312 $sql .=
" SUM(b.qty) as qty_toproduce";
3313 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3314 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
3316 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3317 $sql .=
" AND b.fk_product =".((int) $this->
id);
3318 $sql .=
" GROUP BY b.rowid";
3320 $result = $this->db->query($sql);
3322 $obj = $this->db->fetch_object($result);
3323 $this->stats_bom[
'nb_toproduce'] = !empty($obj->nb_toproduce) ? $obj->nb_toproduce : 0;
3324 $this->stats_bom[
'qty_toproduce'] = !empty($obj->qty_toproduce) ?
price2num($obj->qty_toproduce) : 0;
3326 $this->error = $this->db->error();
3330 $sql =
"SELECT COUNT(DISTINCT bl.rowid) as nb_toconsume,";
3331 $sql .=
" SUM(bl.qty) as qty_toconsume";
3332 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3333 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
3335 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3336 $sql .=
" AND bl.fk_product =".((int) $this->
id);
3338 $result = $this->db->query($sql);
3340 $obj = $this->db->fetch_object($result);
3341 $this->stats_bom[
'nb_toconsume'] = !empty($obj->nb_toconsume) ? $obj->nb_toconsume : 0;
3342 $this->stats_bom[
'qty_toconsume'] = !empty($obj->qty_toconsume) ?
price2num($obj->qty_toconsume) : 0;
3344 $this->error = $this->db->error();
3348 if (!empty($error)) {
3352 $parameters = array(
'socid' => $socid);
3353 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3355 $this->stats_bom = $hookmanager->resArray[
'stats_bom'];
3371 global $user, $hookmanager, $action;
3373 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_customers, COUNT(DISTINCT p.rowid) as nb,";
3374 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3375 $sql .=
" FROM ".$this->db->prefix().
"propaldet as pd";
3376 $sql .=
", ".$this->db->prefix().
"propal as p";
3377 $sql .=
", ".$this->db->prefix().
"societe as s";
3378 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3379 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3381 $sql .=
" WHERE p.rowid = pd.fk_propal";
3382 $sql .=
" AND p.fk_soc = s.rowid";
3383 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
3384 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3385 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3386 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3390 $sql .=
" AND p.fk_soc = ".((int) $socid);
3393 $result = $this->db->query($sql);
3395 $obj = $this->db->fetch_object($result);
3396 $this->stats_propale[
'customers'] = $obj->nb_customers;
3397 $this->stats_propale[
'nb'] = $obj->nb;
3398 $this->stats_propale[
'rows'] = $obj->nb_rows;
3399 $this->stats_propale[
'qty'] = $obj->qty ? $obj->qty : 0;
3404 if (is_array($TFather) && !empty($TFather)) {
3405 foreach ($TFather as &$fatherData) {
3406 $pFather =
new Product($this->db);
3407 $pFather->id = $fatherData[
'id'];
3408 $qtyCoef = $fatherData[
'qty'];
3410 if ($fatherData[
'incdec']) {
3411 $pFather->load_stats_propale($socid);
3413 $this->stats_propale[
'customers'] += $pFather->stats_propale[
'customers'];
3414 $this->stats_propale[
'nb'] += $pFather->stats_propale[
'nb'];
3415 $this->stats_propale[
'rows'] += $pFather->stats_propale[
'rows'];
3416 $this->stats_propale[
'qty'] += $pFather->stats_propale[
'qty'] * $qtyCoef;
3422 $parameters = array(
'socid' => $socid);
3423 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerProposal', $parameters, $this, $action);
3425 $this->stats_propale = $hookmanager->resArray[
'stats_propale'];
3430 $this->error = $this->db->error();
3446 global $user, $hookmanager, $action;
3448 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_suppliers, COUNT(DISTINCT p.rowid) as nb,";
3449 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3450 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as pd";
3451 $sql .=
", ".$this->db->prefix().
"supplier_proposal as p";
3452 $sql .=
", ".$this->db->prefix().
"societe as s";
3453 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3454 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3456 $sql .=
" WHERE p.rowid = pd.fk_supplier_proposal";
3457 $sql .=
" AND p.fk_soc = s.rowid";
3458 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
3459 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3460 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3461 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3465 $sql .=
" AND p.fk_soc = ".((int) $socid);
3468 $result = $this->db->query($sql);
3470 $obj = $this->db->fetch_object($result);
3471 $this->stats_proposal_supplier[
'suppliers'] = $obj->nb_suppliers;
3472 $this->stats_proposal_supplier[
'nb'] = $obj->nb;
3473 $this->stats_proposal_supplier[
'rows'] = $obj->nb_rows;
3474 $this->stats_proposal_supplier[
'qty'] = $obj->qty ? $obj->qty : 0;
3476 $parameters = array(
'socid' => $socid);
3477 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierProposal', $parameters, $this, $action);
3479 $this->stats_proposal_supplier = $hookmanager->resArray[
'stats_proposal_supplier'];
3484 $this->error = $this->db->error();
3502 global $user, $hookmanager, $action;
3504 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3505 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3506 $sql .=
" FROM ".$this->db->prefix().
"commandedet as cd";
3507 $sql .=
", ".$this->db->prefix().
"commande as c";
3508 $sql .=
", ".$this->db->prefix().
"societe as s";
3509 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3510 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3512 $sql .=
" WHERE c.rowid = cd.fk_commande";
3513 $sql .=
" AND c.fk_soc = s.rowid";
3514 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'commande').
")";
3515 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3516 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3517 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3520 $sql .=
" AND c.fk_soc = ".((int) $socid);
3522 if ($filtrestatut !=
'') {
3523 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3526 $result = $this->db->query($sql);
3528 $obj = $this->db->fetch_object($result);
3529 $this->stats_commande[
'customers'] = $obj->nb_customers;
3530 $this->stats_commande[
'nb'] = $obj->nb;
3531 $this->stats_commande[
'rows'] = $obj->nb_rows;
3532 $this->stats_commande[
'qty'] = $obj->qty ? $obj->qty : 0;
3537 if (is_array($TFather) && !empty($TFather)) {
3538 foreach ($TFather as &$fatherData) {
3539 $pFather =
new Product($this->db);
3540 $pFather->id = $fatherData[
'id'];
3541 $qtyCoef = $fatherData[
'qty'];
3543 if ($fatherData[
'incdec']) {
3544 $pFather->load_stats_commande($socid, $filtrestatut);
3546 $this->stats_commande[
'customers'] += $pFather->stats_commande[
'customers'];
3547 $this->stats_commande[
'nb'] += $pFather->stats_commande[
'nb'];
3548 $this->stats_commande[
'rows'] += $pFather->stats_commande[
'rows'];
3549 $this->stats_commande[
'qty'] += $pFather->stats_commande[
'qty'] * $qtyCoef;
3561 $sql =
"SELECT SUM(".$this->db->ifsql(
'f.type=2', -1, 1).
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3562 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3563 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON ((el.fk_target = f.rowid AND el.targettype = 'facture' AND sourcetype = 'commande') OR (el.fk_source = f.rowid AND el.targettype = 'commande' AND sourcetype = 'facture'))";
3564 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3565 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3567 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3568 $resql = $this->db->query($sql);
3570 if ($this->db->num_rows($resql) > 0) {
3571 $obj = $this->db->fetch_object($resql);
3572 $adeduire += $obj->count;
3576 $this->stats_commande[
'qty'] -= $adeduire;
3579 include_once DOL_DOCUMENT_ROOT.
'/compta/facture/class/facture.class.php';
3583 $sql =
"SELECT sum(".$this->db->ifsql(
'f.type=2', -1, 1).
" * fd.qty) as count FROM ".MAIN_DB_PREFIX.
"facturedet as fd ";
3584 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"facture as f ON fd.fk_facture = f.rowid";
3585 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"element_element as el ON ((el.fk_target = f.rowid AND el.targettype = 'facture' AND sourcetype = 'commande') OR (el.fk_source = f.rowid AND el.targettype = 'commande' AND sourcetype = 'facture'))";
3586 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"commande as c ON el.fk_source = c.rowid";
3587 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3589 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3590 $resql = $this->db->query($sql);
3592 if ($this->db->num_rows($resql) > 0) {
3593 $obj = $this->db->fetch_object($resql);
3594 $adeduire += $obj->count;
3597 $this->error = $this->db->error();
3601 $this->stats_commande[
'qty'] -= $adeduire;
3605 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3606 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerOrder', $parameters, $this, $action);
3608 $this->stats_commande = $hookmanager->resArray[
'stats_commande'];
3612 $this->error = $this->db->error();
3630 global $user, $hookmanager, $action;
3632 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_suppliers, COUNT(DISTINCT c.rowid) as nb,";
3633 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3634 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as cd";
3635 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as c";
3636 $sql .=
", ".$this->db->prefix().
"societe as s";
3637 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3638 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3640 $sql .=
" WHERE c.rowid = cd.fk_commande";
3641 $sql .=
" AND c.fk_soc = s.rowid";
3642 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3643 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3644 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3645 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3648 $sql .=
" AND c.fk_soc = ".((int) $socid);
3650 if ($filtrestatut !=
'') {
3651 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3653 if (!empty($dateofvirtualstock)) {
3654 $sql .=
" AND c.date_livraison <= '".$this->db->idate($dateofvirtualstock).
"'";
3657 $result = $this->db->query($sql);
3659 $obj = $this->db->fetch_object($result);
3660 $this->stats_commande_fournisseur[
'suppliers'] = $obj->nb_suppliers;
3661 $this->stats_commande_fournisseur[
'nb'] = $obj->nb;
3662 $this->stats_commande_fournisseur[
'rows'] = $obj->nb_rows;
3663 $this->stats_commande_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
3665 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3666 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierOrder', $parameters, $this, $action);
3668 $this->stats_commande_fournisseur = $hookmanager->resArray[
'stats_commande_fournisseur'];
3673 $this->error = $this->db->error().
' sql='.$sql;
3688 public function load_stats_sending($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $filterShipmentStatus =
'')
3691 global $user, $hookmanager, $action;
3693 $sql =
"SELECT COUNT(DISTINCT e.fk_soc) as nb_customers, COUNT(DISTINCT e.rowid) as nb,";
3694 $sql .=
" COUNT(ed.rowid) as nb_rows, SUM(ed.qty) as qty";
3695 $sql .=
" FROM ".$this->db->prefix().
"expeditiondet as ed";
3696 $sql .=
", ".$this->db->prefix().
"commandedet as cd";
3697 $sql .=
", ".$this->db->prefix().
"commande as c";
3698 $sql .=
", ".$this->db->prefix().
"expedition as e";
3699 $sql .=
", ".$this->db->prefix().
"societe as s";
3700 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3701 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3703 $sql .=
" WHERE e.rowid = ed.fk_expedition";
3704 $sql .=
" AND c.rowid = cd.fk_commande";
3705 $sql .=
" AND e.fk_soc = s.rowid";
3706 $sql .=
" AND e.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'expedition').
")";
3707 $sql .=
" AND ed.fk_elementdet = cd.rowid";
3708 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3709 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3710 $sql .=
" AND e.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3713 $sql .=
" AND e.fk_soc = ".((int) $socid);
3715 if ($filtrestatut !=
'') {
3716 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3718 if (!empty($filterShipmentStatus)) {
3719 $sql .=
" AND e.fk_statut IN (".$this->db->sanitize($filterShipmentStatus).
")";
3722 $result = $this->db->query($sql);
3724 $obj = $this->db->fetch_object($result);
3725 $this->stats_expedition[
'customers'] = $obj->nb_customers;
3726 $this->stats_expedition[
'nb'] = $obj->nb;
3727 $this->stats_expedition[
'rows'] = $obj->nb_rows;
3728 $this->stats_expedition[
'qty'] = $obj->qty ? $obj->qty : 0;
3733 if (is_array($TFather) && !empty($TFather)) {
3734 foreach ($TFather as &$fatherData) {
3735 $pFather =
new Product($this->db);
3736 $pFather->id = $fatherData[
'id'];
3737 $qtyCoef = $fatherData[
'qty'];
3739 if ($fatherData[
'incdec']) {
3740 $pFather->load_stats_sending($socid, $filtrestatut, $forVirtualStock);
3742 $this->stats_expedition[
'customers'] += $pFather->stats_expedition[
'customers'];
3743 $this->stats_expedition[
'nb'] += $pFather->stats_expedition[
'nb'];
3744 $this->stats_expedition[
'rows'] += $pFather->stats_expedition[
'rows'];
3745 $this->stats_expedition[
'qty'] += $pFather->stats_expedition[
'qty'] * $qtyCoef;
3751 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock,
'filterShipmentStatus' => $filterShipmentStatus);
3752 $reshook = $hookmanager->executeHooks(
'loadStatsSending', $parameters, $this, $action);
3754 $this->stats_expedition = $hookmanager->resArray[
'stats_expedition'];
3759 $this->error = $this->db->error();
3774 public function load_stats_reception($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null)
3777 global $user, $hookmanager, $action;
3779 $sql =
"SELECT COUNT(DISTINCT cf.fk_soc) as nb_suppliers, COUNT(DISTINCT cf.rowid) as nb,";
3780 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
3781 $sql .=
" FROM ".$this->db->prefix().
"receptiondet_batch as fd";
3782 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as cf";
3783 $sql .=
", ".$this->db->prefix().
"societe as s";
3784 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3785 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3787 $sql .=
" WHERE cf.rowid = fd.fk_element";
3788 $sql .=
" AND cf.fk_soc = s.rowid";
3789 $sql .=
" AND cf.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3790 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3791 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3792 $sql .=
" AND cf.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3795 $sql .=
" AND cf.fk_soc = ".((int) $socid);
3797 if ($filtrestatut !=
'') {
3798 $sql .=
" AND cf.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3800 if (!empty($dateofvirtualstock)) {
3801 $sql .=
" AND fd.datec <= '".$this->db->idate($dateofvirtualstock).
"'";
3804 $result = $this->db->query($sql);
3806 $obj = $this->db->fetch_object($result);
3807 $this->stats_reception[
'suppliers'] = $obj->nb_suppliers;
3808 $this->stats_reception[
'nb'] = $obj->nb;
3809 $this->stats_reception[
'rows'] = $obj->nb_rows;
3810 $this->stats_reception[
'qty'] = $obj->qty ? $obj->qty : 0;
3812 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3813 $reshook = $hookmanager->executeHooks(
'loadStatsReception', $parameters, $this, $action);
3815 $this->stats_reception = $hookmanager->resArray[
'stats_reception'];
3820 $this->error = $this->db->error();
3836 public function load_stats_inproduction($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null, $warehouseid = 0)
3839 global $user, $hookmanager, $action;
3841 $serviceStockIsEnabled = isModEnabled(
"service") &&
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES');
3843 $sql =
"SELECT COUNT(DISTINCT m.fk_soc) as nb_customers, COUNT(DISTINCT m.rowid) as nb,";
3844 $sql .=
" COUNT(mp.rowid) as nb_rows, SUM(mp.qty) as qty, role";
3845 $sql .=
" FROM ".$this->db->prefix().
"mrp_production as mp";
3846 $sql .=
", ".$this->db->prefix().
"mrp_mo as m";
3847 $sql .=
" LEFT JOIN ".$this->db->prefix().
"societe as s ON s.rowid = m.fk_soc";
3848 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3849 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3851 $sql .=
" WHERE m.rowid = mp.fk_mo";
3852 $sql .=
" AND m.entity IN (".getEntity(($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE')) ?
'stock' :
'mrp').
")";
3853 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3854 $sql .=
" AND (mp.disable_stock_change IN (0) OR mp.disable_stock_change IS NULL)";
3855 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3856 $sql .=
" AND m.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3859 $sql .=
" AND m.fk_soc = ".((int) $socid);
3861 if ($filtrestatut !=
'') {
3862 $sql .=
" AND m.status IN (".$this->db->sanitize($filtrestatut).
")";
3864 if (!empty($dateofvirtualstock)) {
3865 $sql .=
" AND m.date_valid <= '".$this->db->idate($dateofvirtualstock).
"'";
3867 if (!$serviceStockIsEnabled) {
3868 $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))";
3870 if (!empty($warehouseid)) {
3871 $sql .=
" AND m.fk_warehouse = ".((int) $warehouseid);
3873 $sql .=
" GROUP BY role";
3876 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
3878 $this->stats_mrptoconsume[
'customers'] = 0;
3879 $this->stats_mrptoconsume[
'nb'] = 0;
3880 $this->stats_mrptoconsume[
'rows'] = 0;
3881 $this->stats_mrptoconsume[
'qty'] = 0;
3882 $this->stats_mrptoproduce[
'customers'] = 0;
3883 $this->stats_mrptoproduce[
'nb'] = 0;
3884 $this->stats_mrptoproduce[
'rows'] = 0;
3885 $this->stats_mrptoproduce[
'qty'] = 0;
3888 $result = $this->db->query($sql);
3890 while ($obj = $this->db->fetch_object($result)) {
3891 if ($obj->role ==
'toconsume' && empty($warehouseid)) {
3892 $this->stats_mrptoconsume[
'customers'] += $obj->nb_customers;
3893 $this->stats_mrptoconsume[
'nb'] += $obj->nb;
3894 $this->stats_mrptoconsume[
'rows'] += $obj->nb_rows;
3895 $this->stats_mrptoconsume[
'qty'] += ($obj->qty ? $obj->qty : 0);
3897 if ($obj->role ==
'consumed' && empty($warehouseid)) {
3901 $this->stats_mrptoconsume[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3903 if ($obj->role ==
'toproduce') {
3905 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] += ($obj->qty ? $obj->qty : 0);
3907 $this->stats_mrptoproduce[
'customers'] += $obj->nb_customers;
3908 $this->stats_mrptoproduce[
'nb'] += $obj->nb;
3909 $this->stats_mrptoproduce[
'rows'] += $obj->nb_rows;
3910 $this->stats_mrptoproduce[
'qty'] += ($obj->qty ? $obj->qty : 0);
3913 if ($obj->role ==
'produced') {
3918 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3920 $this->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3927 if ($this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] < 0) {
3928 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
3931 if ($this->stats_mrptoconsume[
'qty'] < 0) {
3932 $this->stats_mrptoconsume[
'qty'] = 0;
3934 if ($this->stats_mrptoproduce[
'qty'] < 0) {
3935 $this->stats_mrptoproduce[
'qty'] = 0;
3939 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3940 $reshook = $hookmanager->executeHooks(
'loadStatsInProduction', $parameters, $this, $action);
3942 $this->stats_mrptoproduce = $hookmanager->resArray[
'stats_mrptoproduce'];
3947 $this->error = $this->db->error();
3962 global $user, $hookmanager, $action;
3964 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3965 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3966 $sql .=
" FROM ".$this->db->prefix().
"contratdet as cd";
3967 $sql .=
", ".$this->db->prefix().
"contrat as c";
3968 $sql .=
", ".$this->db->prefix().
"societe as s";
3969 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3970 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3972 $sql .=
" WHERE c.rowid = cd.fk_contrat";
3973 $sql .=
" AND c.fk_soc = s.rowid";
3974 $sql .=
" AND c.entity IN (".getEntity(
'contract').
")";
3975 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3976 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3977 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3981 $sql .=
" AND c.fk_soc = ".((int) $socid);
3984 $result = $this->db->query($sql);
3986 $obj = $this->db->fetch_object($result);
3987 $this->stats_contrat[
'customers'] = $obj->nb_customers;
3988 $this->stats_contrat[
'nb'] = $obj->nb;
3989 $this->stats_contrat[
'rows'] = $obj->nb_rows;
3990 $this->stats_contrat[
'qty'] = $obj->qty ? $obj->qty : 0;
3995 if (is_array($TFather) && !empty($TFather)) {
3996 foreach ($TFather as &$fatherData) {
3997 $pFather =
new Product($this->db);
3998 $pFather->id = $fatherData[
'id'];
3999 $qtyCoef = $fatherData[
'qty'];
4001 if ($fatherData[
'incdec']) {
4002 $pFather->load_stats_contrat($socid);
4004 $this->stats_contrat[
'customers'] += $pFather->stats_contrat[
'customers'];
4005 $this->stats_contrat[
'nb'] += $pFather->stats_contrat[
'nb'];
4006 $this->stats_contrat[
'rows'] += $pFather->stats_contrat[
'rows'];
4007 $this->stats_contrat[
'qty'] += $pFather->stats_contrat[
'qty'] * $qtyCoef;
4013 $parameters = array(
'socid' => $socid);
4014 $reshook = $hookmanager->executeHooks(
'loadStatsContract', $parameters, $this, $action);
4016 $this->stats_contrat = $hookmanager->resArray[
'stats_contrat'];
4021 $this->error = $this->db->error().
' sql='.$sql;
4036 global $user, $hookmanager, $action;
4038 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4039 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(".$this->db->ifsql(
'f.type != 2',
'fd.qty',
'fd.qty * -1').
") as qty";
4040 $sql .=
" FROM ".$this->db->prefix().
"facturedet as fd";
4041 $sql .=
", ".$this->db->prefix().
"facture as f";
4042 $sql .=
", ".$this->db->prefix().
"societe as s";
4043 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4044 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4046 $sql .=
" WHERE f.rowid = fd.fk_facture";
4047 $sql .=
" AND f.fk_soc = s.rowid";
4048 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4049 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4050 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4051 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4055 $sql .=
" AND f.fk_soc = ".((int) $socid);
4058 $result = $this->db->query($sql);
4060 $obj = $this->db->fetch_object($result);
4061 $this->stats_facture[
'customers'] = $obj->nb_customers;
4062 $this->stats_facture[
'nb'] = $obj->nb;
4063 $this->stats_facture[
'rows'] = $obj->nb_rows;
4064 $this->stats_facture[
'qty'] = $obj->qty ? $obj->qty : 0;
4069 if (is_array($TFather) && !empty($TFather)) {
4070 foreach ($TFather as &$fatherData) {
4071 $pFather =
new Product($this->db);
4072 $pFather->id = $fatherData[
'id'];
4073 $qtyCoef = $fatherData[
'qty'];
4075 if ($fatherData[
'incdec']) {
4076 $pFather->load_stats_facture($socid);
4078 $this->stats_facture[
'customers'] += $pFather->stats_facture[
'customers'];
4079 $this->stats_facture[
'nb'] += $pFather->stats_facture[
'nb'];
4080 $this->stats_facture[
'rows'] += $pFather->stats_facture[
'rows'];
4081 $this->stats_facture[
'qty'] += $pFather->stats_facture[
'qty'] * $qtyCoef;
4087 $parameters = array(
'socid' => $socid);
4088 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoice', $parameters, $this, $action);
4090 $this->stats_facture = $hookmanager->resArray[
'stats_facture'];
4095 $this->error = $this->db->error();
4111 global $user, $hookmanager, $action;
4113 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4114 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4115 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facturedet_rec as fd";
4116 $sql .=
", ".MAIN_DB_PREFIX.
"facture_rec as f";
4117 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
4118 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4119 $sql .=
", ".MAIN_DB_PREFIX.
"societe_commerciaux as sc";
4121 $sql .=
" WHERE f.rowid = fd.fk_facture";
4122 $sql .=
" AND f.fk_soc = s.rowid";
4123 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4124 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4125 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4126 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4130 $sql .=
" AND f.fk_soc = ".((int) $socid);
4133 $result = $this->db->query($sql);
4135 $obj = $this->db->fetch_object($result);
4136 $this->stats_facturerec[
'customers'] = $obj->nb_customers;
4137 $this->stats_facturerec[
'nb'] = $obj->nb;
4138 $this->stats_facturerec[
'rows'] = $obj->nb_rows;
4139 $this->stats_facturerec[
'qty'] = $obj->qty ? $obj->qty : 0;
4144 if (is_array($TFather) && !empty($TFather)) {
4145 foreach ($TFather as &$fatherData) {
4146 $pFather =
new Product($this->db);
4147 $pFather->id = $fatherData[
'id'];
4148 $qtyCoef = $fatherData[
'qty'];
4150 if ($fatherData[
'incdec']) {
4151 $pFather->load_stats_facture($socid);
4153 $this->stats_facturerec[
'customers'] += $pFather->stats_facturerec[
'customers'];
4154 $this->stats_facturerec[
'nb'] += $pFather->stats_facturerec[
'nb'];
4155 $this->stats_facturerec[
'rows'] += $pFather->stats_facturerec[
'rows'];
4156 $this->stats_facturerec[
'qty'] += $pFather->stats_facturerec[
'qty'] * $qtyCoef;
4162 $parameters = array(
'socid' => $socid);
4163 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoiceRec', $parameters, $this, $action);
4165 $this->stats_facturerec = $hookmanager->resArray[
'stats_facturerec'];
4170 $this->error = $this->db->error();
4185 global $user, $hookmanager, $action;
4187 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
4188 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4189 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as fd";
4190 $sql .=
", ".$this->db->prefix().
"facture_fourn as f";
4191 $sql .=
", ".$this->db->prefix().
"societe as s";
4192 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4193 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4195 $sql .=
" WHERE f.rowid = fd.fk_facture_fourn";
4196 $sql .=
" AND f.fk_soc = s.rowid";
4197 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4198 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4199 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4200 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4204 $sql .=
" AND f.fk_soc = ".((int) $socid);
4207 $result = $this->db->query($sql);
4209 $obj = $this->db->fetch_object($result);
4210 $this->stats_facture_fournisseur[
'suppliers'] = $obj->nb_suppliers;
4211 $this->stats_facture_fournisseur[
'nb'] = $obj->nb;
4212 $this->stats_facture_fournisseur[
'rows'] = $obj->nb_rows;
4213 $this->stats_facture_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
4215 $parameters = array(
'socid' => $socid);
4216 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoice', $parameters, $this, $action);
4218 $this->stats_facture_fournisseur = $hookmanager->resArray[
'stats_facture_fournisseur'];
4223 $this->error = $this->db->error();
4242 $resql = $this->db->query($sql);
4244 $num = $this->db->num_rows($resql);
4247 $arr = $this->db->fetch_array($resql);
4248 if (is_array($arr)) {
4249 $keyfortab = (string) $arr[1];
4251 $keyfortab = substr($keyfortab, -2);
4254 if ($mode ==
'byunit') {
4255 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[0];
4256 } elseif ($mode ==
'bynumber') {
4257 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4258 } elseif ($mode ==
'byamount') {
4259 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4268 $this->error = $this->db->error().
' sql='.$sql;
4275 } elseif ($year == -1) {
4284 for ($j = 0; $j < 12; $j++) {
4286 $idx = ucfirst(
dol_trunc(
dol_print_date(
dol_mktime(12, 0, 0, $month, 1, 1970),
"%b"), 1,
'right',
'UTF-8', 1));
4289 $result[$j] = array($idx, isset($tab[$year.$month]) ? $tab[$year.$month] : 0);
4292 $month =
"0".($month - 1);
4294 $month = substr($month, 1);
4302 return array_reverse($result);
4317 public function get_nb_vente($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4322 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4323 if ($mode ==
'bynumber') {
4324 $sql .=
", count(DISTINCT f.rowid)";
4326 $sql .=
", sum(d.total_ht) as total_ht";
4327 $sql .=
" FROM ".$this->db->prefix().
"facturedet as d, ".$this->db->prefix().
"facture as f, ".$this->db->prefix().
"societe as s";
4328 if ($filteronproducttype >= 0) {
4329 $sql .=
", ".$this->db->prefix().
"product as p";
4331 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4332 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4334 $sql .=
" WHERE f.rowid = d.fk_facture";
4335 if ($this->
id > 0) {
4336 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4338 $sql .=
" AND d.fk_product > 0";
4340 if ($filteronproducttype >= 0) {
4341 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4343 $sql .=
" AND f.fk_soc = s.rowid";
4344 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4345 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4346 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4349 $sql .=
" AND f.fk_soc = $socid";
4351 $sql .= $morefilter;
4352 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4353 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4355 return $this->
_get_stats($sql, $mode, $year);
4370 public function get_nb_achat($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4375 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4376 if ($mode ==
'bynumber') {
4377 $sql .=
", count(DISTINCT f.rowid)";
4379 $sql .=
", sum(d.total_ht) as total_ht";
4380 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as d, ".$this->db->prefix().
"facture_fourn as f, ".$this->db->prefix().
"societe as s";
4381 if ($filteronproducttype >= 0) {
4382 $sql .=
", ".$this->db->prefix().
"product as p";
4384 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4385 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4387 $sql .=
" WHERE f.rowid = d.fk_facture_fourn";
4388 if ($this->
id > 0) {
4389 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4391 $sql .=
" AND d.fk_product > 0";
4393 if ($filteronproducttype >= 0) {
4394 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4396 $sql .=
" AND f.fk_soc = s.rowid";
4397 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4398 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4399 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4402 $sql .=
" AND f.fk_soc = $socid";
4404 $sql .= $morefilter;
4405 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4406 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4408 return $this->
_get_stats($sql, $mode, $year);
4422 public function get_nb_propal($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4427 $sql =
"SELECT sum(d.qty) as qty, date_format(p.datep, '%Y%m')";
4428 if ($mode ==
'bynumber') {
4429 $sql .=
", count(DISTINCT p.rowid)";
4431 $sql .=
", sum(d.total_ht) as total_ht";
4432 $sql .=
" FROM ".$this->db->prefix().
"propaldet as d, ".$this->db->prefix().
"propal as p, ".$this->db->prefix().
"societe as s";
4433 if ($filteronproducttype >= 0) {
4434 $sql .=
", ".$this->db->prefix().
"product as prod";
4436 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4437 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4439 $sql .=
" WHERE p.rowid = d.fk_propal";
4440 if ($this->
id > 0) {
4441 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4443 $sql .=
" AND d.fk_product > 0";
4445 if ($filteronproducttype >= 0) {
4446 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4448 $sql .=
" AND p.fk_soc = s.rowid";
4449 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
4450 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4451 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4454 $sql .=
" AND p.fk_soc = ".((int) $socid);
4456 $sql .= $morefilter;
4457 $sql .=
" GROUP BY date_format(p.datep,'%Y%m')";
4458 $sql .=
" ORDER BY date_format(p.datep,'%Y%m') DESC";
4460 return $this->
_get_stats($sql, $mode, $year);
4479 $sql =
"SELECT sum(d.qty) as qty, date_format(p.date_valid, '%Y%m')";
4480 if ($mode ==
'bynumber') {
4481 $sql .=
", count(DISTINCT p.rowid)";
4483 $sql .=
", sum(d.total_ht) as total_ht";
4484 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as d, ".$this->db->prefix().
"supplier_proposal as p, ".$this->db->prefix().
"societe as s";
4485 if ($filteronproducttype >= 0) {
4486 $sql .=
", ".$this->db->prefix().
"product as prod";
4488 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4489 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4491 $sql .=
" WHERE p.rowid = d.fk_supplier_proposal";
4492 if ($this->
id > 0) {
4493 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4495 $sql .=
" AND d.fk_product > 0";
4497 if ($filteronproducttype >= 0) {
4498 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4500 $sql .=
" AND p.fk_soc = s.rowid";
4501 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
4502 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4503 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4506 $sql .=
" AND p.fk_soc = ".((int) $socid);
4508 $sql .= $morefilter;
4509 $sql .=
" GROUP BY date_format(p.date_valid,'%Y%m')";
4510 $sql .=
" ORDER BY date_format(p.date_valid,'%Y%m') DESC";
4512 return $this->
_get_stats($sql, $mode, $year);
4526 public function get_nb_order($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4531 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4532 if ($mode ==
'bynumber') {
4533 $sql .=
", count(DISTINCT c.rowid)";
4535 $sql .=
", sum(d.total_ht) as total_ht";
4536 $sql .=
" FROM ".$this->db->prefix().
"commandedet as d, ".$this->db->prefix().
"commande as c, ".$this->db->prefix().
"societe as s";
4537 if ($filteronproducttype >= 0) {
4538 $sql .=
", ".$this->db->prefix().
"product as p";
4540 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4541 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4543 $sql .=
" WHERE c.rowid = d.fk_commande";
4544 if ($this->
id > 0) {
4545 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4547 $sql .=
" AND d.fk_product > 0";
4549 if ($filteronproducttype >= 0) {
4550 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4552 $sql .=
" AND c.fk_soc = s.rowid";
4553 $sql .=
" AND c.entity IN (".getEntity(
'commande').
")";
4554 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4555 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4558 $sql .=
" AND c.fk_soc = ".((int) $socid);
4560 $sql .= $morefilter;
4561 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4562 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4564 return $this->
_get_stats($sql, $mode, $year);
4583 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4584 if ($mode ==
'bynumber') {
4585 $sql .=
", count(DISTINCT c.rowid)";
4587 $sql .=
", sum(d.total_ht) as total_ht";
4588 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as d, ".$this->db->prefix().
"commande_fournisseur as c, ".$this->db->prefix().
"societe as s";
4589 if ($filteronproducttype >= 0) {
4590 $sql .=
", ".$this->db->prefix().
"product as p";
4592 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4593 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4595 $sql .=
" WHERE c.rowid = d.fk_commande";
4596 if ($this->
id > 0) {
4597 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4599 $sql .=
" AND d.fk_product > 0";
4601 if ($filteronproducttype >= 0) {
4602 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4604 $sql .=
" AND c.fk_soc = s.rowid";
4605 $sql .=
" AND c.entity IN (".getEntity(
'supplier_order').
")";
4606 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4607 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4610 $sql .=
" AND c.fk_soc = ".((int) $socid);
4612 $sql .= $morefilter;
4613 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4614 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4616 return $this->
_get_stats($sql, $mode, $year);
4630 public function get_nb_contract($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4635 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_contrat, '%Y%m')";
4636 if ($mode ==
'bynumber') {
4637 $sql .=
", count(DISTINCT c.rowid)";
4639 $sql .=
", sum(d.total_ht) as total_ht";
4640 $sql .=
" FROM ".$this->db->prefix().
"contratdet as d, ".$this->db->prefix().
"contrat as c, ".$this->db->prefix().
"societe as s";
4641 if ($filteronproducttype >= 0) {
4642 $sql .=
", ".$this->db->prefix().
"product as p";
4644 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4645 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4647 $sql .=
" WHERE c.entity IN (".getEntity(
'contract').
")";
4648 $sql .=
" AND c.rowid = d.fk_contrat";
4650 if ($this->
id > 0) {
4651 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4653 $sql .=
" AND d.fk_product > 0";
4655 if ($filteronproducttype >= 0) {
4656 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4658 $sql .=
" AND c.fk_soc = s.rowid";
4660 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4661 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4664 $sql .=
" AND c.fk_soc = ".((int) $socid);
4666 $sql .= $morefilter;
4667 $sql .=
" GROUP BY date_format(c.date_contrat,'%Y%m')";
4668 $sql .=
" ORDER BY date_format(c.date_contrat,'%Y%m') DESC";
4670 return $this->
_get_stats($sql, $mode, $year);
4684 public function get_nb_mos($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4689 $sql =
"SELECT sum(d.qty), date_format(d.date_valid, '%Y%m')";
4690 if ($mode ==
'bynumber') {
4691 $sql .=
", count(DISTINCT d.rowid)";
4693 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as d LEFT JOIN ".$this->db->prefix().
"societe as s ON d.fk_soc = s.rowid";
4694 if ($filteronproducttype >= 0) {
4695 $sql .=
", ".$this->db->prefix().
"product as p";
4697 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4698 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4701 $sql .=
" WHERE d.entity IN (".getEntity(
'mo').
")";
4702 $sql .=
" AND d.status > 0";
4704 if ($this->
id > 0) {
4705 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4707 $sql .=
" AND d.fk_product > 0";
4709 if ($filteronproducttype >= 0) {
4710 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4713 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4714 $sql .=
" AND d.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4717 $sql .=
" AND d.fk_soc = ".((int) $socid);
4719 $sql .= $morefilter;
4720 $sql .=
" GROUP BY date_format(d.date_valid,'%Y%m')";
4721 $sql .=
" ORDER BY date_format(d.date_valid,'%Y%m') DESC";
4723 return $this->
_get_stats($sql, $mode, $year);
4743 if (!is_numeric($id_pere)) {
4746 if (!is_numeric($id_fils)) {
4749 if (!is_numeric($incdec)) {
4759 $sql =
"SELECT fk_product_pere from ".$this->db->prefix().
"product_association";
4760 $sql .=
" WHERE fk_product_pere = ".((int) $id_fils).
" AND fk_product_fils = ".((int) $id_pere);
4761 if (!$this->db->query($sql)) {
4766 $sql =
"SELECT MAX(rang) as max_rank FROM ".$this->db->prefix().
"product_association";
4767 $sql .=
" WHERE fk_product_pere = ".((int) $id_pere);
4768 $resql = $this->db->query($sql);
4770 $obj = $this->db->fetch_object($resql);
4771 $rank = $obj->max_rank + 1;
4773 $sql =
"INSERT INTO ".$this->db->prefix().
"product_association(fk_product_pere,fk_product_fils,qty,incdec,rang)";
4774 $sql .=
" VALUES (".((int) $id_pere).
", ".((int) $id_fils).
", ".
price2num($qty,
'MS').
", ".((int) $incdec).
", ".((int) $rank).
")";
4775 if (! $this->db->query($sql)) {
4781 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_ADD', $user);
4783 $this->error = $this->db->lasterror();
4784 dol_syslog(get_class($this).
'::addSubproduct error='.$this->error, LOG_ERR);
4816 if (!is_numeric($id_pere)) {
4819 if (!is_numeric($id_fils)) {
4822 if (!is_numeric($incdec)) {
4825 if (!is_numeric($qty)) {
4829 $sql =
'UPDATE '.$this->db->prefix().
'product_association SET ';
4830 $sql .=
'qty = '.price2num($qty,
'MS');
4831 $sql .=
',incdec = '.((int) $incdec);
4832 $sql .=
' WHERE fk_product_pere = '.((int) $id_pere).
' AND fk_product_fils = '.((int) $id_fils);
4834 if (!$this->db->query($sql)) {
4840 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_UPDATE', $user);
4842 $this->error = $this->db->lasterror();
4843 dol_syslog(get_class($this).
'::updateSubproduct error='.$this->error, LOG_ERR);
4867 if (!is_numeric($fk_parent)) {
4870 if (!is_numeric($fk_child)) {
4874 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
4875 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
4876 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
4878 dol_syslog(get_class($this).
'::del_sousproduit', LOG_DEBUG);
4879 if (!$this->db->query($sql)) {
4885 $sqlrank =
"SELECT rowid, rang FROM ".$this->db->prefix().
"product_association";
4886 $sqlrank .=
" WHERE fk_product_pere = ".((int) $fk_parent);
4887 $sqlrank .=
" ORDER BY rang";
4888 $resqlrank = $this->db->query($sqlrank);
4891 while ($objrank = $this->db->fetch_object($resqlrank)) {
4893 $sql =
"UPDATE ".$this->db->prefix().
"product_association";
4894 $sql .=
" SET rang = ".((int) $cpt);
4895 $sql .=
" WHERE rowid = ".((int) $objrank->rowid);
4896 if (! $this->db->query($sql)) {
4905 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_DELETE', $user);
4907 $this->error = $this->db->lasterror();
4908 dol_syslog(get_class($this).
'::delSubproduct error='.$this->error, LOG_ERR);
4928 $sql =
"SELECT fk_product_pere, qty, incdec";
4929 $sql .=
" FROM ".$this->db->prefix().
"product_association";
4930 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
4931 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
4933 $result = $this->db->query($sql);
4935 $num = $this->db->num_rows($result);
4938 $obj = $this->db->fetch_object($result);
4940 $this->is_sousproduit_qty = $obj->qty;
4941 $this->is_sousproduit_incdec = $obj->incdec;
4972 dol_syslog(get_class($this).
"::add_fournisseur id_fourn = ".$id_fourn.
" ref_fourn=".$ref_fourn.
" quantity=".$quantity, LOG_DEBUG);
4979 $sql =
"SELECT rowid, fk_product";
4980 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
4981 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
4982 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
4983 $sql .=
" AND fk_product <> ".((int) $this->
id);
4984 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
4986 $resql = $this->db->query($sql);
4988 $obj = $this->db->fetch_object($resql);
4991 $this->product_id_already_linked = $obj->fk_product;
4994 $this->db->free($resql);
4998 $sql =
"SELECT rowid";
4999 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5000 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5002 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5004 $sql .=
" AND (ref_fourn = '' OR ref_fourn IS NULL)";
5006 $sql .=
" AND quantity = ".((float) $quantity);
5007 $sql .=
" AND fk_product = ".((int) $this->
id);
5008 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5010 $resql = $this->db->query($sql);
5012 $obj = $this->db->fetch_object($resql);
5016 $sql =
"INSERT INTO ".$this->db->prefix().
"product_fournisseur_price(";
5019 $sql .=
", fk_product";
5021 $sql .=
", ref_fourn";
5022 $sql .=
", quantity";
5023 $sql .=
", fk_user";
5025 $sql .=
") VALUES (";
5026 $sql .=
"'".$this->db->idate($now).
"'";
5027 $sql .=
", ".((int) $conf->entity);
5028 $sql .=
", ".((int) $this->
id);
5029 $sql .=
", ".((int) $id_fourn);
5030 $sql .=
", '".$this->db->escape($ref_fourn).
"'";
5031 $sql .=
", ".((float) $quantity);
5032 $sql .=
", ".((int) $user->id);
5036 if ($this->db->query($sql)) {
5037 $this->product_fourn_price_id = $this->db->last_insert_id($this->db->prefix().
"product_fournisseur_price");
5040 $this->error = $this->db->lasterror();
5045 $this->product_fourn_price_id = $obj->rowid;
5049 $this->error = $this->db->lasterror();
5068 $sql =
"SELECT DISTINCT p.fk_soc";
5069 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as p";
5070 $sql .=
" WHERE p.fk_product = ".((int) $this->
id);
5071 $sql .=
" AND p.entity = ".((int) $conf->entity);
5073 $result = $this->db->query($sql);
5075 $num = $this->db->num_rows($result);
5078 $obj = $this->db->fetch_object($result);
5079 $list[$i] = $obj->fk_soc;
5104 $sql =
"INSERT INTO ".$this->db->prefix().
"product_price (";
5106 $sql .=
", fk_product";
5107 $sql .=
", date_price";
5108 $sql .=
", price_level";
5110 $sql .=
", price_ttc";
5111 $sql .=
", price_min";
5112 $sql .=
", price_min_ttc";
5113 $sql .=
", price_base_type";
5114 $sql .=
", price_label";
5115 $sql .=
", default_vat_code";
5117 $sql .=
", recuperableonly";
5118 $sql .=
", localtax1_tx";
5119 $sql .=
", localtax1_type";
5120 $sql .=
", localtax2_tx";
5121 $sql .=
", localtax2_type";
5122 $sql .=
", fk_user_author";
5124 $sql .=
", price_by_qty";
5125 $sql .=
", fk_price_expression";
5126 $sql .=
", fk_multicurrency";
5127 $sql .=
", multicurrency_code";
5128 $sql .=
", multicurrency_tx";
5129 $sql .=
", multicurrency_price";
5130 $sql .=
", multicurrency_price_ttc";
5135 $sql .=
", '".$this->db->idate($now).
"'";
5136 $sql .=
", price_level";
5138 $sql .=
", price_ttc";
5139 $sql .=
", price_min";
5140 $sql .=
", price_min_ttc";
5141 $sql .=
", price_base_type";
5142 $sql .=
", price_label";
5143 $sql .=
", default_vat_code";
5145 $sql .=
", recuperableonly";
5146 $sql .=
", localtax1_tx";
5147 $sql .=
", localtax1_type";
5148 $sql .=
", localtax2_tx";
5149 $sql .=
", localtax2_type";
5150 $sql .=
", ".$user->id;
5152 $sql .=
", price_by_qty";
5153 $sql .=
", fk_price_expression";
5154 $sql .=
", fk_multicurrency";
5155 $sql .=
", multicurrency_code";
5156 $sql .=
", multicurrency_tx";
5157 $sql .=
", multicurrency_price";
5158 $sql .=
", multicurrency_price_ttc";
5159 $sql .=
" FROM ".$this->db->prefix().
"product_price ps";
5160 $sql .=
" WHERE fk_product = ".((int) $fromId);
5161 $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)";
5162 $sql .=
" ORDER BY date_price DESC";
5165 $resql = $this->db->query($sql);
5167 $this->db->rollback();
5171 $this->db->commit();
5188 $sql =
'INSERT INTO '.$this->db->prefix().
'product_association (fk_product_pere, fk_product_fils, qty, incdec)';
5189 $sql .=
" SELECT ".$toId.
", fk_product_fils, qty, incdec FROM ".$this->db->prefix().
"product_association";
5190 $sql .=
" WHERE fk_product_pere = ".((int) $fromId);
5192 dol_syslog(get_class($this).
'::clone_association', LOG_DEBUG);
5193 if (!$this->db->query($sql)) {
5194 $this->db->rollback();
5198 $this->db->commit();
5231 $sql =
"INSERT ".$this->db->prefix().
"product_fournisseur_price (";
5232 $sql .=
" datec, fk_product, fk_soc, price, quantity, fk_user, tva_tx)";
5233 $sql .=
" SELECT '".$this->db->idate($now).
"', ".((int) $toId).
", fk_soc, price, quantity, fk_user, tva_tx";
5234 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5235 $sql .=
" WHERE fk_product = ".((int) $fromId);
5237 dol_syslog(get_class($this).
'::clone_fournisseurs', LOG_DEBUG);
5238 $resql = $this->db->query($sql);
5240 $this->db->rollback();
5243 $this->db->commit();
5261 public function fetch_prod_arbo($prod, $compl_path =
'', $multiply = 1, $level = 1, $id_parent = 0, $ignore_stock_load = 0)
5267 foreach ($prod as $id_product => $desc_pere) {
5268 if (is_array($desc_pere)) {
5269 $id = (!empty($desc_pere[0]) ? $desc_pere[0] :
'');
5270 $nb = (!empty($desc_pere[1]) ? $desc_pere[1] :
'');
5271 $type = (!empty($desc_pere[2]) ? $desc_pere[2] :
'');
5272 $label = (!empty($desc_pere[3]) ? $desc_pere[3] :
'');
5273 $incdec = (!empty($desc_pere[4]) ? $desc_pere[4] : 0);
5275 if ($multiply < 1) {
5280 if (is_null($tmpproduct)) {
5281 $tmpproduct =
new Product($this->db);
5283 $tmpproduct->fetch($id);
5285 if (empty($ignore_stock_load) && ($tmpproduct->isProduct() ||
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES'))) {
5286 $tmpproduct->load_stock(
'nobatch,novirtual');
5289 $this->res[] = array(
5291 'id_parent' => $id_parent,
5292 'ref' => $tmpproduct->ref,
5294 'nb_total' => $nb * $multiply,
5295 'stock' => $tmpproduct->stock_reel,
5296 'stock_alert' => $tmpproduct->seuil_stock_alerte,
5298 'fullpath' => $compl_path.$label,
5300 'desiredstock' => $tmpproduct->desiredstock,
5302 'incdec' => $incdec,
5303 'entity' => $tmpproduct->entity
5307 if (isset($desc_pere[
'childs']) && is_array($desc_pere[
'childs'])) {
5309 $this->
fetch_prod_arbo($desc_pere[
'childs'], $compl_path.$desc_pere[3].
" -> ", $desc_pere[1] * $multiply, $level + 1, $id, $ignore_stock_load);
5327 $this->res = array();
5328 if (isset($this->sousprods) && is_array($this->sousprods)) {
5329 foreach ($this->sousprods as $prod_name => $desc_product) {
5330 if (is_array($desc_product)) {
5331 $this->
fetch_prod_arbo($desc_product,
"", $multiply, 1, $this->
id, $ignore_stock_load);
5350 $sql =
"SELECT COUNT(pa.rowid) as nb";
5351 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa";
5353 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id).
" OR pa.fk_product_pere = ".((int) $this->
id);
5354 } elseif ($mode == -1) {
5355 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id);
5356 } elseif ($mode == 1) {
5357 $sql .=
" WHERE pa.fk_product_pere = ".((int) $this->
id);
5360 $resql = $this->db->query($sql);
5362 $obj = $this->db->fetch_object($resql);
5381 $sql =
"SELECT count(rowid) as nb FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_parent = ".((int) $this->
id);
5382 $sql .=
" AND entity IN (".getEntity(
'product').
")";
5384 $resql = $this->db->query($sql);
5386 $obj = $this->db->fetch_object($resql);
5403 if (isModEnabled(
'variants')) {
5404 $sql =
"SELECT rowid FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_child = ".((int) $this->
id).
" AND entity IN (".
getEntity(
'product').
")";
5406 $query = $this->db->query($sql);
5409 if (!$this->db->num_rows($query)) {
5430 $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";
5431 $sql .=
", p.tosell as status, p.tobuy as status_buy";
5432 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa,";
5433 $sql .=
" ".$this->db->prefix().
"product as p";
5434 $sql .=
" WHERE p.rowid = pa.fk_product_pere";
5435 $sql .=
" AND pa.fk_product_fils = ".((int) $this->
id);
5437 $res = $this->db->query($sql);
5440 while ($record = $this->db->fetch_array($res)) {
5442 $prods[$record[
'id']][
'id'] = $record[
'rowid'];
5443 $prods[$record[
'id']][
'ref'] = $record[
'ref'];
5444 $prods[$record[
'id']][
'label'] = $record[
'label'];
5445 $prods[$record[
'id']][
'qty'] = $record[
'qty'];
5446 $prods[$record[
'id']][
'incdec'] = $record[
'incdec'];
5447 $prods[$record[
'id']][
'fk_product_type'] = $record[
'fk_product_type'];
5448 $prods[$record[
'id']][
'entity'] = $record[
'entity'];
5449 $prods[$record[
'id']][
'status'] = $record[
'status'];
5450 $prods[$record[
'id']][
'status_buy'] = $record[
'status_buy'];
5469 public function getChildsArbo($id, $firstlevelonly = 0, $level = 1, $parents = array())
5471 global $alreadyfound;
5477 $sql =
"SELECT p.rowid, p.ref, p.label as label, p.fk_product_type,";
5478 $sql .=
" pa.qty as qty, pa.fk_product_fils as id, pa.incdec,";
5479 $sql .=
" pa.rowid as fk_association, pa.rang";
5480 $sql .=
" FROM ".$this->db->prefix().
"product as p,";
5481 $sql .=
" ".$this->db->prefix().
"product_association as pa";
5482 $sql .=
" WHERE p.rowid = pa.fk_product_fils";
5483 $sql .=
" AND pa.fk_product_pere = ".((int) $id);
5484 $sql .=
" AND pa.fk_product_fils <> ".((int) $id);
5485 $sql .=
" ORDER BY pa.rang";
5487 dol_syslog(get_class($this).
'::getChildsArbo id='.$id.
' level='.$level.
' parents='.(is_array($parents) ? implode(
',', $parents) : $parents), LOG_DEBUG);
5490 $alreadyfound = array($id => 1);
5497 $res = $this->db->query($sql);
5500 while ($rec = $this->db->fetch_array($res)) {
5501 if (!empty($alreadyfound[$rec[
'rowid']])) {
5502 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);
5503 if (in_array($rec[
'id'], $parents)) {
5507 $alreadyfound[$rec[
'rowid']] = 1;
5508 $prods[$rec[
'rowid']] = array(
5511 2 => $rec[
'fk_product_type'],
5512 3 => $this->db->escape($rec[
'label']),
5513 4 => $rec[
'incdec'],
5515 6 => $rec[
'fk_association'],
5520 if (empty($firstlevelonly)) {
5521 $parents[] = $rec[
'rowid'];
5522 $listofchilds = $this->
getChildsArbo($rec[
'rowid'], 0, $level + 1, $parents);
5523 foreach ($listofchilds as $keyChild => $valueChild) {
5524 $prods[$rec[
'rowid']][
'childs'][$keyChild] = $valueChild;
5548 foreach ($this->
getChildsArbo($this->
id) as $keyChild => $valueChild) {
5549 $parent[$this->label][$keyChild] = $valueChild;
5551 foreach ($parent as $key => $value) {
5552 $this->sousprods[$key] = $value;
5565 global $conf, $langs, $user;
5567 $langs->loadLangs(array(
'products',
'other'));
5570 $nofetch = !empty($params[
'nofetch']);
5573 return [
'optimize' => $langs->trans(
"ShowProduct")];
5577 $permissiontoreadproduct = 0;
5578 if ($this->
type == self::TYPE_PRODUCT && $user->hasRight(
'product',
'read')) {
5579 $permissiontoreadproduct = 1;
5581 if ($this->
type == self::TYPE_SERVICE && $user->hasRight(
'service',
'read')) {
5582 $permissiontoreadproduct = 1;
5585 if (!empty($this->entity) && $permissiontoreadproduct) {
5586 $tmpphoto = $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 80, 0, 0, 0, 0,
'1');
5587 if ($this->nbphoto > 0) {
5588 $datas[
'photo'] =
'<div class="photointooltip floatright">'.
"\n" . $tmpphoto .
'</div>';
5593 $datas[
'picto'] =
img_picto(
'',
'product').
' <u class="paddingrightonly">'.$langs->trans(
"Product").
'</u>';
5595 $datas[
'picto'] =
img_picto(
'',
'service').
' <u class="paddingrightonly">'.$langs->trans(
"Service").
'</u>';
5597 if (isset($this->
status) && isset($this->status_buy)) {
5598 $datas[
'status'] =
' '.$this->getLibStatut(5, 0) .
' '.$this->getLibStatut(5, 1);
5601 if (!empty($this->
ref)) {
5602 $datas[
'ref'] =
'<br><b>'.$langs->trans(
'ProductRef').
':</b> '.$this->ref;
5604 if (!empty($this->label)) {
5605 $datas[
'label'] =
'<br><b>'.$langs->trans(
'ProductLabel').
':</b> '.$this->label;
5608 if ($permissiontoreadproduct) {
5613 if (isModEnabled(
'productbatch')) {
5614 $langs->load(
"productbatch");
5615 $datas[
'batchstatus'] =
"<br><b>".$langs->trans(
"ManageLotSerial").
'</b>: '.$this->
getLibStatut(0, 2);
5618 if (isModEnabled(
'barcode')) {
5619 $datas[
'barcode'] =
'<br><b>'.$langs->trans(
'BarCode').
':</b> '.$this->barcode;
5623 if ($this->weight) {
5624 $datas[
'weight'] =
"<br><b>".$langs->trans(
"Weight").
'</b>: '.$this->weight.
' '.
measuringUnitString(0,
"weight", $this->weight_units);
5627 if ($this->length) {
5628 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Length").
'</b>: '.$this->length.
' '.
measuringUnitString(0,
'size', $this->length_units);
5631 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Width").
'</b>: '.$this->width.
' '.
measuringUnitString(0,
'size', $this->width_units);
5633 if ($this->height) {
5634 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Height").
'</b>: '.$this->height.
' '.
measuringUnitString(0,
'size', $this->height_units);
5637 $datas[
'size'] =
"<br>".$labelsize;
5640 $labelsurfacevolume =
"";
5641 if ($this->surface) {
5642 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Surface").
'</b>: '.$this->surface.
' '.
measuringUnitString(0,
'surface', $this->surface_units);
5644 if ($this->volume) {
5645 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Volume").
'</b>: '.$this->volume.
' '.
measuringUnitString(0,
'volume', $this->volume_units);
5647 if ($labelsurfacevolume) {
5648 $datas[
'surface'] =
"<br>" . $labelsurfacevolume;
5651 if ($this->
isService() && !empty($this->duration_value)) {
5653 $datas[
'duration'] =
'<br><b>'.$langs->trans(
"Duration").
':</b> '.$this->duration_value;
5654 if ($this->duration_value > 1) {
5655 $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"));
5656 } elseif ($this->duration_value > 0) {
5657 $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"));
5659 $datas[
'duration'] .= (!empty($this->duration_unit) && isset($dur[$this->duration_unit]) ?
" ".$langs->trans($dur[$this->duration_unit]) :
'');
5661 if (empty($user->socid)) {
5662 if (!empty($this->pmp) && $this->pmp) {
5663 $datas[
'pmp'] =
"<br><b>".$langs->trans(
"PMPValue").
'</b>: '.
price($this->pmp, 0,
'', 1, -1, -1, $conf->currency);
5666 if (isModEnabled(
'accounting')) {
5667 if ($this->
status && isset($this->accountancy_code_sell)) {
5668 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5669 $selllabel =
'<br>';
5670 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellCode').
':</b> '.
length_accountg($this->accountancy_code_sell);
5671 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellIntraCode').
':</b> '.
length_accountg($this->accountancy_code_sell_intra);
5672 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellExportCode').
':</b> '.
length_accountg($this->accountancy_code_sell_export);
5673 $datas[
'accountancysell'] = $selllabel;
5675 if ($this->status_buy && isset($this->accountancy_code_buy)) {
5676 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5678 if (empty($this->
status)) {
5679 $buylabel .=
'<br>';
5681 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyCode').
':</b> '.
length_accountg($this->accountancy_code_buy);
5682 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyIntraCode').
':</b> '.
length_accountg($this->accountancy_code_buy_intra);
5683 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyExportCode').
':</b> '.
length_accountg($this->accountancy_code_buy_export);
5684 $datas[
'accountancybuy'] = $buylabel;
5689 if (isModEnabled(
'category') && !$nofetch) {
5690 require_once DOL_DOCUMENT_ROOT .
'/categories/class/categorie.class.php';
5691 $form =
new Form($this->db);
5692 $datas[
'categories'] =
'<br>' . $form->showCategories($this->
id, Categorie::TYPE_PRODUCT, 1);
5712 public function getNomUrl($withpicto = 0, $option =
'', $maxlength = 0, $save_lastsearch_value = -1, $notooltip = 0, $morecss =
'', $add_label = 0, $sep =
' - ')
5714 global $langs, $hookmanager;
5716 include_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
5720 $newref = $this->ref;
5722 $newref =
dol_trunc($newref, $maxlength,
'middle');
5726 'objecttype' => (isset($this->
type) ? ($this->
type == 1 ?
'service' :
'product') : $this->element),
5727 'option' => $option,
5730 $classfortooltip =
'classfortooltip';
5733 $classfortooltip =
'classforajaxtooltip';
5734 $dataparams =
' data-params="'.dol_escape_htmltag(json_encode($params)).
'"';
5741 if (empty($notooltip)) {
5743 $label = $langs->trans(
"ShowProduct");
5744 $linkclose .=
' alt="'.dol_escape_htmltag($label, 1, 1).
'"';
5746 $linkclose .= ($label ?
' title="'.dol_escape_htmltag($label, 1, 1).
'"' :
' title="tocomplete"');
5747 $linkclose .= $dataparams.
' class="nowraponall '.$classfortooltip.($morecss ?
' '.$morecss :
'').
'"';
5749 $linkclose =
' class="nowraponall'.($morecss ?
' '.$morecss :
'').
'"';
5752 if ($option ==
'supplier' || $option ==
'category') {
5753 $url = DOL_URL_ROOT.
'/product/price_suppliers.php?id='.$this->id;
5754 } elseif ($option ==
'stock') {
5755 $url = DOL_URL_ROOT.
'/product/stock/product.php?id='.$this->id;
5756 } elseif ($option ==
'composition') {
5757 $url = DOL_URL_ROOT.
'/product/composition/card.php?id='.$this->id;
5759 $url = DOL_URL_ROOT.
'/product/card.php?id='.$this->id;
5762 if ($option !==
'nolink') {
5764 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
5765 if ($save_lastsearch_value == -1 && isset($_SERVER[
"PHP_SELF"]) && preg_match(
'/list\.php/', $_SERVER[
"PHP_SELF"])) {
5766 $add_save_lastsearch_values = 1;
5768 if ($add_save_lastsearch_values) {
5769 $url .=
'&save_lastsearch_values=1';
5773 $linkstart =
'<a href="'.$url.
'"';
5774 $linkstart .= $linkclose.
'>';
5777 $result .= $linkstart;
5780 $result .= (
img_object(($notooltip ?
'' : $label),
'product',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
5783 $result .= (
img_object(($notooltip ?
'' : $label),
'service',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
5786 $result .=
'<span class="aaa">'.dol_escape_htmltag($newref).
'</span>';
5787 $result .= $linkend;
5788 if ($withpicto != 2) {
5789 $result .= (($add_label && $this->label) ? $sep.dol_trunc($this->label, ($add_label > 1 ? $add_label : 0)) :
'');
5793 $hookmanager->initHooks(array(
'productdao'));
5794 $parameters = array(
'id' => $this->
id,
'getnomurl' => &$result,
'label' => &$label);
5795 $reshook = $hookmanager->executeHooks(
'getNomUrl', $parameters, $this, $action);
5797 $result = $hookmanager->resPrint;
5799 $result .= $hookmanager->resPrint;
5816 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
5820 $langs->load(
"products");
5821 $outputlangs->load(
"products");
5828 $modelpath =
"core/modules/product/doc/";
5830 return $this->
commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
5846 return $this->
LibStatut($this->status_buy, $mode, $type);
5848 return $this->
LibStatut($this->status_batch, $mode, $type);
5851 return $this->
LibStatut($this->status_buy, $mode, $type);
5869 $labelStatus = $labelStatusShort =
'';
5871 $langs->load(
'products');
5872 if (isModEnabled(
'productbatch')) {
5873 $langs->load(
"productbatch");
5879 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial')));
5880 return dolGetStatus($label);
5882 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort')));
5883 return dolGetStatus($label);
5887 return dolGetStatus($langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch'),
'',
'', empty($status) ?
'status5' :
'status4', 3,
'dot');
5893 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'));
5897 $statuttrans = empty($status) ?
'status5' :
'status4';
5902 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSellShort');
5903 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSell');
5904 } elseif ($type == 1) {
5905 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuyShort');
5906 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuy');
5907 } elseif ($type == 2) {
5908 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch');
5909 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort');
5911 } elseif ($status == 1) {
5914 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSellShort');
5915 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSell');
5916 } elseif ($type == 1) {
5917 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBuyShort');
5918 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBuy');
5919 } elseif ($type == 2) {
5920 $labelStatus = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial'));
5921 $labelStatusShort = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort'));
5923 } elseif ($type == 2 && $status == 2) {
5924 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSerial');
5925 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort');
5929 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'),
'',
'',
'status0', 0);
5931 return dolGetStatus($labelStatus, $labelStatusShort,
'', $statuttrans, $mode);
5945 $langs->load(
'products');
5948 if (isset($this->finished) && $this->finished >= 0) {
5949 $sql =
"SELECT label, code FROM ".$this->db->prefix().
"c_product_nature where code = ".((int) $this->finished).
" AND active=1";
5950 $resql = $this->db->query($sql);
5952 $this->error = $this->db->error().
' sql='.$sql;
5953 dol_syslog(__METHOD__.
' Error '.$this->error, LOG_ERR);
5955 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
5956 $label = $langs->trans($res[
'label']);
5958 $this->db->free($resql);
5982 public function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label =
'', $price = 0, $inventorycode =
'', $origin_element =
'', $origin_id =
null, $disablestockchangeforsubproduct = 0, $extrafields =
null)
5988 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
5994 $nbpiece = abs($nbpiece);
5997 $op[0] =
"+".trim((
string) $nbpiece);
5998 $op[1] =
"-".trim((
string) $nbpiece);
6001 $movementstock->setOrigin($origin_element, $origin_id);
6002 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'',
'',
'',
'',
false, 0, $disablestockchangeforsubproduct);
6006 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6007 $movementstock->array_options = $array_options;
6008 $movementstock->insertExtraFields();
6010 $this->db->commit();
6013 $this->error = $movementstock->error;
6014 $this->errors = $movementstock->errors;
6016 $this->db->rollback();
6045 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)
6051 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6057 $nbpiece = abs($nbpiece);
6061 $op[0] =
"+".trim((
string) $nbpiece);
6062 $op[1] =
"-".trim((
string) $nbpiece);
6065 $movementstock->setOrigin($origin_element, $origin_id);
6066 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'', $dlc, $dluo, $lot,
false, 0, $disablestockchangeforsubproduct, 0, $force_update_batch);
6070 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6071 $movementstock->array_options = $array_options;
6072 $movementstock->insertExtraFields();
6074 $this->db->commit();
6077 $this->error = $movementstock->error;
6078 $this->errors = $movementstock->errors;
6080 $this->db->rollback();
6100 public function load_stock($option =
'', $includedraftpoforvirtual =
null, $dateofvirtualstock =
null)
6103 $this->stock_reel = 0;
6104 $this->stock_warehouse = array();
6105 $this->stock_theorique = 0;
6108 $warehouseStatus = array();
6109 if (preg_match(
'/warehouseclosed/', $option)) {
6112 if (preg_match(
'/warehouseopen/', $option)) {
6115 if (preg_match(
'/warehouseinternal/', $option)) {
6123 $sql =
"SELECT ps.rowid, ps.reel, ps.fk_entrepot";
6124 $sql .=
" FROM ".$this->db->prefix().
"product_stock as ps";
6125 $sql .=
", ".$this->db->prefix().
"entrepot as w";
6126 $sql .=
" WHERE w.entity IN (".getEntity(
'stock').
")";
6127 $sql .=
" AND w.rowid = ps.fk_entrepot";
6128 $sql .=
" AND ps.fk_product = ".((int) $this->
id);
6129 if (count($warehouseStatus)) {
6130 $sql .=
" AND w.statut IN (".$this->db->sanitize(implode(
',', $warehouseStatus)).
")";
6133 $sql .=
" ORDER BY ps.reel ".(getDolGlobalString(
'DO_NOT_TRY_TO_DEFRAGMENT_STOCKS_WAREHOUSE') ?
'DESC' :
'ASC');
6135 dol_syslog(get_class($this).
"::load_stock", LOG_DEBUG);
6136 $result = $this->db->query($sql);
6138 $num = $this->db->num_rows($result);
6142 $row = $this->db->fetch_object($result);
6143 $this->stock_warehouse[$row->fk_entrepot] =
new stdClass();
6144 $this->stock_warehouse[$row->fk_entrepot]->real = $row->reel;
6145 $this->stock_warehouse[$row->fk_entrepot]->id = $row->rowid;
6146 if ((!preg_match(
'/nobatch/', $option)) && $this->
hasbatch()) {
6147 $this->stock_warehouse[$row->fk_entrepot]->detail_batch =
Productbatch::findAll($this->db, $row->rowid, 1, $this->id);
6149 $this->stock_reel += $row->reel;
6153 $this->db->free($result);
6155 if (!preg_match(
'/novirtual/', $option)) {
6161 $this->error = $this->db->lasterror();
6180 global $hookmanager, $action;
6182 $stock_commande_client = 0;
6183 $stock_commande_fournisseur = 0;
6184 $stock_sending_client = 0;
6185 $stock_reception_fournisseur = 0;
6186 $stock_inproduction = 0;
6190 if (isModEnabled(
'order')) {
6195 $stock_commande_client = $this->stats_commande[
'qty'];
6197 if (isModEnabled(
"shipping")) {
6198 require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expedition.class.php';
6199 $filterShipmentStatus =
'';
6209 $stock_sending_client = $this->stats_expedition[
'qty'];
6212 if (isModEnabled(
"supplier_order")) {
6213 $filterStatus =
getDolGlobalString(
'SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK',
'3,4');
6214 if (isset($includedraftpoforvirtual)) {
6215 $filterStatus =
'0,1,2,'.$filterStatus;
6221 $stock_commande_fournisseur = $this->stats_commande_fournisseur[
'qty'];
6224 if (isModEnabled(
"supplier_order") || isModEnabled(
"supplier_invoice")) {
6225 $filterStatus =
'4';
6226 if (isset($includedraftpoforvirtual)) {
6227 $filterStatus =
'0,'.$filterStatus;
6233 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
6236 if (isModEnabled(
'mrp')) {
6241 $stock_inproduction = $this->stats_mrptoproduce[
'qty'] - $this->stats_mrptoconsume[
'qty'];
6244 $this->stock_theorique = $this->stock_reel + $stock_inproduction;
6248 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6250 $this->stock_theorique += 0;
6252 $this->stock_theorique -= $stock_commande_client;
6256 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6258 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6260 $this->stock_theorique -= $stock_reception_fournisseur;
6262 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6265 $parameters = array(
'id' => $this->
id,
'includedraftpoforvirtual' => $includedraftpoforvirtual);
6267 $reshook = $hookmanager->executeHooks(
'loadvirtualstock', $parameters, $this, $action);
6269 $this->stock_theorique = $hookmanager->resArray[
'stock_theorique'];
6270 } elseif ($reshook == 0 && isset($hookmanager->resArray[
'stock_stats_hook'])) {
6271 $this->stock_theorique += $hookmanager->resArray[
'stock_stats_hook'];
6275 if (!empty($this->stock_warehouse) &&
getDolGlobalString(
'STOCK_ALLOW_VIRTUAL_STOCK_PER_WAREHOUSE')) {
6276 foreach ($this->stock_warehouse as $warehouseid => $stockwarehouse) {
6277 if (isModEnabled(
'mrp')) {
6284 if ($this->fk_default_warehouse == $warehouseid) {
6285 $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']);
6287 $this->stock_warehouse[$warehouseid]->virtual = $this->stock_warehouse[$warehouseid]->real + $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'];
6307 $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";
6308 $sql .=
" WHERE pb.fk_product_stock = ps.rowid AND ps.fk_product = ".((int) $this->
id).
" AND pb.batch = '".$this->db->escape($batch).
"'";
6309 $sql .=
" GROUP BY pb.batch, pb.eatby, pb.sellby";
6310 dol_syslog(get_class($this).
"::loadBatchInfo load first entry found for lot/serial = ".$batch, LOG_DEBUG);
6311 $resql = $this->db->query($sql);
6313 $num = $this->db->num_rows($resql);
6316 $obj = $this->db->fetch_object($resql);
6317 $result[] = array(
'batch' => $batch,
'eatby' => $this->db->jdate($obj->eatby),
'sellby' => $this->db->jdate($obj->sellby),
'qty' => $obj->qty);
6323 $this->db->rollback();
6340 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6346 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos";
6348 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product').dol_sanitizeFileName($this->
ref);
6353 $dir_osencoded = $dir;
6355 if (is_dir($dir_osencoded)) {
6356 $originImage = $dir.
'/'.$file[
'name'];
6367 if (is_numeric($result) && $result > 0) {
6384 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6385 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6389 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos/";
6391 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product');
6395 if (file_exists($dir_osencoded)) {
6396 $handle = opendir($dir_osencoded);
6397 if (is_resource($handle)) {
6398 while (($file = readdir($handle)) !==
false) {
6400 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6423 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6424 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6430 $handle = @opendir($dir_osencoded);
6431 if (is_resource($handle)) {
6432 while (($file = readdir($handle)) !==
false) {
6434 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6441 $photo_vignette =
'';
6443 if (preg_match(
'/('.$this->regeximgext.
')$/i', $photo, $regs)) {
6444 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $photo).
'_small'.$regs[0];
6447 $dirthumb = $dir.
'thumbs/';
6451 $obj[
'photo'] = $photo;
6452 if ($photo_vignette &&
dol_is_file($dirthumb.$photo_vignette)) {
6453 $obj[
'photo_vignette'] =
'thumbs/'.$photo_vignette;
6455 $obj[
'photo_vignette'] =
"";
6458 $tabobj[$nbphoto - 1] = $obj;
6461 if ($nbmax && $nbphoto >= $nbmax) {
6483 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6484 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6486 $dir = dirname($file).
'/';
6487 $dirthumb = $dir.
'/thumbs/';
6488 $filename = preg_replace(
'/'.preg_quote($dir,
'/').
'/i',
'', $file);
6494 if (preg_match(
'/('.$this->regeximgext.
')$/i', $filename, $regs)) {
6495 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_small'.$regs[0];
6496 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6500 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_mini'.$regs[0];
6501 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6518 $infoImg = getimagesize($file_osencoded);
6519 $this->imgWidth = $infoImg[0];
6520 $this->imgHeight = $infoImg[1];
6530 global $hookmanager;
6532 $this->nb = array();
6534 $sql =
"SELECT count(p.rowid) as nb, fk_product_type";
6535 $sql .=
" FROM ".$this->db->prefix().
"product as p";
6536 $sql .=
' WHERE p.entity IN ('.getEntity($this->element, 1).
')';
6538 if (is_object($hookmanager)) {
6539 $parameters = array();
6540 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
6541 $sql .= $hookmanager->resPrint;
6543 $sql .=
' GROUP BY fk_product_type';
6545 $resql = $this->db->query($sql);
6547 while ($obj = $this->db->fetch_object($resql)) {
6548 if ($obj->fk_product_type == 1) {
6549 $this->nb[
"services"] = $obj->nb;
6551 $this->nb[
"products"] = $obj->nb;
6554 $this->db->free($resql);
6558 $this->error = $this->db->error();
6600 return $this->mandatory_period == 1;
6610 return $this->status_batch > 0;
6630 $dirsociete = array_merge(array(
'/core/modules/barcode/'), $conf->modules_parts[
'barcode']);
6631 foreach ($dirsociete as $dirroot) {
6639 '@phan-var-force ModeleNumRefBarCode $mod';
6641 $result = $mod->getNextValue(
$object, $type);
6643 dol_syslog(get_class($this).
"::get_barcode barcode=".$result.
" module=".$var);
6660 $this->specimen = 1;
6662 $this->
ref =
'PRODUCT_SPEC';
6663 $this->label =
'PRODUCT SPECIMEN';
6664 $this->
description =
'This is description of this product specimen that was created the '.dol_print_date($now,
'dayhourlog').
'.';
6665 $this->specimen = 1;
6666 $this->country_id = 1;
6668 $this->status_buy = 1;
6670 $this->sell_or_eat_by_mandatory = 0;
6671 $this->note_private =
'This is a comment (private)';
6672 $this->note_public =
'This is a comment (public)';
6673 $this->date_creation = $now;
6674 $this->date_modification = $now;
6677 $this->weight_units = 3;
6680 $this->length_units = 1;
6682 $this->width_units = 0;
6683 $this->height =
null;
6684 $this->height_units =
null;
6686 $this->surface = 30;
6687 $this->surface_units = 0;
6688 $this->volume = 300;
6689 $this->volume_units = 0;
6691 $this->barcode = -1;
6706 if (!$this->fk_unit) {
6710 $langs->load(
'products');
6712 $label_type =
'label';
6713 if ($type ==
'short') {
6714 $label_type =
'short_label';
6717 $sql =
"SELECT ".$label_type.
", code from ".$this->db->prefix().
"c_units where rowid = ".((int) $this->fk_unit);
6719 $resql = $this->db->query($sql);
6721 $this->error = $this->db->error();
6722 dol_syslog(get_class($this).
"::getLabelOfUnit Error ".$this->error, LOG_ERR);
6724 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
6725 $label = ($label_type ==
'short_label' ? $res[$label_type] :
'unit'.$res[
'code']);
6727 $this->db->free($resql);
6741 $maxpricesupplier = 0;
6744 include_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.product.class.php';
6746 $product_fourn_list = $product_fourn->list_product_fournisseur_price($this->
id,
'',
'');
6748 if (is_array($product_fourn_list) && count($product_fourn_list) > 0) {
6749 foreach ($product_fourn_list as $productfourn) {
6750 if ($productfourn->fourn_unitprice > $maxpricesupplier) {
6751 $maxpricesupplier = $productfourn->fourn_unitprice;
6759 return $maxpricesupplier;
6775 require_once DOL_DOCUMENT_ROOT.
'/categories/class/categorie.class.php';
6776 return parent::setCategoriesCommon($categories, Categorie::TYPE_PRODUCT);
6790 'product_customer_price',
6791 'product_customer_price_log'
6810 $sql =
"SELECT rowid, level, fk_level, var_percent, var_min_percent FROM ".$this->db->prefix().
"product_pricerules";
6811 $query = $this->db->query($sql);
6815 while ($result = $this->db->fetch_object($query)) {
6816 $rules[$result->level] = $result;
6825 for ($i = 1; $i <= $nbofproducts; $i++) {
6826 $price = $baseprice;
6827 $price_min = $baseprice;
6831 if ($i > 1 && isset($rules[$i]->var_percent) && $rules[$i]->var_percent) {
6832 $price = $prices[$rules[$i]->fk_level] * (1 + ($rules[$i]->var_percent / 100));
6835 $prices[$i] = $price;
6838 if (isset($rules[$i]->var_min_percent) && $rules[$i]->var_min_percent) {
6839 $price_min = $price * (1 - ($rules[$i]->var_min_percent / 100));
6843 $check_amount = (($price == $this->multiprices[$i]) && ($price_min == $this->multiprices_min[$i]));
6844 $check_type = ($baseprice == $this->multiprices_base_type[$i]);
6846 if ($check_amount && $check_type) {
6850 if ($this->
updatePrice($price, $price_type, $user, $price_vat, $price_min, $i, $npr, $psq, 1) < 0) {
6868 return $user->rights->produit;
6870 return $user->rights->service;
6882 $sql =
"SELECT p.rowid, p.ref, p.datec as date_creation, p.tms as date_modification,";
6883 $sql .=
" p.fk_user_author, p.fk_user_modif";
6884 $sql .=
" FROM ".$this->db->prefix().$this->table_element.
" as p";
6885 $sql .=
" WHERE p.rowid = ".((int) $id);
6887 $result = $this->db->query($sql);
6889 if ($this->db->num_rows($result)) {
6890 $obj = $this->db->fetch_object($result);
6892 $this->
id = $obj->rowid;
6893 $this->
ref = $obj->ref;
6895 $this->user_creation_id = $obj->fk_user_author;
6896 $this->user_modification_id = $obj->fk_user_modif;
6898 $this->date_creation = $this->db->jdate($obj->date_creation);
6899 $this->date_modification = $this->db->jdate($obj->date_modification);
6902 $this->db->free($result);
6916 if (empty($this->duration_value)) {
6917 $this->errors[] =
'ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
6921 if ($this->duration_unit ==
'i') {
6922 $prodDurationHours = 1. / 60;
6924 if ($this->duration_unit ==
'h') {
6925 $prodDurationHours = 1.;
6927 if ($this->duration_unit ==
'd') {
6928 $prodDurationHours = 24.;
6930 if ($this->duration_unit ==
'w') {
6931 $prodDurationHours = 24. * 7;
6933 if ($this->duration_unit ==
'm') {
6934 $prodDurationHours = 24. * 30;
6936 if ($this->duration_unit ==
'y') {
6937 $prodDurationHours = 24. * 365;
6939 $prodDurationHours *= $this->duration_value;
6941 return $prodDurationHours;
6954 global $langs, $conf;
6956 $selected = (empty($arraydata[
'selected']) ? 0 : $arraydata[
'selected']);
6958 $return =
'<div class="box-flex-item box-flex-grow-zero">';
6959 $return .=
'<div class="info-box info-box-sm">';
6960 $return .=
'<div class="info-box-img">';
6963 $label .= $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 120, 160, 0, 0, 0,
'',
'photoref photokanban');
6973 $return .=
'</div>';
6974 $return .=
'<div class="info-box-content">';
6975 $return .=
'<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this,
'getNomUrl') ? $this->
getNomUrl() : $this->ref).
'</span>';
6976 if ($selected >= 0) {
6977 $return .=
'<input id="cb'.$this->id.
'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->
id.
'"'.($selected ?
' checked="checked"' :
'').
'>';
6979 if (property_exists($this,
'label')) {
6980 $return .=
'<br><span class="info-box-label opacitymedium inline-block tdoverflowmax150 valignmiddle" title="'.dol_escape_htmltag($this->label).
'">'.
dol_escape_htmltag($this->label).
'</span>';
6982 if (property_exists($this,
'price') && property_exists($this,
'price_ttc')) {
6983 if ($this->price_base_type ==
'TTC') {
6984 $return .=
'<br><span class="info-box-status amount">'.price($this->price_ttc).
' '.$langs->trans(
"TTC").
'</span>';
6987 $return .=
'<br><span class="info-box-status amount">'.price($this->
price).
' '.$langs->trans(
"HT").
'</span>';
6992 if (property_exists($this,
'stock_reel') && $this->
isProduct()) {
6993 $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>';
6996 if (method_exists($this,
'getLibStatut')) {
6998 $return .=
'<br><div class="info-box-status inline-block valignmiddle">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7000 $return .=
'<div class="info-box-status inline-block valignmiddle marginleftonly paddingleft">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7003 $return .=
'</div>';
7004 $return .=
'</div>';
7005 $return .=
'</div>';
7018 if (!is_numeric($limit)) {
7022 $sql =
"SELECT p.rowid, p.ref, p.label, p.description, p.entity, ef.filename
7023 FROM ".MAIN_DB_PREFIX.
"product AS p
7024 JOIN ".MAIN_DB_PREFIX.
"ecm_files AS ef ON p.rowid = ef.src_object_id
7025 WHERE ef.entity IN (".
getEntity(
'product').
")
7026 AND (ef.filename LIKE '%.png' OR ef.filename LIKE '%.jpeg' OR ef.filename LIKE '%.svg')
7027 GROUP BY p.rowid, p.ref, p.label, p.description, p.entity, ef.filename
7028 ORDER BY p.datec ASC
7029 LIMIT " . ((int) $limit);
7031 $resql = $this->db->query($sql);
7032 $products = array();
7035 while ($obj = $this->db->fetch_object($resql)) {
7036 $products[] = array(
7037 'rowid' => $obj->rowid,
7039 'label' => $obj->label,
7040 'description' => $obj->description,
7041 'entity' => $obj->entity,
7042 'filename' => $obj->filename
7048 if (empty($products)) {
7061 public $picto =
'service';
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
length_accountg($account)
Return General accounting account with defined length (used for product and miscellaneous)
print $langs trans("AuditedSecurityEvents").'</strong >< span class="opacitymedium"></span >< br > status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Parent class of all other business classes (invoices, contracts, proposals, orders,...
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
deleteEcmFiles($mode=0)
Delete related files of object in database.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
isObjectUsed($id=0, $entity=0)
Function to check if an object is used by others (by children).
deleteExtraFields()
Delete all extra fields values for the current object.
addThumbs($file)
Build thumb.
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
show_photos($modulepart, $sdir, $size=0, $nbmax=0, $nbbyrow=5, $showfilename=0, $showaction=0, $maxHeight=120, $maxWidth=160, $nolink=0, $overwritetitle=0, $usesharelink=0, $cache='', $addphotorefcss='photoref')
Show photos of an object (nbmax maximum), into several columns.
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
call_trigger($triggerName, $user)
Call trigger based on this instance.
Class to manage Dolibarr database access.
Class to manage ECM files.
const STATUS_OPEN_INTERNAL
Warehouse open and only operations for stock transfers/corrections allowed (not for customer shipping...
const STATUS_OPEN_ALL
Warehouse open and any operations are allowed (customer shipping, supplier dispatch,...
const STATUS_CLOSED
Warehouse closed, inactive.
const STATUS_CLOSED
Closed status -> parcel was received by customer / end of process prev status : validated or shipment...
const STATUS_VALIDATED
Validated status -> parcel is ready to be sent prev status : draft next status : closed or shipment_i...
const STATUS_DRAFT
Draft status.
Class to manage stock movements.
Class to parse product price expressions.
Class ProductCombination Used to represent the relation between a product and one of its variants.
File of class to manage predefined price products or services by customer.
Class to manage predefined suppliers products.
Class to manage products or services.
static replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
get_nb_achat($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units or supplier invoices in which product is included.
getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp=0)
Return price of sell of a product for a seller/buyer/product.
__construct($db)
Constructor.
is_sousproduit($fk_parent, $fk_child)
Check if it is a sub-product into a kit.
const SELL_OR_EAT_BY_MANDATORY_ID_NONE
Const sell or eat by mandatory id.
isStockManaged()
Return if the object is managed in stock.
setPriceExpression($expression_id)
Sets the supplier price expression.
getArrayForPriceCompare($level=0)
used to check if price have really change to avoid log pollution
get_arbo_each_prod($multiply=1, $ignore_stock_load=0)
Build the tree of subproducts and return it.
check_barcode($valuetotest, $typefortest)
Check barcode.
list_suppliers()
Return list of suppliers providing the product or service.
load_stats_mo($socid=0)
Charge tableau des stats OF pour le produit/service.
isVariant()
Return if loaded product is a variant.
updatePrice($newprice, $newpricebase, $user, $newvat=null, $newminprice=0, $level=0, $newnpr=0, $newpbq=0, $ignore_autogen=0, $localtaxes_array=array(), $newdefaultvatcode='', $price_label='', $notrigger=0)
Modify customer price of a product/Service for a given level.
hasVariants()
Return if a product has variants or not.
delMultiLangs($langtodelete, $user)
Delete a language for this product.
getLabelOfUnit($type='long')
Returns the text label from units dictionary.
load_stats_proposal_supplier($socid=0)
Charge tableau des stats propale pour le produit/service.
getLibFinished()
Retour label of nature of product.
add_sousproduit($id_pere, $id_fils, $qty, $incdec=1, $notrigger=0)
Link a product/service to a parent product/service.
add_fournisseur($user, $id_fourn, $ref_fourn, $quantity)
Add a supplier price for the product.
hasFatherOrChild($mode=0)
Count all parent and children products for current product (first level only)
load_stats_facturerec($socid=0)
Charge tableau des stats facture recurrentes pour le produit/service.
get_nb_propalsupplier($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in proposals in which product is included.
get_nb_contract($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
load_stats_facture_fournisseur($socid=0)
Charge tableau des stats facture pour le produit/service.
get_nb_ordersupplier($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
getMultiLangs()
Load array this->multilangs.
get_nb_mos($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
clone_associations($fromId, $toId)
Clone links between products.
create($user, $notrigger=0)
Insert product into database.
load_stats_contrat($socid=0)
Charge tableau des stats contrat pour le produit/service.
isService()
Return if the object is a service.
getRights()
Returns the rights used for this class.
loadBatchInfo($batch)
Load existing information about a serial.
load_stock($option='', $includedraftpoforvirtual=null, $dateofvirtualstock=null)
Load information about stock of a product into ->stock_reel, ->stock_warehouse[] (including stock_war...
getProductDurationHours()
Return the duration of a service in hours (for a service based on duration fields)
get_buyprice($prodfournprice, $qty, $product_id=0, $fourn_ref='', $fk_soc=0)
Read price used by a provider.
clone_fournisseurs($fromId, $toId)
Recopie les fournisseurs et prix fournisseurs d'un produit/service sur un autre.
const TYPE_PRODUCT
Regular product.
$stock_warehouse
Contains detail of stock of product into each warehouse.
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 sell or eat by mandatory list.
getChildsArbo($id, $firstlevelonly=0, $level=1, $parents=array())
Return children of product $id.
load_virtual_stock($includedraftpoforvirtual=null, $dateofvirtualstock=null)
Load value ->stock_theorique of a product.
load_stats_propale($socid=0)
Charge tableau des stats propale pour le produit/service.
get_barcode($object, $type='')
Get a barcode from the module to generate barcode values.
setAccountancyCode($type, $value)
Sets an accountancy code for a product.
getProductsToPreviewInEmail($limit)
Retrieve and display products.
load_stats_facture($socid=0)
Charge tableau des stats facture pour le produit/service.
setCategories($categories)
Sets object to supplied categories.
load_stats_reception($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null)
Charge tableau des stats réception fournisseur pour le produit/service.
get_nb_propal($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in proposals in which product is included.
update($id, $user, $notrigger=0, $action='update', $updatetype=false)
Update a record into database.
setMultiLangs($user)
Update or add a translation for a product.
correct_stock_batch($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $dlc='', $dluo='', $lot='', $inventorycode='', $origin_element='', $origin_id=null, $disablestockchangeforsubproduct=0, $extrafields=null, $force_update_batch=false)
Adjust stock in a warehouse for product with batch number.
load_stats_bom($socid=0)
Charge tableau des stats OF pour le produit/service.
hasbatch()
Return if the object has a sell-by or eat-by date.
del_sousproduit($fk_parent, $fk_child, $notrigger=0)
Remove a link between a subproduct and a parent product/service.
fetch($id=0, $ref='', $ref_ext='', $barcode='', $ignore_expression=0, $ignore_price_load=0, $ignore_lang_load=0)
Load a product in memory from database.
update_sousproduit($id_pere, $id_fils, $qty, $incdec=1, $notrigger=0)
Modify composed product.
load_stats_commande($socid=0, $filtrestatut='', $forVirtualStock=0)
Charge tableau des stats commande client pour le produit/service.
delete_photo($file)
Delete a photo and its thumbs.
fetch_prod_arbo($prod, $compl_path='', $multiply=1, $level=1, $id_parent=0, $ignore_stock_load=0)
Function recursive, used only by get_arbo_each_prod(), to build tree of subproducts into ->res Define...
getKanbanView($option='', $arraydata=null)
Return clickable link of object (with eventually picto)
getLibStatut($mode=0, $type=0)
Return label of status of object.
load_stats_sending($socid=0, $filtrestatut='', $forVirtualStock=0, $filterShipmentStatus='')
Charge tableau des stats expedition client pour le produit/service.
clone_price($fromId, $toId)
Recopie les prix d'un produit/service sur un autre.
load_stats_inproduction($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null, $warehouseid=0)
Charge tableau des stats production pour le produit/service.
check()
Check that ref and label are ok.
initAsSpecimen()
Initialise an instance with random values.
liste_photos($dir, $nbmax=0)
Return an array with all photos of product found on disk.
loadStateBoard()
Load indicators this->nb for the dashboard.
getFather()
Return all parent products for current product (first level only)
getNomUrl($withpicto=0, $option='', $maxlength=0, $save_lastsearch_value=-1, $notooltip=0, $morecss='', $add_label=0, $sep=' - ')
Return clickable link of object (with eventually picto)
getSellOrEatByMandatoryLabel()
Get sell or eat by mandatory label.
verify()
Check properties of product are ok (like name, barcode, ...).
get_nb_order($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
min_recommended_price()
Return minimum product recommended price.
_log_price($user, $level=0)
Insert a track that we changed a customer price.
_get_stats($sql, $mode, $year=0)
Return an array formatted for showing graphs.
load_stats_commande_fournisseur($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null)
Charge tableau des stats commande fournisseur pour le produit/service.
isMandatoryPeriod()
Return if the object has a constraint on mandatory_period.
isProduct()
Return if the object is a product.
generateMultiprices(User $user, $baseprice, $price_type, $price_vat, $npr, $psq)
Generates prices for a product based on product multiprice generation rules.
LibStatut($status, $mode=0, $type=0)
Return label of a given status.
const TYPE_SERVICE
Service.
is_photo_available($sdir)
Return if at least one photo is available.
get_image_size($file)
Load size of image file.
get_nb_vente($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units or customers invoices in which product is included.
getTooltipContentArray($params)
getTooltipContentArray
Class to manage products or services.
Manage record for batch number management.
static findAll($dbs, $fk_product_stock, $with_qty=0, $fk_product=0)
Return all batch detail records for a given product and warehouse.
Class with list of lots and properties.
Class to manage Dolibarr users.
hasRight($module, $permlevel1, $permlevel2='')
Return if a user has a permission.
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_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $nohook=0, $varfiles='addedfile', $upload_dir='')
Check validity of a file upload from an GUI page, and move it to its final destination.
dol_is_file($pathoffile)
Return if path is a file.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
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.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
dol_clone($object, $native=0)
Create a clone of instance of object (new instance with same value for each properties) With native =...
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)
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
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.
utf8_check($str)
Check if a string is in UTF8.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_localtax($vatrate, $local, $thirdparty_buyer=null, $thirdparty_seller=null, $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate,...
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
measuringUnitString($unit, $measuring_style='', $scale='', $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
measuring_units_squared($unit)
Transform a given unit scale into the square of that unit, if known.
measuring_units_cubed($unit)
Transform a given unit scale into the cube of that unit, if known.
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type