42require_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
43require_once DOL_DOCUMENT_ROOT.
'/core/class/commonobject.class.php';
44require_once DOL_DOCUMENT_ROOT.
'/product/class/productbatch.class.php';
45require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/productlot.class.php';
46require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/entrepot.class.php';
57 const SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY = 1;
58 const SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY = 2;
59 const SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT = 3;
64 public $element =
'product';
69 public $table_element =
'product';
74 public $fk_element =
'fk_product';
79 protected $childtables = array(
80 'supplier_proposaldet' => array(
'name' =>
'SupplierProposal',
'parent' =>
'supplier_proposal',
'parentkey' =>
'fk_supplier_proposal'),
81 'propaldet' => array(
'name' =>
'Proposal',
'parent' =>
'propal',
'parentkey' =>
'fk_propal'),
82 'commandedet' => array(
'name' =>
'Order',
'parent' =>
'commande',
'parentkey' =>
'fk_commande'),
83 'facturedet' => array(
'name' =>
'Invoice',
'parent' =>
'facture',
'parentkey' =>
'fk_facture'),
84 'contratdet' => array(
'name' =>
'Contract',
'parent' =>
'contrat',
'parentkey' =>
'fk_contrat'),
85 'facture_fourn_det' => array(
'name' =>
'SupplierInvoice',
'parent' =>
'facture_fourn',
'parentkey' =>
'fk_facture_fourn'),
86 'commande_fournisseurdet' => array(
'name' =>
'SupplierOrder',
'parent' =>
'commande_fournisseur',
'parentkey' =>
'fk_commande'),
87 'mrp_production' => array(
'name' =>
'Mo',
'parent' =>
'mrp_mo',
'parentkey' =>
'fk_mo',
'enabled' =>
'isModEnabled("mrp")'),
88 'bom_bom' => array(
'name' =>
'BOM',
'enabled' =>
'isModEnabled("bom")'),
89 'bom_bomline' => array(
'name' =>
'BOMLine',
'parent' =>
'bom_bom',
'parentkey' =>
'fk_bom',
'enabled' =>
'isModEnabled("bom")'),
97 public $picto =
'product';
108 public $regeximgext =
'\.gif|\.jpg|\.jpeg|\.png|\.bmp|\.webp|\.xpm|\.xbm';
155 public $price_formated;
167 public $price_ttc_formated;
181 public $price_min_ttc;
187 public $price_base_type;
197 public $multiprices = array();
201 public $multiprices_ttc = array();
205 public $multiprices_base_type = array();
209 public $multiprices_default_vat_code = array();
213 public $multiprices_min = array();
217 public $multiprices_min_ttc = array();
221 public $multiprices_tva_tx = array();
225 public $multiprices_recuperableonly = array();
231 public $price_by_qty;
235 public $prices_by_qty = array();
239 public $prices_by_qty_id = array();
243 public $prices_by_qty_list = array();
253 public $multilangs = array();
258 public $default_vat_code;
273 public $remise_percent;
278 public $localtax1_tx;
282 public $localtax2_tx;
286 public $localtax1_type;
290 public $localtax2_type;
297 public $desc_supplier;
301 public $vatrate_supplier;
305 public $default_vat_code_supplier;
310 public $fourn_multicurrency_price;
314 public $fourn_multicurrency_unitprice;
318 public $fourn_multicurrency_tx;
322 public $fourn_multicurrency_id;
326 public $fourn_multicurrency_code;
348 public $qc_frequency;
355 public $stock_reel = 0;
362 public $stock_theorique;
383 public $seuil_stock_alerte = 0;
388 public $desiredstock = 0;
393 public $duration_value;
397 public $duration_unit;
406 public $fk_default_workstation;
428 public $status_buy = 0;
450 public $fk_default_bom;
457 public $product_fourn_price_id;
479 public $status_batch = 0;
486 public $sell_or_eat_by_mandatory = 0;
493 public $batch_mask =
'';
518 public $weight_units;
526 public $length_units;
542 public $height_units;
550 public $surface_units;
558 public $volume_units;
567 public $net_measure_units;
572 public $accountancy_code_sell;
576 public $accountancy_code_sell_intra;
580 public $accountancy_code_sell_export;
584 public $accountancy_code_buy;
588 public $accountancy_code_buy_intra;
592 public $accountancy_code_buy_export;
602 public $barcode_type;
607 public $barcode_type_code;
612 public $stats_propale = array();
617 public $stats_commande = array();
622 public $stats_contrat = array();
627 public $stats_facture = array();
632 public $stats_proposal_supplier = array();
637 public $stats_commande_fournisseur = array();
642 public $stats_expedition = array();
647 public $stats_reception = array();
652 public $stats_mo = array();
657 public $stats_bom = array();
662 public $stats_mrptoconsume = array();
667 public $stats_mrptoproduce = array();
672 public $stats_facturerec = array();
677 public $stats_facture_fournisseur = array();
682 public $stats_facturefournrec = array();
697 public $product_fourn_id;
703 public $product_id_already_linked;
714 public $stock_warehouse = array();
719 public $fk_default_warehouse;
724 public $fk_price_expression;
742 public $fourn_price_base_type;
759 public $ref_supplier;
773 public $price_autogen = 0;
780 public $supplierprices;
787 public $sousprods = array();
800 public $is_object_used;
811 public $is_sousproduit_qty;
823 public $is_sousproduit_incdec;
828 public $mandatory_period;
835 public $stockable_product = 1;
865 public $fields = array(
866 'rowid' => array(
'type' =>
'integer',
'label' =>
'TechnicalID',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'index' => 1,
'position' => 1,
'comment' =>
'Id'),
867 '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'),
868 'entity' => array(
'type' =>
'integer',
'label' =>
'Entity',
'enabled' => 1,
'visible' => 0,
'default' =>
'1',
'notnull' => 1,
'index' => 1,
'position' => 5),
869 'label' => array(
'type' =>
'varchar(255)',
'label' =>
'Label',
'enabled' => 1,
'visible' => 1,
'notnull' => 1,
'showoncombobox' => 2,
'position' => 15,
'csslist' =>
'tdoverflowmax250'),
870 'barcode' => array(
'type' =>
'varchar(255)',
'label' =>
'Barcode',
'enabled' =>
'isModEnabled("barcode")',
'position' => 20,
'visible' => -1,
'showoncombobox' => 3,
'cssview' =>
'tdwordbreak',
'csslist' =>
'tdoverflowmax125'),
871 'fk_barcode_type' => array(
'type' =>
'integer',
'label' =>
'BarcodeType',
'enabled' => 1,
'position' => 21,
'notnull' => 0,
'visible' => -1,),
872 'note_public' => array(
'type' =>
'html',
'label' =>
'NotePublic',
'enabled' => 1,
'visible' => 0,
'position' => 61),
873 'note' => array(
'type' =>
'html',
'label' =>
'NotePrivate',
'enabled' => 1,
'visible' => 0,
'position' => 62),
874 'datec' => array(
'type' =>
'datetime',
'label' =>
'DateCreation',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 500),
875 'tms' => array(
'type' =>
'timestamp',
'label' =>
'DateModification',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 501),
877 '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'),
878 'fk_user_modif' => array(
'type' =>
'integer:User:user/class/user.class.php',
'label' =>
'UserModif',
'enabled' => 1,
'visible' => -2,
'notnull' => -1,
'position' => 511),
880 'localtax1_tx' => array(
'type' =>
'double(6,3)',
'label' =>
'Localtax1tx',
'enabled' => 1,
'position' => 150,
'notnull' => 0,
'visible' => -1,),
881 'localtax1_type' => array(
'type' =>
'varchar(10)',
'label' =>
'Localtax1type',
'enabled' => 1,
'position' => 155,
'notnull' => 1,
'visible' => -1,),
882 'localtax2_tx' => array(
'type' =>
'double(6,3)',
'label' =>
'Localtax2tx',
'enabled' => 1,
'position' => 160,
'notnull' => 0,
'visible' => -1,),
883 'localtax2_type' => array(
'type' =>
'varchar(10)',
'label' =>
'Localtax2type',
'enabled' => 1,
'position' => 165,
'notnull' => 1,
'visible' => -1,),
884 'last_main_doc' => array(
'type' =>
'varchar(255)',
'label' =>
'LastMainDoc',
'enabled' => 1,
'visible' => -1,
'position' => 170),
885 'import_key' => array(
'type' =>
'varchar(14)',
'label' =>
'ImportId',
'enabled' => 1,
'visible' => -2,
'notnull' => -1,
'index' => 0,
'position' => 1000),
888 'mandatory_period' => array(
'type' =>
'integer',
'label' =>
'mandatoryperiod',
'enabled' => 1,
'visible' => -1,
'notnull' => 1,
'default' =>
'0',
'index' => 1,
'position' => 1000),
889 'stockable_product' =>array(
'type' =>
'integer',
'label' =>
'stockable_product',
'enabled' => 1,
'visible' => 1,
'default' =>
'1',
'notnull' => 1,
'index' => 1,
'position' => 502),
905 const ENABLED_STOCK = 1;
916 $this->ismultientitymanaged = 1;
917 $this->isextrafieldmanaged = 1;
930 $this->
ref = trim($this->
ref);
958 public function create($user, $notrigger = 0)
960 global
$conf, $langs;
966 $this->
ref = trim($this->
ref);
970 $this->label = trim($this->label);
971 $this->price_ttc = (float)
price2num($this->price_ttc);
973 $this->price_min_ttc = (float)
price2num($this->price_min_ttc);
974 $this->price_min = (float)
price2num($this->price_min);
975 $this->price_label = trim($this->price_label);
976 if (empty($this->tva_tx)) {
979 if (empty($this->tva_npr)) {
983 if (empty($this->localtax1_tx)) {
984 $this->localtax1_tx = 0;
986 if (empty($this->localtax2_tx)) {
987 $this->localtax2_tx = 0;
989 if (empty($this->localtax1_type)) {
990 $this->localtax1_type =
'0';
992 if (empty($this->localtax2_type)) {
993 $this->localtax2_type =
'0';
999 if (empty($this->
price)) {
1002 if (empty($this->price_min)) {
1003 $this->price_min = 0;
1006 if (empty($this->price_by_qty)) {
1007 $this->price_by_qty = 0;
1010 if (empty($this->
status)) {
1013 if (empty($this->status_buy)) {
1014 $this->status_buy = 0;
1016 if (empty($this->stockable_product)) {
1017 $this->stockable_product = 0;
1026 if ($this->price_base_type ==
'TTC' && $this->price_ttc > 0) {
1027 $price_ttc =
price2num($this->price_ttc,
'MU');
1028 $price_ht =
price2num($this->price_ttc / (1 + ($this->tva_tx / 100)),
'MU');
1032 if ($this->price_base_type !=
'TTC' && $this->
price > 0) {
1034 $price_ttc =
price2num($this->
price * (1 + ($this->tva_tx / 100)),
'MU');
1038 if (($this->price_min_ttc > 0) && ($this->price_base_type ==
'TTC')) {
1039 $price_min_ttc =
price2num($this->price_min_ttc,
'MU');
1040 $price_min_ht =
price2num($this->price_min_ttc / (1 + ($this->tva_tx / 100)),
'MU');
1044 if (($this->price_min > 0) && ($this->price_base_type !=
'TTC')) {
1045 $price_min_ht =
price2num($this->price_min,
'MU');
1046 $price_min_ttc =
price2num($this->price_min * (1 + ($this->tva_tx / 100)),
'MU');
1049 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
1050 $this->accountancy_code_buy_intra = trim($this->accountancy_code_buy_intra);
1051 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
1052 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
1053 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
1054 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
1060 require_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
1061 $this->accountancy_code_buy =
clean_account($this->accountancy_code_buy);
1062 $this->accountancy_code_buy_intra =
clean_account($this->accountancy_code_buy_intra);
1063 $this->accountancy_code_buy_export =
clean_account($this->accountancy_code_buy_export);
1064 $this->accountancy_code_sell =
clean_account($this->accountancy_code_sell);
1065 $this->accountancy_code_sell_intra =
clean_account($this->accountancy_code_sell_intra);
1066 $this->accountancy_code_sell_export =
clean_account($this->accountancy_code_sell_export);
1070 $this->barcode = trim($this->barcode);
1071 $this->mandatory_period = empty($this->mandatory_period) ? 0 : $this->mandatory_period;
1073 if (empty($this->label)) {
1074 $langs->load(
'errors');
1075 $this->errors[] = $langs->trans(
'ErrorMandatoryParametersNotProvided');
1079 if (empty($this->
ref) || $this->
ref ==
'auto') {
1081 $module =
getDolGlobalString(
'PRODUCT_CODEPRODUCT_ADDON',
'mod_codeproduct_leopard');
1082 if ($module !=
'mod_codeproduct_leopard') {
1083 if (substr($module, 0, 16) ==
'mod_codeproduct_' && substr($module, -3) ==
'php') {
1084 $module = substr($module, 0,
dol_strlen($module) - 4);
1087 $modCodeProduct =
new $module();
1088 '@phan-var-force ModeleProductCode $modCodeProduct';
1089 if (!empty($modCodeProduct->code_auto)) {
1090 $this->
ref = $modCodeProduct->getNextValue($this, $this->
type);
1092 unset($modCodeProduct);
1095 if (empty($this->
ref)) {
1096 $this->error =
'ProductModuleNotSetupForAutoRef';
1101 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);
1105 if (empty($this->date_creation)) {
1106 $this->date_creation = $now;
1112 if ($this->barcode ==
'-1' || $this->barcode ==
'auto') {
1113 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1118 $result = $this->
verify();
1121 $sql =
"SELECT count(*) as nb";
1122 $sql .=
" FROM ".$this->db->prefix().
"product";
1123 $sql .=
" WHERE entity IN (".getEntity(
'product').
")";
1124 $sql .=
" AND ref = '".$this->db->escape($this->
ref).
"'";
1126 $result = $this->db->query($sql);
1128 $obj = $this->db->fetch_object($result);
1129 if ($obj->nb == 0) {
1131 $sql =
"INSERT INTO ".$this->db->prefix().
"product (";
1135 $sql .=
", ref_ext";
1136 $sql .=
", price_min";
1137 $sql .=
", price_min_ttc";
1139 $sql .=
", fk_user_author";
1140 $sql .=
", fk_product_type";
1142 $sql .=
", price_ttc";
1143 $sql .=
", price_base_type";
1144 $sql .=
", price_label";
1148 $sql .=
", accountancy_code_buy";
1149 $sql .=
", accountancy_code_buy_intra";
1150 $sql .=
", accountancy_code_buy_export";
1151 $sql .=
", accountancy_code_sell";
1152 $sql .=
", accountancy_code_sell_intra";
1153 $sql .=
", accountancy_code_sell_export";
1156 $sql .=
", finished";
1157 $sql .=
", tobatch";
1158 $sql .=
", sell_or_eat_by_mandatory";
1159 $sql .=
", batch_mask";
1160 $sql .=
", fk_unit";
1161 $sql .=
", mandatory_period";
1162 $sql .=
", stockable_product";
1163 if (!empty($this->default_vat_code)) $sql.=
", default_vat_code";
1164 $sql .=
") VALUES (";
1165 $sql .=
"'".$this->db->idate($this->date_creation).
"'";
1166 $sql .=
", ".(!empty($this->entity) ? (int) $this->entity : (int)
$conf->entity);
1167 $sql .=
", '".$this->db->escape($this->
ref).
"'";
1168 $sql .=
", ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1169 $sql .=
", ".price2num($price_min_ht);
1170 $sql .=
", ".price2num($price_min_ttc);
1171 $sql .=
", ".(!empty($this->label) ?
"'".$this->db->escape($this->label).
"'" :
"null");
1172 $sql .=
", ".((int) $user->id);
1173 $sql .=
", ".((int) $this->
type);
1174 $sql .=
", ".price2num($price_ht,
'MT');
1175 $sql .=
", ".price2num($price_ttc,
'MT');
1176 $sql .=
", '".$this->db->escape($this->price_base_type).
"'";
1177 $sql .=
", ".(!empty($this->price_label) ?
"'".$this->db->escape($this->price_label).
"'" :
"null");
1178 $sql .=
", ".((int) $this->
status);
1179 $sql .=
", ".((int) $this->status_buy);
1181 $sql .=
", '".$this->db->escape($this->accountancy_code_buy).
"'";
1182 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_intra).
"'";
1183 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_export).
"'";
1184 $sql .=
", '".$this->db->escape($this->accountancy_code_sell).
"'";
1185 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_intra).
"'";
1186 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_export).
"'";
1188 $sql .=
", '".$this->db->escape($this->canvas).
"'";
1189 $sql .=
", ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
'NULL' : (int) $this->finished);
1190 $sql .=
", ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : ((int) $this->status_batch));
1191 $sql .=
", ".((empty($this->sell_or_eat_by_mandatory) || $this->sell_or_eat_by_mandatory < 0) ? 0 : ((int) $this->sell_or_eat_by_mandatory));
1192 $sql .=
", '".$this->db->escape($this->batch_mask).
"'";
1193 $sql .=
", ".($this->fk_unit > 0 ? ((int) $this->fk_unit) :
'NULL');
1194 $sql .=
", '".$this->db->escape((
string) $this->mandatory_period).
"'";
1195 $sql .=
", ".((int) $this->stockable_product);
1196 if (!empty($this->default_vat_code)) $sql.=
", '".$this->db->escape($this->default_vat_code).
"'";
1198 dol_syslog(get_class($this).
"::Create", LOG_DEBUG);
1200 $result = $this->db->query($sql);
1202 $id = $this->db->last_insert_id($this->db->prefix().
"product");
1206 $this->
price = $price_ht;
1207 $this->price_ttc = $price_ttc;
1208 $this->price_min = $price_min_ht;
1209 $this->price_min_ttc = $price_min_ttc;
1213 if ($this->
update($id, $user, 1,
'add') <= 0) {
1218 $this->error = $this->db->lasterror();
1223 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " .((int) $this->id) .
" AND entity = " . ((
int)
$conf->entity));
1225 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1226 $sql .=
" fk_product";
1228 $sql .=
", accountancy_code_buy";
1229 $sql .=
", accountancy_code_buy_intra";
1230 $sql .=
", accountancy_code_buy_export";
1231 $sql .=
", accountancy_code_sell";
1232 $sql .=
", accountancy_code_sell_intra";
1233 $sql .=
", accountancy_code_sell_export";
1234 $sql .=
") VALUES (";
1236 $sql .=
", " . ((int)
$conf->entity);
1237 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1238 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1239 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1240 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1241 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1242 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1244 $result = $this->db->query($sql);
1247 $this->error =
'ErrorFailedToInsertAccountancyForEntity';
1252 $this->error =
'ErrorFailedToGetInsertedId';
1256 $this->error = $this->db->lasterror();
1260 $langs->load(
"products");
1262 $this->error =
"ErrorProductAlreadyExists";
1263 dol_syslog(get_class($this).
"::Create fails, ref ".$this->
ref.
" already exists");
1267 $this->error = $this->db->lasterror();
1270 if (!$error && !$notrigger) {
1272 $result = $this->
call_trigger(
'PRODUCT_CREATE', $user);
1280 $this->db->commit();
1283 $this->db->rollback();
1287 $this->db->rollback();
1288 dol_syslog(get_class($this).
"::Create fails verify ".implode(
',', $this->errors), LOG_WARNING);
1304 $this->errors = array();
1307 $this->
ref = trim($this->
ref);
1310 $this->errors[] =
'ErrorBadRef';
1314 $arrayofnonnegativevalue = array(
'weight' =>
'Weight',
'width' =>
'Width',
'height' =>
'Height',
'length' =>
'Length',
'surface' =>
'Surface',
'volume' =>
'Volume');
1315 foreach ($arrayofnonnegativevalue as $key => $value) {
1316 if (property_exists($this, $key) && !empty($this->$key) && ($this->$key < 0)) {
1317 $langs->loadLangs(array(
"main",
"other"));
1318 $this->error = $langs->trans(
"FieldCannotBeNegative", $langs->transnoentitiesnoconv($value));
1319 $this->errors[] = $this->error;
1324 $rescode = $this->
check_barcode($this->barcode, $this->barcode_type_code);
1326 if ($rescode == -1) {
1327 $this->errors[] =
'ErrorBadBarCodeSyntax';
1328 } elseif ($rescode == -2) {
1329 $this->errors[] =
'ErrorBarCodeRequired';
1330 } elseif ($rescode == -3) {
1332 $this->errors[] =
'ErrorBarCodeAlreadyUsed';
1360 $dirsociete = array_merge(array(
'/core/modules/barcode/'),
$conf->modules_parts[
'barcode']);
1361 foreach ($dirsociete as $dirroot) {
1368 $mod =
new $module();
1369 '@phan-var-force ModeleNumRefBarCode $mod';
1371 dol_syslog(get_class($this).
"::check_barcode value=".$valuetotest.
" type=".$typefortest.
" module=".$module);
1372 $result = $mod->verif($this->db, $valuetotest, $this, 0, $typefortest);
1390 public function update($id, $user, $notrigger = 0, $action =
'update', $updatetype =
false)
1392 global $langs,
$conf, $hookmanager;
1397 if (!$this->label) {
1398 $this->label =
'MISSING LABEL';
1403 $this->
ref = trim($this->
ref);
1407 $this->label = trim($this->label);
1409 $this->note_private = (isset($this->note_private) ? trim($this->note_private) :
null);
1410 $this->note_public = (isset($this->note_public) ? trim($this->note_public) :
null);
1411 $this->net_measure =
price2num($this->net_measure);
1412 $this->net_measure_units = (!is_numeric($this->net_measure_units) ? null : (int) $this->net_measure_units);
1413 $this->weight =
price2num($this->weight);
1414 $this->weight_units = (!is_numeric($this->weight_units) ? null : (int) $this->weight_units);
1415 $this->length =
price2num($this->length);
1416 $this->length_units = (!is_numeric($this->length_units) ? null : (int) $this->length_units);
1418 $this->width_units = (!is_numeric($this->width_units) ? null : (int) $this->width_units);
1419 $this->height =
price2num($this->height);
1420 $this->height_units = (!is_numeric($this->height_units) ? null : (int) $this->height_units);
1421 $this->surface =
price2num($this->surface);
1422 $this->surface_units = (!is_numeric($this->surface_units) ? null : (int) $this->surface_units);
1423 $this->volume =
price2num($this->volume);
1424 $this->volume_units = (!is_numeric($this->volume_units) ? null : (int) $this->volume_units);
1427 if (is_numeric($this->length_units)) {
1428 $this->width_units = $this->length_units;
1430 if (is_numeric($this->length_units)) {
1431 $this->height_units = $this->length_units;
1435 if (empty($this->surface) && !empty($this->length) && !empty($this->width) && $this->length_units == $this->width_units) {
1436 $this->surface = (float) $this->length * (
float) $this->width;
1439 if (empty($this->volume) && !empty($this->surface) && !empty($this->height) && $this->length_units == $this->height_units) {
1440 $this->volume = $this->surface * (float) $this->height;
1444 if (empty($this->tva_tx)) {
1447 if (empty($this->tva_npr)) {
1450 if (empty($this->localtax1_tx)) {
1451 $this->localtax1_tx = 0;
1453 if (empty($this->localtax2_tx)) {
1454 $this->localtax2_tx = 0;
1456 if (empty($this->localtax1_type)) {
1457 $this->localtax1_type =
'0';
1459 if (empty($this->localtax2_type)) {
1460 $this->localtax2_type =
'0';
1462 if (empty($this->
status)) {
1465 if (empty($this->status_buy)) {
1466 $this->status_buy = 0;
1469 if (empty($this->country_id)) {
1470 $this->country_id = 0;
1472 if (empty($this->country_id) && !empty($this->country_code)) {
1473 $country_id =
getCountry($this->country_code,
'3');
1474 $this->country_id = is_int($country_id) ? $country_id : 0;
1477 if (empty($this->state_id)) {
1478 $this->state_id = 0;
1481 if (empty($this->stockable_product)) {
1482 $this->stockable_product = 0;
1486 $this->barcode = (empty($this->barcode) ?
'' : trim($this->barcode));
1488 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
1489 $this->accountancy_code_buy_intra = (!empty($this->accountancy_code_buy_intra) ? trim($this->accountancy_code_buy_intra) :
'');
1490 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
1491 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
1492 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
1493 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
1499 require_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
1500 $this->accountancy_code_buy =
clean_account($this->accountancy_code_buy);
1501 $this->accountancy_code_buy_intra =
clean_account($this->accountancy_code_buy_intra);
1502 $this->accountancy_code_buy_export =
clean_account($this->accountancy_code_buy_export);
1503 $this->accountancy_code_sell =
clean_account($this->accountancy_code_sell);
1504 $this->accountancy_code_sell_intra =
clean_account($this->accountancy_code_sell_intra);
1505 $this->accountancy_code_sell_export =
clean_account($this->accountancy_code_sell_export);
1512 if ($action !=
'add') {
1513 $result = $this->
verify();
1522 if (is_null($this->oldcopy) || (is_object($this->oldcopy) && empty($this->oldcopy->id))) {
1527 if ($this->
hasbatch() && !$this->oldcopy->hasbatch()) {
1529 $valueforundefinedlot =
'000000';
1534 dol_syslog(
"Flag batch of product id=".$this->
id.
" is set to ON, so we will create missing records into product_batch");
1537 foreach ($this->stock_warehouse as $idW => $ObjW) {
1539 foreach ($ObjW->detail_batch as $detail) {
1540 if ($detail->batch == $valueforundefinedlot || $detail->batch ==
'Undefined') {
1542 $sqlclean =
"DELETE FROM ".$this->db->prefix().
"product_batch WHERE batch in('Undefined', '".$this->db->escape($valueforundefinedlot).
"') AND fk_product_stock = ".((int) $ObjW->id);
1543 $result = $this->db->query($sqlclean);
1551 $qty_batch += $detail->qty;
1555 if ($ObjW->real != $qty_batch) {
1557 $ObjBatch->batch = $valueforundefinedlot;
1558 $ObjBatch->qty = ($ObjW->real - $qty_batch);
1559 $ObjBatch->fk_product_stock = (int) $ObjW->id;
1561 if ($ObjBatch->create($user, 1) < 0) {
1563 $this->errors = $ObjBatch->errors;
1568 if ($ObjLot->fetch(0, $this->id, $valueforundefinedlot) == 0) {
1569 $ObjLot->fk_product = $this->id;
1570 $ObjLot->entity = (int) $this->entity;
1571 $ObjLot->fk_user_creat = $user->id;
1572 $ObjLot->batch = $valueforundefinedlot;
1573 if ($ObjLot->create($user, 1) < 0) {
1575 $this->errors = $ObjLot->errors;
1584 if ($this->barcode == -1) {
1585 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1588 $sql =
"UPDATE ".$this->db->prefix().
"product";
1589 $sql .=
" SET label = '".$this->db->escape($this->label).
"'";
1592 $sql .=
", fk_product_type = ".((int) $this->
type);
1595 $sql .=
", ref = '".$this->db->escape($this->
ref).
"'";
1596 $sql .=
", ref_ext = ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1597 $sql .=
", default_vat_code = ".($this->default_vat_code ?
"'".$this->db->escape($this->default_vat_code).
"'" :
"null");
1598 $sql .=
", tva_tx = ".((float) $this->tva_tx);
1599 $sql .=
", recuperableonly = ".((int) $this->tva_npr);
1600 $sql .=
", localtax1_tx = ".((float) $this->localtax1_tx);
1601 $sql .=
", localtax2_tx = ".((float) $this->localtax2_tx);
1602 $sql .=
", localtax1_type = ".($this->localtax1_type !=
'' ?
"'".$this->db->escape($this->localtax1_type).
"'" :
"'0'");
1603 $sql .=
", localtax2_type = ".($this->localtax2_type !=
'' ?
"'".$this->db->escape($this->localtax2_type).
"'" :
"'0'");
1605 $sql .=
", barcode = ".(empty($this->barcode) ?
"null" :
"'".$this->db->escape($this->barcode).
"'");
1606 $sql .=
", fk_barcode_type = ".(empty($this->barcode_type) ?
"null" : $this->db->escape((
string) $this->barcode_type));
1608 $sql .=
", tosell = ".(int) $this->
status;
1609 $sql .=
", tobuy = ".(int) $this->status_buy;
1610 $sql .=
", tobatch = ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : (int) $this->status_batch);
1611 $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);
1612 $sql .=
", batch_mask = '".$this->db->escape($this->batch_mask).
"'";
1614 $sql .=
", finished = ".((!isset($this->finished) || $this->finished < 0 || $this->finished ===
'') ?
"null" : (int) $this->finished);
1615 $sql .=
", fk_default_bom = ".((!isset($this->fk_default_bom) || $this->fk_default_bom < 0 || $this->fk_default_bom ==
'') ?
"null" : (int) $this->fk_default_bom);
1616 $sql .=
", net_measure = ".($this->net_measure !=
'' ?
"'".$this->db->escape($this->net_measure).
"'" :
'null');
1617 $sql .=
", net_measure_units = ".((string) $this->net_measure_units !=
'' ? ((
int) $this->net_measure_units) :
'null');
1618 $sql .=
", weight = ".($this->weight !=
'' ?
"'".$this->db->escape($this->weight).
"'" :
'null');
1619 $sql .=
", weight_units = ".((string) $this->weight_units !=
'' ? ((
int) $this->weight_units) :
'null');
1620 $sql .=
", length = ".($this->length !=
'' ?
"'".$this->db->escape($this->length).
"'" :
'null');
1621 $sql .=
", length_units = ".((string) $this->length_units !=
'' ? ((
int) $this->length_units) :
'null');
1622 $sql .=
", width= ".($this->width !=
'' ?
"'".$this->db->escape($this->width).
"'" :
'null');
1623 $sql .=
", width_units = ".((string) $this->width_units !=
'' ? ((
int) $this->width_units) :
'null');
1624 $sql .=
", height = ".($this->height !=
'' ?
"'".$this->db->escape($this->height).
"'" :
'null');
1625 $sql .=
", height_units = ".((string) $this->height_units !=
'' ? ((
int) $this->height_units) :
'null');
1626 $sql .=
", surface = ".($this->surface !=
'' ?
"'".$this->db->escape($this->surface).
"'" :
'null');
1627 $sql .=
", surface_units = ".((string) $this->surface_units !=
'' ? ((
int) $this->surface_units) :
'null');
1628 $sql .=
", volume = ".($this->volume !=
'' ?
"'".$this->db->escape($this->volume).
"'" :
'null');
1629 $sql .=
", volume_units = ".((string) $this->volume_units !=
'' ? ((
int) $this->volume_units) :
'null');
1630 $sql .=
", fk_default_warehouse = ".($this->fk_default_warehouse > 0 ? ((int) $this->fk_default_warehouse) :
'null');
1631 $sql .=
", fk_default_workstation = ".($this->fk_default_workstation > 0 ? ((int) $this->fk_default_workstation) :
'null');
1632 $sql .=
", seuil_stock_alerte = ".((isset($this->seuil_stock_alerte) && is_numeric($this->seuil_stock_alerte)) ? (
float) $this->seuil_stock_alerte :
'null');
1633 $sql .=
", description = '".$this->db->escape($this->
description).
"'";
1634 $sql .=
", url = ".($this->url ?
"'".$this->db->escape($this->url).
"'" :
'null');
1635 $sql .=
", customcode = '".$this->db->escape($this->customcode).
"'";
1636 $sql .=
", fk_country = ".($this->country_id > 0 ? (int) $this->country_id :
'null');
1637 $sql .=
", fk_state = ".($this->state_id > 0 ? (int) $this->state_id :
'null');
1638 $sql .=
", lifetime = ".($this->lifetime > 0 ? (int) $this->lifetime :
'null');
1639 $sql .=
", qc_frequency = ".($this->qc_frequency > 0 ? (int) $this->qc_frequency :
'null');
1640 $sql .=
", note = ".(isset($this->note_private) ?
"'".$this->db->escape($this->note_private).
"'" :
'null');
1641 $sql .=
", note_public = ".(isset($this->note_public) ?
"'".$this->db->escape($this->note_public).
"'" :
'null');
1642 $sql .=
", duration = '".$this->db->escape($this->duration_value.$this->duration_unit).
"'";
1644 $sql .=
", accountancy_code_buy = '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1645 $sql .=
", accountancy_code_buy_intra = '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1646 $sql .=
", accountancy_code_buy_export = '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1647 $sql .=
", accountancy_code_sell= '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1648 $sql .=
", accountancy_code_sell_intra= '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1649 $sql .=
", accountancy_code_sell_export= '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1651 $sql .=
", desiredstock = ".((isset($this->desiredstock) && is_numeric($this->desiredstock)) ? (
float) $this->desiredstock :
"null");
1652 $sql .=
", cost_price = ".($this->cost_price !=
'' ? ((float) $this->cost_price) :
'null');
1653 $sql .=
", fk_unit= ".(!$this->fk_unit ?
'NULL' : (int) $this->fk_unit);
1654 $sql .=
", price_autogen = ".(!$this->price_autogen ? 0 : 1);
1655 $sql .=
", fk_price_expression = ".($this->fk_price_expression != 0 ? (int) $this->fk_price_expression :
'NULL');
1656 $sql .=
", fk_user_modif = ".($user->id > 0 ? (int) $user->id :
'NULL');
1657 $sql .=
", mandatory_period = ".((int) $this->mandatory_period);
1658 $sql .=
", stockable_product = ".(int) $this->stockable_product;
1660 $sql .=
", packaging = ".(float) $this->packaging;
1664 $sql .=
" WHERE rowid = ".((int) $id);
1666 dol_syslog(get_class($this).
"::update", LOG_DEBUG);
1668 $resql = $this->db->query($sql);
1675 $this->db->rollback();
1684 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " . ((
int) $this->id) .
" AND entity = " . ((
int)
$conf->entity));
1686 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1687 $sql .=
" fk_product";
1689 $sql .=
", accountancy_code_buy";
1690 $sql .=
", accountancy_code_buy_intra";
1691 $sql .=
", accountancy_code_buy_export";
1692 $sql .=
", accountancy_code_sell";
1693 $sql .=
", accountancy_code_sell_intra";
1694 $sql .=
", accountancy_code_sell_export";
1695 $sql .=
") VALUES (";
1696 $sql .= ((int) $this->
id);
1697 $sql .=
", " . ((int)
$conf->entity);
1698 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1699 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1700 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1701 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1702 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1703 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1705 $result = $this->db->query($sql);
1708 $this->error =
'ErrorFailedToUpdateAccountancyForEntity';
1712 if (!$this->
hasbatch() && $this->oldcopy->hasbatch()) {
1714 $sql =
'SELECT pb.qty, ps.fk_entrepot, pb.batch FROM '.MAIN_DB_PREFIX.
'product_batch as pb';
1715 $sql .=
' INNER JOIN '.MAIN_DB_PREFIX.
'product_stock as ps ON (ps.rowid = pb.fk_product_stock)';
1716 $sql .=
' WHERE ps.fk_product = '.(int) $this->
id;
1718 $resql = $this->db->query($sql);
1722 while ($obj = $this->db->fetch_object($resql)) {
1724 $fk_entrepot = $obj->fk_entrepot;
1728 $batch = $obj->batch;
1731 $addOremove = $value > 0 ? 1 : 0;
1732 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1733 $res = $this->
correct_stock_batch($user, $fk_entrepot, abs($value), $addOremove, $label, $price, $dlc, $dluo, $batch, $inventorycode,
'',
null, 0,
null,
true);
1736 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1737 $res = $this->
correct_stock($user, $fk_entrepot, abs($value), (
int) empty($addOremove), $label, $price, $inventorycode,
'',
null, 0);
1756 if (!$error && !$notrigger) {
1758 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
1765 if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) {
1767 if (
$conf->product->dir_output) {
1770 if (file_exists($olddir)) {
1774 $res = @rename($olddir, $newdir);
1776 $langs->load(
"errors");
1777 $this->error = $langs->trans(
'ErrorFailToRenameDir', $olddir, $newdir);
1781 require_once DOL_DOCUMENT_ROOT .
'/ecm/class/ecmfiles.class.php';
1782 $ecmfiles =
new EcmFiles($this->db);
1783 $ecmfiles->updateAfterRename(
"produit/".
dol_sanitizeFileName($this->oldcopy->ref),
"produit/".dol_sanitizeFileName($this->ref));
1790 if (isModEnabled(
'variants')) {
1791 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1795 foreach ($comb->fetchAllByFkProductParent($this->id) as $currcomb) {
1796 $currcomb->updateProperties($this, $user);
1800 $this->db->commit();
1803 $this->db->rollback();
1807 if ($this->db->errno() ==
'DB_ERROR_RECORD_ALREADY_EXISTS') {
1808 $langs->load(
"errors");
1809 if (empty(
$conf->barcode->enabled) || empty($this->barcode)) {
1810 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductAlreadyExists", $this->
ref);
1812 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductBarCodeAlreadyExists", $this->barcode);
1814 $this->errors[] = $this->error;
1815 $this->db->rollback();
1818 $this->error = $langs->trans(
"Error").
" : ".$this->db->error().
" - ".$sql;
1819 $this->errors[] = $this->error;
1820 $this->db->rollback();
1825 $this->db->rollback();
1826 dol_syslog(get_class($this).
"::Update fails verify ".implode(
',', $this->errors), LOG_WARNING);
1838 public function delete(
User $user, $notrigger = 0)
1841 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
1846 if (empty($this->
id)) {
1847 $this->error =
"Object must be fetched before calling delete";
1850 if (($this->
isProduct() && !$user->
hasRight(
'produit',
'supprimer')) || ($this->isService() && !$user->hasRight(
'service',
'supprimer'))) {
1851 $this->error =
"ErrorForbidden";
1856 if (empty($objectisused)) {
1859 if (!$error && empty($notrigger)) {
1861 $result = $this->
call_trigger(
'PRODUCT_DELETE', $user);
1870 $sql =
"DELETE FROM ".$this->db->prefix().
'product_batch';
1871 $sql .=
" WHERE fk_product_stock IN (";
1872 $sql .=
"SELECT rowid FROM ".$this->db->prefix().
'product_stock';
1873 $sql .=
" WHERE fk_product = ".((int) $this->
id).
")";
1875 $result = $this->db->query($sql);
1878 $this->errors[] = $this->db->lasterror();
1884 $elements = array(
'product_fournisseur_price',
'product_price',
'product_lang',
'categorie_product',
'product_stock',
'product_customer_price',
'product_lot');
1885 foreach ($elements as $table) {
1887 $sql =
"DELETE FROM ".$this->db->prefix().$table;
1888 $sql .=
" WHERE fk_product = ".(int) $this->
id;
1890 $result = $this->db->query($sql);
1893 $this->errors[] = $this->db->lasterror();
1900 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1901 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination2ValuePair.class.php';
1906 if ($prodcomb->deleteByFkProductParent($user, $this->id) < 0) {
1908 $this->errors[] =
'Error deleting combinations';
1912 if (!$error && ($prodcomb->fetchByFkProductChild($this->id) > 0) && ($prodcomb->delete($user) < 0)) {
1914 $this->errors[] =
'Error deleting child combination';
1920 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
1921 $sql .=
" WHERE fk_product_pere = ".(int) $this->
id.
" OR fk_product_fils = ".(
int) $this->id;
1923 $result = $this->db->query($sql);
1926 $this->errors[] = $this->db->lasterror();
1935 dol_syslog(get_class($this).
"::delete error -4 ".$this->error, LOG_ERR);
1941 $sqlz =
"DELETE FROM ".$this->db->prefix().
"product";
1942 $sqlz .=
" WHERE rowid = ".(int) $this->
id;
1944 $resultz = $this->db->query($sqlz);
1947 $this->errors[] = $this->db->lasterror();
1963 if ($conf->product->dir_output) {
1964 $dir =
$conf->product->dir_output.
"/".$ref;
1965 if (file_exists($dir)) {
1968 $this->errors[] =
'ErrorFailToDeleteDir';
1976 $this->db->commit();
1979 foreach ($this->errors as $errmsg) {
1980 dol_syslog(get_class($this).
"::delete ".$errmsg, LOG_ERR);
1981 $this->error .= ($this->error ?
', '.$errmsg : $errmsg);
1983 $this->db->rollback();
1987 $this->error =
"ErrorRecordIsUsedCantDelete";
2001 $sellByLabel = $langs->trans(
'SellByDate');
2002 $eatByLabel = $langs->trans(
'EatByDate');
2004 self::SELL_OR_EAT_BY_MANDATORY_ID_NONE => $langs->trans(
'BatchSellOrEatByMandatoryNone'),
2005 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY => $sellByLabel,
2006 self::SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY => $eatByLabel,
2007 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT => $langs->trans(
'BatchSellOrEatByMandatoryAll', $sellByLabel, $eatByLabel),
2018 $sellOrEatByMandatoryLabel =
'';
2021 if (isset($sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory])) {
2022 $sellOrEatByMandatoryLabel = $sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory];
2025 return $sellOrEatByMandatoryLabel;
2038 $langs_available = $langs->get_available_languages(DOL_DOCUMENT_ROOT, 0, 2);
2039 $current_lang = $langs->getDefaultLang();
2041 foreach ($langs_available as $key => $value) {
2042 if ($key == $current_lang) {
2043 $sql =
"SELECT rowid";
2044 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2045 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2046 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
2048 $result = $this->db->query($sql);
2050 if ($this->db->num_rows($result)) {
2051 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
2053 $sql2 .=
" label='".$this->db->escape($this->label).
"',";
2054 $sql2 .=
" description='".$this->db->escape($this->
description).
"'";
2056 $sql2 .=
", note='".$this->db->escape($this->other).
"'";
2058 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
2060 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
2065 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->label).
"',";
2066 $sql2 .=
" '".$this->db->escape($this->
description).
"'";
2068 $sql2 .=
", '".$this->db->escape($this->other).
"'";
2072 dol_syslog(get_class($this).
'::setMultiLangs key = current_lang = '.$key);
2073 if (!$this->db->query($sql2)) {
2074 $this->error = $this->db->lasterror();
2077 } elseif (isset($this->multilangs[$key])) {
2078 if (empty($this->multilangs[$key][
"label"])) {
2079 $this->errors[] = $key .
' : ' . $langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Label"));
2083 $sql =
"SELECT rowid";
2084 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2085 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2086 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
2088 $result = $this->db->query($sql);
2090 if ($this->db->num_rows($result)) {
2091 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
2093 $sql2 .=
" label = '".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
2094 $sql2 .=
" description = '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
2097 $sql2 .=
", note = '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
2099 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
2101 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
2106 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
2107 $sql2 .=
" '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
2110 $sql2 .=
", '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
2116 if ($this->multilangs[
"$key"][
"label"] || $this->multilangs[
"$key"][
"description"]) {
2117 if (!$this->db->query($sql2)) {
2118 $this->error = $this->db->lasterror();
2128 $result = $this->
call_trigger(
'PRODUCT_SET_MULTILANGS', $user);
2130 $this->error = $this->db->lasterror();
2148 $sql =
"DELETE FROM ".$this->db->prefix().
"product_lang";
2149 $sql .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($langtodelete).
"'";
2151 dol_syslog(get_class($this).
'::delMultiLangs', LOG_DEBUG);
2152 $result = $this->db->query($sql);
2155 $result = $this->
call_trigger(
'PRODUCT_DEL_MULTILANGS', $user);
2157 $this->error = $this->db->lasterror();
2158 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
2162 unset($this->multilangs[$langtodelete]);
2165 $this->error = $this->db->lasterror();
2166 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
2187 if ($type ==
'buy') {
2188 $field =
'accountancy_code_buy';
2189 } elseif ($type ==
'buy_intra') {
2190 $field =
'accountancy_code_buy_intra';
2191 } elseif ($type ==
'buy_export') {
2192 $field =
'accountancy_code_buy_export';
2193 } elseif ($type ==
'sell') {
2194 $field =
'accountancy_code_sell';
2195 } elseif ($type ==
'sell_intra') {
2196 $field =
'accountancy_code_sell_intra';
2197 } elseif ($type ==
'sell_export') {
2198 $field =
'accountancy_code_sell_export';
2203 $sql =
"UPDATE ".$this->db->prefix().$this->table_element.
" SET ";
2204 $sql .=
"$field = '".$this->db->escape($value).
"'";
2205 $sql .=
" WHERE rowid = ".((int) $this->
id);
2208 $resql = $this->db->query($sql);
2212 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
2219 $this->db->rollback();
2223 $this->$field = $value;
2225 $this->db->commit();
2228 $this->error = $this->db->lasterror();
2229 $this->db->rollback();
2243 $current_lang = $langs->getDefaultLang();
2245 $sql =
"SELECT lang, label, description, note as other";
2246 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
2247 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2249 $result = $this->db->query($sql);
2251 while ($obj = $this->db->fetch_object($result)) {
2253 if ($obj->lang == $current_lang) {
2254 $this->label = $obj->label;
2256 $this->other = $obj->other;
2258 $this->multilangs[(string) $obj->lang][
"label"] = $obj->label;
2259 $this->multilangs[(string) $obj->lang][
"description"] = $obj->description;
2260 $this->multilangs[(string) $obj->lang][
"other"] = $obj->other;
2264 $this->error =
"Error: ".$this->db->lasterror().
" - ".$sql;
2277 $testExit = array(
'multiprices',
'multiprices_ttc',
'multiprices_base_type',
'multiprices_min',
'multiprices_min_ttc',
'multiprices_tva_tx',
'multiprices_recuperableonly');
2279 foreach ($testExit as $field) {
2280 if (!isset($this->$field)) {
2283 $tmparray = $this->$field;
2284 if (!isset($tmparray[$level])) {
2290 'level' => $level ? $level : 1,
2291 'multiprices' => (float) $this->multiprices[$level],
2292 'multiprices_ttc' => (
float) $this->multiprices_ttc[$level],
2293 'multiprices_base_type' => $this->multiprices_base_type[$level],
2294 'multiprices_min' => (float) $this->multiprices_min[$level],
2295 'multiprices_min_ttc' => (
float) $this->multiprices_min_ttc[$level],
2296 'multiprices_tva_tx' => (float) $this->multiprices_tva_tx[$level],
2297 'multiprices_recuperableonly' => (
float) $this->multiprices_recuperableonly[$level],
2320 if (empty($this->price_by_qty)) {
2321 $this->price_by_qty = 0;
2325 $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,";
2326 $sql .=
" localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, price_min,price_min_ttc,price_by_qty,entity,fk_price_expression) ";
2327 $sql .=
" VALUES(".($level ? ((int) $level) : 1).
", '".$this->db->idate($now).
"', ".((int) $this->
id).
", ".((int) $user->id).
", ".(empty($this->price_label) ?
"null" :
"'".$this->db->escape($this->price_label).
"'").
", ".((float)
price2num($this->
price)).
", ".((
float)
price2num($this->price_ttc)).
",'".$this->db->escape($this->price_base_type).
"',".((int) $this->
status).
", ".((float)
price2num($this->tva_tx)).
", ".($this->default_vat_code ? (
"'".$this->db->escape($this->default_vat_code).
"'") :
"null").
", ".((
int) $this->tva_npr).
",";
2328 $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');
2331 dol_syslog(get_class($this).
"::_log_price", LOG_DEBUG);
2332 $resql = $this->db->query($sql);
2334 $this->error = $this->db->lasterror();
2354 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price_by_qty";
2355 $sql .=
" WHERE fk_product_price = ".((int) $rowid);
2356 $resql = $this->db->query($sql);
2358 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price";
2359 $sql .=
" WHERE rowid=".((int) $rowid);
2360 $resql = $this->db->query($sql);
2364 $this->error = $this->db->lasterror();
2379 public function getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp = 0)
2381 global $hookmanager, $action;
2384 if (is_object($hookmanager)) {
2385 $parameters = array(
'thirdparty_seller' => $thirdparty_seller,
'thirdparty_buyer' => $thirdparty_buyer,
'pqp' => $pqp);
2387 $reshook = $hookmanager->executeHooks(
'getSellPrice', $parameters, $this, $action);
2389 return $hookmanager->resArray;
2394 $tva_tx =
get_default_tva($thirdparty_seller, $thirdparty_buyer, $this->
id);
2395 $tva_npr =
get_default_npr($thirdparty_seller, $thirdparty_buyer, $this->
id);
2396 if (empty($tva_tx)) {
2400 $pu_ht = $this->price;
2401 $pu_ttc = $this->price_ttc;
2402 $price_min = $this->price_min;
2403 $price_min_ttc = $this->price_min_ttc;
2404 $price_base_type = $this->price_base_type;
2408 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2412 $filter = array(
't.fk_product' => (
string) $this->
id,
't.fk_soc' => (
string) $thirdparty_buyer->id);
2415 $pricebycustomerexist =
false;
2416 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2418 if (count($prodcustprice->lines) > 0) {
2419 $date_now = (int) floor(
dol_now() / 86400) * 86400;
2420 foreach ($prodcustprice->lines as $k => $custprice_line) {
2421 if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
2422 $pricebycustomerexist =
true;
2423 $pu_ht =
price($custprice_line->price);
2424 $price_min =
price($custprice_line->price_min);
2425 $price_min_ttc =
price($custprice_line->price_min_ttc);
2426 $pu_ttc =
price($custprice_line->price_ttc);
2427 $price_base_type = $custprice_line->price_base_type;
2428 $tva_tx = $custprice_line->tva_tx;
2429 if ($custprice_line->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2430 $tva_tx .=
' (' . $custprice_line->default_vat_code .
')';
2432 $tva_npr = $custprice_line->recuperableonly;
2433 if (empty($tva_tx)) {
2442 if (!$pricebycustomerexist && !empty($thirdparty_buyer->price_level)) {
2443 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
2444 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
2445 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
2446 $price_min_ttc = $this->multiprices_min_ttc[$thirdparty_buyer->price_level];
2447 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
2450 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2451 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2453 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2454 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2456 if (empty($tva_tx)) {
2461 } elseif (
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !empty($thirdparty_buyer->price_level)) {
2462 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
2463 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
2464 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
2465 $price_min_ttc = $this->multiprices_min_ttc[$thirdparty_buyer->price_level];
2466 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
2468 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2469 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2471 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2472 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2474 if (empty($tva_tx)) {
2480 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2484 $filter = array(
't.fk_product' => (
string) $this->
id,
't.fk_soc' => (
string) $thirdparty_buyer->id);
2486 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2488 if (count($prodcustprice->lines) > 0) {
2489 $date_now = (int) floor(
dol_now() / 86400) * 86400;
2490 foreach ($prodcustprice->lines as $k => $custprice_line) {
2491 if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
2492 $pu_ht =
price($custprice_line->price);
2493 $price_min =
price($custprice_line->price_min);
2494 $price_min_ttc =
price($custprice_line->price_min_ttc);
2495 $pu_ttc =
price($custprice_line->price_ttc);
2496 $price_base_type = $custprice_line->price_base_type;
2497 $tva_tx = $custprice_line->tva_tx;
2498 if ($custprice_line->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2499 $tva_tx .=
' (' . $custprice_line->default_vat_code .
')';
2501 $tva_npr = $custprice_line->recuperableonly;
2502 if (empty($tva_tx)) {
2512 if ($this->prices_by_qty[0]) {
2515 foreach ($this->prices_by_qty_list[0] as $priceforthequantityarray) {
2516 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2520 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2521 $pu_ht = $priceforthequantityarray[
'unitprice'];
2523 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2530 if ($this->prices_by_qty[$thirdparty_buyer->price_level]) {
2533 foreach ($this->prices_by_qty_list[$thirdparty_buyer->price_level] as $priceforthequantityarray) {
2534 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2538 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2539 $pu_ht = $priceforthequantityarray[
'unitprice'];
2541 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2548 $localtax1 =
get_localtax((
string) $tva_tx, 1, $thirdparty_buyer, $thirdparty_seller, $tva_npr);
2549 $localtax2 =
get_localtax((
string) $tva_tx, 2, $thirdparty_buyer, $thirdparty_seller, $tva_npr);
2551 return array(
'pu_ht' => $pu_ht,
'pu_ttc' => $pu_ttc,
'price_min' => $price_min,
'price_min_ttc' => $price_min_ttc,
'price_base_type' => $price_base_type,
'tva_tx' => $tva_tx,
'tva_npr' => $tva_npr,
'localtax1' => $localtax1,
'localtax2' => $localtax2);
2568 public function get_buyprice($prodfournprice, $qty, $product_id = 0, $fourn_ref =
'', $fk_soc = 0)
2571 global $action, $hookmanager;
2574 if (is_object($hookmanager)) {
2575 $parameters = array(
2576 'prodfournprice' => $prodfournprice,
2578 'product_id' => $product_id,
2579 'fourn_ref' => $fourn_ref,
2580 'fk_soc' => $fk_soc,
2583 $reshook = $hookmanager->executeHooks(
'getBuyPrice', $parameters, $this, $action);
2585 return $hookmanager->resArray;
2592 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2593 $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,";
2594 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2595 $sql .=
" pfp.packaging";
2596 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2597 $sql .=
" WHERE pfp.rowid = ".((int) $prodfournprice);
2599 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2601 $sql .=
" ORDER BY pfp.quantity DESC";
2603 dol_syslog(get_class($this).
"::get_buyprice first search by prodfournprice/qty", LOG_DEBUG);
2604 $resql = $this->db->query($sql);
2606 $obj = $this->db->fetch_object($resql);
2607 if ($obj && $obj->quantity > 0) {
2608 if (isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2610 $prod_supplier->product_fourn_price_id = $obj->rowid;
2611 $prod_supplier->id = $obj->fk_product;
2612 $prod_supplier->fourn_qty = $obj->quantity;
2613 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2614 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2616 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2618 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2619 if ($price_result >= 0) {
2620 $obj->price = $price_result;
2623 $this->product_fourn_price_id = $obj->rowid;
2624 $this->buyprice = $obj->price;
2625 $this->fourn_pu = $obj->price / $obj->quantity;
2626 $this->fourn_price_base_type =
'HT';
2627 $this->fourn_socid = $obj->fk_soc;
2628 $this->ref_fourn = $obj->ref_supplier;
2629 $this->ref_supplier = $obj->ref_supplier;
2630 $this->desc_supplier = $obj->desc_supplier;
2631 $this->remise_percent = $obj->remise_percent;
2632 $this->vatrate_supplier = $obj->tva_tx;
2633 $this->default_vat_code_supplier = $obj->default_vat_code;
2634 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2635 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2636 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2637 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2638 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2640 $this->packaging = (float) $obj->packaging;
2642 $result = $obj->fk_product;
2646 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2647 $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,";
2648 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2649 $sql .=
" pfp.packaging";
2650 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2651 $sql .=
" WHERE 1 = 1";
2652 if ($product_id > 0) {
2653 $sql .=
" AND pfp.fk_product = ".((int) $product_id);
2655 if ($fourn_ref !=
'none') {
2656 $sql .=
" AND pfp.ref_fourn = '".$this->db->escape($fourn_ref).
"'";
2659 $sql .=
" AND pfp.fk_soc = ".((int) $fk_soc);
2662 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2664 $sql .=
" ORDER BY pfp.quantity DESC";
2667 dol_syslog(get_class($this).
"::get_buyprice second search from qty/ref/product_id", LOG_DEBUG);
2668 $resql = $this->db->query($sql);
2670 $obj = $this->db->fetch_object($resql);
2671 if ($obj && $obj->quantity > 0) {
2672 if (isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2674 $prod_supplier->product_fourn_price_id = $obj->rowid;
2675 $prod_supplier->id = $obj->fk_product;
2676 $prod_supplier->fourn_qty = $obj->quantity;
2677 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2678 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2680 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2682 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2683 if ($price_result >= 0) {
2684 $obj->price = $price_result;
2687 $this->product_fourn_price_id = $obj->rowid;
2688 $this->buyprice = $obj->price;
2689 $this->fourn_qty = $obj->quantity;
2690 $this->fourn_pu = $obj->price / $obj->quantity;
2691 $this->fourn_price_base_type =
'HT';
2692 $this->fourn_socid = $obj->fk_soc;
2693 $this->ref_fourn = $obj->ref_supplier;
2694 $this->ref_supplier = $obj->ref_supplier;
2695 $this->desc_supplier = $obj->desc_supplier;
2696 $this->remise_percent = $obj->remise_percent;
2697 $this->vatrate_supplier = $obj->tva_tx;
2698 $this->default_vat_code_supplier = $obj->default_vat_code;
2699 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2700 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2701 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2702 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2703 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2705 $this->packaging = (float) $obj->packaging;
2707 $result = $obj->fk_product;
2713 $this->error = $this->db->lasterror();
2718 $this->error = $this->db->lasterror();
2742 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)
2748 dol_syslog(get_class($this).
"::update_price id=".$id.
" newprice=".$newprice.
" newpricebase=".$newpricebase.
" newminprice=".$newminprice.
" level=".$level.
" npr=".$newnpr.
" newdefaultvatcode=".$newdefaultvatcode);
2751 if (empty($this->tva_tx)) {
2752 $this->tva_tx = 0.0;
2754 if (empty($newnpr)) {
2757 if (empty($newminprice)) {
2762 if ($newvat ===
null || $newvat ==
'') {
2763 $newvat = (float) $this->tva_tx;
2766 $localtaxtype1 =
'';
2767 $localtaxtype2 =
'';
2772 return $this->
generateMultiprices($user, $newprice, $newpricebase, $newvat, $newnpr, $newpbq);
2775 if (!empty($newminprice) && ($newminprice > $newprice)) {
2776 $this->error =
'ErrorPriceCantBeLowerThanMinPrice';
2780 if ($newprice === 0 || $newprice !==
'') {
2781 if ($newpricebase ==
'TTC') {
2782 $price_ttc = (float)
price2num($newprice,
'MU');
2783 $price = (float)
price2num($newprice) / (1 + ((float) $newvat / 100));
2784 $price = (float)
price2num($price,
'MU');
2786 if ((
string) $newminprice !=
'0') {
2787 $price_min_ttc = (float)
price2num($newminprice,
'MU');
2788 $price_min = (float)
price2num($newminprice) / (1 + ($newvat / 100));
2789 $price_min = (float)
price2num($price_min,
'MU');
2792 $price_min_ttc = 0.0;
2795 $price = (float)
price2num($newprice,
'MU');
2796 $price_ttc = ($newnpr != 1) ? (
float)
price2num($newprice) * (1 + ($newvat / 100)) : $price;
2797 $price_ttc = (float)
price2num($price_ttc,
'MU');
2799 if ((
string) $newminprice !=
'0') {
2800 $price_min = (float)
price2num($newminprice,
'MU');
2801 $price_min_ttc = (float)
price2num($newminprice) * (1 + ($newvat / 100));
2802 $price_min_ttc = (float)
price2num($price_min_ttc,
'MU');
2806 $price_min_ttc = 0.0;
2810 if (count($localtaxes_array) > 0) {
2811 $localtaxtype1 = $localtaxes_array[
'0'];
2812 $localtax1 = $localtaxes_array[
'1'];
2813 $localtaxtype2 = $localtaxes_array[
'2'];
2814 $localtax2 = $localtaxes_array[
'3'];
2817 if (!empty($newdefaultvatcode)) {
2820 $sql =
"SELECT t.rowid, t.code, t.recuperableonly as tva_npr, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
2821 $sql .=
" FROM ".MAIN_DB_PREFIX.
"c_tva as t, ".MAIN_DB_PREFIX.
"c_country as c";
2822 $sql .=
" WHERE t.fk_pays = c.rowid AND c.code = '".$this->db->escape($mysoc->country_code).
"'";
2823 $sql .=
" AND t.taux = ".((float) $newdefaultvatcode).
" AND t.active = 1";
2824 $sql .=
" AND t.code = '".$this->db->escape($newdefaultvatcode).
"'";
2825 $resql = $this->db->query($sql);
2827 $obj = $this->db->fetch_object($resql);
2829 $npr = $obj->tva_npr;
2830 $localtax1 = $obj->localtax1;
2831 $localtax2 = $obj->localtax2;
2832 $localtaxtype1 = $obj->localtax1_type;
2833 $localtaxtype2 = $obj->localtax2_type;
2838 $localtaxtype1 =
'0';
2840 $localtaxtype2 =
'0';
2844 if (empty($localtax1)) {
2847 if (empty($localtax2)) {
2855 $sql =
"UPDATE ".$this->db->prefix().
"product SET";
2856 $sql .=
" price_base_type = '".$this->db->escape($newpricebase).
"',";
2857 $sql .=
" price = ".(float) $price.
",";
2858 $sql .=
" price_ttc = ".(float) $price_ttc.
",";
2859 $sql .=
" price_min = ".(float) $price_min.
",";
2860 $sql .=
" price_min_ttc = ".(float) $price_min_ttc.
",";
2861 $sql .=
" localtax1_tx = ".($localtax1 >= 0 ? (float) $localtax1 :
'NULL').
",";
2862 $sql .=
" localtax2_tx = ".($localtax2 >= 0 ? (float) $localtax2 :
'NULL').
",";
2863 $sql .=
" localtax1_type = ".($localtaxtype1 !=
'' ?
"'".$this->db->escape($localtaxtype1).
"'" :
"'0'").
",";
2864 $sql .=
" localtax2_type = ".($localtaxtype2 !=
'' ?
"'".$this->db->escape($localtaxtype2).
"'" :
"'0'").
",";
2865 $sql .=
" default_vat_code = ".($newdefaultvatcode ?
"'".$this->db->escape($newdefaultvatcode).
"'" :
"null").
",";
2866 $sql .=
" price_label = ".(!empty($price_label) ?
"'".$this->db->escape($price_label).
"'" :
"null").
",";
2867 $sql .=
" tva_tx = ".(float)
price2num($newvat).
",";
2868 $sql .=
" recuperableonly = '".$this->db->escape((
string) $newnpr).
"'";
2869 $sql .=
" WHERE rowid = ".((int) $id);
2871 dol_syslog(get_class($this).
"::update_price", LOG_DEBUG);
2872 $resql = $this->db->query($sql);
2874 $this->multiprices[$level] = $price;
2875 $this->multiprices_ttc[$level] = $price_ttc;
2876 $this->multiprices_min[$level] = $price_min;
2877 $this->multiprices_min_ttc[$level] = $price_min_ttc;
2878 $this->multiprices_base_type[$level] = $newpricebase;
2879 $this->multiprices_default_vat_code[$level] = $newdefaultvatcode;
2880 $this->multiprices_tva_tx[$level] = $newvat;
2881 $this->multiprices_recuperableonly[$level] = $newnpr;
2883 $this->
price = $price;
2884 $this->price_label = $price_label;
2885 $this->price_ttc = $price_ttc;
2886 $this->price_min = $price_min;
2887 $this->price_min_ttc = $price_min_ttc;
2888 $this->price_base_type = $newpricebase;
2889 $this->default_vat_code = $newdefaultvatcode;
2890 $this->tva_tx = $newvat;
2891 $this->tva_npr = $newnpr;
2894 $this->localtax1_tx = $localtax1;
2895 $this->localtax2_tx = $localtax2;
2896 $this->localtax1_type = $localtaxtype1;
2897 $this->localtax2_type = $localtaxtype2;
2900 $this->price_by_qty = $newpbq;
2904 if (!empty(array_diff_assoc($newPriceData, $lastPriceData)) || !
getDolGlobalString(
'PRODUIT_MULTIPRICES')) {
2908 $this->level = $level;
2912 $result = $this->
call_trigger(
'PRODUCT_PRICE_MODIFY', $user);
2914 $this->db->rollback();
2920 $this->db->commit();
2922 $this->db->rollback();
2923 $this->error = $this->db->lasterror();
2942 $this->fk_price_expression = $expression_id;
2944 return $this->
update($this->
id, $user);
2959 public function fetch($id = 0, $ref =
'', $ref_ext =
'', $barcode =
'', $ignore_expression = 0, $ignore_price_load = 0, $ignore_lang_load = 0)
2961 include_once DOL_DOCUMENT_ROOT.
'/core/lib/company.lib.php';
2965 dol_syslog(get_class($this).
"::fetch id=".$id.
" ref=".$ref.
" ref_ext=".$ref_ext);
2968 if (!$id && !$ref && !$ref_ext && !$barcode) {
2969 $this->error =
'ErrorWrongParameters';
2970 dol_syslog(get_class($this).
"::fetch ".$this->error, LOG_ERR);
2974 $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,";
2975 $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,";
2976 $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,";
2977 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.last_main_doc,";
2978 $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,";
2980 $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,";
2982 $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,";
2987 $separatedEntityPMP =
false;
2988 $separatedStock =
false;
2989 $visibleWarehousesEntities =
$conf->entity;
2992 $checkPMPPerEntity = $this->db->query(
"SELECT pmp FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = ".((int) $id).
" AND entity = ".(
int)
$conf->entity);
2993 if ($this->db->num_rows($checkPMPPerEntity) > 0) {
2994 $separatedEntityPMP =
true;
2998 $separatedStock =
true;
2999 if (isset($mc->sharings[
'stock']) && !empty($mc->sharings[
'stock'])) {
3000 $visibleWarehousesEntities .=
"," . implode(
",", $mc->sharings[
'stock']);
3003 if ($separatedEntityPMP) {
3004 $sql .=
" ppe.pmp,";
3008 $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,";
3009 $sql .=
" p.fk_price_expression, p.price_autogen, p.stockable_product, p.model_pdf,";
3010 $sql .=
" p.price_label,";
3011 if ($separatedStock) {
3012 $sql .=
" SUM(sp.reel) as stock";
3016 $sql .=
" FROM ".$this->db->prefix().
"product as p";
3018 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int)
$conf->entity);
3020 if ($separatedStock) {
3021 $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).
"))";
3025 $sql .=
" WHERE p.rowid = ".((int) $id);
3027 $sql .=
" WHERE p.entity IN (".getEntity($this->element).
")";
3029 $sql .=
" AND p.ref = '".$this->db->escape($ref).
"'";
3030 } elseif ($ref_ext) {
3031 $sql .=
" AND p.ref_ext = '".$this->db->escape($ref_ext).
"'";
3032 } elseif ($barcode) {
3033 $sql .=
" AND p.barcode = '".$this->db->escape($barcode).
"'";
3036 if ($separatedStock) {
3037 $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,";
3038 $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,";
3039 $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,";
3040 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
3041 $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,";
3043 $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,";
3045 $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,";
3047 if ($separatedEntityPMP) {
3048 $sql .=
" ppe.pmp,";
3052 $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,";
3053 $sql .=
" p.fk_price_expression, p.price_autogen, p.stockable_product, p.model_pdf,";
3054 $sql .=
" p.price_label";
3055 if (!$separatedStock) {
3056 $sql .=
", p.stock";
3060 $resql = $this->db->query($sql);
3062 unset($this->oldcopy);
3064 if ($this->db->num_rows($resql) > 0) {
3065 $obj = $this->db->fetch_object($resql);
3067 $this->
id = $obj->rowid;
3068 $this->
ref = $obj->ref;
3069 $this->ref_ext = $obj->ref_ext;
3070 $this->label = $obj->label;
3072 $this->url = $obj->url;
3073 $this->note_public = $obj->note_public;
3074 $this->note_private = $obj->note_private;
3075 $this->note = $obj->note_private;
3077 $this->
type = $obj->fk_product_type;
3078 $this->price_label = $obj->price_label;
3079 $this->
status = $obj->tosell;
3080 $this->status_buy = $obj->tobuy;
3081 $this->status_batch = $obj->tobatch;
3082 $this->sell_or_eat_by_mandatory = $obj->sell_or_eat_by_mandatory;
3083 $this->batch_mask = $obj->batch_mask;
3085 $this->customcode = $obj->customcode;
3086 $this->country_id = $obj->fk_country;
3087 $this->country_code =
getCountry($this->country_id,
'2', $this->db);
3088 $this->state_id = $obj->fk_state;
3089 $this->lifetime = $obj->lifetime;
3090 $this->qc_frequency = $obj->qc_frequency;
3091 $this->
price = $obj->price;
3092 $this->price_ttc = $obj->price_ttc;
3093 $this->price_min = $obj->price_min;
3094 $this->price_min_ttc = $obj->price_min_ttc;
3095 $this->price_base_type = $obj->price_base_type;
3096 $this->cost_price = isset($obj->cost_price) ? (float) $obj->cost_price :
null;
3097 $this->default_vat_code = $obj->default_vat_code;
3098 $this->tva_tx = $obj->tva_tx;
3100 $this->tva_npr = $obj->tva_npr;
3102 $this->localtax1_tx = $obj->localtax1_tx;
3103 $this->localtax2_tx = $obj->localtax2_tx;
3104 $this->localtax1_type = $obj->localtax1_type;
3105 $this->localtax2_type = $obj->localtax2_type;
3107 $this->finished = $obj->finished;
3108 $this->fk_default_bom = $obj->fk_default_bom;
3110 $this->duration = $obj->duration;
3112 preg_match(
'/([\d.]+)(\w+)/', $obj->duration, $matches);
3113 $this->duration_value = !empty($matches[1]) ? (float) $matches[1] : 0;
3114 $this->duration_unit = !empty($matches[2]) ? (string) $matches[2] :
null;
3115 $this->canvas = $obj->canvas;
3116 $this->net_measure = $obj->net_measure;
3117 $this->net_measure_units = $obj->net_measure_units;
3118 $this->weight = $obj->weight;
3119 $this->weight_units = (is_null($obj->weight_units) ? 0 : $obj->weight_units);
3120 $this->length = $obj->length;
3121 $this->length_units = (is_null($obj->length_units) ? 0 : $obj->length_units);
3122 $this->width = $obj->width;
3123 $this->width_units = (is_null($obj->width_units) ? 0 : $obj->width_units);
3124 $this->height = $obj->height;
3125 $this->height_units = (is_null($obj->height_units) ? 0 : $obj->height_units);
3127 $this->surface = $obj->surface;
3128 $this->surface_units = (is_null($obj->surface_units) ? 0 : $obj->surface_units);
3129 $this->volume = $obj->volume;
3130 $this->volume_units = (is_null($obj->volume_units) ? 0 : $obj->volume_units);
3131 $this->barcode = $obj->barcode;
3132 $this->barcode_type = $obj->fk_barcode_type;
3134 $this->accountancy_code_buy = $obj->accountancy_code_buy;
3135 $this->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra;
3136 $this->accountancy_code_buy_export = $obj->accountancy_code_buy_export;
3137 $this->accountancy_code_sell = $obj->accountancy_code_sell;
3138 $this->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra;
3139 $this->accountancy_code_sell_export = $obj->accountancy_code_sell_export;
3141 $this->fk_default_warehouse = $obj->fk_default_warehouse;
3142 $this->fk_default_workstation = $obj->fk_default_workstation;
3143 $this->seuil_stock_alerte = $obj->seuil_stock_alerte;
3144 $this->desiredstock = $obj->desiredstock;
3145 $this->stock_reel = $obj->stock;
3146 $this->stockable_product = $obj->stockable_product;
3147 $this->pmp = $obj->pmp;
3149 $this->date_creation = $this->db->jdate($obj->datec);
3150 $this->date_modification = $this->db->jdate($obj->tms);
3152 $this->import_key = $obj->import_key;
3153 $this->entity = $obj->entity;
3155 $this->ref_ext = $obj->ref_ext;
3156 $this->fk_price_expression = $obj->fk_price_expression;
3157 $this->fk_unit = $obj->fk_unit;
3158 $this->price_autogen = $obj->price_autogen;
3159 $this->model_pdf = $obj->model_pdf;
3160 $this->last_main_doc = $obj->last_main_doc;
3162 $this->mandatory_period = $obj->mandatory_period;
3165 $this->packaging = (float) $obj->packaging;
3168 $this->db->free($resql);
3180 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
3181 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3182 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3183 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3184 $sql .=
" ,price_label";
3185 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3186 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3187 $sql .=
" AND price_level=".((int) $i);
3188 $sql .=
" AND fk_product = ".((int) $this->
id);
3189 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3191 $resql = $this->db->query($sql);
3193 $result = $this->db->fetch_array($resql);
3195 $this->multiprices[$i] = $result ? $result[
"price"] :
null;
3196 $this->multiprices_ttc[$i] = $result ? $result[
"price_ttc"] :
null;
3197 $this->multiprices_min[$i] = $result ? $result[
"price_min"] :
null;
3198 $this->multiprices_min_ttc[$i] = $result ? $result[
"price_min_ttc"] :
null;
3199 $this->multiprices_base_type[$i] = $result ? $result[
"price_base_type"] :
null;
3201 $this->multiprices_tva_tx[$i] = $result ? $result[
"tva_tx"].(!empty($result[
'default_vat_code']) ?
' ('.$result[
'default_vat_code'].
')' :
'') :
null;
3202 $this->multiprices_recuperableonly[$i] = $result ? $result[
"recuperableonly"] :
null;
3241 $this->error = $this->db->lasterror;
3247 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY') && empty($ignore_price_load)) {
3248 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3249 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid";
3250 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3251 $sql .=
" WHERE fk_product = ".((int) $this->
id);
3252 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3255 $resql = $this->db->query($sql);
3257 $result = $this->db->fetch_array($resql);
3261 $this->prices_by_qty[0] = $result[
"price_by_qty"];
3262 $this->prices_by_qty_id[0] = $result[
"rowid"];
3264 if ($this->prices_by_qty[0] == 1) {
3265 $sql =
"SELECT rowid,price, unitprice, quantity, remise_percent, remise, remise, price_base_type";
3266 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3267 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[0]);
3268 $sql .=
" ORDER BY quantity ASC";
3270 $resql = $this->db->query($sql);
3272 $resultat = array();
3274 while ($result = $this->db->fetch_array($resql)) {
3275 $resultat[$ii] = array();
3276 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3277 $resultat[$ii][
"price"] = $result[
"price"];
3278 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3279 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3280 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3282 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3285 $this->prices_by_qty_list[0] = $resultat;
3287 $this->error = $this->db->lasterror;
3293 $this->error = $this->db->lasterror;
3296 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') && empty($ignore_price_load)) {
3297 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
3298 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3299 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3300 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3301 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3302 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3303 $sql .=
" AND price_level=".((int) $i);
3304 $sql .=
" AND fk_product = ".((int) $this->
id);
3305 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3307 $resql = $this->db->query($sql);
3309 $this->error = $this->db->lasterror;
3312 $result = $this->db->fetch_array($resql);
3313 $this->multiprices[$i] = (!empty($result[
"price"]) ? $result[
"price"] : 0);
3314 $this->multiprices_ttc[$i] = (!empty($result[
"price_ttc"]) ? $result[
"price_ttc"] : 0);
3315 $this->multiprices_min[$i] = (!empty($result[
"price_min"]) ? $result[
"price_min"] : 0);
3316 $this->multiprices_min_ttc[$i] = (!empty($result[
"price_min_ttc"]) ? $result[
"price_min_ttc"] : 0);
3317 $this->multiprices_base_type[$i] = (!empty($result[
"price_base_type"]) ? $result[
"price_base_type"] :
'');
3319 $this->multiprices_tva_tx[$i] = (!empty($result[
"tva_tx"]) ? $result[
"tva_tx"] : 0);
3320 $this->multiprices_recuperableonly[$i] = (!empty($result[
"recuperableonly"]) ? $result[
"recuperableonly"] : 0);
3323 $this->prices_by_qty[$i] = (!empty($result[
"price_by_qty"]) ? $result[
"price_by_qty"] : 0);
3324 $this->prices_by_qty_id[$i] = (!empty($result[
"rowid"]) ? $result[
"rowid"] : 0);
3326 if ($this->prices_by_qty[$i] == 1) {
3327 $sql =
"SELECT rowid, price, unitprice, quantity, remise_percent, remise, price_base_type";
3328 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3329 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[$i]);
3330 $sql .=
" ORDER BY quantity ASC";
3332 $resql = $this->db->query($sql);
3334 $resultat = array();
3336 while ($result = $this->db->fetch_array($resql)) {
3337 $resultat[$ii] = array();
3338 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3339 $resultat[$ii][
"price"] = $result[
"price"];
3340 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3341 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3342 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3343 $resultat[$ii][
"remise"] = $result[
"remise"];
3344 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3347 $this->prices_by_qty_list[$i] = $resultat;
3349 $this->error = $this->db->lasterror;
3357 if (isModEnabled(
'dynamicprices') && !empty($this->fk_price_expression) && empty($ignore_expression)) {
3358 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
3360 $price_result = $priceparser->parseProduct($this);
3361 if ($price_result >= 0) {
3362 $this->
price = $price_result;
3364 $this->price_ttc = (float)
price2num($this->
price) * (1 + ($this->tva_tx / 100));
3365 $this->price_ttc = (float)
price2num($this->price_ttc,
'MU');
3371 $this->stock_warehouse = array();
3378 $this->error = $this->db->lasterror();
3393 global $user, $hookmanager, $action;
3397 foreach (array(
'toconsume',
'consumed',
'toproduce',
'produced') as $role) {
3398 $this->stats_mo[
'customers_'.$role] = 0;
3399 $this->stats_mo[
'nb_'.$role] = 0;
3400 $this->stats_mo[
'qty_'.$role] = 0;
3402 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3403 $sql .=
" SUM(mp.qty) as qty";
3404 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as c";
3405 $sql .=
" INNER JOIN ".$this->db->prefix().
"mrp_production as mp ON mp.fk_mo=c.rowid";
3406 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3407 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3410 $sql .=
" c.entity IN (".getEntity(
'mo').
")";
3412 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3413 $sql .=
" AND mp.role ='".$this->db->escape($role).
"'";
3415 $sql .=
" AND c.fk_soc = ".((int) $socid);
3418 $result = $this->db->query($sql);
3420 $obj = $this->db->fetch_object($result);
3421 $this->stats_mo[
'customers_'.$role] = $obj->nb_customers ? $obj->nb_customers : 0;
3422 $this->stats_mo[
'nb_'.$role] = $obj->nb ? $obj->nb : 0;
3423 $this->stats_mo[
'qty_'.$role] = $obj->qty ?
price2num($obj->qty,
'MS') : 0;
3425 $this->error = $this->db->error();
3430 if (!empty($error)) {
3434 $parameters = array(
'socid' => $socid);
3435 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3437 $this->stats_mo = $hookmanager->resArray[
'stats_mo'];
3453 global $hookmanager, $action;
3457 $this->stats_bom[
'nb_toproduce'] = 0;
3458 $this->stats_bom[
'nb_toconsume'] = 0;
3459 $this->stats_bom[
'qty_toproduce'] = 0;
3460 $this->stats_bom[
'qty_toconsume'] = 0;
3462 $sql =
"SELECT COUNT(DISTINCT b.rowid) as nb_toproduce,";
3463 $sql .=
" SUM(b.qty) as qty_toproduce";
3464 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3465 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom = b.rowid";
3467 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3468 $sql .=
" AND b.fk_product =".((int) $this->
id);
3469 $sql .=
" GROUP BY b.rowid";
3471 $result = $this->db->query($sql);
3473 $obj = $this->db->fetch_object($result);
3474 $this->stats_bom[
'nb_toproduce'] = !empty($obj->nb_toproduce) ? $obj->nb_toproduce : 0;
3475 $this->stats_bom[
'qty_toproduce'] = !empty($obj->qty_toproduce) ?
price2num($obj->qty_toproduce) : 0;
3477 $this->error = $this->db->error();
3481 $sql =
"SELECT COUNT(DISTINCT bl.rowid) as nb_toconsume,";
3482 $sql .=
" SUM(bl.qty) as qty_toconsume";
3483 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3484 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
3486 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3487 $sql .=
" AND bl.fk_product =".((int) $this->
id);
3489 $result = $this->db->query($sql);
3491 $obj = $this->db->fetch_object($result);
3492 $this->stats_bom[
'nb_toconsume'] = !empty($obj->nb_toconsume) ? $obj->nb_toconsume : 0;
3493 $this->stats_bom[
'qty_toconsume'] = !empty($obj->qty_toconsume) ?
price2num($obj->qty_toconsume) : 0;
3495 $this->error = $this->db->error();
3499 if (!empty($error)) {
3503 $parameters = array(
'socid' => $socid);
3504 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3506 $this->stats_bom = $hookmanager->resArray[
'stats_bom'];
3522 global $user, $hookmanager, $action;
3524 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_customers, COUNT(DISTINCT p.rowid) as nb,";
3525 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3526 $sql .=
" FROM ".$this->db->prefix().
"propaldet as pd";
3527 $sql .=
", ".$this->db->prefix().
"propal as p";
3528 $sql .=
", ".$this->db->prefix().
"societe as s";
3529 $sql .=
" WHERE p.rowid = pd.fk_propal";
3530 $sql .=
" AND p.fk_soc = s.rowid";
3531 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
3532 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3533 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3534 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $user->id);
3538 $sql .=
" AND p.fk_soc = ".((int) $socid);
3541 $result = $this->db->query($sql);
3543 $obj = $this->db->fetch_object($result);
3544 $this->stats_propale[
'customers'] = $obj->nb_customers;
3545 $this->stats_propale[
'nb'] = $obj->nb;
3546 $this->stats_propale[
'rows'] = $obj->nb_rows;
3547 $this->stats_propale[
'qty'] = $obj->qty ? $obj->qty : 0;
3552 if (is_array($TFather) && !empty($TFather)) {
3553 foreach ($TFather as &$fatherData) {
3554 $pFather =
new Product($this->db);
3555 $pFather->id = $fatherData[
'id'];
3556 $qtyCoef = $fatherData[
'qty'];
3558 if ($fatherData[
'incdec']) {
3559 $pFather->load_stats_propale($socid);
3561 $this->stats_propale[
'customers'] += $pFather->stats_propale[
'customers'];
3562 $this->stats_propale[
'nb'] += $pFather->stats_propale[
'nb'];
3563 $this->stats_propale[
'rows'] += $pFather->stats_propale[
'rows'];
3564 $this->stats_propale[
'qty'] += $pFather->stats_propale[
'qty'] * $qtyCoef;
3570 $parameters = array(
'socid' => $socid);
3571 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerProposal', $parameters, $this, $action);
3573 $this->stats_propale = $hookmanager->resArray[
'stats_propale'];
3578 $this->error = $this->db->error();
3594 global $user, $hookmanager, $action;
3596 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_suppliers, COUNT(DISTINCT p.rowid) as nb,";
3597 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3598 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as pd";
3599 $sql .=
", ".$this->db->prefix().
"supplier_proposal as p";
3600 $sql .=
", ".$this->db->prefix().
"societe as s";
3601 $sql .=
" WHERE p.rowid = pd.fk_supplier_proposal";
3602 $sql .=
" AND p.fk_soc = s.rowid";
3603 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
3604 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3605 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
3606 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $user->id);
3610 $sql .=
" AND p.fk_soc = ".((int) $socid);
3613 $result = $this->db->query($sql);
3615 $obj = $this->db->fetch_object($result);
3616 $this->stats_proposal_supplier[
'suppliers'] = $obj->nb_suppliers;
3617 $this->stats_proposal_supplier[
'nb'] = $obj->nb;
3618 $this->stats_proposal_supplier[
'rows'] = $obj->nb_rows;
3619 $this->stats_proposal_supplier[
'qty'] = $obj->qty ? $obj->qty : 0;
3621 $parameters = array(
'socid' => $socid);
3622 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierProposal', $parameters, $this, $action);
3624 $this->stats_proposal_supplier = $hookmanager->resArray[
'stats_proposal_supplier'];
3629 $this->error = $this->db->error();
3647 global $user, $hookmanager, $action;
3649 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3650 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3651 $sql .=
" FROM ".$this->db->prefix().
"commandedet as cd";
3652 $sql .=
", ".$this->db->prefix().
"commande as c";
3653 $sql .=
", ".$this->db->prefix().
"societe as s";
3654 $sql .=
" WHERE c.rowid = cd.fk_commande";
3655 $sql .=
" AND c.fk_soc = s.rowid";
3656 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'commande').
")";
3657 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3658 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3659 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3662 $sql .=
" AND c.fk_soc = ".((int) $socid);
3664 if ($filtrestatut !=
'') {
3665 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3668 $result = $this->db->query($sql);
3670 $obj = $this->db->fetch_object($result);
3671 $this->stats_commande[
'customers'] = $obj->nb_customers;
3672 $this->stats_commande[
'nb'] = $obj->nb;
3673 $this->stats_commande[
'rows'] = $obj->nb_rows;
3674 $this->stats_commande[
'qty'] = $obj->qty ? $obj->qty : 0;
3679 if (is_array($TFather) && !empty($TFather)) {
3680 foreach ($TFather as &$fatherData) {
3681 $pFather =
new Product($this->db);
3682 $pFather->id = $fatherData[
'id'];
3683 $qtyCoef = $fatherData[
'qty'];
3685 if ($fatherData[
'incdec']) {
3686 $pFather->load_stats_commande($socid, $filtrestatut);
3688 $this->stats_commande[
'customers'] += $pFather->stats_commande[
'customers'];
3689 $this->stats_commande[
'nb'] += $pFather->stats_commande[
'nb'];
3690 $this->stats_commande[
'rows'] += $pFather->stats_commande[
'rows'];
3691 $this->stats_commande[
'qty'] += $pFather->stats_commande[
'qty'] * $qtyCoef;
3703 $sql =
"SELECT SUM(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3704 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3705 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON ((el.fk_target = f.rowid AND el.targettype = 'facture' AND sourcetype = 'commande') OR (el.fk_source = f.rowid AND el.targettype = 'commande' AND sourcetype = 'facture'))";
3706 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3707 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3709 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3710 $resql = $this->db->query($sql);
3712 if ($this->db->num_rows($resql) > 0) {
3713 $obj = $this->db->fetch_object($resql);
3714 $adeduire += $obj->count;
3718 $this->stats_commande[
'qty'] -= $adeduire;
3721 include_once DOL_DOCUMENT_ROOT.
'/compta/facture/class/facture.class.php';
3725 $sql =
"SELECT sum(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count";
3726 $sql .=
" FROM " . $this->db->prefix() .
"facturedet as fd";
3727 $sql .=
" JOIN " . $this->db->prefix() .
"facture as f ON fd.fk_facture = f.rowid";
3728 $sql .=
" JOIN " . $this->db->prefix() .
"element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture' AND el.sourcetype = 'commande'";
3729 $sql .=
" JOIN " . $this->db->prefix() .
"commande as c ON el.fk_source = c.rowid";
3730 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3731 $sql .=
" UNION ALL";
3732 $sql .=
" SELECT sum(".$this->db->ifsql(
'f.type=2',
'-1',
'1').
" * fd.qty) as count";
3733 $sql .=
" FROM " . $this->db->prefix() .
"facturedet as fd";
3734 $sql .=
" JOIN " . $this->db->prefix() .
"facture as f ON fd.fk_facture = f.rowid";
3735 $sql .=
" JOIN " . $this->db->prefix() .
"element_element as el ON el.fk_source = f.rowid AND el.targettype = 'commande' AND el.sourcetype = 'facture'";
3736 $sql .=
" JOIN " . $this->db->prefix() .
"commande as c ON el.fk_source = c.rowid";
3737 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product =".((int) $this->
id);
3738 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3739 $resql = $this->db->query($sql);
3741 if ($this->db->num_rows($resql) > 0) {
3742 $obj = $this->db->fetch_object($resql);
3743 $adeduire += $obj->count;
3746 $this->error = $this->db->error();
3750 $this->stats_commande[
'qty'] -= $adeduire;
3754 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3755 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerOrder', $parameters, $this, $action);
3757 $this->stats_commande = $hookmanager->resArray[
'stats_commande'];
3761 $this->error = $this->db->error();
3779 global $user, $hookmanager, $action;
3781 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_suppliers, COUNT(DISTINCT c.rowid) as nb,";
3782 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3783 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as cd";
3784 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as c";
3785 $sql .=
", ".$this->db->prefix().
"societe as s";
3786 $sql .=
" WHERE c.rowid = cd.fk_commande";
3787 $sql .=
" AND c.fk_soc = s.rowid";
3788 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3789 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3790 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3791 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
3794 $sql .=
" AND c.fk_soc = ".((int) $socid);
3796 if ($filtrestatut !=
'') {
3797 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3799 if (!empty($dateofvirtualstock)) {
3800 $sql .=
" AND c.date_livraison <= '".$this->db->idate($dateofvirtualstock).
"'";
3803 $result = $this->db->query($sql);
3805 $obj = $this->db->fetch_object($result);
3806 $this->stats_commande_fournisseur[
'suppliers'] = $obj->nb_suppliers;
3807 $this->stats_commande_fournisseur[
'nb'] = $obj->nb;
3808 $this->stats_commande_fournisseur[
'rows'] = $obj->nb_rows;
3809 $this->stats_commande_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
3811 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3812 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierOrder', $parameters, $this, $action);
3814 $this->stats_commande_fournisseur = $hookmanager->resArray[
'stats_commande_fournisseur'];
3819 $this->error = $this->db->error().
' sql='.$sql;
3834 public function load_stats_sending($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $filterShipmentStatus =
'')
3837 global $user, $hookmanager, $action;
3839 $sql =
"SELECT COUNT(DISTINCT e.fk_soc) as nb_customers, COUNT(DISTINCT e.rowid) as nb,";
3840 $sql .=
" COUNT(ed.rowid) as nb_rows, SUM(ed.qty) as qty";
3841 $sql .=
" FROM ".$this->db->prefix().
"expeditiondet as ed";
3842 $sql .=
", ".$this->db->prefix().
"commandedet as cd";
3843 $sql .=
", ".$this->db->prefix().
"commande as c";
3844 $sql .=
", ".$this->db->prefix().
"expedition as e";
3845 $sql .=
", ".$this->db->prefix().
"societe as s";
3846 $sql .=
" WHERE e.rowid = ed.fk_expedition";
3847 $sql .=
" AND c.rowid = cd.fk_commande";
3848 $sql .=
" AND e.fk_soc = s.rowid";
3849 $sql .=
" AND e.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'expedition').
")";
3850 $sql .=
" AND ed.fk_elementdet = cd.rowid";
3851 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3852 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3853 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = e.fk_soc AND sc.fk_user = ".((int) $user->id);
3856 $sql .=
" AND e.fk_soc = ".((int) $socid);
3858 if ($filtrestatut !=
'') {
3859 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3861 if (!empty($filterShipmentStatus)) {
3862 $sql .=
" AND e.fk_statut IN (".$this->db->sanitize($filterShipmentStatus).
")";
3865 $result = $this->db->query($sql);
3867 $obj = $this->db->fetch_object($result);
3868 $this->stats_expedition[
'customers'] = $obj->nb_customers;
3869 $this->stats_expedition[
'nb'] = $obj->nb;
3870 $this->stats_expedition[
'rows'] = $obj->nb_rows;
3871 $this->stats_expedition[
'qty'] = $obj->qty ? $obj->qty : 0;
3876 if (is_array($TFather) && !empty($TFather)) {
3877 foreach ($TFather as &$fatherData) {
3878 $pFather =
new Product($this->db);
3879 $pFather->id = $fatherData[
'id'];
3880 $qtyCoef = $fatherData[
'qty'];
3882 if ($fatherData[
'incdec']) {
3883 $pFather->load_stats_sending($socid, $filtrestatut, $forVirtualStock);
3885 $this->stats_expedition[
'customers'] += $pFather->stats_expedition[
'customers'];
3886 $this->stats_expedition[
'nb'] += $pFather->stats_expedition[
'nb'];
3887 $this->stats_expedition[
'rows'] += $pFather->stats_expedition[
'rows'];
3888 $this->stats_expedition[
'qty'] += $pFather->stats_expedition[
'qty'] * $qtyCoef;
3894 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock,
'filterShipmentStatus' => $filterShipmentStatus);
3895 $reshook = $hookmanager->executeHooks(
'loadStatsSending', $parameters, $this, $action);
3897 $this->stats_expedition = $hookmanager->resArray[
'stats_expedition'];
3902 $this->error = $this->db->error();
3917 public function load_stats_reception($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null)
3920 global $user, $hookmanager, $action;
3922 $sql =
"SELECT COUNT(DISTINCT cf.fk_soc) as nb_suppliers, COUNT(DISTINCT cf.rowid) as nb,";
3923 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
3924 $sql .=
" FROM ".$this->db->prefix().
"receptiondet_batch as fd";
3925 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as cf";
3926 $sql .=
", ".$this->db->prefix().
"societe as s";
3927 $sql .=
" WHERE cf.rowid = fd.fk_element";
3928 $sql .=
" AND cf.fk_soc = s.rowid";
3929 $sql .=
" AND cf.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3930 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3931 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3932 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = cf.fk_soc AND sc.fk_user = ".((int) $user->id);
3935 $sql .=
" AND cf.fk_soc = ".((int) $socid);
3937 if ($filtrestatut !=
'') {
3938 $sql .=
" AND cf.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3940 if (!empty($dateofvirtualstock)) {
3941 $sql .=
" AND fd.datec <= '".$this->db->idate($dateofvirtualstock).
"'";
3944 $result = $this->db->query($sql);
3946 $obj = $this->db->fetch_object($result);
3947 $this->stats_reception[
'suppliers'] = $obj->nb_suppliers;
3948 $this->stats_reception[
'nb'] = $obj->nb;
3949 $this->stats_reception[
'rows'] = $obj->nb_rows;
3950 $this->stats_reception[
'qty'] = $obj->qty ? $obj->qty : 0;
3952 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3953 $reshook = $hookmanager->executeHooks(
'loadStatsReception', $parameters, $this, $action);
3955 $this->stats_reception = $hookmanager->resArray[
'stats_reception'];
3960 $this->error = $this->db->error();
3976 public function load_stats_inproduction($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null, $warehouseid = 0)
3979 global $user, $hookmanager, $action;
3981 $serviceStockIsEnabled = isModEnabled(
"service") &&
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES');
3983 $sql =
"SELECT COUNT(DISTINCT m.fk_soc) as nb_customers, COUNT(DISTINCT m.rowid) as nb,";
3984 $sql .=
" COUNT(mp.rowid) as nb_rows, SUM(mp.qty) as qty, role";
3985 $sql .=
" FROM ".$this->db->prefix().
"mrp_production as mp";
3986 $sql .=
", ".$this->db->prefix().
"mrp_mo as m";
3987 $sql .=
" LEFT JOIN ".$this->db->prefix().
"societe as s ON s.rowid = m.fk_soc";
3988 $sql .=
" WHERE m.rowid = mp.fk_mo";
3989 $sql .=
" AND m.entity IN (".getEntity(($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE')) ?
'stock' :
'mrp').
")";
3990 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3991 $sql .=
" AND (mp.disable_stock_change IN (0) OR mp.disable_stock_change IS NULL)";
3992 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3993 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = m.fk_soc AND sc.fk_user = ".((int) $user->id);
3996 $sql .=
" AND m.fk_soc = ".((int) $socid);
3998 if ($filtrestatut !=
'') {
3999 $sql .=
" AND m.status IN (".$this->db->sanitize($filtrestatut).
")";
4001 if (!empty($dateofvirtualstock)) {
4002 $sql .=
" AND m.date_valid <= '".$this->db->idate($dateofvirtualstock).
"'";
4004 if (!$serviceStockIsEnabled) {
4005 $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))";
4007 if (!empty($warehouseid)) {
4008 $sql .=
" AND m.fk_warehouse = ".((int) $warehouseid);
4010 $sql .=
" GROUP BY role";
4013 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
4015 $this->stats_mrptoconsume[
'customers'] = 0;
4016 $this->stats_mrptoconsume[
'nb'] = 0;
4017 $this->stats_mrptoconsume[
'rows'] = 0;
4018 $this->stats_mrptoconsume[
'qty'] = 0.0;
4019 $this->stats_mrptoproduce[
'customers'] = 0;
4020 $this->stats_mrptoproduce[
'nb'] = 0;
4021 $this->stats_mrptoproduce[
'rows'] = 0;
4022 $this->stats_mrptoproduce[
'qty'] = 0.0;
4025 $result = $this->db->query($sql);
4027 while ($obj = $this->db->fetch_object($result)) {
4028 if ($obj->role ==
'toconsume' && empty($warehouseid)) {
4029 $this->stats_mrptoconsume[
'customers'] += (int) $obj->nb_customers;
4030 $this->stats_mrptoconsume[
'nb'] += (int) $obj->nb;
4031 $this->stats_mrptoconsume[
'rows'] += (int) $obj->nb_rows;
4032 $this->stats_mrptoconsume[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4034 if ($obj->role ==
'consumed' && empty($warehouseid)) {
4038 $this->stats_mrptoconsume[
'qty'] -= ($obj->qty ? (float) $obj->qty : 0.0);
4040 if ($obj->role ==
'toproduce') {
4042 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4044 $this->stats_mrptoproduce[
'customers'] += (int) $obj->nb_customers;
4045 $this->stats_mrptoproduce[
'nb'] += (int) $obj->nb;
4046 $this->stats_mrptoproduce[
'rows'] += (int) $obj->nb_rows;
4047 $this->stats_mrptoproduce[
'qty'] += ($obj->qty ? (float) $obj->qty : 0.0);
4050 if ($obj->role ==
'produced') {
4055 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
4057 $this->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
4064 if ($this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] < 0) {
4065 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
4068 if ($this->stats_mrptoconsume[
'qty'] < 0) {
4069 $this->stats_mrptoconsume[
'qty'] = 0;
4071 if ($this->stats_mrptoproduce[
'qty'] < 0) {
4072 $this->stats_mrptoproduce[
'qty'] = 0;
4076 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
4077 $reshook = $hookmanager->executeHooks(
'loadStatsInProduction', $parameters, $this, $action);
4079 $this->stats_mrptoproduce = $hookmanager->resArray[
'stats_mrptoproduce'];
4084 $this->error = $this->db->error();
4099 global $user, $hookmanager, $action;
4101 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
4102 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
4103 $sql .=
" FROM ".$this->db->prefix().
"contratdet as cd";
4104 $sql .=
", ".$this->db->prefix().
"contrat as c";
4105 $sql .=
", ".$this->db->prefix().
"societe as s";
4106 $sql .=
" WHERE c.rowid = cd.fk_contrat";
4107 $sql .=
" AND c.fk_soc = s.rowid";
4108 $sql .=
" AND c.entity IN (".getEntity(
'contract').
")";
4109 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
4110 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4111 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = c.fk_soc AND sc.fk_user = ".((int) $user->id);
4115 $sql .=
" AND c.fk_soc = ".((int) $socid);
4118 $result = $this->db->query($sql);
4120 $obj = $this->db->fetch_object($result);
4121 $this->stats_contrat[
'customers'] = $obj->nb_customers;
4122 $this->stats_contrat[
'nb'] = $obj->nb;
4123 $this->stats_contrat[
'rows'] = $obj->nb_rows;
4124 $this->stats_contrat[
'qty'] = $obj->qty ? $obj->qty : 0;
4129 if (is_array($TFather) && !empty($TFather)) {
4130 foreach ($TFather as &$fatherData) {
4131 $pFather =
new Product($this->db);
4132 $pFather->id = $fatherData[
'id'];
4133 $qtyCoef = $fatherData[
'qty'];
4135 if ($fatherData[
'incdec']) {
4136 $pFather->load_stats_contrat($socid);
4138 $this->stats_contrat[
'customers'] += $pFather->stats_contrat[
'customers'];
4139 $this->stats_contrat[
'nb'] += $pFather->stats_contrat[
'nb'];
4140 $this->stats_contrat[
'rows'] += $pFather->stats_contrat[
'rows'];
4141 $this->stats_contrat[
'qty'] += $pFather->stats_contrat[
'qty'] * $qtyCoef;
4147 $parameters = array(
'socid' => $socid);
4148 $reshook = $hookmanager->executeHooks(
'loadStatsContract', $parameters, $this, $action);
4150 $this->stats_contrat = $hookmanager->resArray[
'stats_contrat'];
4155 $this->error = $this->db->error().
' sql='.$sql;
4170 global $user, $hookmanager, $action;
4172 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4173 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(".$this->db->ifsql(
'f.type != 2',
'fd.qty',
'fd.qty * -1').
") as qty";
4174 $sql .=
" FROM ".$this->db->prefix().
"facturedet as fd";
4175 $sql .=
", ".$this->db->prefix().
"facture as f";
4176 $sql .=
", ".$this->db->prefix().
"societe as s";
4177 $sql .=
" WHERE f.rowid = fd.fk_facture";
4178 $sql .=
" AND f.fk_soc = s.rowid";
4179 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4180 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4181 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4182 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4186 $sql .=
" AND f.fk_soc = ".((int) $socid);
4189 $result = $this->db->query($sql);
4191 $obj = $this->db->fetch_object($result);
4192 $this->stats_facture[
'customers'] = $obj->nb_customers;
4193 $this->stats_facture[
'nb'] = $obj->nb;
4194 $this->stats_facture[
'rows'] = $obj->nb_rows;
4195 $this->stats_facture[
'qty'] = $obj->qty ? $obj->qty : 0;
4200 if (is_array($TFather) && !empty($TFather)) {
4201 foreach ($TFather as &$fatherData) {
4202 $pFather =
new Product($this->db);
4203 $pFather->id = $fatherData[
'id'];
4204 $qtyCoef = $fatherData[
'qty'];
4206 if ($fatherData[
'incdec']) {
4207 $pFather->load_stats_facture($socid);
4209 $this->stats_facture[
'customers'] += $pFather->stats_facture[
'customers'];
4210 $this->stats_facture[
'nb'] += $pFather->stats_facture[
'nb'];
4211 $this->stats_facture[
'rows'] += $pFather->stats_facture[
'rows'];
4212 $this->stats_facture[
'qty'] += $pFather->stats_facture[
'qty'] * $qtyCoef;
4218 $parameters = array(
'socid' => $socid);
4219 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoice', $parameters, $this, $action);
4221 $this->stats_facture = $hookmanager->resArray[
'stats_facture'];
4226 $this->error = $this->db->error();
4242 global $user, $hookmanager, $action;
4244 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
4245 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4246 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facturedet_rec as fd";
4247 $sql .=
", ".MAIN_DB_PREFIX.
"facture_rec as f";
4248 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
4249 $sql .=
" WHERE f.rowid = fd.fk_facture";
4250 $sql .=
" AND f.fk_soc = s.rowid";
4251 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4252 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4253 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4254 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4258 $sql .=
" AND f.fk_soc = ".((int) $socid);
4261 $result = $this->db->query($sql);
4263 $obj = $this->db->fetch_object($result);
4264 $this->stats_facturerec[
'customers'] = (int) $obj->nb_customers;
4265 $this->stats_facturerec[
'nb'] = (int) $obj->nb;
4266 $this->stats_facturerec[
'rows'] = (int) $obj->nb_rows;
4267 $this->stats_facturerec[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4272 if (is_array($TFather) && !empty($TFather)) {
4273 foreach ($TFather as &$fatherData) {
4274 $pFather =
new Product($this->db);
4275 $pFather->id = $fatherData[
'id'];
4276 $qtyCoef = $fatherData[
'qty'];
4278 if ($fatherData[
'incdec']) {
4279 $pFather->load_stats_facture($socid);
4281 $this->stats_facturerec[
'customers'] += $pFather->stats_facturerec[
'customers'];
4282 $this->stats_facturerec[
'nb'] += $pFather->stats_facturerec[
'nb'];
4283 $this->stats_facturerec[
'rows'] += $pFather->stats_facturerec[
'rows'];
4284 $this->stats_facturerec[
'qty'] += $pFather->stats_facturerec[
'qty'] * $qtyCoef;
4290 $parameters = array(
'socid' => $socid);
4291 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoiceRec', $parameters, $this, $action);
4293 $this->stats_facturerec = $hookmanager->resArray[
'stats_facturerec'];
4298 $this->error = $this->db->error();
4313 global $user, $hookmanager, $action;
4315 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
4316 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4317 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as fd";
4318 $sql .=
", ".$this->db->prefix().
"facture_fourn as f";
4319 $sql .=
", ".$this->db->prefix().
"societe as s";
4320 $sql .=
" WHERE f.rowid = fd.fk_facture_fourn";
4321 $sql .=
" AND f.fk_soc = s.rowid";
4322 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4323 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4324 if (empty($user->fk_soc) && !$user->hasRight(
'societe',
'client',
'voir')) {
4325 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc = f.fk_soc AND sc.fk_user = ".((int) $user->id);
4329 $sql .=
" AND f.fk_soc = ".((int) $socid);
4332 $result = $this->db->query($sql);
4334 $obj = $this->db->fetch_object($result);
4335 $this->stats_facture_fournisseur[
'suppliers'] = (int) $obj->nb_suppliers;
4336 $this->stats_facture_fournisseur[
'nb'] = (int) $obj->nb;
4337 $this->stats_facture_fournisseur[
'rows'] = (int) $obj->nb_rows;
4338 $this->stats_facture_fournisseur[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4340 $parameters = array(
'socid' => $socid);
4341 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoice', $parameters, $this, $action);
4343 $this->stats_facture_fournisseur = $hookmanager->resArray[
'stats_facture_fournisseur'];
4348 $this->error = $this->db->error();
4363 global $user, $hookmanager, $action;
4365 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
4366 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
4367 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facture_fourn_det_rec as fd";
4368 $sql .=
", ".MAIN_DB_PREFIX.
"facture_fourn_rec as f";
4369 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
4370 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4371 $sql .=
", ".MAIN_DB_PREFIX.
"societe_commerciaux as sc";
4373 $sql .=
" WHERE f.rowid = fd.fk_facture";
4374 $sql .=
" AND f.fk_soc = s.rowid";
4375 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4376 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
4377 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4378 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4382 $sql .=
" AND f.fk_soc = ".((int) $socid);
4385 $result = $this->db->query($sql);
4387 $obj = $this->db->fetch_object($result);
4388 $this->stats_facturefournrec[
'suppliers'] = (int) $obj->nb_suppliers;
4389 $this->stats_facturefournrec[
'nb'] = (int) $obj->nb;
4390 $this->stats_facturefournrec[
'rows'] = (int) $obj->nb_rows;
4391 $this->stats_facturefournrec[
'qty'] = $obj->qty ? (float) $obj->qty : 0.0;
4393 $parameters = array(
'socid' => $socid);
4394 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoiceRec', $parameters, $this, $action);
4396 $this->stats_facturefournrec = $hookmanager->resArray[
'stats_facturefournrec'];
4401 $this->error = $this->db->error();
4420 $resql = $this->db->query($sql);
4422 $num = $this->db->num_rows($resql);
4425 $arr = $this->db->fetch_array($resql);
4426 if (is_array($arr)) {
4427 $keyfortab = (string) $arr[1];
4429 $keyfortab = substr($keyfortab, -2);
4432 if ($mode ==
'byunit') {
4433 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[0];
4434 } elseif ($mode ==
'bynumber') {
4435 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4436 } elseif ($mode ==
'byamount') {
4437 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4446 $this->error = $this->db->error().
' sql='.$sql;
4453 } elseif ($year == -1) {
4462 for ($j = 0; $j < 12; $j++) {
4464 $idx = ucfirst(
dol_trunc(
dol_print_date(
dol_mktime(12, 0, 0, $month, 1, 1970),
"%b"), 1,
'right',
'UTF-8', 1));
4467 $result[$j] = array($idx, isset($tab[$year.$month]) ? $tab[$year.$month] : 0);
4470 $month =
"0".($month - 1);
4472 $month = substr($month, 1);
4482 return array_reverse($result);
4497 public function get_nb_vente($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4502 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4503 if ($mode ==
'bynumber') {
4504 $sql .=
", count(DISTINCT f.rowid)";
4506 $sql .=
", sum(d.total_ht) as total_ht";
4507 $sql .=
" FROM ".$this->db->prefix().
"facturedet as d, ".$this->db->prefix().
"facture as f, ".$this->db->prefix().
"societe as s";
4508 if ($filteronproducttype >= 0) {
4509 $sql .=
", ".$this->db->prefix().
"product as p";
4511 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4512 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4514 $sql .=
" WHERE f.rowid = d.fk_facture";
4515 if ($this->
id > 0) {
4516 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4518 $sql .=
" AND d.fk_product > 0";
4520 if ($filteronproducttype >= 0) {
4521 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4523 $sql .=
" AND f.fk_soc = s.rowid";
4524 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4525 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4526 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4529 $sql .=
" AND f.fk_soc = $socid";
4531 $sql .= $morefilter;
4532 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4533 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4535 return $this->
_get_stats($sql, $mode, $year);
4550 public function get_nb_achat($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4555 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4556 if ($mode ==
'bynumber') {
4557 $sql .=
", count(DISTINCT f.rowid)";
4559 $sql .=
", sum(d.total_ht) as total_ht";
4560 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as d, ".$this->db->prefix().
"facture_fourn as f, ".$this->db->prefix().
"societe as s";
4561 if ($filteronproducttype >= 0) {
4562 $sql .=
", ".$this->db->prefix().
"product as p";
4564 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4565 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4567 $sql .=
" WHERE f.rowid = d.fk_facture_fourn";
4568 if ($this->
id > 0) {
4569 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4571 $sql .=
" AND d.fk_product > 0";
4573 if ($filteronproducttype >= 0) {
4574 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4576 $sql .=
" AND f.fk_soc = s.rowid";
4577 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4578 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4579 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4582 $sql .=
" AND f.fk_soc = $socid";
4584 $sql .= $morefilter;
4585 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4586 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4588 return $this->
_get_stats($sql, $mode, $year);
4602 public function get_nb_propal($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4607 $sql =
"SELECT sum(d.qty) as qty, date_format(p.datep, '%Y%m')";
4608 if ($mode ==
'bynumber') {
4609 $sql .=
", count(DISTINCT p.rowid)";
4611 $sql .=
", sum(d.total_ht) as total_ht";
4612 $sql .=
" FROM ".$this->db->prefix().
"propaldet as d, ".$this->db->prefix().
"propal as p, ".$this->db->prefix().
"societe as s";
4613 if ($filteronproducttype >= 0) {
4614 $sql .=
", ".$this->db->prefix().
"product as prod";
4616 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4617 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4619 $sql .=
" WHERE p.rowid = d.fk_propal";
4620 if ($this->
id > 0) {
4621 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4623 $sql .=
" AND d.fk_product > 0";
4625 if ($filteronproducttype >= 0) {
4626 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4628 $sql .=
" AND p.fk_soc = s.rowid";
4629 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
4630 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4631 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4634 $sql .=
" AND p.fk_soc = ".((int) $socid);
4636 $sql .= $morefilter;
4637 $sql .=
" GROUP BY date_format(p.datep,'%Y%m')";
4638 $sql .=
" ORDER BY date_format(p.datep,'%Y%m') DESC";
4640 return $this->
_get_stats($sql, $mode, $year);
4659 $sql =
"SELECT sum(d.qty) as qty, date_format(p.date_valid, '%Y%m')";
4660 if ($mode ==
'bynumber') {
4661 $sql .=
", count(DISTINCT p.rowid)";
4663 $sql .=
", sum(d.total_ht) as total_ht";
4664 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as d, ".$this->db->prefix().
"supplier_proposal as p, ".$this->db->prefix().
"societe as s";
4665 if ($filteronproducttype >= 0) {
4666 $sql .=
", ".$this->db->prefix().
"product as prod";
4668 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4669 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4671 $sql .=
" WHERE p.rowid = d.fk_supplier_proposal";
4672 if ($this->
id > 0) {
4673 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4675 $sql .=
" AND d.fk_product > 0";
4677 if ($filteronproducttype >= 0) {
4678 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4680 $sql .=
" AND p.fk_soc = s.rowid";
4681 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
4682 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4683 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4686 $sql .=
" AND p.fk_soc = ".((int) $socid);
4688 $sql .= $morefilter;
4689 $sql .=
" GROUP BY date_format(p.date_valid,'%Y%m')";
4690 $sql .=
" ORDER BY date_format(p.date_valid,'%Y%m') DESC";
4692 return $this->
_get_stats($sql, $mode, $year);
4706 public function get_nb_order($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4711 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4712 if ($mode ==
'bynumber') {
4713 $sql .=
", count(DISTINCT c.rowid)";
4715 $sql .=
", sum(d.total_ht) as total_ht";
4716 $sql .=
" FROM ".$this->db->prefix().
"commandedet as d, ".$this->db->prefix().
"commande as c, ".$this->db->prefix().
"societe as s";
4717 if ($filteronproducttype >= 0) {
4718 $sql .=
", ".$this->db->prefix().
"product as p";
4720 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4721 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4723 $sql .=
" WHERE c.rowid = d.fk_commande";
4724 if ($this->
id > 0) {
4725 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4727 $sql .=
" AND d.fk_product > 0";
4729 if ($filteronproducttype >= 0) {
4730 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4732 $sql .=
" AND c.fk_soc = s.rowid";
4733 $sql .=
" AND c.entity IN (".getEntity(
'commande').
")";
4734 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4735 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4738 $sql .=
" AND c.fk_soc = ".((int) $socid);
4740 $sql .= $morefilter;
4741 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4742 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4744 return $this->
_get_stats($sql, $mode, $year);
4763 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4764 if ($mode ==
'bynumber') {
4765 $sql .=
", count(DISTINCT c.rowid)";
4767 $sql .=
", sum(d.total_ht) as total_ht";
4768 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as d, ".$this->db->prefix().
"commande_fournisseur as c, ".$this->db->prefix().
"societe as s";
4769 if ($filteronproducttype >= 0) {
4770 $sql .=
", ".$this->db->prefix().
"product as p";
4772 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4773 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4775 $sql .=
" WHERE c.rowid = d.fk_commande";
4776 if ($this->
id > 0) {
4777 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4779 $sql .=
" AND d.fk_product > 0";
4781 if ($filteronproducttype >= 0) {
4782 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4784 $sql .=
" AND c.fk_soc = s.rowid";
4785 $sql .=
" AND c.entity IN (".getEntity(
'supplier_order').
")";
4786 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4787 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4790 $sql .=
" AND c.fk_soc = ".((int) $socid);
4792 $sql .= $morefilter;
4793 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4794 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4796 return $this->
_get_stats($sql, $mode, $year);
4810 public function get_nb_contract($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4815 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_contrat, '%Y%m')";
4816 if ($mode ==
'bynumber') {
4817 $sql .=
", count(DISTINCT c.rowid)";
4819 $sql .=
", sum(d.total_ht) as total_ht";
4820 $sql .=
" FROM ".$this->db->prefix().
"contratdet as d, ".$this->db->prefix().
"contrat as c, ".$this->db->prefix().
"societe as s";
4821 if ($filteronproducttype >= 0) {
4822 $sql .=
", ".$this->db->prefix().
"product as p";
4824 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4825 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4827 $sql .=
" WHERE c.entity IN (".getEntity(
'contract').
")";
4828 $sql .=
" AND c.rowid = d.fk_contrat";
4830 if ($this->
id > 0) {
4831 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4833 $sql .=
" AND d.fk_product > 0";
4835 if ($filteronproducttype >= 0) {
4836 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4838 $sql .=
" AND c.fk_soc = s.rowid";
4840 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4841 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4844 $sql .=
" AND c.fk_soc = ".((int) $socid);
4846 $sql .= $morefilter;
4847 $sql .=
" GROUP BY date_format(c.date_contrat,'%Y%m')";
4848 $sql .=
" ORDER BY date_format(c.date_contrat,'%Y%m') DESC";
4850 return $this->
_get_stats($sql, $mode, $year);
4864 public function get_nb_mos($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4869 $sql =
"SELECT sum(d.qty), date_format(d.date_valid, '%Y%m')";
4870 if ($mode ==
'bynumber') {
4871 $sql .=
", count(DISTINCT d.rowid)";
4873 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as d LEFT JOIN ".$this->db->prefix().
"societe as s ON d.fk_soc = s.rowid";
4874 if ($filteronproducttype >= 0) {
4875 $sql .=
", ".$this->db->prefix().
"product as p";
4877 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4878 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4881 $sql .=
" WHERE d.entity IN (".getEntity(
'mo').
")";
4882 $sql .=
" AND d.status > 0";
4884 if ($this->
id > 0) {
4885 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4887 $sql .=
" AND d.fk_product > 0";
4889 if ($filteronproducttype >= 0) {
4890 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4893 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4894 $sql .=
" AND d.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4897 $sql .=
" AND d.fk_soc = ".((int) $socid);
4899 $sql .= $morefilter;
4900 $sql .=
" GROUP BY date_format(d.date_valid,'%Y%m')";
4901 $sql .=
" ORDER BY date_format(d.date_valid,'%Y%m') DESC";
4903 return $this->
_get_stats($sql, $mode, $year);
4923 if (!is_numeric($id_pere)) {
4926 if (!is_numeric($id_fils)) {
4929 if (!is_numeric($incdec)) {
4939 $sql =
"SELECT fk_product_pere from ".$this->db->prefix().
"product_association";
4940 $sql .=
" WHERE fk_product_pere = ".((int) $id_fils).
" AND fk_product_fils = ".((int) $id_pere);
4941 if (!$this->db->query($sql)) {
4946 $sql =
"SELECT MAX(rang) as max_rank FROM ".$this->db->prefix().
"product_association";
4947 $sql .=
" WHERE fk_product_pere = ".((int) $id_pere);
4948 $resql = $this->db->query($sql);
4950 $obj = $this->db->fetch_object($resql);
4951 $rank = $obj->max_rank + 1;
4953 $sql =
"INSERT INTO ".$this->db->prefix().
"product_association(fk_product_pere,fk_product_fils,qty,incdec,rang)";
4954 $sql .=
" VALUES (".((int) $id_pere).
", ".((int) $id_fils).
", ".
price2num($qty,
'MS').
", ".((int) $incdec).
", ".((int) $rank).
")";
4955 if (! $this->db->query($sql)) {
4961 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_ADD', $user);
4963 $this->error = $this->db->lasterror();
4964 dol_syslog(get_class($this).
'::addSubproduct error='.$this->error, LOG_ERR);
4996 if (!is_numeric($id_pere)) {
4999 if (!is_numeric($id_fils)) {
5002 if (!is_numeric($incdec)) {
5005 if (!is_numeric($qty)) {
5009 $sql =
'UPDATE '.$this->db->prefix().
'product_association SET ';
5010 $sql .=
'qty = '.price2num($qty,
'MS');
5011 $sql .=
',incdec = '.((int) $incdec);
5012 $sql .=
' WHERE fk_product_pere = '.((int) $id_pere).
' AND fk_product_fils = '.((int) $id_fils);
5014 if (!$this->db->query($sql)) {
5020 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_UPDATE', $user);
5022 $this->error = $this->db->lasterror();
5023 dol_syslog(get_class($this).
'::updateSubproduct error='.$this->error, LOG_ERR);
5047 if (!is_numeric($fk_parent)) {
5050 if (!is_numeric($fk_child)) {
5054 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
5055 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5056 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
5058 dol_syslog(get_class($this).
'::del_sousproduit', LOG_DEBUG);
5059 if (!$this->db->query($sql)) {
5065 $sqlrank =
"SELECT rowid, rang FROM ".$this->db->prefix().
"product_association";
5066 $sqlrank .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5067 $sqlrank .=
" ORDER BY rang";
5068 $resqlrank = $this->db->query($sqlrank);
5071 while ($objrank = $this->db->fetch_object($resqlrank)) {
5073 $sql =
"UPDATE ".$this->db->prefix().
"product_association";
5074 $sql .=
" SET rang = ".((int) $cpt);
5075 $sql .=
" WHERE rowid = ".((int) $objrank->rowid);
5076 if (! $this->db->query($sql)) {
5085 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_DELETE', $user);
5087 $this->error = $this->db->lasterror();
5088 dol_syslog(get_class($this).
'::delSubproduct error='.$this->error, LOG_ERR);
5108 $sql =
"SELECT fk_product_pere, qty, incdec";
5109 $sql .=
" FROM ".$this->db->prefix().
"product_association";
5110 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
5111 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
5113 $result = $this->db->query($sql);
5115 $num = $this->db->num_rows($result);
5118 $obj = $this->db->fetch_object($result);
5120 $this->is_sousproduit_qty = $obj->qty;
5121 $this->is_sousproduit_incdec = $obj->incdec;
5152 dol_syslog(get_class($this).
"::add_fournisseur id_fourn = ".$id_fourn.
" ref_fourn=".$ref_fourn.
" quantity=".$quantity, LOG_DEBUG);
5159 $sql =
"SELECT rowid, fk_product";
5160 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5161 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5162 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5163 $sql .=
" AND fk_product <> ".((int) $this->
id);
5164 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5166 $resql = $this->db->query($sql);
5168 $obj = $this->db->fetch_object($resql);
5171 $this->product_id_already_linked = $obj->fk_product;
5174 $this->db->free($resql);
5178 $sql =
"SELECT rowid";
5179 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5180 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
5182 $sql .=
" AND ref_fourn = '".$this->db->escape($ref_fourn).
"'";
5184 $sql .=
" AND (ref_fourn = '' OR ref_fourn IS NULL)";
5186 $sql .=
" AND quantity = ".((float) $quantity);
5187 $sql .=
" AND fk_product = ".((int) $this->
id);
5188 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
5190 $resql = $this->db->query($sql);
5192 $obj = $this->db->fetch_object($resql);
5196 $sql =
"INSERT INTO ".$this->db->prefix().
"product_fournisseur_price(";
5199 $sql .=
", fk_product";
5201 $sql .=
", ref_fourn";
5202 $sql .=
", quantity";
5203 $sql .=
", fk_user";
5205 $sql .=
") VALUES (";
5206 $sql .=
"'".$this->db->idate($now).
"'";
5207 $sql .=
", ".((int)
$conf->entity);
5208 $sql .=
", ".((int) $this->
id);
5209 $sql .=
", ".((int) $id_fourn);
5210 $sql .=
", '".$this->db->escape($ref_fourn).
"'";
5211 $sql .=
", ".((float) $quantity);
5212 $sql .=
", ".((int) $user->id);
5216 if ($this->db->query($sql)) {
5217 $this->product_fourn_price_id = $this->db->last_insert_id($this->db->prefix().
"product_fournisseur_price");
5220 $this->error = $this->db->lasterror();
5225 $this->product_fourn_price_id = $obj->rowid;
5229 $this->error = $this->db->lasterror();
5248 $sql =
"SELECT DISTINCT p.fk_soc";
5249 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as p";
5250 $sql .=
" WHERE p.fk_product = ".((int) $this->
id);
5251 $sql .=
" AND p.entity = ".((int)
$conf->entity);
5253 $result = $this->db->query($sql);
5255 $num = $this->db->num_rows($result);
5258 $obj = $this->db->fetch_object($result);
5259 $list[$i] = $obj->fk_soc;
5284 $sql =
"INSERT INTO ".$this->db->prefix().
"product_price (";
5286 $sql .=
", fk_product";
5287 $sql .=
", date_price";
5288 $sql .=
", price_level";
5290 $sql .=
", price_ttc";
5291 $sql .=
", price_min";
5292 $sql .=
", price_min_ttc";
5293 $sql .=
", price_base_type";
5294 $sql .=
", price_label";
5295 $sql .=
", default_vat_code";
5297 $sql .=
", recuperableonly";
5298 $sql .=
", localtax1_tx";
5299 $sql .=
", localtax1_type";
5300 $sql .=
", localtax2_tx";
5301 $sql .=
", localtax2_type";
5302 $sql .=
", fk_user_author";
5304 $sql .=
", price_by_qty";
5305 $sql .=
", fk_price_expression";
5306 $sql .=
", fk_multicurrency";
5307 $sql .=
", multicurrency_code";
5308 $sql .=
", multicurrency_tx";
5309 $sql .=
", multicurrency_price";
5310 $sql .=
", multicurrency_price_ttc";
5314 $sql .=
", ".((int) $toId);
5315 $sql .=
", '".$this->db->idate($now).
"'";
5316 $sql .=
", price_level";
5318 $sql .=
", price_ttc";
5319 $sql .=
", price_min";
5320 $sql .=
", price_min_ttc";
5321 $sql .=
", price_base_type";
5322 $sql .=
", price_label";
5323 $sql .=
", default_vat_code";
5325 $sql .=
", recuperableonly";
5326 $sql .=
", localtax1_tx";
5327 $sql .=
", localtax1_type";
5328 $sql .=
", localtax2_tx";
5329 $sql .=
", localtax2_type";
5330 $sql .=
", ".((int) $user->id);
5332 $sql .=
", price_by_qty";
5333 $sql .=
", fk_price_expression";
5334 $sql .=
", fk_multicurrency";
5335 $sql .=
", multicurrency_code";
5336 $sql .=
", multicurrency_tx";
5337 $sql .=
", multicurrency_price";
5338 $sql .=
", multicurrency_price_ttc";
5339 $sql .=
" FROM ".$this->db->prefix().
"product_price ps";
5340 $sql .=
" WHERE fk_product = ".((int) $fromId);
5341 $sql .=
" AND date_price IN (SELECT MAX(pd.date_price) FROM ".$this->db->prefix().
"product_price pd WHERE pd.fk_product = ".((int) $fromId).
" AND pd.price_level = ps.price_level)";
5342 $sql .=
" ORDER BY date_price DESC";
5345 $resql = $this->db->query($sql);
5347 $this->db->rollback();
5351 $this->db->commit();
5368 $sql =
'INSERT INTO '.$this->db->prefix().
'product_association (fk_product_pere, fk_product_fils, qty, incdec)';
5369 $sql .=
" SELECT ".((int) $toId).
", fk_product_fils, qty, incdec FROM ".$this->db->prefix().
"product_association";
5370 $sql .=
" WHERE fk_product_pere = ".((int) $fromId);
5372 dol_syslog(get_class($this).
'::clone_association', LOG_DEBUG);
5373 if (!$this->db->query($sql)) {
5374 $this->db->rollback();
5378 $this->db->commit();
5411 $sql =
"INSERT ".$this->db->prefix().
"product_fournisseur_price (";
5412 $sql .=
" datec, fk_product, fk_soc, price, quantity, fk_user, tva_tx)";
5413 $sql .=
" SELECT '".$this->db->idate($now).
"', ".((int) $toId).
", fk_soc, price, quantity, fk_user, tva_tx";
5414 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5415 $sql .=
" WHERE fk_product = ".((int) $fromId);
5417 dol_syslog(get_class($this).
'::clone_fournisseurs', LOG_DEBUG);
5418 $resql = $this->db->query($sql);
5420 $this->db->rollback();
5423 $this->db->commit();
5441 public function fetch_prod_arbo($prod, $compl_path =
'', $multiply = 1, $level = 1, $id_parent = 0, $ignore_stock_load = 0)
5446 if ($multiply < 1) {
5447 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);
5452 foreach ($prod as $id_product => $desc_pere) {
5453 if (is_array($desc_pere)) {
5454 $id = (!empty($desc_pere[0]) ? $desc_pere[0] :
'');
5455 $nb = (!empty($desc_pere[1]) ? $desc_pere[1] :
'');
5456 $type = (!empty($desc_pere[2]) ? $desc_pere[2] :
'');
5457 $label = (!empty($desc_pere[3]) ? $desc_pere[3] :
'');
5458 $incdec = (!empty($desc_pere[4]) ? $desc_pere[4] : 0);
5461 if (is_null($tmpproduct)) {
5462 $tmpproduct =
new Product($this->db);
5464 $tmpproduct->fetch($id);
5466 if (empty($ignore_stock_load) && ($tmpproduct->isProduct() ||
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES'))) {
5467 $tmpproduct->load_stock(
'nobatch,novirtual');
5470 $this->res[] = array(
5472 'id_parent' => $id_parent,
5473 'ref' => $tmpproduct->ref,
5475 'nb_total' => $nb * $multiply,
5476 'stock' => $tmpproduct->stock_reel,
5477 'stock_alert' => $tmpproduct->seuil_stock_alerte,
5479 'fullpath' => $compl_path.$label,
5481 'desiredstock' => $tmpproduct->desiredstock,
5483 'incdec' => $incdec,
5484 'entity' => $tmpproduct->entity
5488 if (isset($desc_pere[
'childs']) && is_array($desc_pere[
'childs'])) {
5489 if (!is_int($desc_pere[1] * $multiply)) {
5490 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);
5494 $this->
fetch_prod_arbo($desc_pere[
'childs'], $compl_path.$desc_pere[3].
" -> ", (
int) ceil($desc_pere[1] * $multiply), $level + 1, $id, $ignore_stock_load);
5512 $this->res = array();
5513 if (isset($this->sousprods) && is_array($this->sousprods)) {
5514 foreach ($this->sousprods as $prod_name => $desc_product) {
5515 if (is_array($desc_product)) {
5516 $this->
fetch_prod_arbo($desc_product,
"", $multiply, 1, $this->
id, $ignore_stock_load);
5535 $sql =
"SELECT COUNT(pa.rowid) as nb";
5536 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa";
5538 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id).
" OR pa.fk_product_pere = ".((int) $this->
id);
5539 } elseif ($mode == -1) {
5540 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id);
5541 } elseif ($mode == 1) {
5542 $sql .=
" WHERE pa.fk_product_pere = ".((int) $this->
id);
5545 $resql = $this->db->query($sql);
5547 $obj = $this->db->fetch_object($resql);
5566 $sql =
"SELECT count(rowid) as nb FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_parent = ".((int) $this->
id);
5567 $sql .=
" AND entity IN (".getEntity(
'product').
")";
5569 $resql = $this->db->query($sql);
5571 $obj = $this->db->fetch_object($resql);
5588 if (isModEnabled(
'variants')) {
5589 $sql =
"SELECT rowid FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_child = ".((int) $this->
id).
" AND entity IN (".
getEntity(
'product').
")";
5591 $query = $this->db->query($sql);
5594 if (!$this->db->num_rows($query)) {
5615 $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";
5616 $sql .=
", p.tosell as status, p.tobuy as status_buy";
5617 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa,";
5618 $sql .=
" ".$this->db->prefix().
"product as p";
5619 $sql .=
" WHERE p.rowid = pa.fk_product_pere";
5620 $sql .=
" AND pa.fk_product_fils = ".((int) $this->
id);
5622 $res = $this->db->query($sql);
5625 while ($record = $this->db->fetch_array($res)) {
5627 $prods[$record[
'id']] = array();
5628 $prods[$record[
'id']][
'id'] = $record[
'rowid'];
5629 $prods[$record[
'id']][
'ref'] = $record[
'ref'];
5630 $prods[$record[
'id']][
'label'] = $record[
'label'];
5631 $prods[$record[
'id']][
'qty'] = $record[
'qty'];
5632 $prods[$record[
'id']][
'incdec'] = $record[
'incdec'];
5633 $prods[$record[
'id']][
'fk_product_type'] = $record[
'fk_product_type'];
5634 $prods[$record[
'id']][
'entity'] = $record[
'entity'];
5635 $prods[$record[
'id']][
'status'] = $record[
'status'];
5636 $prods[$record[
'id']][
'status_buy'] = $record[
'status_buy'];
5655 public function getChildsArbo($id, $firstlevelonly = 0, $level = 1, $parents = array())
5661 $sql =
"SELECT p.rowid, p.ref, p.label as label, p.fk_product_type,";
5662 $sql .=
" pa.qty as qty, pa.fk_product_fils as id, pa.incdec,";
5663 $sql .=
" pa.rowid as fk_association, pa.rang";
5664 $sql .=
" FROM ".$this->db->prefix().
"product as p,";
5665 $sql .=
" ".$this->db->prefix().
"product_association as pa";
5666 $sql .=
" WHERE p.rowid = pa.fk_product_fils";
5667 $sql .=
" AND pa.fk_product_pere = ".((int) $id);
5668 $sql .=
" AND pa.fk_product_fils <> ".((int) $id);
5669 $sql .=
" ORDER BY pa.rang";
5671 dol_syslog(get_class($this).
'::getChildsArbo id='.$id.
' level='.$level.
' parents='.(is_array($parents) ? implode(
',', $parents) : $parents), LOG_DEBUG);
5678 $res = $this->db->query($sql);
5681 if ($this->db->num_rows($res) > 0) {
5685 while ($rec = $this->db->fetch_array($res)) {
5686 if (in_array($rec[
'id'], $parents)) {
5687 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);
5691 $prods[$rec[
'rowid']] = array(
5694 2 => $rec[
'fk_product_type'],
5695 3 => $this->db->escape($rec[
'label']),
5696 4 => $rec[
'incdec'],
5698 6 => $rec[
'fk_association'],
5703 if (empty($firstlevelonly)) {
5704 $listofchilds = $this->
getChildsArbo($rec[
'rowid'], 0, $level + 1, $parents);
5705 foreach ($listofchilds as $keyChild => $valueChild) {
5706 $prods[$rec[
'rowid']][
'childs'][$keyChild] = $valueChild;
5730 foreach ($this->
getChildsArbo($this->
id) as $keyChild => $valueChild) {
5731 $parent[$this->label][$keyChild] = $valueChild;
5733 foreach ($parent as $key => $value) {
5734 $this->sousprods[$key] = $value;
5747 global
$conf, $langs, $user;
5749 $langs->loadLangs(array(
'products',
'other'));
5752 $nofetch = !empty($params[
'nofetch']);
5755 return [
'optimize' => $langs->trans(
"ShowProduct")];
5759 $permissiontoreadproduct = 0;
5760 if ($this->
type == self::TYPE_PRODUCT && $user->hasRight(
'product',
'read')) {
5761 $permissiontoreadproduct = 1;
5763 if ($this->
type == self::TYPE_SERVICE && $user->hasRight(
'service',
'read')) {
5764 $permissiontoreadproduct = 1;
5767 if (!empty($this->entity) && $permissiontoreadproduct) {
5768 $tmpphoto = $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 80, 0, 0, 0, 0,
'1');
5769 if ($this->nbphoto > 0) {
5770 $datas[
'photo'] =
'<div class="photointooltip floatright">'.
"\n" . $tmpphoto .
'</div>';
5775 $datas[
'picto'] =
img_picto(
'',
'product').
' <u class="paddingrightonly">'.$langs->trans(
"Product").
'</u>';
5777 $datas[
'picto'] =
img_picto(
'',
'service').
' <u class="paddingrightonly">'.$langs->trans(
"Service").
'</u>';
5779 if (isset($this->
status) && isset($this->status_buy)) {
5780 $datas[
'status'] =
' '.$this->getLibStatut(5, 0) .
' '.$this->getLibStatut(5, 1);
5783 if (!empty($this->
ref)) {
5784 $datas[
'ref'] =
'<br><b>'.$langs->trans(
'ProductRef').
':</b> '.$this->ref;
5786 if (!empty($this->label)) {
5787 $datas[
'label'] =
'<br><b>'.$langs->trans(
'ProductLabel').
':</b> '.$this->label;
5790 if ($permissiontoreadproduct) {
5795 if (isModEnabled(
'productbatch')) {
5796 $langs->load(
"productbatch");
5797 $datas[
'batchstatus'] =
"<br><b>".$langs->trans(
"ManageLotSerial").
'</b>: '.$this->
getLibStatut(0, 2);
5798 if ($this->status_batch) {
5799 $datas[
'batchdlc'] =
"<br><b>".$langs->trans(
"BatchSellOrEatByMandatoryList", $langs->transnoentitiesnoconv(
"SellByDate"), $langs->transnoentitiesnoconv(
"EatByDate")).
'</b>: '.$this->
getSellOrEatByMandatoryLabel();
5803 if (isModEnabled(
'barcode')) {
5804 $datas[
'barcode'] =
'<br><b>'.$langs->trans(
'BarCode').
':</b> '.$this->barcode;
5808 if ($this->weight) {
5809 $datas[
'weight'] =
"<br><b>".$langs->trans(
"Weight").
'</b>: '.$this->weight.
' '.
measuringUnitString(0,
"weight", $this->weight_units);
5812 if ($this->length) {
5813 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Length").
'</b>: '.$this->length.
' '.
measuringUnitString(0,
'size', $this->length_units);
5816 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Width").
'</b>: '.$this->width.
' '.
measuringUnitString(0,
'size', $this->width_units);
5818 if ($this->height) {
5819 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Height").
'</b>: '.$this->height.
' '.
measuringUnitString(0,
'size', $this->height_units);
5822 $datas[
'size'] =
"<br>".$labelsize;
5825 $labelsurfacevolume =
"";
5826 if ($this->surface) {
5827 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Surface").
'</b>: '.$this->surface.
' '.
measuringUnitString(0,
'surface', $this->surface_units);
5829 if ($this->volume) {
5830 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Volume").
'</b>: '.$this->volume.
' '.
measuringUnitString(0,
'volume', $this->volume_units);
5832 if ($labelsurfacevolume) {
5833 $datas[
'surface'] =
"<br>" . $labelsurfacevolume;
5836 if ($this->
isService() && !empty($this->duration_value)) {
5838 $datas[
'duration'] =
'<br><b>'.$langs->trans(
"Duration").
':</b> '.$this->duration_value;
5839 if ($this->duration_value > 1) {
5840 $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"));
5841 } elseif ($this->duration_value > 0) {
5842 $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"));
5844 $datas[
'duration'] .= (!empty($this->duration_unit) && isset($dur[$this->duration_unit]) ?
" ".$langs->trans($dur[$this->duration_unit]) :
'');
5846 if (empty($user->socid)) {
5847 if ($this->
isStockManaged() && !empty($this->pmp) && $this->pmp) {
5848 $datas[
'pmp'] =
"<br><b>".$langs->trans(
"PMPValue").
'</b>: '.
price($this->pmp, 0,
'', 1, -1, -1,
$conf->currency);
5851 if (isModEnabled(
'accounting')) {
5852 if ($this->
status && isset($this->accountancy_code_sell)) {
5853 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5854 $selllabel =
'<br>';
5855 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellCode').
':</b> '.
length_accountg($this->accountancy_code_sell);
5856 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellIntraCode').
':</b> '.
length_accountg($this->accountancy_code_sell_intra);
5857 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellExportCode').
':</b> '.
length_accountg($this->accountancy_code_sell_export);
5858 $datas[
'accountancysell'] = $selllabel;
5860 if ($this->status_buy && isset($this->accountancy_code_buy)) {
5861 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5863 if (empty($this->
status)) {
5864 $buylabel .=
'<br>';
5866 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyCode').
':</b> '.
length_accountg($this->accountancy_code_buy);
5867 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyIntraCode').
':</b> '.
length_accountg($this->accountancy_code_buy_intra);
5868 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyExportCode').
':</b> '.
length_accountg($this->accountancy_code_buy_export);
5869 $datas[
'accountancybuy'] = $buylabel;
5874 if (isModEnabled(
'category') && !$nofetch) {
5875 require_once DOL_DOCUMENT_ROOT .
'/categories/class/categorie.class.php';
5876 $form =
new Form($this->db);
5877 $datas[
'categories'] =
'<br>' . $form->showCategories($this->
id, Categorie::TYPE_PRODUCT, 1);
5897 public function getNomUrl($withpicto = 0, $option =
'', $maxlength = 0, $save_lastsearch_value = -1, $notooltip = 0, $morecss =
'', $add_label = 0, $sep =
' - ')
5899 global $langs, $hookmanager;
5901 include_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
5905 $newref = $this->ref;
5907 $newref =
dol_trunc($newref, $maxlength,
'middle');
5911 'objecttype' => ($this->
type == 1 ?
'service' :
'product'),
5912 'option' => $option,
5915 $classfortooltip =
'classfortooltip';
5918 $classfortooltip =
'classforajaxtooltip';
5919 $dataparams =
' data-params="'.dol_escape_htmltag(json_encode($params)).
'"';
5926 if (empty($notooltip)) {
5928 $label = $langs->trans(
"ShowProduct");
5929 $linkclose .=
' alt="'.dol_escape_htmltag($label, 1, 1).
'"';
5931 $linkclose .= ($label ?
' title="'.dol_escape_htmltag($label, 1, 1).
'"' :
' title="tocomplete"');
5932 $linkclose .= $dataparams.
' class="nowraponall '.$classfortooltip.($morecss ?
' '.$morecss :
'').
'"';
5934 $linkclose =
' class="nowraponall'.($morecss ?
' '.$morecss :
'').
'"';
5937 if ($option ==
'supplier' || $option ==
'category') {
5938 $url = DOL_URL_ROOT.
'/product/price_suppliers.php?id='.$this->id;
5939 } elseif ($option ==
'stock') {
5940 $url = DOL_URL_ROOT.
'/product/stock/product.php?id='.$this->id;
5941 } elseif ($option ==
'composition') {
5942 $url = DOL_URL_ROOT.
'/product/composition/card.php?id='.$this->id;
5944 $url = DOL_URL_ROOT.
'/product/card.php?id='.$this->id;
5947 if ($option !==
'nolink') {
5949 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
5950 if ($save_lastsearch_value == -1 && isset($_SERVER[
"PHP_SELF"]) && preg_match(
'/list\.php/', $_SERVER[
"PHP_SELF"])) {
5951 $add_save_lastsearch_values = 1;
5953 if ($add_save_lastsearch_values) {
5954 $url .=
'&save_lastsearch_values=1';
5958 $linkstart =
'<a href="'.$url.
'"';
5959 $linkstart .= $linkclose.
'>';
5962 $result .= $linkstart;
5965 $result .= (
img_object(($notooltip ?
'' : $label),
'product',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
5968 $result .= (
img_object(($notooltip ?
'' : $label),
'service',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
5971 $result .=
'<span class="aaa">'.dol_escape_htmltag($newref).
'</span>';
5972 $result .= $linkend;
5973 if ($withpicto != 2) {
5974 $result .= (($add_label && $this->label) ? $sep.dol_trunc($this->label, ($add_label > 1 ? $add_label : 0)) :
'');
5978 $hookmanager->initHooks(array(
'productdao'));
5979 $parameters = array(
'id' => $this->
id,
'getnomurl' => &$result,
'label' => &$label);
5980 $reshook = $hookmanager->executeHooks(
'getNomUrl', $parameters, $this, $action);
5982 $result = $hookmanager->resPrint;
5984 $result .= $hookmanager->resPrint;
6001 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
6005 $langs->load(
"products");
6006 $outputlangs->load(
"products");
6013 $modelpath =
"core/modules/product/doc/";
6015 return $this->
commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
6031 return $this->
LibStatut($this->status_buy, $mode, $type);
6033 return $this->
LibStatut($this->status_batch, $mode, $type);
6036 return $this->
LibStatut($this->status_buy, $mode, $type);
6054 $labelStatus = $labelStatusShort =
'';
6056 $langs->load(
'products');
6057 if (isModEnabled(
'productbatch')) {
6058 $langs->load(
"productbatch");
6064 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial')));
6067 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort')));
6072 return dolGetStatus($langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch'),
'',
'', empty($status) ?
'status5' :
'status4', 3,
'dot');
6078 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'));
6082 $statuttrans = empty($status) ?
'status5' :
'status4';
6087 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSellShort');
6088 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSell');
6089 } elseif ($type == 1) {
6090 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuyShort');
6091 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuy');
6092 } elseif ($type == 2) {
6093 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch');
6094 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort');
6096 } elseif ($status == 1) {
6099 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSellShort');
6100 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSell');
6101 } elseif ($type == 1) {
6102 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBuyShort');
6103 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBuy');
6104 } elseif ($type == 2) {
6105 $labelStatus = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial'));
6106 $labelStatusShort = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort'));
6108 } elseif ($type == 2 && $status == 2) {
6109 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSerial');
6110 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort');
6114 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'),
'',
'',
'status0', 0);
6116 return dolGetStatus($labelStatus, $labelStatusShort,
'', $statuttrans, $mode);
6130 $langs->load(
'products');
6133 if (isset($this->finished) && $this->finished >= 0) {
6134 $sql =
"SELECT label, code FROM ".$this->db->prefix().
"c_product_nature where code = ".((int) $this->finished).
" AND active=1";
6135 $resql = $this->db->query($sql);
6137 $this->error = $this->db->error().
' sql='.$sql;
6138 dol_syslog(__METHOD__.
' Error '.$this->error, LOG_ERR);
6140 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
6141 $label = $langs->trans($res[
'label']);
6143 $this->db->free($resql);
6167 public function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label =
'', $price = 0, $inventorycode =
'', $origin_element =
'', $origin_id =
null, $disablestockchangeforsubproduct = 0, $extrafields =
null)
6173 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6176 $nbpiece = (float) $nbpiece;
6181 $nbpiece = abs($nbpiece);
6188 $movementstock->setOrigin($origin_element, (
int) $origin_id);
6189 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'',
'',
'',
'',
false, 0, $disablestockchangeforsubproduct);
6193 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6194 $movementstock->array_options = $array_options;
6195 $movementstock->insertExtraFields();
6197 $this->db->commit();
6200 $this->error = $movementstock->error;
6201 $this->errors = $movementstock->errors;
6203 $this->db->rollback();
6232 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)
6238 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
6241 $nbpiece = (float) $nbpiece;
6246 $nbpiece = abs($nbpiece);
6254 $movementstock->setOrigin($origin_element, (
int) $origin_id);
6255 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'', $dlc, $dluo, $lot,
false, 0, $disablestockchangeforsubproduct, 0, $force_update_batch);
6259 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
6260 $movementstock->array_options = $array_options;
6261 $movementstock->insertExtraFields();
6263 $this->db->commit();
6266 $this->error = $movementstock->error;
6267 $this->errors = $movementstock->errors;
6269 $this->db->rollback();
6289 public function load_stock($option =
'', $includedraftpoforvirtual =
null, $dateofvirtualstock =
null)
6292 $this->stock_reel = 0;
6293 $this->stock_warehouse = array();
6294 $this->stock_theorique = 0;
6297 $warehouseStatus = array();
6298 if (preg_match(
'/warehouseclosed/', $option)) {
6301 if (preg_match(
'/warehouseopen/', $option)) {
6304 if (preg_match(
'/warehouseinternal/', $option)) {
6312 $sql =
"SELECT ps.rowid, ps.reel, ps.fk_entrepot";
6313 $sql .=
" FROM ".$this->db->prefix().
"product_stock as ps";
6314 $sql .=
", ".$this->db->prefix().
"entrepot as w";
6315 $sql .=
" WHERE w.entity IN (".getEntity(
'stock').
")";
6316 $sql .=
" AND w.rowid = ps.fk_entrepot";
6317 $sql .=
" AND ps.fk_product = ".((int) $this->
id);
6318 if (count($warehouseStatus)) {
6319 $sql .=
" AND w.statut IN (".$this->db->sanitize(implode(
',', $warehouseStatus)).
")";
6322 $sql .=
" ORDER BY ps.reel ".(getDolGlobalString(
'DO_NOT_TRY_TO_DEFRAGMENT_STOCKS_WAREHOUSE') ?
'DESC' :
'ASC');
6324 dol_syslog(get_class($this).
"::load_stock", LOG_DEBUG);
6325 $result = $this->db->query($sql);
6327 $num = $this->db->num_rows($result);
6331 $row = $this->db->fetch_object($result);
6332 $this->stock_warehouse[$row->fk_entrepot] =
new stdClass();
6333 $this->stock_warehouse[$row->fk_entrepot]->real = $row->reel;
6334 $this->stock_warehouse[$row->fk_entrepot]->id = $row->rowid;
6335 if ((!preg_match(
'/nobatch/', $option)) && $this->
hasbatch()) {
6336 $this->stock_warehouse[$row->fk_entrepot]->detail_batch =
Productbatch::findAll($this->db, $row->rowid, 1, $this->id);
6338 $this->stock_reel += $row->reel;
6341 $this->stock_reel = (float)
price2num($this->stock_reel,
'MS');
6343 $this->db->free($result);
6345 if (!preg_match(
'/novirtual/', $option)) {
6351 $this->error = $this->db->lasterror();
6370 global $hookmanager, $action;
6372 $stock_commande_client = 0;
6373 $stock_commande_fournisseur = 0;
6374 $stock_sending_client = 0;
6375 $stock_reception_fournisseur = 0;
6376 $stock_inproduction = 0;
6380 if (isModEnabled(
'order')) {
6385 $stock_commande_client = $this->stats_commande[
'qty'];
6387 if (isModEnabled(
"shipping")) {
6388 require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expedition.class.php';
6389 $filterShipmentStatus =
'';
6399 $stock_sending_client = $this->stats_expedition[
'qty'];
6402 if (isModEnabled(
"supplier_order")) {
6403 $filterStatus =
getDolGlobalString(
'SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK',
'3,4');
6404 if (isset($includedraftpoforvirtual)) {
6405 $filterStatus =
'0,1,2,'.$filterStatus;
6411 $stock_commande_fournisseur = $this->stats_commande_fournisseur[
'qty'];
6414 if (isModEnabled(
"supplier_order") || isModEnabled(
"supplier_invoice")) {
6415 $filterStatus =
'4';
6416 if (isset($includedraftpoforvirtual)) {
6417 $filterStatus =
'0,'.$filterStatus;
6423 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
6426 if (isModEnabled(
'mrp')) {
6431 $stock_inproduction = $this->stats_mrptoproduce[
'qty'] - $this->stats_mrptoconsume[
'qty'];
6434 $this->stock_theorique = $this->stock_reel + $stock_inproduction;
6438 $weBillOrderOrShipmentReception =
getDolGlobalString(
'STOCK_DO_WE_BILL_ORDER_OR_SHIPMENTECEPTION_FOR_VIRTUALSTOCK',
'order');
6442 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6446 $result = $tmpnewprod->load_stats_commande(0,
'0', 1);
6447 $this->stock_theorique += $tmpnewprod->stats_commande[
'qty'];
6449 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6450 $this->stock_theorique -= $stock_commande_client;
6451 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6452 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6457 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6459 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6461 if (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER_INCLUDE_DRAFT')) {
6463 $result = $tmpnewprod->load_stats_commande_fournisseur(0,
'0', 1);
6464 $this->stock_theorique += $this->stats_commande_fournisseur[
'qty'];
6466 $this->stock_theorique -= $stock_reception_fournisseur;
6467 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'order') {
6468 $this->stock_theorique += $stock_commande_fournisseur;
6469 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
6470 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6473 $parameters = array(
'id' => $this->
id,
'includedraftpoforvirtual' => $includedraftpoforvirtual);
6475 $reshook = $hookmanager->executeHooks(
'loadvirtualstock', $parameters, $this, $action);
6477 $this->stock_theorique = $hookmanager->resArray[
'stock_theorique'];
6478 } elseif ($reshook == 0 && isset($hookmanager->resArray[
'stock_stats_hook'])) {
6479 $this->stock_theorique += $hookmanager->resArray[
'stock_stats_hook'];
6483 if (!empty($this->stock_warehouse) &&
getDolGlobalString(
'STOCK_ALLOW_VIRTUAL_STOCK_PER_WAREHOUSE')) {
6484 foreach ($this->stock_warehouse as $warehouseid => $stockwarehouse) {
6485 if (isModEnabled(
'mrp')) {
6492 if ($this->fk_default_warehouse == $warehouseid) {
6493 $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']);
6495 $this->stock_warehouse[$warehouseid]->virtual = $this->stock_warehouse[$warehouseid]->real + $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'];
6512 $this->stock_warehouse = array();
6517 if (count($prods_arbo) > 0) {
6518 $productCachedList = array();
6519 $stockByComponentList = array();
6521 foreach ($prods_arbo as $componentArr) {
6522 $componentId = $componentArr[
'id'];
6524 if ($componentArr[
'incdec'] == 1) {
6525 if (!isset($productCachedList[$componentId])) {
6526 $componentStatic =
new self($this->db);
6527 $componentStatic->fetch($componentId);
6529 $childrenNb = $componentStatic->hasFatherOrChild(1);
6530 if ($childrenNb == 0) {
6531 $componentStatic->load_stock(
'nobatch,novirtual');
6532 if (!isset($stockByComponentList[$componentId])) {
6533 $stockByComponentList[$componentId] = array(
6537 $stockByComponentList[$componentId][
'qty_need'] += $componentArr[
'nb_total'];
6539 $productCachedList[$componentId] = $componentStatic;
6544 if (!empty($stockByComponentList)) {
6545 foreach ($stockByComponentList as $componentId => $stockByComponentArr) {
6546 if (!isset($productCachedList[$componentId])) {
6547 $componentStatic =
new self($this->db);
6548 $componentStatic->fetch($componentId);
6549 $componentStatic->load_stock(
'nobatch,novirtual');
6550 $productCachedList[$componentId] = $componentStatic;
6552 $component = $productCachedList[$componentId];
6555 if ($component->stock_reel < $stockByComponentArr[
'qty_need']) {
6558 $this->error =
'Not enough component [id='.$componentId.
'] in stock, real='.$component->stock_reel.
' and need='.$stockByComponentArr[
'qty_need'];
6559 $this->errors[] = $this->error;
6560 dol_syslog(__METHOD__.
' : '.$this->error, LOG_ERR);
6562 if (!empty($component->stock_warehouse)) {
6563 foreach ($component->stock_warehouse as $warehouseId => $warehouseObj) {
6564 $kitWarehouseAvailable =
new stdClass();
6565 $kitWarehouseAvailable->id = $warehouseObj->id;
6566 $kitWarehouseAvailable->real = $qtyWish;
6567 $this->stock_warehouse[$warehouseId] = $kitWarehouseAvailable;
6576 } elseif (
getDolGlobalInt(
'PRODUIT_SOUSPRODUITS_ALSO_ENABLE_PARENT_STOCK_MOVE') && empty($productCachedList)) {
6600 $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";
6601 $sql .=
" WHERE pb.fk_product_stock = ps.rowid AND ps.fk_product = ".((int) $this->
id).
" AND pb.batch = '".$this->db->escape($batch).
"'";
6602 $sql .=
" GROUP BY pb.batch, pb.eatby, pb.sellby";
6603 dol_syslog(get_class($this).
"::loadBatchInfo load first entry found for lot/serial = ".$batch, LOG_DEBUG);
6604 $resql = $this->db->query($sql);
6606 $num = $this->db->num_rows($resql);
6609 $obj = $this->db->fetch_object($resql);
6610 $result[] = array(
'batch' => $batch,
'eatby' => $this->db->jdate($obj->eatby),
'sellby' => $this->db->jdate($obj->sellby),
'qty' => $obj->qty);
6616 $this->db->rollback();
6633 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6639 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos";
6641 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product').dol_sanitizeFileName($this->
ref);
6646 $dir_osencoded = $dir;
6648 if (is_dir($dir_osencoded)) {
6649 $originImage = $dir.
'/'.$file[
'name'];
6660 if (is_numeric($result) && $result > 0) {
6677 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6678 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6682 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos/";
6684 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product');
6688 if (file_exists($dir_osencoded)) {
6689 $handle = opendir($dir_osencoded);
6690 if (is_resource($handle)) {
6691 while (($file = readdir($handle)) !==
false) {
6693 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6716 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6717 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6723 $handle = @opendir($dir_osencoded);
6724 if (is_resource($handle)) {
6725 while (($file = readdir($handle)) !==
false) {
6727 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6734 $photo_vignette =
'';
6736 if (preg_match(
'/('.$this->regeximgext.
')$/i', $photo, $regs)) {
6737 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $photo).
'_small'.$regs[0];
6740 $dirthumb = $dir.
'thumbs/';
6744 $obj[
'photo'] = $photo;
6745 if ($photo_vignette &&
dol_is_file($dirthumb.$photo_vignette)) {
6746 $obj[
'photo_vignette'] =
'thumbs/'.$photo_vignette;
6748 $obj[
'photo_vignette'] =
"";
6751 $tabobj[$nbphoto - 1] = $obj;
6754 if ($nbmax && $nbphoto >= $nbmax) {
6776 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6777 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6779 $dir = dirname($file).
'/';
6780 $dirthumb = $dir.
'/thumbs/';
6781 $filename = preg_replace(
'/'.preg_quote($dir,
'/').
'/i',
'', $file);
6787 if (preg_match(
'/('.$this->regeximgext.
')$/i', $filename, $regs)) {
6788 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_small'.$regs[0];
6789 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6793 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_mini'.$regs[0];
6794 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6811 $infoImg = getimagesize($file_osencoded);
6812 $this->imgWidth = $infoImg[0];
6813 $this->imgHeight = $infoImg[1];
6823 global $hookmanager;
6825 $this->nb = array();
6827 $sql =
"SELECT count(p.rowid) as nb, fk_product_type";
6828 $sql .=
" FROM ".$this->db->prefix().
"product as p";
6829 $sql .=
' WHERE p.entity IN ('.getEntity($this->element, 1).
')';
6831 if (is_object($hookmanager)) {
6832 $parameters = array();
6833 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
6834 $sql .= $hookmanager->resPrint;
6836 $sql .=
' GROUP BY fk_product_type';
6838 $resql = $this->db->query($sql);
6840 while ($obj = $this->db->fetch_object($resql)) {
6841 if ($obj->fk_product_type == 1) {
6842 $this->nb[
"services"] = $obj->nb;
6844 $this->nb[
"products"] = $obj->nb;
6847 $this->db->free($resql);
6851 $this->error = $this->db->error();
6893 return $this->mandatory_period == 1;
6903 return $this->status_batch > 0;
6923 $dirsociete = array_merge(array(
'/core/modules/barcode/'),
$conf->modules_parts[
'barcode']);
6924 foreach ($dirsociete as $dirroot) {
6932 '@phan-var-force ModeleNumRefBarCode $mod';
6934 $result = $mod->getNextValue(
$object, $type);
6936 dol_syslog(get_class($this).
"::get_barcode barcode=".$result.
" module=".$var);
6953 $this->specimen = 1;
6955 $this->
ref =
'PRODUCT_SPEC';
6956 $this->label =
'PRODUCT SPECIMEN';
6957 $this->
description =
'This is description of this product specimen that was created the '.dol_print_date($now,
'dayhourlog').
'.';
6958 $this->specimen = 1;
6959 $this->country_id = 1;
6961 $this->status_buy = 1;
6963 $this->sell_or_eat_by_mandatory = 0;
6964 $this->note_private =
'This is a comment (private)';
6965 $this->note_public =
'This is a comment (public)';
6966 $this->date_creation = $now;
6967 $this->date_modification = $now;
6970 $this->weight_units = 3;
6973 $this->length_units = 1;
6975 $this->width_units = 0;
6976 $this->height =
null;
6977 $this->height_units =
null;
6979 $this->surface = 30;
6980 $this->surface_units = 0;
6981 $this->volume = 300;
6982 $this->volume_units = 0;
6984 $this->barcode = -1;
7002 if (empty($this->fk_unit)) {
7005 if (empty($outputlangs)) {
7006 $outputlangs = $langs;
7009 $outputlangs->load(
'products');
7012 $sql =
"SELECT code, label, short_label FROM ".$this->db->prefix().
"c_units where rowid = ".((int) $this->fk_unit);
7014 $resql = $this->db->query($sql);
7016 $this->error = $this->db->error();
7017 dol_syslog(get_class($this).
"::getLabelOfUnit Error ".$this->error, LOG_ERR);
7019 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
7020 if ($type ==
'short') {
7022 $label = $outputlangs->transnoentitiesnoconv($res[
'short_label']);
7024 $label = $outputlangs->trans($res[
'short_label']);
7026 } elseif ($type ==
'code') {
7027 $label = $res[
'code'];
7029 if ($outputlangs->trans(
'unit'.$res[
'code']) ==
'unit'.$res[
'code']) {
7031 $label = $res[
'label'];
7035 $label = $outputlangs->transnoentitiesnoconv(
'unit'.$res[
'code']);
7037 $label = $outputlangs->trans(
'unit'.$res[
'code']);
7042 $this->db->free($resql);
7056 $maxpricesupplier = 0;
7059 include_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.product.class.php';
7061 $product_fourn_list = $product_fourn->list_product_fournisseur_price($this->
id,
'',
'');
7063 if (is_array($product_fourn_list) && count($product_fourn_list) > 0) {
7064 foreach ($product_fourn_list as $productfourn) {
7065 if ($productfourn->fourn_unitprice > $maxpricesupplier) {
7066 $maxpricesupplier = $productfourn->fourn_unitprice;
7074 return $maxpricesupplier;
7090 require_once DOL_DOCUMENT_ROOT.
'/categories/class/categorie.class.php';
7091 return parent::setCategoriesCommon($categories, Categorie::TYPE_PRODUCT);
7105 'product_customer_price',
7106 'product_customer_price_log'
7125 $sql =
"SELECT rowid, level, fk_level, var_percent, var_min_percent FROM ".$this->db->prefix().
"product_pricerules";
7126 $query = $this->db->query($sql);
7130 while ($result = $this->db->fetch_object($query)) {
7131 $rules[$result->level] = $result;
7140 for ($i = 1; $i <= $nbofproducts; $i++) {
7141 $price = $baseprice;
7142 $price_min = $baseprice;
7146 if ($i > 1 && isset($rules[$i]->var_percent) && $rules[$i]->var_percent) {
7147 $price = $prices[$rules[$i]->fk_level] * (1 + ($rules[$i]->var_percent / 100));
7150 $prices[$i] = $price;
7153 if (isset($rules[$i]->var_min_percent) && $rules[$i]->var_min_percent) {
7154 $price_min = $price * (1 - ($rules[$i]->var_min_percent / 100));
7158 $check_amount = (($price == $this->multiprices[$i]) && ($price_min == $this->multiprices_min[$i]));
7159 $check_type = ($baseprice == $this->multiprices_base_type[$i]);
7161 if ($check_amount && $check_type) {
7165 if ($this->
updatePrice($price, $price_type, $user, $price_vat, $price_min, $i, $npr, $psq, 1) < 0) {
7183 return $user->rights->produit;
7185 return $user->rights->service;
7197 $sql =
"SELECT p.rowid, p.ref, p.datec as date_creation, p.tms as date_modification,";
7198 $sql .=
" p.fk_user_author, p.fk_user_modif";
7199 $sql .=
" FROM ".$this->db->prefix().$this->table_element.
" as p";
7200 $sql .=
" WHERE p.rowid = ".((int) $id);
7202 $result = $this->db->query($sql);
7204 if ($this->db->num_rows($result)) {
7205 $obj = $this->db->fetch_object($result);
7207 $this->
id = $obj->rowid;
7208 $this->
ref = $obj->ref;
7210 $this->user_creation_id = $obj->fk_user_author;
7211 $this->user_modification_id = $obj->fk_user_modif;
7213 $this->date_creation = $this->db->jdate($obj->date_creation);
7214 $this->date_modification = $this->db->jdate($obj->date_modification);
7217 $this->db->free($result);
7231 if (empty($this->duration_value)) {
7232 $this->errors[] =
'ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
7235 if ($this->duration_unit ==
's') {
7236 $prodDurationHours = 1. / 3600;
7237 } elseif ($this->duration_unit ==
'i' || $this->duration_unit ==
'mn' || $this->duration_unit ==
'min') {
7238 $prodDurationHours = 1. / 60;
7239 } elseif ($this->duration_unit ==
'h') {
7240 $prodDurationHours = 1.;
7241 } elseif ($this->duration_unit ==
'd') {
7242 $prodDurationHours = 24.;
7243 } elseif ($this->duration_unit ==
'w') {
7244 $prodDurationHours = 24. * 7;
7245 } elseif ($this->duration_unit ==
'm') {
7246 $prodDurationHours = 24. * 30;
7247 } elseif ($this->duration_unit ==
'y') {
7248 $prodDurationHours = 24. * 365;
7252 $this->errors[] =
'ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
7255 $prodDurationHours *= $this->duration_value;
7257 return $prodDurationHours;
7270 global $langs,
$conf;
7272 $selected = (empty($arraydata[
'selected']) ? 0 : $arraydata[
'selected']);
7274 $return =
'<div class="box-flex-item box-flex-grow-zero">';
7275 $return .=
'<div class="info-box info-box-sm">';
7276 $return .=
'<div class="info-box-img">';
7279 $label .= $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 120, 160, 0, 0, 0,
'',
'photoref photokanban');
7289 $return .=
'</div>';
7290 $return .=
'<div class="info-box-content">';
7291 $return .=
'<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this,
'getNomUrl') ? $this->
getNomUrl() : $this->ref).
'</span>';
7292 if ($selected >= 0) {
7293 $return .=
'<input id="cb'.$this->id.
'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->
id.
'"'.($selected ?
' checked="checked"' :
'').
'>';
7295 if (property_exists($this,
'label')) {
7296 $return .=
'<br><span class="info-box-label opacitymedium inline-block tdoverflowmax150 valignmiddle" title="'.dol_escape_htmltag($this->label).
'">'.
dol_escape_htmltag($this->label).
'</span>';
7298 if (property_exists($this,
'price') && property_exists($this,
'price_ttc')) {
7299 if ($this->price_base_type ==
'TTC') {
7300 $return .=
'<br><span class="info-box-status amount">'.price($this->price_ttc).
' '.$langs->trans(
"TTC").
'</span>';
7303 $return .=
'<br><span class="info-box-status amount">'.price($this->
price).
' '.$langs->trans(
"HT").
'</span>';
7308 if (property_exists($this,
'stock_reel') && $this->
isProduct()) {
7309 $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>';
7312 if (method_exists($this,
'getLibStatut')) {
7314 $return .=
'<br><div class="info-box-status inline-block valignmiddle">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7316 $return .=
'<div class="info-box-status inline-block valignmiddle marginleftonly paddingleft">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
7319 $return .=
'</div>';
7320 $return .=
'</div>';
7321 $return .=
'</div>';
7334 if (!is_numeric($limit)) {
7338 $sql =
"SELECT p.rowid, p.ref, p.label, p.description, p.entity, ef.filename
7339 FROM ".MAIN_DB_PREFIX.
"product AS p
7340 JOIN ".MAIN_DB_PREFIX.
"ecm_files AS ef ON p.rowid = ef.src_object_id
7341 WHERE ef.entity IN (".
getEntity(
'product').
")
7342 AND (ef.filename LIKE '%.png' OR ef.filename LIKE '%.jpeg' OR ef.filename LIKE '%.svg')
7343 GROUP BY p.rowid, p.ref, p.label, p.description, p.entity, ef.filename
7344 ORDER BY p.datec ASC
7345 LIMIT " . ((int) $limit);
7347 $resql = $this->db->query($sql);
7348 $products = array();
7351 while ($obj = $this->db->fetch_object($resql)) {
7352 $products[] = array(
7353 'rowid' => $obj->rowid,
7355 'label' => $obj->label,
7356 'description' => $obj->description,
7357 'entity' => $obj->entity,
7358 'filename' => $obj->filename
7364 if (empty($products)) {
7377 public $picto =
'service';
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
length_accountg($account)
Return General accounting account with defined length (used for product and miscellaneous)
clean_account($account)
Return accounting account without zero on the right.
Parent class of all other business classes (invoices, contracts, proposals, orders,...
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
deleteEcmFiles($mode=0)
Delete related files of object in database.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
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.
call_trigger($triggerName, $user)
Call trigger based on this instance.
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.
check_barcode($valuetotest, $typefortest)
Check barcode.
list_suppliers()
Return list of suppliers providing the product or service.
load_stats_mo($socid=0)
Charge tableau des stats OF pour le produit/service.
isVariant()
Return if loaded product is a variant.
updatePrice($newprice, $newpricebase, $user, $newvat=null, $newminprice=0, $level=0, $newnpr=0, $newpbq=0, $ignore_autogen=0, $localtaxes_array=array(), $newdefaultvatcode='', $price_label='', $notrigger=0)
Modify customer price of a product/Service for a given level.
hasVariants()
Return if a product has variants or not.
delMultiLangs($langtodelete, $user)
Delete a language for this product.
load_stats_proposal_supplier($socid=0)
Charge tableau des stats propale pour le produit/service.
getLibFinished()
Retour label of nature of product.
add_sousproduit($id_pere, $id_fils, $qty, $incdec=1, $notrigger=0)
Link a product/service to a parent product/service.
add_fournisseur($user, $id_fourn, $ref_fourn, $quantity)
Add a supplier price for the product.
hasFatherOrChild($mode=0)
Count all parent and children products for current product (first level only)
load_stats_facturerec($socid=0)
Load array of statistics for recurring invoice for product/service.
get_nb_propalsupplier($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in proposals in which product is included.
load_stats_facturefournrec($socid=0)
Load array of statistics for recurring supplier invoice for product/service.
get_nb_contract($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
load_stats_facture_fournisseur($socid=0)
Load array of statistics for vendor invoice for product/service.
get_nb_ordersupplier($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
getMultiLangs()
Load array this->multilangs.
get_nb_mos($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
clone_associations($fromId, $toId)
Clone links between products.
create($user, $notrigger=0)
Insert product into database.
load_stats_contrat($socid=0)
Charge tableau des stats contrat pour le produit/service.
isService()
Return if the object is a service.
getRights()
Returns the rights used for this class.
loadBatchInfo($batch)
Load existing information about a serial.
load_stock($option='', $includedraftpoforvirtual=null, $dateofvirtualstock=null)
Load information about stock of a product into ->stock_reel, ->stock_warehouse[] (including stock_war...
getProductDurationHours()
Return the duration of a service in hours (for a service based on duration fields)
get_buyprice($prodfournprice, $qty, $product_id=0, $fourn_ref='', $fk_soc=0)
Read price used by a provider.
clone_fournisseurs($fromId, $toId)
Recopie les fournisseurs et prix fournisseurs d'un produit/service sur un autre.
const TYPE_PRODUCT
Regular product.
add_photo($sdir, $file)
Move an uploaded file described into $file array into target directory $sdir.
log_price_delete($user, $rowid)
Delete a price line.
info($id)
Load information for tab info.
correct_stock($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $inventorycode='', $origin_element='', $origin_id=null, $disablestockchangeforsubproduct=0, $extrafields=null)
Adjust stock in a warehouse for product.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
Create a document onto disk according to template module.
static getSellOrEatByMandatoryList()
Get the array of labels of Sell by or Eat by all mandatory flags for each status.
getChildsArbo($id, $firstlevelonly=0, $level=1, $parents=array())
Return children of product $id.
load_virtual_stock($includedraftpoforvirtual=null, $dateofvirtualstock=null)
Load value ->stock_theorique of a product.
load_stats_propale($socid=0)
Charge tableau des stats propale pour le produit/service.
get_barcode($object, $type='')
Get a barcode from the module to generate barcode values.
setAccountancyCode($type, $value)
Sets an accountancy code for a product.
getProductsToPreviewInEmail($limit)
Retrieve and display products.
load_stats_facture($socid=0)
Charge tableau des stats facture pour le produit/service.
setCategories($categories)
Sets object to supplied categories.
load_stats_reception($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null)
Charge tableau des stats réception fournisseur pour le produit/service.
get_nb_propal($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in proposals in which product is included.
update($id, $user, $notrigger=0, $action='update', $updatetype=false)
Update a record into database.
setMultiLangs($user)
Update or add a translation for a product.
correct_stock_batch($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $dlc='', $dluo='', $lot='', $inventorycode='', $origin_element='', $origin_id=null, $disablestockchangeforsubproduct=0, $extrafields=null, $force_update_batch=false)
Adjust stock in a warehouse for product with batch number.
load_stats_bom($socid=0)
Charge tableau des stats OF pour le produit/service.
hasbatch()
Return if the object has a batch management.
del_sousproduit($fk_parent, $fk_child, $notrigger=0)
Remove a link between a subproduct and a parent product/service.
fetch($id=0, $ref='', $ref_ext='', $barcode='', $ignore_expression=0, $ignore_price_load=0, $ignore_lang_load=0)
Load a product in memory from database.
update_sousproduit($id_pere, $id_fils, $qty, $incdec=1, $notrigger=0)
Modify composed product.
load_stats_commande($socid=0, $filtrestatut='', $forVirtualStock=0)
Charge tableau des stats commande client pour le produit/service.
delete_photo($file)
Delete a photo and its thumbs.
fetch_prod_arbo($prod, $compl_path='', $multiply=1, $level=1, $id_parent=0, $ignore_stock_load=0)
Function recursive, used only by get_arbo_each_prod(), to build tree of subproducts into ->res Define...
getKanbanView($option='', $arraydata=null)
Return clickable link of object (with eventually picto)
getLibStatut($mode=0, $type=0)
Return label of status of object.
load_stats_sending($socid=0, $filtrestatut='', $forVirtualStock=0, $filterShipmentStatus='')
Charge tableau des stats expedition client pour le produit/service.
clone_price($fromId, $toId)
Recopie les prix d'un produit/service sur un autre.
load_stats_inproduction($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null, $warehouseid=0)
Charge tableau des stats production pour le produit/service.
check()
Check that ref and label are ok.
initAsSpecimen()
Initialise an instance with random values.
liste_photos($dir, $nbmax=0)
Return an array with all photos of product found on disk.
loadStateBoard()
Load indicators this->nb for the dashboard.
getFather()
Return all parent products for current product (first level only)
getNomUrl($withpicto=0, $option='', $maxlength=0, $save_lastsearch_value=-1, $notooltip=0, $morecss='', $add_label=0, $sep=' - ')
Return clickable link of object (with eventually picto)
getSellOrEatByMandatoryLabel()
Get the label for sell by or eat by mandatory flag of the current product.
verify()
Check properties of product are ok (like name, barcode, ...).
get_nb_order($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
loadStockForVirtualProduct($option='', $qtyWish=1)
Load stock for components of virtual product (first level only)
min_recommended_price()
Return minimum product recommended price.
_log_price($user, $level=0)
Insert a track that we changed a customer price.
getLabelOfUnit($type='long', $outputlangs=null, $noentities=0)
Reads the units dictionary to return the translation code of a unit (if type='code'),...
_get_stats($sql, $mode, $year=0)
Return an array formatted for showing graphs.
load_stats_commande_fournisseur($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null)
Charge tableau des stats commande fournisseur pour le produit/service.
isMandatoryPeriod()
Return if the object has a constraint on mandatory_period.
isProduct()
Return if the object is a product.
generateMultiprices(User $user, $baseprice, $price_type, $price_vat, $npr, $psq)
Generates prices for a product based on product multiprice generation rules.
LibStatut($status, $mode=0, $type=0)
Return label of a given status.
const TYPE_SERVICE
Service.
is_photo_available($sdir)
Return if at least one photo is available.
get_image_size($file)
Load size of image file.
get_nb_vente($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units or customers invoices in which product is included.
getTooltipContentArray($params)
getTooltipContentArray
Class to manage products or services.
Manage record for batch number management.
static findAll($dbs, $fk_product_stock, $with_qty=0, $fk_product=0)
Return all batch detail records for a given product and warehouse.
Class with list of lots and properties.
Class to manage Dolibarr users.
hasRight($module, $permlevel1, $permlevel2='')
Return if a user has a permission.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0, $level=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
dol_is_file($pathoffile)
Return if path is a file.
dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $nohook=0, $keyforsourcefile='addedfile', $upload_dir='', $mode=0)
Check validity of a file upload from an GUI page, and move it to its final destination.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
dolGetFirstLineOfText($text, $nboflines=1, $charset='UTF-8')
Return first line of text.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='', $keepspaces=0)
Clean a string from all punctuation characters to use it as a ref or login.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
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)
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
dol_clone($object, $native=2)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0)
Clean a string to use it as a file name.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
utf8_check($str)
Check if a string is in UTF8.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_localtax($vatrate, $local, $thirdparty_buyer=null, $thirdparty_seller=null, $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate,...
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
measuring_units_squared($unitscale)
Transform a given unit scale into the square of that unit, if known.
measuringUnitString($unitid, $measuring_style='', $unitscale=null, $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
measuring_units_cubed($unit)
Transform a given unit scale into the cube of that unit, if known.
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type