40 require_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
41 require_once DOL_DOCUMENT_ROOT.
'/core/class/commonobject.class.php';
42 require_once DOL_DOCUMENT_ROOT.
'/product/class/productbatch.class.php';
43 require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/productlot.class.php';
44 require_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')
95 public $picto =
'product';
102 public $regeximgext =
'\.gif|\.jpg|\.jpeg|\.png|\.bmp|\.webp|\.xpm|\.xbm';
145 public $price_formated;
154 public $price_ttc_formated;
168 public $price_min_ttc;
174 public $price_base_type;
179 public $multiprices_ttc = array();
180 public $multiprices_base_type = array();
181 public $multiprices_default_vat_code = array();
182 public $multiprices_min = array();
183 public $multiprices_min_ttc = array();
184 public $multiprices_tva_tx = array();
185 public $multiprices_recuperableonly = array();
189 public $prices_by_qty = array();
190 public $prices_by_qty_id = array();
191 public $prices_by_qty_list = array();
217 public $localtax2_tx;
218 public $localtax1_type;
219 public $localtax2_type;
223 public $desc_supplier;
224 public $vatrate_supplier;
225 public $default_vat_code_supplier;
226 public $fourn_multicurrency_price;
227 public $fourn_multicurrency_unitprice;
228 public $fourn_multicurrency_tx;
229 public $fourn_multicurrency_id;
230 public $fourn_multicurrency_code;
236 public $qc_frequency;
243 public $stock_reel = 0;
250 public $stock_theorique;
267 public $seuil_stock_alerte = 0;
290 public $fk_default_workstation;
312 public $status_buy = 0;
334 public $fk_default_bom;
341 public $product_fourn_price_id;
363 public $status_batch = 0;
370 public $sell_or_eat_by_mandatory = 0;
377 public $batch_mask =
'';
395 public $weight_units;
397 public $length_units;
401 public $height_units;
403 public $surface_units;
405 public $volume_units;
408 public $net_measure_units;
410 public $accountancy_code_sell;
411 public $accountancy_code_sell_intra;
412 public $accountancy_code_sell_export;
413 public $accountancy_code_buy;
414 public $accountancy_code_buy_intra;
415 public $accountancy_code_buy_export;
425 public $barcode_type;
430 public $barcode_type_code;
432 public $stats_propale = array();
433 public $stats_commande = array();
434 public $stats_contrat = array();
435 public $stats_facture = array();
436 public $stats_proposal_supplier = array();
437 public $stats_commande_fournisseur = array();
438 public $stats_expedition = array();
439 public $stats_reception = array();
440 public $stats_mo = array();
441 public $stats_bom = array();
442 public $stats_mrptoconsume = array();
443 public $stats_mrptoproduce = array();
444 public $stats_facturerec = array();
445 public $stats_facture_fournisseur = array();
454 public $date_creation;
459 public $date_modification;
475 public $fk_default_warehouse;
479 public $fk_price_expression;
484 public $fourn_price_base_type;
500 public $ref_supplier;
514 public $price_autogen = 0;
521 public $supplierprices;
541 public $is_object_used;
543 public $is_sousproduit_qty;
544 public $is_sousproduit_incdec;
546 public $mandatory_period;
577 public $fields = array(
578 'rowid' => array(
'type' =>
'integer',
'label' =>
'TechnicalID',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'index' => 1,
'position' => 1,
'comment' =>
'Id'),
579 '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'),
580 'entity' => array(
'type' =>
'integer',
'label' =>
'Entity',
'enabled' => 1,
'visible' => 0,
'default' =>
'1',
'notnull' => 1,
'index' => 1,
'position' => 5),
581 'label' => array(
'type' =>
'varchar(255)',
'label' =>
'Label',
'enabled' => 1,
'visible' => 1,
'notnull' => 1,
'showoncombobox' => 2,
'position' => 15,
'csslist' =>
'tdoverflowmax250'),
582 'barcode' => array(
'type' =>
'varchar(255)',
'label' =>
'Barcode',
'enabled' =>
'isModEnabled("barcode")',
'position' => 20,
'visible' => -1,
'showoncombobox' => 3,
'cssview' =>
'tdwordbreak',
'csslist' =>
'tdoverflowmax125'),
583 'fk_barcode_type' => array(
'type' =>
'integer',
'label' =>
'BarcodeType',
'enabled' => 1,
'position' => 21,
'notnull' => 0,
'visible' => -1,),
584 'note_public' => array(
'type' =>
'html',
'label' =>
'NotePublic',
'enabled' => 1,
'visible' => 0,
'position' => 61),
585 'note' => array(
'type' =>
'html',
'label' =>
'NotePrivate',
'enabled' => 1,
'visible' => 0,
'position' => 62),
586 'datec' => array(
'type' =>
'datetime',
'label' =>
'DateCreation',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 500),
587 'tms' => array(
'type' =>
'timestamp',
'label' =>
'DateModification',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 501),
589 'fk_user_author' => array(
'type' =>
'integer',
'label' =>
'UserAuthor',
'enabled' => 1,
'visible' => -2,
'notnull' => 1,
'position' => 510,
'foreignkey' =>
'llx_user.rowid'),
590 'fk_user_modif' => array(
'type' =>
'integer',
'label' =>
'UserModif',
'enabled' => 1,
'visible' => -2,
'notnull' => -1,
'position' => 511),
592 'localtax1_tx' => array(
'type' =>
'double(6,3)',
'label' =>
'Localtax1tx',
'enabled' => 1,
'position' => 150,
'notnull' => 0,
'visible' => -1,),
593 'localtax1_type' => array(
'type' =>
'varchar(10)',
'label' =>
'Localtax1type',
'enabled' => 1,
'position' => 155,
'notnull' => 1,
'visible' => -1,),
594 'localtax2_tx' => array(
'type' =>
'double(6,3)',
'label' =>
'Localtax2tx',
'enabled' => 1,
'position' => 160,
'notnull' => 0,
'visible' => -1,),
595 'localtax2_type' => array(
'type' =>
'varchar(10)',
'label' =>
'Localtax2type',
'enabled' => 1,
'position' => 165,
'notnull' => 1,
'visible' => -1,),
596 'last_main_doc' => array(
'type' =>
'varchar(255)',
'label' =>
'LastMainDoc',
'enabled' => 1,
'visible' => -1,
'position' => 170),
597 'import_key' => array(
'type' =>
'varchar(14)',
'label' =>
'ImportId',
'enabled' => 1,
'visible' => -2,
'notnull' => -1,
'index' => 0,
'position' => 1000),
600 'mandatory_period' => array(
'type' =>
'integer',
'label' =>
'mandatoryperiod',
'enabled' => 1,
'visible' => 1,
'notnull' => 1,
'default' =>
'0',
'index' => 1,
'position' => 1000),
621 $this->ismultientitymanaged = 1;
622 $this->isextrafieldmanaged = 1;
635 $this->
ref = trim($this->
ref);
663 public function create($user, $notrigger = 0)
665 global $conf, $langs;
671 $this->
ref = trim($this->
ref);
675 $this->label = trim($this->label);
680 $this->price_label = trim($this->price_label);
681 if (empty($this->tva_tx)) {
684 if (empty($this->tva_npr)) {
688 if (empty($this->localtax1_tx)) {
689 $this->localtax1_tx = 0;
691 if (empty($this->localtax2_tx)) {
692 $this->localtax2_tx = 0;
694 if (empty($this->localtax1_type)) {
695 $this->localtax1_type =
'0';
697 if (empty($this->localtax2_type)) {
698 $this->localtax2_type =
'0';
700 if (empty($this->
price)) {
703 if (empty($this->price_min)) {
704 $this->price_min = 0;
707 if (empty($this->price_by_qty)) {
708 $this->price_by_qty = 0;
711 if (empty($this->
status)) {
714 if (empty($this->status_buy)) {
715 $this->status_buy = 0;
724 if ($this->price_base_type ==
'TTC' && $this->price_ttc > 0) {
725 $price_ttc =
price2num($this->price_ttc,
'MU');
726 $price_ht =
price2num($this->price_ttc / (1 + ($this->tva_tx / 100)),
'MU');
730 if ($this->price_base_type !=
'TTC' && $this->
price > 0) {
732 $price_ttc =
price2num($this->
price * (1 + ($this->tva_tx / 100)),
'MU');
736 if (($this->price_min_ttc > 0) && ($this->price_base_type ==
'TTC')) {
737 $price_min_ttc =
price2num($this->price_min_ttc,
'MU');
738 $price_min_ht =
price2num($this->price_min_ttc / (1 + ($this->tva_tx / 100)),
'MU');
742 if (($this->price_min > 0) && ($this->price_base_type !=
'TTC')) {
743 $price_min_ht =
price2num($this->price_min,
'MU');
744 $price_min_ttc =
price2num($this->price_min * (1 + ($this->tva_tx / 100)),
'MU');
747 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
748 $this->accountancy_code_buy_intra = trim($this->accountancy_code_buy_intra);
749 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
750 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
751 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
752 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
755 $this->barcode = trim($this->barcode);
756 $this->mandatory_period = empty($this->mandatory_period) ? 0 : $this->mandatory_period;
758 if (empty($this->label)) {
759 $this->error =
'ErrorMandatoryParametersNotProvided';
763 if (empty($this->
ref) || $this->
ref ==
'auto') {
766 if ($module !=
'mod_codeproduct_leopard') {
767 if (substr($module, 0, 16) ==
'mod_codeproduct_' && substr($module, -3) ==
'php') {
768 $module = substr($module, 0,
dol_strlen($module) - 4);
771 $modCodeProduct =
new $module();
772 '@phan-var-force ModeleProductCode $modCodeProduct';
773 if (!empty($modCodeProduct->code_auto)) {
774 $this->
ref = $modCodeProduct->getNextValue($this, $this->
type);
776 unset($modCodeProduct);
779 if (empty($this->
ref)) {
780 $this->error =
'ProductModuleNotSetupForAutoRef';
785 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);
789 if (empty($this->date_creation)) {
790 $this->date_creation = $now;
796 if ($this->barcode == -1) {
797 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
802 $result = $this->
verify();
805 $sql =
"SELECT count(*) as nb";
806 $sql .=
" FROM ".$this->db->prefix().
"product";
807 $sql .=
" WHERE entity IN (".getEntity(
'product').
")";
808 $sql .=
" AND ref = '".$this->db->escape($this->
ref).
"'";
810 $result = $this->db->query(
$sql);
812 $obj = $this->db->fetch_object($result);
815 $sql =
"INSERT INTO ".$this->db->prefix().
"product (";
820 $sql .=
", price_min";
821 $sql .=
", price_min_ttc";
823 $sql .=
", fk_user_author";
824 $sql .=
", fk_product_type";
826 $sql .=
", price_ttc";
827 $sql .=
", price_base_type";
828 $sql .=
", price_label";
832 $sql .=
", accountancy_code_buy";
833 $sql .=
", accountancy_code_buy_intra";
834 $sql .=
", accountancy_code_buy_export";
835 $sql .=
", accountancy_code_sell";
836 $sql .=
", accountancy_code_sell_intra";
837 $sql .=
", accountancy_code_sell_export";
840 $sql .=
", finished";
842 $sql .=
", sell_or_eat_by_mandatory";
843 $sql .=
", batch_mask";
845 $sql .=
", mandatory_period";
846 $sql .=
") VALUES (";
847 $sql .=
"'".$this->db->idate($this->date_creation).
"'";
848 $sql .=
", ".(!empty($this->entity) ? (int) $this->entity : (
int) $conf->entity);
849 $sql .=
", '".$this->db->escape($this->
ref).
"'";
850 $sql .=
", ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
851 $sql .=
", ".price2num($price_min_ht);
852 $sql .=
", ".price2num($price_min_ttc);
853 $sql .=
", ".(!empty($this->label) ?
"'".$this->db->escape($this->label).
"'" :
"null");
854 $sql .=
", ".((int) $user->id);
856 $sql .=
", ".price2num($price_ht,
'MT');
857 $sql .=
", ".price2num($price_ttc,
'MT');
858 $sql .=
", '".$this->db->escape($this->price_base_type).
"'";
859 $sql .=
", ".(!empty($this->price_label) ?
"'".$this->db->escape($this->price_label).
"'" :
"null");
861 $sql .=
", ".((int) $this->status_buy);
863 $sql .=
", '".$this->db->escape($this->accountancy_code_buy).
"'";
864 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_intra).
"'";
865 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_export).
"'";
866 $sql .=
", '".$this->db->escape($this->accountancy_code_sell).
"'";
867 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_intra).
"'";
868 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_export).
"'";
870 $sql .=
", '".$this->db->escape($this->canvas).
"'";
871 $sql .=
", ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
'NULL' : (
int) $this->finished);
872 $sql .=
", ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : ((
int) $this->status_batch));
873 $sql .=
", ".((empty($this->sell_or_eat_by_mandatory) || $this->sell_or_eat_by_mandatory < 0) ? 0 : ((
int) $this->sell_or_eat_by_mandatory));
874 $sql .=
", '".$this->db->escape($this->batch_mask).
"'";
875 $sql .=
", ".($this->fk_unit > 0 ? ((int) $this->fk_unit) :
'NULL');
876 $sql .=
", '".$this->db->escape($this->mandatory_period).
"'";
879 dol_syslog(get_class($this).
"::Create", LOG_DEBUG);
881 $result = $this->db->query(
$sql);
883 $id = $this->db->last_insert_id($this->db->prefix().
"product");
887 $this->
price = $price_ht;
888 $this->price_ttc = $price_ttc;
889 $this->price_min = $price_min_ht;
890 $this->price_min_ttc = $price_min_ttc;
894 if ($this->
update($id, $user,
true,
'add') <= 0) {
899 $this->error = $this->db->lasterror();
904 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " .((int) $this->id) .
" AND entity = " . ((
int) $conf->entity));
906 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
907 $sql .=
" fk_product";
909 $sql .=
", accountancy_code_buy";
910 $sql .=
", accountancy_code_buy_intra";
911 $sql .=
", accountancy_code_buy_export";
912 $sql .=
", accountancy_code_sell";
913 $sql .=
", accountancy_code_sell_intra";
914 $sql .=
", accountancy_code_sell_export";
915 $sql .=
") VALUES (";
917 $sql .=
", " . $conf->entity;
918 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
919 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
920 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
921 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
922 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
923 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
925 $result = $this->db->query(
$sql);
928 $this->error =
'ErrorFailedToInsertAccountancyForEntity';
933 $this->error =
'ErrorFailedToGetInsertedId';
937 $this->error = $this->db->lasterror();
941 $langs->load(
"products");
943 $this->error =
"ErrorProductAlreadyExists";
944 dol_syslog(get_class($this).
"::Create fails, ref ".$this->
ref.
" already exists");
948 $this->error = $this->db->lasterror();
951 if (!$error && !$notrigger) {
964 $this->db->rollback();
968 $this->db->rollback();
969 dol_syslog(get_class($this).
"::Create fails verify ".implode(
',', $this->errors), LOG_WARNING);
985 $this->errors = array();
988 $this->
ref = trim($this->
ref);
991 $this->errors[] =
'ErrorBadRef';
995 $arrayofnonnegativevalue = array(
'weight' =>
'Weight',
'width' =>
'Width',
'height' =>
'Height',
'length' =>
'Length',
'surface' =>
'Surface',
'volume' =>
'Volume');
996 foreach ($arrayofnonnegativevalue as $key => $value) {
997 if (property_exists($this, $key) && !empty($this->$key) && ($this->$key < 0)) {
998 $langs->loadLangs(array(
"main",
"other"));
999 $this->error = $langs->trans(
"FieldCannotBeNegative", $langs->transnoentitiesnoconv($value));
1000 $this->errors[] = $this->error;
1005 $rescode = $this->
check_barcode($this->barcode, $this->barcode_type_code);
1007 if ($rescode == -1) {
1008 $this->errors[] =
'ErrorBadBarCodeSyntax';
1009 } elseif ($rescode == -2) {
1010 $this->errors[] =
'ErrorBarCodeRequired';
1011 } elseif ($rescode == -3) {
1013 $this->errors[] =
'ErrorBarCodeAlreadyUsed';
1038 $module = strtolower($conf->global->BARCODE_PRODUCT_ADDON_NUM);
1040 $dirsociete = array_merge(array(
'/core/modules/barcode/'), $conf->modules_parts[
'barcode']);
1041 foreach ($dirsociete as $dirroot) {
1048 $mod =
new $module();
1049 '@phan-var-force ModeleNumRefBarCode $mod';
1051 dol_syslog(get_class($this).
"::check_barcode value=".$valuetotest.
" type=".$typefortest.
" module=".$module);
1052 $result = $mod->verif($this->db, $valuetotest, $this, 0, $typefortest);
1070 public function update($id, $user, $notrigger = 0, $action =
'update', $updatetype =
false)
1072 global $langs, $conf, $hookmanager;
1077 if (!$this->label) {
1078 $this->label =
'MISSING LABEL';
1083 $this->
ref = trim($this->
ref);
1087 $this->label = trim($this->label);
1089 $this->note_private = (isset($this->note_private) ? trim($this->note_private) :
null);
1090 $this->note_public = (isset($this->note_public) ? trim($this->note_public) :
null);
1091 $this->net_measure =
price2num($this->net_measure);
1092 $this->net_measure_units = (empty($this->net_measure_units) ?
'' : trim($this->net_measure_units));
1093 $this->weight =
price2num($this->weight);
1094 $this->weight_units = (empty($this->weight_units) ?
'' : trim($this->weight_units));
1095 $this->length =
price2num($this->length);
1096 $this->length_units = (empty($this->length_units) ?
'' : trim($this->length_units));
1098 $this->width_units = (empty($this->width_units) ?
'' : trim($this->width_units));
1099 $this->height =
price2num($this->height);
1100 $this->height_units = (empty($this->height_units) ?
'' : trim($this->height_units));
1101 $this->surface =
price2num($this->surface);
1102 $this->surface_units = (empty($this->surface_units) ?
'' : trim($this->surface_units));
1103 $this->volume =
price2num($this->volume);
1104 $this->volume_units = (empty($this->volume_units) ?
'' : trim($this->volume_units));
1107 if (is_numeric($this->length_units)) {
1108 $this->width_units = $this->length_units;
1110 if (is_numeric($this->length_units)) {
1111 $this->height_units = $this->length_units;
1115 if (empty($this->surface) && !empty($this->length) && !empty($this->width) && $this->length_units == $this->width_units) {
1116 $this->surface = (
float) $this->length * (
float) $this->width;
1119 if (empty($this->volume) && !empty($this->surface) && !empty($this->height) && $this->length_units == $this->height_units) {
1120 $this->volume = $this->surface * (
float) $this->height;
1124 if (empty($this->tva_tx)) {
1127 if (empty($this->tva_npr)) {
1130 if (empty($this->localtax1_tx)) {
1131 $this->localtax1_tx = 0;
1133 if (empty($this->localtax2_tx)) {
1134 $this->localtax2_tx = 0;
1136 if (empty($this->localtax1_type)) {
1137 $this->localtax1_type =
'0';
1139 if (empty($this->localtax2_type)) {
1140 $this->localtax2_type =
'0';
1142 if (empty($this->
status)) {
1145 if (empty($this->status_buy)) {
1146 $this->status_buy = 0;
1149 if (empty($this->country_id)) {
1150 $this->country_id = 0;
1153 if (empty($this->state_id)) {
1154 $this->state_id = 0;
1158 $this->barcode = (empty($this->barcode) ?
'' : trim($this->barcode));
1160 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
1161 $this->accountancy_code_buy_intra = (!empty($this->accountancy_code_buy_intra) ? trim($this->accountancy_code_buy_intra) :
'');
1162 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
1163 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
1164 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
1165 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
1172 if ($action !=
'add') {
1173 $result = $this->
verify();
1181 if (empty($this->oldcopy)) {
1186 if ($this->
hasbatch() && !$this->oldcopy->hasbatch()) {
1188 $valueforundefinedlot =
'000000';
1193 dol_syslog(
"Flag batch of product id=".$this->
id.
" is set to ON, so we will create missing records into product_batch");
1196 foreach ($this->stock_warehouse as $idW => $ObjW) {
1198 foreach ($ObjW->detail_batch as $detail) {
1199 if ($detail->batch == $valueforundefinedlot || $detail->batch ==
'Undefined') {
1201 $sqlclean =
"DELETE FROM ".$this->db->prefix().
"product_batch WHERE batch in('Undefined', '".$this->db->escape($valueforundefinedlot).
"') AND fk_product_stock = ".((int) $ObjW->id);
1202 $result = $this->db->query($sqlclean);
1210 $qty_batch += $detail->qty;
1214 if ($ObjW->real != $qty_batch) {
1216 $ObjBatch->batch = $valueforundefinedlot;
1217 $ObjBatch->qty = ($ObjW->real - $qty_batch);
1218 $ObjBatch->fk_product_stock = $ObjW->id;
1220 if ($ObjBatch->create($user, 1) < 0) {
1222 $this->errors = $ObjBatch->errors;
1227 if ($ObjLot->fetch(0, $this->id, $valueforundefinedlot) == 0) {
1228 $ObjLot->fk_product = $this->id;
1229 $ObjLot->entity = $this->entity;
1230 $ObjLot->fk_user_creat = $user->id;
1231 $ObjLot->batch = $valueforundefinedlot;
1232 if ($ObjLot->create($user,
true) < 0) {
1234 $this->errors = $ObjLot->errors;
1243 if ($this->barcode == -1) {
1244 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1247 $sql =
"UPDATE ".$this->db->prefix().
"product";
1248 $sql .=
" SET label = '".$this->db->escape($this->label).
"'";
1251 $sql .=
", fk_product_type = ".((int) $this->
type);
1254 $sql .=
", ref = '".$this->db->escape($this->
ref).
"'";
1255 $sql .=
", ref_ext = ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1256 $sql .=
", default_vat_code = ".($this->default_vat_code ?
"'".$this->db->escape($this->default_vat_code).
"'" :
"null");
1257 $sql .=
", tva_tx = ".((float) $this->tva_tx);
1258 $sql .=
", recuperableonly = ".((int) $this->tva_npr);
1259 $sql .=
", localtax1_tx = ".((float) $this->localtax1_tx);
1260 $sql .=
", localtax2_tx = ".((float) $this->localtax2_tx);
1261 $sql .=
", localtax1_type = ".($this->localtax1_type !=
'' ?
"'".$this->db->escape($this->localtax1_type).
"'" :
"'0'");
1262 $sql .=
", localtax2_type = ".($this->localtax2_type !=
'' ?
"'".$this->db->escape($this->localtax2_type).
"'" :
"'0'");
1264 $sql .=
", barcode = ".(empty($this->barcode) ?
"null" :
"'".$this->db->escape($this->barcode).
"'");
1265 $sql .=
", fk_barcode_type = ".(empty($this->barcode_type) ?
"null" : $this->db->escape($this->barcode_type));
1268 $sql .=
", tobuy = ".(int) $this->status_buy;
1269 $sql .=
", tobatch = ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : (
int) $this->status_batch);
1270 $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);
1271 $sql .=
", batch_mask = '".$this->db->escape($this->batch_mask).
"'";
1273 $sql .=
", finished = ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
"null" : (
int) $this->finished);
1274 $sql .=
", fk_default_bom = ".((!isset($this->fk_default_bom) || $this->fk_default_bom < 0 || $this->fk_default_bom ==
'') ?
"null" : (
int) $this->fk_default_bom);
1275 $sql .=
", net_measure = ".($this->net_measure !=
'' ?
"'".$this->db->escape($this->net_measure).
"'" :
'null');
1276 $sql .=
", net_measure_units = ".($this->net_measure_units !=
'' ?
"'".$this->db->escape($this->net_measure_units).
"'" :
'null');
1277 $sql .=
", weight = ".($this->weight !=
'' ?
"'".$this->db->escape($this->weight).
"'" :
'null');
1278 $sql .=
", weight_units = ".($this->weight_units !=
'' ?
"'".$this->db->escape($this->weight_units).
"'" :
'null');
1279 $sql .=
", length = ".($this->length !=
'' ?
"'".$this->db->escape($this->length).
"'" :
'null');
1280 $sql .=
", length_units = ".($this->length_units !=
'' ?
"'".$this->db->escape($this->length_units).
"'" :
'null');
1281 $sql .=
", width= ".($this->width !=
'' ?
"'".$this->db->escape($this->width).
"'" :
'null');
1282 $sql .=
", width_units = ".($this->width_units !=
'' ?
"'".$this->db->escape($this->width_units).
"'" :
'null');
1283 $sql .=
", height = ".($this->height !=
'' ?
"'".$this->db->escape($this->height).
"'" :
'null');
1284 $sql .=
", height_units = ".($this->height_units !=
'' ?
"'".$this->db->escape($this->height_units).
"'" :
'null');
1285 $sql .=
", surface = ".($this->surface !=
'' ?
"'".$this->db->escape($this->surface).
"'" :
'null');
1286 $sql .=
", surface_units = ".($this->surface_units !=
'' ?
"'".$this->db->escape($this->surface_units).
"'" :
'null');
1287 $sql .=
", volume = ".($this->volume !=
'' ?
"'".$this->db->escape($this->volume).
"'" :
'null');
1288 $sql .=
", volume_units = ".($this->volume_units !=
'' ?
"'".$this->db->escape($this->volume_units).
"'" :
'null');
1289 $sql .=
", fk_default_warehouse = ".($this->fk_default_warehouse > 0 ? ((int) $this->fk_default_warehouse) :
'null');
1290 $sql .=
", fk_default_workstation = ".($this->fk_default_workstation > 0 ? ((int) $this->fk_default_workstation) :
'null');
1291 $sql .=
", seuil_stock_alerte = ".((isset($this->seuil_stock_alerte) && is_numeric($this->seuil_stock_alerte)) ? (
float) $this->seuil_stock_alerte :
'null');
1292 $sql .=
", description = '".$this->db->escape($this->
description).
"'";
1293 $sql .=
", url = ".($this->url ?
"'".$this->db->escape($this->url).
"'" :
'null');
1294 $sql .=
", customcode = '".$this->db->escape($this->customcode).
"'";
1295 $sql .=
", fk_country = ".($this->country_id > 0 ? (int) $this->country_id :
'null');
1296 $sql .=
", fk_state = ".($this->state_id > 0 ? (int) $this->state_id :
'null');
1297 $sql .=
", lifetime = ".($this->lifetime > 0 ? (int) $this->lifetime :
'null');
1298 $sql .=
", qc_frequency = ".($this->qc_frequency > 0 ? (int) $this->qc_frequency :
'null');
1299 $sql .=
", note = ".(isset($this->note_private) ?
"'".$this->db->escape($this->note_private).
"'" :
'null');
1300 $sql .=
", note_public = ".(isset($this->note_public) ?
"'".$this->db->escape($this->note_public).
"'" :
'null');
1301 $sql .=
", duration = '".$this->db->escape($this->duration_value.$this->duration_unit).
"'";
1303 $sql .=
", accountancy_code_buy = '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1304 $sql .=
", accountancy_code_buy_intra = '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1305 $sql .=
", accountancy_code_buy_export = '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1306 $sql .=
", accountancy_code_sell= '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1307 $sql .=
", accountancy_code_sell_intra= '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1308 $sql .=
", accountancy_code_sell_export= '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1310 $sql .=
", desiredstock = ".((isset($this->desiredstock) && is_numeric($this->desiredstock)) ? (
float) $this->desiredstock :
"null");
1311 $sql .=
", cost_price = ".($this->cost_price !=
'' ? $this->db->escape($this->cost_price) :
'null');
1312 $sql .=
", fk_unit= ".(!$this->fk_unit ?
'NULL' : (int) $this->fk_unit);
1313 $sql .=
", price_autogen = ".(!$this->price_autogen ? 0 : 1);
1314 $sql .=
", fk_price_expression = ".($this->fk_price_expression != 0 ? (int) $this->fk_price_expression :
'NULL');
1315 $sql .=
", fk_user_modif = ".($user->id > 0 ? $user->id :
'NULL');
1316 $sql .=
", mandatory_period = ".($this->mandatory_period);
1318 $sql .=
" WHERE rowid = ".((int) $id);
1320 dol_syslog(get_class($this).
"::update", LOG_DEBUG);
1322 $resql = $this->db->query(
$sql);
1329 $this->error = $langs->trans(
"Error").
" : ".$this->db->error().
" - ".
$sql;
1330 $this->db->rollback();
1339 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " . ((
int) $this->id) .
" AND entity = " . ((
int) $conf->entity));
1341 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1342 $sql .=
" fk_product";
1344 $sql .=
", accountancy_code_buy";
1345 $sql .=
", accountancy_code_buy_intra";
1346 $sql .=
", accountancy_code_buy_export";
1347 $sql .=
", accountancy_code_sell";
1348 $sql .=
", accountancy_code_sell_intra";
1349 $sql .=
", accountancy_code_sell_export";
1350 $sql .=
") VALUES (";
1352 $sql .=
", " . $conf->entity;
1353 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1354 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1355 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1356 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1357 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1358 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1360 $result = $this->db->query(
$sql);
1363 $this->error =
'ErrorFailedToUpdateAccountancyForEntity';
1367 if (!$this->
hasbatch() && $this->oldcopy->hasbatch()) {
1369 $sql =
'SELECT pb.qty, ps.fk_entrepot, pb.batch FROM '.MAIN_DB_PREFIX.
'product_batch as pb';
1370 $sql .=
' INNER JOIN '.MAIN_DB_PREFIX.
'product_stock as ps ON (ps.rowid = pb.fk_product_stock)';
1371 $sql .=
' WHERE ps.fk_product = '.(int) $this->
id;
1373 $resql = $this->db->query(
$sql);
1377 while ($obj = $this->db->fetch_object($resql)) {
1379 $fk_entrepot = $obj->fk_entrepot;
1383 $batch = $obj->batch;
1386 $addOremove = $value > 0 ? 1 : 0;
1387 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1388 $res = $this->
correct_stock_batch($user, $fk_entrepot, abs($value), $addOremove, $label, $price, $dlc, $dluo, $batch, $inventorycode,
'',
null, 0,
null,
true);
1391 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1392 $res = $this->
correct_stock($user, $fk_entrepot, abs($value), (
int) empty($addOremove), $label, $price, $inventorycode,
'',
null, 0);
1411 if (!$error && !$notrigger) {
1413 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
1420 if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) {
1422 if ($conf->product->dir_output) {
1425 if (file_exists($olddir)) {
1429 $res = @rename($olddir, $newdir);
1431 $langs->load(
"errors");
1432 $this->error = $langs->trans(
'ErrorFailToRenameDir', $olddir, $newdir);
1441 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1445 foreach ($comb->fetchAllByFkProductParent($this->id) as $currcomb) {
1446 $currcomb->updateProperties($this, $user);
1450 $this->db->commit();
1453 $this->db->rollback();
1457 if ($this->db->errno() ==
'DB_ERROR_RECORD_ALREADY_EXISTS') {
1458 $langs->load(
"errors");
1459 if (empty($conf->barcode->enabled) || empty($this->barcode)) {
1460 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductAlreadyExists", $this->
ref);
1462 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductBarCodeAlreadyExists", $this->barcode);
1464 $this->errors[] = $this->error;
1465 $this->db->rollback();
1468 $this->error = $langs->trans(
"Error").
" : ".$this->db->error().
" - ".
$sql;
1469 $this->errors[] = $this->error;
1470 $this->db->rollback();
1475 $this->db->rollback();
1476 dol_syslog(get_class($this).
"::Update fails verify ".implode(
',', $this->errors), LOG_WARNING);
1488 public function delete(
User $user, $notrigger = 0)
1490 global $conf, $langs;
1491 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
1496 if (empty($this->
id)) {
1497 $this->error =
"Object must be fetched before calling delete";
1501 $this->error =
"ErrorForbidden";
1506 if (empty($objectisused)) {
1509 if (!$error && empty($notrigger)) {
1511 $result = $this->
call_trigger(
'PRODUCT_DELETE', $user);
1520 $sql =
"DELETE FROM ".$this->db->prefix().
'product_batch';
1521 $sql .=
" WHERE fk_product_stock IN (";
1522 $sql .=
"SELECT rowid FROM ".$this->db->prefix().
'product_stock';
1523 $sql .=
" WHERE fk_product = ".((int) $this->
id).
")";
1525 $result = $this->db->query(
$sql);
1528 $this->errors[] = $this->db->lasterror();
1534 $elements = array(
'product_fournisseur_price',
'product_price',
'product_lang',
'categorie_product',
'product_stock',
'product_customer_price',
'product_lot');
1535 foreach ($elements as $table) {
1537 $sql =
"DELETE FROM ".$this->db->prefix().$table;
1538 $sql .=
" WHERE fk_product = ".(int) $this->
id;
1540 $result = $this->db->query(
$sql);
1543 $this->errors[] = $this->db->lasterror();
1550 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1551 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination2ValuePair.class.php';
1556 if ($prodcomb->deleteByFkProductParent($user, $this->id) < 0) {
1558 $this->errors[] =
'Error deleting combinations';
1562 if (!$error && ($prodcomb->fetchByFkProductChild($this->id) > 0) && ($prodcomb->delete($user) < 0)) {
1564 $this->errors[] =
'Error deleting child combination';
1570 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
1571 $sql .=
" WHERE fk_product_pere = ".(int) $this->
id.
" OR fk_product_fils = ".(
int) $this->id;
1573 $result = $this->db->query(
$sql);
1576 $this->errors[] = $this->db->lasterror();
1585 dol_syslog(get_class($this).
"::delete error -4 ".$this->error, LOG_ERR);
1591 $sqlz =
"DELETE FROM ".$this->db->prefix().
"product";
1592 $sqlz .=
" WHERE rowid = ".(int) $this->
id;
1594 $resultz = $this->db->query($sqlz);
1597 $this->errors[] = $this->db->lasterror();
1613 if ($conf->product->dir_output) {
1614 $dir = $conf->product->dir_output.
"/".$ref;
1615 if (file_exists($dir)) {
1618 $this->errors[] =
'ErrorFailToDeleteDir';
1626 $this->db->commit();
1629 foreach ($this->errors as $errmsg) {
1630 dol_syslog(get_class($this).
"::delete ".$errmsg, LOG_ERR);
1631 $this->error .= ($this->error ?
', '.$errmsg : $errmsg);
1633 $this->db->rollback();
1637 $this->error =
"ErrorRecordIsUsedCantDelete";
1651 $sellByLabel = $langs->trans(
'SellByDate');
1652 $eatByLabel = $langs->trans(
'EatByDate');
1654 self::SELL_OR_EAT_BY_MANDATORY_ID_NONE => $langs->trans(
'BatchSellOrEatByMandatoryNone'),
1655 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY => $sellByLabel,
1656 self::SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY => $eatByLabel,
1657 self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT => $langs->trans(
'BatchSellOrEatByMandatoryAll', $sellByLabel, $eatByLabel),
1668 $sellOrEatByMandatoryLabel =
'';
1671 if (isset($sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory])) {
1672 $sellOrEatByMandatoryLabel = $sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory];
1675 return $sellOrEatByMandatoryLabel;
1686 global $conf, $langs;
1688 $langs_available = $langs->get_available_languages(DOL_DOCUMENT_ROOT, 0, 2);
1689 $current_lang = $langs->getDefaultLang();
1691 foreach ($langs_available as $key => $value) {
1692 if ($key == $current_lang) {
1693 $sql =
"SELECT rowid";
1694 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1695 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1696 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
1698 $result = $this->db->query(
$sql);
1700 if ($this->db->num_rows($result)) {
1701 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
1703 $sql2 .=
" label='".$this->db->escape($this->label).
"',";
1704 $sql2 .=
" description='".$this->db->escape($this->
description).
"'";
1706 $sql2 .=
", note='".$this->db->escape($this->other).
"'";
1708 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
1710 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
1715 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->label).
"',";
1716 $sql2 .=
" '".$this->db->escape($this->
description).
"'";
1718 $sql2 .=
", '".$this->db->escape($this->other).
"'";
1722 dol_syslog(get_class($this).
'::setMultiLangs key = current_lang = '.$key);
1723 if (!$this->db->query($sql2)) {
1724 $this->error = $this->db->lasterror();
1727 } elseif (isset($this->multilangs[$key])) {
1728 if (empty($this->multilangs[
"$key"][
"label"])) {
1729 $this->errors[] = $key .
' : ' . $langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Label"));
1733 $sql =
"SELECT rowid";
1734 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1735 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1736 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
1738 $result = $this->db->query(
$sql);
1740 if ($this->db->num_rows($result)) {
1741 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
1743 $sql2 .=
" label = '".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
1744 $sql2 .=
" description = '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
1746 $sql2 .=
", note = '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
1748 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
1750 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
1755 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
1756 $sql2 .=
" '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
1758 $sql2 .=
", '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
1764 if ($this->multilangs[
"$key"][
"label"] || $this->multilangs[
"$key"][
"description"]) {
1765 if (!$this->db->query($sql2)) {
1766 $this->error = $this->db->lasterror();
1776 $result = $this->
call_trigger(
'PRODUCT_SET_MULTILANGS', $user);
1778 $this->error = $this->db->lasterror();
1796 $sql =
"DELETE FROM ".$this->db->prefix().
"product_lang";
1797 $sql .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($langtodelete).
"'";
1799 dol_syslog(get_class($this).
'::delMultiLangs', LOG_DEBUG);
1800 $result = $this->db->query(
$sql);
1803 $result = $this->
call_trigger(
'PRODUCT_DEL_MULTILANGS', $user);
1805 $this->error = $this->db->lasterror();
1806 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
1812 $this->error = $this->db->lasterror();
1813 dol_syslog(get_class($this).
'::delMultiLangs error='.$this->error, LOG_ERR);
1828 global $user, $langs, $conf;
1834 if ($type ==
'buy') {
1835 $field =
'accountancy_code_buy';
1836 } elseif ($type ==
'buy_intra') {
1837 $field =
'accountancy_code_buy_intra';
1838 } elseif ($type ==
'buy_export') {
1839 $field =
'accountancy_code_buy_export';
1840 } elseif ($type ==
'sell') {
1841 $field =
'accountancy_code_sell';
1842 } elseif ($type ==
'sell_intra') {
1843 $field =
'accountancy_code_sell_intra';
1844 } elseif ($type ==
'sell_export') {
1845 $field =
'accountancy_code_sell_export';
1850 $sql =
"UPDATE ".$this->db->prefix().$this->table_element.
" SET ";
1851 $sql .=
"$field = '".$this->db->escape($value).
"'";
1852 $sql .=
" WHERE rowid = ".((int) $this->
id);
1855 $resql = $this->db->query(
$sql);
1859 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
1866 $this->db->rollback();
1870 $this->$field = $value;
1872 $this->db->commit();
1875 $this->error = $this->db->lasterror();
1876 $this->db->rollback();
1890 $current_lang = $langs->getDefaultLang();
1892 $sql =
"SELECT lang, label, description, note as other";
1893 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1894 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1896 $result = $this->db->query(
$sql);
1898 while ($obj = $this->db->fetch_object($result)) {
1900 if ($obj->lang == $current_lang) {
1901 $this->label = $obj->label;
1903 $this->other = $obj->other;
1905 $this->multilangs[(string) $obj->lang][
"label"] = $obj->label;
1906 $this->multilangs[(
string) $obj->lang][
"description"] = $obj->description;
1907 $this->multilangs[(string) $obj->lang][
"other"] = $obj->other;
1911 $this->error =
"Error: ".$this->db->lasterror().
" - ".
$sql;
1924 $testExit = array(
'multiprices',
'multiprices_ttc',
'multiprices_base_type',
'multiprices_min',
'multiprices_min_ttc',
'multiprices_tva_tx',
'multiprices_recuperableonly');
1926 foreach ($testExit as $field) {
1927 if (!isset($this->$field)) {
1930 $tmparray = $this->$field;
1931 if (!isset($tmparray[$level])) {
1937 'level' => $level ? $level : 1,
1938 'multiprices' => (
float) $this->multiprices[$level],
1939 'multiprices_ttc' => (
float) $this->multiprices_ttc[$level],
1940 'multiprices_base_type' => $this->multiprices_base_type[$level],
1941 'multiprices_min' => (
float) $this->multiprices_min[$level],
1942 'multiprices_min_ttc' => (
float) $this->multiprices_min_ttc[$level],
1943 'multiprices_tva_tx' => (
float) $this->multiprices_tva_tx[$level],
1944 'multiprices_recuperableonly' => (
float) $this->multiprices_recuperableonly[$level],
1967 if (empty($this->price_by_qty)) {
1968 $this->price_by_qty = 0;
1972 $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,";
1973 $sql .=
" localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, price_min,price_min_ttc,price_by_qty,entity,fk_price_expression) ";
1974 $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).
",";
1975 $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');
1978 dol_syslog(get_class($this).
"::_log_price", LOG_DEBUG);
1979 $resql = $this->db->query(
$sql);
1981 $this->error = $this->db->lasterror();
2001 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price_by_qty";
2002 $sql .=
" WHERE fk_product_price = ".((int) $rowid);
2003 $resql = $this->db->query(
$sql);
2005 $sql =
"DELETE FROM ".$this->db->prefix().
"product_price";
2006 $sql .=
" WHERE rowid=".((int) $rowid);
2007 $resql = $this->db->query(
$sql);
2011 $this->error = $this->db->lasterror();
2026 public function getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp = 0)
2028 global $conf, $hookmanager, $action;
2031 if (is_object($hookmanager)) {
2032 $parameters = array(
'thirdparty_seller' => $thirdparty_seller,
'thirdparty_buyer' => $thirdparty_buyer,
'pqp' => $pqp);
2034 $reshook = $hookmanager->executeHooks(
'getSellPrice', $parameters, $this, $action);
2036 return $hookmanager->resArray;
2047 $pu_ht = $this->price;
2048 $pu_ttc = $this->price_ttc;
2049 $price_min = $this->price_min;
2050 $price_base_type = $this->price_base_type;
2053 if (
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !empty($thirdparty_buyer->price_level)) {
2054 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
2055 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
2056 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
2057 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
2059 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2060 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2062 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2063 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2071 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2075 $filter = array(
't.fk_product' => $this->
id,
't.fk_soc' => $thirdparty_buyer->id);
2077 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2079 if (count($prodcustprice->lines) > 0) {
2080 $pu_ht =
price($prodcustprice->lines[0]->price);
2081 $price_min =
price($prodcustprice->lines[0]->price_min);
2082 $pu_ttc =
price($prodcustprice->lines[0]->price_ttc);
2083 $price_base_type = $prodcustprice->lines[0]->price_base_type;
2084 $tva_tx = $prodcustprice->lines[0]->tva_tx;
2085 if ($prodcustprice->lines[0]->default_vat_code && !preg_match(
'/\(.*\)/',
$tva_tx)) {
2086 $tva_tx .=
' ('.$prodcustprice->lines[0]->default_vat_code.
')';
2088 $tva_npr = $prodcustprice->lines[0]->recuperableonly;
2096 if ($this->prices_by_qty[0]) {
2099 foreach ($this->prices_by_qty_list[0] as $priceforthequantityarray) {
2100 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2104 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2105 $pu_ht = $priceforthequantityarray[
'unitprice'];
2107 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2114 if ($this->prices_by_qty[$thirdparty_buyer->price_level]) {
2117 foreach ($this->prices_by_qty_list[$thirdparty_buyer->price_level] as $priceforthequantityarray) {
2118 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2122 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2123 $pu_ht = $priceforthequantityarray[
'unitprice'];
2125 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2132 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);
2149 public function get_buyprice($prodfournprice, $qty, $product_id = 0, $fourn_ref =
'', $fk_soc = 0)
2152 global $action, $hookmanager;
2155 if (is_object($hookmanager)) {
2156 $parameters = array(
2157 'prodfournprice' => $prodfournprice,
2159 'product_id' => $product_id,
2160 'fourn_ref' => $fourn_ref,
2161 'fk_soc' => $fk_soc,
2164 $reshook = $hookmanager->executeHooks(
'getBuyPrice', $parameters, $this, $action);
2166 return $hookmanager->resArray;
2173 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2174 $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,";
2175 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2176 $sql .=
" pfp.packaging";
2177 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2178 $sql .=
" WHERE pfp.rowid = ".((int) $prodfournprice);
2180 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2182 $sql .=
" ORDER BY pfp.quantity DESC";
2184 dol_syslog(get_class($this).
"::get_buyprice first search by prodfournprice/qty", LOG_DEBUG);
2185 $resql = $this->db->query(
$sql);
2187 $obj = $this->db->fetch_object($resql);
2188 if ($obj && $obj->quantity > 0) {
2189 if (
isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2191 $prod_supplier->product_fourn_price_id = $obj->rowid;
2192 $prod_supplier->id = $obj->fk_product;
2193 $prod_supplier->fourn_qty = $obj->quantity;
2194 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2195 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2197 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2199 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2200 if ($price_result >= 0) {
2201 $obj->price = $price_result;
2204 $this->product_fourn_price_id = $obj->rowid;
2205 $this->buyprice = $obj->price;
2206 $this->fourn_pu = $obj->price / $obj->quantity;
2207 $this->fourn_price_base_type =
'HT';
2208 $this->fourn_socid = $obj->fk_soc;
2209 $this->ref_fourn = $obj->ref_supplier;
2210 $this->ref_supplier = $obj->ref_supplier;
2211 $this->desc_supplier = $obj->desc_supplier;
2212 $this->remise_percent = $obj->remise_percent;
2213 $this->vatrate_supplier = $obj->tva_tx;
2214 $this->default_vat_code_supplier = $obj->default_vat_code;
2215 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2216 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2217 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2218 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2219 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2221 $this->packaging = $obj->packaging;
2223 $result = $obj->fk_product;
2227 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2228 $sql .=
" pfp.fk_product, pfp.ref_fourn as ref_supplier, pfp.desc_fourn as desc_supplier, pfp.tva_tx, pfp.default_vat_code, pfp.fk_supplier_price_expression,";
2229 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2230 $sql .=
" pfp.packaging";
2231 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2232 $sql .=
" WHERE 1 = 1";
2233 if ($product_id > 0) {
2234 $sql .=
" AND pfp.fk_product = ".((int) $product_id);
2236 if ($fourn_ref !=
'none') {
2237 $sql .=
" AND pfp.ref_fourn = '".$this->db->escape($fourn_ref).
"'";
2240 $sql .=
" AND pfp.fk_soc = ".((int) $fk_soc);
2243 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2245 $sql .=
" ORDER BY pfp.quantity DESC";
2248 dol_syslog(get_class($this).
"::get_buyprice second search from qty/ref/product_id", LOG_DEBUG);
2249 $resql = $this->db->query(
$sql);
2251 $obj = $this->db->fetch_object($resql);
2252 if ($obj && $obj->quantity > 0) {
2253 if (
isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2255 $prod_supplier->product_fourn_price_id = $obj->rowid;
2256 $prod_supplier->id = $obj->fk_product;
2257 $prod_supplier->fourn_qty = $obj->quantity;
2258 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2259 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2261 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2263 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2265 $obj->price = $price_result;
2268 $this->product_fourn_price_id = $obj->rowid;
2269 $this->buyprice = $obj->price;
2270 $this->fourn_qty = $obj->quantity;
2271 $this->fourn_pu = $obj->price / $obj->quantity;
2272 $this->fourn_price_base_type =
'HT';
2273 $this->fourn_socid = $obj->fk_soc;
2274 $this->ref_fourn = $obj->ref_supplier;
2275 $this->ref_supplier = $obj->ref_supplier;
2276 $this->desc_supplier = $obj->desc_supplier;
2277 $this->remise_percent = $obj->remise_percent;
2278 $this->vatrate_supplier = $obj->tva_tx;
2279 $this->default_vat_code_supplier = $obj->default_vat_code;
2280 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2281 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2282 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2283 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2284 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2286 $this->packaging = $obj->packaging;
2288 $result = $obj->fk_product;
2294 $this->error = $this->db->lasterror();
2299 $this->error = $this->db->lasterror();
2323 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)
2325 global $conf, $langs;
2331 dol_syslog(get_class($this).
"::update_price id=".$id.
" newprice=".$newprice.
" newpricebase=".$newpricebase.
" newminprice=".$newminprice.
" level=".$level.
" npr=".$newnpr.
" newdefaultvatcode=".$newdefaultvatcode);
2334 if (empty($this->tva_tx)) {
2337 if (empty($newnpr)) {
2340 if (empty($newminprice)) {
2345 if ($newvat ===
null || $newvat ==
'') {
2351 if ((
getDolGlobalString(
'PRODUIT_MULTIPRICES') ||
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) && !$ignore_autogen && $this->price_autogen && ($level == 1)) {
2352 return $this->
generateMultiprices($user, $newprice, $newpricebase, $newvat, $newnpr, $newpbq);
2355 if (!empty($newminprice) && ($newminprice > $newprice)) {
2356 $this->error =
'ErrorPriceCantBeLowerThanMinPrice';
2360 if ($newprice !==
'' || $newprice === 0) {
2361 if ($newpricebase ==
'TTC') {
2362 $price_ttc =
price2num($newprice,
'MU');
2366 if ($newminprice !=
'' || $newminprice == 0) {
2367 $price_min_ttc =
price2num($newminprice,
'MU');
2368 $price_min = (
float)
price2num($newminprice) / (1 + ($newvat / 100));
2369 $price_min =
price2num($price_min,
'MU');
2376 $price_ttc = ($newnpr != 1) ?
price2num($newprice) * (1 + ($newvat / 100)) : $price;
2379 if ($newminprice !==
'' || $newminprice === 0) {
2380 $price_min =
price2num($newminprice,
'MU');
2381 $price_min_ttc = (
float)
price2num($newminprice) * (1 + ($newvat / 100));
2382 $price_min_ttc =
price2num($price_min_ttc,
'MU');
2391 if (count($localtaxes_array) > 0) {
2392 $localtaxtype1 = $localtaxes_array[
'0'];
2393 $localtax1 = $localtaxes_array[
'1'];
2394 $localtaxtype2 = $localtaxes_array[
'2'];
2395 $localtax2 = $localtaxes_array[
'3'];
2398 if (!empty($newdefaultvatcode)) {
2401 $sql =
"SELECT t.rowid, t.code, t.recuperableonly as tva_npr, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
2402 $sql .=
" FROM ".MAIN_DB_PREFIX.
"c_tva as t, ".MAIN_DB_PREFIX.
"c_country as c";
2403 $sql .=
" WHERE t.fk_pays = c.rowid AND c.code = '".$this->db->escape($mysoc->country_code).
"'";
2404 $sql .=
" AND t.taux = ".((float) $newdefaultvatcode).
" AND t.active = 1";
2405 $sql .=
" AND t.code = '".$this->db->escape($newdefaultvatcode).
"'";
2406 $resql = $this->db->query(
$sql);
2408 $obj = $this->db->fetch_object($resql);
2410 $npr = $obj->tva_npr;
2411 $localtax1 = $obj->localtax1;
2412 $localtax2 = $obj->localtax2;
2413 $localtaxtype1 = $obj->localtax1_type;
2414 $localtaxtype2 = $obj->localtax2_type;
2419 $localtaxtype1 =
'0';
2421 $localtaxtype2 =
'0';
2425 if (empty($localtax1)) {
2428 if (empty($localtax2)) {
2436 $sql =
"UPDATE ".$this->db->prefix().
"product SET";
2437 $sql .=
" price_base_type = '".$this->db->escape($newpricebase).
"',";
2438 $sql .=
" price = ".(float) $price.
",";
2439 $sql .=
" price_ttc = ".(float) $price_ttc.
",";
2440 $sql .=
" price_min = ".(float) $price_min.
",";
2441 $sql .=
" price_min_ttc = ".(float) $price_min_ttc.
",";
2442 $sql .=
" localtax1_tx = ".($localtax1 >= 0 ? (
float) $localtax1 :
'NULL').
",";
2443 $sql .=
" localtax2_tx = ".($localtax2 >= 0 ? (
float) $localtax2 :
'NULL').
",";
2444 $sql .=
" localtax1_type = ".($localtaxtype1 !=
'' ?
"'".$this->db->escape($localtaxtype1).
"'" :
"'0'").
",";
2445 $sql .=
" localtax2_type = ".($localtaxtype2 !=
'' ?
"'".$this->db->escape($localtaxtype2).
"'" :
"'0'").
",";
2446 $sql .=
" default_vat_code = ".($newdefaultvatcode ?
"'".$this->db->escape($newdefaultvatcode).
"'" :
"null").
",";
2447 $sql .=
" price_label = ".(!empty($price_label) ?
"'".$this->db->escape($price_label).
"'" :
"null").
",";
2449 $sql .=
" recuperableonly = '".$this->db->escape($newnpr).
"'";
2450 $sql .=
" WHERE rowid = ".((int) $id);
2452 dol_syslog(get_class($this).
"::update_price", LOG_DEBUG);
2453 $resql = $this->db->query(
$sql);
2455 $this->multiprices[$level] = $price;
2456 $this->multiprices_ttc[$level] = $price_ttc;
2457 $this->multiprices_min[$level] = $price_min;
2458 $this->multiprices_min_ttc[$level] = $price_min_ttc;
2459 $this->multiprices_base_type[$level] = $newpricebase;
2460 $this->multiprices_default_vat_code[$level] = $newdefaultvatcode;
2461 $this->multiprices_tva_tx[$level] = $newvat;
2462 $this->multiprices_recuperableonly[$level] = $newnpr;
2464 $this->
price = $price;
2465 $this->price_label = $price_label;
2466 $this->price_ttc = $price_ttc;
2467 $this->price_min = $price_min;
2468 $this->price_min_ttc = $price_min_ttc;
2469 $this->price_base_type = $newpricebase;
2470 $this->default_vat_code = $newdefaultvatcode;
2471 $this->tva_tx = $newvat;
2472 $this->tva_npr = $newnpr;
2475 $this->localtax1_tx = $localtax1;
2476 $this->localtax2_tx = $localtax2;
2477 $this->localtax1_type = $localtaxtype1;
2478 $this->localtax2_type = $localtaxtype2;
2481 $this->price_by_qty = $newpbq;
2485 if (!empty(array_diff_assoc($newPriceData, $lastPriceData)) || !
getDolGlobalString(
'PRODUIT_MULTIPRICES')) {
2489 $this->level = $level;
2493 $result = $this->
call_trigger(
'PRODUCT_PRICE_MODIFY', $user);
2495 $this->db->rollback();
2501 $this->db->commit();
2503 $this->db->rollback();
2504 $this->error = $this->db->lasterror();
2523 $this->fk_price_expression = $expression_id;
2525 return $this->
update($this->
id, $user);
2540 public function fetch($id = 0, $ref =
'', $ref_ext =
'', $barcode =
'', $ignore_expression = 0, $ignore_price_load = 0, $ignore_lang_load = 0)
2542 include_once DOL_DOCUMENT_ROOT.
'/core/lib/company.lib.php';
2544 global $langs, $conf;
2546 dol_syslog(get_class($this).
"::fetch id=".$id.
" ref=".$ref.
" ref_ext=".$ref_ext);
2549 if (!$id && !$ref && !$ref_ext && !$barcode) {
2550 $this->error =
'ErrorWrongParameters';
2551 dol_syslog(get_class($this).
"::fetch ".$this->error, LOG_ERR);
2555 $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,";
2556 $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,";
2557 $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,";
2558 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.last_main_doc,";
2559 $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,";
2561 $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,";
2563 $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,";
2568 $separatedEntityPMP =
false;
2569 $separatedStock =
false;
2570 $visibleWarehousesEntities = $conf->entity;
2573 $checkPMPPerEntity = $this->db->query(
"SELECT pmp FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = ".((int) $id).
" AND entity = ".(
int) $conf->entity);
2574 if ($this->db->num_rows($checkPMPPerEntity) > 0) {
2575 $separatedEntityPMP =
true;
2579 $separatedStock =
true;
2580 if (isset($mc->sharings[
'stock']) && !empty($mc->sharings[
'stock'])) {
2581 $visibleWarehousesEntities .=
"," . implode(
",", $mc->sharings[
'stock']);
2584 if ($separatedEntityPMP) {
2585 $sql .=
" ppe.pmp,";
2589 $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,";
2590 $sql .=
" p.fk_price_expression, p.price_autogen, p.model_pdf,";
2591 $sql .=
" p.price_label,";
2592 if ($separatedStock) {
2593 $sql .=
" SUM(sp.reel) as stock";
2597 $sql .=
" FROM ".$this->db->prefix().
"product as p";
2599 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int) $conf->entity);
2601 if ($separatedStock) {
2602 $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).
"))";
2606 $sql .=
" WHERE p.rowid = ".((int) $id);
2608 $sql .=
" WHERE p.entity IN (".getEntity($this->element).
")";
2610 $sql .=
" AND p.ref = '".$this->db->escape($ref).
"'";
2611 } elseif ($ref_ext) {
2612 $sql .=
" AND p.ref_ext = '".$this->db->escape($ref_ext).
"'";
2613 } elseif ($barcode) {
2614 $sql .=
" AND p.barcode = '".$this->db->escape($barcode).
"'";
2617 if ($separatedStock) {
2618 $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,";
2619 $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,";
2620 $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,";
2621 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
2622 $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,";
2624 $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,";
2626 $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,";
2628 if ($separatedEntityPMP) {
2629 $sql .=
" ppe.pmp,";
2633 $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,";
2634 $sql .=
" p.fk_price_expression, p.price_autogen, p.model_pdf";
2635 $sql .=
" ,p.price_label";
2636 if (!$separatedStock) {
2637 $sql .=
", p.stock";
2641 $resql = $this->db->query(
$sql);
2643 unset($this->oldcopy);
2645 if ($this->db->num_rows($resql) > 0) {
2646 $obj = $this->db->fetch_object($resql);
2648 $this->
id = $obj->rowid;
2649 $this->
ref = $obj->ref;
2650 $this->ref_ext = $obj->ref_ext;
2651 $this->label = $obj->label;
2653 $this->url = $obj->url;
2654 $this->note_public = $obj->note_public;
2655 $this->note_private = $obj->note_private;
2656 $this->note = $obj->note_private;
2658 $this->
type = $obj->fk_product_type;
2659 $this->price_label = $obj->price_label;
2660 $this->
status = $obj->tosell;
2661 $this->status_buy = $obj->tobuy;
2662 $this->status_batch = $obj->tobatch;
2663 $this->sell_or_eat_by_mandatory = $obj->sell_or_eat_by_mandatory;
2664 $this->batch_mask = $obj->batch_mask;
2666 $this->customcode = $obj->customcode;
2667 $this->country_id = $obj->fk_country;
2668 $this->country_code =
getCountry($this->country_id, 2, $this->db);
2669 $this->state_id = $obj->fk_state;
2670 $this->lifetime = $obj->lifetime;
2671 $this->qc_frequency = $obj->qc_frequency;
2672 $this->
price = $obj->price;
2673 $this->price_ttc = $obj->price_ttc;
2674 $this->price_min = $obj->price_min;
2675 $this->price_min_ttc = $obj->price_min_ttc;
2676 $this->price_base_type = $obj->price_base_type;
2677 $this->cost_price = $obj->cost_price;
2678 $this->default_vat_code = $obj->default_vat_code;
2679 $this->tva_tx = $obj->tva_tx;
2681 $this->tva_npr = $obj->tva_npr;
2683 $this->localtax1_tx = $obj->localtax1_tx;
2684 $this->localtax2_tx = $obj->localtax2_tx;
2685 $this->localtax1_type = $obj->localtax1_type;
2686 $this->localtax2_type = $obj->localtax2_type;
2688 $this->finished = $obj->finished;
2689 $this->fk_default_bom = $obj->fk_default_bom;
2691 $this->duration = $obj->duration;
2692 $this->duration_value = $obj->duration ? substr($obj->duration, 0,
dol_strlen($obj->duration) - 1) :
null;
2693 $this->duration_unit = $obj->duration ? substr($obj->duration, -1) :
null;
2694 $this->canvas = $obj->canvas;
2695 $this->net_measure = $obj->net_measure;
2696 $this->net_measure_units = $obj->net_measure_units;
2697 $this->weight = $obj->weight;
2698 $this->weight_units = $obj->weight_units;
2699 $this->length = $obj->length;
2700 $this->length_units = $obj->length_units;
2701 $this->width = $obj->width;
2702 $this->width_units = $obj->width_units;
2703 $this->height = $obj->height;
2704 $this->height_units = $obj->height_units;
2706 $this->surface = $obj->surface;
2707 $this->surface_units = $obj->surface_units;
2708 $this->volume = $obj->volume;
2709 $this->volume_units = $obj->volume_units;
2710 $this->barcode = $obj->barcode;
2711 $this->barcode_type = $obj->fk_barcode_type;
2713 $this->accountancy_code_buy = $obj->accountancy_code_buy;
2714 $this->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra;
2715 $this->accountancy_code_buy_export = $obj->accountancy_code_buy_export;
2716 $this->accountancy_code_sell = $obj->accountancy_code_sell;
2717 $this->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra;
2718 $this->accountancy_code_sell_export = $obj->accountancy_code_sell_export;
2720 $this->fk_default_warehouse = $obj->fk_default_warehouse;
2721 $this->fk_default_workstation = $obj->fk_default_workstation;
2722 $this->seuil_stock_alerte = $obj->seuil_stock_alerte;
2723 $this->desiredstock = $obj->desiredstock;
2724 $this->stock_reel = $obj->stock;
2725 $this->pmp = $obj->pmp;
2727 $this->date_creation = $obj->datec;
2728 $this->date_modification = $obj->tms;
2729 $this->import_key = $obj->import_key;
2730 $this->entity = $obj->entity;
2732 $this->ref_ext = $obj->ref_ext;
2733 $this->fk_price_expression = $obj->fk_price_expression;
2734 $this->fk_unit = $obj->fk_unit;
2735 $this->price_autogen = $obj->price_autogen;
2736 $this->model_pdf = $obj->model_pdf;
2737 $this->last_main_doc = $obj->last_main_doc;
2739 $this->mandatory_period = $obj->mandatory_period;
2741 $this->db->free($resql);
2753 for ($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) {
2754 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
2755 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
2756 $sql .=
" ,price_label";
2757 $sql .=
" FROM ".$this->db->prefix().
"product_price";
2758 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
2759 $sql .=
" AND price_level=".((int) $i);
2760 $sql .=
" AND fk_product = ".((int) $this->
id);
2761 $sql .=
" ORDER BY date_price DESC, rowid DESC";
2763 $resql = $this->db->query(
$sql);
2765 $result = $this->db->fetch_array($resql);
2767 $this->multiprices[$i] = $result ? $result[
"price"] :
null;
2768 $this->multiprices_ttc[$i] = $result ? $result[
"price_ttc"] :
null;
2769 $this->multiprices_min[$i] = $result ? $result[
"price_min"] :
null;
2770 $this->multiprices_min_ttc[$i] = $result ? $result[
"price_min_ttc"] :
null;
2771 $this->multiprices_base_type[$i] = $result ? $result[
"price_base_type"] :
null;
2773 $this->multiprices_tva_tx[$i] = $result ? $result[
"tva_tx"].($result ?
' ('.$result[
'default_vat_code'].
')' :
'') :
null;
2774 $this->multiprices_recuperableonly[$i] = $result ? $result[
"recuperableonly"] :
null;
2813 $this->error = $this->db->lasterror;
2817 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES') && empty($ignore_price_load)) {
2819 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY') && empty($ignore_price_load)) {
2820 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
2821 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid";
2822 $sql .=
" FROM ".$this->db->prefix().
"product_price";
2823 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2824 $sql .=
" ORDER BY date_price DESC, rowid DESC";
2827 $resql = $this->db->query(
$sql);
2829 $result = $this->db->fetch_array($resql);
2833 $this->prices_by_qty[0] = $result[
"price_by_qty"];
2834 $this->prices_by_qty_id[0] = $result[
"rowid"];
2836 if ($this->prices_by_qty[0] == 1) {
2837 $sql =
"SELECT rowid,price, unitprice, quantity, remise_percent, remise, remise, price_base_type";
2838 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
2839 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[0]);
2840 $sql .=
" ORDER BY quantity ASC";
2842 $resql = $this->db->query(
$sql);
2844 $resultat = array();
2846 while ($result = $this->db->fetch_array($resql)) {
2847 $resultat[$ii] = array();
2848 $resultat[$ii][
"rowid"] = $result[
"rowid"];
2849 $resultat[$ii][
"price"] = $result[
"price"];
2850 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
2851 $resultat[$ii][
"quantity"] = $result[
"quantity"];
2852 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
2854 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
2857 $this->prices_by_qty_list[0] = $resultat;
2859 $this->error = $this->db->lasterror;
2865 $this->error = $this->db->lasterror;
2868 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') && empty($ignore_price_load)) {
2869 for ($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) {
2870 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
2871 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
2872 $sql .=
" FROM ".$this->db->prefix().
"product_price";
2873 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
2874 $sql .=
" AND price_level=".((int) $i);
2875 $sql .=
" AND fk_product = ".((int) $this->
id);
2876 $sql .=
" ORDER BY date_price DESC, rowid DESC";
2878 $resql = $this->db->query(
$sql);
2880 $this->error = $this->db->lasterror;
2882 } elseif ($result = $this->db->fetch_array($resql)) {
2883 $this->multiprices[$i] = (!empty($result[
"price"]) ? $result[
"price"] : 0);
2884 $this->multiprices_ttc[$i] = (!empty($result[
"price_ttc"]) ? $result[
"price_ttc"] : 0);
2885 $this->multiprices_min[$i] = (!empty($result[
"price_min"]) ? $result[
"price_min"] : 0);
2886 $this->multiprices_min_ttc[$i] = (!empty($result[
"price_min_ttc"]) ? $result[
"price_min_ttc"] : 0);
2887 $this->multiprices_base_type[$i] = (!empty($result[
"price_base_type"]) ? $result[
"price_base_type"] :
'');
2889 $this->multiprices_tva_tx[$i] = (!empty($result[
"tva_tx"]) ? $result[
"tva_tx"] : 0);
2890 $this->multiprices_recuperableonly[$i] = (!empty($result[
"recuperableonly"]) ? $result[
"recuperableonly"] : 0);
2893 $this->prices_by_qty[$i] = (!empty($result[
"price_by_qty"]) ? $result[
"price_by_qty"] : 0);
2894 $this->prices_by_qty_id[$i] = (!empty($result[
"rowid"]) ? $result[
"rowid"] : 0);
2896 if ($this->prices_by_qty[$i] == 1) {
2897 $sql =
"SELECT rowid, price, unitprice, quantity, remise_percent, remise, price_base_type";
2898 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
2899 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[$i]);
2900 $sql .=
" ORDER BY quantity ASC";
2902 $resql = $this->db->query(
$sql);
2904 $resultat = array();
2906 while ($result = $this->db->fetch_array($resql)) {
2907 $resultat[$ii] = array();
2908 $resultat[$ii][
"rowid"] = $result[
"rowid"];
2909 $resultat[$ii][
"price"] = $result[
"price"];
2910 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
2911 $resultat[$ii][
"quantity"] = $result[
"quantity"];
2912 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
2913 $resultat[$ii][
"remise"] = $result[
"remise"];
2914 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
2917 $this->prices_by_qty_list[$i] = $resultat;
2919 $this->error = $this->db->lasterror;
2927 if (
isModEnabled(
'dynamicprices') && !empty($this->fk_price_expression) && empty($ignore_expression)) {
2928 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2930 $price_result = $priceparser->parseProduct($this);
2931 if ($price_result >= 0) {
2932 $this->
price = $price_result;
2941 $this->stock_warehouse = array();
2948 $this->error = $this->db->lasterror();
2963 global $user, $hookmanager, $action;
2967 foreach (array(
'toconsume',
'consumed',
'toproduce',
'produced') as $role) {
2968 $this->stats_mo[
'customers_'.$role] = 0;
2969 $this->stats_mo[
'nb_'.$role] = 0;
2970 $this->stats_mo[
'qty_'.$role] = 0;
2972 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
2973 $sql .=
" SUM(mp.qty) as qty";
2974 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as c";
2975 $sql .=
" INNER JOIN ".$this->db->prefix().
"mrp_production as mp ON mp.fk_mo=c.rowid";
2976 if (!$user->hasRight(
'societe',
'client',
'voir')) {
2977 $sql .=
" INNER JOIN ".$this->db->prefix().
"societe_commerciaux as sc ON sc.fk_soc=c.fk_soc AND sc.fk_user = ".((int) $user->id);
2980 $sql .=
" c.entity IN (".getEntity(
'mo').
")";
2982 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
2983 $sql .=
" AND mp.role ='".$this->db->escape($role).
"'";
2985 $sql .=
" AND c.fk_soc = ".((int) $socid);
2988 $result = $this->db->query(
$sql);
2990 $obj = $this->db->fetch_object($result);
2991 $this->stats_mo[
'customers_'.$role] = $obj->nb_customers ? $obj->nb_customers : 0;
2992 $this->stats_mo[
'nb_'.$role] = $obj->nb ? $obj->nb : 0;
2993 $this->stats_mo[
'qty_'.$role] = $obj->qty ?
price2num($obj->qty,
'MS') : 0;
2995 $this->error = $this->db->error();
3000 if (!empty($error)) {
3004 $parameters = array(
'socid' => $socid);
3005 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3007 $this->stats_mo = $hookmanager->resArray[
'stats_mo'];
3023 global $user, $hookmanager, $action;
3027 $this->stats_bom[
'nb_toproduce'] = 0;
3028 $this->stats_bom[
'nb_toconsume'] = 0;
3029 $this->stats_bom[
'qty_toproduce'] = 0;
3030 $this->stats_bom[
'qty_toconsume'] = 0;
3032 $sql =
"SELECT COUNT(DISTINCT b.rowid) as nb_toproduce,";
3033 $sql .=
" SUM(b.qty) as qty_toproduce";
3034 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3035 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
3037 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3038 $sql .=
" AND b.fk_product =".((int) $this->
id);
3039 $sql .=
" GROUP BY b.rowid";
3041 $result = $this->db->query(
$sql);
3043 $obj = $this->db->fetch_object($result);
3044 $this->stats_bom[
'nb_toproduce'] = !empty($obj->nb_toproduce) ? $obj->nb_toproduce : 0;
3045 $this->stats_bom[
'qty_toproduce'] = !empty($obj->qty_toproduce) ?
price2num($obj->qty_toproduce) : 0;
3047 $this->error = $this->db->error();
3051 $sql =
"SELECT COUNT(DISTINCT bl.rowid) as nb_toconsume,";
3052 $sql .=
" SUM(bl.qty) as qty_toconsume";
3053 $sql .=
" FROM ".$this->db->prefix().
"bom_bom as b";
3054 $sql .=
" INNER JOIN ".$this->db->prefix().
"bom_bomline as bl ON bl.fk_bom=b.rowid";
3056 $sql .=
" b.entity IN (".getEntity(
'bom').
")";
3057 $sql .=
" AND bl.fk_product =".((int) $this->
id);
3059 $result = $this->db->query(
$sql);
3061 $obj = $this->db->fetch_object($result);
3062 $this->stats_bom[
'nb_toconsume'] = !empty($obj->nb_toconsume) ? $obj->nb_toconsume : 0;
3063 $this->stats_bom[
'qty_toconsume'] = !empty($obj->qty_toconsume) ?
price2num($obj->qty_toconsume) : 0;
3065 $this->error = $this->db->error();
3069 if (!empty($error)) {
3073 $parameters = array(
'socid' => $socid);
3074 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerMO', $parameters, $this, $action);
3076 $this->stats_bom = $hookmanager->resArray[
'stats_bom'];
3092 global $conf, $user, $hookmanager, $action;
3094 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_customers, COUNT(DISTINCT p.rowid) as nb,";
3095 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3096 $sql .=
" FROM ".$this->db->prefix().
"propaldet as pd";
3097 $sql .=
", ".$this->db->prefix().
"propal as p";
3098 $sql .=
", ".$this->db->prefix().
"societe as s";
3099 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3100 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3102 $sql .=
" WHERE p.rowid = pd.fk_propal";
3103 $sql .=
" AND p.fk_soc = s.rowid";
3104 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
3105 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3106 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3107 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3111 $sql .=
" AND p.fk_soc = ".((int) $socid);
3114 $result = $this->db->query(
$sql);
3116 $obj = $this->db->fetch_object($result);
3117 $this->stats_propale[
'customers'] = $obj->nb_customers;
3118 $this->stats_propale[
'nb'] = $obj->nb;
3119 $this->stats_propale[
'rows'] = $obj->nb_rows;
3120 $this->stats_propale[
'qty'] = $obj->qty ? $obj->qty : 0;
3125 if (is_array($TFather) && !empty($TFather)) {
3126 foreach ($TFather as &$fatherData) {
3127 $pFather =
new Product($this->db);
3128 $pFather->id = $fatherData[
'id'];
3129 $qtyCoef = $fatherData[
'qty'];
3131 if ($fatherData[
'incdec']) {
3132 $pFather->load_stats_propale($socid);
3134 $this->stats_propale[
'customers'] += $pFather->stats_propale[
'customers'];
3135 $this->stats_propale[
'nb'] += $pFather->stats_propale[
'nb'];
3136 $this->stats_propale[
'rows'] += $pFather->stats_propale[
'rows'];
3137 $this->stats_propale[
'qty'] += $pFather->stats_propale[
'qty'] * $qtyCoef;
3143 $parameters = array(
'socid' => $socid);
3144 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerProposal', $parameters, $this, $action);
3146 $this->stats_propale = $hookmanager->resArray[
'stats_propale'];
3151 $this->error = $this->db->error();
3167 global $conf, $user, $hookmanager, $action;
3169 $sql =
"SELECT COUNT(DISTINCT p.fk_soc) as nb_suppliers, COUNT(DISTINCT p.rowid) as nb,";
3170 $sql .=
" COUNT(pd.rowid) as nb_rows, SUM(pd.qty) as qty";
3171 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as pd";
3172 $sql .=
", ".$this->db->prefix().
"supplier_proposal as p";
3173 $sql .=
", ".$this->db->prefix().
"societe as s";
3174 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3175 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3177 $sql .=
" WHERE p.rowid = pd.fk_supplier_proposal";
3178 $sql .=
" AND p.fk_soc = s.rowid";
3179 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
3180 $sql .=
" AND pd.fk_product = ".((int) $this->
id);
3181 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3182 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3186 $sql .=
" AND p.fk_soc = ".((int) $socid);
3189 $result = $this->db->query(
$sql);
3191 $obj = $this->db->fetch_object($result);
3192 $this->stats_proposal_supplier[
'suppliers'] = $obj->nb_suppliers;
3193 $this->stats_proposal_supplier[
'nb'] = $obj->nb;
3194 $this->stats_proposal_supplier[
'rows'] = $obj->nb_rows;
3195 $this->stats_proposal_supplier[
'qty'] = $obj->qty ? $obj->qty : 0;
3197 $parameters = array(
'socid' => $socid);
3198 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierProposal', $parameters, $this, $action);
3200 $this->stats_proposal_supplier = $hookmanager->resArray[
'stats_proposal_supplier'];
3205 $this->error = $this->db->error();
3223 global $conf, $user, $hookmanager, $action;
3225 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3226 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3227 $sql .=
" FROM ".$this->db->prefix().
"commandedet as cd";
3228 $sql .=
", ".$this->db->prefix().
"commande as c";
3229 $sql .=
", ".$this->db->prefix().
"societe as s";
3230 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3231 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3233 $sql .=
" WHERE c.rowid = cd.fk_commande";
3234 $sql .=
" AND c.fk_soc = s.rowid";
3235 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'commande').
")";
3236 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3237 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3238 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3241 $sql .=
" AND c.fk_soc = ".((int) $socid);
3243 if ($filtrestatut !=
'') {
3244 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3247 $result = $this->db->query(
$sql);
3249 $obj = $this->db->fetch_object($result);
3250 $this->stats_commande[
'customers'] = $obj->nb_customers;
3251 $this->stats_commande[
'nb'] = $obj->nb;
3252 $this->stats_commande[
'rows'] = $obj->nb_rows;
3253 $this->stats_commande[
'qty'] = $obj->qty ? $obj->qty : 0;
3258 if (is_array($TFather) && !empty($TFather)) {
3259 foreach ($TFather as &$fatherData) {
3260 $pFather =
new Product($this->db);
3261 $pFather->id = $fatherData[
'id'];
3262 $qtyCoef = $fatherData[
'qty'];
3264 if ($fatherData[
'incdec']) {
3265 $pFather->load_stats_commande($socid, $filtrestatut);
3267 $this->stats_commande[
'customers'] += $pFather->stats_commande[
'customers'];
3268 $this->stats_commande[
'nb'] += $pFather->stats_commande[
'nb'];
3269 $this->stats_commande[
'rows'] += $pFather->stats_commande[
'rows'];
3270 $this->stats_commande[
'qty'] += $pFather->stats_commande[
'qty'] * $qtyCoef;
3282 $sql =
"SELECT SUM(".$this->db->ifsql(
'f.type=2', -1, 1).
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3283 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3284 $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'))";
3285 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3286 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3288 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3289 $resql = $this->db->query(
$sql);
3291 if ($this->db->num_rows($resql) > 0) {
3292 $obj = $this->db->fetch_object($resql);
3293 $adeduire += $obj->count;
3297 $this->stats_commande[
'qty'] -= $adeduire;
3300 include_once DOL_DOCUMENT_ROOT.
'/compta/facture/class/facture.class.php';
3304 $sql =
"SELECT sum(".$this->db->ifsql(
'f.type=2', -1, 1).
" * fd.qty) as count FROM ".MAIN_DB_PREFIX.
"facturedet as fd ";
3305 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"facture as f ON fd.fk_facture = f.rowid";
3306 $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'))";
3307 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"commande as c ON el.fk_source = c.rowid";
3308 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3310 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3311 $resql = $this->db->query(
$sql);
3313 if ($this->db->num_rows($resql) > 0) {
3314 $obj = $this->db->fetch_object($resql);
3315 $adeduire += $obj->count;
3318 $this->error = $this->db->error();
3322 $this->stats_commande[
'qty'] -= $adeduire;
3326 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3327 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerOrder', $parameters, $this, $action);
3329 $this->stats_commande = $hookmanager->resArray[
'stats_commande'];
3333 $this->error = $this->db->error();
3351 global $conf, $user, $hookmanager, $action;
3353 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_suppliers, COUNT(DISTINCT c.rowid) as nb,";
3354 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3355 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as cd";
3356 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as c";
3357 $sql .=
", ".$this->db->prefix().
"societe as s";
3358 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3359 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3361 $sql .=
" WHERE c.rowid = cd.fk_commande";
3362 $sql .=
" AND c.fk_soc = s.rowid";
3363 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3364 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3365 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3366 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3369 $sql .=
" AND c.fk_soc = ".((int) $socid);
3371 if ($filtrestatut !=
'') {
3372 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3374 if (!empty($dateofvirtualstock)) {
3375 $sql .=
" AND c.date_livraison <= '".$this->db->idate($dateofvirtualstock).
"'";
3378 $result = $this->db->query(
$sql);
3380 $obj = $this->db->fetch_object($result);
3381 $this->stats_commande_fournisseur[
'suppliers'] = $obj->nb_suppliers;
3382 $this->stats_commande_fournisseur[
'nb'] = $obj->nb;
3383 $this->stats_commande_fournisseur[
'rows'] = $obj->nb_rows;
3384 $this->stats_commande_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
3386 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3387 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierOrder', $parameters, $this, $action);
3389 $this->stats_commande_fournisseur = $hookmanager->resArray[
'stats_commande_fournisseur'];
3394 $this->error = $this->db->error().
' sql='.
$sql;
3409 public function load_stats_sending($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $filterShipmentStatus =
'')
3412 global $conf, $user, $hookmanager, $action;
3414 $sql =
"SELECT COUNT(DISTINCT e.fk_soc) as nb_customers, COUNT(DISTINCT e.rowid) as nb,";
3415 $sql .=
" COUNT(ed.rowid) as nb_rows, SUM(ed.qty) as qty";
3416 $sql .=
" FROM ".$this->db->prefix().
"expeditiondet as ed";
3417 $sql .=
", ".$this->db->prefix().
"commandedet as cd";
3418 $sql .=
", ".$this->db->prefix().
"commande as c";
3419 $sql .=
", ".$this->db->prefix().
"expedition as e";
3420 $sql .=
", ".$this->db->prefix().
"societe as s";
3421 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3422 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3424 $sql .=
" WHERE e.rowid = ed.fk_expedition";
3425 $sql .=
" AND c.rowid = cd.fk_commande";
3426 $sql .=
" AND e.fk_soc = s.rowid";
3427 $sql .=
" AND e.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'expedition').
")";
3428 $sql .=
" AND ed.fk_elementdet = cd.rowid";
3429 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3430 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3431 $sql .=
" AND e.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3434 $sql .=
" AND e.fk_soc = ".((int) $socid);
3436 if ($filtrestatut !=
'') {
3437 $sql .=
" AND c.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3439 if (!empty($filterShipmentStatus)) {
3440 $sql .=
" AND e.fk_statut IN (".$this->db->sanitize($filterShipmentStatus).
")";
3443 $result = $this->db->query(
$sql);
3445 $obj = $this->db->fetch_object($result);
3446 $this->stats_expedition[
'customers'] = $obj->nb_customers;
3447 $this->stats_expedition[
'nb'] = $obj->nb;
3448 $this->stats_expedition[
'rows'] = $obj->nb_rows;
3449 $this->stats_expedition[
'qty'] = $obj->qty ? $obj->qty : 0;
3454 if (is_array($TFather) && !empty($TFather)) {
3455 foreach ($TFather as &$fatherData) {
3456 $pFather =
new Product($this->db);
3457 $pFather->id = $fatherData[
'id'];
3458 $qtyCoef = $fatherData[
'qty'];
3460 if ($fatherData[
'incdec']) {
3461 $pFather->load_stats_sending($socid, $filtrestatut, $forVirtualStock);
3463 $this->stats_expedition[
'customers'] += $pFather->stats_expedition[
'customers'];
3464 $this->stats_expedition[
'nb'] += $pFather->stats_expedition[
'nb'];
3465 $this->stats_expedition[
'rows'] += $pFather->stats_expedition[
'rows'];
3466 $this->stats_expedition[
'qty'] += $pFather->stats_expedition[
'qty'] * $qtyCoef;
3472 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock,
'filterShipmentStatus' => $filterShipmentStatus);
3473 $reshook = $hookmanager->executeHooks(
'loadStatsSending', $parameters, $this, $action);
3475 $this->stats_expedition = $hookmanager->resArray[
'stats_expedition'];
3480 $this->error = $this->db->error();
3495 public function load_stats_reception($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null)
3498 global $conf, $user, $hookmanager, $action;
3500 $sql =
"SELECT COUNT(DISTINCT cf.fk_soc) as nb_suppliers, COUNT(DISTINCT cf.rowid) as nb,";
3501 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
3502 $sql .=
" FROM ".$this->db->prefix().
"receptiondet_batch as fd";
3503 $sql .=
", ".$this->db->prefix().
"commande_fournisseur as cf";
3504 $sql .=
", ".$this->db->prefix().
"societe as s";
3505 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3506 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3508 $sql .=
" WHERE cf.rowid = fd.fk_element";
3509 $sql .=
" AND cf.fk_soc = s.rowid";
3510 $sql .=
" AND cf.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'supplier_order').
")";
3511 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3512 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3513 $sql .=
" AND cf.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3516 $sql .=
" AND cf.fk_soc = ".((int) $socid);
3518 if ($filtrestatut !=
'') {
3519 $sql .=
" AND cf.fk_statut IN (".$this->db->sanitize($filtrestatut).
")";
3521 if (!empty($dateofvirtualstock)) {
3522 $sql .=
" AND fd.datec <= '".$this->db->idate($dateofvirtualstock).
"'";
3525 $result = $this->db->query(
$sql);
3527 $obj = $this->db->fetch_object($result);
3528 $this->stats_reception[
'suppliers'] = $obj->nb_suppliers;
3529 $this->stats_reception[
'nb'] = $obj->nb;
3530 $this->stats_reception[
'rows'] = $obj->nb_rows;
3531 $this->stats_reception[
'qty'] = $obj->qty ? $obj->qty : 0;
3533 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3534 $reshook = $hookmanager->executeHooks(
'loadStatsReception', $parameters, $this, $action);
3536 $this->stats_reception = $hookmanager->resArray[
'stats_reception'];
3541 $this->error = $this->db->error();
3557 public function load_stats_inproduction($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null, $warehouseid = 0)
3560 global $user, $hookmanager, $action;
3564 $sql =
"SELECT COUNT(DISTINCT m.fk_soc) as nb_customers, COUNT(DISTINCT m.rowid) as nb,";
3565 $sql .=
" COUNT(mp.rowid) as nb_rows, SUM(mp.qty) as qty, role";
3566 $sql .=
" FROM ".$this->db->prefix().
"mrp_production as mp";
3567 $sql .=
", ".$this->db->prefix().
"mrp_mo as m";
3568 $sql .=
" LEFT JOIN ".$this->db->prefix().
"societe as s ON s.rowid = m.fk_soc";
3569 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3570 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3572 $sql .=
" WHERE m.rowid = mp.fk_mo";
3573 $sql .=
" AND m.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'mrp').
")";
3574 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3575 $sql .=
" AND mp.disable_stock_change IN (0)";
3576 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3577 $sql .=
" AND m.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3580 $sql .=
" AND m.fk_soc = ".((int) $socid);
3582 if ($filtrestatut !=
'') {
3583 $sql .=
" AND m.status IN (".$this->db->sanitize($filtrestatut).
")";
3585 if (!empty($dateofvirtualstock)) {
3586 $sql .=
" AND m.date_valid <= '".$this->db->idate($dateofvirtualstock).
"'";
3588 if (!$serviceStockIsEnabled) {
3589 $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))";
3591 if (!empty($warehouseid)) {
3592 $sql .=
" AND m.fk_warehouse = ".((int) $warehouseid);
3594 $sql .=
" GROUP BY role";
3597 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
3599 $this->stats_mrptoconsume[
'customers'] = 0;
3600 $this->stats_mrptoconsume[
'nb'] = 0;
3601 $this->stats_mrptoconsume[
'rows'] = 0;
3602 $this->stats_mrptoconsume[
'qty'] = 0;
3603 $this->stats_mrptoproduce[
'customers'] = 0;
3604 $this->stats_mrptoproduce[
'nb'] = 0;
3605 $this->stats_mrptoproduce[
'rows'] = 0;
3606 $this->stats_mrptoproduce[
'qty'] = 0;
3609 $result = $this->db->query(
$sql);
3611 while ($obj = $this->db->fetch_object($result)) {
3612 if ($obj->role ==
'toconsume' && empty($warehouseid)) {
3613 $this->stats_mrptoconsume[
'customers'] += $obj->nb_customers;
3614 $this->stats_mrptoconsume[
'nb'] += $obj->nb;
3615 $this->stats_mrptoconsume[
'rows'] += $obj->nb_rows;
3616 $this->stats_mrptoconsume[
'qty'] += ($obj->qty ? $obj->qty : 0);
3618 if ($obj->role ==
'consumed' && empty($warehouseid)) {
3622 $this->stats_mrptoconsume[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3624 if ($obj->role ==
'toproduce') {
3626 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] += ($obj->qty ? $obj->qty : 0);
3628 $this->stats_mrptoproduce[
'customers'] += $obj->nb_customers;
3629 $this->stats_mrptoproduce[
'nb'] += $obj->nb;
3630 $this->stats_mrptoproduce[
'rows'] += $obj->nb_rows;
3631 $this->stats_mrptoproduce[
'qty'] += ($obj->qty ? $obj->qty : 0);
3634 if ($obj->role ==
'produced') {
3639 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3641 $this->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3648 if ($this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] < 0) {
3649 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
3652 if ($this->stats_mrptoconsume[
'qty'] < 0) {
3653 $this->stats_mrptoconsume[
'qty'] = 0;
3655 if ($this->stats_mrptoproduce[
'qty'] < 0) {
3656 $this->stats_mrptoproduce[
'qty'] = 0;
3660 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3661 $reshook = $hookmanager->executeHooks(
'loadStatsInProduction', $parameters, $this, $action);
3663 $this->stats_mrptoproduce = $hookmanager->resArray[
'stats_mrptoproduce'];
3668 $this->error = $this->db->error();
3683 global $conf, $user, $hookmanager, $action;
3685 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3686 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3687 $sql .=
" FROM ".$this->db->prefix().
"contratdet as cd";
3688 $sql .=
", ".$this->db->prefix().
"contrat as c";
3689 $sql .=
", ".$this->db->prefix().
"societe as s";
3690 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3691 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3693 $sql .=
" WHERE c.rowid = cd.fk_contrat";
3694 $sql .=
" AND c.fk_soc = s.rowid";
3695 $sql .=
" AND c.entity IN (".getEntity(
'contract').
")";
3696 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3697 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3698 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3702 $sql .=
" AND c.fk_soc = ".((int) $socid);
3705 $result = $this->db->query(
$sql);
3707 $obj = $this->db->fetch_object($result);
3708 $this->stats_contrat[
'customers'] = $obj->nb_customers;
3709 $this->stats_contrat[
'nb'] = $obj->nb;
3710 $this->stats_contrat[
'rows'] = $obj->nb_rows;
3711 $this->stats_contrat[
'qty'] = $obj->qty ? $obj->qty : 0;
3716 if (is_array($TFather) && !empty($TFather)) {
3717 foreach ($TFather as &$fatherData) {
3718 $pFather =
new Product($this->db);
3719 $pFather->id = $fatherData[
'id'];
3720 $qtyCoef = $fatherData[
'qty'];
3722 if ($fatherData[
'incdec']) {
3723 $pFather->load_stats_contrat($socid);
3725 $this->stats_contrat[
'customers'] += $pFather->stats_contrat[
'customers'];
3726 $this->stats_contrat[
'nb'] += $pFather->stats_contrat[
'nb'];
3727 $this->stats_contrat[
'rows'] += $pFather->stats_contrat[
'rows'];
3728 $this->stats_contrat[
'qty'] += $pFather->stats_contrat[
'qty'] * $qtyCoef;
3734 $parameters = array(
'socid' => $socid);
3735 $reshook = $hookmanager->executeHooks(
'loadStatsContract', $parameters, $this, $action);
3737 $this->stats_contrat = $hookmanager->resArray[
'stats_contrat'];
3742 $this->error = $this->db->error().
' sql='.
$sql;
3757 global $conf, $user, $hookmanager, $action;
3759 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
3760 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(".$this->db->ifsql(
'f.type != 2',
'fd.qty',
'fd.qty * -1').
") as qty";
3761 $sql .=
" FROM ".$this->db->prefix().
"facturedet as fd";
3762 $sql .=
", ".$this->db->prefix().
"facture as f";
3763 $sql .=
", ".$this->db->prefix().
"societe as s";
3764 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3765 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3767 $sql .=
" WHERE f.rowid = fd.fk_facture";
3768 $sql .=
" AND f.fk_soc = s.rowid";
3769 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
3770 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3771 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3772 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3776 $sql .=
" AND f.fk_soc = ".((int) $socid);
3779 $result = $this->db->query(
$sql);
3781 $obj = $this->db->fetch_object($result);
3782 $this->stats_facture[
'customers'] = $obj->nb_customers;
3783 $this->stats_facture[
'nb'] = $obj->nb;
3784 $this->stats_facture[
'rows'] = $obj->nb_rows;
3785 $this->stats_facture[
'qty'] = $obj->qty ? $obj->qty : 0;
3790 if (is_array($TFather) && !empty($TFather)) {
3791 foreach ($TFather as &$fatherData) {
3792 $pFather =
new Product($this->db);
3793 $pFather->id = $fatherData[
'id'];
3794 $qtyCoef = $fatherData[
'qty'];
3796 if ($fatherData[
'incdec']) {
3797 $pFather->load_stats_facture($socid);
3799 $this->stats_facture[
'customers'] += $pFather->stats_facture[
'customers'];
3800 $this->stats_facture[
'nb'] += $pFather->stats_facture[
'nb'];
3801 $this->stats_facture[
'rows'] += $pFather->stats_facture[
'rows'];
3802 $this->stats_facture[
'qty'] += $pFather->stats_facture[
'qty'] * $qtyCoef;
3808 $parameters = array(
'socid' => $socid);
3809 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoice', $parameters, $this, $action);
3811 $this->stats_facture = $hookmanager->resArray[
'stats_facture'];
3816 $this->error = $this->db->error();
3832 global $conf, $user, $hookmanager, $action;
3834 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_customers, COUNT(DISTINCT f.rowid) as nb,";
3835 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
3836 $sql .=
" FROM ".MAIN_DB_PREFIX.
"facturedet_rec as fd";
3837 $sql .=
", ".MAIN_DB_PREFIX.
"facture_rec as f";
3838 $sql .=
", ".MAIN_DB_PREFIX.
"societe as s";
3839 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3840 $sql .=
", ".MAIN_DB_PREFIX.
"societe_commerciaux as sc";
3842 $sql .=
" WHERE f.rowid = fd.fk_facture";
3843 $sql .=
" AND f.fk_soc = s.rowid";
3844 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
3845 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3846 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3847 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3851 $sql .=
" AND f.fk_soc = ".((int) $socid);
3854 $result = $this->db->query(
$sql);
3856 $obj = $this->db->fetch_object($result);
3857 $this->stats_facturerec[
'customers'] = $obj->nb_customers;
3858 $this->stats_facturerec[
'nb'] = $obj->nb;
3859 $this->stats_facturerec[
'rows'] = $obj->nb_rows;
3860 $this->stats_facturerec[
'qty'] = $obj->qty ? $obj->qty : 0;
3865 if (is_array($TFather) && !empty($TFather)) {
3866 foreach ($TFather as &$fatherData) {
3867 $pFather =
new Product($this->db);
3868 $pFather->id = $fatherData[
'id'];
3869 $qtyCoef = $fatherData[
'qty'];
3871 if ($fatherData[
'incdec']) {
3872 $pFather->load_stats_facture($socid);
3874 $this->stats_facturerec[
'customers'] += $pFather->stats_facturerec[
'customers'];
3875 $this->stats_facturerec[
'nb'] += $pFather->stats_facturerec[
'nb'];
3876 $this->stats_facturerec[
'rows'] += $pFather->stats_facturerec[
'rows'];
3877 $this->stats_facturerec[
'qty'] += $pFather->stats_facturerec[
'qty'] * $qtyCoef;
3883 $parameters = array(
'socid' => $socid);
3884 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerInvoiceRec', $parameters, $this, $action);
3886 $this->stats_facturerec = $hookmanager->resArray[
'stats_facturerec'];
3891 $this->error = $this->db->error();
3906 global $conf, $user, $hookmanager, $action;
3908 $sql =
"SELECT COUNT(DISTINCT f.fk_soc) as nb_suppliers, COUNT(DISTINCT f.rowid) as nb,";
3909 $sql .=
" COUNT(fd.rowid) as nb_rows, SUM(fd.qty) as qty";
3910 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as fd";
3911 $sql .=
", ".$this->db->prefix().
"facture_fourn as f";
3912 $sql .=
", ".$this->db->prefix().
"societe as s";
3913 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3914 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3916 $sql .=
" WHERE f.rowid = fd.fk_facture_fourn";
3917 $sql .=
" AND f.fk_soc = s.rowid";
3918 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
3919 $sql .=
" AND fd.fk_product = ".((int) $this->
id);
3920 if (!$user->hasRight(
'societe',
'client',
'voir')) {
3921 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3925 $sql .=
" AND f.fk_soc = ".((int) $socid);
3928 $result = $this->db->query(
$sql);
3930 $obj = $this->db->fetch_object($result);
3931 $this->stats_facture_fournisseur[
'suppliers'] = $obj->nb_suppliers;
3932 $this->stats_facture_fournisseur[
'nb'] = $obj->nb;
3933 $this->stats_facture_fournisseur[
'rows'] = $obj->nb_rows;
3934 $this->stats_facture_fournisseur[
'qty'] = $obj->qty ? $obj->qty : 0;
3936 $parameters = array(
'socid' => $socid);
3937 $reshook = $hookmanager->executeHooks(
'loadStatsSupplierInvoice', $parameters, $this, $action);
3939 $this->stats_facture_fournisseur = $hookmanager->resArray[
'stats_facture_fournisseur'];
3944 $this->error = $this->db->error();
3963 $resql = $this->db->query(
$sql);
3965 $num = $this->db->num_rows($resql);
3968 $arr = $this->db->fetch_array($resql);
3969 if (is_array($arr)) {
3970 $keyfortab = (string) $arr[1];
3972 $keyfortab = substr($keyfortab, -2);
3975 if ($mode ==
'byunit') {
3976 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[0];
3977 } elseif ($mode ==
'bynumber') {
3978 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
3979 } elseif ($mode ==
'byamount') {
3980 $tab[$keyfortab] = (empty($tab[$keyfortab]) ? 0 : $tab[$keyfortab]) + $arr[2];
3989 $this->error = $this->db->error().
' sql='.
$sql;
3996 } elseif ($year == -1) {
4005 for ($j = 0; $j < 12; $j++) {
4007 $idx = ucfirst(
dol_trunc(
dol_print_date(
dol_mktime(12, 0, 0, $month, 1, 1970),
"%b"), 1,
'right',
'UTF-8', 1));
4010 $result[$j] = array($idx, isset($tab[$year.$month]) ? $tab[$year.$month] : 0);
4013 $month =
"0".($month - 1);
4015 $month = substr($month, 1);
4023 return array_reverse($result);
4038 public function get_nb_vente($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4044 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4045 if ($mode ==
'bynumber') {
4046 $sql .=
", count(DISTINCT f.rowid)";
4048 $sql .=
", sum(d.total_ht) as total_ht";
4049 $sql .=
" FROM ".$this->db->prefix().
"facturedet as d, ".$this->db->prefix().
"facture as f, ".$this->db->prefix().
"societe as s";
4050 if ($filteronproducttype >= 0) {
4051 $sql .=
", ".$this->db->prefix().
"product as p";
4053 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4054 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4056 $sql .=
" WHERE f.rowid = d.fk_facture";
4057 if ($this->
id > 0) {
4058 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4060 $sql .=
" AND d.fk_product > 0";
4062 if ($filteronproducttype >= 0) {
4063 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4065 $sql .=
" AND f.fk_soc = s.rowid";
4066 $sql .=
" AND f.entity IN (".getEntity(
'invoice').
")";
4067 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4068 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4071 $sql .=
" AND f.fk_soc = $socid";
4073 $sql .= $morefilter;
4074 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4075 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4092 public function get_nb_achat($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4098 $sql =
"SELECT sum(d.qty) as qty, date_format(f.datef, '%Y%m')";
4099 if ($mode ==
'bynumber') {
4100 $sql .=
", count(DISTINCT f.rowid)";
4102 $sql .=
", sum(d.total_ht) as total_ht";
4103 $sql .=
" FROM ".$this->db->prefix().
"facture_fourn_det as d, ".$this->db->prefix().
"facture_fourn as f, ".$this->db->prefix().
"societe as s";
4104 if ($filteronproducttype >= 0) {
4105 $sql .=
", ".$this->db->prefix().
"product as p";
4107 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4108 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4110 $sql .=
" WHERE f.rowid = d.fk_facture_fourn";
4111 if ($this->
id > 0) {
4112 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4114 $sql .=
" AND d.fk_product > 0";
4116 if ($filteronproducttype >= 0) {
4117 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4119 $sql .=
" AND f.fk_soc = s.rowid";
4120 $sql .=
" AND f.entity IN (".getEntity(
'facture_fourn').
")";
4121 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4122 $sql .=
" AND f.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4125 $sql .=
" AND f.fk_soc = $socid";
4127 $sql .= $morefilter;
4128 $sql .=
" GROUP BY date_format(f.datef,'%Y%m')";
4129 $sql .=
" ORDER BY date_format(f.datef,'%Y%m') DESC";
4145 public function get_nb_propal($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4148 global $conf, $user;
4150 $sql =
"SELECT sum(d.qty) as qty, date_format(p.datep, '%Y%m')";
4151 if ($mode ==
'bynumber') {
4152 $sql .=
", count(DISTINCT p.rowid)";
4154 $sql .=
", sum(d.total_ht) as total_ht";
4155 $sql .=
" FROM ".$this->db->prefix().
"propaldet as d, ".$this->db->prefix().
"propal as p, ".$this->db->prefix().
"societe as s";
4156 if ($filteronproducttype >= 0) {
4157 $sql .=
", ".$this->db->prefix().
"product as prod";
4159 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4160 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4162 $sql .=
" WHERE p.rowid = d.fk_propal";
4163 if ($this->
id > 0) {
4164 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4166 $sql .=
" AND d.fk_product > 0";
4168 if ($filteronproducttype >= 0) {
4169 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4171 $sql .=
" AND p.fk_soc = s.rowid";
4172 $sql .=
" AND p.entity IN (".getEntity(
'propal').
")";
4173 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4174 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4177 $sql .=
" AND p.fk_soc = ".((int) $socid);
4179 $sql .= $morefilter;
4180 $sql .=
" GROUP BY date_format(p.datep,'%Y%m')";
4181 $sql .=
" ORDER BY date_format(p.datep,'%Y%m') DESC";
4203 $sql =
"SELECT sum(d.qty) as qty, date_format(p.date_valid, '%Y%m')";
4204 if ($mode ==
'bynumber') {
4205 $sql .=
", count(DISTINCT p.rowid)";
4207 $sql .=
", sum(d.total_ht) as total_ht";
4208 $sql .=
" FROM ".$this->db->prefix().
"supplier_proposaldet as d, ".$this->db->prefix().
"supplier_proposal as p, ".$this->db->prefix().
"societe as s";
4209 if ($filteronproducttype >= 0) {
4210 $sql .=
", ".$this->db->prefix().
"product as prod";
4212 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4213 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4215 $sql .=
" WHERE p.rowid = d.fk_supplier_proposal";
4216 if ($this->
id > 0) {
4217 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4219 $sql .=
" AND d.fk_product > 0";
4221 if ($filteronproducttype >= 0) {
4222 $sql .=
" AND prod.rowid = d.fk_product AND prod.fk_product_type = ".((int) $filteronproducttype);
4224 $sql .=
" AND p.fk_soc = s.rowid";
4225 $sql .=
" AND p.entity IN (".getEntity(
'supplier_proposal').
")";
4226 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4227 $sql .=
" AND p.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4230 $sql .=
" AND p.fk_soc = ".((int) $socid);
4232 $sql .= $morefilter;
4233 $sql .=
" GROUP BY date_format(p.date_valid,'%Y%m')";
4234 $sql .=
" ORDER BY date_format(p.date_valid,'%Y%m') DESC";
4250 public function get_nb_order($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4253 global $conf, $user;
4255 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4256 if ($mode ==
'bynumber') {
4257 $sql .=
", count(DISTINCT c.rowid)";
4259 $sql .=
", sum(d.total_ht) as total_ht";
4260 $sql .=
" FROM ".$this->db->prefix().
"commandedet as d, ".$this->db->prefix().
"commande as c, ".$this->db->prefix().
"societe as s";
4261 if ($filteronproducttype >= 0) {
4262 $sql .=
", ".$this->db->prefix().
"product as p";
4264 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4265 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4267 $sql .=
" WHERE c.rowid = d.fk_commande";
4268 if ($this->
id > 0) {
4269 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4271 $sql .=
" AND d.fk_product > 0";
4273 if ($filteronproducttype >= 0) {
4274 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4276 $sql .=
" AND c.fk_soc = s.rowid";
4277 $sql .=
" AND c.entity IN (".getEntity(
'commande').
")";
4278 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4279 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4282 $sql .=
" AND c.fk_soc = ".((int) $socid);
4284 $sql .= $morefilter;
4285 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4286 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4305 global $conf, $user;
4307 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_commande, '%Y%m')";
4308 if ($mode ==
'bynumber') {
4309 $sql .=
", count(DISTINCT c.rowid)";
4311 $sql .=
", sum(d.total_ht) as total_ht";
4312 $sql .=
" FROM ".$this->db->prefix().
"commande_fournisseurdet as d, ".$this->db->prefix().
"commande_fournisseur as c, ".$this->db->prefix().
"societe as s";
4313 if ($filteronproducttype >= 0) {
4314 $sql .=
", ".$this->db->prefix().
"product as p";
4316 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4317 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4319 $sql .=
" WHERE c.rowid = d.fk_commande";
4320 if ($this->
id > 0) {
4321 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4323 $sql .=
" AND d.fk_product > 0";
4325 if ($filteronproducttype >= 0) {
4326 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4328 $sql .=
" AND c.fk_soc = s.rowid";
4329 $sql .=
" AND c.entity IN (".getEntity(
'supplier_order').
")";
4330 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4331 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4334 $sql .=
" AND c.fk_soc = ".((int) $socid);
4336 $sql .= $morefilter;
4337 $sql .=
" GROUP BY date_format(c.date_commande,'%Y%m')";
4338 $sql .=
" ORDER BY date_format(c.date_commande,'%Y%m') DESC";
4354 public function get_nb_contract($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4357 global $conf, $user;
4359 $sql =
"SELECT sum(d.qty) as qty, date_format(c.date_contrat, '%Y%m')";
4360 if ($mode ==
'bynumber') {
4361 $sql .=
", count(DISTINCT c.rowid)";
4363 $sql .=
", sum(d.total_ht) as total_ht";
4364 $sql .=
" FROM ".$this->db->prefix().
"contratdet as d, ".$this->db->prefix().
"contrat as c, ".$this->db->prefix().
"societe as s";
4365 if ($filteronproducttype >= 0) {
4366 $sql .=
", ".$this->db->prefix().
"product as p";
4368 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4369 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4371 $sql .=
" WHERE c.entity IN (".getEntity(
'contract').
")";
4372 $sql .=
" AND c.rowid = d.fk_contrat";
4374 if ($this->
id > 0) {
4375 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4377 $sql .=
" AND d.fk_product > 0";
4379 if ($filteronproducttype >= 0) {
4380 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4382 $sql .=
" AND c.fk_soc = s.rowid";
4384 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4385 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4388 $sql .=
" AND c.fk_soc = ".((int) $socid);
4390 $sql .= $morefilter;
4391 $sql .=
" GROUP BY date_format(c.date_contrat,'%Y%m')";
4392 $sql .=
" ORDER BY date_format(c.date_contrat,'%Y%m') DESC";
4408 public function get_nb_mos($socid, $mode, $filteronproducttype = -1, $year = 0, $morefilter =
'')
4411 global $conf, $user;
4413 $sql =
"SELECT sum(d.qty), date_format(d.date_valid, '%Y%m')";
4414 if ($mode ==
'bynumber') {
4415 $sql .=
", count(DISTINCT d.rowid)";
4417 $sql .=
" FROM ".$this->db->prefix().
"mrp_mo as d LEFT JOIN ".$this->db->prefix().
"societe as s ON d.fk_soc = s.rowid";
4418 if ($filteronproducttype >= 0) {
4419 $sql .=
", ".$this->db->prefix().
"product as p";
4421 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4422 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
4425 $sql .=
" WHERE d.entity IN (".getEntity(
'mo').
")";
4426 $sql .=
" AND d.status > 0";
4428 if ($this->
id > 0) {
4429 $sql .=
" AND d.fk_product = ".((int) $this->
id);
4431 $sql .=
" AND d.fk_product > 0";
4433 if ($filteronproducttype >= 0) {
4434 $sql .=
" AND p.rowid = d.fk_product AND p.fk_product_type = ".((int) $filteronproducttype);
4437 if (!$user->hasRight(
'societe',
'client',
'voir')) {
4438 $sql .=
" AND d.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
4441 $sql .=
" AND d.fk_soc = ".((int) $socid);
4443 $sql .= $morefilter;
4444 $sql .=
" GROUP BY date_format(d.date_valid,'%Y%m')";
4445 $sql .=
" ORDER BY date_format(d.date_valid,'%Y%m') DESC";
4467 if (!is_numeric($id_pere)) {
4470 if (!is_numeric($id_fils)) {
4473 if (!is_numeric($incdec)) {
4483 $sql =
"SELECT fk_product_pere from ".$this->db->prefix().
"product_association";
4484 $sql .=
" WHERE fk_product_pere = ".((int) $id_fils).
" AND fk_product_fils = ".((int) $id_pere);
4485 if (!$this->db->query(
$sql)) {
4490 $sql =
"SELECT MAX(rang) as max_rank FROM ".$this->db->prefix().
"product_association";
4491 $sql .=
" WHERE fk_product_pere = ".((int) $id_pere);
4492 $resql = $this->db->query(
$sql);
4494 $obj = $this->db->fetch_object($resql);
4495 $rank = $obj->max_rank + 1;
4497 $sql =
"INSERT INTO ".$this->db->prefix().
"product_association(fk_product_pere,fk_product_fils,qty,incdec,rang)";
4498 $sql .=
" VALUES (".((int) $id_pere).
", ".((int) $id_fils).
", ".
price2num($qty,
'MS').
", ".
price2num($incdec,
'MS').
", ".((int) $rank).
")";
4499 if (! $this->db->query(
$sql)) {
4505 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_ADD', $user);
4507 $this->error = $this->db->lasterror();
4508 dol_syslog(get_class($this).
'::addSubproduct error='.$this->error, LOG_ERR);
4540 if (!is_numeric($id_pere)) {
4543 if (!is_numeric($id_fils)) {
4546 if (!is_numeric($incdec)) {
4549 if (!is_numeric($qty)) {
4553 $sql =
'UPDATE '.$this->db->prefix().
'product_association SET ';
4554 $sql .=
'qty = '.price2num($qty,
'MS');
4555 $sql .=
',incdec = '.price2num($incdec,
'MS');
4556 $sql .=
' WHERE fk_product_pere = '.((int) $id_pere).
' AND fk_product_fils = '.((int) $id_fils);
4558 if (!$this->db->query(
$sql)) {
4564 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_UPDATE', $user);
4566 $this->error = $this->db->lasterror();
4567 dol_syslog(get_class($this).
'::updateSubproduct error='.$this->error, LOG_ERR);
4591 if (!is_numeric($fk_parent)) {
4594 if (!is_numeric($fk_child)) {
4598 $sql =
"DELETE FROM ".$this->db->prefix().
"product_association";
4599 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
4600 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
4602 dol_syslog(get_class($this).
'::del_sousproduit', LOG_DEBUG);
4603 if (!$this->db->query(
$sql)) {
4609 $sqlrank =
"SELECT rowid, rang FROM ".$this->db->prefix().
"product_association";
4610 $sqlrank .=
" WHERE fk_product_pere = ".((int) $fk_parent);
4611 $sqlrank .=
" ORDER BY rang";
4612 $resqlrank = $this->db->query($sqlrank);
4615 while ($objrank = $this->db->fetch_object($resqlrank)) {
4617 $sql =
"UPDATE ".$this->db->prefix().
"product_association";
4618 $sql .=
" SET rang = ".((int) $cpt);
4619 $sql .=
" WHERE rowid = ".((int) $objrank->rowid);
4620 if (! $this->db->query(
$sql)) {
4629 $result = $this->
call_trigger(
'PRODUCT_SUBPRODUCT_DELETE', $user);
4631 $this->error = $this->db->lasterror();
4632 dol_syslog(get_class($this).
'::delSubproduct error='.$this->error, LOG_ERR);
4652 $sql =
"SELECT fk_product_pere, qty, incdec";
4653 $sql .=
" FROM ".$this->db->prefix().
"product_association";
4654 $sql .=
" WHERE fk_product_pere = ".((int) $fk_parent);
4655 $sql .=
" AND fk_product_fils = ".((int) $fk_child);
4657 $result = $this->db->query(
$sql);
4659 $num = $this->db->num_rows($result);
4662 $obj = $this->db->fetch_object($result);
4664 $this->is_sousproduit_qty = $obj->qty;
4665 $this->is_sousproduit_incdec = $obj->incdec;
4696 dol_syslog(get_class($this).
"::add_fournisseur id_fourn = ".$id_fourn.
" ref_fourn=".
$ref_fourn.
" quantity=".$quantity, LOG_DEBUG);
4703 $sql =
"SELECT rowid, fk_product";
4704 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
4705 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
4707 $sql .=
" AND fk_product <> ".((int) $this->
id);
4708 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
4710 $resql = $this->db->query(
$sql);
4712 $obj = $this->db->fetch_object($resql);
4715 $this->product_id_already_linked = $obj->fk_product;
4718 $this->db->free($resql);
4722 $sql =
"SELECT rowid";
4723 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
4724 $sql .=
" WHERE fk_soc = ".((int) $id_fourn);
4728 $sql .=
" AND (ref_fourn = '' OR ref_fourn IS NULL)";
4730 $sql .=
" AND quantity = ".((float) $quantity);
4731 $sql .=
" AND fk_product = ".((int) $this->
id);
4732 $sql .=
" AND entity IN (".getEntity(
'productsupplierprice').
")";
4734 $resql = $this->db->query(
$sql);
4736 $obj = $this->db->fetch_object($resql);
4740 $sql =
"INSERT INTO ".$this->db->prefix().
"product_fournisseur_price(";
4743 $sql .=
", fk_product";
4745 $sql .=
", ref_fourn";
4746 $sql .=
", quantity";
4747 $sql .=
", fk_user";
4749 $sql .=
") VALUES (";
4750 $sql .=
"'".$this->db->idate($now).
"'";
4751 $sql .=
", ".((int) $conf->entity);
4752 $sql .=
", ".((int) $this->
id);
4753 $sql .=
", ".((int) $id_fourn);
4755 $sql .=
", ".((float) $quantity);
4756 $sql .=
", ".((int) $user->id);
4760 if ($this->db->query(
$sql)) {
4761 $this->product_fourn_price_id = $this->db->last_insert_id($this->db->prefix().
"product_fournisseur_price");
4764 $this->error = $this->db->lasterror();
4769 $this->product_fourn_price_id = $obj->rowid;
4773 $this->error = $this->db->lasterror();
4792 $sql =
"SELECT DISTINCT p.fk_soc";
4793 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as p";
4794 $sql .=
" WHERE p.fk_product = ".((int) $this->
id);
4795 $sql .=
" AND p.entity = ".((int) $conf->entity);
4797 $result = $this->db->query(
$sql);
4799 $num = $this->db->num_rows($result);
4802 $obj = $this->db->fetch_object($result);
4803 $list[$i] = $obj->fk_soc;
4821 global $conf, $user;
4828 $sql =
"INSERT INTO ".$this->db->prefix().
"product_price (";
4830 $sql .=
", fk_product";
4831 $sql .=
", date_price";
4832 $sql .=
", price_level";
4834 $sql .=
", price_ttc";
4835 $sql .=
", price_min";
4836 $sql .=
", price_min_ttc";
4837 $sql .=
", price_base_type";
4838 $sql .=
", price_label";
4839 $sql .=
", default_vat_code";
4841 $sql .=
", recuperableonly";
4842 $sql .=
", localtax1_tx";
4843 $sql .=
", localtax1_type";
4844 $sql .=
", localtax2_tx";
4845 $sql .=
", localtax2_type";
4846 $sql .=
", fk_user_author";
4848 $sql .=
", price_by_qty";
4849 $sql .=
", fk_price_expression";
4850 $sql .=
", fk_multicurrency";
4851 $sql .=
", multicurrency_code";
4852 $sql .=
", multicurrency_tx";
4853 $sql .=
", multicurrency_price";
4854 $sql .=
", multicurrency_price_ttc";
4859 $sql .=
", '".$this->db->idate($now).
"'";
4860 $sql .=
", price_level";
4862 $sql .=
", price_ttc";
4863 $sql .=
", price_min";
4864 $sql .=
", price_min_ttc";
4865 $sql .=
", price_base_type";
4866 $sql .=
", price_label";
4867 $sql .=
", default_vat_code";
4869 $sql .=
", recuperableonly";
4870 $sql .=
", localtax1_tx";
4871 $sql .=
", localtax1_type";
4872 $sql .=
", localtax2_tx";
4873 $sql .=
", localtax2_type";
4874 $sql .=
", ".$user->id;
4876 $sql .=
", price_by_qty";
4877 $sql .=
", fk_price_expression";
4878 $sql .=
", fk_multicurrency";
4879 $sql .=
", multicurrency_code";
4880 $sql .=
", multicurrency_tx";
4881 $sql .=
", multicurrency_price";
4882 $sql .=
", multicurrency_price_ttc";
4883 $sql .=
" FROM ".$this->db->prefix().
"product_price ps";
4884 $sql .=
" WHERE fk_product = ".((int) $fromId);
4885 $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)";
4886 $sql .=
" ORDER BY date_price DESC";
4889 $resql = $this->db->query(
$sql);
4891 $this->db->rollback();
4895 $this->db->commit();
4912 $sql =
'INSERT INTO '.$this->db->prefix().
'product_association (fk_product_pere, fk_product_fils, qty, incdec)';
4913 $sql .=
" SELECT ".$toId.
", fk_product_fils, qty, incdec FROM ".$this->db->prefix().
"product_association";
4914 $sql .=
" WHERE fk_product_pere = ".((int) $fromId);
4916 dol_syslog(get_class($this).
'::clone_association', LOG_DEBUG);
4917 if (!$this->db->query(
$sql)) {
4918 $this->db->rollback();
4922 $this->db->commit();
4955 $sql =
"INSERT ".$this->db->prefix().
"product_fournisseur_price (";
4956 $sql .=
" datec, fk_product, fk_soc, price, quantity, fk_user, tva_tx)";
4957 $sql .=
" SELECT '".$this->db->idate($now).
"', ".((int) $toId).
", fk_soc, price, quantity, fk_user, tva_tx";
4958 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price";
4959 $sql .=
" WHERE fk_product = ".((int) $fromId);
4961 dol_syslog(get_class($this).
'::clone_fournisseurs', LOG_DEBUG);
4962 $resql = $this->db->query(
$sql);
4964 $this->db->rollback();
4967 $this->db->commit();
4985 public function fetch_prod_arbo($prod, $compl_path =
'', $multiply = 1, $level = 1, $id_parent = 0, $ignore_stock_load = 0)
4988 global $conf, $langs;
4992 foreach ($prod as $id_product => $desc_pere) {
4993 if (is_array($desc_pere)) {
4994 $id = (!empty($desc_pere[0]) ? $desc_pere[0] :
'');
4995 $nb = (!empty($desc_pere[1]) ? $desc_pere[1] :
'');
4996 $type = (!empty($desc_pere[2]) ? $desc_pere[2] :
'');
4997 $label = (!empty($desc_pere[3]) ? $desc_pere[3] :
'');
4998 $incdec = (!empty($desc_pere[4]) ? $desc_pere[4] : 0);
5000 if ($multiply < 1) {
5005 if (is_null($tmpproduct)) {
5006 $tmpproduct =
new Product($this->db);
5008 $tmpproduct->fetch($id);
5010 if (empty($ignore_stock_load) && ($tmpproduct->isProduct() ||
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES'))) {
5011 $tmpproduct->load_stock(
'nobatch,novirtual');
5014 $this->res[] = array(
5016 'id_parent' => $id_parent,
5017 'ref' => $tmpproduct->ref,
5019 'nb_total' => $nb * $multiply,
5020 'stock' => $tmpproduct->stock_reel,
5021 'stock_alert' => $tmpproduct->seuil_stock_alerte,
5023 'fullpath' => $compl_path.$label,
5025 'desiredstock' => $tmpproduct->desiredstock,
5027 'incdec' => $incdec,
5028 'entity' => $tmpproduct->entity
5032 if (isset($desc_pere[
'childs']) && is_array($desc_pere[
'childs'])) {
5034 $this->
fetch_prod_arbo($desc_pere[
'childs'], $compl_path.$desc_pere[3].
" -> ", $desc_pere[1] * $multiply, $level + 1, $id, $ignore_stock_load);
5052 $this->res = array();
5053 if (isset($this->sousprods) && is_array($this->sousprods)) {
5054 foreach ($this->sousprods as $prod_name => $desc_product) {
5055 if (is_array($desc_product)) {
5056 $this->
fetch_prod_arbo($desc_product,
"", $multiply, 1, $this->
id, $ignore_stock_load);
5075 $sql =
"SELECT COUNT(pa.rowid) as nb";
5076 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa";
5078 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id).
" OR pa.fk_product_pere = ".((int) $this->
id);
5079 } elseif ($mode == -1) {
5080 $sql .=
" WHERE pa.fk_product_fils = ".((int) $this->
id);
5081 } elseif ($mode == 1) {
5082 $sql .=
" WHERE pa.fk_product_pere = ".((int) $this->
id);
5085 $resql = $this->db->query(
$sql);
5087 $obj = $this->db->fetch_object($resql);
5106 $sql =
"SELECT count(rowid) as nb FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_parent = ".((int) $this->
id);
5107 $sql .=
" AND entity IN (".getEntity(
'product').
")";
5109 $resql = $this->db->query(
$sql);
5111 $obj = $this->db->fetch_object($resql);
5130 $sql =
"SELECT rowid FROM ".$this->db->prefix().
"product_attribute_combination WHERE fk_product_child = ".((int) $this->
id).
" AND entity IN (".
getEntity(
'product').
")";
5132 $query = $this->db->query(
$sql);
5135 if (!$this->db->num_rows($query)) {
5156 $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";
5157 $sql .=
", p.tosell as status, p.tobuy as status_buy";
5158 $sql .=
" FROM ".$this->db->prefix().
"product_association as pa,";
5159 $sql .=
" ".$this->db->prefix().
"product as p";
5160 $sql .=
" WHERE p.rowid = pa.fk_product_pere";
5161 $sql .=
" AND pa.fk_product_fils = ".((int) $this->
id);
5163 $res = $this->db->query(
$sql);
5166 while ($record = $this->db->fetch_array($res)) {
5168 $prods[$record[
'id']][
'id'] = $record[
'rowid'];
5169 $prods[$record[
'id']][
'ref'] = $record[
'ref'];
5170 $prods[$record[
'id']][
'label'] = $record[
'label'];
5171 $prods[$record[
'id']][
'qty'] = $record[
'qty'];
5172 $prods[$record[
'id']][
'incdec'] = $record[
'incdec'];
5173 $prods[$record[
'id']][
'fk_product_type'] = $record[
'fk_product_type'];
5174 $prods[$record[
'id']][
'entity'] = $record[
'entity'];
5175 $prods[$record[
'id']][
'status'] = $record[
'status'];
5176 $prods[$record[
'id']][
'status_buy'] = $record[
'status_buy'];
5195 public function getChildsArbo($id, $firstlevelonly = 0, $level = 1, $parents = array())
5197 global $alreadyfound;
5203 $sql =
"SELECT p.rowid, p.ref, p.label as label, p.fk_product_type,";
5204 $sql .=
" pa.qty as qty, pa.fk_product_fils as id, pa.incdec,";
5205 $sql .=
" pa.rowid as fk_association, pa.rang";
5206 $sql .=
" FROM ".$this->db->prefix().
"product as p,";
5207 $sql .=
" ".$this->db->prefix().
"product_association as pa";
5208 $sql .=
" WHERE p.rowid = pa.fk_product_fils";
5209 $sql .=
" AND pa.fk_product_pere = ".((int) $id);
5210 $sql .=
" AND pa.fk_product_fils <> ".((int) $id);
5211 $sql .=
" ORDER BY pa.rang";
5213 dol_syslog(get_class($this).
'::getChildsArbo id='.$id.
' level='.$level.
' parents='.(is_array($parents) ? implode(
',', $parents) : $parents), LOG_DEBUG);
5216 $alreadyfound = array($id => 1);
5223 $res = $this->db->query(
$sql);
5226 while ($rec = $this->db->fetch_array($res)) {
5227 if (!empty($alreadyfound[$rec[
'rowid']])) {
5228 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);
5229 if (in_array($rec[
'id'], $parents)) {
5233 $alreadyfound[$rec[
'rowid']] = 1;
5234 $prods[$rec[
'rowid']] = array(
5237 2 => $rec[
'fk_product_type'],
5238 3 => $this->db->escape($rec[
'label']),
5239 4 => $rec[
'incdec'],
5241 6 => $rec[
'fk_association'],
5246 if (empty($firstlevelonly)) {
5247 $parents[] = $rec[
'rowid'];
5248 $listofchilds = $this->
getChildsArbo($rec[
'rowid'], 0, $level + 1, $parents);
5249 foreach ($listofchilds as $keyChild => $valueChild) {
5250 $prods[$rec[
'rowid']][
'childs'][$keyChild] = $valueChild;
5274 foreach ($this->
getChildsArbo($this->
id) as $keyChild => $valueChild) {
5275 $parent[$this->label][$keyChild] = $valueChild;
5277 foreach ($parent as $key => $value) {
5278 $this->sousprods[$key] = $value;
5290 global $conf, $langs, $user;
5292 $langs->loadLangs(array(
'products',
'other'));
5295 $nofetch = !empty($params[
'nofetch']);
5298 return [
'optimize' => $langs->trans(
"ShowProduct")];
5301 if (!empty($this->entity)) {
5302 $tmpphoto = $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 80, 0, 0, 0, 0, 1);
5303 if ($this->nbphoto > 0) {
5304 $datas[
'photo'] =
'<div class="photointooltip floatright">'.
"\n" . $tmpphoto .
'</div>';
5309 $datas[
'picto'] =
img_picto(
'',
'product').
' <u class="paddingrightonly">'.$langs->trans(
"Product").
'</u>';
5311 $datas[
'picto'] =
img_picto(
'',
'service').
' <u class="paddingrightonly">'.$langs->trans(
"Service").
'</u>';
5313 if (isset($this->
status) && isset($this->status_buy)) {
5314 $datas[
'status'] =
' '.$this->getLibStatut(5, 0) .
' '.$this->getLibStatut(5, 1);
5317 if (!empty($this->
ref)) {
5318 $datas[
'ref'] =
'<br><b>'.$langs->trans(
'ProductRef').
':</b> '.$this->ref;
5320 if (!empty($this->label)) {
5321 $datas[
'label'] =
'<br><b>'.$langs->trans(
'ProductLabel').
':</b> '.$this->label;
5328 $langs->load(
"productbatch");
5329 $datas[
'batchstatus'] =
"<br><b>".$langs->trans(
"ManageLotSerial").
'</b>: '.$this->
getLibStatut(0, 2);
5333 $datas[
'barcode'] =
'<br><b>'.$langs->trans(
'BarCode').
':</b> '.$this->barcode;
5337 if ($this->weight) {
5338 $datas[
'weight'] =
"<br><b>".$langs->trans(
"Weight").
'</b>: '.$this->weight.
' '.
measuringUnitString(0,
"weight", $this->weight_units);
5341 if ($this->length) {
5342 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Length").
'</b>: '.$this->length.
' '.
measuringUnitString(0,
'size', $this->length_units);
5345 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Width").
'</b>: '.$this->width.
' '.
measuringUnitString(0,
'size', $this->width_units);
5347 if ($this->height) {
5348 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Height").
'</b>: '.$this->height.
' '.
measuringUnitString(0,
'size', $this->height_units);
5351 $datas[
'size'] =
"<br>".$labelsize;
5354 $labelsurfacevolume =
"";
5355 if ($this->surface) {
5356 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Surface").
'</b>: '.$this->surface.
' '.
measuringUnitString(0,
'surface', $this->surface_units);
5358 if ($this->volume) {
5359 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Volume").
'</b>: '.$this->volume.
' '.
measuringUnitString(0,
'volume', $this->volume_units);
5361 if ($labelsurfacevolume) {
5362 $datas[
'surface'] =
"<br>" . $labelsurfacevolume;
5368 if ($this->duration_value > 1) {
5369 $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"));
5370 } elseif ($this->duration_value > 0) {
5371 $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"));
5373 $datas[
'duration'] .= (!empty($this->duration_unit) && isset($dur[$this->duration_unit]) ?
" ".$langs->trans($dur[$this->duration_unit]) :
'');
5375 if (empty($user->socid)) {
5377 $datas[
'pmp'] =
"<br><b>".$langs->trans(
"PMPValue").
'</b>: '.
price($this->pmp, 0,
'', 1, -1, -1, $conf->currency);
5381 if ($this->
status && isset($this->accountancy_code_sell)) {
5382 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5383 $selllabel =
'<br>';
5384 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellCode').
':</b> '.
length_accountg($this->accountancy_code_sell);
5385 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellIntraCode').
':</b> '.
length_accountg($this->accountancy_code_sell_intra);
5386 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellExportCode').
':</b> '.
length_accountg($this->accountancy_code_sell_export);
5387 $datas[
'accountancysell'] = $selllabel;
5389 if ($this->status_buy && isset($this->accountancy_code_buy)) {
5390 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5392 if (empty($this->
status)) {
5393 $buylabel .=
'<br>';
5395 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyCode').
':</b> '.
length_accountg($this->accountancy_code_buy);
5396 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyIntraCode').
':</b> '.
length_accountg($this->accountancy_code_buy_intra);
5397 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyExportCode').
':</b> '.
length_accountg($this->accountancy_code_buy_export);
5398 $datas[
'accountancybuy'] = $buylabel;
5404 require_once DOL_DOCUMENT_ROOT .
'/categories/class/categorie.class.php';
5405 $form =
new Form($this->db);
5406 $datas[
'categories'] =
'<br>' . $form->showCategories($this->
id, Categorie::TYPE_PRODUCT, 1);
5425 public function getNomUrl($withpicto = 0, $option =
'', $maxlength = 0, $save_lastsearch_value = -1, $notooltip = 0, $morecss =
'', $add_label = 0, $sep =
' - ')
5427 global $conf, $langs, $hookmanager, $user;
5428 include_once DOL_DOCUMENT_ROOT.
'/core/lib/product.lib.php';
5432 $newref = $this->ref;
5434 $newref =
dol_trunc($newref, $maxlength,
'middle');
5438 'objecttype' => (isset($this->
type) ? ($this->
type == 1 ?
'service' :
'product') : $this->element),
5439 'option' => $option,
5442 $classfortooltip =
'classfortooltip';
5445 $classfortooltip =
'classforajaxtooltip';
5446 $dataparams =
' data-params="'.dol_escape_htmltag(json_encode($params)).
'"';
5453 if (empty($notooltip)) {
5455 $label = $langs->trans(
"ShowProduct");
5456 $linkclose .=
' alt="'.dol_escape_htmltag($label, 1, 1).
'"';
5458 $linkclose .= ($label ?
' title="'.dol_escape_htmltag($label, 1, 1).
'"' :
' title="tocomplete"');
5459 $linkclose .= $dataparams.
' class="nowraponall '.$classfortooltip.($morecss ?
' '.$morecss :
'').
'"';
5461 $linkclose =
' class="nowraponall'.($morecss ?
' '.$morecss :
'').
'"';
5464 if ($option ==
'supplier' || $option ==
'category') {
5465 $url = DOL_URL_ROOT.
'/product/price_suppliers.php?id='.$this->id;
5466 } elseif ($option ==
'stock') {
5467 $url = DOL_URL_ROOT.
'/product/stock/product.php?id='.$this->id;
5468 } elseif ($option ==
'composition') {
5469 $url = DOL_URL_ROOT.
'/product/composition/card.php?id='.$this->id;
5471 $url = DOL_URL_ROOT.
'/product/card.php?id='.$this->id;
5474 if ($option !==
'nolink') {
5476 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
5477 if ($save_lastsearch_value == -1 && isset($_SERVER[
"PHP_SELF"]) && preg_match(
'/list\.php/', $_SERVER[
"PHP_SELF"])) {
5478 $add_save_lastsearch_values = 1;
5480 if ($add_save_lastsearch_values) {
5481 $url .=
'&save_lastsearch_values=1';
5485 $linkstart =
'<a href="'.$url.
'"';
5486 $linkstart .= $linkclose.
'>';
5489 $result .= $linkstart;
5492 $result .= (
img_object(($notooltip ?
'' : $label),
'product',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
5495 $result .= (
img_object(($notooltip ?
'' : $label),
'service',
'class="paddingright"', 0, 0, $notooltip ? 0 : 1));
5498 $result .=
'<span class="aaa">'.dol_escape_htmltag($newref).
'</span>';
5499 $result .= $linkend;
5500 if ($withpicto != 2) {
5501 $result .= (($add_label && $this->label) ? $sep.dol_trunc($this->label, ($add_label > 1 ? $add_label : 0)) :
'');
5505 $hookmanager->initHooks(array(
'productdao'));
5506 $parameters = array(
'id' => $this->
id,
'getnomurl' => &$result,
'label' => &$label);
5507 $reshook = $hookmanager->executeHooks(
'getNomUrl', $parameters, $this, $action);
5509 $result = $hookmanager->resPrint;
5511 $result .= $hookmanager->resPrint;
5528 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
5530 global $conf, $user, $langs;
5532 $langs->load(
"products");
5533 $outputlangs->load(
"products");
5540 $modelpath =
"core/modules/product/doc/";
5542 return $this->
commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
5558 return $this->
LibStatut($this->status_buy, $mode, $type);
5560 return $this->
LibStatut($this->status_batch, $mode, $type);
5563 return $this->
LibStatut($this->status_buy, $mode, $type);
5579 global $conf, $langs;
5581 $labelStatus = $labelStatusShort =
'';
5583 $langs->load(
'products');
5585 $langs->load(
"productbatch");
5591 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial')));
5594 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort')));
5599 return dolGetStatus($langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch'),
'',
'', empty($status) ?
'status5' :
'status4', 3,
'dot');
5605 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'));
5609 $statuttrans = empty($status) ?
'status5' :
'status4';
5614 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSellShort');
5615 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSell');
5616 } elseif ($type == 1) {
5617 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuyShort');
5618 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuy');
5619 } elseif ($type == 2) {
5620 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch');
5621 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort');
5623 } elseif ($status == 1) {
5626 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSellShort');
5627 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSell');
5628 } elseif ($type == 1) {
5629 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBuyShort');
5630 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBuy');
5631 } elseif ($type == 2) {
5632 $labelStatus = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial'));
5633 $labelStatusShort = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort'));
5635 } elseif ($type == 2 && $status == 2) {
5636 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSerial');
5637 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort');
5641 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'),
'',
'',
'status0', 0);
5643 return dolGetStatus($labelStatus, $labelStatusShort,
'', $statuttrans, $mode);
5656 $langs->load(
'products');
5659 if (isset($this->finished) && $this->finished >= 0) {
5660 $sql =
"SELECT label, code FROM ".$this->db->prefix().
"c_product_nature where code = ".((int) $this->finished).
" AND active=1";
5661 $resql = $this->db->query(
$sql);
5663 $this->error = $this->db->error().
' sql='.
$sql;
5664 dol_syslog(__METHOD__.
' Error '.$this->error, LOG_ERR);
5666 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
5667 $label = $langs->trans($res[
'label']);
5669 $this->db->free($resql);
5693 public function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label =
'', $price = 0, $inventorycode =
'', $origin_element =
'', $origin_id =
null, $disablestockchangeforsubproduct = 0, $extrafields =
null)
5699 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
5705 $nbpiece = abs($nbpiece);
5708 $op[0] =
"+".trim((
string) $nbpiece);
5709 $op[1] =
"-".trim((
string) $nbpiece);
5712 $movementstock->setOrigin($origin_element, $origin_id);
5713 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'',
'',
'',
'',
false, 0, $disablestockchangeforsubproduct);
5717 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
5718 $movementstock->array_options = $array_options;
5719 $movementstock->insertExtraFields();
5721 $this->db->commit();
5724 $this->error = $movementstock->error;
5725 $this->errors = $movementstock->errors;
5727 $this->db->rollback();
5756 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)
5762 include_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
5768 $nbpiece = abs($nbpiece);
5772 $op[0] =
"+".trim((
string) $nbpiece);
5773 $op[1] =
"-".trim((
string) $nbpiece);
5776 $movementstock->setOrigin($origin_element, $origin_id);
5777 $result = $movementstock->_create($user, $this->
id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode,
'', $dlc, $dluo, $lot,
false, 0, $disablestockchangeforsubproduct, 0, $force_update_batch);
5781 $array_options = $extrafields->getOptionalsFromPost(
'stock_mouvement');
5782 $movementstock->array_options = $array_options;
5783 $movementstock->insertExtraFields();
5785 $this->db->commit();
5788 $this->error = $movementstock->error;
5789 $this->errors = $movementstock->errors;
5791 $this->db->rollback();
5811 public function load_stock($option =
'', $includedraftpoforvirtual =
null, $dateofvirtualstock =
null)
5816 $this->stock_reel = 0;
5817 $this->stock_warehouse = array();
5818 $this->stock_theorique = 0;
5821 $warehouseStatus = array();
5822 if (preg_match(
'/warehouseclosed/', $option)) {
5825 if (preg_match(
'/warehouseopen/', $option)) {
5828 if (preg_match(
'/warehouseinternal/', $option)) {
5836 $sql =
"SELECT ps.rowid, ps.reel, ps.fk_entrepot";
5837 $sql .=
" FROM ".$this->db->prefix().
"product_stock as ps";
5838 $sql .=
", ".$this->db->prefix().
"entrepot as w";
5839 $sql .=
" WHERE w.entity IN (".getEntity(
'stock').
")";
5840 $sql .=
" AND w.rowid = ps.fk_entrepot";
5841 $sql .=
" AND ps.fk_product = ".((int) $this->
id);
5842 if (count($warehouseStatus)) {
5843 $sql .=
" AND w.statut IN (".$this->db->sanitize(implode(
',', $warehouseStatus)).
")";
5846 $sql .=
" ORDER BY ps.reel ".(getDolGlobalString(
'DO_NOT_TRY_TO_DEFRAGMENT_STOCKS_WAREHOUSE') ?
'DESC' :
'ASC');
5848 dol_syslog(get_class($this).
"::load_stock", LOG_DEBUG);
5849 $result = $this->db->query(
$sql);
5851 $num = $this->db->num_rows($result);
5855 $row = $this->db->fetch_object($result);
5856 $this->stock_warehouse[$row->fk_entrepot] =
new stdClass();
5857 $this->stock_warehouse[$row->fk_entrepot]->real = $row->reel;
5858 $this->stock_warehouse[$row->fk_entrepot]->id = $row->rowid;
5859 if ((!preg_match(
'/nobatch/', $option)) && $this->
hasbatch()) {
5860 $this->stock_warehouse[$row->fk_entrepot]->detail_batch =
Productbatch::findAll($this->db, $row->rowid, 1, $this->id);
5862 $this->stock_reel += $row->reel;
5866 $this->db->free($result);
5868 if (!preg_match(
'/novirtual/', $option)) {
5874 $this->error = $this->db->lasterror();
5893 global $conf, $hookmanager, $action;
5895 $stock_commande_client = 0;
5896 $stock_commande_fournisseur = 0;
5897 $stock_sending_client = 0;
5898 $stock_reception_fournisseur = 0;
5899 $stock_inproduction = 0;
5908 $stock_commande_client = $this->stats_commande[
'qty'];
5911 require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expedition.class.php';
5912 $filterShipmentStatus =
'';
5922 $stock_sending_client = $this->stats_expedition[
'qty'];
5925 $filterStatus = !
getDolGlobalString(
'SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK') ?
'3,4' : $conf->global->SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK;
5926 if (isset($includedraftpoforvirtual)) {
5927 $filterStatus =
'0,1,2,'.$filterStatus;
5933 $stock_commande_fournisseur = $this->stats_commande_fournisseur[
'qty'];
5937 $filterStatus =
'4';
5938 if (isset($includedraftpoforvirtual)) {
5939 $filterStatus =
'0,'.$filterStatus;
5945 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
5949 $filterStatus =
'4';
5950 if (isset($includedraftpoforvirtual)) {
5951 $filterStatus =
'0,'.$filterStatus;
5957 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
5964 $stock_inproduction = $this->stats_mrptoproduce[
'qty'] - $this->stats_mrptoconsume[
'qty'];
5967 $this->stock_theorique = $this->stock_reel + $stock_inproduction;
5971 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
5973 $this->stock_theorique += 0;
5975 $this->stock_theorique -= $stock_commande_client;
5979 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
5981 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
5983 $this->stock_theorique -= $stock_reception_fournisseur;
5985 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
5988 $parameters = array(
'id' => $this->
id,
'includedraftpoforvirtual' => $includedraftpoforvirtual);
5990 $reshook = $hookmanager->executeHooks(
'loadvirtualstock', $parameters, $this, $action);
5992 $this->stock_theorique = $hookmanager->resArray[
'stock_theorique'];
5993 } elseif ($reshook == 0 && isset($hookmanager->resArray[
'stock_stats_hook'])) {
5994 $this->stock_theorique += $hookmanager->resArray[
'stock_stats_hook'];
5998 if (!empty($this->stock_warehouse) &&
getDolGlobalString(
'STOCK_ALLOW_VIRTUAL_STOCK_PER_WAREHOUSE')) {
5999 foreach ($this->stock_warehouse as $warehouseid => $stockwarehouse) {
6007 if ($this->fk_default_warehouse == $warehouseid) {
6008 $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']);
6010 $this->stock_warehouse[$warehouseid]->virtual = $this->stock_warehouse[$warehouseid]->real + $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'];
6030 $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";
6031 $sql .=
" WHERE pb.fk_product_stock = ps.rowid AND ps.fk_product = ".((int) $this->
id).
" AND pb.batch = '".$this->db->escape($batch).
"'";
6032 $sql .=
" GROUP BY pb.batch, pb.eatby, pb.sellby";
6033 dol_syslog(get_class($this).
"::loadBatchInfo load first entry found for lot/serial = ".$batch, LOG_DEBUG);
6034 $resql = $this->db->query(
$sql);
6036 $num = $this->db->num_rows($resql);
6039 $obj = $this->db->fetch_object($resql);
6040 $result[] = array(
'batch' => $batch,
'eatby' => $this->db->jdate($obj->eatby),
'sellby' => $this->db->jdate($obj->sellby),
'qty' => $obj->qty);
6046 $this->db->rollback();
6064 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6070 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos";
6072 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product').dol_sanitizeFileName($this->
ref);
6077 $dir_osencoded = $dir;
6079 if (is_dir($dir_osencoded)) {
6080 $originImage = $dir.
'/'.$file[
'name'];
6091 if (is_numeric($result) && $result > 0) {
6108 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6109 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6115 $dir .=
'/'.get_exdir($this->
id, 2, 0, 0, $this,
'product').$this->id.
"/photos/";
6117 $dir .=
'/'.get_exdir(0, 0, 0, 0, $this,
'product');
6123 if (file_exists($dir_osencoded)) {
6124 $handle = opendir($dir_osencoded);
6125 if (is_resource($handle)) {
6126 while (($file = readdir($handle)) !==
false) {
6128 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6150 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6151 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6157 $handle = @opendir($dir_osencoded);
6158 if (is_resource($handle)) {
6159 while (($file = readdir($handle)) !==
false) {
6161 $file = mb_convert_encoding($file,
'UTF-8',
'ISO-8859-1');
6168 $photo_vignette =
'';
6170 if (preg_match(
'/('.$this->regeximgext.
')$/i', $photo, $regs)) {
6171 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $photo).
'_small'.$regs[0];
6174 $dirthumb = $dir.
'thumbs/';
6178 $obj[
'photo'] = $photo;
6179 if ($photo_vignette &&
dol_is_file($dirthumb.$photo_vignette)) {
6180 $obj[
'photo_vignette'] =
'thumbs/'.$photo_vignette;
6182 $obj[
'photo_vignette'] =
"";
6185 $tabobj[$nbphoto - 1] = $obj;
6188 if ($nbmax && $nbphoto >= $nbmax) {
6210 include_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
6211 include_once DOL_DOCUMENT_ROOT.
'/core/lib/images.lib.php';
6213 $dir = dirname($file).
'/';
6214 $dirthumb = $dir.
'/thumbs/';
6215 $filename = preg_replace(
'/'.preg_quote($dir,
'/').
'/i',
'', $file);
6221 if (preg_match(
'/('.$this->regeximgext.
')$/i', $filename, $regs)) {
6222 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_small'.$regs[0];
6223 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6227 $photo_vignette = preg_replace(
'/'.$regs[0].
'/i',
'', $filename).
'_mini'.$regs[0];
6228 if (file_exists(
dol_osencode($dirthumb.$photo_vignette))) {
6245 $infoImg = getimagesize($file_osencoded);
6246 $this->imgWidth = $infoImg[0];
6247 $this->imgHeight = $infoImg[1];
6257 global $hookmanager;
6259 $this->nb = array();
6261 $sql =
"SELECT count(p.rowid) as nb, fk_product_type";
6262 $sql .=
" FROM ".$this->db->prefix().
"product as p";
6263 $sql .=
' WHERE p.entity IN ('.getEntity($this->element, 1).
')';
6265 if (is_object($hookmanager)) {
6266 $parameters = array();
6267 $reshook = $hookmanager->executeHooks(
'printFieldListWhere', $parameters, $this);
6268 $sql .= $hookmanager->resPrint;
6270 $sql .=
' GROUP BY fk_product_type';
6272 $resql = $this->db->query(
$sql);
6274 while ($obj = $this->db->fetch_object($resql)) {
6275 if ($obj->fk_product_type == 1) {
6276 $this->nb[
"services"] = $obj->nb;
6278 $this->nb[
"products"] = $obj->nb;
6281 $this->db->free($resql);
6285 $this->error = $this->db->error();
6327 return ($this->mandatory_period == 1 ?
true :
false);
6337 return ($this->status_batch > 0 ?
true :
false);
6357 $dirsociete = array_merge(array(
'/core/modules/barcode/'), $conf->modules_parts[
'barcode']);
6358 foreach ($dirsociete as $dirroot) {
6366 '@phan-var-force ModeleNumRefBarCode $module';
6368 $result = $mod->getNextValue(
$object, $type);
6370 dol_syslog(get_class($this).
"::get_barcode barcode=".$result.
" module=".$var);
6387 $this->specimen = 1;
6389 $this->
ref =
'PRODUCT_SPEC';
6390 $this->label =
'PRODUCT SPECIMEN';
6391 $this->
description =
'This is description of this product specimen that was created the '.dol_print_date($now,
'dayhourlog').
'.';
6392 $this->specimen = 1;
6393 $this->country_id = 1;
6395 $this->status_buy = 1;
6397 $this->sell_or_eat_by_mandatory = 0;
6398 $this->note_private =
'This is a comment (private)';
6399 $this->note_public =
'This is a comment (public)';
6400 $this->date_creation = $now;
6401 $this->date_modification = $now;
6404 $this->weight_units = 3;
6407 $this->length_units = 1;
6409 $this->width_units = 0;
6410 $this->height =
null;
6411 $this->height_units =
null;
6413 $this->surface = 30;
6414 $this->surface_units = 0;
6415 $this->volume = 300;
6416 $this->volume_units = 0;
6418 $this->barcode = -1;
6433 if (!$this->fk_unit) {
6437 $langs->load(
'products');
6439 $label_type =
'label';
6440 if ($type ==
'short') {
6441 $label_type =
'short_label';
6444 $sql =
"SELECT ".$label_type.
", code from ".$this->db->prefix().
"c_units where rowid = ".((int) $this->fk_unit);
6446 $resql = $this->db->query(
$sql);
6448 $this->error = $this->db->error();
6449 dol_syslog(get_class($this).
"::getLabelOfUnit Error ".$this->error, LOG_ERR);
6451 } elseif ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
6452 $label = ($label_type ==
'short_label' ? $res[$label_type] :
'unit'.$res[
'code']);
6454 $this->db->free($resql);
6470 $maxpricesupplier = 0;
6473 include_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.product.class.php';
6475 $product_fourn_list = $product_fourn->list_product_fournisseur_price($this->
id,
'',
'');
6477 if (is_array($product_fourn_list) && count($product_fourn_list) > 0) {
6478 foreach ($product_fourn_list as $productfourn) {
6479 if ($productfourn->fourn_unitprice > $maxpricesupplier) {
6480 $maxpricesupplier = $productfourn->fourn_unitprice;
6484 $maxpricesupplier *= $conf->global->PRODUCT_MINIMUM_RECOMMENDED_PRICE;
6488 return $maxpricesupplier;
6504 require_once DOL_DOCUMENT_ROOT.
'/categories/class/categorie.class.php';
6505 return parent::setCategoriesCommon($categories, Categorie::TYPE_PRODUCT);
6519 'product_customer_price',
6520 'product_customer_price_log'
6541 $sql =
"SELECT rowid, level, fk_level, var_percent, var_min_percent FROM ".$this->db->prefix().
"product_pricerules";
6542 $query = $this->db->query(
$sql);
6546 while ($result = $this->db->fetch_object($query)) {
6547 $rules[$result->level] = $result;
6556 for ($i = 1; $i <= $nbofproducts; $i++) {
6557 $price = $baseprice;
6558 $price_min = $baseprice;
6562 if ($i > 1 && isset($rules[$i]->var_percent) && $rules[$i]->var_percent) {
6563 $price = $prices[$rules[$i]->fk_level] * (1 + ($rules[$i]->var_percent / 100));
6566 $prices[$i] = $price;
6569 if (isset($rules[$i]->var_min_percent) && $rules[$i]->var_min_percent) {
6570 $price_min = $price * (1 - ($rules[$i]->var_min_percent / 100));
6574 $check_amount = (($price == $this->multiprices[$i]) && ($price_min == $this->multiprices_min[$i]));
6575 $check_type = ($baseprice == $this->multiprices_base_type[$i]);
6577 if ($check_amount && $check_type) {
6581 if ($this->
updatePrice($price, $price_type, $user, $price_vat, $price_min, $i, $npr, $psq,
true) < 0) {
6599 return $user->rights->produit;
6601 return $user->rights->service;
6613 $sql =
"SELECT p.rowid, p.ref, p.datec as date_creation, p.tms as date_modification,";
6614 $sql .=
" p.fk_user_author, p.fk_user_modif";
6615 $sql .=
" FROM ".$this->db->prefix().$this->table_element.
" as p";
6616 $sql .=
" WHERE p.rowid = ".((int) $id);
6618 $result = $this->db->query(
$sql);
6620 if ($this->db->num_rows($result)) {
6621 $obj = $this->db->fetch_object($result);
6623 $this->
id = $obj->rowid;
6624 $this->
ref = $obj->ref;
6626 $this->user_creation_id = $obj->fk_user_author;
6627 $this->user_modification_id = $obj->fk_user_modif;
6629 $this->date_creation = $this->db->jdate($obj->date_creation);
6630 $this->date_modification = $this->db->jdate($obj->date_modification);
6633 $this->db->free($result);
6649 if (empty($this->duration_value)) {
6650 $this->errors[] =
'ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
6654 if ($this->duration_unit ==
'i') {
6655 $prodDurationHours = 1. / 60;
6657 if ($this->duration_unit ==
'h') {
6658 $prodDurationHours = 1.;
6660 if ($this->duration_unit ==
'd') {
6661 $prodDurationHours = 24.;
6663 if ($this->duration_unit ==
'w') {
6664 $prodDurationHours = 24. * 7;
6666 if ($this->duration_unit ==
'm') {
6667 $prodDurationHours = 24. * 30;
6669 if ($this->duration_unit ==
'y') {
6670 $prodDurationHours = 24. * 365;
6674 return $prodDurationHours;
6687 global $langs,$conf;
6689 $selected = (empty($arraydata[
'selected']) ? 0 : $arraydata[
'selected']);
6691 $return =
'<div class="box-flex-item box-flex-grow-zero">';
6692 $return .=
'<div class="info-box info-box-sm">';
6693 $return .=
'<div class="info-box-img">';
6696 $label .= $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 120, 160, 0, 0, 0,
'',
'photoref photokanban');
6706 $return .=
'</div>';
6707 $return .=
'<div class="info-box-content">';
6708 $return .=
'<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this,
'getNomUrl') ? $this->
getNomUrl() : $this->ref).
'</span>';
6709 if ($selected >= 0) {
6710 $return .=
'<input id="cb'.$this->id.
'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->
id.
'"'.($selected ?
' checked="checked"' :
'').
'>';
6712 if (property_exists($this,
'label')) {
6713 $return .=
'<br><span class="info-box-label opacitymedium inline-block tdoverflowmax150 valignmiddle" title="'.dol_escape_htmltag($this->label).
'">'.
dol_escape_htmltag($this->label).
'</span>';
6715 if (property_exists($this,
'price') && property_exists($this,
'price_ttc')) {
6716 if ($this->price_base_type ==
'TTC') {
6717 $return .=
'<br><span class="info-box-status amount">'.price($this->price_ttc).
' '.$langs->trans(
"TTC").
'</span>';
6720 $return .=
'<br><span class="info-box-status amount">'.price($this->
price).
' '.$langs->trans(
"HT").
'</span>';
6725 if (property_exists($this,
'stock_reel') && $this->
isProduct()) {
6726 $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>';
6729 if (method_exists($this,
'getLibStatut')) {
6731 $return .=
'<br><div class="info-box-status inline-block valignmiddle">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
6733 $return .=
'<div class="info-box-status inline-block valignmiddle marginleftonly paddingleft">'.$this->getLibStatut(3, 1).
' '.$this->
getLibStatut(3, 0).
'</div>';
6736 $return .=
'</div>';
6737 $return .=
'</div>';
6738 $return .=
'</div>';
6749 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).
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.
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.
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
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...
get_arbo_each_prod($multiply=1, $ignore_stock_load=0)
Build the tree of subproducts and return it.
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.
if(isModEnabled('invoice') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&!getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD') && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') && $user->hasRight('tax', 'charges', 'lire')) if(isModEnabled('invoice') &&isModEnabled('order') && $user->hasRight("commande", "lire") &&!getDolGlobalString('WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER')) $sql
Social contributions to pay.
print *****$script_file(".$version.") pid 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.
if(!function_exists('dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
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).
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.
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
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.
isModEnabled($module)
Is Dolibarr module enabled.
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.
div float
Buy price without taxes.
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