666 public function create($user, $notrigger = 0)
668 global $conf, $langs;
674 $this->
ref = trim($this->
ref);
678 $this->label = trim($this->label);
679 $this->price_ttc = (float)
price2num($this->price_ttc);
681 $this->price_min_ttc = (float)
price2num($this->price_min_ttc);
682 $this->price_min = (float)
price2num($this->price_min);
683 $this->price_label = trim($this->price_label);
684 if (empty($this->tva_tx)) {
687 if (empty($this->tva_npr)) {
691 if (empty($this->localtax1_tx)) {
692 $this->localtax1_tx = 0;
694 if (empty($this->localtax2_tx)) {
695 $this->localtax2_tx = 0;
697 if (empty($this->localtax1_type)) {
698 $this->localtax1_type =
'0';
700 if (empty($this->localtax2_type)) {
701 $this->localtax2_type =
'0';
703 if (empty($this->
price)) {
706 if (empty($this->price_min)) {
707 $this->price_min = 0;
710 if (empty($this->price_by_qty)) {
711 $this->price_by_qty = 0;
714 if (empty($this->
status)) {
717 if (empty($this->status_buy)) {
718 $this->status_buy = 0;
727 if ($this->price_base_type ==
'TTC' && $this->price_ttc > 0) {
728 $price_ttc =
price2num($this->price_ttc,
'MU');
729 $price_ht =
price2num($this->price_ttc / (1 + ($this->tva_tx / 100)),
'MU');
733 if ($this->price_base_type !=
'TTC' && $this->
price > 0) {
735 $price_ttc =
price2num($this->
price * (1 + ($this->tva_tx / 100)),
'MU');
739 if (($this->price_min_ttc > 0) && ($this->price_base_type ==
'TTC')) {
740 $price_min_ttc =
price2num($this->price_min_ttc,
'MU');
741 $price_min_ht =
price2num($this->price_min_ttc / (1 + ($this->tva_tx / 100)),
'MU');
745 if (($this->price_min > 0) && ($this->price_base_type !=
'TTC')) {
746 $price_min_ht =
price2num($this->price_min,
'MU');
747 $price_min_ttc =
price2num($this->price_min * (1 + ($this->tva_tx / 100)),
'MU');
750 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
751 $this->accountancy_code_buy_intra = trim($this->accountancy_code_buy_intra);
752 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
753 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
754 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
755 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
758 $this->barcode = trim($this->barcode);
759 $this->mandatory_period = empty($this->mandatory_period) ? 0 : $this->mandatory_period;
761 if (empty($this->label)) {
762 $this->error =
'ErrorMandatoryParametersNotProvided';
766 if (empty($this->
ref) || $this->
ref ==
'auto') {
769 if ($module !=
'mod_codeproduct_leopard') {
770 if (substr($module, 0, 16) ==
'mod_codeproduct_' && substr($module, -3) ==
'php') {
771 $module = substr($module, 0,
dol_strlen($module) - 4);
774 $modCodeProduct =
new $module();
775 '@phan-var-force ModeleProductCode $modCodeProduct';
776 if (!empty($modCodeProduct->code_auto)) {
777 $this->
ref = $modCodeProduct->getNextValue($this, $this->
type);
779 unset($modCodeProduct);
782 if (empty($this->
ref)) {
783 $this->error =
'ProductModuleNotSetupForAutoRef';
788 dol_syslog(get_class($this).
"::create ref=".$this->
ref.
" price=".$this->price.
" price_ttc=".$this->price_ttc.
" tva_tx=".$this->tva_tx.
" price_base_type=".$this->price_base_type, LOG_DEBUG);
792 if (empty($this->date_creation)) {
793 $this->date_creation = $now;
799 if ($this->barcode ==
'-1' || $this->barcode ==
'auto') {
800 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
805 $result = $this->
verify();
808 $sql =
"SELECT count(*) as nb";
809 $sql .=
" FROM ".$this->db->prefix().
"product";
810 $sql .=
" WHERE entity IN (".getEntity(
'product').
")";
811 $sql .=
" AND ref = '".$this->db->escape($this->
ref).
"'";
813 $result = $this->db->query($sql);
815 $obj = $this->db->fetch_object($result);
818 $sql =
"INSERT INTO ".$this->db->prefix().
"product (";
823 $sql .=
", price_min";
824 $sql .=
", price_min_ttc";
826 $sql .=
", fk_user_author";
827 $sql .=
", fk_product_type";
829 $sql .=
", price_ttc";
830 $sql .=
", price_base_type";
831 $sql .=
", price_label";
835 $sql .=
", accountancy_code_buy";
836 $sql .=
", accountancy_code_buy_intra";
837 $sql .=
", accountancy_code_buy_export";
838 $sql .=
", accountancy_code_sell";
839 $sql .=
", accountancy_code_sell_intra";
840 $sql .=
", accountancy_code_sell_export";
843 $sql .=
", finished";
845 $sql .=
", sell_or_eat_by_mandatory";
846 $sql .=
", batch_mask";
848 $sql .=
", mandatory_period";
849 $sql .=
") VALUES (";
850 $sql .=
"'".$this->db->idate($this->date_creation).
"'";
851 $sql .=
", ".(!empty($this->entity) ? (int) $this->entity : (int) $conf->entity);
852 $sql .=
", '".$this->db->escape($this->
ref).
"'";
853 $sql .=
", ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
854 $sql .=
", ".price2num($price_min_ht);
855 $sql .=
", ".price2num($price_min_ttc);
856 $sql .=
", ".(!empty($this->label) ?
"'".$this->db->escape($this->label).
"'" :
"null");
857 $sql .=
", ".((int) $user->id);
858 $sql .=
", ".((int) $this->
type);
859 $sql .=
", ".price2num($price_ht,
'MT');
860 $sql .=
", ".price2num($price_ttc,
'MT');
861 $sql .=
", '".$this->db->escape($this->price_base_type).
"'";
862 $sql .=
", ".(!empty($this->price_label) ?
"'".$this->db->escape($this->price_label).
"'" :
"null");
863 $sql .=
", ".((int) $this->
status);
864 $sql .=
", ".((int) $this->status_buy);
866 $sql .=
", '".$this->db->escape($this->accountancy_code_buy).
"'";
867 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_intra).
"'";
868 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_export).
"'";
869 $sql .=
", '".$this->db->escape($this->accountancy_code_sell).
"'";
870 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_intra).
"'";
871 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_export).
"'";
873 $sql .=
", '".$this->db->escape($this->canvas).
"'";
874 $sql .=
", ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
'NULL' : (int) $this->finished);
875 $sql .=
", ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : ((int) $this->status_batch));
876 $sql .=
", ".((empty($this->sell_or_eat_by_mandatory) || $this->sell_or_eat_by_mandatory < 0) ? 0 : ((int) $this->sell_or_eat_by_mandatory));
877 $sql .=
", '".$this->db->escape($this->batch_mask).
"'";
878 $sql .=
", ".($this->fk_unit > 0 ? ((int) $this->fk_unit) :
'NULL');
879 $sql .=
", '".$this->db->escape($this->mandatory_period).
"'";
882 dol_syslog(get_class($this).
"::Create", LOG_DEBUG);
884 $result = $this->db->query($sql);
886 $id = $this->db->last_insert_id($this->db->prefix().
"product");
890 $this->
price = $price_ht;
891 $this->price_ttc = $price_ttc;
892 $this->price_min = $price_min_ht;
893 $this->price_min_ttc = $price_min_ttc;
897 if ($this->
update($id, $user,
true,
'add') <= 0) {
902 $this->error = $this->db->lasterror();
907 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " .((int) $this->id) .
" AND entity = " . ((
int) $conf->entity));
909 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
910 $sql .=
" fk_product";
912 $sql .=
", accountancy_code_buy";
913 $sql .=
", accountancy_code_buy_intra";
914 $sql .=
", accountancy_code_buy_export";
915 $sql .=
", accountancy_code_sell";
916 $sql .=
", accountancy_code_sell_intra";
917 $sql .=
", accountancy_code_sell_export";
918 $sql .=
") VALUES (";
920 $sql .=
", " . $conf->entity;
921 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
922 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
923 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
924 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
925 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
926 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
928 $result = $this->db->query($sql);
931 $this->error =
'ErrorFailedToInsertAccountancyForEntity';
936 $this->error =
'ErrorFailedToGetInsertedId';
940 $this->error = $this->db->lasterror();
944 $langs->load(
"products");
946 $this->error =
"ErrorProductAlreadyExists";
947 dol_syslog(get_class($this).
"::Create fails, ref ".$this->
ref.
" already exists");
951 $this->error = $this->db->lasterror();
954 if (!$error && !$notrigger) {
967 $this->db->rollback();
971 $this->db->rollback();
972 dol_syslog(get_class($this).
"::Create fails verify ".implode(
',', $this->errors), LOG_WARNING);
1073 public function update($id, $user, $notrigger = 0, $action =
'update', $updatetype =
false)
1075 global $langs, $conf, $hookmanager;
1080 if (!$this->label) {
1081 $this->label =
'MISSING LABEL';
1086 $this->
ref = trim($this->
ref);
1090 $this->label = trim($this->label);
1092 $this->note_private = (isset($this->note_private) ? trim($this->note_private) :
null);
1093 $this->note_public = (isset($this->note_public) ? trim($this->note_public) :
null);
1094 $this->net_measure =
price2num($this->net_measure);
1095 $this->net_measure_units = (empty($this->net_measure_units) ?
'' : trim($this->net_measure_units));
1096 $this->weight =
price2num($this->weight);
1097 $this->weight_units = (empty($this->weight_units) ?
'' : trim($this->weight_units));
1098 $this->length =
price2num($this->length);
1099 $this->length_units = (empty($this->length_units) ?
'' : trim($this->length_units));
1101 $this->width_units = (empty($this->width_units) ?
'' : trim($this->width_units));
1102 $this->height =
price2num($this->height);
1103 $this->height_units = (empty($this->height_units) ?
'' : trim($this->height_units));
1104 $this->surface =
price2num($this->surface);
1105 $this->surface_units = (empty($this->surface_units) ?
'' : trim($this->surface_units));
1106 $this->volume =
price2num($this->volume);
1107 $this->volume_units = (empty($this->volume_units) ?
'' : trim($this->volume_units));
1110 if (is_numeric($this->length_units)) {
1111 $this->width_units = $this->length_units;
1113 if (is_numeric($this->length_units)) {
1114 $this->height_units = $this->length_units;
1118 if (empty($this->surface) && !empty($this->length) && !empty($this->width) && $this->length_units == $this->width_units) {
1119 $this->surface = (float) $this->length * (
float) $this->width;
1122 if (empty($this->volume) && !empty($this->surface) && !empty($this->height) && $this->length_units == $this->height_units) {
1123 $this->volume = $this->surface * (float) $this->height;
1127 if (empty($this->tva_tx)) {
1130 if (empty($this->tva_npr)) {
1133 if (empty($this->localtax1_tx)) {
1134 $this->localtax1_tx = 0;
1136 if (empty($this->localtax2_tx)) {
1137 $this->localtax2_tx = 0;
1139 if (empty($this->localtax1_type)) {
1140 $this->localtax1_type =
'0';
1142 if (empty($this->localtax2_type)) {
1143 $this->localtax2_type =
'0';
1145 if (empty($this->
status)) {
1148 if (empty($this->status_buy)) {
1149 $this->status_buy = 0;
1152 if (empty($this->country_id)) {
1153 $this->country_id = 0;
1156 if (empty($this->state_id)) {
1157 $this->state_id = 0;
1161 $this->barcode = (empty($this->barcode) ?
'' : trim($this->barcode));
1163 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
1164 $this->accountancy_code_buy_intra = (!empty($this->accountancy_code_buy_intra) ? trim($this->accountancy_code_buy_intra) :
'');
1165 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
1166 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
1167 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
1168 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
1175 if ($action !=
'add') {
1176 $result = $this->
verify();
1184 if (is_null($this->oldcopy) || (is_object($this->oldcopy) && $this->oldcopy->isEmpty())) {
1189 if ($this->
hasbatch() && !$this->oldcopy->hasbatch()) {
1191 $valueforundefinedlot =
'000000';
1196 dol_syslog(
"Flag batch of product id=".$this->
id.
" is set to ON, so we will create missing records into product_batch");
1199 foreach ($this->stock_warehouse as $idW => $ObjW) {
1201 foreach ($ObjW->detail_batch as $detail) {
1202 if ($detail->batch == $valueforundefinedlot || $detail->batch ==
'Undefined') {
1204 $sqlclean =
"DELETE FROM ".$this->db->prefix().
"product_batch WHERE batch in('Undefined', '".$this->db->escape($valueforundefinedlot).
"') AND fk_product_stock = ".((int) $ObjW->id);
1205 $result = $this->db->query($sqlclean);
1213 $qty_batch += $detail->qty;
1217 if ($ObjW->real != $qty_batch) {
1219 $ObjBatch->batch = $valueforundefinedlot;
1220 $ObjBatch->qty = ($ObjW->real - $qty_batch);
1221 $ObjBatch->fk_product_stock = $ObjW->id;
1223 if ($ObjBatch->create($user, 1) < 0) {
1225 $this->errors = $ObjBatch->errors;
1230 if ($ObjLot->fetch(0, $this->id, $valueforundefinedlot) == 0) {
1231 $ObjLot->fk_product = $this->id;
1232 $ObjLot->entity = $this->entity;
1233 $ObjLot->fk_user_creat = $user->id;
1234 $ObjLot->batch = $valueforundefinedlot;
1235 if ($ObjLot->create($user,
true) < 0) {
1237 $this->errors = $ObjLot->errors;
1246 if ($this->barcode == -1) {
1247 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1250 $sql =
"UPDATE ".$this->db->prefix().
"product";
1251 $sql .=
" SET label = '".$this->db->escape($this->label).
"'";
1254 $sql .=
", fk_product_type = ".((int) $this->
type);
1257 $sql .=
", ref = '".$this->db->escape($this->
ref).
"'";
1258 $sql .=
", ref_ext = ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1259 $sql .=
", default_vat_code = ".($this->default_vat_code ?
"'".$this->db->escape($this->default_vat_code).
"'" :
"null");
1260 $sql .=
", tva_tx = ".((float) $this->tva_tx);
1261 $sql .=
", recuperableonly = ".((int) $this->tva_npr);
1262 $sql .=
", localtax1_tx = ".((float) $this->localtax1_tx);
1263 $sql .=
", localtax2_tx = ".((float) $this->localtax2_tx);
1264 $sql .=
", localtax1_type = ".($this->localtax1_type !=
'' ?
"'".$this->db->escape($this->localtax1_type).
"'" :
"'0'");
1265 $sql .=
", localtax2_type = ".($this->localtax2_type !=
'' ?
"'".$this->db->escape($this->localtax2_type).
"'" :
"'0'");
1267 $sql .=
", barcode = ".(empty($this->barcode) ?
"null" :
"'".$this->db->escape($this->barcode).
"'");
1268 $sql .=
", fk_barcode_type = ".(empty($this->barcode_type) ?
"null" : $this->db->escape($this->barcode_type));
1270 $sql .=
", tosell = ".(int) $this->
status;
1271 $sql .=
", tobuy = ".(int) $this->status_buy;
1272 $sql .=
", tobatch = ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : (int) $this->status_batch);
1273 $sql .=
", sell_or_eat_by_mandatory = ".((empty($this->sell_or_eat_by_mandatory) || $this->sell_or_eat_by_mandatory < 0) ? 0 : (int) $this->sell_or_eat_by_mandatory);
1274 $sql .=
", batch_mask = '".$this->db->escape($this->batch_mask).
"'";
1276 $sql .=
", finished = ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
"null" : (int) $this->finished);
1277 $sql .=
", fk_default_bom = ".((!isset($this->fk_default_bom) || $this->fk_default_bom < 0 || $this->fk_default_bom ==
'') ?
"null" : (int) $this->fk_default_bom);
1278 $sql .=
", net_measure = ".($this->net_measure !=
'' ?
"'".$this->db->escape($this->net_measure).
"'" :
'null');
1279 $sql .=
", net_measure_units = ".($this->net_measure_units !=
'' ?
"'".$this->db->escape($this->net_measure_units).
"'" :
'null');
1280 $sql .=
", weight = ".($this->weight !=
'' ?
"'".$this->db->escape($this->weight).
"'" :
'null');
1281 $sql .=
", weight_units = ".($this->weight_units !=
'' ?
"'".$this->db->escape($this->weight_units).
"'" :
'null');
1282 $sql .=
", length = ".($this->length !=
'' ?
"'".$this->db->escape($this->length).
"'" :
'null');
1283 $sql .=
", length_units = ".($this->length_units !=
'' ?
"'".$this->db->escape($this->length_units).
"'" :
'null');
1284 $sql .=
", width= ".($this->width !=
'' ?
"'".$this->db->escape($this->width).
"'" :
'null');
1285 $sql .=
", width_units = ".($this->width_units !=
'' ?
"'".$this->db->escape($this->width_units).
"'" :
'null');
1286 $sql .=
", height = ".($this->height !=
'' ?
"'".$this->db->escape($this->height).
"'" :
'null');
1287 $sql .=
", height_units = ".($this->height_units !=
'' ?
"'".$this->db->escape($this->height_units).
"'" :
'null');
1288 $sql .=
", surface = ".($this->surface !=
'' ?
"'".$this->db->escape($this->surface).
"'" :
'null');
1289 $sql .=
", surface_units = ".($this->surface_units !=
'' ?
"'".$this->db->escape($this->surface_units).
"'" :
'null');
1290 $sql .=
", volume = ".($this->volume !=
'' ?
"'".$this->db->escape($this->volume).
"'" :
'null');
1291 $sql .=
", volume_units = ".($this->volume_units !=
'' ?
"'".$this->db->escape($this->volume_units).
"'" :
'null');
1292 $sql .=
", fk_default_warehouse = ".($this->fk_default_warehouse > 0 ? ((int) $this->fk_default_warehouse) :
'null');
1293 $sql .=
", fk_default_workstation = ".($this->fk_default_workstation > 0 ? ((int) $this->fk_default_workstation) :
'null');
1294 $sql .=
", seuil_stock_alerte = ".((isset($this->seuil_stock_alerte) && is_numeric($this->seuil_stock_alerte)) ? (
float) $this->seuil_stock_alerte :
'null');
1295 $sql .=
", description = '".$this->db->escape($this->
description).
"'";
1296 $sql .=
", url = ".($this->url ?
"'".$this->db->escape($this->url).
"'" :
'null');
1297 $sql .=
", customcode = '".$this->db->escape($this->customcode).
"'";
1298 $sql .=
", fk_country = ".($this->country_id > 0 ? (int) $this->country_id :
'null');
1299 $sql .=
", fk_state = ".($this->state_id > 0 ? (int) $this->state_id :
'null');
1300 $sql .=
", lifetime = ".($this->lifetime > 0 ? (int) $this->lifetime :
'null');
1301 $sql .=
", qc_frequency = ".($this->qc_frequency > 0 ? (int) $this->qc_frequency :
'null');
1302 $sql .=
", note = ".(isset($this->note_private) ?
"'".$this->db->escape($this->note_private).
"'" :
'null');
1303 $sql .=
", note_public = ".(isset($this->note_public) ?
"'".$this->db->escape($this->note_public).
"'" :
'null');
1304 $sql .=
", duration = '".$this->db->escape($this->duration_value.$this->duration_unit).
"'";
1306 $sql .=
", accountancy_code_buy = '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1307 $sql .=
", accountancy_code_buy_intra = '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1308 $sql .=
", accountancy_code_buy_export = '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1309 $sql .=
", accountancy_code_sell= '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1310 $sql .=
", accountancy_code_sell_intra= '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1311 $sql .=
", accountancy_code_sell_export= '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1313 $sql .=
", desiredstock = ".((isset($this->desiredstock) && is_numeric($this->desiredstock)) ? (
float) $this->desiredstock :
"null");
1314 $sql .=
", cost_price = ".($this->cost_price !=
'' ? $this->db->escape($this->cost_price) :
'null');
1315 $sql .=
", fk_unit= ".(!$this->fk_unit ?
'NULL' : (int) $this->fk_unit);
1316 $sql .=
", price_autogen = ".(!$this->price_autogen ? 0 : 1);
1317 $sql .=
", fk_price_expression = ".($this->fk_price_expression != 0 ? (int) $this->fk_price_expression :
'NULL');
1318 $sql .=
", fk_user_modif = ".($user->id > 0 ? $user->id :
'NULL');
1319 $sql .=
", mandatory_period = ".($this->mandatory_period);
1321 $sql .=
" WHERE rowid = ".((int) $id);
1323 dol_syslog(get_class($this).
"::update", LOG_DEBUG);
1325 $resql = $this->db->query($sql);
1332 $this->error = $langs->trans(
"Error").
" : ".$this->db->error().
" - ".$sql;
1333 $this->db->rollback();
1342 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " . ((
int) $this->id) .
" AND entity = " . ((
int) $conf->entity));
1344 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1345 $sql .=
" fk_product";
1347 $sql .=
", accountancy_code_buy";
1348 $sql .=
", accountancy_code_buy_intra";
1349 $sql .=
", accountancy_code_buy_export";
1350 $sql .=
", accountancy_code_sell";
1351 $sql .=
", accountancy_code_sell_intra";
1352 $sql .=
", accountancy_code_sell_export";
1353 $sql .=
") VALUES (";
1355 $sql .=
", " . $conf->entity;
1356 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1357 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1358 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1359 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1360 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1361 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1363 $result = $this->db->query($sql);
1366 $this->error =
'ErrorFailedToUpdateAccountancyForEntity';
1370 if (!$this->
hasbatch() && $this->oldcopy->hasbatch()) {
1372 $sql =
'SELECT pb.qty, ps.fk_entrepot, pb.batch FROM '.MAIN_DB_PREFIX.
'product_batch as pb';
1373 $sql .=
' INNER JOIN '.MAIN_DB_PREFIX.
'product_stock as ps ON (ps.rowid = pb.fk_product_stock)';
1374 $sql .=
' WHERE ps.fk_product = '.(int) $this->
id;
1376 $resql = $this->db->query($sql);
1380 while ($obj = $this->db->fetch_object($resql)) {
1382 $fk_entrepot = $obj->fk_entrepot;
1386 $batch = $obj->batch;
1389 $addOremove = $value > 0 ? 1 : 0;
1390 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1391 $res = $this->
correct_stock_batch($user, $fk_entrepot, abs($value), $addOremove, $label, $price, $dlc, $dluo, $batch, $inventorycode,
'',
null, 0,
null,
true);
1394 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1395 $res = $this->
correct_stock($user, $fk_entrepot, abs($value), (
int) empty($addOremove), $label, $price, $inventorycode,
'',
null, 0);
1414 if (!$error && !$notrigger) {
1416 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
1423 if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) {
1425 if ($conf->product->dir_output) {
1428 if (file_exists($olddir)) {
1432 $res = @rename($olddir, $newdir);
1434 $langs->load(
"errors");
1435 $this->error = $langs->trans(
'ErrorFailToRenameDir', $olddir, $newdir);
1443 if (isModEnabled(
'variants')) {
1444 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1448 foreach ($comb->fetchAllByFkProductParent($this->id) as $currcomb) {
1449 $currcomb->updateProperties($this, $user);
1453 $this->db->commit();
1456 $this->db->rollback();
1460 if ($this->db->errno() ==
'DB_ERROR_RECORD_ALREADY_EXISTS') {
1461 $langs->load(
"errors");
1462 if (empty($conf->barcode->enabled) || empty($this->barcode)) {
1463 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductAlreadyExists", $this->
ref);
1465 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductBarCodeAlreadyExists", $this->barcode);
1467 $this->errors[] = $this->error;
1468 $this->db->rollback();
1471 $this->error = $langs->trans(
"Error").
" : ".$this->db->error().
" - ".$sql;
1472 $this->errors[] = $this->error;
1473 $this->db->rollback();
1478 $this->db->rollback();
1479 dol_syslog(get_class($this).
"::Update fails verify ".implode(
',', $this->errors), LOG_WARNING);
1689 global $conf, $langs;
1691 $langs_available = $langs->get_available_languages(DOL_DOCUMENT_ROOT, 0, 2);
1692 $current_lang = $langs->getDefaultLang();
1694 foreach ($langs_available as $key => $value) {
1695 if ($key == $current_lang) {
1696 $sql =
"SELECT rowid";
1697 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1698 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1699 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
1701 $result = $this->db->query($sql);
1703 if ($this->db->num_rows($result)) {
1704 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
1706 $sql2 .=
" label='".$this->db->escape($this->label).
"',";
1707 $sql2 .=
" description='".$this->db->escape($this->
description).
"'";
1709 $sql2 .=
", note='".$this->db->escape($this->other).
"'";
1711 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
1713 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
1718 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->label).
"',";
1719 $sql2 .=
" '".$this->db->escape($this->
description).
"'";
1721 $sql2 .=
", '".$this->db->escape($this->other).
"'";
1725 dol_syslog(get_class($this).
'::setMultiLangs key = current_lang = '.$key);
1726 if (!$this->db->query($sql2)) {
1727 $this->error = $this->db->lasterror();
1730 } elseif (isset($this->multilangs[$key])) {
1731 if (empty($this->multilangs[
"$key"][
"label"])) {
1732 $this->errors[] = $key .
' : ' . $langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Label"));
1736 $sql =
"SELECT rowid";
1737 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1738 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1739 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
1741 $result = $this->db->query($sql);
1743 if ($this->db->num_rows($result)) {
1744 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
1746 $sql2 .=
" label = '".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
1747 $sql2 .=
" description = '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
1749 $sql2 .=
", note = '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
1751 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
1753 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
1758 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
1759 $sql2 .=
" '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
1761 $sql2 .=
", '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
1767 if ($this->multilangs[
"$key"][
"label"] || $this->multilangs[
"$key"][
"description"]) {
1768 if (!$this->db->query($sql2)) {
1769 $this->error = $this->db->lasterror();
1779 $result = $this->
call_trigger(
'PRODUCT_SET_MULTILANGS', $user);
1781 $this->error = $this->db->lasterror();
2029 public function getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp = 0)
2031 global $conf, $hookmanager, $action;
2034 if (is_object($hookmanager)) {
2035 $parameters = array(
'thirdparty_seller' => $thirdparty_seller,
'thirdparty_buyer' => $thirdparty_buyer,
'pqp' => $pqp);
2037 $reshook = $hookmanager->executeHooks(
'getSellPrice', $parameters, $this, $action);
2039 return $hookmanager->resArray;
2050 $pu_ht = $this->price;
2051 $pu_ttc = $this->price_ttc;
2052 $price_min = $this->price_min;
2053 $price_base_type = $this->price_base_type;
2056 if (
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !empty($thirdparty_buyer->price_level)) {
2057 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
2058 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
2059 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
2060 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
2062 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2063 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2065 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2066 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2074 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2078 $filter = array(
't.fk_product' => $this->
id,
't.fk_soc' => $thirdparty_buyer->id);
2080 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2082 if (count($prodcustprice->lines) > 0) {
2083 $pu_ht =
price($prodcustprice->lines[0]->price);
2084 $price_min =
price($prodcustprice->lines[0]->price_min);
2085 $pu_ttc =
price($prodcustprice->lines[0]->price_ttc);
2086 $price_base_type = $prodcustprice->lines[0]->price_base_type;
2087 $tva_tx = $prodcustprice->lines[0]->tva_tx;
2088 if ($prodcustprice->lines[0]->default_vat_code && !preg_match(
'/\(.*\)/',
$tva_tx)) {
2089 $tva_tx .=
' ('.$prodcustprice->lines[0]->default_vat_code.
')';
2091 $tva_npr = $prodcustprice->lines[0]->recuperableonly;
2099 if ($this->prices_by_qty[0]) {
2102 foreach ($this->prices_by_qty_list[0] as $priceforthequantityarray) {
2103 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2107 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2108 $pu_ht = $priceforthequantityarray[
'unitprice'];
2110 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2117 if ($this->prices_by_qty[$thirdparty_buyer->price_level]) {
2120 foreach ($this->prices_by_qty_list[$thirdparty_buyer->price_level] as $priceforthequantityarray) {
2121 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2125 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2126 $pu_ht = $priceforthequantityarray[
'unitprice'];
2128 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2135 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);
2152 public function get_buyprice($prodfournprice, $qty, $product_id = 0, $fourn_ref =
'', $fk_soc = 0)
2155 global $action, $hookmanager;
2158 if (is_object($hookmanager)) {
2159 $parameters = array(
2160 'prodfournprice' => $prodfournprice,
2162 'product_id' => $product_id,
2163 'fourn_ref' => $fourn_ref,
2164 'fk_soc' => $fk_soc,
2167 $reshook = $hookmanager->executeHooks(
'getBuyPrice', $parameters, $this, $action);
2169 return $hookmanager->resArray;
2176 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2177 $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,";
2178 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2179 $sql .=
" pfp.packaging";
2180 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2181 $sql .=
" WHERE pfp.rowid = ".((int) $prodfournprice);
2183 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2185 $sql .=
" ORDER BY pfp.quantity DESC";
2187 dol_syslog(get_class($this).
"::get_buyprice first search by prodfournprice/qty", LOG_DEBUG);
2188 $resql = $this->db->query($sql);
2190 $obj = $this->db->fetch_object($resql);
2191 if ($obj && $obj->quantity > 0) {
2192 if (isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2194 $prod_supplier->product_fourn_price_id = $obj->rowid;
2195 $prod_supplier->id = $obj->fk_product;
2196 $prod_supplier->fourn_qty = $obj->quantity;
2197 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2198 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2200 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2202 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2203 if ($price_result >= 0) {
2204 $obj->price = $price_result;
2207 $this->product_fourn_price_id = $obj->rowid;
2208 $this->buyprice = $obj->price;
2209 $this->fourn_pu = $obj->price / $obj->quantity;
2210 $this->fourn_price_base_type =
'HT';
2211 $this->fourn_socid = $obj->fk_soc;
2212 $this->ref_fourn = $obj->ref_supplier;
2213 $this->ref_supplier = $obj->ref_supplier;
2214 $this->desc_supplier = $obj->desc_supplier;
2215 $this->remise_percent = $obj->remise_percent;
2216 $this->vatrate_supplier = $obj->tva_tx;
2217 $this->default_vat_code_supplier = $obj->default_vat_code;
2218 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2219 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2220 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2221 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2222 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2224 $this->packaging = $obj->packaging;
2226 $result = $obj->fk_product;
2230 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2231 $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,";
2232 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2233 $sql .=
" pfp.packaging";
2234 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2235 $sql .=
" WHERE 1 = 1";
2236 if ($product_id > 0) {
2237 $sql .=
" AND pfp.fk_product = ".((int) $product_id);
2239 if ($fourn_ref !=
'none') {
2240 $sql .=
" AND pfp.ref_fourn = '".$this->db->escape($fourn_ref).
"'";
2243 $sql .=
" AND pfp.fk_soc = ".((int) $fk_soc);
2246 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2248 $sql .=
" ORDER BY pfp.quantity DESC";
2251 dol_syslog(get_class($this).
"::get_buyprice second search from qty/ref/product_id", LOG_DEBUG);
2252 $resql = $this->db->query($sql);
2254 $obj = $this->db->fetch_object($resql);
2255 if ($obj && $obj->quantity > 0) {
2256 if (isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2258 $prod_supplier->product_fourn_price_id = $obj->rowid;
2259 $prod_supplier->id = $obj->fk_product;
2260 $prod_supplier->fourn_qty = $obj->quantity;
2261 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2262 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2264 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2266 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2268 $obj->price = $price_result;
2271 $this->product_fourn_price_id = $obj->rowid;
2272 $this->buyprice = $obj->price;
2273 $this->fourn_qty = $obj->quantity;
2274 $this->fourn_pu = $obj->price / $obj->quantity;
2275 $this->fourn_price_base_type =
'HT';
2276 $this->fourn_socid = $obj->fk_soc;
2277 $this->ref_fourn = $obj->ref_supplier;
2278 $this->ref_supplier = $obj->ref_supplier;
2279 $this->desc_supplier = $obj->desc_supplier;
2280 $this->remise_percent = $obj->remise_percent;
2281 $this->vatrate_supplier = $obj->tva_tx;
2282 $this->default_vat_code_supplier = $obj->default_vat_code;
2283 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2284 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2285 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2286 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2287 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2289 $this->packaging = $obj->packaging;
2291 $result = $obj->fk_product;
2297 $this->error = $this->db->lasterror();
2302 $this->error = $this->db->lasterror();
2326 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)
2328 global $conf, $langs;
2334 dol_syslog(get_class($this).
"::update_price id=".$id.
" newprice=".$newprice.
" newpricebase=".$newpricebase.
" newminprice=".$newminprice.
" level=".$level.
" npr=".$newnpr.
" newdefaultvatcode=".$newdefaultvatcode);
2337 if (empty($this->tva_tx)) {
2340 if (empty($newnpr)) {
2343 if (empty($newminprice)) {
2348 if ($newvat ===
null || $newvat ==
'') {
2354 if ((
getDolGlobalString(
'PRODUIT_MULTIPRICES') ||
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) && !$ignore_autogen && $this->price_autogen && ($level == 1)) {
2355 return $this->
generateMultiprices($user, $newprice, $newpricebase, $newvat, $newnpr, $newpbq);
2358 if (!empty($newminprice) && ($newminprice > $newprice)) {
2359 $this->error =
'ErrorPriceCantBeLowerThanMinPrice';
2363 if ($newprice !==
'' || $newprice === 0) {
2364 if ($newpricebase ==
'TTC') {
2365 $price_ttc =
price2num($newprice,
'MU');
2366 $price = (float)
price2num($newprice) / (1 + ((float) $newvat / 100));
2369 if ($newminprice !=
'' || $newminprice == 0) {
2370 $price_min_ttc =
price2num($newminprice,
'MU');
2371 $price_min = (float)
price2num($newminprice) / (1 + ($newvat / 100));
2372 $price_min =
price2num($price_min,
'MU');
2378 $price = (float)
price2num($newprice,
'MU');
2379 $price_ttc = ($newnpr != 1) ?
price2num($newprice) * (1 + ($newvat / 100)) : $price;
2380 $price_ttc = (float)
price2num($price_ttc,
'MU');
2382 if ($newminprice !==
'' || $newminprice === 0) {
2383 $price_min =
price2num($newminprice,
'MU');
2384 $price_min_ttc = (float)
price2num($newminprice) * (1 + ($newvat / 100));
2385 $price_min_ttc =
price2num($price_min_ttc,
'MU');
2394 if (count($localtaxes_array) > 0) {
2395 $localtaxtype1 = $localtaxes_array[
'0'];
2396 $localtax1 = $localtaxes_array[
'1'];
2397 $localtaxtype2 = $localtaxes_array[
'2'];
2398 $localtax2 = $localtaxes_array[
'3'];
2401 if (!empty($newdefaultvatcode)) {
2404 $sql =
"SELECT t.rowid, t.code, t.recuperableonly as tva_npr, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
2405 $sql .=
" FROM ".MAIN_DB_PREFIX.
"c_tva as t, ".MAIN_DB_PREFIX.
"c_country as c";
2406 $sql .=
" WHERE t.fk_pays = c.rowid AND c.code = '".$this->db->escape($mysoc->country_code).
"'";
2407 $sql .=
" AND t.taux = ".((float) $newdefaultvatcode).
" AND t.active = 1";
2408 $sql .=
" AND t.code = '".$this->db->escape($newdefaultvatcode).
"'";
2409 $resql = $this->db->query($sql);
2411 $obj = $this->db->fetch_object($resql);
2413 $npr = $obj->tva_npr;
2414 $localtax1 = $obj->localtax1;
2415 $localtax2 = $obj->localtax2;
2416 $localtaxtype1 = $obj->localtax1_type;
2417 $localtaxtype2 = $obj->localtax2_type;
2422 $localtaxtype1 =
'0';
2424 $localtaxtype2 =
'0';
2428 if (empty($localtax1)) {
2431 if (empty($localtax2)) {
2439 $sql =
"UPDATE ".$this->db->prefix().
"product SET";
2440 $sql .=
" price_base_type = '".$this->db->escape($newpricebase).
"',";
2441 $sql .=
" price = ".(float) $price.
",";
2442 $sql .=
" price_ttc = ".(float) $price_ttc.
",";
2443 $sql .=
" price_min = ".(float) $price_min.
",";
2444 $sql .=
" price_min_ttc = ".(float) $price_min_ttc.
",";
2445 $sql .=
" localtax1_tx = ".($localtax1 >= 0 ? (float) $localtax1 :
'NULL').
",";
2446 $sql .=
" localtax2_tx = ".($localtax2 >= 0 ? (float) $localtax2 :
'NULL').
",";
2447 $sql .=
" localtax1_type = ".($localtaxtype1 !=
'' ?
"'".$this->db->escape($localtaxtype1).
"'" :
"'0'").
",";
2448 $sql .=
" localtax2_type = ".($localtaxtype2 !=
'' ?
"'".$this->db->escape($localtaxtype2).
"'" :
"'0'").
",";
2449 $sql .=
" default_vat_code = ".($newdefaultvatcode ?
"'".$this->db->escape($newdefaultvatcode).
"'" :
"null").
",";
2450 $sql .=
" price_label = ".(!empty($price_label) ?
"'".$this->db->escape($price_label).
"'" :
"null").
",";
2451 $sql .=
" tva_tx = ".(float)
price2num($newvat).
",";
2452 $sql .=
" recuperableonly = '".$this->db->escape($newnpr).
"'";
2453 $sql .=
" WHERE rowid = ".((int) $id);
2455 dol_syslog(get_class($this).
"::update_price", LOG_DEBUG);
2456 $resql = $this->db->query($sql);
2458 $this->multiprices[$level] = $price;
2459 $this->multiprices_ttc[$level] = $price_ttc;
2460 $this->multiprices_min[$level] = $price_min;
2461 $this->multiprices_min_ttc[$level] = $price_min_ttc;
2462 $this->multiprices_base_type[$level] = $newpricebase;
2463 $this->multiprices_default_vat_code[$level] = $newdefaultvatcode;
2464 $this->multiprices_tva_tx[$level] = $newvat;
2465 $this->multiprices_recuperableonly[$level] = $newnpr;
2467 $this->
price = $price;
2468 $this->price_label = $price_label;
2469 $this->price_ttc = $price_ttc;
2470 $this->price_min = $price_min;
2471 $this->price_min_ttc = $price_min_ttc;
2472 $this->price_base_type = $newpricebase;
2473 $this->default_vat_code = $newdefaultvatcode;
2474 $this->tva_tx = $newvat;
2475 $this->tva_npr = $newnpr;
2478 $this->localtax1_tx = $localtax1;
2479 $this->localtax2_tx = $localtax2;
2480 $this->localtax1_type = $localtaxtype1;
2481 $this->localtax2_type = $localtaxtype2;
2484 $this->price_by_qty = $newpbq;
2488 if (!empty(array_diff_assoc($newPriceData, $lastPriceData)) || !
getDolGlobalString(
'PRODUIT_MULTIPRICES')) {
2492 $this->level = $level;
2496 $result = $this->
call_trigger(
'PRODUCT_PRICE_MODIFY', $user);
2498 $this->db->rollback();
2504 $this->db->commit();
2506 $this->db->rollback();
2507 $this->error = $this->db->lasterror();
2543 public function fetch($id = 0, $ref =
'', $ref_ext =
'', $barcode =
'', $ignore_expression = 0, $ignore_price_load = 0, $ignore_lang_load = 0)
2545 include_once DOL_DOCUMENT_ROOT.
'/core/lib/company.lib.php';
2547 global $langs, $conf;
2549 dol_syslog(get_class($this).
"::fetch id=".$id.
" ref=".$ref.
" ref_ext=".$ref_ext);
2552 if (!$id && !$ref && !$ref_ext && !$barcode) {
2553 $this->error =
'ErrorWrongParameters';
2554 dol_syslog(get_class($this).
"::fetch ".$this->error, LOG_ERR);
2558 $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,";
2559 $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,";
2560 $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,";
2561 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.last_main_doc,";
2562 $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,";
2564 $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,";
2566 $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,";
2571 $separatedEntityPMP =
false;
2572 $separatedStock =
false;
2573 $visibleWarehousesEntities = $conf->entity;
2576 $checkPMPPerEntity = $this->db->query(
"SELECT pmp FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = ".((int) $id).
" AND entity = ".(
int) $conf->entity);
2577 if ($this->db->num_rows($checkPMPPerEntity) > 0) {
2578 $separatedEntityPMP =
true;
2582 $separatedStock =
true;
2583 if (isset($mc->sharings[
'stock']) && !empty($mc->sharings[
'stock'])) {
2584 $visibleWarehousesEntities .=
"," . implode(
",", $mc->sharings[
'stock']);
2587 if ($separatedEntityPMP) {
2588 $sql .=
" ppe.pmp,";
2592 $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,";
2593 $sql .=
" p.fk_price_expression, p.price_autogen, p.model_pdf,";
2594 $sql .=
" p.price_label,";
2595 if ($separatedStock) {
2596 $sql .=
" SUM(sp.reel) as stock";
2600 $sql .=
" FROM ".$this->db->prefix().
"product as p";
2602 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int) $conf->entity);
2604 if ($separatedStock) {
2605 $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).
"))";
2609 $sql .=
" WHERE p.rowid = ".((int) $id);
2611 $sql .=
" WHERE p.entity IN (".getEntity($this->element).
")";
2613 $sql .=
" AND p.ref = '".$this->db->escape($ref).
"'";
2614 } elseif ($ref_ext) {
2615 $sql .=
" AND p.ref_ext = '".$this->db->escape($ref_ext).
"'";
2616 } elseif ($barcode) {
2617 $sql .=
" AND p.barcode = '".$this->db->escape($barcode).
"'";
2620 if ($separatedStock) {
2621 $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,";
2622 $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,";
2623 $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,";
2624 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
2625 $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,";
2627 $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,";
2629 $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,";
2631 if ($separatedEntityPMP) {
2632 $sql .=
" ppe.pmp,";
2636 $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,";
2637 $sql .=
" p.fk_price_expression, p.price_autogen, p.model_pdf";
2638 $sql .=
" ,p.price_label";
2639 if (!$separatedStock) {
2640 $sql .=
", p.stock";
2644 $resql = $this->db->query($sql);
2646 unset($this->oldcopy);
2648 if ($this->db->num_rows($resql) > 0) {
2649 $obj = $this->db->fetch_object($resql);
2651 $this->
id = $obj->rowid;
2652 $this->
ref = $obj->ref;
2653 $this->ref_ext = $obj->ref_ext;
2654 $this->label = $obj->label;
2656 $this->url = $obj->url;
2657 $this->note_public = $obj->note_public;
2658 $this->note_private = $obj->note_private;
2659 $this->note = $obj->note_private;
2661 $this->
type = $obj->fk_product_type;
2662 $this->price_label = $obj->price_label;
2663 $this->
status = $obj->tosell;
2664 $this->status_buy = $obj->tobuy;
2665 $this->status_batch = $obj->tobatch;
2666 $this->sell_or_eat_by_mandatory = $obj->sell_or_eat_by_mandatory;
2667 $this->batch_mask = $obj->batch_mask;
2669 $this->customcode = $obj->customcode;
2670 $this->country_id = $obj->fk_country;
2671 $this->country_code =
getCountry($this->country_id, 2, $this->db);
2672 $this->state_id = $obj->fk_state;
2673 $this->lifetime = $obj->lifetime;
2674 $this->qc_frequency = $obj->qc_frequency;
2675 $this->
price = $obj->price;
2676 $this->price_ttc = $obj->price_ttc;
2677 $this->price_min = $obj->price_min;
2678 $this->price_min_ttc = $obj->price_min_ttc;
2679 $this->price_base_type = $obj->price_base_type;
2680 $this->cost_price = $obj->cost_price;
2681 $this->default_vat_code = $obj->default_vat_code;
2682 $this->tva_tx = $obj->tva_tx;
2684 $this->tva_npr = $obj->tva_npr;
2686 $this->localtax1_tx = $obj->localtax1_tx;
2687 $this->localtax2_tx = $obj->localtax2_tx;
2688 $this->localtax1_type = $obj->localtax1_type;
2689 $this->localtax2_type = $obj->localtax2_type;
2691 $this->finished = $obj->finished;
2692 $this->fk_default_bom = $obj->fk_default_bom;
2694 $this->duration = $obj->duration;
2695 $this->duration_value = $obj->duration ? (int) (substr($obj->duration, 0,
dol_strlen($obj->duration) - 1)) : 0;
2696 $this->duration_unit = $obj->duration ? substr($obj->duration, -1) :
null;
2697 $this->canvas = $obj->canvas;
2698 $this->net_measure = $obj->net_measure;
2699 $this->net_measure_units = $obj->net_measure_units;
2700 $this->weight = $obj->weight;
2701 $this->weight_units = $obj->weight_units;
2702 $this->length = $obj->length;
2703 $this->length_units = $obj->length_units;
2704 $this->width = $obj->width;
2705 $this->width_units = $obj->width_units;
2706 $this->height = $obj->height;
2707 $this->height_units = $obj->height_units;
2709 $this->surface = $obj->surface;
2710 $this->surface_units = $obj->surface_units;
2711 $this->volume = $obj->volume;
2712 $this->volume_units = $obj->volume_units;
2713 $this->barcode = $obj->barcode;
2714 $this->barcode_type = $obj->fk_barcode_type;
2716 $this->accountancy_code_buy = $obj->accountancy_code_buy;
2717 $this->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra;
2718 $this->accountancy_code_buy_export = $obj->accountancy_code_buy_export;
2719 $this->accountancy_code_sell = $obj->accountancy_code_sell;
2720 $this->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra;
2721 $this->accountancy_code_sell_export = $obj->accountancy_code_sell_export;
2723 $this->fk_default_warehouse = $obj->fk_default_warehouse;
2724 $this->fk_default_workstation = $obj->fk_default_workstation;
2725 $this->seuil_stock_alerte = $obj->seuil_stock_alerte;
2726 $this->desiredstock = $obj->desiredstock;
2727 $this->stock_reel = $obj->stock;
2728 $this->pmp = $obj->pmp;
2730 $this->date_creation = $obj->datec;
2731 $this->date_modification = $obj->tms;
2732 $this->import_key = $obj->import_key;
2733 $this->entity = $obj->entity;
2735 $this->ref_ext = $obj->ref_ext;
2736 $this->fk_price_expression = $obj->fk_price_expression;
2737 $this->fk_unit = $obj->fk_unit;
2738 $this->price_autogen = $obj->price_autogen;
2739 $this->model_pdf = $obj->model_pdf;
2740 $this->last_main_doc = $obj->last_main_doc;
2742 $this->mandatory_period = $obj->mandatory_period;
2744 $this->db->free($resql);
2756 for ($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) {
2757 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
2758 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
2759 $sql .=
" ,price_label";
2760 $sql .=
" FROM ".$this->db->prefix().
"product_price";
2761 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
2762 $sql .=
" AND price_level=".((int) $i);
2763 $sql .=
" AND fk_product = ".((int) $this->
id);
2764 $sql .=
" ORDER BY date_price DESC, rowid DESC";
2766 $resql = $this->db->query($sql);
2768 $result = $this->db->fetch_array($resql);
2770 $this->multiprices[$i] = $result ? $result[
"price"] :
null;
2771 $this->multiprices_ttc[$i] = $result ? $result[
"price_ttc"] :
null;
2772 $this->multiprices_min[$i] = $result ? $result[
"price_min"] :
null;
2773 $this->multiprices_min_ttc[$i] = $result ? $result[
"price_min_ttc"] :
null;
2774 $this->multiprices_base_type[$i] = $result ? $result[
"price_base_type"] :
null;
2776 $this->multiprices_tva_tx[$i] = $result ? $result[
"tva_tx"].($result ?
' ('.$result[
'default_vat_code'].
')' :
'') :
null;
2777 $this->multiprices_recuperableonly[$i] = $result ? $result[
"recuperableonly"] :
null;
2816 $this->error = $this->db->lasterror;
2820 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES') && empty($ignore_price_load)) {
2822 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY') && empty($ignore_price_load)) {
2823 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
2824 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid";
2825 $sql .=
" FROM ".$this->db->prefix().
"product_price";
2826 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2827 $sql .=
" ORDER BY date_price DESC, rowid DESC";
2830 $resql = $this->db->query($sql);
2832 $result = $this->db->fetch_array($resql);
2836 $this->prices_by_qty[0] = $result[
"price_by_qty"];
2837 $this->prices_by_qty_id[0] = $result[
"rowid"];
2839 if ($this->prices_by_qty[0] == 1) {
2840 $sql =
"SELECT rowid,price, unitprice, quantity, remise_percent, remise, remise, price_base_type";
2841 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
2842 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[0]);
2843 $sql .=
" ORDER BY quantity ASC";
2845 $resql = $this->db->query($sql);
2847 $resultat = array();
2849 while ($result = $this->db->fetch_array($resql)) {
2850 $resultat[$ii] = array();
2851 $resultat[$ii][
"rowid"] = $result[
"rowid"];
2852 $resultat[$ii][
"price"] = $result[
"price"];
2853 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
2854 $resultat[$ii][
"quantity"] = $result[
"quantity"];
2855 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
2857 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
2860 $this->prices_by_qty_list[0] = $resultat;
2862 $this->error = $this->db->lasterror;
2868 $this->error = $this->db->lasterror;
2871 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') && empty($ignore_price_load)) {
2872 for ($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) {
2873 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
2874 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
2875 $sql .=
" FROM ".$this->db->prefix().
"product_price";
2876 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
2877 $sql .=
" AND price_level=".((int) $i);
2878 $sql .=
" AND fk_product = ".((int) $this->
id);
2879 $sql .=
" ORDER BY date_price DESC, rowid DESC";
2881 $resql = $this->db->query($sql);
2883 $this->error = $this->db->lasterror;
2885 } elseif ($result = $this->db->fetch_array($resql)) {
2886 $this->multiprices[$i] = (!empty($result[
"price"]) ? $result[
"price"] : 0);
2887 $this->multiprices_ttc[$i] = (!empty($result[
"price_ttc"]) ? $result[
"price_ttc"] : 0);
2888 $this->multiprices_min[$i] = (!empty($result[
"price_min"]) ? $result[
"price_min"] : 0);
2889 $this->multiprices_min_ttc[$i] = (!empty($result[
"price_min_ttc"]) ? $result[
"price_min_ttc"] : 0);
2890 $this->multiprices_base_type[$i] = (!empty($result[
"price_base_type"]) ? $result[
"price_base_type"] :
'');
2892 $this->multiprices_tva_tx[$i] = (!empty($result[
"tva_tx"]) ? $result[
"tva_tx"] : 0);
2893 $this->multiprices_recuperableonly[$i] = (!empty($result[
"recuperableonly"]) ? $result[
"recuperableonly"] : 0);
2896 $this->prices_by_qty[$i] = (!empty($result[
"price_by_qty"]) ? $result[
"price_by_qty"] : 0);
2897 $this->prices_by_qty_id[$i] = (!empty($result[
"rowid"]) ? $result[
"rowid"] : 0);
2899 if ($this->prices_by_qty[$i] == 1) {
2900 $sql =
"SELECT rowid, price, unitprice, quantity, remise_percent, remise, price_base_type";
2901 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
2902 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[$i]);
2903 $sql .=
" ORDER BY quantity ASC";
2905 $resql = $this->db->query($sql);
2907 $resultat = array();
2909 while ($result = $this->db->fetch_array($resql)) {
2910 $resultat[$ii] = array();
2911 $resultat[$ii][
"rowid"] = $result[
"rowid"];
2912 $resultat[$ii][
"price"] = $result[
"price"];
2913 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
2914 $resultat[$ii][
"quantity"] = $result[
"quantity"];
2915 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
2916 $resultat[$ii][
"remise"] = $result[
"remise"];
2917 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
2920 $this->prices_by_qty_list[$i] = $resultat;
2922 $this->error = $this->db->lasterror;
2930 if (isModEnabled(
'dynamicprices') && !empty($this->fk_price_expression) && empty($ignore_expression)) {
2931 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2933 $price_result = $priceparser->parseProduct($this);
2934 if ($price_result >= 0) {
2935 $this->
price = $price_result;
2937 $this->price_ttc = (float)
price2num($this->
price) * (1 + ($this->tva_tx / 100));
2938 $this->price_ttc = (float)
price2num($this->price_ttc,
'MU');
2944 $this->stock_warehouse = array();
2951 $this->error = $this->db->lasterror();
3226 global $conf, $user, $hookmanager, $action;
3228 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3229 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3230 $sql .=
" FROM ".$this->db->prefix().
"commandedet as cd";
3231 $sql .=
", ".$this->db->prefix().
"commande as c";
3232 $sql .=
", ".$this->db->prefix().
"societe as s";
3233 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3234 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3236 $sql .=
" WHERE c.rowid = cd.fk_commande";
3237 $sql .=
" AND c.fk_soc = s.rowid";
3238 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'commande').
")";
3239 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3240 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3241 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3244 $sql .=
" AND c.fk_soc = ".((int) $socid);
3246 if ($filtrestatut !=
'') {
3247 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3250 $result = $this->db->query($sql);
3252 $obj = $this->db->fetch_object($result);
3253 $this->stats_commande[
'customers'] = $obj->nb_customers;
3254 $this->stats_commande[
'nb'] = $obj->nb;
3255 $this->stats_commande[
'rows'] = $obj->nb_rows;
3256 $this->stats_commande[
'qty'] = $obj->qty ? $obj->qty : 0;
3261 if (is_array($TFather) && !empty($TFather)) {
3262 foreach ($TFather as &$fatherData) {
3263 $pFather =
new Product($this->db);
3264 $pFather->id = $fatherData[
'id'];
3265 $qtyCoef = $fatherData[
'qty'];
3267 if ($fatherData[
'incdec']) {
3268 $pFather->load_stats_commande($socid, $filtrestatut);
3270 $this->stats_commande[
'customers'] += $pFather->stats_commande[
'customers'];
3271 $this->stats_commande[
'nb'] += $pFather->stats_commande[
'nb'];
3272 $this->stats_commande[
'rows'] += $pFather->stats_commande[
'rows'];
3273 $this->stats_commande[
'qty'] += $pFather->stats_commande[
'qty'] * $qtyCoef;
3285 $sql =
"SELECT SUM(".$this->db->ifsql(
'f.type=2', -1, 1).
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3286 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3287 $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'))";
3288 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3289 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3291 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3292 $resql = $this->db->query($sql);
3294 if ($this->db->num_rows($resql) > 0) {
3295 $obj = $this->db->fetch_object($resql);
3296 $adeduire += $obj->count;
3300 $this->stats_commande[
'qty'] -= $adeduire;
3303 include_once DOL_DOCUMENT_ROOT.
'/compta/facture/class/facture.class.php';
3307 $sql =
"SELECT sum(".$this->db->ifsql(
'f.type=2', -1, 1).
" * fd.qty) as count FROM ".MAIN_DB_PREFIX.
"facturedet as fd ";
3308 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"facture as f ON fd.fk_facture = f.rowid";
3309 $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'))";
3310 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"commande as c ON el.fk_source = c.rowid";
3311 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3313 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3314 $resql = $this->db->query($sql);
3316 if ($this->db->num_rows($resql) > 0) {
3317 $obj = $this->db->fetch_object($resql);
3318 $adeduire += $obj->count;
3321 $this->error = $this->db->error();
3325 $this->stats_commande[
'qty'] -= $adeduire;
3329 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3330 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerOrder', $parameters, $this, $action);
3332 $this->stats_commande = $hookmanager->resArray[
'stats_commande'];
3336 $this->error = $this->db->error();
3560 public function load_stats_inproduction($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null, $warehouseid = 0)
3563 global $user, $hookmanager, $action;
3565 $serviceStockIsEnabled = isModEnabled(
"service") &&
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES');
3567 $sql =
"SELECT COUNT(DISTINCT m.fk_soc) as nb_customers, COUNT(DISTINCT m.rowid) as nb,";
3568 $sql .=
" COUNT(mp.rowid) as nb_rows, SUM(mp.qty) as qty, role";
3569 $sql .=
" FROM ".$this->db->prefix().
"mrp_production as mp";
3570 $sql .=
", ".$this->db->prefix().
"mrp_mo as m";
3571 $sql .=
" LEFT JOIN ".$this->db->prefix().
"societe as s ON s.rowid = m.fk_soc";
3572 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3573 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3575 $sql .=
" WHERE m.rowid = mp.fk_mo";
3576 $sql .=
" AND m.entity IN (".getEntity(($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE')) ?
'stock' :
'mrp').
")";
3577 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3578 $sql .=
" AND (mp.disable_stock_change IN (0) OR mp.disable_stock_change IS NULL)";
3579 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3580 $sql .=
" AND m.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3583 $sql .=
" AND m.fk_soc = ".((int) $socid);
3585 if ($filtrestatut !=
'') {
3586 $sql .=
" AND m.status IN (".$this->db->sanitize($filtrestatut).
")";
3588 if (!empty($dateofvirtualstock)) {
3589 $sql .=
" AND m.date_valid <= '".$this->db->idate($dateofvirtualstock).
"'";
3591 if (!$serviceStockIsEnabled) {
3592 $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))";
3594 if (!empty($warehouseid)) {
3595 $sql .=
" AND m.fk_warehouse = ".((int) $warehouseid);
3597 $sql .=
" GROUP BY role";
3600 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
3602 $this->stats_mrptoconsume[
'customers'] = 0;
3603 $this->stats_mrptoconsume[
'nb'] = 0;
3604 $this->stats_mrptoconsume[
'rows'] = 0;
3605 $this->stats_mrptoconsume[
'qty'] = 0;
3606 $this->stats_mrptoproduce[
'customers'] = 0;
3607 $this->stats_mrptoproduce[
'nb'] = 0;
3608 $this->stats_mrptoproduce[
'rows'] = 0;
3609 $this->stats_mrptoproduce[
'qty'] = 0;
3612 $result = $this->db->query($sql);
3614 while ($obj = $this->db->fetch_object($result)) {
3615 if ($obj->role ==
'toconsume' && empty($warehouseid)) {
3616 $this->stats_mrptoconsume[
'customers'] += $obj->nb_customers;
3617 $this->stats_mrptoconsume[
'nb'] += $obj->nb;
3618 $this->stats_mrptoconsume[
'rows'] += $obj->nb_rows;
3619 $this->stats_mrptoconsume[
'qty'] += ($obj->qty ? $obj->qty : 0);
3621 if ($obj->role ==
'consumed' && empty($warehouseid)) {
3625 $this->stats_mrptoconsume[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3627 if ($obj->role ==
'toproduce') {
3629 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] += ($obj->qty ? $obj->qty : 0);
3631 $this->stats_mrptoproduce[
'customers'] += $obj->nb_customers;
3632 $this->stats_mrptoproduce[
'nb'] += $obj->nb;
3633 $this->stats_mrptoproduce[
'rows'] += $obj->nb_rows;
3634 $this->stats_mrptoproduce[
'qty'] += ($obj->qty ? $obj->qty : 0);
3637 if ($obj->role ==
'produced') {
3642 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3644 $this->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3651 if ($this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] < 0) {
3652 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
3655 if ($this->stats_mrptoconsume[
'qty'] < 0) {
3656 $this->stats_mrptoconsume[
'qty'] = 0;
3658 if ($this->stats_mrptoproduce[
'qty'] < 0) {
3659 $this->stats_mrptoproduce[
'qty'] = 0;
3663 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3664 $reshook = $hookmanager->executeHooks(
'loadStatsInProduction', $parameters, $this, $action);
3666 $this->stats_mrptoproduce = $hookmanager->resArray[
'stats_mrptoproduce'];
3671 $this->error = $this->db->error();
5293 global $conf, $langs, $user;
5295 $langs->loadLangs(array(
'products',
'other'));
5298 $nofetch = !empty($params[
'nofetch']);
5301 return [
'optimize' => $langs->trans(
"ShowProduct")];
5305 $permissiontoreadproduct = 0;
5306 if ($this->
type == self::TYPE_PRODUCT && $user->hasRight(
'product',
'read')) {
5307 $permissiontoreadproduct = 1;
5309 if ($this->
type == self::TYPE_SERVICE && $user->hasRight(
'service',
'read')) {
5310 $permissiontoreadproduct = 1;
5313 if (!empty($this->entity) && $permissiontoreadproduct) {
5314 $tmpphoto = $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 80, 0, 0, 0, 0, 1);
5315 if ($this->nbphoto > 0) {
5316 $datas[
'photo'] =
'<div class="photointooltip floatright">'.
"\n" . $tmpphoto .
'</div>';
5321 $datas[
'picto'] =
img_picto(
'',
'product').
' <u class="paddingrightonly">'.$langs->trans(
"Product").
'</u>';
5323 $datas[
'picto'] =
img_picto(
'',
'service').
' <u class="paddingrightonly">'.$langs->trans(
"Service").
'</u>';
5325 if (isset($this->
status) && isset($this->status_buy)) {
5326 $datas[
'status'] =
' '.$this->getLibStatut(5, 0) .
' '.$this->getLibStatut(5, 1);
5329 if (!empty($this->
ref)) {
5330 $datas[
'ref'] =
'<br><b>'.$langs->trans(
'ProductRef').
':</b> '.$this->ref;
5332 if (!empty($this->label)) {
5333 $datas[
'label'] =
'<br><b>'.$langs->trans(
'ProductLabel').
':</b> '.$this->label;
5336 if ($permissiontoreadproduct) {
5341 if (isModEnabled(
'productbatch')) {
5342 $langs->load(
"productbatch");
5343 $datas[
'batchstatus'] =
"<br><b>".$langs->trans(
"ManageLotSerial").
'</b>: '.$this->
getLibStatut(0, 2);
5346 if (isModEnabled(
'barcode')) {
5347 $datas[
'barcode'] =
'<br><b>'.$langs->trans(
'BarCode').
':</b> '.$this->barcode;
5351 if ($this->weight) {
5352 $datas[
'weight'] =
"<br><b>".$langs->trans(
"Weight").
'</b>: '.$this->weight.
' '.
measuringUnitString(0,
"weight", $this->weight_units);
5355 if ($this->length) {
5356 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Length").
'</b>: '.$this->length.
' '.
measuringUnitString(0,
'size', $this->length_units);
5359 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Width").
'</b>: '.$this->width.
' '.
measuringUnitString(0,
'size', $this->width_units);
5361 if ($this->height) {
5362 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Height").
'</b>: '.$this->height.
' '.
measuringUnitString(0,
'size', $this->height_units);
5365 $datas[
'size'] =
"<br>".$labelsize;
5368 $labelsurfacevolume =
"";
5369 if ($this->surface) {
5370 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Surface").
'</b>: '.$this->surface.
' '.
measuringUnitString(0,
'surface', $this->surface_units);
5372 if ($this->volume) {
5373 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Volume").
'</b>: '.$this->volume.
' '.
measuringUnitString(0,
'volume', $this->volume_units);
5375 if ($labelsurfacevolume) {
5376 $datas[
'surface'] =
"<br>" . $labelsurfacevolume;
5382 if ($this->duration_value > 1) {
5383 $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"));
5384 } elseif ($this->duration_value > 0) {
5385 $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"));
5387 $datas[
'duration'] .= (!empty($this->duration_unit) && isset($dur[$this->duration_unit]) ?
" ".$langs->trans($dur[$this->duration_unit]) :
'');
5389 if (empty($user->socid)) {
5391 $datas[
'pmp'] =
"<br><b>".$langs->trans(
"PMPValue").
'</b>: '.
price($this->pmp, 0,
'', 1, -1, -1, $conf->currency);
5394 if (isModEnabled(
'accounting')) {
5395 if ($this->
status && isset($this->accountancy_code_sell)) {
5396 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5397 $selllabel =
'<br>';
5398 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellCode').
':</b> '.
length_accountg($this->accountancy_code_sell);
5399 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellIntraCode').
':</b> '.
length_accountg($this->accountancy_code_sell_intra);
5400 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellExportCode').
':</b> '.
length_accountg($this->accountancy_code_sell_export);
5401 $datas[
'accountancysell'] = $selllabel;
5403 if ($this->status_buy && isset($this->accountancy_code_buy)) {
5404 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5406 if (empty($this->
status)) {
5407 $buylabel .=
'<br>';
5409 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyCode').
':</b> '.
length_accountg($this->accountancy_code_buy);
5410 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyIntraCode').
':</b> '.
length_accountg($this->accountancy_code_buy_intra);
5411 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyExportCode').
':</b> '.
length_accountg($this->accountancy_code_buy_export);
5412 $datas[
'accountancybuy'] = $buylabel;
5417 if (isModEnabled(
'category') && !$nofetch) {
5418 require_once DOL_DOCUMENT_ROOT .
'/categories/class/categorie.class.php';
5419 $form =
new Form($this->db);
5420 $datas[
'categories'] =
'<br>' . $form->showCategories($this->
id, Categorie::TYPE_PRODUCT, 1);
5594 global $conf, $langs;
5596 $labelStatus = $labelStatusShort =
'';
5598 $langs->load(
'products');
5599 if (isModEnabled(
'productbatch')) {
5600 $langs->load(
"productbatch");
5606 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial')));
5607 return dolGetStatus($label);
5609 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort')));
5610 return dolGetStatus($label);
5614 return dolGetStatus($langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch'),
'',
'', empty($status) ?
'status5' :
'status4', 3,
'dot');
5620 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'));
5624 $statuttrans = empty($status) ?
'status5' :
'status4';
5629 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSellShort');
5630 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSell');
5631 } elseif ($type == 1) {
5632 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuyShort');
5633 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuy');
5634 } elseif ($type == 2) {
5635 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch');
5636 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort');
5638 } elseif ($status == 1) {
5641 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSellShort');
5642 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSell');
5643 } elseif ($type == 1) {
5644 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBuyShort');
5645 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBuy');
5646 } elseif ($type == 2) {
5647 $labelStatus = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial'));
5648 $labelStatusShort = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort'));
5650 } elseif ($type == 2 && $status == 2) {
5651 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSerial');
5652 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort');
5656 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'),
'',
'',
'status0', 0);
5658 return dolGetStatus($labelStatus, $labelStatusShort,
'', $statuttrans, $mode);
5908 global $conf, $hookmanager, $action;
5910 $stock_commande_client = 0;
5911 $stock_commande_fournisseur = 0;
5912 $stock_sending_client = 0;
5913 $stock_reception_fournisseur = 0;
5914 $stock_inproduction = 0;
5918 if (isModEnabled(
'order')) {
5923 $stock_commande_client = $this->stats_commande[
'qty'];
5925 if (isModEnabled(
"shipping")) {
5926 require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expedition.class.php';
5927 $filterShipmentStatus =
'';
5937 $stock_sending_client = $this->stats_expedition[
'qty'];
5940 if (isModEnabled(
"supplier_order")) {
5941 $filterStatus =
getDolGlobalString(
'SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK',
'3,4');
5942 if (isset($includedraftpoforvirtual)) {
5943 $filterStatus =
'0,1,2,'.$filterStatus;
5949 $stock_commande_fournisseur = $this->stats_commande_fournisseur[
'qty'];
5952 if ((isModEnabled(
"supplier_order") || isModEnabled(
"supplier_invoice")) && !isModEnabled(
'reception')) {
5954 $filterStatus =
'4';
5955 if (isset($includedraftpoforvirtual)) {
5956 $filterStatus =
'0,'.$filterStatus;
5962 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
5965 if ((isModEnabled(
"supplier_order") || isModEnabled(
"supplier_invoice")) && isModEnabled(
"reception")) {
5967 $filterStatus =
'4';
5968 if (isset($includedraftpoforvirtual)) {
5969 $filterStatus =
'0,'.$filterStatus;
5975 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
5978 if (isModEnabled(
'mrp')) {
5983 $stock_inproduction = $this->stats_mrptoproduce[
'qty'] - $this->stats_mrptoconsume[
'qty'];
5986 $this->stock_theorique = $this->stock_reel + $stock_inproduction;
5990 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
5992 $this->stock_theorique += 0;
5994 $this->stock_theorique -= $stock_commande_client;
5998 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6000 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6002 $this->stock_theorique -= $stock_reception_fournisseur;
6004 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6007 $parameters = array(
'id' => $this->
id,
'includedraftpoforvirtual' => $includedraftpoforvirtual);
6009 $reshook = $hookmanager->executeHooks(
'loadvirtualstock', $parameters, $this, $action);
6011 $this->stock_theorique = $hookmanager->resArray[
'stock_theorique'];
6012 } elseif ($reshook == 0 && isset($hookmanager->resArray[
'stock_stats_hook'])) {
6013 $this->stock_theorique += $hookmanager->resArray[
'stock_stats_hook'];
6017 if (!empty($this->stock_warehouse) &&
getDolGlobalString(
'STOCK_ALLOW_VIRTUAL_STOCK_PER_WAREHOUSE')) {
6018 foreach ($this->stock_warehouse as $warehouseid => $stockwarehouse) {
6019 if (isModEnabled(
'mrp')) {
6026 if ($this->fk_default_warehouse == $warehouseid) {
6027 $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']);
6029 $this->stock_warehouse[$warehouseid]->virtual = $this->stock_warehouse[$warehouseid]->real + $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'];