656 public function create($user, $notrigger = 0)
658 global $conf, $langs;
664 $this->
ref = trim($this->
ref);
668 $this->label = trim($this->label);
669 $this->price_ttc =
price2num($this->price_ttc);
671 $this->price_min_ttc =
price2num($this->price_min_ttc);
672 $this->price_min =
price2num($this->price_min);
673 if (empty($this->tva_tx)) {
676 if (empty($this->tva_npr)) {
680 if (empty($this->localtax1_tx)) {
681 $this->localtax1_tx = 0;
683 if (empty($this->localtax2_tx)) {
684 $this->localtax2_tx = 0;
686 if (empty($this->localtax1_type)) {
687 $this->localtax1_type =
'0';
689 if (empty($this->localtax2_type)) {
690 $this->localtax2_type =
'0';
692 if (empty($this->
price)) {
695 if (empty($this->price_min)) {
696 $this->price_min = 0;
699 if (empty($this->price_by_qty)) {
700 $this->price_by_qty = 0;
703 if (empty($this->
status)) {
706 if (empty($this->status_buy)) {
707 $this->status_buy = 0;
716 if ($this->price_base_type ==
'TTC' && $this->price_ttc > 0) {
717 $price_ttc =
price2num($this->price_ttc,
'MU');
718 $price_ht =
price2num($this->price_ttc / (1 + ($this->tva_tx / 100)),
'MU');
722 if ($this->price_base_type !=
'TTC' && $this->
price > 0) {
724 $price_ttc =
price2num($this->
price * (1 + ($this->tva_tx / 100)),
'MU');
728 if (($this->price_min_ttc > 0) && ($this->price_base_type ==
'TTC')) {
729 $price_min_ttc =
price2num($this->price_min_ttc,
'MU');
730 $price_min_ht =
price2num($this->price_min_ttc / (1 + ($this->tva_tx / 100)),
'MU');
734 if (($this->price_min > 0) && ($this->price_base_type !=
'TTC')) {
735 $price_min_ht =
price2num($this->price_min,
'MU');
736 $price_min_ttc =
price2num($this->price_min * (1 + ($this->tva_tx / 100)),
'MU');
739 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
740 $this->accountancy_code_buy_intra = trim($this->accountancy_code_buy_intra);
741 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
742 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
743 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
744 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
747 $this->barcode = trim($this->barcode);
748 $this->mandatory_period = empty($this->mandatory_period) ? 0 : $this->mandatory_period;
750 if (empty($this->label)) {
751 $this->error =
'ErrorMandatoryParametersNotProvided';
755 if (empty($this->
ref) || $this->
ref ==
'auto') {
758 if ($module !=
'mod_codeproduct_leopard') {
759 if (substr($module, 0, 16) ==
'mod_codeproduct_' && substr($module, -3) ==
'php') {
760 $module = substr($module, 0,
dol_strlen($module) - 4);
763 $modCodeProduct =
new $module();
764 if (!empty($modCodeProduct->code_auto)) {
765 $this->
ref = $modCodeProduct->getNextValue($this, $this->
type);
767 unset($modCodeProduct);
770 if (empty($this->
ref)) {
771 $this->error =
'ProductModuleNotSetupForAutoRef';
776 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);
783 if ($this->barcode == -1) {
784 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
789 $result = $this->
verify();
792 $sql =
"SELECT count(*) as nb";
793 $sql .=
" FROM ".$this->db->prefix().
"product";
794 $sql .=
" WHERE entity IN (".getEntity(
'product').
")";
795 $sql .=
" AND ref = '".$this->db->escape($this->
ref).
"'";
797 $result = $this->db->query($sql);
799 $obj = $this->db->fetch_object($result);
802 $sql =
"INSERT INTO ".$this->db->prefix().
"product (";
807 $sql .=
", price_min";
808 $sql .=
", price_min_ttc";
810 $sql .=
", fk_user_author";
811 $sql .=
", fk_product_type";
813 $sql .=
", price_ttc";
814 $sql .=
", price_base_type";
818 $sql .=
", accountancy_code_buy";
819 $sql .=
", accountancy_code_buy_intra";
820 $sql .=
", accountancy_code_buy_export";
821 $sql .=
", accountancy_code_sell";
822 $sql .=
", accountancy_code_sell_intra";
823 $sql .=
", accountancy_code_sell_export";
826 $sql .=
", finished";
828 $sql .=
", batch_mask";
830 $sql .=
", mandatory_period";
831 $sql .=
") VALUES (";
832 $sql .=
"'".$this->db->idate($now).
"'";
833 $sql .=
", ".(!empty($this->entity) ? (int) $this->entity : (int) $conf->entity);
834 $sql .=
", '".$this->db->escape($this->
ref).
"'";
835 $sql .=
", ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
836 $sql .=
", ".price2num($price_min_ht);
837 $sql .=
", ".price2num($price_min_ttc);
838 $sql .=
", ".(!empty($this->label) ?
"'".$this->db->escape($this->label).
"'" :
"null");
839 $sql .=
", ".((int) $user->id);
840 $sql .=
", ".((int) $this->
type);
841 $sql .=
", ".price2num($price_ht,
'MT');
842 $sql .=
", ".price2num($price_ttc,
'MT');
843 $sql .=
", '".$this->db->escape($this->price_base_type).
"'";
844 $sql .=
", ".((int) $this->
status);
845 $sql .=
", ".((int) $this->status_buy);
847 $sql .=
", '".$this->db->escape($this->accountancy_code_buy).
"'";
848 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_intra).
"'";
849 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_export).
"'";
850 $sql .=
", '".$this->db->escape($this->accountancy_code_sell).
"'";
851 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_intra).
"'";
852 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_export).
"'";
854 $sql .=
", '".$this->db->escape($this->canvas).
"'";
855 $sql .=
", ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
'NULL' : (int) $this->finished);
856 $sql .=
", ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : ((int) $this->status_batch));
857 $sql .=
", '".$this->db->escape($this->batch_mask).
"'";
858 $sql .=
", ".($this->fk_unit > 0 ? ((int) $this->fk_unit) :
'NULL');
859 $sql .=
", '".$this->db->escape($this->mandatory_period).
"'";
862 dol_syslog(get_class($this).
"::Create", LOG_DEBUG);
863 $result = $this->db->query($sql);
865 $id = $this->db->last_insert_id($this->db->prefix().
"product");
869 $this->
price = $price_ht;
870 $this->price_ttc = $price_ttc;
871 $this->price_min = $price_min_ht;
872 $this->price_min_ttc = $price_min_ttc;
876 if ($this->
update($id, $user,
true,
'add') <= 0) {
881 $this->error = $this->db->lasterror();
886 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " .((int) $this->id) .
" AND entity = " . ((
int) $conf->entity));
888 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
889 $sql .=
" fk_product";
891 $sql .=
", accountancy_code_buy";
892 $sql .=
", accountancy_code_buy_intra";
893 $sql .=
", accountancy_code_buy_export";
894 $sql .=
", accountancy_code_sell";
895 $sql .=
", accountancy_code_sell_intra";
896 $sql .=
", accountancy_code_sell_export";
897 $sql .=
") VALUES (";
899 $sql .=
", " . $conf->entity;
900 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
901 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
902 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
903 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
904 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
905 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
907 $result = $this->db->query($sql);
910 $this->error =
'ErrorFailedToInsertAccountancyForEntity';
915 $this->error =
'ErrorFailedToGetInsertedId';
919 $this->error = $this->db->lasterror();
923 $langs->load(
"products");
925 $this->error =
"ErrorProductAlreadyExists";
926 dol_syslog(get_class($this).
"::Create fails, ref ".$this->
ref.
" already exists");
930 $this->error = $this->db->lasterror();
933 if (!$error && !$notrigger) {
946 $this->db->rollback();
950 $this->db->rollback();
951 dol_syslog(get_class($this).
"::Create fails verify ".join(
',', $this->errors), LOG_WARNING);
1051 public function update($id, $user, $notrigger =
false, $action =
'update', $updatetype =
false)
1053 global $langs, $conf, $hookmanager;
1058 if (!$this->label) {
1059 $this->label =
'MISSING LABEL';
1064 $this->
ref = trim($this->
ref);
1068 $this->label = trim($this->label);
1070 $this->note_private = (isset($this->note_private) ? trim($this->note_private) :
null);
1071 $this->note_public = (isset($this->note_public) ? trim($this->note_public) :
null);
1072 $this->net_measure =
price2num($this->net_measure);
1073 $this->net_measure_units = trim($this->net_measure_units);
1074 $this->weight =
price2num($this->weight);
1075 $this->weight_units = trim($this->weight_units);
1076 $this->length =
price2num($this->length);
1077 $this->length_units = trim($this->length_units);
1079 $this->width_units = trim($this->width_units);
1080 $this->height =
price2num($this->height);
1081 $this->height_units = trim($this->height_units);
1082 $this->surface =
price2num($this->surface);
1083 $this->surface_units = trim($this->surface_units);
1084 $this->volume =
price2num($this->volume);
1085 $this->volume_units = trim($this->volume_units);
1088 if (is_numeric($this->length_units)) {
1089 $this->width_units = $this->length_units;
1091 if (is_numeric($this->length_units)) {
1092 $this->height_units = $this->length_units;
1096 if (empty($this->surface) && !empty($this->length) && !empty($this->width) && $this->length_units == $this->width_units) {
1097 $this->surface = $this->length * $this->width;
1100 if (empty($this->volume) && !empty($this->surface) && !empty($this->height) && $this->length_units == $this->height_units) {
1101 $this->volume = $this->surface * $this->height;
1105 if (empty($this->tva_tx)) {
1108 if (empty($this->tva_npr)) {
1111 if (empty($this->localtax1_tx)) {
1112 $this->localtax1_tx = 0;
1114 if (empty($this->localtax2_tx)) {
1115 $this->localtax2_tx = 0;
1117 if (empty($this->localtax1_type)) {
1118 $this->localtax1_type =
'0';
1120 if (empty($this->localtax2_type)) {
1121 $this->localtax2_type =
'0';
1123 if (empty($this->
status)) {
1126 if (empty($this->status_buy)) {
1127 $this->status_buy = 0;
1130 if (empty($this->country_id)) {
1131 $this->country_id = 0;
1134 if (empty($this->state_id)) {
1135 $this->state_id = 0;
1139 $this->barcode = trim($this->barcode);
1141 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
1142 $this->accountancy_code_buy_intra = trim($this->accountancy_code_buy_intra);
1143 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
1144 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
1145 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
1146 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
1153 if ($action !=
'add') {
1154 $result = $this->
verify();
1162 if (empty($this->oldcopy)) {
1167 if ($this->
hasbatch() && !$this->oldcopy->hasbatch()) {
1169 $valueforundefinedlot =
'000000';
1171 $valueforundefinedlot = $conf->global->STOCK_DEFAULT_BATCH;
1174 dol_syslog(
"Flag batch of product id=".$this->
id.
" is set to ON, so we will create missing records into product_batch");
1177 foreach ($this->stock_warehouse as $idW => $ObjW) {
1179 foreach ($ObjW->detail_batch as $detail) {
1180 if ($detail->batch == $valueforundefinedlot || $detail->batch ==
'Undefined') {
1182 $sqlclean =
"DELETE FROM ".$this->db->prefix().
"product_batch WHERE batch in('Undefined', '".$this->db->escape($valueforundefinedlot).
"') AND fk_product_stock = ".((int) $ObjW->id);
1183 $result = $this->db->query($sqlclean);
1191 $qty_batch += $detail->qty;
1195 if ($ObjW->real != $qty_batch) {
1197 $ObjBatch->batch = $valueforundefinedlot;
1198 $ObjBatch->qty = ($ObjW->real - $qty_batch);
1199 $ObjBatch->fk_product_stock = $ObjW->id;
1201 if ($ObjBatch->create($user, 1) < 0) {
1203 $this->errors = $ObjBatch->errors;
1207 if ($ObjLot->fetch(0, $this->id, $valueforundefinedlot) == 0) {
1208 $ObjLot->fk_product = $this->id;
1209 $ObjLot->entity = $this->entity;
1210 $ObjLot->fk_user_creat = $user->id;
1211 $ObjLot->batch = $valueforundefinedlot;
1212 if ($ObjLot->create($user,
true) < 0) {
1214 $this->errors = $ObjLot->errors;
1223 if ($this->barcode == -1) {
1224 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1227 $sql =
"UPDATE ".$this->db->prefix().
"product";
1228 $sql .=
" SET label = '".$this->db->escape($this->label).
"'";
1231 $sql .=
", fk_product_type = ".((int) $this->
type);
1234 $sql .=
", ref = '".$this->db->escape($this->
ref).
"'";
1235 $sql .=
", ref_ext = ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1236 $sql .=
", default_vat_code = ".($this->default_vat_code ?
"'".$this->db->escape($this->default_vat_code).
"'" :
"null");
1237 $sql .=
", tva_tx = ".((float) $this->tva_tx);
1238 $sql .=
", recuperableonly = ".((int) $this->tva_npr);
1239 $sql .=
", localtax1_tx = ".((float) $this->localtax1_tx);
1240 $sql .=
", localtax2_tx = ".((float) $this->localtax2_tx);
1241 $sql .=
", localtax1_type = ".($this->localtax1_type !=
'' ?
"'".$this->db->escape($this->localtax1_type).
"'" :
"'0'");
1242 $sql .=
", localtax2_type = ".($this->localtax2_type !=
'' ?
"'".$this->db->escape($this->localtax2_type).
"'" :
"'0'");
1244 $sql .=
", barcode = ".(empty($this->barcode) ?
"null" :
"'".$this->db->escape($this->barcode).
"'");
1245 $sql .=
", fk_barcode_type = ".(empty($this->barcode_type) ?
"null" : $this->db->escape($this->barcode_type));
1247 $sql .=
", tosell = ".(int) $this->
status;
1248 $sql .=
", tobuy = ".(int) $this->status_buy;
1249 $sql .=
", tobatch = ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : (int) $this->status_batch);
1250 $sql .=
", batch_mask = '".$this->db->escape($this->batch_mask).
"'";
1252 $sql .=
", finished = ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
"null" : (int) $this->finished);
1253 $sql .=
", fk_default_bom = ".((!isset($this->fk_default_bom) || $this->fk_default_bom < 0 || $this->fk_default_bom ==
'') ?
"null" : (int) $this->fk_default_bom);
1254 $sql .=
", net_measure = ".($this->net_measure !=
'' ?
"'".$this->db->escape($this->net_measure).
"'" :
'null');
1255 $sql .=
", net_measure_units = ".($this->net_measure_units !=
'' ?
"'".$this->db->escape($this->net_measure_units).
"'" :
'null');
1256 $sql .=
", weight = ".($this->weight !=
'' ?
"'".$this->db->escape($this->weight).
"'" :
'null');
1257 $sql .=
", weight_units = ".($this->weight_units !=
'' ?
"'".$this->db->escape($this->weight_units).
"'" :
'null');
1258 $sql .=
", length = ".($this->length !=
'' ?
"'".$this->db->escape($this->length).
"'" :
'null');
1259 $sql .=
", length_units = ".($this->length_units !=
'' ?
"'".$this->db->escape($this->length_units).
"'" :
'null');
1260 $sql .=
", width= ".($this->width !=
'' ?
"'".$this->db->escape($this->width).
"'" :
'null');
1261 $sql .=
", width_units = ".($this->width_units !=
'' ?
"'".$this->db->escape($this->width_units).
"'" :
'null');
1262 $sql .=
", height = ".($this->height !=
'' ?
"'".$this->db->escape($this->height).
"'" :
'null');
1263 $sql .=
", height_units = ".($this->height_units !=
'' ?
"'".$this->db->escape($this->height_units).
"'" :
'null');
1264 $sql .=
", surface = ".($this->surface !=
'' ?
"'".$this->db->escape($this->surface).
"'" :
'null');
1265 $sql .=
", surface_units = ".($this->surface_units !=
'' ?
"'".$this->db->escape($this->surface_units).
"'" :
'null');
1266 $sql .=
", volume = ".($this->volume !=
'' ?
"'".$this->db->escape($this->volume).
"'" :
'null');
1267 $sql .=
", volume_units = ".($this->volume_units !=
'' ?
"'".$this->db->escape($this->volume_units).
"'" :
'null');
1268 $sql .=
", fk_default_warehouse = ".($this->fk_default_warehouse > 0 ? ((int) $this->fk_default_warehouse) :
'null');
1269 $sql .=
", fk_default_workstation = ".($this->fk_default_workstation > 0 ? ((int) $this->fk_default_workstation) :
'null');
1270 $sql .=
", seuil_stock_alerte = ".((isset($this->seuil_stock_alerte) && is_numeric($this->seuil_stock_alerte)) ? (
float) $this->seuil_stock_alerte :
'null');
1271 $sql .=
", description = '".$this->db->escape($this->
description).
"'";
1272 $sql .=
", url = ".($this->url ?
"'".$this->db->escape($this->url).
"'" :
'null');
1273 $sql .=
", customcode = '".$this->db->escape($this->customcode).
"'";
1274 $sql .=
", fk_country = ".($this->country_id > 0 ? (int) $this->country_id :
'null');
1275 $sql .=
", fk_state = ".($this->state_id > 0 ? (int) $this->state_id :
'null');
1276 $sql .=
", lifetime = ".($this->lifetime > 0 ? (int) $this->lifetime :
'null');
1277 $sql .=
", qc_frequency = ".($this->qc_frequency > 0 ? (int) $this->qc_frequency :
'null');
1278 $sql .=
", note = ".(isset($this->note_private) ?
"'".$this->db->escape($this->note_private).
"'" :
'null');
1279 $sql .=
", note_public = ".(isset($this->note_public) ?
"'".$this->db->escape($this->note_public).
"'" :
'null');
1280 $sql .=
", duration = '".$this->db->escape($this->duration_value.$this->duration_unit).
"'";
1282 $sql .=
", accountancy_code_buy = '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1283 $sql .=
", accountancy_code_buy_intra = '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1284 $sql .=
", accountancy_code_buy_export = '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1285 $sql .=
", accountancy_code_sell= '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1286 $sql .=
", accountancy_code_sell_intra= '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1287 $sql .=
", accountancy_code_sell_export= '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1289 $sql .=
", desiredstock = ".((isset($this->desiredstock) && is_numeric($this->desiredstock)) ? (
float) $this->desiredstock :
"null");
1290 $sql .=
", cost_price = ".($this->cost_price !=
'' ? $this->db->escape($this->cost_price) :
'null');
1291 $sql .=
", fk_unit= ".(!$this->fk_unit ?
'NULL' : (int) $this->fk_unit);
1292 $sql .=
", price_autogen = ".(!$this->price_autogen ? 0 : 1);
1293 $sql .=
", fk_price_expression = ".($this->fk_price_expression != 0 ? (int) $this->fk_price_expression :
'NULL');
1294 $sql .=
", fk_user_modif = ".($user->id > 0 ? $user->id :
'NULL');
1295 $sql .=
", mandatory_period = ".($this->mandatory_period);
1297 $sql .=
" WHERE rowid = ".((int) $id);
1299 dol_syslog(get_class($this).
"::update", LOG_DEBUG);
1301 $resql = $this->db->query($sql);
1308 $this->error = $langs->trans(
"Error").
" : ".$this->db->error().
" - ".$sql;
1317 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " . ((
int) $this->id) .
" AND entity = " . ((
int) $conf->entity));
1319 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1320 $sql .=
" fk_product";
1322 $sql .=
", accountancy_code_buy";
1323 $sql .=
", accountancy_code_buy_intra";
1324 $sql .=
", accountancy_code_buy_export";
1325 $sql .=
", accountancy_code_sell";
1326 $sql .=
", accountancy_code_sell_intra";
1327 $sql .=
", accountancy_code_sell_export";
1328 $sql .=
") VALUES (";
1330 $sql .=
", " . $conf->entity;
1331 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1332 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1333 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1334 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1335 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1336 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1338 $result = $this->db->query($sql);
1341 $this->error =
'ErrorFailedToUpdateAccountancyForEntity';
1345 if (!$this->
hasbatch() && $this->oldcopy->hasbatch()) {
1347 $sql =
'SELECT pb.qty, ps.fk_entrepot, pb.batch FROM '.MAIN_DB_PREFIX.
'product_batch as pb';
1348 $sql.=
' INNER JOIN '.MAIN_DB_PREFIX.
'product_stock as ps ON (ps.rowid = pb.fk_product_stock)';
1349 $sql.=
' WHERE ps.fk_product = '.(int) $this->
id;
1351 $resql = $this->db->query($sql);
1355 while ($obj = $this->db->fetch_object($resql)) {
1357 $fk_entrepot = $obj->fk_entrepot;
1361 $batch = $obj->batch;
1364 $addOremove = $value > 0 ? 1 : 0;
1365 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1366 $res = $this->
correct_stock_batch($user, $fk_entrepot, abs($value), $addOremove, $label, $price, $dlc, $dluo, $batch, $inventorycode,
'',
null, 0,
null,
true);
1369 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1370 $res = $this->
correct_stock($user, $fk_entrepot, abs($value), (
int) empty($addOremove), $label, $price, $inventorycode,
'',
null, 0);
1389 if (!$error && !$notrigger) {
1391 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
1398 if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) {
1400 if ($conf->product->dir_output) {
1403 if (file_exists($olddir)) {
1407 $res = @rename($olddir, $newdir);
1409 $langs->load(
"errors");
1410 $this->error = $langs->trans(
'ErrorFailToRenameDir', $olddir, $newdir);
1418 if (isModEnabled(
'variants')) {
1419 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1423 foreach ($comb->fetchAllByFkProductParent($this->id) as $currcomb) {
1424 $currcomb->updateProperties($this, $user);
1428 $this->db->commit();
1431 $this->db->rollback();
1435 if ($this->db->errno() ==
'DB_ERROR_RECORD_ALREADY_EXISTS') {
1436 $langs->load(
"errors");
1437 if (empty($conf->barcode->enabled) || empty($this->barcode)) {
1438 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductAlreadyExists", $this->
ref);
1440 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductBarCodeAlreadyExists", $this->barcode);
1442 $this->errors[] = $this->error;
1443 $this->db->rollback();
1446 $this->error = $langs->trans(
"Error").
" : ".$this->db->error().
" - ".$sql;
1447 $this->errors[] = $this->error;
1448 $this->db->rollback();
1453 $this->db->rollback();
1454 dol_syslog(get_class($this).
"::Update fails verify ".join(
',', $this->errors), LOG_WARNING);
1628 global $conf, $langs;
1630 $langs_available = $langs->get_available_languages(DOL_DOCUMENT_ROOT, 0, 2);
1631 $current_lang = $langs->getDefaultLang();
1633 foreach ($langs_available as $key => $value) {
1634 if ($key == $current_lang) {
1635 $sql =
"SELECT rowid";
1636 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1637 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1638 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
1640 $result = $this->db->query($sql);
1642 if ($this->db->num_rows($result)) {
1643 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
1645 $sql2 .=
" label='".$this->db->escape($this->label).
"',";
1646 $sql2 .=
" description='".$this->db->escape($this->
description).
"'";
1648 $sql2 .=
", note='".$this->db->escape($this->other).
"'";
1650 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
1652 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
1657 $sql2 .=
" VALUES(".$this->id.
",'".$this->db->escape($key).
"','".$this->db->escape($this->label).
"',";
1658 $sql2 .=
" '".$this->db->escape($this->
description).
"'";
1660 $sql2 .=
", '".$this->db->escape($this->other).
"'";
1664 dol_syslog(get_class($this).
'::setMultiLangs key = current_lang = '.$key);
1665 if (!$this->db->query($sql2)) {
1666 $this->error = $this->db->lasterror();
1669 } elseif (isset($this->multilangs[$key])) {
1670 if (empty($this->multilangs[
"$key"][
"label"])) {
1671 $this->errors[] = $key .
' : ' . $langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Label"));
1675 $sql =
"SELECT rowid";
1676 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1677 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1678 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
1680 $result = $this->db->query($sql);
1682 if ($this->db->num_rows($result)) {
1683 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
1685 $sql2 .=
" label = '".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
1686 $sql2 .=
" description = '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
1688 $sql2 .=
", note = '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
1690 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
1692 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
1697 $sql2 .=
" VALUES(".$this->id.
",'".$this->db->escape($key).
"','".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
1698 $sql2 .=
" '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
1700 $sql2 .=
", '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
1706 if ($this->multilangs[
"$key"][
"label"] || $this->multilangs[
"$key"][
"description"]) {
1707 if (!$this->db->query($sql2)) {
1708 $this->error = $this->db->lasterror();
1718 $result = $this->
call_trigger(
'PRODUCT_SET_MULTILANGS', $user);
1720 $this->error = $this->db->lasterror();
1968 public function getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp = 0)
1970 global $conf, $hookmanager, $action;
1973 if (is_object($hookmanager)) {
1974 $parameters = array(
'thirdparty_seller'=>$thirdparty_seller,
'thirdparty_buyer' => $thirdparty_buyer,
'pqp' => $pqp);
1976 $reshook = $hookmanager->executeHooks(
'getSellPrice', $parameters, $this, $action);
1978 return $hookmanager->resArray;
1989 $pu_ht = $this->price;
1990 $pu_ttc = $this->price_ttc;
1991 $price_min = $this->price_min;
1992 $price_base_type = $this->price_base_type;
1995 if (
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !empty($thirdparty_buyer->price_level)) {
1996 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
1997 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
1998 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
1999 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
2001 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2002 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2004 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2005 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2013 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2017 $filter = array(
't.fk_product' => $this->
id,
't.fk_soc' => $thirdparty_buyer->id);
2019 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2021 if (count($prodcustprice->lines) > 0) {
2022 $pu_ht =
price($prodcustprice->lines[0]->price);
2023 $price_min =
price($prodcustprice->lines[0]->price_min);
2024 $pu_ttc =
price($prodcustprice->lines[0]->price_ttc);
2025 $price_base_type = $prodcustprice->lines[0]->price_base_type;
2026 $tva_tx = $prodcustprice->lines[0]->tva_tx;
2027 if ($prodcustprice->lines[0]->default_vat_code && !preg_match(
'/\(.*\)/',
$tva_tx)) {
2028 $tva_tx .=
' ('.$prodcustprice->lines[0]->default_vat_code.
')';
2030 $tva_npr = $prodcustprice->lines[0]->recuperableonly;
2038 if ($this->prices_by_qty[0]) {
2041 foreach ($this->prices_by_qty_list[0] as $priceforthequantityarray) {
2042 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2046 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2047 $pu_ht = $priceforthequantityarray[
'unitprice'];
2049 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2056 if ($this->prices_by_qty[$thirdparty_buyer->price_level]) {
2059 foreach ($this->prices_by_qty_list[$thirdparty_buyer->price_level] as $priceforthequantityarray) {
2060 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2064 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2065 $pu_ht = $priceforthequantityarray[
'unitprice'];
2067 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2074 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);
2091 public function get_buyprice($prodfournprice, $qty, $product_id = 0, $fourn_ref =
'', $fk_soc = 0)
2098 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2099 $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,";
2100 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2101 $sql .=
" pfp.packaging";
2102 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2103 $sql .=
" WHERE pfp.rowid = ".((int) $prodfournprice);
2105 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2107 $sql .=
" ORDER BY pfp.quantity DESC";
2109 dol_syslog(get_class($this).
"::get_buyprice first search by prodfournprice/qty", LOG_DEBUG);
2110 $resql = $this->db->query($sql);
2112 $obj = $this->db->fetch_object($resql);
2113 if ($obj && $obj->quantity > 0) {
2114 if (isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2116 $prod_supplier->product_fourn_price_id = $obj->rowid;
2117 $prod_supplier->id = $obj->fk_product;
2118 $prod_supplier->fourn_qty = $obj->quantity;
2119 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2120 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2122 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2124 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2125 if ($price_result >= 0) {
2126 $obj->price = $price_result;
2129 $this->product_fourn_price_id = $obj->rowid;
2130 $this->buyprice = $obj->price;
2131 $this->fourn_pu = $obj->price / $obj->quantity;
2132 $this->fourn_price_base_type =
'HT';
2133 $this->fourn_socid = $obj->fk_soc;
2134 $this->ref_fourn = $obj->ref_supplier;
2135 $this->ref_supplier = $obj->ref_supplier;
2136 $this->desc_supplier = $obj->desc_supplier;
2137 $this->remise_percent = $obj->remise_percent;
2138 $this->vatrate_supplier = $obj->tva_tx;
2139 $this->default_vat_code_supplier = $obj->default_vat_code;
2140 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2141 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2142 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2143 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2144 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2146 $this->packaging = $obj->packaging;
2148 $result = $obj->fk_product;
2152 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2153 $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,";
2154 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2155 $sql .=
" pfp.packaging";
2156 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2157 $sql .=
" WHERE 1 = 1";
2158 if ($product_id > 0) {
2159 $sql .=
" AND pfp.fk_product = ".((int) $product_id);
2161 if ($fourn_ref !=
'none') {
2162 $sql .=
" AND pfp.ref_fourn = '".$this->db->escape($fourn_ref).
"'";
2165 $sql .=
" AND pfp.fk_soc = ".((int) $fk_soc);
2168 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2170 $sql .=
" ORDER BY pfp.quantity DESC";
2173 dol_syslog(get_class($this).
"::get_buyprice second search from qty/ref/product_id", LOG_DEBUG);
2174 $resql = $this->db->query($sql);
2176 $obj = $this->db->fetch_object($resql);
2177 if ($obj && $obj->quantity > 0) {
2178 if (isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2180 $prod_supplier->product_fourn_price_id = $obj->rowid;
2181 $prod_supplier->id = $obj->fk_product;
2182 $prod_supplier->fourn_qty = $obj->quantity;
2183 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2184 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2186 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2188 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2190 $obj->price = $price_result;
2193 $this->product_fourn_price_id = $obj->rowid;
2194 $this->buyprice = $obj->price;
2195 $this->fourn_qty = $obj->quantity;
2196 $this->fourn_pu = $obj->price / $obj->quantity;
2197 $this->fourn_price_base_type =
'HT';
2198 $this->fourn_socid = $obj->fk_soc;
2199 $this->ref_fourn = $obj->ref_supplier;
2200 $this->ref_supplier = $obj->ref_supplier;
2201 $this->desc_supplier = $obj->desc_supplier;
2202 $this->remise_percent = $obj->remise_percent;
2203 $this->vatrate_supplier = $obj->tva_tx;
2204 $this->default_vat_code_supplier = $obj->default_vat_code;
2205 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2206 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2207 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2208 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2209 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2211 $this->packaging = $obj->packaging;
2213 $result = $obj->fk_product;
2219 $this->error = $this->db->lasterror();
2224 $this->error = $this->db->lasterror();
2247 public function updatePrice($newprice, $newpricebase, $user, $newvat =
'', $newminprice = 0, $level = 0, $newnpr = 0, $newpbq = 0, $ignore_autogen = 0, $localtaxes_array = array(), $newdefaultvatcode =
'', $notrigger = 0)
2249 global $conf, $langs;
2255 dol_syslog(get_class($this).
"::update_price id=".$id.
" newprice=".$newprice.
" newpricebase=".$newpricebase.
" newminprice=".$newminprice.
" level=".$level.
" npr=".$newnpr.
" newdefaultvatcode=".$newdefaultvatcode);
2258 if (empty($this->tva_tx)) {
2261 if (empty($newnpr)) {
2264 if (empty($newminprice)) {
2267 if (empty($newminprice)) {
2272 if ($newvat ==
'') {
2278 if ((
getDolGlobalString(
'PRODUIT_MULTIPRICES') ||
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) && !$ignore_autogen && $this->price_autogen && ($level == 1)) {
2279 return $this->
generateMultiprices($user, $newprice, $newpricebase, $newvat, $newnpr, $newpbq);
2282 if (!empty($newminprice) && ($newminprice > $newprice)) {
2283 $this->error =
'ErrorPriceCantBeLowerThanMinPrice';
2287 if ($newprice !==
'' || $newprice === 0) {
2288 if ($newpricebase ==
'TTC') {
2289 $price_ttc =
price2num($newprice,
'MU');
2290 $price =
price2num($newprice) / (1 + ($newvat / 100));
2293 if ($newminprice !=
'' || $newminprice == 0) {
2294 $price_min_ttc =
price2num($newminprice,
'MU');
2295 $price_min =
price2num($newminprice) / (1 + ($newvat / 100));
2296 $price_min =
price2num($price_min,
'MU');
2303 $price_ttc = ($newnpr != 1) ? (
float)
price2num($newprice) * (1 + ($newvat / 100)) : $price;
2304 $price_ttc =
price2num($price_ttc,
'MU');
2306 if ($newminprice !==
'' || $newminprice === 0) {
2307 $price_min =
price2num($newminprice,
'MU');
2308 $price_min_ttc =
price2num($newminprice) * (1 + ($newvat / 100));
2309 $price_min_ttc =
price2num($price_min_ttc,
'MU');
2318 if (count($localtaxes_array) > 0) {
2319 $localtaxtype1 = $localtaxes_array[
'0'];
2320 $localtax1 = $localtaxes_array[
'1'];
2321 $localtaxtype2 = $localtaxes_array[
'2'];
2322 $localtax2 = $localtaxes_array[
'3'];
2325 if (!empty($newdefaultvatcode)) {
2328 $sql =
"SELECT t.rowid, t.code, t.recuperableonly as tva_npr, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
2329 $sql .=
" FROM ".MAIN_DB_PREFIX.
"c_tva as t, ".MAIN_DB_PREFIX.
"c_country as c";
2330 $sql .=
" WHERE t.fk_pays = c.rowid AND c.code = '".$this->db->escape($mysoc->country_code).
"'";
2331 $sql .=
" AND t.taux = ".((float) $newdefaultvatcode).
" AND t.active = 1";
2332 $sql .=
" AND t.code = '".$this->db->escape($newdefaultvatcode).
"'";
2333 $resql = $this->db->query($sql);
2335 $obj = $this->db->fetch_object($resql);
2337 $npr = $obj->tva_npr;
2338 $localtax1 = $obj->localtax1;
2339 $localtax2 = $obj->localtax2;
2340 $localtaxtype1 = $obj->localtax1_type;
2341 $localtaxtype2 = $obj->localtax2_type;
2346 $localtaxtype1 =
'0';
2348 $localtaxtype2 =
'0';
2352 if (empty($localtax1)) {
2355 if (empty($localtax2)) {
2363 $sql =
"UPDATE ".$this->db->prefix().
"product SET";
2364 $sql .=
" price_base_type = '".$this->db->escape($newpricebase).
"',";
2365 $sql .=
" price = ".(float) $price.
",";
2366 $sql .=
" price_ttc = ".(float) $price_ttc.
",";
2367 $sql .=
" price_min = ".(float) $price_min.
",";
2368 $sql .=
" price_min_ttc = ".(float) $price_min_ttc.
",";
2369 $sql .=
" localtax1_tx = ".($localtax1 >= 0 ? (float) $localtax1 :
'NULL').
",";
2370 $sql .=
" localtax2_tx = ".($localtax2 >= 0 ? (float) $localtax2 :
'NULL').
",";
2371 $sql .=
" localtax1_type = ".($localtaxtype1 !=
'' ?
"'".$this->db->escape($localtaxtype1).
"'" :
"'0'").
",";
2372 $sql .=
" localtax2_type = ".($localtaxtype2 !=
'' ?
"'".$this->db->escape($localtaxtype2).
"'" :
"'0'").
",";
2373 $sql .=
" default_vat_code = ".($newdefaultvatcode ?
"'".$this->db->escape($newdefaultvatcode).
"'" :
"null").
",";
2374 $sql .=
" tva_tx = ".(float)
price2num($newvat).
",";
2375 $sql .=
" recuperableonly = '".$this->db->escape($newnpr).
"'";
2376 $sql .=
" WHERE rowid = ".((int) $id);
2378 dol_syslog(get_class($this).
"::update_price", LOG_DEBUG);
2379 $resql = $this->db->query($sql);
2381 $this->multiprices[$level] = $price;
2382 $this->multiprices_ttc[$level] = $price_ttc;
2383 $this->multiprices_min[$level] = $price_min;
2384 $this->multiprices_min_ttc[$level] = $price_min_ttc;
2385 $this->multiprices_base_type[$level] = $newpricebase;
2386 $this->multiprices_default_vat_code[$level] = $newdefaultvatcode;
2387 $this->multiprices_tva_tx[$level] = $newvat;
2388 $this->multiprices_recuperableonly[$level] = $newnpr;
2390 $this->
price = $price;
2391 $this->price_ttc = $price_ttc;
2392 $this->price_min = $price_min;
2393 $this->price_min_ttc = $price_min_ttc;
2394 $this->price_base_type = $newpricebase;
2395 $this->default_vat_code = $newdefaultvatcode;
2396 $this->tva_tx = $newvat;
2397 $this->tva_npr = $newnpr;
2399 $this->localtax1_tx = $localtax1;
2400 $this->localtax2_tx = $localtax2;
2401 $this->localtax1_type = $localtaxtype1;
2402 $this->localtax2_type = $localtaxtype2;
2405 $this->price_by_qty = $newpbq;
2409 if (!empty(array_diff_assoc($newPriceData, $lastPriceData)) || !
getDolGlobalString(
'PRODUIT_MULTIPRICES')) {
2413 $this->level = $level;
2417 $result = $this->
call_trigger(
'PRODUCT_PRICE_MODIFY', $user);
2419 $this->db->rollback();
2425 $this->db->commit();
2427 $this->db->rollback();
2428 $this->error = $this->db->lasterror();
2464 public function fetch($id =
'', $ref =
'', $ref_ext =
'', $barcode =
'', $ignore_expression = 0, $ignore_price_load = 0, $ignore_lang_load = 0)
2466 include_once DOL_DOCUMENT_ROOT.
'/core/lib/company.lib.php';
2468 global $langs, $conf;
2470 dol_syslog(get_class($this).
"::fetch id=".$id.
" ref=".$ref.
" ref_ext=".$ref_ext);
2473 if (!$id && !$ref && !$ref_ext && !$barcode) {
2474 $this->error =
'ErrorWrongParameters';
2475 dol_syslog(get_class($this).
"::fetch ".$this->error, LOG_ERR);
2479 $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,";
2480 $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,";
2481 $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,";
2482 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
2483 $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,";
2485 $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,";
2487 $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,";
2492 $separatedEntityPMP =
false;
2493 $separatedStock =
false;
2494 $visibleWarehousesEntities = $conf->entity;
2497 $checkPMPPerEntity = $this->db->query(
"SELECT pmp FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = ".((int) $id).
" AND entity = ".(
int) $conf->entity);
2498 if ($this->db->num_rows($checkPMPPerEntity)>0) {
2499 $separatedEntityPMP =
true;
2503 $separatedStock =
true;
2504 if (isset($mc->sharings[
'stock']) && !empty($mc->sharings[
'stock'])) {
2505 $visibleWarehousesEntities .=
"," . implode(
",", $mc->sharings[
'stock']);
2508 if ($separatedEntityPMP) {
2509 $sql .=
" ppe.pmp,";
2513 $sql .=
" p.datec, p.tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.batch_mask, p.fk_unit,";
2514 $sql .=
" p.fk_price_expression, p.price_autogen, p.model_pdf,";
2515 if ($separatedStock) {
2516 $sql .=
" SUM(sp.reel) as stock";
2520 $sql .=
" FROM ".$this->db->prefix().
"product as p";
2522 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int) $conf->entity);
2524 if ($separatedStock) {
2525 $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).
"))";
2529 $sql .=
" WHERE p.rowid = ".((int) $id);
2531 $sql .=
" WHERE p.entity IN (".getEntity($this->element).
")";
2533 $sql .=
" AND p.ref = '".$this->db->escape($ref).
"'";
2534 } elseif ($ref_ext) {
2535 $sql .=
" AND p.ref_ext = '".$this->db->escape($ref_ext).
"'";
2536 } elseif ($barcode) {
2537 $sql .=
" AND p.barcode = '".$this->db->escape($barcode).
"'";
2540 if ($separatedStock) {
2541 $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,";
2542 $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,";
2543 $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,";
2544 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
2545 $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,";
2547 $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,";
2549 $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,";
2551 if ($separatedEntityPMP) {
2552 $sql .=
" ppe.pmp,";
2556 $sql .=
" p.datec, p.tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.batch_mask, p.fk_unit,";
2557 $sql .=
" p.fk_price_expression, p.price_autogen, p.model_pdf";
2558 if (!$separatedStock) {
2559 $sql .=
", p.stock";
2563 $resql = $this->db->query($sql);
2565 unset($this->oldcopy);
2567 if ($this->db->num_rows($resql) > 0) {
2568 $obj = $this->db->fetch_object($resql);
2570 $this->
id = $obj->rowid;
2571 $this->
ref = $obj->ref;
2572 $this->ref_ext = $obj->ref_ext;
2573 $this->label = $obj->label;
2575 $this->url = $obj->url;
2576 $this->note_public = $obj->note_public;
2577 $this->note_private = $obj->note_private;
2578 $this->note = $obj->note_private;
2580 $this->
type = $obj->fk_product_type;
2581 $this->
status = $obj->tosell;
2582 $this->status_buy = $obj->tobuy;
2583 $this->status_batch = $obj->tobatch;
2584 $this->batch_mask = $obj->batch_mask;
2586 $this->customcode = $obj->customcode;
2587 $this->country_id = $obj->fk_country;
2588 $this->country_code =
getCountry($this->country_id, 2, $this->db);
2589 $this->state_id = $obj->fk_state;
2590 $this->lifetime = $obj->lifetime;
2591 $this->qc_frequency = $obj->qc_frequency;
2592 $this->
price = $obj->price;
2593 $this->price_ttc = $obj->price_ttc;
2594 $this->price_min = $obj->price_min;
2595 $this->price_min_ttc = $obj->price_min_ttc;
2596 $this->price_base_type = $obj->price_base_type;
2597 $this->cost_price = $obj->cost_price;
2598 $this->default_vat_code = $obj->default_vat_code;
2599 $this->tva_tx = $obj->tva_tx;
2601 $this->tva_npr = $obj->tva_npr;
2603 $this->localtax1_tx = $obj->localtax1_tx;
2604 $this->localtax2_tx = $obj->localtax2_tx;
2605 $this->localtax1_type = $obj->localtax1_type;
2606 $this->localtax2_type = $obj->localtax2_type;
2608 $this->finished = $obj->finished;
2609 $this->fk_default_bom = $obj->fk_default_bom;
2611 $this->duration = $obj->duration;
2612 $this->duration_value = $obj->duration ? (int) (substr($obj->duration, 0,
dol_strlen($obj->duration) - 1)) : 0;
2613 $this->duration_unit = $obj->duration ? substr($obj->duration, -1) :
null;
2614 $this->canvas = $obj->canvas;
2615 $this->net_measure = $obj->net_measure;
2616 $this->net_measure_units = $obj->net_measure_units;
2617 $this->weight = $obj->weight;
2618 $this->weight_units = $obj->weight_units;
2619 $this->length = $obj->length;
2620 $this->length_units = $obj->length_units;
2621 $this->width = $obj->width;
2622 $this->width_units = $obj->width_units;
2623 $this->height = $obj->height;
2624 $this->height_units = $obj->height_units;
2626 $this->surface = $obj->surface;
2627 $this->surface_units = $obj->surface_units;
2628 $this->volume = $obj->volume;
2629 $this->volume_units = $obj->volume_units;
2630 $this->barcode = $obj->barcode;
2631 $this->barcode_type = $obj->fk_barcode_type;
2633 $this->accountancy_code_buy = $obj->accountancy_code_buy;
2634 $this->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra;
2635 $this->accountancy_code_buy_export = $obj->accountancy_code_buy_export;
2636 $this->accountancy_code_sell = $obj->accountancy_code_sell;
2637 $this->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra;
2638 $this->accountancy_code_sell_export = $obj->accountancy_code_sell_export;
2640 $this->fk_default_warehouse = $obj->fk_default_warehouse;
2641 $this->fk_default_workstation = $obj->fk_default_workstation;
2642 $this->seuil_stock_alerte = $obj->seuil_stock_alerte;
2643 $this->desiredstock = $obj->desiredstock;
2644 $this->stock_reel = $obj->stock;
2645 $this->pmp = $obj->pmp;
2647 $this->date_creation = $obj->datec;
2648 $this->date_modification = $obj->tms;
2649 $this->import_key = $obj->import_key;
2650 $this->entity = $obj->entity;
2652 $this->ref_ext = $obj->ref_ext;
2653 $this->fk_price_expression = $obj->fk_price_expression;
2654 $this->fk_unit = $obj->fk_unit;
2655 $this->price_autogen = $obj->price_autogen;
2656 $this->model_pdf = $obj->model_pdf;
2658 $this->mandatory_period = $obj->mandatory_period;
2660 $this->db->free($resql);
2672 for ($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) {
2673 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
2674 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
2675 $sql .=
" FROM ".$this->db->prefix().
"product_price";
2676 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
2677 $sql .=
" AND price_level=".((int) $i);
2678 $sql .=
" AND fk_product = ".((int) $this->
id);
2679 $sql .=
" ORDER BY date_price DESC, rowid DESC";
2681 $resql = $this->db->query($sql);
2683 $result = $this->db->fetch_array($resql);
2685 $this->multiprices[$i] = $result ? $result[
"price"] :
null;
2686 $this->multiprices_ttc[$i] = $result ? $result[
"price_ttc"] :
null;
2687 $this->multiprices_min[$i] = $result ? $result[
"price_min"] :
null;
2688 $this->multiprices_min_ttc[$i] = $result ? $result[
"price_min_ttc"] :
null;
2689 $this->multiprices_base_type[$i] = $result ? $result[
"price_base_type"] :
null;
2691 $this->multiprices_tva_tx[$i] = $result ? $result[
"tva_tx"].($result ?
' ('.$result[
'default_vat_code'].
')' :
'') :
null;
2692 $this->multiprices_recuperableonly[$i] = $result ? $result[
"recuperableonly"] :
null;
2730 $this->error = $this->db->lasterror;
2734 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES') && empty($ignore_price_load)) {
2736 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY') && empty($ignore_price_load)) {
2737 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
2738 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid";
2739 $sql .=
" FROM ".$this->db->prefix().
"product_price";
2740 $sql .=
" WHERE fk_product = ".((int) $this->
id);
2741 $sql .=
" ORDER BY date_price DESC, rowid DESC";
2743 $resql = $this->db->query($sql);
2745 $result = $this->db->fetch_array($resql);
2748 $this->prices_by_qty[0] = $result[
"price_by_qty"];
2749 $this->prices_by_qty_id[0] = $result[
"rowid"];
2751 if ($this->prices_by_qty[0] == 1) {
2752 $sql =
"SELECT rowid,price, unitprice, quantity, remise_percent, remise, remise, price_base_type";
2753 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
2754 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[0]);
2755 $sql .=
" ORDER BY quantity ASC";
2756 $resultat = array();
2757 $resql = $this->db->query($sql);
2760 while ($result = $this->db->fetch_array($resql)) {
2761 $resultat[$ii] = array();
2762 $resultat[$ii][
"rowid"] = $result[
"rowid"];
2763 $resultat[$ii][
"price"] = $result[
"price"];
2764 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
2765 $resultat[$ii][
"quantity"] = $result[
"quantity"];
2766 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
2768 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
2771 $this->prices_by_qty_list[0] = $resultat;
2773 $this->error = $this->db->lasterror;
2778 $this->error = $this->db->lasterror;
2781 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') && empty($ignore_price_load)) {
2782 for ($i = 1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++) {
2783 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
2784 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
2785 $sql .=
" FROM ".$this->db->prefix().
"product_price";
2786 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
2787 $sql .=
" AND price_level=".((int) $i);
2788 $sql .=
" AND fk_product = ".((int) $this->
id);
2789 $sql .=
" ORDER BY date_price DESC, rowid DESC";
2791 $resql = $this->db->query($sql);
2793 $result = $this->db->fetch_array($resql);
2795 $this->multiprices[$i] = (!empty($result[
"price"]) ? $result[
"price"] : 0);
2796 $this->multiprices_ttc[$i] = (!empty($result[
"price_ttc"]) ? $result[
"price_ttc"] : 0);
2797 $this->multiprices_min[$i] = (!empty($result[
"price_min"]) ? $result[
"price_min"] : 0);
2798 $this->multiprices_min_ttc[$i] = (!empty($result[
"price_min_ttc"]) ? $result[
"price_min_ttc"] : 0);
2799 $this->multiprices_base_type[$i] = (!empty($result[
"price_base_type"]) ? $result[
"price_base_type"] :
'');
2801 $this->multiprices_tva_tx[$i] = (!empty($result[
"tva_tx"]) ? $result[
"tva_tx"] : 0);
2802 $this->multiprices_recuperableonly[$i] = (!empty($result[
"recuperableonly"]) ? $result[
"recuperableonly"] : 0);
2805 $this->prices_by_qty[$i] = (!empty($result[
"price_by_qty"]) ? $result[
"price_by_qty"] : 0);
2806 $this->prices_by_qty_id[$i] = (!empty($result[
"rowid"]) ? $result[
"rowid"] : 0);
2808 if ($this->prices_by_qty[$i] == 1) {
2809 $sql =
"SELECT rowid, price, unitprice, quantity, remise_percent, remise, price_base_type";
2810 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
2811 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[$i]);
2812 $sql .=
" ORDER BY quantity ASC";
2813 $resultat = array();
2814 $resql = $this->db->query($sql);
2817 while ($result = $this->db->fetch_array($resql)) {
2818 $resultat[$ii] = array();
2819 $resultat[$ii][
"rowid"] = $result[
"rowid"];
2820 $resultat[$ii][
"price"] = $result[
"price"];
2821 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
2822 $resultat[$ii][
"quantity"] = $result[
"quantity"];
2823 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
2824 $resultat[$ii][
"remise"] = $result[
"remise"];
2825 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
2828 $this->prices_by_qty_list[$i] = $resultat;
2830 $this->error = $this->db->lasterror;
2835 $this->error = $this->db->lasterror;
2841 if (isModEnabled(
'dynamicprices') && !empty($this->fk_price_expression) && empty($ignore_expression)) {
2842 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2844 $price_result = $priceparser->parseProduct($this);
2845 if ($price_result >= 0) {
2846 $this->
price = $price_result;
2848 $this->price_ttc =
price2num($this->
price) * (1 + ($this->tva_tx / 100));
2849 $this->price_ttc =
price2num($this->price_ttc,
'MU');
2855 $this->stock_warehouse = array();
2862 $this->error = $this->db->lasterror();
3137 global $conf, $user, $hookmanager, $action;
3139 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3140 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3141 $sql .=
" FROM ".$this->db->prefix().
"commandedet as cd";
3142 $sql .=
", ".$this->db->prefix().
"commande as c";
3143 $sql .=
", ".$this->db->prefix().
"societe as s";
3144 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid && !$forVirtualStock) {
3145 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3147 $sql .=
" WHERE c.rowid = cd.fk_commande";
3148 $sql .=
" AND c.fk_soc = s.rowid";
3149 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'commande').
")";
3150 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3151 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid && !$forVirtualStock) {
3152 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3155 $sql .=
" AND c.fk_soc = ".((int) $socid);
3157 if ($filtrestatut !=
'') {
3158 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3161 $result = $this->db->query($sql);
3163 $obj = $this->db->fetch_object($result);
3164 $this->stats_commande[
'customers'] = $obj->nb_customers;
3165 $this->stats_commande[
'nb'] = $obj->nb;
3166 $this->stats_commande[
'rows'] = $obj->nb_rows;
3167 $this->stats_commande[
'qty'] = $obj->qty ? $obj->qty : 0;
3172 if (is_array($TFather) && !empty($TFather)) {
3173 foreach ($TFather as &$fatherData) {
3174 $pFather =
new Product($this->db);
3175 $pFather->id = $fatherData[
'id'];
3176 $qtyCoef = $fatherData[
'qty'];
3178 if ($fatherData[
'incdec']) {
3179 $pFather->load_stats_commande($socid, $filtrestatut);
3181 $this->stats_commande[
'customers'] += $pFather->stats_commande[
'customers'];
3182 $this->stats_commande[
'nb'] += $pFather->stats_commande[
'nb'];
3183 $this->stats_commande[
'rows'] += $pFather->stats_commande[
'rows'];
3184 $this->stats_commande[
'qty'] += $pFather->stats_commande[
'qty'] * $qtyCoef;
3196 $sql =
"SELECT SUM(".$this->db->ifsql(
'f.type=2', -1, 1).
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3197 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3198 $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'))";
3199 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3200 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3202 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3203 $resql = $this->db->query($sql);
3205 if ($this->db->num_rows($resql) > 0) {
3206 $obj = $this->db->fetch_object($resql);
3207 $adeduire += $obj->count;
3211 $this->stats_commande[
'qty'] -= $adeduire;
3214 include_once DOL_DOCUMENT_ROOT.
'/compta/facture/class/facture.class.php';
3218 $sql =
"SELECT sum(".$this->db->ifsql(
'f.type=2', -1, 1).
" * fd.qty) as count FROM ".MAIN_DB_PREFIX.
"facturedet as fd ";
3219 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"facture as f ON fd.fk_facture = f.rowid";
3220 $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'))";
3221 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"commande as c ON el.fk_source = c.rowid";
3222 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3224 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3225 $resql = $this->db->query($sql);
3227 if ($this->db->num_rows($resql) > 0) {
3228 $obj = $this->db->fetch_object($resql);
3229 $adeduire += $obj->count;
3232 $this->error = $this->db->error();
3236 $this->stats_commande[
'qty'] -= $adeduire;
3240 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3241 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerOrder', $parameters, $this, $action);
3243 $this->stats_commande = $hookmanager->resArray[
'stats_commande'];
3247 $this->error = $this->db->error();
3473 global $conf, $user, $hookmanager, $action;
3475 $serviceStockIsEnabled = isModEnabled(
"service") &&
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES');
3477 $sql =
"SELECT COUNT(DISTINCT m.fk_soc) as nb_customers, COUNT(DISTINCT m.rowid) as nb,";
3478 $sql .=
" COUNT(mp.rowid) as nb_rows, SUM(mp.qty) as qty, role";
3479 $sql .=
" FROM ".$this->db->prefix().
"mrp_production as mp";
3480 $sql .=
", ".$this->db->prefix().
"mrp_mo as m";
3481 $sql .=
" LEFT JOIN ".$this->db->prefix().
"societe as s ON s.rowid = m.fk_soc";
3482 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid && !$forVirtualStock) {
3483 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3485 $sql .=
" WHERE m.rowid = mp.fk_mo";
3486 $sql .=
" AND m.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'mrp').
")";
3487 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3488 $sql .=
" AND (mp.disable_stock_change IN (0) OR mp.disable_stock_change IS NULL)";
3489 if (!$user->hasRight(
'societe',
'client',
'voir') && !$socid && !$forVirtualStock) {
3490 $sql .=
" AND m.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3493 $sql .=
" AND m.fk_soc = ".((int) $socid);
3495 if ($filtrestatut !=
'') {
3496 $sql .=
" AND m.status IN (".$this->db->sanitize($filtrestatut).
")";
3498 if (!empty($dateofvirtualstock)) {
3499 $sql .=
" AND m.date_valid <= '".$this->db->idate($dateofvirtualstock).
"'";
3501 if (!$serviceStockIsEnabled) {
3502 $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))";
3504 $sql .=
" GROUP BY role";
3506 $this->stats_mrptoconsume[
'customers'] = 0;
3507 $this->stats_mrptoconsume[
'nb'] = 0;
3508 $this->stats_mrptoconsume[
'rows'] = 0;
3509 $this->stats_mrptoconsume[
'qty'] = 0;
3510 $this->stats_mrptoproduce[
'customers'] = 0;
3511 $this->stats_mrptoproduce[
'nb'] = 0;
3512 $this->stats_mrptoproduce[
'rows'] = 0;
3513 $this->stats_mrptoproduce[
'qty'] = 0;
3515 $result = $this->db->query($sql);
3517 while ($obj = $this->db->fetch_object($result)) {
3518 if ($obj->role ==
'toconsume') {
3519 $this->stats_mrptoconsume[
'customers'] += $obj->nb_customers;
3520 $this->stats_mrptoconsume[
'nb'] += $obj->nb;
3521 $this->stats_mrptoconsume[
'rows'] += $obj->nb_rows;
3522 $this->stats_mrptoconsume[
'qty'] += ($obj->qty ? $obj->qty : 0);
3524 if ($obj->role ==
'consumed') {
3528 $this->stats_mrptoconsume[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3530 if ($obj->role ==
'toproduce') {
3531 $this->stats_mrptoproduce[
'customers'] += $obj->nb_customers;
3532 $this->stats_mrptoproduce[
'nb'] += $obj->nb;
3533 $this->stats_mrptoproduce[
'rows'] += $obj->nb_rows;
3534 $this->stats_mrptoproduce[
'qty'] += ($obj->qty ? $obj->qty : 0);
3536 if ($obj->role ==
'produced') {
3540 $this->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3545 if ($this->stats_mrptoconsume[
'qty'] < 0) {
3546 $this->stats_mrptoconsume[
'qty'] = 0;
3548 if ($this->stats_mrptoproduce[
'qty'] < 0) {
3549 $this->stats_mrptoproduce[
'qty'] = 0;
3552 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3553 $reshook = $hookmanager->executeHooks(
'loadStatsInProduction', $parameters, $this, $action);
3555 $this->stats_mrptoproduce = $hookmanager->resArray[
'stats_mrptoproduce'];
3560 $this->error = $this->db->error();
5178 global $conf, $langs;
5180 $langs->loadLangs(array(
'products',
'other'));
5183 $nofetch = !empty($params[
'nofetch']);
5186 return [
'optimize' => $langs->trans(
"ShowProduct")];
5189 if (!empty($this->entity)) {
5190 $tmpphoto = $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 80, 0, 0, 0, 0, 1);
5191 if ($this->nbphoto > 0) {
5192 $datas[
'photo'] =
'<div class="photointooltip floatright">'.
"\n" . $tmpphoto .
'</div>';
5197 $datas[
'picto'] =
img_picto(
'',
'product').
' <u class="paddingrightonly">'.$langs->trans(
"Product").
'</u>';
5199 $datas[
'picto']=
img_picto(
'',
'service').
' <u class="paddingrightonly">'.$langs->trans(
"Service").
'</u>';
5201 if (isset($this->
status) && isset($this->status_buy)) {
5202 $datas[
'status']=
' '.$this->getLibStatut(5, 0) .
' '.$this->getLibStatut(5, 1);
5205 if (!empty($this->
ref)) {
5206 $datas[
'ref']=
'<br><b>'.$langs->trans(
'ProductRef').
':</b> '.$this->ref;
5208 if (!empty($this->label)) {
5209 $datas[
'label']=
'<br><b>'.$langs->trans(
'ProductLabel').
':</b> '.$this->label;
5212 $datas[
'description']=
'<br><b>'.$langs->trans(
'ProductDescription').
':</b> '.dolGetFirstLineofText($this->
description, 5);
5215 if (isModEnabled(
'productbatch')) {
5216 $langs->load(
"productbatch");
5217 $datas[
'batchstatus']=
"<br><b>".$langs->trans(
"ManageLotSerial").
'</b>: '.$this->
getLibStatut(0, 2);
5220 if (isModEnabled(
'barcode')) {
5221 $datas[
'barcode']=
'<br><b>'.$langs->trans(
'BarCode').
':</b> '.$this->barcode;
5225 if ($this->weight) {
5226 $datas[
'weight']=
"<br><b>".$langs->trans(
"Weight").
'</b>: '.$this->weight.
' '.
measuringUnitString(0,
"weight", $this->weight_units);
5229 if ($this->length) {
5230 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Length").
'</b>: '.$this->length.
' '.
measuringUnitString(0,
'size', $this->length_units);
5233 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Width").
'</b>: '.$this->width.
' '.
measuringUnitString(0,
'size', $this->width_units);
5235 if ($this->height) {
5236 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Height").
'</b>: '.$this->height.
' '.
measuringUnitString(0,
'size', $this->height_units);
5239 $datas[
'size']=
"<br>".$labelsize;
5242 $labelsurfacevolume =
"";
5243 if ($this->surface) {
5244 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Surface").
'</b>: '.$this->surface.
' '.
measuringUnitString(0,
'surface', $this->surface_units);
5246 if ($this->volume) {
5247 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Volume").
'</b>: '.$this->volume.
' '.
measuringUnitString(0,
'volume', $this->volume_units);
5249 if ($labelsurfacevolume) {
5250 $datas[
'surface']=
"<br>" . $labelsurfacevolume;
5253 if (!empty($this->pmp) && $this->pmp) {
5254 $datas[
'pmp'] =
"<br><b>".$langs->trans(
"PMPValue").
'</b>: '.
price($this->pmp, 0,
'', 1, -1, -1, $conf->currency);
5257 if (isModEnabled(
'accounting')) {
5258 if ($this->
status && isset($this->accountancy_code_sell)) {
5259 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5260 $selllabel =
'<br>';
5261 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellCode').
':</b> '.
length_accountg($this->accountancy_code_sell);
5262 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellIntraCode').
':</b> '.
length_accountg($this->accountancy_code_sell_intra);
5263 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellExportCode').
':</b> '.
length_accountg($this->accountancy_code_sell_export);
5264 $datas[
'accountancysell'] = $selllabel;
5266 if ($this->status_buy && isset($this->accountancy_code_buy)) {
5267 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5269 if (empty($this->
status)) {
5270 $buylabel .=
'<br>';
5272 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyCode').
':</b> '.
length_accountg($this->accountancy_code_buy);
5273 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyIntraCode').
':</b> '.
length_accountg($this->accountancy_code_buy_intra);
5274 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyExportCode').
':</b> '.
length_accountg($this->accountancy_code_buy_export);
5275 $datas[
'accountancybuy'] = $buylabel;
5279 if (isModEnabled(
'categorie') && !$nofetch) {
5280 require_once DOL_DOCUMENT_ROOT .
'/categories/class/categorie.class.php';
5281 $form =
new Form($this->db);
5282 $datas[
'categories'] =
'<br>' . $form->showCategories($this->
id, Categorie::TYPE_PRODUCT, 1);
5455 global $conf, $langs;
5457 $labelStatus = $labelStatusShort =
'';
5459 $langs->load(
'products');
5460 if (isModEnabled(
'productbatch')) {
5461 $langs->load(
"productbatch");
5467 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial')));
5468 return dolGetStatus($label);
5470 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort')));
5471 return dolGetStatus($label);
5475 return dolGetStatus($langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch'),
'',
'', empty($status) ?
'status5' :
'status4', 3,
'dot');
5481 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'));
5485 $statuttrans = empty($status) ?
'status5' :
'status4';
5490 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSellShort');
5491 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSell');
5492 } elseif ($type == 1) {
5493 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuyShort');
5494 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuy');
5495 } elseif ($type == 2) {
5496 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch');
5497 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort');
5499 } elseif ($status == 1) {
5502 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSellShort');
5503 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSell');
5504 } elseif ($type == 1) {
5505 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBuyShort');
5506 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBuy');
5507 } elseif ($type == 2) {
5508 $labelStatus = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial'));
5509 $labelStatusShort = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort'));
5511 } elseif ($type == 2 && $status == 2) {
5512 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSerial');
5513 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort');
5517 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'),
'',
'',
'status0', 0);
5519 return dolGetStatus($labelStatus, $labelStatusShort,
'', $statuttrans, $mode);
5769 global $conf, $hookmanager, $action;
5771 $stock_commande_client = 0;
5772 $stock_commande_fournisseur = 0;
5773 $stock_sending_client = 0;
5774 $stock_reception_fournisseur = 0;
5775 $stock_inproduction = 0;
5779 if (isModEnabled(
'commande')) {
5784 $stock_commande_client = $this->stats_commande[
'qty'];
5786 if (isModEnabled(
"expedition")) {
5787 require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expedition.class.php';
5788 $filterShipmentStatus =
'';
5798 $stock_sending_client = $this->stats_expedition[
'qty'];
5800 if (isModEnabled(
"supplier_order")) {
5801 $filterStatus = !
getDolGlobalString(
'SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK') ?
'3,4' : $conf->global->SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK;
5802 if (isset($includedraftpoforvirtual)) {
5803 $filterStatus =
'0,1,2,'.$filterStatus;
5809 $stock_commande_fournisseur = $this->stats_commande_fournisseur[
'qty'];
5811 if ((isModEnabled(
"supplier_order") || isModEnabled(
"supplier_invoice")) && empty($conf->reception->enabled)) {
5813 $filterStatus =
'4';
5814 if (isset($includedraftpoforvirtual)) {
5815 $filterStatus =
'0,'.$filterStatus;
5821 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
5823 if ((isModEnabled(
"supplier_order") || isModEnabled(
"supplier_invoice")) && isModEnabled(
"reception")) {
5825 $filterStatus =
'4';
5826 if (isset($includedraftpoforvirtual)) {
5827 $filterStatus =
'0,'.$filterStatus;
5833 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
5835 if (isModEnabled(
'mrp')) {
5840 $stock_inproduction = $this->stats_mrptoproduce[
'qty'] - $this->stats_mrptoconsume[
'qty'];
5843 $this->stock_theorique = $this->stock_reel + $stock_inproduction;
5847 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
5849 $this->stock_theorique += 0;
5851 $this->stock_theorique -= $stock_commande_client;
5855 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
5857 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
5859 $this->stock_theorique -= $stock_reception_fournisseur;
5861 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
5864 $parameters = array(
'id'=>$this->
id,
'includedraftpoforvirtual' => $includedraftpoforvirtual);
5866 $reshook = $hookmanager->executeHooks(
'loadvirtualstock', $parameters, $this, $action);
5868 $this->stock_theorique = $hookmanager->resArray[
'stock_theorique'];
5869 } elseif ($reshook == 0 && isset($hookmanager->resArray[
'stock_stats_hook'])) {
5870 $this->stock_theorique += $hookmanager->resArray[
'stock_stats_hook'];