39require_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
40require_once DOL_DOCUMENT_ROOT.
'/core/class/commonobject.class.php';
41require_once DOL_DOCUMENT_ROOT.
'/product/class/productbatch.class.php';
42require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/productlot.class.php';
43require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/entrepot.class.php';
53 public $element =
'product';
58 public $table_element =
'product';
63 public $fk_element =
'fk_product';
68 protected $childtables = array(
69 'supplier_proposaldet' => array(
'name' =>
'SupplierProposal',
'parent' =>
'supplier_proposal',
'parentkey' =>
'fk_supplier_proposal'),
70 'propaldet' => array(
'name' =>
'Proposal',
'parent' =>
'propal',
'parentkey' =>
'fk_propal'),
71 'commandedet' => array(
'name' =>
'Order',
'parent' =>
'commande',
'parentkey' =>
'fk_commande'),
72 'facturedet' => array(
'name' =>
'Invoice',
'parent' =>
'facture',
'parentkey' =>
'fk_facture'),
73 'contratdet' => array(
'name' =>
'Contract',
'parent' =>
'contrat',
'parentkey' =>
'fk_contrat'),
74 'facture_fourn_det' => array(
'name' =>
'SupplierInvoice',
'parent' =>
'facture_fourn',
'parentkey' =>
'fk_facture_fourn'),
75 'commande_fournisseurdet' => array(
'name' =>
'SupplierOrder',
'parent' =>
'commande_fournisseur',
'parentkey' =>
'fk_commande'),
76 'mrp_production' => array(
'name' =>
'Mo',
'parent' =>
'mrp_mo',
'parentkey' =>
'fk_mo' ),
77 'bom_bom' => array(
'name' =>
'BOM'),
78 'bom_bomline' => array(
'name' =>
'BOMLine',
'parent' =>
'bom_bom',
'parentkey' =>
'fk_bom'),
86 public $ismultientitymanaged = 1;
91 public $isextrafieldmanaged = 1;
96 public $picto =
'product';
103 public $regeximgext =
'\.gif|\.jpg|\.jpeg|\.png|\.bmp|\.webp|\.xpm|\.xbm';
146 public $price_formated;
155 public $price_ttc_formated;
169 public $price_min_ttc;
175 public $price_base_type;
179 public $multiprices_ttc = array();
180 public $multiprices_base_type = array();
181 public $multiprices_default_vat_code = array();
182 public $multiprices_min = array();
183 public $multiprices_min_ttc = array();
184 public $multiprices_tva_tx = array();
185 public $multiprices_recuperableonly = array();
189 public $prices_by_qty = array();
190 public $prices_by_qty_id = array();
191 public $prices_by_qty_list = array();
217 public $localtax2_tx;
218 public $localtax1_type;
219 public $localtax2_type;
223 public $desc_supplier;
224 public $vatrate_supplier;
225 public $default_vat_code_supplier;
226 public $fourn_multicurrency_price;
227 public $fourn_multicurrency_unitprice;
228 public $fourn_multicurrency_tx;
229 public $fourn_multicurrency_id;
230 public $fourn_multicurrency_code;
236 public $qc_frequency;
243 public $stock_reel = 0;
250 public $stock_theorique;
271 public $seuil_stock_alerte = 0;
316 public $status_buy = 0;
338 public $fk_default_bom;
345 public $product_fourn_price_id;
367 public $status_batch = 0;
374 public $batch_mask =
'';
392 public $weight_units;
394 public $length_units;
398 public $height_units;
400 public $surface_units;
402 public $volume_units;
405 public $net_measure_units;
407 public $accountancy_code_sell;
408 public $accountancy_code_sell_intra;
409 public $accountancy_code_sell_export;
410 public $accountancy_code_buy;
411 public $accountancy_code_buy_intra;
412 public $accountancy_code_buy_export;
422 public $barcode_type;
427 public $barcode_type_code;
429 public $stats_propale = array();
430 public $stats_commande = array();
431 public $stats_contrat = array();
432 public $stats_facture = array();
433 public $stats_proposal_supplier = array();
434 public $stats_commande_fournisseur = array();
435 public $stats_expedition = array();
436 public $stats_reception = array();
437 public $stats_mo = array();
438 public $stats_bom = array();
439 public $stats_mrptoconsume = array();
440 public $stats_mrptoproduce = array();
441 public $stats_facturerec = array();
442 public $stats_facture_fournisseur = array();
451 public $date_creation;
456 public $date_modification;
472 public $fk_default_warehouse;
476 public $fk_price_expression;
481 public $fourn_price_base_type;
493 public $ref_supplier;
507 public $price_autogen = 0;
514 public $supplierprices;
521 public $sousprods = array();
534 public $is_object_used;
536 public $is_sousproduit_qty;
537 public $is_sousproduit_incdec;
539 public $mandatory_period;
570 public $fields = array(
571 'rowid' => array(
'type'=>
'integer',
'label'=>
'TechnicalID',
'enabled'=>1,
'visible'=>-2,
'notnull'=>1,
'index'=>1,
'position'=>1,
'comment'=>
'Id'),
572 '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'),
573 'entity' =>array(
'type'=>
'integer',
'label'=>
'Entity',
'enabled'=>1,
'visible'=>0,
'default'=>1,
'notnull'=>1,
'index'=>1,
'position'=>5),
574 'label' =>array(
'type'=>
'varchar(255)',
'label'=>
'Label',
'enabled'=>1,
'visible'=>1,
'notnull'=>1,
'showoncombobox'=>2,
'position'=>15,
'csslist'=>
'tdoverflowmax250'),
575 'barcode' =>array(
'type'=>
'varchar(255)',
'label'=>
'Barcode',
'enabled'=>
'isModEnabled("barcode")',
'position'=>20,
'visible'=>-1,
'showoncombobox'=>3),
576 'fk_barcode_type' => array(
'type'=>
'integer',
'label'=>
'BarcodeType',
'enabled'=>
'1',
'position'=>21,
'notnull'=>0,
'visible'=>-1,),
577 'note_public' =>array(
'type'=>
'html',
'label'=>
'NotePublic',
'enabled'=>1,
'visible'=>0,
'position'=>61),
578 'note' =>array(
'type'=>
'html',
'label'=>
'NotePrivate',
'enabled'=>1,
'visible'=>0,
'position'=>62),
579 'datec' =>array(
'type'=>
'datetime',
'label'=>
'DateCreation',
'enabled'=>1,
'visible'=>-2,
'notnull'=>1,
'position'=>500),
580 'tms' =>array(
'type'=>
'timestamp',
'label'=>
'DateModification',
'enabled'=>1,
'visible'=>-2,
'notnull'=>1,
'position'=>501),
582 'fk_user_author'=>array(
'type'=>
'integer',
'label'=>
'UserAuthor',
'enabled'=>1,
'visible'=>-2,
'notnull'=>1,
'position'=>510,
'foreignkey'=>
'llx_user.rowid'),
583 'fk_user_modif' =>array(
'type'=>
'integer',
'label'=>
'UserModif',
'enabled'=>1,
'visible'=>-2,
'notnull'=>-1,
'position'=>511),
585 'localtax1_tx' => array(
'type'=>
'double(6,3)',
'label'=>
'Localtax1tx',
'enabled'=>
'1',
'position'=>150,
'notnull'=>0,
'visible'=>-1,),
586 'localtax1_type' => array(
'type'=>
'varchar(10)',
'label'=>
'Localtax1type',
'enabled'=>
'1',
'position'=>155,
'notnull'=>1,
'visible'=>-1,),
587 'localtax2_tx' => array(
'type'=>
'double(6,3)',
'label'=>
'Localtax2tx',
'enabled'=>
'1',
'position'=>160,
'notnull'=>0,
'visible'=>-1,),
588 'localtax2_type' => array(
'type'=>
'varchar(10)',
'label'=>
'Localtax2type',
'enabled'=>
'1',
'position'=>165,
'notnull'=>1,
'visible'=>-1,),
589 'import_key' =>array(
'type'=>
'varchar(14)',
'label'=>
'ImportId',
'enabled'=>1,
'visible'=>-2,
'notnull'=>-1,
'index'=>0,
'position'=>1000),
592 'mandatory_period' => array(
'type'=>
'integer',
'label'=>
'mandatoryperiod',
'enabled'=>1,
'visible'=>1,
'notnull'=>1,
'default'=>0,
'index'=>1,
'position'=>1000),
608 const SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY = 1;
609 const SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY = 2;
610 const SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT = 3;
632 $this->
ref = trim($this->
ref);
660 public function create($user, $notrigger = 0)
662 global $conf, $langs;
668 $this->
ref = trim($this->
ref);
672 $this->label = trim($this->label);
673 $this->price_ttc =
price2num($this->price_ttc);
675 $this->price_min_ttc =
price2num($this->price_min_ttc);
676 $this->price_min =
price2num($this->price_min);
677 if (empty($this->tva_tx)) {
680 if (empty($this->tva_npr)) {
684 if (empty($this->localtax1_tx)) {
685 $this->localtax1_tx = 0;
687 if (empty($this->localtax2_tx)) {
688 $this->localtax2_tx = 0;
690 if (empty($this->localtax1_type)) {
691 $this->localtax1_type =
'0';
693 if (empty($this->localtax2_type)) {
694 $this->localtax2_type =
'0';
696 if (empty($this->
price)) {
699 if (empty($this->price_min)) {
700 $this->price_min = 0;
703 if (empty($this->price_by_qty)) {
704 $this->price_by_qty = 0;
707 if (empty($this->
status)) {
710 if (empty($this->status_buy)) {
711 $this->status_buy = 0;
720 if ($this->price_base_type ==
'TTC' && $this->price_ttc > 0) {
721 $price_ttc =
price2num($this->price_ttc,
'MU');
722 $price_ht =
price2num($this->price_ttc / (1 + ($this->tva_tx / 100)),
'MU');
726 if ($this->price_base_type !=
'TTC' && $this->
price > 0) {
728 $price_ttc =
price2num($this->
price * (1 + ($this->tva_tx / 100)),
'MU');
732 if (($this->price_min_ttc > 0) && ($this->price_base_type ==
'TTC')) {
733 $price_min_ttc =
price2num($this->price_min_ttc,
'MU');
734 $price_min_ht =
price2num($this->price_min_ttc / (1 + ($this->tva_tx / 100)),
'MU');
738 if (($this->price_min > 0) && ($this->price_base_type !=
'TTC')) {
739 $price_min_ht =
price2num($this->price_min,
'MU');
740 $price_min_ttc =
price2num($this->price_min * (1 + ($this->tva_tx / 100)),
'MU');
743 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
744 $this->accountancy_code_buy_intra = trim($this->accountancy_code_buy_intra);
745 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
746 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
747 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
748 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
751 $this->barcode = trim($this->barcode);
752 $this->mandatory_period = empty($this->mandatory_period) ? 0 : $this->mandatory_period;
754 if (empty($this->label)) {
755 $this->error =
'ErrorMandatoryParametersNotProvided';
759 if (empty($this->
ref) || $this->
ref ==
'auto') {
762 if ($module !=
'mod_codeproduct_leopard') {
763 if (substr($module, 0, 16) ==
'mod_codeproduct_' && substr($module, -3) ==
'php') {
764 $module = substr($module, 0,
dol_strlen($module) - 4);
767 $modCodeProduct =
new $module();
768 if (!empty($modCodeProduct->code_auto)) {
769 $this->
ref = $modCodeProduct->getNextValue($this, $this->
type);
771 unset($modCodeProduct);
774 if (empty($this->
ref)) {
775 $this->error =
'ProductModuleNotSetupForAutoRef';
780 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);
787 if ($this->barcode == -1) {
788 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
793 $result = $this->
verify();
796 $sql =
"SELECT count(*) as nb";
797 $sql .=
" FROM ".$this->db->prefix().
"product";
798 $sql .=
" WHERE entity IN (".getEntity(
'product').
")";
799 $sql .=
" AND ref = '".$this->db->escape($this->
ref).
"'";
801 $result = $this->db->query($sql);
803 $obj = $this->db->fetch_object($result);
806 $sql =
"INSERT INTO ".$this->db->prefix().
"product (";
811 $sql .=
", price_min";
812 $sql .=
", price_min_ttc";
814 $sql .=
", fk_user_author";
815 $sql .=
", fk_product_type";
817 $sql .=
", price_ttc";
818 $sql .=
", price_base_type";
822 $sql .=
", accountancy_code_buy";
823 $sql .=
", accountancy_code_buy_intra";
824 $sql .=
", accountancy_code_buy_export";
825 $sql .=
", accountancy_code_sell";
826 $sql .=
", accountancy_code_sell_intra";
827 $sql .=
", accountancy_code_sell_export";
830 $sql .=
", finished";
832 $sql .=
", batch_mask";
834 $sql .=
", mandatory_period";
835 $sql .=
") VALUES (";
836 $sql .=
"'".$this->db->idate($now).
"'";
837 $sql .=
", ".(!empty($this->entity) ? (int) $this->entity : (int) $conf->entity);
838 $sql .=
", '".$this->db->escape($this->
ref).
"'";
839 $sql .=
", ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
840 $sql .=
", ".price2num($price_min_ht);
841 $sql .=
", ".price2num($price_min_ttc);
842 $sql .=
", ".(!empty($this->label) ?
"'".$this->db->escape($this->label).
"'" :
"null");
843 $sql .=
", ".((int) $user->id);
844 $sql .=
", ".((int) $this->
type);
845 $sql .=
", ".price2num($price_ht,
'MT');
846 $sql .=
", ".price2num($price_ttc,
'MT');
847 $sql .=
", '".$this->db->escape($this->price_base_type).
"'";
848 $sql .=
", ".((int) $this->
status);
849 $sql .=
", ".((int) $this->status_buy);
851 $sql .=
", '".$this->db->escape($this->accountancy_code_buy).
"'";
852 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_intra).
"'";
853 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_export).
"'";
854 $sql .=
", '".$this->db->escape($this->accountancy_code_sell).
"'";
855 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_intra).
"'";
856 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_export).
"'";
858 $sql .=
", '".$this->db->escape($this->canvas).
"'";
859 $sql .=
", ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
'NULL' : (int) $this->finished);
860 $sql .=
", ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : ((int) $this->status_batch));
861 $sql .=
", '".$this->db->escape($this->batch_mask).
"'";
862 $sql .=
", ".($this->fk_unit > 0 ? ((int) $this->fk_unit) :
'NULL');
863 $sql .=
", '".$this->db->escape($this->mandatory_period).
"'";
866 dol_syslog(get_class($this).
"::Create", LOG_DEBUG);
867 $result = $this->db->query($sql);
869 $id = $this->db->last_insert_id($this->db->prefix().
"product");
873 $this->
price = $price_ht;
874 $this->price_ttc = $price_ttc;
875 $this->price_min = $price_min_ht;
876 $this->price_min_ttc = $price_min_ttc;
880 if ($this->
update($id, $user,
true,
'add') <= 0) {
885 $this->error = $this->db->lasterror();
890 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " .((int) $this->id) .
" AND entity = " . ((
int) $conf->entity));
892 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
893 $sql .=
" fk_product";
895 $sql .=
", accountancy_code_buy";
896 $sql .=
", accountancy_code_buy_intra";
897 $sql .=
", accountancy_code_buy_export";
898 $sql .=
", accountancy_code_sell";
899 $sql .=
", accountancy_code_sell_intra";
900 $sql .=
", accountancy_code_sell_export";
901 $sql .=
") VALUES (";
903 $sql .=
", " . $conf->entity;
904 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
905 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
906 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
907 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
908 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
909 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
911 $result = $this->db->query($sql);
914 $this->error =
'ErrorFailedToInsertAccountancyForEntity';
919 $this->error =
'ErrorFailedToGetInsertedId';
923 $this->error = $this->db->lasterror();
927 $langs->load(
"products");
929 $this->error =
"ErrorProductAlreadyExists";
930 dol_syslog(get_class($this).
"::Create fails, ref ".$this->
ref.
" already exists");
934 $this->error = $this->db->lasterror();
937 if (!$error && !$notrigger) {
950 $this->db->rollback();
954 $this->db->rollback();
955 dol_syslog(get_class($this).
"::Create fails verify ".join(
',', $this->errors), LOG_WARNING);
971 $this->errors = array();
974 $this->
ref = trim($this->
ref);
977 $this->errors[] =
'ErrorBadRef';
981 $arrayofnonnegativevalue = array(
'weight'=>
'Weight',
'width'=>
'Width',
'height'=>
'Height',
'length'=>
'Length',
'surface'=>
'Surface',
'volume'=>
'Volume');
982 foreach ($arrayofnonnegativevalue as $key => $value) {
983 if (property_exists($this, $key) && !empty($this->$key) && ($this->$key < 0)) {
984 $langs->loadLangs(array(
"main",
"other"));
985 $this->error = $langs->trans(
"FieldCannotBeNegative", $langs->transnoentitiesnoconv($value));
986 $this->errors[] = $this->error;
991 $rescode = $this->
check_barcode($this->barcode, $this->barcode_type_code);
993 if ($rescode == -1) {
994 $this->errors[] =
'ErrorBadBarCodeSyntax';
995 } elseif ($rescode == -2) {
996 $this->errors[] =
'ErrorBarCodeRequired';
997 } elseif ($rescode == -3) {
999 $this->errors[] =
'ErrorBarCodeAlreadyUsed';
1024 $module = strtolower($conf->global->BARCODE_PRODUCT_ADDON_NUM);
1026 $dirsociete = array_merge(array(
'/core/modules/barcode/'), $conf->modules_parts[
'barcode']);
1027 foreach ($dirsociete as $dirroot) {
1034 $mod =
new $module();
1036 dol_syslog(get_class($this).
"::check_barcode value=".$valuetotest.
" type=".$typefortest.
" module=".$module);
1037 $result = $mod->verif($this->db, $valuetotest, $this, 0, $typefortest);
1055 public function update($id, $user, $notrigger =
false, $action =
'update', $updatetype =
false)
1057 global $langs, $conf, $hookmanager;
1062 if (!$this->label) {
1063 $this->label =
'MISSING LABEL';
1068 $this->
ref = trim($this->
ref);
1072 $this->label = trim($this->label);
1074 $this->note_private = (isset($this->note_private) ? trim($this->note_private) :
null);
1075 $this->note_public = (isset($this->note_public) ? trim($this->note_public) :
null);
1076 $this->net_measure =
price2num($this->net_measure);
1077 $this->net_measure_units = trim($this->net_measure_units);
1078 $this->weight =
price2num($this->weight);
1079 $this->weight_units = trim($this->weight_units);
1080 $this->length =
price2num($this->length);
1081 $this->length_units = trim($this->length_units);
1083 $this->width_units = trim($this->width_units);
1084 $this->height =
price2num($this->height);
1085 $this->height_units = trim($this->height_units);
1086 $this->surface =
price2num($this->surface);
1087 $this->surface_units = trim($this->surface_units);
1088 $this->volume =
price2num($this->volume);
1089 $this->volume_units = trim($this->volume_units);
1092 if (is_numeric($this->length_units)) {
1093 $this->width_units = $this->length_units;
1095 if (is_numeric($this->length_units)) {
1096 $this->height_units = $this->length_units;
1100 if (empty($this->surface) && !empty($this->length) && !empty($this->width) && $this->length_units == $this->width_units) {
1101 $this->surface = $this->length * $this->width;
1104 if (empty($this->volume) && !empty($this->surface) && !empty($this->height) && $this->length_units == $this->height_units) {
1105 $this->volume = $this->surface * $this->height;
1109 if (empty($this->tva_tx)) {
1112 if (empty($this->tva_npr)) {
1115 if (empty($this->localtax1_tx)) {
1116 $this->localtax1_tx = 0;
1118 if (empty($this->localtax2_tx)) {
1119 $this->localtax2_tx = 0;
1121 if (empty($this->localtax1_type)) {
1122 $this->localtax1_type =
'0';
1124 if (empty($this->localtax2_type)) {
1125 $this->localtax2_type =
'0';
1127 if (empty($this->
status)) {
1130 if (empty($this->status_buy)) {
1131 $this->status_buy = 0;
1134 if (empty($this->country_id)) {
1135 $this->country_id = 0;
1138 if (empty($this->state_id)) {
1139 $this->state_id = 0;
1143 $this->barcode = trim($this->barcode);
1145 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
1146 $this->accountancy_code_buy_intra = trim($this->accountancy_code_buy_intra);
1147 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
1148 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
1149 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
1150 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
1157 if ($action !=
'add') {
1158 $result = $this->
verify();
1166 if (empty($this->oldcopy)) {
1171 if ($this->
hasbatch() && !$this->oldcopy->hasbatch()) {
1173 $valueforundefinedlot =
'000000';
1175 $valueforundefinedlot = $conf->global->STOCK_DEFAULT_BATCH;
1178 dol_syslog(
"Flag batch of product id=".$this->
id.
" is set to ON, so we will create missing records into product_batch");
1181 foreach ($this->stock_warehouse as $idW => $ObjW) {
1183 foreach ($ObjW->detail_batch as $detail) {
1184 if ($detail->batch == $valueforundefinedlot || $detail->batch ==
'Undefined') {
1186 $sqlclean =
"DELETE FROM ".$this->db->prefix().
"product_batch WHERE batch in('Undefined', '".$this->db->escape($valueforundefinedlot).
"') AND fk_product_stock = ".((int) $ObjW->id);
1187 $result = $this->db->query($sqlclean);
1195 $qty_batch += $detail->qty;
1199 if ($ObjW->real != $qty_batch) {
1201 $ObjBatch->batch = $valueforundefinedlot;
1202 $ObjBatch->qty = ($ObjW->real - $qty_batch);
1203 $ObjBatch->fk_product_stock = $ObjW->id;
1205 if ($ObjBatch->create($user, 1) < 0) {
1207 $this->errors = $ObjBatch->errors;
1211 if ($ObjLot->fetch(0, $this->id, $valueforundefinedlot) == 0) {
1212 $ObjLot->fk_product = $this->id;
1213 $ObjLot->entity = $this->entity;
1214 $ObjLot->fk_user_creat = $user->id;
1215 $ObjLot->batch = $valueforundefinedlot;
1216 if ($ObjLot->create($user,
true) < 0) {
1218 $this->errors = $ObjLot->errors;
1227 if ($this->barcode == -1) {
1228 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1231 $sql =
"UPDATE ".$this->db->prefix().
"product";
1232 $sql .=
" SET label = '".$this->db->escape($this->label).
"'";
1235 $sql .=
", fk_product_type = ".((int) $this->
type);
1238 $sql .=
", ref = '".$this->db->escape($this->
ref).
"'";
1239 $sql .=
", ref_ext = ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1240 $sql .=
", default_vat_code = ".($this->default_vat_code ?
"'".$this->db->escape($this->default_vat_code).
"'" :
"null");
1241 $sql .=
", tva_tx = ".((float) $this->tva_tx);
1242 $sql .=
", recuperableonly = ".((int) $this->tva_npr);
1243 $sql .=
", localtax1_tx = ".((float) $this->localtax1_tx);
1244 $sql .=
", localtax2_tx = ".((float) $this->localtax2_tx);
1245 $sql .=
", localtax1_type = ".($this->localtax1_type !=
'' ?
"'".$this->db->escape($this->localtax1_type).
"'" :
"'0'");
1246 $sql .=
", localtax2_type = ".($this->localtax2_type !=
'' ?
"'".$this->db->escape($this->localtax2_type).
"'" :
"'0'");
1248 $sql .=
", barcode = ".(empty($this->barcode) ?
"null" :
"'".$this->db->escape($this->barcode).
"'");
1249 $sql .=
", fk_barcode_type = ".(empty($this->barcode_type) ?
"null" : $this->db->escape($this->barcode_type));
1251 $sql .=
", tosell = ".(int) $this->
status;
1252 $sql .=
", tobuy = ".(int) $this->status_buy;
1253 $sql .=
", tobatch = ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : (int) $this->status_batch);
1254 $sql .=
", batch_mask = '".$this->db->escape($this->batch_mask).
"'";
1256 $sql .=
", finished = ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
"null" : (int) $this->finished);
1257 $sql .=
", fk_default_bom = ".((!isset($this->fk_default_bom) || $this->fk_default_bom < 0 || $this->fk_default_bom ==
'') ?
"null" : (int) $this->fk_default_bom);
1258 $sql .=
", net_measure = ".($this->net_measure !=
'' ?
"'".$this->db->escape($this->net_measure).
"'" :
'null');
1259 $sql .=
", net_measure_units = ".($this->net_measure_units !=
'' ?
"'".$this->db->escape($this->net_measure_units).
"'" :
'null');
1260 $sql .=
", weight = ".($this->weight !=
'' ?
"'".$this->db->escape($this->weight).
"'" :
'null');
1261 $sql .=
", weight_units = ".($this->weight_units !=
'' ?
"'".$this->db->escape($this->weight_units).
"'" :
'null');
1262 $sql .=
", length = ".($this->length !=
'' ?
"'".$this->db->escape($this->length).
"'" :
'null');
1263 $sql .=
", length_units = ".($this->length_units !=
'' ?
"'".$this->db->escape($this->length_units).
"'" :
'null');
1264 $sql .=
", width= ".($this->width !=
'' ?
"'".$this->db->escape($this->width).
"'" :
'null');
1265 $sql .=
", width_units = ".($this->width_units !=
'' ?
"'".$this->db->escape($this->width_units).
"'" :
'null');
1266 $sql .=
", height = ".($this->height !=
'' ?
"'".$this->db->escape($this->height).
"'" :
'null');
1267 $sql .=
", height_units = ".($this->height_units !=
'' ?
"'".$this->db->escape($this->height_units).
"'" :
'null');
1268 $sql .=
", surface = ".($this->surface !=
'' ?
"'".$this->db->escape($this->surface).
"'" :
'null');
1269 $sql .=
", surface_units = ".($this->surface_units !=
'' ?
"'".$this->db->escape($this->surface_units).
"'" :
'null');
1270 $sql .=
", volume = ".($this->volume !=
'' ?
"'".$this->db->escape($this->volume).
"'" :
'null');
1271 $sql .=
", volume_units = ".($this->volume_units !=
'' ?
"'".$this->db->escape($this->volume_units).
"'" :
'null');
1272 $sql .=
", fk_default_warehouse = ".($this->fk_default_warehouse > 0 ? ((int) $this->fk_default_warehouse) :
'null');
1273 $sql .=
", fk_default_workstation = ".($this->fk_default_workstation > 0 ? ((int) $this->fk_default_workstation) :
'null');
1274 $sql .=
", seuil_stock_alerte = ".((isset($this->seuil_stock_alerte) && is_numeric($this->seuil_stock_alerte)) ? (
float) $this->seuil_stock_alerte :
'null');
1275 $sql .=
", description = '".$this->db->escape($this->
description).
"'";
1276 $sql .=
", url = ".($this->url ?
"'".$this->db->escape($this->url).
"'" :
'null');
1277 $sql .=
", customcode = '".$this->db->escape($this->customcode).
"'";
1278 $sql .=
", fk_country = ".($this->country_id > 0 ? (int) $this->country_id :
'null');
1279 $sql .=
", fk_state = ".($this->state_id > 0 ? (int) $this->state_id :
'null');
1280 $sql .=
", lifetime = ".($this->lifetime > 0 ? (int) $this->lifetime :
'null');
1281 $sql .=
", qc_frequency = ".($this->qc_frequency > 0 ? (int) $this->qc_frequency :
'null');
1282 $sql .=
", note = ".(isset($this->note_private) ?
"'".$this->db->escape($this->note_private).
"'" :
'null');
1283 $sql .=
", note_public = ".(isset($this->note_public) ?
"'".$this->db->escape($this->note_public).
"'" :
'null');
1284 $sql .=
", duration = '".$this->db->escape($this->duration_value.$this->duration_unit).
"'";
1286 $sql .=
", accountancy_code_buy = '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1287 $sql .=
", accountancy_code_buy_intra = '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1288 $sql .=
", accountancy_code_buy_export = '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1289 $sql .=
", accountancy_code_sell= '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1290 $sql .=
", accountancy_code_sell_intra= '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1291 $sql .=
", accountancy_code_sell_export= '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1293 $sql .=
", desiredstock = ".((isset($this->desiredstock) && is_numeric($this->desiredstock)) ? (
float) $this->desiredstock :
"null");
1294 $sql .=
", cost_price = ".($this->cost_price !=
'' ? $this->db->escape($this->cost_price) :
'null');
1295 $sql .=
", fk_unit= ".(!$this->fk_unit ?
'NULL' : (int) $this->fk_unit);
1296 $sql .=
", price_autogen = ".(!$this->price_autogen ? 0 : 1);
1297 $sql .=
", fk_price_expression = ".($this->fk_price_expression != 0 ? (int) $this->fk_price_expression :
'NULL');
1298 $sql .=
", fk_user_modif = ".($user->id > 0 ? $user->id :
'NULL');
1299 $sql .=
", mandatory_period = ".($this->mandatory_period);
1301 $sql .=
" WHERE rowid = ".((int) $id);
1303 dol_syslog(get_class($this).
"::update", LOG_DEBUG);
1305 $resql = $this->db->query($sql);
1320 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " . ((
int) $this->id) .
" AND entity = " . ((
int) $conf->entity));
1322 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1323 $sql .=
" fk_product";
1325 $sql .=
", accountancy_code_buy";
1326 $sql .=
", accountancy_code_buy_intra";
1327 $sql .=
", accountancy_code_buy_export";
1328 $sql .=
", accountancy_code_sell";
1329 $sql .=
", accountancy_code_sell_intra";
1330 $sql .=
", accountancy_code_sell_export";
1331 $sql .=
") VALUES (";
1333 $sql .=
", " . $conf->entity;
1334 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1335 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1336 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1337 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1338 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1339 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1341 $result = $this->db->query($sql);
1344 $this->error =
'ErrorFailedToUpdateAccountancyForEntity';
1348 if (!$this->
hasbatch() && $this->oldcopy->hasbatch()) {
1350 $sql =
'SELECT pb.qty, ps.fk_entrepot, pb.batch FROM '.MAIN_DB_PREFIX.
'product_batch as pb';
1351 $sql.=
' INNER JOIN '.MAIN_DB_PREFIX.
'product_stock as ps ON (ps.rowid = pb.fk_product_stock)';
1352 $sql.=
' WHERE ps.fk_product = '.(int) $this->
id;
1354 $resql = $this->db->query($sql);
1358 while ($obj = $this->db->fetch_object($resql)) {
1360 $fk_entrepot = $obj->fk_entrepot;
1364 $batch = $obj->batch;
1367 $addOremove = $value > 0 ? 1 : 0;
1368 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1369 $res = $this->
correct_stock_batch($user, $fk_entrepot, abs($value), $addOremove, $label, $price, $dlc, $dluo, $batch, $inventorycode,
'',
null, 0,
null,
true);
1372 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1373 $res = $this->
correct_stock($user, $fk_entrepot, abs($value), (
int) empty($addOremove), $label, $price, $inventorycode,
'',
null, 0);
1392 if (!$error && !$notrigger) {
1394 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
1401 if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) {
1403 if ($conf->product->dir_output) {
1406 if (file_exists($olddir)) {
1410 $res = @rename($olddir, $newdir);
1412 $langs->load(
"errors");
1413 $this->error = $langs->trans(
'ErrorFailToRenameDir', $olddir, $newdir);
1421 if (isModEnabled(
'variants')) {
1422 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1426 foreach ($comb->fetchAllByFkProductParent($this->id) as $currcomb) {
1427 $currcomb->updateProperties($this, $user);
1431 $this->db->commit();
1434 $this->db->rollback();
1438 if ($this->db->errno() ==
'DB_ERROR_RECORD_ALREADY_EXISTS') {
1439 $langs->load(
"errors");
1440 if (empty($conf->barcode->enabled) || empty($this->barcode)) {
1441 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductAlreadyExists", $this->
ref);
1443 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductBarCodeAlreadyExists", $this->barcode);
1445 $this->errors[] = $this->error;
1446 $this->db->rollback();
1449 $this->error = $langs->trans(
"Error").
" : ".$this->db->error().
" - ".$sql;
1450 $this->errors[] = $this->error;
1451 $this->db->rollback();
1456 $this->db->rollback();
1457 dol_syslog(get_class($this).
"::Update fails verify ".join(
',', $this->errors), LOG_WARNING);
1469 public function delete(
User $user, $notrigger = 0)
1471 global $conf, $langs;
1472 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
1477 if (empty($this->
id)) {
1478 $this->error =
"Object must be fetched before calling delete";
1482 $this->error =
"ErrorForbidden";
1487 if (empty($objectisused)) {
1490 if (!$error && empty($notrigger)) {
1492 $result = $this->
call_trigger(
'PRODUCT_DELETE', $user);
1501 $sql =
"DELETE FROM ".$this->db->prefix().
'product_batch';
1502 $sql .=
" WHERE fk_product_stock IN (";
1503 $sql .=
"SELECT rowid FROM ".$this->db->prefix().
'product_stock';
1504 $sql .=
" WHERE fk_product = ".((int) $this->
id).
")";
1506 $result = $this->db->query($sql);
1509 $this->errors[] = $this->db->lasterror();
1515 $elements = array(
'product_fournisseur_price',
'product_price',
'product_lang',
'categorie_product',
'product_stock',
'product_customer_price',
'product_lot');
1516 foreach ($elements as $table) {
1518 $sql =
"DELETE FROM ".$this->db->prefix().$table;
1519 $sql .=
" WHERE fk_product = ".(int) $this->
id;
1521 $result = $this->db->query($sql);
1524 $this->errors[] = $this->db->lasterror();
1531 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1532 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination2ValuePair.class.php';
1537 if ($prodcomb->deleteByFkProductParent($user, $this->id) < 0) {
1539 $this->errors[] =
'Error deleting combinations';
1543 if (!$error && ($prodcomb->fetchByFkProductChild($this->id) > 0) && ($prodcomb->delete($user) < 0)) {
1545 $this->errors[] =
'Error deleting child combination';
1551 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
1552 $sql .=
" WHERE fk_product_pere = ".(int) $this->
id.
" OR fk_product_fils = ".(
int) $this->id;
1554 $result = $this->db->query($sql);
1557 $this->errors[] = $this->db->lasterror();
1566 dol_syslog(get_class($this).
"::delete error -4 ".$this->error, LOG_ERR);
1572 $sqlz =
"DELETE FROM ".$this->db->prefix().
"product";
1573 $sqlz .=
" WHERE rowid = ".(int) $this->
id;
1575 $resultz = $this->db->query($sqlz);
1578 $this->errors[] = $this->db->lasterror();
1594 if ($conf->product->dir_output) {
1595 $dir = $conf->product->dir_output.
"/".$ref;
1596 if (file_exists($dir)) {
1599 $this->errors[] =
'ErrorFailToDeleteDir';
1607 $this->db->commit();
1610 foreach ($this->errors as $errmsg) {
1611 dol_syslog(get_class($this).
"::delete ".$errmsg, LOG_ERR);
1612 $this->error .= ($this->error ?
', '.$errmsg : $errmsg);
1614 $this->db->rollback();
1618 $this->error =
"ErrorRecordIsUsedCantDelete";
1631 global $conf, $langs;
1633 $langs_available = $langs->get_available_languages(DOL_DOCUMENT_ROOT, 0, 2);
1634 $current_lang = $langs->getDefaultLang();
1636 foreach ($langs_available as $key => $value) {
1637 if ($key == $current_lang) {
1638 $sql =
"SELECT rowid";
1639 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1640 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1641 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
1643 $result = $this->db->query($sql);
1645 if ($this->db->num_rows($result)) {
1646 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
1648 $sql2 .=
" label='".$this->db->escape($this->label).
"',";
1649 $sql2 .=
" description='".$this->db->escape($this->
description).
"'";
1651 $sql2 .=
", note='".$this->db->escape($this->other).
"'";
1653 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
1655 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
1660 $sql2 .=
" VALUES(".$this->id.
",'".$this->db->escape($key).
"','".$this->db->escape($this->label).
"',";
1661 $sql2 .=
" '".$this->db->escape($this->
description).
"'";
1663 $sql2 .=
", '".$this->db->escape($this->other).
"'";
1667 dol_syslog(get_class($this).
'::setMultiLangs key = current_lang = '.$key);
1668 if (!$this->db->query($sql2)) {
1669 $this->error = $this->db->lasterror();
1672 } elseif (isset($this->multilangs[$key])) {
1673 if (empty($this->multilangs[
"$key"][
"label"])) {
1674 $this->errors[] = $key .
' : ' . $langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Label"));
1678 $sql =
"SELECT rowid";
1679 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1680 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1681 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
1683 $result = $this->db->query($sql);
1685 if ($this->db->num_rows($result)) {
1686 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
1688 $sql2 .=
" label = '".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
1689 $sql2 .=
" description = '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
1691 $sql2 .=
", note = '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
1693 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
1695 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
1700 $sql2 .=
" VALUES(".$this->id.
",'".$this->db->escape($key).
"','".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
1701 $sql2 .=
" '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
1703 $sql2 .=
", '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
1709 if ($this->multilangs[
"$key"][
"label"] || $this->multilangs[
"$key"][
"description"]) {
1710 if (!$this->db->query($sql2)) {
1711 $this->error = $this->db->lasterror();
1721 $result = $this->
call_trigger(
'PRODUCT_SET_MULTILANGS', $user);
1723 $this->error = $this->db->lasterror();
1741 $sql =
"DELETE FROM ".$this->db->prefix().
"product_lang";
1742 $sql .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($langtodelete).
"'";
1744 dol_syslog(get_class($this).
'::delMultiLangs', LOG_DEBUG);
1745 $result = $this->db->query($sql);
1748 $result = $this->
call_trigger(
'PRODUCT_DEL_MULTILANGS', $user);
1750 $this->error = $this->db->lasterror();
1751 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
1757 $this->error = $this->db->lasterror();
1758 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
1773 global $user, $langs, $conf;
1779 if ($type ==
'buy') {
1780 $field =
'accountancy_code_buy';
1781 } elseif ($type ==
'buy_intra') {
1782 $field =
'accountancy_code_buy_intra';
1783 } elseif ($type ==
'buy_export') {
1784 $field =
'accountancy_code_buy_export';
1785 } elseif ($type ==
'sell') {
1786 $field =
'accountancy_code_sell';
1787 } elseif ($type ==
'sell_intra') {
1788 $field =
'accountancy_code_sell_intra';
1789 } elseif ($type ==
'sell_export') {
1790 $field =
'accountancy_code_sell_export';
1795 $sql =
"UPDATE ".$this->db->prefix().$this->table_element.
" SET ";
1796 $sql .=
"$field = '".$this->db->escape($value).
"'";
1797 $sql .=
" WHERE rowid = ".((int) $this->
id);
1800 $resql = $this->db->query($sql);
1804 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
1811 $this->db->rollback();
1815 $this->$field = $value;
1817 $this->db->commit();
1820 $this->error = $this->db->lasterror();
1821 $this->db->rollback();
1835 $current_lang = $langs->getDefaultLang();
1837 $sql =
"SELECT lang, label, description, note as other";
1838 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1839 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1841 $result = $this->db->query($sql);
1843 while ($obj = $this->db->fetch_object($result)) {
1845 if ($obj->lang == $current_lang) {
1846 $this->label = $obj->label;
1848 $this->other = $obj->other;
1850 $this->multilangs[
"$obj->lang"][
"label"] = $obj->label;
1851 $this->multilangs[
"$obj->lang"][
"description"] = $obj->description;
1852 $this->multilangs[
"$obj->lang"][
"other"] = $obj->other;
1856 $this->error =
"Error: ".$this->db->lasterror().
" - ".$sql;
1869 $testExit = array(
'multiprices',
'multiprices_ttc',
'multiprices_base_type',
'multiprices_min',
'multiprices_min_ttc',
'multiprices_tva_tx',
'multiprices_recuperableonly');
1871 foreach ($testExit as $field) {
1872 if (!isset($this->$field)) {
1875 $tmparray = $this->$field;
1876 if (!isset($tmparray[$level])) {
1882 'level' => $level ? $level : 1,
1883 'multiprices' => (float) $this->multiprices[$level],
1884 'multiprices_ttc' => (
float) $this->multiprices_ttc[$level],
1885 'multiprices_base_type' => $this->multiprices_base_type[$level],
1886 'multiprices_min' => (float) $this->multiprices_min[$level],
1887 'multiprices_min_ttc' => (
float) $this->multiprices_min_ttc[$level],
1888 'multiprices_tva_tx' => (float) $this->multiprices_tva_tx[$level],
1889 'multiprices_recuperableonly' => (
float) $this->multiprices_recuperableonly[$level],
1912 if (empty($this->price_by_qty)) {
1913 $this->price_by_qty = 0;
1917 $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,";
1918 $sql .=
" localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, price_min,price_min_ttc,price_by_qty,entity,fk_price_expression) ";
1919 $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).
",";
1920 $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');
1923 dol_syslog(get_class($this).
"::_log_price", LOG_DEBUG);
1924 $resql = $this->db->query($sql);
1926 $this->error = $this->db->lasterror();
1946 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price_by_qty";
1947 $sql .=
" WHERE fk_product_price = ".((int) $rowid);
1948 $resql = $this->db->query($sql);
1950 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price";
1951 $sql .=
" WHERE rowid=".((int) $rowid);
1952 $resql = $this->db->query($sql);
1956 $this->error = $this->db->lasterror();
1971 public function getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp = 0)
1973 global $conf, $hookmanager, $action;
1976 if (is_object($hookmanager)) {
1977 $parameters = array(
'thirdparty_seller'=>$thirdparty_seller,
'thirdparty_buyer' => $thirdparty_buyer,
'pqp' => $pqp);
1979 $reshook = $hookmanager->executeHooks(
'getSellPrice', $parameters, $this, $action);
1981 return $hookmanager->resArray;
1992 $pu_ht = $this->price;
1993 $pu_ttc = $this->price_ttc;
1994 $price_min = $this->price_min;
1995 $price_base_type = $this->price_base_type;
1998 if (
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !empty($thirdparty_buyer->price_level)) {
1999 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
2000 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
2001 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
2002 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
2004 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2005 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2007 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2008 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2016 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2020 $filter = array(
't.fk_product' => $this->
id,
't.fk_soc' => $thirdparty_buyer->id);
2022 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2024 if (count($prodcustprice->lines) > 0) {
2025 $pu_ht =
price($prodcustprice->lines[0]->price);
2026 $price_min =
price($prodcustprice->lines[0]->price_min);
2027 $pu_ttc =
price($prodcustprice->lines[0]->price_ttc);
2028 $price_base_type = $prodcustprice->lines[0]->price_base_type;
2029 $tva_tx = $prodcustprice->lines[0]->tva_tx;
2030 if ($prodcustprice->lines[0]->default_vat_code && !preg_match(
'/\(.*\)/',
$tva_tx)) {
2031 $tva_tx .=
' ('.$prodcustprice->lines[0]->default_vat_code.
')';
2033 $tva_npr = $prodcustprice->lines[0]->recuperableonly;
2041 if ($this->prices_by_qty[0]) {
2044 foreach ($this->prices_by_qty_list[0] as $priceforthequantityarray) {
2045 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2049 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2050 $pu_ht = $priceforthequantityarray[
'unitprice'];
2052 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2059 if ($this->prices_by_qty[$thirdparty_buyer->price_level]) {
2062 foreach ($this->prices_by_qty_list[$thirdparty_buyer->price_level] as $priceforthequantityarray) {
2063 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2067 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2068 $pu_ht = $priceforthequantityarray[
'unitprice'];
2070 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2077 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);
2094 public function get_buyprice($prodfournprice, $qty, $product_id = 0, $fourn_ref =
'', $fk_soc = 0)
2101 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2102 $sql .=
" pfp.fk_product, pfp.ref_fourn as ref_supplier, pfp.desc_fourn as desc_supplier, pfp.tva_tx, pfp.default_vat_code, pfp.fk_supplier_price_expression,";
2103 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2104 $sql .=
" pfp.packaging";
2105 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2106 $sql .=
" WHERE pfp.rowid = ".((int) $prodfournprice);
2108 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2110 $sql .=
" ORDER BY pfp.quantity DESC";
2112 dol_syslog(get_class($this).
"::get_buyprice first search by prodfournprice/qty", LOG_DEBUG);
2113 $resql = $this->db->query($sql);
2115 $obj = $this->db->fetch_object($resql);
2116 if ($obj && $obj->quantity > 0) {
2117 if (isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2119 $prod_supplier->product_fourn_price_id = $obj->rowid;
2120 $prod_supplier->id = $obj->fk_product;
2121 $prod_supplier->fourn_qty = $obj->quantity;
2122 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2123 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2125 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2127 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2128 if ($price_result >= 0) {
2129 $obj->price = $price_result;
2132 $this->product_fourn_price_id = $obj->rowid;
2133 $this->buyprice = $obj->price;
2134 $this->fourn_pu = $obj->price / $obj->quantity;
2135 $this->fourn_price_base_type =
'HT';
2136 $this->fourn_socid = $obj->fk_soc;
2137 $this->ref_fourn = $obj->ref_supplier;
2138 $this->ref_supplier = $obj->ref_supplier;
2139 $this->desc_supplier = $obj->desc_supplier;
2140 $this->remise_percent = $obj->remise_percent;
2141 $this->vatrate_supplier = $obj->tva_tx;
2142 $this->default_vat_code_supplier = $obj->default_vat_code;
2143 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2144 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2145 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2146 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2147 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2149 $this->packaging = $obj->packaging;
2151 $result = $obj->fk_product;
2155 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2156 $sql .=
" pfp.fk_product, pfp.ref_fourn as ref_supplier, pfp.desc_fourn as desc_supplier, pfp.tva_tx, pfp.default_vat_code, pfp.fk_supplier_price_expression,";
2157 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2158 $sql .=
" pfp.packaging";
2159 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2160 $sql .=
" WHERE 1 = 1";
2161 if ($product_id > 0) {
2162 $sql .=
" AND pfp.fk_product = ".((int) $product_id);
2164 if ($fourn_ref !=
'none') {
2165 $sql .=
" AND pfp.ref_fourn = '".$this->db->escape($fourn_ref).
"'";
2168 $sql .=
" AND pfp.fk_soc = ".((int) $fk_soc);
2171 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2173 $sql .=
" ORDER BY pfp.quantity DESC";
2176 dol_syslog(get_class($this).
"::get_buyprice second search from qty/ref/product_id", LOG_DEBUG);
2177 $resql = $this->db->query($sql);
2179 $obj = $this->db->fetch_object($resql);
2180 if ($obj && $obj->quantity > 0) {
2181 if (isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2183 $prod_supplier->product_fourn_price_id = $obj->rowid;
2184 $prod_supplier->id = $obj->fk_product;
2185 $prod_supplier->fourn_qty = $obj->quantity;
2186 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2187 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2189 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2191 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2193 $obj->price = $price_result;
2196 $this->product_fourn_price_id = $obj->rowid;
2197 $this->buyprice = $obj->price;
2198 $this->fourn_qty = $obj->quantity;
2199 $this->fourn_pu = $obj->price / $obj->quantity;
2200 $this->fourn_price_base_type =
'HT';
2201 $this->fourn_socid = $obj->fk_soc;
2202 $this->ref_fourn = $obj->ref_supplier;
2203 $this->ref_supplier = $obj->ref_supplier;
2204 $this->desc_supplier = $obj->desc_supplier;
2205 $this->remise_percent = $obj->remise_percent;
2206 $this->vatrate_supplier = $obj->tva_tx;
2207 $this->default_vat_code_supplier = $obj->default_vat_code;
2208 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2209 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2210 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2211 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2212 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2214 $this->packaging = $obj->packaging;
2216 $result = $obj->fk_product;
2222 $this->error = $this->db->lasterror();
2227 $this->error = $this->db->lasterror();
2250 public function updatePrice($newprice, $newpricebase, $user, $newvat =
'', $newminprice = 0, $level = 0, $newnpr = 0, $newpbq = 0, $ignore_autogen = 0, $localtaxes_array = array(), $newdefaultvatcode =
'', $notrigger = 0)
2252 global $conf, $langs;
2258 dol_syslog(get_class($this).
"::update_price id=".$id.
" newprice=".$newprice.
" newpricebase=".$newpricebase.
" newminprice=".$newminprice.
" level=".$level.
" npr=".$newnpr.
" newdefaultvatcode=".$newdefaultvatcode);
2261 if (empty($this->tva_tx)) {
2264 if (empty($newnpr)) {
2267 if (empty($newminprice)) {
2270 if (empty($newminprice)) {
2275 if ($newvat ==
'') {
2281 if ((
getDolGlobalString(
'PRODUIT_MULTIPRICES') ||
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) && !$ignore_autogen && $this->price_autogen && ($level == 1)) {
2282 return $this->
generateMultiprices($user, $newprice, $newpricebase, $newvat, $newnpr, $newpbq);
2285 if (!empty($newminprice) && ($newminprice > $newprice)) {
2286 $this->error =
'ErrorPriceCantBeLowerThanMinPrice';
2290 if ($newprice !==
'' || $newprice === 0) {
2291 if ($newpricebase ==
'TTC') {
2292 $price_ttc =
price2num($newprice,
'MU');
2293 $price =
price2num($newprice) / (1 + ($newvat / 100));
2296 if ($newminprice !=
'' || $newminprice == 0) {
2297 $price_min_ttc =
price2num($newminprice,
'MU');
2298 $price_min =
price2num($newminprice) / (1 + ($newvat / 100));
2299 $price_min =
price2num($price_min,
'MU');
2306 $price_ttc = ($newnpr != 1) ? (
float)
price2num($newprice) * (1 + ($newvat / 100)) : $price;
2307 $price_ttc =
price2num($price_ttc,
'MU');
2309 if ($newminprice !==
'' || $newminprice === 0) {
2310 $price_min =
price2num($newminprice,
'MU');
2311 $price_min_ttc =
price2num($newminprice) * (1 + ($newvat / 100));
2312 $price_min_ttc =
price2num($price_min_ttc,
'MU');
2321 if (count($localtaxes_array) > 0) {
2322 $localtaxtype1 = $localtaxes_array[
'0'];
2323 $localtax1 = $localtaxes_array[
'1'];
2324 $localtaxtype2 = $localtaxes_array[
'2'];
2325 $localtax2 = $localtaxes_array[
'3'];
2328 if (!empty($newdefaultvatcode)) {
2331 $sql =
"SELECT t.rowid, t.code, t.recuperableonly as tva_npr, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
2332 $sql .=
" FROM ".MAIN_DB_PREFIX.
"c_tva as t, ".MAIN_DB_PREFIX.
"c_country as c";
2333 $sql .=
" WHERE t.fk_pays = c.rowid AND c.code = '".$this->db->escape($mysoc->country_code).
"'";
2334 $sql .=
" AND t.taux = ".((float) $newdefaultvatcode).
" AND t.active = 1";
2335 $sql .=
" AND t.code = '".$this->db->escape($newdefaultvatcode).
"'";
2336 $resql = $this->db->query($sql);
2338 $obj = $this->db->fetch_object($resql);
2340 $npr = $obj->tva_npr;
2341 $localtax1 = $obj->localtax1;
2342 $localtax2 = $obj->localtax2;
2343 $localtaxtype1 = $obj->localtax1_type;
2344 $localtaxtype2 = $obj->localtax2_type;
2349 $localtaxtype1 =
'0';
2351 $localtaxtype2 =
'0';
2355 if (empty($localtax1)) {
2358 if (empty($localtax2)) {
2366 $sql =
"UPDATE ".$this->db->prefix().
"product SET";
2367 $sql .=
" price_base_type = '".$this->db->escape($newpricebase).
"',";
2368 $sql .=
" price = ".(float) $price.
",";
2369 $sql .=
" price_ttc = ".(float) $price_ttc.
",";
2370 $sql .=
" price_min = ".(float) $price_min.
",";
2371 $sql .=
" price_min_ttc = ".(float) $price_min_ttc.
",";
2372 $sql .=
" localtax1_tx = ".($localtax1 >= 0 ? (float) $localtax1 :
'NULL').
",";
2373 $sql .=
" localtax2_tx = ".($localtax2 >= 0 ? (float) $localtax2 :
'NULL').
",";
2374 $sql .=
" localtax1_type = ".($localtaxtype1 !=
'' ?
"'".$this->db->escape($localtaxtype1).
"'" :
"'0'").
",";
2375 $sql .=
" localtax2_type = ".($localtaxtype2 !=
'' ?
"'".$this->db->escape($localtaxtype2).
"'" :
"'0'").
",";
2376 $sql .=
" default_vat_code = ".($newdefaultvatcode ?
"'".$this->db->escape($newdefaultvatcode).
"'" :
"null").
",";
2377 $sql .=
" tva_tx = ".(float)
price2num($newvat).
",";
2378 $sql .=
" recuperableonly = '".$this->db->escape($newnpr).
"'";
2379 $sql .=
" WHERE rowid = ".((int) $id);
2381 dol_syslog(get_class($this).
"::update_price", LOG_DEBUG);
2382 $resql = $this->db->query($sql);
2384 $this->multiprices[$level] = $price;
2385 $this->multiprices_ttc[$level] = $price_ttc;
2386 $this->multiprices_min[$level] = $price_min;
2387 $this->multiprices_min_ttc[$level] = $price_min_ttc;
2388 $this->multiprices_base_type[$level] = $newpricebase;
2389 $this->multiprices_default_vat_code[$level] = $newdefaultvatcode;
2390 $this->multiprices_tva_tx[$level] = $newvat;
2391 $this->multiprices_recuperableonly[$level] = $newnpr;
2393 $this->
price = $price;
2394 $this->price_ttc = $price_ttc;
2395 $this->price_min = $price_min;
2396 $this->price_min_ttc = $price_min_ttc;
2397 $this->price_base_type = $newpricebase;
2398 $this->default_vat_code = $newdefaultvatcode;
2399 $this->tva_tx = $newvat;
2400 $this->tva_npr = $newnpr;
2402 $this->localtax1_tx = $localtax1;
2403 $this->localtax2_tx = $localtax2;
2404 $this->localtax1_type = $localtaxtype1;
2405 $this->localtax2_type = $localtaxtype2;
2408 $this->price_by_qty = $newpbq;
2412 if (!empty(array_diff_assoc($newPriceData, $lastPriceData)) || !
getDolGlobalString(
'PRODUIT_MULTIPRICES')) {
2416 $this->level = $level;
2420 $result = $this->
call_trigger(
'PRODUCT_PRICE_MODIFY', $user);
2422 $this->db->rollback();
2428 $this->db->commit();
2430 $this->db->rollback();
2431 $this->error = $this->db->lasterror();
2450 $this->fk_price_expression = $expression_id;
2452 return $this->
update($this->
id, $user);
2467 public function fetch($id =
'', $ref =
'', $ref_ext =
'', $barcode =
'', $ignore_expression = 0, $ignore_price_load = 0, $ignore_lang_load = 0)
2469 include_once DOL_DOCUMENT_ROOT.
'/core/lib/company.lib.php';
2471 global $langs, $conf;
2473 dol_syslog(get_class($this).
"::fetch id=".$id.
" ref=".$ref.
" ref_ext=".$ref_ext);
2476 if (!$id && !$ref && !$ref_ext && !$barcode) {
2477 $this->error =
'ErrorWrongParameters';
2478 dol_syslog(get_class($this).
"::fetch ".$this->error, LOG_ERR);
2482 $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,";
2483 $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,";
2484 $sql .=
" p.tobuy, p.fk_product_type, p.duration, p.fk_default_warehouse, p.fk_default_workstation, p.seuil_stock_alerte, p.canvas, p.net_measure, p.net_measure_units, p.weight, p.weight_units,";
2485 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
2486 $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,";
2488 $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,";
2490 $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,";
2495 $separatedEntityPMP =
false;
2496 $separatedStock =
false;
2497 $visibleWarehousesEntities = $conf->entity;
2500 $checkPMPPerEntity = $this->db->query(
"SELECT pmp FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = ".((int) $id).
" AND entity = ".(
int) $conf->entity);
2501 if ($this->db->num_rows($checkPMPPerEntity)>0) {
2502 $separatedEntityPMP =
true;
2506 $separatedStock =
true;
2507 if (isset($mc->sharings[
'stock']) && !empty($mc->sharings[
'stock'])) {
2508 $visibleWarehousesEntities .=
"," . implode(
",", $mc->sharings[
'stock']);
2511 if ($separatedEntityPMP) {
2512 $sql .=
" ppe.pmp,";
2516 $sql .=
" p.datec, p.tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.batch_mask, p.fk_unit,";
2517 $sql .=
" p.fk_price_expression, p.price_autogen, p.model_pdf,";
2518 if ($separatedStock) {
2519 $sql .=
" SUM(sp.reel) as stock";
2523 $sql .=
" FROM ".$this->db->prefix().
"product as p";
2525 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int) $conf->entity);
2527 if ($separatedStock) {
2528 $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).
"))";
2532 $sql .=
" WHERE p.rowid = ".((int) $id);
2534 $sql .=
" WHERE p.entity IN (".getEntity($this->element).
")";
2536 $sql .=
" AND p.ref = '".$this->db->escape($ref).
"'";
2537 } elseif ($ref_ext) {
2538 $sql .=
" AND p.ref_ext = '".$this->db->escape($ref_ext).
"'";
2539 } elseif ($barcode) {
2540 $sql .=
" AND p.barcode = '".$this->db->escape($barcode).
"'";
2543 if ($separatedStock) {
2544 $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,";
2545 $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,";
2546 $sql .=
" p.tobuy, p.fk_product_type, p.duration, p.fk_default_warehouse, p.fk_default_workstation, p.seuil_stock_alerte, p.canvas, p.net_measure, p.net_measure_units, p.weight, p.weight_units,";
2547 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
2548 $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,";
2550 $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,";
2552 $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,";
2554 if ($separatedEntityPMP) {
2555 $sql .=
" ppe.pmp,";
2559 $sql .=
" p.datec, p.tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.batch_mask, p.fk_unit,";
2560 $sql .=
" p.fk_price_expression, p.price_autogen, p.model_pdf";
2561 if (!$separatedStock) {
2562 $sql .=
", p.stock";
2566 $resql = $this->db->query($sql);
2568 unset($this->oldcopy);
2570 if ($this->db->num_rows($resql) > 0) {
2571 $obj = $this->db->fetch_object($resql);
2573 $this->
id = $obj->rowid;
2574 $this->
ref = $obj->ref;
2575 $this->ref_ext = $obj->ref_ext;
2576 $this->label = $obj->label;
2578 $this->url = $obj->url;
2579 $this->note_public = $obj->note_public;
2580 $this->note_private = $obj->note_private;
2581 $this->note = $obj->note_private;
2583 $this->
type = $obj->fk_product_type;
2584 $this->
status = $obj->tosell;
2585 $this->status_buy = $obj->tobuy;
2586 $this->status_batch = $obj->tobatch;
2587 $this->batch_mask = $obj->batch_mask;
2589 $this->customcode = $obj->customcode;
2590 $this->country_id = $obj->fk_country;
2591 $this->country_code =
getCountry($this->country_id, 2, $this->db);
2592 $this->state_id = $obj->fk_state;
2593 $this->lifetime = $obj->lifetime;
2594 $this->qc_frequency = $obj->qc_frequency;
2595 $this->
price = $obj->price;
2596 $this->price_ttc = $obj->price_ttc;
2597 $this->price_min = $obj->price_min;
2598 $this->price_min_ttc = $obj->price_min_ttc;
2599 $this->price_base_type = $obj->price_base_type;
2600 $this->cost_price = isset($obj->cost_price) ? (float) $obj->cost_price :
null;
2601 $this->default_vat_code = $obj->default_vat_code;
2602 $this->tva_tx = $obj->tva_tx;
2604 $this->tva_npr = $obj->tva_npr;
2606 $this->localtax1_tx = $obj->localtax1_tx;
2607 $this->localtax2_tx = $obj->localtax2_tx;
2608 $this->localtax1_type = $obj->localtax1_type;
2609 $this->localtax2_type = $obj->localtax2_type;
2611 $this->finished = $obj->finished;
2612 $this->fk_default_bom = $obj->fk_default_bom;
2614 $this->duration = $obj->duration;
2615 $this->duration_value = $obj->duration ? (int) (substr($obj->duration, 0,
dol_strlen($obj->duration) - 1)) : 0;
2616 $this->duration_unit = $obj->duration ? substr($obj->duration, -1) :
null;
2617 $this->canvas = $obj->canvas;
2618 $this->net_measure = $obj->net_measure;
2619 $this->net_measure_units = $obj->net_measure_units;
2620 $this->weight = $obj->weight;
2621 $this->weight_units = $obj->weight_units;
2622 $this->length = $obj->length;
2623 $this->length_units = $obj->length_units;
2624 $this->width = $obj->width;
2625 $this->width_units = $obj->width_units;
2626 $this->height = $obj->height;
2627 $this->height_units = $obj->height_units;
2629 $this->surface = $obj->surface;
2630 $this->surface_units = $obj->surface_units;
2631 $this->volume = $obj->volume;
2632 $this->volume_units = $obj->volume_units;
2633 $this->barcode = $obj->barcode;
2634 $this->barcode_type = $obj->fk_barcode_type;
2636 $this->accountancy_code_buy = $obj->accountancy_code_buy;
2637 $this->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra;
2638 $this->accountancy_code_buy_export = $obj->accountancy_code_buy_export;
2639 $this->accountancy_code_sell = $obj->accountancy_code_sell;
2640 $this->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra;
2641 $this->accountancy_code_sell_export = $obj->accountancy_code_sell_export;
2643 $this->fk_default_warehouse = $obj->fk_default_warehouse;
2644 $this->fk_default_workstation = $obj->fk_default_workstation;
2645 $this->seuil_stock_alerte = $obj->seuil_stock_alerte;
2646 $this->desiredstock = $obj->desiredstock;
2647 $this->stock_reel = $obj->stock;
2648 $this->pmp = $obj->pmp;
2650 $this->date_creation = $obj->datec;
2651 $this->date_modification = $obj->tms;
2652 $this->import_key = $obj->import_key;
2653 $this->entity = $obj->entity;
2655 $this->ref_ext = $obj->ref_ext;
2656 $this->fk_price_expression = $obj->fk_price_expression;
2657 $this->fk_unit = $obj->fk_unit;
2658 $this->price_autogen = $obj->price_autogen;
2659 $this->model_pdf = $obj->model_pdf;
2661 $this->mandatory_period = $obj->mandatory_period;
2663 $this->db->free($resql);
2675 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
2676 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
2677 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
2678 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
2679 $sql .=
" FROM ".$this->db->prefix().
"product_price";
2680 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
2681 $sql .=
" AND price_level=".((int) $i);
2682 $sql .=
" AND fk_product = ".((int) $this->
id);
2683 $sql .=
" ORDER BY date_price DESC, rowid DESC";
2685 $resql = $this->db->query($sql);
2687 $result = $this->db->fetch_array($resql);
2689 $this->multiprices[$i] = $result ? $result[
"price"] :
null;
2690 $this->multiprices_ttc[$i] = $result ? $result[
"price_ttc"] :
null;
2691 $this->multiprices_min[$i] = $result ? $result[
"price_min"] :
null;
2692 $this->multiprices_min_ttc[$i] = $result ? $result[
"price_min_ttc"] :
null;
2693 $this->multiprices_base_type[$i] = $result ? $result[
"price_base_type"] :
null;
2695 $this->multiprices_tva_tx[$i] = $result ? $result[
"tva_tx"].($result ?
' ('.$result[
'default_vat_code'].
')' :
'') :
null;
2696 $this->multiprices_recuperableonly[$i] = $result ? $result[
"recuperableonly"] :
null;
2734 $this->error = $this->db->lasterror;
2738 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES') && empty($ignore_price_load)) {
2740 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY') && empty($ignore_price_load)) {
2741 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
2742 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid";
2743 $sql .=
" FROM ".$this->db->prefix().
"product_price";
2744 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2745 $sql .=
" ORDER BY date_price DESC, rowid DESC";
2747 $resql = $this->db->query($sql);
2749 $result = $this->db->fetch_array($resql);
2752 $this->prices_by_qty[0] = $result[
"price_by_qty"];
2753 $this->prices_by_qty_id[0] = $result[
"rowid"];
2755 if ($this->prices_by_qty[0] == 1) {
2756 $sql =
"SELECT rowid,price, unitprice, quantity, remise_percent, remise, remise, price_base_type";
2757 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
2758 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[0]);
2759 $sql .=
" ORDER BY quantity ASC";
2760 $resultat = array();
2761 $resql = $this->db->query($sql);
2764 while ($result = $this->db->fetch_array($resql)) {
2765 $resultat[$ii] = array();
2766 $resultat[$ii][
"rowid"] = $result[
"rowid"];
2767 $resultat[$ii][
"price"] = $result[
"price"];
2768 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
2769 $resultat[$ii][
"quantity"] = $result[
"quantity"];
2770 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
2772 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
2775 $this->prices_by_qty_list[0] = $resultat;
2777 $this->error = $this->db->lasterror;
2782 $this->error = $this->db->lasterror;
2785 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') && empty($ignore_price_load)) {
2786 $produit_multiprices_limit =
getDolGlobalInt(
'PRODUIT_MULTIPRICES_LIMIT');
2787 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
2788 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
2789 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
2790 $sql .=
" FROM ".$this->db->prefix().
"product_price";
2791 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
2792 $sql .=
" AND price_level=".((int) $i);
2793 $sql .=
" AND fk_product = ".((int) $this->
id);
2794 $sql .=
" ORDER BY date_price DESC, rowid DESC";
2796 $resql = $this->db->query($sql);
2798 $result = $this->db->fetch_array($resql);
2800 $this->multiprices[$i] = (!empty($result[
"price"]) ? $result[
"price"] : 0);
2801 $this->multiprices_ttc[$i] = (!empty($result[
"price_ttc"]) ? $result[
"price_ttc"] : 0);
2802 $this->multiprices_min[$i] = (!empty($result[
"price_min"]) ? $result[
"price_min"] : 0);
2803 $this->multiprices_min_ttc[$i] = (!empty($result[
"price_min_ttc"]) ? $result[
"price_min_ttc"] : 0);
2804 $this->multiprices_base_type[$i] = (!empty($result[
"price_base_type"]) ? $result[
"price_base_type"] :
'');
2806 $this->multiprices_tva_tx[$i] = (!empty($result[
"tva_tx"]) ? $result[
"tva_tx"] : 0);
2807 $this->multiprices_recuperableonly[$i] = (!empty($result[
"recuperableonly"]) ? $result[
"recuperableonly"] : 0);
2810 $this->prices_by_qty[$i] = (!empty($result[
"price_by_qty"]) ? $result[
"price_by_qty"] : 0);
2811 $this->prices_by_qty_id[$i] = (!empty($result[
"rowid"]) ? $result[
"rowid"] : 0);
2813 if ($this->prices_by_qty[$i] == 1) {
2814 $sql =
"SELECT rowid, price, unitprice, quantity, remise_percent, remise, price_base_type";
2815 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
2816 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[$i]);
2817 $sql .=
" ORDER BY quantity ASC";
2818 $resultat = array();
2819 $resql = $this->db->query($sql);
2822 while ($result = $this->db->fetch_array($resql)) {
2823 $resultat[$ii] = array();
2824 $resultat[$ii][
"rowid"] = $result[
"rowid"];
2825 $resultat[$ii][
"price"] = $result[
"price"];
2826 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
2827 $resultat[$ii][
"quantity"] = $result[
"quantity"];
2828 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
2829 $resultat[$ii][
"remise"] = $result[
"remise"];
2830 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
2833 $this->prices_by_qty_list[$i] = $resultat;
2835 $this->error = $this->db->lasterror;
2840 $this->error = $this->db->lasterror;
2846 if (isModEnabled(
'dynamicprices') && !empty($this->fk_price_expression) && empty($ignore_expression)) {
2847 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2849 $price_result = $priceparser->parseProduct($this);
2850 if ($price_result >= 0) {
2851 $this->
price = $price_result;
2853 $this->price_ttc =
price2num($this->
price) * (1 + ($this->tva_tx / 100));
2854 $this->price_ttc =
price2num($this->price_ttc,
'MU');
2860 $this->stock_warehouse = array();
2867 $this->error = $this->db->lasterror();
2882 global $user, $hookmanager, $action;
2886 foreach (array(
'toconsume',
'consumed',
'toproduce',
'produced') as $role) {
2887 $this->stats_mo[
'customers_'.$role] = 0;
2888 $this->stats_mo[
'nb_'.$role] = 0;
2889 $this->stats_mo[
'qty_'.$role] = 0;
2891 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
2892 $sql .=
" SUM(mp.qty) as qty";
2893 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as c";
2894 $sql .=
" INNER JOIN ".$this->db->prefix().
"mrp_production as mp ON mp.fk_mo=c.rowid";
2895 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
2896 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc=c.fk_soc AND sc.fk_user = ".((int) $user->id);
2899 $sql .=
" c.entity IN (".getEntity(
'mo').
")";
2901 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
2902 $sql .=
" AND mp.role ='".$this->db->escape($role).
"'";
2904 $sql .=
" AND c.fk_soc = ".((int) $socid);
2907 $result = $this->db->query($sql);
2909 $obj = $this->db->fetch_object($result);
2910 $this->stats_mo[
'customers_'.$role] = $obj->nb_customers ? $obj->nb_customers : 0;
2911 $this->stats_mo[
'nb_'.$role] = $obj->nb ? $obj->nb : 0;
2912 $this->stats_mo[
'qty_'.$role] = $obj->qty ?
price2num($obj->qty,
'MS') : 0;
2914 $this->error = $this->db->error();
2919 if (!empty($error)) {
2923 $parameters = array(
'socid' => $socid);
2924 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
2926 $this->stats_mo = $hookmanager->resArray[
'stats_mo'];
2942 global $user, $hookmanager, $action;
2946 $this->stats_bom[
'nb_toproduce'] = 0;
2947 $this->stats_bom[
'nb_toconsume'] = 0;
2948 $this->stats_bom[
'qty_toproduce'] = 0;
2949 $this->stats_bom[
'qty_toconsume'] = 0;
2951 $sql =
"SELECT COUNT(DISTINCT b.rowid) as nb_toproduce,";
2952 $sql .=
" SUM(b.qty) as qty_toproduce";
2953 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
2954 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
2956 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
2957 $sql .=
" AND b.fk_product =".((int) $this->
id);
2958 $sql .=
" GROUP BY b.rowid";
2960 $result = $this->db->query($sql);
2962 $obj = $this->db->fetch_object($result);
2963 $this->stats_bom[
'nb_toproduce'] = !empty($obj->nb_toproduce) ? $obj->nb_toproduce : 0;
2964 $this->stats_bom[
'qty_toproduce'] = !empty($obj->qty_toproduce) ?
price2num($obj->qty_toproduce) : 0;
2966 $this->error = $this->db->error();
2970 $sql =
"SELECT COUNT(DISTINCT bl.rowid) as nb_toconsume,";
2971 $sql .=
" SUM(bl.qty) as qty_toconsume";
2972 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
2973 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
2975 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
2976 $sql .=
" AND bl.fk_product =".((int) $this->
id);
2978 $result = $this->db->query($sql);
2980 $obj = $this->db->fetch_object($result);
2981 $this->stats_bom[
'nb_toconsume'] = !empty($obj->nb_toconsume) ? $obj->nb_toconsume : 0;
2982 $this->stats_bom[
'qty_toconsume'] = !empty($obj->qty_toconsume) ?
price2num($obj->qty_toconsume) : 0;
2984 $this->error = $this->db->error();
2988 if (!empty($error)) {
2992 $parameters = array(
'socid' => $socid);
2993 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
2995 $this->stats_bom = $hookmanager->resArray[
'stats_bom'];
3011 global $conf, $user, $hookmanager, $action;
3013 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_customers, COUNT(DISTINCT p.rowid) as nb,";
3014 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3015 $sql .=
" FROM ".$this->db->prefix().
"propaldet as pd";
3016 $sql .=
", ".$this->db->prefix().
"propal as p";
3017 $sql .=
", ".$this->db->prefix().
"societe as s";
3018 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
3019 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3021 $sql .=
" WHERE p.rowid = pd.fk_propal";
3022 $sql .=
" AND p.fk_soc = s.rowid";
3023 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
3024 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3025 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
3026 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3030 $sql .=
" AND p.fk_soc = ".((int) $socid);
3033 $result = $this->db->query($sql);
3035 $obj = $this->db->fetch_object($result);
3036 $this->stats_propale[
'customers'] = $obj->nb_customers;
3037 $this->stats_propale[
'nb'] = $obj->nb;
3038 $this->stats_propale[
'rows'] = $obj->nb_rows;
3039 $this->stats_propale[
'qty'] = $obj->qty ? $obj->qty : 0;
3044 if (is_array($TFather) && !empty($TFather)) {
3045 foreach ($TFather as &$fatherData) {
3046 $pFather =
new Product($this->db);
3047 $pFather->id = $fatherData[
'id'];
3048 $qtyCoef = $fatherData[
'qty'];
3050 if ($fatherData[
'incdec']) {
3051 $pFather->load_stats_propale($socid);
3053 $this->stats_propale[
'customers'] += $pFather->stats_propale[
'customers'];
3054 $this->stats_propale[
'nb'] += $pFather->stats_propale[
'nb'];
3055 $this->stats_propale[
'rows'] += $pFather->stats_propale[
'rows'];
3056 $this->stats_propale[
'qty'] += $pFather->stats_propale[
'qty'] * $qtyCoef;
3062 $parameters = array(
'socid' => $socid);
3063 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerProposal', $parameters, $this, $action);
3065 $this->stats_propale = $hookmanager->resArray[
'stats_propale'];
3070 $this->error = $this->db->error();
3086 global $conf, $user, $hookmanager, $action;
3088 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_suppliers, COUNT(DISTINCT p.rowid) as nb,";
3089 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3090 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as pd";
3091 $sql .=
", ".$this->db->prefix().
"supplier_proposal as p";
3092 $sql .=
", ".$this->db->prefix().
"societe as s";
3093 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
3094 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3096 $sql .=
" WHERE p.rowid = pd.fk_supplier_proposal";
3097 $sql .=
" AND p.fk_soc = s.rowid";
3098 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
3099 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3100 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
3101 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3105 $sql .=
" AND p.fk_soc = ".((int) $socid);
3108 $result = $this->db->query($sql);
3110 $obj = $this->db->fetch_object($result);
3111 $this->stats_proposal_supplier[
'suppliers'] = $obj->nb_suppliers;
3112 $this->stats_proposal_supplier[
'nb'] = $obj->nb;
3113 $this->stats_proposal_supplier[
'rows'] = $obj->nb_rows;
3114 $this->stats_proposal_supplier[
'qty'] = $obj->qty ? $obj->qty : 0;
3116 $parameters = array(
'socid' => $socid);
3117 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierProposal', $parameters, $this, $action);
3119 $this->stats_proposal_supplier = $hookmanager->resArray[
'stats_proposal_supplier'];
3124 $this->error = $this->db->error();
3142 global $conf, $user, $hookmanager, $action;
3144 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3145 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3146 $sql .=
" FROM ".$this->db->prefix().
"commandedet as cd";
3147 $sql .=
", ".$this->db->prefix().
"commande as c";
3148 $sql .=
", ".$this->db->prefix().
"societe as s";
3149 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid && !$forVirtualStock) {
3150 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3152 $sql .=
" WHERE c.rowid = cd.fk_commande";
3153 $sql .=
" AND c.fk_soc = s.rowid";
3154 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'commande').
")";
3155 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3156 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid && !$forVirtualStock) {
3157 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3160 $sql .=
" AND c.fk_soc = ".((int) $socid);
3162 if ($filtrestatut !=
'') {
3163 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3166 $result = $this->db->query($sql);
3168 $obj = $this->db->fetch_object($result);
3169 $this->stats_commande[
'customers'] = $obj->nb_customers;
3170 $this->stats_commande[
'nb'] = $obj->nb;
3171 $this->stats_commande[
'rows'] = $obj->nb_rows;
3172 $this->stats_commande[
'qty'] = $obj->qty ? $obj->qty : 0;
3177 if (is_array($TFather) && !empty($TFather)) {
3178 foreach ($TFather as &$fatherData) {
3179 $pFather =
new Product($this->db);
3180 $pFather->id = $fatherData[
'id'];
3181 $qtyCoef = $fatherData[
'qty'];
3183 if ($fatherData[
'incdec']) {
3184 $pFather->load_stats_commande($socid, $filtrestatut);
3186 $this->stats_commande[
'customers'] += $pFather->stats_commande[
'customers'];
3187 $this->stats_commande[
'nb'] += $pFather->stats_commande[
'nb'];
3188 $this->stats_commande[
'rows'] += $pFather->stats_commande[
'rows'];
3189 $this->stats_commande[
'qty'] += $pFather->stats_commande[
'qty'] * $qtyCoef;
3201 $sql =
"SELECT SUM(".$this->db->ifsql(
'f.type=2', -1, 1).
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3202 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3203 $sql .=
" JOIN ".$this->db->prefix().
"element_element as el ON ((el.fk_target = f.rowid AND el.targettype = 'facture' AND sourcetype = 'commande') OR (el.fk_source = f.rowid AND el.targettype = 'commande' AND sourcetype = 'facture'))";
3204 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3205 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3207 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3208 $resql = $this->db->query($sql);
3210 if ($this->db->num_rows($resql) > 0) {
3211 $obj = $this->db->fetch_object($resql);
3212 $adeduire += $obj->count;
3216 $this->stats_commande[
'qty'] -= $adeduire;
3219 include_once DOL_DOCUMENT_ROOT.
'/compta/facture/class/facture.class.php';
3223 $sql =
"SELECT sum(".$this->db->ifsql(
'f.type=2', -1, 1).
" * fd.qty) as count FROM ".MAIN_DB_PREFIX.
"facturedet as fd ";
3224 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"facture as f ON fd.fk_facture = f.rowid";
3225 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"element_element as el ON ((el.fk_target = f.rowid AND el.targettype = 'facture' AND sourcetype = 'commande') OR (el.fk_source = f.rowid AND el.targettype = 'commande' AND sourcetype = 'facture'))";
3226 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"commande as c ON el.fk_source = c.rowid";
3227 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3229 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3230 $resql = $this->db->query($sql);
3232 if ($this->db->num_rows($resql) > 0) {
3233 $obj = $this->db->fetch_object($resql);
3234 $adeduire += $obj->count;
3237 $this->error = $this->db->error();
3241 $this->stats_commande[
'qty'] -= $adeduire;
3245 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3246 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerOrder', $parameters, $this, $action);
3248 $this->stats_commande = $hookmanager->resArray[
'stats_commande'];
3252 $this->error = $this->db->error();
3270 global $conf, $user, $hookmanager, $action;
3272 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_suppliers, COUNT(DISTINCT c.rowid) as nb,";
3273 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3274 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as cd";
3275 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as c";
3276 $sql .=
", ".$this->db->prefix().
"societe as s";
3277 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid && !$forVirtualStock) {
3278 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3280 $sql .=
" WHERE c.rowid = cd.fk_commande";
3281 $sql .=
" AND c.fk_soc = s.rowid";
3282 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3283 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3284 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid && !$forVirtualStock) {
3285 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3288 $sql .=
" AND c.fk_soc = ".((int) $socid);
3290 if ($filtrestatut !=
'') {
3291 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3293 if (!empty($dateofvirtualstock)) {
3294 $sql .=
" AND c.date_livraison <= '".$this->db->idate($dateofvirtualstock).
"'";
3297 $result = $this->db->query($sql);
3299 $obj = $this->db->fetch_object($result);
3300 $this->stats_commande_fournisseur[
'suppliers'] = $obj->nb_suppliers;
3301 $this->stats_commande_fournisseur[
'nb'] = $obj->nb;
3302 $this->stats_commande_fournisseur[
'rows'] = $obj->nb_rows;
3303 $this->stats_commande_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
3305 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3306 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierOrder', $parameters, $this, $action);
3308 $this->stats_commande_fournisseur = $hookmanager->resArray[
'stats_commande_fournisseur'];
3313 $this->error = $this->db->error().
' sql='.$sql;
3328 public function load_stats_sending($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $filterShipmentStatus =
'')
3331 global $conf, $user, $hookmanager, $action;
3333 $sql =
"SELECT COUNT(DISTINCT e.fk_soc) as nb_customers, COUNT(DISTINCT e.rowid) as nb,";
3334 $sql .=
" COUNT(ed.rowid) as nb_rows, SUM(ed.qty) as qty";
3335 $sql .=
" FROM ".$this->db->prefix().
"expeditiondet as ed";
3336 $sql .=
", ".$this->db->prefix().
"commandedet as cd";
3337 $sql .=
", ".$this->db->prefix().
"commande as c";
3338 $sql .=
", ".$this->db->prefix().
"expedition as e";
3339 $sql .=
", ".$this->db->prefix().
"societe as s";
3340 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid && !$forVirtualStock) {
3341 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3343 $sql .=
" WHERE e.rowid = ed.fk_expedition";
3344 $sql .=
" AND c.rowid = cd.fk_commande";
3345 $sql .=
" AND e.fk_soc = s.rowid";
3346 $sql .=
" AND e.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'expedition').
")";
3347 $sql .=
" AND ed.fk_origin_line = cd.rowid";
3348 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3349 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid && !$forVirtualStock) {
3350 $sql .=
" AND e.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3353 $sql .=
" AND e.fk_soc = ".((int) $socid);
3355 if ($filtrestatut !=
'') {
3356 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3358 if (!empty($filterShipmentStatus)) {
3359 $sql .=
" AND e.fk_statut IN (".$this->db->sanitize($filterShipmentStatus).
")";
3362 $result = $this->db->query($sql);
3364 $obj = $this->db->fetch_object($result);
3365 $this->stats_expedition[
'customers'] = $obj->nb_customers;
3366 $this->stats_expedition[
'nb'] = $obj->nb;
3367 $this->stats_expedition[
'rows'] = $obj->nb_rows;
3368 $this->stats_expedition[
'qty'] = $obj->qty ? $obj->qty : 0;
3373 if (is_array($TFather) && !empty($TFather)) {
3374 foreach ($TFather as &$fatherData) {
3375 $pFather =
new Product($this->db);
3376 $pFather->id = $fatherData[
'id'];
3377 $qtyCoef = $fatherData[
'qty'];
3379 if ($fatherData[
'incdec']) {
3380 $pFather->load_stats_sending($socid, $filtrestatut, $forVirtualStock);
3382 $this->stats_expedition[
'customers'] += $pFather->stats_expedition[
'customers'];
3383 $this->stats_expedition[
'nb'] += $pFather->stats_expedition[
'nb'];
3384 $this->stats_expedition[
'rows'] += $pFather->stats_expedition[
'rows'];
3385 $this->stats_expedition[
'qty'] += $pFather->stats_expedition[
'qty'] * $qtyCoef;
3391 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock,
'filterShipmentStatus' => $filterShipmentStatus);
3392 $reshook = $hookmanager->executeHooks(
'loadStatsSending', $parameters, $this, $action);
3394 $this->stats_expedition = $hookmanager->resArray[
'stats_expedition'];
3399 $this->error = $this->db->error();
3414 public function load_stats_reception($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null)
3417 global $conf, $user, $hookmanager, $action;
3419 $sql =
"SELECT COUNT(DISTINCT cf.fk_soc) as nb_suppliers, COUNT(DISTINCT cf.rowid) as nb,";
3420 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
3421 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseur_dispatch as fd";
3422 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as cf";
3423 $sql .=
", ".$this->db->prefix().
"societe as s";
3424 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid && !$forVirtualStock) {
3425 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3427 $sql .=
" WHERE cf.rowid = fd.fk_commande";
3428 $sql .=
" AND cf.fk_soc = s.rowid";
3429 $sql .=
" AND cf.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3430 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3431 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid && !$forVirtualStock) {
3432 $sql .=
" AND cf.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3435 $sql .=
" AND cf.fk_soc = ".((int) $socid);
3437 if ($filtrestatut !=
'') {
3438 $sql .=
" AND cf.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3440 if (!empty($dateofvirtualstock)) {
3441 $sql .=
" AND fd.datec <= '".$this->db->idate($dateofvirtualstock).
"'";
3444 $result = $this->db->query($sql);
3446 $obj = $this->db->fetch_object($result);
3447 $this->stats_reception[
'suppliers'] = $obj->nb_suppliers;
3448 $this->stats_reception[
'nb'] = $obj->nb;
3449 $this->stats_reception[
'rows'] = $obj->nb_rows;
3450 $this->stats_reception[
'qty'] = $obj->qty ? $obj->qty : 0;
3452 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3453 $reshook = $hookmanager->executeHooks(
'loadStatsReception', $parameters, $this, $action);
3455 $this->stats_reception = $hookmanager->resArray[
'stats_reception'];
3460 $this->error = $this->db->error();
3478 global $conf, $user, $hookmanager, $action;
3480 $serviceStockIsEnabled = isModEnabled(
"service") &&
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES');
3482 $sql =
"SELECT COUNT(DISTINCT m.fk_soc) as nb_customers, COUNT(DISTINCT m.rowid) as nb,";
3483 $sql .=
" COUNT(mp.rowid) as nb_rows, SUM(mp.qty) as qty, role";
3484 $sql .=
" FROM ".$this->db->prefix().
"mrp_production as mp";
3485 $sql .=
", ".$this->db->prefix().
"mrp_mo as m";
3486 $sql .=
" LEFT JOIN ".$this->db->prefix().
"societe as s ON s.rowid = m.fk_soc";
3487 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid && !$forVirtualStock) {
3488 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3490 $sql .=
" WHERE m.rowid = mp.fk_mo";
3491 $sql .=
" AND m.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'mrp').
")";
3492 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3493 $sql .=
" AND (mp.disable_stock_change IN (0) OR mp.disable_stock_change IS NULL)";
3494 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid && !$forVirtualStock) {
3495 $sql .=
" AND m.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3498 $sql .=
" AND m.fk_soc = ".((int) $socid);
3500 if ($filtrestatut !=
'') {
3501 $sql .=
" AND m.status IN (".$this->db->sanitize($filtrestatut).
")";
3503 if (!empty($dateofvirtualstock)) {
3504 $sql .=
" AND m.date_valid <= '".$this->db->idate($dateofvirtualstock).
"'";
3506 if (!$serviceStockIsEnabled) {
3507 $sql .=
"AND EXISTS (SELECT p.rowid FROM ".$this->db->prefix().
"product AS p WHERE p.rowid = ".((int) $this->
id).
" AND p.fk_product_type IN (0))";
3509 $sql .=
" GROUP BY role";
3511 $this->stats_mrptoconsume[
'customers'] = 0;
3512 $this->stats_mrptoconsume[
'nb'] = 0;
3513 $this->stats_mrptoconsume[
'rows'] = 0;
3514 $this->stats_mrptoconsume[
'qty'] = 0;
3515 $this->stats_mrptoproduce[
'customers'] = 0;
3516 $this->stats_mrptoproduce[
'nb'] = 0;
3517 $this->stats_mrptoproduce[
'rows'] = 0;
3518 $this->stats_mrptoproduce[
'qty'] = 0;
3520 $result = $this->db->query($sql);
3522 while ($obj = $this->db->fetch_object($result)) {
3523 if ($obj->role ==
'toconsume') {
3524 $this->stats_mrptoconsume[
'customers'] += $obj->nb_customers;
3525 $this->stats_mrptoconsume[
'nb'] += $obj->nb;
3526 $this->stats_mrptoconsume[
'rows'] += $obj->nb_rows;
3527 $this->stats_mrptoconsume[
'qty'] += ($obj->qty ? $obj->qty : 0);
3529 if ($obj->role ==
'consumed') {
3533 $this->stats_mrptoconsume[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3535 if ($obj->role ==
'toproduce') {
3536 $this->stats_mrptoproduce[
'customers'] += $obj->nb_customers;
3537 $this->stats_mrptoproduce[
'nb'] += $obj->nb;
3538 $this->stats_mrptoproduce[
'rows'] += $obj->nb_rows;
3539 $this->stats_mrptoproduce[
'qty'] += ($obj->qty ? $obj->qty : 0);
3541 if ($obj->role ==
'produced') {
3545 $this->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3550 if ($this->stats_mrptoconsume[
'qty'] < 0) {
3551 $this->stats_mrptoconsume[
'qty'] = 0;
3553 if ($this->stats_mrptoproduce[
'qty'] < 0) {
3554 $this->stats_mrptoproduce[
'qty'] = 0;
3557 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3558 $reshook = $hookmanager->executeHooks(
'loadStatsInProduction', $parameters, $this, $action);
3560 $this->stats_mrptoproduce = $hookmanager->resArray[
'stats_mrptoproduce'];
3565 $this->error = $this->db->error();
3580 global $conf, $user, $hookmanager, $action;
3582 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3583 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3584 $sql .=
" FROM ".$this->db->prefix().
"contratdet as cd";
3585 $sql .=
", ".$this->db->prefix().
"contrat as c";
3586 $sql .=
", ".$this->db->prefix().
"societe as s";
3587 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
3588 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3590 $sql .=
" WHERE c.rowid = cd.fk_contrat";
3591 $sql .=
" AND c.fk_soc = s.rowid";
3592 $sql .=
" AND c.entity IN (".getEntity(
'contract').
")";
3593 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3594 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
3595 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3599 $sql .=
" AND c.fk_soc = ".((int) $socid);
3602 $result = $this->db->query($sql);
3604 $obj = $this->db->fetch_object($result);
3605 $this->stats_contrat[
'customers'] = $obj->nb_customers;
3606 $this->stats_contrat[
'nb'] = $obj->nb;
3607 $this->stats_contrat[
'rows'] = $obj->nb_rows;
3608 $this->stats_contrat[
'qty'] = $obj->qty ? $obj->qty : 0;
3613 if (is_array($TFather) && !empty($TFather)) {
3614 foreach ($TFather as &$fatherData) {
3615 $pFather =
new Product($this->db);
3616 $pFather->id = $fatherData[
'id'];
3617 $qtyCoef = $fatherData[
'qty'];
3619 if ($fatherData[
'incdec']) {
3620 $pFather->load_stats_contrat($socid);
3622 $this->stats_contrat[
'customers'] += $pFather->stats_contrat[
'customers'];
3623 $this->stats_contrat[
'nb'] += $pFather->stats_contrat[
'nb'];
3624 $this->stats_contrat[
'rows'] += $pFather->stats_contrat[
'rows'];
3625 $this->stats_contrat[
'qty'] += $pFather->stats_contrat[
'qty'] * $qtyCoef;
3631 $parameters = array(
'socid' => $socid);
3632 $reshook = $hookmanager->executeHooks(
'loadStatsContract', $parameters, $this, $action);
3634 $this->stats_contrat = $hookmanager->resArray[
'stats_contrat'];
3639 $this->error = $this->db->error().
' sql='.$sql;
3654 global $conf, $user, $hookmanager, $action;
3656 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
3657 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(".$this->db->ifsql(
'f.type != 2',
'fd.qty',
'fd.qty * -1').
") as qty";
3658 $sql .=
" FROM ".$this->db->prefix().
"facturedet as fd";
3659 $sql .=
", ".$this->db->prefix().
"facture as f";
3660 $sql .=
", ".$this->db->prefix().
"societe as s";
3661 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
3662 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3664 $sql .=
" WHERE f.rowid = fd.fk_facture";
3665 $sql .=
" AND f.fk_soc = s.rowid";
3666 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
3667 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3668 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
3669 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3673 $sql .=
" AND f.fk_soc = ".((int) $socid);
3676 $result = $this->db->query($sql);
3678 $obj = $this->db->fetch_object($result);
3679 $this->stats_facture[
'customers'] = $obj->nb_customers;
3680 $this->stats_facture[
'nb'] = $obj->nb;
3681 $this->stats_facture[
'rows'] = $obj->nb_rows;
3682 $this->stats_facture[
'qty'] = $obj->qty ? $obj->qty : 0;
3687 if (is_array($TFather) && !empty($TFather)) {
3688 foreach ($TFather as &$fatherData) {
3689 $pFather =
new Product($this->db);
3690 $pFather->id = $fatherData[
'id'];
3691 $qtyCoef = $fatherData[
'qty'];
3693 if ($fatherData[
'incdec']) {
3694 $pFather->load_stats_facture($socid);
3696 $this->stats_facture[
'customers'] += $pFather->stats_facture[
'customers'];
3697 $this->stats_facture[
'nb'] += $pFather->stats_facture[
'nb'];
3698 $this->stats_facture[
'rows'] += $pFather->stats_facture[
'rows'];
3699 $this->stats_facture[
'qty'] += $pFather->stats_facture[
'qty'] * $qtyCoef;
3705 $parameters = array(
'socid' => $socid);
3706 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoice', $parameters, $this, $action);
3708 $this->stats_facture = $hookmanager->resArray[
'stats_facture'];
3713 $this->error = $this->db->error();
3729 global $conf, $user, $hookmanager, $action;
3731 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
3732 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
3733 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facturedet_rec as fd";
3734 $sql .=
", ".MAIN_DB_PREFIX.
"facture_rec as f";
3735 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
3736 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
3737 $sql .=
", ".MAIN_DB_PREFIX.
"societe_commerciaux as sc";
3739 $sql .=
" WHERE f.rowid = fd.fk_facture";
3740 $sql .=
" AND f.fk_soc = s.rowid";
3741 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
3742 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3743 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
3744 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3748 $sql .=
" AND f.fk_soc = ".((int) $socid);
3751 $result = $this->db->query($sql);
3753 $obj = $this->db->fetch_object($result);
3754 $this->stats_facturerec[
'customers'] = $obj->nb_customers;
3755 $this->stats_facturerec[
'nb'] = $obj->nb;
3756 $this->stats_facturerec[
'rows'] = $obj->nb_rows;
3757 $this->stats_facturerec[
'qty'] = $obj->qty ? $obj->qty : 0;
3762 if (is_array($TFather) && !empty($TFather)) {
3763 foreach ($TFather as &$fatherData) {
3764 $pFather =
new Product($this->db);
3765 $pFather->id = $fatherData[
'id'];
3766 $qtyCoef = $fatherData[
'qty'];
3768 if ($fatherData[
'incdec']) {
3769 $pFather->load_stats_facture($socid);
3771 $this->stats_facturerec[
'customers'] += $pFather->stats_facturerec[
'customers'];
3772 $this->stats_facturerec[
'nb'] += $pFather->stats_facturerec[
'nb'];
3773 $this->stats_facturerec[
'rows'] += $pFather->stats_facturerec[
'rows'];
3774 $this->stats_facturerec[
'qty'] += $pFather->stats_facturerec[
'qty'] * $qtyCoef;
3780 $parameters = array(
'socid' => $socid);
3781 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoiceRec', $parameters, $this, $action);
3783 $this->stats_facturerec = $hookmanager->resArray[
'stats_facturerec'];
3788 $this->error = $this->db->error();
3803 global $conf, $user, $hookmanager, $action;
3805 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
3806 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
3807 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as fd";
3808 $sql .=
", ".$this->db->prefix().
"facture_fourn as f";
3809 $sql .=
", ".$this->db->prefix().
"societe as s";
3810 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
3811 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3813 $sql .=
" WHERE f.rowid = fd.fk_facture_fourn";
3814 $sql .=
" AND f.fk_soc = s.rowid";
3815 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
3816 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3817 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
3818 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3822 $sql .=
" AND f.fk_soc = ".((int) $socid);
3825 $result = $this->db->query($sql);
3827 $obj = $this->db->fetch_object($result);
3828 $this->stats_facture_fournisseur[
'suppliers'] = $obj->nb_suppliers;
3829 $this->stats_facture_fournisseur[
'nb'] = $obj->nb;
3830 $this->stats_facture_fournisseur[
'rows'] = $obj->nb_rows;
3831 $this->stats_facture_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
3833 $parameters = array(
'socid' => $socid);
3834 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoice', $parameters, $this, $action);
3836 $this->stats_facture_fournisseur = $hookmanager->resArray[
'stats_facture_fournisseur'];
3841 $this->error = $this->db->error();
3860 $resql = $this->db->query($sql);
3862 $num = $this->db->num_rows($resql);
3865 $arr = $this->db->fetch_array($resql);
3866 $keyfortab = (string) $arr[1];
3868 $keyfortab = substr($keyfortab, -2);
3871 if ($mode ==
'byunit') {
3872 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[0];
3873 } elseif ($mode ==
'bynumber') {
3874 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
3875 } elseif ($mode ==
'byamount') {
3876 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
3884 $this->error = $this->db->error().
' sql='.$sql;
3889 $year = strftime(
'%Y', time());
3890 $month = strftime(
'%m', time());
3891 } elseif ($year == -1) {
3900 for ($j = 0; $j < 12; $j++) {
3902 $idx = ucfirst(
dol_trunc(
dol_print_date(
dol_mktime(12, 0, 0, $month, 1, 1970),
"%b"), 1,
'right',
'UTF-8', 1));
3905 $result[$j] = array($idx, isset($tab[$year.$month]) ? $tab[$year.$month] : 0);
3908 $month =
"0".($month - 1);
3910 $month = substr($month, 1);
3918 return array_reverse($result);
3933 public function get_nb_vente($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
3939 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
3940 if ($mode ==
'bynumber') {
3941 $sql .=
", count(DISTINCT f.rowid)";
3943 $sql .=
", sum(d.total_ht) as total_ht";
3944 $sql .=
" FROM ".$this->db->prefix().
"facturedet as d, ".$this->db->prefix().
"facture as f, ".$this->db->prefix().
"societe as s";
3945 if ($filteronproducttype >= 0) {
3946 $sql .=
", ".$this->db->prefix().
"product as p";
3948 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
3949 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3951 $sql .=
" WHERE f.rowid = d.fk_facture";
3952 if ($this->
id > 0) {
3953 $sql .=
" AND d.fk_product = ".((int) $this->
id);
3955 $sql .=
" AND d.fk_product > 0";
3957 if ($filteronproducttype >= 0) {
3958 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
3960 $sql .=
" AND f.fk_soc = s.rowid";
3961 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
3962 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
3963 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3966 $sql .=
" AND f.fk_soc = $socid";
3968 $sql .= $morefilter;
3969 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
3970 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
3972 return $this->
_get_stats($sql, $mode, $year);
3987 public function get_nb_achat($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
3993 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
3994 if ($mode ==
'bynumber') {
3995 $sql .=
", count(DISTINCT f.rowid)";
3997 $sql .=
", sum(d.total_ht) as total_ht";
3998 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as d, ".$this->db->prefix().
"facture_fourn as f, ".$this->db->prefix().
"societe as s";
3999 if ($filteronproducttype >= 0) {
4000 $sql .=
", ".$this->db->prefix().
"product as p";
4002 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
4003 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4005 $sql .=
" WHERE f.rowid = d.fk_facture_fourn";
4006 if ($this->
id > 0) {
4007 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4009 $sql .=
" AND d.fk_product > 0";
4011 if ($filteronproducttype >= 0) {
4012 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4014 $sql .=
" AND f.fk_soc = s.rowid";
4015 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4016 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
4017 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4020 $sql .=
" AND f.fk_soc = $socid";
4022 $sql .= $morefilter;
4023 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4024 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4026 return $this->
_get_stats($sql, $mode, $year);
4040 public function get_nb_propal($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4043 global $conf, $user;
4045 $sql =
"SELECT sum(d.qty) as qty, date_format(p.datep, '%Y%m')";
4046 if ($mode ==
'bynumber') {
4047 $sql .=
", count(DISTINCT p.rowid)";
4049 $sql .=
", sum(d.total_ht) as total_ht";
4050 $sql .=
" FROM ".$this->db->prefix().
"propaldet as d, ".$this->db->prefix().
"propal as p, ".$this->db->prefix().
"societe as s";
4051 if ($filteronproducttype >= 0) {
4052 $sql .=
", ".$this->db->prefix().
"product as prod";
4054 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
4055 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4057 $sql .=
" WHERE p.rowid = d.fk_propal";
4058 if ($this->
id > 0) {
4059 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4061 $sql .=
" AND d.fk_product > 0";
4063 if ($filteronproducttype >= 0) {
4064 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4066 $sql .=
" AND p.fk_soc = s.rowid";
4067 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
4068 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
4069 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4072 $sql .=
" AND p.fk_soc = ".((int) $socid);
4074 $sql .= $morefilter;
4075 $sql .=
" GROUP BY date_format(p.datep,'%Y%m')";
4076 $sql .=
" ORDER BY date_format(p.datep,'%Y%m') DESC";
4078 return $this->
_get_stats($sql, $mode, $year);
4098 $sql =
"SELECT sum(d.qty) as qty, date_format(p.date_valid, '%Y%m')";
4099 if ($mode ==
'bynumber') {
4100 $sql .=
", count(DISTINCT p.rowid)";
4102 $sql .=
", sum(d.total_ht) as total_ht";
4103 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as d, ".$this->db->prefix().
"supplier_proposal as p, ".$this->db->prefix().
"societe as s";
4104 if ($filteronproducttype >= 0) {
4105 $sql .=
", ".$this->db->prefix().
"product as prod";
4107 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
4108 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4110 $sql .=
" WHERE p.rowid = d.fk_supplier_proposal";
4111 if ($this->
id > 0) {
4112 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4114 $sql .=
" AND d.fk_product > 0";
4116 if ($filteronproducttype >= 0) {
4117 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4119 $sql .=
" AND p.fk_soc = s.rowid";
4120 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
4121 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
4122 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4125 $sql .=
" AND p.fk_soc = ".((int) $socid);
4127 $sql .= $morefilter;
4128 $sql .=
" GROUP BY date_format(p.date_valid,'%Y%m')";
4129 $sql .=
" ORDER BY date_format(p.date_valid,'%Y%m') DESC";
4131 return $this->
_get_stats($sql, $mode, $year);
4145 public function get_nb_order($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4148 global $conf, $user;
4150 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4151 if ($mode ==
'bynumber') {
4152 $sql .=
", count(DISTINCT c.rowid)";
4154 $sql .=
", sum(d.total_ht) as total_ht";
4155 $sql .=
" FROM ".$this->db->prefix().
"commandedet as d, ".$this->db->prefix().
"commande as c, ".$this->db->prefix().
"societe as s";
4156 if ($filteronproducttype >= 0) {
4157 $sql .=
", ".$this->db->prefix().
"product as p";
4159 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
4160 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4162 $sql .=
" WHERE c.rowid = d.fk_commande";
4163 if ($this->
id > 0) {
4164 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4166 $sql .=
" AND d.fk_product > 0";
4168 if ($filteronproducttype >= 0) {
4169 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4171 $sql .=
" AND c.fk_soc = s.rowid";
4172 $sql .=
" AND c.entity IN (".getEntity(
'commande').
")";
4173 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
4174 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4177 $sql .=
" AND c.fk_soc = ".((int) $socid);
4179 $sql .= $morefilter;
4180 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4181 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4183 return $this->
_get_stats($sql, $mode, $year);
4200 global $conf, $user;
4202 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4203 if ($mode ==
'bynumber') {
4204 $sql .=
", count(DISTINCT c.rowid)";
4206 $sql .=
", sum(d.total_ht) as total_ht";
4207 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as d, ".$this->db->prefix().
"commande_fournisseur as c, ".$this->db->prefix().
"societe as s";
4208 if ($filteronproducttype >= 0) {
4209 $sql .=
", ".$this->db->prefix().
"product as p";
4211 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
4212 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4214 $sql .=
" WHERE c.rowid = d.fk_commande";
4215 if ($this->
id > 0) {
4216 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4218 $sql .=
" AND d.fk_product > 0";
4220 if ($filteronproducttype >= 0) {
4221 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4223 $sql .=
" AND c.fk_soc = s.rowid";
4224 $sql .=
" AND c.entity IN (".getEntity(
'supplier_order').
")";
4225 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
4226 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4229 $sql .=
" AND c.fk_soc = ".((int) $socid);
4231 $sql .= $morefilter;
4232 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4233 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4235 return $this->
_get_stats($sql, $mode, $year);
4249 public function get_nb_contract($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4252 global $conf, $user;
4254 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_contrat, '%Y%m')";
4255 if ($mode ==
'bynumber') {
4256 $sql .=
", count(DISTINCT c.rowid)";
4258 $sql .=
", sum(d.total_ht) as total_ht";
4259 $sql .=
" FROM ".$this->db->prefix().
"contratdet as d, ".$this->db->prefix().
"contrat as c, ".$this->db->prefix().
"societe as s";
4260 if ($filteronproducttype >= 0) {
4261 $sql .=
", ".$this->db->prefix().
"product as p";
4263 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
4264 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4267 $sql .=
" WHERE c.entity IN (".getEntity(
'contract').
")";
4268 $sql .=
" AND c.rowid = d.fk_contrat";
4270 if ($this->
id > 0) {
4271 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4273 $sql .=
" AND d.fk_product > 0";
4275 if ($filteronproducttype >= 0) {
4276 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4278 $sql .=
" AND c.fk_soc = s.rowid";
4280 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
4281 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4284 $sql .=
" AND c.fk_soc = ".((int) $socid);
4286 $sql .= $morefilter;
4287 $sql .=
" GROUP BY date_format(c.date_contrat,'%Y%m')";
4288 $sql .=
" ORDER BY date_format(c.date_contrat,'%Y%m') DESC";
4290 return $this->
_get_stats($sql, $mode, $year);
4304 public function get_nb_mos($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4307 global $conf, $user;
4309 $sql =
"SELECT sum(d.qty), date_format(d.date_valid, '%Y%m')";
4310 if ($mode ==
'bynumber') {
4311 $sql .=
", count(DISTINCT d.rowid)";
4313 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as d LEFT JOIN ".$this->db->prefix().
"societe as s ON d.fk_soc = s.rowid";
4314 if ($filteronproducttype >= 0) {
4315 $sql .=
", ".$this->db->prefix().
"product as p";
4317 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
4318 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4321 $sql .=
" WHERE d.entity IN (".getEntity(
'mo').
")";
4322 $sql .=
" AND d.status > 0";
4324 if ($this->
id > 0) {
4325 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4327 $sql .=
" AND d.fk_product > 0";
4329 if ($filteronproducttype >= 0) {
4330 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4333 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid) {
4334 $sql .=
" AND d.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4337 $sql .=
" AND d.fk_soc = ".((int) $socid);
4339 $sql .= $morefilter;
4340 $sql .=
" GROUP BY date_format(d.date_valid,'%Y%m')";
4341 $sql .=
" ORDER BY date_format(d.date_valid,'%Y%m') DESC";
4343 return $this->
_get_stats($sql, $mode, $year);
4363 if (!is_numeric($id_pere)) {
4366 if (!is_numeric($id_fils)) {
4369 if (!is_numeric($incdec)) {
4379 $sql =
"SELECT fk_product_pere from ".$this->db->prefix().
"product_association";
4380 $sql .=
" WHERE fk_product_pere = ".((int) $id_fils).
" AND fk_product_fils = ".((int) $id_pere);
4381 if (!$this->db->query($sql)) {
4386 $sql =
"SELECT MAX(rang) as max_rank FROM ".$this->db->prefix().
"product_association";
4387 $sql .=
" WHERE fk_product_pere = ".((int) $id_pere);
4388 $resql = $this->db->query($sql);
4390 $obj = $this->db->fetch_object($resql);
4391 $rank = $obj->max_rank + 1;
4393 $sql =
"INSERT INTO ".$this->db->prefix().
"product_association(fk_product_pere,fk_product_fils,qty,incdec,rang)";
4394 $sql .=
" VALUES (".((int) $id_pere).
", ".((int) $id_fils).
", ".
price2num($qty,
'MS').
", ".
price2num($incdec,
'MS').
", ".((int) $rank).
")";
4395 if (! $this->db->query($sql)) {
4401 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_ADD', $user);
4403 $this->error = $this->db->lasterror();
4404 dol_syslog(get_class($this).
'::addSubproduct error='.$this->error, LOG_ERR);
4436 if (!is_numeric($id_pere)) {
4439 if (!is_numeric($id_fils)) {
4442 if (!is_numeric($incdec)) {
4445 if (!is_numeric($qty)) {
4449 $sql =
'UPDATE '.$this->db->prefix().
'product_association SET ';
4450 $sql .=
'qty = '.price2num($qty,
'MS');
4451 $sql .=
',incdec = '.price2num($incdec,
'MS');
4452 $sql .=
' WHERE fk_product_pere = '.((int) $id_pere).
' AND fk_product_fils = '.((int) $id_fils);
4454 if (!$this->db->query($sql)) {
4460 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_UPDATE', $user);
4462 $this->error = $this->db->lasterror();
4463 dol_syslog(get_class($this).
'::updateSubproduct error='.$this->error, LOG_ERR);
4487 if (!is_numeric($fk_parent)) {
4490 if (!is_numeric($fk_child)) {
4494 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
4495 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
4496 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
4498 dol_syslog(get_class($this).
'::del_sousproduit', LOG_DEBUG);
4499 if (!$this->db->query($sql)) {
4505 $sqlrank =
"SELECT rowid, rang FROM ".$this->db->prefix().
"product_association";
4506 $sqlrank.=
" WHERE fk_product_pere = ".((int) $fk_parent);
4507 $sqlrank.=
" ORDER BY rang";
4508 $resqlrank = $this->db->query($sqlrank);
4511 while ($objrank = $this->db->fetch_object($resqlrank)) {
4513 $sql =
"UPDATE ".$this->db->prefix().
"product_association";
4514 $sql.=
" SET rang = ".((int) $cpt);
4515 $sql.=
" WHERE rowid = ".((int) $objrank->rowid);
4516 if (! $this->db->query($sql)) {
4525 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_DELETE', $user);
4527 $this->error = $this->db->lasterror();
4528 dol_syslog(get_class($this).
'::delSubproduct error='.$this->error, LOG_ERR);
4548 $sql =
"SELECT fk_product_pere, qty, incdec";
4549 $sql .=
" FROM ".$this->db->prefix().
"product_association";
4550 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
4551 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
4553 $result = $this->db->query($sql);
4555 $num = $this->db->num_rows($result);
4558 $obj = $this->db->fetch_object($result);
4560 $this->is_sousproduit_qty = $obj->qty;
4561 $this->is_sousproduit_incdec = $obj->incdec;
4592 dol_syslog(get_class($this).
"::add_fournisseur id_fourn = ".$id_fourn.
" ref_fourn=".
$ref_fourn.
" quantity=".$quantity, LOG_DEBUG);
4598 $sql =
"SELECT rowid, fk_product";
4599 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
4600 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
4601 $sql .=
" AND ref_fourn = '".$this->db->escape(
$ref_fourn).
"'";
4602 $sql .=
" AND fk_product <> ".((int) $this->
id);
4603 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
4605 $resql = $this->db->query($sql);
4607 $obj = $this->db->fetch_object($resql);
4610 $this->product_id_already_linked = $obj->fk_product;
4613 $this->db->free($resql);
4617 $sql =
"SELECT rowid";
4618 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
4619 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
4621 $sql .=
" AND ref_fourn = '".$this->db->escape(
$ref_fourn).
"'";
4623 $sql .=
" AND (ref_fourn = '' OR ref_fourn IS NULL)";
4625 $sql .=
" AND quantity = ".((float) $quantity);
4626 $sql .=
" AND fk_product = ".((int) $this->
id);
4627 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
4629 $resql = $this->db->query($sql);
4631 $obj = $this->db->fetch_object($resql);
4635 $sql =
"INSERT INTO ".$this->db->prefix().
"product_fournisseur_price(";
4638 $sql .=
", fk_product";
4640 $sql .=
", ref_fourn";
4641 $sql .=
", quantity";
4642 $sql .=
", fk_user";
4644 $sql .=
") VALUES (";
4645 $sql .=
"'".$this->db->idate($now).
"'";
4646 $sql .=
", ".$conf->entity;
4647 $sql .=
", ".$this->id;
4648 $sql .=
", ".$id_fourn;
4649 $sql .=
", '".$this->db->escape(
$ref_fourn).
"'";
4650 $sql .=
", ".$quantity;
4651 $sql .=
", ".$user->id;
4655 if ($this->db->query($sql)) {
4656 $this->product_fourn_price_id = $this->db->last_insert_id($this->db->prefix().
"product_fournisseur_price");
4659 $this->error = $this->db->lasterror();
4664 $this->product_fourn_price_id = $obj->rowid;
4668 $this->error = $this->db->lasterror();
4687 $sql =
"SELECT DISTINCT p.fk_soc";
4688 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as p";
4689 $sql .=
" WHERE p.fk_product = ".((int) $this->
id);
4690 $sql .=
" AND p.entity = ".((int) $conf->entity);
4692 $result = $this->db->query($sql);
4694 $num = $this->db->num_rows($result);
4697 $obj = $this->db->fetch_object($result);
4698 $list[$i] = $obj->fk_soc;
4716 global $conf, $user;
4723 $sql =
"INSERT INTO ".$this->db->prefix().
"product_price (";
4725 $sql .=
", fk_product";
4726 $sql .=
", date_price";
4727 $sql .=
", price_level";
4729 $sql .=
", price_ttc";
4730 $sql .=
", price_min";
4731 $sql .=
", price_min_ttc";
4732 $sql .=
", price_base_type";
4733 $sql .=
", default_vat_code";
4735 $sql .=
", recuperableonly";
4736 $sql .=
", localtax1_tx";
4737 $sql .=
", localtax1_type";
4738 $sql .=
", localtax2_tx";
4739 $sql .=
", localtax2_type";
4740 $sql .=
", fk_user_author";
4742 $sql .=
", price_by_qty";
4743 $sql .=
", fk_price_expression";
4744 $sql .=
", fk_multicurrency";
4745 $sql .=
", multicurrency_code";
4746 $sql .=
", multicurrency_tx";
4747 $sql .=
", multicurrency_price";
4748 $sql .=
", multicurrency_price_ttc";
4753 $sql .=
", '".$this->db->idate($now).
"'";
4754 $sql .=
", price_level";
4756 $sql .=
", price_ttc";
4757 $sql .=
", price_min";
4758 $sql .=
", price_min_ttc";
4759 $sql .=
", price_base_type";
4760 $sql .=
", default_vat_code";
4762 $sql .=
", recuperableonly";
4763 $sql .=
", localtax1_tx";
4764 $sql .=
", localtax1_type";
4765 $sql .=
", localtax2_tx";
4766 $sql .=
", localtax2_type";
4767 $sql .=
", ".$user->id;
4769 $sql .=
", price_by_qty";
4770 $sql .=
", fk_price_expression";
4771 $sql .=
", fk_multicurrency";
4772 $sql .=
", multicurrency_code";
4773 $sql .=
", multicurrency_tx";
4774 $sql .=
", multicurrency_price";
4775 $sql .=
", multicurrency_price_ttc";
4776 $sql .=
" FROM ".$this->db->prefix().
"product_price ps";
4777 $sql .=
" WHERE fk_product = ".((int) $fromId);
4778 $sql .=
" AND date_price IN (SELECT MAX(pd.date_price) FROM ".$this->db->prefix().
"product_price pd WHERE pd.fk_product = ".((int) $fromId).
" AND pd.price_level = ps.price_level)";
4779 $sql .=
" ORDER BY date_price DESC";
4782 $resql = $this->db->query($sql);
4784 $this->db->rollback();
4788 $this->db->commit();
4805 $sql =
'INSERT INTO '.$this->db->prefix().
'product_association (fk_product_pere, fk_product_fils, qty, incdec)';
4806 $sql .=
" SELECT ".$toId.
", fk_product_fils, qty, incdec FROM ".$this->db->prefix().
"product_association";
4807 $sql .=
" WHERE fk_product_pere = ".((int) $fromId);
4809 dol_syslog(get_class($this).
'::clone_association', LOG_DEBUG);
4810 if (!$this->db->query($sql)) {
4811 $this->db->rollback();
4815 $this->db->commit();
4848 $sql =
"INSERT ".$this->db->prefix().
"product_fournisseur_price (";
4849 $sql .=
" datec, fk_product, fk_soc, price, quantity, fk_user, tva_tx)";
4850 $sql .=
" SELECT '".$this->db->idate($now).
"', ".((int) $toId).
", fk_soc, price, quantity, fk_user, tva_tx";
4851 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
4852 $sql .=
" WHERE fk_product = ".((int) $fromId);
4854 dol_syslog(get_class($this).
'::clone_fournisseurs', LOG_DEBUG);
4855 $resql = $this->db->query($sql);
4857 $this->db->rollback();
4860 $this->db->commit();
4878 public function fetch_prod_arbo($prod, $compl_path =
'', $multiply = 1, $level = 1, $id_parent = 0, $ignore_stock_load = 0)
4881 global $conf, $langs;
4885 foreach ($prod as $id_product => $desc_pere) {
4886 if (is_array($desc_pere)) {
4887 $id = (!empty($desc_pere[0]) ? $desc_pere[0] :
'');
4888 $nb = (!empty($desc_pere[1]) ? $desc_pere[1] :
'');
4889 $type = (!empty($desc_pere[2]) ? $desc_pere[2] :
'');
4890 $label = (!empty($desc_pere[3]) ? $desc_pere[3] :
'');
4891 $incdec = (!empty($desc_pere[4]) ? $desc_pere[4] : 0);
4893 if ($multiply < 1) {
4898 if (is_null($tmpproduct)) {
4899 $tmpproduct =
new Product($this->db);
4901 $tmpproduct->fetch($id);
4903 if (empty($ignore_stock_load) && ($tmpproduct->isProduct() ||
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES'))) {
4904 $tmpproduct->load_stock(
'nobatch,novirtual');
4907 $this->res[] = array(
4909 'id_parent'=>$id_parent,
4910 'ref'=>$tmpproduct->ref,
4912 'nb_total'=>$nb * $multiply,
4913 'stock'=>$tmpproduct->stock_reel,
4914 'stock_alert'=>$tmpproduct->seuil_stock_alerte,
4916 'fullpath'=>$compl_path.$label,
4918 'desiredstock'=>$tmpproduct->desiredstock,
4921 'entity'=>$tmpproduct->entity
4925 if (isset($desc_pere[
'childs']) && is_array($desc_pere[
'childs'])) {
4927 $this->
fetch_prod_arbo($desc_pere[
'childs'], $compl_path.$desc_pere[3].
" -> ", $desc_pere[1] * $multiply, $level + 1, $id, $ignore_stock_load);
4945 $this->res = array();
4946 if (isset($this->sousprods) && is_array($this->sousprods)) {
4947 foreach ($this->sousprods as $prod_name => $desc_product) {
4948 if (is_array($desc_product)) {
4949 $this->
fetch_prod_arbo($desc_product,
"", $multiply, 1, $this->
id, $ignore_stock_load);
4968 $sql =
"SELECT COUNT(pa.rowid) as nb";
4969 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa";
4971 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id).
" OR pa.fk_product_pere = ".((int) $this->
id);
4972 } elseif ($mode == -1) {
4973 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id);
4974 } elseif ($mode == 1) {
4975 $sql .=
" WHERE pa.fk_product_pere = ".((int) $this->
id);
4978 $resql = $this->db->query($sql);
4980 $obj = $this->db->fetch_object($resql);
4999 $sql =
"SELECT count(rowid) as nb FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_parent = ".((int) $this->
id);
5000 $sql .=
" AND entity IN (".getEntity(
'product').
")";
5002 $resql = $this->db->query($sql);
5004 $obj = $this->db->fetch_object($resql);
5022 if (isModEnabled(
'variants')) {
5023 $sql =
"SELECT rowid FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_child = ".((int) $this->
id).
" AND entity IN (".
getEntity(
'product').
")";
5025 $query = $this->db->query($sql);
5028 if (!$this->db->num_rows($query)) {
5049 $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";
5050 $sql .=
", p.tosell as status, p.tobuy as status_buy";
5051 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa,";
5052 $sql .=
" ".$this->db->prefix().
"product as p";
5053 $sql .=
" WHERE p.rowid = pa.fk_product_pere";
5054 $sql .=
" AND pa.fk_product_fils = ".((int) $this->
id);
5056 $res = $this->db->query($sql);
5059 while ($record = $this->db->fetch_array(
$res)) {
5061 $prods[$record[
'id']][
'id'] = $record[
'rowid'];
5062 $prods[$record[
'id']][
'ref'] = $record[
'ref'];
5063 $prods[$record[
'id']][
'label'] = $record[
'label'];
5064 $prods[$record[
'id']][
'qty'] = $record[
'qty'];
5065 $prods[$record[
'id']][
'incdec'] = $record[
'incdec'];
5066 $prods[$record[
'id']][
'fk_product_type'] = $record[
'fk_product_type'];
5067 $prods[$record[
'id']][
'entity'] = $record[
'entity'];
5068 $prods[$record[
'id']][
'status'] = $record[
'status'];
5069 $prods[$record[
'id']][
'status_buy'] = $record[
'status_buy'];
5088 public function getChildsArbo($id, $firstlevelonly = 0, $level = 1, $parents = array())
5094 $sql =
"SELECT p.rowid, p.ref, p.label as label, p.fk_product_type,";
5095 $sql .=
" pa.qty as qty, pa.fk_product_fils as id, pa.incdec,";
5096 $sql .=
" pa.rowid as fk_association, pa.rang";
5097 $sql .=
" FROM ".$this->db->prefix().
"product as p,";
5098 $sql .=
" ".$this->db->prefix().
"product_association as pa";
5099 $sql .=
" WHERE p.rowid = pa.fk_product_fils";
5100 $sql .=
" AND pa.fk_product_pere = ".((int) $id);
5101 $sql .=
" AND pa.fk_product_fils <> ".((int) $id);
5102 $sql.=
" ORDER BY pa.rang";
5104 dol_syslog(get_class($this).
'::getChildsArbo id='.$id.
' level='.$level.
' parents='.(is_array($parents) ? implode(
',', $parents) : $parents), LOG_DEBUG);
5111 $res = $this->db->query($sql);
5114 if ($this->db->num_rows(
$res) > 0) {
5118 while ($rec = $this->db->fetch_array(
$res)) {
5119 if (in_array($rec[
'id'], $parents)) {
5120 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);
5124 $prods[$rec[
'rowid']] = array(
5127 2=>$rec[
'fk_product_type'],
5128 3=>$this->db->escape($rec[
'label']),
5131 6=>$rec[
'fk_association'],
5136 if (empty($firstlevelonly)) {
5137 $listofchilds = $this->
getChildsArbo($rec[
'rowid'], 0, $level + 1, $parents);
5138 foreach ($listofchilds as $keyChild => $valueChild) {
5139 $prods[$rec[
'rowid']][
'childs'][$keyChild] = $valueChild;
5163 foreach ($this->
getChildsArbo($this->
id) as $keyChild => $valueChild) {
5164 $parent[$this->label][$keyChild] = $valueChild;
5166 foreach ($parent as $key => $value) {
5167 $this->sousprods[$key] = $value;
5179 global $conf, $langs;
5181 $langs->loadLangs(array(
'products',
'other'));
5184 $nofetch = !empty($params[
'nofetch']);
5187 return [
'optimize' => $langs->trans(
"ShowProduct")];
5190 if (!empty($this->entity)) {
5191 $tmpphoto = $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 80, 0, 0, 0, 0, 1);
5192 if ($this->nbphoto > 0) {
5193 $datas[
'photo'] =
'<div class="photointooltip floatright">'.
"\n" . $tmpphoto .
'</div>';
5198 $datas[
'picto'] =
img_picto(
'',
'product').
' <u class="paddingrightonly">'.$langs->trans(
"Product").
'</u>';
5200 $datas[
'picto']=
img_picto(
'',
'service').
' <u class="paddingrightonly">'.$langs->trans(
"Service").
'</u>';
5202 if (isset($this->
status) && isset($this->status_buy)) {
5203 $datas[
'status']=
' '.$this->getLibStatut(5, 0) .
' '.$this->getLibStatut(5, 1);
5206 if (!empty($this->
ref)) {
5207 $datas[
'ref']=
'<br><b>'.$langs->trans(
'ProductRef').
':</b> '.$this->ref;
5209 if (!empty($this->label)) {
5210 $datas[
'label']=
'<br><b>'.$langs->trans(
'ProductLabel').
':</b> '.$this->label;
5213 $datas[
'description']=
'<br><b>'.$langs->trans(
'ProductDescription').
':</b> '.dolGetFirstLineofText($this->
description, 5);
5216 if (isModEnabled(
'productbatch')) {
5217 $langs->load(
"productbatch");
5218 $datas[
'batchstatus']=
"<br><b>".$langs->trans(
"ManageLotSerial").
'</b>: '.$this->
getLibStatut(0, 2);
5221 if (isModEnabled(
'barcode')) {
5222 $datas[
'barcode']=
'<br><b>'.$langs->trans(
'BarCode').
':</b> '.$this->barcode;
5226 if ($this->weight) {
5227 $datas[
'weight']=
"<br><b>".$langs->trans(
"Weight").
'</b>: '.$this->weight.
' '.
measuringUnitString(0,
"weight", $this->weight_units);
5230 if ($this->length) {
5231 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Length").
'</b>: '.$this->length.
' '.
measuringUnitString(0,
'size', $this->length_units);
5234 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Width").
'</b>: '.$this->width.
' '.
measuringUnitString(0,
'size', $this->width_units);
5236 if ($this->height) {
5237 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Height").
'</b>: '.$this->height.
' '.
measuringUnitString(0,
'size', $this->height_units);
5240 $datas[
'size']=
"<br>".$labelsize;
5243 $labelsurfacevolume =
"";
5244 if ($this->surface) {
5245 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Surface").
'</b>: '.$this->surface.
' '.
measuringUnitString(0,
'surface', $this->surface_units);
5247 if ($this->volume) {
5248 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Volume").
'</b>: '.$this->volume.
' '.
measuringUnitString(0,
'volume', $this->volume_units);
5250 if ($labelsurfacevolume) {
5251 $datas[
'surface']=
"<br>" . $labelsurfacevolume;
5254 if (!empty($this->pmp) && $this->pmp) {
5255 $datas[
'pmp'] =
"<br><b>".$langs->trans(
"PMPValue").
'</b>: '.
price($this->pmp, 0,
'', 1, -1, -1, $conf->currency);
5258 if (isModEnabled(
'accounting')) {
5259 if ($this->
status && isset($this->accountancy_code_sell)) {
5260 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5261 $selllabel =
'<br>';
5262 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellCode').
':</b> '.
length_accountg($this->accountancy_code_sell);
5263 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellIntraCode').
':</b> '.
length_accountg($this->accountancy_code_sell_intra);
5264 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellExportCode').
':</b> '.
length_accountg($this->accountancy_code_sell_export);
5265 $datas[
'accountancysell'] = $selllabel;
5267 if ($this->status_buy && isset($this->accountancy_code_buy)) {
5268 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5270 if (empty($this->
status)) {
5271 $buylabel .=
'<br>';
5273 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyCode').
':</b> '.
length_accountg($this->accountancy_code_buy);
5274 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyIntraCode').
':</b> '.
length_accountg($this->accountancy_code_buy_intra);
5275 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyExportCode').
':</b> '.
length_accountg($this->accountancy_code_buy_export);
5276 $datas[
'accountancybuy'] = $buylabel;
5280 if (isModEnabled(
'categorie') && !$nofetch) {
5281 require_once DOL_DOCUMENT_ROOT .
'/categories/class/categorie.class.php';
5282 $form =
new Form($this->db);
5283 $datas[
'categories'] =
'<br>' . $form->showCategories($this->
id, Categorie::TYPE_PRODUCT, 1);
5302 public function getNomUrl($withpicto = 0, $option =
'', $maxlength = 0, $save_lastsearch_value = -1, $notooltip = 0, $morecss =
'', $add_label = 0, $sep =
' - ')
5304 global $conf, $langs, $hookmanager;
5305 include_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
5309 $newref = $this->ref;
5311 $newref =
dol_trunc($newref, $maxlength,
'middle');
5315 'objecttype' => (isset($this->
type) ? ($this->
type == 1 ?
'service' :
'product') : $this->element),
5316 'option' => $option,
5319 $classfortooltip =
'classfortooltip';
5322 $classfortooltip =
'classforajaxtooltip';
5323 $dataparams =
' data-params="'.dol_escape_htmltag(json_encode($params)).
'"';
5330 if (empty($notooltip)) {
5332 $label = $langs->trans(
"ShowProduct");
5333 $linkclose .=
' alt="'.dol_escape_htmltag($label, 1, 1).
'"';
5335 $linkclose .= ($label ?
' title="'.dol_escape_htmltag($label, 1, 1).
'"' :
' title="tocomplete"');
5336 $linkclose .= $dataparams.
' class="nowraponall '.$classfortooltip.($morecss ?
' '.$morecss :
'').
'"';
5338 $linkclose =
' class="nowraponall'.($morecss ?
' '.$morecss :
'').
'"';
5341 if ($option ==
'supplier' || $option ==
'category') {
5342 $url = DOL_URL_ROOT.
'/product/fournisseurs.php?id='.$this->id;
5343 } elseif ($option ==
'stock') {
5344 $url = DOL_URL_ROOT.
'/product/stock/product.php?id='.$this->id;
5345 } elseif ($option ==
'composition') {
5346 $url = DOL_URL_ROOT.
'/product/composition/card.php?id='.$this->id;
5348 $url = DOL_URL_ROOT.
'/product/card.php?id='.$this->id;
5351 if ($option !==
'nolink') {
5353 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
5354 if ($save_lastsearch_value == -1 && isset($_SERVER[
"PHP_SELF"]) && preg_match(
'/list\.php/', $_SERVER[
"PHP_SELF"])) {
5355 $add_save_lastsearch_values = 1;
5357 if ($add_save_lastsearch_values) {
5358 $url .=
'&save_lastsearch_values=1';
5362 $linkstart =
'<a href="'.$url.
'"';
5363 $linkstart .= $linkclose.
'>';
5366 $result .= $linkstart;
5369 $result .= (
img_object(($notooltip ?
'' : $label),
'product',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
5372 $result .= (
img_object(($notooltip ?
'' : $label),
'service',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
5375 $result .=
'<span class="aaa">'.dol_escape_htmltag($newref).
'</span>';
5376 $result .= $linkend;
5377 if ($withpicto != 2) {
5378 $result .= (($add_label && $this->label) ? $sep.dol_trunc($this->label, ($add_label > 1 ? $add_label : 0)) :
'');
5382 $hookmanager->initHooks(array(
'productdao'));
5383 $parameters = array(
'id'=>$this->
id,
'getnomurl' => &$result,
'label' => &$label);
5384 $reshook = $hookmanager->executeHooks(
'getNomUrl', $parameters, $this, $action);
5386 $result = $hookmanager->resPrint;
5388 $result .= $hookmanager->resPrint;
5405 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
5407 global $conf, $user, $langs;
5409 $langs->load(
"products");
5410 $outputlangs->load(
"products");
5417 $modelpath =
"core/modules/product/doc/";
5419 return $this->
commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
5435 return $this->
LibStatut($this->status_buy, $mode, $type);
5437 return $this->
LibStatut($this->status_batch, $mode, $type);
5440 return $this->
LibStatut($this->status_buy, $mode, $type);
5456 global $conf, $langs;
5458 $labelStatus = $labelStatusShort =
'';
5460 $langs->load(
'products');
5461 if (isModEnabled(
'productbatch')) {
5462 $langs->load(
"productbatch");
5468 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial')));
5469 return dolGetStatus($label);
5471 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort')));
5472 return dolGetStatus($label);
5476 return dolGetStatus($langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch'),
'',
'', empty($status) ?
'status5' :
'status4', 3,
'dot');
5482 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'));
5486 $statuttrans = empty($status) ?
'status5' :
'status4';
5491 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSellShort');
5492 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSell');
5493 } elseif ($type == 1) {
5494 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuyShort');
5495 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuy');
5496 } elseif ($type == 2) {
5497 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch');
5498 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort');
5500 } elseif ($status == 1) {
5503 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSellShort');
5504 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSell');
5505 } elseif ($type == 1) {
5506 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBuyShort');
5507 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBuy');
5508 } elseif ($type == 2) {
5509 $labelStatus = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial'));
5510 $labelStatusShort = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort'));
5512 } elseif ($type == 2 && $status == 2) {
5513 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSerial');
5514 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort');
5518 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'),
'',
'',
'status0', 0);
5520 return dolGetStatus($labelStatus, $labelStatusShort,
'', $statuttrans, $mode);
5533 $langs->load(
'products');
5535 if (isset($this->finished) && $this->finished >= 0) {
5536 $sql =
"SELECT label, code FROM ".$this->db->prefix().
"c_product_nature where code = ".((int) $this->finished).
" AND active=1";
5537 $resql = $this->db->query($sql);
5538 if ($resql && $this->db->num_rows($resql) > 0) {
5539 $res = $this->db->fetch_array($resql);
5540 $label = $langs->trans(
$res[
'label']);
5541 $this->db->free($resql);
5544 $this->error = $this->db->error().
' sql='.$sql;
5545 dol_syslog(__METHOD__.
' Error '.$this->error, LOG_ERR);
5571 public function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label =
'', $price = 0, $inventorycode =
'', $origin_element =
'', $origin_id =
null, $disablestockchangeforsubproduct = 0, $extrafields =
null)
5577 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
5583 $nbpiece = abs($nbpiece);
5586 $op[0] =
"+".trim($nbpiece);
5587 $op[1] =
"-".trim($nbpiece);
5590 $movementstock->setOrigin($origin_element, $origin_id);
5591 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'',
'',
'',
'',
false, 0, $disablestockchangeforsubproduct);
5595 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
5596 $movementstock->array_options = $array_options;
5597 $movementstock->insertExtraFields();
5599 $this->db->commit();
5602 $this->error = $movementstock->error;
5603 $this->errors = $movementstock->errors;
5605 $this->db->rollback();
5634 public function correct_stock_batch($user, $id_entrepot, $nbpiece, $movement, $label =
'', $price = 0, $dlc =
'', $dluo =
'', $lot =
'', $inventorycode =
'', $origin_element =
'', $origin_id =
null, $disablestockchangeforsubproduct = 0, $extrafields =
null, $force_update_batch =
false)
5640 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
5646 $nbpiece = abs($nbpiece);
5649 $op[0] =
"+".trim($nbpiece);
5650 $op[1] =
"-".trim($nbpiece);
5653 $movementstock->setOrigin($origin_element, $origin_id);
5654 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'', $dlc, $dluo, $lot,
false, 0, $disablestockchangeforsubproduct, 0, $force_update_batch);
5658 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
5659 $movementstock->array_options = $array_options;
5660 $movementstock->insertExtraFields();
5662 $this->db->commit();
5665 $this->error = $movementstock->error;
5666 $this->errors = $movementstock->errors;
5668 $this->db->rollback();
5688 public function load_stock($option =
'', $includedraftpoforvirtual =
null, $dateofvirtualstock =
null)
5693 $this->stock_reel = 0;
5694 $this->stock_warehouse = array();
5695 $this->stock_theorique = 0;
5698 $warehouseStatus = array();
5699 if (preg_match(
'/warehouseclosed/', $option)) {
5702 if (preg_match(
'/warehouseopen/', $option)) {
5705 if (preg_match(
'/warehouseinternal/', $option)) {
5713 $sql =
"SELECT ps.rowid, ps.reel, ps.fk_entrepot";
5714 $sql .=
" FROM ".$this->db->prefix().
"product_stock as ps";
5715 $sql .=
", ".$this->db->prefix().
"entrepot as w";
5716 $sql .=
" WHERE w.entity IN (".getEntity(
'stock').
")";
5717 $sql .=
" AND w.rowid = ps.fk_entrepot";
5718 $sql .=
" AND ps.fk_product = ".((int) $this->
id);
5719 if (count($warehouseStatus)) {
5720 $sql .=
" AND w.statut IN (".$this->db->sanitize(implode(
',', $warehouseStatus)).
")";
5723 $sql .=
" ORDER BY ps.reel ".(getDolGlobalString(
'DO_NOT_TRY_TO_DEFRAGMENT_STOCKS_WAREHOUSE') ?
'DESC' :
'ASC');
5725 dol_syslog(get_class($this).
"::load_stock", LOG_DEBUG);
5726 $result = $this->db->query($sql);
5728 $num = $this->db->num_rows($result);
5732 $row = $this->db->fetch_object($result);
5733 $this->stock_warehouse[$row->fk_entrepot] =
new stdClass();
5734 $this->stock_warehouse[$row->fk_entrepot]->real = $row->reel;
5735 $this->stock_warehouse[$row->fk_entrepot]->id = $row->rowid;
5736 if ((!preg_match(
'/nobatch/', $option)) && $this->
hasbatch()) {
5737 $this->stock_warehouse[$row->fk_entrepot]->detail_batch =
Productbatch::findAll($this->db, $row->rowid, 1, $this->id);
5739 $this->stock_reel += $row->reel;
5743 $this->db->free($result);
5745 if (!preg_match(
'/novirtual/', $option)) {
5751 $this->error = $this->db->lasterror();
5770 global $conf, $hookmanager, $action;
5772 $stock_commande_client = 0;
5773 $stock_commande_fournisseur = 0;
5774 $stock_sending_client = 0;
5775 $stock_reception_fournisseur = 0;
5776 $stock_inproduction = 0;
5780 if (isModEnabled(
'commande')) {
5785 $stock_commande_client = $this->stats_commande[
'qty'];
5787 if (isModEnabled(
"expedition")) {
5788 require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expedition.class.php';
5789 $filterShipmentStatus =
'';
5799 $stock_sending_client = $this->stats_expedition[
'qty'];
5801 if (isModEnabled(
"supplier_order")) {
5802 $filterStatus = !
getDolGlobalString(
'SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK') ?
'3,4' : $conf->global->SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK;
5803 if (isset($includedraftpoforvirtual)) {
5804 $filterStatus =
'0,1,2,'.$filterStatus;
5810 $stock_commande_fournisseur = $this->stats_commande_fournisseur[
'qty'];
5812 if ((isModEnabled(
"supplier_order") || isModEnabled(
"supplier_invoice")) && empty($conf->reception->enabled)) {
5814 $filterStatus =
'4';
5815 if (isset($includedraftpoforvirtual)) {
5816 $filterStatus =
'0,'.$filterStatus;
5822 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
5824 if ((isModEnabled(
"supplier_order") || isModEnabled(
"supplier_invoice")) && isModEnabled(
"reception")) {
5826 $filterStatus =
'4';
5827 if (isset($includedraftpoforvirtual)) {
5828 $filterStatus =
'0,'.$filterStatus;
5834 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
5836 if (isModEnabled(
'mrp')) {
5841 $stock_inproduction = $this->stats_mrptoproduce[
'qty'] - $this->stats_mrptoconsume[
'qty'];
5844 $this->stock_theorique = $this->stock_reel + $stock_inproduction;
5848 $weBillOrderOrShipmentReception =
getDolGlobalString(
'STOCK_DO_WE_BILL_ORDER_OR_SHIPMENTECEPTION_FOR_VIRTUALSTOCK',
'order');
5852 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
5856 $result = $tmpnewprod->load_stats_commande(0,
'0', 1);
5857 $this->stock_theorique += $tmpnewprod->stats_commande[
'qty'];
5859 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'order') {
5860 $this->stock_theorique -= $stock_commande_client;
5861 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
5862 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
5867 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
5869 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
5871 if (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER_INCLUDE_DRAFT')) {
5873 $result = $tmpnewprod->load_stats_commande_fournisseur(0,
'0', 1);
5874 $this->stock_theorique += $this->stats_commande_fournisseur[
'qty'];
5876 $this->stock_theorique -= $stock_reception_fournisseur;
5877 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'order') {
5878 $this->stock_theorique += $stock_commande_fournisseur;
5879 } elseif (
getDolGlobalString(
'STOCK_CALCULATE_ON_SUPPLIER_BILL') && $weBillOrderOrShipmentReception ==
'shipmentreception') {
5880 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
5883 $parameters = array(
'id'=>$this->
id,
'includedraftpoforvirtual' => $includedraftpoforvirtual);
5885 $reshook = $hookmanager->executeHooks(
'loadvirtualstock', $parameters, $this, $action);
5887 $this->stock_theorique = $hookmanager->resArray[
'stock_theorique'];
5888 } elseif ($reshook == 0 && isset($hookmanager->resArray[
'stock_stats_hook'])) {
5889 $this->stock_theorique += $hookmanager->resArray[
'stock_stats_hook'];
5907 $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";
5908 $sql .=
" WHERE pb.fk_product_stock = ps.rowid AND ps.fk_product = ".((int) $this->
id).
" AND pb.batch = '".$this->db->escape($batch).
"'";
5909 $sql .=
" GROUP BY pb.batch, pb.eatby, pb.sellby";
5910 dol_syslog(get_class($this).
"::loadBatchInfo load first entry found for lot/serial = ".$batch, LOG_DEBUG);
5911 $resql = $this->db->query($sql);
5913 $num = $this->db->num_rows($resql);
5916 $obj = $this->db->fetch_object($resql);
5917 $result[] = array(
'batch'=>$batch,
'eatby'=>$this->db->jdate($obj->eatby),
'sellby'=>$this->db->jdate($obj->sellby),
'qty'=>$obj->qty);
5923 $this->db->rollback();
5941 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
5947 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos";
5949 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product').dol_sanitizeFileName($this->
ref);
5954 $dir_osencoded = $dir;
5956 if (is_dir($dir_osencoded)) {
5957 $originImage = $dir.
'/'.$file[
'name'];
5968 if (is_numeric($result) && $result > 0) {
5985 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
5986 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
5992 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos/";
5994 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product');
6000 if (file_exists($dir_osencoded)) {
6001 $handle = opendir($dir_osencoded);
6002 if (is_resource($handle)) {
6003 while (($file = readdir($handle)) !==
false) {
6005 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6027 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6028 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6034 $handle = @opendir($dir_osencoded);
6035 if (is_resource($handle)) {
6036 while (($file = readdir($handle)) !==
false) {
6038 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6045 $photo_vignette =
'';
6047 if (preg_match(
'/('.$this->regeximgext.
')$/i', $photo, $regs)) {
6048 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $photo).
'_small'.$regs[0];
6051 $dirthumb = $dir.
'thumbs/';
6055 $obj[
'photo'] = $photo;
6056 if ($photo_vignette &&
dol_is_file($dirthumb.$photo_vignette)) {
6057 $obj[
'photo_vignette'] =
'thumbs/'.$photo_vignette;
6059 $obj[
'photo_vignette'] =
"";
6062 $tabobj[$nbphoto - 1] = $obj;
6065 if ($nbmax && $nbphoto >= $nbmax) {
6087 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6088 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6090 $dir = dirname($file).
'/';
6091 $dirthumb = $dir.
'/thumbs/';
6092 $filename = preg_replace(
'/'.preg_quote($dir,
'/').
'/i',
'', $file);
6098 if (preg_match(
'/('.$this->regeximgext.
')$/i', $filename, $regs)) {
6099 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_small'.$regs[0];
6100 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6104 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_mini'.$regs[0];
6105 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6122 $infoImg = getimagesize($file_osencoded);
6123 $this->imgWidth = $infoImg[0];
6124 $this->imgHeight = $infoImg[1];
6136 global $hookmanager;
6138 $this->nb = array();
6140 $sql =
"SELECT count(p.rowid) as nb, fk_product_type";
6141 $sql .=
" FROM ".$this->db->prefix().
"product as p";
6142 $sql .=
' WHERE p.entity IN ('.getEntity($this->element, 1).
')';
6144 if (is_object($hookmanager)) {
6145 $parameters = array();
6146 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
6147 $sql .= $hookmanager->resPrint;
6149 $sql .=
' GROUP BY fk_product_type';
6151 $resql = $this->db->query($sql);
6153 while ($obj = $this->db->fetch_object($resql)) {
6154 if ($obj->fk_product_type == 1) {
6155 $this->nb[
"services"] = $obj->nb;
6157 $this->nb[
"products"] = $obj->nb;
6160 $this->db->free($resql);
6164 $this->error = $this->db->error();
6206 return ($this->mandatory_period == 1 ?
true :
false);
6216 return ($this->status_batch > 0 ?
true :
false);
6236 $dirsociete = array_merge(array(
'/core/modules/barcode/'), $conf->modules_parts[
'barcode']);
6237 foreach ($dirsociete as $dirroot) {
6243 $var = $conf->global->BARCODE_PRODUCT_ADDON_NUM;
6246 $result = $mod->getNextValue($object, $type);
6248 dol_syslog(get_class($this).
"::get_barcode barcode=".$result.
" module=".$var);
6265 $this->specimen = 1;
6267 $this->
ref =
'PRODUCT_SPEC';
6268 $this->label =
'PRODUCT SPECIMEN';
6269 $this->
description =
'This is description of this product specimen that was created the '.dol_print_date($now,
'dayhourlog').
'.';
6270 $this->specimen = 1;
6271 $this->country_id = 1;
6273 $this->status_buy = 1;
6275 $this->note_private =
'This is a comment (private)';
6276 $this->note_public =
'This is a comment (public)';
6277 $this->date_creation = $now;
6278 $this->date_modification = $now;
6281 $this->weight_units = 3;
6284 $this->length_units = 1;
6286 $this->width_units = 0;
6287 $this->height =
null;
6288 $this->height_units =
null;
6290 $this->surface = 30;
6291 $this->surface_units = 0;
6292 $this->volume = 300;
6293 $this->volume_units = 0;
6295 $this->barcode = -1;
6308 if (!$this->fk_unit) {
6312 $langs->load(
'products');
6314 $label_type =
'label';
6315 if ($type ==
'short') {
6316 $label_type =
'short_label';
6319 $sql =
"SELECT ".$label_type.
", code from ".$this->db->prefix().
"c_units where rowid = ".((int) $this->fk_unit);
6321 $resql = $this->db->query($sql);
6322 if ($resql && $this->db->num_rows($resql) > 0) {
6323 $res = $this->db->fetch_array($resql);
6324 $label = ($label_type ==
'short_label' ?
$res[$label_type] :
'unit'.$res[
'code']);
6325 $this->db->free($resql);
6328 $this->error = $this->db->error();
6329 dol_syslog(get_class($this).
"::getLabelOfUnit Error ".$this->error, LOG_ERR);
6345 $maxpricesupplier = 0;
6348 include_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.product.class.php';
6350 $product_fourn_list = $product_fourn->list_product_fournisseur_price($this->
id,
'',
'');
6352 if (is_array($product_fourn_list) && count($product_fourn_list) > 0) {
6353 foreach ($product_fourn_list as $productfourn) {
6354 if ($productfourn->fourn_unitprice > $maxpricesupplier) {
6355 $maxpricesupplier = $productfourn->fourn_unitprice;
6359 $maxpricesupplier *= $conf->global->PRODUCT_MINIMUM_RECOMMENDED_PRICE;
6363 return $maxpricesupplier;
6379 require_once DOL_DOCUMENT_ROOT.
'/categories/class/categorie.class.php';
6380 return parent::setCategoriesCommon($categories, Categorie::TYPE_PRODUCT);
6394 'product_customer_price',
6395 'product_customer_price_log'
6416 $sql =
"SELECT rowid, level, fk_level, var_percent, var_min_percent FROM ".$this->db->prefix().
"product_pricerules";
6417 $query = $this->db->query($sql);
6421 while ($result = $this->db->fetch_object($query)) {
6422 $rules[$result->level] = $result;
6431 for ($i = 1; $i <= $nbofproducts; $i++) {
6432 $price = $baseprice;
6433 $price_min = $baseprice;
6437 if ($i > 1 && isset($rules[$i]->var_percent) && $rules[$i]->var_percent) {
6438 $price = $prices[$rules[$i]->fk_level] * (1 + ($rules[$i]->var_percent / 100));
6441 $prices[$i] = $price;
6444 if (isset($rules[$i]->var_min_percent) && $rules[$i]->var_min_percent) {
6445 $price_min = $price * (1 - ($rules[$i]->var_min_percent / 100));
6449 $check_amount = (($price == $this->multiprices[$i]) && ($price_min == $this->multiprices_min[$i]));
6450 $check_type = ($baseprice == $this->multiprices_base_type[$i]);
6452 if ($check_amount && $check_type) {
6456 if ($this->
updatePrice($price, $price_type, $user, $price_vat, $price_min, $i, $npr, $psq,
true) < 0) {
6474 return $user->rights->produit;
6476 return $user->rights->service;
6488 $sql =
"SELECT p.rowid, p.ref, p.datec as date_creation, p.tms as date_modification,";
6489 $sql .=
" p.fk_user_author, p.fk_user_modif";
6490 $sql .=
" FROM ".$this->db->prefix().$this->table_element.
" as p";
6491 $sql .=
" WHERE p.rowid = ".((int) $id);
6493 $result = $this->db->query($sql);
6495 if ($this->db->num_rows($result)) {
6496 $obj = $this->db->fetch_object($result);
6498 $this->
id = $obj->rowid;
6499 $this->
ref = $obj->ref;
6501 $this->user_creation_id = $obj->fk_user_author;
6502 $this->user_modification_id = $obj->fk_user_modif;
6504 $this->date_creation = $this->db->jdate($obj->date_creation);
6505 $this->date_modification = $this->db->jdate($obj->date_modification);
6508 $this->db->free($result);
6523 if (empty($this->duration_value)) {
6524 $this->errors[]=
'ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
6528 if ($this->duration_unit ==
'i') {
6529 $prodDurationHours = 1. / 60;
6531 if ($this->duration_unit ==
'h') {
6532 $prodDurationHours = 1.;
6534 if ($this->duration_unit ==
'd') {
6535 $prodDurationHours = 24.;
6537 if ($this->duration_unit ==
'w') {
6538 $prodDurationHours = 24. * 7;
6540 if ($this->duration_unit ==
'm') {
6541 $prodDurationHours = 24. * 30;
6543 if ($this->duration_unit ==
'y') {
6544 $prodDurationHours = 24. * 365;
6548 return $prodDurationHours;
6561 global $langs,$conf;
6563 $selected = (empty($arraydata[
'selected']) ? 0 : $arraydata[
'selected']);
6565 $return =
'<div class="box-flex-item box-flex-grow-zero">';
6566 $return .=
'<div class="info-box info-box-sm">';
6567 $return .=
'<div class="info-box-img">';
6570 $label .= $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 120, 160, 0, 0, 0,
'',
'photoref photokanban');
6580 $return .=
'</div>';
6581 $return .=
'<div class="info-box-content">';
6582 $return .=
'<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this,
'getNomUrl') ? $this->
getNomUrl() : $this->ref).
'</span>';
6583 if ($selected >= 0) {
6584 $return .=
'<input id="cb'.$this->id.
'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->
id.
'"'.($selected ?
' checked="checked"' :
'').
'>';
6586 if (property_exists($this,
'label')) {
6587 $return .=
'<br><span class="info-box-label opacitymedium">'.$this->label.
'</span>';
6589 if (property_exists($this,
'price') && property_exists($this,
'price_ttc')) {
6590 if ($this->price_base_type ==
'TTC') {
6591 $return .=
'<br><span class="info-box-status amount">'.price($this->price_ttc).
' '.$langs->trans(
"TTC").
'</span>';
6594 $return .=
'<br><span class="info-box-status amount">'.price($this->
price).
' '.$langs->trans(
"HT").
'</span>';
6599 if (property_exists($this,
'stock_reel') && $this->
isProduct()) {
6600 $return .=
'<br><div class="info-box-status opacitymedium inline-block valignmiddle">'.img_picto($langs->trans(
'PhysicalStock'),
'stock').
'</div><div class="inline-block valignmiddle paddingleft" title="'.$langs->trans(
'PhysicalStock').
'">'.$this->stock_reel.
'</div>';
6603 if (method_exists($this,
'getLibStatut')) {
6605 $return .=
'<br><div class="info-box-status inline-block valignmiddle">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
6607 $return .=
'<div class="info-box-status inline-block valignmiddle marginleftonly paddingleft">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
6610 $return .=
'</div>';
6611 $return .=
'</div>';
6612 $return .=
'</div>';
6623 public $picto =
'service';
length_accountg($account)
Return General accounting account with defined length (used for product and miscellaneous)
print $langs trans("AuditedSecurityEvents").'</strong >< span class="opacitymedium"></span >< br > status
Parent class of all other business classes (invoices, contracts, proposals, orders,...
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
deleteEcmFiles($mode=0)
Delete related files of object in database.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
isObjectUsed($id=0, $entity=0)
Function to check if an object is used by others (by children).
deleteExtraFields()
Delete all extra fields values for the current object.
addThumbs($file)
Build thumb.
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
show_photos($modulepart, $sdir, $size=0, $nbmax=0, $nbbyrow=5, $showfilename=0, $showaction=0, $maxHeight=120, $maxWidth=160, $nolink=0, $overwritetitle=0, $usesharelink=0, $cache='', $addphotorefcss='photoref')
Show photos of an object (nbmax maximum), into several columns.
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
call_trigger($triggerName, $user)
Call trigger based on this instance.
Class to manage Dolibarr database access.
const STATUS_OPEN_INTERNAL
Warehouse open and only operations for stock transfers/corrections allowed (not for customer shipping...
const STATUS_OPEN_ALL
Warehouse open and any operations are allowed (customer shipping, supplier dispatch,...
const STATUS_CLOSED
Warehouse closed, inactive.
const STATUS_CLOSED
Closed status.
const STATUS_VALIDATED
Validated status.
const STATUS_DRAFT
Draft status.
Class to manage stock movements.
Class to parse product price expressions.
Class ProductCombination Used to represent a product combination.
File of class to manage predefined price products or services by customer.
Class to manage predefined suppliers products.
Class to manage products or services.
static replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
get_nb_achat($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units or supplier invoices in which product is included.
getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp=0)
Return price of sell of a product for a seller/buyer/product.
__construct($db)
Constructor.
$price_by_qty
Price by quantity arrays.
is_sousproduit($fk_parent, $fk_child)
Check if it is a sub-product into a kit.
const SELL_OR_EAT_BY_MANDATORY_ID_NONE
Const sell or eat by mandatory id.
isStockManaged()
Return if object need to have its stock managed.
$duration
Service expiration label (value + unit)
setPriceExpression($expression_id)
Sets the supplier price expression.
getArrayForPriceCompare($level=0)
used to check if price have really change to avoid log pollution
get_arbo_each_prod($multiply=1, $ignore_stock_load=0)
Build the tree of subproducts and return it.
check_barcode($valuetotest, $typefortest)
Check barcode.
list_suppliers()
Return list of suppliers providing the product or service.
load_stats_mo($socid=0)
Charge tableau des stats OF pour le produit/service.
isVariant()
Return if loaded product is a variant.
hasVariants()
Return if a product has variants or not.
delMultiLangs($langtodelete, $user)
Delete a language for this product.
getLabelOfUnit($type='long')
Returns the text label from units dictionary.
load_stats_proposal_supplier($socid=0)
Charge tableau des stats propale pour le produit/service.
getLibFinished()
Retour label of nature of product.
add_sousproduit($id_pere, $id_fils, $qty, $incdec=1, $notrigger=0)
Link a product/service to a parent product/service.
add_fournisseur($user, $id_fourn, $ref_fourn, $quantity)
Add a supplier price for the product.
hasFatherOrChild($mode=0)
Count all parent and children products for current product (first level only)
load_stats_facturerec($socid=0)
Charge tableau des stats facture recurrentes pour le produit/service.
$product_id_already_linked
Product ID already linked to a reference supplier.
get_nb_propalsupplier($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in proposals in which product is included.
get_nb_contract($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
load_stats_facture_fournisseur($socid=0)
Charge tableau des stats facture pour le produit/service.
get_nb_ordersupplier($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
getMultiLangs()
Load array this->multilangs.
get_nb_mos($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
clone_associations($fromId, $toId)
Clone links between products.
create($user, $notrigger=0)
Insert product into database.
load_stats_contrat($socid=0)
Charge tableau des stats contrat pour le produit/service.
updatePrice($newprice, $newpricebase, $user, $newvat='', $newminprice=0, $level=0, $newnpr=0, $newpbq=0, $ignore_autogen=0, $localtaxes_array=array(), $newdefaultvatcode='', $notrigger=0)
Modify customer price of a product/Service for a given level.
isService()
Return if object is a product.
getRights()
Returns the rights used for this class.
loadBatchInfo($batch)
Load existing information about a serial.
load_stock($option='', $includedraftpoforvirtual=null, $dateofvirtualstock=null)
Load information about stock of a product into ->stock_reel, ->stock_warehouse[] (including stock_war...
getProductDurationHours()
Return the duration in Hours of a service base on duration fields.
fetch($id='', $ref='', $ref_ext='', $barcode='', $ignore_expression=0, $ignore_price_load=0, $ignore_lang_load=0)
Load a product in memory from database.
$default_vat_code
Default VAT code for product (link to code into llx_c_tva but without foreign keys)
$duration_unit
Serivce expiration unit.
get_buyprice($prodfournprice, $qty, $product_id=0, $fourn_ref='', $fk_soc=0)
Read price used by a provider.
clone_fournisseurs($fromId, $toId)
Recopie les fournisseurs et prix fournisseurs d'un produit/service sur un autre.
const TYPE_PRODUCT
Regular product.
$stock_warehouse
Contains detail of stock of product into each warehouse.
$fk_default_workstation
Service Workstation.
add_photo($sdir, $file)
Move an uploaded file described into $file array into target directory $sdir.
log_price_delete($user, $rowid)
Delete a price line.
update($id, $user, $notrigger=false, $action='update', $updatetype=false)
Update a record into database.
info($id)
Load information for tab info.
load_stats_inproduction($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null)
Charge tableau des stats production pour le produit/service.
correct_stock($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $inventorycode='', $origin_element='', $origin_id=null, $disablestockchangeforsubproduct=0, $extrafields=null)
Adjust stock in a warehouse for product.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
Create a document onto disk according to template module.
$multiprices
Arrays for multiprices.
$localtax1_tx
Other local taxes.
getChildsArbo($id, $firstlevelonly=0, $level=1, $parents=array())
Return childs of product $id.
load_virtual_stock($includedraftpoforvirtual=null, $dateofvirtualstock=null)
Load value ->stock_theorique of a product.
load_stats_propale($socid=0)
Charge tableau des stats propale pour le produit/service.
get_barcode($object, $type='')
Get a barcode from the module to generate barcode values.
setAccountancyCode($type, $value)
Sets an accountancy code for a product.
load_stats_facture($socid=0)
Charge tableau des stats facture pour le produit/service.
$remise_percent
Default discount percent.
setCategories($categories)
Sets object to supplied categories.
load_stats_reception($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null)
Charge tableau des stats réception fournisseur pour le produit/service.
get_nb_propal($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in proposals in which product is included.
setMultiLangs($user)
Update or add a translation for a product.
correct_stock_batch($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $dlc='', $dluo='', $lot='', $inventorycode='', $origin_element='', $origin_id=null, $disablestockchangeforsubproduct=0, $extrafields=null, $force_update_batch=false)
Adjust stock in a warehouse for product with batch number.
$tva_npr
int French VAT NPR is used (0 or 1)
$tva_tx
Default VAT rate of product.
load_stats_bom($socid=0)
Charge tableau des stats OF pour le produit/service.
hasbatch()
Return if object has a sell-by date or eat-by date.
$weight
Metric of products.
del_sousproduit($fk_parent, $fk_child, $notrigger=0)
Remove a link between a subproduct and a parent product/service.
update_sousproduit($id_pere, $id_fils, $qty, $incdec=1, $notrigger=0)
Modify composed product.
load_stats_commande($socid=0, $filtrestatut='', $forVirtualStock=0)
Charge tableau des stats commande client pour le produit/service.
delete_photo($file)
Delete a photo and its thumbs.
fetch_prod_arbo($prod, $compl_path='', $multiply=1, $level=1, $id_parent=0, $ignore_stock_load=0)
Function recursive, used only by get_arbo_each_prod(), to build tree of subproducts into ->res Define...
getKanbanView($option='', $arraydata=null)
Return clicable link of object (with eventually picto)
getLibStatut($mode=0, $type=0)
Return label of status of object.
load_stats_sending($socid=0, $filtrestatut='', $forVirtualStock=0, $filterShipmentStatus='')
Charge tableau des stats expedition client pour le produit/service.
clone_price($fromId, $toId)
Recopie les prix d'un produit/service sur un autre.
$duration_value
Service expiration.
check()
Check that ref and label are ok.
initAsSpecimen()
Initialise an instance with random values.
liste_photos($dir, $nbmax=0)
Return an array with all photos of product found on disk.
getFather()
Return all parent products for current product (first level only)
getNomUrl($withpicto=0, $option='', $maxlength=0, $save_lastsearch_value=-1, $notooltip=0, $morecss='', $add_label=0, $sep=' - ')
Return clickable link of object (with eventually picto)
$product_fourn_id
Id du fournisseur.
$desiredstock
Ask for replenishment when $desiredstock < $stock_reel.
verify()
Check properties of product are ok (like name, barcode, ...).
get_nb_order($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
load_state_board()
Load indicators this->nb for the dashboard.
min_recommended_price()
Return minimum product recommended price.
_log_price($user, $level=0)
Insert a track that we changed a customer price.
_get_stats($sql, $mode, $year=0)
Return an array formated for showing graphs.
$multilangs
Array for multilangs.
load_stats_commande_fournisseur($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null)
Charge tableau des stats commande fournisseur pour le produit/service.
isMandatoryPeriod()
Return if object have a constraint on mandatory_period.
isProduct()
Return if object is a product.
generateMultiprices(User $user, $baseprice, $price_type, $price_vat, $npr, $psq)
Generates prices for a product based on product multiprice generation rules.
LibStatut($status, $mode=0, $type=0)
Return label of a given status.
const TYPE_SERVICE
Service.
is_photo_available($sdir)
Return if at least one photo is available.
get_image_size($file)
Load size of image file.
get_nb_vente($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units or customers invoices in which product is included.
getTooltipContentArray($params)
getTooltipContentArray
Class to manage products or services.
Manage record for batch number management.
static findAll($dbs, $fk_product_stock, $with_qty=0, $fk_product=0)
Return all batch detail records for a given product and warehouse.
Class with list of lots and properties.
Class to manage Dolibarr users.
hasRight($module, $permlevel1, $permlevel2='')
Return if a user has a permission.
getCountry($searchkey, $withcode='', $dbtouse=0, $outputlangs='', $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $nohook=0, $varfiles='addedfile', $upload_dir='')
Make control on an uploaded file from an GUI page and move it to final destination.
dol_is_file($pathoffile)
Return if path is a file.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='', $keepspaces=0)
Clean a string from all punctuation characters to use it as a ref or login.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
dol_clone($object, $native=0)
Create a clone of instance of object (new instance with same value for each properties) With native =...
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
get_localtax($vatrate, $local, $thirdparty_buyer="", $thirdparty_seller="", $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate,...
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
utf8_check($str)
Check if a string is in UTF8.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
measuringUnitString($unit, $measuring_style='', $scale='', $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
measuring_units_squared($unit)
Transform a given unit scale into the square of that unit, if known.
measuring_units_cubed($unit)
Transform a given unit scale into the cube of that unit, if known.
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type