40require_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
41require_once DOL_DOCUMENT_ROOT.
'/core/class/commonobject.class.php';
42require_once DOL_DOCUMENT_ROOT.
'/product/class/productbatch.class.php';
43require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/productlot.class.php';
44require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/entrepot.class.php';
55 const SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY = 1;
56 const SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY = 2;
57 const SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT = 3;
62 public $element =
'product';
67 public $table_element =
'product';
72 public $fk_element =
'fk_product';
82 protected $childtables = array(
83 'supplier_proposaldet' => array(
'name' =>
'SupplierProposal',
'parent' =>
'supplier_proposal',
'parentkey' =>
'fk_supplier_proposal'),
84 'propaldet' => array(
'name' =>
'Proposal',
'parent' =>
'propal',
'parentkey' =>
'fk_propal'),
85 'commandedet' => array(
'name' =>
'Order',
'parent' =>
'commande',
'parentkey' =>
'fk_commande'),
86 'facturedet' => array(
'name' =>
'Invoice',
'parent' =>
'facture',
'parentkey' =>
'fk_facture'),
87 'contratdet' => array(
'name' =>
'Contract',
'parent' =>
'contrat',
'parentkey' =>
'fk_contrat'),
88 'facture_fourn_det' => array(
'name' =>
'SupplierInvoice',
'parent' =>
'facture_fourn',
'parentkey' =>
'fk_facture_fourn'),
89 'commande_fournisseurdet' => array(
'name' =>
'SupplierOrder',
'parent' =>
'commande_fournisseur',
'parentkey' =>
'fk_commande'),
90 'mrp_production' => array(
'name' =>
'Mo',
'parent' =>
'mrp_mo',
'parentkey' =>
'fk_mo')
98 public $picto =
'product';
105 public $regeximgext =
'\.gif|\.jpg|\.jpeg|\.png|\.bmp|\.webp|\.xpm|\.xbm';
148 public $price_formated;
157 public $price_ttc_formated;
171 public $price_min_ttc;
177 public $price_base_type;
182 public $multiprices_ttc = array();
183 public $multiprices_base_type = array();
184 public $multiprices_default_vat_code = array();
185 public $multiprices_min = array();
186 public $multiprices_min_ttc = array();
187 public $multiprices_tva_tx = array();
188 public $multiprices_recuperableonly = array();
192 public $prices_by_qty = array();
193 public $prices_by_qty_id = array();
194 public $prices_by_qty_list = array();
220 public $localtax2_tx;
221 public $localtax1_type;
222 public $localtax2_type;
226 public $desc_supplier;
227 public $vatrate_supplier;
228 public $default_vat_code_supplier;
229 public $fourn_multicurrency_price;
230 public $fourn_multicurrency_unitprice;
231 public $fourn_multicurrency_tx;
232 public $fourn_multicurrency_id;
233 public $fourn_multicurrency_code;
251 public $qc_frequency;
258 public $stock_reel = 0;
265 public $stock_theorique;
282 public $seuil_stock_alerte = 0;
305 public $fk_default_workstation;
327 public $status_buy = 0;
349 public $fk_default_bom;
356 public $product_fourn_price_id;
378 public $status_batch = 0;
385 public $sell_or_eat_by_mandatory = 0;
392 public $batch_mask =
'';
410 public $weight_units;
412 public $length_units;
416 public $height_units;
418 public $surface_units;
420 public $volume_units;
423 public $net_measure_units;
425 public $accountancy_code_sell;
426 public $accountancy_code_sell_intra;
427 public $accountancy_code_sell_export;
428 public $accountancy_code_buy;
429 public $accountancy_code_buy_intra;
430 public $accountancy_code_buy_export;
440 public $barcode_type;
445 public $barcode_type_code;
447 public $stats_propale = array();
448 public $stats_commande = array();
449 public $stats_contrat = array();
450 public $stats_facture = array();
451 public $stats_proposal_supplier = array();
452 public $stats_commande_fournisseur = array();
453 public $stats_expedition = array();
454 public $stats_reception = array();
455 public $stats_mo = array();
456 public $stats_bom = array();
457 public $stats_mrptoconsume = array();
458 public $stats_mrptoproduce = array();
459 public $stats_facturerec = array();
460 public $stats_facture_fournisseur = array();
470 public $product_fourn_id;
476 public $product_id_already_linked;
490 public $fk_default_warehouse;
495 public $fk_price_expression;
513 public $fourn_price_base_type;
529 public $ref_supplier;
543 public $price_autogen = 0;
550 public $supplierprices;
570 public $is_object_used;
581 public $is_sousproduit_qty;
593 public $is_sousproduit_incdec;
595 public $mandatory_period;
626 public $fields = array(
627 'rowid' => array(
'type' =>
'integer',
'label' =>
'TechnicalID',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'index' => 1,
'position' => 1,
'comment' =>
'Id'),
628 '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'),
629 'entity' => array(
'type' =>
'integer',
'label' =>
'Entity',
'enabled' => 1,
'visible' => 0,
'default' =>
'1',
'notnull' => 1,
'index' => 1,
'position' => 5),
630 'label' => array(
'type' =>
'varchar(255)',
'label' =>
'Label',
'enabled' => 1,
'visible' => 1,
'notnull' => 1,
'showoncombobox' => 2,
'position' => 15,
'csslist' =>
'tdoverflowmax250'),
631 'barcode' => array(
'type' =>
'varchar(255)',
'label' =>
'Barcode',
'enabled' =>
'isModEnabled("barcode")',
'position' => 20,
'visible' => -1,
'showoncombobox' => 3,
'cssview' =>
'tdwordbreak',
'csslist' =>
'tdoverflowmax125'),
632 'fk_barcode_type' => array(
'type' =>
'integer',
'label' =>
'BarcodeType',
'enabled' => 1,
'position' => 21,
'notnull' => 0,
'visible' => -1,),
633 'note_public' => array(
'type' =>
'html',
'label' =>
'NotePublic',
'enabled' => 1,
'visible' => 0,
'position' => 61),
634 'note' => array(
'type' =>
'html',
'label' =>
'NotePrivate',
'enabled' => 1,
'visible' => 0,
'position' => 62),
635 'datec' => array(
'type' =>
'datetime',
'label' =>
'DateCreation',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 500),
636 'tms' => array(
'type' =>
'timestamp',
'label' =>
'DateModification',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 501),
638 'fk_user_author' => array(
'type' =>
'integer',
'label' =>
'UserAuthor',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 510,
'foreignkey' =>
'llx_user.rowid'),
639 'fk_user_modif' => array(
'type' =>
'integer',
'label' =>
'UserModif',
'enabled' => 1,
'visible' => -2,
'notnull' => -1,
'position' => 511),
641 'localtax1_tx' => array(
'type' =>
'double(6,3)',
'label' =>
'Localtax1tx',
'enabled' => 1,
'position' => 150,
'notnull' => 0,
'visible' => -1,),
642 'localtax1_type' => array(
'type' =>
'varchar(10)',
'label' =>
'Localtax1type',
'enabled' => 1,
'position' => 155,
'notnull' => 1,
'visible' => -1,),
643 'localtax2_tx' => array(
'type' =>
'double(6,3)',
'label' =>
'Localtax2tx',
'enabled' => 1,
'position' => 160,
'notnull' => 0,
'visible' => -1,),
644 'localtax2_type' => array(
'type' =>
'varchar(10)',
'label' =>
'Localtax2type',
'enabled' => 1,
'position' => 165,
'notnull' => 1,
'visible' => -1,),
645 'last_main_doc' => array(
'type' =>
'varchar(255)',
'label' =>
'LastMainDoc',
'enabled' => 1,
'visible' => -1,
'position' => 170),
646 'import_key' => array(
'type' =>
'varchar(14)',
'label' =>
'ImportId',
'enabled' => 1,
'visible' => -2,
'notnull' => -1,
'index' => 0,
'position' => 1000),
649 'mandatory_period' => array(
'type' =>
'integer',
'label' =>
'mandatoryperiod',
'enabled' => 1,
'visible' => 1,
'notnull' => 1,
'default' =>
'0',
'index' => 1,
'position' => 1000),
670 $this->ismultientitymanaged = 1;
671 $this->isextrafieldmanaged = 1;
684 $this->
ref = trim($this->
ref);
712 public function create($user, $notrigger = 0)
714 global $conf, $langs;
720 $this->
ref = trim($this->
ref);
724 $this->label = trim($this->label);
725 $this->price_ttc = (float)
price2num($this->price_ttc);
727 $this->price_min_ttc = (float)
price2num($this->price_min_ttc);
728 $this->price_min = (float)
price2num($this->price_min);
729 $this->price_label = trim($this->price_label);
730 if (empty($this->tva_tx)) {
733 if (empty($this->tva_npr)) {
737 if (empty($this->localtax1_tx)) {
738 $this->localtax1_tx = 0;
740 if (empty($this->localtax2_tx)) {
741 $this->localtax2_tx = 0;
743 if (empty($this->localtax1_type)) {
744 $this->localtax1_type =
'0';
746 if (empty($this->localtax2_type)) {
747 $this->localtax2_type =
'0';
749 if (empty($this->
price)) {
752 if (empty($this->price_min)) {
753 $this->price_min = 0;
756 if (empty($this->price_by_qty)) {
757 $this->price_by_qty = 0;
760 if (empty($this->
status)) {
763 if (empty($this->status_buy)) {
764 $this->status_buy = 0;
773 if ($this->price_base_type ==
'TTC' && $this->price_ttc > 0) {
774 $price_ttc =
price2num($this->price_ttc,
'MU');
775 $price_ht =
price2num($this->price_ttc / (1 + ($this->tva_tx / 100)),
'MU');
779 if ($this->price_base_type !=
'TTC' && $this->
price > 0) {
781 $price_ttc =
price2num($this->
price * (1 + ($this->tva_tx / 100)),
'MU');
785 if (($this->price_min_ttc > 0) && ($this->price_base_type ==
'TTC')) {
786 $price_min_ttc =
price2num($this->price_min_ttc,
'MU');
787 $price_min_ht =
price2num($this->price_min_ttc / (1 + ($this->tva_tx / 100)),
'MU');
791 if (($this->price_min > 0) && ($this->price_base_type !=
'TTC')) {
792 $price_min_ht =
price2num($this->price_min,
'MU');
793 $price_min_ttc =
price2num($this->price_min * (1 + ($this->tva_tx / 100)),
'MU');
796 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
797 $this->accountancy_code_buy_intra = trim($this->accountancy_code_buy_intra);
798 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
799 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
800 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
801 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
804 $this->barcode = trim($this->barcode);
805 $this->mandatory_period = empty($this->mandatory_period) ? 0 : $this->mandatory_period;
807 if (empty($this->label)) {
808 $this->error =
'ErrorMandatoryParametersNotProvided';
812 if (empty($this->
ref) || $this->
ref ==
'auto') {
815 if ($module !=
'mod_codeproduct_leopard') {
816 if (substr($module, 0, 16) ==
'mod_codeproduct_' && substr($module, -3) ==
'php') {
817 $module = substr($module, 0,
dol_strlen($module) - 4);
820 $modCodeProduct =
new $module();
821 '@phan-var-force ModeleProductCode $modCodeProduct';
822 if (!empty($modCodeProduct->code_auto)) {
823 $this->
ref = $modCodeProduct->getNextValue($this, $this->
type);
825 unset($modCodeProduct);
828 if (empty($this->
ref)) {
829 $this->error =
'ProductModuleNotSetupForAutoRef';
834 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);
838 if (empty($this->date_creation)) {
839 $this->date_creation = $now;
845 if ($this->barcode ==
'-1' || $this->barcode ==
'auto') {
846 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
851 $result = $this->
verify();
854 $sql =
"SELECT count(*) as nb";
855 $sql .=
" FROM ".$this->db->prefix().
"product";
856 $sql .=
" WHERE entity IN (".getEntity(
'product').
")";
857 $sql .=
" AND ref = '".$this->db->escape($this->
ref).
"'";
859 $result = $this->db->query($sql);
861 $obj = $this->db->fetch_object($result);
864 $sql =
"INSERT INTO ".$this->db->prefix().
"product (";
869 $sql .=
", price_min";
870 $sql .=
", price_min_ttc";
872 $sql .=
", fk_user_author";
873 $sql .=
", fk_product_type";
875 $sql .=
", price_ttc";
876 $sql .=
", price_base_type";
877 $sql .=
", price_label";
881 $sql .=
", accountancy_code_buy";
882 $sql .=
", accountancy_code_buy_intra";
883 $sql .=
", accountancy_code_buy_export";
884 $sql .=
", accountancy_code_sell";
885 $sql .=
", accountancy_code_sell_intra";
886 $sql .=
", accountancy_code_sell_export";
889 $sql .=
", finished";
891 $sql .=
", sell_or_eat_by_mandatory";
892 $sql .=
", batch_mask";
894 $sql .=
", mandatory_period";
895 $sql .=
") VALUES (";
896 $sql .=
"'".$this->db->idate($this->date_creation).
"'";
897 $sql .=
", ".(!empty($this->entity) ? (int) $this->entity : (int) $conf->entity);
898 $sql .=
", '".$this->db->escape($this->
ref).
"'";
899 $sql .=
", ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
900 $sql .=
", ".price2num($price_min_ht);
901 $sql .=
", ".price2num($price_min_ttc);
902 $sql .=
", ".(!empty($this->label) ?
"'".$this->db->escape($this->label).
"'" :
"null");
903 $sql .=
", ".((int) $user->id);
904 $sql .=
", ".((int) $this->
type);
905 $sql .=
", ".price2num($price_ht,
'MT');
906 $sql .=
", ".price2num($price_ttc,
'MT');
907 $sql .=
", '".$this->db->escape($this->price_base_type).
"'";
908 $sql .=
", ".(!empty($this->price_label) ?
"'".$this->db->escape($this->price_label).
"'" :
"null");
909 $sql .=
", ".((int) $this->
status);
910 $sql .=
", ".((int) $this->status_buy);
912 $sql .=
", '".$this->db->escape($this->accountancy_code_buy).
"'";
913 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_intra).
"'";
914 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_export).
"'";
915 $sql .=
", '".$this->db->escape($this->accountancy_code_sell).
"'";
916 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_intra).
"'";
917 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_export).
"'";
919 $sql .=
", '".$this->db->escape($this->canvas).
"'";
920 $sql .=
", ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
'NULL' : (int) $this->finished);
921 $sql .=
", ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : ((int) $this->status_batch));
922 $sql .=
", ".((empty($this->sell_or_eat_by_mandatory) || $this->sell_or_eat_by_mandatory < 0) ? 0 : ((int) $this->sell_or_eat_by_mandatory));
923 $sql .=
", '".$this->db->escape($this->batch_mask).
"'";
924 $sql .=
", ".($this->fk_unit > 0 ? ((int) $this->fk_unit) :
'NULL');
925 $sql .=
", '".$this->db->escape($this->mandatory_period).
"'";
928 dol_syslog(get_class($this).
"::Create", LOG_DEBUG);
930 $result = $this->db->query($sql);
932 $id = $this->db->last_insert_id($this->db->prefix().
"product");
936 $this->
price = $price_ht;
937 $this->price_ttc = $price_ttc;
938 $this->price_min = $price_min_ht;
939 $this->price_min_ttc = $price_min_ttc;
943 if ($this->
update($id, $user, 1,
'add') <= 0) {
948 $this->error = $this->db->lasterror();
953 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " .((int) $this->id) .
" AND entity = " . ((
int) $conf->entity));
955 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
956 $sql .=
" fk_product";
958 $sql .=
", accountancy_code_buy";
959 $sql .=
", accountancy_code_buy_intra";
960 $sql .=
", accountancy_code_buy_export";
961 $sql .=
", accountancy_code_sell";
962 $sql .=
", accountancy_code_sell_intra";
963 $sql .=
", accountancy_code_sell_export";
964 $sql .=
") VALUES (";
966 $sql .=
", " . $conf->entity;
967 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
968 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
969 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
970 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
971 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
972 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
974 $result = $this->db->query($sql);
977 $this->error =
'ErrorFailedToInsertAccountancyForEntity';
982 $this->error =
'ErrorFailedToGetInsertedId';
986 $this->error = $this->db->lasterror();
990 $langs->load(
"products");
992 $this->error =
"ErrorProductAlreadyExists";
993 dol_syslog(get_class($this).
"::Create fails, ref ".$this->
ref.
" already exists");
997 $this->error = $this->db->lasterror();
1000 if (!$error && !$notrigger) {
1002 $result = $this->
call_trigger(
'PRODUCT_CREATE', $user);
1010 $this->db->commit();
1013 $this->db->rollback();
1017 $this->db->rollback();
1018 dol_syslog(get_class($this).
"::Create fails verify ".implode(
',', $this->errors), LOG_WARNING);
1034 $this->errors = array();
1037 $this->
ref = trim($this->
ref);
1040 $this->errors[] =
'ErrorBadRef';
1044 $arrayofnonnegativevalue = array(
'weight' =>
'Weight',
'width' =>
'Width',
'height' =>
'Height',
'length' =>
'Length',
'surface' =>
'Surface',
'volume' =>
'Volume');
1045 foreach ($arrayofnonnegativevalue as $key => $value) {
1046 if (property_exists($this, $key) && !empty($this->$key) && ($this->$key < 0)) {
1047 $langs->loadLangs(array(
"main",
"other"));
1048 $this->error = $langs->trans(
"FieldCannotBeNegative", $langs->transnoentitiesnoconv($value));
1049 $this->errors[] = $this->error;
1054 $rescode = $this->
check_barcode($this->barcode, $this->barcode_type_code);
1056 if ($rescode == -1) {
1057 $this->errors[] =
'ErrorBadBarCodeSyntax';
1058 } elseif ($rescode == -2) {
1059 $this->errors[] =
'ErrorBarCodeRequired';
1060 } elseif ($rescode == -3) {
1062 $this->errors[] =
'ErrorBarCodeAlreadyUsed';
1089 $dirsociete = array_merge(array(
'/core/modules/barcode/'), $conf->modules_parts[
'barcode']);
1090 foreach ($dirsociete as $dirroot) {
1097 $mod =
new $module();
1098 '@phan-var-force ModeleNumRefBarCode $mod';
1100 dol_syslog(get_class($this).
"::check_barcode value=".$valuetotest.
" type=".$typefortest.
" module=".$module);
1101 $result = $mod->verif($this->db, $valuetotest, $this, 0, $typefortest);
1119 public function update($id, $user, $notrigger = 0, $action =
'update', $updatetype =
false)
1121 global $langs, $conf, $hookmanager;
1126 if (!$this->label) {
1127 $this->label =
'MISSING LABEL';
1132 $this->
ref = trim($this->
ref);
1136 $this->label = trim($this->label);
1138 $this->note_private = (isset($this->note_private) ? trim($this->note_private) :
null);
1139 $this->note_public = (isset($this->note_public) ? trim($this->note_public) :
null);
1140 $this->net_measure =
price2num($this->net_measure);
1141 $this->net_measure_units = (empty($this->net_measure_units) ?
'' : trim($this->net_measure_units));
1142 $this->weight =
price2num($this->weight);
1143 $this->weight_units = (empty($this->weight_units) ?
'' : trim($this->weight_units));
1144 $this->length =
price2num($this->length);
1145 $this->length_units = (empty($this->length_units) ?
'' : trim($this->length_units));
1147 $this->width_units = (empty($this->width_units) ?
'' : trim($this->width_units));
1148 $this->height =
price2num($this->height);
1149 $this->height_units = (empty($this->height_units) ?
'' : trim($this->height_units));
1150 $this->surface =
price2num($this->surface);
1151 $this->surface_units = (empty($this->surface_units) ?
'' : trim($this->surface_units));
1152 $this->volume =
price2num($this->volume);
1153 $this->volume_units = (empty($this->volume_units) ?
'' : trim($this->volume_units));
1156 if (is_numeric($this->length_units)) {
1157 $this->width_units = $this->length_units;
1159 if (is_numeric($this->length_units)) {
1160 $this->height_units = $this->length_units;
1164 if (empty($this->surface) && !empty($this->length) && !empty($this->width) && $this->length_units == $this->width_units) {
1165 $this->surface = (float) $this->length * (
float) $this->width;
1168 if (empty($this->volume) && !empty($this->surface) && !empty($this->height) && $this->length_units == $this->height_units) {
1169 $this->volume = $this->surface * (float) $this->height;
1173 if (empty($this->tva_tx)) {
1176 if (empty($this->tva_npr)) {
1179 if (empty($this->localtax1_tx)) {
1180 $this->localtax1_tx = 0;
1182 if (empty($this->localtax2_tx)) {
1183 $this->localtax2_tx = 0;
1185 if (empty($this->localtax1_type)) {
1186 $this->localtax1_type =
'0';
1188 if (empty($this->localtax2_type)) {
1189 $this->localtax2_type =
'0';
1191 if (empty($this->
status)) {
1194 if (empty($this->status_buy)) {
1195 $this->status_buy = 0;
1198 if (empty($this->country_id)) {
1199 $this->country_id = 0;
1202 if (empty($this->state_id)) {
1203 $this->state_id = 0;
1207 $this->barcode = (empty($this->barcode) ?
'' : trim($this->barcode));
1209 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
1210 $this->accountancy_code_buy_intra = (!empty($this->accountancy_code_buy_intra) ? trim($this->accountancy_code_buy_intra) :
'');
1211 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
1212 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
1213 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
1214 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
1221 if ($action !=
'add') {
1222 $result = $this->
verify();
1230 if (is_null($this->oldcopy) || (is_object($this->oldcopy) && $this->oldcopy->isEmpty())) {
1235 if ($this->
hasbatch() && !$this->oldcopy->hasbatch()) {
1237 $valueforundefinedlot =
'000000';
1242 dol_syslog(
"Flag batch of product id=".$this->
id.
" is set to ON, so we will create missing records into product_batch");
1245 foreach ($this->stock_warehouse as $idW => $ObjW) {
1247 foreach ($ObjW->detail_batch as $detail) {
1248 if ($detail->batch == $valueforundefinedlot || $detail->batch ==
'Undefined') {
1250 $sqlclean =
"DELETE FROM ".$this->db->prefix().
"product_batch WHERE batch in('Undefined', '".$this->db->escape($valueforundefinedlot).
"') AND fk_product_stock = ".((int) $ObjW->id);
1251 $result = $this->db->query($sqlclean);
1259 $qty_batch += $detail->qty;
1263 if ($ObjW->real != $qty_batch) {
1265 $ObjBatch->batch = $valueforundefinedlot;
1266 $ObjBatch->qty = ($ObjW->real - $qty_batch);
1267 $ObjBatch->fk_product_stock = $ObjW->id;
1269 if ($ObjBatch->create($user, 1) < 0) {
1271 $this->errors = $ObjBatch->errors;
1276 if ($ObjLot->fetch(0, $this->id, $valueforundefinedlot) == 0) {
1277 $ObjLot->fk_product = $this->id;
1278 $ObjLot->entity = $this->entity;
1279 $ObjLot->fk_user_creat = $user->id;
1280 $ObjLot->batch = $valueforundefinedlot;
1281 if ($ObjLot->create($user,
true) < 0) {
1283 $this->errors = $ObjLot->errors;
1292 if ($this->barcode == -1) {
1293 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1296 $sql =
"UPDATE ".$this->db->prefix().
"product";
1297 $sql .=
" SET label = '".$this->db->escape($this->label).
"'";
1300 $sql .=
", fk_product_type = ".((int) $this->
type);
1303 $sql .=
", ref = '".$this->db->escape($this->
ref).
"'";
1304 $sql .=
", ref_ext = ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1305 $sql .=
", default_vat_code = ".($this->default_vat_code ?
"'".$this->db->escape($this->default_vat_code).
"'" :
"null");
1306 $sql .=
", tva_tx = ".((float) $this->tva_tx);
1307 $sql .=
", recuperableonly = ".((int) $this->tva_npr);
1308 $sql .=
", localtax1_tx = ".((float) $this->localtax1_tx);
1309 $sql .=
", localtax2_tx = ".((float) $this->localtax2_tx);
1310 $sql .=
", localtax1_type = ".($this->localtax1_type !=
'' ?
"'".$this->db->escape($this->localtax1_type).
"'" :
"'0'");
1311 $sql .=
", localtax2_type = ".($this->localtax2_type !=
'' ?
"'".$this->db->escape($this->localtax2_type).
"'" :
"'0'");
1313 $sql .=
", barcode = ".(empty($this->barcode) ?
"null" :
"'".$this->db->escape($this->barcode).
"'");
1314 $sql .=
", fk_barcode_type = ".(empty($this->barcode_type) ?
"null" : $this->db->escape($this->barcode_type));
1316 $sql .=
", tosell = ".(int) $this->
status;
1317 $sql .=
", tobuy = ".(int) $this->status_buy;
1318 $sql .=
", tobatch = ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : (int) $this->status_batch);
1319 $sql .=
", sell_or_eat_by_mandatory = ".((empty($this->sell_or_eat_by_mandatory) || $this->sell_or_eat_by_mandatory < 0) ? 0 : (int) $this->sell_or_eat_by_mandatory);
1320 $sql .=
", batch_mask = '".$this->db->escape($this->batch_mask).
"'";
1322 $sql .=
", finished = ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
"null" : (int) $this->finished);
1323 $sql .=
", fk_default_bom = ".((!isset($this->fk_default_bom) || $this->fk_default_bom < 0 || $this->fk_default_bom ==
'') ?
"null" : (int) $this->fk_default_bom);
1324 $sql .=
", net_measure = ".($this->net_measure !=
'' ?
"'".$this->db->escape($this->net_measure).
"'" :
'null');
1325 $sql .=
", net_measure_units = ".($this->net_measure_units !=
'' ?
"'".$this->db->escape($this->net_measure_units).
"'" :
'null');
1326 $sql .=
", weight = ".($this->weight !=
'' ?
"'".$this->db->escape($this->weight).
"'" :
'null');
1327 $sql .=
", weight_units = ".($this->weight_units !=
'' ?
"'".$this->db->escape($this->weight_units).
"'" :
'null');
1328 $sql .=
", length = ".($this->length !=
'' ?
"'".$this->db->escape($this->length).
"'" :
'null');
1329 $sql .=
", length_units = ".($this->length_units !=
'' ?
"'".$this->db->escape($this->length_units).
"'" :
'null');
1330 $sql .=
", width= ".($this->width !=
'' ?
"'".$this->db->escape($this->width).
"'" :
'null');
1331 $sql .=
", width_units = ".($this->width_units !=
'' ?
"'".$this->db->escape($this->width_units).
"'" :
'null');
1332 $sql .=
", height = ".($this->height !=
'' ?
"'".$this->db->escape($this->height).
"'" :
'null');
1333 $sql .=
", height_units = ".($this->height_units !=
'' ?
"'".$this->db->escape($this->height_units).
"'" :
'null');
1334 $sql .=
", surface = ".($this->surface !=
'' ?
"'".$this->db->escape($this->surface).
"'" :
'null');
1335 $sql .=
", surface_units = ".($this->surface_units !=
'' ?
"'".$this->db->escape($this->surface_units).
"'" :
'null');
1336 $sql .=
", volume = ".($this->volume !=
'' ?
"'".$this->db->escape($this->volume).
"'" :
'null');
1337 $sql .=
", volume_units = ".($this->volume_units !=
'' ?
"'".$this->db->escape($this->volume_units).
"'" :
'null');
1338 $sql .=
", fk_default_warehouse = ".($this->fk_default_warehouse > 0 ? ((int) $this->fk_default_warehouse) :
'null');
1339 $sql .=
", fk_default_workstation = ".($this->fk_default_workstation > 0 ? ((int) $this->fk_default_workstation) :
'null');
1340 $sql .=
", seuil_stock_alerte = ".((isset($this->seuil_stock_alerte) && is_numeric($this->seuil_stock_alerte)) ? (
float) $this->seuil_stock_alerte :
'null');
1341 $sql .=
", description = '".$this->db->escape($this->
description).
"'";
1342 $sql .=
", url = ".($this->url ?
"'".$this->db->escape($this->url).
"'" :
'null');
1343 $sql .=
", customcode = '".$this->db->escape($this->customcode).
"'";
1344 $sql .=
", fk_country = ".($this->country_id > 0 ? (int) $this->country_id :
'null');
1345 $sql .=
", fk_state = ".($this->state_id > 0 ? (int) $this->state_id :
'null');
1346 $sql .=
", lifetime = ".($this->lifetime > 0 ? (int) $this->lifetime :
'null');
1347 $sql .=
", qc_frequency = ".($this->qc_frequency > 0 ? (int) $this->qc_frequency :
'null');
1348 $sql .=
", note = ".(isset($this->note_private) ?
"'".$this->db->escape($this->note_private).
"'" :
'null');
1349 $sql .=
", note_public = ".(isset($this->note_public) ?
"'".$this->db->escape($this->note_public).
"'" :
'null');
1350 $sql .=
", duration = '".$this->db->escape($this->duration_value.$this->duration_unit).
"'";
1352 $sql .=
", accountancy_code_buy = '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1353 $sql .=
", accountancy_code_buy_intra = '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1354 $sql .=
", accountancy_code_buy_export = '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1355 $sql .=
", accountancy_code_sell= '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1356 $sql .=
", accountancy_code_sell_intra= '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1357 $sql .=
", accountancy_code_sell_export= '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1359 $sql .=
", desiredstock = ".((isset($this->desiredstock) && is_numeric($this->desiredstock)) ? (
float) $this->desiredstock :
"null");
1360 $sql .=
", cost_price = ".($this->cost_price !=
'' ? $this->db->escape($this->cost_price) :
'null');
1361 $sql .=
", fk_unit= ".(!$this->fk_unit ?
'NULL' : (int) $this->fk_unit);
1362 $sql .=
", price_autogen = ".(!$this->price_autogen ? 0 : 1);
1363 $sql .=
", fk_price_expression = ".($this->fk_price_expression != 0 ? (int) $this->fk_price_expression :
'NULL');
1364 $sql .=
", fk_user_modif = ".($user->id > 0 ? $user->id :
'NULL');
1365 $sql .=
", mandatory_period = ".($this->mandatory_period);
1367 $sql .=
" WHERE rowid = ".((int) $id);
1369 dol_syslog(get_class($this).
"::update", LOG_DEBUG);
1371 $resql = $this->db->query($sql);
1378 $this->error = $langs->trans(
"Error").
" : ".$this->db->error().
" - ".$sql;
1379 $this->db->rollback();
1388 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " . ((
int) $this->id) .
" AND entity = " . ((
int) $conf->entity));
1390 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1391 $sql .=
" fk_product";
1393 $sql .=
", accountancy_code_buy";
1394 $sql .=
", accountancy_code_buy_intra";
1395 $sql .=
", accountancy_code_buy_export";
1396 $sql .=
", accountancy_code_sell";
1397 $sql .=
", accountancy_code_sell_intra";
1398 $sql .=
", accountancy_code_sell_export";
1399 $sql .=
") VALUES (";
1401 $sql .=
", " . $conf->entity;
1402 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1403 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1404 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1405 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1406 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1407 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1409 $result = $this->db->query($sql);
1412 $this->error =
'ErrorFailedToUpdateAccountancyForEntity';
1416 if (!$this->
hasbatch() && $this->oldcopy->hasbatch()) {
1418 $sql =
'SELECT pb.qty, ps.fk_entrepot, pb.batch FROM '.MAIN_DB_PREFIX.
'product_batch as pb';
1419 $sql .=
' INNER JOIN '.MAIN_DB_PREFIX.
'product_stock as ps ON (ps.rowid = pb.fk_product_stock)';
1420 $sql .=
' WHERE ps.fk_product = '.(int) $this->
id;
1422 $resql = $this->db->query($sql);
1426 while ($obj = $this->db->fetch_object($resql)) {
1428 $fk_entrepot = $obj->fk_entrepot;
1432 $batch = $obj->batch;
1435 $addOremove = $value > 0 ? 1 : 0;
1436 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1437 $res = $this->
correct_stock_batch($user, $fk_entrepot, abs($value), $addOremove, $label, $price, $dlc, $dluo, $batch, $inventorycode,
'',
null, 0,
null,
true);
1440 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1441 $res = $this->
correct_stock($user, $fk_entrepot, abs($value), (
int) empty($addOremove), $label, $price, $inventorycode,
'',
null, 0);
1460 if (!$error && !$notrigger) {
1462 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
1469 if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) {
1471 if ($conf->product->dir_output) {
1474 if (file_exists($olddir)) {
1478 $res = @rename($olddir, $newdir);
1480 $langs->load(
"errors");
1481 $this->error = $langs->trans(
'ErrorFailToRenameDir', $olddir, $newdir);
1485 require_once DOL_DOCUMENT_ROOT .
'/ecm/class/ecmfiles.class.php';
1486 $ecmfiles =
new EcmFiles($this->db);
1487 $ecmfiles->updateAfterRename(
"produit/".
dol_sanitizeFileName($this->oldcopy->ref),
"produit/".dol_sanitizeFileName($this->ref));
1494 if (isModEnabled(
'variants')) {
1495 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1499 foreach ($comb->fetchAllByFkProductParent($this->id) as $currcomb) {
1500 $currcomb->updateProperties($this, $user);
1504 $this->db->commit();
1507 $this->db->rollback();
1511 if ($this->db->errno() ==
'DB_ERROR_RECORD_ALREADY_EXISTS') {
1512 $langs->load(
"errors");
1513 if (empty($conf->barcode->enabled) || empty($this->barcode)) {
1514 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductAlreadyExists", $this->
ref);
1516 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductBarCodeAlreadyExists", $this->barcode);
1518 $this->errors[] = $this->error;
1519 $this->db->rollback();
1522 $this->error = $langs->trans(
"Error").
" : ".$this->db->error().
" - ".$sql;
1523 $this->errors[] = $this->error;
1524 $this->db->rollback();
1529 $this->db->rollback();
1530 dol_syslog(get_class($this).
"::Update fails verify ".implode(
',', $this->errors), LOG_WARNING);
1542 public function delete(
User $user, $notrigger = 0)
1544 global $conf, $langs;
1545 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
1550 if (empty($this->
id)) {
1551 $this->error =
"Object must be fetched before calling delete";
1554 if (($this->
isProduct() && !$user->
hasRight(
'produit',
'supprimer')) || ($this->isService() && !$user->hasRight(
'service',
'supprimer'))) {
1555 $this->error =
"ErrorForbidden";
1560 if (empty($objectisused)) {
1563 if (!$error && empty($notrigger)) {
1565 $result = $this->
call_trigger(
'PRODUCT_DELETE', $user);
1574 $sql =
"DELETE FROM ".$this->db->prefix().
'product_batch';
1575 $sql .=
" WHERE fk_product_stock IN (";
1576 $sql .=
"SELECT rowid FROM ".$this->db->prefix().
'product_stock';
1577 $sql .=
" WHERE fk_product = ".((int) $this->
id).
")";
1579 $result = $this->db->query($sql);
1582 $this->errors[] = $this->db->lasterror();
1588 $elements = array(
'product_fournisseur_price',
'product_price',
'product_lang',
'categorie_product',
'product_stock',
'product_customer_price',
'product_lot');
1589 foreach ($elements as $table) {
1591 $sql =
"DELETE FROM ".$this->db->prefix().$table;
1592 $sql .=
" WHERE fk_product = ".(int) $this->
id;
1594 $result = $this->db->query($sql);
1597 $this->errors[] = $this->db->lasterror();
1604 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1605 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination2ValuePair.class.php';
1610 if ($prodcomb->deleteByFkProductParent($user, $this->id) < 0) {
1612 $this->errors[] =
'Error deleting combinations';
1616 if (!$error && ($prodcomb->fetchByFkProductChild($this->id) > 0) && ($prodcomb->delete($user) < 0)) {
1618 $this->errors[] =
'Error deleting child combination';
1624 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
1625 $sql .=
" WHERE fk_product_pere = ".(int) $this->
id.
" OR fk_product_fils = ".(
int) $this->id;
1627 $result = $this->db->query($sql);
1630 $this->errors[] = $this->db->lasterror();
1639 dol_syslog(get_class($this).
"::delete error -4 ".$this->error, LOG_ERR);
1645 $sqlz =
"DELETE FROM ".$this->db->prefix().
"product";
1646 $sqlz .=
" WHERE rowid = ".(int) $this->
id;
1648 $resultz = $this->db->query($sqlz);
1651 $this->errors[] = $this->db->lasterror();
1667 if ($conf->product->dir_output) {
1668 $dir = $conf->product->dir_output.
"/".$ref;
1669 if (file_exists($dir)) {
1672 $this->errors[] =
'ErrorFailToDeleteDir';
1680 $this->db->commit();
1683 foreach ($this->errors as $errmsg) {
1684 dol_syslog(get_class($this).
"::delete ".$errmsg, LOG_ERR);
1685 $this->error .= ($this->error ?
', '.$errmsg : $errmsg);
1687 $this->db->rollback();
1691 $this->error =
"ErrorRecordIsUsedCantDelete";
1705 $sellByLabel = $langs->trans(
'SellByDate');
1706 $eatByLabel = $langs->trans(
'EatByDate');
1708 self::SELL_OR_EAT_BY_MANDATORY_ID_NONE => $langs->trans(
'BatchSellOrEatByMandatoryNone'),
1709 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY => $sellByLabel,
1710 self::SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY => $eatByLabel,
1711 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT => $langs->trans(
'BatchSellOrEatByMandatoryAll', $sellByLabel, $eatByLabel),
1722 $sellOrEatByMandatoryLabel =
'';
1725 if (isset($sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory])) {
1726 $sellOrEatByMandatoryLabel = $sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory];
1729 return $sellOrEatByMandatoryLabel;
1740 global $conf, $langs;
1742 $langs_available = $langs->get_available_languages(DOL_DOCUMENT_ROOT, 0, 2);
1743 $current_lang = $langs->getDefaultLang();
1745 foreach ($langs_available as $key => $value) {
1746 if ($key == $current_lang) {
1747 $sql =
"SELECT rowid";
1748 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1749 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1750 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
1752 $result = $this->db->query($sql);
1754 if ($this->db->num_rows($result)) {
1755 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
1757 $sql2 .=
" label='".$this->db->escape($this->label).
"',";
1758 $sql2 .=
" description='".$this->db->escape($this->
description).
"'";
1760 $sql2 .=
", note='".$this->db->escape($this->other).
"'";
1762 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
1764 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
1769 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->label).
"',";
1770 $sql2 .=
" '".$this->db->escape($this->
description).
"'";
1772 $sql2 .=
", '".$this->db->escape($this->other).
"'";
1776 dol_syslog(get_class($this).
'::setMultiLangs key = current_lang = '.$key);
1777 if (!$this->db->query($sql2)) {
1778 $this->error = $this->db->lasterror();
1781 } elseif (isset($this->multilangs[$key])) {
1782 if (empty($this->multilangs[
"$key"][
"label"])) {
1783 $this->errors[] = $key .
' : ' . $langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Label"));
1787 $sql =
"SELECT rowid";
1788 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1789 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1790 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
1792 $result = $this->db->query($sql);
1794 if ($this->db->num_rows($result)) {
1795 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
1797 $sql2 .=
" label = '".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
1798 $sql2 .=
" description = '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
1800 $sql2 .=
", note = '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
1802 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
1804 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
1809 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
1810 $sql2 .=
" '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
1812 $sql2 .=
", '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
1818 if ($this->multilangs[
"$key"][
"label"] || $this->multilangs[
"$key"][
"description"]) {
1819 if (!$this->db->query($sql2)) {
1820 $this->error = $this->db->lasterror();
1830 $result = $this->
call_trigger(
'PRODUCT_SET_MULTILANGS', $user);
1832 $this->error = $this->db->lasterror();
1850 $sql =
"DELETE FROM ".$this->db->prefix().
"product_lang";
1851 $sql .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($langtodelete).
"'";
1853 dol_syslog(get_class($this).
'::delMultiLangs', LOG_DEBUG);
1854 $result = $this->db->query($sql);
1857 $result = $this->
call_trigger(
'PRODUCT_DEL_MULTILANGS', $user);
1859 $this->error = $this->db->lasterror();
1860 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
1866 $this->error = $this->db->lasterror();
1867 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
1882 global $user, $langs, $conf;
1888 if ($type ==
'buy') {
1889 $field =
'accountancy_code_buy';
1890 } elseif ($type ==
'buy_intra') {
1891 $field =
'accountancy_code_buy_intra';
1892 } elseif ($type ==
'buy_export') {
1893 $field =
'accountancy_code_buy_export';
1894 } elseif ($type ==
'sell') {
1895 $field =
'accountancy_code_sell';
1896 } elseif ($type ==
'sell_intra') {
1897 $field =
'accountancy_code_sell_intra';
1898 } elseif ($type ==
'sell_export') {
1899 $field =
'accountancy_code_sell_export';
1904 $sql =
"UPDATE ".$this->db->prefix().$this->table_element.
" SET ";
1905 $sql .=
"$field = '".$this->db->escape($value).
"'";
1906 $sql .=
" WHERE rowid = ".((int) $this->
id);
1909 $resql = $this->db->query($sql);
1913 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
1920 $this->db->rollback();
1924 $this->$field = $value;
1926 $this->db->commit();
1929 $this->error = $this->db->lasterror();
1930 $this->db->rollback();
1944 $current_lang = $langs->getDefaultLang();
1946 $sql =
"SELECT lang, label, description, note as other";
1947 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1948 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1950 $result = $this->db->query($sql);
1952 while ($obj = $this->db->fetch_object($result)) {
1954 if ($obj->lang == $current_lang) {
1955 $this->label = $obj->label;
1957 $this->other = $obj->other;
1959 $this->multilangs[(string) $obj->lang][
"label"] = $obj->label;
1960 $this->multilangs[(string) $obj->lang][
"description"] = $obj->description;
1961 $this->multilangs[(string) $obj->lang][
"other"] = $obj->other;
1965 $this->error =
"Error: ".$this->db->lasterror().
" - ".$sql;
1978 $testExit = array(
'multiprices',
'multiprices_ttc',
'multiprices_base_type',
'multiprices_min',
'multiprices_min_ttc',
'multiprices_tva_tx',
'multiprices_recuperableonly');
1980 foreach ($testExit as $field) {
1981 if (!isset($this->$field)) {
1984 $tmparray = $this->$field;
1985 if (!isset($tmparray[$level])) {
1991 'level' => $level ? $level : 1,
1992 'multiprices' => (float) $this->multiprices[$level],
1993 'multiprices_ttc' => (
float) $this->multiprices_ttc[$level],
1994 'multiprices_base_type' => $this->multiprices_base_type[$level],
1995 'multiprices_min' => (float) $this->multiprices_min[$level],
1996 'multiprices_min_ttc' => (
float) $this->multiprices_min_ttc[$level],
1997 'multiprices_tva_tx' => (float) $this->multiprices_tva_tx[$level],
1998 'multiprices_recuperableonly' => (
float) $this->multiprices_recuperableonly[$level],
2021 if (empty($this->price_by_qty)) {
2022 $this->price_by_qty = 0;
2026 $sql =
"INSERT INTO ".$this->db->prefix().
"product_price(price_level,date_price, fk_product, fk_user_author, price_label, price, price_ttc, price_base_type,tosell, tva_tx, default_vat_code, recuperableonly,";
2027 $sql .=
" localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, price_min,price_min_ttc,price_by_qty,entity,fk_price_expression) ";
2028 $sql .=
" VALUES(".($level ? ((int) $level) : 1).
", '".$this->db->idate($now).
"', ".((int) $this->
id).
", ".((int) $user->id).
", ".(empty($this->price_label) ?
"null" :
"'".$this->db->escape($this->price_label).
"'").
", ".((float)
price2num($this->
price)).
", ".((
float)
price2num($this->price_ttc)).
",'".$this->db->escape($this->price_base_type).
"',".((int) $this->
status).
", ".((float)
price2num($this->tva_tx)).
", ".($this->default_vat_code ? (
"'".$this->db->escape($this->default_vat_code).
"'") :
"null").
", ".((
int) $this->tva_npr).
",";
2029 $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');
2032 dol_syslog(get_class($this).
"::_log_price", LOG_DEBUG);
2033 $resql = $this->db->query($sql);
2035 $this->error = $this->db->lasterror();
2055 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price_by_qty";
2056 $sql .=
" WHERE fk_product_price = ".((int) $rowid);
2057 $resql = $this->db->query($sql);
2059 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price";
2060 $sql .=
" WHERE rowid=".((int) $rowid);
2061 $resql = $this->db->query($sql);
2065 $this->error = $this->db->lasterror();
2080 public function getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp = 0)
2082 global $conf, $hookmanager, $action;
2085 if (is_object($hookmanager)) {
2086 $parameters = array(
'thirdparty_seller' => $thirdparty_seller,
'thirdparty_buyer' => $thirdparty_buyer,
'pqp' => $pqp);
2088 $reshook = $hookmanager->executeHooks(
'getSellPrice', $parameters, $this, $action);
2090 return $hookmanager->resArray;
2096 $tva_npr =
get_default_npr($thirdparty_seller, $thirdparty_buyer, $this->
id);
2101 $pu_ht = $this->price;
2102 $pu_ttc = $this->price_ttc;
2103 $price_min = $this->price_min;
2104 $price_base_type = $this->price_base_type;
2107 if (
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !empty($thirdparty_buyer->price_level)) {
2108 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
2109 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
2110 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
2111 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
2113 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2114 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2116 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2117 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2125 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2129 $filter = array(
't.fk_product' => $this->
id,
't.fk_soc' => $thirdparty_buyer->id);
2131 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2133 if (count($prodcustprice->lines) > 0) {
2134 $pu_ht =
price($prodcustprice->lines[0]->price);
2135 $price_min =
price($prodcustprice->lines[0]->price_min);
2136 $pu_ttc =
price($prodcustprice->lines[0]->price_ttc);
2137 $price_base_type = $prodcustprice->lines[0]->price_base_type;
2138 $tva_tx = $prodcustprice->lines[0]->tva_tx;
2139 if ($prodcustprice->lines[0]->default_vat_code && !preg_match(
'/\(.*\)/',
$tva_tx)) {
2140 $tva_tx .=
' ('.$prodcustprice->lines[0]->default_vat_code.
')';
2142 $tva_npr = $prodcustprice->lines[0]->recuperableonly;
2150 if ($this->prices_by_qty[0]) {
2153 foreach ($this->prices_by_qty_list[0] as $priceforthequantityarray) {
2154 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2158 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2159 $pu_ht = $priceforthequantityarray[
'unitprice'];
2161 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2168 if ($this->prices_by_qty[$thirdparty_buyer->price_level]) {
2171 foreach ($this->prices_by_qty_list[$thirdparty_buyer->price_level] as $priceforthequantityarray) {
2172 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2176 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2177 $pu_ht = $priceforthequantityarray[
'unitprice'];
2179 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2186 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);
2203 public function get_buyprice($prodfournprice, $qty, $product_id = 0, $fourn_ref =
'', $fk_soc = 0)
2206 global $action, $hookmanager;
2209 if (is_object($hookmanager)) {
2210 $parameters = array(
2211 'prodfournprice' => $prodfournprice,
2213 'product_id' => $product_id,
2214 'fourn_ref' => $fourn_ref,
2215 'fk_soc' => $fk_soc,
2218 $reshook = $hookmanager->executeHooks(
'getBuyPrice', $parameters, $this, $action);
2220 return $hookmanager->resArray;
2227 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2228 $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,";
2229 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2230 $sql .=
" pfp.packaging";
2231 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2232 $sql .=
" WHERE pfp.rowid = ".((int) $prodfournprice);
2234 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2236 $sql .=
" ORDER BY pfp.quantity DESC";
2238 dol_syslog(get_class($this).
"::get_buyprice first search by prodfournprice/qty", LOG_DEBUG);
2239 $resql = $this->db->query($sql);
2241 $obj = $this->db->fetch_object($resql);
2242 if ($obj && $obj->quantity > 0) {
2243 if (isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2245 $prod_supplier->product_fourn_price_id = $obj->rowid;
2246 $prod_supplier->id = $obj->fk_product;
2247 $prod_supplier->fourn_qty = $obj->quantity;
2248 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2249 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2251 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2253 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2254 if ($price_result >= 0) {
2255 $obj->price = $price_result;
2258 $this->product_fourn_price_id = $obj->rowid;
2259 $this->buyprice = $obj->price;
2260 $this->fourn_pu = $obj->price / $obj->quantity;
2261 $this->fourn_price_base_type =
'HT';
2262 $this->fourn_socid = $obj->fk_soc;
2263 $this->ref_fourn = $obj->ref_supplier;
2264 $this->ref_supplier = $obj->ref_supplier;
2265 $this->desc_supplier = $obj->desc_supplier;
2266 $this->remise_percent = $obj->remise_percent;
2267 $this->vatrate_supplier = $obj->tva_tx;
2268 $this->default_vat_code_supplier = $obj->default_vat_code;
2269 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2270 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2271 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2272 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2273 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2275 $this->packaging = $obj->packaging;
2277 $result = $obj->fk_product;
2281 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2282 $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,";
2283 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2284 $sql .=
" pfp.packaging";
2285 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2286 $sql .=
" WHERE 1 = 1";
2287 if ($product_id > 0) {
2288 $sql .=
" AND pfp.fk_product = ".((int) $product_id);
2290 if ($fourn_ref !=
'none') {
2291 $sql .=
" AND pfp.ref_fourn = '".$this->db->escape($fourn_ref).
"'";
2294 $sql .=
" AND pfp.fk_soc = ".((int) $fk_soc);
2297 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2299 $sql .=
" ORDER BY pfp.quantity DESC";
2302 dol_syslog(get_class($this).
"::get_buyprice second search from qty/ref/product_id", LOG_DEBUG);
2303 $resql = $this->db->query($sql);
2305 $obj = $this->db->fetch_object($resql);
2306 if ($obj && $obj->quantity > 0) {
2307 if (isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2309 $prod_supplier->product_fourn_price_id = $obj->rowid;
2310 $prod_supplier->id = $obj->fk_product;
2311 $prod_supplier->fourn_qty = $obj->quantity;
2312 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2313 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2315 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2317 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2319 $obj->price = $price_result;
2322 $this->product_fourn_price_id = $obj->rowid;
2323 $this->buyprice = $obj->price;
2324 $this->fourn_qty = $obj->quantity;
2325 $this->fourn_pu = $obj->price / $obj->quantity;
2326 $this->fourn_price_base_type =
'HT';
2327 $this->fourn_socid = $obj->fk_soc;
2328 $this->ref_fourn = $obj->ref_supplier;
2329 $this->ref_supplier = $obj->ref_supplier;
2330 $this->desc_supplier = $obj->desc_supplier;
2331 $this->remise_percent = $obj->remise_percent;
2332 $this->vatrate_supplier = $obj->tva_tx;
2333 $this->default_vat_code_supplier = $obj->default_vat_code;
2334 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2335 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2336 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2337 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2338 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2340 $this->packaging = $obj->packaging;
2342 $result = $obj->fk_product;
2348 $this->error = $this->db->lasterror();
2353 $this->error = $this->db->lasterror();
2377 public function updatePrice($newprice, $newpricebase, $user, $newvat =
null, $newminprice = 0, $level = 0, $newnpr = 0, $newpbq = 0, $ignore_autogen = 0, $localtaxes_array = array(), $newdefaultvatcode =
'', $price_label =
'', $notrigger = 0)
2379 global $conf, $langs;
2385 dol_syslog(get_class($this).
"::update_price id=".$id.
" newprice=".$newprice.
" newpricebase=".$newpricebase.
" newminprice=".$newminprice.
" level=".$level.
" npr=".$newnpr.
" newdefaultvatcode=".$newdefaultvatcode);
2388 if (empty($this->tva_tx)) {
2391 if (empty($newnpr)) {
2394 if (empty($newminprice)) {
2399 if ($newvat ===
null || $newvat ==
'') {
2405 if ((
getDolGlobalString(
'PRODUIT_MULTIPRICES') ||
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) && !$ignore_autogen && $this->price_autogen && ($level == 1)) {
2406 return $this->
generateMultiprices($user, $newprice, $newpricebase, $newvat, $newnpr, $newpbq);
2409 if (!empty($newminprice) && ($newminprice > $newprice)) {
2410 $this->error =
'ErrorPriceCantBeLowerThanMinPrice';
2414 if ($newprice === 0 || $newprice !==
'') {
2415 if ($newpricebase ==
'TTC') {
2416 $price_ttc =
price2num($newprice,
'MU');
2417 $price = (float)
price2num($newprice) / (1 + ((float) $newvat / 100));
2420 if ($newminprice !=
'' || $newminprice == 0) {
2421 $price_min_ttc =
price2num($newminprice,
'MU');
2422 $price_min = (float)
price2num($newminprice) / (1 + ($newvat / 100));
2423 $price_min =
price2num($price_min,
'MU');
2429 $price = (float)
price2num($newprice,
'MU');
2430 $price_ttc = ($newnpr != 1) ?
price2num($newprice) * (1 + ($newvat / 100)) : $price;
2431 $price_ttc = (float)
price2num($price_ttc,
'MU');
2433 if ($newminprice !==
'' || $newminprice === 0) {
2434 $price_min =
price2num($newminprice,
'MU');
2435 $price_min_ttc = (float)
price2num($newminprice) * (1 + ($newvat / 100));
2436 $price_min_ttc =
price2num($price_min_ttc,
'MU');
2445 if (count($localtaxes_array) > 0) {
2446 $localtaxtype1 = $localtaxes_array[
'0'];
2447 $localtax1 = $localtaxes_array[
'1'];
2448 $localtaxtype2 = $localtaxes_array[
'2'];
2449 $localtax2 = $localtaxes_array[
'3'];
2452 if (!empty($newdefaultvatcode)) {
2455 $sql =
"SELECT t.rowid, t.code, t.recuperableonly as tva_npr, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
2456 $sql .=
" FROM ".MAIN_DB_PREFIX.
"c_tva as t, ".MAIN_DB_PREFIX.
"c_country as c";
2457 $sql .=
" WHERE t.fk_pays = c.rowid AND c.code = '".$this->db->escape($mysoc->country_code).
"'";
2458 $sql .=
" AND t.taux = ".((float) $newdefaultvatcode).
" AND t.active = 1";
2459 $sql .=
" AND t.code = '".$this->db->escape($newdefaultvatcode).
"'";
2460 $resql = $this->db->query($sql);
2462 $obj = $this->db->fetch_object($resql);
2464 $npr = $obj->tva_npr;
2465 $localtax1 = $obj->localtax1;
2466 $localtax2 = $obj->localtax2;
2467 $localtaxtype1 = $obj->localtax1_type;
2468 $localtaxtype2 = $obj->localtax2_type;
2473 $localtaxtype1 =
'0';
2475 $localtaxtype2 =
'0';
2479 if (empty($localtax1)) {
2482 if (empty($localtax2)) {
2490 $sql =
"UPDATE ".$this->db->prefix().
"product SET";
2491 $sql .=
" price_base_type = '".$this->db->escape($newpricebase).
"',";
2492 $sql .=
" price = ".(float) $price.
",";
2493 $sql .=
" price_ttc = ".(float) $price_ttc.
",";
2494 $sql .=
" price_min = ".(float) $price_min.
",";
2495 $sql .=
" price_min_ttc = ".(float) $price_min_ttc.
",";
2496 $sql .=
" localtax1_tx = ".($localtax1 >= 0 ? (float) $localtax1 :
'NULL').
",";
2497 $sql .=
" localtax2_tx = ".($localtax2 >= 0 ? (float) $localtax2 :
'NULL').
",";
2498 $sql .=
" localtax1_type = ".($localtaxtype1 !=
'' ?
"'".$this->db->escape($localtaxtype1).
"'" :
"'0'").
",";
2499 $sql .=
" localtax2_type = ".($localtaxtype2 !=
'' ?
"'".$this->db->escape($localtaxtype2).
"'" :
"'0'").
",";
2500 $sql .=
" default_vat_code = ".($newdefaultvatcode ?
"'".$this->db->escape($newdefaultvatcode).
"'" :
"null").
",";
2501 $sql .=
" price_label = ".(!empty($price_label) ?
"'".$this->db->escape($price_label).
"'" :
"null").
",";
2502 $sql .=
" tva_tx = ".(float)
price2num($newvat).
",";
2503 $sql .=
" recuperableonly = '".$this->db->escape($newnpr).
"'";
2504 $sql .=
" WHERE rowid = ".((int) $id);
2506 dol_syslog(get_class($this).
"::update_price", LOG_DEBUG);
2507 $resql = $this->db->query($sql);
2509 $this->multiprices[$level] = $price;
2510 $this->multiprices_ttc[$level] = $price_ttc;
2511 $this->multiprices_min[$level] = $price_min;
2512 $this->multiprices_min_ttc[$level] = $price_min_ttc;
2513 $this->multiprices_base_type[$level] = $newpricebase;
2514 $this->multiprices_default_vat_code[$level] = $newdefaultvatcode;
2515 $this->multiprices_tva_tx[$level] = $newvat;
2516 $this->multiprices_recuperableonly[$level] = $newnpr;
2518 $this->
price = $price;
2519 $this->price_label = $price_label;
2520 $this->price_ttc = $price_ttc;
2521 $this->price_min = $price_min;
2522 $this->price_min_ttc = $price_min_ttc;
2523 $this->price_base_type = $newpricebase;
2524 $this->default_vat_code = $newdefaultvatcode;
2525 $this->tva_tx = $newvat;
2526 $this->tva_npr = $newnpr;
2529 $this->localtax1_tx = $localtax1;
2530 $this->localtax2_tx = $localtax2;
2531 $this->localtax1_type = $localtaxtype1;
2532 $this->localtax2_type = $localtaxtype2;
2535 $this->price_by_qty = $newpbq;
2539 if (!empty(array_diff_assoc($newPriceData, $lastPriceData)) || !
getDolGlobalString(
'PRODUIT_MULTIPRICES')) {
2543 $this->level = $level;
2547 $result = $this->
call_trigger(
'PRODUCT_PRICE_MODIFY', $user);
2549 $this->db->rollback();
2555 $this->db->commit();
2557 $this->db->rollback();
2558 $this->error = $this->db->lasterror();
2577 $this->fk_price_expression = $expression_id;
2579 return $this->
update($this->
id, $user);
2594 public function fetch($id = 0, $ref =
'', $ref_ext =
'', $barcode =
'', $ignore_expression = 0, $ignore_price_load = 0, $ignore_lang_load = 0)
2596 include_once DOL_DOCUMENT_ROOT.
'/core/lib/company.lib.php';
2598 global $langs, $conf;
2600 dol_syslog(get_class($this).
"::fetch id=".$id.
" ref=".$ref.
" ref_ext=".$ref_ext);
2603 if (!$id && !$ref && !$ref_ext && !$barcode) {
2604 $this->error =
'ErrorWrongParameters';
2605 dol_syslog(get_class($this).
"::fetch ".$this->error, LOG_ERR);
2609 $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,";
2610 $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,";
2611 $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,";
2612 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.last_main_doc,";
2613 $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,";
2615 $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,";
2617 $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,";
2622 $separatedEntityPMP =
false;
2623 $separatedStock =
false;
2624 $visibleWarehousesEntities = $conf->entity;
2627 $checkPMPPerEntity = $this->db->query(
"SELECT pmp FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = ".((int) $id).
" AND entity = ".(
int) $conf->entity);
2628 if ($this->db->num_rows($checkPMPPerEntity) > 0) {
2629 $separatedEntityPMP =
true;
2633 $separatedStock =
true;
2634 if (isset($mc->sharings[
'stock']) && !empty($mc->sharings[
'stock'])) {
2635 $visibleWarehousesEntities .=
"," . implode(
",", $mc->sharings[
'stock']);
2638 if ($separatedEntityPMP) {
2639 $sql .=
" ppe.pmp,";
2643 $sql .=
" p.datec, p.tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.sell_or_eat_by_mandatory, p.batch_mask, p.fk_unit,";
2644 $sql .=
" p.fk_price_expression, p.price_autogen, p.model_pdf,";
2645 $sql .=
" p.price_label,";
2646 if ($separatedStock) {
2647 $sql .=
" SUM(sp.reel) as stock";
2651 $sql .=
" FROM ".$this->db->prefix().
"product as p";
2653 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int) $conf->entity);
2655 if ($separatedStock) {
2656 $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).
"))";
2660 $sql .=
" WHERE p.rowid = ".((int) $id);
2662 $sql .=
" WHERE p.entity IN (".getEntity($this->element).
")";
2664 $sql .=
" AND p.ref = '".$this->db->escape($ref).
"'";
2665 } elseif ($ref_ext) {
2666 $sql .=
" AND p.ref_ext = '".$this->db->escape($ref_ext).
"'";
2667 } elseif ($barcode) {
2668 $sql .=
" AND p.barcode = '".$this->db->escape($barcode).
"'";
2671 if ($separatedStock) {
2672 $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,";
2673 $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,";
2674 $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,";
2675 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
2676 $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,";
2678 $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,";
2680 $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,";
2682 if ($separatedEntityPMP) {
2683 $sql .=
" ppe.pmp,";
2687 $sql .=
" p.datec, p.tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.sell_or_eat_by_mandatory, p.batch_mask, p.fk_unit,";
2688 $sql .=
" p.fk_price_expression, p.price_autogen, p.model_pdf";
2689 $sql .=
" ,p.price_label";
2690 if (!$separatedStock) {
2691 $sql .=
", p.stock";
2695 $resql = $this->db->query($sql);
2697 unset($this->oldcopy);
2699 if ($this->db->num_rows($resql) > 0) {
2700 $obj = $this->db->fetch_object($resql);
2702 $this->
id = $obj->rowid;
2703 $this->
ref = $obj->ref;
2704 $this->ref_ext = $obj->ref_ext;
2705 $this->label = $obj->label;
2707 $this->url = $obj->url;
2708 $this->note_public = $obj->note_public;
2709 $this->note_private = $obj->note_private;
2710 $this->note = $obj->note_private;
2712 $this->
type = $obj->fk_product_type;
2713 $this->price_label = $obj->price_label;
2714 $this->
status = $obj->tosell;
2715 $this->status_buy = $obj->tobuy;
2716 $this->status_batch = $obj->tobatch;
2717 $this->sell_or_eat_by_mandatory = $obj->sell_or_eat_by_mandatory;
2718 $this->batch_mask = $obj->batch_mask;
2720 $this->customcode = $obj->customcode;
2721 $this->country_id = $obj->fk_country;
2722 $this->country_code =
getCountry($this->country_id, 2, $this->db);
2723 $this->state_id = $obj->fk_state;
2724 $this->lifetime = $obj->lifetime;
2725 $this->qc_frequency = $obj->qc_frequency;
2726 $this->
price = $obj->price;
2727 $this->price_ttc = $obj->price_ttc;
2728 $this->price_min = $obj->price_min;
2729 $this->price_min_ttc = $obj->price_min_ttc;
2730 $this->price_base_type = $obj->price_base_type;
2731 $this->cost_price = $obj->cost_price;
2732 $this->default_vat_code = $obj->default_vat_code;
2733 $this->tva_tx = $obj->tva_tx;
2735 $this->tva_npr = $obj->tva_npr;
2737 $this->localtax1_tx = $obj->localtax1_tx;
2738 $this->localtax2_tx = $obj->localtax2_tx;
2739 $this->localtax1_type = $obj->localtax1_type;
2740 $this->localtax2_type = $obj->localtax2_type;
2742 $this->finished = $obj->finished;
2743 $this->fk_default_bom = $obj->fk_default_bom;
2745 $this->duration = $obj->duration;
2746 $this->duration_value = $obj->duration ? substr($obj->duration, 0,
dol_strlen($obj->duration) - 1) :
null;
2747 $this->duration_unit = $obj->duration ? substr($obj->duration, -1) :
null;
2748 $this->canvas = $obj->canvas;
2749 $this->net_measure = $obj->net_measure;
2750 $this->net_measure_units = $obj->net_measure_units;
2751 $this->weight = $obj->weight;
2752 $this->weight_units = $obj->weight_units;
2753 $this->length = $obj->length;
2754 $this->length_units = $obj->length_units;
2755 $this->width = $obj->width;
2756 $this->width_units = $obj->width_units;
2757 $this->height = $obj->height;
2758 $this->height_units = $obj->height_units;
2760 $this->surface = $obj->surface;
2761 $this->surface_units = $obj->surface_units;
2762 $this->volume = $obj->volume;
2763 $this->volume_units = $obj->volume_units;
2764 $this->barcode = $obj->barcode;
2765 $this->barcode_type = $obj->fk_barcode_type;
2767 $this->accountancy_code_buy = $obj->accountancy_code_buy;
2768 $this->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra;
2769 $this->accountancy_code_buy_export = $obj->accountancy_code_buy_export;
2770 $this->accountancy_code_sell = $obj->accountancy_code_sell;
2771 $this->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra;
2772 $this->accountancy_code_sell_export = $obj->accountancy_code_sell_export;
2774 $this->fk_default_warehouse = $obj->fk_default_warehouse;
2775 $this->fk_default_workstation = $obj->fk_default_workstation;
2776 $this->seuil_stock_alerte = $obj->seuil_stock_alerte;
2777 $this->desiredstock = $obj->desiredstock;
2778 $this->stock_reel = $obj->stock;
2779 $this->pmp = $obj->pmp;
2781 $this->date_creation = $obj->datec;
2782 $this->date_modification = $obj->tms;
2783 $this->import_key = $obj->import_key;
2784 $this->entity = $obj->entity;
2786 $this->ref_ext = $obj->ref_ext;
2787 $this->fk_price_expression = $obj->fk_price_expression;
2788 $this->fk_unit = $obj->fk_unit;
2789 $this->price_autogen = $obj->price_autogen;
2790 $this->model_pdf = $obj->model_pdf;
2791 $this->last_main_doc = $obj->last_main_doc;
2793 $this->mandatory_period = $obj->mandatory_period;
2795 $this->db->free($resql);
2808 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
2809 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
2810 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
2811 $sql .=
" ,price_label";
2812 $sql .=
" FROM ".$this->db->prefix().
"product_price";
2813 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
2814 $sql .=
" AND price_level=".((int) $i);
2815 $sql .=
" AND fk_product = ".((int) $this->
id);
2816 $sql .=
" ORDER BY date_price DESC, rowid DESC";
2818 $resql = $this->db->query($sql);
2820 $result = $this->db->fetch_array($resql);
2822 $this->multiprices[$i] = $result ? $result[
"price"] :
null;
2823 $this->multiprices_ttc[$i] = $result ? $result[
"price_ttc"] :
null;
2824 $this->multiprices_min[$i] = $result ? $result[
"price_min"] :
null;
2825 $this->multiprices_min_ttc[$i] = $result ? $result[
"price_min_ttc"] :
null;
2826 $this->multiprices_base_type[$i] = $result ? $result[
"price_base_type"] :
null;
2828 $this->multiprices_tva_tx[$i] = $result ? $result[
"tva_tx"].($result ?
' ('.$result[
'default_vat_code'].
')' :
'') :
null;
2829 $this->multiprices_recuperableonly[$i] = $result ? $result[
"recuperableonly"] :
null;
2868 $this->error = $this->db->lasterror;
2872 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES') && empty($ignore_price_load)) {
2874 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY') && empty($ignore_price_load)) {
2875 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
2876 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid";
2877 $sql .=
" FROM ".$this->db->prefix().
"product_price";
2878 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2879 $sql .=
" ORDER BY date_price DESC, rowid DESC";
2882 $resql = $this->db->query($sql);
2884 $result = $this->db->fetch_array($resql);
2888 $this->prices_by_qty[0] = $result[
"price_by_qty"];
2889 $this->prices_by_qty_id[0] = $result[
"rowid"];
2891 if ($this->prices_by_qty[0] == 1) {
2892 $sql =
"SELECT rowid,price, unitprice, quantity, remise_percent, remise, remise, price_base_type";
2893 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
2894 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[0]);
2895 $sql .=
" ORDER BY quantity ASC";
2897 $resql = $this->db->query($sql);
2899 $resultat = array();
2901 while ($result = $this->db->fetch_array($resql)) {
2902 $resultat[$ii] = array();
2903 $resultat[$ii][
"rowid"] = $result[
"rowid"];
2904 $resultat[$ii][
"price"] = $result[
"price"];
2905 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
2906 $resultat[$ii][
"quantity"] = $result[
"quantity"];
2907 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
2909 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
2912 $this->prices_by_qty_list[0] = $resultat;
2914 $this->error = $this->db->lasterror;
2920 $this->error = $this->db->lasterror;
2923 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') && empty($ignore_price_load)) {
2925 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
2926 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
2927 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
2928 $sql .=
" FROM ".$this->db->prefix().
"product_price";
2929 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
2930 $sql .=
" AND price_level=".((int) $i);
2931 $sql .=
" AND fk_product = ".((int) $this->
id);
2932 $sql .=
" ORDER BY date_price DESC, rowid DESC";
2934 $resql = $this->db->query($sql);
2936 $this->error = $this->db->lasterror;
2938 } elseif ($result = $this->db->fetch_array($resql)) {
2939 $this->multiprices[$i] = (!empty($result[
"price"]) ? $result[
"price"] : 0);
2940 $this->multiprices_ttc[$i] = (!empty($result[
"price_ttc"]) ? $result[
"price_ttc"] : 0);
2941 $this->multiprices_min[$i] = (!empty($result[
"price_min"]) ? $result[
"price_min"] : 0);
2942 $this->multiprices_min_ttc[$i] = (!empty($result[
"price_min_ttc"]) ? $result[
"price_min_ttc"] : 0);
2943 $this->multiprices_base_type[$i] = (!empty($result[
"price_base_type"]) ? $result[
"price_base_type"] :
'');
2945 $this->multiprices_tva_tx[$i] = (!empty($result[
"tva_tx"]) ? $result[
"tva_tx"] : 0);
2946 $this->multiprices_recuperableonly[$i] = (!empty($result[
"recuperableonly"]) ? $result[
"recuperableonly"] : 0);
2949 $this->prices_by_qty[$i] = (!empty($result[
"price_by_qty"]) ? $result[
"price_by_qty"] : 0);
2950 $this->prices_by_qty_id[$i] = (!empty($result[
"rowid"]) ? $result[
"rowid"] : 0);
2952 if ($this->prices_by_qty[$i] == 1) {
2953 $sql =
"SELECT rowid, price, unitprice, quantity, remise_percent, remise, price_base_type";
2954 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
2955 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[$i]);
2956 $sql .=
" ORDER BY quantity ASC";
2958 $resql = $this->db->query($sql);
2960 $resultat = array();
2962 while ($result = $this->db->fetch_array($resql)) {
2963 $resultat[$ii] = array();
2964 $resultat[$ii][
"rowid"] = $result[
"rowid"];
2965 $resultat[$ii][
"price"] = $result[
"price"];
2966 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
2967 $resultat[$ii][
"quantity"] = $result[
"quantity"];
2968 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
2969 $resultat[$ii][
"remise"] = $result[
"remise"];
2970 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
2973 $this->prices_by_qty_list[$i] = $resultat;
2975 $this->error = $this->db->lasterror;
2983 if (isModEnabled(
'dynamicprices') && !empty($this->fk_price_expression) && empty($ignore_expression)) {
2984 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2986 $price_result = $priceparser->parseProduct($this);
2987 if ($price_result >= 0) {
2988 $this->
price = $price_result;
2990 $this->price_ttc = (float)
price2num($this->
price) * (1 + ($this->tva_tx / 100));
2991 $this->price_ttc = (float)
price2num($this->price_ttc,
'MU');
2997 $this->stock_warehouse = array();
3004 $this->error = $this->db->lasterror();
3019 global $user, $hookmanager, $action;
3023 foreach (array(
'toconsume',
'consumed',
'toproduce',
'produced') as $role) {
3024 $this->stats_mo[
'customers_'.$role] = 0;
3025 $this->stats_mo[
'nb_'.$role] = 0;
3026 $this->stats_mo[
'qty_'.$role] = 0;
3028 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3029 $sql .=
" SUM(mp.qty) as qty";
3030 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as c";
3031 $sql .=
" INNER JOIN ".$this->db->prefix().
"mrp_production as mp ON mp.fk_mo=c.rowid";
3032 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3033 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc=c.fk_soc AND sc.fk_user = ".((int) $user->id);
3036 $sql .=
" c.entity IN (".getEntity(
'mo').
")";
3038 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3039 $sql .=
" AND mp.role ='".$this->db->escape($role).
"'";
3041 $sql .=
" AND c.fk_soc = ".((int) $socid);
3044 $result = $this->db->query($sql);
3046 $obj = $this->db->fetch_object($result);
3047 $this->stats_mo[
'customers_'.$role] = $obj->nb_customers ? $obj->nb_customers : 0;
3048 $this->stats_mo[
'nb_'.$role] = $obj->nb ? $obj->nb : 0;
3049 $this->stats_mo[
'qty_'.$role] = $obj->qty ?
price2num($obj->qty,
'MS') : 0;
3051 $this->error = $this->db->error();
3056 if (!empty($error)) {
3060 $parameters = array(
'socid' => $socid);
3061 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3063 $this->stats_mo = $hookmanager->resArray[
'stats_mo'];
3079 global $user, $hookmanager, $action;
3083 $this->stats_bom[
'nb_toproduce'] = 0;
3084 $this->stats_bom[
'nb_toconsume'] = 0;
3085 $this->stats_bom[
'qty_toproduce'] = 0;
3086 $this->stats_bom[
'qty_toconsume'] = 0;
3088 $sql =
"SELECT COUNT(DISTINCT b.rowid) as nb_toproduce,";
3089 $sql .=
" SUM(b.qty) as qty_toproduce";
3090 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3091 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
3093 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3094 $sql .=
" AND b.fk_product =".((int) $this->
id);
3095 $sql .=
" GROUP BY b.rowid";
3097 $result = $this->db->query($sql);
3099 $obj = $this->db->fetch_object($result);
3100 $this->stats_bom[
'nb_toproduce'] = !empty($obj->nb_toproduce) ? $obj->nb_toproduce : 0;
3101 $this->stats_bom[
'qty_toproduce'] = !empty($obj->qty_toproduce) ?
price2num($obj->qty_toproduce) : 0;
3103 $this->error = $this->db->error();
3107 $sql =
"SELECT COUNT(DISTINCT bl.rowid) as nb_toconsume,";
3108 $sql .=
" SUM(bl.qty) as qty_toconsume";
3109 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3110 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
3112 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3113 $sql .=
" AND bl.fk_product =".((int) $this->
id);
3115 $result = $this->db->query($sql);
3117 $obj = $this->db->fetch_object($result);
3118 $this->stats_bom[
'nb_toconsume'] = !empty($obj->nb_toconsume) ? $obj->nb_toconsume : 0;
3119 $this->stats_bom[
'qty_toconsume'] = !empty($obj->qty_toconsume) ?
price2num($obj->qty_toconsume) : 0;
3121 $this->error = $this->db->error();
3125 if (!empty($error)) {
3129 $parameters = array(
'socid' => $socid);
3130 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3132 $this->stats_bom = $hookmanager->resArray[
'stats_bom'];
3148 global $conf, $user, $hookmanager, $action;
3150 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_customers, COUNT(DISTINCT p.rowid) as nb,";
3151 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3152 $sql .=
" FROM ".$this->db->prefix().
"propaldet as pd";
3153 $sql .=
", ".$this->db->prefix().
"propal as p";
3154 $sql .=
", ".$this->db->prefix().
"societe as s";
3155 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3156 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3158 $sql .=
" WHERE p.rowid = pd.fk_propal";
3159 $sql .=
" AND p.fk_soc = s.rowid";
3160 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
3161 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3162 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3163 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3167 $sql .=
" AND p.fk_soc = ".((int) $socid);
3170 $result = $this->db->query($sql);
3172 $obj = $this->db->fetch_object($result);
3173 $this->stats_propale[
'customers'] = $obj->nb_customers;
3174 $this->stats_propale[
'nb'] = $obj->nb;
3175 $this->stats_propale[
'rows'] = $obj->nb_rows;
3176 $this->stats_propale[
'qty'] = $obj->qty ? $obj->qty : 0;
3181 if (is_array($TFather) && !empty($TFather)) {
3182 foreach ($TFather as &$fatherData) {
3183 $pFather =
new Product($this->db);
3184 $pFather->id = $fatherData[
'id'];
3185 $qtyCoef = $fatherData[
'qty'];
3187 if ($fatherData[
'incdec']) {
3188 $pFather->load_stats_propale($socid);
3190 $this->stats_propale[
'customers'] += $pFather->stats_propale[
'customers'];
3191 $this->stats_propale[
'nb'] += $pFather->stats_propale[
'nb'];
3192 $this->stats_propale[
'rows'] += $pFather->stats_propale[
'rows'];
3193 $this->stats_propale[
'qty'] += $pFather->stats_propale[
'qty'] * $qtyCoef;
3199 $parameters = array(
'socid' => $socid);
3200 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerProposal', $parameters, $this, $action);
3202 $this->stats_propale = $hookmanager->resArray[
'stats_propale'];
3207 $this->error = $this->db->error();
3223 global $conf, $user, $hookmanager, $action;
3225 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_suppliers, COUNT(DISTINCT p.rowid) as nb,";
3226 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3227 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as pd";
3228 $sql .=
", ".$this->db->prefix().
"supplier_proposal as p";
3229 $sql .=
", ".$this->db->prefix().
"societe as s";
3230 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3231 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3233 $sql .=
" WHERE p.rowid = pd.fk_supplier_proposal";
3234 $sql .=
" AND p.fk_soc = s.rowid";
3235 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
3236 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3237 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3238 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3242 $sql .=
" AND p.fk_soc = ".((int) $socid);
3245 $result = $this->db->query($sql);
3247 $obj = $this->db->fetch_object($result);
3248 $this->stats_proposal_supplier[
'suppliers'] = $obj->nb_suppliers;
3249 $this->stats_proposal_supplier[
'nb'] = $obj->nb;
3250 $this->stats_proposal_supplier[
'rows'] = $obj->nb_rows;
3251 $this->stats_proposal_supplier[
'qty'] = $obj->qty ? $obj->qty : 0;
3253 $parameters = array(
'socid' => $socid);
3254 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierProposal', $parameters, $this, $action);
3256 $this->stats_proposal_supplier = $hookmanager->resArray[
'stats_proposal_supplier'];
3261 $this->error = $this->db->error();
3279 global $conf, $user, $hookmanager, $action;
3281 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3282 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3283 $sql .=
" FROM ".$this->db->prefix().
"commandedet as cd";
3284 $sql .=
", ".$this->db->prefix().
"commande as c";
3285 $sql .=
", ".$this->db->prefix().
"societe as s";
3286 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3287 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3289 $sql .=
" WHERE c.rowid = cd.fk_commande";
3290 $sql .=
" AND c.fk_soc = s.rowid";
3291 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'commande').
")";
3292 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3293 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3294 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3297 $sql .=
" AND c.fk_soc = ".((int) $socid);
3299 if ($filtrestatut !=
'') {
3300 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3303 $result = $this->db->query($sql);
3305 $obj = $this->db->fetch_object($result);
3306 $this->stats_commande[
'customers'] = $obj->nb_customers;
3307 $this->stats_commande[
'nb'] = $obj->nb;
3308 $this->stats_commande[
'rows'] = $obj->nb_rows;
3309 $this->stats_commande[
'qty'] = $obj->qty ? $obj->qty : 0;
3314 if (is_array($TFather) && !empty($TFather)) {
3315 foreach ($TFather as &$fatherData) {
3316 $pFather =
new Product($this->db);
3317 $pFather->id = $fatherData[
'id'];
3318 $qtyCoef = $fatherData[
'qty'];
3320 if ($fatherData[
'incdec']) {
3321 $pFather->load_stats_commande($socid, $filtrestatut);
3323 $this->stats_commande[
'customers'] += $pFather->stats_commande[
'customers'];
3324 $this->stats_commande[
'nb'] += $pFather->stats_commande[
'nb'];
3325 $this->stats_commande[
'rows'] += $pFather->stats_commande[
'rows'];
3326 $this->stats_commande[
'qty'] += $pFather->stats_commande[
'qty'] * $qtyCoef;
3338 $sql =
"SELECT SUM(".$this->db->ifsql(
'f.type=2', -1, 1).
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3339 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3340 $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'))";
3341 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3342 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3344 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3345 $resql = $this->db->query($sql);
3347 if ($this->db->num_rows($resql) > 0) {
3348 $obj = $this->db->fetch_object($resql);
3349 $adeduire += $obj->count;
3353 $this->stats_commande[
'qty'] -= $adeduire;
3356 include_once DOL_DOCUMENT_ROOT.
'/compta/facture/class/facture.class.php';
3360 $sql =
"SELECT sum(".$this->db->ifsql(
'f.type=2', -1, 1).
" * fd.qty) as count FROM ".MAIN_DB_PREFIX.
"facturedet as fd ";
3361 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"facture as f ON fd.fk_facture = f.rowid";
3362 $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'))";
3363 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"commande as c ON el.fk_source = c.rowid";
3364 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3366 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3367 $resql = $this->db->query($sql);
3369 if ($this->db->num_rows($resql) > 0) {
3370 $obj = $this->db->fetch_object($resql);
3371 $adeduire += $obj->count;
3374 $this->error = $this->db->error();
3378 $this->stats_commande[
'qty'] -= $adeduire;
3382 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3383 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerOrder', $parameters, $this, $action);
3385 $this->stats_commande = $hookmanager->resArray[
'stats_commande'];
3389 $this->error = $this->db->error();
3407 global $conf, $user, $hookmanager, $action;
3409 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_suppliers, COUNT(DISTINCT c.rowid) as nb,";
3410 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3411 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as cd";
3412 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as c";
3413 $sql .=
", ".$this->db->prefix().
"societe as s";
3414 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3415 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3417 $sql .=
" WHERE c.rowid = cd.fk_commande";
3418 $sql .=
" AND c.fk_soc = s.rowid";
3419 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3420 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3421 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3422 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3425 $sql .=
" AND c.fk_soc = ".((int) $socid);
3427 if ($filtrestatut !=
'') {
3428 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3430 if (!empty($dateofvirtualstock)) {
3431 $sql .=
" AND c.date_livraison <= '".$this->db->idate($dateofvirtualstock).
"'";
3434 $result = $this->db->query($sql);
3436 $obj = $this->db->fetch_object($result);
3437 $this->stats_commande_fournisseur[
'suppliers'] = $obj->nb_suppliers;
3438 $this->stats_commande_fournisseur[
'nb'] = $obj->nb;
3439 $this->stats_commande_fournisseur[
'rows'] = $obj->nb_rows;
3440 $this->stats_commande_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
3442 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3443 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierOrder', $parameters, $this, $action);
3445 $this->stats_commande_fournisseur = $hookmanager->resArray[
'stats_commande_fournisseur'];
3450 $this->error = $this->db->error().
' sql='.$sql;
3465 public function load_stats_sending($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $filterShipmentStatus =
'')
3468 global $conf, $user, $hookmanager, $action;
3470 $sql =
"SELECT COUNT(DISTINCT e.fk_soc) as nb_customers, COUNT(DISTINCT e.rowid) as nb,";
3471 $sql .=
" COUNT(ed.rowid) as nb_rows, SUM(ed.qty) as qty";
3472 $sql .=
" FROM ".$this->db->prefix().
"expeditiondet as ed";
3473 $sql .=
", ".$this->db->prefix().
"commandedet as cd";
3474 $sql .=
", ".$this->db->prefix().
"commande as c";
3475 $sql .=
", ".$this->db->prefix().
"expedition as e";
3476 $sql .=
", ".$this->db->prefix().
"societe as s";
3477 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3478 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3480 $sql .=
" WHERE e.rowid = ed.fk_expedition";
3481 $sql .=
" AND c.rowid = cd.fk_commande";
3482 $sql .=
" AND e.fk_soc = s.rowid";
3483 $sql .=
" AND e.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'expedition').
")";
3484 $sql .=
" AND ed.fk_elementdet = cd.rowid";
3485 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3486 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3487 $sql .=
" AND e.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3490 $sql .=
" AND e.fk_soc = ".((int) $socid);
3492 if ($filtrestatut !=
'') {
3493 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3495 if (!empty($filterShipmentStatus)) {
3496 $sql .=
" AND e.fk_statut IN (".$this->db->sanitize($filterShipmentStatus).
")";
3499 $result = $this->db->query($sql);
3501 $obj = $this->db->fetch_object($result);
3502 $this->stats_expedition[
'customers'] = $obj->nb_customers;
3503 $this->stats_expedition[
'nb'] = $obj->nb;
3504 $this->stats_expedition[
'rows'] = $obj->nb_rows;
3505 $this->stats_expedition[
'qty'] = $obj->qty ? $obj->qty : 0;
3510 if (is_array($TFather) && !empty($TFather)) {
3511 foreach ($TFather as &$fatherData) {
3512 $pFather =
new Product($this->db);
3513 $pFather->id = $fatherData[
'id'];
3514 $qtyCoef = $fatherData[
'qty'];
3516 if ($fatherData[
'incdec']) {
3517 $pFather->load_stats_sending($socid, $filtrestatut, $forVirtualStock);
3519 $this->stats_expedition[
'customers'] += $pFather->stats_expedition[
'customers'];
3520 $this->stats_expedition[
'nb'] += $pFather->stats_expedition[
'nb'];
3521 $this->stats_expedition[
'rows'] += $pFather->stats_expedition[
'rows'];
3522 $this->stats_expedition[
'qty'] += $pFather->stats_expedition[
'qty'] * $qtyCoef;
3528 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock,
'filterShipmentStatus' => $filterShipmentStatus);
3529 $reshook = $hookmanager->executeHooks(
'loadStatsSending', $parameters, $this, $action);
3531 $this->stats_expedition = $hookmanager->resArray[
'stats_expedition'];
3536 $this->error = $this->db->error();
3551 public function load_stats_reception($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null)
3554 global $conf, $user, $hookmanager, $action;
3556 $sql =
"SELECT COUNT(DISTINCT cf.fk_soc) as nb_suppliers, COUNT(DISTINCT cf.rowid) as nb,";
3557 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
3558 $sql .=
" FROM ".$this->db->prefix().
"receptiondet_batch as fd";
3559 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as cf";
3560 $sql .=
", ".$this->db->prefix().
"societe as s";
3561 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3562 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3564 $sql .=
" WHERE cf.rowid = fd.fk_element";
3565 $sql .=
" AND cf.fk_soc = s.rowid";
3566 $sql .=
" AND cf.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3567 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3568 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3569 $sql .=
" AND cf.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3572 $sql .=
" AND cf.fk_soc = ".((int) $socid);
3574 if ($filtrestatut !=
'') {
3575 $sql .=
" AND cf.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3577 if (!empty($dateofvirtualstock)) {
3578 $sql .=
" AND fd.datec <= '".$this->db->idate($dateofvirtualstock).
"'";
3581 $result = $this->db->query($sql);
3583 $obj = $this->db->fetch_object($result);
3584 $this->stats_reception[
'suppliers'] = $obj->nb_suppliers;
3585 $this->stats_reception[
'nb'] = $obj->nb;
3586 $this->stats_reception[
'rows'] = $obj->nb_rows;
3587 $this->stats_reception[
'qty'] = $obj->qty ? $obj->qty : 0;
3589 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3590 $reshook = $hookmanager->executeHooks(
'loadStatsReception', $parameters, $this, $action);
3592 $this->stats_reception = $hookmanager->resArray[
'stats_reception'];
3597 $this->error = $this->db->error();
3613 public function load_stats_inproduction($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null, $warehouseid = 0)
3616 global $user, $hookmanager, $action;
3618 $serviceStockIsEnabled = isModEnabled(
"service") &&
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES');
3620 $sql =
"SELECT COUNT(DISTINCT m.fk_soc) as nb_customers, COUNT(DISTINCT m.rowid) as nb,";
3621 $sql .=
" COUNT(mp.rowid) as nb_rows, SUM(mp.qty) as qty, role";
3622 $sql .=
" FROM ".$this->db->prefix().
"mrp_production as mp";
3623 $sql .=
", ".$this->db->prefix().
"mrp_mo as m";
3624 $sql .=
" LEFT JOIN ".$this->db->prefix().
"societe as s ON s.rowid = m.fk_soc";
3625 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3626 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3628 $sql .=
" WHERE m.rowid = mp.fk_mo";
3629 $sql .=
" AND m.entity IN (".getEntity(($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE')) ?
'stock' :
'mrp').
")";
3630 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3631 $sql .=
" AND (mp.disable_stock_change IN (0) OR mp.disable_stock_change IS NULL)";
3632 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3633 $sql .=
" AND m.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3636 $sql .=
" AND m.fk_soc = ".((int) $socid);
3638 if ($filtrestatut !=
'') {
3639 $sql .=
" AND m.status IN (".$this->db->sanitize($filtrestatut).
")";
3641 if (!empty($dateofvirtualstock)) {
3642 $sql .=
" AND m.date_valid <= '".$this->db->idate($dateofvirtualstock).
"'";
3644 if (!$serviceStockIsEnabled) {
3645 $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))";
3647 if (!empty($warehouseid)) {
3648 $sql .=
" AND m.fk_warehouse = ".((int) $warehouseid);
3650 $sql .=
" GROUP BY role";
3653 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
3655 $this->stats_mrptoconsume[
'customers'] = 0;
3656 $this->stats_mrptoconsume[
'nb'] = 0;
3657 $this->stats_mrptoconsume[
'rows'] = 0;
3658 $this->stats_mrptoconsume[
'qty'] = 0;
3659 $this->stats_mrptoproduce[
'customers'] = 0;
3660 $this->stats_mrptoproduce[
'nb'] = 0;
3661 $this->stats_mrptoproduce[
'rows'] = 0;
3662 $this->stats_mrptoproduce[
'qty'] = 0;
3665 $result = $this->db->query($sql);
3667 while ($obj = $this->db->fetch_object($result)) {
3668 if ($obj->role ==
'toconsume' && empty($warehouseid)) {
3669 $this->stats_mrptoconsume[
'customers'] += $obj->nb_customers;
3670 $this->stats_mrptoconsume[
'nb'] += $obj->nb;
3671 $this->stats_mrptoconsume[
'rows'] += $obj->nb_rows;
3672 $this->stats_mrptoconsume[
'qty'] += ($obj->qty ? $obj->qty : 0);
3674 if ($obj->role ==
'consumed' && empty($warehouseid)) {
3678 $this->stats_mrptoconsume[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3680 if ($obj->role ==
'toproduce') {
3682 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] += ($obj->qty ? $obj->qty : 0);
3684 $this->stats_mrptoproduce[
'customers'] += $obj->nb_customers;
3685 $this->stats_mrptoproduce[
'nb'] += $obj->nb;
3686 $this->stats_mrptoproduce[
'rows'] += $obj->nb_rows;
3687 $this->stats_mrptoproduce[
'qty'] += ($obj->qty ? $obj->qty : 0);
3690 if ($obj->role ==
'produced') {
3695 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3697 $this->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3704 if ($this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] < 0) {
3705 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
3708 if ($this->stats_mrptoconsume[
'qty'] < 0) {
3709 $this->stats_mrptoconsume[
'qty'] = 0;
3711 if ($this->stats_mrptoproduce[
'qty'] < 0) {
3712 $this->stats_mrptoproduce[
'qty'] = 0;
3716 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3717 $reshook = $hookmanager->executeHooks(
'loadStatsInProduction', $parameters, $this, $action);
3719 $this->stats_mrptoproduce = $hookmanager->resArray[
'stats_mrptoproduce'];
3724 $this->error = $this->db->error();
3739 global $conf, $user, $hookmanager, $action;
3741 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3742 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3743 $sql .=
" FROM ".$this->db->prefix().
"contratdet as cd";
3744 $sql .=
", ".$this->db->prefix().
"contrat as c";
3745 $sql .=
", ".$this->db->prefix().
"societe as s";
3746 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3747 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3749 $sql .=
" WHERE c.rowid = cd.fk_contrat";
3750 $sql .=
" AND c.fk_soc = s.rowid";
3751 $sql .=
" AND c.entity IN (".getEntity(
'contract').
")";
3752 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3753 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3754 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3758 $sql .=
" AND c.fk_soc = ".((int) $socid);
3761 $result = $this->db->query($sql);
3763 $obj = $this->db->fetch_object($result);
3764 $this->stats_contrat[
'customers'] = $obj->nb_customers;
3765 $this->stats_contrat[
'nb'] = $obj->nb;
3766 $this->stats_contrat[
'rows'] = $obj->nb_rows;
3767 $this->stats_contrat[
'qty'] = $obj->qty ? $obj->qty : 0;
3772 if (is_array($TFather) && !empty($TFather)) {
3773 foreach ($TFather as &$fatherData) {
3774 $pFather =
new Product($this->db);
3775 $pFather->id = $fatherData[
'id'];
3776 $qtyCoef = $fatherData[
'qty'];
3778 if ($fatherData[
'incdec']) {
3779 $pFather->load_stats_contrat($socid);
3781 $this->stats_contrat[
'customers'] += $pFather->stats_contrat[
'customers'];
3782 $this->stats_contrat[
'nb'] += $pFather->stats_contrat[
'nb'];
3783 $this->stats_contrat[
'rows'] += $pFather->stats_contrat[
'rows'];
3784 $this->stats_contrat[
'qty'] += $pFather->stats_contrat[
'qty'] * $qtyCoef;
3790 $parameters = array(
'socid' => $socid);
3791 $reshook = $hookmanager->executeHooks(
'loadStatsContract', $parameters, $this, $action);
3793 $this->stats_contrat = $hookmanager->resArray[
'stats_contrat'];
3798 $this->error = $this->db->error().
' sql='.$sql;
3813 global $conf, $user, $hookmanager, $action;
3815 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
3816 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(".$this->db->ifsql(
'f.type != 2',
'fd.qty',
'fd.qty * -1').
") as qty";
3817 $sql .=
" FROM ".$this->db->prefix().
"facturedet as fd";
3818 $sql .=
", ".$this->db->prefix().
"facture as f";
3819 $sql .=
", ".$this->db->prefix().
"societe as s";
3820 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3821 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3823 $sql .=
" WHERE f.rowid = fd.fk_facture";
3824 $sql .=
" AND f.fk_soc = s.rowid";
3825 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
3826 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3827 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3828 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3832 $sql .=
" AND f.fk_soc = ".((int) $socid);
3835 $result = $this->db->query($sql);
3837 $obj = $this->db->fetch_object($result);
3838 $this->stats_facture[
'customers'] = $obj->nb_customers;
3839 $this->stats_facture[
'nb'] = $obj->nb;
3840 $this->stats_facture[
'rows'] = $obj->nb_rows;
3841 $this->stats_facture[
'qty'] = $obj->qty ? $obj->qty : 0;
3846 if (is_array($TFather) && !empty($TFather)) {
3847 foreach ($TFather as &$fatherData) {
3848 $pFather =
new Product($this->db);
3849 $pFather->id = $fatherData[
'id'];
3850 $qtyCoef = $fatherData[
'qty'];
3852 if ($fatherData[
'incdec']) {
3853 $pFather->load_stats_facture($socid);
3855 $this->stats_facture[
'customers'] += $pFather->stats_facture[
'customers'];
3856 $this->stats_facture[
'nb'] += $pFather->stats_facture[
'nb'];
3857 $this->stats_facture[
'rows'] += $pFather->stats_facture[
'rows'];
3858 $this->stats_facture[
'qty'] += $pFather->stats_facture[
'qty'] * $qtyCoef;
3864 $parameters = array(
'socid' => $socid);
3865 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoice', $parameters, $this, $action);
3867 $this->stats_facture = $hookmanager->resArray[
'stats_facture'];
3872 $this->error = $this->db->error();
3888 global $conf, $user, $hookmanager, $action;
3890 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
3891 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
3892 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facturedet_rec as fd";
3893 $sql .=
", ".MAIN_DB_PREFIX.
"facture_rec as f";
3894 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
3895 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3896 $sql .=
", ".MAIN_DB_PREFIX.
"societe_commerciaux as sc";
3898 $sql .=
" WHERE f.rowid = fd.fk_facture";
3899 $sql .=
" AND f.fk_soc = s.rowid";
3900 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
3901 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3902 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3903 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3907 $sql .=
" AND f.fk_soc = ".((int) $socid);
3910 $result = $this->db->query($sql);
3912 $obj = $this->db->fetch_object($result);
3913 $this->stats_facturerec[
'customers'] = $obj->nb_customers;
3914 $this->stats_facturerec[
'nb'] = $obj->nb;
3915 $this->stats_facturerec[
'rows'] = $obj->nb_rows;
3916 $this->stats_facturerec[
'qty'] = $obj->qty ? $obj->qty : 0;
3921 if (is_array($TFather) && !empty($TFather)) {
3922 foreach ($TFather as &$fatherData) {
3923 $pFather =
new Product($this->db);
3924 $pFather->id = $fatherData[
'id'];
3925 $qtyCoef = $fatherData[
'qty'];
3927 if ($fatherData[
'incdec']) {
3928 $pFather->load_stats_facture($socid);
3930 $this->stats_facturerec[
'customers'] += $pFather->stats_facturerec[
'customers'];
3931 $this->stats_facturerec[
'nb'] += $pFather->stats_facturerec[
'nb'];
3932 $this->stats_facturerec[
'rows'] += $pFather->stats_facturerec[
'rows'];
3933 $this->stats_facturerec[
'qty'] += $pFather->stats_facturerec[
'qty'] * $qtyCoef;
3939 $parameters = array(
'socid' => $socid);
3940 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoiceRec', $parameters, $this, $action);
3942 $this->stats_facturerec = $hookmanager->resArray[
'stats_facturerec'];
3947 $this->error = $this->db->error();
3962 global $conf, $user, $hookmanager, $action;
3964 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
3965 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
3966 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as fd";
3967 $sql .=
", ".$this->db->prefix().
"facture_fourn as f";
3968 $sql .=
", ".$this->db->prefix().
"societe as s";
3969 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3970 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3972 $sql .=
" WHERE f.rowid = fd.fk_facture_fourn";
3973 $sql .=
" AND f.fk_soc = s.rowid";
3974 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
3975 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3976 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3977 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3981 $sql .=
" AND f.fk_soc = ".((int) $socid);
3984 $result = $this->db->query($sql);
3986 $obj = $this->db->fetch_object($result);
3987 $this->stats_facture_fournisseur[
'suppliers'] = $obj->nb_suppliers;
3988 $this->stats_facture_fournisseur[
'nb'] = $obj->nb;
3989 $this->stats_facture_fournisseur[
'rows'] = $obj->nb_rows;
3990 $this->stats_facture_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
3992 $parameters = array(
'socid' => $socid);
3993 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoice', $parameters, $this, $action);
3995 $this->stats_facture_fournisseur = $hookmanager->resArray[
'stats_facture_fournisseur'];
4000 $this->error = $this->db->error();
4019 $resql = $this->db->query($sql);
4021 $num = $this->db->num_rows($resql);
4024 $arr = $this->db->fetch_array($resql);
4025 if (is_array($arr)) {
4026 $keyfortab = (string) $arr[1];
4028 $keyfortab = substr($keyfortab, -2);
4031 if ($mode ==
'byunit') {
4032 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[0];
4033 } elseif ($mode ==
'bynumber') {
4034 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4035 } elseif ($mode ==
'byamount') {
4036 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
4045 $this->error = $this->db->error().
' sql='.$sql;
4052 } elseif ($year == -1) {
4061 for ($j = 0; $j < 12; $j++) {
4063 $idx = ucfirst(
dol_trunc(
dol_print_date(
dol_mktime(12, 0, 0, $month, 1, 1970),
"%b"), 1,
'right',
'UTF-8', 1));
4066 $result[$j] = array($idx, isset($tab[$year.$month]) ? $tab[$year.$month] : 0);
4069 $month =
"0".($month - 1);
4071 $month = substr($month, 1);
4079 return array_reverse($result);
4094 public function get_nb_vente($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4100 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4101 if ($mode ==
'bynumber') {
4102 $sql .=
", count(DISTINCT f.rowid)";
4104 $sql .=
", sum(d.total_ht) as total_ht";
4105 $sql .=
" FROM ".$this->db->prefix().
"facturedet as d, ".$this->db->prefix().
"facture as f, ".$this->db->prefix().
"societe as s";
4106 if ($filteronproducttype >= 0) {
4107 $sql .=
", ".$this->db->prefix().
"product as p";
4109 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4110 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4112 $sql .=
" WHERE f.rowid = d.fk_facture";
4113 if ($this->
id > 0) {
4114 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4116 $sql .=
" AND d.fk_product > 0";
4118 if ($filteronproducttype >= 0) {
4119 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4121 $sql .=
" AND f.fk_soc = s.rowid";
4122 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4123 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4124 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4127 $sql .=
" AND f.fk_soc = $socid";
4129 $sql .= $morefilter;
4130 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4131 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4133 return $this->
_get_stats($sql, $mode, $year);
4148 public function get_nb_achat($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4154 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4155 if ($mode ==
'bynumber') {
4156 $sql .=
", count(DISTINCT f.rowid)";
4158 $sql .=
", sum(d.total_ht) as total_ht";
4159 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as d, ".$this->db->prefix().
"facture_fourn as f, ".$this->db->prefix().
"societe as s";
4160 if ($filteronproducttype >= 0) {
4161 $sql .=
", ".$this->db->prefix().
"product as p";
4163 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4164 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4166 $sql .=
" WHERE f.rowid = d.fk_facture_fourn";
4167 if ($this->
id > 0) {
4168 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4170 $sql .=
" AND d.fk_product > 0";
4172 if ($filteronproducttype >= 0) {
4173 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4175 $sql .=
" AND f.fk_soc = s.rowid";
4176 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4177 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4178 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4181 $sql .=
" AND f.fk_soc = $socid";
4183 $sql .= $morefilter;
4184 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4185 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4187 return $this->
_get_stats($sql, $mode, $year);
4201 public function get_nb_propal($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4204 global $conf, $user;
4206 $sql =
"SELECT sum(d.qty) as qty, date_format(p.datep, '%Y%m')";
4207 if ($mode ==
'bynumber') {
4208 $sql .=
", count(DISTINCT p.rowid)";
4210 $sql .=
", sum(d.total_ht) as total_ht";
4211 $sql .=
" FROM ".$this->db->prefix().
"propaldet as d, ".$this->db->prefix().
"propal as p, ".$this->db->prefix().
"societe as s";
4212 if ($filteronproducttype >= 0) {
4213 $sql .=
", ".$this->db->prefix().
"product as prod";
4215 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4216 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4218 $sql .=
" WHERE p.rowid = d.fk_propal";
4219 if ($this->
id > 0) {
4220 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4222 $sql .=
" AND d.fk_product > 0";
4224 if ($filteronproducttype >= 0) {
4225 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4227 $sql .=
" AND p.fk_soc = s.rowid";
4228 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
4229 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4230 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4233 $sql .=
" AND p.fk_soc = ".((int) $socid);
4235 $sql .= $morefilter;
4236 $sql .=
" GROUP BY date_format(p.datep,'%Y%m')";
4237 $sql .=
" ORDER BY date_format(p.datep,'%Y%m') DESC";
4239 return $this->
_get_stats($sql, $mode, $year);
4259 $sql =
"SELECT sum(d.qty) as qty, date_format(p.date_valid, '%Y%m')";
4260 if ($mode ==
'bynumber') {
4261 $sql .=
", count(DISTINCT p.rowid)";
4263 $sql .=
", sum(d.total_ht) as total_ht";
4264 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as d, ".$this->db->prefix().
"supplier_proposal as p, ".$this->db->prefix().
"societe as s";
4265 if ($filteronproducttype >= 0) {
4266 $sql .=
", ".$this->db->prefix().
"product as prod";
4268 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4269 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4271 $sql .=
" WHERE p.rowid = d.fk_supplier_proposal";
4272 if ($this->
id > 0) {
4273 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4275 $sql .=
" AND d.fk_product > 0";
4277 if ($filteronproducttype >= 0) {
4278 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4280 $sql .=
" AND p.fk_soc = s.rowid";
4281 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
4282 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4283 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4286 $sql .=
" AND p.fk_soc = ".((int) $socid);
4288 $sql .= $morefilter;
4289 $sql .=
" GROUP BY date_format(p.date_valid,'%Y%m')";
4290 $sql .=
" ORDER BY date_format(p.date_valid,'%Y%m') DESC";
4292 return $this->
_get_stats($sql, $mode, $year);
4306 public function get_nb_order($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4309 global $conf, $user;
4311 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4312 if ($mode ==
'bynumber') {
4313 $sql .=
", count(DISTINCT c.rowid)";
4315 $sql .=
", sum(d.total_ht) as total_ht";
4316 $sql .=
" FROM ".$this->db->prefix().
"commandedet as d, ".$this->db->prefix().
"commande as c, ".$this->db->prefix().
"societe as s";
4317 if ($filteronproducttype >= 0) {
4318 $sql .=
", ".$this->db->prefix().
"product as p";
4320 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4321 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4323 $sql .=
" WHERE c.rowid = d.fk_commande";
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);
4332 $sql .=
" AND c.fk_soc = s.rowid";
4333 $sql .=
" AND c.entity IN (".getEntity(
'commande').
")";
4334 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4335 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4338 $sql .=
" AND c.fk_soc = ".((int) $socid);
4340 $sql .= $morefilter;
4341 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4342 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4344 return $this->
_get_stats($sql, $mode, $year);
4361 global $conf, $user;
4363 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4364 if ($mode ==
'bynumber') {
4365 $sql .=
", count(DISTINCT c.rowid)";
4367 $sql .=
", sum(d.total_ht) as total_ht";
4368 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as d, ".$this->db->prefix().
"commande_fournisseur as c, ".$this->db->prefix().
"societe as s";
4369 if ($filteronproducttype >= 0) {
4370 $sql .=
", ".$this->db->prefix().
"product as p";
4372 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4373 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4375 $sql .=
" WHERE c.rowid = d.fk_commande";
4376 if ($this->
id > 0) {
4377 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4379 $sql .=
" AND d.fk_product > 0";
4381 if ($filteronproducttype >= 0) {
4382 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4384 $sql .=
" AND c.fk_soc = s.rowid";
4385 $sql .=
" AND c.entity IN (".getEntity(
'supplier_order').
")";
4386 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4387 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4390 $sql .=
" AND c.fk_soc = ".((int) $socid);
4392 $sql .= $morefilter;
4393 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4394 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4396 return $this->
_get_stats($sql, $mode, $year);
4410 public function get_nb_contract($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4413 global $conf, $user;
4415 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_contrat, '%Y%m')";
4416 if ($mode ==
'bynumber') {
4417 $sql .=
", count(DISTINCT c.rowid)";
4419 $sql .=
", sum(d.total_ht) as total_ht";
4420 $sql .=
" FROM ".$this->db->prefix().
"contratdet as d, ".$this->db->prefix().
"contrat as c, ".$this->db->prefix().
"societe as s";
4421 if ($filteronproducttype >= 0) {
4422 $sql .=
", ".$this->db->prefix().
"product as p";
4424 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4425 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4427 $sql .=
" WHERE c.entity IN (".getEntity(
'contract').
")";
4428 $sql .=
" AND c.rowid = d.fk_contrat";
4430 if ($this->
id > 0) {
4431 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4433 $sql .=
" AND d.fk_product > 0";
4435 if ($filteronproducttype >= 0) {
4436 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4438 $sql .=
" AND c.fk_soc = s.rowid";
4440 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4441 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4444 $sql .=
" AND c.fk_soc = ".((int) $socid);
4446 $sql .= $morefilter;
4447 $sql .=
" GROUP BY date_format(c.date_contrat,'%Y%m')";
4448 $sql .=
" ORDER BY date_format(c.date_contrat,'%Y%m') DESC";
4450 return $this->
_get_stats($sql, $mode, $year);
4464 public function get_nb_mos($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4467 global $conf, $user;
4469 $sql =
"SELECT sum(d.qty), date_format(d.date_valid, '%Y%m')";
4470 if ($mode ==
'bynumber') {
4471 $sql .=
", count(DISTINCT d.rowid)";
4473 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as d LEFT JOIN ".$this->db->prefix().
"societe as s ON d.fk_soc = s.rowid";
4474 if ($filteronproducttype >= 0) {
4475 $sql .=
", ".$this->db->prefix().
"product as p";
4477 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4478 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4481 $sql .=
" WHERE d.entity IN (".getEntity(
'mo').
")";
4482 $sql .=
" AND d.status > 0";
4484 if ($this->
id > 0) {
4485 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4487 $sql .=
" AND d.fk_product > 0";
4489 if ($filteronproducttype >= 0) {
4490 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4493 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4494 $sql .=
" AND d.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4497 $sql .=
" AND d.fk_soc = ".((int) $socid);
4499 $sql .= $morefilter;
4500 $sql .=
" GROUP BY date_format(d.date_valid,'%Y%m')";
4501 $sql .=
" ORDER BY date_format(d.date_valid,'%Y%m') DESC";
4503 return $this->
_get_stats($sql, $mode, $year);
4523 if (!is_numeric($id_pere)) {
4526 if (!is_numeric($id_fils)) {
4529 if (!is_numeric($incdec)) {
4539 $sql =
"SELECT fk_product_pere from ".$this->db->prefix().
"product_association";
4540 $sql .=
" WHERE fk_product_pere = ".((int) $id_fils).
" AND fk_product_fils = ".((int) $id_pere);
4541 if (!$this->db->query($sql)) {
4546 $sql =
"SELECT MAX(rang) as max_rank FROM ".$this->db->prefix().
"product_association";
4547 $sql .=
" WHERE fk_product_pere = ".((int) $id_pere);
4548 $resql = $this->db->query($sql);
4550 $obj = $this->db->fetch_object($resql);
4551 $rank = $obj->max_rank + 1;
4553 $sql =
"INSERT INTO ".$this->db->prefix().
"product_association(fk_product_pere,fk_product_fils,qty,incdec,rang)";
4554 $sql .=
" VALUES (".((int) $id_pere).
", ".((int) $id_fils).
", ".
price2num($qty,
'MS').
", ".((int) $incdec).
", ".((int) $rank).
")";
4555 if (! $this->db->query($sql)) {
4561 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_ADD', $user);
4563 $this->error = $this->db->lasterror();
4564 dol_syslog(get_class($this).
'::addSubproduct error='.$this->error, LOG_ERR);
4596 if (!is_numeric($id_pere)) {
4599 if (!is_numeric($id_fils)) {
4602 if (!is_numeric($incdec)) {
4605 if (!is_numeric($qty)) {
4609 $sql =
'UPDATE '.$this->db->prefix().
'product_association SET ';
4610 $sql .=
'qty = '.price2num($qty,
'MS');
4611 $sql .=
',incdec = '.((int) $incdec);
4612 $sql .=
' WHERE fk_product_pere = '.((int) $id_pere).
' AND fk_product_fils = '.((int) $id_fils);
4614 if (!$this->db->query($sql)) {
4620 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_UPDATE', $user);
4622 $this->error = $this->db->lasterror();
4623 dol_syslog(get_class($this).
'::updateSubproduct error='.$this->error, LOG_ERR);
4647 if (!is_numeric($fk_parent)) {
4650 if (!is_numeric($fk_child)) {
4654 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
4655 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
4656 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
4658 dol_syslog(get_class($this).
'::del_sousproduit', LOG_DEBUG);
4659 if (!$this->db->query($sql)) {
4665 $sqlrank =
"SELECT rowid, rang FROM ".$this->db->prefix().
"product_association";
4666 $sqlrank .=
" WHERE fk_product_pere = ".((int) $fk_parent);
4667 $sqlrank .=
" ORDER BY rang";
4668 $resqlrank = $this->db->query($sqlrank);
4671 while ($objrank = $this->db->fetch_object($resqlrank)) {
4673 $sql =
"UPDATE ".$this->db->prefix().
"product_association";
4674 $sql .=
" SET rang = ".((int) $cpt);
4675 $sql .=
" WHERE rowid = ".((int) $objrank->rowid);
4676 if (! $this->db->query($sql)) {
4685 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_DELETE', $user);
4687 $this->error = $this->db->lasterror();
4688 dol_syslog(get_class($this).
'::delSubproduct error='.$this->error, LOG_ERR);
4708 $sql =
"SELECT fk_product_pere, qty, incdec";
4709 $sql .=
" FROM ".$this->db->prefix().
"product_association";
4710 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
4711 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
4713 $result = $this->db->query($sql);
4715 $num = $this->db->num_rows($result);
4718 $obj = $this->db->fetch_object($result);
4720 $this->is_sousproduit_qty = $obj->qty;
4721 $this->is_sousproduit_incdec = $obj->incdec;
4752 dol_syslog(get_class($this).
"::add_fournisseur id_fourn = ".$id_fourn.
" ref_fourn=".
$ref_fourn.
" quantity=".$quantity, LOG_DEBUG);
4759 $sql =
"SELECT rowid, fk_product";
4760 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
4761 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
4762 $sql .=
" AND ref_fourn = '".$this->db->escape(
$ref_fourn).
"'";
4763 $sql .=
" AND fk_product <> ".((int) $this->
id);
4764 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
4766 $resql = $this->db->query($sql);
4768 $obj = $this->db->fetch_object($resql);
4771 $this->product_id_already_linked = $obj->fk_product;
4774 $this->db->free($resql);
4778 $sql =
"SELECT rowid";
4779 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
4780 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
4782 $sql .=
" AND ref_fourn = '".$this->db->escape(
$ref_fourn).
"'";
4784 $sql .=
" AND (ref_fourn = '' OR ref_fourn IS NULL)";
4786 $sql .=
" AND quantity = ".((float) $quantity);
4787 $sql .=
" AND fk_product = ".((int) $this->
id);
4788 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
4790 $resql = $this->db->query($sql);
4792 $obj = $this->db->fetch_object($resql);
4796 $sql =
"INSERT INTO ".$this->db->prefix().
"product_fournisseur_price(";
4799 $sql .=
", fk_product";
4801 $sql .=
", ref_fourn";
4802 $sql .=
", quantity";
4803 $sql .=
", fk_user";
4805 $sql .=
") VALUES (";
4806 $sql .=
"'".$this->db->idate($now).
"'";
4807 $sql .=
", ".((int) $conf->entity);
4808 $sql .=
", ".((int) $this->
id);
4809 $sql .=
", ".((int) $id_fourn);
4810 $sql .=
", '".$this->db->escape(
$ref_fourn).
"'";
4811 $sql .=
", ".((float) $quantity);
4812 $sql .=
", ".((int) $user->id);
4816 if ($this->db->query($sql)) {
4817 $this->product_fourn_price_id = $this->db->last_insert_id($this->db->prefix().
"product_fournisseur_price");
4820 $this->error = $this->db->lasterror();
4825 $this->product_fourn_price_id = $obj->rowid;
4829 $this->error = $this->db->lasterror();
4848 $sql =
"SELECT DISTINCT p.fk_soc";
4849 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as p";
4850 $sql .=
" WHERE p.fk_product = ".((int) $this->
id);
4851 $sql .=
" AND p.entity = ".((int) $conf->entity);
4853 $result = $this->db->query($sql);
4855 $num = $this->db->num_rows($result);
4858 $obj = $this->db->fetch_object($result);
4859 $list[$i] = $obj->fk_soc;
4877 global $conf, $user;
4884 $sql =
"INSERT INTO ".$this->db->prefix().
"product_price (";
4886 $sql .=
", fk_product";
4887 $sql .=
", date_price";
4888 $sql .=
", price_level";
4890 $sql .=
", price_ttc";
4891 $sql .=
", price_min";
4892 $sql .=
", price_min_ttc";
4893 $sql .=
", price_base_type";
4894 $sql .=
", price_label";
4895 $sql .=
", default_vat_code";
4897 $sql .=
", recuperableonly";
4898 $sql .=
", localtax1_tx";
4899 $sql .=
", localtax1_type";
4900 $sql .=
", localtax2_tx";
4901 $sql .=
", localtax2_type";
4902 $sql .=
", fk_user_author";
4904 $sql .=
", price_by_qty";
4905 $sql .=
", fk_price_expression";
4906 $sql .=
", fk_multicurrency";
4907 $sql .=
", multicurrency_code";
4908 $sql .=
", multicurrency_tx";
4909 $sql .=
", multicurrency_price";
4910 $sql .=
", multicurrency_price_ttc";
4915 $sql .=
", '".$this->db->idate($now).
"'";
4916 $sql .=
", price_level";
4918 $sql .=
", price_ttc";
4919 $sql .=
", price_min";
4920 $sql .=
", price_min_ttc";
4921 $sql .=
", price_base_type";
4922 $sql .=
", price_label";
4923 $sql .=
", default_vat_code";
4925 $sql .=
", recuperableonly";
4926 $sql .=
", localtax1_tx";
4927 $sql .=
", localtax1_type";
4928 $sql .=
", localtax2_tx";
4929 $sql .=
", localtax2_type";
4930 $sql .=
", ".$user->id;
4932 $sql .=
", price_by_qty";
4933 $sql .=
", fk_price_expression";
4934 $sql .=
", fk_multicurrency";
4935 $sql .=
", multicurrency_code";
4936 $sql .=
", multicurrency_tx";
4937 $sql .=
", multicurrency_price";
4938 $sql .=
", multicurrency_price_ttc";
4939 $sql .=
" FROM ".$this->db->prefix().
"product_price ps";
4940 $sql .=
" WHERE fk_product = ".((int) $fromId);
4941 $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)";
4942 $sql .=
" ORDER BY date_price DESC";
4945 $resql = $this->db->query($sql);
4947 $this->db->rollback();
4951 $this->db->commit();
4968 $sql =
'INSERT INTO '.$this->db->prefix().
'product_association (fk_product_pere, fk_product_fils, qty, incdec)';
4969 $sql .=
" SELECT ".$toId.
", fk_product_fils, qty, incdec FROM ".$this->db->prefix().
"product_association";
4970 $sql .=
" WHERE fk_product_pere = ".((int) $fromId);
4972 dol_syslog(get_class($this).
'::clone_association', LOG_DEBUG);
4973 if (!$this->db->query($sql)) {
4974 $this->db->rollback();
4978 $this->db->commit();
5011 $sql =
"INSERT ".$this->db->prefix().
"product_fournisseur_price (";
5012 $sql .=
" datec, fk_product, fk_soc, price, quantity, fk_user, tva_tx)";
5013 $sql .=
" SELECT '".$this->db->idate($now).
"', ".((int) $toId).
", fk_soc, price, quantity, fk_user, tva_tx";
5014 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
5015 $sql .=
" WHERE fk_product = ".((int) $fromId);
5017 dol_syslog(get_class($this).
'::clone_fournisseurs', LOG_DEBUG);
5018 $resql = $this->db->query($sql);
5020 $this->db->rollback();
5023 $this->db->commit();
5041 public function fetch_prod_arbo($prod, $compl_path =
'', $multiply = 1, $level = 1, $id_parent = 0, $ignore_stock_load = 0)
5044 global $conf, $langs;
5048 foreach ($prod as $id_product => $desc_pere) {
5049 if (is_array($desc_pere)) {
5050 $id = (!empty($desc_pere[0]) ? $desc_pere[0] :
'');
5051 $nb = (!empty($desc_pere[1]) ? $desc_pere[1] :
'');
5052 $type = (!empty($desc_pere[2]) ? $desc_pere[2] :
'');
5053 $label = (!empty($desc_pere[3]) ? $desc_pere[3] :
'');
5054 $incdec = (!empty($desc_pere[4]) ? $desc_pere[4] : 0);
5056 if ($multiply < 1) {
5061 if (is_null($tmpproduct)) {
5062 $tmpproduct =
new Product($this->db);
5064 $tmpproduct->fetch($id);
5066 if (empty($ignore_stock_load) && ($tmpproduct->isProduct() ||
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES'))) {
5067 $tmpproduct->load_stock(
'nobatch,novirtual');
5070 $this->res[] = array(
5072 'id_parent' => $id_parent,
5073 'ref' => $tmpproduct->ref,
5075 'nb_total' => $nb * $multiply,
5076 'stock' => $tmpproduct->stock_reel,
5077 'stock_alert' => $tmpproduct->seuil_stock_alerte,
5079 'fullpath' => $compl_path.$label,
5081 'desiredstock' => $tmpproduct->desiredstock,
5083 'incdec' => $incdec,
5084 'entity' => $tmpproduct->entity
5088 if (isset($desc_pere[
'childs']) && is_array($desc_pere[
'childs'])) {
5090 $this->
fetch_prod_arbo($desc_pere[
'childs'], $compl_path.$desc_pere[3].
" -> ", $desc_pere[1] * $multiply, $level + 1, $id, $ignore_stock_load);
5108 $this->res = array();
5109 if (isset($this->sousprods) && is_array($this->sousprods)) {
5110 foreach ($this->sousprods as $prod_name => $desc_product) {
5111 if (is_array($desc_product)) {
5112 $this->
fetch_prod_arbo($desc_product,
"", $multiply, 1, $this->
id, $ignore_stock_load);
5131 $sql =
"SELECT COUNT(pa.rowid) as nb";
5132 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa";
5134 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id).
" OR pa.fk_product_pere = ".((int) $this->
id);
5135 } elseif ($mode == -1) {
5136 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id);
5137 } elseif ($mode == 1) {
5138 $sql .=
" WHERE pa.fk_product_pere = ".((int) $this->
id);
5141 $resql = $this->db->query($sql);
5143 $obj = $this->db->fetch_object($resql);
5162 $sql =
"SELECT count(rowid) as nb FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_parent = ".((int) $this->
id);
5163 $sql .=
" AND entity IN (".getEntity(
'product').
")";
5165 $resql = $this->db->query($sql);
5167 $obj = $this->db->fetch_object($resql);
5185 if (isModEnabled(
'variants')) {
5186 $sql =
"SELECT rowid FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_child = ".((int) $this->
id).
" AND entity IN (".
getEntity(
'product').
")";
5188 $query = $this->db->query($sql);
5191 if (!$this->db->num_rows($query)) {
5212 $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";
5213 $sql .=
", p.tosell as status, p.tobuy as status_buy";
5214 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa,";
5215 $sql .=
" ".$this->db->prefix().
"product as p";
5216 $sql .=
" WHERE p.rowid = pa.fk_product_pere";
5217 $sql .=
" AND pa.fk_product_fils = ".((int) $this->
id);
5219 $res = $this->db->query($sql);
5222 while ($record = $this->db->fetch_array($res)) {
5224 $prods[$record[
'id']][
'id'] = $record[
'rowid'];
5225 $prods[$record[
'id']][
'ref'] = $record[
'ref'];
5226 $prods[$record[
'id']][
'label'] = $record[
'label'];
5227 $prods[$record[
'id']][
'qty'] = $record[
'qty'];
5228 $prods[$record[
'id']][
'incdec'] = $record[
'incdec'];
5229 $prods[$record[
'id']][
'fk_product_type'] = $record[
'fk_product_type'];
5230 $prods[$record[
'id']][
'entity'] = $record[
'entity'];
5231 $prods[$record[
'id']][
'status'] = $record[
'status'];
5232 $prods[$record[
'id']][
'status_buy'] = $record[
'status_buy'];
5251 public function getChildsArbo($id, $firstlevelonly = 0, $level = 1, $parents = array())
5253 global $alreadyfound;
5259 $sql =
"SELECT p.rowid, p.ref, p.label as label, p.fk_product_type,";
5260 $sql .=
" pa.qty as qty, pa.fk_product_fils as id, pa.incdec,";
5261 $sql .=
" pa.rowid as fk_association, pa.rang";
5262 $sql .=
" FROM ".$this->db->prefix().
"product as p,";
5263 $sql .=
" ".$this->db->prefix().
"product_association as pa";
5264 $sql .=
" WHERE p.rowid = pa.fk_product_fils";
5265 $sql .=
" AND pa.fk_product_pere = ".((int) $id);
5266 $sql .=
" AND pa.fk_product_fils <> ".((int) $id);
5267 $sql .=
" ORDER BY pa.rang";
5269 dol_syslog(get_class($this).
'::getChildsArbo id='.$id.
' level='.$level.
' parents='.(is_array($parents) ? implode(
',', $parents) : $parents), LOG_DEBUG);
5272 $alreadyfound = array($id => 1);
5279 $res = $this->db->query($sql);
5282 while ($rec = $this->db->fetch_array($res)) {
5283 if (!empty($alreadyfound[$rec[
'rowid']])) {
5284 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);
5285 if (in_array($rec[
'id'], $parents)) {
5289 $alreadyfound[$rec[
'rowid']] = 1;
5290 $prods[$rec[
'rowid']] = array(
5293 2 => $rec[
'fk_product_type'],
5294 3 => $this->db->escape($rec[
'label']),
5295 4 => $rec[
'incdec'],
5297 6 => $rec[
'fk_association'],
5302 if (empty($firstlevelonly)) {
5303 $parents[] = $rec[
'rowid'];
5304 $listofchilds = $this->
getChildsArbo($rec[
'rowid'], 0, $level + 1, $parents);
5305 foreach ($listofchilds as $keyChild => $valueChild) {
5306 $prods[$rec[
'rowid']][
'childs'][$keyChild] = $valueChild;
5330 foreach ($this->
getChildsArbo($this->
id) as $keyChild => $valueChild) {
5331 $parent[$this->label][$keyChild] = $valueChild;
5333 foreach ($parent as $key => $value) {
5334 $this->sousprods[$key] = $value;
5346 global $conf, $langs, $user;
5348 $langs->loadLangs(array(
'products',
'other'));
5351 $nofetch = !empty($params[
'nofetch']);
5354 return [
'optimize' => $langs->trans(
"ShowProduct")];
5357 if (!empty($this->entity)) {
5358 $tmpphoto = $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 80, 0, 0, 0, 0, 1);
5359 if ($this->nbphoto > 0) {
5360 $datas[
'photo'] =
'<div class="photointooltip floatright">'.
"\n" . $tmpphoto .
'</div>';
5365 $datas[
'picto'] =
img_picto(
'',
'product').
' <u class="paddingrightonly">'.$langs->trans(
"Product").
'</u>';
5367 $datas[
'picto'] =
img_picto(
'',
'service').
' <u class="paddingrightonly">'.$langs->trans(
"Service").
'</u>';
5369 if (isset($this->
status) && isset($this->status_buy)) {
5370 $datas[
'status'] =
' '.$this->getLibStatut(5, 0) .
' '.$this->getLibStatut(5, 1);
5373 if (!empty($this->
ref)) {
5374 $datas[
'ref'] =
'<br><b>'.$langs->trans(
'ProductRef').
':</b> '.$this->ref;
5376 if (!empty($this->label)) {
5377 $datas[
'label'] =
'<br><b>'.$langs->trans(
'ProductLabel').
':</b> '.$this->label;
5383 if (isModEnabled(
'productbatch')) {
5384 $langs->load(
"productbatch");
5385 $datas[
'batchstatus'] =
"<br><b>".$langs->trans(
"ManageLotSerial").
'</b>: '.$this->
getLibStatut(0, 2);
5388 if (isModEnabled(
'barcode')) {
5389 $datas[
'barcode'] =
'<br><b>'.$langs->trans(
'BarCode').
':</b> '.$this->barcode;
5393 if ($this->weight) {
5394 $datas[
'weight'] =
"<br><b>".$langs->trans(
"Weight").
'</b>: '.$this->weight.
' '.
measuringUnitString(0,
"weight", $this->weight_units);
5397 if ($this->length) {
5398 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Length").
'</b>: '.$this->length.
' '.
measuringUnitString(0,
'size', $this->length_units);
5401 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Width").
'</b>: '.$this->width.
' '.
measuringUnitString(0,
'size', $this->width_units);
5403 if ($this->height) {
5404 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Height").
'</b>: '.$this->height.
' '.
measuringUnitString(0,
'size', $this->height_units);
5407 $datas[
'size'] =
"<br>".$labelsize;
5410 $labelsurfacevolume =
"";
5411 if ($this->surface) {
5412 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Surface").
'</b>: '.$this->surface.
' '.
measuringUnitString(0,
'surface', $this->surface_units);
5414 if ($this->volume) {
5415 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Volume").
'</b>: '.$this->volume.
' '.
measuringUnitString(0,
'volume', $this->volume_units);
5417 if ($labelsurfacevolume) {
5418 $datas[
'surface'] =
"<br>" . $labelsurfacevolume;
5421 if ($this->
isService() && !empty($this->duration_value)) {
5424 if ($this->duration_value > 1) {
5425 $dur = array(
"i" => $langs->trans(
"Minutes"),
"h" => $langs->trans(
"Hours"),
"d" => $langs->trans(
"Days"),
"w" => $langs->trans(
"Weeks"),
"m" => $langs->trans(
"Months"),
"y" => $langs->trans(
"Years"));
5426 } elseif ($this->duration_value > 0) {
5427 $dur = array(
"i" => $langs->trans(
"Minute"),
"h" => $langs->trans(
"Hour"),
"d" => $langs->trans(
"Day"),
"w" => $langs->trans(
"Week"),
"m" => $langs->trans(
"Month"),
"y" => $langs->trans(
"Year"));
5429 $datas[
'duration'] .= (!empty($this->duration_unit) && isset($dur[$this->duration_unit]) ?
" ".$langs->trans($dur[$this->duration_unit]) :
'');
5431 if (empty($user->socid)) {
5433 $datas[
'pmp'] =
"<br><b>".$langs->trans(
"PMPValue").
'</b>: '.
price($this->pmp, 0,
'', 1, -1, -1, $conf->currency);
5436 if (isModEnabled(
'accounting')) {
5437 if ($this->
status && isset($this->accountancy_code_sell)) {
5438 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5439 $selllabel =
'<br>';
5440 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellCode').
':</b> '.
length_accountg($this->accountancy_code_sell);
5441 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellIntraCode').
':</b> '.
length_accountg($this->accountancy_code_sell_intra);
5442 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellExportCode').
':</b> '.
length_accountg($this->accountancy_code_sell_export);
5443 $datas[
'accountancysell'] = $selllabel;
5445 if ($this->status_buy && isset($this->accountancy_code_buy)) {
5446 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5448 if (empty($this->
status)) {
5449 $buylabel .=
'<br>';
5451 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyCode').
':</b> '.
length_accountg($this->accountancy_code_buy);
5452 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyIntraCode').
':</b> '.
length_accountg($this->accountancy_code_buy_intra);
5453 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyExportCode').
':</b> '.
length_accountg($this->accountancy_code_buy_export);
5454 $datas[
'accountancybuy'] = $buylabel;
5459 if (isModEnabled(
'category') && !$nofetch) {
5460 require_once DOL_DOCUMENT_ROOT .
'/categories/class/categorie.class.php';
5461 $form =
new Form($this->db);
5462 $datas[
'categories'] =
'<br>' . $form->showCategories($this->
id, Categorie::TYPE_PRODUCT, 1);
5481 public function getNomUrl($withpicto = 0, $option =
'', $maxlength = 0, $save_lastsearch_value = -1, $notooltip = 0, $morecss =
'', $add_label = 0, $sep =
' - ')
5483 global $conf, $langs, $hookmanager, $user;
5484 include_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
5488 $newref = $this->ref;
5490 $newref =
dol_trunc($newref, $maxlength,
'middle');
5494 'objecttype' => (isset($this->
type) ? ($this->
type == 1 ?
'service' :
'product') : $this->element),
5495 'option' => $option,
5498 $classfortooltip =
'classfortooltip';
5501 $classfortooltip =
'classforajaxtooltip';
5502 $dataparams =
' data-params="'.dol_escape_htmltag(json_encode($params)).
'"';
5509 if (empty($notooltip)) {
5511 $label = $langs->trans(
"ShowProduct");
5512 $linkclose .=
' alt="'.dol_escape_htmltag($label, 1, 1).
'"';
5514 $linkclose .= ($label ?
' title="'.dol_escape_htmltag($label, 1, 1).
'"' :
' title="tocomplete"');
5515 $linkclose .= $dataparams.
' class="nowraponall '.$classfortooltip.($morecss ?
' '.$morecss :
'').
'"';
5517 $linkclose =
' class="nowraponall'.($morecss ?
' '.$morecss :
'').
'"';
5520 if ($option ==
'supplier' || $option ==
'category') {
5521 $url = DOL_URL_ROOT.
'/product/price_suppliers.php?id='.$this->id;
5522 } elseif ($option ==
'stock') {
5523 $url = DOL_URL_ROOT.
'/product/stock/product.php?id='.$this->id;
5524 } elseif ($option ==
'composition') {
5525 $url = DOL_URL_ROOT.
'/product/composition/card.php?id='.$this->id;
5527 $url = DOL_URL_ROOT.
'/product/card.php?id='.$this->id;
5530 if ($option !==
'nolink') {
5532 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
5533 if ($save_lastsearch_value == -1 && isset($_SERVER[
"PHP_SELF"]) && preg_match(
'/list\.php/', $_SERVER[
"PHP_SELF"])) {
5534 $add_save_lastsearch_values = 1;
5536 if ($add_save_lastsearch_values) {
5537 $url .=
'&save_lastsearch_values=1';
5541 $linkstart =
'<a href="'.$url.
'"';
5542 $linkstart .= $linkclose.
'>';
5545 $result .= $linkstart;
5548 $result .= (
img_object(($notooltip ?
'' : $label),
'product',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
5551 $result .= (
img_object(($notooltip ?
'' : $label),
'service',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
5554 $result .=
'<span class="aaa">'.dol_escape_htmltag($newref).
'</span>';
5555 $result .= $linkend;
5556 if ($withpicto != 2) {
5557 $result .= (($add_label && $this->label) ? $sep.dol_trunc($this->label, ($add_label > 1 ? $add_label : 0)) :
'');
5561 $hookmanager->initHooks(array(
'productdao'));
5562 $parameters = array(
'id' => $this->
id,
'getnomurl' => &$result,
'label' => &$label);
5563 $reshook = $hookmanager->executeHooks(
'getNomUrl', $parameters, $this, $action);
5565 $result = $hookmanager->resPrint;
5567 $result .= $hookmanager->resPrint;
5584 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
5586 global $conf, $user, $langs;
5588 $langs->load(
"products");
5589 $outputlangs->load(
"products");
5596 $modelpath =
"core/modules/product/doc/";
5598 return $this->
commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
5614 return $this->
LibStatut($this->status_buy, $mode, $type);
5616 return $this->
LibStatut($this->status_batch, $mode, $type);
5619 return $this->
LibStatut($this->status_buy, $mode, $type);
5635 global $conf, $langs;
5637 $labelStatus = $labelStatusShort =
'';
5639 $langs->load(
'products');
5640 if (isModEnabled(
'productbatch')) {
5641 $langs->load(
"productbatch");
5647 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial')));
5648 return dolGetStatus($label);
5650 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort')));
5651 return dolGetStatus($label);
5655 return dolGetStatus($langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch'),
'',
'', empty($status) ?
'status5' :
'status4', 3,
'dot');
5661 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'));
5665 $statuttrans = empty($status) ?
'status5' :
'status4';
5670 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSellShort');
5671 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSell');
5672 } elseif ($type == 1) {
5673 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuyShort');
5674 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuy');
5675 } elseif ($type == 2) {
5676 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch');
5677 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort');
5679 } elseif ($status == 1) {
5682 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSellShort');
5683 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSell');
5684 } elseif ($type == 1) {
5685 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBuyShort');
5686 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBuy');
5687 } elseif ($type == 2) {
5688 $labelStatus = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial'));
5689 $labelStatusShort = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort'));
5691 } elseif ($type == 2 && $status == 2) {
5692 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSerial');
5693 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort');
5697 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'),
'',
'',
'status0', 0);
5699 return dolGetStatus($labelStatus, $labelStatusShort,
'', $statuttrans, $mode);
5712 $langs->load(
'products');
5715 if (isset($this->finished) && $this->finished >= 0) {
5716 $sql =
"SELECT label, code FROM ".$this->db->prefix().
"c_product_nature where code = ".((int) $this->finished).
" AND active=1";
5717 $resql = $this->db->query($sql);
5719 $this->error = $this->db->error().
' sql='.$sql;
5720 dol_syslog(__METHOD__.
' Error '.$this->error, LOG_ERR);
5722 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
5723 $label = $langs->trans($res[
'label']);
5725 $this->db->free($resql);
5749 public function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label =
'', $price = 0, $inventorycode =
'', $origin_element =
'', $origin_id =
null, $disablestockchangeforsubproduct = 0, $extrafields =
null)
5755 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
5761 $nbpiece = abs($nbpiece);
5764 $op[0] =
"+".trim((
string) $nbpiece);
5765 $op[1] =
"-".trim((
string) $nbpiece);
5768 $movementstock->setOrigin($origin_element, $origin_id);
5769 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'',
'',
'',
'',
false, 0, $disablestockchangeforsubproduct);
5773 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
5774 $movementstock->array_options = $array_options;
5775 $movementstock->insertExtraFields();
5777 $this->db->commit();
5780 $this->error = $movementstock->error;
5781 $this->errors = $movementstock->errors;
5783 $this->db->rollback();
5812 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)
5818 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
5824 $nbpiece = abs($nbpiece);
5828 $op[0] =
"+".trim((
string) $nbpiece);
5829 $op[1] =
"-".trim((
string) $nbpiece);
5832 $movementstock->setOrigin($origin_element, $origin_id);
5833 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'', $dlc, $dluo, $lot,
false, 0, $disablestockchangeforsubproduct, 0, $force_update_batch);
5837 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
5838 $movementstock->array_options = $array_options;
5839 $movementstock->insertExtraFields();
5841 $this->db->commit();
5844 $this->error = $movementstock->error;
5845 $this->errors = $movementstock->errors;
5847 $this->db->rollback();
5867 public function load_stock($option =
'', $includedraftpoforvirtual =
null, $dateofvirtualstock =
null)
5872 $this->stock_reel = 0;
5873 $this->stock_warehouse = array();
5874 $this->stock_theorique = 0;
5877 $warehouseStatus = array();
5878 if (preg_match(
'/warehouseclosed/', $option)) {
5881 if (preg_match(
'/warehouseopen/', $option)) {
5884 if (preg_match(
'/warehouseinternal/', $option)) {
5892 $sql =
"SELECT ps.rowid, ps.reel, ps.fk_entrepot";
5893 $sql .=
" FROM ".$this->db->prefix().
"product_stock as ps";
5894 $sql .=
", ".$this->db->prefix().
"entrepot as w";
5895 $sql .=
" WHERE w.entity IN (".getEntity(
'stock').
")";
5896 $sql .=
" AND w.rowid = ps.fk_entrepot";
5897 $sql .=
" AND ps.fk_product = ".((int) $this->
id);
5898 if (count($warehouseStatus)) {
5899 $sql .=
" AND w.statut IN (".$this->db->sanitize(implode(
',', $warehouseStatus)).
")";
5902 $sql .=
" ORDER BY ps.reel ".(getDolGlobalString(
'DO_NOT_TRY_TO_DEFRAGMENT_STOCKS_WAREHOUSE') ?
'DESC' :
'ASC');
5904 dol_syslog(get_class($this).
"::load_stock", LOG_DEBUG);
5905 $result = $this->db->query($sql);
5907 $num = $this->db->num_rows($result);
5911 $row = $this->db->fetch_object($result);
5912 $this->stock_warehouse[$row->fk_entrepot] =
new stdClass();
5913 $this->stock_warehouse[$row->fk_entrepot]->real = $row->reel;
5914 $this->stock_warehouse[$row->fk_entrepot]->id = $row->rowid;
5915 if ((!preg_match(
'/nobatch/', $option)) && $this->
hasbatch()) {
5916 $this->stock_warehouse[$row->fk_entrepot]->detail_batch =
Productbatch::findAll($this->db, $row->rowid, 1, $this->id);
5918 $this->stock_reel += $row->reel;
5922 $this->db->free($result);
5924 if (!preg_match(
'/novirtual/', $option)) {
5930 $this->error = $this->db->lasterror();
5949 global $conf, $hookmanager, $action;
5951 $stock_commande_client = 0;
5952 $stock_commande_fournisseur = 0;
5953 $stock_sending_client = 0;
5954 $stock_reception_fournisseur = 0;
5955 $stock_inproduction = 0;
5959 if (isModEnabled(
'order')) {
5964 $stock_commande_client = $this->stats_commande[
'qty'];
5966 if (isModEnabled(
"shipping")) {
5967 require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expedition.class.php';
5968 $filterShipmentStatus =
'';
5978 $stock_sending_client = $this->stats_expedition[
'qty'];
5980 if (isModEnabled(
"supplier_order")) {
5981 $filterStatus =
getDolGlobalString(
'SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK',
'3,4');
5982 if (isset($includedraftpoforvirtual)) {
5983 $filterStatus =
'0,1,2,'.$filterStatus;
5989 $stock_commande_fournisseur = $this->stats_commande_fournisseur[
'qty'];
5991 if ((isModEnabled(
"supplier_order") || isModEnabled(
"supplier_invoice")) && empty($conf->reception->enabled)) {
5993 $filterStatus =
'4';
5994 if (isset($includedraftpoforvirtual)) {
5995 $filterStatus =
'0,'.$filterStatus;
6001 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
6003 if ((isModEnabled(
"supplier_order") || isModEnabled(
"supplier_invoice")) && isModEnabled(
"reception")) {
6005 $filterStatus =
'4';
6006 if (isset($includedraftpoforvirtual)) {
6007 $filterStatus =
'0,'.$filterStatus;
6013 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
6015 if (isModEnabled(
'mrp')) {
6020 $stock_inproduction = $this->stats_mrptoproduce[
'qty'] - $this->stats_mrptoconsume[
'qty'];
6023 $this->stock_theorique = $this->stock_reel + $stock_inproduction;
6027 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6029 $this->stock_theorique += 0;
6031 $this->stock_theorique -= $stock_commande_client;
6035 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6037 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6039 $this->stock_theorique -= $stock_reception_fournisseur;
6041 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6044 $parameters = array(
'id' => $this->
id,
'includedraftpoforvirtual' => $includedraftpoforvirtual);
6046 $reshook = $hookmanager->executeHooks(
'loadvirtualstock', $parameters, $this, $action);
6048 $this->stock_theorique = $hookmanager->resArray[
'stock_theorique'];
6049 } elseif ($reshook == 0 && isset($hookmanager->resArray[
'stock_stats_hook'])) {
6050 $this->stock_theorique += $hookmanager->resArray[
'stock_stats_hook'];
6054 if (!empty($this->stock_warehouse) &&
getDolGlobalString(
'STOCK_ALLOW_VIRTUAL_STOCK_PER_WAREHOUSE')) {
6055 foreach ($this->stock_warehouse as $warehouseid => $stockwarehouse) {
6056 if (isModEnabled(
'mrp')) {
6063 if ($this->fk_default_warehouse == $warehouseid) {
6064 $this->stock_warehouse[$warehouseid]->virtual = $this->stock_warehouse[$warehouseid]->real + $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] + $this->stats_commande_fournisseur[
'qty'] - ($this->stats_commande[
'qty'] + $this->stats_mrptoconsume[
'qty']);
6066 $this->stock_warehouse[$warehouseid]->virtual = $this->stock_warehouse[$warehouseid]->real + $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'];
6086 $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";
6087 $sql .=
" WHERE pb.fk_product_stock = ps.rowid AND ps.fk_product = ".((int) $this->
id).
" AND pb.batch = '".$this->db->escape($batch).
"'";
6088 $sql .=
" GROUP BY pb.batch, pb.eatby, pb.sellby";
6089 dol_syslog(get_class($this).
"::loadBatchInfo load first entry found for lot/serial = ".$batch, LOG_DEBUG);
6090 $resql = $this->db->query($sql);
6092 $num = $this->db->num_rows($resql);
6095 $obj = $this->db->fetch_object($resql);
6096 $result[] = array(
'batch' => $batch,
'eatby' => $this->db->jdate($obj->eatby),
'sellby' => $this->db->jdate($obj->sellby),
'qty' => $obj->qty);
6102 $this->db->rollback();
6120 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6126 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos";
6128 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product').dol_sanitizeFileName($this->
ref);
6133 $dir_osencoded = $dir;
6135 if (is_dir($dir_osencoded)) {
6136 $originImage = $dir.
'/'.$file[
'name'];
6147 if (is_numeric($result) && $result > 0) {
6164 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6165 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6171 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos/";
6173 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product');
6179 if (file_exists($dir_osencoded)) {
6180 $handle = opendir($dir_osencoded);
6181 if (is_resource($handle)) {
6182 while (($file = readdir($handle)) !==
false) {
6184 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6206 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6207 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6213 $handle = @opendir($dir_osencoded);
6214 if (is_resource($handle)) {
6215 while (($file = readdir($handle)) !==
false) {
6217 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6224 $photo_vignette =
'';
6226 if (preg_match(
'/('.$this->regeximgext.
')$/i', $photo, $regs)) {
6227 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $photo).
'_small'.$regs[0];
6230 $dirthumb = $dir.
'thumbs/';
6234 $obj[
'photo'] = $photo;
6235 if ($photo_vignette &&
dol_is_file($dirthumb.$photo_vignette)) {
6236 $obj[
'photo_vignette'] =
'thumbs/'.$photo_vignette;
6238 $obj[
'photo_vignette'] =
"";
6241 $tabobj[$nbphoto - 1] = $obj;
6244 if ($nbmax && $nbphoto >= $nbmax) {
6266 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6267 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6269 $dir = dirname($file).
'/';
6270 $dirthumb = $dir.
'/thumbs/';
6271 $filename = preg_replace(
'/'.preg_quote($dir,
'/').
'/i',
'', $file);
6277 if (preg_match(
'/('.$this->regeximgext.
')$/i', $filename, $regs)) {
6278 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_small'.$regs[0];
6279 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6283 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_mini'.$regs[0];
6284 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6301 $infoImg = getimagesize($file_osencoded);
6302 $this->imgWidth = $infoImg[0];
6303 $this->imgHeight = $infoImg[1];
6313 global $hookmanager;
6315 $this->nb = array();
6317 $sql =
"SELECT count(p.rowid) as nb, fk_product_type";
6318 $sql .=
" FROM ".$this->db->prefix().
"product as p";
6319 $sql .=
' WHERE p.entity IN ('.getEntity($this->element, 1).
')';
6321 if (is_object($hookmanager)) {
6322 $parameters = array();
6323 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
6324 $sql .= $hookmanager->resPrint;
6326 $sql .=
' GROUP BY fk_product_type';
6328 $resql = $this->db->query($sql);
6330 while ($obj = $this->db->fetch_object($resql)) {
6331 if ($obj->fk_product_type == 1) {
6332 $this->nb[
"services"] = $obj->nb;
6334 $this->nb[
"products"] = $obj->nb;
6337 $this->db->free($resql);
6341 $this->error = $this->db->error();
6383 return $this->mandatory_period == 1;
6393 return $this->status_batch > 0;
6413 $dirsociete = array_merge(array(
'/core/modules/barcode/'), $conf->modules_parts[
'barcode']);
6414 foreach ($dirsociete as $dirroot) {
6422 '@phan-var-force ModeleNumRefBarCode $module';
6424 $result = $mod->getNextValue(
$object, $type);
6426 dol_syslog(get_class($this).
"::get_barcode barcode=".$result.
" module=".$var);
6443 $this->specimen = 1;
6445 $this->
ref =
'PRODUCT_SPEC';
6446 $this->label =
'PRODUCT SPECIMEN';
6447 $this->
description =
'This is description of this product specimen that was created the '.dol_print_date($now,
'dayhourlog').
'.';
6448 $this->specimen = 1;
6449 $this->country_id = 1;
6451 $this->status_buy = 1;
6453 $this->sell_or_eat_by_mandatory = 0;
6454 $this->note_private =
'This is a comment (private)';
6455 $this->note_public =
'This is a comment (public)';
6456 $this->date_creation = $now;
6457 $this->date_modification = $now;
6460 $this->weight_units = 3;
6463 $this->length_units = 1;
6465 $this->width_units = 0;
6466 $this->height =
null;
6467 $this->height_units =
null;
6469 $this->surface = 30;
6470 $this->surface_units = 0;
6471 $this->volume = 300;
6472 $this->volume_units = 0;
6474 $this->barcode = -1;
6489 if (!$this->fk_unit) {
6493 $langs->load(
'products');
6495 $label_type =
'label';
6496 if ($type ==
'short') {
6497 $label_type =
'short_label';
6500 $sql =
"SELECT ".$label_type.
", code from ".$this->db->prefix().
"c_units where rowid = ".((int) $this->fk_unit);
6502 $resql = $this->db->query($sql);
6504 $this->error = $this->db->error();
6505 dol_syslog(get_class($this).
"::getLabelOfUnit Error ".$this->error, LOG_ERR);
6507 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
6508 $label = ($label_type ==
'short_label' ? $res[$label_type] :
'unit'.$res[
'code']);
6510 $this->db->free($resql);
6526 $maxpricesupplier = 0;
6529 include_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.product.class.php';
6531 $product_fourn_list = $product_fourn->list_product_fournisseur_price($this->
id,
'',
'');
6533 if (is_array($product_fourn_list) && count($product_fourn_list) > 0) {
6534 foreach ($product_fourn_list as $productfourn) {
6535 if ($productfourn->fourn_unitprice > $maxpricesupplier) {
6536 $maxpricesupplier = $productfourn->fourn_unitprice;
6544 return $maxpricesupplier;
6560 require_once DOL_DOCUMENT_ROOT.
'/categories/class/categorie.class.php';
6561 return parent::setCategoriesCommon($categories, Categorie::TYPE_PRODUCT);
6575 'product_customer_price',
6576 'product_customer_price_log'
6597 $sql =
"SELECT rowid, level, fk_level, var_percent, var_min_percent FROM ".$this->db->prefix().
"product_pricerules";
6598 $query = $this->db->query($sql);
6602 while ($result = $this->db->fetch_object($query)) {
6603 $rules[$result->level] = $result;
6612 for ($i = 1; $i <= $nbofproducts; $i++) {
6613 $price = $baseprice;
6614 $price_min = $baseprice;
6618 if ($i > 1 && isset($rules[$i]->var_percent) && $rules[$i]->var_percent) {
6619 $price = $prices[$rules[$i]->fk_level] * (1 + ($rules[$i]->var_percent / 100));
6622 $prices[$i] = $price;
6625 if (isset($rules[$i]->var_min_percent) && $rules[$i]->var_min_percent) {
6626 $price_min = $price * (1 - ($rules[$i]->var_min_percent / 100));
6630 $check_amount = (($price == $this->multiprices[$i]) && ($price_min == $this->multiprices_min[$i]));
6631 $check_type = ($baseprice == $this->multiprices_base_type[$i]);
6633 if ($check_amount && $check_type) {
6637 if ($this->
updatePrice($price, $price_type, $user, $price_vat, $price_min, $i, $npr, $psq, 1) < 0) {
6655 return $user->rights->produit;
6657 return $user->rights->service;
6669 $sql =
"SELECT p.rowid, p.ref, p.datec as date_creation, p.tms as date_modification,";
6670 $sql .=
" p.fk_user_author, p.fk_user_modif";
6671 $sql .=
" FROM ".$this->db->prefix().$this->table_element.
" as p";
6672 $sql .=
" WHERE p.rowid = ".((int) $id);
6674 $result = $this->db->query($sql);
6676 if ($this->db->num_rows($result)) {
6677 $obj = $this->db->fetch_object($result);
6679 $this->
id = $obj->rowid;
6680 $this->
ref = $obj->ref;
6682 $this->user_creation_id = $obj->fk_user_author;
6683 $this->user_modification_id = $obj->fk_user_modif;
6685 $this->date_creation = $this->db->jdate($obj->date_creation);
6686 $this->date_modification = $this->db->jdate($obj->date_modification);
6689 $this->db->free($result);
6705 if (empty($this->duration_value)) {
6706 $this->errors[] =
'ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
6710 if ($this->duration_unit ==
'i') {
6711 $prodDurationHours = 1. / 60;
6713 if ($this->duration_unit ==
'h') {
6714 $prodDurationHours = 1.;
6716 if ($this->duration_unit ==
'd') {
6717 $prodDurationHours = 24.;
6719 if ($this->duration_unit ==
'w') {
6720 $prodDurationHours = 24. * 7;
6722 if ($this->duration_unit ==
'm') {
6723 $prodDurationHours = 24. * 30;
6725 if ($this->duration_unit ==
'y') {
6726 $prodDurationHours = 24. * 365;
6730 return $prodDurationHours;
6743 global $langs,$conf;
6745 $selected = (empty($arraydata[
'selected']) ? 0 : $arraydata[
'selected']);
6747 $return =
'<div class="box-flex-item box-flex-grow-zero">';
6748 $return .=
'<div class="info-box info-box-sm">';
6749 $return .=
'<div class="info-box-img">';
6752 $label .= $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 120, 160, 0, 0, 0,
'',
'photoref photokanban');
6762 $return .=
'</div>';
6763 $return .=
'<div class="info-box-content">';
6764 $return .=
'<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this,
'getNomUrl') ? $this->
getNomUrl() : $this->ref).
'</span>';
6765 if ($selected >= 0) {
6766 $return .=
'<input id="cb'.$this->id.
'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->
id.
'"'.($selected ?
' checked="checked"' :
'').
'>';
6768 if (property_exists($this,
'label')) {
6769 $return .=
'<br><span class="info-box-label opacitymedium inline-block tdoverflowmax150 valignmiddle" title="'.dol_escape_htmltag($this->label).
'">'.
dol_escape_htmltag($this->label).
'</span>';
6771 if (property_exists($this,
'price') && property_exists($this,
'price_ttc')) {
6772 if ($this->price_base_type ==
'TTC') {
6773 $return .=
'<br><span class="info-box-status amount">'.price($this->price_ttc).
' '.$langs->trans(
"TTC").
'</span>';
6776 $return .=
'<br><span class="info-box-status amount">'.price($this->
price).
' '.$langs->trans(
"HT").
'</span>';
6781 if (property_exists($this,
'stock_reel') && $this->
isProduct()) {
6782 $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>';
6785 if (method_exists($this,
'getLibStatut')) {
6787 $return .=
'<br><div class="info-box-status inline-block valignmiddle">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
6789 $return .=
'<div class="info-box-status inline-block valignmiddle marginleftonly paddingleft">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
6792 $return .=
'</div>';
6793 $return .=
'</div>';
6794 $return .=
'</div>';
6805 public $picto =
'service';
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
length_accountg($account)
Return General accounting account with defined length (used for product and miscellaneous)
print $langs trans("AuditedSecurityEvents").'</strong >< span class="opacitymedium"></span >< br > status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Parent class of all other business classes (invoices, contracts, proposals, orders,...
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
deleteEcmFiles($mode=0)
Delete related files of object in database.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
isObjectUsed($id=0, $entity=0)
Function to check if an object is used by others (by children).
deleteExtraFields()
Delete all extra fields values for the current object.
addThumbs($file)
Build thumb.
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
show_photos($modulepart, $sdir, $size=0, $nbmax=0, $nbbyrow=5, $showfilename=0, $showaction=0, $maxHeight=120, $maxWidth=160, $nolink=0, $overwritetitle=0, $usesharelink=0, $cache='', $addphotorefcss='photoref')
Show photos of an object (nbmax maximum), into several columns.
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
call_trigger($triggerName, $user)
Call trigger based on this instance.
Class to manage Dolibarr database access.
Class to manage ECM files.
const STATUS_OPEN_INTERNAL
Warehouse open and only operations for stock transfers/corrections allowed (not for customer shipping...
const STATUS_OPEN_ALL
Warehouse open and any operations are allowed (customer shipping, supplier dispatch,...
const STATUS_CLOSED
Warehouse closed, inactive.
const STATUS_CLOSED
Closed status -> parcel was received by customer / end of process prev status : validated or shipment...
const STATUS_VALIDATED
Validated status -> parcel is ready to be sent prev status : draft next status : closed or shipment_i...
const STATUS_DRAFT
Draft status.
Class to manage stock movements.
Class to parse product price expressions.
Class ProductCombination Used to represent the relation between a product and one of its variants.
File of class to manage predefined price products or services by customer.
Class to manage predefined suppliers products.
Class to manage products or services.
static replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
get_nb_achat($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units or supplier invoices in which product is included.
getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp=0)
Return price of sell of a product for a seller/buyer/product.
__construct($db)
Constructor.
$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 the object is managed in stock.
$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.
updatePrice($newprice, $newpricebase, $user, $newvat=null, $newminprice=0, $level=0, $newnpr=0, $newpbq=0, $ignore_autogen=0, $localtaxes_array=array(), $newdefaultvatcode='', $price_label='', $notrigger=0)
Modify customer price of a product/Service for a given level.
hasVariants()
Return if a product has variants or not.
delMultiLangs($langtodelete, $user)
Delete a language for this product.
getLabelOfUnit($type='long')
Returns the text label from units dictionary.
load_stats_proposal_supplier($socid=0)
Charge tableau des stats propale pour le produit/service.
getLibFinished()
Retour label of nature of product.
add_sousproduit($id_pere, $id_fils, $qty, $incdec=1, $notrigger=0)
Link a product/service to a parent product/service.
add_fournisseur($user, $id_fourn, $ref_fourn, $quantity)
Add a supplier price for the product.
hasFatherOrChild($mode=0)
Count all parent and children products for current product (first level only)
load_stats_facturerec($socid=0)
Charge tableau des stats facture recurrentes pour le produit/service.
get_nb_propalsupplier($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in proposals in which product is included.
get_nb_contract($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
load_stats_facture_fournisseur($socid=0)
Charge tableau des stats facture pour le produit/service.
get_nb_ordersupplier($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
getMultiLangs()
Load array this->multilangs.
get_nb_mos($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
clone_associations($fromId, $toId)
Clone links between products.
create($user, $notrigger=0)
Insert product into database.
load_stats_contrat($socid=0)
Charge tableau des stats contrat pour le produit/service.
isService()
Return if the object is a service.
getRights()
Returns the rights used for this class.
loadBatchInfo($batch)
Load existing information about a serial.
$pmp
Average price value for product entry into stock (PMP)
load_stock($option='', $includedraftpoforvirtual=null, $dateofvirtualstock=null)
Load information about stock of a product into ->stock_reel, ->stock_warehouse[] (including stock_war...
getProductDurationHours()
Return the duration of a service in hours (for a service based on duration fields)
$default_vat_code
Default VAT code for product (link to code into llx_c_tva but without foreign keys)
$duration_unit
Service 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.
add_photo($sdir, $file)
Move an uploaded file described into $file array into target directory $sdir.
log_price_delete($user, $rowid)
Delete a price line.
info($id)
Load information for tab info.
correct_stock($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $inventorycode='', $origin_element='', $origin_id=null, $disablestockchangeforsubproduct=0, $extrafields=null)
Adjust stock in a warehouse for product.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
Create a document onto disk according to template module.
static getSellOrEatByMandatoryList()
Get sell or eat by mandatory list.
$multiprices
Arrays for multiprices.
$localtax1_tx
Other local taxes.
getChildsArbo($id, $firstlevelonly=0, $level=1, $parents=array())
Return children of product $id.
load_virtual_stock($includedraftpoforvirtual=null, $dateofvirtualstock=null)
Load value ->stock_theorique of a product.
load_stats_propale($socid=0)
Charge tableau des stats propale pour le produit/service.
get_barcode($object, $type='')
Get a barcode from the module to generate barcode values.
setAccountancyCode($type, $value)
Sets an accountancy code for a product.
load_stats_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.
update($id, $user, $notrigger=0, $action='update', $updatetype=false)
Update a record into database.
setMultiLangs($user)
Update or add a translation for a product.
correct_stock_batch($user, $id_entrepot, $nbpiece, $movement, $label='', $price=0, $dlc='', $dluo='', $lot='', $inventorycode='', $origin_element='', $origin_id=null, $disablestockchangeforsubproduct=0, $extrafields=null, $force_update_batch=false)
Adjust stock in a warehouse for product with batch number.
$tva_tx
Default VAT rate of product.
load_stats_bom($socid=0)
Charge tableau des stats OF pour le produit/service.
hasbatch()
Return if the object has a sell-by or eat-by date.
$weight
Metric of products.
del_sousproduit($fk_parent, $fk_child, $notrigger=0)
Remove a link between a subproduct and a parent product/service.
fetch($id=0, $ref='', $ref_ext='', $barcode='', $ignore_expression=0, $ignore_price_load=0, $ignore_lang_load=0)
Load a product in memory from database.
update_sousproduit($id_pere, $id_fils, $qty, $incdec=1, $notrigger=0)
Modify composed product.
load_stats_commande($socid=0, $filtrestatut='', $forVirtualStock=0)
Charge tableau des stats commande client pour le produit/service.
delete_photo($file)
Delete a photo and its thumbs.
fetch_prod_arbo($prod, $compl_path='', $multiply=1, $level=1, $id_parent=0, $ignore_stock_load=0)
Function recursive, used only by get_arbo_each_prod(), to build tree of subproducts into ->res Define...
getKanbanView($option='', $arraydata=null)
Return 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.
load_stats_inproduction($socid=0, $filtrestatut='', $forVirtualStock=0, $dateofvirtualstock=null, $warehouseid=0)
Charge tableau des stats production pour le produit/service.
$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.
loadStateBoard()
Load indicators this->nb for the dashboard.
getFather()
Return all parent products for current product (first level only)
getNomUrl($withpicto=0, $option='', $maxlength=0, $save_lastsearch_value=-1, $notooltip=0, $morecss='', $add_label=0, $sep=' - ')
Return clickable link of object (with eventually picto)
getSellOrEatByMandatoryLabel()
Get sell or eat by mandatory label.
$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.
min_recommended_price()
Return minimum product recommended price.
_log_price($user, $level=0)
Insert a track that we changed a customer price.
_get_stats($sql, $mode, $year=0)
Return an array formatted for showing graphs.
$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 the object has a constraint on mandatory_period.
isProduct()
Return if the object is a product.
generateMultiprices(User $user, $baseprice, $price_type, $price_vat, $npr, $psq)
Generates prices for a product based on product multiprice generation rules.
LibStatut($status, $mode=0, $type=0)
Return label of a given status.
const TYPE_SERVICE
Service.
is_photo_available($sdir)
Return if at least one photo is available.
get_image_size($file)
Load size of image file.
get_nb_vente($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units or customers invoices in which product is included.
getTooltipContentArray($params)
getTooltipContentArray
Class to manage products or services.
Manage record for batch number management.
static findAll($dbs, $fk_product_stock, $with_qty=0, $fk_product=0)
Return all batch detail records for a given product and warehouse.
Class with list of lots and properties.
Class to manage Dolibarr users.
hasRight($module, $permlevel1, $permlevel2='')
Return if a user has a permission.
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $nohook=0, $varfiles='addedfile', $upload_dir='')
Check validity of a file upload from an GUI page, and move it to its final destination.
dol_is_file($pathoffile)
Return if path is a file.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dolGetFirstLineOfText($text, $nboflines=1, $charset='UTF-8')
Return first line of text.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='', $keepspaces=0)
Clean a string from all punctuation characters to use it as a ref or login.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
dol_clone($object, $native=0)
Create a clone of instance of object (new instance with same value for each properties) With native =...
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
utf8_check($str)
Check if a string is in UTF8.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_localtax($vatrate, $local, $thirdparty_buyer=null, $thirdparty_seller=null, $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate,...
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
measuringUnitString($unit, $measuring_style='', $scale='', $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
measuring_units_squared($unit)
Transform a given unit scale into the square of that unit, if known.
measuring_units_cubed($unit)
Transform a given unit scale into the cube of that unit, if known.
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type