NEW make sell or eat by mandatory in product lot

This commit is contained in:
VESSILLER 2023-05-30 08:37:17 +02:00
parent 2878cd879e
commit 8caa6131df
9 changed files with 515 additions and 127 deletions

View file

@ -43,6 +43,7 @@ require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
if (isModEnabled('project')) {
require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
}
require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php';
// Load translation files required by the page
$langs->loadLangs(array("bills", "orders", "sendings", "companies", "deliveries", "products", "stocks", "receptions"));
@ -327,6 +328,8 @@ if ($action == 'dispatch' && $permissiontoreceive) {
// We ask to move a qty
if (GETPOST($qty) > 0) {
$productId = (int) GETPOST($prod, 'int');
if (!(GETPOST($ent, 'int') > 0)) {
dol_syslog('No dispatch for line '.$key.' as no warehouse was chosen.');
$text = $langs->transnoentities('Warehouse').', '.$langs->transnoentities('Line').' '.($numline).'-'.($reg[1] + 1);
@ -334,7 +337,9 @@ if ($action == 'dispatch' && $permissiontoreceive) {
$error++;
}
if (!(GETPOST($lot, 'alpha') || $dDLUO || $dDLC)) {
// check sell-by / eat-by date is mandatory
$errorMsgArr = Productlot::checkSellOrEatByMandatoryFromProductIdAndDates($productId, $dDLC, $dDLUO);
if (!(GETPOST($lot, 'alpha')) || !empty($errorMsgArr)) {
dol_syslog('No dispatch for line '.$key.' as serial/eat-by/sellby date are not set');
$text = $langs->transnoentities('atleast1batchfield').', '.$langs->transnoentities('Line').' '.($numline).'-'.($reg[1] + 1);
setEventMessages($langs->trans('ErrorFieldRequired', $text), null, 'errors');
@ -342,7 +347,7 @@ if ($action == 'dispatch' && $permissiontoreceive) {
}
if (!$error) {
$result = $object->dispatchProduct($user, GETPOST($prod, 'int'), GETPOST($qty), GETPOST($ent, 'int'), GETPOST($pu), GETPOST('comment'), $dDLUO, $dDLC, GETPOST($lot, 'alpha'), GETPOST($fk_commandefourndet, 'int'), $notrigger);
$result = $object->dispatchProduct($user, $productId, GETPOST($qty), GETPOST($ent, 'int'), GETPOST($pu), GETPOST('comment'), $dDLUO, $dDLC, GETPOST($lot, 'alpha'), GETPOST($fk_commandefourndet, 'int'), $notrigger);
if ($result < 0) {
setEventMessages($object->error, $object->errors, 'errors');
$error++;
@ -359,7 +364,7 @@ if ($action == 'dispatch' && $permissiontoreceive) {
$sql .= ", price = ".price2num(GETPOST($pu), 'MU', 2)." * quantity";
$sql .= ", remise_percent = ".price2num((empty($dto) ? 0 : $dto), 3, 2)."'";
$sql .= " WHERE fk_soc = ".((int) $object->socid);
$sql .= " AND fk_product=".((int) GETPOST($prod, 'int'));
$sql .= " AND fk_product=".($productId);
$resql = $db->query($sql);
}

View file

@ -6,6 +6,9 @@ ProductStatusNotOnBatch=No (lot/serial not used)
ProductStatusOnBatchShort=Lot
ProductStatusOnSerialShort=Serial
ProductStatusNotOnBatchShort=No
BatchSellOrEatByMandatoryList=Make %s or %s mandatory
BatchSellOrEatByMandatoryNone=None
BatchSellOrEatByMandatoryAll=%s and %s
Batch=Lot/Serial
atleast1batchfield=Eat-by date or Sell-by date or Lot/Serial number
batch_number=Lot/Serial number

View file

@ -0,0 +1,69 @@
<?php
/* Copyright (C) 2023 Lionel Vessiller <lvessiller@open-dsi.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* \file htdocs/takepos/ajax/ajax.php
* \brief Ajax search component for TakePos. It search products of a category.
*/
if (!defined('NOTOKENRENEWAL')) {
define('NOTOKENRENEWAL', '1');
}
if (!defined('NOREQUIREMENU')) {
define('NOREQUIREMENU', '1');
}
if (!defined('NOREQUIREHTML')) {
define('NOREQUIREHTML', '1');
}
if (!defined('NOREQUIREAJAX')) {
define('NOREQUIREAJAX', '1');
}
if (!defined('NOBROWSERNOTIF')) {
define('NOBROWSERNOTIF', '1');
}
// Load Dolibarr environment
require '../../main.inc.php'; // Load $user and permissions
require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php';
$action = GETPOST('action', 'aZ09');
$productId = GETPOST('product_id', 'int');
$batch = GETPOST('batch', 'alphanohtml');
/*
* View
*/
top_httphead('application/json');
$rows = array();
if ($action == 'search' && $batch != '') {
$productLot = new Productlot($db);
$result = $productLot->fetch('', $productId, $batch);
if ($result > 0 && $productLot->id > 0) {
$rows[] = array(
'rowid' => $productLot->id,
'sellby' => ($productLot->sellby ? dol_print_date($productLot->sellby, 'day') : ''),
'eatby' => ($productLot->eatby ? dol_print_date($productLot->eatby, 'day') : ''),
);
}
}
echo json_encode($rows);
exit();

View file

@ -537,6 +537,7 @@ if (empty($reshook)) {
$object->status = GETPOST('statut');
$object->status_buy = GETPOST('statut_buy');
$object->status_batch = GETPOST('status_batch');
$object->sell_or_eat_by_mandatory = GETPOST('sell_or_eat_by_mandatory', 'int');
$object->batch_mask = GETPOST('batch_mask');
$object->barcode_type = GETPOST('fk_barcode_type');
@ -731,6 +732,7 @@ if (empty($reshook)) {
$object->status = GETPOST('statut', 'int');
$object->status_buy = GETPOST('statut_buy', 'int');
$object->status_batch = GETPOST('status_batch', 'aZ09');
$object->sell_or_eat_by_mandatory = GETPOST('sell_or_eat_by_mandatory', 'int');
$object->batch_mask = GETPOST('batch_mask', 'alpha');
$object->fk_default_warehouse = GETPOST('fk_default_warehouse');
$object->fk_default_workstation = GETPOST('fk_default_workstation');
@ -1217,7 +1219,10 @@ $formcompany = new FormCompany($db);
if (isModEnabled('accounting')) {
$formaccounting = new FormAccounting($db);
}
$sellOrEatByMandatoryList = null;
if (isModEnabled('productbatch')) {
$sellOrEatByMandatoryList = Product::getSellOrEatByMandatoryList();
}
$title = $langs->trans('ProductServiceCard');
@ -1417,6 +1422,13 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) {
print '</td></tr>';
}
}
// SellBy / EatBy mandatory list
if (!empty($sellOrEatByMandatoryList)) {
print '<tr><td>'.$langs->trans('BatchSellOrEatByMandatoryList', $langs->trans('SellByDate'), $langs->trans('EatByDate')).'</td><td>';
print $form->selectarray('sell_or_eat_by_mandatory', $sellOrEatByMandatoryList, GETPOST('sell_or_eat_by_mandatory', 'int'));
print '</td></tr>';
}
}
$showbarcode = isModEnabled('barcode');
@ -1981,6 +1993,18 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) {
print '</td></tr>';
}
}
// SellBy / EatBy mandatory list
if (!empty($sellOrEatByMandatoryList)) {
if (GETPOSTISSET('sell_or_eat_by_mandatory')) {
$sellOrEatByMandatorySelectedId = GETPOST('sell_or_eat_by_mandatory', 'int');
} else {
$sellOrEatByMandatorySelectedId = $object->sell_or_eat_by_mandatory;
}
print '<tr><td>'.$langs->trans('BatchSellOrEatByMandatoryList', $langs->trans('SellByDate'), $langs->trans('EatByDate')).'</td><td>';
print $form->selectarray('sell_or_eat_by_mandatory', $sellOrEatByMandatoryList, $sellOrEatByMandatorySelectedId);
print '</td></tr>';
}
}
// Barcode
@ -2419,6 +2443,10 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) {
print '</td></tr>';
}
}
print '<tr><td>'.$langs->trans('BatchSellOrEatByMandatoryList', $langs->trans('SellByDate'), $langs->trans('EatByDate')).'</td><td>';
print $object->getSellOrEatByMandatoryLabel();
print '</td></tr>';
}
if (empty($conf->global->PRODUCT_DISABLE_ACCOUNTING)) {

View file

@ -45,6 +45,14 @@ require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
*/
class Product extends CommonObject
{
/**
* Const sell or eat by mandatory id
*/
const SELL_OR_EAT_BY_MANDATORY_ID_NONE = 0;
const SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY = 1;
const SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY = 2;
const SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT = 3;
/**
* @var string ID to identify managed object
*/
@ -324,6 +332,13 @@ class Product extends CommonObject
*/
public $status_batch = 0;
/**
* Make sell-by or eat-by date mandatory
*
* @var int
*/
public $sell_or_eat_by_mandatory = 0;
/**
* If allowed, we can edit batch or serial number mask for each product
*
@ -783,6 +798,7 @@ class Product extends CommonObject
$sql .= ", canvas";
$sql .= ", finished";
$sql .= ", tobatch";
$sql .= ", sell_or_eat_by_mandatory";
$sql .= ", batch_mask";
$sql .= ", fk_unit";
$sql .= ", mandatory_period";
@ -812,6 +828,7 @@ class Product extends CommonObject
$sql .= ", '".$this->db->escape($this->canvas)."'";
$sql .= ", ".((!isset($this->finished) || $this->finished < 0 || $this->finished == '') ? 'NULL' : (int) $this->finished);
$sql .= ", ".((empty($this->status_batch) || $this->status_batch < 0) ? '0' : ((int) $this->status_batch));
$sql .= ", ".((empty($this->sell_or_eat_by_mandatory) || $this->sell_or_eat_by_mandatory < 0) ? 0 : ((int) $this->sell_or_eat_by_mandatory));
$sql .= ", '".$this->db->escape($this->batch_mask)."'";
$sql .= ", ".($this->fk_unit > 0 ? ((int) $this->fk_unit) : 'NULL');
$sql .= ", '".$this->db->escape($this->mandatory_period)."'";
@ -1193,6 +1210,7 @@ class Product extends CommonObject
$sql .= ", tosell = ".(int) $this->status;
$sql .= ", tobuy = ".(int) $this->status_buy;
$sql .= ", tobatch = ".((empty($this->status_batch) || $this->status_batch < 0) ? '0' : (int) $this->status_batch);
$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);
$sql .= ", batch_mask = '".$this->db->escape($this->batch_mask)."'";
$sql .= ", finished = ".((!isset($this->finished) || $this->finished < 0 || $this->finished == '') ? "null" : (int) $this->finished);
@ -1526,6 +1544,42 @@ class Product extends CommonObject
}
}
/**
* Get sell or eat by mandatory list
*
* @return array Sell or eat by mandatory list
*/
public static function getSellOrEatByMandatoryList()
{
global $langs;
$sellByLabel = $langs->trans('SellByDate');
$eatByLabel = $langs->trans('EatByDate');
return array(
self::SELL_OR_EAT_BY_MANDATORY_ID_NONE => $langs->trans('BatchSellOrEatByMandatoryNone'),
self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY => $sellByLabel,
self::SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY => $eatByLabel,
self::SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT => $langs->trans('BatchSellOrEatByMandatoryAll', $sellByLabel, $eatByLabel),
);
}
/**
* Get sell or eat by mandatory label
*
* @return string Sell or eat by mandatory label
*/
public function getSellOrEatByMandatoryLabel()
{
$sellOrEatByMandatoryLabel = '';
$sellOrEatByMandatoryList = self::getSellOrEatByMandatoryList();
if (isset($sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory])) {
$sellOrEatByMandatoryLabel = $sellOrEatByMandatoryList[$this->sell_or_eat_by_mandatory];
}
return $sellOrEatByMandatoryLabel;
}
/**
* Update or add a translation for a product
*
@ -2417,7 +2471,7 @@ class Product extends CommonObject
} else {
$sql .= " p.pmp,";
}
$sql .= " p.datec, p.tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.batch_mask, p.fk_unit,";
$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,";
$sql .= " p.fk_price_expression, p.price_autogen, p.model_pdf,";
if ($separatedStock) {
$sql .= " SUM(sp.reel) as stock";
@ -2460,7 +2514,7 @@ class Product extends CommonObject
} else {
$sql .= " p.pmp,";
}
$sql .= " p.datec, p.tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.batch_mask, p.fk_unit,";
$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,";
$sql .= " p.fk_price_expression, p.price_autogen, p.model_pdf";
if (!$separatedStock) {
$sql .= ", p.stock";
@ -2488,6 +2542,7 @@ class Product extends CommonObject
$this->status = $obj->tosell;
$this->status_buy = $obj->tobuy;
$this->status_batch = $obj->tobatch;
$this->sell_or_eat_by_mandatory = $obj->sell_or_eat_by_mandatory;
$this->batch_mask = $obj->batch_mask;
$this->customcode = $obj->customcode;
@ -6081,6 +6136,7 @@ class Product extends CommonObject
$this->status = 1;
$this->status_buy = 1;
$this->tobatch = 0;
$this->sell_or_eat_by_mandatory = 0;
$this->note_private = 'This is a comment (private)';
$this->note_public = 'This is a comment (public)';
$this->date_creation = $now;

View file

@ -105,13 +105,13 @@ class Productlot extends CommonObject
'fk_product' => array('type'=>'integer:Product:product/class/product.class.php', 'label'=>'Product', 'enabled'=>1, 'visible'=>1, 'position'=>5, 'notnull'=>1, 'index'=>1, 'searchall'=>1),
'batch' => array('type'=>'varchar(30)', 'label'=>'Batch', 'enabled'=>1, 'visible'=>1, 'notnull'=>0, 'showoncombobox'=>1, 'index'=>1, 'position'=>10, 'comment'=>'Batch', 'searchall'=>1),
'entity' => array('type'=>'integer', 'label'=>'Entity', 'enabled'=>1, 'visible'=>0, 'default'=>1, 'notnull'=>1, 'index'=>1, 'position'=>20),
'sellby' => array('type'=>'date', 'label'=>'SellByDate', 'enabled'=>'empty($conf->global->PRODUCT_DISABLE_SELLBY)?1:0', 'visible'=>5, 'position'=>60),
'sellby' => array('type'=>'date', 'label'=>'SellByDate', 'enabled'=>'empty($conf->global->PRODUCT_DISABLE_SELLBY)?1:0', 'visible'=>1, 'notnull'=>0, 'position'=>60),
'eol_date' => array('type'=>'date', 'label'=>'EndOfLife', 'enabled'=>'empty($conf->global->PRODUCT_ENABLE_TRACEABILITY)?0:1', 'visible'=>5, 'position'=>70),
'manufacturing_date' => array('type'=>'date', 'label'=>'ManufacturingDate', 'enabled'=>'empty($conf->global->PRODUCT_ENABLE_TRACEABILITY)?0:1', 'visible'=>5, 'position'=>80),
'scrapping_date' => array('type'=>'date', 'label'=>'DestructionDate', 'enabled'=>'empty($conf->global->PRODUCT_ENABLE_TRACEABILITY)?0:1', 'visible'=>5, 'position'=>90),
//'commissionning_date' => array('type'=>'date', 'label'=>'FirstUseDate', 'enabled'=>'empty($conf->global->PRODUCT_ENABLE_TRACEABILITY)?0:1', 'visible'=>5, 'position'=>100),
//'qc_frequency' => array('type'=>'varchar(6)', 'label'=>'QCFrequency', 'enabled'=>'empty($conf->global->PRODUCT_ENABLE_QUALITYCONTROL)?1:0', 'visible'=>5, 'position'=>110),
'eatby' => array('type'=>'date', 'label'=>'EatByDate', 'enabled'=>'empty($conf->global->PRODUCT_DISABLE_EATBY)?1:0', 'visible'=>5, 'position'=>62),
'eatby' => array('type'=>'date', 'label'=>'EatByDate', 'enabled'=>'empty($conf->global->PRODUCT_DISABLE_EATBY)?1:0', 'visible'=>1, 'notnull'=>0, 'position'=>62),
'model_pdf' => array('type' => 'varchar(255)', 'label' => 'Model pdf', 'enabled' => 1, 'visible' => 0, 'position' => 215),
'last_main_doc' => array('type' => 'varchar(255)', 'label' => 'LastMainDoc', 'enabled' => 1, 'visible' => -1, 'position' => 310),
'datec' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'position'=>500),
@ -171,6 +171,126 @@ class Productlot extends CommonObject
$this->db = $db;
}
/**
* Check sell or eat by date is mandatory
*
* @param string $onlyFieldName [=''] check all fields by default or only one field name ("sellby", "eatby")
* @return int <0 if KO, 0 nothing done, >0 if OK
*/
public function checkSellOrEatByMandatory($onlyFieldName = '')
{
global $conf;
if (!empty($conf->global->PRODUCT_DISABLE_SELLBY) && !empty($conf->global->PRODUCT_DISABLE_EATBY)) {
return 0;
}
$errorMsgArr = array();
if ($this->fk_product > 0) {
$res = $this->fetch_product();
$product = $this->product;
if ($res <= 0) {
$errorMsgArr[] = $product->errorsToString();
}
if (empty($errorMsgArr)) {
$errorMsgArr = self::checkSellOrEatByMandatoryFromProductAndDates($product, $this->sellby, $this->eatby, $onlyFieldName, true);
}
}
if (!empty($errorMsgArr)) {
$this->errors = array_merge($this->errors, $errorMsgArr);
return -1;
} else {
return 1;
}
}
/**
* Check sell or eat by date is mandatory from product id and sell-by and eat-by dates
*
* @param int $productId Product id
* @param int $sellBy Sell by date
* @param int $eatBy Eat by date
* @param string $onlyFieldName [=''] check all fields by default or only one field name ("sellby", "eatby")
* @return array|null Array of errors or null if nothing done
*/
public static function checkSellOrEatByMandatoryFromProductIdAndDates($productId, $sellBy, $eatBy, $onlyFieldName = '')
{
global $conf, $db;
if (!empty($conf->global->PRODUCT_DISABLE_SELLBY) && !empty($conf->global->PRODUCT_DISABLE_EATBY)) {
return null;
}
$errorMsgArr = array();
if ($productId > 0) {
$product = new Product($db);
$res = $product->fetch($productId);
if ($res <= 0) {
$errorMsgArr[] = $product->errorsToString();
}
if (empty($errorMsgArr)) {
$errorMsgArr = self::checkSellOrEatByMandatoryFromProductAndDates($product, $sellBy, $eatBy, $onlyFieldName, true);
}
}
return $errorMsgArr;
}
/**
* Check sell or eat by date is mandatory from product and sell-by and eat-by dates
*
* @param Product $product Product object
* @param int $sellBy Sell by date
* @param int $eatBy Eat by date
* @param string $onlyFieldName [=''] check all fields by default or only one field name ("sellby", "eatby")
* @param bool $alreadyCheckConf [=false] conf hasn't been already checked by default or true not to check conf
* @return array|null Array of errors or null if nothing done
*/
public static function checkSellOrEatByMandatoryFromProductAndDates($product, $sellBy, $eatBy, $onlyFieldName = '', $alreadyCheckConf = false)
{
global $conf, $langs;
if ($alreadyCheckConf === false && !empty($conf->global->PRODUCT_DISABLE_SELLBY) && !empty($conf->global->PRODUCT_DISABLE_EATBY)) {
return null;
}
$errorMsgArr = array();
$checkSellByMandatory = false;
$checkEatByMandatory = false;
$sellOrEatByMandatoryId = $product->sell_or_eat_by_mandatory;
if (empty($conf->global->PRODUCT_DISABLE_SELLBY) && $sellOrEatByMandatoryId == Product::SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY && ($onlyFieldName == '' || $onlyFieldName == 'sellby')) {
$checkSellByMandatory = true;
} elseif (empty($conf->global->PRODUCT_DISABLE_EATBY) && $sellOrEatByMandatoryId == Product::SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY && ($onlyFieldName == '' || $onlyFieldName == 'eatby')) {
$checkEatByMandatory = true;
} elseif ($sellOrEatByMandatoryId == Product::SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT) {
if (empty($conf->global->PRODUCT_DISABLE_SELLBY) && ($onlyFieldName == '' || $onlyFieldName == 'sellby')) {
$checkSellByMandatory = true;
}
if (empty($conf->global->PRODUCT_DISABLE_EATBY) && ($onlyFieldName == '' || $onlyFieldName == 'eatby')) {
$checkEatByMandatory = true;
}
}
if ($checkSellByMandatory === true) {
if (!isset($sellBy) || dol_strlen($sellBy) == 0) {
// error : sell by is mandatory
$errorMsgArr[] = $langs->trans('ErrorFieldRequired', $langs->transnoentities('SellByDate'));
}
}
if ($checkEatByMandatory === true) {
if (!isset($eatBy) || dol_strlen($eatBy) == 0) {
// error : eat by is mandatory
$errorMsgArr[] = $langs->trans('ErrorFieldRequired', $langs->transnoentities('EatByDate'));
}
}
return $errorMsgArr;
}
/**
* Create object into database
*
@ -209,78 +329,86 @@ class Productlot extends CommonObject
// Check parameters
// Put here code to add control on parameters values
// Insert request
$sql = 'INSERT INTO '.$this->db->prefix().$this->table_element.'(';
$sql .= 'entity,';
$sql .= 'fk_product,';
$sql .= 'batch,';
$sql .= 'eatby,';
$sql .= 'sellby,';
$sql .= 'eol_date,';
$sql .= 'manufacturing_date,';
$sql .= 'scrapping_date,';
//$sql .= 'commissionning_date,';
//$sql .= 'qc_frequency,';
$sql .= 'datec,';
$sql .= 'fk_user_creat,';
$sql .= 'fk_user_modif,';
$sql .= 'import_key';
$sql .= ') VALUES (';
$sql .= ' '.(!isset($this->entity) ? $conf->entity : $this->entity).',';
$sql .= ' '.(!isset($this->fk_product) ? 'NULL' : $this->fk_product).',';
$sql .= ' '.(!isset($this->batch) ? 'NULL' : "'".$this->db->escape($this->batch)."'").',';
$sql .= ' '.(!isset($this->eatby) || dol_strlen($this->eatby) == 0 ? 'NULL' : "'".$this->db->idate($this->eatby)."'").',';
$sql .= ' '.(!isset($this->sellby) || dol_strlen($this->sellby) == 0 ? 'NULL' : "'".$this->db->idate($this->sellby)."'").',';
$sql .= ' '.(!isset($this->eol_date) || dol_strlen($this->eol_date) == 0 ? 'NULL' : "'".$this->db->idate($this->eol_date)."'").',';
$sql .= ' '.(!isset($this->manufacturing_date) || dol_strlen($this->manufacturing_date) == 0 ? 'NULL' : "'".$this->db->idate($this->manufacturing_date)."'").',';
$sql .= ' '.(!isset($this->scrapping_date) || dol_strlen($this->scrapping_date) == 0 ? 'NULL' : "'".$this->db->idate($this->scrapping_date)."'").',';
//$sql .= ' '.(!isset($this->commissionning_date) || dol_strlen($this->commissionning_date) == 0 ? 'NULL' : "'".$this->db->idate($this->commissionning_date)."'").',';
//$sql .= ' '.(!isset($this->qc_frequency) ? 'NULL' : $this->qc_frequency).',';
$sql .= ' '."'".$this->db->idate(dol_now())."'".',';
$sql .= ' '.(!isset($this->fk_user_creat) ? 'NULL' : $this->fk_user_creat).',';
$sql .= ' '.(!isset($this->fk_user_modif) ? 'NULL' : $this->fk_user_modif).',';
$sql .= ' '.(!isset($this->import_key) ? 'NULL' : $this->import_key);
$sql .= ')';
$this->db->begin();
$resql = $this->db->query($sql);
if (!$resql) {
$res = $this->checkSellOrEatByMandatory();
if ($res < 0) {
$error++;
$this->errors[] = 'Error '.$this->db->lasterror();
dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
}
if (!$error) {
$this->id = $this->db->last_insert_id($this->db->prefix().$this->table_element);
// Insert request
$sql = 'INSERT INTO ' . $this->db->prefix() . $this->table_element . '(';
$sql .= 'entity,';
$sql .= 'fk_product,';
$sql .= 'batch,';
$sql .= 'eatby,';
$sql .= 'sellby,';
$sql .= 'eol_date,';
$sql .= 'manufacturing_date,';
$sql .= 'scrapping_date,';
//$sql .= 'commissionning_date,';
//$sql .= 'qc_frequency,';
$sql .= 'datec,';
$sql .= 'fk_user_creat,';
$sql .= 'fk_user_modif,';
$sql .= 'import_key';
$sql .= ') VALUES (';
$sql .= ' ' . (!isset($this->entity) ? $conf->entity : $this->entity) . ',';
$sql .= ' ' . (!isset($this->fk_product) ? 'NULL' : $this->fk_product) . ',';
$sql .= ' ' . (!isset($this->batch) ? 'NULL' : "'" . $this->db->escape($this->batch) . "'") . ',';
$sql .= ' ' . (!isset($this->eatby) || dol_strlen($this->eatby) == 0 ? 'NULL' : "'" . $this->db->idate($this->eatby) . "'") . ',';
$sql .= ' ' . (!isset($this->sellby) || dol_strlen($this->sellby) == 0 ? 'NULL' : "'" . $this->db->idate($this->sellby) . "'") . ',';
$sql .= ' ' . (!isset($this->eol_date) || dol_strlen($this->eol_date) == 0 ? 'NULL' : "'" . $this->db->idate($this->eol_date) . "'") . ',';
$sql .= ' ' . (!isset($this->manufacturing_date) || dol_strlen($this->manufacturing_date) == 0 ? 'NULL' : "'" . $this->db->idate($this->manufacturing_date) . "'") . ',';
$sql .= ' ' . (!isset($this->scrapping_date) || dol_strlen($this->scrapping_date) == 0 ? 'NULL' : "'" . $this->db->idate($this->scrapping_date) . "'") . ',';
//$sql .= ' '.(!isset($this->commissionning_date) || dol_strlen($this->commissionning_date) == 0 ? 'NULL' : "'".$this->db->idate($this->commissionning_date)."'").',';
//$sql .= ' '.(!isset($this->qc_frequency) ? 'NULL' : $this->qc_frequency).',';
$sql .= ' ' . "'" . $this->db->idate(dol_now()) . "'" . ',';
$sql .= ' ' . (!isset($this->fk_user_creat) ? 'NULL' : $this->fk_user_creat) . ',';
$sql .= ' ' . (!isset($this->fk_user_modif) ? 'NULL' : $this->fk_user_modif) . ',';
$sql .= ' ' . (!isset($this->import_key) ? 'NULL' : $this->import_key);
$sql .= ')';
$this->db->begin();
$resql = $this->db->query($sql);
if (!$resql) {
$error++;
$this->errors[] = 'Error ' . $this->db->lasterror();
}
// Actions on extra fields
if (!$error) {
$result = $this->insertExtraFields();
if ($result < 0) {
$error++;
$this->id = $this->db->last_insert_id($this->db->prefix() . $this->table_element);
// Actions on extra fields
if (!$error) {
$result = $this->insertExtraFields();
if ($result < 0) {
$error++;
}
}
if (!$error && !$notrigger) {
// Call triggers
$result = $this->call_trigger('PRODUCTLOT_CREATE', $user);
if ($result < 0) {
$error++;
}
// End call triggers
}
}
if (!$error && !$notrigger) {
// Call triggers
$result = $this->call_trigger('PRODUCTLOT_CREATE', $user);
if ($result < 0) {
$error++;
}
// End call triggers
// Commit or rollback
if ($error) {
$this->db->rollback();
} else {
$this->db->commit();
}
}
// Commit or rollback
if ($error) {
$this->db->rollback();
dol_syslog(__METHOD__ . ' ' . join(',', $this->errors), LOG_ERR);
return -1 * $error;
} else {
$this->db->commit();
return $this->id;
}
}
@ -412,64 +540,75 @@ class Productlot extends CommonObject
$this->import_key = trim($this->import_key);
}
// Check parameters
// Put here code to add a control on parameters values
$res = $this->checkSellOrEatByMandatory();
if ($res < 0) {
$error++;
}
// $this->oldcopy should have been set by the caller of update (here properties were already modified)
if (empty($this->oldcopy)) {
$this->oldcopy = dol_clone($this);
}
// Update request
$sql = 'UPDATE '.$this->db->prefix().$this->table_element.' SET';
$sql .= ' entity = '.(isset($this->entity) ? $this->entity : "null").',';
$sql .= ' fk_product = '.(isset($this->fk_product) ? $this->fk_product : "null").',';
$sql .= ' batch = '.(isset($this->batch) ? "'".$this->db->escape($this->batch)."'" : "null").',';
$sql .= ' eatby = '.(!isset($this->eatby) || dol_strlen($this->eatby) != 0 ? "'".$this->db->idate($this->eatby)."'" : 'null').',';
$sql .= ' sellby = '.(!isset($this->sellby) || dol_strlen($this->sellby) != 0 ? "'".$this->db->idate($this->sellby)."'" : 'null').',';
$sql .= ' eol_date = '.(!isset($this->eol_date) || dol_strlen($this->eol_date) != 0 ? "'".$this->db->idate($this->eol_date)."'" : 'null').',';
$sql .= ' manufacturing_date = '.(!isset($this->manufacturing_date) || dol_strlen($this->manufacturing_date) != 0 ? "'".$this->db->idate($this->manufacturing_date)."'" : 'null').',';
$sql .= ' scrapping_date = '.(!isset($this->scrapping_date) || dol_strlen($this->scrapping_date) != 0 ? "'".$this->db->idate($this->scrapping_date)."'" : 'null').',';
//$sql .= ' commissionning_date = '.(!isset($this->first_use_date) || dol_strlen($this->first_use_date) != 0 ? "'".$this->db->idate($this->first_use_date)."'" : 'null').',';
//$sql .= ' qc_frequency = '.(!isset($this->qc_frequency) || dol_strlen($this->qc_frequency) != 0 ? "'".$this->db->escape($this->qc_frequency)."'" : 'null').',';
$sql .= ' datec = '.(!isset($this->datec) || dol_strlen($this->datec) != 0 ? "'".$this->db->idate($this->datec)."'" : 'null').',';
$sql .= ' tms = '.(dol_strlen($this->tms) != 0 ? "'".$this->db->idate($this->tms)."'" : "'".$this->db->idate(dol_now())."'").',';
$sql .= ' fk_user_creat = '.(isset($this->fk_user_creat) ? $this->fk_user_creat : "null").',';
$sql .= ' fk_user_modif = '.(isset($this->fk_user_modif) ? $this->fk_user_modif : "null").',';
$sql .= ' import_key = '.(isset($this->import_key) ? $this->import_key : "null");
$sql .= ' WHERE rowid='.((int) $this->id);
$this->db->begin();
$resql = $this->db->query($sql);
if (!$resql) {
$error++;
$this->errors[] = 'Error '.$this->db->lasterror();
dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
}
// Actions on extra fields
if (!$error) {
$result = $this->insertExtraFields();
if ($result < 0) {
// Update request
$sql = 'UPDATE ' . $this->db->prefix() . $this->table_element . ' SET';
$sql .= ' entity = ' . (isset($this->entity) ? $this->entity : "null") . ',';
$sql .= ' fk_product = ' . (isset($this->fk_product) ? $this->fk_product : "null") . ',';
$sql .= ' batch = ' . (isset($this->batch) ? "'" . $this->db->escape($this->batch) . "'" : "null") . ',';
$sql .= ' eatby = ' . (!isset($this->eatby) || dol_strlen($this->eatby) != 0 ? "'" . $this->db->idate($this->eatby) . "'" : 'null') . ',';
$sql .= ' sellby = ' . (!isset($this->sellby) || dol_strlen($this->sellby) != 0 ? "'" . $this->db->idate($this->sellby) . "'" : 'null') . ',';
$sql .= ' eol_date = ' . (!isset($this->eol_date) || dol_strlen($this->eol_date) != 0 ? "'" . $this->db->idate($this->eol_date) . "'" : 'null') . ',';
$sql .= ' manufacturing_date = ' . (!isset($this->manufacturing_date) || dol_strlen($this->manufacturing_date) != 0 ? "'" . $this->db->idate($this->manufacturing_date) . "'" : 'null') . ',';
$sql .= ' scrapping_date = ' . (!isset($this->scrapping_date) || dol_strlen($this->scrapping_date) != 0 ? "'" . $this->db->idate($this->scrapping_date) . "'" : 'null') . ',';
//$sql .= ' commissionning_date = '.(!isset($this->first_use_date) || dol_strlen($this->first_use_date) != 0 ? "'".$this->db->idate($this->first_use_date)."'" : 'null').',';
//$sql .= ' qc_frequency = '.(!isset($this->qc_frequency) || dol_strlen($this->qc_frequency) != 0 ? "'".$this->db->escape($this->qc_frequency)."'" : 'null').',';
$sql .= ' datec = ' . (!isset($this->datec) || dol_strlen($this->datec) != 0 ? "'" . $this->db->idate($this->datec) . "'" : 'null') . ',';
$sql .= ' tms = ' . (dol_strlen($this->tms) != 0 ? "'" . $this->db->idate($this->tms) . "'" : "'" . $this->db->idate(dol_now()) . "'") . ',';
$sql .= ' fk_user_creat = ' . (isset($this->fk_user_creat) ? $this->fk_user_creat : "null") . ',';
$sql .= ' fk_user_modif = ' . (isset($this->fk_user_modif) ? $this->fk_user_modif : "null") . ',';
$sql .= ' import_key = ' . (isset($this->import_key) ? $this->import_key : "null");
$sql .= ' WHERE rowid=' . ((int)$this->id);
$this->db->begin();
$resql = $this->db->query($sql);
if (!$resql) {
$error++;
$this->errors[] = 'Error ' . $this->db->lasterror();
}
// Actions on extra fields
if (!$error) {
$result = $this->insertExtraFields();
if ($result < 0) {
$error++;
}
}
if (!$error && !$notrigger) {
// Call triggers
$result = $this->call_trigger('PRODUCTLOT_MODIFY', $user);
if ($result < 0) {
$error++;
}
// End call triggers
}
// Commit or rollback
if ($error) {
$this->db->rollback();
} else {
$this->db->commit();
}
}
if (!$error && !$notrigger) {
// Call triggers
$result = $this->call_trigger('PRODUCTLOT_MODIFY', $user);
if ($result < 0) {
$error++;
}
// End call triggers
}
// Commit or rollback
if ($error) {
$this->db->rollback();
dol_syslog(__METHOD__ . ' ' . join(',', $this->errors), LOG_ERR);
return -1 * $error;
} else {
$this->db->commit();
return 1;
}
}

View file

@ -150,10 +150,24 @@ if (empty($reshook)) {
if ($action == 'seteatby' && $user->rights->stock->creer && ! GETPOST('cancel', 'alpha')) {
$newvalue = dol_mktime(12, 0, 0, GETPOST('eatbymonth', 'int'), GETPOST('eatbyday', 'int'), GETPOST('eatbyyear', 'int'));
$result = $object->setValueFrom('eatby', $newvalue, '', null, 'date', '', $user, 'PRODUCTLOT_MODIFY');
if ($result < 0) {
setEventMessages($object->error, null, 'errors');
$action == 'editeatby';
// check parameters
$object->eatby = $newvalue;
$res = $object->checkSellOrEatByMandatory('eatby');
if ($res < 0) {
$error++;
}
if (!$error) {
$result = $object->setValueFrom('eatby', $newvalue, '', null, 'date', '', $user, 'PRODUCTLOT_MODIFY');
if ($result < 0) {
$error++;
}
}
if ($error) {
setEventMessages($object->error, $object->errors, 'errors');
$action = 'editeatby';
} else {
$action = 'view';
}
@ -161,10 +175,24 @@ if (empty($reshook)) {
if ($action == 'setsellby' && $user->rights->stock->creer && ! GETPOST('cancel', 'alpha')) {
$newvalue = dol_mktime(12, 0, 0, GETPOST('sellbymonth', 'int'), GETPOST('sellbyday', 'int'), GETPOST('sellbyyear', 'int'));
$result = $object->setValueFrom('sellby', $newvalue, '', null, 'date', '', $user, 'PRODUCTLOT_MODIFY');
if ($result < 0) {
setEventMessages($object->error, null, 'errors');
$action == 'editsellby';
// check parameters
$object->sellby = $newvalue;
$res = $object->checkSellOrEatByMandatory('sellby');
if ($res < 0) {
$error++;
}
if (!$error) {
$result = $object->setValueFrom('sellby', $newvalue, '', null, 'date', '', $user, 'PRODUCTLOT_MODIFY');
if ($result < 0) {
$error++;
}
}
if ($error) {
setEventMessages($object->error, $object->errors, 'errors');
$action = 'editsellby';
} else {
$action = 'view';
}
@ -377,7 +405,17 @@ $title = $langs->trans("ProductLot");
$help_url = '';
llxHeader('', $title, $help_url);
$res = $object->fetch_product();
if ($res > 0 && $object->product) {
if ($object->product->sell_or_eat_by_mandatory == Product::SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY) {
$object->fields['sellby']['notnull'] = 1;
} elseif ($object->product->sell_or_eat_by_mandatory == Product::SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY) {
$object->fields['eatby']['notnull'] = 1;
} elseif ($object->product->sell_or_eat_by_mandatory == Product::SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT) {
$object->fields['sellby']['notnull'] = 1;
$object->fields['eatby']['notnull'] = 1;
}
}
// Part to create
if ($action == 'create') {
@ -468,7 +506,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
// Sell by
if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
print '<tr><td>';
print $form->editfieldkey($langs->trans('SellByDate'), 'sellby', $object->sellby, $object, $user->rights->stock->creer, 'datepicker');
print $form->editfieldkey($langs->trans('SellByDate'), 'sellby', $object->sellby, $object, $user->rights->stock->creer, 'datepicker', '', $object->fields['sellby']['notnull']);
print '</td><td>';
print $form->editfieldval($langs->trans('SellByDate'), 'sellby', $object->sellby, $object, $user->rights->stock->creer, 'datepicker', '', null, null, '', 1, '', 'id', 'auto', array(), $action);
print '</td>';
@ -478,7 +516,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
// Eat by
if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
print '<tr><td>';
print $form->editfieldkey($langs->trans('EatByDate'), 'eatby', $object->eatby, $object, $user->rights->stock->creer, 'datepicker');
print $form->editfieldkey($langs->trans('EatByDate'), 'eatby', $object->eatby, $object, $user->rights->stock->creer, 'datepicker', '', $object->fields['eatby']['notnull']);
print '</td><td>';
print $form->editfieldval($langs->trans('EatByDate'), 'eatby', $object->eatby, $object, $user->rights->stock->creer, 'datepicker', '', null, null, '', 1, '', 'id', 'auto', array(), $action);
print '</td>';

View file

@ -29,6 +29,10 @@ if (empty($conf) || !is_object($conf)) {
<!-- BEGIN PHP TEMPLATE STOCKCORRECTION.TPL.PHP -->
<?php
/**
* @var Product $object
*/
$productref = '';
if ($object->element == 'product') {
$productref = $object->ref;
@ -54,6 +58,19 @@ if ($pdluoid > 0) {
}
}
$sellByCss = '';
$eatByCss = '';
if ($object->sell_or_eat_by_mandatory == Product::SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY) {
$sellByCss = 'fieldrequired';
} elseif ($object->sell_or_eat_by_mandatory == Product::SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY) {
$eatByCss = 'fieldrequired';
} elseif ($object->sell_or_eat_by_mandatory == Product::SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT) {
$sellByCss = 'fieldrequired';
$eatByCss = 'fieldrequired';
}
$disableSellBy = getDolGlobalInt('PRODUCT_DISABLE_SELLBY');
$disableEatBy = getDolGlobalInt('PRODUCT_DISABLE_EATBY');
print '<script type="text/javascript">
jQuery(document).ready(function() {
function init_price()
@ -81,9 +98,29 @@ print '<script type="text/javascript">
jQuery("#mouvement option[value=0]").attr("selected","selected").trigger("change");
jQuery("#mouvement").trigger("change");
}
});
});
</script>';
});';
if ($disableSellBy == 0 || $disableEatBy == 0) {
print '
var disableSellBy = '.dol_escape_js($disableSellBy).';
var disableEatBy = '.dol_escape_js($disableSellBy).';
jQuery("#batch_number").change(function(event) {
var batch = jQuery(this).val();
jQuery.getJSON("'.DOL_URL_ROOT.'/product/ajax/product_lot.php?action=search&token='.newToken().'&product_id='.$id.'&batch="+batch, function(data) {
if (data.length > 0) {
var productLot = data[0];
if (disableSellBy == 0) {
jQuery("#sellby").val(productLot.sellby);
}
if (disableEatBy == 0) {
jQuery("#eatby").val(productLot.eatby);
}
}
});
});';
}
print '});';
print '</script>';
print load_fiche_titre($langs->trans("StockCorrection"), '', 'generic');
@ -155,21 +192,21 @@ if (ismodEnabled('productbatch') &&
print '<input type="text" name="batch_number_bis" size="40" disabled="disabled" value="'.(GETPOST('batch_number') ?GETPOST('batch_number') : $pdluo->batch).'">';
print '<input type="hidden" name="batch_number" value="'.(GETPOST('batch_number') ?GETPOST('batch_number') : $pdluo->batch).'">';
} else {
print img_picto('', 'barcode', 'class="pictofixedwidth"').'<input type="text" name="batch_number" class="minwidth300" value="'.(GETPOST('batch_number') ? GETPOST('batch_number') : $pdluo->batch).'">';
print img_picto('', 'barcode', 'class="pictofixedwidth"').'<input type="text" id="batch_number" name="batch_number" class="minwidth300" value="'.(GETPOST('batch_number') ? GETPOST('batch_number') : $pdluo->batch).'">';
}
print '</td>';
print '</tr>';
print '<tr>';
if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
print '<td>'.$langs->trans("SellByDate").'</td><td>';
print '<td'.($sellByCss ? ' class="'.$sellByCss.'"' : '').'>'.$langs->trans("SellByDate").'</td><td>';
$sellbyselected = dol_mktime(0, 0, 0, GETPOST('sellbymonth'), GETPOST('sellbyday'), GETPOST('sellbyyear'));
// If form was opened for a specific pdluoid, field is disabled
print $form->selectDate(($pdluo->id > 0 ? $pdluo->sellby : $sellbyselected), 'sellby', '', '', 1, "", 1, 0, ($pdluoid > 0 ? 1 : 0));
print '</td>';
}
if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
print '<td>'.$langs->trans("EatByDate").'</td><td>';
print '<td'.($eatByCss ? ' class="'.$eatByCss.'"' : '').'>'.$langs->trans("EatByDate").'</td><td>';
$eatbyselected = dol_mktime(0, 0, 0, GETPOST('eatbymonth'), GETPOST('eatbyday'), GETPOST('eatbyyear'));
// If form was opened for a specific pdluoid, field is disabled
print $form->selectDate(($pdluo->id > 0 ? $pdluo->eatby : $eatbyselected), 'eatby', '', '', 1, "", 1, 0, ($pdluoid > 0 ? 1 : 0));

View file

@ -843,6 +843,19 @@ class Reception extends CommonObject
$this->error = $langs->trans('ErrorProductDoesNotNeedBatchNumber', $product->ref);
return -1;
}
// check sell-by / eat-by date is mandatory
$errorMsgArr = Productlot::checkSellOrEatByMandatoryFromProductAndDates($product, $sellby, $eatby);
if (!empty($errorMsgArr)) {
$errorMessage = '<b>' . $product->ref . '</b> : ';
$errorMessage .= '<ul>';
foreach ($errorMsgArr as $errorMsg) {
$errorMessage .= '<li>' . $errorMsg . '</li>';
}
$errorMessage .= '</ul>';
$this->error = $errorMessage;
return -1;
}
}
unset($product);