916 public function create($user, $notrigger = 0)
918 global
$conf, $langs;
924 $this->
ref = trim($this->
ref);
928 $this->label = trim($this->label);
929 $this->price_ttc = (float)
price2num($this->price_ttc);
931 $this->price_min_ttc = (float)
price2num($this->price_min_ttc);
932 $this->price_min = (float)
price2num($this->price_min);
933 $this->price_label = trim($this->price_label);
934 if (empty($this->tva_tx)) {
937 if (empty($this->tva_npr)) {
941 if (empty($this->localtax1_tx)) {
942 $this->localtax1_tx = 0;
944 if (empty($this->localtax2_tx)) {
945 $this->localtax2_tx = 0;
947 if (empty($this->localtax1_type)) {
948 $this->localtax1_type =
'0';
950 if (empty($this->localtax2_type)) {
951 $this->localtax2_type =
'0';
953 if (empty($this->
price)) {
956 if (empty($this->price_min)) {
957 $this->price_min = 0;
960 if (empty($this->price_by_qty)) {
961 $this->price_by_qty = 0;
964 if (empty($this->
status)) {
967 if (empty($this->status_buy)) {
968 $this->status_buy = 0;
977 if ($this->price_base_type ==
'TTC' && $this->price_ttc > 0) {
978 $price_ttc =
price2num($this->price_ttc,
'MU');
979 $price_ht =
price2num($this->price_ttc / (1 + ($this->tva_tx / 100)),
'MU');
983 if ($this->price_base_type !=
'TTC' && $this->
price > 0) {
985 $price_ttc =
price2num($this->
price * (1 + ($this->tva_tx / 100)),
'MU');
989 if (($this->price_min_ttc > 0) && ($this->price_base_type ==
'TTC')) {
990 $price_min_ttc =
price2num($this->price_min_ttc,
'MU');
991 $price_min_ht =
price2num($this->price_min_ttc / (1 + ($this->tva_tx / 100)),
'MU');
995 if (($this->price_min > 0) && ($this->price_base_type !=
'TTC')) {
996 $price_min_ht =
price2num($this->price_min,
'MU');
997 $price_min_ttc =
price2num($this->price_min * (1 + ($this->tva_tx / 100)),
'MU');
1000 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
1001 $this->accountancy_code_buy_intra = trim($this->accountancy_code_buy_intra);
1002 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
1003 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
1004 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
1005 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
1008 $this->barcode = trim($this->barcode);
1009 $this->mandatory_period = empty($this->mandatory_period) ? 0 : $this->mandatory_period;
1011 if (empty($this->label)) {
1012 $this->error =
'ErrorMandatoryParametersNotProvided';
1016 if (empty($this->
ref) || $this->
ref ==
'auto') {
1018 $module =
getDolGlobalString(
'PRODUCT_CODEPRODUCT_ADDON',
'mod_codeproduct_leopard');
1019 if ($module !=
'mod_codeproduct_leopard') {
1020 if (substr($module, 0, 16) ==
'mod_codeproduct_' && substr($module, -3) ==
'php') {
1021 $module = substr($module, 0,
dol_strlen($module) - 4);
1024 $modCodeProduct =
new $module();
1025 '@phan-var-force ModeleProductCode $modCodeProduct';
1026 if (!empty($modCodeProduct->code_auto)) {
1027 $this->
ref = $modCodeProduct->getNextValue($this, $this->
type);
1029 unset($modCodeProduct);
1032 if (empty($this->
ref)) {
1033 $this->error =
'ProductModuleNotSetupForAutoRef';
1038 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);
1042 if (empty($this->date_creation)) {
1043 $this->date_creation = $now;
1049 if ($this->barcode ==
'-1' || $this->barcode ==
'auto') {
1050 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1055 $result = $this->
verify();
1058 $sql =
"SELECT count(*) as nb";
1059 $sql .=
" FROM ".$this->db->prefix().
"product";
1060 $sql .=
" WHERE entity IN (".getEntity(
'product').
")";
1061 $sql .=
" AND ref = '".$this->db->escape($this->
ref).
"'";
1063 $result = $this->db->query($sql);
1065 $obj = $this->db->fetch_object($result);
1066 if ($obj->nb == 0) {
1068 $sql =
"INSERT INTO ".$this->db->prefix().
"product (";
1072 $sql .=
", ref_ext";
1073 $sql .=
", price_min";
1074 $sql .=
", price_min_ttc";
1076 $sql .=
", fk_user_author";
1077 $sql .=
", fk_product_type";
1079 $sql .=
", price_ttc";
1080 $sql .=
", price_base_type";
1081 $sql .=
", price_label";
1085 $sql .=
", accountancy_code_buy";
1086 $sql .=
", accountancy_code_buy_intra";
1087 $sql .=
", accountancy_code_buy_export";
1088 $sql .=
", accountancy_code_sell";
1089 $sql .=
", accountancy_code_sell_intra";
1090 $sql .=
", accountancy_code_sell_export";
1093 $sql .=
", finished";
1094 $sql .=
", tobatch";
1095 $sql .=
", sell_or_eat_by_mandatory";
1096 $sql .=
", batch_mask";
1097 $sql .=
", fk_unit";
1098 $sql .=
", mandatory_period";
1099 $sql .=
") VALUES (";
1100 $sql .=
"'".$this->db->idate($this->date_creation).
"'";
1101 $sql .=
", ".(!empty($this->entity) ? (int) $this->entity : (int)
$conf->entity);
1102 $sql .=
", '".$this->db->escape($this->
ref).
"'";
1103 $sql .=
", ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1104 $sql .=
", ".price2num($price_min_ht);
1105 $sql .=
", ".price2num($price_min_ttc);
1106 $sql .=
", ".(!empty($this->label) ?
"'".$this->db->escape($this->label).
"'" :
"null");
1107 $sql .=
", ".((int) $user->id);
1108 $sql .=
", ".((int) $this->
type);
1109 $sql .=
", ".price2num($price_ht,
'MT');
1110 $sql .=
", ".price2num($price_ttc,
'MT');
1111 $sql .=
", '".$this->db->escape($this->price_base_type).
"'";
1112 $sql .=
", ".(!empty($this->price_label) ?
"'".$this->db->escape($this->price_label).
"'" :
"null");
1113 $sql .=
", ".((int) $this->
status);
1114 $sql .=
", ".((int) $this->status_buy);
1116 $sql .=
", '".$this->db->escape($this->accountancy_code_buy).
"'";
1117 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_intra).
"'";
1118 $sql .=
", '".$this->db->escape($this->accountancy_code_buy_export).
"'";
1119 $sql .=
", '".$this->db->escape($this->accountancy_code_sell).
"'";
1120 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_intra).
"'";
1121 $sql .=
", '".$this->db->escape($this->accountancy_code_sell_export).
"'";
1123 $sql .=
", '".$this->db->escape($this->canvas).
"'";
1124 $sql .=
", ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
'NULL' : (int) $this->finished);
1125 $sql .=
", ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : ((int) $this->status_batch));
1126 $sql .=
", ".((empty($this->sell_or_eat_by_mandatory) || $this->sell_or_eat_by_mandatory < 0) ? 0 : ((int) $this->sell_or_eat_by_mandatory));
1127 $sql .=
", '".$this->db->escape($this->batch_mask).
"'";
1128 $sql .=
", ".($this->fk_unit > 0 ? ((int) $this->fk_unit) :
'NULL');
1129 $sql .=
", '".$this->db->escape($this->mandatory_period).
"'";
1132 dol_syslog(get_class($this).
"::Create", LOG_DEBUG);
1134 $result = $this->db->query($sql);
1136 $id = $this->db->last_insert_id($this->db->prefix().
"product");
1140 $this->
price = $price_ht;
1141 $this->price_ttc = $price_ttc;
1142 $this->price_min = $price_min_ht;
1143 $this->price_min_ttc = $price_min_ttc;
1147 if ($this->
update($id, $user, 1,
'add') <= 0) {
1152 $this->error = $this->db->lasterror();
1157 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " .((int) $this->id) .
" AND entity = " . ((
int)
$conf->entity));
1159 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1160 $sql .=
" fk_product";
1162 $sql .=
", accountancy_code_buy";
1163 $sql .=
", accountancy_code_buy_intra";
1164 $sql .=
", accountancy_code_buy_export";
1165 $sql .=
", accountancy_code_sell";
1166 $sql .=
", accountancy_code_sell_intra";
1167 $sql .=
", accountancy_code_sell_export";
1168 $sql .=
") VALUES (";
1170 $sql .=
", " . ((int)
$conf->entity);
1171 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1172 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1173 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1174 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1175 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1176 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1178 $result = $this->db->query($sql);
1181 $this->error =
'ErrorFailedToInsertAccountancyForEntity';
1186 $this->error =
'ErrorFailedToGetInsertedId';
1190 $this->error = $this->db->lasterror();
1194 $langs->load(
"products");
1196 $this->error =
"ErrorProductAlreadyExists";
1197 dol_syslog(get_class($this).
"::Create fails, ref ".$this->
ref.
" already exists");
1201 $this->error = $this->db->lasterror();
1204 if (!$error && !$notrigger) {
1206 $result = $this->
call_trigger(
'PRODUCT_CREATE', $user);
1214 $this->db->commit();
1217 $this->db->rollback();
1221 $this->db->rollback();
1222 dol_syslog(get_class($this).
"::Create fails verify ".implode(
',', $this->errors), LOG_WARNING);
1324 public function update($id, $user, $notrigger = 0, $action =
'update', $updatetype =
false)
1326 global $langs,
$conf, $hookmanager;
1331 if (!$this->label) {
1332 $this->label =
'MISSING LABEL';
1337 $this->
ref = trim($this->
ref);
1341 $this->label = trim($this->label);
1343 $this->note_private = (isset($this->note_private) ? trim($this->note_private) :
null);
1344 $this->note_public = (isset($this->note_public) ? trim($this->note_public) :
null);
1345 $this->net_measure =
price2num($this->net_measure);
1346 $this->net_measure_units = (empty($this->net_measure_units) ?
'' : trim((
string) $this->net_measure_units));
1347 $this->weight =
price2num($this->weight);
1348 $this->weight_units = (empty($this->weight_units) ?
'' : trim((
string) $this->weight_units));
1349 $this->length =
price2num($this->length);
1350 $this->length_units = (empty($this->length_units) ?
'' : trim((
string) $this->length_units));
1352 $this->width_units = (empty($this->width_units) ?
'' : trim((
string) $this->width_units));
1353 $this->height =
price2num($this->height);
1354 $this->height_units = (empty($this->height_units) ?
'' : trim((
string) $this->height_units));
1355 $this->surface =
price2num($this->surface);
1356 $this->surface_units = (empty($this->surface_units) ?
'' : trim((
string) $this->surface_units));
1357 $this->volume =
price2num($this->volume);
1358 $this->volume_units = (empty($this->volume_units) ?
'' : trim((
string) $this->volume_units));
1361 if (is_numeric($this->length_units)) {
1362 $this->width_units = $this->length_units;
1364 if (is_numeric($this->length_units)) {
1365 $this->height_units = $this->length_units;
1369 if (empty($this->surface) && !empty($this->length) && !empty($this->width) && $this->length_units == $this->width_units) {
1370 $this->surface = (float) $this->length * (
float) $this->width;
1373 if (empty($this->volume) && !empty($this->surface) && !empty($this->height) && $this->length_units == $this->height_units) {
1374 $this->volume = $this->surface * (float) $this->height;
1378 if (empty($this->tva_tx)) {
1381 if (empty($this->tva_npr)) {
1384 if (empty($this->localtax1_tx)) {
1385 $this->localtax1_tx = 0;
1387 if (empty($this->localtax2_tx)) {
1388 $this->localtax2_tx = 0;
1390 if (empty($this->localtax1_type)) {
1391 $this->localtax1_type =
'0';
1393 if (empty($this->localtax2_type)) {
1394 $this->localtax2_type =
'0';
1396 if (empty($this->
status)) {
1399 if (empty($this->status_buy)) {
1400 $this->status_buy = 0;
1403 if (empty($this->country_id)) {
1404 $this->country_id = 0;
1407 if (empty($this->state_id)) {
1408 $this->state_id = 0;
1412 $this->barcode = (empty($this->barcode) ?
'' : trim($this->barcode));
1414 $this->accountancy_code_buy = trim($this->accountancy_code_buy);
1415 $this->accountancy_code_buy_intra = (!empty($this->accountancy_code_buy_intra) ? trim($this->accountancy_code_buy_intra) :
'');
1416 $this->accountancy_code_buy_export = trim($this->accountancy_code_buy_export);
1417 $this->accountancy_code_sell = trim($this->accountancy_code_sell);
1418 $this->accountancy_code_sell_intra = trim($this->accountancy_code_sell_intra);
1419 $this->accountancy_code_sell_export = trim($this->accountancy_code_sell_export);
1426 if ($action !=
'add') {
1427 $result = $this->
verify();
1435 if (is_null($this->oldcopy) || (is_object($this->oldcopy) && $this->oldcopy->isEmpty())) {
1440 if ($this->
hasbatch() && !$this->oldcopy->hasbatch()) {
1442 $valueforundefinedlot =
'000000';
1447 dol_syslog(
"Flag batch of product id=".$this->
id.
" is set to ON, so we will create missing records into product_batch");
1450 foreach ($this->stock_warehouse as $idW => $ObjW) {
1452 foreach ($ObjW->detail_batch as $detail) {
1453 if ($detail->batch == $valueforundefinedlot || $detail->batch ==
'Undefined') {
1455 $sqlclean =
"DELETE FROM ".$this->db->prefix().
"product_batch WHERE batch in('Undefined', '".$this->db->escape($valueforundefinedlot).
"') AND fk_product_stock = ".((int) $ObjW->id);
1456 $result = $this->db->query($sqlclean);
1464 $qty_batch += $detail->qty;
1468 if ($ObjW->real != $qty_batch) {
1470 $ObjBatch->batch = $valueforundefinedlot;
1471 $ObjBatch->qty = ($ObjW->real - $qty_batch);
1472 $ObjBatch->fk_product_stock = (int) $ObjW->id;
1474 if ($ObjBatch->create($user, 1) < 0) {
1476 $this->errors = $ObjBatch->errors;
1481 if ($ObjLot->fetch(0, $this->id, $valueforundefinedlot) == 0) {
1482 $ObjLot->fk_product = $this->id;
1483 $ObjLot->entity = $this->entity;
1484 $ObjLot->fk_user_creat = $user->id;
1485 $ObjLot->batch = $valueforundefinedlot;
1486 if ($ObjLot->create($user,
true) < 0) {
1488 $this->errors = $ObjLot->errors;
1497 if ($this->barcode == -1) {
1498 $this->barcode = $this->
get_barcode($this, $this->barcode_type_code);
1501 $sql =
"UPDATE ".$this->db->prefix().
"product";
1502 $sql .=
" SET label = '".$this->db->escape($this->label).
"'";
1505 $sql .=
", fk_product_type = ".((int) $this->
type);
1508 $sql .=
", ref = '".$this->db->escape($this->
ref).
"'";
1509 $sql .=
", ref_ext = ".(!empty($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
1510 $sql .=
", default_vat_code = ".($this->default_vat_code ?
"'".$this->db->escape($this->default_vat_code).
"'" :
"null");
1511 $sql .=
", tva_tx = ".((float) $this->tva_tx);
1512 $sql .=
", recuperableonly = ".((int) $this->tva_npr);
1513 $sql .=
", localtax1_tx = ".((float) $this->localtax1_tx);
1514 $sql .=
", localtax2_tx = ".((float) $this->localtax2_tx);
1515 $sql .=
", localtax1_type = ".($this->localtax1_type !=
'' ?
"'".$this->db->escape($this->localtax1_type).
"'" :
"'0'");
1516 $sql .=
", localtax2_type = ".($this->localtax2_type !=
'' ?
"'".$this->db->escape($this->localtax2_type).
"'" :
"'0'");
1518 $sql .=
", barcode = ".(empty($this->barcode) ?
"null" :
"'".$this->db->escape($this->barcode).
"'");
1519 $sql .=
", fk_barcode_type = ".(empty($this->barcode_type) ?
"null" : $this->db->escape($this->barcode_type));
1521 $sql .=
", tosell = ".(int) $this->
status;
1522 $sql .=
", tobuy = ".(int) $this->status_buy;
1523 $sql .=
", tobatch = ".((empty($this->status_batch) || $this->status_batch < 0) ?
'0' : (int) $this->status_batch);
1524 $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);
1525 $sql .=
", batch_mask = '".$this->db->escape($this->batch_mask).
"'";
1527 $sql .=
", finished = ".((!isset($this->finished) || $this->finished < 0 || $this->finished ==
'') ?
"null" : (int) $this->finished);
1528 $sql .=
", fk_default_bom = ".((!isset($this->fk_default_bom) || $this->fk_default_bom < 0 || $this->fk_default_bom ==
'') ?
"null" : (int) $this->fk_default_bom);
1529 $sql .=
", net_measure = ".($this->net_measure !=
'' ?
"'".$this->db->escape($this->net_measure).
"'" :
'null');
1530 $sql .=
", net_measure_units = ".($this->net_measure_units !=
'' ?
"'".$this->db->escape($this->net_measure_units).
"'" :
'null');
1531 $sql .=
", weight = ".($this->weight !=
'' ?
"'".$this->db->escape($this->weight).
"'" :
'null');
1532 $sql .=
", weight_units = ".($this->weight_units !=
'' ?
"'".$this->db->escape($this->weight_units).
"'" :
'null');
1533 $sql .=
", length = ".($this->length !=
'' ?
"'".$this->db->escape($this->length).
"'" :
'null');
1534 $sql .=
", length_units = ".($this->length_units !=
'' ?
"'".$this->db->escape($this->length_units).
"'" :
'null');
1535 $sql .=
", width= ".($this->width !=
'' ?
"'".$this->db->escape($this->width).
"'" :
'null');
1536 $sql .=
", width_units = ".($this->width_units !=
'' ?
"'".$this->db->escape($this->width_units).
"'" :
'null');
1537 $sql .=
", height = ".($this->height !=
'' ?
"'".$this->db->escape($this->height).
"'" :
'null');
1538 $sql .=
", height_units = ".($this->height_units !=
'' ?
"'".$this->db->escape($this->height_units).
"'" :
'null');
1539 $sql .=
", surface = ".($this->surface !=
'' ?
"'".$this->db->escape($this->surface).
"'" :
'null');
1540 $sql .=
", surface_units = ".($this->surface_units !=
'' ?
"'".$this->db->escape($this->surface_units).
"'" :
'null');
1541 $sql .=
", volume = ".($this->volume !=
'' ?
"'".$this->db->escape($this->volume).
"'" :
'null');
1542 $sql .=
", volume_units = ".($this->volume_units !=
'' ?
"'".$this->db->escape($this->volume_units).
"'" :
'null');
1543 $sql .=
", fk_default_warehouse = ".($this->fk_default_warehouse > 0 ? ((int) $this->fk_default_warehouse) :
'null');
1544 $sql .=
", fk_default_workstation = ".($this->fk_default_workstation > 0 ? ((int) $this->fk_default_workstation) :
'null');
1545 $sql .=
", seuil_stock_alerte = ".((isset($this->seuil_stock_alerte) && is_numeric($this->seuil_stock_alerte)) ? (
float) $this->seuil_stock_alerte :
'null');
1546 $sql .=
", description = '".$this->db->escape($this->
description).
"'";
1547 $sql .=
", url = ".($this->url ?
"'".$this->db->escape($this->url).
"'" :
'null');
1548 $sql .=
", customcode = '".$this->db->escape($this->customcode).
"'";
1549 $sql .=
", fk_country = ".($this->country_id > 0 ? (int) $this->country_id :
'null');
1550 $sql .=
", fk_state = ".($this->state_id > 0 ? (int) $this->state_id :
'null');
1551 $sql .=
", lifetime = ".($this->lifetime > 0 ? (int) $this->lifetime :
'null');
1552 $sql .=
", qc_frequency = ".($this->qc_frequency > 0 ? (int) $this->qc_frequency :
'null');
1553 $sql .=
", note = ".(isset($this->note_private) ?
"'".$this->db->escape($this->note_private).
"'" :
'null');
1554 $sql .=
", note_public = ".(isset($this->note_public) ?
"'".$this->db->escape($this->note_public).
"'" :
'null');
1555 $sql .=
", duration = '".$this->db->escape($this->duration_value.$this->duration_unit).
"'";
1557 $sql .=
", accountancy_code_buy = '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1558 $sql .=
", accountancy_code_buy_intra = '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1559 $sql .=
", accountancy_code_buy_export = '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1560 $sql .=
", accountancy_code_sell= '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1561 $sql .=
", accountancy_code_sell_intra= '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1562 $sql .=
", accountancy_code_sell_export= '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1564 $sql .=
", desiredstock = ".((isset($this->desiredstock) && is_numeric($this->desiredstock)) ? (
float) $this->desiredstock :
"null");
1565 $sql .=
", cost_price = ".($this->cost_price !=
'' ? $this->db->escape($this->cost_price) :
'null');
1566 $sql .=
", fk_unit= ".(!$this->fk_unit ?
'NULL' : (int) $this->fk_unit);
1567 $sql .=
", price_autogen = ".(!$this->price_autogen ? 0 : 1);
1568 $sql .=
", fk_price_expression = ".($this->fk_price_expression != 0 ? (int) $this->fk_price_expression :
'NULL');
1569 $sql .=
", fk_user_modif = ".($user->id > 0 ? $user->id :
'NULL');
1570 $sql .=
", mandatory_period = ".($this->mandatory_period);
1572 $sql .=
" WHERE rowid = ".((int) $id);
1574 dol_syslog(get_class($this).
"::update", LOG_DEBUG);
1576 $resql = $this->db->query($sql);
1583 $this->db->rollback();
1592 $this->db->query(
"DELETE FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = " . ((
int) $this->id) .
" AND entity = " . ((
int)
$conf->entity));
1594 $sql =
"INSERT INTO " . $this->db->prefix() .
"product_perentity (";
1595 $sql .=
" fk_product";
1597 $sql .=
", accountancy_code_buy";
1598 $sql .=
", accountancy_code_buy_intra";
1599 $sql .=
", accountancy_code_buy_export";
1600 $sql .=
", accountancy_code_sell";
1601 $sql .=
", accountancy_code_sell_intra";
1602 $sql .=
", accountancy_code_sell_export";
1603 $sql .=
") VALUES (";
1604 $sql .= ((int) $this->
id);
1605 $sql .=
", " . ((int)
$conf->entity);
1606 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy) .
"'";
1607 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_intra) .
"'";
1608 $sql .=
", '" . $this->db->escape($this->accountancy_code_buy_export) .
"'";
1609 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell) .
"'";
1610 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_intra) .
"'";
1611 $sql .=
", '" . $this->db->escape($this->accountancy_code_sell_export) .
"'";
1613 $result = $this->db->query($sql);
1616 $this->error =
'ErrorFailedToUpdateAccountancyForEntity';
1620 if (!$this->
hasbatch() && $this->oldcopy->hasbatch()) {
1622 $sql =
'SELECT pb.qty, ps.fk_entrepot, pb.batch FROM '.MAIN_DB_PREFIX.
'product_batch as pb';
1623 $sql .=
' INNER JOIN '.MAIN_DB_PREFIX.
'product_stock as ps ON (ps.rowid = pb.fk_product_stock)';
1624 $sql .=
' WHERE ps.fk_product = '.(int) $this->
id;
1626 $resql = $this->db->query($sql);
1630 while ($obj = $this->db->fetch_object($resql)) {
1632 $fk_entrepot = $obj->fk_entrepot;
1636 $batch = $obj->batch;
1639 $addOremove = $value > 0 ? 1 : 0;
1640 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1641 $res = $this->
correct_stock_batch($user, $fk_entrepot, abs($value), $addOremove, $label, $price, $dlc, $dluo, $batch, $inventorycode,
'',
null, 0,
null,
true);
1644 $label = $langs->trans(
'BatchStockMouvementAddInGlobal');
1645 $res = $this->
correct_stock($user, $fk_entrepot, abs($value), (
int) empty($addOremove), $label, $price, $inventorycode,
'',
null, 0);
1664 if (!$error && !$notrigger) {
1666 $result = $this->
call_trigger(
'PRODUCT_MODIFY', $user);
1673 if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) {
1675 if (
$conf->product->dir_output) {
1678 if (file_exists($olddir)) {
1682 $res = @rename($olddir, $newdir);
1684 $langs->load(
"errors");
1685 $this->error = $langs->trans(
'ErrorFailToRenameDir', $olddir, $newdir);
1689 require_once DOL_DOCUMENT_ROOT .
'/ecm/class/ecmfiles.class.php';
1690 $ecmfiles =
new EcmFiles($this->db);
1691 $ecmfiles->updateAfterRename(
"produit/".
dol_sanitizeFileName($this->oldcopy->ref),
"produit/".dol_sanitizeFileName($this->ref));
1698 if (isModEnabled(
'variants')) {
1699 include_once DOL_DOCUMENT_ROOT.
'/variants/class/ProductCombination.class.php';
1703 foreach ($comb->fetchAllByFkProductParent($this->id) as $currcomb) {
1704 $currcomb->updateProperties($this, $user);
1708 $this->db->commit();
1711 $this->db->rollback();
1715 if ($this->db->errno() ==
'DB_ERROR_RECORD_ALREADY_EXISTS') {
1716 $langs->load(
"errors");
1717 if (empty(
$conf->barcode->enabled) || empty($this->barcode)) {
1718 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductAlreadyExists", $this->
ref);
1720 $this->error = $langs->trans(
"Error").
" : ".$langs->trans(
"ErrorProductBarCodeAlreadyExists", $this->barcode);
1722 $this->errors[] = $this->error;
1723 $this->db->rollback();
1726 $this->error = $langs->trans(
"Error").
" : ".$this->db->error().
" - ".$sql;
1727 $this->errors[] = $this->error;
1728 $this->db->rollback();
1733 $this->db->rollback();
1734 dol_syslog(get_class($this).
"::Update fails verify ".implode(
',', $this->errors), LOG_WARNING);
1946 $langs_available = $langs->get_available_languages(DOL_DOCUMENT_ROOT, 0, 2);
1947 $current_lang = $langs->getDefaultLang();
1949 foreach ($langs_available as $key => $value) {
1950 if ($key == $current_lang) {
1951 $sql =
"SELECT rowid";
1952 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1953 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1954 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
1956 $result = $this->db->query($sql);
1958 if ($this->db->num_rows($result)) {
1959 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
1961 $sql2 .=
" label='".$this->db->escape($this->label).
"',";
1962 $sql2 .=
" description='".$this->db->escape($this->
description).
"'";
1964 $sql2 .=
", note='".$this->db->escape($this->other).
"'";
1966 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
1968 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
1973 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->label).
"',";
1974 $sql2 .=
" '".$this->db->escape($this->
description).
"'";
1976 $sql2 .=
", '".$this->db->escape($this->other).
"'";
1980 dol_syslog(get_class($this).
'::setMultiLangs key = current_lang = '.$key);
1981 if (!$this->db->query($sql2)) {
1982 $this->error = $this->db->lasterror();
1985 } elseif (isset($this->multilangs[$key])) {
1986 if (empty($this->multilangs[$key][
"label"])) {
1987 $this->errors[] = $key .
' : ' . $langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Label"));
1991 $sql =
"SELECT rowid";
1992 $sql .=
" FROM ".$this->db->prefix().
"product_lang";
1993 $sql .=
" WHERE fk_product = ".((int) $this->
id);
1994 $sql .=
" AND lang = '".$this->db->escape($key).
"'";
1996 $result = $this->db->query($sql);
1998 if ($this->db->num_rows($result)) {
1999 $sql2 =
"UPDATE ".$this->db->prefix().
"product_lang";
2001 $sql2 .=
" label = '".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
2002 $sql2 .=
" description = '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
2005 $sql2 .=
", note = '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
2007 $sql2 .=
" WHERE fk_product = ".((int) $this->
id).
" AND lang = '".$this->db->escape($key).
"'";
2009 $sql2 =
"INSERT INTO ".$this->db->prefix().
"product_lang (fk_product, lang, label, description";
2014 $sql2 .=
" VALUES(".((int) $this->
id).
",'".$this->db->escape($key).
"','".$this->db->escape($this->multilangs[
"$key"][
"label"]).
"',";
2015 $sql2 .=
" '".$this->db->escape($this->multilangs[
"$key"][
"description"]).
"'";
2018 $sql2 .=
", '".$this->db->escape($this->multilangs[
"$key"][
"other"]).
"'";
2024 if ($this->multilangs[
"$key"][
"label"] || $this->multilangs[
"$key"][
"description"]) {
2025 if (!$this->db->query($sql2)) {
2026 $this->error = $this->db->lasterror();
2036 $result = $this->
call_trigger(
'PRODUCT_SET_MULTILANGS', $user);
2038 $this->error = $this->db->lasterror();
2286 public function getSellPrice($thirdparty_seller, $thirdparty_buyer, $pqp = 0)
2288 global $hookmanager, $action;
2291 if (is_object($hookmanager)) {
2292 $parameters = array(
'thirdparty_seller' => $thirdparty_seller,
'thirdparty_buyer' => $thirdparty_buyer,
'pqp' => $pqp);
2294 $reshook = $hookmanager->executeHooks(
'getSellPrice', $parameters, $this, $action);
2296 return $hookmanager->resArray;
2301 $tva_tx =
get_default_tva($thirdparty_seller, $thirdparty_buyer, $this->
id);
2302 $tva_npr =
get_default_npr($thirdparty_seller, $thirdparty_buyer, $this->
id);
2303 if (empty($tva_tx)) {
2307 $pu_ht = $this->price;
2308 $pu_ttc = $this->price_ttc;
2309 $price_min = $this->price_min;
2310 $price_base_type = $this->price_base_type;
2314 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2318 $filter = array(
't.fk_product' => $this->
id,
't.fk_soc' => $thirdparty_buyer->id);
2321 $pricebycustomerexist =
false;
2322 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2324 if (count($prodcustprice->lines) > 0) {
2325 $pricebycustomerexist =
true;
2326 $pu_ht =
price($prodcustprice->lines[0]->price);
2327 $price_min =
price($prodcustprice->lines[0]->price_min);
2328 $pu_ttc =
price($prodcustprice->lines[0]->price_ttc);
2329 $price_base_type = $prodcustprice->lines[0]->price_base_type;
2330 $tva_tx = $prodcustprice->lines[0]->tva_tx;
2331 if ($prodcustprice->lines[0]->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2332 $tva_tx .=
' ('.$prodcustprice->lines[0]->default_vat_code.
')';
2334 $tva_npr = $prodcustprice->lines[0]->recuperableonly;
2335 if (empty($tva_tx)) {
2341 if (!$pricebycustomerexist && !empty($thirdparty_buyer->price_level)) {
2342 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
2343 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
2344 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
2345 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
2348 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2349 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2351 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2352 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2354 if (empty($tva_tx)) {
2359 } elseif (
getDolGlobalString(
'PRODUIT_MULTIPRICES') && !empty($thirdparty_buyer->price_level)) {
2360 $pu_ht = $this->multiprices[$thirdparty_buyer->price_level];
2361 $pu_ttc = $this->multiprices_ttc[$thirdparty_buyer->price_level];
2362 $price_min = $this->multiprices_min[$thirdparty_buyer->price_level];
2363 $price_base_type = $this->multiprices_base_type[$thirdparty_buyer->price_level];
2365 if (isset($this->multiprices_tva_tx[$thirdparty_buyer->price_level])) {
2366 $tva_tx = $this->multiprices_tva_tx[$thirdparty_buyer->price_level];
2368 if (isset($this->multiprices_recuperableonly[$thirdparty_buyer->price_level])) {
2369 $tva_npr = $this->multiprices_recuperableonly[$thirdparty_buyer->price_level];
2371 if (empty($tva_tx)) {
2377 require_once DOL_DOCUMENT_ROOT.
'/product/class/productcustomerprice.class.php';
2381 $filter = array(
't.fk_product' => $this->
id,
't.fk_soc' => $thirdparty_buyer->id);
2383 $result = $prodcustprice->fetchAll(
'',
'', 0, 0, $filter);
2385 if (count($prodcustprice->lines) > 0) {
2386 $pu_ht =
price($prodcustprice->lines[0]->price);
2387 $price_min =
price($prodcustprice->lines[0]->price_min);
2388 $pu_ttc =
price($prodcustprice->lines[0]->price_ttc);
2389 $price_base_type = $prodcustprice->lines[0]->price_base_type;
2390 $tva_tx = $prodcustprice->lines[0]->tva_tx;
2391 if ($prodcustprice->lines[0]->default_vat_code && !preg_match(
'/\(.*\)/', $tva_tx)) {
2392 $tva_tx .=
' ('.$prodcustprice->lines[0]->default_vat_code.
')';
2394 $tva_npr = $prodcustprice->lines[0]->recuperableonly;
2395 if (empty($tva_tx)) {
2402 if ($this->prices_by_qty[0]) {
2405 foreach ($this->prices_by_qty_list[0] as $priceforthequantityarray) {
2406 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2410 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2411 $pu_ht = $priceforthequantityarray[
'unitprice'];
2413 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2420 if ($this->prices_by_qty[$thirdparty_buyer->price_level]) {
2423 foreach ($this->prices_by_qty_list[$thirdparty_buyer->price_level] as $priceforthequantityarray) {
2424 if ($priceforthequantityarray[
'rowid'] != $pqp) {
2428 if ($priceforthequantityarray[
'price_base_type'] ==
'HT') {
2429 $pu_ht = $priceforthequantityarray[
'unitprice'];
2431 $pu_ttc = $priceforthequantityarray[
'unitprice'];
2438 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);
2455 public function get_buyprice($prodfournprice, $qty, $product_id = 0, $fourn_ref =
'', $fk_soc = 0)
2458 global $action, $hookmanager;
2461 if (is_object($hookmanager)) {
2462 $parameters = array(
2463 'prodfournprice' => $prodfournprice,
2465 'product_id' => $product_id,
2466 'fourn_ref' => $fourn_ref,
2467 'fk_soc' => $fk_soc,
2470 $reshook = $hookmanager->executeHooks(
'getBuyPrice', $parameters, $this, $action);
2472 return $hookmanager->resArray;
2479 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2480 $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,";
2481 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2482 $sql .=
" pfp.packaging";
2483 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2484 $sql .=
" WHERE pfp.rowid = ".((int) $prodfournprice);
2486 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2488 $sql .=
" ORDER BY pfp.quantity DESC";
2490 dol_syslog(get_class($this).
"::get_buyprice first search by prodfournprice/qty", LOG_DEBUG);
2491 $resql = $this->db->query($sql);
2493 $obj = $this->db->fetch_object($resql);
2494 if ($obj && $obj->quantity > 0) {
2495 if (isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2497 $prod_supplier->product_fourn_price_id = $obj->rowid;
2498 $prod_supplier->id = $obj->fk_product;
2499 $prod_supplier->fourn_qty = $obj->quantity;
2500 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2501 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2503 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2505 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2506 if ($price_result >= 0) {
2507 $obj->price = $price_result;
2510 $this->product_fourn_price_id = $obj->rowid;
2511 $this->buyprice = $obj->price;
2512 $this->fourn_pu = $obj->price / $obj->quantity;
2513 $this->fourn_price_base_type =
'HT';
2514 $this->fourn_socid = $obj->fk_soc;
2515 $this->ref_fourn = $obj->ref_supplier;
2516 $this->ref_supplier = $obj->ref_supplier;
2517 $this->desc_supplier = $obj->desc_supplier;
2518 $this->remise_percent = $obj->remise_percent;
2519 $this->vatrate_supplier = $obj->tva_tx;
2520 $this->default_vat_code_supplier = $obj->default_vat_code;
2521 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2522 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2523 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2524 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2525 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2527 $this->packaging = $obj->packaging;
2529 $result = $obj->fk_product;
2533 $sql =
"SELECT pfp.rowid, pfp.price as price, pfp.quantity as quantity, pfp.remise_percent, pfp.fk_soc,";
2534 $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,";
2535 $sql .=
" pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
2536 $sql .=
" pfp.packaging";
2537 $sql .=
" FROM ".$this->db->prefix().
"product_fournisseur_price as pfp";
2538 $sql .=
" WHERE 1 = 1";
2539 if ($product_id > 0) {
2540 $sql .=
" AND pfp.fk_product = ".((int) $product_id);
2542 if ($fourn_ref !=
'none') {
2543 $sql .=
" AND pfp.ref_fourn = '".$this->db->escape($fourn_ref).
"'";
2546 $sql .=
" AND pfp.fk_soc = ".((int) $fk_soc);
2549 $sql .=
" AND pfp.quantity <= ".((float) $qty);
2551 $sql .=
" ORDER BY pfp.quantity DESC";
2554 dol_syslog(get_class($this).
"::get_buyprice second search from qty/ref/product_id", LOG_DEBUG);
2555 $resql = $this->db->query($sql);
2557 $obj = $this->db->fetch_object($resql);
2558 if ($obj && $obj->quantity > 0) {
2559 if (isModEnabled(
'dynamicprices') && !empty($obj->fk_supplier_price_expression)) {
2561 $prod_supplier->product_fourn_price_id = $obj->rowid;
2562 $prod_supplier->id = $obj->fk_product;
2563 $prod_supplier->fourn_qty = $obj->quantity;
2564 $prod_supplier->fourn_tva_tx = $obj->tva_tx;
2565 $prod_supplier->fk_supplier_price_expression = $obj->fk_supplier_price_expression;
2567 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
2569 $price_result = $priceparser->parseProductSupplier($prod_supplier);
2571 $obj->price = $price_result;
2574 $this->product_fourn_price_id = $obj->rowid;
2575 $this->buyprice = $obj->price;
2576 $this->fourn_qty = $obj->quantity;
2577 $this->fourn_pu = $obj->price / $obj->quantity;
2578 $this->fourn_price_base_type =
'HT';
2579 $this->fourn_socid = $obj->fk_soc;
2580 $this->ref_fourn = $obj->ref_supplier;
2581 $this->ref_supplier = $obj->ref_supplier;
2582 $this->desc_supplier = $obj->desc_supplier;
2583 $this->remise_percent = $obj->remise_percent;
2584 $this->vatrate_supplier = $obj->tva_tx;
2585 $this->default_vat_code_supplier = $obj->default_vat_code;
2586 $this->fourn_multicurrency_price = $obj->multicurrency_price;
2587 $this->fourn_multicurrency_unitprice = $obj->multicurrency_unitprice;
2588 $this->fourn_multicurrency_tx = $obj->multicurrency_tx;
2589 $this->fourn_multicurrency_id = $obj->fk_multicurrency;
2590 $this->fourn_multicurrency_code = $obj->multicurrency_code;
2592 $this->packaging = $obj->packaging;
2594 $result = $obj->fk_product;
2600 $this->error = $this->db->lasterror();
2605 $this->error = $this->db->lasterror();
2629 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)
2635 dol_syslog(get_class($this).
"::update_price id=".$id.
" newprice=".$newprice.
" newpricebase=".$newpricebase.
" newminprice=".$newminprice.
" level=".$level.
" npr=".$newnpr.
" newdefaultvatcode=".$newdefaultvatcode);
2638 if (empty($this->tva_tx)) {
2639 $this->tva_tx = 0.0;
2641 if (empty($newnpr)) {
2644 if (empty($newminprice)) {
2649 if ($newvat ===
null || $newvat ==
'') {
2650 $newvat = (float) $this->tva_tx;
2653 $localtaxtype1 =
'';
2654 $localtaxtype2 =
'';
2659 return $this->
generateMultiprices($user, $newprice, $newpricebase, $newvat, $newnpr, $newpbq);
2662 if (!empty($newminprice) && ($newminprice > $newprice)) {
2663 $this->error =
'ErrorPriceCantBeLowerThanMinPrice';
2667 if ($newprice === 0 || $newprice !==
'') {
2668 if ($newpricebase ==
'TTC') {
2669 $price_ttc = (float)
price2num($newprice,
'MU');
2670 $price = (float)
price2num($newprice) / (1 + ((float) $newvat / 100));
2671 $price = (float)
price2num($price,
'MU');
2673 if ((
string) $newminprice !=
'0') {
2674 $price_min_ttc = (float)
price2num($newminprice,
'MU');
2675 $price_min = (float)
price2num($newminprice) / (1 + ($newvat / 100));
2676 $price_min = (float)
price2num($price_min,
'MU');
2679 $price_min_ttc = 0.0;
2682 $price = (float)
price2num($newprice,
'MU');
2683 $price_ttc = ($newnpr != 1) ? (
float)
price2num($newprice) * (1 + ($newvat / 100)) : $price;
2684 $price_ttc = (float)
price2num($price_ttc,
'MU');
2686 if ((
string) $newminprice !=
'0') {
2687 $price_min = (float)
price2num($newminprice,
'MU');
2688 $price_min_ttc = (float)
price2num($newminprice) * (1 + ($newvat / 100));
2689 $price_min_ttc = (float)
price2num($price_min_ttc,
'MU');
2693 $price_min_ttc = 0.0;
2697 if (count($localtaxes_array) > 0) {
2698 $localtaxtype1 = $localtaxes_array[
'0'];
2699 $localtax1 = $localtaxes_array[
'1'];
2700 $localtaxtype2 = $localtaxes_array[
'2'];
2701 $localtax2 = $localtaxes_array[
'3'];
2704 if (!empty($newdefaultvatcode)) {
2707 $sql =
"SELECT t.rowid, t.code, t.recuperableonly as tva_npr, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
2708 $sql .=
" FROM ".MAIN_DB_PREFIX.
"c_tva as t, ".MAIN_DB_PREFIX.
"c_country as c";
2709 $sql .=
" WHERE t.fk_pays = c.rowid AND c.code = '".$this->db->escape($mysoc->country_code).
"'";
2710 $sql .=
" AND t.taux = ".((float) $newdefaultvatcode).
" AND t.active = 1";
2711 $sql .=
" AND t.code = '".$this->db->escape($newdefaultvatcode).
"'";
2712 $resql = $this->db->query($sql);
2714 $obj = $this->db->fetch_object($resql);
2716 $npr = $obj->tva_npr;
2717 $localtax1 = $obj->localtax1;
2718 $localtax2 = $obj->localtax2;
2719 $localtaxtype1 = $obj->localtax1_type;
2720 $localtaxtype2 = $obj->localtax2_type;
2725 $localtaxtype1 =
'0';
2727 $localtaxtype2 =
'0';
2731 if (empty($localtax1)) {
2734 if (empty($localtax2)) {
2742 $sql =
"UPDATE ".$this->db->prefix().
"product SET";
2743 $sql .=
" price_base_type = '".$this->db->escape($newpricebase).
"',";
2744 $sql .=
" price = ".(float) $price.
",";
2745 $sql .=
" price_ttc = ".(float) $price_ttc.
",";
2746 $sql .=
" price_min = ".(float) $price_min.
",";
2747 $sql .=
" price_min_ttc = ".(float) $price_min_ttc.
",";
2748 $sql .=
" localtax1_tx = ".($localtax1 >= 0 ? (float) $localtax1 :
'NULL').
",";
2749 $sql .=
" localtax2_tx = ".($localtax2 >= 0 ? (float) $localtax2 :
'NULL').
",";
2750 $sql .=
" localtax1_type = ".($localtaxtype1 !=
'' ?
"'".$this->db->escape($localtaxtype1).
"'" :
"'0'").
",";
2751 $sql .=
" localtax2_type = ".($localtaxtype2 !=
'' ?
"'".$this->db->escape($localtaxtype2).
"'" :
"'0'").
",";
2752 $sql .=
" default_vat_code = ".($newdefaultvatcode ?
"'".$this->db->escape($newdefaultvatcode).
"'" :
"null").
",";
2753 $sql .=
" price_label = ".(!empty($price_label) ?
"'".$this->db->escape($price_label).
"'" :
"null").
",";
2754 $sql .=
" tva_tx = ".(float)
price2num($newvat).
",";
2755 $sql .=
" recuperableonly = '".$this->db->escape($newnpr).
"'";
2756 $sql .=
" WHERE rowid = ".((int) $id);
2758 dol_syslog(get_class($this).
"::update_price", LOG_DEBUG);
2759 $resql = $this->db->query($sql);
2761 $this->multiprices[$level] = $price;
2762 $this->multiprices_ttc[$level] = $price_ttc;
2763 $this->multiprices_min[$level] = $price_min;
2764 $this->multiprices_min_ttc[$level] = $price_min_ttc;
2765 $this->multiprices_base_type[$level] = $newpricebase;
2766 $this->multiprices_default_vat_code[$level] = $newdefaultvatcode;
2767 $this->multiprices_tva_tx[$level] = $newvat;
2768 $this->multiprices_recuperableonly[$level] = $newnpr;
2770 $this->
price = $price;
2771 $this->price_label = $price_label;
2772 $this->price_ttc = $price_ttc;
2773 $this->price_min = $price_min;
2774 $this->price_min_ttc = $price_min_ttc;
2775 $this->price_base_type = $newpricebase;
2776 $this->default_vat_code = $newdefaultvatcode;
2777 $this->tva_tx = $newvat;
2778 $this->tva_npr = $newnpr;
2781 $this->localtax1_tx = $localtax1;
2782 $this->localtax2_tx = $localtax2;
2783 $this->localtax1_type = $localtaxtype1;
2784 $this->localtax2_type = $localtaxtype2;
2787 $this->price_by_qty = $newpbq;
2791 if (!empty(array_diff_assoc($newPriceData, $lastPriceData)) || !
getDolGlobalString(
'PRODUIT_MULTIPRICES')) {
2795 $this->level = $level;
2799 $result = $this->
call_trigger(
'PRODUCT_PRICE_MODIFY', $user);
2801 $this->db->rollback();
2807 $this->db->commit();
2809 $this->db->rollback();
2810 $this->error = $this->db->lasterror();
2846 public function fetch($id = 0, $ref =
'', $ref_ext =
'', $barcode =
'', $ignore_expression = 0, $ignore_price_load = 0, $ignore_lang_load = 0)
2848 include_once DOL_DOCUMENT_ROOT.
'/core/lib/company.lib.php';
2852 dol_syslog(get_class($this).
"::fetch id=".$id.
" ref=".$ref.
" ref_ext=".$ref_ext);
2855 if (!$id && !$ref && !$ref_ext && !$barcode) {
2856 $this->error =
'ErrorWrongParameters';
2857 dol_syslog(get_class($this).
"::fetch ".$this->error, LOG_ERR);
2861 $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,";
2862 $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,";
2863 $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,";
2864 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.last_main_doc,";
2865 $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,";
2867 $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,";
2869 $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,";
2874 $separatedEntityPMP =
false;
2875 $separatedStock =
false;
2876 $visibleWarehousesEntities =
$conf->entity;
2879 $checkPMPPerEntity = $this->db->query(
"SELECT pmp FROM " . $this->db->prefix() .
"product_perentity WHERE fk_product = ".((int) $id).
" AND entity = ".(
int)
$conf->entity);
2880 if ($this->db->num_rows($checkPMPPerEntity) > 0) {
2881 $separatedEntityPMP =
true;
2885 $separatedStock =
true;
2886 if (isset($mc->sharings[
'stock']) && !empty($mc->sharings[
'stock'])) {
2887 $visibleWarehousesEntities .=
"," . implode(
",", $mc->sharings[
'stock']);
2890 if ($separatedEntityPMP) {
2891 $sql .=
" ppe.pmp,";
2895 $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,";
2896 $sql .=
" p.fk_price_expression, p.price_autogen, p.model_pdf,";
2897 $sql .=
" p.price_label,";
2898 if ($separatedStock) {
2899 $sql .=
" SUM(sp.reel) as stock";
2903 $sql .=
" FROM ".$this->db->prefix().
"product as p";
2905 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int)
$conf->entity);
2907 if ($separatedStock) {
2908 $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).
"))";
2912 $sql .=
" WHERE p.rowid = ".((int) $id);
2914 $sql .=
" WHERE p.entity IN (".getEntity($this->element).
")";
2916 $sql .=
" AND p.ref = '".$this->db->escape($ref).
"'";
2917 } elseif ($ref_ext) {
2918 $sql .=
" AND p.ref_ext = '".$this->db->escape($ref_ext).
"'";
2919 } elseif ($barcode) {
2920 $sql .=
" AND p.barcode = '".$this->db->escape($barcode).
"'";
2923 if ($separatedStock) {
2924 $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,";
2925 $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,";
2926 $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,";
2927 $sql .=
" p.length, p.length_units, p.width, p.width_units, p.height, p.height_units,";
2928 $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,";
2930 $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,";
2932 $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,";
2934 if ($separatedEntityPMP) {
2935 $sql .=
" ppe.pmp,";
2939 $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,";
2940 $sql .=
" p.fk_price_expression, p.price_autogen, p.model_pdf";
2941 $sql .=
" ,p.price_label";
2942 if (!$separatedStock) {
2943 $sql .=
", p.stock";
2947 $resql = $this->db->query($sql);
2949 unset($this->oldcopy);
2951 if ($this->db->num_rows($resql) > 0) {
2952 $obj = $this->db->fetch_object($resql);
2954 $this->
id = $obj->rowid;
2955 $this->
ref = $obj->ref;
2956 $this->ref_ext = $obj->ref_ext;
2957 $this->label = $obj->label;
2959 $this->url = $obj->url;
2960 $this->note_public = $obj->note_public;
2961 $this->note_private = $obj->note_private;
2962 $this->note = $obj->note_private;
2964 $this->
type = $obj->fk_product_type;
2965 $this->price_label = $obj->price_label;
2966 $this->
status = $obj->tosell;
2967 $this->status_buy = $obj->tobuy;
2968 $this->status_batch = $obj->tobatch;
2969 $this->sell_or_eat_by_mandatory = $obj->sell_or_eat_by_mandatory;
2970 $this->batch_mask = $obj->batch_mask;
2972 $this->customcode = $obj->customcode;
2973 $this->country_id = $obj->fk_country;
2974 $this->country_code =
getCountry($this->country_id,
'2', $this->db);
2975 $this->state_id = $obj->fk_state;
2976 $this->lifetime = $obj->lifetime;
2977 $this->qc_frequency = $obj->qc_frequency;
2978 $this->
price = $obj->price;
2979 $this->price_ttc = $obj->price_ttc;
2980 $this->price_min = $obj->price_min;
2981 $this->price_min_ttc = $obj->price_min_ttc;
2982 $this->price_base_type = $obj->price_base_type;
2983 $this->cost_price = $obj->cost_price;
2984 $this->default_vat_code = $obj->default_vat_code;
2985 $this->tva_tx = $obj->tva_tx;
2987 $this->tva_npr = $obj->tva_npr;
2989 $this->localtax1_tx = $obj->localtax1_tx;
2990 $this->localtax2_tx = $obj->localtax2_tx;
2991 $this->localtax1_type = $obj->localtax1_type;
2992 $this->localtax2_type = $obj->localtax2_type;
2994 $this->finished = $obj->finished;
2995 $this->fk_default_bom = $obj->fk_default_bom;
2997 $this->duration = $obj->duration;
2999 preg_match(
'/(\d+)(\w+)/', $obj->duration, $matches);
3000 $this->duration_value = !empty($matches[1]) ? (int) $matches[1] : 0;
3001 $this->duration_unit = !empty($matches[2]) ? (string) $matches[2] :
null;
3002 $this->canvas = $obj->canvas;
3003 $this->net_measure = $obj->net_measure;
3004 $this->net_measure_units = $obj->net_measure_units;
3005 $this->weight = $obj->weight;
3006 $this->weight_units = $obj->weight_units;
3007 $this->length = $obj->length;
3008 $this->length_units = $obj->length_units;
3009 $this->width = $obj->width;
3010 $this->width_units = $obj->width_units;
3011 $this->height = $obj->height;
3012 $this->height_units = $obj->height_units;
3014 $this->surface = $obj->surface;
3015 $this->surface_units = $obj->surface_units;
3016 $this->volume = $obj->volume;
3017 $this->volume_units = $obj->volume_units;
3018 $this->barcode = $obj->barcode;
3019 $this->barcode_type = $obj->fk_barcode_type;
3021 $this->accountancy_code_buy = $obj->accountancy_code_buy;
3022 $this->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra;
3023 $this->accountancy_code_buy_export = $obj->accountancy_code_buy_export;
3024 $this->accountancy_code_sell = $obj->accountancy_code_sell;
3025 $this->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra;
3026 $this->accountancy_code_sell_export = $obj->accountancy_code_sell_export;
3028 $this->fk_default_warehouse = $obj->fk_default_warehouse;
3029 $this->fk_default_workstation = $obj->fk_default_workstation;
3030 $this->seuil_stock_alerte = $obj->seuil_stock_alerte;
3031 $this->desiredstock = $obj->desiredstock;
3032 $this->stock_reel = $obj->stock;
3033 $this->pmp = $obj->pmp;
3035 $this->date_creation = $obj->datec;
3036 $this->date_modification = $obj->tms;
3037 $this->import_key = $obj->import_key;
3038 $this->entity = $obj->entity;
3040 $this->ref_ext = $obj->ref_ext;
3041 $this->fk_price_expression = $obj->fk_price_expression;
3042 $this->fk_unit = $obj->fk_unit;
3043 $this->price_autogen = $obj->price_autogen;
3044 $this->model_pdf = $obj->model_pdf;
3045 $this->last_main_doc = $obj->last_main_doc;
3047 $this->mandatory_period = $obj->mandatory_period;
3049 $this->db->free($resql);
3062 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3063 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3064 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3065 $sql .=
" ,price_label";
3066 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3067 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3068 $sql .=
" AND price_level=".((int) $i);
3069 $sql .=
" AND fk_product = ".((int) $this->
id);
3070 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3072 $resql = $this->db->query($sql);
3074 $result = $this->db->fetch_array($resql);
3076 $this->multiprices[$i] = $result ? $result[
"price"] :
null;
3077 $this->multiprices_ttc[$i] = $result ? $result[
"price_ttc"] :
null;
3078 $this->multiprices_min[$i] = $result ? $result[
"price_min"] :
null;
3079 $this->multiprices_min_ttc[$i] = $result ? $result[
"price_min_ttc"] :
null;
3080 $this->multiprices_base_type[$i] = $result ? $result[
"price_base_type"] :
null;
3082 $this->multiprices_tva_tx[$i] = $result ? $result[
"tva_tx"].($result ?
' ('.$result[
'default_vat_code'].
')' :
'') :
null;
3083 $this->multiprices_recuperableonly[$i] = $result ? $result[
"recuperableonly"] :
null;
3122 $this->error = $this->db->lasterror;
3128 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY') && empty($ignore_price_load)) {
3129 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3130 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid";
3131 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3132 $sql .=
" WHERE fk_product = ".((int) $this->
id);
3133 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3136 $resql = $this->db->query($sql);
3138 $result = $this->db->fetch_array($resql);
3142 $this->prices_by_qty[0] = $result[
"price_by_qty"];
3143 $this->prices_by_qty_id[0] = $result[
"rowid"];
3145 if ($this->prices_by_qty[0] == 1) {
3146 $sql =
"SELECT rowid,price, unitprice, quantity, remise_percent, remise, remise, price_base_type";
3147 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3148 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[0]);
3149 $sql .=
" ORDER BY quantity ASC";
3151 $resql = $this->db->query($sql);
3153 $resultat = array();
3155 while ($result = $this->db->fetch_array($resql)) {
3156 $resultat[$ii] = array();
3157 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3158 $resultat[$ii][
"price"] = $result[
"price"];
3159 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3160 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3161 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3163 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3166 $this->prices_by_qty_list[0] = $resultat;
3168 $this->error = $this->db->lasterror;
3174 $this->error = $this->db->lasterror;
3177 } elseif (
getDolGlobalString(
'PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') && empty($ignore_price_load)) {
3179 for ($i = 1; $i <= $produit_multiprices_limit; $i++) {
3180 $sql =
"SELECT price, price_ttc, price_min, price_min_ttc,";
3181 $sql .=
" price_base_type, tva_tx, default_vat_code, tosell, price_by_qty, rowid, recuperableonly";
3182 $sql .=
" FROM ".$this->db->prefix().
"product_price";
3183 $sql .=
" WHERE entity IN (".getEntity(
'productprice').
")";
3184 $sql .=
" AND price_level=".((int) $i);
3185 $sql .=
" AND fk_product = ".((int) $this->
id);
3186 $sql .=
" ORDER BY date_price DESC, rowid DESC";
3188 $resql = $this->db->query($sql);
3190 $this->error = $this->db->lasterror;
3192 } elseif ($result = $this->db->fetch_array($resql)) {
3193 $this->multiprices[$i] = (!empty($result[
"price"]) ? $result[
"price"] : 0);
3194 $this->multiprices_ttc[$i] = (!empty($result[
"price_ttc"]) ? $result[
"price_ttc"] : 0);
3195 $this->multiprices_min[$i] = (!empty($result[
"price_min"]) ? $result[
"price_min"] : 0);
3196 $this->multiprices_min_ttc[$i] = (!empty($result[
"price_min_ttc"]) ? $result[
"price_min_ttc"] : 0);
3197 $this->multiprices_base_type[$i] = (!empty($result[
"price_base_type"]) ? $result[
"price_base_type"] :
'');
3199 $this->multiprices_tva_tx[$i] = (!empty($result[
"tva_tx"]) ? $result[
"tva_tx"] : 0);
3200 $this->multiprices_recuperableonly[$i] = (!empty($result[
"recuperableonly"]) ? $result[
"recuperableonly"] : 0);
3203 $this->prices_by_qty[$i] = (!empty($result[
"price_by_qty"]) ? $result[
"price_by_qty"] : 0);
3204 $this->prices_by_qty_id[$i] = (!empty($result[
"rowid"]) ? $result[
"rowid"] : 0);
3206 if ($this->prices_by_qty[$i] == 1) {
3207 $sql =
"SELECT rowid, price, unitprice, quantity, remise_percent, remise, price_base_type";
3208 $sql .=
" FROM ".$this->db->prefix().
"product_price_by_qty";
3209 $sql .=
" WHERE fk_product_price = ".((int) $this->prices_by_qty_id[$i]);
3210 $sql .=
" ORDER BY quantity ASC";
3212 $resql = $this->db->query($sql);
3214 $resultat = array();
3216 while ($result = $this->db->fetch_array($resql)) {
3217 $resultat[$ii] = array();
3218 $resultat[$ii][
"rowid"] = $result[
"rowid"];
3219 $resultat[$ii][
"price"] = $result[
"price"];
3220 $resultat[$ii][
"unitprice"] = $result[
"unitprice"];
3221 $resultat[$ii][
"quantity"] = $result[
"quantity"];
3222 $resultat[$ii][
"remise_percent"] = $result[
"remise_percent"];
3223 $resultat[$ii][
"remise"] = $result[
"remise"];
3224 $resultat[$ii][
"price_base_type"] = $result[
"price_base_type"];
3227 $this->prices_by_qty_list[$i] = $resultat;
3229 $this->error = $this->db->lasterror;
3237 if (isModEnabled(
'dynamicprices') && !empty($this->fk_price_expression) && empty($ignore_expression)) {
3238 include_once DOL_DOCUMENT_ROOT.
'/product/dynamic_price/class/price_parser.class.php';
3240 $price_result = $priceparser->parseProduct($this);
3241 if ($price_result >= 0) {
3242 $this->
price = $price_result;
3244 $this->price_ttc = (float)
price2num($this->
price) * (1 + ($this->tva_tx / 100));
3245 $this->price_ttc = (float)
price2num($this->price_ttc,
'MU');
3251 $this->stock_warehouse = array();
3258 $this->error = $this->db->lasterror();
3533 global $user, $hookmanager, $action;
3535 $sql =
"SELECT COUNT(DISTINCT c.fk_soc) as nb_customers, COUNT(DISTINCT c.rowid) as nb,";
3536 $sql .=
" COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty";
3537 $sql .=
" FROM ".$this->db->prefix().
"commandedet as cd";
3538 $sql .=
", ".$this->db->prefix().
"commande as c";
3539 $sql .=
", ".$this->db->prefix().
"societe as s";
3540 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3541 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3543 $sql .=
" WHERE c.rowid = cd.fk_commande";
3544 $sql .=
" AND c.fk_soc = s.rowid";
3545 $sql .=
" AND c.entity IN (".getEntity($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ?
'stock' :
'commande').
")";
3546 $sql .=
" AND cd.fk_product = ".((int) $this->
id);
3547 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3548 $sql .=
" AND c.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3551 $sql .=
" AND c.fk_soc = ".((int) $socid);
3553 if ($filtrestatut !=
'') {
3554 $sql .=
" AND c.fk_statut in (".$this->db->sanitize($filtrestatut).
")";
3557 $result = $this->db->query($sql);
3559 $obj = $this->db->fetch_object($result);
3560 $this->stats_commande[
'customers'] = $obj->nb_customers;
3561 $this->stats_commande[
'nb'] = $obj->nb;
3562 $this->stats_commande[
'rows'] = $obj->nb_rows;
3563 $this->stats_commande[
'qty'] = $obj->qty ? $obj->qty : 0;
3568 if (is_array($TFather) && !empty($TFather)) {
3569 foreach ($TFather as &$fatherData) {
3570 $pFather =
new Product($this->db);
3571 $pFather->id = $fatherData[
'id'];
3572 $qtyCoef = $fatherData[
'qty'];
3574 if ($fatherData[
'incdec']) {
3575 $pFather->load_stats_commande($socid, $filtrestatut);
3577 $this->stats_commande[
'customers'] += $pFather->stats_commande[
'customers'];
3578 $this->stats_commande[
'nb'] += $pFather->stats_commande[
'nb'];
3579 $this->stats_commande[
'rows'] += $pFather->stats_commande[
'rows'];
3580 $this->stats_commande[
'qty'] += $pFather->stats_commande[
'qty'] * $qtyCoef;
3592 $sql =
"SELECT SUM(".$this->db->ifsql(
'f.type=2', -1, 1).
" * fd.qty) as count FROM ".$this->db->prefix().
"facturedet as fd ";
3593 $sql .=
" JOIN ".$this->db->prefix().
"facture as f ON fd.fk_facture = f.rowid";
3594 $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'))";
3595 $sql .=
" JOIN ".$this->db->prefix().
"commande as c ON el.fk_source = c.rowid";
3596 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND c.facture = 0 AND fd.fk_product = ".((int) $this->
id);
3598 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3599 $resql = $this->db->query($sql);
3601 if ($this->db->num_rows($resql) > 0) {
3602 $obj = $this->db->fetch_object($resql);
3603 $adeduire += $obj->count;
3607 $this->stats_commande[
'qty'] -= $adeduire;
3610 include_once DOL_DOCUMENT_ROOT.
'/compta/facture/class/facture.class.php';
3614 $sql =
"SELECT sum(".$this->db->ifsql(
'f.type=2', -1, 1).
" * fd.qty) as count FROM ".MAIN_DB_PREFIX.
"facturedet as fd ";
3615 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"facture as f ON fd.fk_facture = f.rowid";
3616 $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'))";
3617 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"commande as c ON el.fk_source = c.rowid";
3618 $sql .=
" WHERE c.fk_statut IN (".$this->db->sanitize($filtrestatut).
") AND f.fk_statut > ".
Facture::STATUS_DRAFT.
" AND fd.fk_product = ".((int) $this->
id);
3620 dol_syslog(__METHOD__.
":: sql $sql", LOG_NOTICE);
3621 $resql = $this->db->query($sql);
3623 if ($this->db->num_rows($resql) > 0) {
3624 $obj = $this->db->fetch_object($resql);
3625 $adeduire += $obj->count;
3628 $this->error = $this->db->error();
3632 $this->stats_commande[
'qty'] -= $adeduire;
3636 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3637 $reshook = $hookmanager->executeHooks(
'loadStatsCustomerOrder', $parameters, $this, $action);
3639 $this->stats_commande = $hookmanager->resArray[
'stats_commande'];
3643 $this->error = $this->db->error();
3867 public function load_stats_inproduction($socid = 0, $filtrestatut =
'', $forVirtualStock = 0, $dateofvirtualstock =
null, $warehouseid = 0)
3870 global $user, $hookmanager, $action;
3872 $serviceStockIsEnabled = isModEnabled(
"service") &&
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES');
3874 $sql =
"SELECT COUNT(DISTINCT m.fk_soc) as nb_customers, COUNT(DISTINCT m.rowid) as nb,";
3875 $sql .=
" COUNT(mp.rowid) as nb_rows, SUM(mp.qty) as qty, role";
3876 $sql .=
" FROM ".$this->db->prefix().
"mrp_production as mp";
3877 $sql .=
", ".$this->db->prefix().
"mrp_mo as m";
3878 $sql .=
" LEFT JOIN ".$this->db->prefix().
"societe as s ON s.rowid = m.fk_soc";
3879 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3880 $sql .=
", ".$this->db->prefix().
"societe_commerciaux as sc";
3882 $sql .=
" WHERE m.rowid = mp.fk_mo";
3883 $sql .=
" AND m.entity IN (".getEntity(($forVirtualStock &&
getDolGlobalString(
'STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE')) ?
'stock' :
'mrp').
")";
3884 $sql .=
" AND mp.fk_product = ".((int) $this->
id);
3885 $sql .=
" AND (mp.disable_stock_change IN (0) OR mp.disable_stock_change IS NULL)";
3886 if (!$user->hasRight(
'societe',
'client',
'voir') && !$forVirtualStock) {
3887 $sql .=
" AND m.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
3890 $sql .=
" AND m.fk_soc = ".((int) $socid);
3892 if ($filtrestatut !=
'') {
3893 $sql .=
" AND m.status IN (".$this->db->sanitize($filtrestatut).
")";
3895 if (!empty($dateofvirtualstock)) {
3896 $sql .=
" AND m.date_valid <= '".$this->db->idate($dateofvirtualstock).
"'";
3898 if (!$serviceStockIsEnabled) {
3899 $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))";
3901 if (!empty($warehouseid)) {
3902 $sql .=
" AND m.fk_warehouse = ".((int) $warehouseid);
3904 $sql .=
" GROUP BY role";
3907 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
3909 $this->stats_mrptoconsume[
'customers'] = 0;
3910 $this->stats_mrptoconsume[
'nb'] = 0;
3911 $this->stats_mrptoconsume[
'rows'] = 0;
3912 $this->stats_mrptoconsume[
'qty'] = 0;
3913 $this->stats_mrptoproduce[
'customers'] = 0;
3914 $this->stats_mrptoproduce[
'nb'] = 0;
3915 $this->stats_mrptoproduce[
'rows'] = 0;
3916 $this->stats_mrptoproduce[
'qty'] = 0;
3919 $result = $this->db->query($sql);
3921 while ($obj = $this->db->fetch_object($result)) {
3922 if ($obj->role ==
'toconsume' && empty($warehouseid)) {
3923 $this->stats_mrptoconsume[
'customers'] += $obj->nb_customers;
3924 $this->stats_mrptoconsume[
'nb'] += $obj->nb;
3925 $this->stats_mrptoconsume[
'rows'] += $obj->nb_rows;
3926 $this->stats_mrptoconsume[
'qty'] += ($obj->qty ? $obj->qty : 0);
3928 if ($obj->role ==
'consumed' && empty($warehouseid)) {
3932 $this->stats_mrptoconsume[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3934 if ($obj->role ==
'toproduce') {
3936 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] += ($obj->qty ? $obj->qty : 0);
3938 $this->stats_mrptoproduce[
'customers'] += $obj->nb_customers;
3939 $this->stats_mrptoproduce[
'nb'] += $obj->nb;
3940 $this->stats_mrptoproduce[
'rows'] += $obj->nb_rows;
3941 $this->stats_mrptoproduce[
'qty'] += ($obj->qty ? $obj->qty : 0);
3944 if ($obj->role ==
'produced') {
3949 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3951 $this->stats_mrptoproduce[
'qty'] -= ($obj->qty ? $obj->qty : 0);
3958 if ($this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] < 0) {
3959 $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'] = 0;
3962 if ($this->stats_mrptoconsume[
'qty'] < 0) {
3963 $this->stats_mrptoconsume[
'qty'] = 0;
3965 if ($this->stats_mrptoproduce[
'qty'] < 0) {
3966 $this->stats_mrptoproduce[
'qty'] = 0;
3970 $parameters = array(
'socid' => $socid,
'filtrestatut' => $filtrestatut,
'forVirtualStock' => $forVirtualStock);
3971 $reshook = $hookmanager->executeHooks(
'loadStatsInProduction', $parameters, $this, $action);
3973 $this->stats_mrptoproduce = $hookmanager->resArray[
'stats_mrptoproduce'];
3978 $this->error = $this->db->error();
5597 global
$conf, $langs, $user;
5599 $langs->loadLangs(array(
'products',
'other'));
5602 $nofetch = !empty($params[
'nofetch']);
5605 return [
'optimize' => $langs->trans(
"ShowProduct")];
5609 $permissiontoreadproduct = 0;
5610 if ($this->
type == self::TYPE_PRODUCT && $user->hasRight(
'product',
'read')) {
5611 $permissiontoreadproduct = 1;
5613 if ($this->
type == self::TYPE_SERVICE && $user->hasRight(
'service',
'read')) {
5614 $permissiontoreadproduct = 1;
5617 if (!empty($this->entity) && $permissiontoreadproduct) {
5618 $tmpphoto = $this->
show_photos(
'product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 80, 0, 0, 0, 0,
'1');
5619 if ($this->nbphoto > 0) {
5620 $datas[
'photo'] =
'<div class="photointooltip floatright">'.
"\n" . $tmpphoto .
'</div>';
5625 $datas[
'picto'] =
img_picto(
'',
'product').
' <u class="paddingrightonly">'.$langs->trans(
"Product").
'</u>';
5627 $datas[
'picto'] =
img_picto(
'',
'service').
' <u class="paddingrightonly">'.$langs->trans(
"Service").
'</u>';
5629 if (isset($this->
status) && isset($this->status_buy)) {
5630 $datas[
'status'] =
' '.$this->getLibStatut(5, 0) .
' '.$this->getLibStatut(5, 1);
5633 if (!empty($this->
ref)) {
5634 $datas[
'ref'] =
'<br><b>'.$langs->trans(
'ProductRef').
':</b> '.$this->ref;
5636 if (!empty($this->label)) {
5637 $datas[
'label'] =
'<br><b>'.$langs->trans(
'ProductLabel').
':</b> '.$this->label;
5640 if ($permissiontoreadproduct) {
5645 if (isModEnabled(
'productbatch')) {
5646 $langs->load(
"productbatch");
5647 $datas[
'batchstatus'] =
"<br><b>".$langs->trans(
"ManageLotSerial").
'</b>: '.$this->
getLibStatut(0, 2);
5650 if (isModEnabled(
'barcode')) {
5651 $datas[
'barcode'] =
'<br><b>'.$langs->trans(
'BarCode').
':</b> '.$this->barcode;
5655 if ($this->weight) {
5656 $datas[
'weight'] =
"<br><b>".$langs->trans(
"Weight").
'</b>: '.$this->weight.
' '.
measuringUnitString(0,
"weight", $this->weight_units);
5659 if ($this->length) {
5660 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Length").
'</b>: '.$this->length.
' '.
measuringUnitString(0,
'size', $this->length_units);
5663 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Width").
'</b>: '.$this->width.
' '.
measuringUnitString(0,
'size', $this->width_units);
5665 if ($this->height) {
5666 $labelsize .= ($labelsize ?
" - " :
"").
"<b>".$langs->trans(
"Height").
'</b>: '.$this->height.
' '.
measuringUnitString(0,
'size', $this->height_units);
5669 $datas[
'size'] =
"<br>".$labelsize;
5672 $labelsurfacevolume =
"";
5673 if ($this->surface) {
5674 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Surface").
'</b>: '.$this->surface.
' '.
measuringUnitString(0,
'surface', $this->surface_units);
5676 if ($this->volume) {
5677 $labelsurfacevolume .= ($labelsurfacevolume ?
" - " :
"").
"<b>".$langs->trans(
"Volume").
'</b>: '.$this->volume.
' '.
measuringUnitString(0,
'volume', $this->volume_units);
5679 if ($labelsurfacevolume) {
5680 $datas[
'surface'] =
"<br>" . $labelsurfacevolume;
5683 if ($this->
isService() && !empty($this->duration_value)) {
5685 $datas[
'duration'] =
'<br><b>'.$langs->trans(
"Duration").
':</b> '.$this->duration_value;
5686 if ($this->duration_value > 1) {
5687 $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"));
5688 } elseif ($this->duration_value > 0) {
5689 $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"));
5691 $datas[
'duration'] .= (!empty($this->duration_unit) && isset($dur[$this->duration_unit]) ?
" ".$langs->trans($dur[$this->duration_unit]) :
'');
5693 if (empty($user->socid)) {
5694 if (!empty($this->pmp) && $this->pmp) {
5695 $datas[
'pmp'] =
"<br><b>".$langs->trans(
"PMPValue").
'</b>: '.
price($this->pmp, 0,
'', 1, -1, -1,
$conf->currency);
5698 if (isModEnabled(
'accounting')) {
5699 if ($this->
status && isset($this->accountancy_code_sell)) {
5700 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5701 $selllabel =
'<br>';
5702 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellCode').
':</b> '.
length_accountg($this->accountancy_code_sell);
5703 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellIntraCode').
':</b> '.
length_accountg($this->accountancy_code_sell_intra);
5704 $selllabel .=
'<br><b>'.$langs->trans(
'ProductAccountancySellExportCode').
':</b> '.
length_accountg($this->accountancy_code_sell_export);
5705 $datas[
'accountancysell'] = $selllabel;
5707 if ($this->status_buy && isset($this->accountancy_code_buy)) {
5708 include_once DOL_DOCUMENT_ROOT.
'/core/lib/accounting.lib.php';
5710 if (empty($this->
status)) {
5711 $buylabel .=
'<br>';
5713 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyCode').
':</b> '.
length_accountg($this->accountancy_code_buy);
5714 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyIntraCode').
':</b> '.
length_accountg($this->accountancy_code_buy_intra);
5715 $buylabel .=
'<br><b>'.$langs->trans(
'ProductAccountancyBuyExportCode').
':</b> '.
length_accountg($this->accountancy_code_buy_export);
5716 $datas[
'accountancybuy'] = $buylabel;
5721 if (isModEnabled(
'category') && !$nofetch) {
5722 require_once DOL_DOCUMENT_ROOT .
'/categories/class/categorie.class.php';
5723 $form =
new Form($this->db);
5724 $datas[
'categories'] =
'<br>' . $form->showCategories($this->
id, Categorie::TYPE_PRODUCT, 1);
5901 $labelStatus = $labelStatusShort =
'';
5903 $langs->load(
'products');
5904 if (isModEnabled(
'productbatch')) {
5905 $langs->load(
"productbatch");
5911 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial')));
5914 $label = ($status == 0 ? $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort') : ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort')));
5919 return dolGetStatus($langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch'),
'',
'', empty($status) ?
'status5' :
'status4', 3,
'dot');
5925 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'));
5929 $statuttrans = empty($status) ?
'status5' :
'status4';
5934 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSellShort');
5935 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnSell');
5936 } elseif ($type == 1) {
5937 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuyShort');
5938 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBuy');
5939 } elseif ($type == 2) {
5940 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatch');
5941 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusNotOnBatchShort');
5943 } elseif ($status == 1) {
5946 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSellShort');
5947 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSell');
5948 } elseif ($type == 1) {
5949 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnBuyShort');
5950 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnBuy');
5951 } elseif ($type == 2) {
5952 $labelStatus = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatch') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerial'));
5953 $labelStatusShort = ($status == 1 ? $langs->transnoentitiesnoconv(
'ProductStatusOnBatchShort') : $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort'));
5955 } elseif ($type == 2 && $status == 2) {
5956 $labelStatus = $langs->transnoentitiesnoconv(
'ProductStatusOnSerial');
5957 $labelStatusShort = $langs->transnoentitiesnoconv(
'ProductStatusOnSerialShort');
5961 return dolGetStatus($langs->transnoentitiesnoconv(
'Unknown'),
'',
'',
'status0', 0);
5963 return dolGetStatus($labelStatus, $labelStatusShort,
'', $statuttrans, $mode);
6213 global $hookmanager, $action;
6215 $stock_commande_client = 0;
6216 $stock_commande_fournisseur = 0;
6217 $stock_sending_client = 0;
6218 $stock_reception_fournisseur = 0;
6219 $stock_inproduction = 0;
6223 if (isModEnabled(
'order')) {
6228 $stock_commande_client = $this->stats_commande[
'qty'];
6230 if (isModEnabled(
"shipping")) {
6231 require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expedition.class.php';
6232 $filterShipmentStatus =
'';
6242 $stock_sending_client = $this->stats_expedition[
'qty'];
6245 if (isModEnabled(
"supplier_order")) {
6246 $filterStatus =
getDolGlobalString(
'SUPPLIER_ORDER_STATUS_FOR_VIRTUAL_STOCK',
'3,4');
6247 if (isset($includedraftpoforvirtual)) {
6248 $filterStatus =
'0,1,2,'.$filterStatus;
6254 $stock_commande_fournisseur = $this->stats_commande_fournisseur[
'qty'];
6257 if (isModEnabled(
"supplier_order") || isModEnabled(
"supplier_invoice")) {
6258 $filterStatus =
'4';
6259 if (isset($includedraftpoforvirtual)) {
6260 $filterStatus =
'0,'.$filterStatus;
6266 $stock_reception_fournisseur = $this->stats_reception[
'qty'];
6269 if (isModEnabled(
'mrp')) {
6274 $stock_inproduction = $this->stats_mrptoproduce[
'qty'] - $this->stats_mrptoconsume[
'qty'];
6277 $this->stock_theorique = $this->stock_reel + $stock_inproduction;
6281 $this->stock_theorique -= ($stock_commande_client - $stock_sending_client);
6283 $this->stock_theorique += 0;
6285 $this->stock_theorique -= $stock_commande_client;
6289 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6291 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6293 $this->stock_theorique -= $stock_reception_fournisseur;
6295 $this->stock_theorique += ($stock_commande_fournisseur - $stock_reception_fournisseur);
6298 $parameters = array(
'id' => $this->
id,
'includedraftpoforvirtual' => $includedraftpoforvirtual);
6300 $reshook = $hookmanager->executeHooks(
'loadvirtualstock', $parameters, $this, $action);
6302 $this->stock_theorique = $hookmanager->resArray[
'stock_theorique'];
6303 } elseif ($reshook == 0 && isset($hookmanager->resArray[
'stock_stats_hook'])) {
6304 $this->stock_theorique += $hookmanager->resArray[
'stock_stats_hook'];
6308 if (!empty($this->stock_warehouse) &&
getDolGlobalString(
'STOCK_ALLOW_VIRTUAL_STOCK_PER_WAREHOUSE')) {
6309 foreach ($this->stock_warehouse as $warehouseid => $stockwarehouse) {
6310 if (isModEnabled(
'mrp')) {
6317 if ($this->fk_default_warehouse == $warehouseid) {
6318 $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']);
6320 $this->stock_warehouse[$warehouseid]->virtual = $this->stock_warehouse[$warehouseid]->real + $this->stock_warehouse[$warehouseid]->stats_mrptoproduce[
'qty'];