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' ),
91 'bom_bom' => array(
'name' =>
'BOM'),
92 'bom_bomline' => array(
'name' =>
'BOMLine',
'parent' =>
'bom_bom',
'parentkey' =>
'fk_bom'),
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;
239 public $qc_frequency;
246 public $stock_reel = 0;
253 public $stock_theorique;
270 public $seuil_stock_alerte = 0;
293 public $fk_default_workstation;
315 public $status_buy = 0;
337 public $fk_default_bom;
344 public $product_fourn_price_id;
366 public $status_batch = 0;
373 public $sell_or_eat_by_mandatory = 0;
380 public $batch_mask =
'';
398 public $weight_units;
400 public $length_units;
404 public $height_units;
406 public $surface_units;
408 public $volume_units;
411 public $net_measure_units;
413 public $accountancy_code_sell;
414 public $accountancy_code_sell_intra;
415 public $accountancy_code_sell_export;
416 public $accountancy_code_buy;
417 public $accountancy_code_buy_intra;
418 public $accountancy_code_buy_export;
428 public $barcode_type;
433 public $barcode_type_code;
435 public $stats_propale = array();
436 public $stats_commande = array();
437 public $stats_contrat = array();
438 public $stats_facture = array();
439 public $stats_proposal_supplier = array();
440 public $stats_commande_fournisseur = array();
441 public $stats_expedition = array();
442 public $stats_reception = array();
443 public $stats_mo = array();
444 public $stats_bom = array();
445 public $stats_mrptoconsume = array();
446 public $stats_mrptoproduce = array();
447 public $stats_facturerec = array();
448 public $stats_facture_fournisseur = array();
457 public $date_creation;
462 public $date_modification;
478 public $fk_default_warehouse;
482 public $fk_price_expression;
487 public $fourn_price_base_type;
503 public $ref_supplier;
517 public $price_autogen = 0;
524 public $supplierprices;
544 public $is_object_used;
546 public $is_sousproduit_qty;
547 public $is_sousproduit_incdec;
549 public $mandatory_period;
580 public $fields = array(
581 'rowid' => array(
'type' =>
'integer',
'label' =>
'TechnicalID',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'index' => 1,
'position' => 1,
'comment' =>
'Id'),
582 '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'),
583 'entity' => array(
'type' =>
'integer',
'label' =>
'Entity',
'enabled' => 1,
'visible' => 0,
'default' =>
'1',
'notnull' => 1,
'index' => 1,
'position' => 5),
584 'label' => array(
'type' =>
'varchar(255)',
'label' =>
'Label',
'enabled' => 1,
'visible' => 1,
'notnull' => 1,
'showoncombobox' => 2,
'position' => 15,
'csslist' =>
'tdoverflowmax250'),
585 'barcode' => array(
'type' =>
'varchar(255)',
'label' =>
'Barcode',
'enabled' =>
'isModEnabled("barcode")',
'position' => 20,
'visible' => -1,
'showoncombobox' => 3,
'cssview' =>
'tdwordbreak',
'csslist' =>
'tdoverflowmax125'),
586 'fk_barcode_type' => array(
'type' =>
'integer',
'label' =>
'BarcodeType',
'enabled' => 1,
'position' => 21,
'notnull' => 0,
'visible' => -1,),
587 'note_public' => array(
'type' =>
'html',
'label' =>
'NotePublic',
'enabled' => 1,
'visible' => 0,
'position' => 61),
588 'note' => array(
'type' =>
'html',
'label' =>
'NotePrivate',
'enabled' => 1,
'visible' => 0,
'position' => 62),
589 'datec' => array(
'type' =>
'datetime',
'label' =>
'DateCreation',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 500),
590 'tms' => array(
'type' =>
'timestamp',
'label' =>
'DateModification',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 501),
592 'fk_user_author' => array(
'type' =>
'integer',
'label' =>
'UserAuthor',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 510,
'foreignkey' =>
'llx_user.rowid'),
593 'fk_user_modif' => array(
'type' =>
'integer',
'label' =>
'UserModif',
'enabled' => 1,
'visible' => -2,
'notnull' => -1,
'position' => 511),
595 'localtax1_tx' => array(
'type' =>
'double(6,3)',
'label' =>
'Localtax1tx',
'enabled' => 1,
'position' => 150,
'notnull' => 0,
'visible' => -1,),
596 'localtax1_type' => array(
'type' =>
'varchar(10)',
'label' =>
'Localtax1type',
'enabled' => 1,
'position' => 155,
'notnull' => 1,
'visible' => -1,),
597 'localtax2_tx' => array(
'type' =>
'double(6,3)',
'label' =>
'Localtax2tx',
'enabled' => 1,
'position' => 160,
'notnull' => 0,
'visible' => -1,),
598 'localtax2_type' => array(
'type' =>
'varchar(10)',
'label' =>
'Localtax2type',
'enabled' => 1,
'position' => 165,
'notnull' => 1,
'visible' => -1,),
599 'last_main_doc' => array(
'type' =>
'varchar(255)',
'label' =>
'LastMainDoc',
'enabled' => 1,
'visible' => -1,
'position' => 170),
600 'import_key' => array(
'type' =>
'varchar(14)',
'label' =>
'ImportId',
'enabled' => 1,
'visible' => -2,
'notnull' => -1,
'index' => 0,
'position' => 1000),
603 'mandatory_period' => array(
'type' =>
'integer',
'label' =>
'mandatoryperiod',
'enabled' => 1,
'visible' => -1,
'notnull' => 1,
'default' =>
'0',
'index' => 1,
'position' => 1000),
624 $this->ismultientitymanaged = 1;
625 $this->isextrafieldmanaged = 1;
638 $this->
ref = trim($this->
ref);
666 public function create($user, $notrigger = 0)
668 global $conf, $langs;
674 $this->
ref = trim($this->
ref);
678 $this->label = trim($this->label);
679 $this->price_ttc = (float)
price2num($this->price_ttc);
681 $this->price_min_ttc = (float)
price2num($this->price_min_ttc);
682 $this->price_min = (float)
price2num($this->price_min);
683 $this->price_label = trim($this->price_label);
684 if (empty($this->tva_tx)) {
687 if (empty($this->tva_npr)) {
691 if (empty($this->localtax1_tx)) {
692 $this->localtax1_tx = 0;
694 if (empty($this->localtax2_tx)) {
695 $this->localtax2_tx = 0;
697 if (empty($this->localtax1_type)) {
698 $this->localtax1_type =
'0';
700 if (empty($this->localtax2_type)) {
701 $this->localtax2_type =
'0';
703 if (empty($this->
price)) {
706 if (empty($this->price_min)) {
707 $this->price_min = 0;
710 if (empty($this->price_by_qty)) {
711 $this->price_by_qty = 0;
714 if (empty($this->
status)) {
717 if (empty($this->status_buy)) {
718 $this->status_buy = 0;
727 if ($this->price_base_type ==
'TTC' && $this->price_ttc > 0) {
728 $price_ttc =
price2num($this->price_ttc,
'MU');
729 $price_ht =
price2num($this->price_ttc / (1 + ($this->tva_tx / 100)),
'MU');
733 if ($this->price_base_type !=
'TTC' && $this->
price > 0) {
735 $price_ttc =
price2num($this->
price * (1 + ($this->tva_tx / 100)),
'MU');
739 if (($this->price_min_ttc > 0) && ($this->price_base_type ==
'TTC')) {
740 $price_min_ttc =
price2num($this->price_min_ttc,
'MU');
741 $price_min_ht =
price2num($this->price_min_ttc / (1 + ($this->tva_tx / 100)),
'MU');
745 if (($this->price_min > 0) && ($this->price_base_type !=
'TTC')) {
746 $price_min_ht =
price2num($this->price_min,
'MU');
747 $price_min_ttc =
price2num($this->price_min * (1 + ($this->tva_tx / 100)),
'MU');
750 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
751 $this->accountancy_code_buy_intra = trim($this->accountancy_code_buy_intra);
752 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
753 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
754 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
755 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
758 $this->barcode = trim($this->barcode);
759 $this->mandatory_period = empty($this->mandatory_period) ? 0 : $this->mandatory_period;
761 if (empty($this->label)) {
762 $this->error =
'ErrorMandatoryParametersNotProvided';
766 if (empty($this->
ref) || $this->
ref ==
'auto') {
769 if ($module !=
'mod_codeproduct_leopard') {
770 if (substr($module, 0, 16) ==
'mod_codeproduct_' && substr($module, -3) ==
'php') {
771 $module = substr($module, 0,
dol_strlen($module) - 4);
774 $modCodeProduct =
new $module();
775 '@phan-var-force ModeleProductCode $modCodeProduct';
776 if (!empty($modCodeProduct->code_auto)) {
777 $this->
ref = $modCodeProduct->getNextValue($this, $this->
type);
779 unset($modCodeProduct);
782 if (empty($this->
ref)) {
783 $this->error =
'ProductModuleNotSetupForAutoRef';
788 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);
792 if (empty($this->date_creation)) {
793 $this->date_creation = $now;
799 if ($this->barcode ==
'-1' || $this->barcode ==
'auto') {
800 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
805 $result = $this->
verify();
808 $sql =
"SELECT count(*) as nb";
809 $sql .=
" FROM ".$this->db->prefix().
"product";
810 $sql .=
" WHERE entity IN (".getEntity(
'product').
")";
811 $sql .=
" AND ref = '".$this->db->escape($this->
ref).
"'";
813 $result = $this->db->query($sql);
815 $obj = $this->db->fetch_object($result);
818 $sql =
"INSERT INTO ".$this->db->prefix().
"product (";
823 $sql .=
", price_min";
824 $sql .=
", price_min_ttc";
826 $sql .=
", fk_user_author";
827 $sql .=
", fk_product_type";
829 $sql .=
", price_ttc";
830 $sql .=
", price_base_type";
831 $sql .=
", price_label";
835 $sql .=
", accountancy_code_buy";
836 $sql .=
", accountancy_code_buy_intra";
837 $sql .=
", accountancy_code_buy_export";
838 $sql .=
", accountancy_code_sell";
839 $sql .=
", accountancy_code_sell_intra";
840 $sql .=
", accountancy_code_sell_export";
843 $sql .=
", finished";
845 $sql .=
", sell_or_eat_by_mandatory";
846 $sql .=
", batch_mask";
848 $sql .=
", mandatory_period";
849 $sql .=
") VALUES (";
850 $sql .=
"'".$this->db->idate($this->date_creation).
"'";
851 $sql .=
", ".(!empty($this->entity) ? (int) $this->entity : (int) $conf->entity);
852 $sql .=
", '".$this->db->escape($this->
ref).
"'";
853 $sql .=
", ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
854 $sql .=
", ".price2num($price_min_ht);
855 $sql .=
", ".price2num($price_min_ttc);
856 $sql .=
", ".(!empty($this->label) ?
"'".$this->db->escape($this->label).
"'" :
"null");
857 $sql .=
", ".((int) $user->id);
858 $sql .=
", ".((int) $this->
type);
859 $sql .=
", ".price2num($price_ht,
'MT');
860 $sql .=
", ".price2num($price_ttc,
'MT');
861 $sql .=
", '".$this->db->escape($this->price_base_type).
"'";
862 $sql .=
", ".(!empty($this->price_label) ?
"'".$this->db->escape($this->price_label).
"'" :
"null");
863 $sql .=
", ".((int) $this->
status);
864 $sql .=
", ".((int) $this->status_buy);
866 $sql .=
", '".$this->db->escape($this->accountancy_code_buy).
"'";
867 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_intra).
"'";
868 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_export).
"'";
869 $sql .=
", '".$this->db->escape($this->accountancy_code_sell).
"'";
870 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_intra).
"'";
871 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_export).
"'";
873 $sql .=
", '".$this->db->escape($this->canvas).
"'";
874 $sql .=
", ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
'NULL' : (int) $this->finished);
875 $sql .=
", ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : ((int) $this->status_batch));
876 $sql .=
", ".((empty($this->sell_or_eat_by_mandatory) || $this->sell_or_eat_by_mandatory < 0) ? 0 : ((int) $this->sell_or_eat_by_mandatory));
877 $sql .=
", '".$this->db->escape($this->batch_mask).
"'";
878 $sql .=
", ".($this->fk_unit > 0 ? ((int) $this->fk_unit) :
'NULL');
879 $sql .=
", '".$this->db->escape($this->mandatory_period).
"'";
882 dol_syslog(get_class($this).
"::Create", LOG_DEBUG);
884 $result = $this->db->query($sql);
886 $id = $this->db->last_insert_id($this->db->prefix().
"product");
890 $this->
price = $price_ht;
891 $this->price_ttc = $price_ttc;
892 $this->price_min = $price_min_ht;
893 $this->price_min_ttc = $price_min_ttc;
897 if ($this->
update($id, $user,
true,
'add') <= 0) {
902 $this->error = $this->db->lasterror();
907 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " .((int) $this->id) .
" AND entity = " . ((
int) $conf->entity));
909 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
910 $sql .=
" fk_product";
912 $sql .=
", accountancy_code_buy";
913 $sql .=
", accountancy_code_buy_intra";
914 $sql .=
", accountancy_code_buy_export";
915 $sql .=
", accountancy_code_sell";
916 $sql .=
", accountancy_code_sell_intra";
917 $sql .=
", accountancy_code_sell_export";
918 $sql .=
") VALUES (";
920 $sql .=
", " . $conf->entity;
921 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
922 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
923 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
924 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
925 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
926 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
928 $result = $this->db->query($sql);
931 $this->error =
'ErrorFailedToInsertAccountancyForEntity';
936 $this->error =
'ErrorFailedToGetInsertedId';
940 $this->error = $this->db->lasterror();
944 $langs->load(
"products");
946 $this->error =
"ErrorProductAlreadyExists";
947 dol_syslog(get_class($this).
"::Create fails, ref ".$this->
ref.
" already exists");
951 $this->error = $this->db->lasterror();
954 if (!$error && !$notrigger) {
967 $this->db->rollback();
971 $this->db->rollback();
972 dol_syslog(get_class($this).
"::Create fails verify ".implode(
',', $this->errors), LOG_WARNING);
988 $this->errors = array();
991 $this->
ref = trim($this->
ref);
994 $this->errors[] =
'ErrorBadRef';
998 $arrayofnonnegativevalue = array(
'weight' =>
'Weight',
'width' =>
'Width',
'height' =>
'Height',
'length' =>
'Length',
'surface' =>
'Surface',
'volume' =>
'Volume');
999 foreach ($arrayofnonnegativevalue as $key => $value) {
1000 if (property_exists($this, $key) && !empty($this->$key) && ($this->$key < 0)) {
1001 $langs->loadLangs(array(
"main",
"other"));
1002 $this->error = $langs->trans(
"FieldCannotBeNegative", $langs->transnoentitiesnoconv($value));
1003 $this->errors[] = $this->error;
1008 $rescode = $this->
check_barcode($this->barcode, $this->barcode_type_code);
1010 if ($rescode == -1) {
1011 $this->errors[] =
'ErrorBadBarCodeSyntax';
1012 } elseif ($rescode == -2) {
1013 $this->errors[] =
'ErrorBarCodeRequired';
1014 } elseif ($rescode == -3) {
1016 $this->errors[] =
'ErrorBarCodeAlreadyUsed';
1043 $dirsociete = array_merge(array(
'/core/modules/barcode/'), $conf->modules_parts[
'barcode']);
1044 foreach ($dirsociete as $dirroot) {
1051 $mod =
new $module();
1052 '@phan-var-force ModeleNumRefBarCode $mod';
1054 dol_syslog(get_class($this).
"::check_barcode value=".$valuetotest.
" type=".$typefortest.
" module=".$module);
1055 $result = $mod->verif($this->db, $valuetotest, $this, 0, $typefortest);
1073 public function update($id, $user, $notrigger = 0, $action =
'update', $updatetype =
false)
1075 global $langs, $conf, $hookmanager;
1080 if (!$this->label) {
1081 $this->label =
'MISSING LABEL';
1086 $this->
ref = trim($this->
ref);
1090 $this->label = trim($this->label);
1092 $this->note_private = (isset($this->note_private) ? trim($this->note_private) :
null);
1093 $this->note_public = (isset($this->note_public) ? trim($this->note_public) :
null);
1094 $this->net_measure =
price2num($this->net_measure);
1095 $this->net_measure_units = (empty($this->net_measure_units) ?
'' : trim($this->net_measure_units));
1096 $this->weight =
price2num($this->weight);
1097 $this->weight_units = (empty($this->weight_units) ?
'' : trim($this->weight_units));
1098 $this->length =
price2num($this->length);
1099 $this->length_units = (empty($this->length_units) ?
'' : trim($this->length_units));
1101 $this->width_units = (empty($this->width_units) ?
'' : trim($this->width_units));
1102 $this->height =
price2num($this->height);
1103 $this->height_units = (empty($this->height_units) ?
'' : trim($this->height_units));
1104 $this->surface =
price2num($this->surface);
1105 $this->surface_units = (empty($this->surface_units) ?
'' : trim($this->surface_units));
1106 $this->volume =
price2num($this->volume);
1107 $this->volume_units = (empty($this->volume_units) ?
'' : trim($this->volume_units));
1110 if (is_numeric($this->length_units)) {
1111 $this->width_units = $this->length_units;
1113 if (is_numeric($this->length_units)) {
1114 $this->height_units = $this->length_units;
1118 if (empty($this->surface) && !empty($this->length) && !empty($this->width) && $this->length_units == $this->width_units) {
1119 $this->surface = (float) $this->length * (
float) $this->width;
1122 if (empty($this->volume) && !empty($this->surface) && !empty($this->height) && $this->length_units == $this->height_units) {
1123 $this->volume = $this->surface * (float) $this->height;
1127 if (empty($this->tva_tx)) {
1130 if (empty($this->tva_npr)) {
1133 if (empty($this->localtax1_tx)) {
1134 $this->localtax1_tx = 0;
1136 if (empty($this->localtax2_tx)) {
1137 $this->localtax2_tx = 0;
1139 if (empty($this->localtax1_type)) {
1140 $this->localtax1_type =
'0';
1142 if (empty($this->localtax2_type)) {
1143 $this->localtax2_type =
'0';
1145 if (empty($this->
status)) {
1148 if (empty($this->status_buy)) {
1149 $this->status_buy = 0;
1152 if (empty($this->country_id)) {
1153 $this->country_id = 0;
1156 if (empty($this->state_id)) {
1157 $this->state_id = 0;
1161 $this->barcode = (empty($this->barcode) ?
'' : trim($this->barcode));
1163 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
1164 $this->accountancy_code_buy_intra = (!empty($this->accountancy_code_buy_intra) ? trim($this->accountancy_code_buy_intra) :
'');
1165 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
1166 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
1167 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
1168 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
1175 if ($action !=
'add') {
1176 $result = $this->
verify();
1184 if (is_null($this->oldcopy) || (is_object($this->oldcopy) && $this->oldcopy->isEmpty())) {
1189 if ($this->
hasbatch() && !$this->oldcopy->hasbatch()) {
1191 $valueforundefinedlot =
'000000';
1196 dol_syslog(
"Flag batch of product id=".$this->
id.
" is set to ON, so we will create missing records into product_batch");
1199 foreach ($this->stock_warehouse as $idW => $ObjW) {
1201 foreach ($ObjW->detail_batch as $detail) {
1202 if ($detail->batch == $valueforundefinedlot || $detail->batch ==
'Undefined') {
1204 $sqlclean =
"DELETE FROM ".$this->db->prefix().
"product_batch WHERE batch in('Undefined', '".$this->db->escape($valueforundefinedlot).
"') AND fk_product_stock = ".((int) $ObjW->id);
1205 $result = $this->db->query($sqlclean);
1213 $qty_batch += $detail->qty;
1217 if ($ObjW->real != $qty_batch) {
1219 $ObjBatch->batch = $valueforundefinedlot;
1220 $ObjBatch->qty = ($ObjW->real - $qty_batch);
1221 $ObjBatch->fk_product_stock = $ObjW->id;
1223 if ($ObjBatch->create($user, 1) < 0) {
1225 $this->errors = $ObjBatch->errors;
1230 if ($ObjLot->fetch(0, $this->id, $valueforundefinedlot) == 0) {
1231 $ObjLot->fk_product = $this->id;
1232 $ObjLot->entity = $this->entity;
1233 $ObjLot->fk_user_creat = $user->id;
1234 $ObjLot->batch = $valueforundefinedlot;
1235 if ($ObjLot->create($user,
true) < 0) {
1237 $this->errors = $ObjLot->errors;
1246 if ($this->barcode == -1) {
1247 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1250 $sql =
"UPDATE ".$this->db->prefix().
"product";
1251 $sql .=
" SET label = '".$this->db->escape($this->label).
"'";
1254 $sql .=
", fk_product_type = ".((int) $this->
type);
1257 $sql .=
", ref = '".$this->db->escape($this->
ref).
"'";
1258 $sql .=
", ref_ext = ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1259 $sql .=
", default_vat_code = ".($this->default_vat_code ?
"'".$this->db->escape($this->default_vat_code).
"'" :
"null");
1260 $sql .=
", tva_tx = ".((float) $this->tva_tx);
1261 $sql .=
", recuperableonly = ".((int) $this->tva_npr);
1262 $sql .=
", localtax1_tx = ".((float) $this->localtax1_tx);
1263 $sql .=
", localtax2_tx = ".((float) $this->localtax2_tx);
1264 $sql .=
", localtax1_type = ".($this->localtax1_type !=
'' ?
"'".$this->db->escape($this->localtax1_type).
"'" :
"'0'");
1265 $sql .=
", localtax2_type = ".($this->localtax2_type !=
'' ?
"'".$this->db->escape($this->localtax2_type).
"'" :
"'0'");
1267 $sql .=
", barcode = ".(empty($this->barcode) ?
"null" :
"'".$this->db->escape($this->barcode).
"'");
1268 $sql .=
", fk_barcode_type = ".(empty($this->barcode_type) ?
"null" : $this->db->escape($this->barcode_type));
1270 $sql .=
", tosell = ".(int) $this->
status;
1271 $sql .=
", tobuy = ".(int) $this->status_buy;
1272 $sql .=
", tobatch = ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : (int) $this->status_batch);
1273 $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);
1274 $sql .=
", batch_mask = '".$this->db->escape($this->batch_mask).
"'";
1276 $sql .=
", finished = ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
"null" : (int) $this->finished);
1277 $sql .=
", fk_default_bom = ".((!isset($this->fk_default_bom) || $this->fk_default_bom < 0 || $this->fk_default_bom ==
'') ?
"null" : (int) $this->fk_default_bom);
1278 $sql .=
", net_measure = ".($this->net_measure !=
'' ?
"'".$this->db->escape($this->net_measure).
"'" :
'null');
1279 $sql .=
", net_measure_units = ".($this->net_measure_units !=
'' ?
"'".$this->db->escape($this->net_measure_units).
"'" :
'null');
1280 $sql .=
", weight = ".($this->weight !=
'' ?
"'".$this->db->escape($this->weight).
"'" :
'null');
1281 $sql .=
", weight_units = ".($this->weight_units !=
'' ?
"'".$this->db->escape($this->weight_units).
"'" :
'null');
1282 $sql .=
", length = ".($this->length !=
'' ?
"'".$this->db->escape($this->length).
"'" :
'null');
1283 $sql .=
", length_units = ".($this->length_units !=
'' ?
"'".$this->db->escape($this->length_units).
"'" :
'null');
1284 $sql .=
", width= ".($this->width !=
'' ?
"'".$this->db->escape($this->width).
"'" :
'null');
1285 $sql .=
", width_units = ".($this->width_units !=
'' ?
"'".$this->db->escape($this->width_units).
"'" :
'null');
1286 $sql .=
", height = ".($this->height !=
'' ?
"'".$this->db->escape($this->height).
"'" :
'null');
1287 $sql .=
", height_units = ".($this->height_units !=
'' ?
"'".$this->db->escape($this->height_units).
"'" :
'null');
1288 $sql .=
", surface = ".($this->surface !=
'' ?
"'".$this->db->escape($this->surface).
"'" :
'null');
1289 $sql .=
", surface_units = ".($this->surface_units !=
'' ?
"'".$this->db->escape($this->surface_units).
"'" :
'null');
1290 $sql .=
", volume = ".($this->volume !=
'' ?
"'".$this->db->escape($this->volume).
"'" :
'null');
1291 $sql .=
", volume_units = ".($this->volume_units !=
'' ?
"'".$this->db->escape($this->volume_units).
"'" :
'null');
1292 $sql .=
", fk_default_warehouse = ".($this->fk_default_warehouse > 0 ? ((int) $this->fk_default_warehouse) :
'null');
1293 $sql .=
", fk_default_workstation = ".($this->fk_default_workstation > 0 ? ((int) $this->fk_default_workstation) :
'null');
1294 $sql .=
", seuil_stock_alerte = ".((isset($this->seuil_stock_alerte) && is_numeric($this->seuil_stock_alerte)) ? (
float) $this->seuil_stock_alerte :
'null');
1295 $sql .=
", description = '".$this->db->escape($this->
description).
"'";
1296 $sql .=
", url = ".($this->url ?
"'".$this->db->escape($this->url).
"'" :
'null');
1297 $sql .=
", customcode = '".$this->db->escape($this->customcode).
"'";
1298 $sql .=
", fk_country = ".($this->country_id > 0 ? (int) $this->country_id :
'null');
1299 $sql .=
", fk_state = ".($this->state_id > 0 ? (int) $this->state_id :
'null');
1300 $sql .=
", lifetime = ".($this->lifetime > 0 ? (int) $this->lifetime :
'null');
1301 $sql .=
", qc_frequency = ".($this->qc_frequency > 0 ? (int) $this->qc_frequency :
'null');
1302 $sql .=
", note = ".(isset($this->note_private) ?
"'".$this->db->escape($this->note_private).
"'" :
'null');
1303 $sql .=
", note_public = ".(isset($this->note_public) ?
"'".$this->db->escape($this->note_public).
"'" :
'null');
1304 $sql .=
", duration = '".$this->db->escape($this->duration_value.$this->duration_unit).
"'";
1306 $sql .=
", accountancy_code_buy = '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1307 $sql .=
", accountancy_code_buy_intra = '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1308 $sql .=
", accountancy_code_buy_export = '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1309 $sql .=
", accountancy_code_sell= '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1310 $sql .=
", accountancy_code_sell_intra= '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1311 $sql .=
", accountancy_code_sell_export= '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1313 $sql .=
", desiredstock = ".((isset($this->desiredstock) && is_numeric($this->desiredstock)) ? (
float) $this->desiredstock :
"null");
1314 $sql .=
", cost_price = ".($this->cost_price !=
'' ? $this->db->escape($this->cost_price) :
'null');
1315 $sql .=
", fk_unit= ".(!$this->fk_unit ?
'NULL' : (int) $this->fk_unit);
1316 $sql .=
", price_autogen = ".(!$this->price_autogen ? 0 : 1);
1317 $sql .=
", fk_price_expression = ".($this->fk_price_expression != 0 ? (int) $this->fk_price_expression :
'NULL');
1318 $sql .=
", fk_user_modif = ".($user->id > 0 ? $user->id :
'NULL');
1319 $sql .=
", mandatory_period = ".($this->mandatory_period);
1321 $sql .=
" WHERE rowid = ".((int) $id);
1323 dol_syslog(get_class($this).
"::update", LOG_DEBUG);
1325 $resql = $this->db->query($sql);
1332 $this->db->rollback();
1341 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " . ((
int) $this->id) .
" AND entity = " . ((
int) $conf->entity));
1343 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1344 $sql .=
" fk_product";
1346 $sql .=
", accountancy_code_buy";
1347 $sql .=
", accountancy_code_buy_intra";
1348 $sql .=
", accountancy_code_buy_export";
1349 $sql .=
", accountancy_code_sell";
1350 $sql .=
", accountancy_code_sell_intra";
1351 $sql .=
", accountancy_code_sell_export";
1352 $sql .=
") VALUES (";
1354 $sql .=
", " . $conf->entity;
1355 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1356 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1357 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1358 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1359 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1360 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1362 $result = $this->db->query($sql);
1365 $this->error =
'ErrorFailedToUpdateAccountancyForEntity';
1369 if (!$this->
hasbatch() && $this->oldcopy->hasbatch()) {
1371 $sql =
'SELECT pb.qty, ps.fk_entrepot, pb.batch FROM '.MAIN_DB_PREFIX.
'product_batch as pb';
1372 $sql .=
' INNER JOIN '.MAIN_DB_PREFIX.
'product_stock as ps ON (ps.rowid = pb.fk_product_stock)';
1373 $sql .=
' WHERE ps.fk_product = '.(int) $this->
id;
1375 $resql = $this->db->query($sql);
1379 while ($obj = $this->db->fetch_object($resql)) {
1381 $fk_entrepot = $obj->fk_entrepot;
1385 $batch = $obj->batch;
1388 $addOremove = $value > 0 ? 1 : 0;
1389 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1390 $res = $this->
correct_stock_batch($user, $fk_entrepot, abs($value), $addOremove, $label, $price, $dlc, $dluo, $batch, $inventorycode,
'',
null, 0,
null,
true);
1393 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1394 $res = $this->
correct_stock($user, $fk_entrepot, abs($value), (
int) empty($addOremove), $label, $price, $inventorycode,
'',
null, 0);
1413 if (!$error && !$notrigger) {
1415 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
1422 if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) {
1424 if ($conf->product->dir_output) {
1427 if (file_exists($olddir)) {
1431 $res = @rename($olddir, $newdir);
1433 $langs->load(
"errors");
1434 $this->error = $langs->trans(
'ErrorFailToRenameDir', $olddir, $newdir);
1442 if (isModEnabled(
'variants')) {
1443 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1447 foreach ($comb->fetchAllByFkProductParent($this->id) as $currcomb) {
1448 $currcomb->updateProperties($this, $user);
1452 $this->db->commit();
1455 $this->db->rollback();
1459 if ($this->db->errno() ==
'DB_ERROR_RECORD_ALREADY_EXISTS') {
1460 $langs->load(
"errors");
1461 if (empty($conf->barcode->enabled) || empty($this->barcode)) {
1462 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductAlreadyExists", $this->
ref);
1464 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductBarCodeAlreadyExists", $this->barcode);
1466 $this->errors[] = $this->error;
1467 $this->db->rollback();
1470 $this->error = $langs->trans(
"Error").
" : ".$this->db->error().
" - ".$sql;
1471 $this->errors[] = $this->error;
1472 $this->db->rollback();
1477 $this->db->rollback();
1478 dol_syslog(get_class($this).
"::Update fails verify ".implode(
',', $this->errors), LOG_WARNING);
1490 public function delete(
User $user, $notrigger = 0)
1492 global $conf, $langs;
1493 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
1498 if (empty($this->
id)) {
1499 $this->error =
"Object must be fetched before calling delete";
1503 $this->error =
"ErrorForbidden";
1508 if (empty($objectisused)) {
1511 if (!$error && empty($notrigger)) {
1513 $result = $this->
call_trigger(
'PRODUCT_DELETE', $user);
1522 $sql =
"DELETE FROM ".$this->db->prefix().
'product_batch';
1523 $sql .=
" WHERE fk_product_stock IN (";
1524 $sql .=
"SELECT rowid FROM ".$this->db->prefix().
'product_stock';
1525 $sql .=
" WHERE fk_product = ".((int) $this->
id).
")";
1527 $result = $this->db->query($sql);
1530 $this->errors[] = $this->db->lasterror();
1536 $elements = array(
'product_fournisseur_price',
'product_price',
'product_lang',
'categorie_product',
'product_stock',
'product_customer_price',
'product_lot');
1537 foreach ($elements as $table) {
1539 $sql =
"DELETE FROM ".$this->db->prefix().$table;
1540 $sql .=
" WHERE fk_product = ".(int) $this->
id;
1542 $result = $this->db->query($sql);
1545 $this->errors[] = $this->db->lasterror();
1552 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1553 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination2ValuePair.class.php';
1558 if ($prodcomb->deleteByFkProductParent($user, $this->id) < 0) {
1560 $this->errors[] =
'Error deleting combinations';
1564 if (!$error && ($prodcomb->fetchByFkProductChild($this->id) > 0) && ($prodcomb->delete($user) < 0)) {
1566 $this->errors[] =
'Error deleting child combination';
1572 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
1573 $sql .=
" WHERE fk_product_pere = ".(int) $this->
id.
" OR fk_product_fils = ".(
int) $this->id;
1575 $result = $this->db->query($sql);
1578 $this->errors[] = $this->db->lasterror();
1587 dol_syslog(get_class($this).
"::delete error -4 ".$this->error, LOG_ERR);
1593 $sqlz =
"DELETE FROM ".$this->db->prefix().
"product";
1594 $sqlz .=
" WHERE rowid = ".(int) $this->
id;
1596 $resultz = $this->db->query($sqlz);
1599 $this->errors[] = $this->db->lasterror();
1615 if ($conf->product->dir_output) {
1616 $dir = $conf->product->dir_output.
"/".$ref;
1617 if (file_exists($dir)) {
1620 $this->errors[] =
'ErrorFailToDeleteDir';
1628 $this->db->commit();
1631 foreach ($this->errors as $errmsg) {
1632 dol_syslog(get_class($this).
"::delete ".$errmsg, LOG_ERR);
1633 $this->error .= ($this->error ?
', '.$errmsg : $errmsg);
1635 $this->db->rollback();
1639 $this->error =
"ErrorRecordIsUsedCantDelete";
1653 $sellByLabel = $langs->trans(
'SellByDate');
1654 $eatByLabel = $langs->trans(
'EatByDate');
1656 self::SELL_OR_EAT_BY_MANDATORY_ID_NONE => $langs->trans(
'BatchSellOrEatByMandatoryNone'),
1657 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY => $sellByLabel,
1658 self::SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY => $eatByLabel,
1659 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT => $langs->trans(
'BatchSellOrEatByMandatoryAll', $sellByLabel, $eatByLabel),
1670 $sellOrEatByMandatoryLabel =
'';
1673 if (isset($sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory])) {
1674 $sellOrEatByMandatoryLabel = $sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory];
1677 return $sellOrEatByMandatoryLabel;
1688 global $conf, $langs;
1690 $langs_available = $langs->get_available_languages(DOL_DOCUMENT_ROOT, 0, 2);
1691 $current_lang = $langs->getDefaultLang();
1693 foreach ($langs_available as $key => $value) {
1694 if ($key == $current_lang) {
1695 $sql =
"SELECT rowid";
1696 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1697 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1698 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
1700 $result = $this->db->query($sql);
1702 if ($this->db->num_rows($result)) {
1703 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
1705 $sql2 .=
" label='".$this->db->escape($this->label).
"',";
1706 $sql2 .=
" description='".$this->db->escape($this->
description).
"'";
1708 $sql2 .=
", note='".$this->db->escape($this->other).
"'";
1710 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
1712 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
1717 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->label).
"',";
1718 $sql2 .=
" '".$this->db->escape($this->
description).
"'";
1720 $sql2 .=
", '".$this->db->escape($this->other).
"'";
1724 dol_syslog(get_class($this).
'::setMultiLangs key = current_lang = '.$key);
1725 if (!$this->db->query($sql2)) {
1726 $this->error = $this->db->lasterror();
1729 } elseif (isset($this->multilangs[$key])) {
1730 if (empty($this->multilangs[
"$key"][
"label"])) {
1731 $this->errors[] = $key .
' : ' . $langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Label"));
1735 $sql =
"SELECT rowid";
1736 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1737 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1738 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
1740 $result = $this->db->query($sql);
1742 if ($this->db->num_rows($result)) {
1743 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
1745 $sql2 .=
" label = '".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
1746 $sql2 .=
" description = '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
1748 $sql2 .=
", note = '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
1750 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
1752 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
1757 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
1758 $sql2 .=
" '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
1760 $sql2 .=
", '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
1766 if ($this->multilangs[
"$key"][
"label"] || $this->multilangs[
"$key"][
"description"]) {
1767 if (!$this->db->query($sql2)) {
1768 $this->error = $this->db->lasterror();
1778 $result = $this->
call_trigger(
'PRODUCT_SET_MULTILANGS', $user);
1780 $this->error = $this->db->lasterror();
1798 $sql =
"DELETE FROM ".$this->db->prefix().
"product_lang";
1799 $sql .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($langtodelete).
"'";
1801 dol_syslog(get_class($this).
'::delMultiLangs', LOG_DEBUG);
1802 $result = $this->db->query($sql);
1805 $result = $this->
call_trigger(
'PRODUCT_DEL_MULTILANGS', $user);
1807 $this->error = $this->db->lasterror();
1808 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
1814 $this->error = $this->db->lasterror();
1815 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
1830 global $user, $langs, $conf;
1836 if ($type ==
'buy') {
1837 $field =
'accountancy_code_buy';
1838 } elseif ($type ==
'buy_intra') {
1839 $field =
'accountancy_code_buy_intra';
1840 } elseif ($type ==
'buy_export') {
1841 $field =
'accountancy_code_buy_export';
1842 } elseif ($type ==
'sell') {
1843 $field =
'accountancy_code_sell';
1844 } elseif ($type ==
'sell_intra') {
1845 $field =
'accountancy_code_sell_intra';
1846 } elseif ($type ==
'sell_export') {
1847 $field =
'accountancy_code_sell_export';
1852 $sql =
"UPDATE ".$this->db->prefix().$this->table_element.
" SET ";
1853 $sql .=
"$field = '".$this->db->escape($value).
"'";
1854 $sql .=
" WHERE rowid = ".((int) $this->
id);
1857 $resql = $this->db->query($sql);
1861 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
1868 $this->db->rollback();
1872 $this->$field = $value;
1874 $this->db->commit();
1877 $this->error = $this->db->lasterror();
1878 $this->db->rollback();
1892 $current_lang = $langs->getDefaultLang();
1894 $sql =
"SELECT lang, label, description, note as other";
1895 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1896 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1898 $result = $this->db->query($sql);
1900 while ($obj = $this->db->fetch_object($result)) {
1902 if ($obj->lang == $current_lang) {
1903 $this->label = $obj->label;
1905 $this->other = $obj->other;
1907 $this->multilangs[(string) $obj->lang][
"label"] = $obj->label;
1908 $this->multilangs[(string) $obj->lang][
"description"] = $obj->description;
1909 $this->multilangs[(string) $obj->lang][
"other"] = $obj->other;
1913 $this->error =
"Error: ".$this->db->lasterror().
" - ".$sql;
1926 $testExit = array(
'multiprices',
'multiprices_ttc',
'multiprices_base_type',
'multiprices_min',
'multiprices_min_ttc',
'multiprices_tva_tx',
'multiprices_recuperableonly');
1928 foreach ($testExit as $field) {
1929 if (!isset($this->$field)) {
1932 $tmparray = $this->$field;
1933 if (!isset($tmparray[$level])) {
1939 'level' => $level ? $level : 1,
1940 'multiprices' => (float) $this->multiprices[$level],
1941 'multiprices_ttc' => (
float) $this->multiprices_ttc[$level],
1942 'multiprices_base_type' => $this->multiprices_base_type[$level],
1943 'multiprices_min' => (float) $this->multiprices_min[$level],
1944 'multiprices_min_ttc' => (
float) $this->multiprices_min_ttc[$level],
1945 'multiprices_tva_tx' => (float) $this->multiprices_tva_tx[$level],
1946 'multiprices_recuperableonly' => (
float) $this->multiprices_recuperableonly[$level],
1969 if (empty($this->price_by_qty)) {
1970 $this->price_by_qty = 0;
1974 $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,";
1975 $sql .=
" localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, price_min,price_min_ttc,price_by_qty,entity,fk_price_expression) ";
1976 $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).
",";
1977 $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');
1980 dol_syslog(get_class($this).
"::_log_price", LOG_DEBUG);
1981 $resql = $this->db->query($sql);
1983 $this->error = $this->db->lasterror();
2003 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price_by_qty";
2004 $sql .=
" WHERE fk_product_price = ".((int) $rowid);
2005 $resql = $this->db->query($sql);
2007 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price";
2008 $sql .=
" WHERE rowid=".((int) $rowid);
2009 $resql = $this->db->query($sql);
2013 $this->error = $this->db->lasterror();
2028 public function getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp = 0)
2030 global $conf, $hookmanager, $action;
2033 if (is_object($hookmanager)) {
2034 $parameters = array(
'thirdparty_seller' => $thirdparty_seller,
'thirdparty_buyer' => $thirdparty_buyer,
'pqp' => $pqp);
2036 $reshook = $hookmanager->executeHooks(
'getSellPrice', $parameters, $this, $action);
2038 return $hookmanager->resArray;
2049 $pu_ht = $this->price;
2050 $pu_ttc = $this->price_ttc;
2051 $price_min = $this->price_min;
2052 $price_base_type = $this->price_base_type;
2055 if (
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !empty($thirdparty_buyer->price_level)) {
2056 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
2057 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
2058 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
2059 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
2061 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2062 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2064 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2065 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2073 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2077 $filter = array(
't.fk_product' => $this->
id,
't.fk_soc' => $thirdparty_buyer->id);
2079 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2081 if (count($prodcustprice->lines) > 0) {
2082 $pu_ht =
price($prodcustprice->lines[0]->price);
2083 $price_min =
price($prodcustprice->lines[0]->price_min);
2084 $pu_ttc =
price($prodcustprice->lines[0]->price_ttc);
2085 $price_base_type = $prodcustprice->lines[0]->price_base_type;
2086 $tva_tx = $prodcustprice->lines[0]->tva_tx;
2087 if ($prodcustprice->lines[0]->default_vat_code && !preg_match(
'/\(.*\)/',
$tva_tx)) {
2088 $tva_tx .=
' ('.$prodcustprice->lines[0]->default_vat_code.
')';
2090 $tva_npr = $prodcustprice->lines[0]->recuperableonly;
2098 if ($this->prices_by_qty[0]) {
2101 foreach ($this->prices_by_qty_list[0] as $priceforthequantityarray) {
2102 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2106 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2107 $pu_ht = $priceforthequantityarray[
'unitprice'];
2109 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2116 if ($this->prices_by_qty[$thirdparty_buyer->price_level]) {
2119 foreach ($this->prices_by_qty_list[$thirdparty_buyer->price_level] as $priceforthequantityarray) {
2120 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2124 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2125 $pu_ht = $priceforthequantityarray[
'unitprice'];
2127 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2134 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);
2151 public function get_buyprice($prodfournprice, $qty, $product_id = 0, $fourn_ref =
'', $fk_soc = 0)
2154 global $action, $hookmanager;
2157 if (is_object($hookmanager)) {
2158 $parameters = array(
2159 'prodfournprice' => $prodfournprice,
2161 'product_id' => $product_id,
2162 'fourn_ref' => $fourn_ref,
2163 'fk_soc' => $fk_soc,
2166 $reshook = $hookmanager->executeHooks(
'getBuyPrice', $parameters, $this, $action);
2168 return $hookmanager->resArray;
2175 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2176 $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,";
2177 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2178 $sql .=
" pfp.packaging";
2179 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2180 $sql .=
" WHERE pfp.rowid = ".((int) $prodfournprice);
2182 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2184 $sql .=
" ORDER BY pfp.quantity DESC";
2186 dol_syslog(get_class($this).
"::get_buyprice first search by prodfournprice/qty", LOG_DEBUG);
2187 $resql = $this->db->query($sql);
2189 $obj = $this->db->fetch_object($resql);
2190 if ($obj && $obj->quantity > 0) {
2191 if (isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2193 $prod_supplier->product_fourn_price_id = $obj->rowid;
2194 $prod_supplier->id = $obj->fk_product;
2195 $prod_supplier->fourn_qty = $obj->quantity;
2196 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2197 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2199 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2201 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2202 if ($price_result >= 0) {
2203 $obj->price = $price_result;
2206 $this->product_fourn_price_id = $obj->rowid;
2207 $this->buyprice = $obj->price;
2208 $this->fourn_pu = $obj->price / $obj->quantity;
2209 $this->fourn_price_base_type =
'HT';
2210 $this->fourn_socid = $obj->fk_soc;
2211 $this->ref_fourn = $obj->ref_supplier;
2212 $this->ref_supplier = $obj->ref_supplier;
2213 $this->desc_supplier = $obj->desc_supplier;
2214 $this->remise_percent = $obj->remise_percent;
2215 $this->vatrate_supplier = $obj->tva_tx;
2216 $this->default_vat_code_supplier = $obj->default_vat_code;
2217 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2218 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2219 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2220 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2221 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2223 $this->packaging = $obj->packaging;
2225 $result = $obj->fk_product;
2229 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2230 $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,";
2231 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2232 $sql .=
" pfp.packaging";
2233 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2234 $sql .=
" WHERE 1 = 1";
2235 if ($product_id > 0) {
2236 $sql .=
" AND pfp.fk_product = ".((int) $product_id);
2238 if ($fourn_ref !=
'none') {
2239 $sql .=
" AND pfp.ref_fourn = '".$this->db->escape($fourn_ref).
"'";
2242 $sql .=
" AND pfp.fk_soc = ".((int) $fk_soc);
2245 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2247 $sql .=
" ORDER BY pfp.quantity DESC";
2250 dol_syslog(get_class($this).
"::get_buyprice second search from qty/ref/product_id", LOG_DEBUG);
2251 $resql = $this->db->query($sql);
2253 $obj = $this->db->fetch_object($resql);
2254 if ($obj && $obj->quantity > 0) {
2255 if (isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2257 $prod_supplier->product_fourn_price_id = $obj->rowid;
2258 $prod_supplier->id = $obj->fk_product;
2259 $prod_supplier->fourn_qty = $obj->quantity;
2260 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2261 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2263 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2265 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2267 $obj->price = $price_result;
2270 $this->product_fourn_price_id = $obj->rowid;
2271 $this->buyprice = $obj->price;
2272 $this->fourn_qty = $obj->quantity;
2273 $this->fourn_pu = $obj->price / $obj->quantity;
2274 $this->fourn_price_base_type =
'HT';
2275 $this->fourn_socid = $obj->fk_soc;
2276 $this->ref_fourn = $obj->ref_supplier;
2277 $this->ref_supplier = $obj->ref_supplier;
2278 $this->desc_supplier = $obj->desc_supplier;
2279 $this->remise_percent = $obj->remise_percent;
2280 $this->vatrate_supplier = $obj->tva_tx;
2281 $this->default_vat_code_supplier = $obj->default_vat_code;
2282 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2283 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2284 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2285 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2286 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2288 $this->packaging = $obj->packaging;
2290 $result = $obj->fk_product;
2296 $this->error = $this->db->lasterror();
2301 $this->error = $this->db->lasterror();
2325 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)
2327 global $conf, $langs;
2333 dol_syslog(get_class($this).
"::update_price id=".$id.
" newprice=".$newprice.
" newpricebase=".$newpricebase.
" newminprice=".$newminprice.
" level=".$level.
" npr=".$newnpr.
" newdefaultvatcode=".$newdefaultvatcode);
2336 if (empty($this->tva_tx)) {
2339 if (empty($newnpr)) {
2342 if (empty($newminprice)) {
2347 if ($newvat ===
null || $newvat ==
'') {
2353 if ((
getDolGlobalString(
'PRODUIT_MULTIPRICES') ||
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) && !$ignore_autogen && $this->price_autogen && ($level == 1)) {
2354 return $this->
generateMultiprices($user, $newprice, $newpricebase, $newvat, $newnpr, $newpbq);
2357 if (!empty($newminprice) && ($newminprice > $newprice)) {
2358 $this->error =
'ErrorPriceCantBeLowerThanMinPrice';
2362 if ($newprice !==
'' || $newprice === 0) {
2363 if ($newpricebase ==
'TTC') {
2364 $price_ttc = (float)
price2num($newprice,
'MU');
2365 $price = (float)
price2num($newprice) / (1 + ((float) $newvat / 100));
2366 $price = (float)
price2num($price,
'MU');
2368 if ($newminprice !=
'' || $newminprice == 0) {
2369 $price_min_ttc = (float)
price2num($newminprice,
'MU');
2370 $price_min = (float)
price2num($newminprice) / (1 + ($newvat / 100));
2371 $price_min = (float)
price2num($price_min,
'MU');
2377 $price = (float)
price2num($newprice,
'MU');
2378 $price_ttc = ($newnpr != 1) ?
price2num($newprice) * (1 + ($newvat / 100)) : $price;
2379 $price_ttc = (float)
price2num($price_ttc,
'MU');
2381 if ($newminprice !==
'' || $newminprice === 0) {
2382 $price_min = (float)
price2num($newminprice,
'MU');
2383 $price_min_ttc = (float)
price2num($newminprice) * (1 + ($newvat / 100));
2384 $price_min_ttc = (float)
price2num($price_min_ttc,
'MU');
2393 if (count($localtaxes_array) > 0) {
2394 $localtaxtype1 = $localtaxes_array[
'0'];
2395 $localtax1 = $localtaxes_array[
'1'];
2396 $localtaxtype2 = $localtaxes_array[
'2'];
2397 $localtax2 = $localtaxes_array[
'3'];
2400 if (!empty($newdefaultvatcode)) {
2403 $sql =
"SELECT t.rowid, t.code, t.recuperableonly as tva_npr, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
2404 $sql .=
" FROM ".MAIN_DB_PREFIX.
"c_tva as t, ".MAIN_DB_PREFIX.
"c_country as c";
2405 $sql .=
" WHERE t.fk_pays = c.rowid AND c.code = '".$this->db->escape($mysoc->country_code).
"'";
2406 $sql .=
" AND t.taux = ".((float) $newdefaultvatcode).
" AND t.active = 1";
2407 $sql .=
" AND t.code = '".$this->db->escape($newdefaultvatcode).
"'";
2408 $resql = $this->db->query($sql);
2410 $obj = $this->db->fetch_object($resql);
2412 $npr = $obj->tva_npr;
2413 $localtax1 = $obj->localtax1;
2414 $localtax2 = $obj->localtax2;
2415 $localtaxtype1 = $obj->localtax1_type;
2416 $localtaxtype2 = $obj->localtax2_type;
2421 $localtaxtype1 =
'0';
2423 $localtaxtype2 =
'0';
2427 if (empty($localtax1)) {
2430 if (empty($localtax2)) {
2438 $sql =
"UPDATE ".$this->db->prefix().
"product SET";
2439 $sql .=
" price_base_type = '".$this->db->escape($newpricebase).
"',";
2440 $sql .=
" price = ".(float) $price.
",";
2441 $sql .=
" price_ttc = ".(float) $price_ttc.
",";
2442 $sql .=
" price_min = ".(float) $price_min.
",";
2443 $sql .=
" price_min_ttc = ".(float) $price_min_ttc.
",";
2444 $sql .=
" localtax1_tx = ".($localtax1 >= 0 ? (float) $localtax1 :
'NULL').
",";
2445 $sql .=
" localtax2_tx = ".($localtax2 >= 0 ? (float) $localtax2 :
'NULL').
",";
2446 $sql .=
" localtax1_type = ".($localtaxtype1 !=
'' ?
"'".$this->db->escape($localtaxtype1).
"'" :
"'0'").
",";
2447 $sql .=
" localtax2_type = ".($localtaxtype2 !=
'' ?
"'".$this->db->escape($localtaxtype2).
"'" :
"'0'").
",";
2448 $sql .=
" default_vat_code = ".($newdefaultvatcode ?
"'".$this->db->escape($newdefaultvatcode).
"'" :
"null").
",";
2449 $sql .=
" price_label = ".(!empty($price_label) ?
"'".$this->db->escape($price_label).
"'" :
"null").
",";
2450 $sql .=
" tva_tx = ".(float)
price2num($newvat).
",";
2451 $sql .=
" recuperableonly = '".$this->db->escape($newnpr).
"'";
2452 $sql .=
" WHERE rowid = ".((int) $id);
2454 dol_syslog(get_class($this).
"::update_price", LOG_DEBUG);
2455 $resql = $this->db->query($sql);
2457 $this->multiprices[$level] = $price;
2458 $this->multiprices_ttc[$level] = $price_ttc;
2459 $this->multiprices_min[$level] = $price_min;
2460 $this->multiprices_min_ttc[$level] = $price_min_ttc;
2461 $this->multiprices_base_type[$level] = $newpricebase;
2462 $this->multiprices_default_vat_code[$level] = $newdefaultvatcode;
2463 $this->multiprices_tva_tx[$level] = $newvat;
2464 $this->multiprices_recuperableonly[$level] = $newnpr;
2466 $this->
price = $price;
2467 $this->price_label = $price_label;
2468 $this->price_ttc = $price_ttc;
2469 $this->price_min = $price_min;
2470 $this->price_min_ttc = $price_min_ttc;
2471 $this->price_base_type = $newpricebase;
2472 $this->default_vat_code = $newdefaultvatcode;
2473 $this->tva_tx = $newvat;
2474 $this->tva_npr = $newnpr;
2477 $this->localtax1_tx = $localtax1;
2478 $this->localtax2_tx = $localtax2;
2479 $this->localtax1_type = $localtaxtype1;
2480 $this->localtax2_type = $localtaxtype2;
2483 $this->price_by_qty = $newpbq;
2487 if (!empty(array_diff_assoc($newPriceData, $lastPriceData)) || !
getDolGlobalString(
'PRODUIT_MULTIPRICES')) {
2491 $this->level = $level;
2495 $result = $this->
call_trigger(
'PRODUCT_PRICE_MODIFY', $user);
2497 $this->db->rollback();
2503 $this->db->commit();
2505 $this->db->rollback();
2506 $this->error = $this->db->lasterror();
2525 $this->fk_price_expression = $expression_id;
2527 return $this->
update($this->
id, $user);
2542 public function fetch($id = 0, $ref =
'', $ref_ext =
'', $barcode =
'', $ignore_expression = 0, $ignore_price_load = 0, $ignore_lang_load = 0)
2544 include_once DOL_DOCUMENT_ROOT.
'/core/lib/company.lib.php';
2546 global $langs, $conf;
2548 dol_syslog(get_class($this).
"::fetch id=".$id.
" ref=".$ref.
" ref_ext=".$ref_ext);
2551 if (!$id && !$ref && !$ref_ext && !$barcode) {
2552 $this->error =
'ErrorWrongParameters';
2553 dol_syslog(get_class($this).
"::fetch ".$this->error, LOG_ERR);
2557 $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,";
2558 $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,";
2559 $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,";
2560 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.last_main_doc,";
2561 $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,";
2563 $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,";
2565 $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,";
2570 $separatedEntityPMP =
false;
2571 $separatedStock =
false;
2572 $visibleWarehousesEntities = $conf->entity;
2575 $checkPMPPerEntity = $this->db->query(
"SELECT pmp FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = ".((int) $id).
" AND entity = ".(
int) $conf->entity);
2576 if ($this->db->num_rows($checkPMPPerEntity) > 0) {
2577 $separatedEntityPMP =
true;
2581 $separatedStock =
true;
2582 if (isset($mc->sharings[
'stock']) && !empty($mc->sharings[
'stock'])) {
2583 $visibleWarehousesEntities .=
"," . implode(
",", $mc->sharings[
'stock']);
2586 if ($separatedEntityPMP) {
2587 $sql .=
" ppe.pmp,";
2591 $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,";
2592 $sql .=
" p.fk_price_expression, p.price_autogen, p.model_pdf,";
2593 $sql .=
" p.price_label,";
2594 if ($separatedStock) {
2595 $sql .=
" SUM(sp.reel) as stock";
2599 $sql .=
" FROM ".$this->db->prefix().
"product as p";
2601 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int) $conf->entity);
2603 if ($separatedStock) {
2604 $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).
"))";
2608 $sql .=
" WHERE p.rowid = ".((int) $id);
2610 $sql .=
" WHERE p.entity IN (".getEntity($this->element).
")";
2612 $sql .=
" AND p.ref = '".$this->db->escape($ref).
"'";
2613 } elseif ($ref_ext) {
2614 $sql .=
" AND p.ref_ext = '".$this->db->escape($ref_ext).
"'";
2615 } elseif ($barcode) {
2616 $sql .=
" AND p.barcode = '".$this->db->escape($barcode).
"'";
2619 if ($separatedStock) {
2620 $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,";
2621 $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,";
2622 $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,";
2623 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
2624 $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,";
2626 $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,";
2628 $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,";
2630 if ($separatedEntityPMP) {
2631 $sql .=
" ppe.pmp,";
2635 $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,";
2636 $sql .=
" p.fk_price_expression, p.price_autogen, p.model_pdf";
2637 $sql .=
" ,p.price_label";
2638 if (!$separatedStock) {
2639 $sql .=
", p.stock";
2643 $resql = $this->db->query($sql);
2645 unset($this->oldcopy);
2647 if ($this->db->num_rows($resql) > 0) {
2648 $obj = $this->db->fetch_object($resql);
2650 $this->
id = $obj->rowid;
2651 $this->
ref = $obj->ref;
2652 $this->ref_ext = $obj->ref_ext;
2653 $this->label = $obj->label;
2655 $this->url = $obj->url;
2656 $this->note_public = $obj->note_public;
2657 $this->note_private = $obj->note_private;
2658 $this->note = $obj->note_private;
2660 $this->
type = $obj->fk_product_type;
2661 $this->price_label = $obj->price_label;
2662 $this->
status = $obj->tosell;
2663 $this->status_buy = $obj->tobuy;
2664 $this->status_batch = $obj->tobatch;
2665 $this->sell_or_eat_by_mandatory = $obj->sell_or_eat_by_mandatory;
2666 $this->batch_mask = $obj->batch_mask;
2668 $this->customcode = $obj->customcode;
2669 $this->country_id = $obj->fk_country;
2670 $this->country_code =
getCountry($this->country_id, 2, $this->db);
2671 $this->state_id = $obj->fk_state;
2672 $this->lifetime = $obj->lifetime;
2673 $this->qc_frequency = $obj->qc_frequency;
2674 $this->
price = $obj->price;
2675 $this->price_ttc = $obj->price_ttc;
2676 $this->price_min = $obj->price_min;
2677 $this->price_min_ttc = $obj->price_min_ttc;
2678 $this->price_base_type = $obj->price_base_type;
2679 $this->cost_price = $obj->cost_price;
2680 $this->default_vat_code = $obj->default_vat_code;
2681 $this->tva_tx = $obj->tva_tx;
2683 $this->tva_npr = $obj->tva_npr;
2685 $this->localtax1_tx = $obj->localtax1_tx;
2686 $this->localtax2_tx = $obj->localtax2_tx;
2687 $this->localtax1_type = $obj->localtax1_type;
2688 $this->localtax2_type = $obj->localtax2_type;
2690 $this->finished = $obj->finished;
2691 $this->fk_default_bom = $obj->fk_default_bom;
2693 $this->duration = $obj->duration;
2694 $this->duration_value = $obj->duration ? (int) (substr($obj->duration, 0,
dol_strlen($obj->duration) - 1)) : 0;
2695 $this->duration_unit = $obj->duration ? substr($obj->duration, -1) :
null;
2696 $this->canvas = $obj->canvas;
2697 $this->net_measure = $obj->net_measure;
2698 $this->net_measure_units = $obj->net_measure_units;
2699 $this->weight = $obj->weight;
2700 $this->weight_units = $obj->weight_units;
2701 $this->length = $obj->length;
2702 $this->length_units = $obj->length_units;
2703 $this->width = $obj->width;
2704 $this->width_units = $obj->width_units;
2705 $this->height = $obj->height;
2706 $this->height_units = $obj->height_units;
2708 $this->surface = $obj->surface;
2709 $this->surface_units = $obj->surface_units;
2710 $this->volume = $obj->volume;
2711 $this->volume_units = $obj->volume_units;
2712 $this->barcode = $obj->barcode;
2713 $this->barcode_type = $obj->fk_barcode_type;
2715 $this->accountancy_code_buy = $obj->accountancy_code_buy;
2716 $this->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra;
2717 $this->accountancy_code_buy_export = $obj->accountancy_code_buy_export;
2718 $this->accountancy_code_sell = $obj->accountancy_code_sell;
2719 $this->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra;
2720 $this->accountancy_code_sell_export = $obj->accountancy_code_sell_export;
2722 $this->fk_default_warehouse = $obj->fk_default_warehouse;
2723 $this->fk_default_workstation = $obj->fk_default_workstation;
2724 $this->seuil_stock_alerte = $obj->seuil_stock_alerte;
2725 $this->desiredstock = $obj->desiredstock;
2726 $this->stock_reel = $obj->stock;
2727 $this->pmp = $obj->pmp;
2729 $this->date_creation = $obj->datec;
2730 $this->date_modification = $obj->tms;
2731 $this->import_key = $obj->import_key;
2732 $this->entity = $obj->entity;
2734 $this->ref_ext = $obj->ref_ext;
2735 $this->fk_price_expression = $obj->fk_price_expression;
2736 $this->fk_unit = $obj->fk_unit;
2737 $this->price_autogen = $obj->price_autogen;
2738 $this->model_pdf = $obj->model_pdf;
2739 $this->last_main_doc = $obj->last_main_doc;
2741 $this->mandatory_period = $obj->mandatory_period;
2743 $this->db->free($resql);
2755 for ($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) {
2756 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
2757 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
2758 $sql .=
" ,price_label";
2759 $sql .=
" FROM ".$this->db->prefix().
"product_price";
2760 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
2761 $sql .=
" AND price_level=".((int) $i);
2762 $sql .=
" AND fk_product = ".((int) $this->
id);
2763 $sql .=
" ORDER BY date_price DESC, rowid DESC";
2765 $resql = $this->db->query($sql);
2767 $result = $this->db->fetch_array($resql);
2769 $this->multiprices[$i] = $result ? $result[
"price"] :
null;
2770 $this->multiprices_ttc[$i] = $result ? $result[
"price_ttc"] :
null;
2771 $this->multiprices_min[$i] = $result ? $result[
"price_min"] :
null;
2772 $this->multiprices_min_ttc[$i] = $result ? $result[
"price_min_ttc"] :
null;
2773 $this->multiprices_base_type[$i] = $result ? $result[
"price_base_type"] :
null;
2775 $this->multiprices_tva_tx[$i] = $result ? $result[
"tva_tx"].($result ?
' ('.$result[
'default_vat_code'].
')' :
'') :
null;
2776 $this->multiprices_recuperableonly[$i] = $result ? $result[
"recuperableonly"] :
null;
2815 $this->error = $this->db->lasterror;
2819 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES') && empty($ignore_price_load)) {
2821 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY') && empty($ignore_price_load)) {
2822 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
2823 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid";
2824 $sql .=
" FROM ".$this->db->prefix().
"product_price";
2825 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2826 $sql .=
" ORDER BY date_price DESC, rowid DESC";
2829 $resql = $this->db->query($sql);
2831 $result = $this->db->fetch_array($resql);
2835 $this->prices_by_qty[0] = $result[
"price_by_qty"];
2836 $this->prices_by_qty_id[0] = $result[
"rowid"];
2838 if ($this->prices_by_qty[0] == 1) {
2839 $sql =
"SELECT rowid,price, unitprice, quantity, remise_percent, remise, remise, price_base_type";
2840 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
2841 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[0]);
2842 $sql .=
" ORDER BY quantity ASC";
2844 $resql = $this->db->query($sql);
2846 $resultat = array();
2848 while ($result = $this->db->fetch_array($resql)) {
2849 $resultat[$ii] = array();
2850 $resultat[$ii][
"rowid"] = $result[
"rowid"];
2851 $resultat[$ii][
"price"] = $result[
"price"];
2852 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
2853 $resultat[$ii][
"quantity"] = $result[
"quantity"];
2854 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
2856 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
2859 $this->prices_by_qty_list[0] = $resultat;
2861 $this->error = $this->db->lasterror;
2867 $this->error = $this->db->lasterror;
2870 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') && empty($ignore_price_load)) {
2871 for ($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) {
2872 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
2873 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
2874 $sql .=
" FROM ".$this->db->prefix().
"product_price";
2875 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
2876 $sql .=
" AND price_level=".((int) $i);
2877 $sql .=
" AND fk_product = ".((int) $this->
id);
2878 $sql .=
" ORDER BY date_price DESC, rowid DESC";
2880 $resql = $this->db->query($sql);
2882 $this->error = $this->db->lasterror;
2884 } elseif ($result = $this->db->fetch_array($resql)) {
2885 $this->multiprices[$i] = (!empty($result[
"price"]) ? $result[
"price"] : 0);
2886 $this->multiprices_ttc[$i] = (!empty($result[
"price_ttc"]) ? $result[
"price_ttc"] : 0);
2887 $this->multiprices_min[$i] = (!empty($result[
"price_min"]) ? $result[
"price_min"] : 0);
2888 $this->multiprices_min_ttc[$i] = (!empty($result[
"price_min_ttc"]) ? $result[
"price_min_ttc"] : 0);
2889 $this->multiprices_base_type[$i] = (!empty($result[
"price_base_type"]) ? $result[
"price_base_type"] :
'');
2891 $this->multiprices_tva_tx[$i] = (!empty($result[
"tva_tx"]) ? $result[
"tva_tx"] : 0);
2892 $this->multiprices_recuperableonly[$i] = (!empty($result[
"recuperableonly"]) ? $result[
"recuperableonly"] : 0);
2895 $this->prices_by_qty[$i] = (!empty($result[
"price_by_qty"]) ? $result[
"price_by_qty"] : 0);
2896 $this->prices_by_qty_id[$i] = (!empty($result[
"rowid"]) ? $result[
"rowid"] : 0);
2898 if ($this->prices_by_qty[$i] == 1) {
2899 $sql =
"SELECT rowid, price, unitprice, quantity, remise_percent, remise, price_base_type";
2900 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
2901 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[$i]);
2902 $sql .=
" ORDER BY quantity ASC";
2904 $resql = $this->db->query($sql);
2906 $resultat = array();
2908 while ($result = $this->db->fetch_array($resql)) {
2909 $resultat[$ii] = array();
2910 $resultat[$ii][
"rowid"] = $result[
"rowid"];
2911 $resultat[$ii][
"price"] = $result[
"price"];
2912 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
2913 $resultat[$ii][
"quantity"] = $result[
"quantity"];
2914 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
2915 $resultat[$ii][
"remise"] = $result[
"remise"];
2916 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
2919 $this->prices_by_qty_list[$i] = $resultat;
2921 $this->error = $this->db->lasterror;
2929 if (isModEnabled(
'dynamicprices') && !empty($this->fk_price_expression) && empty($ignore_expression)) {
2930 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2932 $price_result = $priceparser->parseProduct($this);
2933 if ($price_result >= 0) {
2934 $this->
price = $price_result;
2936 $this->price_ttc = (float)
price2num($this->
price) * (1 + ($this->tva_tx / 100));
2937 $this->price_ttc = (float)
price2num($this->price_ttc,
'MU');
2943 $this->stock_warehouse = array();
2950 $this->error = $this->db->lasterror();
2965 global $user, $hookmanager, $action;
2969 foreach (array(
'toconsume',
'consumed',
'toproduce',
'produced') as $role) {
2970 $this->stats_mo[
'customers_'.$role] = 0;
2971 $this->stats_mo[
'nb_'.$role] = 0;
2972 $this->stats_mo[
'qty_'.$role] = 0;
2974 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
2975 $sql .=
" SUM(mp.qty) as qty";
2976 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as c";
2977 $sql .=
" INNER JOIN ".$this->db->prefix().
"mrp_production as mp ON mp.fk_mo=c.rowid";
2978 if (!$user->hasRight(
'societe',
'client',
'voir')) {
2979 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc=c.fk_soc AND sc.fk_user = ".((int) $user->id);
2982 $sql .=
" c.entity IN (".getEntity(
'mo').
")";
2984 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
2985 $sql .=
" AND mp.role ='".$this->db->escape($role).
"'";
2987 $sql .=
" AND c.fk_soc = ".((int) $socid);
2990 $result = $this->db->query($sql);
2992 $obj = $this->db->fetch_object($result);
2993 $this->stats_mo[
'customers_'.$role] = $obj->nb_customers ? $obj->nb_customers : 0;
2994 $this->stats_mo[
'nb_'.$role] = $obj->nb ? $obj->nb : 0;
2995 $this->stats_mo[
'qty_'.$role] = $obj->qty ?
price2num($obj->qty,
'MS') : 0;
2997 $this->error = $this->db->error();
3002 if (!empty($error)) {
3006 $parameters = array(
'socid' => $socid);
3007 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3009 $this->stats_mo = $hookmanager->resArray[
'stats_mo'];
3025 global $user, $hookmanager, $action;
3029 $this->stats_bom[
'nb_toproduce'] = 0;
3030 $this->stats_bom[
'nb_toconsume'] = 0;
3031 $this->stats_bom[
'qty_toproduce'] = 0;
3032 $this->stats_bom[
'qty_toconsume'] = 0;
3034 $sql =
"SELECT COUNT(DISTINCT b.rowid) as nb_toproduce,";
3035 $sql .=
" SUM(b.qty) as qty_toproduce";
3036 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3037 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
3039 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3040 $sql .=
" AND b.fk_product =".((int) $this->
id);
3041 $sql .=
" GROUP BY b.rowid";
3043 $result = $this->db->query($sql);
3045 $obj = $this->db->fetch_object($result);
3046 $this->stats_bom[
'nb_toproduce'] = !empty($obj->nb_toproduce) ? $obj->nb_toproduce : 0;
3047 $this->stats_bom[
'qty_toproduce'] = !empty($obj->qty_toproduce) ?
price2num($obj->qty_toproduce) : 0;
3049 $this->error = $this->db->error();
3053 $sql =
"SELECT COUNT(DISTINCT bl.rowid) as nb_toconsume,";
3054 $sql .=
" SUM(bl.qty) as qty_toconsume";
3055 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3056 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
3058 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3059 $sql .=
" AND bl.fk_product =".((int) $this->
id);
3061 $result = $this->db->query($sql);
3063 $obj = $this->db->fetch_object($result);
3064 $this->stats_bom[
'nb_toconsume'] = !empty($obj->nb_toconsume) ? $obj->nb_toconsume : 0;
3065 $this->stats_bom[
'qty_toconsume'] = !empty($obj->qty_toconsume) ?
price2num($obj->qty_toconsume) : 0;
3067 $this->error = $this->db->error();
3071 if (!empty($error)) {
3075 $parameters = array(
'socid' => $socid);
3076 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3078 $this->stats_bom = $hookmanager->resArray[
'stats_bom'];
3094 global $conf, $user, $hookmanager, $action;
3096 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_customers, COUNT(DISTINCT p.rowid) as nb,";
3097 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3098 $sql .=
" FROM ".$this->db->prefix().
"propaldet as pd";
3099 $sql .=
", ".$this->db->prefix().
"propal as p";
3100 $sql .=
", ".$this->db->prefix().
"societe as s";
3101 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3102 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3104 $sql .=
" WHERE p.rowid = pd.fk_propal";
3105 $sql .=
" AND p.fk_soc = s.rowid";
3106 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
3107 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3108 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3109 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3113 $sql .=
" AND p.fk_soc = ".((int) $socid);
3116 $result = $this->db->query($sql);
3118 $obj = $this->db->fetch_object($result);
3119 $this->stats_propale[
'customers'] = $obj->nb_customers;
3120 $this->stats_propale[
'nb'] = $obj->nb;
3121 $this->stats_propale[
'rows'] = $obj->nb_rows;
3122 $this->stats_propale[
'qty'] = $obj->qty ? $obj->qty : 0;
3127 if (is_array($TFather) && !empty($TFather)) {
3128 foreach ($TFather as &$fatherData) {
3129 $pFather =
new Product($this->db);
3130 $pFather->id = $fatherData[
'id'];
3131 $qtyCoef = $fatherData[
'qty'];
3133 if ($fatherData[
'incdec']) {
3134 $pFather->load_stats_propale($socid);
3136 $this->stats_propale[
'customers'] += $pFather->stats_propale[
'customers'];
3137 $this->stats_propale[
'nb'] += $pFather->stats_propale[
'nb'];
3138 $this->stats_propale[
'rows'] += $pFather->stats_propale[
'rows'];
3139 $this->stats_propale[
'qty'] += $pFather->stats_propale[
'qty'] * $qtyCoef;
3145 $parameters = array(
'socid' => $socid);
3146 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerProposal', $parameters, $this, $action);
3148 $this->stats_propale = $hookmanager->resArray[
'stats_propale'];
3153 $this->error = $this->db->error();
3169 global $conf, $user, $hookmanager, $action;
3171 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_suppliers, COUNT(DISTINCT p.rowid) as nb,";
3172 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3173 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as pd";
3174 $sql .=
", ".$this->db->prefix().
"supplier_proposal as p";
3175 $sql .=
", ".$this->db->prefix().
"societe as s";
3176 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3177 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3179 $sql .=
" WHERE p.rowid = pd.fk_supplier_proposal";
3180 $sql .=
" AND p.fk_soc = s.rowid";
3181 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
3182 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3183 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3184 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3188 $sql .=
" AND p.fk_soc = ".((int) $socid);
3191 $result = $this->db->query($sql);
3193 $obj = $this->db->fetch_object($result);
3194 $this->stats_proposal_supplier[
'suppliers'] = $obj->nb_suppliers;
3195 $this->stats_proposal_supplier[
'nb'] = $obj->nb;
3196 $this->stats_proposal_supplier[
'rows'] = $obj->nb_rows;
3197 $this->stats_proposal_supplier[
'qty'] = $obj->qty ? $obj->qty : 0;
3199 $parameters = array(
'socid' => $socid);
3200 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierProposal', $parameters, $this, $action);
3202 $this->stats_proposal_supplier = $hookmanager->resArray[
'stats_proposal_supplier'];
3207 $this->error = $this->db->error();
3225 global $conf, $user, $hookmanager, $action;
3227 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3228 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3229 $sql .=
" FROM ".$this->db->prefix().
"commandedet as cd";
3230 $sql .=
", ".$this->db->prefix().
"commande as c";
3231 $sql .=
", ".$this->db->prefix().
"societe as s";
3232 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3233 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3235 $sql .=
" WHERE c.rowid = cd.fk_commande";
3236 $sql .=
" AND c.fk_soc = s.rowid";
3237 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'commande').
")";
3238 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3239 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3240 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3243 $sql .=
" AND c.fk_soc = ".((int) $socid);
3245 if ($filtrestatut !=
'') {
3246 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3249 $result = $this->db->query($sql);
3251 $obj = $this->db->fetch_object($result);
3252 $this->stats_commande[
'customers'] = $obj->nb_customers;
3253 $this->stats_commande[
'nb'] = $obj->nb;
3254 $this->stats_commande[
'rows'] = $obj->nb_rows;
3255 $this->stats_commande[
'qty'] = $obj->qty ? $obj->qty : 0;
3260 if (is_array($TFather) && !empty($TFather)) {
3261 foreach ($TFather as &$fatherData) {
3262 $pFather =
new Product($this->db);
3263 $pFather->id = $fatherData[
'id'];
3264 $qtyCoef = $fatherData[
'qty'];
3266 if ($fatherData[
'incdec']) {
3267 $pFather->load_stats_commande($socid, $filtrestatut);
3269 $this->stats_commande[
'customers'] += $pFather->stats_commande[
'customers'];
3270 $this->stats_commande[
'nb'] += $pFather->stats_commande[
'nb'];
3271 $this->stats_commande[
'rows'] += $pFather->stats_commande[
'rows'];
3272 $this->stats_commande[
'qty'] += $pFather->stats_commande[
'qty'] * $qtyCoef;
3284 $sql =
"SELECT SUM(".$this->db->ifsql(
'f.type=2', -1, 1).
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3285 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3286 $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'))";
3287 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3288 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3290 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3291 $resql = $this->db->query($sql);
3293 if ($this->db->num_rows($resql) > 0) {
3294 $obj = $this->db->fetch_object($resql);
3295 $adeduire += $obj->count;
3299 $this->stats_commande[
'qty'] -= $adeduire;
3302 include_once DOL_DOCUMENT_ROOT.
'/compta/facture/class/facture.class.php';
3306 $sql =
"SELECT sum(".$this->db->ifsql(
'f.type=2', -1, 1).
" * fd.qty) as count FROM ".MAIN_DB_PREFIX.
"facturedet as fd ";
3307 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"facture as f ON fd.fk_facture = f.rowid";
3308 $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'))";
3309 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"commande as c ON el.fk_source = c.rowid";
3310 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3312 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3313 $resql = $this->db->query($sql);
3315 if ($this->db->num_rows($resql) > 0) {
3316 $obj = $this->db->fetch_object($resql);
3317 $adeduire += $obj->count;
3320 $this->error = $this->db->error();
3324 $this->stats_commande[
'qty'] -= $adeduire;
3328 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3329 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerOrder', $parameters, $this, $action);
3331 $this->stats_commande = $hookmanager->resArray[
'stats_commande'];
3335 $this->error = $this->db->error();
3353 global $conf, $user, $hookmanager, $action;
3355 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_suppliers, COUNT(DISTINCT c.rowid) as nb,";
3356 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3357 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as cd";
3358 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as c";
3359 $sql .=
", ".$this->db->prefix().
"societe as s";
3360 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3361 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3363 $sql .=
" WHERE c.rowid = cd.fk_commande";
3364 $sql .=
" AND c.fk_soc = s.rowid";
3365 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3366 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3367 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3368 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3371 $sql .=
" AND c.fk_soc = ".((int) $socid);
3373 if ($filtrestatut !=
'') {
3374 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3376 if (!empty($dateofvirtualstock)) {
3377 $sql .=
" AND c.date_livraison <= '".$this->db->idate($dateofvirtualstock).
"'";
3380 $result = $this->db->query($sql);
3382 $obj = $this->db->fetch_object($result);
3383 $this->stats_commande_fournisseur[
'suppliers'] = $obj->nb_suppliers;
3384 $this->stats_commande_fournisseur[
'nb'] = $obj->nb;
3385 $this->stats_commande_fournisseur[
'rows'] = $obj->nb_rows;
3386 $this->stats_commande_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
3388 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3389 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierOrder', $parameters, $this, $action);
3391 $this->stats_commande_fournisseur = $hookmanager->resArray[
'stats_commande_fournisseur'];
3396 $this->error = $this->db->error().
' sql='.$sql;
3411 public function load_stats_sending($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $filterShipmentStatus =
'')
3414 global $conf, $user, $hookmanager, $action;
3416 $sql =
"SELECT COUNT(DISTINCT e.fk_soc) as nb_customers, COUNT(DISTINCT e.rowid) as nb,";
3417 $sql .=
" COUNT(ed.rowid) as nb_rows, SUM(ed.qty) as qty";
3418 $sql .=
" FROM ".$this->db->prefix().
"expeditiondet as ed";
3419 $sql .=
", ".$this->db->prefix().
"commandedet as cd";
3420 $sql .=
", ".$this->db->prefix().
"commande as c";
3421 $sql .=
", ".$this->db->prefix().
"expedition as e";
3422 $sql .=
", ".$this->db->prefix().
"societe as s";
3423 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3424 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3426 $sql .=
" WHERE e.rowid = ed.fk_expedition";
3427 $sql .=
" AND c.rowid = cd.fk_commande";
3428 $sql .=
" AND e.fk_soc = s.rowid";
3429 $sql .=
" AND e.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'expedition').
")";
3430 $sql .=
" AND ed.fk_elementdet = cd.rowid";
3431 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3432 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3433 $sql .=
" AND e.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3436 $sql .=
" AND e.fk_soc = ".((int) $socid);
3438 if ($filtrestatut !=
'') {
3439 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3441 if (!empty($filterShipmentStatus)) {
3442 $sql .=
" AND e.fk_statut IN (".$this->db->sanitize($filterShipmentStatus).
")";
3445 $result = $this->db->query($sql);
3447 $obj = $this->db->fetch_object($result);
3448 $this->stats_expedition[
'customers'] = $obj->nb_customers;
3449 $this->stats_expedition[
'nb'] = $obj->nb;
3450 $this->stats_expedition[
'rows'] = $obj->nb_rows;
3451 $this->stats_expedition[
'qty'] = $obj->qty ? $obj->qty : 0;
3456 if (is_array($TFather) && !empty($TFather)) {
3457 foreach ($TFather as &$fatherData) {
3458 $pFather =
new Product($this->db);
3459 $pFather->id = $fatherData[
'id'];
3460 $qtyCoef = $fatherData[
'qty'];
3462 if ($fatherData[
'incdec']) {
3463 $pFather->load_stats_sending($socid, $filtrestatut, $forVirtualStock);
3465 $this->stats_expedition[
'customers'] += $pFather->stats_expedition[
'customers'];
3466 $this->stats_expedition[
'nb'] += $pFather->stats_expedition[
'nb'];
3467 $this->stats_expedition[
'rows'] += $pFather->stats_expedition[
'rows'];
3468 $this->stats_expedition[
'qty'] += $pFather->stats_expedition[
'qty'] * $qtyCoef;
3474 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock,
'filterShipmentStatus' => $filterShipmentStatus);
3475 $reshook = $hookmanager->executeHooks(
'loadStatsSending', $parameters, $this, $action);
3477 $this->stats_expedition = $hookmanager->resArray[
'stats_expedition'];
3482 $this->error = $this->db->error();
3497 public function load_stats_reception($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null)
3500 global $conf, $user, $hookmanager, $action;
3502 $sql =
"SELECT COUNT(DISTINCT cf.fk_soc) as nb_suppliers, COUNT(DISTINCT cf.rowid) as nb,";
3503 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
3504 $sql .=
" FROM ".$this->db->prefix().
"receptiondet_batch as fd";
3505 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as cf";
3506 $sql .=
", ".$this->db->prefix().
"societe as s";
3507 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3508 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3510 $sql .=
" WHERE cf.rowid = fd.fk_element";
3511 $sql .=
" AND cf.fk_soc = s.rowid";
3512 $sql .=
" AND cf.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3513 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3514 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3515 $sql .=
" AND cf.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3518 $sql .=
" AND cf.fk_soc = ".((int) $socid);
3520 if ($filtrestatut !=
'') {
3521 $sql .=
" AND cf.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3523 if (!empty($dateofvirtualstock)) {
3524 $sql .=
" AND fd.datec <= '".$this->db->idate($dateofvirtualstock).
"'";
3527 $result = $this->db->query($sql);
3529 $obj = $this->db->fetch_object($result);
3530 $this->stats_reception[
'suppliers'] = $obj->nb_suppliers;
3531 $this->stats_reception[
'nb'] = $obj->nb;
3532 $this->stats_reception[
'rows'] = $obj->nb_rows;
3533 $this->stats_reception[
'qty'] = $obj->qty ? $obj->qty : 0;
3535 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3536 $reshook = $hookmanager->executeHooks(
'loadStatsReception', $parameters, $this, $action);
3538 $this->stats_reception = $hookmanager->resArray[
'stats_reception'];
3543 $this->error = $this->db->error();
3559 public function load_stats_inproduction($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null, $warehouseid = 0)
3562 global $user, $hookmanager, $action;
3564 $serviceStockIsEnabled = isModEnabled(
"service") &&
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES');
3566 $sql =
"SELECT COUNT(DISTINCT m.fk_soc) as nb_customers, COUNT(DISTINCT m.rowid) as nb,";
3567 $sql .=
" COUNT(mp.rowid) as nb_rows, SUM(mp.qty) as qty, role";
3568 $sql .=
" FROM ".$this->db->prefix().
"mrp_production as mp";
3569 $sql .=
", ".$this->db->prefix().
"mrp_mo as m";
3570 $sql .=
" LEFT JOIN ".$this->db->prefix().
"societe as s ON s.rowid = m.fk_soc";
3571 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3572 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3574 $sql .=
" WHERE m.rowid = mp.fk_mo";
3575 $sql .=
" AND m.entity IN (".getEntity(($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE')) ?
'stock' :
'mrp').
")";
3576 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3577 $sql .=
" AND (mp.disable_stock_change IN (0) OR mp.disable_stock_change IS NULL)";
3578 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3579 $sql .=
" AND m.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3582 $sql .=
" AND m.fk_soc = ".((int) $socid);
3584 if ($filtrestatut !=
'') {
3585 $sql .=
" AND m.status IN (".$this->db->sanitize($filtrestatut).
")";
3587 if (!empty($dateofvirtualstock)) {
3588 $sql .=
" AND m.date_valid <= '".$this->db->idate($dateofvirtualstock).
"'";
3590 if (!$serviceStockIsEnabled) {
3591 $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))";
3593 if (!empty($warehouseid)) {
3594 $sql .=
" AND m.fk_warehouse = ".((int) $warehouseid);
3596 $sql .=
" GROUP BY role";
3599 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
3601 $this->stats_mrptoconsume[
'customers'] = 0;
3602 $this->stats_mrptoconsume[
'nb'] = 0;
3603 $this->stats_mrptoconsume[
'rows'] = 0;
3604 $this->stats_mrptoconsume[
'qty'] = 0;
3605 $this->stats_mrptoproduce[
'customers'] = 0;
3606 $this->stats_mrptoproduce[
'nb'] = 0;
3607 $this->stats_mrptoproduce[
'rows'] = 0;
3608 $this->stats_mrptoproduce[
'qty'] = 0;
3611 $result = $this->db->query($sql);
3613 while ($obj = $this->db->fetch_object($result)) {
3614 if ($obj->role ==
'toconsume' && empty($warehouseid)) {
3615 $this->stats_mrptoconsume[
'customers'] += $obj->nb_customers;
3616 $this->stats_mrptoconsume[
'nb'] += $obj->nb;
3617 $this->stats_mrptoconsume[
'rows'] += $obj->nb_rows;
3618 $this->stats_mrptoconsume[
'qty'] += ($obj->qty ? $obj->qty : 0);
3620 if ($obj->role ==
'consumed' && empty($warehouseid)) {
3624 $this->stats_mrptoconsume[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3626 if ($obj->role ==
'toproduce') {
3628 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] += ($obj->qty ? $obj->qty : 0);
3630 $this->stats_mrptoproduce[
'customers'] += $obj->nb_customers;
3631 $this->stats_mrptoproduce[
'nb'] += $obj->nb;
3632 $this->stats_mrptoproduce[
'rows'] += $obj->nb_rows;
3633 $this->stats_mrptoproduce[
'qty'] += ($obj->qty ? $obj->qty : 0);
3636 if ($obj->role ==
'produced') {
3641 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3643 $this->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3650 if ($this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] < 0) {
3651 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
3654 if ($this->stats_mrptoconsume[
'qty'] < 0) {
3655 $this->stats_mrptoconsume[
'qty'] = 0;
3657 if ($this->stats_mrptoproduce[
'qty'] < 0) {
3658 $this->stats_mrptoproduce[
'qty'] = 0;
3662 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3663 $reshook = $hookmanager->executeHooks(
'loadStatsInProduction', $parameters, $this, $action);
3665 $this->stats_mrptoproduce = $hookmanager->resArray[
'stats_mrptoproduce'];
3670 $this->error = $this->db->error();
3685 global $conf, $user, $hookmanager, $action;
3687 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3688 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3689 $sql .=
" FROM ".$this->db->prefix().
"contratdet as cd";
3690 $sql .=
", ".$this->db->prefix().
"contrat as c";
3691 $sql .=
", ".$this->db->prefix().
"societe as s";
3692 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3693 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3695 $sql .=
" WHERE c.rowid = cd.fk_contrat";
3696 $sql .=
" AND c.fk_soc = s.rowid";
3697 $sql .=
" AND c.entity IN (".getEntity(
'contract').
")";
3698 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3699 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3700 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3704 $sql .=
" AND c.fk_soc = ".((int) $socid);
3707 $result = $this->db->query($sql);
3709 $obj = $this->db->fetch_object($result);
3710 $this->stats_contrat[
'customers'] = $obj->nb_customers;
3711 $this->stats_contrat[
'nb'] = $obj->nb;
3712 $this->stats_contrat[
'rows'] = $obj->nb_rows;
3713 $this->stats_contrat[
'qty'] = $obj->qty ? $obj->qty : 0;
3718 if (is_array($TFather) && !empty($TFather)) {
3719 foreach ($TFather as &$fatherData) {
3720 $pFather =
new Product($this->db);
3721 $pFather->id = $fatherData[
'id'];
3722 $qtyCoef = $fatherData[
'qty'];
3724 if ($fatherData[
'incdec']) {
3725 $pFather->load_stats_contrat($socid);
3727 $this->stats_contrat[
'customers'] += $pFather->stats_contrat[
'customers'];
3728 $this->stats_contrat[
'nb'] += $pFather->stats_contrat[
'nb'];
3729 $this->stats_contrat[
'rows'] += $pFather->stats_contrat[
'rows'];
3730 $this->stats_contrat[
'qty'] += $pFather->stats_contrat[
'qty'] * $qtyCoef;
3736 $parameters = array(
'socid' => $socid);
3737 $reshook = $hookmanager->executeHooks(
'loadStatsContract', $parameters, $this, $action);
3739 $this->stats_contrat = $hookmanager->resArray[
'stats_contrat'];
3744 $this->error = $this->db->error().
' sql='.$sql;
3759 global $conf, $user, $hookmanager, $action;
3761 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
3762 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(".$this->db->ifsql(
'f.type != 2',
'fd.qty',
'fd.qty * -1').
") as qty";
3763 $sql .=
" FROM ".$this->db->prefix().
"facturedet as fd";
3764 $sql .=
", ".$this->db->prefix().
"facture as f";
3765 $sql .=
", ".$this->db->prefix().
"societe as s";
3766 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3767 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3769 $sql .=
" WHERE f.rowid = fd.fk_facture";
3770 $sql .=
" AND f.fk_soc = s.rowid";
3771 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
3772 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3773 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3774 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3778 $sql .=
" AND f.fk_soc = ".((int) $socid);
3781 $result = $this->db->query($sql);
3783 $obj = $this->db->fetch_object($result);
3784 $this->stats_facture[
'customers'] = $obj->nb_customers;
3785 $this->stats_facture[
'nb'] = $obj->nb;
3786 $this->stats_facture[
'rows'] = $obj->nb_rows;
3787 $this->stats_facture[
'qty'] = $obj->qty ? $obj->qty : 0;
3792 if (is_array($TFather) && !empty($TFather)) {
3793 foreach ($TFather as &$fatherData) {
3794 $pFather =
new Product($this->db);
3795 $pFather->id = $fatherData[
'id'];
3796 $qtyCoef = $fatherData[
'qty'];
3798 if ($fatherData[
'incdec']) {
3799 $pFather->load_stats_facture($socid);
3801 $this->stats_facture[
'customers'] += $pFather->stats_facture[
'customers'];
3802 $this->stats_facture[
'nb'] += $pFather->stats_facture[
'nb'];
3803 $this->stats_facture[
'rows'] += $pFather->stats_facture[
'rows'];
3804 $this->stats_facture[
'qty'] += $pFather->stats_facture[
'qty'] * $qtyCoef;
3810 $parameters = array(
'socid' => $socid);
3811 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoice', $parameters, $this, $action);
3813 $this->stats_facture = $hookmanager->resArray[
'stats_facture'];
3818 $this->error = $this->db->error();
3834 global $conf, $user, $hookmanager, $action;
3836 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
3837 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
3838 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facturedet_rec as fd";
3839 $sql .=
", ".MAIN_DB_PREFIX.
"facture_rec as f";
3840 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
3841 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3842 $sql .=
", ".MAIN_DB_PREFIX.
"societe_commerciaux as sc";
3844 $sql .=
" WHERE f.rowid = fd.fk_facture";
3845 $sql .=
" AND f.fk_soc = s.rowid";
3846 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
3847 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3848 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3849 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3853 $sql .=
" AND f.fk_soc = ".((int) $socid);
3856 $result = $this->db->query($sql);
3858 $obj = $this->db->fetch_object($result);
3859 $this->stats_facturerec[
'customers'] = $obj->nb_customers;
3860 $this->stats_facturerec[
'nb'] = $obj->nb;
3861 $this->stats_facturerec[
'rows'] = $obj->nb_rows;
3862 $this->stats_facturerec[
'qty'] = $obj->qty ? $obj->qty : 0;
3867 if (is_array($TFather) && !empty($TFather)) {
3868 foreach ($TFather as &$fatherData) {
3869 $pFather =
new Product($this->db);
3870 $pFather->id = $fatherData[
'id'];
3871 $qtyCoef = $fatherData[
'qty'];
3873 if ($fatherData[
'incdec']) {
3874 $pFather->load_stats_facture($socid);
3876 $this->stats_facturerec[
'customers'] += $pFather->stats_facturerec[
'customers'];
3877 $this->stats_facturerec[
'nb'] += $pFather->stats_facturerec[
'nb'];
3878 $this->stats_facturerec[
'rows'] += $pFather->stats_facturerec[
'rows'];
3879 $this->stats_facturerec[
'qty'] += $pFather->stats_facturerec[
'qty'] * $qtyCoef;
3885 $parameters = array(
'socid' => $socid);
3886 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoiceRec', $parameters, $this, $action);
3888 $this->stats_facturerec = $hookmanager->resArray[
'stats_facturerec'];
3893 $this->error = $this->db->error();
3908 global $conf, $user, $hookmanager, $action;
3910 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
3911 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
3912 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as fd";
3913 $sql .=
", ".$this->db->prefix().
"facture_fourn as f";
3914 $sql .=
", ".$this->db->prefix().
"societe as s";
3915 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3916 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3918 $sql .=
" WHERE f.rowid = fd.fk_facture_fourn";
3919 $sql .=
" AND f.fk_soc = s.rowid";
3920 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
3921 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3922 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3923 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3927 $sql .=
" AND f.fk_soc = ".((int) $socid);
3930 $result = $this->db->query($sql);
3932 $obj = $this->db->fetch_object($result);
3933 $this->stats_facture_fournisseur[
'suppliers'] = $obj->nb_suppliers;
3934 $this->stats_facture_fournisseur[
'nb'] = $obj->nb;
3935 $this->stats_facture_fournisseur[
'rows'] = $obj->nb_rows;
3936 $this->stats_facture_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
3938 $parameters = array(
'socid' => $socid);
3939 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoice', $parameters, $this, $action);
3941 $this->stats_facture_fournisseur = $hookmanager->resArray[
'stats_facture_fournisseur'];
3946 $this->error = $this->db->error();
3965 $resql = $this->db->query($sql);
3967 $num = $this->db->num_rows($resql);
3970 $arr = $this->db->fetch_array($resql);
3971 if (is_array($arr)) {
3972 $keyfortab = (string) $arr[1];
3974 $keyfortab = substr($keyfortab, -2);
3977 if ($mode ==
'byunit') {
3978 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[0];
3979 } elseif ($mode ==
'bynumber') {
3980 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
3981 } elseif ($mode ==
'byamount') {
3982 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
3991 $this->error = $this->db->error().
' sql='.$sql;
3998 } elseif ($year == -1) {
4007 for ($j = 0; $j < 12; $j++) {
4009 $idx = ucfirst(
dol_trunc(
dol_print_date(
dol_mktime(12, 0, 0, $month, 1, 1970),
"%b"), 1,
'right',
'UTF-8', 1));
4012 $result[$j] = array($idx, isset($tab[$year.$month]) ? $tab[$year.$month] : 0);
4015 $month =
"0".($month - 1);
4017 $month = substr($month, 1);
4025 return array_reverse($result);
4040 public function get_nb_vente($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4046 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4047 if ($mode ==
'bynumber') {
4048 $sql .=
", count(DISTINCT f.rowid)";
4050 $sql .=
", sum(d.total_ht) as total_ht";
4051 $sql .=
" FROM ".$this->db->prefix().
"facturedet as d, ".$this->db->prefix().
"facture as f, ".$this->db->prefix().
"societe as s";
4052 if ($filteronproducttype >= 0) {
4053 $sql .=
", ".$this->db->prefix().
"product as p";
4055 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4056 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4058 $sql .=
" WHERE f.rowid = d.fk_facture";
4059 if ($this->
id > 0) {
4060 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4062 $sql .=
" AND d.fk_product > 0";
4064 if ($filteronproducttype >= 0) {
4065 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4067 $sql .=
" AND f.fk_soc = s.rowid";
4068 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4069 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4070 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4073 $sql .=
" AND f.fk_soc = $socid";
4075 $sql .= $morefilter;
4076 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4077 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4079 return $this->
_get_stats($sql, $mode, $year);
4094 public function get_nb_achat($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().
"facture_fourn_det as d, ".$this->db->prefix().
"facture_fourn 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_fourn";
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(
'facture_fourn').
")";
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);
4147 public function get_nb_propal($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4150 global $conf, $user;
4152 $sql =
"SELECT sum(d.qty) as qty, date_format(p.datep, '%Y%m')";
4153 if ($mode ==
'bynumber') {
4154 $sql .=
", count(DISTINCT p.rowid)";
4156 $sql .=
", sum(d.total_ht) as total_ht";
4157 $sql .=
" FROM ".$this->db->prefix().
"propaldet as d, ".$this->db->prefix().
"propal as p, ".$this->db->prefix().
"societe as s";
4158 if ($filteronproducttype >= 0) {
4159 $sql .=
", ".$this->db->prefix().
"product as prod";
4161 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4162 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4164 $sql .=
" WHERE p.rowid = d.fk_propal";
4165 if ($this->
id > 0) {
4166 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4168 $sql .=
" AND d.fk_product > 0";
4170 if ($filteronproducttype >= 0) {
4171 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4173 $sql .=
" AND p.fk_soc = s.rowid";
4174 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
4175 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4176 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4179 $sql .=
" AND p.fk_soc = ".((int) $socid);
4181 $sql .= $morefilter;
4182 $sql .=
" GROUP BY date_format(p.datep,'%Y%m')";
4183 $sql .=
" ORDER BY date_format(p.datep,'%Y%m') DESC";
4185 return $this->
_get_stats($sql, $mode, $year);
4205 $sql =
"SELECT sum(d.qty) as qty, date_format(p.date_valid, '%Y%m')";
4206 if ($mode ==
'bynumber') {
4207 $sql .=
", count(DISTINCT p.rowid)";
4209 $sql .=
", sum(d.total_ht) as total_ht";
4210 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as d, ".$this->db->prefix().
"supplier_proposal as p, ".$this->db->prefix().
"societe as s";
4211 if ($filteronproducttype >= 0) {
4212 $sql .=
", ".$this->db->prefix().
"product as prod";
4214 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4215 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4217 $sql .=
" WHERE p.rowid = d.fk_supplier_proposal";
4218 if ($this->
id > 0) {
4219 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4221 $sql .=
" AND d.fk_product > 0";
4223 if ($filteronproducttype >= 0) {
4224 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4226 $sql .=
" AND p.fk_soc = s.rowid";
4227 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
4228 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4229 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4232 $sql .=
" AND p.fk_soc = ".((int) $socid);
4234 $sql .= $morefilter;
4235 $sql .=
" GROUP BY date_format(p.date_valid,'%Y%m')";
4236 $sql .=
" ORDER BY date_format(p.date_valid,'%Y%m') DESC";
4238 return $this->
_get_stats($sql, $mode, $year);
4252 public function get_nb_order($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4255 global $conf, $user;
4257 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4258 if ($mode ==
'bynumber') {
4259 $sql .=
", count(DISTINCT c.rowid)";
4261 $sql .=
", sum(d.total_ht) as total_ht";
4262 $sql .=
" FROM ".$this->db->prefix().
"commandedet as d, ".$this->db->prefix().
"commande as c, ".$this->db->prefix().
"societe as s";
4263 if ($filteronproducttype >= 0) {
4264 $sql .=
", ".$this->db->prefix().
"product as p";
4266 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4267 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4269 $sql .=
" WHERE c.rowid = d.fk_commande";
4270 if ($this->
id > 0) {
4271 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4273 $sql .=
" AND d.fk_product > 0";
4275 if ($filteronproducttype >= 0) {
4276 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4278 $sql .=
" AND c.fk_soc = s.rowid";
4279 $sql .=
" AND c.entity IN (".getEntity(
'commande').
")";
4280 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4281 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4284 $sql .=
" AND c.fk_soc = ".((int) $socid);
4286 $sql .= $morefilter;
4287 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4288 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4290 return $this->
_get_stats($sql, $mode, $year);
4307 global $conf, $user;
4309 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4310 if ($mode ==
'bynumber') {
4311 $sql .=
", count(DISTINCT c.rowid)";
4313 $sql .=
", sum(d.total_ht) as total_ht";
4314 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as d, ".$this->db->prefix().
"commande_fournisseur as c, ".$this->db->prefix().
"societe as s";
4315 if ($filteronproducttype >= 0) {
4316 $sql .=
", ".$this->db->prefix().
"product as p";
4318 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4319 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4321 $sql .=
" WHERE c.rowid = d.fk_commande";
4322 if ($this->
id > 0) {
4323 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4325 $sql .=
" AND d.fk_product > 0";
4327 if ($filteronproducttype >= 0) {
4328 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4330 $sql .=
" AND c.fk_soc = s.rowid";
4331 $sql .=
" AND c.entity IN (".getEntity(
'supplier_order').
")";
4332 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4333 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4336 $sql .=
" AND c.fk_soc = ".((int) $socid);
4338 $sql .= $morefilter;
4339 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4340 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4342 return $this->
_get_stats($sql, $mode, $year);
4356 public function get_nb_contract($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4359 global $conf, $user;
4361 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_contrat, '%Y%m')";
4362 if ($mode ==
'bynumber') {
4363 $sql .=
", count(DISTINCT c.rowid)";
4365 $sql .=
", sum(d.total_ht) as total_ht";
4366 $sql .=
" FROM ".$this->db->prefix().
"contratdet as d, ".$this->db->prefix().
"contrat as c, ".$this->db->prefix().
"societe as s";
4367 if ($filteronproducttype >= 0) {
4368 $sql .=
", ".$this->db->prefix().
"product as p";
4370 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4371 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4373 $sql .=
" WHERE c.entity IN (".getEntity(
'contract').
")";
4374 $sql .=
" AND c.rowid = d.fk_contrat";
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";
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_contrat,'%Y%m')";
4394 $sql .=
" ORDER BY date_format(c.date_contrat,'%Y%m') DESC";
4396 return $this->
_get_stats($sql, $mode, $year);
4410 public function get_nb_mos($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4413 global $conf, $user;
4415 $sql =
"SELECT sum(d.qty), date_format(d.date_valid, '%Y%m')";
4416 if ($mode ==
'bynumber') {
4417 $sql .=
", count(DISTINCT d.rowid)";
4419 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as d LEFT JOIN ".$this->db->prefix().
"societe as s ON d.fk_soc = s.rowid";
4420 if ($filteronproducttype >= 0) {
4421 $sql .=
", ".$this->db->prefix().
"product as p";
4423 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4424 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4427 $sql .=
" WHERE d.entity IN (".getEntity(
'mo').
")";
4428 $sql .=
" AND d.status > 0";
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);
4439 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4440 $sql .=
" AND d.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4443 $sql .=
" AND d.fk_soc = ".((int) $socid);
4445 $sql .= $morefilter;
4446 $sql .=
" GROUP BY date_format(d.date_valid,'%Y%m')";
4447 $sql .=
" ORDER BY date_format(d.date_valid,'%Y%m') DESC";
4449 return $this->
_get_stats($sql, $mode, $year);
4469 if (!is_numeric($id_pere)) {
4472 if (!is_numeric($id_fils)) {
4475 if (!is_numeric($incdec)) {
4485 $sql =
"SELECT fk_product_pere from ".$this->db->prefix().
"product_association";
4486 $sql .=
" WHERE fk_product_pere = ".((int) $id_fils).
" AND fk_product_fils = ".((int) $id_pere);
4487 if (!$this->db->query($sql)) {
4492 $sql =
"SELECT MAX(rang) as max_rank FROM ".$this->db->prefix().
"product_association";
4493 $sql .=
" WHERE fk_product_pere = ".((int) $id_pere);
4494 $resql = $this->db->query($sql);
4496 $obj = $this->db->fetch_object($resql);
4497 $rank = $obj->max_rank + 1;
4499 $sql =
"INSERT INTO ".$this->db->prefix().
"product_association(fk_product_pere,fk_product_fils,qty,incdec,rang)";
4500 $sql .=
" VALUES (".((int) $id_pere).
", ".((int) $id_fils).
", ".
price2num($qty,
'MS').
", ".
price2num($incdec,
'MS').
", ".((int) $rank).
")";
4501 if (! $this->db->query($sql)) {
4507 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_ADD', $user);
4509 $this->error = $this->db->lasterror();
4510 dol_syslog(get_class($this).
'::addSubproduct error='.$this->error, LOG_ERR);
4542 if (!is_numeric($id_pere)) {
4545 if (!is_numeric($id_fils)) {
4548 if (!is_numeric($incdec)) {
4551 if (!is_numeric($qty)) {
4555 $sql =
'UPDATE '.$this->db->prefix().
'product_association SET ';
4556 $sql .=
'qty = '.price2num($qty,
'MS');
4557 $sql .=
',incdec = '.price2num($incdec,
'MS');
4558 $sql .=
' WHERE fk_product_pere = '.((int) $id_pere).
' AND fk_product_fils = '.((int) $id_fils);
4560 if (!$this->db->query($sql)) {
4566 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_UPDATE', $user);
4568 $this->error = $this->db->lasterror();
4569 dol_syslog(get_class($this).
'::updateSubproduct error='.$this->error, LOG_ERR);
4593 if (!is_numeric($fk_parent)) {
4596 if (!is_numeric($fk_child)) {
4600 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
4601 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
4602 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
4604 dol_syslog(get_class($this).
'::del_sousproduit', LOG_DEBUG);
4605 if (!$this->db->query($sql)) {
4611 $sqlrank =
"SELECT rowid, rang FROM ".$this->db->prefix().
"product_association";
4612 $sqlrank .=
" WHERE fk_product_pere = ".((int) $fk_parent);
4613 $sqlrank .=
" ORDER BY rang";
4614 $resqlrank = $this->db->query($sqlrank);
4617 while ($objrank = $this->db->fetch_object($resqlrank)) {
4619 $sql =
"UPDATE ".$this->db->prefix().
"product_association";
4620 $sql .=
" SET rang = ".((int) $cpt);
4621 $sql .=
" WHERE rowid = ".((int) $objrank->rowid);
4622 if (! $this->db->query($sql)) {
4631 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_DELETE', $user);
4633 $this->error = $this->db->lasterror();
4634 dol_syslog(get_class($this).
'::delSubproduct error='.$this->error, LOG_ERR);
4654 $sql =
"SELECT fk_product_pere, qty, incdec";
4655 $sql .=
" FROM ".$this->db->prefix().
"product_association";
4656 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
4657 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
4659 $result = $this->db->query($sql);
4661 $num = $this->db->num_rows($result);
4664 $obj = $this->db->fetch_object($result);
4666 $this->is_sousproduit_qty = $obj->qty;
4667 $this->is_sousproduit_incdec = $obj->incdec;
4698 dol_syslog(get_class($this).
"::add_fournisseur id_fourn = ".$id_fourn.
" ref_fourn=".
$ref_fourn.
" quantity=".$quantity, LOG_DEBUG);
4705 $sql =
"SELECT rowid, fk_product";
4706 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
4707 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
4708 $sql .=
" AND ref_fourn = '".$this->db->escape(
$ref_fourn).
"'";
4709 $sql .=
" AND fk_product <> ".((int) $this->
id);
4710 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
4712 $resql = $this->db->query($sql);
4714 $obj = $this->db->fetch_object($resql);
4717 $this->product_id_already_linked = $obj->fk_product;
4720 $this->db->free($resql);
4724 $sql =
"SELECT rowid";
4725 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
4726 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
4728 $sql .=
" AND ref_fourn = '".$this->db->escape(
$ref_fourn).
"'";
4730 $sql .=
" AND (ref_fourn = '' OR ref_fourn IS NULL)";
4732 $sql .=
" AND quantity = ".((float) $quantity);
4733 $sql .=
" AND fk_product = ".((int) $this->
id);
4734 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
4736 $resql = $this->db->query($sql);
4738 $obj = $this->db->fetch_object($resql);
4742 $sql =
"INSERT INTO ".$this->db->prefix().
"product_fournisseur_price(";
4745 $sql .=
", fk_product";
4747 $sql .=
", ref_fourn";
4748 $sql .=
", quantity";
4749 $sql .=
", fk_user";
4751 $sql .=
") VALUES (";
4752 $sql .=
"'".$this->db->idate($now).
"'";
4753 $sql .=
", ".((int) $conf->entity);
4754 $sql .=
", ".((int) $this->
id);
4755 $sql .=
", ".((int) $id_fourn);
4756 $sql .=
", '".$this->db->escape(
$ref_fourn).
"'";
4757 $sql .=
", ".((float) $quantity);
4758 $sql .=
", ".((int) $user->id);
4762 if ($this->db->query($sql)) {
4763 $this->product_fourn_price_id = $this->db->last_insert_id($this->db->prefix().
"product_fournisseur_price");
4766 $this->error = $this->db->lasterror();
4771 $this->product_fourn_price_id = $obj->rowid;
4775 $this->error = $this->db->lasterror();
4794 $sql =
"SELECT DISTINCT p.fk_soc";
4795 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as p";
4796 $sql .=
" WHERE p.fk_product = ".((int) $this->
id);
4797 $sql .=
" AND p.entity = ".((int) $conf->entity);
4799 $result = $this->db->query($sql);
4801 $num = $this->db->num_rows($result);
4804 $obj = $this->db->fetch_object($result);
4805 $list[$i] = $obj->fk_soc;
4823 global $conf, $user;
4830 $sql =
"INSERT INTO ".$this->db->prefix().
"product_price (";
4832 $sql .=
", fk_product";
4833 $sql .=
", date_price";
4834 $sql .=
", price_level";
4836 $sql .=
", price_ttc";
4837 $sql .=
", price_min";
4838 $sql .=
", price_min_ttc";
4839 $sql .=
", price_base_type";
4840 $sql .=
", price_label";
4841 $sql .=
", default_vat_code";
4843 $sql .=
", recuperableonly";
4844 $sql .=
", localtax1_tx";
4845 $sql .=
", localtax1_type";
4846 $sql .=
", localtax2_tx";
4847 $sql .=
", localtax2_type";
4848 $sql .=
", fk_user_author";
4850 $sql .=
", price_by_qty";
4851 $sql .=
", fk_price_expression";
4852 $sql .=
", fk_multicurrency";
4853 $sql .=
", multicurrency_code";
4854 $sql .=
", multicurrency_tx";
4855 $sql .=
", multicurrency_price";
4856 $sql .=
", multicurrency_price_ttc";
4861 $sql .=
", '".$this->db->idate($now).
"'";
4862 $sql .=
", price_level";
4864 $sql .=
", price_ttc";
4865 $sql .=
", price_min";
4866 $sql .=
", price_min_ttc";
4867 $sql .=
", price_base_type";
4868 $sql .=
", price_label";
4869 $sql .=
", default_vat_code";
4871 $sql .=
", recuperableonly";
4872 $sql .=
", localtax1_tx";
4873 $sql .=
", localtax1_type";
4874 $sql .=
", localtax2_tx";
4875 $sql .=
", localtax2_type";
4876 $sql .=
", ".$user->id;
4878 $sql .=
", price_by_qty";
4879 $sql .=
", fk_price_expression";
4880 $sql .=
", fk_multicurrency";
4881 $sql .=
", multicurrency_code";
4882 $sql .=
", multicurrency_tx";
4883 $sql .=
", multicurrency_price";
4884 $sql .=
", multicurrency_price_ttc";
4885 $sql .=
" FROM ".$this->db->prefix().
"product_price ps";
4886 $sql .=
" WHERE fk_product = ".((int) $fromId);
4887 $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)";
4888 $sql .=
" ORDER BY date_price DESC";
4891 $resql = $this->db->query($sql);
4893 $this->db->rollback();
4897 $this->db->commit();
4914 $sql =
'INSERT INTO '.$this->db->prefix().
'product_association (fk_product_pere, fk_product_fils, qty, incdec)';
4915 $sql .=
" SELECT ".$toId.
", fk_product_fils, qty, incdec FROM ".$this->db->prefix().
"product_association";
4916 $sql .=
" WHERE fk_product_pere = ".((int) $fromId);
4918 dol_syslog(get_class($this).
'::clone_association', LOG_DEBUG);
4919 if (!$this->db->query($sql)) {
4920 $this->db->rollback();
4924 $this->db->commit();
4957 $sql =
"INSERT ".$this->db->prefix().
"product_fournisseur_price (";
4958 $sql .=
" datec, fk_product, fk_soc, price, quantity, fk_user, tva_tx)";
4959 $sql .=
" SELECT '".$this->db->idate($now).
"', ".((int) $toId).
", fk_soc, price, quantity, fk_user, tva_tx";
4960 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
4961 $sql .=
" WHERE fk_product = ".((int) $fromId);
4963 dol_syslog(get_class($this).
'::clone_fournisseurs', LOG_DEBUG);
4964 $resql = $this->db->query($sql);
4966 $this->db->rollback();
4969 $this->db->commit();
4987 public function fetch_prod_arbo($prod, $compl_path =
'', $multiply = 1, $level = 1, $id_parent = 0, $ignore_stock_load = 0)
4990 global $conf, $langs;
4994 foreach ($prod as $id_product => $desc_pere) {
4995 if (is_array($desc_pere)) {
4996 $id = (!empty($desc_pere[0]) ? $desc_pere[0] :
'');
4997 $nb = (!empty($desc_pere[1]) ? $desc_pere[1] :
'');
4998 $type = (!empty($desc_pere[2]) ? $desc_pere[2] :
'');
4999 $label = (!empty($desc_pere[3]) ? $desc_pere[3] :
'');
5000 $incdec = (!empty($desc_pere[4]) ? $desc_pere[4] : 0);
5002 if ($multiply < 1) {
5007 if (is_null($tmpproduct)) {
5008 $tmpproduct =
new Product($this->db);
5010 $tmpproduct->fetch($id);
5012 if (empty($ignore_stock_load) && ($tmpproduct->isProduct() ||
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES'))) {
5013 $tmpproduct->load_stock(
'nobatch,novirtual');
5016 $this->res[] = array(
5018 'id_parent' => $id_parent,
5019 'ref' => $tmpproduct->ref,
5021 'nb_total' => $nb * $multiply,
5022 'stock' => $tmpproduct->stock_reel,
5023 'stock_alert' => $tmpproduct->seuil_stock_alerte,
5025 'fullpath' => $compl_path.$label,
5027 'desiredstock' => $tmpproduct->desiredstock,
5029 'incdec' => $incdec,
5030 'entity' => $tmpproduct->entity
5034 if (isset($desc_pere[
'childs']) && is_array($desc_pere[
'childs'])) {
5036 $this->
fetch_prod_arbo($desc_pere[
'childs'], $compl_path.$desc_pere[3].
" -> ", $desc_pere[1] * $multiply, $level + 1, $id, $ignore_stock_load);
5054 $this->res = array();
5055 if (isset($this->sousprods) && is_array($this->sousprods)) {
5056 foreach ($this->sousprods as $prod_name => $desc_product) {
5057 if (is_array($desc_product)) {
5058 $this->
fetch_prod_arbo($desc_product,
"", $multiply, 1, $this->
id, $ignore_stock_load);
5077 $sql =
"SELECT COUNT(pa.rowid) as nb";
5078 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa";
5080 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id).
" OR pa.fk_product_pere = ".((int) $this->
id);
5081 } elseif ($mode == -1) {
5082 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id);
5083 } elseif ($mode == 1) {
5084 $sql .=
" WHERE pa.fk_product_pere = ".((int) $this->
id);
5087 $resql = $this->db->query($sql);
5089 $obj = $this->db->fetch_object($resql);
5108 $sql =
"SELECT count(rowid) as nb FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_parent = ".((int) $this->
id);
5109 $sql .=
" AND entity IN (".getEntity(
'product').
")";
5111 $resql = $this->db->query($sql);
5113 $obj = $this->db->fetch_object($resql);
5131 if (isModEnabled(
'variants')) {
5132 $sql =
"SELECT rowid FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_child = ".((int) $this->
id).
" AND entity IN (".
getEntity(
'product').
")";
5134 $query = $this->db->query($sql);
5137 if (!$this->db->num_rows($query)) {
5158 $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";
5159 $sql .=
", p.tosell as status, p.tobuy as status_buy";
5160 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa,";
5161 $sql .=
" ".$this->db->prefix().
"product as p";
5162 $sql .=
" WHERE p.rowid = pa.fk_product_pere";
5163 $sql .=
" AND pa.fk_product_fils = ".((int) $this->
id);
5165 $res = $this->db->query($sql);
5168 while ($record = $this->db->fetch_array($res)) {
5170 $prods[$record[
'id']][
'id'] = $record[
'rowid'];
5171 $prods[$record[
'id']][
'ref'] = $record[
'ref'];
5172 $prods[$record[
'id']][
'label'] = $record[
'label'];
5173 $prods[$record[
'id']][
'qty'] = $record[
'qty'];
5174 $prods[$record[
'id']][
'incdec'] = $record[
'incdec'];
5175 $prods[$record[
'id']][
'fk_product_type'] = $record[
'fk_product_type'];
5176 $prods[$record[
'id']][
'entity'] = $record[
'entity'];
5177 $prods[$record[
'id']][
'status'] = $record[
'status'];
5178 $prods[$record[
'id']][
'status_buy'] = $record[
'status_buy'];
5197 public function getChildsArbo($id, $firstlevelonly = 0, $level = 1, $parents = array())
5199 global $alreadyfound;
5205 $sql =
"SELECT p.rowid, p.ref, p.label as label, p.fk_product_type,";
5206 $sql .=
" pa.qty as qty, pa.fk_product_fils as id, pa.incdec,";
5207 $sql .=
" pa.rowid as fk_association, pa.rang";
5208 $sql .=
" FROM ".$this->db->prefix().
"product as p,";
5209 $sql .=
" ".$this->db->prefix().
"product_association as pa";
5210 $sql .=
" WHERE p.rowid = pa.fk_product_fils";
5211 $sql .=
" AND pa.fk_product_pere = ".((int) $id);
5212 $sql .=
" AND pa.fk_product_fils <> ".((int) $id);
5213 $sql .=
" ORDER BY pa.rang";
5215 dol_syslog(get_class($this).
'::getChildsArbo id='.$id.
' level='.$level.
' parents='.(is_array($parents) ? implode(
',', $parents) : $parents), LOG_DEBUG);
5218 $alreadyfound = array($id => 1);
5225 $res = $this->db->query($sql);
5228 while ($rec = $this->db->fetch_array($res)) {
5229 if (!empty($alreadyfound[$rec[
'rowid']])) {
5230 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);
5231 if (in_array($rec[
'id'], $parents)) {
5235 $alreadyfound[$rec[
'rowid']] = 1;
5236 $prods[$rec[
'rowid']] = array(
5239 2 => $rec[
'fk_product_type'],
5240 3 => $this->db->escape($rec[
'label']),
5241 4 => $rec[
'incdec'],
5243 6 => $rec[
'fk_association'],
5248 if (empty($firstlevelonly)) {
5249 $parents[] = $rec[
'rowid'];
5250 $listofchilds = $this->
getChildsArbo($rec[
'rowid'], 0, $level + 1, $parents);
5251 foreach ($listofchilds as $keyChild => $valueChild) {
5252 $prods[$rec[
'rowid']][
'childs'][$keyChild] = $valueChild;
5276 foreach ($this->
getChildsArbo($this->
id) as $keyChild => $valueChild) {
5277 $parent[$this->label][$keyChild] = $valueChild;
5279 foreach ($parent as $key => $value) {
5280 $this->sousprods[$key] = $value;
5292 global $conf, $langs, $user;
5294 $langs->loadLangs(array(
'products',
'other'));
5297 $nofetch = !empty($params[
'nofetch']);
5300 return [
'optimize' => $langs->trans(
"ShowProduct")];
5304 $permissiontoreadproduct = 0;
5305 if ($this->
type == self::TYPE_PRODUCT && $user->hasRight(
'product',
'read')) {
5306 $permissiontoreadproduct = 1;
5308 if ($this->
type == self::TYPE_SERVICE && $user->hasRight(
'service',
'read')) {
5309 $permissiontoreadproduct = 1;
5312 if (!empty($this->entity) && $permissiontoreadproduct) {
5313 $tmpphoto = $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 80, 0, 0, 0, 0, 1);
5314 if ($this->nbphoto > 0) {
5315 $datas[
'photo'] =
'<div class="photointooltip floatright">'.
"\n" . $tmpphoto .
'</div>';
5320 $datas[
'picto'] =
img_picto(
'',
'product').
' <u class="paddingrightonly">'.$langs->trans(
"Product").
'</u>';
5322 $datas[
'picto'] =
img_picto(
'',
'service').
' <u class="paddingrightonly">'.$langs->trans(
"Service").
'</u>';
5324 if (isset($this->
status) && isset($this->status_buy)) {
5325 $datas[
'status'] =
' '.$this->getLibStatut(5, 0) .
' '.$this->getLibStatut(5, 1);
5328 if (!empty($this->
ref)) {
5329 $datas[
'ref'] =
'<br><b>'.$langs->trans(
'ProductRef').
':</b> '.$this->ref;
5331 if (!empty($this->label)) {
5332 $datas[
'label'] =
'<br><b>'.$langs->trans(
'ProductLabel').
':</b> '.$this->label;
5335 if ($permissiontoreadproduct) {
5340 if (isModEnabled(
'productbatch')) {
5341 $langs->load(
"productbatch");
5342 $datas[
'batchstatus'] =
"<br><b>".$langs->trans(
"ManageLotSerial").
'</b>: '.$this->
getLibStatut(0, 2);
5345 if (isModEnabled(
'barcode')) {
5346 $datas[
'barcode'] =
'<br><b>'.$langs->trans(
'BarCode').
':</b> '.$this->barcode;
5350 if ($this->weight) {
5351 $datas[
'weight'] =
"<br><b>".$langs->trans(
"Weight").
'</b>: '.$this->weight.
' '.
measuringUnitString(0,
"weight", $this->weight_units);
5354 if ($this->length) {
5355 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Length").
'</b>: '.$this->length.
' '.
measuringUnitString(0,
'size', $this->length_units);
5358 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Width").
'</b>: '.$this->width.
' '.
measuringUnitString(0,
'size', $this->width_units);
5360 if ($this->height) {
5361 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Height").
'</b>: '.$this->height.
' '.
measuringUnitString(0,
'size', $this->height_units);
5364 $datas[
'size'] =
"<br>".$labelsize;
5367 $labelsurfacevolume =
"";
5368 if ($this->surface) {
5369 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Surface").
'</b>: '.$this->surface.
' '.
measuringUnitString(0,
'surface', $this->surface_units);
5371 if ($this->volume) {
5372 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Volume").
'</b>: '.$this->volume.
' '.
measuringUnitString(0,
'volume', $this->volume_units);
5374 if ($labelsurfacevolume) {
5375 $datas[
'surface'] =
"<br>" . $labelsurfacevolume;
5381 if ($this->duration_value > 1) {
5382 $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"));
5383 } elseif ($this->duration_value > 0) {
5384 $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"));
5386 $datas[
'duration'] .= (!empty($this->duration_unit) && isset($dur[$this->duration_unit]) ?
" ".$langs->trans($dur[$this->duration_unit]) :
'');
5388 if (empty($user->socid)) {
5390 $datas[
'pmp'] =
"<br><b>".$langs->trans(
"PMPValue").
'</b>: '.
price($this->pmp, 0,
'', 1, -1, -1, $conf->currency);
5393 if (isModEnabled(
'accounting')) {
5394 if ($this->
status && isset($this->accountancy_code_sell)) {
5395 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5396 $selllabel =
'<br>';
5397 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellCode').
':</b> '.
length_accountg($this->accountancy_code_sell);
5398 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellIntraCode').
':</b> '.
length_accountg($this->accountancy_code_sell_intra);
5399 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellExportCode').
':</b> '.
length_accountg($this->accountancy_code_sell_export);
5400 $datas[
'accountancysell'] = $selllabel;
5402 if ($this->status_buy && isset($this->accountancy_code_buy)) {
5403 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5405 if (empty($this->
status)) {
5406 $buylabel .=
'<br>';
5408 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyCode').
':</b> '.
length_accountg($this->accountancy_code_buy);
5409 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyIntraCode').
':</b> '.
length_accountg($this->accountancy_code_buy_intra);
5410 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyExportCode').
':</b> '.
length_accountg($this->accountancy_code_buy_export);
5411 $datas[
'accountancybuy'] = $buylabel;
5416 if (isModEnabled(
'category') && !$nofetch) {
5417 require_once DOL_DOCUMENT_ROOT .
'/categories/class/categorie.class.php';
5418 $form =
new Form($this->db);
5419 $datas[
'categories'] =
'<br>' . $form->showCategories($this->
id, Categorie::TYPE_PRODUCT, 1);
5439 public function getNomUrl($withpicto = 0, $option =
'', $maxlength = 0, $save_lastsearch_value = -1, $notooltip = 0, $morecss =
'', $add_label = 0, $sep =
' - ')
5441 global $langs, $hookmanager;
5442 include_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
5446 $newref = $this->ref;
5448 $newref =
dol_trunc($newref, $maxlength,
'middle');
5452 'objecttype' => (isset($this->
type) ? ($this->
type == 1 ?
'service' :
'product') : $this->element),
5453 'option' => $option,
5456 $classfortooltip =
'classfortooltip';
5459 $classfortooltip =
'classforajaxtooltip';
5460 $dataparams =
' data-params="'.dol_escape_htmltag(json_encode($params)).
'"';
5467 if (empty($notooltip)) {
5469 $label = $langs->trans(
"ShowProduct");
5470 $linkclose .=
' alt="'.dol_escape_htmltag($label, 1, 1).
'"';
5472 $linkclose .= ($label ?
' title="'.dol_escape_htmltag($label, 1, 1).
'"' :
' title="tocomplete"');
5473 $linkclose .= $dataparams.
' class="nowraponall '.$classfortooltip.($morecss ?
' '.$morecss :
'').
'"';
5475 $linkclose =
' class="nowraponall'.($morecss ?
' '.$morecss :
'').
'"';
5478 if ($option ==
'supplier' || $option ==
'category') {
5479 $url = DOL_URL_ROOT.
'/product/price_suppliers.php?id='.$this->id;
5480 } elseif ($option ==
'stock') {
5481 $url = DOL_URL_ROOT.
'/product/stock/product.php?id='.$this->id;
5482 } elseif ($option ==
'composition') {
5483 $url = DOL_URL_ROOT.
'/product/composition/card.php?id='.$this->id;
5485 $url = DOL_URL_ROOT.
'/product/card.php?id='.$this->id;
5488 if ($option !==
'nolink') {
5490 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
5491 if ($save_lastsearch_value == -1 && isset($_SERVER[
"PHP_SELF"]) && preg_match(
'/list\.php/', $_SERVER[
"PHP_SELF"])) {
5492 $add_save_lastsearch_values = 1;
5494 if ($add_save_lastsearch_values) {
5495 $url .=
'&save_lastsearch_values=1';
5499 $linkstart =
'<a href="'.$url.
'"';
5500 $linkstart .= $linkclose.
'>';
5503 $result .= $linkstart;
5506 $result .= (
img_object(($notooltip ?
'' : $label),
'product',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
5509 $result .= (
img_object(($notooltip ?
'' : $label),
'service',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
5512 $result .=
'<span class="aaa">'.dol_escape_htmltag($newref).
'</span>';
5513 $result .= $linkend;
5514 if ($withpicto != 2) {
5515 $result .= (($add_label && $this->label) ? $sep.dol_trunc($this->label, ($add_label > 1 ? $add_label : 0)) :
'');
5519 $hookmanager->initHooks(array(
'productdao'));
5520 $parameters = array(
'id' => $this->
id,
'getnomurl' => &$result,
'label' => &$label);
5521 $reshook = $hookmanager->executeHooks(
'getNomUrl', $parameters, $this, $action);
5523 $result = $hookmanager->resPrint;
5525 $result .= $hookmanager->resPrint;
5542 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
5544 global $conf, $user, $langs;
5546 $langs->load(
"products");
5547 $outputlangs->load(
"products");
5554 $modelpath =
"core/modules/product/doc/";
5556 return $this->
commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
5572 return $this->
LibStatut($this->status_buy, $mode, $type);
5574 return $this->
LibStatut($this->status_batch, $mode, $type);
5577 return $this->
LibStatut($this->status_buy, $mode, $type);
5593 global $conf, $langs;
5595 $labelStatus = $labelStatusShort =
'';
5597 $langs->load(
'products');
5598 if (isModEnabled(
'productbatch')) {
5599 $langs->load(
"productbatch");
5605 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial')));
5606 return dolGetStatus($label);
5608 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort')));
5609 return dolGetStatus($label);
5613 return dolGetStatus($langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch'),
'',
'', empty($status) ?
'status5' :
'status4', 3,
'dot');
5619 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'));
5623 $statuttrans = empty($status) ?
'status5' :
'status4';
5628 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSellShort');
5629 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSell');
5630 } elseif ($type == 1) {
5631 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuyShort');
5632 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuy');
5633 } elseif ($type == 2) {
5634 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch');
5635 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort');
5637 } elseif ($status == 1) {
5640 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSellShort');
5641 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSell');
5642 } elseif ($type == 1) {
5643 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBuyShort');
5644 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBuy');
5645 } elseif ($type == 2) {
5646 $labelStatus = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial'));
5647 $labelStatusShort = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort'));
5649 } elseif ($type == 2 && $status == 2) {
5650 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSerial');
5651 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort');
5655 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'),
'',
'',
'status0', 0);
5657 return dolGetStatus($labelStatus, $labelStatusShort,
'', $statuttrans, $mode);
5670 $langs->load(
'products');
5673 if (isset($this->finished) && $this->finished >= 0) {
5674 $sql =
"SELECT label, code FROM ".$this->db->prefix().
"c_product_nature where code = ".((int) $this->finished).
" AND active=1";
5675 $resql = $this->db->query($sql);
5677 $this->error = $this->db->error().
' sql='.$sql;
5678 dol_syslog(__METHOD__.
' Error '.$this->error, LOG_ERR);
5680 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
5681 $label = $langs->trans($res[
'label']);
5683 $this->db->free($resql);
5707 public function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label =
'', $price = 0, $inventorycode =
'', $origin_element =
'', $origin_id =
null, $disablestockchangeforsubproduct = 0, $extrafields =
null)
5713 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
5719 $nbpiece = abs($nbpiece);
5722 $op[0] =
"+".trim((
string) $nbpiece);
5723 $op[1] =
"-".trim((
string) $nbpiece);
5726 $movementstock->setOrigin($origin_element, $origin_id);
5727 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'',
'',
'',
'',
false, 0, $disablestockchangeforsubproduct);
5731 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
5732 $movementstock->array_options = $array_options;
5733 $movementstock->insertExtraFields();
5735 $this->db->commit();
5738 $this->error = $movementstock->error;
5739 $this->errors = $movementstock->errors;
5741 $this->db->rollback();
5770 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)
5776 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
5782 $nbpiece = abs($nbpiece);
5786 $op[0] =
"+".trim((
string) $nbpiece);
5787 $op[1] =
"-".trim((
string) $nbpiece);
5790 $movementstock->setOrigin($origin_element, $origin_id);
5791 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'', $dlc, $dluo, $lot,
false, 0, $disablestockchangeforsubproduct, 0, $force_update_batch);
5795 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
5796 $movementstock->array_options = $array_options;
5797 $movementstock->insertExtraFields();
5799 $this->db->commit();
5802 $this->error = $movementstock->error;
5803 $this->errors = $movementstock->errors;
5805 $this->db->rollback();
5825 public function load_stock($option =
'', $includedraftpoforvirtual =
null, $dateofvirtualstock =
null)
5830 $this->stock_reel = 0;
5831 $this->stock_warehouse = array();
5832 $this->stock_theorique = 0;
5835 $warehouseStatus = array();
5836 if (preg_match(
'/warehouseclosed/', $option)) {
5839 if (preg_match(
'/warehouseopen/', $option)) {
5842 if (preg_match(
'/warehouseinternal/', $option)) {
5850 $sql =
"SELECT ps.rowid, ps.reel, ps.fk_entrepot";
5851 $sql .=
" FROM ".$this->db->prefix().
"product_stock as ps";
5852 $sql .=
", ".$this->db->prefix().
"entrepot as w";
5853 $sql .=
" WHERE w.entity IN (".getEntity(
'stock').
")";
5854 $sql .=
" AND w.rowid = ps.fk_entrepot";
5855 $sql .=
" AND ps.fk_product = ".((int) $this->
id);
5856 if (count($warehouseStatus)) {
5857 $sql .=
" AND w.statut IN (".$this->db->sanitize(implode(
',', $warehouseStatus)).
")";
5860 $sql .=
" ORDER BY ps.reel ".(getDolGlobalString(
'DO_NOT_TRY_TO_DEFRAGMENT_STOCKS_WAREHOUSE') ?
'DESC' :
'ASC');
5862 dol_syslog(get_class($this).
"::load_stock", LOG_DEBUG);
5863 $result = $this->db->query($sql);
5865 $num = $this->db->num_rows($result);
5869 $row = $this->db->fetch_object($result);
5870 $this->stock_warehouse[$row->fk_entrepot] =
new stdClass();
5871 $this->stock_warehouse[$row->fk_entrepot]->real = $row->reel;
5872 $this->stock_warehouse[$row->fk_entrepot]->id = $row->rowid;
5873 if ((!preg_match(
'/nobatch/', $option)) && $this->
hasbatch()) {
5874 $this->stock_warehouse[$row->fk_entrepot]->detail_batch =
Productbatch::findAll($this->db, $row->rowid, 1, $this->id);
5876 $this->stock_reel += $row->reel;
5880 $this->db->free($result);
5882 if (!preg_match(
'/novirtual/', $option)) {
5888 $this->error = $this->db->lasterror();
5907 global $conf, $hookmanager, $action;
5909 $stock_commande_client = 0;
5910 $stock_commande_fournisseur = 0;
5911 $stock_sending_client = 0;
5912 $stock_reception_fournisseur = 0;
5913 $stock_inproduction = 0;
5917 if (isModEnabled(
'order')) {
5922 $stock_commande_client = $this->stats_commande[
'qty'];
5924 if (isModEnabled(
"shipping")) {
5925 require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expedition.class.php';
5926 $filterShipmentStatus =
'';
5936 $stock_sending_client = $this->stats_expedition[
'qty'];
5939 if (isModEnabled(
"supplier_order")) {
5940 $filterStatus =
getDolGlobalString(
'SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK',
'3,4');
5941 if (isset($includedraftpoforvirtual)) {
5942 $filterStatus =
'0,1,2,'.$filterStatus;
5948 $stock_commande_fournisseur = $this->stats_commande_fournisseur[
'qty'];
5951 if ((isModEnabled(
"supplier_order") || isModEnabled(
"supplier_invoice")) && !isModEnabled(
'reception')) {
5953 $filterStatus =
'4';
5954 if (isset($includedraftpoforvirtual)) {
5955 $filterStatus =
'0,'.$filterStatus;
5961 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
5964 if ((isModEnabled(
"supplier_order") || isModEnabled(
"supplier_invoice")) && isModEnabled(
"reception")) {
5966 $filterStatus =
'4';
5967 if (isset($includedraftpoforvirtual)) {
5968 $filterStatus =
'0,'.$filterStatus;
5974 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
5977 if (isModEnabled(
'mrp')) {
5982 $stock_inproduction = $this->stats_mrptoproduce[
'qty'] - $this->stats_mrptoconsume[
'qty'];
5985 $this->stock_theorique = $this->stock_reel + $stock_inproduction;
5989 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
5991 $this->stock_theorique += 0;
5993 $this->stock_theorique -= $stock_commande_client;
5997 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
5999 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6001 $this->stock_theorique -= $stock_reception_fournisseur;
6003 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6006 $parameters = array(
'id' => $this->
id,
'includedraftpoforvirtual' => $includedraftpoforvirtual);
6008 $reshook = $hookmanager->executeHooks(
'loadvirtualstock', $parameters, $this, $action);
6010 $this->stock_theorique = $hookmanager->resArray[
'stock_theorique'];
6011 } elseif ($reshook == 0 && isset($hookmanager->resArray[
'stock_stats_hook'])) {
6012 $this->stock_theorique += $hookmanager->resArray[
'stock_stats_hook'];
6016 if (!empty($this->stock_warehouse) &&
getDolGlobalString(
'STOCK_ALLOW_VIRTUAL_STOCK_PER_WAREHOUSE')) {
6017 foreach ($this->stock_warehouse as $warehouseid => $stockwarehouse) {
6018 if (isModEnabled(
'mrp')) {
6025 if ($this->fk_default_warehouse == $warehouseid) {
6026 $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']);
6028 $this->stock_warehouse[$warehouseid]->virtual = $this->stock_warehouse[$warehouseid]->real + $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'];
6048 $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";
6049 $sql .=
" WHERE pb.fk_product_stock = ps.rowid AND ps.fk_product = ".((int) $this->
id).
" AND pb.batch = '".$this->db->escape($batch).
"'";
6050 $sql .=
" GROUP BY pb.batch, pb.eatby, pb.sellby";
6051 dol_syslog(get_class($this).
"::loadBatchInfo load first entry found for lot/serial = ".$batch, LOG_DEBUG);
6052 $resql = $this->db->query($sql);
6054 $num = $this->db->num_rows($resql);
6057 $obj = $this->db->fetch_object($resql);
6058 $result[] = array(
'batch' => $batch,
'eatby' => $this->db->jdate($obj->eatby),
'sellby' => $this->db->jdate($obj->sellby),
'qty' => $obj->qty);
6064 $this->db->rollback();
6082 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6088 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos";
6090 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product').dol_sanitizeFileName($this->
ref);
6095 $dir_osencoded = $dir;
6097 if (is_dir($dir_osencoded)) {
6098 $originImage = $dir.
'/'.$file[
'name'];
6109 if (is_numeric($result) && $result > 0) {
6126 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6127 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6133 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos/";
6135 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product');
6141 if (file_exists($dir_osencoded)) {
6142 $handle = opendir($dir_osencoded);
6143 if (is_resource($handle)) {
6144 while (($file = readdir($handle)) !==
false) {
6146 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6168 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6169 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6175 $handle = @opendir($dir_osencoded);
6176 if (is_resource($handle)) {
6177 while (($file = readdir($handle)) !==
false) {
6179 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6186 $photo_vignette =
'';
6188 if (preg_match(
'/('.$this->regeximgext.
')$/i', $photo, $regs)) {
6189 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $photo).
'_small'.$regs[0];
6192 $dirthumb = $dir.
'thumbs/';
6196 $obj[
'photo'] = $photo;
6197 if ($photo_vignette &&
dol_is_file($dirthumb.$photo_vignette)) {
6198 $obj[
'photo_vignette'] =
'thumbs/'.$photo_vignette;
6200 $obj[
'photo_vignette'] =
"";
6203 $tabobj[$nbphoto - 1] = $obj;
6206 if ($nbmax && $nbphoto >= $nbmax) {
6228 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6229 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6231 $dir = dirname($file).
'/';
6232 $dirthumb = $dir.
'/thumbs/';
6233 $filename = preg_replace(
'/'.preg_quote($dir,
'/').
'/i',
'', $file);
6239 if (preg_match(
'/('.$this->regeximgext.
')$/i', $filename, $regs)) {
6240 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_small'.$regs[0];
6241 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6245 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_mini'.$regs[0];
6246 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6263 $infoImg = getimagesize($file_osencoded);
6264 $this->imgWidth = $infoImg[0];
6265 $this->imgHeight = $infoImg[1];
6275 global $hookmanager;
6277 $this->nb = array();
6279 $sql =
"SELECT count(p.rowid) as nb, fk_product_type";
6280 $sql .=
" FROM ".$this->db->prefix().
"product as p";
6281 $sql .=
' WHERE p.entity IN ('.getEntity($this->element, 1).
')';
6283 if (is_object($hookmanager)) {
6284 $parameters = array();
6285 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
6286 $sql .= $hookmanager->resPrint;
6288 $sql .=
' GROUP BY fk_product_type';
6290 $resql = $this->db->query($sql);
6292 while ($obj = $this->db->fetch_object($resql)) {
6293 if ($obj->fk_product_type == 1) {
6294 $this->nb[
"services"] = $obj->nb;
6296 $this->nb[
"products"] = $obj->nb;
6299 $this->db->free($resql);
6303 $this->error = $this->db->error();
6345 return ($this->mandatory_period == 1 ?
true :
false);
6355 return ($this->status_batch > 0 ?
true :
false);
6375 $dirsociete = array_merge(array(
'/core/modules/barcode/'), $conf->modules_parts[
'barcode']);
6376 foreach ($dirsociete as $dirroot) {
6384 '@phan-var-force ModeleNumRefBarCode $module';
6386 $result = $mod->getNextValue(
$object, $type);
6388 dol_syslog(get_class($this).
"::get_barcode barcode=".$result.
" module=".$var);
6405 $this->specimen = 1;
6407 $this->
ref =
'PRODUCT_SPEC';
6408 $this->label =
'PRODUCT SPECIMEN';
6409 $this->
description =
'This is description of this product specimen that was created the '.dol_print_date($now,
'dayhourlog').
'.';
6410 $this->specimen = 1;
6411 $this->country_id = 1;
6413 $this->status_buy = 1;
6415 $this->sell_or_eat_by_mandatory = 0;
6416 $this->note_private =
'This is a comment (private)';
6417 $this->note_public =
'This is a comment (public)';
6418 $this->date_creation = $now;
6419 $this->date_modification = $now;
6422 $this->weight_units = 3;
6425 $this->length_units = 1;
6427 $this->width_units = 0;
6428 $this->height =
null;
6429 $this->height_units =
null;
6431 $this->surface = 30;
6432 $this->surface_units = 0;
6433 $this->volume = 300;
6434 $this->volume_units = 0;
6436 $this->barcode = -1;
6451 if (!$this->fk_unit) {
6455 $langs->load(
'products');
6457 $label_type =
'label';
6458 if ($type ==
'short') {
6459 $label_type =
'short_label';
6462 $sql =
"SELECT ".$label_type.
", code from ".$this->db->prefix().
"c_units where rowid = ".((int) $this->fk_unit);
6464 $resql = $this->db->query($sql);
6466 $this->error = $this->db->error();
6467 dol_syslog(get_class($this).
"::getLabelOfUnit Error ".$this->error, LOG_ERR);
6469 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
6470 $label = ($label_type ==
'short_label' ? $res[$label_type] :
'unit'.$res[
'code']);
6472 $this->db->free($resql);
6488 $maxpricesupplier = 0;
6491 include_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.product.class.php';
6493 $product_fourn_list = $product_fourn->list_product_fournisseur_price($this->
id,
'',
'');
6495 if (is_array($product_fourn_list) && count($product_fourn_list) > 0) {
6496 foreach ($product_fourn_list as $productfourn) {
6497 if ($productfourn->fourn_unitprice > $maxpricesupplier) {
6498 $maxpricesupplier = $productfourn->fourn_unitprice;
6502 $maxpricesupplier *= $conf->global->PRODUCT_MINIMUM_RECOMMENDED_PRICE;
6506 return $maxpricesupplier;
6522 require_once DOL_DOCUMENT_ROOT.
'/categories/class/categorie.class.php';
6523 return parent::setCategoriesCommon($categories, Categorie::TYPE_PRODUCT);
6537 'product_customer_price',
6538 'product_customer_price_log'
6559 $sql =
"SELECT rowid, level, fk_level, var_percent, var_min_percent FROM ".$this->db->prefix().
"product_pricerules";
6560 $query = $this->db->query($sql);
6564 while ($result = $this->db->fetch_object($query)) {
6565 $rules[$result->level] = $result;
6574 for ($i = 1; $i <= $nbofproducts; $i++) {
6575 $price = $baseprice;
6576 $price_min = $baseprice;
6580 if ($i > 1 && isset($rules[$i]->var_percent) && $rules[$i]->var_percent) {
6581 $price = $prices[$rules[$i]->fk_level] * (1 + ($rules[$i]->var_percent / 100));
6584 $prices[$i] = $price;
6587 if (isset($rules[$i]->var_min_percent) && $rules[$i]->var_min_percent) {
6588 $price_min = $price * (1 - ($rules[$i]->var_min_percent / 100));
6592 $check_amount = (($price == $this->multiprices[$i]) && ($price_min == $this->multiprices_min[$i]));
6593 $check_type = ($baseprice == $this->multiprices_base_type[$i]);
6595 if ($check_amount && $check_type) {
6599 if ($this->
updatePrice($price, $price_type, $user, $price_vat, $price_min, $i, $npr, $psq,
true) < 0) {
6617 return $user->rights->produit;
6619 return $user->rights->service;
6631 $sql =
"SELECT p.rowid, p.ref, p.datec as date_creation, p.tms as date_modification,";
6632 $sql .=
" p.fk_user_author, p.fk_user_modif";
6633 $sql .=
" FROM ".$this->db->prefix().$this->table_element.
" as p";
6634 $sql .=
" WHERE p.rowid = ".((int) $id);
6636 $result = $this->db->query($sql);
6638 if ($this->db->num_rows($result)) {
6639 $obj = $this->db->fetch_object($result);
6641 $this->
id = $obj->rowid;
6642 $this->
ref = $obj->ref;
6644 $this->user_creation_id = $obj->fk_user_author;
6645 $this->user_modification_id = $obj->fk_user_modif;
6647 $this->date_creation = $this->db->jdate($obj->date_creation);
6648 $this->date_modification = $this->db->jdate($obj->date_modification);
6651 $this->db->free($result);
6667 if (empty($this->duration_value)) {
6668 $this->errors[] =
'ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
6672 if ($this->duration_unit ==
'i') {
6673 $prodDurationHours = 1. / 60;
6675 if ($this->duration_unit ==
'h') {
6676 $prodDurationHours = 1.;
6678 if ($this->duration_unit ==
'd') {
6679 $prodDurationHours = 24.;
6681 if ($this->duration_unit ==
'w') {
6682 $prodDurationHours = 24. * 7;
6684 if ($this->duration_unit ==
'm') {
6685 $prodDurationHours = 24. * 30;
6687 if ($this->duration_unit ==
'y') {
6688 $prodDurationHours = 24. * 365;
6692 return $prodDurationHours;
6705 global $langs,$conf;
6707 $selected = (empty($arraydata[
'selected']) ? 0 : $arraydata[
'selected']);
6709 $return =
'<div class="box-flex-item box-flex-grow-zero">';
6710 $return .=
'<div class="info-box info-box-sm">';
6711 $return .=
'<div class="info-box-img">';
6714 $label .= $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 120, 160, 0, 0, 0,
'',
'photoref photokanban');
6724 $return .=
'</div>';
6725 $return .=
'<div class="info-box-content">';
6726 $return .=
'<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this,
'getNomUrl') ? $this->
getNomUrl() : $this->ref).
'</span>';
6727 if ($selected >= 0) {
6728 $return .=
'<input id="cb'.$this->id.
'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->
id.
'"'.($selected ?
' checked="checked"' :
'').
'>';
6730 if (property_exists($this,
'label')) {
6731 $return .=
'<br><span class="info-box-label opacitymedium inline-block tdoverflowmax150 valignmiddle" title="'.dol_escape_htmltag($this->label).
'">'.
dol_escape_htmltag($this->label).
'</span>';
6733 if (property_exists($this,
'price') && property_exists($this,
'price_ttc')) {
6734 if ($this->price_base_type ==
'TTC') {
6735 $return .=
'<br><span class="info-box-status amount">'.price($this->price_ttc).
' '.$langs->trans(
"TTC").
'</span>';
6738 $return .=
'<br><span class="info-box-status amount">'.price($this->
price).
' '.$langs->trans(
"HT").
'</span>';
6743 if (property_exists($this,
'stock_reel') && $this->
isProduct()) {
6744 $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>';
6747 if (method_exists($this,
'getLibStatut')) {
6749 $return .=
'<br><div class="info-box-status inline-block valignmiddle">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
6751 $return .=
'<div class="info-box-status inline-block valignmiddle marginleftonly paddingleft">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
6754 $return .=
'</div>';
6755 $return .=
'</div>';
6756 $return .=
'</div>';
6767 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.
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 object need to have its stock managed.
$duration
Service expiration label (value + unit)
setPriceExpression($expression_id)
Sets the supplier price expression.
getArrayForPriceCompare($level=0)
used to check if price have really change to avoid log pollution
get_arbo_each_prod($multiply=1, $ignore_stock_load=0)
Build the tree of subproducts and return it.
check_barcode($valuetotest, $typefortest)
Check barcode.
list_suppliers()
Return list of suppliers providing the product or service.
load_stats_mo($socid=0)
Charge tableau des stats OF pour le produit/service.
isVariant()
Return if loaded product is a variant.
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.
$product_id_already_linked
Product ID already linked to a reference supplier.
get_nb_propalsupplier($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in proposals in which product is included.
get_nb_contract($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
load_stats_facture_fournisseur($socid=0)
Charge tableau des stats facture pour le produit/service.
get_nb_ordersupplier($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
getMultiLangs()
Load array this->multilangs.
get_nb_mos($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units in orders in which product is included.
clone_associations($fromId, $toId)
Clone links between products.
create($user, $notrigger=0)
Insert product into database.
load_stats_contrat($socid=0)
Charge tableau des stats contrat pour le produit/service.
isService()
Return if object is a product.
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_npr
int French VAT NPR is used (0 or 1)
$tva_tx
Default VAT rate of product.
load_stats_bom($socid=0)
Charge tableau des stats OF pour le produit/service.
hasbatch()
Return if object has a sell-by date or eat-by date.
$weight
Metric of products.
del_sousproduit($fk_parent, $fk_child, $notrigger=0)
Remove a link between a subproduct and a parent product/service.
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)
$product_fourn_id
Id du fournisseur.
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 object have a constraint on mandatory_period.
isProduct()
Return if object is a product.
generateMultiprices(User $user, $baseprice, $price_type, $price_vat, $npr, $psq)
Generates prices for a product based on product multiprice generation rules.
LibStatut($status, $mode=0, $type=0)
Return label of a given status.
const TYPE_SERVICE
Service.
is_photo_available($sdir)
Return if at least one photo is available.
get_image_size($file)
Load size of image file.
get_nb_vente($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
Return nb of units or customers invoices in which product is included.
getTooltipContentArray($params)
getTooltipContentArray
Class to manage products or services.
Manage record for batch number management.
static findAll($dbs, $fk_product_stock, $with_qty=0, $fk_product=0)
Return all batch detail records for a given product and warehouse.
Class with list of lots and properties.
Class to manage Dolibarr users.
hasRight($module, $permlevel1, $permlevel2='')
Return if a user has a permission.
getCountry($searchkey, $withcode='', $dbtouse=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