38 require_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
39 require_once DOL_DOCUMENT_ROOT.
'/core/class/commonobject.class.php';
40 require_once DOL_DOCUMENT_ROOT.
'/product/class/productbatch.class.php';
41 require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/entrepot.class.php';
51 public $element =
'product';
56 public $table_element =
'product';
61 public $fk_element =
'fk_product';
66 protected $childtables = array(
67 'supplier_proposaldet' => array(
'name' =>
'SupplierProposal',
'parent' =>
'supplier_proposal',
'parentkey' =>
'fk_supplier_proposal'),
68 'propaldet' => array(
'name' =>
'Proposal',
'parent' =>
'propal',
'parentkey' =>
'fk_propal'),
69 'commandedet' => array(
'name' =>
'Order',
'parent' =>
'commande',
'parentkey' =>
'fk_commande'),
70 'facturedet' => array(
'name' =>
'Invoice',
'parent' =>
'facture',
'parentkey' =>
'fk_facture'),
71 'contratdet' => array(
'name' =>
'Contract',
'parent' =>
'contrat',
'parentkey' =>
'fk_contrat'),
72 'facture_fourn_det' => array(
'name' =>
'SupplierInvoice',
'parent' =>
'facture_fourn',
'parentkey' =>
'fk_facture_fourn'),
73 'commande_fournisseurdet' => array(
'name' =>
'SupplierOrder',
'parent' =>
'commande_fournisseur',
'parentkey' =>
'fk_commande')
81 public $ismultientitymanaged = 1;
86 public $picto =
'product';
93 public $regeximgext =
'\.gif|\.jpg|\.jpeg|\.png|\.bmp|\.webp|\.xpm|\.xbm';
155 public $price_min_ttc;
161 public $price_base_type;
165 public $multiprices_ttc = array();
166 public $multiprices_base_type = array();
167 public $multiprices_min = array();
168 public $multiprices_min_ttc = array();
169 public $multiprices_tva_tx = array();
170 public $multiprices_recuperableonly = array();
174 public $prices_by_qty = array();
175 public $prices_by_qty_id = array();
176 public $prices_by_qty_list = array();
192 public $localtax2_tx;
193 public $localtax1_type;
194 public $localtax2_type;
198 public $qc_frequency;
205 public $stock_reel = 0;
212 public $stock_theorique;
229 public $seuil_stock_alerte = 0;
239 public $duration_value;
258 public $status_buy = 0;
272 public $fk_default_bom;
279 public $status_batch = 0;
286 public $batch_mask =
'';
304 public $weight_units;
306 public $length_units;
310 public $height_units;
312 public $surface_units;
314 public $volume_units;
317 public $net_measure_units;
319 public $accountancy_code_sell;
320 public $accountancy_code_sell_intra;
321 public $accountancy_code_sell_export;
322 public $accountancy_code_buy;
323 public $accountancy_code_buy_intra;
324 public $accountancy_code_buy_export;
338 public $barcode_type;
345 public $barcode_type_code;
347 public $stats_propale = array();
348 public $stats_commande = array();
349 public $stats_contrat = array();
350 public $stats_facture = array();
351 public $stats_commande_fournisseur = array();
352 public $stats_reception = array();
353 public $stats_mrptoconsume = array();
354 public $stats_mrptoproduce = array();
363 public $date_creation;
368 public $date_modification;
386 public $fk_default_warehouse;
390 public $fk_price_expression;
394 public $fourn_price_base_type;
406 public $ref_supplier;
420 public $price_autogen = 0;
427 public $supplierprices;
434 public $is_object_used;
442 public $mandatory_period;
472 public $fields = array(
473 'rowid' => array(
'type'=>
'integer',
'label'=>
'TechnicalID',
'enabled'=>1,
'visible'=>-2,
'notnull'=>1,
'index'=>1,
'position'=>1,
'comment'=>
'Id'),
474 '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'),
475 'entity' =>array(
'type'=>
'integer',
'label'=>
'Entity',
'enabled'=>1,
'visible'=>0,
'default'=>1,
'notnull'=>1,
'index'=>1,
'position'=>5),
476 'label' =>array(
'type'=>
'varchar(255)',
'label'=>
'Label',
'enabled'=>1,
'visible'=>1,
'notnull'=>1,
'showoncombobox'=>2,
'position'=>15),
477 'barcode' =>array(
'type'=>
'varchar(255)',
'label'=>
'Barcode',
'enabled'=>
'!empty($conf->barcode->enabled)',
'position'=>20,
'visible'=>-1,
'showoncombobox'=>3),
478 'fk_barcode_type' => array(
'type'=>
'integer',
'label'=>
'BarcodeType',
'enabled'=>
'1',
'position'=>21,
'notnull'=>0,
'visible'=>-1,),
479 'note_public' =>array(
'type'=>
'html',
'label'=>
'NotePublic',
'enabled'=>1,
'visible'=>0,
'position'=>61),
480 'note' =>array(
'type'=>
'html',
'label'=>
'NotePrivate',
'enabled'=>1,
'visible'=>0,
'position'=>62),
481 'datec' =>array(
'type'=>
'datetime',
'label'=>
'DateCreation',
'enabled'=>1,
'visible'=>-2,
'notnull'=>1,
'position'=>500),
482 'tms' =>array(
'type'=>
'timestamp',
'label'=>
'DateModification',
'enabled'=>1,
'visible'=>-2,
'notnull'=>1,
'position'=>501),
484 'fk_user_author'=>array(
'type'=>
'integer',
'label'=>
'UserAuthor',
'enabled'=>1,
'visible'=>-2,
'notnull'=>1,
'position'=>510,
'foreignkey'=>
'llx_user.rowid'),
485 'fk_user_modif' =>array(
'type'=>
'integer',
'label'=>
'UserModif',
'enabled'=>1,
'visible'=>-2,
'notnull'=>-1,
'position'=>511),
487 'localtax1_tx' => array(
'type'=>
'double(6,3)',
'label'=>
'Localtax1tx',
'enabled'=>
'1',
'position'=>150,
'notnull'=>0,
'visible'=>-1,),
488 'localtax1_type' => array(
'type'=>
'varchar(10)',
'label'=>
'Localtax1type',
'enabled'=>
'1',
'position'=>155,
'notnull'=>1,
'visible'=>-1,),
489 'localtax2_tx' => array(
'type'=>
'double(6,3)',
'label'=>
'Localtax2tx',
'enabled'=>
'1',
'position'=>160,
'notnull'=>0,
'visible'=>-1,),
490 'localtax2_type' => array(
'type'=>
'varchar(10)',
'label'=>
'Localtax2type',
'enabled'=>
'1',
'position'=>165,
'notnull'=>1,
'visible'=>-1,),
491 'import_key' =>array(
'type'=>
'varchar(14)',
'label'=>
'ImportId',
'enabled'=>1,
'visible'=>-2,
'notnull'=>-1,
'index'=>0,
'position'=>1000),
494 'mandatory_period' => array(
'type'=>
'integer',
'label'=>
'mandatory_period',
'enabled'=>1,
'visible'=>1,
'notnull'=>1,
'default'=>0,
'index'=>1,
'position'=>1000),
558 public function create($user, $notrigger = 0)
560 global $conf, $langs;
566 $this->label = trim($this->label);
567 $this->price_ttc =
price2num($this->price_ttc);
569 $this->price_min_ttc =
price2num($this->price_min_ttc);
570 $this->price_min =
price2num($this->price_min);
571 if (empty($this->tva_tx)) {
574 if (empty($this->tva_npr)) {
578 if (empty($this->localtax1_tx)) {
579 $this->localtax1_tx = 0;
581 if (empty($this->localtax2_tx)) {
582 $this->localtax2_tx = 0;
584 if (empty($this->localtax1_type)) {
585 $this->localtax1_type =
'0';
587 if (empty($this->localtax2_type)) {
588 $this->localtax2_type =
'0';
590 if (empty($this->
price)) {
593 if (empty($this->price_min)) {
594 $this->price_min = 0;
597 if (empty($this->price_by_qty)) {
598 $this->price_by_qty = 0;
601 if (empty($this->status)) {
604 if (empty($this->status_buy)) {
605 $this->status_buy = 0;
614 if ($this->price_base_type ==
'TTC' && $this->price_ttc > 0) {
615 $price_ttc =
price2num($this->price_ttc,
'MU');
616 $price_ht =
price2num($this->price_ttc / (1 + ($this->tva_tx / 100)),
'MU');
620 if ($this->price_base_type !=
'TTC' && $this->
price > 0) {
622 $price_ttc =
price2num($this->
price * (1 + ($this->tva_tx / 100)),
'MU');
626 if (($this->price_min_ttc > 0) && ($this->price_base_type ==
'TTC')) {
627 $price_min_ttc =
price2num($this->price_min_ttc,
'MU');
628 $price_min_ht =
price2num($this->price_min_ttc / (1 + ($this->tva_tx / 100)),
'MU');
632 if (($this->price_min > 0) && ($this->price_base_type !=
'TTC')) {
633 $price_min_ht =
price2num($this->price_min,
'MU');
634 $price_min_ttc =
price2num($this->price_min * (1 + ($this->tva_tx / 100)),
'MU');
637 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
638 $this->accountancy_code_buy_intra = trim($this->accountancy_code_buy_intra);
639 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
640 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
641 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
642 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
645 $this->barcode = trim($this->barcode);
646 $this->mandatory_period = empty($this->mandatory_period) ? 0 : $this->mandatory_period;
648 if (empty($this->label)) {
649 $this->error =
'ErrorMandatoryParametersNotProvided';
653 if (empty($this->
ref) || $this->
ref ==
'auto') {
655 $module = (!empty($conf->global->PRODUCT_CODEPRODUCT_ADDON) ? $conf->global->PRODUCT_CODEPRODUCT_ADDON :
'mod_codeproduct_leopard');
656 if ($module !=
'mod_codeproduct_leopard') {
657 if (substr($module, 0, 16) ==
'mod_codeproduct_' && substr($module, -3) ==
'php') {
658 $module = substr($module, 0,
dol_strlen($module) - 4);
661 $modCodeProduct =
new $module;
662 if (!empty($modCodeProduct->code_auto)) {
663 $this->
ref = $modCodeProduct->getNextValue($this, $this->
type);
665 unset($modCodeProduct);
668 if (empty($this->
ref)) {
669 $this->error =
'ProductModuleNotSetupForAutoRef';
674 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);
681 if ($this->barcode == -1) {
682 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
687 $result = $this->
verify();
690 $sql =
"SELECT count(*) as nb";
691 $sql .=
" FROM ".$this->db->prefix().
"product";
692 $sql .=
" WHERE entity IN (".getEntity(
'product').
")";
693 $sql .=
" AND ref = '".$this->db->escape($this->
ref).
"'";
695 $result = $this->
db->query($sql);
697 $obj = $this->
db->fetch_object($result);
700 $sql =
"INSERT INTO ".$this->db->prefix().
"product (";
705 $sql .=
", price_min";
706 $sql .=
", price_min_ttc";
708 $sql .=
", fk_user_author";
709 $sql .=
", fk_product_type";
711 $sql .=
", price_ttc";
712 $sql .=
", price_base_type";
715 if (empty($conf->global->MAIN_PRODUCT_PERENTITY_SHARED)) {
716 $sql .=
", accountancy_code_buy";
717 $sql .=
", accountancy_code_buy_intra";
718 $sql .=
", accountancy_code_buy_export";
719 $sql .=
", accountancy_code_sell";
720 $sql .=
", accountancy_code_sell_intra";
721 $sql .=
", accountancy_code_sell_export";
724 $sql .=
", finished";
726 $sql .=
", batch_mask";
728 $sql .=
", mandatory_period";
729 $sql .=
") VALUES (";
730 $sql .=
"'".$this->db->idate($now).
"'";
731 $sql .=
", ".((int) $conf->entity);
732 $sql .=
", '".$this->db->escape($this->
ref).
"'";
733 $sql .=
", ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
734 $sql .=
", ".price2num($price_min_ht);
735 $sql .=
", ".price2num($price_min_ttc);
736 $sql .=
", ".(!empty($this->label) ?
"'".$this->db->escape($this->label).
"'" :
"null");
737 $sql .=
", ".((int) $user->id);
738 $sql .=
", ".((int) $this->
type);
739 $sql .=
", ".price2num($price_ht,
'MT');
740 $sql .=
", ".price2num($price_ttc,
'MT');
741 $sql .=
", '".$this->db->escape($this->price_base_type).
"'";
742 $sql .=
", ".((int) $this->status);
743 $sql .=
", ".((int) $this->status_buy);
744 if (empty($conf->global->MAIN_PRODUCT_PERENTITY_SHARED)) {
745 $sql .=
", '".$this->db->escape($this->accountancy_code_buy).
"'";
746 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_intra).
"'";
747 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_export).
"'";
748 $sql .=
", '".$this->db->escape($this->accountancy_code_sell).
"'";
749 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_intra).
"'";
750 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_export).
"'";
752 $sql .=
", '".$this->db->escape($this->canvas).
"'";
753 $sql .=
", ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
'NULL' : (
int) $this->finished);
754 $sql .=
", ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : ((
int) $this->status_batch));
755 $sql .=
", '".$this->db->escape($this->batch_mask).
"'";
756 $sql .=
", ".($this->fk_unit > 0 ? ((int) $this->fk_unit) :
'NULL');
757 $sql .=
", '".$this->db->escape($this->mandatory_period).
"'";
760 dol_syslog(get_class($this).
"::Create", LOG_DEBUG);
761 $result = $this->
db->query($sql);
763 $id = $this->
db->last_insert_id($this->
db->prefix().
"product");
767 $this->
price = $price_ht;
768 $this->price_ttc = $price_ttc;
769 $this->price_min = $price_min_ht;
770 $this->price_min_ttc = $price_min_ttc;
774 if ($this->
update($id, $user,
true,
'add') <= 0) {
779 $this->error = $this->
db->lasterror();
783 if (!$error && !empty($conf->global->MAIN_PRODUCT_PERENTITY_SHARED)) {
784 $this->
db->query(
"DELETE FROM " . $this->
db->prefix() .
"product_perentity WHERE fk_product = " .((int) $this->id) .
" AND entity = " . ((
int) $conf->entity));
786 $sql =
"INSERT INTO " . $this->
db->prefix() .
"product_perentity (";
787 $sql .=
" fk_product";
789 $sql .=
", accountancy_code_buy";
790 $sql .=
", accountancy_code_buy_intra";
791 $sql .=
", accountancy_code_buy_export";
792 $sql .=
", accountancy_code_sell";
793 $sql .=
", accountancy_code_sell_intra";
794 $sql .=
", accountancy_code_sell_export";
795 $sql .=
") VALUES (";
797 $sql .=
", " . $conf->entity;
798 $sql .=
", '" . $this->
db->escape($this->accountancy_code_buy) .
"'";
799 $sql .=
", '" . $this->
db->escape($this->accountancy_code_buy_intra) .
"'";
800 $sql .=
", '" . $this->
db->escape($this->accountancy_code_buy_export) .
"'";
801 $sql .=
", '" . $this->
db->escape($this->accountancy_code_sell) .
"'";
802 $sql .=
", '" . $this->
db->escape($this->accountancy_code_sell_intra) .
"'";
803 $sql .=
", '" . $this->
db->escape($this->accountancy_code_sell_export) .
"'";
805 $result = $this->
db->query($sql);
808 $this->error =
'ErrorFailedToInsertAccountancyForEntity';
813 $this->error =
'ErrorFailedToGetInsertedId';
817 $this->error = $this->
db->lasterror();
821 $langs->load(
"products");
823 $this->error =
"ErrorProductAlreadyExists";
827 $this->error = $this->
db->lasterror();
830 if (!$error && !$notrigger) {
843 $this->
db->rollback();
847 $this->
db->rollback();
848 dol_syslog(get_class($this).
"::Create fails verify ".join(
',', $this->errors), LOG_WARNING);
864 $this->errors = array();
867 $this->
ref = trim($this->
ref);
870 $this->errors[] =
'ErrorBadRef';
874 $arrayofnonnegativevalue = array(
'weight'=>
'Weight',
'width'=>
'Width',
'height'=>
'Height',
'length'=>
'Length',
'surface'=>
'Surface',
'volume'=>
'Volume');
875 foreach ($arrayofnonnegativevalue as $key => $value) {
876 if (property_exists($this, $key) && !empty($this->$key) && ($this->$key < 0)) {
877 $langs->loadLangs(array(
"main",
"other"));
878 $this->error = $langs->trans(
"FieldCannotBeNegative", $langs->transnoentitiesnoconv($value));
879 $this->errors[] = $this->error;
884 $rescode = $this->
check_barcode($this->barcode, $this->barcode_type_code);
886 if ($rescode == -1) {
887 $this->errors[] =
'ErrorBadBarCodeSyntax';
888 } elseif ($rescode == -2) {
889 $this->errors[] =
'ErrorBarCodeRequired';
890 } elseif ($rescode == -3) {
892 $this->errors[] =
'ErrorBarCodeAlreadyUsed';
916 if (!empty($conf->barcode->enabled) && !empty($conf->global->BARCODE_PRODUCT_ADDON_NUM)) {
917 $module = strtolower($conf->global->BARCODE_PRODUCT_ADDON_NUM);
919 $dirsociete = array_merge(array(
'/core/modules/barcode/'), $conf->modules_parts[
'barcode']);
920 foreach ($dirsociete as $dirroot) {
927 $mod =
new $module();
929 dol_syslog(get_class($this).
"::check_barcode value=".$valuetotest.
" type=".$typefortest.
" module=".$module);
930 $result = $mod->verif($this->
db, $valuetotest, $this, 0, $typefortest);
948 public function update($id, $user, $notrigger =
false, $action =
'update', $updatetype =
false)
950 global $langs, $conf, $hookmanager;
956 $this->label =
'MISSING LABEL';
961 $this->label = trim($this->label);
963 $this->note = (isset($this->note) ? trim($this->note) :
null);
964 $this->net_measure =
price2num($this->net_measure);
965 $this->net_measure_units = trim($this->net_measure_units);
966 $this->weight =
price2num($this->weight);
967 $this->weight_units = trim($this->weight_units);
968 $this->length =
price2num($this->length);
969 $this->length_units = trim($this->length_units);
971 $this->width_units = trim($this->width_units);
972 $this->height =
price2num($this->height);
973 $this->height_units = trim($this->height_units);
974 $this->surface =
price2num($this->surface);
975 $this->surface_units = trim($this->surface_units);
976 $this->volume =
price2num($this->volume);
977 $this->volume_units = trim($this->volume_units);
980 if (is_numeric($this->length_units)) {
981 $this->width_units = $this->length_units;
983 if (is_numeric($this->length_units)) {
984 $this->height_units = $this->length_units;
988 if (empty($this->surface) && !empty($this->length) && !empty($this->width) && $this->length_units == $this->width_units) {
989 $this->surface = $this->length * $this->width;
992 if (empty($this->volume) && !empty($this->surface) && !empty($this->height) && $this->length_units == $this->height_units) {
993 $this->volume = $this->surface * $this->height;
997 if (empty($this->tva_tx)) {
1000 if (empty($this->tva_npr)) {
1003 if (empty($this->localtax1_tx)) {
1004 $this->localtax1_tx = 0;
1006 if (empty($this->localtax2_tx)) {
1007 $this->localtax2_tx = 0;
1009 if (empty($this->localtax1_type)) {
1010 $this->localtax1_type =
'0';
1012 if (empty($this->localtax2_type)) {
1013 $this->localtax2_type =
'0';
1015 if (empty($this->status)) {
1018 if (empty($this->status_buy)) {
1019 $this->status_buy = 0;
1022 if (empty($this->country_id)) {
1023 $this->country_id = 0;
1026 if (empty($this->state_id)) {
1027 $this->state_id = 0;
1031 $this->barcode = trim($this->barcode);
1033 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
1034 $this->accountancy_code_buy_intra = trim($this->accountancy_code_buy_intra);
1035 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
1036 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
1037 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
1038 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
1045 if ($action !=
'add') {
1046 $result = $this->
verify();
1053 if (empty($this->oldcopy)) {
1054 $org =
new self($this->db);
1055 $org->fetch($this->
id);
1056 $this->oldcopy = $org;
1061 if ($this->
hasbatch() && !$this->oldcopy->hasbatch()) {
1063 $valueforundefinedlot =
'000000';
1064 if (!empty($conf->global->STOCK_DEFAULT_BATCH)) {
1065 $valueforundefinedlot = $conf->global->STOCK_DEFAULT_BATCH;
1068 dol_syslog(
"Flag batch of product id=".$this->
id.
" is set to ON, so we will create missing records into product_batch");
1071 foreach ($this->stock_warehouse as $idW => $ObjW) {
1073 foreach ($ObjW->detail_batch as $detail) {
1074 if ($detail->batch == $valueforundefinedlot || $detail->batch ==
'Undefined') {
1076 $sqlclean =
"DELETE FROM ".$this->db->prefix().
"product_batch WHERE batch in('Undefined', '".$this->
db->escape($valueforundefinedlot).
"') AND fk_product_stock = ".((int) $ObjW->id);
1077 $result = $this->
db->query($sqlclean);
1085 $qty_batch += $detail->qty;
1089 if ($ObjW->real <> $qty_batch) {
1091 $ObjBatch->batch = $valueforundefinedlot;
1092 $ObjBatch->qty = ($ObjW->real - $qty_batch);
1093 $ObjBatch->fk_product_stock = $ObjW->id;
1095 if ($ObjBatch->create($user, 1) < 0) {
1097 $this->errors = $ObjBatch->errors;
1104 if ($this->barcode == -1) {
1105 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1108 $sql =
"UPDATE ".$this->db->prefix().
"product";
1109 $sql .=
" SET label = '".$this->db->escape($this->label).
"'";
1112 $sql .=
", fk_product_type = ".((int) $this->
type);
1115 $sql .=
", ref = '".$this->db->escape($this->
ref).
"'";
1116 $sql .=
", ref_ext = ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1117 $sql .=
", default_vat_code = ".($this->default_vat_code ?
"'".$this->db->escape($this->default_vat_code).
"'" :
"null");
1118 $sql .=
", tva_tx = ".((float) $this->tva_tx);
1119 $sql .=
", recuperableonly = ".((int) $this->tva_npr);
1120 $sql .=
", localtax1_tx = ".((float) $this->localtax1_tx);
1121 $sql .=
", localtax2_tx = ".((float) $this->localtax2_tx);
1122 $sql .=
", localtax1_type = ".($this->localtax1_type !=
'' ?
"'".$this->db->escape($this->localtax1_type).
"'" :
"'0'");
1123 $sql .=
", localtax2_type = ".($this->localtax2_type !=
'' ?
"'".$this->db->escape($this->localtax2_type).
"'" :
"'0'");
1125 $sql .=
", barcode = ".(empty($this->barcode) ?
"null" :
"'".$this->db->escape($this->barcode).
"'");
1126 $sql .=
", fk_barcode_type = ".(empty($this->barcode_type) ?
"null" : $this->
db->escape($this->barcode_type));
1128 $sql .=
", tosell = ".(int) $this->status;
1129 $sql .=
", tobuy = ".(int) $this->status_buy;
1130 $sql .=
", tobatch = ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : (
int) $this->status_batch);
1131 $sql .=
", batch_mask = '".$this->db->escape($this->batch_mask).
"'";
1133 $sql .=
", finished = ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
"null" : (
int) $this->finished);
1134 $sql .=
", fk_default_bom = ".((!isset($this->fk_default_bom) || $this->fk_default_bom < 0 || $this->fk_default_bom ==
'') ?
"null" : (
int) $this->fk_default_bom);
1135 $sql .=
", net_measure = ".($this->net_measure !=
'' ?
"'".$this->db->escape($this->net_measure).
"'" :
'null');
1136 $sql .=
", net_measure_units = ".($this->net_measure_units !=
'' ?
"'".$this->db->escape($this->net_measure_units).
"'" :
'null');
1137 $sql .=
", weight = ".($this->weight !=
'' ?
"'".$this->db->escape($this->weight).
"'" :
'null');
1138 $sql .=
", weight_units = ".($this->weight_units !=
'' ?
"'".$this->db->escape($this->weight_units).
"'" :
'null');
1139 $sql .=
", length = ".($this->length !=
'' ?
"'".$this->db->escape($this->length).
"'" :
'null');
1140 $sql .=
", length_units = ".($this->length_units !=
'' ?
"'".$this->db->escape($this->length_units).
"'" :
'null');
1141 $sql .=
", width= ".($this->width !=
'' ?
"'".$this->db->escape($this->width).
"'" :
'null');
1142 $sql .=
", width_units = ".($this->width_units !=
'' ?
"'".$this->db->escape($this->width_units).
"'" :
'null');
1143 $sql .=
", height = ".($this->height !=
'' ?
"'".$this->db->escape($this->height).
"'" :
'null');
1144 $sql .=
", height_units = ".($this->height_units !=
'' ?
"'".$this->db->escape($this->height_units).
"'" :
'null');
1145 $sql .=
", surface = ".($this->surface !=
'' ?
"'".$this->db->escape($this->surface).
"'" :
'null');
1146 $sql .=
", surface_units = ".($this->surface_units !=
'' ?
"'".$this->db->escape($this->surface_units).
"'" :
'null');
1147 $sql .=
", volume = ".($this->volume !=
'' ?
"'".$this->db->escape($this->volume).
"'" :
'null');
1148 $sql .=
", volume_units = ".($this->volume_units !=
'' ?
"'".$this->db->escape($this->volume_units).
"'" :
'null');
1149 $sql .=
", fk_default_warehouse = ".($this->fk_default_warehouse > 0 ? $this->
db->escape($this->fk_default_warehouse) :
'null');
1150 $sql .=
", seuil_stock_alerte = ".((isset($this->seuil_stock_alerte) && is_numeric($this->seuil_stock_alerte)) ? (
float) $this->seuil_stock_alerte :
'null');
1151 $sql .=
", description = '".$this->db->escape($this->
description).
"'";
1152 $sql .=
", url = ".($this->url ?
"'".$this->db->escape($this->url).
"'" :
'null');
1153 $sql .=
", customcode = '".$this->db->escape($this->customcode).
"'";
1154 $sql .=
", fk_country = ".($this->country_id > 0 ? (int) $this->country_id :
'null');
1155 $sql .=
", fk_state = ".($this->state_id > 0 ? (int) $this->state_id :
'null');
1156 $sql .=
", lifetime = ".($this->lifetime > 0 ? (int) $this->lifetime :
'null');
1157 $sql .=
", qc_frequency = ".($this->qc_frequency > 0 ? (int) $this->qc_frequency :
'null');
1158 $sql .=
", note = ".(isset($this->note) ?
"'".$this->db->escape($this->note).
"'" :
'null');
1159 $sql .=
", duration = '".$this->db->escape($this->duration_value.$this->duration_unit).
"'";
1160 if (empty($conf->global->MAIN_PRODUCT_PERENTITY_SHARED)) {
1161 $sql .=
", accountancy_code_buy = '" . $this->
db->escape($this->accountancy_code_buy) .
"'";
1162 $sql .=
", accountancy_code_buy_intra = '" . $this->
db->escape($this->accountancy_code_buy_intra) .
"'";
1163 $sql .=
", accountancy_code_buy_export = '" . $this->
db->escape($this->accountancy_code_buy_export) .
"'";
1164 $sql .=
", accountancy_code_sell= '" . $this->
db->escape($this->accountancy_code_sell) .
"'";
1165 $sql .=
", accountancy_code_sell_intra= '" . $this->
db->escape($this->accountancy_code_sell_intra) .
"'";
1166 $sql .=
", accountancy_code_sell_export= '" . $this->
db->escape($this->accountancy_code_sell_export) .
"'";
1168 $sql .=
", desiredstock = ".((isset($this->desiredstock) && is_numeric($this->desiredstock)) ? (
float) $this->desiredstock :
"null");
1169 $sql .=
", cost_price = ".($this->cost_price !=
'' ? $this->
db->escape($this->cost_price) :
'null');
1170 $sql .=
", fk_unit= ".(!$this->fk_unit ?
'NULL' : (int) $this->fk_unit);
1171 $sql .=
", price_autogen = ".(!$this->price_autogen ? 0 : 1);
1172 $sql .=
", fk_price_expression = ".($this->fk_price_expression != 0 ? (int) $this->fk_price_expression :
'NULL');
1173 $sql .=
", fk_user_modif = ".($user->id > 0 ? $user->id :
'NULL');
1174 $sql .=
", mandatory_period = ".($this->mandatory_period );
1176 $sql .=
" WHERE rowid = ".((int) $id);
1178 dol_syslog(get_class($this).
"::update", LOG_DEBUG);
1185 if (!empty($conf->global->MAIN_MULTILANGS)) {
1187 $this->error = $langs->trans(
"Error").
" : ".$this->
db->error().
" - ".$sql;
1195 if (!$error && !empty($conf->global->MAIN_PRODUCT_PERENTITY_SHARED)) {
1196 $this->
db->query(
"DELETE FROM " . $this->
db->prefix() .
"product_perentity WHERE fk_product = " . ((
int) $this->id) .
" AND entity = " . ((
int) $conf->entity));
1198 $sql =
"INSERT INTO " . $this->
db->prefix() .
"product_perentity (";
1199 $sql .=
" fk_product";
1201 $sql .=
", accountancy_code_buy";
1202 $sql .=
", accountancy_code_buy_intra";
1203 $sql .=
", accountancy_code_buy_export";
1204 $sql .=
", accountancy_code_sell";
1205 $sql .=
", accountancy_code_sell_intra";
1206 $sql .=
", accountancy_code_sell_export";
1207 $sql .=
") VALUES (";
1209 $sql .=
", " . $conf->entity;
1210 $sql .=
", '" . $this->
db->escape($this->accountancy_code_buy) .
"'";
1211 $sql .=
", '" . $this->
db->escape($this->accountancy_code_buy_intra) .
"'";
1212 $sql .=
", '" . $this->
db->escape($this->accountancy_code_buy_export) .
"'";
1213 $sql .=
", '" . $this->
db->escape($this->accountancy_code_sell) .
"'";
1214 $sql .=
", '" . $this->
db->escape($this->accountancy_code_sell_intra) .
"'";
1215 $sql .=
", '" . $this->
db->escape($this->accountancy_code_sell_export) .
"'";
1217 $result = $this->
db->query($sql);
1220 $this->error =
'ErrorFailedToUpdateAccountancyForEntity';
1232 if (!$error && !$notrigger) {
1234 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
1241 if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) {
1243 if ($conf->product->dir_output) {
1246 if (file_exists($olddir)) {
1250 $res = @rename($olddir, $newdir);
1252 $langs->load(
"errors");
1253 $this->error = $langs->trans(
'ErrorFailToRenameDir', $olddir, $newdir);
1261 if (!empty($conf->variants->enabled)) {
1262 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1266 foreach ($comb->fetchAllByFkProductParent($this->id) as $currcomb) {
1267 $currcomb->updateProperties($this, $user);
1271 $this->
db->commit();
1274 $this->
db->rollback();
1278 if ($this->
db->errno() ==
'DB_ERROR_RECORD_ALREADY_EXISTS') {
1279 $langs->load(
"errors");
1280 if (empty($conf->barcode->enabled) || empty($this->barcode)) {
1281 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductAlreadyExists", $this->
ref);
1283 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductBarCodeAlreadyExists", $this->barcode);
1285 $this->errors[] = $this->error;
1286 $this->
db->rollback();
1289 $this->error = $langs->trans(
"Error").
" : ".$this->
db->error().
" - ".$sql;
1290 $this->errors[] = $this->error;
1291 $this->
db->rollback();
1296 $this->
db->rollback();
1297 dol_syslog(get_class($this).
"::Update fails verify ".join(
',', $this->errors), LOG_WARNING);
1309 public function delete(
User $user, $notrigger = 0)
1311 global $conf, $langs;
1312 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
1317 if (empty($this->
id)) {
1318 $this->error =
"Object must be fetched before calling delete";
1322 $this->error =
"ErrorForbidden";
1327 if (empty($objectisused)) {
1330 if (!$error && empty($notrigger)) {
1332 $result = $this->
call_trigger(
'PRODUCT_DELETE', $user);
1341 $sql =
"DELETE FROM ".$this->db->prefix().
'product_batch';
1342 $sql .=
" WHERE fk_product_stock IN (";
1343 $sql .=
"SELECT rowid FROM ".$this->db->prefix().
'product_stock';
1344 $sql .=
" WHERE fk_product = ".((int) $this->
id).
")";
1346 $result = $this->
db->query($sql);
1349 $this->errors[] = $this->
db->lasterror();
1355 $elements = array(
'product_fournisseur_price',
'product_price',
'product_lang',
'categorie_product',
'product_stock',
'product_customer_price',
'product_lot');
1356 foreach ($elements as $table) {
1358 $sql =
"DELETE FROM ".$this->db->prefix().$table;
1359 $sql .=
" WHERE fk_product = ".(int) $this->
id;
1361 $result = $this->
db->query($sql);
1364 $this->errors[] = $this->
db->lasterror();
1371 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1372 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination2ValuePair.class.php';
1377 if ($prodcomb->deleteByFkProductParent($user, $this->id) < 0) {
1379 $this->errors[] =
'Error deleting combinations';
1383 if (!$error && ($prodcomb->fetchByFkProductChild($this->id) > 0) && ($prodcomb->delete($user) < 0)) {
1385 $this->errors[] =
'Error deleting child combination';
1391 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
1392 $sql .=
" WHERE fk_product_pere = ".(int) $this->
id.
" OR fk_product_fils = ".(
int) $this->id;
1394 $result = $this->
db->query($sql);
1397 $this->errors[] = $this->
db->lasterror();
1406 dol_syslog(get_class($this).
"::delete error -4 ".$this->error, LOG_ERR);
1412 $sqlz =
"DELETE FROM ".$this->db->prefix().
"product";
1413 $sqlz .=
" WHERE rowid = ".(int) $this->
id;
1415 $resultz = $this->
db->query($sqlz);
1418 $this->errors[] = $this->
db->lasterror();
1433 if ($conf->product->dir_output) {
1434 $dir = $conf->product->dir_output.
"/".$ref;
1435 if (file_exists($dir)) {
1438 $this->errors[] =
'ErrorFailToDeleteDir';
1446 $this->
db->commit();
1449 foreach ($this->errors as $errmsg) {
1450 dol_syslog(get_class($this).
"::delete ".$errmsg, LOG_ERR);
1451 $this->error .= ($this->error ?
', '.$errmsg : $errmsg);
1453 $this->
db->rollback();
1457 $this->error =
"ErrorRecordIsUsedCantDelete";
1470 global $conf, $langs;
1472 $langs_available = $langs->get_available_languages(DOL_DOCUMENT_ROOT, 0, 2);
1473 $current_lang = $langs->getDefaultLang();
1475 foreach ($langs_available as $key => $value) {
1476 if ($key == $current_lang) {
1477 $sql =
"SELECT rowid";
1478 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1479 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1480 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
1482 $result = $this->
db->query($sql);
1484 if ($this->
db->num_rows($result)) {
1485 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
1487 $sql2 .=
" label='".$this->db->escape($this->label).
"',";
1488 $sql2 .=
" description='".$this->db->escape($this->
description).
"'";
1489 if (!empty($conf->global->PRODUCT_USE_OTHER_FIELD_IN_TRANSLATION)) {
1490 $sql2 .=
", note='".$this->db->escape($this->other).
"'";
1492 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->
db->escape($key).
"'";
1494 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
1495 if (!empty($conf->global->PRODUCT_USE_OTHER_FIELD_IN_TRANSLATION)) {
1499 $sql2 .=
" VALUES(".$this->id.
",'".$this->
db->escape($key).
"','".$this->
db->escape($this->label).
"',";
1500 $sql2 .=
" '".$this->db->escape($this->
description).
"'";
1501 if (!empty($conf->global->PRODUCT_USE_OTHER_FIELD_IN_TRANSLATION)) {
1502 $sql2 .=
", '".$this->db->escape($this->other).
"'";
1506 dol_syslog(get_class($this).
'::setMultiLangs key = current_lang = '.$key);
1507 if (!$this->
db->query($sql2)) {
1508 $this->error = $this->
db->lasterror();
1511 } elseif (isset($this->multilangs[$key])) {
1512 if (empty($this->multilangs[
"$key"][
"label"])) {
1513 $this->error = $langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Label"));
1517 $sql =
"SELECT rowid";
1518 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1519 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1520 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
1522 $result = $this->
db->query($sql);
1524 if ($this->
db->num_rows($result)) {
1525 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
1527 $sql2 .=
" label = '".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
1528 $sql2 .=
" description = '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
1529 if (!empty($conf->global->PRODUCT_USE_OTHER_FIELD_IN_TRANSLATION)) {
1530 $sql2 .=
", note = '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
1532 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->
db->escape($key).
"'";
1534 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
1535 if (!empty($conf->global->PRODUCT_USE_OTHER_FIELD_IN_TRANSLATION)) {
1539 $sql2 .=
" VALUES(".$this->id.
",'".$this->
db->escape($key).
"','".$this->
db->escape($this->multilangs[
"$key"][
"label"]).
"',";
1540 $sql2 .=
" '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
1541 if (!empty($conf->global->PRODUCT_USE_OTHER_FIELD_IN_TRANSLATION)) {
1542 $sql2 .=
", '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
1548 if ($this->multilangs[
"$key"][
"label"] || $this->multilangs[
"$key"][
"description"]) {
1549 if (!$this->
db->query($sql2)) {
1550 $this->error = $this->
db->lasterror();
1560 $result = $this->
call_trigger(
'PRODUCT_SET_MULTILANGS', $user);
1562 $this->error = $this->
db->lasterror();
1580 $sql =
"DELETE FROM ".$this->db->prefix().
"product_lang";
1581 $sql .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->
db->escape($langtodelete).
"'";
1583 dol_syslog(get_class($this).
'::delMultiLangs', LOG_DEBUG);
1584 $result = $this->
db->query($sql);
1587 $result = $this->
call_trigger(
'PRODUCT_DEL_MULTILANGS', $user);
1589 $this->error = $this->
db->lasterror();
1590 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
1596 $this->error = $this->
db->lasterror();
1597 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
1612 global $user, $langs, $conf;
1618 if ($type ==
'buy') {
1619 $field =
'accountancy_code_buy';
1620 } elseif ($type ==
'buy_intra') {
1621 $field =
'accountancy_code_buy_intra';
1622 } elseif ($type ==
'buy_export') {
1623 $field =
'accountancy_code_buy_export';
1624 } elseif ($type ==
'sell') {
1625 $field =
'accountancy_code_sell';
1626 } elseif ($type ==
'sell_intra') {
1627 $field =
'accountancy_code_sell_intra';
1628 } elseif ($type ==
'sell_export') {
1629 $field =
'accountancy_code_sell_export';
1634 $sql =
"UPDATE ".$this->db->prefix().$this->table_element.
" SET ";
1635 $sql .=
"$field = '".$this->db->escape($value).
"'";
1636 $sql .=
" WHERE rowid = ".((int) $this->
id);
1643 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
1650 $this->
db->rollback();
1654 $this->$field = $value;
1656 $this->
db->commit();
1659 $this->error = $this->
db->lasterror();
1660 $this->
db->rollback();
1674 $current_lang = $langs->getDefaultLang();
1676 $sql =
"SELECT lang, label, description, note as other";
1677 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1678 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1680 $result = $this->
db->query($sql);
1682 while ($obj = $this->
db->fetch_object($result)) {
1684 if ($obj->lang == $current_lang) {
1685 $this->label = $obj->label;
1687 $this->other = $obj->other;
1689 $this->multilangs[
"$obj->lang"][
"label"] = $obj->label;
1690 $this->multilangs[
"$obj->lang"][
"description"] = $obj->description;
1691 $this->multilangs[
"$obj->lang"][
"other"] = $obj->other;
1695 $this->error =
"Error: ".$this->db->lasterror().
" - ".$sql;
1709 $testExit = array(
'multiprices',
'multiprices_ttc',
'multiprices_base_type',
'multiprices_min',
'multiprices_min_ttc',
'multiprices_tva_tx',
'multiprices_recuperableonly');
1711 foreach ($testExit as $field) {
1712 if (!isset($this->$field)) {
1715 $tmparray = $this->$field;
1716 if (!isset($tmparray[$level])) {
1722 'level' => $level ? $level : 1,
1723 'multiprices' => doubleval($this->multiprices[$level]),
1724 'multiprices_ttc' => doubleval($this->multiprices_ttc[$level]),
1725 'multiprices_base_type' => $this->multiprices_base_type[$level],
1726 'multiprices_min' => doubleval($this->multiprices_min[$level]),
1727 'multiprices_min_ttc' => doubleval($this->multiprices_min_ttc[$level]),
1728 'multiprices_tva_tx' => doubleval($this->multiprices_tva_tx[$level]),
1729 'multiprices_recuperableonly' => doubleval($this->multiprices_recuperableonly[$level]),
1752 if (empty($this->price_by_qty)) {
1753 $this->price_by_qty = 0;
1757 $sql =
"INSERT INTO ".$this->db->prefix().
"product_price(price_level,date_price, fk_product, fk_user_author, price, price_ttc, price_base_type,tosell, tva_tx, default_vat_code, recuperableonly,";
1758 $sql .=
" localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, price_min,price_min_ttc,price_by_qty,entity,fk_price_expression) ";
1759 $sql .=
" VALUES(".($level ? ((int) $level) : 1).
", '".$this->
db->idate($now).
"', ".((int) $this->
id).
", ".((int) $user->id).
", ".((
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).
",";
1760 $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');
1763 dol_syslog(get_class($this).
"::_log_price", LOG_DEBUG);
1766 $this->error = $this->
db->lasterror();
1786 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price_by_qty";
1787 $sql .=
" WHERE fk_product_price = ".((int) $rowid);
1790 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price";
1791 $sql .=
" WHERE rowid=".((int) $rowid);
1796 $this->error = $this->
db->lasterror();
1811 public function getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp = 0)
1813 global $conf, $db, $hookmanager, $action;
1816 if (is_object($hookmanager)) {
1817 $parameters = array(
'thirdparty_seller'=>$thirdparty_seller,
'thirdparty_buyer' => $thirdparty_buyer,
'pqp' => $pqp);
1819 $reshook = $hookmanager->executeHooks(
'getSellPrice', $parameters, $this, $action);
1821 return $hookmanager->resArray;
1832 $pu_ht = $this->price;
1833 $pu_ttc = $this->price_ttc;
1834 $price_min = $this->price_min;
1835 $price_base_type = $this->price_base_type;
1838 if (!empty($conf->global->PRODUIT_MULTIPRICES) && !empty($thirdparty_buyer->price_level)) {
1839 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
1840 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
1841 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
1842 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
1843 if (!empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL)) {
1844 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
1845 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
1847 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
1848 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
1854 } elseif (!empty($conf->global->PRODUIT_CUSTOMER_PRICES)) {
1856 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
1860 $filter = array(
't.fk_product' => $this->
id,
't.fk_soc' => $thirdparty_buyer->id);
1862 $result = $prodcustprice->fetch_all(
'',
'', 0, 0, $filter);
1864 if (count($prodcustprice->lines) > 0) {
1865 $pu_ht =
price($prodcustprice->lines[0]->price);
1866 $price_min =
price($prodcustprice->lines[0]->price_min);
1867 $pu_ttc =
price($prodcustprice->lines[0]->price_ttc);
1868 $price_base_type = $prodcustprice->lines[0]->price_base_type;
1869 $tva_tx = $prodcustprice->lines[0]->tva_tx;
1870 if ($prodcustprice->lines[0]->default_vat_code && !preg_match(
'/\(.*\)/',
$tva_tx)) {
1871 $tva_tx .=
' ('.$prodcustprice->lines[0]->default_vat_code.
')';
1873 $tva_npr = $prodcustprice->lines[0]->recuperableonly;
1879 } elseif (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY)) {
1881 if ($this->prices_by_qty[0]) {
1884 foreach ($this->prices_by_qty_list[0] as $priceforthequantityarray) {
1885 if ($priceforthequantityarray[
'rowid'] != $pqp) {
1889 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
1890 $pu_ht = $priceforthequantityarray[
'unitprice'];
1892 $pu_ttc = $priceforthequantityarray[
'unitprice'];
1897 } elseif (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
1899 if ($this->prices_by_qty[$thirdparty_buyer->price_level]) {
1902 foreach ($this->prices_by_qty_list[$thirdparty_buyer->price_level] as $priceforthequantityarray) {
1903 if ($priceforthequantityarray[
'rowid'] != $pqp) {
1907 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
1908 $pu_ht = $priceforthequantityarray[
'unitprice'];
1910 $pu_ttc = $priceforthequantityarray[
'unitprice'];
1917 return array(
'pu_ht'=>$pu_ht,
'pu_ttc'=>$pu_ttc,
'price_min'=>$price_min,
'price_base_type'=>$price_base_type,
'tva_tx'=>
$tva_tx,
'tva_npr'=>
$tva_npr);
1934 public function get_buyprice($prodfournprice, $qty, $product_id = 0, $fourn_ref =
'', $fk_soc = 0)
1941 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent,";
1942 $sql .=
" pfp.fk_product, pfp.ref_fourn, pfp.desc_fourn, pfp.fk_soc, pfp.tva_tx, pfp.fk_supplier_price_expression,";
1943 $sql .=
" pfp.default_vat_code,";
1944 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
1945 $sql .=
" pfp.packaging";
1946 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
1947 $sql .=
" WHERE pfp.rowid = ".((int) $prodfournprice);
1949 $sql .=
" AND pfp.quantity <= ".((float) $qty);
1951 $sql .=
" ORDER BY pfp.quantity DESC";
1953 dol_syslog(get_class($this).
"::get_buyprice first search by prodfournprice/qty", LOG_DEBUG);
1956 $obj = $this->
db->fetch_object(
$resql);
1957 if ($obj && $obj->quantity > 0) {
1958 if (!empty($conf->dynamicprices->enabled) && !empty($obj->fk_supplier_price_expression)) {
1959 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
1961 $prod_supplier->product_fourn_price_id = $obj->rowid;
1962 $prod_supplier->id = $obj->fk_product;
1963 $prod_supplier->fourn_qty = $obj->quantity;
1964 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
1965 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
1967 $price_result = $priceparser->parseProductSupplier($prod_supplier);
1968 if ($price_result >= 0) {
1969 $obj->price = $price_result;
1972 $this->product_fourn_price_id = $obj->rowid;
1973 $this->buyprice = $obj->price;
1974 $this->fourn_pu = $obj->price / $obj->quantity;
1975 $this->fourn_price_base_type =
'HT';
1976 $this->fourn_socid = $obj->fk_soc;
1977 $this->ref_fourn = $obj->ref_fourn;
1978 $this->ref_supplier = $obj->ref_fourn;
1979 $this->desc_supplier = $obj->desc_fourn;
1980 $this->remise_percent = $obj->remise_percent;
1981 $this->vatrate_supplier = $obj->tva_tx;
1982 $this->default_vat_code = $obj->default_vat_code;
1983 $this->fourn_multicurrency_price = $obj->multicurrency_price;
1984 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
1985 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
1986 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
1987 $this->fourn_multicurrency_code = $obj->multicurrency_code;
1988 if (!empty($conf->global->PRODUCT_USE_SUPPLIER_PACKAGING)) {
1989 $this->packaging = $obj->packaging;
1991 $result = $obj->fk_product;
1995 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
1996 $sql .=
" pfp.fk_product, pfp.ref_fourn as ref_supplier, pfp.desc_fourn as desc_supplier, pfp.tva_tx, pfp.fk_supplier_price_expression,";
1997 $sql .=
" pfp.default_vat_code,";
1998 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
1999 $sql .=
" pfp.packaging";
2000 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2001 $sql .=
" WHERE 1 = 1";
2002 if ($product_id > 0) {
2003 $sql .=
" AND pfp.fk_product = ".((int) $product_id);
2005 if ($fourn_ref !=
'none') {
2006 $sql .=
" AND pfp.ref_fourn = '".$this->db->escape($fourn_ref).
"'";
2009 $sql .=
" AND pfp.fk_soc = ".((int) $fk_soc);
2012 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2014 $sql .=
" ORDER BY pfp.quantity DESC";
2017 dol_syslog(get_class($this).
"::get_buyprice second search from qty/ref/product_id", LOG_DEBUG);
2020 $obj = $this->
db->fetch_object(
$resql);
2021 if ($obj && $obj->quantity > 0) {
2022 if (!empty($conf->dynamicprices->enabled) && !empty($obj->fk_supplier_price_expression)) {
2023 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2025 $prod_supplier->product_fourn_price_id = $obj->rowid;
2026 $prod_supplier->id = $obj->fk_product;
2027 $prod_supplier->fourn_qty = $obj->quantity;
2028 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2029 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2031 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2033 $obj->price = $price_result;
2036 $this->product_fourn_price_id = $obj->rowid;
2037 $this->buyprice = $obj->price;
2038 $this->fourn_qty = $obj->quantity;
2039 $this->fourn_pu = $obj->price / $obj->quantity;
2040 $this->fourn_price_base_type =
'HT';
2041 $this->fourn_socid = $obj->fk_soc;
2042 $this->ref_fourn = $obj->ref_supplier;
2043 $this->ref_supplier = $obj->ref_supplier;
2044 $this->desc_supplier = $obj->desc_supplier;
2045 $this->remise_percent = $obj->remise_percent;
2046 $this->vatrate_supplier = $obj->tva_tx;
2047 $this->default_vat_code = $obj->default_vat_code;
2048 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2049 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2050 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2051 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2052 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2053 if (!empty($conf->global->PRODUCT_USE_SUPPLIER_PACKAGING)) {
2054 $this->packaging = $obj->packaging;
2056 $result = $obj->fk_product;
2062 $this->error = $this->
db->lasterror();
2067 $this->error = $this->
db->lasterror();
2089 public function updatePrice($newprice, $newpricebase, $user, $newvat =
'', $newminprice = 0, $level = 0, $newnpr = 0, $newpbq = 0, $ignore_autogen = 0, $localtaxes_array = array(), $newdefaultvatcode =
'')
2091 global $conf, $langs;
2097 dol_syslog(get_class($this).
"::update_price id=".$id.
" newprice=".$newprice.
" newpricebase=".$newpricebase.
" newminprice=".$newminprice.
" level=".$level.
" npr=".$newnpr.
" newdefaultvatcode=".$newdefaultvatcode);
2100 if (empty($this->tva_tx)) {
2103 if (empty($newnpr)) {
2106 if (empty($newminprice)) {
2109 if (empty($newminprice)) {
2114 if ($newvat ==
'') {
2120 if ((!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) && !$ignore_autogen && $this->price_autogen && ($level == 1)) {
2121 return $this->
generateMultiprices($user, $newprice, $newpricebase, $newvat, $newnpr, $newpbq);
2124 if (!empty($newminprice) && ($newminprice > $newprice)) {
2125 $this->error =
'ErrorPriceCantBeLowerThanMinPrice';
2129 if ($newprice !==
'' || $newprice === 0) {
2130 if ($newpricebase ==
'TTC') {
2131 $price_ttc =
price2num($newprice,
'MU');
2132 $price =
price2num($newprice) / (1 + ($newvat / 100));
2135 if ($newminprice !=
'' || $newminprice == 0) {
2136 $price_min_ttc =
price2num($newminprice,
'MU');
2137 $price_min =
price2num($newminprice) / (1 + ($newvat / 100));
2138 $price_min =
price2num($price_min,
'MU');
2145 $price_ttc = ($newnpr != 1) ?
price2num($newprice) * (1 + ($newvat / 100)) : $price;
2146 $price_ttc =
price2num($price_ttc,
'MU');
2148 if ($newminprice !==
'' || $newminprice === 0) {
2149 $price_min =
price2num($newminprice,
'MU');
2150 $price_min_ttc =
price2num($newminprice) * (1 + ($newvat / 100));
2151 $price_min_ttc =
price2num($price_min_ttc,
'MU');
2160 if (count($localtaxes_array) > 0) {
2161 $localtaxtype1 = $localtaxes_array[
'0'];
2162 $localtax1 = $localtaxes_array[
'1'];
2163 $localtaxtype2 = $localtaxes_array[
'2'];
2164 $localtax2 = $localtaxes_array[
'3'];
2167 $localtaxtype1 =
'0';
2169 $localtaxtype2 =
'0';
2172 if (empty($localtax1)) {
2175 if (empty($localtax2)) {
2183 $sql =
"UPDATE ".$this->db->prefix().
"product SET";
2184 $sql .=
" price_base_type='".$this->db->escape($newpricebase).
"',";
2185 $sql .=
" price=".$price.
",";
2186 $sql .=
" price_ttc=".$price_ttc.
",";
2187 $sql .=
" price_min=".$price_min.
",";
2188 $sql .=
" price_min_ttc=".$price_min_ttc.
",";
2189 $sql .=
" localtax1_tx=".($localtax1 >= 0 ? $localtax1 :
'NULL').
",";
2190 $sql .=
" localtax2_tx=".($localtax2 >= 0 ? $localtax2 :
'NULL').
",";
2191 $sql .=
" localtax1_type=".($localtaxtype1 !=
'' ?
"'".$this->db->escape($localtaxtype1).
"'" :
"'0'").
",";
2192 $sql .=
" localtax2_type=".($localtaxtype2 !=
'' ?
"'".$this->db->escape($localtaxtype2).
"'" :
"'0'").
",";
2193 $sql .=
" default_vat_code=".($newdefaultvatcode ?
"'".$this->db->escape($newdefaultvatcode).
"'" :
"null").
",";
2194 $sql .=
" tva_tx='".price2num($newvat).
"',";
2195 $sql .=
" recuperableonly='".$this->db->escape($newnpr).
"'";
2196 $sql .=
" WHERE rowid = ".((int) $id);
2198 dol_syslog(get_class($this).
"::update_price", LOG_DEBUG);
2201 $this->multiprices[$level] = $price;
2202 $this->multiprices_ttc[$level] = $price_ttc;
2203 $this->multiprices_min[$level] = $price_min;
2204 $this->multiprices_min_ttc[$level] = $price_min_ttc;
2205 $this->multiprices_base_type[$level] = $newpricebase;
2206 $this->multiprices_default_vat_code[$level] = $newdefaultvatcode;
2207 $this->multiprices_tva_tx[$level] = $newvat;
2208 $this->multiprices_recuperableonly[$level] = $newnpr;
2210 $this->
price = $price;
2211 $this->price_ttc = $price_ttc;
2212 $this->price_min = $price_min;
2213 $this->price_min_ttc = $price_min_ttc;
2214 $this->price_base_type = $newpricebase;
2215 $this->default_vat_code = $newdefaultvatcode;
2216 $this->tva_tx = $newvat;
2217 $this->tva_npr = $newnpr;
2219 $this->localtax1_tx = $localtax1;
2220 $this->localtax2_tx = $localtax2;
2221 $this->localtax1_type = $localtaxtype1;
2222 $this->localtax2_type = $localtaxtype2;
2225 $this->price_by_qty = $newpbq;
2229 if (!empty(array_diff_assoc($newPriceData, $lastPriceData)) || empty($conf->global->PRODUIT_MULTIPRICES)) {
2233 $this->level = $level;
2236 $result = $this->
call_trigger(
'PRODUCT_PRICE_MODIFY', $user);
2238 $this->
db->rollback();
2243 $this->
db->commit();
2245 $this->
db->rollback();
2246 $this->error = $this->
db->lasterror();
2265 $this->fk_price_expression = $expression_id;
2267 return $this->
update($this->
id, $user);
2282 public function fetch($id =
'', $ref =
'', $ref_ext =
'', $barcode =
'', $ignore_expression = 0, $ignore_price_load = 0, $ignore_lang_load = 0)
2284 include_once DOL_DOCUMENT_ROOT.
'/core/lib/company.lib.php';
2286 global $langs, $conf;
2288 dol_syslog(get_class($this).
"::fetch id=".$id.
" ref=".$ref.
" ref_ext=".$ref_ext);
2291 if (!$id && !$ref && !$ref_ext && !$barcode) {
2292 $this->error =
'ErrorWrongParameters';
2293 dol_syslog(get_class($this).
"::fetch ".$this->error, LOG_ERR);
2297 $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,";
2298 $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,";
2299 $sql .=
" p.tobuy, p.fk_product_type, p.duration, p.fk_default_warehouse, p.seuil_stock_alerte, p.canvas, p.net_measure, p.net_measure_units, p.weight, p.weight_units,";
2300 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
2301 $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,";
2302 if (empty($conf->global->MAIN_PRODUCT_PERENTITY_SHARED)) {
2303 $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,";
2305 $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,";
2310 $separatedEntityPMP =
false;
2311 $separatedStock =
false;
2312 $visibleWarehousesEntities = $conf->entity;
2313 if (!empty($conf->global->MULTICOMPANY_PRODUCT_SHARING_ENABLED)) {
2314 if (!empty($conf->global->MULTICOMPANY_PMP_PER_ENTITY_ENABLED)) {
2315 $checkPMPPerEntity = $this->
db->query(
"SELECT pmp FROM " . $this->
db->prefix() .
"product_perentity WHERE fk_product = ".((int) $id).
" AND entity = ".(
int) $conf->entity);
2316 if ($this->
db->num_rows($checkPMPPerEntity)>0) {
2317 $separatedEntityPMP =
true;
2321 $separatedStock =
true;
2322 if (isset($mc->sharings[
'stock']) && !empty($mc->sharings[
'stock'])) {
2323 $visibleWarehousesEntities .=
"," . implode(
",", $mc->sharings[
'stock']);
2326 if ($separatedEntityPMP) {
2327 $sql .=
" ppe.pmp,";
2331 $sql .=
" p.datec, p.tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.batch_mask, p.fk_unit,";
2332 $sql .=
" p.fk_price_expression, p.price_autogen, p.model_pdf,";
2333 if ($separatedStock) {
2334 $sql .=
" SUM(sp.reel) as stock";
2338 $sql .=
" FROM ".$this->db->prefix().
"product as p";
2339 if (!empty($conf->global->MAIN_PRODUCT_PERENTITY_SHARED) || $separatedEntityPMP) {
2340 $sql .=
" LEFT JOIN " . $this->
db->prefix() .
"product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int) $conf->entity);
2342 if ($separatedStock) {
2343 $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).
"))";
2347 $sql .=
" WHERE p.rowid = ".((int) $id);
2349 $sql .=
" WHERE p.entity IN (".getEntity($this->element).
")";
2351 $sql .=
" AND p.ref = '".$this->db->escape($ref).
"'";
2352 } elseif ($ref_ext) {
2353 $sql .=
" AND p.ref_ext = '".$this->db->escape($ref_ext).
"'";
2354 } elseif ($barcode) {
2355 $sql .=
" AND p.barcode = '".$this->db->escape($barcode).
"'";
2358 if ($separatedStock) {
2359 $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,";
2360 $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,";
2361 $sql .=
" p.tobuy, p.fk_product_type, p.duration, p.fk_default_warehouse, p.seuil_stock_alerte, p.canvas, p.net_measure, p.net_measure_units, p.weight, p.weight_units,";
2362 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
2363 $sql .=
" p.surface, p.surface_units, p.volume, p.volume_units, p.barcode, p.fk_barcode_type, p.finished,";
2364 if (empty($conf->global->MAIN_PRODUCT_PERENTITY_SHARED)) {
2365 $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,";
2367 $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,";
2369 if ($separatedEntityPMP) {
2370 $sql .=
" ppe.pmp,";
2374 $sql .=
" p.datec, p.tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.batch_mask, p.fk_unit,";
2375 $sql .=
" p.fk_price_expression, p.price_autogen, p.model_pdf";
2376 if (!$separatedStock) {
2377 $sql .=
", p.stock";
2383 unset($this->oldcopy);
2385 if ($this->
db->num_rows(
$resql) > 0) {
2386 $obj = $this->
db->fetch_object(
$resql);
2388 $this->
id = $obj->rowid;
2389 $this->
ref = $obj->ref;
2390 $this->ref_ext = $obj->ref_ext;
2391 $this->label = $obj->label;
2393 $this->url = $obj->url;
2394 $this->note_public = $obj->note_public;
2395 $this->note_private = $obj->note_private;
2396 $this->note = $obj->note_private;
2398 $this->
type = $obj->fk_product_type;
2399 $this->status = $obj->tosell;
2400 $this->status_buy = $obj->tobuy;
2401 $this->status_batch = $obj->tobatch;
2402 $this->batch_mask = $obj->batch_mask;
2404 $this->customcode = $obj->customcode;
2405 $this->country_id = $obj->fk_country;
2406 $this->country_code =
getCountry($this->country_id, 2, $this->
db);
2407 $this->state_id = $obj->fk_state;
2408 $this->lifetime = $obj->lifetime;
2409 $this->qc_frequency = $obj->qc_frequency;
2410 $this->
price = $obj->price;
2411 $this->price_ttc = $obj->price_ttc;
2412 $this->price_min = $obj->price_min;
2413 $this->price_min_ttc = $obj->price_min_ttc;
2414 $this->price_base_type = $obj->price_base_type;
2415 $this->cost_price = $obj->cost_price;
2416 $this->default_vat_code = $obj->default_vat_code;
2417 $this->tva_tx = $obj->tva_tx;
2419 $this->tva_npr = $obj->tva_npr;
2420 $this->recuperableonly = $obj->tva_npr;
2422 $this->localtax1_tx = $obj->localtax1_tx;
2423 $this->localtax2_tx = $obj->localtax2_tx;
2424 $this->localtax1_type = $obj->localtax1_type;
2425 $this->localtax2_type = $obj->localtax2_type;
2427 $this->finished = $obj->finished;
2428 $this->fk_default_bom = $obj->fk_default_bom;
2430 $this->duration = $obj->duration;
2431 $this->duration_value = substr($obj->duration, 0,
dol_strlen($obj->duration) - 1);
2432 $this->duration_unit = substr($obj->duration, -1);
2433 $this->canvas = $obj->canvas;
2434 $this->net_measure = $obj->net_measure;
2435 $this->net_measure_units = $obj->net_measure_units;
2436 $this->weight = $obj->weight;
2437 $this->weight_units = $obj->weight_units;
2438 $this->length = $obj->length;
2439 $this->length_units = $obj->length_units;
2440 $this->width = $obj->width;
2441 $this->width_units = $obj->width_units;
2442 $this->height = $obj->height;
2443 $this->height_units = $obj->height_units;
2445 $this->surface = $obj->surface;
2446 $this->surface_units = $obj->surface_units;
2447 $this->volume = $obj->volume;
2448 $this->volume_units = $obj->volume_units;
2449 $this->barcode = $obj->barcode;
2450 $this->barcode_type = $obj->fk_barcode_type;
2452 $this->accountancy_code_buy = $obj->accountancy_code_buy;
2453 $this->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra;
2454 $this->accountancy_code_buy_export = $obj->accountancy_code_buy_export;
2455 $this->accountancy_code_sell = $obj->accountancy_code_sell;
2456 $this->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra;
2457 $this->accountancy_code_sell_export = $obj->accountancy_code_sell_export;
2459 $this->fk_default_warehouse = $obj->fk_default_warehouse;
2460 $this->seuil_stock_alerte = $obj->seuil_stock_alerte;
2461 $this->desiredstock = $obj->desiredstock;
2462 $this->stock_reel = $obj->stock;
2463 $this->pmp = $obj->pmp;
2465 $this->date_creation = $obj->datec;
2466 $this->date_modification = $obj->tms;
2467 $this->import_key = $obj->import_key;
2468 $this->entity = $obj->entity;
2470 $this->ref_ext = $obj->ref_ext;
2471 $this->fk_price_expression = $obj->fk_price_expression;
2472 $this->fk_unit = $obj->fk_unit;
2473 $this->price_autogen = $obj->price_autogen;
2474 $this->model_pdf = $obj->model_pdf;
2476 $this->mandatory_period = $obj->mandatory_period;
2484 if (!empty($conf->global->MAIN_MULTILANGS) && empty($ignore_lang_load)) {
2489 if (!empty($conf->global->PRODUIT_MULTIPRICES) && empty($ignore_price_load)) {
2490 for ($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) {
2491 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
2492 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
2493 $sql .=
" FROM ".$this->db->prefix().
"product_price";
2494 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
2495 $sql .=
" AND price_level=".((int) $i);
2496 $sql .=
" AND fk_product = ".((int) $this->
id);
2497 $sql .=
" ORDER BY date_price DESC, rowid DESC";
2501 $result = $this->
db->fetch_array(
$resql);
2503 $this->multiprices[$i] = $result ? $result[
"price"] :
null;
2504 $this->multiprices_ttc[$i] = $result ? $result[
"price_ttc"] :
null;
2505 $this->multiprices_min[$i] = $result ? $result[
"price_min"] :
null;
2506 $this->multiprices_min_ttc[$i] = $result ? $result[
"price_min_ttc"] :
null;
2507 $this->multiprices_base_type[$i] = $result ? $result[
"price_base_type"] :
null;
2509 $this->multiprices_tva_tx[$i] = $result ? $result[
"tva_tx"].($result ?
' ('.$result[
'default_vat_code'].
')' :
'') :
null;
2510 $this->multiprices_recuperableonly[$i] = $result ? $result[
"recuperableonly"] :
null;
2548 $this->error = $this->
db->lasterror;
2552 } elseif (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && empty($ignore_price_load)) {
2554 } elseif (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) && empty($ignore_price_load)) {
2555 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
2556 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid";
2557 $sql .=
" FROM ".$this->db->prefix().
"product_price";
2558 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2559 $sql .=
" ORDER BY date_price DESC, rowid DESC";
2563 $result = $this->
db->fetch_array(
$resql);
2566 $this->prices_by_qty[0] = $result[
"price_by_qty"];
2567 $this->prices_by_qty_id[0] = $result[
"rowid"];
2569 if ($this->prices_by_qty[0] == 1) {
2570 $sql =
"SELECT rowid,price, unitprice, quantity, remise_percent, remise, remise, price_base_type";
2571 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
2572 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[0]);
2573 $sql .=
" ORDER BY quantity ASC";
2574 $resultat = array();
2578 while ($result = $this->
db->fetch_array(
$resql)) {
2579 $resultat[$ii] = array();
2580 $resultat[$ii][
"rowid"] = $result[
"rowid"];
2581 $resultat[$ii][
"price"] = $result[
"price"];
2582 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
2583 $resultat[$ii][
"quantity"] = $result[
"quantity"];
2584 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
2586 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
2589 $this->prices_by_qty_list[0] = $resultat;
2591 $this->error = $this->
db->lasterror;
2596 $this->error = $this->
db->lasterror;
2599 } elseif (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES) && empty($ignore_price_load)) {
2600 for ($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) {
2601 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
2602 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
2603 $sql .=
" FROM ".$this->db->prefix().
"product_price";
2604 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
2605 $sql .=
" AND price_level=".((int) $i);
2606 $sql .=
" AND fk_product = ".((int) $this->
id);
2607 $sql .=
" ORDER BY date_price DESC, rowid DESC";
2611 $result = $this->
db->fetch_array(
$resql);
2613 $this->multiprices[$i] = $result[
"price"];
2614 $this->multiprices_ttc[$i] = $result[
"price_ttc"];
2615 $this->multiprices_min[$i] = $result[
"price_min"];
2616 $this->multiprices_min_ttc[$i] = $result[
"price_min_ttc"];
2617 $this->multiprices_base_type[$i] = $result[
"price_base_type"];
2619 $this->multiprices_tva_tx[$i] = $result[
"tva_tx"];
2620 $this->multiprices_recuperableonly[$i] = $result[
"recuperableonly"];
2623 $this->prices_by_qty[$i] = $result[
"price_by_qty"];
2624 $this->prices_by_qty_id[$i] = $result[
"rowid"];
2626 if ($this->prices_by_qty[$i] == 1) {
2627 $sql =
"SELECT rowid, price, unitprice, quantity, remise_percent, remise, price_base_type";
2628 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
2629 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[$i]);
2630 $sql .=
" ORDER BY quantity ASC";
2631 $resultat = array();
2635 while ($result = $this->
db->fetch_array(
$resql)) {
2636 $resultat[$ii] = array();
2637 $resultat[$ii][
"rowid"] = $result[
"rowid"];
2638 $resultat[$ii][
"price"] = $result[
"price"];
2639 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
2640 $resultat[$ii][
"quantity"] = $result[
"quantity"];
2641 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
2642 $resultat[$ii][
"remise"] = $result[
"remise"];
2643 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
2646 $this->prices_by_qty_list[$i] = $resultat;
2648 $this->error = $this->
db->lasterror;
2653 $this->error = $this->
db->lasterror;
2659 if (!empty($conf->dynamicprices->enabled) && !empty($this->fk_price_expression) && empty($ignore_expression)) {
2660 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2662 $price_result = $priceparser->parseProduct($this);
2663 if ($price_result >= 0) {
2664 $this->
price = $price_result;
2666 $this->price_ttc =
price2num($this->
price) * (1 + ($this->tva_tx / 100));
2667 $this->price_ttc =
price2num($this->price_ttc,
'MU');
2673 $this->stock_warehouse = array();
2680 $this->error = $this->
db->lasterror();
2695 global $user, $hookmanager, $action;
2699 foreach (array(
'toconsume',
'consumed',
'toproduce',
'produced') as $role) {
2700 $this->stats_mo[
'customers_'.$role] = 0;
2701 $this->stats_mo[
'nb_'.$role] = 0;
2702 $this->stats_mo[
'qty_'.$role] = 0;
2704 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
2705 $sql .=
" SUM(mp.qty) as qty";
2706 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as c";
2707 $sql .=
" INNER JOIN ".$this->db->prefix().
"mrp_production as mp ON mp.fk_mo=c.rowid";
2708 if (empty($user->rights->societe->client->voir) && !$socid) {
2709 $sql .=
"INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc=c.fk_soc AND sc.fk_user = ".((int) $user->id);
2712 $sql .=
" c.entity IN (".getEntity(
'mo').
")";
2714 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
2715 $sql .=
" AND mp.role ='".$this->db->escape($role).
"'";
2717 $sql .=
" AND c.fk_soc = ".((int) $socid);
2720 $result = $this->
db->query($sql);
2722 $obj = $this->
db->fetch_object($result);
2723 $this->stats_mo[
'customers_'.$role] = $obj->nb_customers ? $obj->nb_customers : 0;
2724 $this->stats_mo[
'nb_'.$role] = $obj->nb ? $obj->nb : 0;
2725 $this->stats_mo[
'qty_'.$role] = $obj->qty ?
price2num($obj->qty,
'MS') : 0;
2727 $this->error = $this->
db->error();
2732 if (!empty($error)) {
2736 $parameters = array(
'socid' => $socid);
2737 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
2739 $this->stats_mo = $hookmanager->resArray[
'stats_mo'];
2755 global $user, $hookmanager, $action;
2759 $this->stats_bom[
'nb_toproduce'] = 0;
2760 $this->stats_bom[
'nb_toconsume'] = 0;
2761 $this->stats_bom[
'qty_toproduce'] = 0;
2762 $this->stats_bom[
'qty_toconsume'] = 0;
2764 $sql =
"SELECT COUNT(DISTINCT b.rowid) as nb_toproduce,";
2765 $sql .=
" SUM(b.qty) as qty_toproduce";
2766 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
2767 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
2769 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
2770 $sql .=
" AND b.fk_product =".((int) $this->
id);
2771 $sql .=
" GROUP BY b.rowid";
2773 $result = $this->
db->query($sql);
2775 $obj = $this->
db->fetch_object($result);
2776 $this->stats_bom[
'nb_toproduce'] = !empty($obj->nb_toproduce) ? $obj->nb_toproduce : 0;
2777 $this->stats_bom[
'qty_toproduce'] = !empty($obj->qty_toproduce) ?
price2num($obj->qty_toproduce) : 0;
2779 $this->error = $this->
db->error();
2783 $sql =
"SELECT COUNT(DISTINCT bl.rowid) as nb_toconsume,";
2784 $sql .=
" SUM(bl.qty) as qty_toconsume";
2785 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
2786 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
2788 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
2789 $sql .=
" AND bl.fk_product =".((int) $this->
id);
2791 $result = $this->
db->query($sql);
2793 $obj = $this->
db->fetch_object($result);
2794 $this->stats_bom[
'nb_toconsume'] = !empty($obj->nb_toconsume) ? $obj->nb_toconsume : 0;
2795 $this->stats_bom[
'qty_toconsume'] = !empty($obj->qty_toconsume) ?
price2num($obj->qty_toconsume) : 0;
2797 $this->error = $this->
db->error();
2801 if (!empty($error)) {
2805 $parameters = array(
'socid' => $socid);
2806 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
2808 $this->stats_bom = $hookmanager->resArray[
'stats_bom'];
2824 global $conf, $user, $hookmanager, $action;
2826 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_customers, COUNT(DISTINCT p.rowid) as nb,";
2827 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
2828 $sql .=
" FROM ".$this->db->prefix().
"propaldet as pd";
2829 $sql .=
", ".$this->db->prefix().
"propal as p";
2830 $sql .=
", ".$this->db->prefix().
"societe as s";
2831 if (empty($user->rights->societe->client->voir) && !$socid) {
2832 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
2834 $sql .=
" WHERE p.rowid = pd.fk_propal";
2835 $sql .=
" AND p.fk_soc = s.rowid";
2836 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
2837 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
2838 if (empty($user->rights->societe->client->voir) && !$socid) {
2839 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
2843 $sql .=
" AND p.fk_soc = ".((int) $socid);
2846 $result = $this->
db->query($sql);
2848 $obj = $this->
db->fetch_object($result);
2849 $this->stats_propale[
'customers'] = $obj->nb_customers;
2850 $this->stats_propale[
'nb'] = $obj->nb;
2851 $this->stats_propale[
'rows'] = $obj->nb_rows;
2852 $this->stats_propale[
'qty'] = $obj->qty ? $obj->qty : 0;
2855 if (!empty($conf->global->PRODUCT_STATS_WITH_PARENT_PROD_IF_INCDEC)) {
2857 if (is_array($TFather) && !empty($TFather)) {
2858 foreach ($TFather as &$fatherData) {
2860 $pFather->id = $fatherData[
'id'];
2861 $qtyCoef = $fatherData[
'qty'];
2863 if ($fatherData[
'incdec']) {
2864 $pFather->load_stats_propale($socid);
2866 $this->stats_propale[
'customers'] += $pFather->stats_propale[
'customers'];
2867 $this->stats_propale[
'nb'] += $pFather->stats_propale[
'nb'];
2868 $this->stats_propale[
'rows'] += $pFather->stats_propale[
'rows'];
2869 $this->stats_propale[
'qty'] += $pFather->stats_propale[
'qty'] * $qtyCoef;
2875 $parameters = array(
'socid' => $socid);
2876 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerProposal', $parameters, $this, $action);
2878 $this->stats_propale = $hookmanager->resArray[
'stats_propale'];
2883 $this->error = $this->
db->error();
2899 global $conf, $user, $hookmanager, $action;
2901 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_suppliers, COUNT(DISTINCT p.rowid) as nb,";
2902 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
2903 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as pd";
2904 $sql .=
", ".$this->db->prefix().
"supplier_proposal as p";
2905 $sql .=
", ".$this->db->prefix().
"societe as s";
2906 if (empty($user->rights->societe->client->voir) && !$socid) {
2907 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
2909 $sql .=
" WHERE p.rowid = pd.fk_supplier_proposal";
2910 $sql .=
" AND p.fk_soc = s.rowid";
2911 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
2912 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
2913 if (empty($user->rights->societe->client->voir) && !$socid) {
2914 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
2918 $sql .=
" AND p.fk_soc = ".((int) $socid);
2921 $result = $this->
db->query($sql);
2923 $obj = $this->
db->fetch_object($result);
2924 $this->stats_proposal_supplier[
'suppliers'] = $obj->nb_suppliers;
2925 $this->stats_proposal_supplier[
'nb'] = $obj->nb;
2926 $this->stats_proposal_supplier[
'rows'] = $obj->nb_rows;
2927 $this->stats_proposal_supplier[
'qty'] = $obj->qty ? $obj->qty : 0;
2929 $parameters = array(
'socid' => $socid);
2930 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierProposal', $parameters, $this, $action);
2932 $this->stats_proposal_supplier = $hookmanager->resArray[
'stats_proposal_supplier'];
2937 $this->error = $this->
db->error();
2955 global $conf, $user, $hookmanager, $action;
2957 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
2958 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
2959 $sql .=
" FROM ".$this->db->prefix().
"commandedet as cd";
2960 $sql .=
", ".$this->db->prefix().
"commande as c";
2961 $sql .=
", ".$this->db->prefix().
"societe as s";
2962 if (empty($user->rights->societe->client->voir) && !$socid && !$forVirtualStock) {
2963 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
2965 $sql .=
" WHERE c.rowid = cd.fk_commande";
2966 $sql .=
" AND c.fk_soc = s.rowid";
2967 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock && !empty($conf->global->STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE) ?
'stock' :
'commande').
")";
2968 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
2969 if (empty($user->rights->societe->client->voir) && !$socid && !$forVirtualStock) {
2970 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
2973 $sql .=
" AND c.fk_soc = ".((int) $socid);
2975 if ($filtrestatut <>
'') {
2976 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
2979 $result = $this->
db->query($sql);
2981 $obj = $this->
db->fetch_object($result);
2982 $this->stats_commande[
'customers'] = $obj->nb_customers;
2983 $this->stats_commande[
'nb'] = $obj->nb;
2984 $this->stats_commande[
'rows'] = $obj->nb_rows;
2985 $this->stats_commande[
'qty'] = $obj->qty ? $obj->qty : 0;
2988 if (!empty($conf->global->PRODUCT_STATS_WITH_PARENT_PROD_IF_INCDEC)) {
2990 if (is_array($TFather) && !empty($TFather)) {
2991 foreach ($TFather as &$fatherData) {
2993 $pFather->id = $fatherData[
'id'];
2994 $qtyCoef = $fatherData[
'qty'];
2996 if ($fatherData[
'incdec']) {
2997 $pFather->load_stats_commande($socid, $filtrestatut);
2999 $this->stats_commande[
'customers'] += $pFather->stats_commande[
'customers'];
3000 $this->stats_commande[
'nb'] += $pFather->stats_commande[
'nb'];
3001 $this->stats_commande[
'rows'] += $pFather->stats_commande[
'rows'];
3002 $this->stats_commande[
'qty'] += $pFather->stats_commande[
'qty'] * $qtyCoef;
3011 if (!empty($conf->global->STOCK_CALCULATE_ON_BILL) && $forVirtualStock) {
3012 if (!empty($conf->global->DECREASE_ONLY_UNINVOICEDPRODUCTS)) {
3014 $sql =
"SELECT SUM(".$this->db->ifsql(
'f.type=2', -1, 1).
" * fd.qty) as count FROM ".$this->
db->prefix().
"facturedet fd ";
3015 $sql .=
" JOIN ".$this->db->prefix().
"facture f ON fd.fk_facture = f.rowid ";
3016 $sql .=
" JOIN ".$this->db->prefix().
"element_element el ON el.fk_target = f.rowid and el.targettype = 'facture' and sourcetype = 'commande'";
3017 $sql .=
" JOIN ".$this->db->prefix().
"commande c ON el.fk_source = c.rowid ";
3018 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3019 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3023 if ($this->
db->num_rows(
$resql) > 0) {
3024 $obj = $this->
db->fetch_object(
$resql);
3025 $adeduire += $obj->count;
3028 $this->error = $this->
db->error();
3032 $this->stats_commande[
'qty'] -= $adeduire;
3036 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3037 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerOrder', $parameters, $this, $action);
3039 $this->stats_commande = $hookmanager->resArray[
'stats_commande'];
3043 $this->error = $this->
db->error();
3060 global $conf, $user, $hookmanager, $action;
3062 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_suppliers, COUNT(DISTINCT c.rowid) as nb,";
3063 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3064 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as cd";
3065 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as c";
3066 $sql .=
", ".$this->db->prefix().
"societe as s";
3067 if (empty($user->rights->societe->client->voir) && !$socid && !$forVirtualStock) {
3068 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3070 $sql .=
" WHERE c.rowid = cd.fk_commande";
3071 $sql .=
" AND c.fk_soc = s.rowid";
3072 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock && !empty($conf->global->STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE) ?
'stock' :
'supplier_order').
")";
3073 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3074 if (empty($user->rights->societe->client->voir) && !$socid && !$forVirtualStock) {
3075 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3078 $sql .=
" AND c.fk_soc = ".((int) $socid);
3080 if ($filtrestatut !=
'') {
3081 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3084 $result = $this->
db->query($sql);
3086 $obj = $this->
db->fetch_object($result);
3087 $this->stats_commande_fournisseur[
'suppliers'] = $obj->nb_suppliers;
3088 $this->stats_commande_fournisseur[
'nb'] = $obj->nb;
3089 $this->stats_commande_fournisseur[
'rows'] = $obj->nb_rows;
3090 $this->stats_commande_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
3092 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3093 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierOrder', $parameters, $this, $action);
3095 $this->stats_commande_fournisseur = $hookmanager->resArray[
'stats_commande_fournisseur'];
3100 $this->error = $this->
db->error().
' sql='.$sql;
3115 public function load_stats_sending($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $filterShipmentStatus =
'')
3118 global $conf, $user, $hookmanager, $action;
3120 $sql =
"SELECT COUNT(DISTINCT e.fk_soc) as nb_customers, COUNT(DISTINCT e.rowid) as nb,";
3121 $sql .=
" COUNT(ed.rowid) as nb_rows, SUM(ed.qty) as qty";
3122 $sql .=
" FROM ".$this->db->prefix().
"expeditiondet as ed";
3123 $sql .=
", ".$this->db->prefix().
"commandedet as cd";
3124 $sql .=
", ".$this->db->prefix().
"commande as c";
3125 $sql .=
", ".$this->db->prefix().
"expedition as e";
3126 $sql .=
", ".$this->db->prefix().
"societe as s";
3127 if (empty($user->rights->societe->client->voir) && !$socid && !$forVirtualStock) {
3128 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3130 $sql .=
" WHERE e.rowid = ed.fk_expedition";
3131 $sql .=
" AND c.rowid = cd.fk_commande";
3132 $sql .=
" AND e.fk_soc = s.rowid";
3133 $sql .=
" AND e.entity IN (".getEntity($forVirtualStock && !empty($conf->global->STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE) ?
'stock' :
'expedition').
")";
3134 $sql .=
" AND ed.fk_origin_line = cd.rowid";
3135 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3136 if (empty($user->rights->societe->client->voir) && !$socid && !$forVirtualStock) {
3137 $sql .=
" AND e.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3140 $sql .=
" AND e.fk_soc = ".((int) $socid);
3142 if ($filtrestatut <>
'') {
3143 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3145 if (!empty($filterShipmentStatus)) {
3146 $sql .=
" AND e.fk_statut IN (".$this->db->sanitize($filterShipmentStatus).
")";
3149 $result = $this->
db->query($sql);
3151 $obj = $this->
db->fetch_object($result);
3152 $this->stats_expedition[
'customers'] = $obj->nb_customers;
3153 $this->stats_expedition[
'nb'] = $obj->nb;
3154 $this->stats_expedition[
'rows'] = $obj->nb_rows;
3155 $this->stats_expedition[
'qty'] = $obj->qty ? $obj->qty : 0;
3158 if (!empty($conf->global->PRODUCT_STATS_WITH_PARENT_PROD_IF_INCDEC)) {
3160 if (is_array($TFather) && !empty($TFather)) {
3161 foreach ($TFather as &$fatherData) {
3163 $pFather->id = $fatherData[
'id'];
3164 $qtyCoef = $fatherData[
'qty'];
3166 if ($fatherData[
'incdec']) {
3167 $pFather->load_stats_sending($socid, $filtrestatut, $forVirtualStock);
3169 $this->stats_expedition[
'customers'] += $pFather->stats_expedition[
'customers'];
3170 $this->stats_expedition[
'nb'] += $pFather->stats_expedition[
'nb'];
3171 $this->stats_expedition[
'rows'] += $pFather->stats_expedition[
'rows'];
3172 $this->stats_expedition[
'qty'] += $pFather->stats_expedition[
'qty'] * $qtyCoef;
3178 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock,
'filterShipmentStatus' => $filterShipmentStatus);
3179 $reshook = $hookmanager->executeHooks(
'loadStatsSending', $parameters, $this, $action);
3181 $this->stats_expedition = $hookmanager->resArray[
'stats_expedition'];
3186 $this->error = $this->
db->error();
3203 global $conf, $user, $hookmanager, $action;
3205 $sql =
"SELECT COUNT(DISTINCT cf.fk_soc) as nb_suppliers, COUNT(DISTINCT cf.rowid) as nb,";
3206 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
3207 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseur_dispatch as fd";
3208 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as cf";
3209 $sql .=
", ".$this->db->prefix().
"societe as s";
3210 if (empty($user->rights->societe->client->voir) && !$socid && !$forVirtualStock) {
3211 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3213 $sql .=
" WHERE cf.rowid = fd.fk_commande";
3214 $sql .=
" AND cf.fk_soc = s.rowid";
3215 $sql .=
" AND cf.entity IN (".getEntity($forVirtualStock && !empty($conf->global->STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE) ?
'stock' :
'supplier_order').
")";
3216 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3217 if (empty($user->rights->societe->client->voir) && !$socid && !$forVirtualStock) {
3218 $sql .=
" AND cf.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3221 $sql .=
" AND cf.fk_soc = ".((int) $socid);
3223 if ($filtrestatut <>
'') {
3224 $sql .=
" AND cf.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3227 $result = $this->
db->query($sql);
3229 $obj = $this->
db->fetch_object($result);
3230 $this->stats_reception[
'suppliers'] = $obj->nb_suppliers;
3231 $this->stats_reception[
'nb'] = $obj->nb;
3232 $this->stats_reception[
'rows'] = $obj->nb_rows;
3233 $this->stats_reception[
'qty'] = $obj->qty ? $obj->qty : 0;
3235 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3236 $reshook = $hookmanager->executeHooks(
'loadStatsReception', $parameters, $this, $action);
3238 $this->stats_reception = $hookmanager->resArray[
'stats_reception'];
3243 $this->error = $this->
db->error();
3260 global $conf, $user, $hookmanager, $action;
3262 $sql =
"SELECT COUNT(DISTINCT m.fk_soc) as nb_customers, COUNT(DISTINCT m.rowid) as nb,";
3263 $sql .=
" COUNT(mp.rowid) as nb_rows, SUM(mp.qty) as qty, role";
3264 $sql .=
" FROM ".$this->db->prefix().
"mrp_production as mp";
3265 $sql .=
", ".$this->db->prefix().
"mrp_mo as m";
3266 $sql .=
" LEFT JOIN ".$this->db->prefix().
"societe as s ON s.rowid = m.fk_soc";
3267 if (empty($user->rights->societe->client->voir) && !$socid && !$forVirtualStock) {
3268 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3270 $sql .=
" WHERE m.rowid = mp.fk_mo";
3271 $sql .=
" AND m.entity IN (".getEntity($forVirtualStock && !empty($conf->global->STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE) ?
'stock' :
'mrp').
")";
3272 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3273 if (empty($user->rights->societe->client->voir) && !$socid && !$forVirtualStock) {
3274 $sql .=
" AND m.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3277 $sql .=
" AND m.fk_soc = ".((int) $socid);
3279 if ($filtrestatut <>
'') {
3280 $sql .=
" AND m.status IN (".$this->db->sanitize($filtrestatut).
")";
3282 $sql .=
" GROUP BY role";
3284 $this->stats_mrptoconsume[
'customers'] = 0;
3285 $this->stats_mrptoconsume[
'nb'] = 0;
3286 $this->stats_mrptoconsume[
'rows'] = 0;
3287 $this->stats_mrptoconsume[
'qty'] = 0;
3288 $this->stats_mrptoproduce[
'customers'] = 0;
3289 $this->stats_mrptoproduce[
'nb'] = 0;
3290 $this->stats_mrptoproduce[
'rows'] = 0;
3291 $this->stats_mrptoproduce[
'qty'] = 0;
3293 $result = $this->
db->query($sql);
3295 while ($obj = $this->
db->fetch_object($result)) {
3296 if ($obj->role ==
'toconsume') {
3297 $this->stats_mrptoconsume[
'customers'] += $obj->nb_customers;
3298 $this->stats_mrptoconsume[
'nb'] += $obj->nb;
3299 $this->stats_mrptoconsume[
'rows'] += $obj->nb_rows;
3300 $this->stats_mrptoconsume[
'qty'] += ($obj->qty ? $obj->qty : 0);
3302 if ($obj->role ==
'consumed') {
3306 $this->stats_mrptoconsume[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3308 if ($obj->role ==
'toproduce') {
3309 $this->stats_mrptoproduce[
'customers'] += $obj->nb_customers;
3310 $this->stats_mrptoproduce[
'nb'] += $obj->nb;
3311 $this->stats_mrptoproduce[
'rows'] += $obj->nb_rows;
3312 $this->stats_mrptoproduce[
'qty'] += ($obj->qty ? $obj->qty : 0);
3314 if ($obj->role ==
'produced') {
3318 $this->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3323 if ($this->stats_mrptoconsume[
'qty'] < 0) {
3324 $this->stats_mrptoconsume[
'qty'] = 0;
3326 if ($this->stats_mrptoproduce[
'qty'] < 0) {
3327 $this->stats_mrptoproduce[
'qty'] = 0;
3330 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3331 $reshook = $hookmanager->executeHooks(
'loadStatsInProduction', $parameters, $this, $action);
3333 $this->stats_mrptoproduce = $hookmanager->resArray[
'stats_mrptoproduce'];
3338 $this->error = $this->
db->error();
3353 global $conf, $user, $hookmanager, $action;
3355 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3356 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3357 $sql .=
" FROM ".$this->db->prefix().
"contratdet as cd";
3358 $sql .=
", ".$this->db->prefix().
"contrat as c";
3359 $sql .=
", ".$this->db->prefix().
"societe as s";
3360 if (empty($user->rights->societe->client->voir) && !$socid) {
3361 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3363 $sql .=
" WHERE c.rowid = cd.fk_contrat";
3364 $sql .=
" AND c.fk_soc = s.rowid";
3365 $sql .=
" AND c.entity IN (".getEntity(
'contract').
")";
3366 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3367 if (empty($user->rights->societe->client->voir) && !$socid) {
3368 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3372 $sql .=
" AND c.fk_soc = ".((int) $socid);
3375 $result = $this->
db->query($sql);
3377 $obj = $this->
db->fetch_object($result);
3378 $this->stats_contrat[
'customers'] = $obj->nb_customers;
3379 $this->stats_contrat[
'nb'] = $obj->nb;
3380 $this->stats_contrat[
'rows'] = $obj->nb_rows;
3381 $this->stats_contrat[
'qty'] = $obj->qty ? $obj->qty : 0;
3384 if (!empty($conf->global->PRODUCT_STATS_WITH_PARENT_PROD_IF_INCDEC)) {
3386 if (is_array($TFather) && !empty($TFather)) {
3387 foreach ($TFather as &$fatherData) {
3389 $pFather->id = $fatherData[
'id'];
3390 $qtyCoef = $fatherData[
'qty'];
3392 if ($fatherData[
'incdec']) {
3393 $pFather->load_stats_contrat($socid);
3395 $this->stats_contrat[
'customers'] += $pFather->stats_contrat[
'customers'];
3396 $this->stats_contrat[
'nb'] += $pFather->stats_contrat[
'nb'];
3397 $this->stats_contrat[
'rows'] += $pFather->stats_contrat[
'rows'];
3398 $this->stats_contrat[
'qty'] += $pFather->stats_contrat[
'qty'] * $qtyCoef;
3404 $parameters = array(
'socid' => $socid);
3405 $reshook = $hookmanager->executeHooks(
'loadStatsContract', $parameters, $this, $action);
3407 $this->stats_contrat = $hookmanager->resArray[
'stats_contrat'];
3412 $this->error = $this->
db->error().
' sql='.$sql;
3427 global $db, $conf, $user, $hookmanager, $action;
3429 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
3430 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(".$this->db->ifsql(
'f.type != 2',
'fd.qty',
'fd.qty * -1').
") as qty";
3431 $sql .=
" FROM ".$this->db->prefix().
"facturedet as fd";
3432 $sql .=
", ".$this->db->prefix().
"facture as f";
3433 $sql .=
", ".$this->db->prefix().
"societe as s";
3434 if (empty($user->rights->societe->client->voir) && !$socid) {
3435 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3437 $sql .=
" WHERE f.rowid = fd.fk_facture";
3438 $sql .=
" AND f.fk_soc = s.rowid";
3439 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
3440 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3441 if (empty($user->rights->societe->client->voir) && !$socid) {
3442 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3446 $sql .=
" AND f.fk_soc = ".((int) $socid);
3449 $result = $this->
db->query($sql);
3451 $obj = $this->
db->fetch_object($result);
3452 $this->stats_facture[
'customers'] = $obj->nb_customers;
3453 $this->stats_facture[
'nb'] = $obj->nb;
3454 $this->stats_facture[
'rows'] = $obj->nb_rows;
3455 $this->stats_facture[
'qty'] = $obj->qty ? $obj->qty : 0;
3458 if (!empty($conf->global->PRODUCT_STATS_WITH_PARENT_PROD_IF_INCDEC)) {
3460 if (is_array($TFather) && !empty($TFather)) {
3461 foreach ($TFather as &$fatherData) {
3463 $pFather->id = $fatherData[
'id'];
3464 $qtyCoef = $fatherData[
'qty'];
3466 if ($fatherData[
'incdec']) {
3467 $pFather->load_stats_facture($socid);
3469 $this->stats_facture[
'customers'] += $pFather->stats_facture[
'customers'];
3470 $this->stats_facture[
'nb'] += $pFather->stats_facture[
'nb'];
3471 $this->stats_facture[
'rows'] += $pFather->stats_facture[
'rows'];
3472 $this->stats_facture[
'qty'] += $pFather->stats_facture[
'qty'] * $qtyCoef;
3478 $parameters = array(
'socid' => $socid);
3479 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoice', $parameters, $this, $action);
3481 $this->stats_facture = $hookmanager->resArray[
'stats_facture'];
3486 $this->error = $this->
db->error();
3502 global $db, $conf, $user, $hookmanager;
3504 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
3505 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
3506 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facturedet_rec as fd";
3507 $sql .=
", ".MAIN_DB_PREFIX.
"facture_rec as f";
3508 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
3509 if (empty($user->rights->societe->client->voir) && !$socid) {
3510 $sql .=
", ".MAIN_DB_PREFIX.
"societe_commerciaux as sc";
3512 $sql .=
" WHERE f.rowid = fd.fk_facture";
3513 $sql .=
" AND f.fk_soc = s.rowid";
3514 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
3515 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3516 if (empty($user->rights->societe->client->voir) && !$socid) {
3517 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3521 $sql .=
" AND f.fk_soc = ".((int) $socid);
3524 $result = $this->
db->query($sql);
3526 $obj = $this->
db->fetch_object($result);
3527 $this->stats_facturerec[
'customers'] = $obj->nb_customers;
3528 $this->stats_facturerec[
'nb'] = $obj->nb;
3529 $this->stats_facturerec[
'rows'] = $obj->nb_rows;
3530 $this->stats_facturerec[
'qty'] = $obj->qty ? $obj->qty : 0;
3533 if (!empty($conf->global->PRODUCT_STATS_WITH_PARENT_PROD_IF_INCDEC)) {
3535 if (is_array($TFather) && !empty($TFather)) {
3536 foreach ($TFather as &$fatherData) {
3538 $pFather->id = $fatherData[
'id'];
3539 $qtyCoef = $fatherData[
'qty'];
3541 if ($fatherData[
'incdec']) {
3542 $pFather->load_stats_facture($socid);
3544 $this->stats_facturerec[
'customers'] += $pFather->stats_facturerec[
'customers'];
3545 $this->stats_facturerec[
'nb'] += $pFather->stats_facturerec[
'nb'];
3546 $this->stats_facturerec[
'rows'] += $pFather->stats_facturerec[
'rows'];
3547 $this->stats_facturerec[
'qty'] += $pFather->stats_facturerec[
'qty'] * $qtyCoef;
3553 $parameters = array(
'socid' => $socid);
3554 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoiceRec', $parameters, $this, $action);
3556 $this->stats_facturerec = $hookmanager->resArray[
'stats_facturerec'];
3561 $this->error = $this->
db->error();
3576 global $conf, $user, $hookmanager, $action;
3578 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
3579 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
3580 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as fd";
3581 $sql .=
", ".$this->db->prefix().
"facture_fourn as f";
3582 $sql .=
", ".$this->db->prefix().
"societe as s";
3583 if (empty($user->rights->societe->client->voir) && !$socid) {
3584 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3586 $sql .=
" WHERE f.rowid = fd.fk_facture_fourn";
3587 $sql .=
" AND f.fk_soc = s.rowid";
3588 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
3589 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3590 if (empty($user->rights->societe->client->voir) && !$socid) {
3591 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3595 $sql .=
" AND f.fk_soc = ".((int) $socid);
3598 $result = $this->
db->query($sql);
3600 $obj = $this->
db->fetch_object($result);
3601 $this->stats_facture_fournisseur[
'suppliers'] = $obj->nb_suppliers;
3602 $this->stats_facture_fournisseur[
'nb'] = $obj->nb;
3603 $this->stats_facture_fournisseur[
'rows'] = $obj->nb_rows;
3604 $this->stats_facture_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
3606 $parameters = array(
'socid' => $socid);
3607 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoice', $parameters, $this, $action);
3609 $this->stats_facture_fournisseur = $hookmanager->resArray[
'stats_facture_fournisseur'];
3614 $this->error = $this->
db->error();
3635 $num = $this->
db->num_rows(
$resql);
3638 $arr = $this->
db->fetch_array(
$resql);
3639 $keyfortab = (string) $arr[1];
3641 $keyfortab = substr($keyfortab, -2);
3644 if ($mode ==
'byunit') {
3645 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[0];
3646 } elseif ($mode ==
'bynumber') {
3647 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
3652 $this->error = $this->
db->error().
' sql='.$sql;
3657 $year = strftime(
'%Y', time());
3658 $month = strftime(
'%m', time());
3659 } elseif ($year == -1) {
3668 for ($j = 0; $j < 12; $j++) {
3670 $idx = ucfirst(
dol_trunc(
dol_print_date(
dol_mktime(12, 0, 0, $month, 1, 1970),
"%b"), 1,
'right',
'UTF-8', 1));
3673 $result[$j] = array($idx, isset($tab[$year.$month]) ? $tab[$year.$month] : 0);
3676 $month =
"0".($month - 1);
3678 $month = substr($month, 1);
3686 return array_reverse($result);
3701 public function get_nb_vente($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
3707 $sql =
"SELECT sum(d.qty), date_format(f.datef, '%Y%m')";
3708 if ($mode ==
'bynumber') {
3709 $sql .=
", count(DISTINCT f.rowid)";
3711 $sql .=
" FROM ".$this->db->prefix().
"facturedet as d, ".$this->
db->prefix().
"facture as f, ".$this->
db->prefix().
"societe as s";
3712 if ($filteronproducttype >= 0) {
3713 $sql .=
", ".$this->db->prefix().
"product as p";
3715 if (empty($user->rights->societe->client->voir) && !$socid) {
3716 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3718 $sql .=
" WHERE f.rowid = d.fk_facture";
3719 if ($this->
id > 0) {
3720 $sql .=
" AND d.fk_product = ".((int) $this->
id);
3722 $sql .=
" AND d.fk_product > 0";
3724 if ($filteronproducttype >= 0) {
3725 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
3727 $sql .=
" AND f.fk_soc = s.rowid";
3728 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
3729 if (empty($user->rights->societe->client->voir) && !$socid) {
3730 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3733 $sql .=
" AND f.fk_soc = $socid";
3735 $sql .= $morefilter;
3736 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
3737 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
3739 return $this->
_get_stats($sql, $mode, $year);
3754 public function get_nb_achat($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
3760 $sql =
"SELECT sum(d.qty), date_format(f.datef, '%Y%m')";
3761 if ($mode ==
'bynumber') {
3762 $sql .=
", count(DISTINCT f.rowid)";
3764 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as d, ".$this->
db->prefix().
"facture_fourn as f, ".$this->
db->prefix().
"societe as s";
3765 if ($filteronproducttype >= 0) {
3766 $sql .=
", ".$this->db->prefix().
"product as p";
3768 if (empty($user->rights->societe->client->voir) && !$socid) {
3769 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3771 $sql .=
" WHERE f.rowid = d.fk_facture_fourn";
3772 if ($this->
id > 0) {
3773 $sql .=
" AND d.fk_product = ".((int) $this->
id);
3775 $sql .=
" AND d.fk_product > 0";
3777 if ($filteronproducttype >= 0) {
3778 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
3780 $sql .=
" AND f.fk_soc = s.rowid";
3781 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
3782 if (empty($user->rights->societe->client->voir) && !$socid) {
3783 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3786 $sql .=
" AND f.fk_soc = $socid";
3788 $sql .= $morefilter;
3789 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
3790 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
3792 return $this->
_get_stats($sql, $mode, $year);
3806 public function get_nb_propal($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
3809 global $conf, $user;
3811 $sql =
"SELECT sum(d.qty), date_format(p.datep, '%Y%m')";
3812 if ($mode ==
'bynumber') {
3813 $sql .=
", count(DISTINCT p.rowid)";
3815 $sql .=
" FROM ".$this->db->prefix().
"propaldet as d, ".$this->
db->prefix().
"propal as p, ".$this->
db->prefix().
"societe as s";
3816 if ($filteronproducttype >= 0) {
3817 $sql .=
", ".$this->db->prefix().
"product as prod";
3819 if (empty($user->rights->societe->client->voir) && !$socid) {
3820 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3822 $sql .=
" WHERE p.rowid = d.fk_propal";
3823 if ($this->
id > 0) {
3824 $sql .=
" AND d.fk_product = ".((int) $this->
id);
3826 $sql .=
" AND d.fk_product > 0";
3828 if ($filteronproducttype >= 0) {
3829 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
3831 $sql .=
" AND p.fk_soc = s.rowid";
3832 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
3833 if (empty($user->rights->societe->client->voir) && !$socid) {
3834 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3837 $sql .=
" AND p.fk_soc = ".((int) $socid);
3839 $sql .= $morefilter;
3840 $sql .=
" GROUP BY date_format(p.datep,'%Y%m')";
3841 $sql .=
" ORDER BY date_format(p.datep,'%Y%m') DESC";
3843 return $this->
_get_stats($sql, $mode, $year);
3863 $sql =
"SELECT sum(d.qty), date_format(p.date_valid, '%Y%m')";
3864 if ($mode ==
'bynumber') {
3865 $sql .=
", count(DISTINCT p.rowid)";
3867 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as d, ".$this->
db->prefix().
"supplier_proposal as p, ".$this->
db->prefix().
"societe as s";
3868 if ($filteronproducttype >= 0) {
3869 $sql .=
", ".$this->db->prefix().
"product as prod";
3871 if (empty($user->rights->societe->client->voir) && !$socid) {
3872 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3874 $sql .=
" WHERE p.rowid = d.fk_supplier_proposal";
3875 if ($this->
id > 0) {
3876 $sql .=
" AND d.fk_product = ".((int) $this->
id);
3878 $sql .=
" AND d.fk_product > 0";
3880 if ($filteronproducttype >= 0) {
3881 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
3883 $sql .=
" AND p.fk_soc = s.rowid";
3884 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
3885 if (empty($user->rights->societe->client->voir) && !$socid) {
3886 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3889 $sql .=
" AND p.fk_soc = ".((int) $socid);
3891 $sql .= $morefilter;
3892 $sql .=
" GROUP BY date_format(p.date_valid,'%Y%m')";
3893 $sql .=
" ORDER BY date_format(p.date_valid,'%Y%m') DESC";
3895 return $this->
_get_stats($sql, $mode, $year);
3909 public function get_nb_order($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
3912 global $conf, $user;
3914 $sql =
"SELECT sum(d.qty), date_format(c.date_commande, '%Y%m')";
3915 if ($mode ==
'bynumber') {
3916 $sql .=
", count(DISTINCT c.rowid)";
3918 $sql .=
" FROM ".$this->db->prefix().
"commandedet as d, ".$this->
db->prefix().
"commande as c, ".$this->
db->prefix().
"societe as s";
3919 if ($filteronproducttype >= 0) {
3920 $sql .=
", ".$this->db->prefix().
"product as p";
3922 if (empty($user->rights->societe->client->voir) && !$socid) {
3923 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3925 $sql .=
" WHERE c.rowid = d.fk_commande";
3926 if ($this->
id > 0) {
3927 $sql .=
" AND d.fk_product = ".((int) $this->
id);
3929 $sql .=
" AND d.fk_product > 0";
3931 if ($filteronproducttype >= 0) {
3932 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
3934 $sql .=
" AND c.fk_soc = s.rowid";
3935 $sql .=
" AND c.entity IN (".getEntity(
'commande').
")";
3936 if (empty($user->rights->societe->client->voir) && !$socid) {
3937 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3940 $sql .=
" AND c.fk_soc = ".((int) $socid);
3942 $sql .= $morefilter;
3943 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
3944 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
3946 return $this->
_get_stats($sql, $mode, $year);
3963 global $conf, $user;
3965 $sql =
"SELECT sum(d.qty), date_format(c.date_commande, '%Y%m')";
3966 if ($mode ==
'bynumber') {
3967 $sql .=
", count(DISTINCT c.rowid)";
3969 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as d, ".$this->
db->prefix().
"commande_fournisseur as c, ".$this->
db->prefix().
"societe as s";
3970 if ($filteronproducttype >= 0) {
3971 $sql .=
", ".$this->db->prefix().
"product as p";
3973 if (empty($user->rights->societe->client->voir) && !$socid) {
3974 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3976 $sql .=
" WHERE c.rowid = d.fk_commande";
3977 if ($this->
id > 0) {
3978 $sql .=
" AND d.fk_product = ".((int) $this->
id);
3980 $sql .=
" AND d.fk_product > 0";
3982 if ($filteronproducttype >= 0) {
3983 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
3985 $sql .=
" AND c.fk_soc = s.rowid";
3986 $sql .=
" AND c.entity IN (".getEntity(
'supplier_order').
")";
3987 if (empty($user->rights->societe->client->voir) && !$socid) {
3988 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3991 $sql .=
" AND c.fk_soc = ".((int) $socid);
3993 $sql .= $morefilter;
3994 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
3995 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
3997 return $this->
_get_stats($sql, $mode, $year);
4011 public function get_nb_contract($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4014 global $conf, $user;
4016 $sql =
"SELECT sum(d.qty), date_format(c.date_contrat, '%Y%m')";
4017 if ($mode ==
'bynumber') {
4018 $sql .=
", count(DISTINCT c.rowid)";
4020 $sql .=
" FROM ".$this->db->prefix().
"contratdet as d, ".$this->
db->prefix().
"contrat as c, ".$this->
db->prefix().
"societe as s";
4021 if ($filteronproducttype >= 0) {
4022 $sql .=
", ".$this->db->prefix().
"product as p";
4024 if (empty($user->rights->societe->client->voir) && !$socid) {
4025 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4028 $sql .=
" WHERE c.entity IN (".getEntity(
'contract').
")";
4029 $sql .=
" AND c.rowid = d.fk_contrat";
4031 if ($this->
id > 0) {
4032 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4034 $sql .=
" AND d.fk_product > 0";
4036 if ($filteronproducttype >= 0) {
4037 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4039 $sql .=
" AND c.fk_soc = s.rowid";
4041 if (empty($user->rights->societe->client->voir) && !$socid) {
4042 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4045 $sql .=
" AND c.fk_soc = ".((int) $socid);
4047 $sql .= $morefilter;
4048 $sql .=
" GROUP BY date_format(c.date_contrat,'%Y%m')";
4049 $sql .=
" ORDER BY date_format(c.date_contrat,'%Y%m') DESC";
4051 return $this->
_get_stats($sql, $mode, $year);
4065 public function get_nb_mos($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4068 global $conf, $user;
4070 $sql =
"SELECT sum(d.qty), date_format(d.date_valid, '%Y%m')";
4071 if ($mode ==
'bynumber') {
4072 $sql .=
", count(DISTINCT d.rowid)";
4074 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as d LEFT JOIN ".$this->
db->prefix().
"societe as s ON d.fk_soc = s.rowid";
4075 if ($filteronproducttype >= 0) {
4076 $sql .=
", ".$this->db->prefix().
"product as p";
4078 if (empty($user->rights->societe->client->voir) && !$socid) {
4079 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4082 $sql .=
" WHERE d.entity IN (".getEntity(
'mo').
")";
4083 $sql .=
" AND d.status > 0";
4085 if ($this->
id > 0) {
4086 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4088 $sql .=
" AND d.fk_product > 0";
4090 if ($filteronproducttype >= 0) {
4091 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4094 if (empty($user->rights->societe->client->voir) && !$socid) {
4095 $sql .=
" AND d.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4098 $sql .=
" AND d.fk_soc = ".((int) $socid);
4100 $sql .= $morefilter;
4101 $sql .=
" GROUP BY date_format(d.date_valid,'%Y%m')";
4102 $sql .=
" ORDER BY date_format(d.date_valid,'%Y%m') DESC";
4104 return $this->
_get_stats($sql, $mode, $year);
4121 if (!is_numeric($id_pere)) {
4124 if (!is_numeric($id_fils)) {
4127 if (!is_numeric($incdec)) {
4137 $sql =
"SELECT fk_product_pere from ".$this->db->prefix().
"product_association";
4138 $sql .=
" WHERE fk_product_pere = ".((int) $id_fils).
" AND fk_product_fils = ".((int) $id_pere);
4139 if (!$this->
db->query($sql)) {
4144 $sql =
"SELECT MAX(rang) as max_rank FROM ".$this->db->prefix().
"product_association";
4145 $sql .=
" WHERE fk_product_pere = ".((int) $id_pere);
4148 $obj = $this->
db->fetch_object(
$resql);
4149 $rank = $obj->max_rank + 1;
4151 $sql =
"INSERT INTO ".$this->db->prefix().
"product_association(fk_product_pere,fk_product_fils,qty,incdec,rang)";
4152 $sql .=
" VALUES (".((int) $id_pere).
", ".((int) $id_fils).
", ".
price2num($qty,
'MS').
", ".
price2num($incdec,
'MS').
", ".((int) $rank).
")";
4153 if (! $this->
db->query($sql)) {
4180 if (!is_numeric($id_pere)) {
4183 if (!is_numeric($id_fils)) {
4186 if (!is_numeric($incdec)) {
4189 if (!is_numeric($qty)) {
4193 $sql =
'UPDATE '.$this->db->prefix().
'product_association SET ';
4194 $sql .=
'qty = '.price2num($qty,
'MS');
4195 $sql .=
',incdec = '.price2num($incdec,
'MS');
4196 $sql .=
' WHERE fk_product_pere = '.((int) $id_pere).
' AND fk_product_fils = '.((int) $id_fils);
4198 if (!$this->
db->query($sql)) {
4217 if (!is_numeric($fk_parent)) {
4220 if (!is_numeric($fk_child)) {
4224 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
4225 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
4226 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
4228 dol_syslog(get_class($this).
'::del_sousproduit', LOG_DEBUG);
4229 if (!$this->
db->query($sql)) {
4235 $sqlrank =
"SELECT rowid, rang FROM ".$this->db->prefix().
"product_association";
4236 $sqlrank.=
" WHERE fk_product_pere = ".((int) $fk_parent);
4237 $sqlrank.=
" ORDER BY rang";
4238 $resqlrank = $this->
db->query($sqlrank);
4241 while ($objrank = $this->
db->fetch_object($resqlrank)) {
4243 $sql =
"UPDATE ".$this->db->prefix().
"product_association";
4244 $sql.=
" SET rang = ".((int) $cpt);
4245 $sql.=
" WHERE rowid = ".((int) $objrank->rowid);
4246 if (! $this->
db->query($sql)) {
4266 $sql =
"SELECT fk_product_pere, qty, incdec";
4267 $sql .=
" FROM ".$this->db->prefix().
"product_association";
4268 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
4269 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
4271 $result = $this->
db->query($sql);
4273 $num = $this->
db->num_rows($result);
4276 $obj = $this->
db->fetch_object($result);
4278 $this->is_sousproduit_qty = $obj->qty;
4279 $this->is_sousproduit_incdec = $obj->incdec;
4310 dol_syslog(get_class($this).
"::add_fournisseur id_fourn = ".$id_fourn.
" ref_fourn=".
$ref_fourn.
" quantity=".$quantity, LOG_DEBUG);
4316 $sql =
"SELECT rowid, fk_product";
4317 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
4318 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
4319 $sql .=
" AND ref_fourn = '".$this->db->escape(
$ref_fourn).
"'";
4320 $sql .=
" AND fk_product <> ".((int) $this->
id);
4321 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
4325 $obj = $this->
db->fetch_object(
$resql);
4328 $this->product_id_already_linked = $obj->fk_product;
4335 $sql =
"SELECT rowid";
4336 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
4337 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
4339 $sql .=
" AND ref_fourn = '".$this->db->escape(
$ref_fourn).
"'";
4341 $sql .=
" AND (ref_fourn = '' OR ref_fourn IS NULL)";
4343 $sql .=
" AND quantity = ".((float) $quantity);
4344 $sql .=
" AND fk_product = ".((int) $this->
id);
4345 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
4349 $obj = $this->
db->fetch_object(
$resql);
4353 $sql =
"INSERT INTO ".$this->db->prefix().
"product_fournisseur_price(";
4356 $sql .=
", fk_product";
4358 $sql .=
", ref_fourn";
4359 $sql .=
", quantity";
4360 $sql .=
", fk_user";
4362 $sql .=
") VALUES (";
4363 $sql .=
"'".$this->db->idate($now).
"'";
4364 $sql .=
", ".$conf->entity;
4365 $sql .=
", ".$this->id;
4366 $sql .=
", ".$id_fourn;
4367 $sql .=
", '".$this->db->escape(
$ref_fourn).
"'";
4368 $sql .=
", ".$quantity;
4369 $sql .=
", ".$user->id;
4373 if ($this->
db->query($sql)) {
4374 $this->product_fourn_price_id = $this->
db->last_insert_id($this->
db->prefix().
"product_fournisseur_price");
4377 $this->error = $this->
db->lasterror();
4382 $this->product_fourn_price_id = $obj->rowid;
4386 $this->error = $this->
db->lasterror();
4405 $sql =
"SELECT DISTINCT p.fk_soc";
4406 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as p";
4407 $sql .=
" WHERE p.fk_product = ".((int) $this->
id);
4408 $sql .=
" AND p.entity = ".((int) $conf->entity);
4410 $result = $this->
db->query($sql);
4412 $num = $this->
db->num_rows($result);
4415 $obj = $this->
db->fetch_object($result);
4416 $list[$i] = $obj->fk_soc;
4434 global $conf, $user;
4441 $sql =
"INSERT INTO ".$this->db->prefix().
"product_price (";
4443 $sql .=
", fk_product";
4444 $sql .=
", date_price";
4445 $sql .=
", price_level";
4447 $sql .=
", price_ttc";
4448 $sql .=
", price_min";
4449 $sql .=
", price_min_ttc";
4450 $sql .=
", price_base_type";
4451 $sql .=
", default_vat_code";
4453 $sql .=
", recuperableonly";
4454 $sql .=
", localtax1_tx";
4455 $sql .=
", localtax1_type";
4456 $sql .=
", localtax2_tx";
4457 $sql .=
", localtax2_type";
4458 $sql .=
", fk_user_author";
4460 $sql .=
", price_by_qty";
4461 $sql .=
", fk_price_expression";
4462 $sql .=
", fk_multicurrency";
4463 $sql .=
", multicurrency_code";
4464 $sql .=
", multicurrency_tx";
4465 $sql .=
", multicurrency_price";
4466 $sql .=
", multicurrency_price_ttc";
4471 $sql .=
", '".$this->db->idate($now).
"'";
4472 $sql .=
", price_level";
4474 $sql .=
", price_ttc";
4475 $sql .=
", price_min";
4476 $sql .=
", price_min_ttc";
4477 $sql .=
", price_base_type";
4478 $sql .=
", default_vat_code";
4480 $sql .=
", recuperableonly";
4481 $sql .=
", localtax1_tx";
4482 $sql .=
", localtax1_type";
4483 $sql .=
", localtax2_tx";
4484 $sql .=
", localtax2_type";
4485 $sql .=
", ".$user->id;
4487 $sql .=
", price_by_qty";
4488 $sql .=
", fk_price_expression";
4489 $sql .=
", fk_multicurrency";
4490 $sql .=
", multicurrency_code";
4491 $sql .=
", multicurrency_tx";
4492 $sql .=
", multicurrency_price";
4493 $sql .=
", multicurrency_price_ttc";
4494 $sql .=
" FROM ".$this->db->prefix().
"product_price";
4495 $sql .=
" WHERE fk_product = ".((int) $fromId);
4496 $sql .=
" ORDER BY date_price DESC";
4497 if ($conf->global->PRODUIT_MULTIPRICES_LIMIT > 0) {
4498 $sql .=
" LIMIT ".$conf->global->PRODUIT_MULTIPRICES_LIMIT;
4504 $this->
db->rollback();
4508 $this->
db->commit();
4525 $sql =
'INSERT INTO '.$this->db->prefix().
'product_association (fk_product_pere, fk_product_fils, qty)';
4526 $sql .=
" SELECT ".$toId.
", fk_product_fils, qty FROM ".$this->
db->prefix().
"product_association";
4527 $sql .=
" WHERE fk_product_pere = ".((int) $fromId);
4529 dol_syslog(get_class($this).
'::clone_association', LOG_DEBUG);
4530 if (!$this->
db->query($sql)) {
4531 $this->
db->rollback();
4535 $this->
db->commit();
4568 $sql =
"INSERT ".$this->db->prefix().
"product_fournisseur_price (";
4569 $sql .=
" datec, fk_product, fk_soc, price, quantity, fk_user)";
4570 $sql .=
" SELECT '".$this->db->idate($now).
"', ".((int) $toId).
", fk_soc, price, quantity, fk_user";
4571 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
4572 $sql .=
" WHERE fk_product = ".((int) $fromId);
4574 dol_syslog(get_class($this).
'::clone_fournisseurs', LOG_DEBUG);
4577 $this->
db->rollback();
4580 $this->
db->commit();
4598 public function fetch_prod_arbo($prod, $compl_path =
'', $multiply = 1, $level = 1, $id_parent = 0, $ignore_stock_load = 0)
4601 global $conf, $langs;
4605 foreach ($prod as $id_product => $desc_pere) {
4606 if (is_array($desc_pere)) {
4607 $id = (!empty($desc_pere[0]) ? $desc_pere[0] :
'');
4608 $nb = (!empty($desc_pere[1]) ? $desc_pere[1] :
'');
4609 $type = (!empty($desc_pere[2]) ? $desc_pere[2] :
'');
4610 $label = (!empty($desc_pere[3]) ? $desc_pere[3] :
'');
4611 $incdec = (!empty($desc_pere[4]) ? $desc_pere[4] : 0);
4613 if ($multiply < 1) {
4618 if (is_null($tmpproduct)) {
4621 $tmpproduct->fetch($id);
4623 if (empty($ignore_stock_load) && ($tmpproduct->isProduct() || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) {
4624 $tmpproduct->load_stock(
'nobatch,novirtual');
4627 $this->res[] = array(
4629 'id_parent'=>$id_parent,
4630 'ref'=>$tmpproduct->ref,
4632 'nb_total'=>$nb * $multiply,
4633 'stock'=>$tmpproduct->stock_reel,
4634 'stock_alert'=>$tmpproduct->seuil_stock_alerte,
4636 'fullpath'=>$compl_path.$label,
4638 'desiredstock'=>$tmpproduct->desiredstock,
4641 'entity'=>$tmpproduct->entity
4645 if (isset($desc_pere[
'childs']) && is_array($desc_pere[
'childs'])) {
4647 $this->
fetch_prod_arbo($desc_pere[
'childs'], $compl_path.$desc_pere[3].
" -> ", $desc_pere[1] * $multiply, $level + 1, $id, $ignore_stock_load);
4665 $this->res = array();
4666 if (isset($this->sousprods) && is_array($this->sousprods)) {
4667 foreach ($this->sousprods as $prod_name => $desc_product) {
4668 if (is_array($desc_product)) {
4669 $this->
fetch_prod_arbo($desc_product,
"", $multiply, 1, $this->
id, $ignore_stock_load);
4688 $sql =
"SELECT COUNT(pa.rowid) as nb";
4689 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa";
4691 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id).
" OR pa.fk_product_pere = ".((int) $this->
id);
4692 } elseif ($mode == -1) {
4693 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id);
4694 } elseif ($mode == 1) {
4695 $sql .=
" WHERE pa.fk_product_pere = ".((int) $this->
id);
4700 $obj = $this->
db->fetch_object(
$resql);
4719 $sql =
"SELECT count(rowid) as nb FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_parent = ".((int) $this->
id);
4720 $sql .=
" AND entity IN (".getEntity(
'product').
")";
4724 $obj = $this->
db->fetch_object(
$resql);
4742 if (!empty($conf->variants->enabled)) {
4743 $sql =
"SELECT rowid FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_child = ".((int) $this->
id).
" AND entity IN (".
getEntity(
'product').
")";
4745 $query = $this->
db->query($sql);
4748 if (!$this->
db->num_rows($query)) {
4769 $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";
4770 $sql .=
", p.tosell as status, p.tobuy as status_buy";
4771 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa,";
4772 $sql .=
" ".$this->db->prefix().
"product as p";
4773 $sql .=
" WHERE p.rowid = pa.fk_product_pere";
4774 $sql .=
" AND pa.fk_product_fils = ".((int) $this->
id);
4776 $res = $this->
db->query($sql);
4779 while ($record = $this->
db->fetch_array($res)) {
4781 $prods[$record[
'id']][
'id'] = $record[
'rowid'];
4782 $prods[$record[
'id']][
'ref'] = $record[
'ref'];
4783 $prods[$record[
'id']][
'label'] = $record[
'label'];
4784 $prods[$record[
'id']][
'qty'] = $record[
'qty'];
4785 $prods[$record[
'id']][
'incdec'] = $record[
'incdec'];
4786 $prods[$record[
'id']][
'fk_product_type'] = $record[
'fk_product_type'];
4787 $prods[$record[
'id']][
'entity'] = $record[
'entity'];
4788 $prods[$record[
'id']][
'status'] = $record[
'status'];
4789 $prods[$record[
'id']][
'status_buy'] = $record[
'status_buy'];
4808 public function getChildsArbo($id, $firstlevelonly = 0, $level = 1, $parents = array())
4810 global $alreadyfound;
4816 $sql =
"SELECT p.rowid, p.ref, p.label as label, p.fk_product_type,";
4817 $sql .=
" pa.qty as qty, pa.fk_product_fils as id, pa.incdec,";
4818 $sql .=
" pa.rowid as fk_association, pa.rang";
4819 $sql .=
" FROM ".$this->db->prefix().
"product as p,";
4820 $sql .=
" ".$this->db->prefix().
"product_association as pa";
4821 $sql .=
" WHERE p.rowid = pa.fk_product_fils";
4822 $sql .=
" AND pa.fk_product_pere = ".((int) $id);
4823 $sql .=
" AND pa.fk_product_fils <> ".((int) $id);
4824 $sql.=
" ORDER BY pa.rang";
4826 dol_syslog(get_class($this).
'::getChildsArbo id='.$id.
' level='.$level.
' parents='.(is_array($parents)?implode(
',', $parents):$parents), LOG_DEBUG);
4829 $alreadyfound = array($id=>1);
4836 $res = $this->
db->query($sql);
4839 while ($rec = $this->
db->fetch_array($res)) {
4840 if (!empty($alreadyfound[$rec[
'rowid']])) {
4841 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);
4842 if (in_array($rec[
'id'], $parents)) {
4846 $alreadyfound[$rec[
'rowid']] = 1;
4847 $prods[$rec[
'rowid']] = array(
4850 2=>$rec[
'fk_product_type'],
4851 3=>$this->
db->escape($rec[
'label']),
4854 6=>$rec[
'fk_association'],
4859 if (empty($firstlevelonly)) {
4860 $listofchilds = $this->
getChildsArbo($rec[
'rowid'], 0, $level + 1, array_push($parents, $rec[
'rowid']));
4861 foreach ($listofchilds as $keyChild => $valueChild) {
4862 $prods[$rec[
'rowid']][
'childs'][$keyChild] = $valueChild;
4886 foreach ($this->
getChildsArbo($this->
id) as $keyChild => $valueChild) {
4887 $parent[$this->label][$keyChild] = $valueChild;
4889 foreach ($parent as $key => $value) {
4890 $this->sousprods[$key] = $value;
4904 public function getNomUrl($withpicto = 0, $option =
'', $maxlength = 0, $save_lastsearch_value = -1, $notooltip = 0)
4906 global $conf, $langs, $hookmanager;
4907 include_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
4909 $result =
''; $label =
'';
4911 $newref = $this->ref;
4913 $newref =
dol_trunc($newref, $maxlength,
'middle');
4916 if (!empty($this->entity)) {
4917 $tmpphoto = $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 80);
4918 if ($this->nbphoto > 0) {
4919 $label .=
'<div class="photointooltip floatright">';
4920 $label .= $tmpphoto;
4927 $label .=
img_picto(
'',
'product').
' <u class="paddingrightonly">'.$langs->trans(
"Product").
'</u>';
4929 $label .=
img_picto(
'',
'service').
' <u class="paddingrightonly">'.$langs->trans(
"Service").
'</u>';
4931 if (isset($this->status) && isset($this->status_buy)) {
4932 $label .=
' '.$this->getLibStatut(5, 0);
4933 $label .=
' '.$this->getLibStatut(5, 1);
4936 if (!empty($this->
ref)) {
4937 $label .=
'<br><b>'.$langs->trans(
'ProductRef').
':</b> '.$this->ref;
4939 if (!empty($this->label)) {
4940 $label .=
'<br><b>'.$langs->trans(
'ProductLabel').
':</b> '.$this->label;
4943 if (!empty($conf->productbatch->enabled)) {
4944 $langs->load(
"productbatch");
4945 $label .=
"<br><b>".$langs->trans(
"ManageLotSerial").
'</b>: '.$this->
getLibStatut(0, 2);
4948 if (!empty($conf->barcode->enabled)) {
4949 $label .=
'<br><b>'.$langs->trans(
'BarCode').
':</b> '.$this->barcode;
4953 if ($this->weight) {
4954 $label .=
"<br><b>".$langs->trans(
"Weight").
'</b>: '.$this->weight.
' '.
measuringUnitString(0,
"weight", $this->weight_units);
4957 if ($this->length) {
4958 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Length").
'</b>: '.$this->length.
' '.
measuringUnitString(0,
'size', $this->length_units);
4961 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Width").
'</b>: '.$this->width.
' '.
measuringUnitString(0,
'size', $this->width_units);
4963 if ($this->height) {
4964 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Height").
'</b>: '.$this->height.
' '.
measuringUnitString(0,
'size', $this->height_units);
4967 $label .=
"<br>".$labelsize;
4970 $labelsurfacevolume =
"";
4971 if ($this->surface) {
4972 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Surface").
'</b>: '.$this->surface.
' '.
measuringUnitString(0,
'surface', $this->surface_units);
4974 if ($this->volume) {
4975 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Volume").
'</b>: '.$this->volume.
' '.
measuringUnitString(0,
'volume', $this->volume_units);
4977 if ($labelsurfacevolume) {
4978 $label .=
"<br>".$labelsurfacevolume;
4981 if (!empty($this->pmp) && $this->pmp) {
4982 $label .=
"<br><b>".$langs->trans(
"PMPValue").
'</b>: '.
price($this->pmp, 0,
'', 1, -1, -1, $conf->currency);
4985 if (!empty($conf->accounting->enabled)) {
4986 if ($this->status && isset($this->accountancy_code_sell)) {
4987 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
4989 $label .=
'<br><b>'.$langs->trans(
'ProductAccountancySellCode').
':</b> '.
length_accountg($this->accountancy_code_sell);
4990 $label .=
'<br><b>'.$langs->trans(
'ProductAccountancySellIntraCode').
':</b> '.
length_accountg($this->accountancy_code_sell_intra);
4991 $label .=
'<br><b>'.$langs->trans(
'ProductAccountancySellExportCode').
':</b> '.
length_accountg($this->accountancy_code_sell_export);
4993 if ($this->status_buy && isset($this->accountancy_code_buy)) {
4994 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
4995 if (empty($this->status)) {
4998 $label .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyCode').
':</b> '.
length_accountg($this->accountancy_code_buy);
4999 $label .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyIntraCode').
':</b> '.
length_accountg($this->accountancy_code_buy_intra);
5000 $label .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyExportCode').
':</b> '.
length_accountg($this->accountancy_code_buy_export);
5005 if (empty($notooltip)) {
5006 if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
5007 $label = $langs->trans(
"ShowProduct");
5008 $linkclose .=
' alt="'.dol_escape_htmltag($label, 1).
'"';
5011 $linkclose .=
' title="'.dol_escape_htmltag($label, 1, 1).
'"';
5012 $linkclose .=
' class="nowraponall classfortooltip"';
5014 $linkclose =
' class="nowraponall"';
5017 if ($option ==
'supplier' || $option ==
'category') {
5018 $url = DOL_URL_ROOT.
'/product/fournisseurs.php?id='.$this->id;
5019 } elseif ($option ==
'stock') {
5020 $url = DOL_URL_ROOT.
'/product/stock/product.php?id='.$this->id;
5021 } elseif ($option ==
'composition') {
5022 $url = DOL_URL_ROOT.
'/product/composition/card.php?id='.$this->id;
5024 $url = DOL_URL_ROOT.
'/product/card.php?id='.$this->id;
5027 if ($option !==
'nolink') {
5029 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
5030 if ($save_lastsearch_value == -1 && preg_match(
'/list\.php/', $_SERVER[
"PHP_SELF"])) {
5031 $add_save_lastsearch_values = 1;
5033 if ($add_save_lastsearch_values) {
5034 $url .=
'&save_lastsearch_values=1';
5038 $linkstart =
'<a href="'.$url.
'"';
5039 $linkstart .= $linkclose.
'>';
5042 $result .= $linkstart;
5045 $result .= (
img_object(($notooltip ?
'' : $label),
'product', ($notooltip ?
'class="paddingright"' :
'class="paddingright classfortooltip"'), 0, 0, $notooltip ? 0 : 1));
5048 $result .= (
img_object(($notooltip ?
'' : $label),
'service', ($notooltip ?
'class="paddingright"' :
'class="paddingright classfortooltip"'), 0, 0, $notooltip ? 0 : 1));
5052 $result .= $linkend;
5055 $hookmanager->initHooks(array(
'productdao'));
5056 $parameters = array(
'id'=>$this->
id,
'getnomurl' => &$result);
5057 $reshook = $hookmanager->executeHooks(
'getNomUrl', $parameters, $this, $action);
5059 $result = $hookmanager->resPrint;
5061 $result .= $hookmanager->resPrint;
5078 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
5080 global $conf, $user, $langs;
5082 $langs->load(
"products");
5083 $outputlangs->load(
"products");
5087 if (!empty($conf->global->PRODUCT_ADDON_PDF)) {
5088 $modele = $conf->global->PRODUCT_ADDON_PDF;
5094 $modelpath =
"core/modules/product/doc/";
5096 return $this->
commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
5110 return $this->
LibStatut($this->status, $mode, $type);
5112 return $this->
LibStatut($this->status_buy, $mode, $type);
5114 return $this->
LibStatut($this->status_batch, $mode, $type);
5117 return $this->
LibStatut($this->status_buy, $mode, $type);
5133 global $conf, $langs;
5135 $labelStatus = $labelStatusShort =
'';
5137 $langs->load(
'products');
5138 if (!empty($conf->productbatch->enabled)) {
5139 $langs->load(
"productbatch");
5145 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial')));
5148 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort')));
5153 return dolGetStatus($langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch'),
'',
'', empty($status) ?
'status5' :
'status4', 3,
'dot');
5159 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'));
5163 $statuttrans = empty($status) ?
'status5' :
'status4';
5168 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSellShort');
5169 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSell');
5170 } elseif ($type == 1) {
5171 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuyShort');
5172 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuy');
5173 } elseif ($type == 2) {
5174 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch');
5175 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort');
5177 } elseif ($status == 1) {
5180 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSellShort');
5181 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSell');
5182 } elseif ($type == 1) {
5183 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBuyShort');
5184 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBuy');
5185 } elseif ($type == 2) {
5186 $labelStatus = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial'));
5187 $labelStatusShort = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort'));
5189 } elseif ( $type == 2 && $status == 2 ) {
5190 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSerial');
5191 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort');
5195 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'),
'',
'',
'status0', 0);
5197 return dolGetStatus($labelStatus, $labelStatusShort,
'', $statuttrans, $mode);
5210 $langs->load(
'products');
5212 if (isset($this->finished) && $this->finished >= 0) {
5213 $sql =
"SELECT label, code FROM ".$this->db->prefix().
"c_product_nature where code = ".((int) $this->finished).
" AND active=1";
5216 $res = $this->
db->fetch_array(
$resql);
5217 $label = $langs->trans($res[
'label']);
5221 $this->error = $this->
db->error().
' sql='.$sql;
5222 dol_syslog(__METHOD__.
' Error '.$this->error, LOG_ERR);
5248 public function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label =
'', $price = 0, $inventorycode =
'', $origin_element =
'', $origin_id =
null, $disablestockchangeforsubproduct = 0, $extrafields =
null)
5254 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
5260 $nbpiece = abs($nbpiece);
5263 $op[0] =
"+".trim($nbpiece);
5264 $op[1] =
"-".trim($nbpiece);
5267 $movementstock->setOrigin($origin_element, $origin_id);
5268 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'',
'',
'',
'',
false, 0, $disablestockchangeforsubproduct);
5272 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
5273 $movementstock->array_options = $array_options;
5274 $movementstock->insertExtraFields();
5276 $this->
db->commit();
5279 $this->error = $movementstock->error;
5280 $this->errors = $movementstock->errors;
5282 $this->
db->rollback();
5308 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)
5314 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
5320 $nbpiece = abs($nbpiece);
5323 $op[0] =
"+".trim($nbpiece);
5324 $op[1] =
"-".trim($nbpiece);
5327 $movementstock->setOrigin($origin_element, $origin_id);
5328 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'', $dlc, $dluo, $lot,
false, 0, $disablestockchangeforsubproduct);
5332 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
5333 $movementstock->array_options = $array_options;
5334 $movementstock->insertExtraFields();
5336 $this->
db->commit();
5339 $this->error = $movementstock->error;
5340 $this->errors = $movementstock->errors;
5342 $this->
db->rollback();
5360 public function load_stock($option =
'', $includedraftpoforvirtual =
null)
5365 $this->stock_reel = 0;
5366 $this->stock_warehouse = array();
5367 $this->stock_theorique = 0;
5370 $warehouseStatus = array();
5371 if (preg_match(
'/warehouseclosed/', $option)) {
5374 if (preg_match(
'/warehouseopen/', $option)) {
5377 if (preg_match(
'/warehouseinternal/', $option)) {
5378 if (!empty($conf->global->ENTREPOT_EXTRA_STATUS)) {
5385 $sql =
"SELECT ps.rowid, ps.reel, ps.fk_entrepot";
5386 $sql .=
" FROM ".$this->db->prefix().
"product_stock as ps";
5387 $sql .=
", ".$this->db->prefix().
"entrepot as w";
5388 $sql .=
" WHERE w.entity IN (".getEntity(
'stock').
")";
5389 $sql .=
" AND w.rowid = ps.fk_entrepot";
5390 $sql .=
" AND ps.fk_product = ".((int) $this->
id);
5391 if (count($warehouseStatus)) {
5392 $sql .=
" AND w.statut IN (".$this->db->sanitize(implode(
',', $warehouseStatus)).
")";
5395 $sql .=
" ORDER BY ps.reel ".(!empty($conf->global->DO_NOT_TRY_TO_DEFRAGMENT_STOCKS_WAREHOUSE)?
'DESC':
'ASC');
5397 dol_syslog(get_class($this).
"::load_stock", LOG_DEBUG);
5398 $result = $this->
db->query($sql);
5400 $num = $this->
db->num_rows($result);
5404 $row = $this->
db->fetch_object($result);
5405 $this->stock_warehouse[$row->fk_entrepot] =
new stdClass();
5406 $this->stock_warehouse[$row->fk_entrepot]->real = $row->reel;
5407 $this->stock_warehouse[$row->fk_entrepot]->id = $row->rowid;
5408 if ((!preg_match(
'/nobatch/', $option)) && $this->
hasbatch()) {
5409 $this->stock_warehouse[$row->fk_entrepot]->detail_batch =
Productbatch::findAll($this->
db, $row->rowid, 1, $this->id);
5411 $this->stock_reel += $row->reel;
5415 $this->
db->free($result);
5417 if (!preg_match(
'/novirtual/', $option)) {
5423 $this->error = $this->
db->lasterror();
5441 global $conf, $hookmanager, $action;
5443 $stock_commande_client = 0;
5444 $stock_commande_fournisseur = 0;
5445 $stock_sending_client = 0;
5446 $stock_reception_fournisseur = 0;
5447 $stock_inproduction = 0;
5451 if (!empty($conf->commande->enabled)) {
5456 $stock_commande_client = $this->stats_commande[
'qty'];
5458 if (!empty($conf->expedition->enabled)) {
5459 require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expedition.class.php';
5460 $filterShipmentStatus =
'';
5461 if (!empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT)) {
5463 } elseif (!empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)) {
5470 $stock_sending_client = $this->stats_expedition[
'qty'];
5472 if ((!empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)) || !empty($conf->supplier_order->enabled)) {
5473 $filterStatus = empty($conf->global->SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK) ?
'3,4' : $conf->global->SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK;
5474 if (isset($includedraftpoforvirtual)) {
5475 $filterStatus =
'0,1,2,'.$filterStatus;
5481 $stock_commande_fournisseur = $this->stats_commande_fournisseur[
'qty'];
5483 if (((!empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)) || !empty($conf->supplier_order->enabled) || !empty($conf->supplier_invoice->enabled)) && empty($conf->reception->enabled)) {
5485 $filterStatus =
'4';
5486 if (isset($includedraftpoforvirtual)) {
5487 $filterStatus =
'0,'.$filterStatus;
5493 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
5495 if (((!empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)) || !empty($conf->supplier_order->enabled) || !empty($conf->supplier_invoice->enabled)) && !empty($conf->reception->enabled)) {
5497 $filterStatus =
'4';
5498 if (isset($includedraftpoforvirtual)) {
5499 $filterStatus =
'0,'.$filterStatus;
5505 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
5507 if (!empty($conf->mrp->enabled)) {
5512 $stock_inproduction = $this->stats_mrptoproduce[
'qty'] - $this->stats_mrptoconsume[
'qty'];
5515 $this->stock_theorique = $this->stock_reel + $stock_inproduction;
5518 if (!empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || !empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)) {
5519 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
5520 } elseif (!empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER)) {
5521 $this->stock_theorique += 0;
5522 } elseif (!empty($conf->global->STOCK_CALCULATE_ON_BILL)) {
5523 $this->stock_theorique -= $stock_commande_client;
5526 if (!empty($conf->global->STOCK_CALCULATE_ON_RECEPTION) || !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE)) {
5527 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
5528 } elseif (!empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) {
5529 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
5530 } elseif (!empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER)) {
5531 $this->stock_theorique -= $stock_reception_fournisseur;
5532 } elseif (!empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL)) {
5533 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
5536 if (!is_object($hookmanager)) {
5537 include_once DOL_DOCUMENT_ROOT.
'/core/class/hookmanager.class.php';
5540 $hookmanager->initHooks(array(
'productdao'));
5541 $parameters = array(
'id'=>$this->
id,
'includedraftpoforvirtual' => $includedraftpoforvirtual);
5543 $reshook = $hookmanager->executeHooks(
'loadvirtualstock', $parameters, $this, $action);
5545 $this->stock_theorique = $hookmanager->resArray[
'stock_theorique'];
5563 $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";
5564 $sql .=
" WHERE pb.fk_product_stock = ps.rowid AND ps.fk_product = ".((int) $this->
id).
" AND pb.batch = '".$this->
db->escape($batch).
"'";
5565 $sql .=
" GROUP BY pb.batch, pb.eatby, pb.sellby";
5566 dol_syslog(get_class($this).
"::loadBatchInfo load first entry found for lot/serial = ".$batch, LOG_DEBUG);
5569 $num = $this->
db->num_rows(
$resql);
5572 $obj = $this->
db->fetch_object(
$resql);
5573 $result[] = array(
'batch'=>$batch,
'eatby'=>$this->
db->jdate($obj->eatby),
'sellby'=>$this->db->jdate($obj->sellby),
'qty'=>$obj->qty);
5579 $this->
db->rollback();
5597 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
5602 if (!empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO)) {
5603 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos";
5605 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product').dol_sanitizeFileName($this->
ref);
5610 $dir_osencoded = $dir;
5612 if (is_dir($dir_osencoded)) {
5613 $originImage = $dir.
'/'.$file[
'name'];
5624 if (is_numeric($result) && $result > 0) {
5641 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
5642 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
5647 if (!empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO)) {
5648 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos/";
5650 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product');
5656 if (file_exists($dir_osencoded)) {
5657 $handle = opendir($dir_osencoded);
5658 if (is_resource($handle)) {
5659 while (($file = readdir($handle)) !==
false) {
5661 $file = utf8_encode($file);
5683 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
5684 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
5690 $handle = @opendir($dir_osencoded);
5691 if (is_resource($handle)) {
5692 while (($file = readdir($handle)) !==
false) {
5694 $file = utf8_encode($file);
5701 $photo_vignette =
'';
5703 if (preg_match(
'/('.$this->regeximgext.
')$/i', $photo, $regs)) {
5704 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $photo).
'_small'.$regs[0];
5707 $dirthumb = $dir.
'thumbs/';
5711 $obj[
'photo'] = $photo;
5712 if ($photo_vignette &&
dol_is_file($dirthumb.$photo_vignette)) {
5713 $obj[
'photo_vignette'] =
'thumbs/'.$photo_vignette;
5715 $obj[
'photo_vignette'] =
"";
5718 $tabobj[$nbphoto - 1] = $obj;
5721 if ($nbmax && $nbphoto >= $nbmax) {
5743 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
5744 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
5746 $dir = dirname($file).
'/';
5747 $dirthumb = $dir.
'/thumbs/';
5748 $filename = preg_replace(
'/'.preg_quote($dir,
'/').
'/i',
'', $file);
5754 if (preg_match(
'/('.$this->regeximgext.
')$/i', $filename, $regs)) {
5755 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_small'.$regs[0];
5756 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
5760 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_mini'.$regs[0];
5761 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
5778 $infoImg = getimagesize($file_osencoded);
5779 $this->imgWidth = $infoImg[0];
5780 $this->imgHeight = $infoImg[1];
5792 global $hookmanager;
5794 $this->nb = array();
5796 $sql =
"SELECT count(p.rowid) as nb, fk_product_type";
5797 $sql .=
" FROM ".$this->db->prefix().
"product as p";
5798 $sql .=
' WHERE p.entity IN ('.getEntity($this->element, 1).
')';
5800 if (is_object($hookmanager)) {
5801 $parameters = array();
5802 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
5803 $sql .= $hookmanager->resPrint;
5805 $sql .=
' GROUP BY fk_product_type';
5809 while ($obj = $this->
db->fetch_object(
$resql)) {
5810 if ($obj->fk_product_type == 1) {
5811 $this->nb[
"services"] = $obj->nb;
5813 $this->nb[
"products"] = $obj->nb;
5820 $this->error = $this->
db->error();
5853 return ($this->mandatory_period == 1 ?
true :
false);
5870 if (!empty($conf->global->BARCODE_PRODUCT_ADDON_NUM)) {
5871 $dirsociete = array_merge(array(
'/core/modules/barcode/'), $conf->modules_parts[
'barcode']);
5872 foreach ($dirsociete as $dirroot) {
5873 $res =
dol_include_once($dirroot.$conf->global->BARCODE_PRODUCT_ADDON_NUM.
'.php');
5878 $var = $conf->global->BARCODE_PRODUCT_ADDON_NUM;
5881 $result = $mod->getNextValue($object, $type);
5883 dol_syslog(get_class($this).
"::get_barcode barcode=".$result.
" module=".$var);
5897 global $user, $langs, $conf, $mysoc;
5902 $this->specimen = 1;
5904 $this->
ref =
'PRODUCT_SPEC';
5905 $this->label =
'PRODUCT SPECIMEN';
5906 $this->
description =
'This is description of this product specimen that was created the '.dol_print_date($now,
'dayhourlog').
'.';
5907 $this->specimen = 1;
5908 $this->country_id = 1;
5912 $this->note =
'This is a comment (private)';
5913 $this->date_creation = $now;
5914 $this->date_modification = $now;
5917 $this->weight_units = 3;
5920 $this->length_units = 1;
5922 $this->width_units = 0;
5923 $this->height =
null;
5924 $this->height_units =
null;
5926 $this->surface = 30;
5927 $this->surface_units = 0;
5928 $this->volume = 300;
5929 $this->volume_units = 0;
5931 $this->barcode = -1;
5944 if (!$this->fk_unit) {
5948 $langs->load(
'products');
5950 $label_type =
'label';
5951 if ($type ==
'short') {
5952 $label_type =
'short_label';
5955 $sql =
"SELECT ".$label_type.
", code from ".$this->
db->prefix().
"c_units where rowid = ".((int) $this->fk_unit);
5959 $res = $this->
db->fetch_array(
$resql);
5960 $label = ($label_type ==
'short_label' ? $res[$label_type] :
'unit'.$res[
'code']);
5964 $this->error = $this->
db->error();
5965 dol_syslog(get_class($this).
"::getLabelOfUnit Error ".$this->error, LOG_ERR);
5977 return ($this->status_batch > 0 ?
true :
false);
5992 $maxpricesupplier = 0;
5994 if (!empty($conf->global->PRODUCT_MINIMUM_RECOMMENDED_PRICE)) {
5995 include_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.product.class.php';
5997 $product_fourn_list = $product_fourn->list_product_fournisseur_price($this->
id,
'',
'');
5999 if (is_array($product_fourn_list) && count($product_fourn_list) > 0) {
6000 foreach ($product_fourn_list as $productfourn) {
6001 if ($productfourn->fourn_unitprice > $maxpricesupplier) {
6002 $maxpricesupplier = $productfourn->fourn_unitprice;
6006 $maxpricesupplier *= $conf->global->PRODUCT_MINIMUM_RECOMMENDED_PRICE;
6010 return $maxpricesupplier;
6026 require_once DOL_DOCUMENT_ROOT.
'/categories/class/categorie.class.php';
6027 return parent::setCategoriesCommon($categories, Categorie::TYPE_PRODUCT);
6041 'product_customer_price',
6042 'product_customer_price_log'
6063 $sql =
"SELECT rowid, level, fk_level, var_percent, var_min_percent FROM ".$this->db->prefix().
"product_pricerules";
6064 $query = $this->
db->query($sql);
6068 while ($result = $this->
db->fetch_object($query)) {
6069 $rules[$result->level] = $result;
6077 for ($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) {
6078 $price = $baseprice;
6079 $price_min = $baseprice;
6083 if ($i > 1 && isset($rules[$i]->var_percent) && $rules[$i]->var_percent) {
6084 $price = $prices[$rules[$i]->fk_level] * (1 + ($rules[$i]->var_percent / 100));
6087 $prices[$i] = $price;
6090 if (isset($rules[$i]->var_min_percent) && $rules[$i]->var_min_percent) {
6091 $price_min = $price * (1 - ($rules[$i]->var_min_percent / 100));
6095 $check_amount = (($price == $this->multiprices[$i]) && ($price_min == $this->multiprices_min[$i]));
6096 $check_type = ($baseprice == $this->multiprices_base_type[$i]);
6098 if ($check_amount && $check_type) {
6102 if ($this->
updatePrice($price, $price_type, $user, $price_vat, $price_min, $i, $npr, $psq,
true) < 0) {
6120 return $user->rights->produit;
6122 return $user->rights->service;
6134 $sql =
"SELECT p.rowid, p.ref, p.datec as date_creation, p.tms as date_modification,";
6135 $sql .=
" p.fk_user_author, p.fk_user_modif";
6136 $sql .=
" FROM ".$this->db->prefix().$this->table_element.
" as p";
6137 $sql .=
" WHERE p.rowid = ".((int) $id);
6139 $result = $this->
db->query($sql);
6141 if ($this->
db->num_rows($result)) {
6142 $obj = $this->
db->fetch_object($result);
6144 $this->
id = $obj->rowid;
6146 if ($obj->fk_user_author) {
6147 $cuser =
new User($this->
db);
6148 $cuser->fetch($obj->fk_user_author);
6149 $this->user_creation = $cuser;
6152 if ($obj->fk_user_modif) {
6153 $muser =
new User($this->
db);
6154 $muser->fetch($obj->fk_user_modif);
6155 $this->user_modification = $muser;
6158 $this->
ref = $obj->ref;
6159 $this->date_creation = $this->
db->jdate($obj->date_creation);
6160 $this->date_modification = $this->
db->jdate($obj->date_modification);
6163 $this->
db->free($result);
6178 public $picto =
'service';