NEW add const CASHDESK_FORCE_DECREASE_STOCK to force batch decrementation
This commit is contained in:
parent
1f4b639ba0
commit
71c9b94b22
@ -2410,12 +2410,23 @@ class Facture extends CommonInvoice
|
||||
* @param string $force_number Reference to force on invoice
|
||||
* @param int $idwarehouse Id of warehouse to use for stock decrease if option to decreasenon stock is on (0=no decrease)
|
||||
* @param int $notrigger 1=Does not execute triggers, 0= execute triggers
|
||||
* @param int $batch_rule [=0] 0 not decrement batch, else batch rule to use
|
||||
* 1=take in batches ordered by sellby and eatby dates
|
||||
* @return int <0 if KO, 0=Nothing done because invoice is not a draft, >0 if OK
|
||||
*/
|
||||
public function validate($user, $force_number = '', $idwarehouse = 0, $notrigger = 0)
|
||||
public function validate($user, $force_number = '', $idwarehouse = 0, $notrigger = 0, $batch_rule = 0)
|
||||
{
|
||||
global $conf, $langs;
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
|
||||
$productStatic = null;
|
||||
$warehouseStatic = null;
|
||||
if ($batch_rule > 0) {
|
||||
require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT . '/product/class/productbatch.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
|
||||
$productStatic = new Product($this->db);
|
||||
$warehouseStatic = new Entrepot($this->db);
|
||||
}
|
||||
|
||||
$now = dol_now();
|
||||
|
||||
@ -2557,11 +2568,93 @@ class Facture extends CommonInvoice
|
||||
$mouvP = new MouvementStock($this->db);
|
||||
$mouvP->origin = &$this;
|
||||
// We decrease stock for product
|
||||
if ($this->type == self::TYPE_CREDIT_NOTE) $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, 0, $langs->trans("InvoiceValidatedInDolibarr", $num));
|
||||
else $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceValidatedInDolibarr", $num));
|
||||
if ($result < 0) {
|
||||
$error++;
|
||||
$this->error = $mouvP->error;
|
||||
if ($this->type == self::TYPE_CREDIT_NOTE) {
|
||||
$result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, 0, $langs->trans("InvoiceValidatedInDolibarr", $num));
|
||||
if ($result < 0) {
|
||||
$error++;
|
||||
$this->error = $mouvP->error;
|
||||
}
|
||||
} else {
|
||||
$is_batch_line = false;
|
||||
if ($batch_rule > 0) {
|
||||
$productStatic->fetch($this->lines[$i]->fk_product);
|
||||
if ($productStatic->hasbatch()) {
|
||||
$is_batch_line = true;
|
||||
$product_qty_remain = $this->lines[$i]->qty;
|
||||
|
||||
$sortfield = null;
|
||||
$sortorder = null;
|
||||
// find all batch order by sellby (DLC) and eatby dates (DLUO) first
|
||||
if ($batch_rule == Productbatch::BATCH_RULE_SELLBY_EATBY_DATES_FIRST) {
|
||||
$sortfield = 'pl.sellby,pl.eatby,pb.qty,pl.rowid';
|
||||
$sortorder = 'ASC,ASC,ASC,ASC';
|
||||
}
|
||||
|
||||
$resBatchList = Productbatch::findAllForProduct($this->db, $productStatic->id, $idwarehouse, (!empty($conf->global->STOCK_ALLOW_NEGATIVE_TRANSFER) ? null : 0), $sortfield, $sortorder);
|
||||
if (!is_array($resBatchList)) {
|
||||
$error++;
|
||||
$this->error = $this->db->lasterror();
|
||||
} else {
|
||||
$batchList = $resBatchList;
|
||||
if (empty($batchList)) {
|
||||
$error++;
|
||||
$langs->load('errors');
|
||||
$warehouseStatic->fetch($idwarehouse);
|
||||
$this->error = $langs->trans('ErrorBatchNoFoundForProductInWarehouse', $productStatic->label, $warehouseStatic->ref);
|
||||
dol_syslog(__METHOD__ . ' Error: ' . $langs->transnoentitiesnoconv('ErrorBatchNoFoundForProductInWarehouse', $productStatic->label, $warehouseStatic->ref), LOG_ERR);
|
||||
} else {
|
||||
foreach ($batchList as $batch) {
|
||||
if ($batch->qty <= 0) continue; // try to decrement only batches have positive quantity first
|
||||
|
||||
// enough quantity in this batch
|
||||
if ($batch->qty >= $product_qty_remain) {
|
||||
$product_batch_qty = $product_qty_remain;
|
||||
}
|
||||
// not enough (take all in batch)
|
||||
else {
|
||||
$product_batch_qty = $batch->qty;
|
||||
}
|
||||
$result = $mouvP->livraison($user, $productStatic->id, $idwarehouse, $product_batch_qty, $this->lines[$i]->subprice, $langs->trans('InvoiceValidatedInDolibarr', $num), '', '', '', $batch->batch);
|
||||
if ($result < 0) {
|
||||
$error++;
|
||||
$this->error = $mouvP->error;
|
||||
break;
|
||||
}
|
||||
|
||||
$product_qty_remain -= $product_batch_qty;
|
||||
// all product quantity was decremented
|
||||
if ($product_qty_remain <= 0) break;
|
||||
}
|
||||
|
||||
if (!$error && $product_qty_remain>0) {
|
||||
if ($conf->global->STOCK_ALLOW_NEGATIVE_TRANSFER) {
|
||||
// take in the first batch
|
||||
$batch = $batchList[0];
|
||||
$result = $mouvP->livraison($user, $productStatic->id, $idwarehouse, $product_qty_remain, $this->lines[$i]->subprice, $langs->trans('InvoiceValidatedInDolibarr', $num), '', '', '', $batch->batch);
|
||||
if ($result < 0) {
|
||||
$error++;
|
||||
$this->error = $mouvP->error;
|
||||
}
|
||||
} else {
|
||||
$error++;
|
||||
$langs->load('errors');
|
||||
$warehouseStatic->fetch($idwarehouse);
|
||||
$this->error = $langs->trans('ErrorBatchNoFoundEnoughQuantityForProductInWarehouse', $productStatic->label, $warehouseStatic->ref);
|
||||
dol_syslog(__METHOD__ . ' Error: ' . $langs->transnoentitiesnoconv('ErrorBatchNoFoundEnoughQuantityForProductInWarehouse', $productStatic->label, $warehouseStatic->ref), LOG_ERR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$is_batch_line) {
|
||||
$result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceValidatedInDolibarr", $num));
|
||||
if ($result < 0) {
|
||||
$error++;
|
||||
$this->error = $mouvP->error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1686,6 +1686,8 @@ CashDeskIdWareHouse=Force and restrict warehouse to use for stock decrease
|
||||
StockDecreaseForPointOfSaleDisabled=Stock decrease from Point of Sale disabled
|
||||
StockDecreaseForPointOfSaleDisabledbyBatch=Stock decrease in POS is not compatible with module Serial/Lot management (currently active) so stock decrease is disabled.
|
||||
CashDeskYouDidNotDisableStockDecease=You did not disable stock decrease when making a sale from Point of Sale. Hence a warehouse is required.
|
||||
CashDeskForceDecreaseStockLabel=Stock decrease for batch products was forced.
|
||||
CashDeskForceDecreaseStockDesc=Decrease first by the oldest eatby and sellby dates.
|
||||
##### Bookmark #####
|
||||
BookmarkSetup=Bookmark module setup
|
||||
BookmarkDesc=This module allows you to manage bookmarks. You can also add shortcuts to any Dolibarr pages or external web sites on your left menu.
|
||||
|
||||
@ -228,6 +228,8 @@ ErrorFieldRequiredForProduct=Field '%s' is required for product %s
|
||||
ProblemIsInSetupOfTerminal=Problem is in setup of terminal %s.
|
||||
ErrorAddAtLeastOneLineFirst=Add at least one line first
|
||||
ErrorRecordAlreadyInAccountingDeletionNotPossible=Error, record is already transferred in accounting, deletion is not possible.
|
||||
ErrorBatchNoFoundForProductInWarehouse=No batch found for prorduct "%s" in warehouse "%s".
|
||||
ErrorBatchNoFoundEnoughQuantityForProductInWarehouse=No enough quantity in batches for product "%s" in warehouse "%s".
|
||||
# Warnings
|
||||
WarningParamUploadMaxFileSizeHigherThanPostMaxSize=Your PHP parameter upload_max_filesize (%s) is higher than PHP parameter post_max_size (%s). This is not a consistent setup.
|
||||
WarningPasswordSetWithNoAccount=A password was set for this member. However, no user account was created. So this password is stored but can't be used to login to Dolibarr. It may be used by an external module/interface but if you don't need to define any login nor password for a member, you can disable option "Manage a login for each member" from Member module setup. If you need to manage a login but don't need any password, you can keep this field empty to avoid this warning. Note: Email can also be used as a login if the member is linked to a user.
|
||||
|
||||
@ -1683,6 +1683,8 @@ CashDeskIdWareHouse=Forcer et restreindre l'emplacement/entrepôt à utiliser po
|
||||
StockDecreaseForPointOfSaleDisabled=Réduction de stock lors de l'utilisation du Point de Vente désactivée
|
||||
StockDecreaseForPointOfSaleDisabledbyBatch=La décrémentation de stock depuis ce module Point de Vente n'est pas encore compatible avec la gestion des numéros de lots/série.
|
||||
CashDeskYouDidNotDisableStockDecease=Vous n'avez pas désactivé la réduction de stock lors d'une vente depuis le Point de vente. Par conséquent, un entrepôt est nécessaire.
|
||||
CashDeskForceDecreaseStockLabel=Décrémentation des stocks pour les lots a été forcé.
|
||||
CashDeskForceDecreaseStockDesc=Décrémentation des lots par DLC et DLUO les plus anciennes.
|
||||
##### Bookmark #####
|
||||
BookmarkSetup=Configuration du module Marque-pages
|
||||
BookmarkDesc=Ce module vous permet de gérer des liens et raccourcis. Il permet aussi d'ajouter n'importe quelle page de Dolibarr ou lien web dans le menu d'accès rapide sur la gauche.
|
||||
|
||||
@ -227,6 +227,8 @@ ErrorNoFieldWithAttributeShowoncombobox=Aucun champ n'a la propriété 'showonco
|
||||
ErrorFieldRequiredForProduct=Le champ '%s' est obligatoire pour le produit %s
|
||||
ProblemIsInSetupOfTerminal=Le problème est dans la configuration du terminal %s.
|
||||
ErrorAddAtLeastOneLineFirst=Ajouter d'abord au moins une ligne
|
||||
ErrorBatchNoFoundForProductInWarehouse=Aucun lot trouvé pour le produit "%s" dans l'entrepôt "%s".
|
||||
ErrorBatchNoFoundEnoughQuantityForProductInWarehouse=Quantité insuffisante dans les lots pour le produit "%s" dans l'entepôt "%s".
|
||||
# Warnings
|
||||
WarningParamUploadMaxFileSizeHigherThanPostMaxSize=Votre paramètre PHP upload_max_filesize (%s) est supérieur au paramètre PHP post_max_size (%s). Ceci n'est pas une configuration cohérente.
|
||||
WarningPasswordSetWithNoAccount=Un mot de passe a été fixé pour cet adhérent. Cependant, aucun compte d'utilisateur n'a été créé. Donc, ce mot de passe est stocké, mais ne peut être utilisé pour accéder à Dolibarr. Il peut être utilisé par un module/interface externe, mais si vous n'avez pas besoin de définir ni login ni mot de passe pour un adhérent, vous pouvez désactiver l'option «Gérer un login pour chaque adhérent" depuis la configuration du module Adhérents. Si vous avez besoin de gérer un login, mais pas de mot de passe, vous pouvez laisser ce champ vide pour éviter cet avertissement. Remarque: L'email peut également être utilisé comme login si l'adhérent est lié à un utilisateur.
|
||||
|
||||
@ -30,6 +30,11 @@ require_once DOL_DOCUMENT_ROOT."/core/class/commonobject.class.php";
|
||||
*/
|
||||
class Productbatch extends CommonObject
|
||||
{
|
||||
/**
|
||||
* Batches rules
|
||||
*/
|
||||
const BATCH_RULE_SELLBY_EATBY_DATES_FIRST = 1;
|
||||
|
||||
/**
|
||||
* @var string ID to identify managed object
|
||||
*/
|
||||
@ -540,4 +545,65 @@ class Productbatch extends CommonObject
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all batch for a product and a warehouse
|
||||
*
|
||||
* @param DoliDB $db Database object
|
||||
* @param int $fk_product Id of product
|
||||
* @param int $fk_warehouse Id of warehouse
|
||||
* @param int $qty_min [=NULL] Minimum quantity
|
||||
* @param string $sortfield [=NULL] List of sort fields, separated by comma. Example: 't1.fielda,t2.fieldb'
|
||||
* @param string $sortorder [=NULL] Sort order, separated by comma. Example: 'ASC,DESC';
|
||||
* @return int|array <0 if KO, array of batch
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function findAllForProduct($db, $fk_product, $fk_warehouse = 0, $qty_min = null, $sortfield = null, $sortorder = null)
|
||||
{
|
||||
$productBatchList = array();
|
||||
|
||||
dol_syslog(__METHOD__ . ' fk_product=' . $fk_product . ', fk_warehouse=' . $fk_warehouse . ', qty_min=' . $qty_min . ', sortfield=' . $sortfield . ', sortorder=' . $sortorder, LOG_DEBUG);
|
||||
|
||||
$sql = "SELECT";
|
||||
$sql .= " pl.rowid";
|
||||
$sql .= ", pl.fk_product";
|
||||
$sql .= ", pl.batch";
|
||||
$sql .= ", pl.sellby";
|
||||
$sql .= ", pl.eatby";
|
||||
$sql .= ", pb.qty";
|
||||
$sql .= " FROM " . MAIN_DB_PREFIX . "product_lot as pl";
|
||||
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "product as p ON p.rowid = pl.fk_product";
|
||||
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "product_batch AS pb ON pl.batch = pb.batch";
|
||||
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "product_stock AS ps ON ps.rowid = pb.fk_product_stock";
|
||||
$sql .= " WHERE p.entity IN (" . getEntity('product') . ")";
|
||||
$sql .= " AND pl.fk_product = " . $fk_product;
|
||||
if ($fk_warehouse > 0) {
|
||||
$sql .= " AND ps.fk_entrepot = " . $fk_warehouse;
|
||||
}
|
||||
if ($qty_min !== null) {
|
||||
$sql .= " AND pb.qty > " . $qty_min;
|
||||
}
|
||||
$sql .= $db->order($sortfield, $sortorder);
|
||||
|
||||
$resql = $db->query($sql);
|
||||
if ($resql) {
|
||||
while ($obj = $db->fetch_object($resql)) {
|
||||
$productBatch = new self($db);
|
||||
$productBatch->id = $obj->rowid;
|
||||
$productBatch->fk_product = $obj->fk_product;
|
||||
$productBatch->batch = $obj->batch;
|
||||
$productBatch->eatby = $db->jdate($obj->eatby);
|
||||
$productBatch->sellby = $db->jdate($obj->sellby);
|
||||
$productBatch->qty = $obj->qty;
|
||||
$productBatchList[] = $productBatch;
|
||||
}
|
||||
$db->free($resql);
|
||||
|
||||
return $productBatchList;
|
||||
} else {
|
||||
dol_syslog(__METHOD__ . ' Error: ' . $db->lasterror(), LOG_ERR);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,7 +179,7 @@ if (!empty($conf->stock->enabled))
|
||||
{
|
||||
print '<tr class="oddeven"><td>'.$langs->trans("CashDeskDoNotDecreaseStock").'</td>'; // Force warehouse (this is not a default value)
|
||||
print '<td>';
|
||||
if (empty($conf->productbatch->enabled)) {
|
||||
if (empty($conf->productbatch->enabled) || !empty($conf->global->CASHDESK_FORCE_DECREASE_STOCK)) {
|
||||
print $form->selectyesno('CASHDESK_NO_DECREASE_STOCK'.$terminal, $conf->global->{'CASHDESK_NO_DECREASE_STOCK'.$terminal}, 1);
|
||||
}
|
||||
else
|
||||
@ -207,6 +207,13 @@ if (!empty($conf->stock->enabled))
|
||||
print '<span class="opacitymedium">'.$langs->trans("StockDecreaseForPointOfSaleDisabled").'</span>';
|
||||
}
|
||||
print '</td></tr>';
|
||||
|
||||
if (!empty($conf->productbatch->enabled) && !empty($conf->global->CASHDESK_FORCE_DECREASE_STOCK) && !$conf->global->{'CASHDESK_NO_DECREASE_STOCK'.$terminal}) {
|
||||
print '<tr class="oddeven"><td>' . $langs->trans('CashDeskForceDecreaseStockLabel') . '</td>';
|
||||
print '<td>';
|
||||
print '<span class="opacitymedium">' . $langs->trans('CashDeskForceDecreaseStockDesc') . '</span>';
|
||||
print '</td></tr>';
|
||||
}
|
||||
}
|
||||
|
||||
if ($conf->receiptprinter->enabled) {
|
||||
|
||||
@ -190,7 +190,12 @@ if ($action == 'valid' && $user->rights->facture->creer)
|
||||
|
||||
$constantforkey = 'CASHDESK_ID_WAREHOUSE'.$_SESSION["takeposterminal"];
|
||||
dol_syslog("Validate invoice with stock change into warehouse defined into constant ".$constantforkey." = ".$conf->global->$constantforkey);
|
||||
$res = $invoice->validate($user, '', $conf->global->$constantforkey);
|
||||
$batch_rule = 0;
|
||||
if (!empty($conf->productbatch->enabled) && !empty($conf->global->CASHDESK_FORCE_DECREASE_STOCK)) {
|
||||
require_once DOL_DOCUMENT_ROOT . '/product/class/productbatch.class.php';
|
||||
$batch_rule = Productbatch::BATCH_RULE_SELLBY_EATBY_DATES_FIRST;
|
||||
}
|
||||
$res = $invoice->validate($user, '', $conf->global->$constantforkey, 0, $batch_rule);
|
||||
|
||||
$conf->global->STOCK_CALCULATE_ON_BILL = $savconst;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user