44require_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
45require_once DOL_DOCUMENT_ROOT.
'/core/class/commonobject.class.php';
46require_once DOL_DOCUMENT_ROOT.
'/product/class/productbatch.class.php';
47require_once DOL_DOCUMENT_ROOT.
'/product/class/productlang.class.php';
48require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/productlot.class.php';
49require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/entrepot.class.php';
60 const SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY = 1;
61 const SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY = 2;
62 const SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT = 3;
68 public $TRIGGER_PREFIX =
'PRODUCT';
73 public $element =
'product';
78 public $table_element =
'product';
83 public $fk_element =
'fk_product';
88 protected $childtables = array(
89 'supplier_proposaldet' => array(
'name' =>
'SupplierProposal',
'parent' =>
'supplier_proposal',
'parentkey' =>
'fk_supplier_proposal'),
90 'propaldet' => array(
'name' =>
'Proposal',
'parent' =>
'propal',
'parentkey' =>
'fk_propal'),
91 'commandedet' => array(
'name' =>
'Order',
'parent' =>
'commande',
'parentkey' =>
'fk_commande'),
92 'facturedet' => array(
'name' =>
'Invoice',
'parent' =>
'facture',
'parentkey' =>
'fk_facture'),
93 'contratdet' => array(
'name' =>
'Contract',
'parent' =>
'contrat',
'parentkey' =>
'fk_contrat'),
94 'facture_fourn_det' => array(
'name' =>
'SupplierInvoice',
'parent' =>
'facture_fourn',
'parentkey' =>
'fk_facture_fourn'),
95 'commande_fournisseurdet' => array(
'name' =>
'SupplierOrder',
'parent' =>
'commande_fournisseur',
'parentkey' =>
'fk_commande'),
96 'mrp_production' => array(
'name' =>
'Mo',
'parent' =>
'mrp_mo',
'parentkey' =>
'fk_mo',
'enabled' =>
'isModEnabled("mrp")'),
97 'bom_bom' => array(
'name' =>
'BOM',
'enabled' =>
'isModEnabled("bom")'),
98 'bom_bomline' => array(
'name' =>
'BOMLine',
'parent' =>
'bom_bom',
'parentkey' =>
'fk_bom',
'enabled' =>
'isModEnabled("bom")'),
106 public $picto =
'product';
117 public $regeximgext =
'\.gif|\.jpg|\.jpeg|\.png|\.bmp|\.webp|\.xpm|\.xbm|\.avif';
171 public $price_formated;
183 public $price_ttc_formated;
197 public $price_min_ttc;
203 public $price_base_type;
213 public $multiprices = array();
217 public $multiprices_ttc = array();
221 public $multiprices_base_type = array();
225 public $multiprices_default_vat_code = array();
229 public $multiprices_min = array();
233 public $multiprices_min_ttc = array();
237 public $multiprices_tva_tx = array();
241 public $multiprices_recuperableonly = array();
247 public $price_by_qty;
251 public $prices_by_qty = array();
255 public $prices_by_qty_id = array();
259 public $prices_by_qty_list = array();
269 public $multilangs = array();
274 public $default_vat_code;
289 public $remise_percent;
294 public $localtax1_tx;
298 public $localtax2_tx;
302 public $localtax1_type;
306 public $localtax2_type;
313 public $desc_supplier;
317 public $vatrate_supplier;
321 public $default_vat_code_supplier;
326 public $fourn_multicurrency_price;
331 public $fourn_multicurrency_unitprice;
335 public $fourn_multicurrency_tx;
339 public $fourn_multicurrency_id;
343 public $fourn_multicurrency_code;
365 public $qc_frequency;
372 public $stock_reel = 0;
379 public $stock_theorique;
400 public $seuil_stock_alerte = 0;
405 public $desiredstock = 0;
410 public $duration_value;
414 public $duration_unit;
423 public $fk_default_workstation;
445 public $status_buy = 0;
467 public $fk_default_bom;
474 public $product_fourn_price_id;
496 public $status_batch = 0;
503 public $sell_or_eat_by_mandatory = 0;
510 public $batch_mask =
'';
535 public $weight_units;
543 public $length_units;
559 public $height_units;
567 public $surface_units;
575 public $volume_units;
584 public $net_measure_units;
589 public $accountancy_code_sell;
593 public $accountancy_code_sell_intra;
597 public $accountancy_code_sell_export;
601 public $accountancy_code_buy;
605 public $accountancy_code_buy_intra;
609 public $accountancy_code_buy_export;
619 public $barcode_type;
624 public $barcode_type_code;
629 public $stats_propale = array();
634 public $stats_commande = array();
639 public $stats_contrat = array();
644 public $stats_facture = array();
649 public $stats_proposal_supplier = array();
654 public $stats_commande_fournisseur = array();
659 public $stats_expedition = array();
664 public $stats_reception = array();
669 public $stats_mo = array();
674 public $stats_bom = array();
679 public $stats_mrptoconsume = array();
684 public $stats_mrptoproduce = array();
689 public $stats_facturerec = array();
694 public $stats_facture_fournisseur = array();
699 public $stats_facturefournrec = array();
714 public $product_fourn_id;
720 public $product_id_already_linked;
731 public $stock_warehouse = array();
736 public $fk_default_warehouse;
741 public $fk_price_expression;
759 public $fourn_price_base_type;
776 public $ref_supplier;
790 public $price_autogen = 0;
797 public $sousprods = array();
810 public $is_object_used;
821 public $is_sousproduit_qty;
833 public $is_sousproduit_incdec;
838 public $mandatory_period;
845 public $stockable_product = 1;
875 public $fields = array(
876 'rowid' => array(
'type' =>
'integer',
'label' =>
'TechnicalID',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'index' => 1,
'position' => 1,
'comment' =>
'Id'),
877 'entity' => array(
'type' =>
'integer',
'label' =>
'Entity',
'enabled' => 1,
'visible' => 0,
'default' =>
'1',
'notnull' => 1,
'index' => 1,
'position' => 5),
878 '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'),
879 'label' => array(
'type' =>
'varchar(255)',
'label' =>
'Label',
'enabled' => 1,
'visible' => 1,
'notnull' => 1,
'showoncombobox' => 2,
'position' => 11,
'csslist' =>
'tdoverflowmax250'),
880 'barcode' => array(
'type' =>
'varchar(255)',
'label' =>
'Barcode',
'enabled' =>
'isModEnabled("barcode")',
'position' => 20,
'visible' => -1,
'showoncombobox' => 3,
'cssview' =>
'tdwordbreak',
'csslist' =>
'tdoverflowmax125'),
881 'fk_barcode_type' => array(
'type' =>
'integer',
'label' =>
'BarcodeType',
'enabled' => 1,
'position' => 21,
'notnull' => 0,
'visible' => -1,),
882 'note_public' => array(
'type' =>
'html',
'label' =>
'NotePublic',
'enabled' => 1,
'visible' => 0,
'position' => 61),
883 'note' => array(
'type' =>
'html',
'label' =>
'NotePrivate',
'enabled' => 1,
'visible' => 0,
'position' => 62),
884 'datec' => array(
'type' =>
'datetime',
'label' =>
'DateCreation',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 500),
885 'tms' => array(
'type' =>
'timestamp',
'label' =>
'DateModification',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 501),
887 'fk_user_author' => array(
'type' =>
'integer:User:user/class/user.class.php',
'label' =>
'UserAuthor',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 510,
'foreignkey' =>
'llx_user.rowid'),
888 'fk_user_modif' => array(
'type' =>
'integer:User:user/class/user.class.php',
'label' =>
'UserModif',
'enabled' => 1,
'visible' => -2,
'notnull' => -1,
'position' => 511),
890 'localtax1_tx' => array(
'type' =>
'double(6,3)',
'label' =>
'Localtax1tx',
'enabled' => 1,
'position' => 150,
'notnull' => 0,
'visible' => -1,),
891 'localtax1_type' => array(
'type' =>
'varchar(10)',
'label' =>
'Localtax1type',
'enabled' => 1,
'position' => 155,
'notnull' => 1,
'visible' => -1,),
892 'localtax2_tx' => array(
'type' =>
'double(6,3)',
'label' =>
'Localtax2tx',
'enabled' => 1,
'position' => 160,
'notnull' => 0,
'visible' => -1,),
893 'localtax2_type' => array(
'type' =>
'varchar(10)',
'label' =>
'Localtax2type',
'enabled' => 1,
'position' => 165,
'notnull' => 1,
'visible' => -1,),
894 'last_main_doc' => array(
'type' =>
'varchar(255)',
'label' =>
'LastMainDoc',
'enabled' => 1,
'visible' => -1,
'position' => 170),
895 'import_key' => array(
'type' =>
'varchar(14)',
'label' =>
'ImportId',
'enabled' => 1,
'visible' => -2,
'notnull' => -1,
'index' => 0,
'position' => 1000),
898 'mandatory_period' => array(
'type' =>
'integer',
'label' =>
'mandatoryperiod',
'enabled' => 1,
'visible' => -1,
'notnull' => 1,
'default' =>
'0',
'index' => 1,
'position' => 1000),
899 'stockable_product' => array(
'type' =>
'integer',
'label' =>
'stockable_product',
'enabled' => 1,
'visible' => 1,
'default' =>
'1',
'notnull' => 1,
'index' => 1,
'position' => 502),
915 const ENABLED_STOCK = 1;
926 $this->ismultientitymanaged = 1;
927 $this->isextrafieldmanaged = 1;
940 $this->
ref = trim((
string) $this->
ref);
950 if (
dol_strlen(trim((
string) $this->label)) == 0) {
968 public function create($user, $notrigger = 0)
970 global
$conf, $langs;
976 $this->
ref = trim((
string) $this->
ref);
980 $this->label = trim((
string) $this->label);
981 $this->price_ttc = (float)
price2num($this->price_ttc);
983 $this->price_min_ttc = (float)
price2num($this->price_min_ttc);
984 $this->price_min = (float)
price2num($this->price_min);
985 $this->price_label = trim((
string) $this->price_label);
986 if (empty($this->tva_tx)) {
989 if (empty($this->tva_npr)) {
993 if (empty($this->localtax1_tx)) {
994 $this->localtax1_tx = 0;
996 if (empty($this->localtax2_tx)) {
997 $this->localtax2_tx = 0;
999 if (empty($this->localtax1_type)) {
1000 $this->localtax1_type =
'0';
1002 if (empty($this->localtax2_type)) {
1003 $this->localtax2_type =
'0';
1006 if (empty($this->price_base_type) &&
getDolGlobalString(
'PRODUCT_PRICE_BASE_TYPE')) {
1009 if (empty($this->
price)) {
1012 if (empty($this->price_min)) {
1013 $this->price_min = 0;
1016 if (empty($this->price_by_qty)) {
1017 $this->price_by_qty = 0;
1020 if (empty($this->
status)) {
1023 if (empty($this->status_buy)) {
1024 $this->status_buy = 0;
1026 if (empty($this->stockable_product)) {
1027 $this->stockable_product = 0;
1036 if ($this->price_base_type ==
'TTC' && $this->price_ttc > 0) {
1037 $price_ttc =
price2num($this->price_ttc,
'MU');
1038 $price_ht =
price2num($this->price_ttc / (1 + ($this->tva_tx / 100)),
'MU');
1042 if ($this->price_base_type !=
'TTC' && $this->
price > 0) {
1044 $price_ttc =
price2num($this->
price * (1 + ($this->tva_tx / 100)),
'MU');
1048 if (($this->price_min_ttc > 0) && ($this->price_base_type ==
'TTC')) {
1049 $price_min_ttc =
price2num($this->price_min_ttc,
'MU');
1050 $price_min_ht =
price2num($this->price_min_ttc / (1 + ($this->tva_tx / 100)),
'MU');
1054 if (($this->price_min > 0) && ($this->price_base_type !=
'TTC')) {
1055 $price_min_ht =
price2num($this->price_min,
'MU');
1056 $price_min_ttc =
price2num($this->price_min * (1 + ($this->tva_tx / 100)),
'MU');
1059 $this->accountancy_code_buy = trim((
string) $this->accountancy_code_buy);
1060 $this->accountancy_code_buy_intra = trim((
string) $this->accountancy_code_buy_intra);
1061 $this->accountancy_code_buy_export = trim((
string) $this->accountancy_code_buy_export);
1062 $this->accountancy_code_sell = trim((
string) $this->accountancy_code_sell);
1063 $this->accountancy_code_sell_intra = trim((
string) $this->accountancy_code_sell_intra);
1064 $this->accountancy_code_sell_export = trim((
string) $this->accountancy_code_sell_export);
1070 require_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
1071 $this->accountancy_code_buy =
clean_account($this->accountancy_code_buy);
1072 $this->accountancy_code_buy_intra =
clean_account($this->accountancy_code_buy_intra);
1073 $this->accountancy_code_buy_export =
clean_account($this->accountancy_code_buy_export);
1074 $this->accountancy_code_sell =
clean_account($this->accountancy_code_sell);
1075 $this->accountancy_code_sell_intra =
clean_account($this->accountancy_code_sell_intra);
1076 $this->accountancy_code_sell_export =
clean_account($this->accountancy_code_sell_export);
1080 $this->barcode = trim((
string) $this->barcode);
1081 $this->mandatory_period = empty($this->mandatory_period) ? 0 : $this->mandatory_period;
1083 if (empty($this->label)) {
1084 $langs->load(
'errors');
1085 $this->errors[] = $langs->trans(
'ErrorMandatoryParametersNotProvided');
1089 if (empty($this->
ref) || $this->
ref ==
'auto') {
1091 $module =
getDolGlobalString(
'PRODUCT_CODEPRODUCT_ADDON',
'mod_codeproduct_leopard');
1092 if ($module !=
'mod_codeproduct_leopard') {
1093 if (substr($module, 0, 16) ==
'mod_codeproduct_' && substr($module, -3) ==
'php') {
1094 $module = substr($module, 0,
dol_strlen($module) - 4);
1097 $modCodeProduct =
new $module();
1098 '@phan-var-force ModeleProductCode $modCodeProduct';
1099 if (!empty($modCodeProduct->code_auto)) {
1100 $this->
ref = $modCodeProduct->getNextValue($this, $this->
type);
1102 unset($modCodeProduct);
1105 if (empty($this->
ref)) {
1106 $this->error =
'ProductModuleNotSetupForAutoRef';
1111 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);
1115 if (empty($this->date_creation)) {
1116 $this->date_creation = $now;
1122 if ($this->barcode ==
'-1' || $this->barcode ==
'auto') {
1123 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1128 $result = $this->
verify();
1131 $sql =
"SELECT count(*) as nb";
1132 $sql .=
" FROM ".$this->db->prefix().
"product";
1133 $sql .=
" WHERE entity IN (".getEntity(
'product').
")";
1134 $sql .=
" AND ref = '".$this->db->escape($this->
ref).
"'";
1136 $result = $this->db->query($sql);
1138 $obj = $this->db->fetch_object($result);
1139 if ($obj->nb == 0) {
1141 $sql =
"INSERT INTO ".$this->db->prefix().
"product (";
1145 $sql .=
", ref_ext";
1146 $sql .=
", price_min";
1147 $sql .=
", price_min_ttc";
1149 $sql .=
", fk_user_author";
1150 $sql .=
", fk_product_type";
1152 $sql .=
", price_ttc";
1153 $sql .=
", price_base_type";
1154 $sql .=
", price_label";
1158 $sql .=
", accountancy_code_buy";
1159 $sql .=
", accountancy_code_buy_intra";
1160 $sql .=
", accountancy_code_buy_export";
1161 $sql .=
", accountancy_code_sell";
1162 $sql .=
", accountancy_code_sell_intra";
1163 $sql .=
", accountancy_code_sell_export";
1166 $sql .=
", finished";
1167 $sql .=
", tobatch";
1168 $sql .=
", sell_or_eat_by_mandatory";
1169 $sql .=
", batch_mask";
1170 $sql .=
", fk_unit";
1171 $sql .=
", mandatory_period";
1172 $sql .=
", stockable_product";
1173 if (!empty($this->default_vat_code)) {
1174 $sql .=
", default_vat_code";
1176 $sql .=
") VALUES (";
1177 $sql .=
"'".$this->db->idate($this->date_creation).
"'";
1178 $sql .=
", ".(!empty($this->entity) ? (int) $this->entity : (int)
$conf->entity);
1179 $sql .=
", '".$this->db->escape($this->
ref).
"'";
1180 $sql .=
", ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1181 $sql .=
", ".price2num($price_min_ht);
1182 $sql .=
", ".price2num($price_min_ttc);
1183 $sql .=
", ".(!empty($this->label) ?
"'".$this->db->escape($this->label).
"'" :
"null");
1184 $sql .=
", ".((int) $user->id);
1185 $sql .=
", ".((int) $this->
type);
1186 $sql .=
", ".price2num($price_ht,
'MT');
1187 $sql .=
", ".price2num($price_ttc,
'MT');
1188 $sql .=
", '".$this->db->escape($this->price_base_type).
"'";
1189 $sql .=
", ".(!empty($this->price_label) ?
"'".$this->db->escape($this->price_label).
"'" :
"null");
1190 $sql .=
", ".((int) $this->
status);
1191 $sql .=
", ".((int) $this->status_buy);
1193 $sql .=
", '".$this->db->escape($this->accountancy_code_buy).
"'";
1194 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_intra).
"'";
1195 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_export).
"'";
1196 $sql .=
", '".$this->db->escape($this->accountancy_code_sell).
"'";
1197 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_intra).
"'";
1198 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_export).
"'";
1200 $sql .=
", '".$this->db->escape($this->canvas).
"'";
1201 $sql .=
", ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
'NULL' : (int) $this->finished);
1202 $sql .=
", ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : ((int) $this->status_batch));
1203 $sql .=
", ".((empty($this->sell_or_eat_by_mandatory) || $this->sell_or_eat_by_mandatory < 0) ? 0 : ((int) $this->sell_or_eat_by_mandatory));
1204 $sql .=
", '".$this->db->escape($this->batch_mask).
"'";
1205 $sql .=
", ".($this->fk_unit > 0 ? ((int) $this->fk_unit) :
'NULL');
1206 $sql .=
", '".$this->db->escape((
string) $this->mandatory_period).
"'";
1207 $sql .=
", ".((int) $this->stockable_product);
1208 if (!empty($this->default_vat_code)) {
1209 $sql .=
", '".$this->db->escape($this->default_vat_code).
"'";
1212 dol_syslog(get_class($this).
"::Create", LOG_DEBUG);
1214 $result = $this->db->query($sql);
1216 $id = $this->db->last_insert_id($this->db->prefix().
"product");
1220 $this->
price = $price_ht;
1221 $this->price_ttc = $price_ttc;
1222 $this->price_min = $price_min_ht;
1223 $this->price_min_ttc = $price_min_ttc;
1227 if ($this->
update($id, $user, 1,
'add') <= 0) {
1232 $this->error = $this->db->lasterror();
1237 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " .((int) $this->id) .
" AND entity = " . ((
int)
$conf->entity));
1239 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1240 $sql .=
" fk_product";
1242 $sql .=
", accountancy_code_buy";
1243 $sql .=
", accountancy_code_buy_intra";
1244 $sql .=
", accountancy_code_buy_export";
1245 $sql .=
", accountancy_code_sell";
1246 $sql .=
", accountancy_code_sell_intra";
1247 $sql .=
", accountancy_code_sell_export";
1248 $sql .=
") VALUES (";
1249 $sql .= ((int) $this->
id);
1250 $sql .=
", " . ((int)
$conf->entity);
1251 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1252 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1253 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1254 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1255 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1256 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1258 $result = $this->db->query($sql);
1261 $this->error =
'ErrorFailedToInsertAccountancyForEntity';
1266 $this->error =
'ErrorFailedToGetInsertedId';
1270 $this->error = $this->db->lasterror();
1274 $langs->load(
"products");
1276 $this->error =
"ErrorProductAlreadyExists";
1277 dol_syslog(get_class($this).
"::Create fails, ref ".$this->
ref.
" already exists");
1281 $this->error = $this->db->lasterror();
1284 if (!$error && !$notrigger) {
1286 $result = $this->call_trigger(
'PRODUCT_CREATE', $user);
1294 $this->db->commit();
1297 $this->db->rollback();
1301 $this->db->rollback();
1302 dol_syslog(get_class($this).
"::Create fails verify ".implode(
',', $this->errors), LOG_WARNING);
1318 $this->errors = array();
1321 $this->
ref = trim((
string) $this->
ref);
1324 $this->errors[] =
'ErrorBadRef';
1328 $arrayofnonnegativevalue = array(
'weight' =>
'Weight',
'width' =>
'Width',
'height' =>
'Height',
'length' =>
'Length',
'surface' =>
'Surface',
'volume' =>
'Volume');
1329 foreach ($arrayofnonnegativevalue as $key => $value) {
1330 if (property_exists($this, $key) && !empty($this->$key) && ($this->$key < 0)) {
1331 $langs->loadLangs(array(
"main",
"other"));
1332 $this->error = $langs->trans(
"FieldCannotBeNegative", $langs->transnoentitiesnoconv($value));
1333 $this->errors[] = $this->error;
1338 $rescode = $this->check_barcode($this->barcode, $this->barcode_type_code);
1340 if ($rescode == -1) {
1341 $this->errors[] =
'ErrorBadBarCodeSyntax';
1342 } elseif ($rescode == -2) {
1343 $this->errors[] =
'ErrorBarCodeRequired';
1344 } elseif ($rescode == -3) {
1346 $this->errors[] =
'ErrorBarCodeAlreadyUsed';
1366 public function check_barcode($valuetotest, $typefortest)
1374 $dirsociete = array_merge(array(
'/core/modules/barcode/'),
$conf->modules_parts[
'barcode']);
1375 foreach ($dirsociete as $dirroot) {
1382 $mod =
new $module();
1383 '@phan-var-force ModeleNumRefBarCode $mod';
1386 dol_syslog(get_class($this).
"::check_barcode value=".$valuetotest.
" type=".$typefortest.
" module=".$module);
1387 $result = $mod->verif($this->db, $valuetotest, $this, 0, $typefortest);
1405 public function update($id, $user, $notrigger = 0, $action =
'update', $updatetype =
false)
1407 global $langs,
$conf, $hookmanager;
1412 if (!$this->label) {
1413 $this->label =
'MISSING LABEL';
1418 $this->
ref = trim((
string) $this->
ref);
1422 $this->label = trim((
string) $this->label);
1424 $this->note_private = (isset($this->note_private) ? trim($this->note_private) :
null);
1425 $this->note_public = (isset($this->note_public) ? trim($this->note_public) :
null);
1426 $this->net_measure =
price2num($this->net_measure);
1427 $this->net_measure_units = (!is_numeric($this->net_measure_units) ? null : (int) $this->net_measure_units);
1428 $this->weight =
price2num($this->weight);
1429 $this->weight_units = (!is_numeric($this->weight_units) ? null : (int) $this->weight_units);
1430 $this->length =
price2num($this->length);
1431 $this->length_units = (!is_numeric($this->length_units) ? null : (int) $this->length_units);
1433 $this->width_units = (!is_numeric($this->width_units) ? null : (int) $this->width_units);
1434 $this->height =
price2num($this->height);
1435 $this->height_units = (!is_numeric($this->height_units) ? null : (int) $this->height_units);
1436 $this->surface =
price2num($this->surface);
1437 $this->surface_units = (!is_numeric($this->surface_units) ? null : (int) $this->surface_units);
1438 $this->volume =
price2num($this->volume);
1439 $this->volume_units = (!is_numeric($this->volume_units) ? null : (int) $this->volume_units);
1442 if (is_numeric($this->length_units)) {
1443 $this->width_units = $this->length_units;
1445 if (is_numeric($this->length_units)) {
1446 $this->height_units = $this->length_units;
1450 if (empty($this->surface) && !empty($this->length) && !empty($this->width) && $this->length_units == $this->width_units) {
1451 $this->surface = (float) $this->length * (
float) $this->width;
1454 if (empty($this->volume) && !empty($this->surface) && !empty($this->height) && $this->length_units == $this->height_units) {
1455 $this->volume = $this->surface * (float) $this->height;
1459 if (empty($this->tva_tx)) {
1462 if (empty($this->tva_npr)) {
1465 if (empty($this->localtax1_tx)) {
1466 $this->localtax1_tx = 0;
1468 if (empty($this->localtax2_tx)) {
1469 $this->localtax2_tx = 0;
1471 if (empty($this->localtax1_type)) {
1472 $this->localtax1_type =
'0';
1474 if (empty($this->localtax2_type)) {
1475 $this->localtax2_type =
'0';
1477 if (empty($this->
status)) {
1480 if (empty($this->status_buy)) {
1481 $this->status_buy = 0;
1484 if (empty($this->country_id)) {
1485 $this->country_id = 0;
1487 if (empty($this->country_id) && !empty($this->country_code)) {
1488 $country_id =
getCountry($this->country_code,
'3');
1489 $this->country_id = is_int($country_id) ? $country_id : 0;
1492 if (empty($this->state_id)) {
1493 $this->state_id = 0;
1496 if (empty($this->stockable_product)) {
1497 $this->stockable_product = 0;
1501 if ($this->barcode ==
'-1' || $this->barcode ==
'auto') {
1502 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1506 $this->barcode = (empty($this->barcode) ?
'' : trim($this->barcode));
1508 $this->accountancy_code_buy = trim((
string) $this->accountancy_code_buy);
1509 $this->accountancy_code_buy_intra = (!empty($this->accountancy_code_buy_intra) ? trim($this->accountancy_code_buy_intra) :
'');
1510 $this->accountancy_code_buy_export = trim((
string) $this->accountancy_code_buy_export);
1511 $this->accountancy_code_sell = trim((
string) $this->accountancy_code_sell);
1512 $this->accountancy_code_sell_intra = trim((
string) $this->accountancy_code_sell_intra);
1513 $this->accountancy_code_sell_export = trim((
string) $this->accountancy_code_sell_export);
1519 require_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
1520 $this->accountancy_code_buy =
clean_account($this->accountancy_code_buy);
1521 $this->accountancy_code_buy_intra =
clean_account($this->accountancy_code_buy_intra);
1522 $this->accountancy_code_buy_export =
clean_account($this->accountancy_code_buy_export);
1523 $this->accountancy_code_sell =
clean_account($this->accountancy_code_sell);
1524 $this->accountancy_code_sell_intra =
clean_account($this->accountancy_code_sell_intra);
1525 $this->accountancy_code_sell_export =
clean_account($this->accountancy_code_sell_export);
1532 if ($action !=
'add') {
1533 $result = $this->
verify();
1545 if (is_null($this->oldcopy) || (is_object($this->oldcopy) && empty($this->oldcopy->id)) || !($this->oldcopy instanceof
Product)) {
1550 if ($this->
hasbatch() && !$this->oldcopy->hasbatch()) {
1552 $valueforundefinedlot =
'000000';
1557 dol_syslog(
"Flag batch of product id=".$this->
id.
" is set to ON, so we will create missing records into product_batch");
1560 foreach ($this->stock_warehouse as $idW => $ObjW) {
1562 foreach ($ObjW->detail_batch as $detail) {
1563 if ($detail->batch == $valueforundefinedlot || $detail->batch ==
'Undefined') {
1565 $sqlclean =
"DELETE FROM ".$this->db->prefix().
"product_batch WHERE batch in('Undefined', '".$this->db->escape($valueforundefinedlot).
"') AND fk_product_stock = ".((int) $ObjW->id);
1566 $result = $this->db->query($sqlclean);
1568 dol_print_error($this->db);
1574 $qty_batch += $detail->qty;
1578 if ($ObjW->real != $qty_batch) {
1580 $ObjBatch->batch = $valueforundefinedlot;
1581 $ObjBatch->qty = ($ObjW->real - $qty_batch);
1582 $ObjBatch->fk_product_stock = (int) $ObjW->id;
1584 if ($ObjBatch->create($user, 1) < 0) {
1586 $this->errors = $ObjBatch->errors;
1591 if ($ObjLot->fetch(0, $this->id, $valueforundefinedlot) == 0) {
1592 $ObjLot->fk_product = $this->id;
1593 $ObjLot->entity = (int) $this->entity;
1594 $ObjLot->fk_user_creat = $user->id;
1595 $ObjLot->batch = $valueforundefinedlot;
1596 if ($ObjLot->create($user, 1) < 0) {
1598 $this->errors = $ObjLot->errors;
1606 $sql =
"UPDATE ".$this->db->prefix().
"product";
1607 $sql .=
" SET label = '".$this->db->escape($this->label).
"'";
1610 $sql .=
", fk_product_type = ".((int) $this->
type);
1613 $sql .=
", ref = '".$this->db->escape($this->
ref).
"'";
1614 $sql .=
", ref_ext = ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1615 $sql .=
", default_vat_code = ".($this->default_vat_code ?
"'".$this->db->escape($this->default_vat_code).
"'" :
"null");
1616 $sql .=
", tva_tx = ".((float) $this->tva_tx);
1617 $sql .=
", recuperableonly = ".((int) $this->tva_npr);
1618 $sql .=
", localtax1_tx = ".((float) $this->localtax1_tx);
1619 $sql .=
", localtax2_tx = ".((float) $this->localtax2_tx);
1620 $sql .=
", localtax1_type = ".($this->localtax1_type !=
'' ?
"'".$this->db->escape($this->localtax1_type).
"'" :
"'0'");
1621 $sql .=
", localtax2_type = ".($this->localtax2_type !=
'' ?
"'".$this->db->escape($this->localtax2_type).
"'" :
"'0'");
1623 $sql .=
", barcode = ".(empty($this->barcode) ?
"null" :
"'".$this->db->escape($this->barcode).
"'");
1624 $sql .=
", fk_barcode_type = ".(empty($this->barcode_type) ?
"null" : $this->db->escape((
string) $this->barcode_type));
1626 $sql .=
", tosell = ".(int) $this->
status;
1627 $sql .=
", tobuy = ".(int) $this->status_buy;
1628 $sql .=
", tobatch = ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : (int) $this->status_batch);
1629 $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);
1630 $sql .=
", batch_mask = '".$this->db->escape($this->batch_mask).
"'";
1632 $sql .=
", finished = ".((!isset($this->finished) || $this->finished < 0 || $this->finished ===
'') ?
"null" : (int) $this->finished);
1633 $sql .=
", fk_default_bom = ".((!isset($this->fk_default_bom) || $this->fk_default_bom < 0 || $this->fk_default_bom ==
'') ?
"null" : (int) $this->fk_default_bom);
1634 $sql .=
", net_measure = ".($this->net_measure !=
'' ?
"'".$this->db->escape($this->net_measure).
"'" :
'null');
1635 $sql .=
", net_measure_units = ".((string) $this->net_measure_units !=
'' ? ((
int) $this->net_measure_units) :
'null');
1636 $sql .=
", weight = ".($this->weight !=
'' ?
"'".$this->db->escape($this->weight).
"'" :
'null');
1637 $sql .=
", weight_units = ".((string) $this->weight_units !=
'' ? ((
int) $this->weight_units) :
'null');
1638 $sql .=
", length = ".($this->length !=
'' ?
"'".$this->db->escape($this->length).
"'" :
'null');
1639 $sql .=
", length_units = ".((string) $this->length_units !=
'' ? ((
int) $this->length_units) :
'null');
1640 $sql .=
", width= ".($this->width !=
'' ?
"'".$this->db->escape($this->width).
"'" :
'null');
1641 $sql .=
", width_units = ".((string) $this->width_units !=
'' ? ((
int) $this->width_units) :
'null');
1642 $sql .=
", height = ".($this->height !=
'' ?
"'".$this->db->escape($this->height).
"'" :
'null');
1643 $sql .=
", height_units = ".((string) $this->height_units !=
'' ? ((
int) $this->height_units) :
'null');
1644 $sql .=
", surface = ".($this->surface !=
'' ?
"'".$this->db->escape($this->surface).
"'" :
'null');
1645 $sql .=
", surface_units = ".((string) $this->surface_units !=
'' ? ((
int) $this->surface_units) :
'null');
1646 $sql .=
", volume = ".($this->volume !=
'' ?
"'".$this->db->escape($this->volume).
"'" :
'null');
1647 $sql .=
", volume_units = ".((string) $this->volume_units !=
'' ? ((
int) $this->volume_units) :
'null');
1648 $sql .=
", fk_default_warehouse = ".($this->fk_default_warehouse > 0 ? ((int) $this->fk_default_warehouse) :
'null');
1649 $sql .=
", fk_default_workstation = ".($this->fk_default_workstation > 0 ? ((int) $this->fk_default_workstation) :
'null');
1650 $sql .=
", seuil_stock_alerte = ".((isset($this->seuil_stock_alerte) && is_numeric($this->seuil_stock_alerte)) ? (
float) $this->seuil_stock_alerte :
'null');
1651 $sql .=
", description = '".$this->db->escape($this->description).
"'";
1652 $sql .=
", url = ".($this->url ?
"'".$this->db->escape($this->url).
"'" :
'null');
1653 $sql .=
", customcode = '".$this->db->escape($this->customcode).
"'";
1654 $sql .=
", fk_country = ".($this->country_id > 0 ? (int) $this->country_id :
'null');
1655 $sql .=
", fk_state = ".($this->state_id > 0 ? (int) $this->state_id :
'null');
1656 $sql .=
", lifetime = ".($this->lifetime > 0 ? (int) $this->lifetime :
'null');
1657 $sql .=
", qc_frequency = ".($this->qc_frequency > 0 ? (int) $this->qc_frequency :
'null');
1658 $sql .=
", note = ".(isset($this->note_private) ?
"'".$this->db->escape($this->note_private).
"'" :
'null');
1659 $sql .=
", note_public = ".(isset($this->note_public) ?
"'".$this->db->escape($this->note_public).
"'" :
'null');
1660 $sql .=
", duration = '".$this->db->escape($this->duration_value.$this->duration_unit).
"'";
1662 $sql .=
", accountancy_code_buy = '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1663 $sql .=
", accountancy_code_buy_intra = '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1664 $sql .=
", accountancy_code_buy_export = '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1665 $sql .=
", accountancy_code_sell= '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1666 $sql .=
", accountancy_code_sell_intra= '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1667 $sql .=
", accountancy_code_sell_export= '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1669 $sql .=
", desiredstock = ".((isset($this->desiredstock) && is_numeric($this->desiredstock)) ? (
float) $this->desiredstock :
"null");
1670 $sql .=
", cost_price = ".($this->cost_price !=
'' ? ((float) $this->cost_price) :
'null');
1671 $sql .=
", fk_unit= ".(!$this->fk_unit ?
'NULL' : (int) $this->fk_unit);
1672 $sql .=
", price_autogen = ".(!$this->price_autogen ? 0 : 1);
1673 $sql .=
", fk_price_expression = ".($this->fk_price_expression != 0 ? (int) $this->fk_price_expression :
'NULL');
1674 $sql .=
", fk_user_modif = ".($user->id > 0 ? (int) $user->id :
'NULL');
1675 $sql .=
", mandatory_period = ".((int) $this->mandatory_period);
1676 $sql .=
", stockable_product = ".(int) $this->stockable_product;
1678 $sql .=
", packaging = ".(float) $this->packaging;
1682 $sql .=
" WHERE rowid = ".((int) $id);
1684 dol_syslog(get_class($this).
"::update", LOG_DEBUG);
1686 $resql = $this->db->query($sql);
1693 $this->db->rollback();
1702 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " . ((
int) $this->id) .
" AND entity = " . ((
int)
$conf->entity));
1704 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1705 $sql .=
" fk_product";
1707 $sql .=
", accountancy_code_buy";
1708 $sql .=
", accountancy_code_buy_intra";
1709 $sql .=
", accountancy_code_buy_export";
1710 $sql .=
", accountancy_code_sell";
1711 $sql .=
", accountancy_code_sell_intra";
1712 $sql .=
", accountancy_code_sell_export";
1713 $sql .=
") VALUES (";
1714 $sql .= ((int) $this->
id);
1715 $sql .=
", " . ((int)
$conf->entity);
1716 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1717 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1718 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1719 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1720 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1721 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1723 $result = $this->db->query($sql);
1726 $this->error =
'ErrorFailedToUpdateAccountancyForEntity';
1730 if (!$this->
hasbatch() && $this->oldcopy->hasbatch()) {
1732 $sql =
'SELECT pb.qty, ps.fk_entrepot, pb.batch FROM '.MAIN_DB_PREFIX.
'product_batch as pb';
1733 $sql .=
' INNER JOIN '.MAIN_DB_PREFIX.
'product_stock as ps ON (ps.rowid = pb.fk_product_stock)';
1734 $sql .=
' WHERE ps.fk_product = '.(int) $this->
id;
1736 $resql = $this->db->query($sql);
1740 while ($obj = $this->db->fetch_object($resql)) {
1742 $fk_entrepot = $obj->fk_entrepot;
1746 $batch = $obj->batch;
1749 $addOremove = $value > 0 ? 1 : 0;
1750 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1751 $res = $this->
correct_stock_batch($user, $fk_entrepot, abs($value), $addOremove, $label, $price, $dlc, $dluo, $batch, $inventorycode,
'',
null, 0,
null,
true);
1754 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1755 $res = $this->
correct_stock($user, $fk_entrepot, abs($value), (
int) empty($addOremove), $label, $price, $inventorycode,
'',
null, 0);
1774 if (!$error && !$notrigger) {
1776 $result = $this->call_trigger(
'PRODUCT_MODIFY', $user);
1783 if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) {
1785 if (
$conf->product->dir_output) {
1788 if (file_exists($olddir)) {
1792 $res = @rename($olddir, $newdir);
1794 $langs->load(
"errors");
1795 $this->error = $langs->trans(
'ErrorFailToRenameDir', $olddir, $newdir);
1799 require_once DOL_DOCUMENT_ROOT .
'/ecm/class/ecmfiles.class.php';
1800 $ecmfiles =
new EcmFiles($this->db);
1801 $ecmfiles->updateAfterRename(
"produit/".
dol_sanitizeFileName($this->oldcopy->ref),
"produit/".dol_sanitizeFileName($this->ref));
1809 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1813 foreach ($comb->fetchAllByFkProductParent($this->id) as $currcomb) {
1814 $currcomb->updateProperties($this, $user);
1818 $this->db->commit();
1821 $this->db->rollback();
1825 if ($this->db->errno() ==
'DB_ERROR_RECORD_ALREADY_EXISTS') {
1826 $langs->load(
"errors");
1827 if (empty(
$conf->barcode->enabled) || empty($this->barcode)) {
1828 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductAlreadyExists", $this->
ref);
1830 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductBarCodeAlreadyExists", $this->barcode);
1832 $this->errors[] = $this->error;
1833 $this->db->rollback();
1836 $this->error = $langs->trans(
"Error").
" : ".$this->db->error().
" - ".$sql;
1837 $this->errors[] = $this->error;
1838 $this->db->rollback();
1843 $this->db->rollback();
1844 dol_syslog(get_class($this).
"::Update fails verify ".implode(
',', $this->errors), LOG_WARNING);
1856 public function delete(
User $user, $notrigger = 0)
1859 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
1864 if (empty($this->
id)) {
1865 $this->error =
"Object must be fetched before calling delete";
1868 if (($this->
isProduct() && !$user->
hasRight(
'produit',
'supprimer')) || ($this->isService() && !$user->hasRight(
'service',
'supprimer'))) {
1869 $this->error =
"ErrorForbidden";
1874 if (empty($objectisused)) {
1877 if (empty($notrigger)) {
1879 $result = $this->call_trigger(
'PRODUCT_DELETE', $user);
1888 $sql =
"DELETE FROM ".$this->db->prefix().
'product_batch';
1889 $sql .=
" WHERE fk_product_stock IN (";
1890 $sql .=
"SELECT rowid FROM ".$this->db->prefix().
'product_stock';
1891 $sql .=
" WHERE fk_product = ".((int) $this->
id).
")";
1893 $result = $this->db->query($sql);
1896 $this->errors[] = $this->db->lasterror();
1902 $sql =
"DELETE FROM " . $this->db->prefix() .
"product_fournisseur_price_log";
1903 $sql .=
" WHERE fk_product_fournisseur IN (";
1904 $sql .=
" SELECT rowid FROM " . $this->db->prefix() .
"product_fournisseur_price";
1905 $sql .=
" WHERE fk_product = " . ((int) $this->
id);
1908 $resql = $this->db->query($sql);
1911 $this->errors[] = $this->db->lasterror();
1917 $sql =
"DELETE FROM ".$this->db->prefix().
"product_lang_extrafields";
1918 $sql .=
" WHERE fk_object IN (SELECT rowid FROM ".$this->db->prefix().
"product_lang WHERE fk_product = ".((int) $this->
id).
")";
1919 $result = $this->db->query($sql);
1922 $this->errors[] = $this->db->lasterror();
1928 $elements = array(
'product_fournisseur_price',
'product_price',
'product_lang',
'categorie_product',
'product_stock',
'product_customer_price',
'product_lot');
1929 foreach ($elements as $table) {
1931 $sql =
"DELETE FROM ".$this->db->prefix().$table;
1932 $sql .=
" WHERE fk_product = ".(int) $this->
id;
1934 $result = $this->db->query($sql);
1937 $this->errors[] = $this->db->lasterror();
1944 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1945 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination2ValuePair.class.php';
1950 if ($prodcomb->deleteByFkProductParent($user, $this->id) < 0) {
1952 $this->errors[] =
'Error deleting combinations';
1956 if (!$error && ($prodcomb->fetchByFkProductChild($this->id) > 0) && ($prodcomb->delete($user) < 0)) {
1958 $this->errors[] =
'Error deleting child combination';
1968 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1971 if ($prodcomb->deleteLinksByProduct($this->id) < 0) {
1973 $this->errors[] = $prodcomb->error;
1979 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
1980 $sql .=
" WHERE fk_product_pere = ".(int) $this->
id.
" OR fk_product_fils = ".(
int) $this->id;
1982 $result = $this->db->query($sql);
1985 $this->errors[] = $this->db->lasterror();
1994 dol_syslog(get_class($this).
"::delete error -4 ".$this->error, LOG_ERR);
2000 $sqlz =
"DELETE FROM ".$this->db->prefix().
"product";
2001 $sqlz .=
" WHERE rowid = ".(int) $this->
id;
2003 $resultz = $this->db->query($sqlz);
2006 $this->errors[] = $this->db->lasterror();
2022 if ($conf->product->dir_output) {
2023 $dir =
$conf->product->dir_output.
"/".$ref;
2024 if (file_exists($dir)) {
2027 $this->errors[] =
'ErrorFailToDeleteDir';
2035 $this->db->commit();
2038 foreach ($this->errors as $errmsg) {
2039 dol_syslog(get_class($this).
"::delete ".$errmsg, LOG_ERR);
2040 $this->error .= ($this->error ?
', '.$errmsg : $errmsg);
2042 $this->db->rollback();
2046 $this->error =
"ErrorRecordIsUsedCantDelete";
2060 $sellByLabel = $langs->trans(
'SellByDate');
2061 $eatByLabel = $langs->trans(
'EatByDate');
2063 self::SELL_OR_EAT_BY_MANDATORY_ID_NONE => $langs->trans(
'BatchSellOrEatByMandatoryNone'),
2064 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY => $sellByLabel,
2065 self::SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY => $eatByLabel,
2066 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT => $langs->trans(
'BatchSellOrEatByMandatoryAll', $sellByLabel, $eatByLabel),
2077 $sellOrEatByMandatoryLabel =
'';
2080 if (isset($sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory])) {
2081 $sellOrEatByMandatoryLabel = $sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory];
2084 return $sellOrEatByMandatoryLabel;
2098 $langs_available = $langs->get_available_languages(DOL_DOCUMENT_ROOT, 0, 2);
2099 $current_lang = $langs->getDefaultLang();
2101 foreach ($langs_available as $key => $value) {
2102 if ($key == $current_lang) {
2103 $sql =
"SELECT rowid";
2104 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2105 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2106 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
2108 $result = $this->db->query($sql);
2109 $objlang = ($result ? $this->db->fetch_object($result) :
null);
2110 $rowidlang = ($objlang ? (int) $objlang->rowid : 0);
2113 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
2115 $sql2 .=
" label='".$this->db->escape($this->label).
"',";
2116 $sql2 .=
" description='".$this->db->escape($this->
description).
"'";
2118 $sql2 .=
", note='".$this->db->escape($this->other).
"'";
2120 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
2122 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
2127 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->label).
"',";
2128 $sql2 .=
" '".$this->db->escape($this->
description).
"'";
2130 $sql2 .=
", '".$this->db->escape($this->other).
"'";
2134 dol_syslog(get_class($this).
'::setMultiLangs key = current_lang = '.$key);
2135 if (!$this->db->query($sql2)) {
2136 $this->error = $this->db->lasterror();
2139 if (empty($rowidlang)) {
2140 $rowidlang = (int) $this->db->last_insert_id($this->db->prefix().
"product_lang");
2145 } elseif (isset($this->multilangs[$key])) {
2146 if (empty($this->multilangs[$key][
"label"])) {
2147 $this->errors[] = $key .
' : ' . $langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Label"));
2151 $sql =
"SELECT rowid";
2152 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2153 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2154 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
2156 $result = $this->db->query($sql);
2157 $objlang = ($result ? $this->db->fetch_object($result) :
null);
2158 $rowidlang = ($objlang ? (int) $objlang->rowid : 0);
2161 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
2163 $sql2 .=
" label = '".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
2164 $sql2 .=
" description = '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
2167 $sql2 .=
", note = '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
2169 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
2171 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
2176 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
2177 $sql2 .=
" '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
2180 $sql2 .=
", '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
2186 if ($this->multilangs[
"$key"][
"label"] || $this->multilangs[
"$key"][
"description"]) {
2187 if (!$this->db->query($sql2)) {
2188 $this->error = $this->db->lasterror();
2191 if (empty($rowidlang)) {
2192 $rowidlang = (int) $this->db->last_insert_id($this->db->prefix().
"product_lang");
2203 if (empty($notrigger)) {
2205 $result = $this->call_trigger(
'PRODUCT_SET_MULTILANGS', $user);
2207 $this->error = $this->db->lasterror();
2226 if (empty($rowidlang) || !isset($this->multilangs[$langcode][
'array_options']) || !is_array($this->multilangs[$langcode][
'array_options'])) {
2231 $productlang->id = $rowidlang;
2232 $productlang->array_options = $this->multilangs[$langcode][
'array_options'];
2233 $result = $productlang->insertExtraFields();
2235 $this->error = $productlang->error;
2236 $this->errors = array_merge($this->errors, $productlang->errors);
2237 dol_syslog(get_class($this).
'::setMultiLangsExtrafields error='.$this->error, LOG_ERR);
2255 dol_syslog(get_class($this).
'::delMultiLangs', LOG_DEBUG);
2258 $sql =
"DELETE FROM ".$this->db->prefix().
"product_lang_extrafields";
2259 $sql .=
" WHERE fk_object IN (SELECT rowid FROM ".$this->db->prefix().
"product_lang";
2260 $sql .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($langtodelete).
"')";
2261 $result = $this->db->query($sql);
2263 $this->error = $this->db->lasterror();
2264 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
2268 $sql =
"DELETE FROM ".$this->db->prefix().
"product_lang";
2269 $sql .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($langtodelete).
"'";
2271 $result = $this->db->query($sql);
2273 if (empty($notrigger)) {
2275 $result = $this->call_trigger(
'PRODUCT_DEL_MULTILANGS', $user);
2277 $this->error = $this->db->lasterror();
2278 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
2283 unset($this->multilangs[$langtodelete]);
2286 $this->error = $this->db->lasterror();
2287 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
2308 if ($type ==
'buy') {
2309 $field =
'accountancy_code_buy';
2310 } elseif ($type ==
'buy_intra') {
2311 $field =
'accountancy_code_buy_intra';
2312 } elseif ($type ==
'buy_export') {
2313 $field =
'accountancy_code_buy_export';
2314 } elseif ($type ==
'sell') {
2315 $field =
'accountancy_code_sell';
2316 } elseif ($type ==
'sell_intra') {
2317 $field =
'accountancy_code_sell_intra';
2318 } elseif ($type ==
'sell_export') {
2319 $field =
'accountancy_code_sell_export';
2324 $sql =
"UPDATE ".$this->db->prefix().$this->table_element.
" SET ";
2325 $sql .=
"$field = '".$this->db->escape($value).
"'";
2326 $sql .=
" WHERE rowid = ".((int) $this->
id);
2329 $resql = $this->db->query($sql);
2333 $result = $this->call_trigger(
'PRODUCT_MODIFY', $user);
2340 $this->db->rollback();
2344 $this->$field = $value;
2346 $this->db->commit();
2349 $this->error = $this->db->lasterror();
2350 $this->db->rollback();
2367 $current_lang = $langs->getDefaultLang();
2370 $sql =
"SELECT rowid, lang, label, description, note as other";
2371 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2372 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2374 $result = $this->db->query($sql);
2376 while ($obj = $this->db->fetch_object($result)) {
2378 if ($obj->lang == $current_lang) {
2379 $this->label = $obj->label;
2381 $this->other = $obj->other;
2383 $this->multilangs[(string) $obj->lang][
"rowid"] = (
int) $obj->rowid;
2384 $this->multilangs[(string) $obj->lang][
"label"] = $obj->label;
2385 $this->multilangs[(string) $obj->lang][
"description"] = $obj->description;
2386 $this->multilangs[(string) $obj->lang][
"other"] = $obj->other;
2390 if ($loadextrafields && !empty($this->multilangs)) {
2392 $extrafields->fetch_name_optionals_label(
'product_lang');
2393 if (!empty($extrafields->attributes[
'product_lang'][
'count'])) {
2395 foreach ($this->multilangs as $langcode => $value) {
2396 $productlang->id = $value[
'rowid'];
2397 $productlang->array_options = array();
2398 $productlang->fetch_optionals();
2399 $this->multilangs[$langcode][
'array_options'] = $productlang->array_options;
2406 $this->error =
"Error: ".$this->db->lasterror().
" - ".$sql;
2419 $testExit = array(
'multiprices',
'multiprices_ttc',
'multiprices_base_type',
'multiprices_min',
'multiprices_min_ttc',
'multiprices_tva_tx',
'multiprices_recuperableonly');
2421 foreach ($testExit as $field) {
2422 if (!isset($this->$field)) {
2425 $tmparray = $this->$field;
2426 if (!isset($tmparray[$level])) {
2432 'level' => $level ? $level : 1,
2433 'multiprices' => (float) $this->multiprices[$level],
2434 'multiprices_ttc' => (
float) $this->multiprices_ttc[$level],
2435 'multiprices_base_type' => $this->multiprices_base_type[$level],
2436 'multiprices_min' => (float) $this->multiprices_min[$level],
2437 'multiprices_min_ttc' => (
float) $this->multiprices_min_ttc[$level],
2438 'multiprices_tva_tx' => (float) $this->multiprices_tva_tx[$level],
2439 'multiprices_recuperableonly' => (
float) $this->multiprices_recuperableonly[$level],
2462 if (empty($this->price_by_qty)) {
2463 $this->price_by_qty = 0;
2467 $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,";
2468 $sql .=
" localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, price_min,price_min_ttc,price_by_qty,entity,fk_price_expression) ";
2469 $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).
"'").
",";
2470 $sql .=
" ".((float)
price2num($this->
price)).
", ".((
float)
price2num($this->price_ttc)).
",'".$this->db->escape($this->price_base_type).
"',".((int) $this->
status).
", ".((float)
price2num($this->tva_tx)).
",";
2471 $sql .=
" ".($this->default_vat_code ? (
"'".$this->db->escape($this->default_vat_code).
"'") :
"null").
", ".((
int) $this->tva_npr).
",";
2472 $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');
2475 dol_syslog(get_class($this).
"::_log_price", LOG_DEBUG);
2476 $resql = $this->db->query($sql);
2478 $this->error = $this->db->lasterror();
2479 dol_print_error($this->db);
2498 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price_by_qty";
2499 $sql .=
" WHERE fk_product_price = ".((int) $rowid);
2500 $sql .=
" AND fk_product_price IN (SELECT pp.rowid FROM ".$this->db->prefix().
"product_price as pp WHERE pp.fk_product = ".((int) $this->
id).
")";
2501 $resql = $this->db->query($sql);
2503 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price_extrafields";
2504 $sql .=
" WHERE fk_object = ".((int) $rowid);
2505 $resql = $this->db->query($sql);
2507 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price";
2508 $sql .=
" WHERE rowid = ".((int) $rowid);
2509 $sql .=
" AND fk_product = ".((int) $this->
id);
2510 $resql = $this->db->query($sql);
2514 $this->error = $this->db->lasterror();
2534 $sql .=
" pl.rowid as log_rowid,";
2535 $sql .=
" pl.datec,";
2536 $sql .=
" pl.price,";
2537 $sql .=
" pl.quantity,";
2538 $sql .=
" pl.fk_user,";
2539 $sql .=
" pl.multicurrency_code,";
2540 $sql .=
" pl.multicurrency_price,";
2542 $sql .=
" pp.fk_soc as supplier_id,";
2543 $sql .=
" pp.ref_fourn as supplier_ref,";
2544 $sql .=
" pp.entity as entity";
2546 $sql .=
" FROM " . $this->db->prefix() .
"product_fournisseur_price_log as pl";
2547 $sql .=
" INNER JOIN " . $this->db->prefix() .
"product_fournisseur_price as pp ON pl.fk_product_fournisseur = pp.rowid";
2549 $sql .=
" WHERE pp.fk_product = " . ((int) $id);
2550 $sql .=
" AND pp.entity IN (" .
getEntity(
'product') .
")";
2551 $sql .=
" ORDER BY pl.datec DESC";
2553 $resql = $this->db->query($sql);
2555 while ($obj = $this->db->fetch_object($resql)) {
2556 if (is_string($obj->datec)) {
2557 $obj->datec = strtotime($obj->datec);
2561 $this->db->free($resql);
2563 $this->error = $this->db->lasterror();
2578 public function getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp = 0)
2580 global $hookmanager, $action;
2583 if (is_object($hookmanager)) {
2584 $parameters = array(
'thirdparty_seller' => $thirdparty_seller,
'thirdparty_buyer' => $thirdparty_buyer,
'pqp' => $pqp);
2586 $reshook = $hookmanager->executeHooks(
'getSellPrice', $parameters, $this, $action);
2588 return $hookmanager->resArray;
2593 $tva_tx =
get_default_tva($thirdparty_seller, $thirdparty_buyer, $this->
id);
2594 $tva_npr =
get_default_npr($thirdparty_seller, $thirdparty_buyer, $this->
id);
2595 if (empty($tva_tx)) {
2599 $pu_ht = $this->price;
2600 $pu_ttc = $this->price_ttc;
2601 $price_min = $this->price_min;
2602 $price_min_ttc = $this->price_min_ttc;
2603 $price_base_type = (empty($this->price_base_type) ?
'HT' : $this->price_base_type);
2607 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2611 $filter = array(
't.fk_product' => (
string) $this->
id,
't.fk_soc' => (
string) $thirdparty_buyer->id);
2614 $pricebycustomerexist =
false;
2615 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2617 if (count($prodcustprice->lines) > 0) {
2618 $date_now = (int) floor(
dol_now() / 86400) * 86400;
2619 foreach ($prodcustprice->lines as $k => $custprice_line) {
2620 if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
2621 $pricebycustomerexist =
true;
2622 $pu_ht =
price($custprice_line->price);
2623 $price_min =
price($custprice_line->price_min);
2624 $price_min_ttc =
price($custprice_line->price_min_ttc);
2625 $pu_ttc =
price($custprice_line->price_ttc);
2626 $price_base_type = $custprice_line->price_base_type;
2627 $tva_tx = $custprice_line->tva_tx;
2628 if ($custprice_line->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2629 $tva_tx .=
' (' . $custprice_line->default_vat_code .
')';
2631 $tva_npr = $custprice_line->recuperableonly;
2632 if (empty($tva_tx)) {
2641 if (!$pricebycustomerexist && !empty($thirdparty_buyer->price_level)) {
2642 $pu_ht = isset($this->multiprices[$thirdparty_buyer->price_level]) ? $this->multiprices[$thirdparty_buyer->price_level] : 0;
2643 $pu_ttc = isset($this->multiprices_ttc[$thirdparty_buyer->price_level]) ? $this->multiprices_ttc[$thirdparty_buyer->price_level] : 0;
2644 $price_min = isset($this->multiprices_min[$thirdparty_buyer->price_level]) ? $this->multiprices_min[$thirdparty_buyer->price_level] : 0;
2645 $price_min_ttc = isset($this->multiprices_min_ttc[$thirdparty_buyer->price_level]) ? $this->multiprices_min_ttc[$thirdparty_buyer->price_level] : 0;
2646 $price_base_type = isset($this->multiprices_base_type[$thirdparty_buyer->price_level]) ? $this->multiprices_base_type[$thirdparty_buyer->price_level] :
'HT';
2649 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2650 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2652 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2653 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2655 if (empty($tva_tx)) {
2660 } elseif (
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !empty($thirdparty_buyer->price_level)) {
2661 $pu_ht = isset($this->multiprices[$thirdparty_buyer->price_level]) ? $this->multiprices[$thirdparty_buyer->price_level] : 0;
2662 $pu_ttc = isset($this->multiprices_ttc[$thirdparty_buyer->price_level]) ? $this->multiprices_ttc[$thirdparty_buyer->price_level] : 0;
2663 $price_min = isset($this->multiprices_min[$thirdparty_buyer->price_level]) ? $this->multiprices_min[$thirdparty_buyer->price_level] : 0;
2664 $price_min_ttc = isset($this->multiprices_min_ttc[$thirdparty_buyer->price_level]) ? $this->multiprices_min_ttc[$thirdparty_buyer->price_level] : 0;
2665 $price_base_type = isset($this->multiprices_base_type[$thirdparty_buyer->price_level]) ? $this->multiprices_base_type[$thirdparty_buyer->price_level] :
'HT';
2668 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2669 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2671 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2672 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2674 if (empty($tva_tx)) {
2680 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2684 $filter = array(
't.fk_product' => (
string) $this->
id,
't.fk_soc' => (
string) $thirdparty_buyer->id);
2686 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2688 if (count($prodcustprice->lines) > 0) {
2689 $date_now = (int) floor(
dol_now() / 86400) * 86400;
2690 foreach ($prodcustprice->lines as $k => $custprice_line) {
2691 if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
2692 $pu_ht =
price($custprice_line->price);
2693 $price_min =
price($custprice_line->price_min);
2694 $price_min_ttc =
price($custprice_line->price_min_ttc);
2695 $pu_ttc =
price($custprice_line->price_ttc);
2696 $price_base_type = $custprice_line->price_base_type;
2697 $tva_tx = $custprice_line->tva_tx;
2698 if ($custprice_line->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2699 $tva_tx .=
' (' . $custprice_line->default_vat_code .
')';
2701 $tva_npr = $custprice_line->recuperableonly;
2702 if (empty($tva_tx)) {
2712 if (!empty($this->prices_by_qty[0])) {
2715 foreach ($this->prices_by_qty_list[0] as $priceforthequantityarray) {
2716 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2720 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2721 $pu_ht = $priceforthequantityarray[
'unitprice'];
2723 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2730 if (!empty($this->prices_by_qty[$thirdparty_buyer->price_level])) {
2733 foreach ($this->prices_by_qty_list[$thirdparty_buyer->price_level] as $priceforthequantityarray) {
2734 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2738 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2739 $pu_ht = $priceforthequantityarray[
'unitprice'];
2741 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2748 return array(
'pu_ht' => $pu_ht,
'pu_ttc' => $pu_ttc,
'price_min' => $price_min,
'price_min_ttc' => $price_min_ttc,
'price_base_type' => $price_base_type,
'tva_tx' => $tva_tx,
'tva_npr' => $tva_npr);
2765 public function get_buyprice($prodfournprice, $qty, $product_id = 0, $fourn_ref =
'', $fk_soc = 0)
2768 global $action, $hookmanager;
2771 if (is_object($hookmanager)) {
2772 $parameters = array(
2773 'prodfournprice' => $prodfournprice,
2775 'product_id' => $product_id,
2776 'fourn_ref' => $fourn_ref,
2777 'fk_soc' => $fk_soc,
2780 $reshook = $hookmanager->executeHooks(
'getBuyPrice', $parameters, $this, $action);
2782 return $hookmanager->resArray;
2789 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2790 $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,";
2791 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2792 $sql .=
" pfp.packaging";
2793 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2794 $sql .=
" WHERE pfp.rowid = ".((int) $prodfournprice);
2796 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2798 $sql .=
" ORDER BY pfp.quantity DESC";
2800 dol_syslog(get_class($this).
"::get_buyprice first search by prodfournprice/qty", LOG_DEBUG);
2801 $resql = $this->db->query($sql);
2803 $obj = $this->db->fetch_object($resql);
2804 if ($obj && $obj->quantity > 0) {
2805 if (
isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2807 $prod_supplier->product_fourn_price_id = $obj->rowid;
2808 $prod_supplier->id = $obj->fk_product;
2809 $prod_supplier->fourn_qty = $obj->quantity;
2810 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2811 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2813 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2815 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2816 if ($price_result >= 0) {
2817 $obj->price = $price_result;
2820 $this->product_fourn_price_id = $obj->rowid;
2821 $this->buyprice = $obj->price;
2822 $this->fourn_pu = $obj->price / $obj->quantity;
2823 $this->fourn_price_base_type =
'HT';
2824 $this->fourn_socid = $obj->fk_soc;
2825 $this->ref_fourn = $obj->ref_supplier;
2826 $this->ref_supplier = $obj->ref_supplier;
2827 $this->desc_supplier = $obj->desc_supplier;
2828 $this->remise_percent = $obj->remise_percent;
2829 $this->vatrate_supplier = $obj->tva_tx;
2830 $this->default_vat_code_supplier = $obj->default_vat_code;
2831 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2832 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2833 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2834 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2835 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2837 $this->packaging = (float) $obj->packaging;
2843 $this->fourn_qty = $obj->quantity;
2844 $result = $obj->fk_product;
2848 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2849 $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,";
2850 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2851 $sql .=
" pfp.packaging";
2852 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2853 $sql .=
" WHERE 1 = 1";
2854 if ($product_id > 0) {
2855 $sql .=
" AND pfp.fk_product = ".((int) $product_id);
2857 if ($fourn_ref !=
'none') {
2858 $sql .=
" AND pfp.ref_fourn = '".$this->db->escape($fourn_ref).
"'";
2861 $sql .=
" AND pfp.fk_soc = ".((int) $fk_soc);
2864 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2866 $sql .=
" ORDER BY pfp.quantity DESC";
2869 dol_syslog(get_class($this).
"::get_buyprice second search from qty/ref/product_id", LOG_DEBUG);
2870 $resql = $this->db->query($sql);
2872 $obj = $this->db->fetch_object($resql);
2873 if ($obj && $obj->quantity > 0) {
2874 if (
isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2876 $prod_supplier->product_fourn_price_id = $obj->rowid;
2877 $prod_supplier->id = $obj->fk_product;
2878 $prod_supplier->fourn_qty = $obj->quantity;
2879 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2880 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2882 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2884 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2885 if ($price_result >= 0) {
2886 $obj->price = $price_result;
2889 $this->product_fourn_price_id = $obj->rowid;
2890 $this->buyprice = $obj->price;
2891 $this->fourn_qty = $obj->quantity;
2892 $this->fourn_pu = $obj->price / $obj->quantity;
2893 $this->fourn_price_base_type =
'HT';
2894 $this->fourn_socid = $obj->fk_soc;
2895 $this->ref_fourn = $obj->ref_supplier;
2896 $this->ref_supplier = $obj->ref_supplier;
2897 $this->desc_supplier = $obj->desc_supplier;
2898 $this->remise_percent = $obj->remise_percent;
2899 $this->vatrate_supplier = $obj->tva_tx;
2900 $this->default_vat_code_supplier = $obj->default_vat_code;
2901 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2902 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2903 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2904 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2905 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2907 $this->packaging = (float) $obj->packaging;
2911 $this->fourn_qty = $obj->quantity;
2912 $result = $obj->fk_product;
2918 $this->error = $this->db->lasterror();
2923 $this->error = $this->db->lasterror();
2947 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)
2953 dol_syslog(get_class($this).
"::update_price id=".$id.
" newprice=".$newprice.
" newpricebase=".$newpricebase.
" newminprice=".$newminprice.
" level=".$level.
" npr=".$newnpr.
" newdefaultvatcode=".$newdefaultvatcode);
2956 if (empty($this->tva_tx)) {
2957 $this->tva_tx = 0.0;
2959 if (empty($newnpr)) {
2962 if (empty($newminprice)) {
2967 if ($newvat ===
null || $newvat ==
'') {
2968 $newvat = (float) $this->tva_tx;
2971 $localtaxtype1 =
'';
2972 $localtaxtype2 =
'';
2977 return $this->
generateMultiprices($user, $newprice, $newpricebase, $newvat, $newnpr, $newpbq);
2980 if (!empty($newminprice) && ($newminprice > $newprice)) {
2981 $this->error =
'ErrorPriceCantBeLowerThanMinPrice';
2985 if ($newprice === 0 || $newprice !==
'') {
2986 if ($newpricebase ==
'TTC') {
2987 $price_ttc = (float)
price2num($newprice,
'MU');
2988 $price = (float)
price2num($newprice) / (1 + ((float) $newvat / 100));
2989 $price = (float)
price2num($price,
'MU');
2991 if ((
string) $newminprice !=
'0') {
2992 $price_min_ttc = (float)
price2num($newminprice,
'MU');
2993 $price_min = (float)
price2num($newminprice) / (1 + ($newvat / 100));
2994 $price_min = (float)
price2num($price_min,
'MU');
2997 $price_min_ttc = 0.0;
3000 $price = (float)
price2num($newprice,
'MU');
3001 $price_ttc = ($newnpr != 1) ? (
float)
price2num($newprice) * (1 + ($newvat / 100)) : $price;
3002 $price_ttc = (float)
price2num($price_ttc,
'MU');
3004 if ((
string) $newminprice !=
'0') {
3005 $price_min = (float)
price2num($newminprice,
'MU');
3006 $price_min_ttc = (float)
price2num($newminprice) * (1 + ($newvat / 100));
3007 $price_min_ttc = (float)
price2num($price_min_ttc,
'MU');
3011 $price_min_ttc = 0.0;
3015 if (count($localtaxes_array) > 0) {
3016 $localtaxtype1 = $localtaxes_array[
'0'];
3017 $localtax1 = $localtaxes_array[
'1'];
3018 $localtaxtype2 = $localtaxes_array[
'2'];
3019 $localtax2 = $localtaxes_array[
'3'];
3022 if (!empty($newdefaultvatcode)) {
3025 $sql =
"SELECT t.rowid, t.code, t.recuperableonly as tva_npr, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
3026 $sql .=
" FROM ".MAIN_DB_PREFIX.
"c_tva as t, ".MAIN_DB_PREFIX.
"c_country as c";
3027 $sql .=
" WHERE t.fk_pays = c.rowid AND c.code = '".$this->db->escape(
$mysoc->country_code).
"'";
3028 $sql .=
" AND t.taux = ".((float) $newdefaultvatcode).
" AND t.active = 1";
3029 $sql .=
" AND t.code = '".$this->db->escape($newdefaultvatcode).
"'";
3030 $resql = $this->db->query($sql);
3032 $obj = $this->db->fetch_object($resql);
3034 $npr = $obj->tva_npr;
3035 $localtax1 = $obj->localtax1;
3036 $localtax2 = $obj->localtax2;
3037 $localtaxtype1 = $obj->localtax1_type;
3038 $localtaxtype2 = $obj->localtax2_type;
3043 $localtaxtype1 =
'0';
3045 $localtaxtype2 =
'0';
3049 if (empty($localtax1)) {
3052 if (empty($localtax2)) {
3061 $updatedefaultprice = (empty($level) || $level == 1);
3065 $sql =
"UPDATE ".$this->db->prefix().
"product SET";
3066 if ($updatedefaultprice) {
3067 $sql .=
" price_base_type = '".$this->db->escape($newpricebase).
"',";
3068 $sql .=
" price = ".(float) $price.
",";
3069 $sql .=
" price_ttc = ".(float) $price_ttc.
",";
3070 $sql .=
" price_min = ".(float) $price_min.
",";
3071 $sql .=
" price_min_ttc = ".(float) $price_min_ttc.
",";
3072 $sql .=
" price_label = ".(!empty($price_label) ?
"'".$this->db->escape($price_label).
"'" :
"null").
",";
3074 $sql .=
" localtax1_tx = ".($localtax1 >= 0 ? (float) $localtax1 :
'NULL').
",";
3075 $sql .=
" localtax2_tx = ".($localtax2 >= 0 ? (float) $localtax2 :
'NULL').
",";
3076 $sql .=
" localtax1_type = ".($localtaxtype1 !=
'' ?
"'".$this->db->escape($localtaxtype1).
"'" :
"'0'").
",";
3077 $sql .=
" localtax2_type = ".($localtaxtype2 !=
'' ?
"'".$this->db->escape($localtaxtype2).
"'" :
"'0'").
",";
3078 $sql .=
" default_vat_code = ".($newdefaultvatcode ?
"'".$this->db->escape($newdefaultvatcode).
"'" :
"null").
",";
3079 $sql .=
" tva_tx = ".(float)
price2num($newvat).
",";
3080 $sql .=
" recuperableonly = '".$this->db->escape((
string) $newnpr).
"'";
3081 $sql .=
" WHERE rowid = ".((int) $id);
3083 dol_syslog(get_class($this).
"::update_price", LOG_DEBUG);
3084 $resql = $this->db->query($sql);
3086 $this->multiprices[$level] = $price;
3087 $this->multiprices_ttc[$level] = $price_ttc;
3088 $this->multiprices_min[$level] = $price_min;
3089 $this->multiprices_min_ttc[$level] = $price_min_ttc;
3090 $this->multiprices_base_type[$level] = $newpricebase;
3091 $this->multiprices_default_vat_code[$level] = $newdefaultvatcode;
3092 $this->multiprices_tva_tx[$level] = $newvat;
3093 $this->multiprices_recuperableonly[$level] = $newnpr;
3097 $savdefaultprice = array($this->
price, $this->price_label, $this->price_ttc, $this->price_min, $this->price_min_ttc, $this->price_base_type);
3099 $this->
price = $price;
3100 $this->price_label = $price_label;
3101 $this->price_ttc = $price_ttc;
3102 $this->price_min = $price_min;
3103 $this->price_min_ttc = $price_min_ttc;
3104 $this->price_base_type = $newpricebase;
3105 $this->default_vat_code = $newdefaultvatcode;
3106 $this->tva_tx = $newvat;
3107 $this->tva_npr = $newnpr;
3110 $this->localtax1_tx = $localtax1;
3111 $this->localtax2_tx = $localtax2;
3112 $this->localtax1_type = $localtaxtype1;
3113 $this->localtax2_type = $localtaxtype2;
3116 $this->price_by_qty = $newpbq;
3120 if (!empty(array_diff_assoc($newPriceData, $lastPriceData)) || (!
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3124 if (!$updatedefaultprice) {
3126 list($this->
price, $this->price_label, $this->price_ttc, $this->price_min, $this->price_min_ttc, $this->price_base_type) = $savdefaultprice;
3129 $this->level = $level;
3133 $result = $this->call_trigger(
'PRODUCT_PRICE_MODIFY', $user);
3135 $this->db->rollback();
3141 $this->db->commit();
3143 $this->db->rollback();
3144 $this->error = $this->db->lasterror();
3163 $this->fk_price_expression = $expression_id;
3165 return $this->
update($this->
id, $user);
3180 public function fetch($id = 0, $ref =
'', $ref_ext =
'', $barcode =
'', $ignore_expression = 0, $ignore_price_load = 0, $ignore_lang_load = 0)
3182 include_once DOL_DOCUMENT_ROOT.
'/core/lib/company.lib.php';
3186 dol_syslog(get_class($this).
"::fetch id=".$id.
" ref=".$ref.
" ref_ext=".$ref_ext);
3189 if (!$id && !$ref && !$ref_ext && !$barcode) {
3190 $this->error =
'ErrorWrongParameters';
3191 dol_syslog(get_class($this).
"::fetch ".$this->error, LOG_ERR);
3195 $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,";
3196 $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,";
3197 $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,";
3198 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.last_main_doc,";
3199 $sql .=
" p.surface, p.surface_units, p.volume, p.volume_units, p.barcode, p.fk_barcode_type, p.finished, p.fk_default_bom, p.mandatory_period, p.packaging,";
3201 $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,";
3203 $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,";
3208 $separatedEntityPMP =
false;
3209 $separatedStock =
false;
3210 $visibleWarehousesEntities =
$conf->entity;
3213 $checkPMPPerEntity = $this->db->query(
"SELECT pmp FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = ".((int) $id).
" AND entity = ".(
int)
$conf->entity);
3214 if ($this->db->num_rows($checkPMPPerEntity) > 0) {
3215 $separatedEntityPMP =
true;
3219 $separatedStock =
true;
3220 if (isset($mc->sharings[
'stock']) && !empty($mc->sharings[
'stock'])) {
3221 $visibleWarehousesEntities .=
"," . implode(
",", $mc->sharings[
'stock']);
3224 if ($separatedEntityPMP) {
3225 $sql .=
" ppe.pmp,";
3229 $sql .=
" p.datec, GREATEST(p.tms, pef.tms) AS tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.sell_or_eat_by_mandatory, p.batch_mask, p.fk_unit,";
3230 $sql .=
" p.fk_price_expression, p.price_autogen, p.stockable_product, p.model_pdf,";
3231 $sql .=
" p.price_label,";
3232 if ($separatedStock) {
3233 $sql .=
" SUM(sp.reel) as stock";
3237 $sql .=
" FROM ".$this->db->prefix().
"product as p";
3238 $sql .=
" LEFT JOIN ".$this->db->prefix().
"product_extrafields as pef ON pef.fk_object=p.rowid";
3240 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int)
$conf->entity);
3242 if ($separatedStock) {
3243 $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).
"))";
3247 $sql .=
" WHERE p.rowid = ".((int) $id);
3249 $sql .=
" WHERE p.entity IN (".getEntity($this->element).
")";
3251 $sql .=
" AND p.ref = '".$this->db->escape($ref).
"'";
3252 } elseif ($ref_ext) {
3253 $sql .=
" AND p.ref_ext = '".$this->db->escape($ref_ext).
"'";
3254 } elseif ($barcode) {
3255 $sql .=
" AND p.barcode = '".$this->db->escape($barcode).
"'";
3258 if ($separatedStock) {
3259 $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,";
3260 $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,";
3261 $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,";
3262 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
3263 $sql .=
" p.surface, p.surface_units, p.volume, p.volume_units, p.barcode, p.fk_barcode_type, p.finished, p.fk_default_bom, p.mandatory_period, p.packaging,";
3265 $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,";
3267 $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,";
3269 if ($separatedEntityPMP) {
3270 $sql .=
" ppe.pmp,";
3274 $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,";
3275 $sql .=
" p.fk_price_expression, p.price_autogen, p.stockable_product, p.model_pdf,";
3276 $sql .=
" p.price_label";
3283 $resql = $this->db->query($sql);
3285 unset($this->oldcopy);
3287 if ($this->db->num_rows($resql) > 0) {
3288 $obj = $this->db->fetch_object($resql);
3290 $this->
id = $obj->rowid;
3291 $this->
ref = $obj->ref;
3292 $this->ref_ext = $obj->ref_ext;
3293 $this->label = $obj->label;
3295 $this->url = $obj->url;
3296 $this->note_public = $obj->note_public;
3297 $this->note_private = $obj->note_private;
3298 $this->note = $obj->note_private;
3300 $this->
type = $obj->fk_product_type;
3301 $this->price_label = $obj->price_label;
3302 $this->
status = $obj->tosell;
3303 $this->status_buy = $obj->tobuy;
3304 $this->status_batch = $obj->tobatch;
3305 $this->sell_or_eat_by_mandatory = $obj->sell_or_eat_by_mandatory;
3306 $this->batch_mask = $obj->batch_mask;
3308 $this->customcode = $obj->customcode;
3309 $this->country_id = $obj->fk_country;
3310 $this->country_code =
getCountry($this->country_id,
'2', $this->db);
3311 $this->state_id = $obj->fk_state;
3312 $this->lifetime = $obj->lifetime;
3313 $this->qc_frequency = $obj->qc_frequency;
3314 $this->
price = $obj->price;
3315 $this->price_ttc = $obj->price_ttc;
3316 $this->price_min = $obj->price_min;
3317 $this->price_min_ttc = $obj->price_min_ttc;
3318 $this->price_base_type = (empty($obj->price_base_type) ?
'HT' : $obj->price_base_type);
3319 $this->cost_price = isset($obj->cost_price) ? (float) $obj->cost_price :
null;
3320 $this->default_vat_code = $obj->default_vat_code;
3321 $this->tva_tx = $obj->tva_tx;
3323 $this->tva_npr = $obj->tva_npr;
3325 $this->localtax1_tx = $obj->localtax1_tx;
3326 $this->localtax2_tx = $obj->localtax2_tx;
3327 $this->localtax1_type = $obj->localtax1_type;
3328 $this->localtax2_type = $obj->localtax2_type;
3330 $this->finished = $obj->finished;
3331 $this->fk_default_bom = $obj->fk_default_bom;
3333 $this->duration = $obj->duration;
3335 preg_match(
'/([\d.]+)(\w+)/', $obj->duration, $matches);
3336 $this->duration_value = !empty($matches[1]) ? (float) $matches[1] : 0;
3337 $this->duration_unit = !empty($matches[2]) ? (string) $matches[2] :
null;
3338 $this->canvas = $obj->canvas;
3339 $this->net_measure = $obj->net_measure;
3340 $this->net_measure_units = $obj->net_measure_units;
3341 $this->weight = $obj->weight;
3342 $this->weight_units = (is_null($obj->weight_units) ? 0 : $obj->weight_units);
3343 $this->length = $obj->length;
3344 $this->length_units = (is_null($obj->length_units) ? 0 : $obj->length_units);
3345 $this->width = $obj->width;
3346 $this->width_units = (is_null($obj->width_units) ? 0 : $obj->width_units);
3347 $this->height = $obj->height;
3348 $this->height_units = (is_null($obj->height_units) ? 0 : $obj->height_units);
3350 $this->surface = $obj->surface;
3351 $this->surface_units = (is_null($obj->surface_units) ? 0 : $obj->surface_units);
3352 $this->volume = $obj->volume;
3353 $this->volume_units = (is_null($obj->volume_units) ? 0 : $obj->volume_units);
3354 $this->barcode = $obj->barcode;
3355 $this->barcode_type = $obj->fk_barcode_type;
3357 $this->accountancy_code_buy = $obj->accountancy_code_buy;
3358 $this->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra;
3359 $this->accountancy_code_buy_export = $obj->accountancy_code_buy_export;
3360 $this->accountancy_code_sell = $obj->accountancy_code_sell;
3361 $this->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra;
3362 $this->accountancy_code_sell_export = $obj->accountancy_code_sell_export;
3364 $this->fk_default_warehouse = $obj->fk_default_warehouse;
3365 $this->fk_default_workstation = $obj->fk_default_workstation;
3366 $this->seuil_stock_alerte = $obj->seuil_stock_alerte;
3367 $this->desiredstock = $obj->desiredstock;
3368 $this->stock_reel = $obj->stock;
3369 $this->stockable_product = $obj->stockable_product;
3370 $this->pmp = $obj->pmp;
3372 $this->date_creation = $this->db->jdate($obj->datec);
3373 $this->date_modification = $this->db->jdate($obj->tms);
3375 $this->import_key = $obj->import_key;
3376 $this->entity = $obj->entity;
3378 $this->ref_ext = $obj->ref_ext;
3379 $this->fk_price_expression = $obj->fk_price_expression;
3380 $this->fk_unit = $obj->fk_unit;
3381 $this->price_autogen = $obj->price_autogen;
3382 $this->model_pdf = $obj->model_pdf;
3383 $this->last_main_doc = $obj->last_main_doc;
3385 $this->mandatory_period = $obj->mandatory_period;
3388 $this->packaging = (float) $obj->packaging;
3391 $this->db->free($resql);
3403 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
3404 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3405 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3406 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3407 $sql .=
" ,price_label";
3408 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3409 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3410 $sql .=
" AND price_level=".((int) $i);
3411 $sql .=
" AND fk_product = ".((int) $this->
id);
3412 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3414 $resql = $this->db->query($sql);
3416 $result = $this->db->fetch_array($resql);
3418 $this->multiprices[$i] = $result ? $result[
"price"] :
null;
3419 $this->multiprices_ttc[$i] = $result ? $result[
"price_ttc"] :
null;
3420 $this->multiprices_min[$i] = $result ? $result[
"price_min"] :
null;
3421 $this->multiprices_min_ttc[$i] = $result ? $result[
"price_min_ttc"] :
null;
3422 $this->multiprices_base_type[$i] = $result ? $result[
"price_base_type"] :
null;
3424 $this->multiprices_tva_tx[$i] = $result ? $result[
"tva_tx"].(!empty($result[
'default_vat_code']) ?
' ('.$result[
'default_vat_code'].
')' :
'') :
null;
3425 $this->multiprices_recuperableonly[$i] = $result ? $result[
"recuperableonly"] :
null;
3464 $this->error = $this->db->lasterror;
3470 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY') && empty($ignore_price_load)) {
3471 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3472 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid";
3473 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3474 $sql .=
" WHERE fk_product = ".((int) $this->
id);
3475 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3478 $resql = $this->db->query($sql);
3480 $result = $this->db->fetch_array($resql);
3484 $this->prices_by_qty[0] = $result[
"price_by_qty"];
3485 $this->prices_by_qty_id[0] = $result[
"rowid"];
3487 if ($this->prices_by_qty[0] == 1) {
3488 $sql =
"SELECT rowid,price, unitprice, quantity, remise_percent, remise, remise, price_base_type";
3489 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3490 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[0]);
3491 $sql .=
" ORDER BY quantity ASC";
3493 $resql = $this->db->query($sql);
3495 $resultat = array();
3497 while ($result = $this->db->fetch_array($resql)) {
3498 $resultat[$ii] = array();
3499 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3500 $resultat[$ii][
"price"] = $result[
"price"];
3501 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3502 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3503 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3505 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3508 $this->prices_by_qty_list[0] = $resultat;
3510 $this->error = $this->db->lasterror;
3516 $this->error = $this->db->lasterror;
3519 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') && empty($ignore_price_load)) {
3520 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
3521 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3522 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3523 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3524 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3525 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3526 $sql .=
" AND price_level=".((int) $i);
3527 $sql .=
" AND fk_product = ".((int) $this->
id);
3528 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3530 $resql = $this->db->query($sql);
3532 $this->error = $this->db->lasterror;
3535 $result = $this->db->fetch_array($resql);
3536 $this->multiprices[$i] = (!empty($result[
"price"]) ? $result[
"price"] : 0);
3537 $this->multiprices_ttc[$i] = (!empty($result[
"price_ttc"]) ? $result[
"price_ttc"] : 0);
3538 $this->multiprices_min[$i] = (!empty($result[
"price_min"]) ? $result[
"price_min"] : 0);
3539 $this->multiprices_min_ttc[$i] = (!empty($result[
"price_min_ttc"]) ? $result[
"price_min_ttc"] : 0);
3540 $this->multiprices_base_type[$i] = (!empty($result[
"price_base_type"]) ? $result[
"price_base_type"] :
'');
3542 $this->multiprices_tva_tx[$i] = (!empty($result[
"tva_tx"]) ? $result[
"tva_tx"] : 0);
3543 $this->multiprices_recuperableonly[$i] = (!empty($result[
"recuperableonly"]) ? $result[
"recuperableonly"] : 0);
3546 $this->prices_by_qty[$i] = (!empty($result[
"price_by_qty"]) ? $result[
"price_by_qty"] : 0);
3547 $this->prices_by_qty_id[$i] = (!empty($result[
"rowid"]) ? $result[
"rowid"] : 0);
3549 if ($this->prices_by_qty[$i] == 1) {
3550 $sql =
"SELECT rowid, price, unitprice, quantity, remise_percent, remise, price_base_type";
3551 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3552 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[$i]);
3553 $sql .=
" ORDER BY quantity ASC";
3555 $resql = $this->db->query($sql);
3557 $resultat = array();
3559 while ($result = $this->db->fetch_array($resql)) {
3560 $resultat[$ii] = array();
3561 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3562 $resultat[$ii][
"price"] = $result[
"price"];
3563 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3564 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3565 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3566 $resultat[$ii][
"remise"] = $result[
"remise"];
3567 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3570 $this->prices_by_qty_list[$i] = $resultat;
3572 $this->error = $this->db->lasterror;
3580 if (
isModEnabled(
'dynamicprices') && !empty($this->fk_price_expression) && empty($ignore_expression)) {
3581 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
3583 $price_result = $priceparser->parseProduct($this);
3584 if ($price_result >= 0) {
3585 $this->
price = $price_result;
3587 $this->price_ttc = (float)
price2num($this->
price) * (1 + ($this->tva_tx / 100));
3588 $this->price_ttc = (float)
price2num($this->price_ttc,
'MU');
3594 $this->stock_warehouse = array();
3601 $this->error = $this->db->lasterror();
3616 global $user, $hookmanager, $action;
3620 foreach (array(
'toconsume',
'consumed',
'toproduce',
'produced') as $role) {
3621 $this->stats_mo[
'customers_'.$role] = 0;
3622 $this->stats_mo[
'nb_'.$role] = 0;
3623 $this->stats_mo[
'qty_'.$role] = 0;
3625 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3626 $sql .=
" SUM(mp.qty) as qty";
3627 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as c";
3628 $sql .=
" INNER JOIN ".$this->db->prefix().
"mrp_production as mp ON mp.fk_mo=c.rowid";
3629 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3630 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3633 $sql .=
" c.entity IN (".getEntity(
'mo').
")";
3635 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3636 $sql .=
" AND mp.role ='".$this->db->escape($role).
"'";
3638 $sql .=
" AND c.fk_soc = ".((int) $socid);
3641 $result = $this->db->query($sql);
3643 $obj = $this->db->fetch_object($result);
3644 $this->stats_mo[
'customers_'.$role] = $obj->nb_customers ? $obj->nb_customers : 0;
3645 $this->stats_mo[
'nb_'.$role] = $obj->nb ? $obj->nb : 0;
3646 $this->stats_mo[
'qty_'.$role] = $obj->qty ?
price2num($obj->qty,
'MS') : 0;
3648 $this->error = $this->db->error();
3653 if (!empty($error)) {
3657 $parameters = array(
'socid' => $socid);
3658 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3660 $this->stats_mo = $hookmanager->resArray[
'stats_mo'];
3676 global $hookmanager, $action;
3680 $this->stats_bom[
'nb_toproduce'] = 0;
3681 $this->stats_bom[
'nb_toconsume'] = 0;
3682 $this->stats_bom[
'qty_toproduce'] = 0;
3683 $this->stats_bom[
'qty_toconsume'] = 0;
3685 $sql =
"SELECT COUNT(DISTINCT b.rowid) as nb_toproduce,";
3686 $sql .=
" SUM(b.qty) as qty_toproduce";
3687 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3688 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom = b.rowid";
3690 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3691 $sql .=
" AND b.fk_product =".((int) $this->
id);
3692 $sql .=
" GROUP BY b.rowid";
3694 $result = $this->db->query($sql);
3696 $obj = $this->db->fetch_object($result);
3697 $this->stats_bom[
'nb_toproduce'] = !empty($obj->nb_toproduce) ? $obj->nb_toproduce : 0;
3698 $this->stats_bom[
'qty_toproduce'] = !empty($obj->qty_toproduce) ?
price2num($obj->qty_toproduce) : 0;
3700 $this->error = $this->db->error();
3704 $sql =
"SELECT COUNT(DISTINCT bl.rowid) as nb_toconsume,";
3705 $sql .=
" SUM(bl.qty) as qty_toconsume";
3706 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3707 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
3709 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3710 $sql .=
" AND bl.fk_product =".((int) $this->
id);
3712 $result = $this->db->query($sql);
3714 $obj = $this->db->fetch_object($result);
3715 $this->stats_bom[
'nb_toconsume'] = !empty($obj->nb_toconsume) ? $obj->nb_toconsume : 0;
3716 $this->stats_bom[
'qty_toconsume'] = !empty($obj->qty_toconsume) ?
price2num($obj->qty_toconsume) : 0;
3718 $this->error = $this->db->error();
3722 if (!empty($error)) {
3726 $parameters = array(
'socid' => $socid);
3727 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3729 $this->stats_bom = $hookmanager->resArray[
'stats_bom'];
3745 global $user, $hookmanager, $action;
3747 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_customers, COUNT(DISTINCT p.rowid) as nb,";
3748 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3749 $sql .=
" FROM ".$this->db->prefix().
"propaldet as pd";
3750 $sql .=
", ".$this->db->prefix().
"propal as p";
3751 $sql .=
", ".$this->db->prefix().
"societe as s";
3752 $sql .=
" WHERE p.rowid = pd.fk_propal";
3753 $sql .=
" AND p.fk_soc = s.rowid";
3754 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
3755 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3756 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3757 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $user->id);
3761 $sql .=
" AND p.fk_soc = ".((int) $socid);
3764 $parameters = array(
'socid' => $socid,
'type_element' =>
'propal');
3765 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3766 $sql .= $hookmanager->resPrint;
3767 $result = $this->db->query($sql);
3769 $obj = $this->db->fetch_object($result);
3770 $this->stats_propale[
'customers'] = (int) $obj->nb_customers;
3771 $this->stats_propale[
'nb'] = (int) $obj->nb;
3772 $this->stats_propale[
'rows'] = (int) $obj->nb_rows;
3773 $this->stats_propale[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
3778 if (is_array($TFather) && !empty($TFather)) {
3779 foreach ($TFather as &$fatherData) {
3780 $pFather =
new Product($this->db);
3781 $pFather->id = (int) $fatherData[
'id'];
3782 $qtyCoef = $fatherData[
'qty'];
3784 if ($fatherData[
'incdec']) {
3785 $pFather->load_stats_propale($socid);
3787 if (!empty($pFather->stats_propale)) {
3788 $this->stats_propale[
'customers'] += $pFather->stats_propale[
'customers'];
3789 $this->stats_propale[
'nb'] += $pFather->stats_propale[
'nb'];
3790 $this->stats_propale[
'rows'] += $pFather->stats_propale[
'rows'];
3791 $this->stats_propale[
'qty'] += $pFather->stats_propale[
'qty'] * $qtyCoef;
3798 $parameters = array(
'socid' => $socid);
3799 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerProposal', $parameters, $this, $action);
3801 $this->stats_propale = $hookmanager->resArray[
'stats_propale'];
3806 $this->error = $this->db->error();
3822 global $user, $hookmanager, $action;
3824 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_suppliers, COUNT(DISTINCT p.rowid) as nb,";
3825 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3826 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as pd";
3827 $sql .=
", ".$this->db->prefix().
"supplier_proposal as p";
3828 $sql .=
", ".$this->db->prefix().
"societe as s";
3829 $sql .=
" WHERE p.rowid = pd.fk_supplier_proposal";
3830 $sql .=
" AND p.fk_soc = s.rowid";
3831 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
3832 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3833 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3834 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $user->id);
3838 $sql .=
" AND p.fk_soc = ".((int) $socid);
3841 $result = $this->db->query($sql);
3843 $obj = $this->db->fetch_object($result);
3844 $this->stats_proposal_supplier[
'suppliers'] = $obj->nb_suppliers;
3845 $this->stats_proposal_supplier[
'nb'] = $obj->nb;
3846 $this->stats_proposal_supplier[
'rows'] = $obj->nb_rows;
3847 $this->stats_proposal_supplier[
'qty'] = $obj->qty ? $obj->qty : 0;
3849 $parameters = array(
'socid' => $socid);
3850 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierProposal', $parameters, $this, $action);
3852 $this->stats_proposal_supplier = $hookmanager->resArray[
'stats_proposal_supplier'];
3857 $this->error = $this->db->error();
3875 global $user, $hookmanager, $action;
3878 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3879 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3880 $sql .=
" FROM ".$this->db->prefix().
"commandedet as cd";
3881 $sql .=
", ".$this->db->prefix().
"commande as c";
3882 $sql .=
", ".$this->db->prefix().
"societe as s";
3883 $sql .=
" WHERE c.rowid = cd.fk_commande";
3884 $sql .=
" AND c.fk_soc = s.rowid";
3885 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'commande').
")";
3886 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3887 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3888 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3891 $sql .=
" AND c.fk_soc = ".((int) $socid);
3893 if ($filtrestatut !=
'') {
3894 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3897 $parameters = array(
'socid' => $socid,
'type_element' =>
'order');
3898 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3899 $sql .= $hookmanager->resPrint;
3900 $result = $this->db->query($sql);
3902 $obj = $this->db->fetch_object($result);
3903 $this->stats_commande[
'customers'] = (int) $obj->nb_customers;
3904 $this->stats_commande[
'nb'] = (int) $obj->nb;
3905 $this->stats_commande[
'rows'] = (int) $obj->nb_rows;
3906 $this->stats_commande[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
3911 if (is_array($TFather) && !empty($TFather)) {
3912 foreach ($TFather as &$fatherData) {
3913 $pFather =
new Product($this->db);
3914 $pFather->id = $fatherData[
'id'];
3915 $qtyCoef = $fatherData[
'qty'];
3917 if ($fatherData[
'incdec']) {
3918 $pFather->load_stats_commande($socid, $filtrestatut);
3920 $this->stats_commande[
'customers'] += $pFather->stats_commande[
'customers'];
3921 $this->stats_commande[
'nb'] += $pFather->stats_commande[
'nb'];
3922 $this->stats_commande[
'rows'] += $pFather->stats_commande[
'rows'];
3923 $this->stats_commande[
'qty'] += $pFather->stats_commande[
'qty'] * $qtyCoef;
3936 $sql =
"SELECT SUM(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3937 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3939 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture' AND sourcetype = 'commande' ";
3940 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3941 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3942 $sql .=
" AND EXISTS (SELECT cd.fk_product FROM ".$this->db->prefix().
"commandedet as cd WHERE cd.fk_product = fd.fk_product AND cd.fk_commande = c.rowid)";
3946 $sql .=
"SELECT SUM(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3947 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3948 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_source = f.rowid AND el.targettype = 'commande' AND sourcetype = 'facture' ";
3949 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_target = c.rowid";
3950 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3951 $sql .=
" AND EXISTS (SELECT cd.fk_product FROM ".$this->db->prefix().
"commandedet as cd WHERE cd.fk_product = fd.fk_product AND cd.fk_commande = c.rowid)";
3953 $parameters = array(
'socid' => $socid,
'type_element' =>
'order');
3954 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3955 $sql .= $hookmanager->resPrint;
3956 $resql = $this->db->query($sql);
3958 while ($obj = $this->db->fetch_object($resql)) {
3959 $adeduire += (float) $obj->count;
3963 $this->stats_commande[
'qty'] -= $adeduire;
3966 include_once DOL_DOCUMENT_ROOT.
'/compta/facture/class/facture.class.php';
3970 $sql =
"SELECT sum(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3971 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3973 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture' AND sourcetype = 'commande' ";
3974 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3975 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3976 $sql .=
" AND EXISTS (SELECT cd.fk_product FROM ".$this->db->prefix().
"commandedet as cd WHERE cd.fk_product = fd.fk_product AND cd.fk_commande = c.rowid)";
3978 $sql .=
" UNION ALL ";
3980 $sql .=
"SELECT sum(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3981 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3982 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON el.fk_source = f.rowid AND el.targettype = 'commande' AND sourcetype = 'facture' ";
3983 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_target = c.rowid";
3984 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3985 $sql .=
" AND EXISTS (SELECT cd.fk_product FROM ".$this->db->prefix().
"commandedet as cd WHERE cd.fk_product = fd.fk_product AND cd.fk_commande = c.rowid)";
3987 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3989 $parameters = array(
'socid' => $socid,
'type_element' =>
'order');
3990 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
3991 $sql .= $hookmanager->resPrint;
3992 $resql = $this->db->query($sql);
3994 while ($obj = $this->db->fetch_object($resql)) {
3995 $adeduire += (float) $obj->count;
3998 $this->error = $this->db->error();
4002 $this->stats_commande[
'qty'] -= $adeduire;
4006 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
4007 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerOrder', $parameters, $this, $action);
4009 $this->stats_commande = $hookmanager->resArray[
'stats_commande'];
4013 $this->error = $this->db->error();
4032 global $user, $hookmanager, $action;
4034 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_suppliers, COUNT(DISTINCT c.rowid) as nb,";
4035 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
4036 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as cd";
4037 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as c";
4038 $sql .=
", ".$this->db->prefix().
"societe as s";
4039 $sql .=
" WHERE c.rowid = cd.fk_commande";
4040 $sql .=
" AND c.fk_soc = s.rowid";
4041 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
4042 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
4043 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
4044 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
4047 $sql .=
" AND c.fk_soc = ".((int) $socid);
4049 if ($filtrestatut !=
'') {
4050 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
4052 if (!empty($dateofvirtualstock)) {
4056 $sqlwindow =
"c.date_livraison <= '".$this->db->idate($dateofvirtualstock).
"'";
4057 if (!empty($dateofvirtualstockmin)) {
4058 $sqlwindow =
"c.date_livraison >= '".$this->db->idate($dateofvirtualstockmin).
"' AND ".$sqlwindow;
4060 if (
getDolGlobalInt(
'STOCK_VIRTUAL_HORIZON_INCLUDE_UNDATED_ORDERS')) {
4061 $sqlwindow .=
" OR c.date_livraison IS NULL";
4063 $sql .=
" AND (".$sqlwindow.
")";
4066 $result = $this->db->query($sql);
4068 $obj = $this->db->fetch_object($result);
4069 $this->stats_commande_fournisseur[
'suppliers'] = $obj->nb_suppliers;
4070 $this->stats_commande_fournisseur[
'nb'] = $obj->nb;
4071 $this->stats_commande_fournisseur[
'rows'] = $obj->nb_rows;
4072 $this->stats_commande_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
4074 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
4075 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierOrder', $parameters, $this, $action);
4077 $this->stats_commande_fournisseur = $hookmanager->resArray[
'stats_commande_fournisseur'];
4082 $this->error = $this->db->error().
' sql='.$sql;
4097 public function load_stats_sending($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $filterShipmentStatus =
'')
4100 global $user, $hookmanager, $action;
4102 $sql =
"SELECT COUNT(DISTINCT e.fk_soc) as nb_customers, COUNT(DISTINCT e.rowid) as nb,";
4103 $sql .=
" COUNT(ed.rowid) as nb_rows, SUM(ed.qty) as qty";
4104 $sql .=
" FROM ".$this->db->prefix().
"expeditiondet as ed";
4105 $sql .=
", ".$this->db->prefix().
"commandedet as cd";
4106 $sql .=
", ".$this->db->prefix().
"commande as c";
4107 $sql .=
", ".$this->db->prefix().
"expedition as e";
4108 $sql .=
", ".$this->db->prefix().
"societe as s";
4109 $sql .=
" WHERE e.rowid = ed.fk_expedition";
4110 $sql .=
" AND c.rowid = cd.fk_commande";
4111 $sql .=
" AND e.fk_soc = s.rowid";
4112 $sql .=
" AND e.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'expedition').
")";
4113 $sql .=
" AND ed.fk_elementdet = cd.rowid";
4114 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
4115 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
4116 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = e.fk_soc AND sc.fk_user = ".((int) $user->id);
4119 $sql .=
" AND e.fk_soc = ".((int) $socid);
4121 if ($filtrestatut !=
'') {
4122 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
4124 if (!empty($filterShipmentStatus)) {
4125 $sql .=
" AND e.fk_statut IN (".$this->db->sanitize($filterShipmentStatus).
")";
4128 $result = $this->db->query($sql);
4130 $obj = $this->db->fetch_object($result);
4131 $this->stats_expedition[
'customers'] = (int) $obj->nb_customers;
4132 $this->stats_expedition[
'nb'] = (int) $obj->nb;
4133 $this->stats_expedition[
'rows'] = (int) $obj->nb_rows;
4134 $this->stats_expedition[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
4139 if (is_array($TFather) && !empty($TFather)) {
4140 foreach ($TFather as &$fatherData) {
4141 $pFather =
new Product($this->db);
4142 $pFather->id = $fatherData[
'id'];
4143 $qtyCoef = $fatherData[
'qty'];
4145 if ($fatherData[
'incdec']) {
4146 $pFather->load_stats_sending($socid, $filtrestatut, $forVirtualStock);
4148 if (!empty($pFather->stats_expedition)) {
4149 $this->stats_expedition[
'customers'] += $pFather->stats_expedition[
'customers'];
4150 $this->stats_expedition[
'nb'] += $pFather->stats_expedition[
'nb'];
4151 $this->stats_expedition[
'rows'] += $pFather->stats_expedition[
'rows'];
4152 $this->stats_expedition[
'qty'] += $pFather->stats_expedition[
'qty'] * $qtyCoef;
4159 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock,
'filterShipmentStatus' => $filterShipmentStatus);
4160 $reshook = $hookmanager->executeHooks(
'loadStatsSending', $parameters, $this, $action);
4162 $this->stats_expedition = $hookmanager->resArray[
'stats_expedition'];
4167 $this->error = $this->db->error();
4183 public function load_stats_reception($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null, $dateofvirtualstockmin =
null)
4186 global $user, $hookmanager, $action;
4188 $sql =
"SELECT COUNT(DISTINCT cf.fk_soc) as nb_suppliers, COUNT(DISTINCT cf.rowid) as nb,";
4189 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4190 $sql .=
" FROM ".$this->db->prefix().
"receptiondet_batch as fd";
4191 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as cf";
4192 $sql .=
", ".$this->db->prefix().
"societe as s";
4193 $sql .=
" WHERE cf.rowid = fd.fk_element";
4194 $sql .=
" AND cf.fk_soc = s.rowid";
4195 $sql .=
" AND cf.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
4196 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4197 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
4198 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = cf.fk_soc AND sc.fk_user = ".((int) $user->id);
4201 $sql .=
" AND cf.fk_soc = ".((int) $socid);
4203 if ($filtrestatut !=
'') {
4204 $sql .=
" AND cf.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
4206 if (!empty($dateofvirtualstock)) {
4207 $sql .=
" AND fd.datec <= '".$this->db->idate($dateofvirtualstock).
"'";
4209 if (!empty($dateofvirtualstockmin)) {
4213 $sqlwindow =
"cf.date_livraison >= '".$this->db->idate($dateofvirtualstockmin).
"' AND cf.date_livraison <= '".$this->db->idate($dateofvirtualstock).
"'";
4214 if (
getDolGlobalInt(
'STOCK_VIRTUAL_HORIZON_INCLUDE_UNDATED_ORDERS')) {
4215 $sqlwindow .=
" OR cf.date_livraison IS NULL";
4217 $sql .=
" AND (".$sqlwindow.
")";
4220 $result = $this->db->query($sql);
4222 $obj = $this->db->fetch_object($result);
4223 $this->stats_reception[
'suppliers'] = $obj->nb_suppliers;
4224 $this->stats_reception[
'nb'] = $obj->nb;
4225 $this->stats_reception[
'rows'] = $obj->nb_rows;
4226 $this->stats_reception[
'qty'] = $obj->qty ? $obj->qty : 0;
4228 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
4229 $reshook = $hookmanager->executeHooks(
'loadStatsReception', $parameters, $this, $action);
4231 $this->stats_reception = $hookmanager->resArray[
'stats_reception'];
4236 $this->error = $this->db->error();
4253 public function load_stats_inproduction($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null, $warehouseid = 0, $dateofvirtualstockmin =
null)
4256 global $user, $hookmanager, $action;
4260 $sql =
"SELECT COUNT(DISTINCT m.fk_soc) as nb_customers, COUNT(DISTINCT m.rowid) as nb,";
4261 $sql .=
" COUNT(mp.rowid) as nb_rows, SUM(mp.qty) as qty, role";
4262 $sql .=
" FROM ".$this->db->prefix().
"mrp_production as mp";
4263 $sql .=
", ".$this->db->prefix().
"mrp_mo as m";
4264 $sql .=
" LEFT JOIN ".$this->db->prefix().
"societe as s ON s.rowid = m.fk_soc";
4265 $sql .=
" WHERE m.rowid = mp.fk_mo";
4266 $sql .=
" AND m.entity IN (".getEntity(($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE')) ?
'stock' :
'mrp').
")";
4267 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
4268 $sql .=
" AND (mp.disable_stock_change IN (0) OR mp.disable_stock_change IS NULL)";
4269 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
4270 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = m.fk_soc AND sc.fk_user = ".((int) $user->id);
4273 $sql .=
" AND m.fk_soc = ".((int) $socid);
4275 if ($filtrestatut !=
'') {
4276 $sql .=
" AND m.status IN (".$this->db->sanitize($filtrestatut).
")";
4278 if (!empty($dateofvirtualstockmin)) {
4283 $sql .=
" AND COALESCE(m.date_end_planned, m.date_valid) >= '".$this->db->idate($dateofvirtualstockmin).
"'";
4284 $sql .=
" AND COALESCE(m.date_end_planned, m.date_valid) <= '".$this->db->idate($dateofvirtualstock).
"'";
4285 } elseif (!empty($dateofvirtualstock)) {
4286 $sql .=
" AND m.date_valid <= '".$this->db->idate($dateofvirtualstock).
"'";
4288 if (!$serviceStockIsEnabled) {
4289 $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))";
4291 if (!empty($warehouseid)) {
4292 $sql .=
" AND m.fk_warehouse = ".((int) $warehouseid);
4294 $sql .=
" GROUP BY role";
4297 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
4299 $this->stats_mrptoconsume[
'customers'] = 0;
4300 $this->stats_mrptoconsume[
'nb'] = 0;
4301 $this->stats_mrptoconsume[
'rows'] = 0;
4302 $this->stats_mrptoconsume[
'qty'] = 0.0;
4303 $this->stats_mrptoproduce[
'customers'] = 0;
4304 $this->stats_mrptoproduce[
'nb'] = 0;
4305 $this->stats_mrptoproduce[
'rows'] = 0;
4306 $this->stats_mrptoproduce[
'qty'] = 0.0;
4309 $result = $this->db->query($sql);
4311 while ($obj = $this->db->fetch_object($result)) {
4312 if ($obj->role ==
'toconsume' && empty($warehouseid)) {
4313 $this->stats_mrptoconsume[
'customers'] += (int) $obj->nb_customers;
4314 $this->stats_mrptoconsume[
'nb'] += (int) $obj->nb;
4315 $this->stats_mrptoconsume[
'rows'] += (int) $obj->nb_rows;
4316 $this->stats_mrptoconsume[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4318 if ($obj->role ==
'consumed' && empty($warehouseid)) {
4322 $this->stats_mrptoconsume[
'qty'] -= ($obj->qty ? (float) $obj->qty : 0.0);
4324 if ($obj->role ==
'toproduce') {
4326 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4328 $this->stats_mrptoproduce[
'customers'] += (int) $obj->nb_customers;
4329 $this->stats_mrptoproduce[
'nb'] += (int) $obj->nb;
4330 $this->stats_mrptoproduce[
'rows'] += (int) $obj->nb_rows;
4331 $this->stats_mrptoproduce[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4334 if ($obj->role ==
'produced') {
4339 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
4341 $this->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
4348 if ($this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] < 0) {
4349 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
4352 if ($this->stats_mrptoconsume[
'qty'] < 0) {
4353 $this->stats_mrptoconsume[
'qty'] = 0;
4355 if ($this->stats_mrptoproduce[
'qty'] < 0) {
4356 $this->stats_mrptoproduce[
'qty'] = 0;
4360 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
4361 $reshook = $hookmanager->executeHooks(
'loadStatsInProduction', $parameters, $this, $action);
4363 $this->stats_mrptoproduce = $hookmanager->resArray[
'stats_mrptoproduce'];
4368 $this->error = $this->db->error();
4383 global $user, $hookmanager, $action;
4385 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
4386 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
4387 $sql .=
" FROM ".$this->db->prefix().
"contratdet as cd";
4388 $sql .=
", ".$this->db->prefix().
"contrat as c";
4389 $sql .=
", ".$this->db->prefix().
"societe as s";
4390 $sql .=
" WHERE c.rowid = cd.fk_contrat";
4391 $sql .=
" AND c.fk_soc = s.rowid";
4392 $sql .=
" AND c.entity IN (".getEntity(
'contract').
")";
4393 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
4394 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4395 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
4399 $sql .=
" AND c.fk_soc = ".((int) $socid);
4402 $result = $this->db->query($sql);
4404 $obj = $this->db->fetch_object($result);
4405 $this->stats_contrat[
'customers'] = (int) $obj->nb_customers;
4406 $this->stats_contrat[
'nb'] = (int) $obj->nb;
4407 $this->stats_contrat[
'rows'] = (int) $obj->nb_rows;
4408 $this->stats_contrat[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
4413 if (is_array($TFather) && !empty($TFather)) {
4414 foreach ($TFather as &$fatherData) {
4415 $pFather =
new Product($this->db);
4416 $pFather->id = $fatherData[
'id'];
4417 $qtyCoef = $fatherData[
'qty'];
4419 if ($fatherData[
'incdec']) {
4420 $pFather->load_stats_contrat($socid);
4422 if (!empty($pFather->stats_contrat)) {
4423 $this->stats_contrat[
'customers'] += $pFather->stats_contrat[
'customers'];
4424 $this->stats_contrat[
'nb'] += $pFather->stats_contrat[
'nb'];
4425 $this->stats_contrat[
'rows'] += $pFather->stats_contrat[
'rows'];
4426 $this->stats_contrat[
'qty'] += $pFather->stats_contrat[
'qty'] * $qtyCoef;
4433 $parameters = array(
'socid' => $socid);
4434 $reshook = $hookmanager->executeHooks(
'loadStatsContract', $parameters, $this, $action);
4436 $this->stats_contrat = $hookmanager->resArray[
'stats_contrat'];
4441 $this->error = $this->db->error().
' sql='.$sql;
4456 global $user, $hookmanager, $action;
4458 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4459 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(".$this->db->ifsql(
'f.type != 2',
'fd.qty',
'fd.qty * -1').
") as qty";
4460 $sql .=
" FROM ".$this->db->prefix().
"facturedet as fd";
4461 $sql .=
", ".$this->db->prefix().
"facture as f";
4462 $sql .=
", ".$this->db->prefix().
"societe as s";
4463 $sql .=
" WHERE f.rowid = fd.fk_facture";
4464 $sql .=
" AND f.fk_soc = s.rowid";
4465 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4466 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4467 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4468 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4472 $sql .=
" AND f.fk_soc = ".((int) $socid);
4475 $result = $this->db->query($sql);
4477 $obj = $this->db->fetch_object($result);
4478 $this->stats_facture[
'customers'] = (int) $obj->nb_customers;
4479 $this->stats_facture[
'nb'] = (int) $obj->nb;
4480 $this->stats_facture[
'rows'] = (int) $obj->nb_rows;
4481 $this->stats_facture[
'qty'] = $obj->qty ? (float) $obj->qty : 0;
4486 if (is_array($TFather) && !empty($TFather)) {
4487 foreach ($TFather as &$fatherData) {
4488 $pFather =
new Product($this->db);
4489 $pFather->id = $fatherData[
'id'];
4490 $qtyCoef = $fatherData[
'qty'];
4492 if ($fatherData[
'incdec']) {
4493 $pFather->load_stats_facture($socid);
4495 if (!empty($pFather->stats_facture)) {
4496 $this->stats_facture[
'customers'] += $pFather->stats_facture[
'customers'];
4497 $this->stats_facture[
'nb'] += $pFather->stats_facture[
'nb'];
4498 $this->stats_facture[
'rows'] += $pFather->stats_facture[
'rows'];
4499 $this->stats_facture[
'qty'] += $pFather->stats_facture[
'qty'] * $qtyCoef;
4506 $parameters = array(
'socid' => $socid);
4507 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoice', $parameters, $this, $action);
4509 $this->stats_facture = $hookmanager->resArray[
'stats_facture'];
4514 $this->error = $this->db->error();
4530 global $user, $hookmanager, $action;
4532 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4533 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4534 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facturedet_rec as fd";
4535 $sql .=
", ".MAIN_DB_PREFIX.
"facture_rec as f";
4536 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
4537 $sql .=
" WHERE f.rowid = fd.fk_facture";
4538 $sql .=
" AND f.fk_soc = s.rowid";
4539 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4540 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4541 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4542 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4546 $sql .=
" AND f.fk_soc = ".((int) $socid);
4549 $result = $this->db->query($sql);
4551 $obj = $this->db->fetch_object($result);
4552 $this->stats_facturerec[
'customers'] = (int) $obj->nb_customers;
4553 $this->stats_facturerec[
'nb'] = (int) $obj->nb;
4554 $this->stats_facturerec[
'rows'] = (int) $obj->nb_rows;
4555 $this->stats_facturerec[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4560 if (is_array($TFather) && !empty($TFather)) {
4561 foreach ($TFather as &$fatherData) {
4562 $pFather =
new Product($this->db);
4563 $pFather->id = $fatherData[
'id'];
4564 $qtyCoef = $fatherData[
'qty'];
4566 if ($fatherData[
'incdec']) {
4567 $pFather->load_stats_facture($socid);
4569 $this->stats_facturerec[
'customers'] += $pFather->stats_facturerec[
'customers'];
4570 $this->stats_facturerec[
'nb'] += $pFather->stats_facturerec[
'nb'];
4571 $this->stats_facturerec[
'rows'] += $pFather->stats_facturerec[
'rows'];
4572 $this->stats_facturerec[
'qty'] += $pFather->stats_facturerec[
'qty'] * $qtyCoef;
4578 $parameters = array(
'socid' => $socid);
4579 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoiceRec', $parameters, $this, $action);
4581 $this->stats_facturerec = $hookmanager->resArray[
'stats_facturerec'];
4586 $this->error = $this->db->error();
4601 global $user, $hookmanager, $action;
4603 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
4604 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4605 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as fd";
4606 $sql .=
", ".$this->db->prefix().
"facture_fourn as f";
4607 $sql .=
", ".$this->db->prefix().
"societe as s";
4608 $sql .=
" WHERE f.rowid = fd.fk_facture_fourn";
4609 $sql .=
" AND f.fk_soc = s.rowid";
4610 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4611 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4612 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4613 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4617 $sql .=
" AND f.fk_soc = ".((int) $socid);
4620 $result = $this->db->query($sql);
4622 $obj = $this->db->fetch_object($result);
4623 $this->stats_facture_fournisseur[
'suppliers'] = (int) $obj->nb_suppliers;
4624 $this->stats_facture_fournisseur[
'nb'] = (int) $obj->nb;
4625 $this->stats_facture_fournisseur[
'rows'] = (int) $obj->nb_rows;
4626 $this->stats_facture_fournisseur[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4628 $parameters = array(
'socid' => $socid);
4629 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoice', $parameters, $this, $action);
4631 $this->stats_facture_fournisseur = $hookmanager->resArray[
'stats_facture_fournisseur'];
4636 $this->error = $this->db->error();
4651 global $user, $hookmanager, $action;
4653 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
4654 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4655 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facture_fourn_det_rec as fd";
4656 $sql .=
", ".MAIN_DB_PREFIX.
"facture_fourn_rec as f";
4657 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
4658 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4659 $sql .=
", ".MAIN_DB_PREFIX.
"societe_commerciaux as sc";
4661 $sql .=
" WHERE f.rowid = fd.fk_facture";
4662 $sql .=
" AND f.fk_soc = s.rowid";
4663 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4664 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4665 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4666 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4670 $sql .=
" AND f.fk_soc = ".((int) $socid);
4673 $result = $this->db->query($sql);
4675 $obj = $this->db->fetch_object($result);
4676 $this->stats_facturefournrec[
'suppliers'] = (int) $obj->nb_suppliers;
4677 $this->stats_facturefournrec[
'nb'] = (int) $obj->nb;
4678 $this->stats_facturefournrec[
'rows'] = (int) $obj->nb_rows;
4679 $this->stats_facturefournrec[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4681 $parameters = array(
'socid' => $socid);
4682 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoiceRec', $parameters, $this, $action);
4684 $this->stats_facturefournrec = $hookmanager->resArray[
'stats_facturefournrec'];
4689 $this->error = $this->db->error();
4708 $resql = $this->db->query($sql);
4710 $num = $this->db->num_rows($resql);
4713 $arr = $this->db->fetch_array($resql);
4714 if (is_array($arr)) {
4715 $keyfortab = (string) $arr[1];
4717 $keyfortab = substr($keyfortab, -2);
4720 if ($mode ==
'byunit') {
4721 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[0];
4722 } elseif ($mode ==
'bynumber') {
4723 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4724 } elseif ($mode ==
'byamount') {
4725 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4734 $this->error = $this->db->error().
' sql='.$sql;
4741 } elseif ($year == -1) {
4750 for ($j = 0; $j < 12; $j++) {
4752 $idx = ucfirst(
dol_trunc(
dol_print_date(
dol_mktime(12, 0, 0, $month, 1, 1970),
"%b"), 1,
'right',
'UTF-8', 1));
4755 $result[$j] = array($idx, isset($tab[$year.$month]) ? $tab[$year.$month] : 0);
4758 $month =
"0".($month - 1);
4760 $month = substr($month, 1);
4770 return array_reverse($result);
4785 public function get_nb_vente($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4790 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4791 if ($mode ==
'bynumber') {
4792 $sql .=
", count(DISTINCT f.rowid)";
4794 $sql .=
", sum(d.total_ht) as total_ht";
4795 $sql .=
" FROM ".$this->db->prefix().
"facturedet as d, ".$this->db->prefix().
"facture as f, ".$this->db->prefix().
"societe as s";
4796 if ($filteronproducttype >= 0) {
4797 $sql .=
", ".$this->db->prefix().
"product as p";
4799 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4800 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4802 $sql .=
" WHERE f.rowid = d.fk_facture";
4803 if ($this->
id > 0) {
4804 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4806 $sql .=
" AND d.fk_product > 0";
4808 if ($filteronproducttype >= 0) {
4809 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4811 $sql .=
" AND f.fk_soc = s.rowid";
4812 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4813 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4814 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4817 $sql .=
" AND f.fk_soc = ".((int) $socid);
4819 $sql .= $morefilter;
4820 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4821 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4823 return $this->
_get_stats($sql, $mode, $year);
4838 public function get_nb_achat($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4843 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4844 if ($mode ==
'bynumber') {
4845 $sql .=
", count(DISTINCT f.rowid)";
4847 $sql .=
", sum(d.total_ht) as total_ht";
4848 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as d, ".$this->db->prefix().
"facture_fourn as f, ".$this->db->prefix().
"societe as s";
4849 if ($filteronproducttype >= 0) {
4850 $sql .=
", ".$this->db->prefix().
"product as p";
4852 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4853 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4855 $sql .=
" WHERE f.rowid = d.fk_facture_fourn";
4856 if ($this->
id > 0) {
4857 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4859 $sql .=
" AND d.fk_product > 0";
4861 if ($filteronproducttype >= 0) {
4862 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4864 $sql .=
" AND f.fk_soc = s.rowid";
4865 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4866 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4867 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4870 $sql .=
" AND f.fk_soc = ".((int) $socid);
4872 $sql .= $morefilter;
4873 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4874 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4876 return $this->
_get_stats($sql, $mode, $year);
4890 public function get_nb_propal($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4893 global $user, $hookmanager;
4895 $sql =
"SELECT sum(d.qty) as qty, date_format(p.datep, '%Y%m')";
4896 if ($mode ==
'bynumber') {
4897 $sql .=
", count(DISTINCT p.rowid)";
4899 $sql .=
", sum(d.total_ht) as total_ht";
4900 $sql .=
" FROM ".$this->db->prefix().
"propaldet as d, ".$this->db->prefix().
"propal as p, ".$this->db->prefix().
"societe as s";
4901 if ($filteronproducttype >= 0) {
4902 $sql .=
", ".$this->db->prefix().
"product as prod";
4904 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4905 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4907 $sql .=
" WHERE p.rowid = d.fk_propal";
4908 if ($this->
id > 0) {
4909 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4911 $sql .=
" AND d.fk_product > 0";
4913 if ($filteronproducttype >= 0) {
4914 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4916 $sql .=
" AND p.fk_soc = s.rowid";
4917 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
4918 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4919 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4922 $sql .=
" AND p.fk_soc = ".((int) $socid);
4924 $sql .= $morefilter;
4925 $parameters = array(
'socid' => $user->socid);
4926 $hookmanager->executeHooks(
'productGetNbPropal', $parameters, $this);
4927 $sql .= $hookmanager->resPrint;
4928 $sql .=
" GROUP BY date_format(p.datep,'%Y%m')";
4929 $sql .=
" ORDER BY date_format(p.datep,'%Y%m') DESC";
4930 return $this->
_get_stats($sql, $mode, $year);
4949 $sql =
"SELECT sum(d.qty) as qty, date_format(p.date_valid, '%Y%m')";
4950 if ($mode ==
'bynumber') {
4951 $sql .=
", count(DISTINCT p.rowid)";
4953 $sql .=
", sum(d.total_ht) as total_ht";
4954 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as d, ".$this->db->prefix().
"supplier_proposal as p, ".$this->db->prefix().
"societe as s";
4955 if ($filteronproducttype >= 0) {
4956 $sql .=
", ".$this->db->prefix().
"product as prod";
4958 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4959 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4961 $sql .=
" WHERE p.rowid = d.fk_supplier_proposal";
4962 if ($this->
id > 0) {
4963 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4965 $sql .=
" AND d.fk_product > 0";
4967 if ($filteronproducttype >= 0) {
4968 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4970 $sql .=
" AND p.fk_soc = s.rowid";
4971 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
4972 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4973 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4976 $sql .=
" AND p.fk_soc = ".((int) $socid);
4978 $sql .= $morefilter;
4979 $sql .=
" GROUP BY date_format(p.date_valid,'%Y%m')";
4980 $sql .=
" ORDER BY date_format(p.date_valid,'%Y%m') DESC";
4982 return $this->
_get_stats($sql, $mode, $year);
4996 public function get_nb_order($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4999 global $user, $hookmanager;
5001 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
5002 if ($mode ==
'bynumber') {
5003 $sql .=
", count(DISTINCT c.rowid)";
5005 $sql .=
", sum(d.total_ht) as total_ht";
5006 $sql .=
" FROM ".$this->db->prefix().
"commandedet as d, ".$this->db->prefix().
"commande as c, ".$this->db->prefix().
"societe as s";
5007 if ($filteronproducttype >= 0) {
5008 $sql .=
", ".$this->db->prefix().
"product as p";
5010 if (!$user->hasRight(
'societe',
'client',
'voir')) {
5011 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
5013 $sql .=
" WHERE c.rowid = d.fk_commande";
5014 if ($this->
id > 0) {
5015 $sql .=
" AND d.fk_product = ".((int) $this->
id);
5017 $sql .=
" AND d.fk_product > 0";
5019 if ($filteronproducttype >= 0) {
5020 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
5022 $sql .=
" AND c.fk_soc = s.rowid";
5023 $sql .=
" AND c.entity IN (".getEntity(
'commande').
")";
5024 if (!$user->hasRight(
'societe',
'client',
'voir')) {
5025 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
5028 $sql .=
" AND c.fk_soc = ".((int) $socid);
5030 $sql .= $morefilter;
5031 $parameters = array(
'socid' => $user->socid);
5032 $hookmanager->executeHooks(
'productGetNbOrder', $parameters, $this);
5033 $sql .= $hookmanager->resPrint;
5034 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
5035 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
5037 return $this->
_get_stats($sql, $mode, $year);
5056 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
5057 if ($mode ==
'bynumber') {
5058 $sql .=
", count(DISTINCT c.rowid)";
5060 $sql .=
", sum(d.total_ht) as total_ht";
5061 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as d, ".$this->db->prefix().
"commande_fournisseur as c, ".$this->db->prefix().
"societe as s";
5062 if ($filteronproducttype >= 0) {
5063 $sql .=
", ".$this->db->prefix().
"product as p";
5065 if (!$user->hasRight(
'societe',
'client',
'voir')) {
5066 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
5068 $sql .=
" WHERE c.rowid = d.fk_commande";
5069 if ($this->
id > 0) {
5070 $sql .=
" AND d.fk_product = ".((int) $this->
id);
5072 $sql .=
" AND d.fk_product > 0";
5074 if ($filteronproducttype >= 0) {
5075 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
5077 $sql .=
" AND c.fk_soc = s.rowid";
5078 $sql .=
" AND c.entity IN (".getEntity(
'supplier_order').
")";
5079 if (!$user->hasRight(
'societe',
'client',
'voir')) {
5080 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
5083 $sql .=
" AND c.fk_soc = ".((int) $socid);
5085 $sql .= $morefilter;
5086 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
5087 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
5089 return $this->
_get_stats($sql, $mode, $year);
5103 public function get_nb_contract($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
5108 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_contrat, '%Y%m')";
5109 if ($mode ==
'bynumber') {
5110 $sql .=
", count(DISTINCT c.rowid)";
5112 $sql .=
", sum(d.total_ht) as total_ht";
5113 $sql .=
" FROM ".$this->db->prefix().
"contratdet as d, ".$this->db->prefix().
"contrat as c, ".$this->db->prefix().
"societe as s";
5114 if ($filteronproducttype >= 0) {
5115 $sql .=
", ".$this->db->prefix().
"product as p";
5117 if (!$user->hasRight(
'societe',
'client',
'voir')) {
5118 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
5120 $sql .=
" WHERE c.entity IN (".getEntity(
'contract').
")";
5121 $sql .=
" AND c.rowid = d.fk_contrat";
5123 if ($this->
id > 0) {
5124 $sql .=
" AND d.fk_product = ".((int) $this->
id);
5126 $sql .=
" AND d.fk_product > 0";
5128 if ($filteronproducttype >= 0) {
5129 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
5131 $sql .=
" AND c.fk_soc = s.rowid";
5133 if (!$user->hasRight(
'societe',
'client',
'voir')) {
5134 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
5137 $sql .=
" AND c.fk_soc = ".((int) $socid);
5139 $sql .= $morefilter;
5140 $sql .=
" GROUP BY date_format(c.date_contrat,'%Y%m')";
5141 $sql .=
" ORDER BY date_format(c.date_contrat,'%Y%m') DESC";
5143 return $this->
_get_stats($sql, $mode, $year);
5157 public function get_nb_mos($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
5162 $sql =
"SELECT sum(d.qty), date_format(d.date_valid, '%Y%m')";
5163 if ($mode ==
'bynumber') {
5164 $sql .=
", count(DISTINCT d.rowid)";
5166 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as d LEFT JOIN ".$this->db->prefix().
"societe as s ON d.fk_soc = s.rowid";
5167 if ($filteronproducttype >= 0) {
5168 $sql .=
", ".$this->db->prefix().
"product as p";
5170 if (!$user->hasRight(
'societe',
'client',
'voir')) {
5171 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
5174 $sql .=
" WHERE d.entity IN (".getEntity(
'mo').
")";
5175 $sql .=
" AND d.status > 0";
5177 if ($this->
id > 0) {
5178 $sql .=
" AND d.fk_product = ".((int) $this->
id);
5180 $sql .=
" AND d.fk_product > 0";
5182 if ($filteronproducttype >= 0) {
5183 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
5186 if (!$user->hasRight(
'societe',
'client',
'voir')) {
5187 $sql .=
" AND d.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
5190 $sql .=
" AND d.fk_soc = ".((int) $socid);
5192 $sql .= $morefilter;
5193 $sql .=
" GROUP BY date_format(d.date_valid,'%Y%m')";
5194 $sql .=
" ORDER BY date_format(d.date_valid,'%Y%m') DESC";
5196 return $this->
_get_stats($sql, $mode, $year);
5216 if (!is_numeric($id_pere)) {
5219 if (!is_numeric($id_fils)) {
5222 if (!is_numeric($incdec)) {
5232 $sql =
"SELECT fk_product_pere from ".$this->db->prefix().
"product_association";
5233 $sql .=
" WHERE fk_product_pere = ".((int) $id_fils).
" AND fk_product_fils = ".((int) $id_pere);
5234 if (!$this->db->query($sql)) {
5235 dol_print_error($this->db);
5239 $sql =
"SELECT MAX(rang) as max_rank FROM ".$this->db->prefix().
"product_association";
5240 $sql .=
" WHERE fk_product_pere = ".((int) $id_pere);
5241 $resql = $this->db->query($sql);
5243 $obj = $this->db->fetch_object($resql);
5244 $rank = $obj->max_rank + 1;
5246 $sql =
"INSERT INTO ".$this->db->prefix().
"product_association(fk_product_pere,fk_product_fils,qty,incdec,rang)";
5247 $sql .=
" VALUES (".((int) $id_pere).
", ".((int) $id_fils).
", ".
price2num($qty,
'MS').
", ".((int) $incdec).
", ".((int) $rank).
")";
5248 if (! $this->db->query($sql)) {
5249 dol_print_error($this->db);
5254 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_ADD', $user);
5256 $this->error = $this->db->lasterror();
5257 dol_syslog(get_class($this).
'::addSubproduct error='.$this->error, LOG_ERR);
5266 dol_print_error($this->db);
5289 if (!is_numeric($id_pere)) {
5292 if (!is_numeric($id_fils)) {
5295 if (!is_numeric($incdec)) {
5298 if (!is_numeric($qty)) {
5302 $sql =
'UPDATE '.$this->db->prefix().
'product_association SET ';
5303 $sql .=
'qty = '.price2num($qty,
'MS');
5304 $sql .=
',incdec = '.((int) $incdec);
5305 $sql .=
' WHERE fk_product_pere = '.((int) $id_pere).
' AND fk_product_fils = '.((int) $id_fils);
5307 if (!$this->db->query($sql)) {
5308 dol_print_error($this->db);
5313 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_UPDATE', $user);
5315 $this->error = $this->db->lasterror();
5316 dol_syslog(get_class($this).
'::updateSubproduct error='.$this->error, LOG_ERR);
5340 if (!is_numeric($fk_parent)) {
5343 if (!is_numeric($fk_child)) {
5347 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
5348 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5349 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
5351 dol_syslog(get_class($this).
'::del_sousproduit', LOG_DEBUG);
5352 if (!$this->db->query($sql)) {
5353 dol_print_error($this->db);
5358 $sqlrank =
"SELECT rowid, rang FROM ".$this->db->prefix().
"product_association";
5359 $sqlrank .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5360 $sqlrank .=
" ORDER BY rang";
5361 $resqlrank = $this->db->query($sqlrank);
5364 while ($objrank = $this->db->fetch_object($resqlrank)) {
5366 $sql =
"UPDATE ".$this->db->prefix().
"product_association";
5367 $sql .=
" SET rang = ".((int) $cpt);
5368 $sql .=
" WHERE rowid = ".((int) $objrank->rowid);
5369 if (! $this->db->query($sql)) {
5370 dol_print_error($this->db);
5378 $result = $this->call_trigger(
'PRODUCT_SUBPRODUCT_DELETE', $user);
5380 $this->error = $this->db->lasterror();
5381 dol_syslog(get_class($this).
'::delSubproduct error='.$this->error, LOG_ERR);
5401 $sql =
"SELECT fk_product_pere, qty, incdec";
5402 $sql .=
" FROM ".$this->db->prefix().
"product_association";
5403 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5404 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
5406 $result = $this->db->query($sql);
5408 $num = $this->db->num_rows($result);
5411 $obj = $this->db->fetch_object($result);
5413 $this->is_sousproduit_qty = $obj->qty;
5414 $this->is_sousproduit_incdec = $obj->incdec;
5421 dol_print_error($this->db);
5445 dol_syslog(get_class($this).
"::add_fournisseur id_fourn = ".$id_fourn.
" ref_fourn=".$ref_fourn.
" quantity=".$quantity, LOG_DEBUG);
5452 $sql =
"SELECT rowid, fk_product";
5453 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5454 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5455 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5456 $sql .=
" AND fk_product <> ".((int) $this->
id);
5457 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5459 $resql = $this->db->query($sql);
5461 $obj = $this->db->fetch_object($resql);
5464 $this->product_id_already_linked = $obj->fk_product;
5467 $this->db->free($resql);
5471 $sql =
"SELECT rowid";
5472 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5473 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5475 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5477 $sql .=
" AND (ref_fourn = '' OR ref_fourn IS NULL)";
5479 $sql .=
" AND quantity = ".((float) $quantity);
5480 $sql .=
" AND fk_product = ".((int) $this->
id);
5481 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5483 $resql = $this->db->query($sql);
5485 $obj = $this->db->fetch_object($resql);
5489 $sql =
"INSERT INTO ".$this->db->prefix().
"product_fournisseur_price(";
5492 $sql .=
", fk_product";
5494 $sql .=
", ref_fourn";
5495 $sql .=
", quantity";
5496 $sql .=
", fk_user";
5498 $sql .=
") VALUES (";
5499 $sql .=
"'".$this->db->idate($now).
"'";
5500 $sql .=
", ".((int)
$conf->entity);
5501 $sql .=
", ".((int) $this->
id);
5502 $sql .=
", ".((int) $id_fourn);
5503 $sql .=
", '".$this->db->escape($ref_fourn).
"'";
5504 $sql .=
", ".((float) $quantity);
5505 $sql .=
", ".((int) $user->id);
5509 if ($this->db->query($sql)) {
5510 $this->product_fourn_price_id = $this->db->last_insert_id($this->db->prefix().
"product_fournisseur_price");
5513 $this->error = $this->db->lasterror();
5518 $this->product_fourn_price_id = $obj->rowid;
5522 $this->error = $this->db->lasterror();
5541 $sql =
"SELECT DISTINCT p.fk_soc";
5542 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as p";
5543 $sql .=
" WHERE p.fk_product = ".((int) $this->
id);
5544 $sql .=
" AND p.entity = ".((int)
$conf->entity);
5546 $result = $this->db->query($sql);
5548 $num = $this->db->num_rows($result);
5551 $obj = $this->db->fetch_object($result);
5552 $list[$i] = $obj->fk_soc;
5578 $sql =
"INSERT INTO ".$this->db->prefix().
"product_price (";
5580 $sql .=
", fk_product";
5581 $sql .=
", date_price";
5582 $sql .=
", price_level";
5584 $sql .=
", price_ttc";
5585 $sql .=
", price_min";
5586 $sql .=
", price_min_ttc";
5587 $sql .=
", price_base_type";
5588 $sql .=
", price_label";
5589 $sql .=
", default_vat_code";
5591 $sql .=
", recuperableonly";
5592 $sql .=
", localtax1_tx";
5593 $sql .=
", localtax1_type";
5594 $sql .=
", localtax2_tx";
5595 $sql .=
", localtax2_type";
5596 $sql .=
", fk_user_author";
5598 $sql .=
", price_by_qty";
5599 $sql .=
", fk_price_expression";
5600 $sql .=
", fk_multicurrency";
5601 $sql .=
", multicurrency_code";
5602 $sql .=
", multicurrency_tx";
5603 $sql .=
", multicurrency_price";
5604 $sql .=
", multicurrency_price_ttc";
5608 $sql .=
", ".((int) $toId);
5609 $sql .=
", '".$this->db->idate($now).
"'";
5610 $sql .=
", price_level";
5612 $sql .=
", price_ttc";
5613 $sql .=
", price_min";
5614 $sql .=
", price_min_ttc";
5615 $sql .=
", price_base_type";
5616 $sql .=
", price_label";
5617 $sql .=
", default_vat_code";
5619 $sql .=
", recuperableonly";
5620 $sql .=
", localtax1_tx";
5621 $sql .=
", localtax1_type";
5622 $sql .=
", localtax2_tx";
5623 $sql .=
", localtax2_type";
5624 $sql .=
", ".((int) $user->id);
5626 $sql .=
", price_by_qty";
5627 $sql .=
", fk_price_expression";
5628 $sql .=
", fk_multicurrency";
5629 $sql .=
", multicurrency_code";
5630 $sql .=
", multicurrency_tx";
5631 $sql .=
", multicurrency_price";
5632 $sql .=
", multicurrency_price_ttc";
5633 $sql .=
" FROM ".$this->db->prefix().
"product_price as ps";
5634 $sql .=
" WHERE ps.fk_product = ".((int) $fromId);
5635 $sql .=
" AND ps.date_price IN (SELECT MAX(pd.date_price) FROM ".$this->db->prefix().
"product_price as pd WHERE pd.fk_product = ".((int) $fromId).
" AND pd.price_level = ps.price_level)";
5636 $sql .=
" ORDER BY ps.date_price DESC";
5639 $resql = $this->db->query($sql);
5641 $this->db->rollback();
5644 $this->db->free($resql);
5658 $this->db->commit();
5675 $sql =
'INSERT INTO '.$this->db->prefix().
'product_association (fk_product_pere, fk_product_fils, qty, incdec)';
5676 $sql .=
" SELECT ".((int) $toId).
", fk_product_fils, qty, incdec FROM ".$this->db->prefix().
"product_association";
5677 $sql .=
" WHERE fk_product_pere = ".((int) $fromId);
5679 dol_syslog(get_class($this).
'::clone_association', LOG_DEBUG);
5680 if (!$this->db->query($sql)) {
5681 $this->db->rollback();
5685 $this->db->commit();
5718 $sql =
"INSERT ".$this->db->prefix().
"product_fournisseur_price (";
5719 $sql .=
" datec, fk_product, fk_soc, price, quantity, fk_user, tva_tx)";
5720 $sql .=
" SELECT '".$this->db->idate($now).
"', ".((int) $toId).
", fk_soc, price, quantity, fk_user, tva_tx";
5721 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5722 $sql .=
" WHERE fk_product = ".((int) $fromId);
5724 dol_syslog(get_class($this).
'::clone_fournisseurs', LOG_DEBUG);
5725 $resql = $this->db->query($sql);
5727 $this->db->rollback();
5730 $this->db->commit();
5748 public function fetch_prod_arbo(
$prod, $compl_path =
'', $multiply = 1, $level = 1, $id_parent = 0, $ignore_stock_load = 0)
5753 if ($multiply < 1) {
5754 dol_syslog(get_class($this).
'::'.__FUNCTION__.
' Product quantity rounded up to 1 from '.$multiply.
'. May result in unexpected end quantity for product children of '.$id_parent, LOG_WARNING);
5758 foreach (
$prod as $id_product => $desc_pere) {
5759 if (is_array($desc_pere)) {
5760 $id = (!empty($desc_pere[0]) ? $desc_pere[0] :
'');
5761 $nb = (!empty($desc_pere[1]) ? $desc_pere[1] :
'');
5762 $type = (!empty($desc_pere[2]) ? $desc_pere[2] :
'');
5763 $label = (!empty($desc_pere[3]) ? $desc_pere[3] :
'');
5764 $incdec = (!empty($desc_pere[4]) ? $desc_pere[4] : 0);
5767 if (is_null($tmpproduct)) {
5768 $tmpproduct =
new Product($this->db);
5770 $tmpproduct->fetch($id);
5772 if (empty($ignore_stock_load) && ($tmpproduct->isProduct() ||
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES'))) {
5773 $tmpproduct->load_stock(
'nobatch,novirtual');
5776 $this->res[] = array(
5778 'id_parent' => $id_parent,
5779 'ref' => $tmpproduct->ref,
5781 'nb_total' => $nb * $multiply,
5782 'stock' => $tmpproduct->stock_reel,
5783 'stock_alert' => $tmpproduct->seuil_stock_alerte,
5785 'fullpath' => $compl_path.$label,
5787 'desiredstock' => $tmpproduct->desiredstock,
5789 'incdec' => $incdec,
5790 'entity' => $tmpproduct->entity
5794 if (isset($desc_pere[
'childs']) && is_array($desc_pere[
'childs'])) {
5795 if (!is_int($desc_pere[1] * $multiply)) {
5796 dol_syslog(get_class($this).
'::'.__FUNCTION__.
' Source product quantity and multiplier may result in unexpected end quantity for '.$label.
'/'.$multiply.
' Child product:'.json_encode($desc_pere), LOG_WARNING);
5800 $this->
fetch_prod_arbo($desc_pere[
'childs'], $compl_path.$desc_pere[3].
" -> ", (
int) ceil($desc_pere[1] * $multiply), $level + 1, $id, $ignore_stock_load);
5818 $this->res = array();
5819 if (isset($this->sousprods) && is_array($this->sousprods)) {
5820 foreach ($this->sousprods as $prod_name => $desc_product) {
5821 if (is_array($desc_product)) {
5822 $this->
fetch_prod_arbo($desc_product,
"", $multiply, 1, $this->
id, $ignore_stock_load);
5840 $sql =
"SELECT COUNT(pa.rowid) as nb";
5841 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa";
5843 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id).
" OR pa.fk_product_pere = ".((int) $this->
id);
5844 } elseif ($mode == -1) {
5845 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id);
5846 } elseif ($mode == 1) {
5847 $sql .=
" WHERE pa.fk_product_pere = ".((int) $this->
id);
5850 $resql = $this->db->query($sql);
5852 $obj = $this->db->fetch_object($resql);
5854 $nb = (int) $obj->nb;
5874 $sql =
"SELECT count(rowid) as nb FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_parent = ".((int) $this->
id);
5875 $sql .=
" AND entity IN (".getEntity(
'product').
")";
5877 $resql = $this->db->query($sql);
5879 $obj = $this->db->fetch_object($resql);
5881 $nb = (int) $obj->nb;
5897 $sql =
"SELECT rowid FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_child = ".((int) $this->
id).
" AND entity IN (".
getEntity(
'product').
")";
5899 $query = $this->db->query($sql);
5902 if (!$this->db->num_rows($query)) {
5907 dol_print_error($this->db);
5923 $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";
5924 $sql .=
", p.tosell as status, p.tobuy as status_buy";
5925 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa,";
5926 $sql .=
" ".$this->db->prefix().
"product as p";
5927 $sql .=
" WHERE p.rowid = pa.fk_product_pere";
5928 $sql .=
" AND pa.fk_product_fils = ".((int) $this->
id);
5930 $res = $this->db->query($sql);
5933 while ($record = $this->db->fetch_array($res)) {
5935 $prods[$record[
'id']] = array();
5936 $prods[$record[
'id']][
'id'] = $record[
'rowid'];
5937 $prods[$record[
'id']][
'ref'] = $record[
'ref'];
5938 $prods[$record[
'id']][
'label'] = $record[
'label'];
5939 $prods[$record[
'id']][
'qty'] = $record[
'qty'];
5940 $prods[$record[
'id']][
'incdec'] = $record[
'incdec'];
5941 $prods[$record[
'id']][
'fk_product_type'] = $record[
'fk_product_type'];
5942 $prods[$record[
'id']][
'entity'] = $record[
'entity'];
5943 $prods[$record[
'id']][
'status'] = $record[
'status'];
5944 $prods[$record[
'id']][
'status_buy'] = $record[
'status_buy'];
5948 dol_print_error($this->db);
5963 public function getChildsArbo($id, $firstlevelonly = 0, $level = 1, $parents = array())
5969 $sql =
"SELECT p.rowid, p.ref, p.label as label, p.fk_product_type,";
5970 $sql .=
" pa.qty as qty, pa.fk_product_fils as id, pa.incdec,";
5971 $sql .=
" pa.rowid as fk_association, pa.rang";
5972 $sql .=
" FROM ".$this->db->prefix().
"product as p,";
5973 $sql .=
" ".$this->db->prefix().
"product_association as pa";
5974 $sql .=
" WHERE p.rowid = pa.fk_product_fils";
5975 $sql .=
" AND pa.fk_product_pere = ".((int) $id);
5976 $sql .=
" AND pa.fk_product_fils <> ".((int) $id);
5977 $sql .=
" ORDER BY pa.rang";
5979 dol_syslog(get_class($this).
'::getChildsArbo id='.$id.
' level='.$level.
' parents='.(is_array($parents) ? implode(
',', $parents) : $parents), LOG_DEBUG);
5986 $res = $this->db->query($sql);
5989 if ($this->db->num_rows($res) > 0) {
5993 while ($rec = $this->db->fetch_array($res)) {
5994 if (in_array($rec[
'id'], $parents)) {
5995 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);
5999 $prods[$rec[
'rowid']] = array(
6002 2 => $rec[
'fk_product_type'],
6003 3 => $this->db->escape($rec[
'label']),
6004 4 => $rec[
'incdec'],
6006 6 => $rec[
'fk_association'],
6011 if (empty($firstlevelonly)) {
6012 $listofchilds = $this->
getChildsArbo($rec[
'rowid'], 0, $level + 1, $parents);
6013 foreach ($listofchilds as $keyChild => $valueChild) {
6014 $prods[$rec[
'rowid']][
'childs'][$keyChild] = $valueChild;
6021 dol_print_error($this->db);
6038 foreach ($this->
getChildsArbo($this->
id) as $keyChild => $valueChild) {
6039 $parent[$this->label][$keyChild] = $valueChild;
6041 foreach ($parent as $key => $value) {
6042 $this->sousprods[$key] = $value;
6055 global
$conf, $langs, $user;
6057 $langs->loadLangs(array(
'products',
'other'));
6060 $nofetch = !empty($params[
'nofetch']);
6063 return [
'optimize' => $langs->trans(
"ShowProduct")];
6067 $permissiontoreadproduct = 0;
6068 if ($this->
type == self::TYPE_PRODUCT && $user->hasRight(
'product',
'read')) {
6069 $permissiontoreadproduct = 1;
6071 if ($this->
type == self::TYPE_SERVICE && $user->hasRight(
'service',
'read')) {
6072 $permissiontoreadproduct = 1;
6075 if (!empty($this->entity) && $permissiontoreadproduct) {
6076 $tmpphoto = $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 80, 0, 0, 0, 0,
'1');
6077 if ($this->nbphoto > 0) {
6078 $datas[
'photo'] =
'<div class="photointooltip floatright">'.
"\n" . $tmpphoto .
'</div>';
6083 $datas[
'picto'] = img_picto(
'',
'product').
' <u class="paddingrightonly">'.$langs->trans(
"Product").
'</u>';
6085 $datas[
'picto'] = img_picto(
'',
'service').
' <u class="paddingrightonly">'.$langs->trans(
"Service").
'</u>';
6087 if (isset($this->
status) && isset($this->status_buy)) {
6088 $datas[
'status'] =
' '.$this->getLibStatut(5, 0) .
' '.$this->getLibStatut(5, 1);
6091 if (!empty($this->
ref)) {
6092 $datas[
'ref'] =
'<br><b>'.$langs->trans(
'ProductRef').
':</b> '.$this->ref;
6094 if (!empty($this->label)) {
6095 $datas[
'label'] =
'<br><b>'.$langs->trans(
'ProductLabel').
':</b> '.$this->label.
'<br>';
6098 if ($permissiontoreadproduct) {
6103 $datas[
'stockmanaged'] =
"<br><b>".$langs->trans(
"StockableProduct").
'</b>: '.yn($this->
isStockManaged());
6107 $langs->load(
"productbatch");
6108 $datas[
'batchstatus'] =
"<br><b>".$langs->trans(
"ManageLotSerial").
'</b>: '.$this->
getLibStatut(0, 2);
6109 if ($this->status_batch) {
6110 $datas[
'batchdlc'] =
"<br><b>".$langs->trans(
"BatchSellOrEatByMandatoryList", $langs->transnoentitiesnoconv(
"SellByDate"), $langs->transnoentitiesnoconv(
"EatByDate")).
'</b>: '.$this->
getSellOrEatByMandatoryLabel();
6115 $datas[
'barcode'] =
'<br><b>'.$langs->trans(
'BarCode').
':</b> '.$this->barcode;
6119 if ($this->weight) {
6120 $datas[
'weight'] =
"<br><b>".$langs->trans(
"Weight").
'</b>: '.$this->weight.
' '.
measuringUnitString(0,
"weight", $this->weight_units);
6123 if ($this->length) {
6124 $labelsize .=
"<b>".$langs->trans(
"Length").
'</b>: '.$this->length.
' '.
measuringUnitString(0,
'size', $this->length_units);
6127 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Width").
'</b>: '.$this->width.
' '.
measuringUnitString(0,
'size', $this->width_units);
6129 if ($this->height) {
6130 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Height").
'</b>: '.$this->height.
' '.
measuringUnitString(0,
'size', $this->height_units);
6133 $datas[
'size'] =
"<br>".$labelsize;
6136 $labelsurfacevolume =
"";
6137 if ($this->surface) {
6138 $labelsurfacevolume .=
"<b>".$langs->trans(
"Surface").
'</b>: '.$this->surface.
' '.
measuringUnitString(0,
'surface', $this->surface_units);
6140 if ($this->volume) {
6141 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Volume").
'</b>: '.$this->volume.
' '.
measuringUnitString(0,
'volume', $this->volume_units);
6143 if ($labelsurfacevolume) {
6144 $datas[
'surface'] =
"<br>" . $labelsurfacevolume;
6147 if ($this->
isService() && !empty($this->duration_value)) {
6149 $datas[
'duration'] =
'<br><b>'.$langs->trans(
"Duration").
':</b> '.$this->duration_value;
6150 if ($this->duration_value > 1) {
6151 $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"));
6152 } elseif ($this->duration_value > 0) {
6153 $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"));
6155 $datas[
'duration'] .= (!empty($this->duration_unit) && isset($dur[$this->duration_unit]) ?
" ".$langs->trans($dur[$this->duration_unit]) :
'');
6157 if (empty($user->socid)) {
6158 if ($this->
isStockManaged() && isset($this->pmp) && $this->pmp) {
6159 $datas[
'pmp'] =
"<br><b>".$langs->trans(
"PMPValue").
'</b>: '.
price($this->pmp, 0,
'', 1, -1, -1,
$conf->currency);
6163 if ($this->
status && isset($this->accountancy_code_sell)) {
6164 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
6165 $selllabel =
'<br>';
6166 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellCode').
':</b> '.
length_accountg($this->accountancy_code_sell);
6167 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellIntraCode').
':</b> '.
length_accountg($this->accountancy_code_sell_intra);
6168 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellExportCode').
':</b> '.
length_accountg($this->accountancy_code_sell_export);
6169 $datas[
'accountancysell'] = $selllabel;
6171 if ($this->status_buy && isset($this->accountancy_code_buy)) {
6172 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
6174 if (empty($this->
status)) {
6175 $buylabel .=
'<br>';
6177 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyCode').
':</b> '.
length_accountg($this->accountancy_code_buy);
6178 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyIntraCode').
':</b> '.
length_accountg($this->accountancy_code_buy_intra);
6179 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyExportCode').
':</b> '.
length_accountg($this->accountancy_code_buy_export);
6180 $datas[
'accountancybuy'] = $buylabel;
6186 require_once DOL_DOCUMENT_ROOT .
'/categories/class/categorie.class.php';
6187 $form =
new Form($this->db);
6188 $datas[
'categories'] =
'<br>' . $form->showCategories($this->
id, Categorie::TYPE_PRODUCT, 1);
6209 public function getNomUrl($withpicto = 0, $option =
'', $maxlength = 0, $save_lastsearch_value = -1, $notooltip = 0, $morecss =
'', $add_label = 0, $sep =
' - ', $addlinktonotes = 0)
6211 global $langs, $hookmanager, $user;
6213 include_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
6217 $newref = (string) $this->
ref;
6219 $newref =
dol_trunc($newref, $maxlength,
'middle');
6223 'objecttype' => ($this->
type == 1 ?
'service' :
'product'),
6224 'option' => $option,
6227 $classfortooltip =
'classfortooltip';
6230 $classfortooltip =
'classforajaxtooltip';
6231 $dataparams =
' data-params="'.dol_escape_htmltag(json_encode($params)).
'"';
6238 if (empty($notooltip)) {
6240 $label = $langs->trans(
"ShowProduct");
6241 $linkclose .=
' alt="'.dol_escape_htmltag($label, 1, 1).
'"';
6243 $linkclose .= ($label ?
' title="'.dol_escape_htmltag($label, 1, 1).
'"' :
' title="tocomplete"');
6244 $linkclose .= $dataparams.
' class="nowraponall '.$classfortooltip.($morecss ?
' '.$morecss :
'').
'"';
6246 $linkclose =
' class="nowraponall'.($morecss ?
' '.$morecss :
'').
'"';
6249 if ($option ==
'supplier' || $option ==
'category') {
6250 $baseurl = DOL_URL_ROOT.
'/product/price_suppliers.php';
6251 } elseif ($option ==
'stock') {
6252 $baseurl = DOL_URL_ROOT.
'/product/stock/product.php';
6253 } elseif ($option ==
'composition') {
6254 $baseurl = DOL_URL_ROOT.
'/product/composition/card.php';
6256 $baseurl = DOL_URL_ROOT.
'/product/card.php';
6258 $query = [
'id' => $this->id];
6260 if ($option !==
'nolink') {
6262 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
6263 if ($save_lastsearch_value == -1 && isset($_SERVER[
"PHP_SELF"]) && preg_match(
'/list\.php/', $_SERVER[
"PHP_SELF"])) {
6264 $add_save_lastsearch_values = 1;
6266 if ($add_save_lastsearch_values) {
6267 $query = array_merge($query, [
'save_lastsearch_values' => 1]);
6272 $linkstart =
'<a href="'.$url.
'"';
6273 $linkstart .= $linkclose.
'>';
6276 $result .= $linkstart;
6279 $result .= (img_object(($notooltip ?
'' : $label),
'product',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
6282 $result .= (img_object(($notooltip ?
'' : $label),
'service',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
6285 $result .=
'<span class="aaa">'.dol_escape_htmltag($newref).
'</span>';
6286 $result .= $linkend;
6287 if ($withpicto != 2) {
6288 $result .= (($add_label && $this->label) ? $sep.dol_trunc($this->label, ($add_label > 1 ? $add_label : 0)) :
'');
6291 if ($addlinktonotes) {
6292 $txttoshow = ($user->socid > 0 ? $this->note_public : $this->note_private);
6295 $result .=
' <span class="note inline-block">';
6296 $result .=
'<a href="'.DOL_URL_ROOT.
'/product/note.php?id='.$this->
id.
'" class="classfortooltip" title="'.
dol_escape_htmltag($notetoshow).
'">';
6297 $result .= img_picto(
'',
'note');
6299 $result .=
'</span>';
6304 $hookmanager->initHooks(array(
'productdao'));
6305 $parameters = array(
'id' => $this->
id,
'getnomurl' => &$result,
'label' => &$label);
6306 $reshook = $hookmanager->executeHooks(
'getNomUrl', $parameters, $this, $action);
6308 $result = $hookmanager->resPrint;
6310 $result .= $hookmanager->resPrint;
6327 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
6331 $langs->load(
"products");
6332 $outputlangs->load(
"products");
6338 if (!empty($this->model_pdf)) {
6339 $modele = $this->model_pdf;
6345 if (empty($modele)) {
6348 $modelpath =
"core/modules/product/doc/";
6349 return $this->
commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
6366 return $this->
LibStatut($this->status_buy, $mode, $type);
6368 return $this->
LibStatut($this->status_batch, $mode, $type);
6371 return $this->
LibStatut($this->status_buy, $mode, $type);
6389 $labelStatus = $labelStatusShort =
'';
6391 $langs->load(
'products');
6393 $langs->load(
"productbatch");
6399 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial')));
6400 return dolGetStatus($label);
6402 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort')));
6403 return dolGetStatus($label);
6407 return dolGetStatus($langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch'),
'',
'', empty($status) ?
'status5' :
'status4', 3,
'dot');
6413 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'));
6417 $statuttrans = empty($status) ?
'status5' :
'status4';
6422 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSellShort');
6423 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSell');
6424 } elseif ($type == 1) {
6425 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuyShort');
6426 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuy');
6427 } elseif ($type == 2) {
6428 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch');
6429 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort');
6431 } elseif ($status == 1) {
6434 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSellShort');
6435 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSell');
6436 } elseif ($type == 1) {
6437 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBuyShort');
6438 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBuy');
6439 } elseif ($type == 2) {
6440 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBatch');
6441 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort');
6443 } elseif ($type == 2 && $status == 2) {
6444 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSerial');
6445 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort');
6449 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'),
'',
'',
'status0', 0);
6451 return dolGetStatus($labelStatus, $labelStatusShort,
'', $statuttrans, $mode);
6465 $langs->load(
'products');
6468 if (isset($this->finished) && $this->finished >= 0) {
6469 $sql =
"SELECT label, code FROM ".$this->db->prefix().
"c_product_nature where code = ".((int) $this->finished).
" AND active=1";
6470 $resql = $this->db->query($sql);
6472 $this->error = $this->db->error().
' sql='.$sql;
6473 dol_syslog(__METHOD__.
' Error '.$this->error, LOG_ERR);
6475 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
6476 $label = $langs->trans($res[
'label']);
6478 $this->db->free($resql);
6502 public function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label =
'', $price = 0, $inventorycode =
'', $origin_element =
'', $origin_id =
null, $disablestockchangeforsubproduct = 0, $extrafields =
null)
6508 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6511 $nbpiece = (float) $nbpiece;
6516 $nbpiece = abs($nbpiece);
6523 $movementstock->setOrigin($origin_element, (
int) $origin_id);
6524 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'',
'',
'',
'',
false, 0, $disablestockchangeforsubproduct);
6528 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6529 $movementstock->array_options = $array_options;
6530 $movementstock->insertExtraFields();
6532 $this->db->commit();
6537 $this->db->rollback();
6566 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)
6572 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6575 $nbpiece = (float) $nbpiece;
6580 $nbpiece = abs($nbpiece);
6588 $movementstock->setOrigin($origin_element, (
int) $origin_id);
6589 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'', $dlc, $dluo, $lot,
false, 0, $disablestockchangeforsubproduct, 0, $force_update_batch);
6593 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6594 $movementstock->array_options = $array_options;
6595 $movementstock->insertExtraFields();
6597 $this->db->commit();
6600 $this->error = $movementstock->error;
6601 $this->errors = $movementstock->errors;
6603 $this->db->rollback();
6623 public function load_stock($option =
'', $includedraftpoforvirtual =
null, $dateofvirtualstock =
null)
6626 $this->stock_reel = 0;
6627 $this->stock_warehouse = array();
6628 $this->stock_theorique = 0;
6631 $warehouseStatus = array();
6632 if (preg_match(
'/warehouseclosed/', $option)) {
6635 if (preg_match(
'/warehouseopen/', $option)) {
6638 if (preg_match(
'/warehouseinternal/', $option)) {
6646 $sql =
"SELECT ps.rowid, ps.reel, ps.fk_entrepot";
6647 $sql .=
" FROM ".$this->db->prefix().
"product_stock as ps";
6648 $sql .=
", ".$this->db->prefix().
"entrepot as w";
6649 $sql .=
" WHERE w.entity IN (".getEntity(
'stock').
")";
6650 $sql .=
" AND w.rowid = ps.fk_entrepot";
6651 $sql .=
" AND ps.fk_product = ".((int) $this->
id);
6652 if (count($warehouseStatus)) {
6653 $sql .=
" AND w.statut IN (".$this->db->sanitize(implode(
',', $warehouseStatus)).
")";
6656 $sql .=
" ORDER BY ps.reel ".(getDolGlobalString(
'DO_NOT_TRY_TO_DEFRAGMENT_STOCKS_WAREHOUSE') ?
'DESC' :
'ASC');
6658 dol_syslog(get_class($this).
"::load_stock", LOG_DEBUG);
6659 $result = $this->db->query($sql);
6661 $num = $this->db->num_rows($result);
6665 $row = $this->db->fetch_object($result);
6666 $this->stock_warehouse[$row->fk_entrepot] =
new stdClass();
6667 $this->stock_warehouse[$row->fk_entrepot]->real = $row->reel;
6668 $this->stock_warehouse[$row->fk_entrepot]->id = $row->rowid;
6669 if ((!preg_match(
'/nobatch/', $option)) && $this->
hasbatch()) {
6670 $this->stock_warehouse[$row->fk_entrepot]->detail_batch =
Productbatch::findAll($this->db, $row->rowid, 1, $this->id);
6672 $this->stock_reel += $row->reel;
6675 $this->stock_reel = (float)
price2num($this->stock_reel,
'MS');
6677 $this->db->free($result);
6679 if (!preg_match(
'/novirtual/', $option)) {
6685 $this->error = $this->db->lasterror();
6704 global $hookmanager, $action;
6706 $stock_commande_client = 0;
6707 $stock_commande_fournisseur = 0;
6708 $stock_sending_client = 0;
6709 $stock_reception_fournisseur = 0;
6710 $stock_inproduction = 0;
6718 $dateofvirtualstockmin = 0;
6719 if (empty($dateofvirtualstock) && $horizoninDays !==
'') {
6720 include_once DOL_DOCUMENT_ROOT.
'/core/lib/date.lib.php';
6728 dol_print_error($this->db, $this->error);
6730 $stock_commande_client = $this->stats_commande[
'qty'];
6733 require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expedition.class.php';
6734 $filterShipmentStatus =
'';
6742 dol_print_error($this->db, $this->error);
6744 $stock_sending_client = $this->stats_expedition[
'qty'];
6748 $filterStatus =
getDolGlobalString(
'SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK',
'3,4');
6749 if (isset($includedraftpoforvirtual)) {
6750 $filterStatus =
'0,1,2,'.$filterStatus;
6754 dol_print_error($this->db, $this->error);
6756 $stock_commande_fournisseur = $this->stats_commande_fournisseur[
'qty'];
6761 if (isset($includedraftpoforvirtual)) {
6762 $filterStatus =
'0,'.$filterStatus;
6764 $result = $this->
load_stats_reception(0, $filterStatus, 1, $dateofvirtualstock, $dateofvirtualstockmin);
6766 dol_print_error($this->db, $this->error);
6768 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
6773 $result = $this->
load_stats_inproduction(0, $filterStatus, 1, $dateofvirtualstock, 0, $dateofvirtualstockmin);
6775 dol_print_error($this->db, $this->error);
6777 $stock_inproduction = $this->stats_mrptoproduce[
'qty'] - $this->stats_mrptoconsume[
'qty'];
6780 $this->stock_theorique = $this->stock_reel + $stock_inproduction;
6784 $weBillOrderOrShipmentReception =
getDolGlobalString(
'STOCK_DO_WE_BILL_ORDER_OR_SHIPMENTECEPTION_FOR_VIRTUALSTOCK',
'order');
6788 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6792 $result = $tmpnewprod->load_stats_commande(0,
'0', 1);
6793 $this->stock_theorique += $tmpnewprod->stats_commande[
'qty'];
6795 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6796 $this->stock_theorique -= $stock_commande_client;
6797 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6798 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6803 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6805 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6807 if (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER_INCLUDE_DRAFT')) {
6809 $result = $tmpnewprod->load_stats_commande_fournisseur(0,
'0', 1);
6810 $this->stock_theorique += $this->stats_commande_fournisseur[
'qty'];
6812 $this->stock_theorique -= $stock_reception_fournisseur;
6813 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6814 $this->stock_theorique += $stock_commande_fournisseur;
6815 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6816 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6819 $parameters = array(
'id' => $this->
id,
'includedraftpoforvirtual' => $includedraftpoforvirtual);
6821 $reshook = $hookmanager->executeHooks(
'loadvirtualstock', $parameters, $this, $action);
6823 $this->stock_theorique = $hookmanager->resArray[
'stock_theorique'];
6824 } elseif ($reshook == 0 && isset($hookmanager->resArray[
'stock_stats_hook'])) {
6825 $this->stock_theorique += $hookmanager->resArray[
'stock_stats_hook'];
6829 if (!empty($this->stock_warehouse) &&
getDolGlobalString(
'STOCK_ALLOW_VIRTUAL_STOCK_PER_WAREHOUSE')) {
6830 foreach ($this->stock_warehouse as $warehouseid => $stockwarehouse) {
6834 dol_print_error($this->db, $this->error);
6838 if ($this->fk_default_warehouse == $warehouseid) {
6839 $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']);
6841 $this->stock_warehouse[$warehouseid]->virtual = $this->stock_warehouse[$warehouseid]->real + $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'];
6858 $this->stock_warehouse = array();
6863 if (count($prods_arbo) > 0) {
6864 $productCachedList = array();
6865 $stockByComponentList = array();
6867 foreach ($prods_arbo as $componentArr) {
6868 $componentId = $componentArr[
'id'];
6870 if ($componentArr[
'incdec'] == 1) {
6871 if (!isset($productCachedList[$componentId])) {
6872 $componentStatic =
new self($this->db);
6873 $componentStatic->fetch($componentId);
6875 $childrenNb = $componentStatic->hasFatherOrChild(1);
6876 if ($childrenNb == 0) {
6877 $componentStatic->load_stock(
'nobatch,novirtual');
6878 if (!isset($stockByComponentList[$componentId])) {
6879 $stockByComponentList[$componentId] = array(
6883 $stockByComponentList[$componentId][
'qty_need'] += $componentArr[
'nb_total'];
6885 $productCachedList[$componentId] = $componentStatic;
6890 if (!empty($stockByComponentList)) {
6891 foreach ($stockByComponentList as $componentId => $stockByComponentArr) {
6892 if (!isset($productCachedList[$componentId])) {
6893 $componentStatic =
new self($this->db);
6894 $componentStatic->fetch($componentId);
6895 $componentStatic->load_stock(
'nobatch,novirtual');
6896 $productCachedList[$componentId] = $componentStatic;
6898 $component = $productCachedList[$componentId];
6901 if ($component->stock_reel < $stockByComponentArr[
'qty_need']) {
6904 $this->error =
'Not enough component [id='.$componentId.
'] in stock, real='.$component->stock_reel.
' and need='.$stockByComponentArr[
'qty_need'];
6905 $this->errors[] = $this->error;
6906 dol_syslog(__METHOD__.
' : '.$this->error, LOG_ERR);
6908 if (!empty($component->stock_warehouse)) {
6909 foreach ($component->stock_warehouse as $warehouseId => $warehouseObj) {
6910 $kitWarehouseAvailable =
new stdClass();
6911 $kitWarehouseAvailable->id = $warehouseObj->id;
6912 $kitWarehouseAvailable->real = $qtyWish;
6913 $this->stock_warehouse[$warehouseId] = $kitWarehouseAvailable;
6922 } elseif (
getDolGlobalInt(
'PRODUIT_SOUSPRODUITS_ALSO_ENABLE_PARENT_STOCK_MOVE') && empty($productCachedList)) {
6946 $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";
6947 $sql .=
" WHERE pb.fk_product_stock = ps.rowid AND ps.fk_product = ".((int) $this->
id).
" AND pb.batch = '".$this->db->escape($batch).
"'";
6948 $sql .=
" GROUP BY pb.batch, pb.eatby, pb.sellby";
6949 dol_syslog(get_class($this).
"::loadBatchInfo load first entry found for lot/serial = ".$batch, LOG_DEBUG);
6950 $resql = $this->db->query($sql);
6952 $num = $this->db->num_rows($resql);
6955 $obj = $this->db->fetch_object($resql);
6956 $result[] = array(
'batch' => $batch,
'eatby' => $this->db->jdate($obj->eatby),
'sellby' => $this->db->jdate($obj->sellby),
'qty' => $obj->qty);
6961 dol_print_error($this->db);
6962 $this->db->rollback();
6979 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6985 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos";
6987 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product').dol_sanitizeFileName($this->
ref);
6992 $dir_osencoded = $dir;
6994 if (is_dir($dir_osencoded)) {
6995 $originImage = $dir.
'/'.$file[
'name'];
7006 if (is_numeric($result) && $result > 0) {
7023 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
7024 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
7028 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos/";
7030 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product');
7034 if (file_exists($dir_osencoded)) {
7035 $handle = opendir($dir_osencoded);
7036 if (is_resource($handle)) {
7037 while (($file = readdir($handle)) !==
false) {
7039 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
7062 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
7063 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
7069 $handle = @opendir($dir_osencoded);
7070 if (is_resource($handle)) {
7071 while (($file = readdir($handle)) !==
false) {
7073 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
7080 $photo_vignette =
'';
7082 if (preg_match(
'/('.$this->regeximgext.
')$/i', $photo, $regs)) {
7083 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $photo).
'_small'.$regs[0];
7086 $dirthumb = $dir.
'thumbs/';
7090 $obj[
'photo'] = $photo;
7091 if ($photo_vignette &&
dol_is_file($dirthumb.$photo_vignette)) {
7092 $obj[
'photo_vignette'] =
'thumbs/'.$photo_vignette;
7094 $obj[
'photo_vignette'] =
"";
7097 $tabobj[$nbphoto - 1] = $obj;
7100 if ($nbmax && $nbphoto >= $nbmax) {
7122 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
7123 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
7125 $dir = dirname($file).
'/';
7126 $dirthumb = $dir.
'/thumbs/';
7127 $filename = preg_replace(
'/'.preg_quote($dir,
'/').
'/i',
'', $file);
7133 if (preg_match(
'/('.$this->regeximgext.
')$/i', $filename, $regs)) {
7134 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_small'.$regs[0];
7135 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
7139 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_mini'.$regs[0];
7140 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
7157 $infoImg = getimagesize($file_osencoded);
7158 $this->imgWidth = $infoImg[0];
7159 $this->imgHeight = $infoImg[1];
7169 global $hookmanager;
7171 $this->nb = array();
7173 $sql =
"SELECT count(p.rowid) as nb, fk_product_type";
7174 $sql .=
" FROM ".$this->db->prefix().
"product as p";
7175 $sql .=
' WHERE p.entity IN ('.getEntity($this->element, 1).
')';
7177 if (is_object($hookmanager)) {
7178 $parameters = array();
7179 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
7180 $sql .= $hookmanager->resPrint;
7182 $sql .=
' GROUP BY fk_product_type';
7184 $resql = $this->db->query($sql);
7186 while ($obj = $this->db->fetch_object($resql)) {
7187 if ($obj->fk_product_type == 1) {
7188 $this->nb[
"services"] = $obj->nb;
7190 $this->nb[
"products"] = $obj->nb;
7193 $this->db->free($resql);
7196 dol_print_error($this->db);
7197 $this->error = $this->db->error();
7239 return $this->mandatory_period == 1;
7249 return $this->status_batch > 0;
7269 $dirsociete = array_merge(array(
'/core/modules/barcode/'),
$conf->modules_parts[
'barcode']);
7270 foreach ($dirsociete as $dirroot) {
7278 '@phan-var-force ModeleNumRefBarCode $mod';
7280 $result = $mod->getNextValue(
$object, $type);
7282 dol_syslog(get_class($this).
"::get_barcode barcode=".$result.
" module=".$var);
7299 $this->specimen = 1;
7301 $this->
ref =
'PRODUCT_SPEC';
7302 $this->label =
'PRODUCT SPECIMEN';
7303 $this->
description =
'This is description of this product specimen that was created the '.dol_print_date($now,
'dayhourlog').
'.';
7304 $this->specimen = 1;
7305 $this->country_id = 1;
7307 $this->status_buy = 1;
7309 $this->sell_or_eat_by_mandatory = 0;
7310 $this->note_private =
'This is a comment (private)';
7311 $this->note_public =
'This is a comment (public)';
7312 $this->date_creation = $now;
7313 $this->date_modification = $now;
7316 $this->weight_units = 3;
7319 $this->length_units = 1;
7321 $this->width_units = 0;
7322 $this->height =
null;
7323 $this->height_units =
null;
7325 $this->surface = 30;
7326 $this->surface_units = 0;
7327 $this->volume = 300;
7328 $this->volume_units = 0;
7330 $this->barcode = -1;
7348 if (empty($this->fk_unit)) {
7351 if (empty($outputlangs)) {
7352 $outputlangs = $langs;
7355 $outputlangs->load(
'products');
7358 $sql =
"SELECT code, label, short_label FROM ".$this->db->prefix().
"c_units where rowid = ".((int) $this->fk_unit);
7360 $resql = $this->db->query($sql);
7362 $this->error = $this->db->error();
7363 dol_syslog(get_class($this).
"::getLabelOfUnit Error ".$this->error, LOG_ERR);
7365 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
7366 if ($type ==
'short') {
7368 $label = $outputlangs->transnoentitiesnoconv($res[
'short_label']);
7370 $label = $outputlangs->trans($res[
'short_label']);
7372 } elseif ($type ==
'code') {
7373 $label = $res[
'code'];
7375 if ($outputlangs->trans(
'unit'.$res[
'code']) ==
'unit'.$res[
'code']) {
7377 $label = $res[
'label'];
7381 $label = $outputlangs->transnoentitiesnoconv(
'unit'.$res[
'code']);
7383 $label = $outputlangs->trans(
'unit'.$res[
'code']);
7388 $this->db->free($resql);
7402 $maxpricesupplier = 0;
7405 include_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.product.class.php';
7407 $product_fourn_list = $product_fourn->list_product_fournisseur_price($this->
id,
'',
'');
7409 if (is_array($product_fourn_list) && count($product_fourn_list) > 0) {
7410 foreach ($product_fourn_list as $productfourn) {
7411 if ($productfourn->fourn_unitprice > $maxpricesupplier) {
7412 $maxpricesupplier = $productfourn->fourn_unitprice;
7420 return $maxpricesupplier;
7436 require_once DOL_DOCUMENT_ROOT.
'/categories/class/categorie.class.php';
7437 return parent::setCategoriesCommon($categories, Categorie::TYPE_PRODUCT);
7451 $sql =
" DELETE FROM ".$dbs->prefix().
"product_customer_price";
7452 $sql .=
" WHERE fk_soc = ".(int) $origin_id;
7453 $sql .=
" AND fk_product IN (SELECT fk_product FROM (SELECT fk_product FROM ".$dbs->prefix().
"product_customer_price WHERE fk_soc = ".(int) $dest_id.
") AS tmp)";
7456 if (!$dbs->
query($sql)) {
7461 'product_customer_price',
7462 'product_customer_price_log'
7481 $sql =
"SELECT rowid, level, fk_level, var_percent, var_min_percent FROM ".$this->db->prefix().
"product_pricerules";
7482 $query = $this->db->query($sql);
7486 while ($result = $this->db->fetch_object($query)) {
7487 $rules[$result->level] = $result;
7496 for ($i = 1; $i <= $nbofproducts; $i++) {
7497 $price = $baseprice;
7498 $price_min = $baseprice;
7502 if ($i > 1 && isset($rules[$i]->var_percent) && $rules[$i]->var_percent) {
7503 $price = $prices[$rules[$i]->fk_level] * (1 + ($rules[$i]->var_percent / 100));
7506 $prices[$i] = $price;
7509 if (isset($rules[$i]->var_min_percent) && $rules[$i]->var_min_percent) {
7510 $price_min = $price * (1 - ($rules[$i]->var_min_percent / 100));
7514 $check_amount = (($price == $this->multiprices[$i]) && ($price_min == $this->multiprices_min[$i]));
7515 $check_type = ($baseprice == $this->multiprices_base_type[$i]);
7517 if ($check_amount && $check_type) {
7521 if ($this->
updatePrice($price, $price_type, $user, $price_vat, $price_min, $i, $npr, $psq, 1) < 0) {
7539 return $user->rights->produit;
7541 return $user->rights->service;
7553 $sql =
"SELECT p.rowid, p.ref, p.datec as date_creation, GREATEST(p.tms, pef.tms) as date_modification,";
7554 $sql .=
" p.fk_user_author, p.fk_user_modif";
7555 $sql .=
" FROM ".$this->db->prefix().$this->table_element.
" as p";
7556 $sql .=
" LEFT JOIN ".$this->db->prefix().$this->table_element.
"_extrafields as pef ON pef.fk_object=p.rowid";
7557 $sql .=
" WHERE p.rowid = ".((int) $id);
7559 $result = $this->db->query($sql);
7561 if ($this->db->num_rows($result)) {
7562 $obj = $this->db->fetch_object($result);
7564 $this->
id = $obj->rowid;
7565 $this->
ref = $obj->ref;
7567 $this->user_creation_id = $obj->fk_user_author;
7568 $this->user_modification_id = $obj->fk_user_modif;
7570 $this->date_creation = $this->db->jdate($obj->date_creation);
7571 $this->date_modification = $this->db->jdate($obj->date_modification);
7574 $this->db->free($result);
7576 dol_print_error($this->db);
7588 if (empty($this->duration_value)) {
7589 $this->errors[] =
'ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
7592 if ($this->duration_unit ==
's') {
7593 $prodDurationHours = 1. / 3600;
7594 } elseif ($this->duration_unit ==
'i' || $this->duration_unit ==
'mn' || $this->duration_unit ==
'min') {
7595 $prodDurationHours = 1. / 60;
7596 } elseif ($this->duration_unit ==
'h') {
7597 $prodDurationHours = 1.;
7598 } elseif ($this->duration_unit ==
'd') {
7599 $prodDurationHours = 24.;
7600 } elseif ($this->duration_unit ==
'w') {
7601 $prodDurationHours = 24. * 7;
7602 } elseif ($this->duration_unit ==
'm') {
7603 $prodDurationHours = 24. * 30;
7604 } elseif ($this->duration_unit ==
'y') {
7605 $prodDurationHours = 24. * 365;
7609 $this->errors[] =
'ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
7612 $prodDurationHours *= $this->duration_value;
7614 return $prodDurationHours;
7627 global $langs,
$conf;
7629 $selected = (empty($arraydata[
'selected']) ? 0 : $arraydata[
'selected']);
7631 $return =
'<div class="box-flex-item box-flex-grow-zero">';
7632 $return .=
'<div class="info-box info-box-sm">';
7633 $return .=
'<div class="info-box-img">';
7635 if ($this->entity !==
null && $this->
is_photo_available($conf->product->multidir_output[$this->entity])) {
7636 $label .= $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 120, 160, 0, 0, 0,
'',
'photoref photokanban');
7640 $label .= img_picto(
'',
'product');
7642 $label .= img_picto(
'',
'service');
7646 $return .=
'</div>';
7647 $return .=
'<div class="info-box-content">';
7648 $return .=
'<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">' . $this->
getNomUrl() .
'</span>';
7649 if ($selected >= 0) {
7650 $return .=
'<input id="cb'.$this->id.
'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->
id.
'"'.($selected ?
' checked="checked"' :
'').
'>';
7652 $return .=
'<br><span class="info-box-label opacitymedium inline-block tdoverflowmax150 valignmiddle" title="'.dol_escape_htmltag($this->label).
'">'.
dol_escape_htmltag($this->label).
'</span>';
7653 if ($this->price_base_type ==
'TTC') {
7654 $return .=
'<br><span class="info-box-status amount">'.price($this->price_ttc).
' '.$langs->trans(
"TTC").
'</span>';
7657 $return .=
'<br><span class="info-box-status amount">'.price($this->
price).
' '.$langs->trans(
"HT").
'</span>';
7662 $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>';
7667 $return .=
'<div class="info-box-status inline-block valignmiddle">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7669 $return .=
'<div class="info-box-status inline-block valignmiddle marginleftonly paddingleft">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7671 $return .=
'</div>';
7672 $return .=
'</div>';
7673 $return .=
'</div>';
7691 $sql =
"INSERT INTO ".$this->db->prefix().
"product_customer_price (";
7693 $sql .=
", fk_product";
7697 $sql .=
", price_ttc";
7698 $sql .=
", price_min";
7699 $sql .=
", price_min_ttc";
7700 $sql .=
", price_base_type";
7701 $sql .=
", default_vat_code";
7703 $sql .=
", recuperableonly";
7704 $sql .=
", localtax1_tx";
7705 $sql .=
", localtax1_type";
7706 $sql .=
", localtax2_tx";
7707 $sql .=
", localtax2_type";
7708 $sql .=
", fk_user";
7712 $sql .=
", ".((int) $toId);
7714 $sql .=
", '".$this->db->idate($now).
"'";
7716 $sql .=
", price_ttc";
7717 $sql .=
", price_min";
7718 $sql .=
", price_min_ttc";
7719 $sql .=
", price_base_type";
7720 $sql .=
", default_vat_code";
7722 $sql .=
", recuperableonly";
7723 $sql .=
", localtax1_tx";
7724 $sql .=
", localtax1_type";
7725 $sql .=
", localtax2_tx";
7726 $sql .=
", localtax2_type";
7727 $sql .=
", ".((int) $user->id);
7728 $sql .=
" FROM ".$this->db->prefix().
"product_customer_price pc";
7729 $sql .=
" WHERE pc.fk_product = ".((int) $fromId);
7730 $sql .=
" AND pc.datec IN (";
7731 $sql .=
" SELECT MAX(pd.datec)";
7732 $sql .=
" FROM ".$this->db->prefix().
"product_customer_price pd";
7733 $sql .=
" WHERE pd.fk_product = ".((int) $fromId);
7734 $sql .=
" AND pd.fk_soc = pc.fk_soc";
7739 $resql = $this->db->query($sql);
7741 $this->db->rollback();
7744 $this->db->free($resql);
7748 $sql_fields =
"SHOW COLUMNS FROM ".MAIN_DB_PREFIX.
"product_customer_price_extrafields";
7749 $res_fields = $this->db->query($sql_fields);
7751 $this->db->rollback();
7755 while ($field = $this->db->fetch_object($res_fields)) {
7756 if (!in_array($field->Field, array(
'rowid',
'tms',
'fk_object'))) {
7757 $fields[] = $field->Field;
7760 if (!empty($fields)) {
7763 $sql .=
" oldp.rowid AS old_price_id,";
7764 $sql .=
" newp.rowid AS new_price_id";
7765 $sql .=
" FROM ".MAIN_DB_PREFIX.
"product_customer_price AS oldp";
7766 $sql .=
" INNER JOIN ".MAIN_DB_PREFIX.
"product_customer_price AS newp";
7767 $sql .=
" ON newp.fk_soc = oldp.fk_soc";
7768 $sql .=
" WHERE oldp.fk_product = ".((int) $fromId);
7769 $sql .=
" AND newp.fk_product = ".((int) $toId);
7770 $sql .=
" AND newp.datec = '".$this->db->idate($now).
"'";
7771 $resql = $this->db->query($sql);
7773 $this->db->rollback();
7776 while ($obj = $this->db->fetch_object($resql)) {
7777 $sql_copy =
"INSERT INTO ".MAIN_DB_PREFIX.
"product_customer_price_extrafields";
7778 $sql_copy .=
" (fk_object";
7779 foreach ($fields as $field) {
7780 $sql_copy .=
",".$field;
7783 $sql_copy .=
" SELECT ";
7784 $sql_copy .= ((int) $obj->new_price_id);
7785 foreach ($fields as $field) {
7786 $sql_copy .=
",".$field;
7788 $sql_copy .=
" FROM ".MAIN_DB_PREFIX.
"product_customer_price_extrafields";
7789 $sql_copy .=
" WHERE fk_object = ".((int) $obj->old_price_id);
7790 $resql_copy = $this->db->query($sql_copy);
7792 $this->db->rollback();
7796 $this->db->free($resql);
7799 $this->db->free($res_fields);
7818 $sql_fields =
"SHOW COLUMNS FROM ".MAIN_DB_PREFIX.
"product_price_extrafields";
7819 $res_fields = $this->db->query($sql_fields);
7821 $this->db->rollback();
7825 while ($field = $this->db->fetch_object($res_fields)) {
7826 if (!in_array($field->Field, array(
'rowid',
'tms',
'fk_object'))) {
7827 $fields[] = $field->Field;
7830 if (!empty($fields)) {
7833 $sql .=
" oldp.rowid AS old_price_id,";
7834 $sql .=
" newp.rowid AS new_price_id";
7835 $sql .=
" FROM ".MAIN_DB_PREFIX.
"product_price AS oldp";
7836 $sql .=
" INNER JOIN ".MAIN_DB_PREFIX.
"product_price AS newp";
7837 $sql .=
" ON newp.price_level = oldp.price_level";
7838 $sql .=
" WHERE oldp.fk_product = ".((int) $fromId);
7839 $sql .=
" AND newp.fk_product = ".((int) $toId);
7840 $sql .=
" AND newp.date_price = '".$this->db->idate($now).
"'";
7841 $resql = $this->db->query($sql);
7843 $this->db->rollback();
7846 while ($obj = $this->db->fetch_object($resql)) {
7847 $sql_copy =
"INSERT INTO ".MAIN_DB_PREFIX.
"product_price_extrafields";
7848 $sql_copy .=
" (fk_object";
7849 foreach ($fields as $field) {
7850 $sql_copy .=
",".$field;
7853 $sql_copy .=
" SELECT ";
7854 $sql_copy .= ((int) $obj->new_price_id);
7855 foreach ($fields as $field) {
7856 $sql_copy .=
",".$field;
7858 $sql_copy .=
" FROM ".MAIN_DB_PREFIX.
"product_price_extrafields";
7859 $sql_copy .=
" WHERE fk_object = ".((int) $obj->old_price_id);
7860 $resql_copy = $this->db->query($sql_copy);
7862 $this->db->rollback();
7867 $this->db->free($resql);
7870 $this->db->free($res_fields);
7882 public $picto =
'service';
if(! $sortfield) if(! $sortorder) $object
length_accountg($account)
Return General accounting account with defined length (used for product and miscellaneous)
clean_account($account)
Return accounting account without zero on the right.
$propal type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
deleteEcmFiles($mode=0)
Delete related files of object in database.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
setErrorsFromObject($object)
setErrorsFromObject
isObjectUsed($id=0, $entity=0)
Function to check if an object is used by others (by children).
deleteExtraFields()
Delete all extra fields values for the current object.
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
show_photos($modulepart, $sdir, $size=0, $nbmax=0, $nbbyrow=5, $showfilename=0, $showaction=0, $maxHeight=120, $maxWidth=160, $nolink=0, $overwritetitle=0, $usesharelink=0, $cache='', $addphotorefcss='photoref')
Show photos of an object (nbmax maximum), into several columns.
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
addThumbs($file, $quality=50)
Build thumb.
Class to manage Dolibarr database access.
Class to manage ECM files.
const STATUS_OPEN_INTERNAL
Warehouse open and only operations for stock transfers/corrections allowed (not for customer shipping...
const STATUS_OPEN_ALL
Warehouse open and any operations are allowed (customer shipping, supplier dispatch,...
const STATUS_CLOSED
Warehouse closed, inactive.
const STATUS_CLOSED
Closed status -> parcel was received by customer / end of process prev status : validated or shipment...
const STATUS_VALIDATED
Validated status -> parcel is ready to be sent prev status : draft next status : closed or shipment_i...
const STATUS_DRAFT
Draft status.
Class to manage stock movements.
Class to parse product price expressions.
Class ProductCombination Used to represent the relation between a product and one of its variants.
File of class to manage predefined price products or services by customer.
Class to manage predefined suppliers products.
Class to manage products or services.
static replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
get_nb_achat($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units or supplier invoices in which product is included.
getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp=0)
Return price of sell of a product for a seller/buyer/product.
__construct($db)
Constructor.
is_sousproduit($fk_parent, $fk_child)
Check if it is a sub-product into a kit.
const DISABLED_STOCK
Stockable product.
const SELL_OR_EAT_BY_MANDATORY_ID_NONE
Const sell or eat by mandatory id.
isStockManaged()
Return if the object is managed in stock.
setPriceExpression($expression_id)
Sets the supplier price expression.
getArrayForPriceCompare($level=0)
used to check if price have really change to avoid log pollution
get_arbo_each_prod($multiply=1, $ignore_stock_load=0)
Build the tree of subproducts and return it.
load_stats_inproduction($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null, $warehouseid=0, $dateofvirtualstockmin=null)
Charge tableau des stats production pour le produit/service.
list_suppliers()
Return list of suppliers providing the product or service.
load_stats_mo($socid=0)
Charge tableau des stats OF pour le produit/service.
isVariant()
Return if loaded product is a variant.
updatePrice($newprice, $newpricebase, $user, $newvat=null, $newminprice=0, $level=0, $newnpr=0, $newpbq=0, $ignore_autogen=0, $localtaxes_array=array(), $newdefaultvatcode='', $price_label='', $notrigger=0)
Modify customer price of a product/Service for a given level.
hasVariants()
Return if a product has variants or not.
load_stats_proposal_supplier($socid=0)
Charge tableau des stats propale pour le produit/service.
getLibFinished()
Retour label of nature of product.
add_sousproduit($id_pere, $id_fils, $qty, $incdec=1, $notrigger=0)
Link a product/service to a parent product/service.
add_fournisseur($user, $id_fourn, $ref_fourn, $quantity)
Add a supplier price for the product.
setMultiLangs($user, $notrigger=0)
Update or add a translation for a product.
hasFatherOrChild($mode=0)
Count all parent and children products for current product (first level only)
load_stats_facturerec($socid=0)
Load array of statistics for recurring invoice for product/service.
get_nb_propalsupplier($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in proposals in which product is included.
load_stats_facturefournrec($socid=0)
Load array of statistics for recurring supplier invoice for product/service.
get_nb_contract($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
load_stats_facture_fournisseur($socid=0)
Load array of statistics for vendor invoice for product/service.
get_nb_ordersupplier($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
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.
load_stats_reception($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null, $dateofvirtualstockmin=null)
Loads supplier reception statistics table for given product or service.
create($user, $notrigger=0)
Insert product into database.
load_stats_contrat($socid=0)
Charge tableau des stats contrat pour le produit/service.
isService()
Return if the object is a service.
getRights()
Returns the rights used for this class.
loadBatchInfo($batch)
Load existing information about a serial.
load_stock($option='', $includedraftpoforvirtual=null, $dateofvirtualstock=null)
Load information about stock of a product into ->stock_reel, ->stock_warehouse[] (including stock_war...
getProductDurationHours()
Return the duration of a service in hours (for a service based on duration fields)
get_buyprice($prodfournprice, $qty, $product_id=0, $fourn_ref='', $fk_soc=0)
Read price used by a provider.
clone_fournisseurs($fromId, $toId)
Copies the suppliers and supplier pricing of a product/service onto another one.
const TYPE_PRODUCT
Regular product.
fetchAllPriceLogs($id)
Get all price change logs for a product, enriched with supplier info.
add_photo($sdir, $file)
Move an uploaded file described into $file array into target directory $sdir.
log_price_delete($user, $rowid)
Delete a price line of this product.
info($id)
Load information for tab info.
correct_stock($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $inventorycode='', $origin_element='', $origin_id=null, $disablestockchangeforsubproduct=0, $extrafields=null)
Adjust stock in a warehouse for product.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
Create a document onto disk according to template module.
static getSellOrEatByMandatoryList()
Get the array of labels of Sell by or Eat by all mandatory flags for each status.
getChildsArbo($id, $firstlevelonly=0, $level=1, $parents=array())
Return children of product $id.
load_virtual_stock($includedraftpoforvirtual=null, $dateofvirtualstock=null)
Load value ->stock_theorique of a product.
load_stats_propale($socid=0)
Charge tableau des stats propale pour le produit/service.
get_barcode($object, $type='')
Get a barcode from the module to generate barcode values.
setAccountancyCode($type, $value)
Sets an accountancy code for a product.
load_stats_commande_fournisseur($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null, $dateofvirtualstockmin=null)
Charge tableau des stats commande fournisseur pour le produit/service.
load_stats_facture($socid=0)
Charge tableau des stats facture pour le produit/service.
setCategories($categories)
Sets object to supplied categories.
get_nb_propal($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in proposals in which product is included.
update($id, $user, $notrigger=0, $action='update', $updatetype=false)
Update a record into database.
correct_stock_batch($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $dlc='', $dluo='', $lot='', $inventorycode='', $origin_element='', $origin_id=null, $disablestockchangeforsubproduct=0, $extrafields=null, $force_update_batch=false)
Adjust stock in a warehouse for product with batch number.
load_stats_bom($socid=0)
Charge tableau des stats OF pour le produit/service.
hasbatch()
Return if the object has a batch management.
getNomUrl($withpicto=0, $option='', $maxlength=0, $save_lastsearch_value=-1, $notooltip=0, $morecss='', $add_label=0, $sep=' - ', $addlinktonotes=0)
Return clickable link of object (with eventually picto)
cloneMultipriceExtra($fromId, $toId)
Clone price level extrafields.
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.
delMultiLangs($langtodelete, $user, $notrigger=0)
Delete a language for this product.
check()
Check that ref and label are ok.
initAsSpecimen()
Initialise an instance with random values.
liste_photos($dir, $nbmax=0)
Return an array with all photos of product found on disk.
loadStateBoard()
Load indicators this->nb for the dashboard.
getFather()
Return all parent products for current product (first level only)
getSellOrEatByMandatoryLabel()
Get the label for sell by or eat by mandatory flag of the current product.
verify()
Check properties of product are ok (like name, barcode, ...).
get_nb_order($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
loadStockForVirtualProduct($option='', $qtyWish=1)
Load stock for components of virtual product (first level only)
setMultiLangsExtrafields($langcode, $rowidlang)
Save the extrafields of a translation of the product (table llx_product_lang_extrafields).
min_recommended_price()
Return minimum product recommended price.
cloneCustomerPriceAndExtra($fromId, $toId)
Clone customer prices using extra fields.
_log_price($user, $level=0)
Insert a track that we changed a customer price.
getLabelOfUnit($type='long', $outputlangs=null, $noentities=0)
Reads the units dictionary to return the translation code of a unit (if type='code'),...
_get_stats($sql, $mode, $year=0)
Return an array formatted for showing graphs.
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.
getMultiLangs($loadextrafields=0)
Load array this->multilangs.
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 of a translation of a product (a row of llx_product_lang).
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 translations.
Class to manage Dolibarr users.
hasRight($module, $permlevel1, $permlevel2='')
Return if a user has a permission.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
dol_get_first_hour($date, $gm='tzserver')
Return GMT time for first hour of a given GMT date (it removes hours, min and second part)
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0)
Add a delay to a date.
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0, $level=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
dol_is_file($pathoffile)
Return if path is a file.
dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $nohook=0, $keyforsourcefile='addedfile', $upload_dir='', $mode=0)
Check validity of a file upload from an GUI page, and move it to its final destination.
dol_now($mode='gmt')
Return date for now.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
dolGetFirstLineOfText($text, $nboflines=1, $charset='UTF-8')
Return first line of text.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dolBuildUrl($url, $params=[], $addtoken=false, $anchor='')
Return path of url.
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_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
dol_clone($srcobject, $native=2)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '...' if string larger than length.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
utf8_check($str)
Check if a string is in UTF8.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_localtax($vatrate, $local, $thirdparty_buyer=null, $thirdparty_seller=null, $vatnpr=0)
Return localtax rate for a particular VAT rate, when selling a product with vat $vatrate,...
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
query($query, $usesavepoint=0, $type='auto', $result_mode=0)
Execute a SQL request and return the resultset.
measuring_units_squared($unitscale)
Transform a given unit scale into the square of that unit, if known.
measuringUnitString($unitid, $measuring_style='', $unitscale=null, $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
measuring_units_cubed($unit)
Transform a given unit scale into the cube of that unit, if known.