diff --git a/htdocs/admin/stock.php b/htdocs/admin/stock.php
index 98ff43360a8..4e9957fe48d 100644
--- a/htdocs/admin/stock.php
+++ b/htdocs/admin/stock.php
@@ -52,14 +52,17 @@ if($action)
// Mode of stock decrease
if ($action == 'STOCK_CALCULATE_ON_BILL'
|| $action == 'STOCK_CALCULATE_ON_VALIDATE_ORDER'
- || $action == 'STOCK_CALCULATE_ON_SHIPMENT')
+ || $action == 'STOCK_CALCULATE_ON_SHIPMENT'
+ || $action == 'STOCK_CALCULATE_ON_SHIPMENT_CLOSE')
{
$res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_BILL", '','chaine',0,'',$conf->entity);
$res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_VALIDATE_ORDER", '','chaine',0,'',$conf->entity);
$res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_SHIPMENT", '','chaine',0,'',$conf->entity);
+ $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_SHIPMENT_CLOSE", '','chaine',0,'',$conf->entity);
if ($action == 'STOCK_CALCULATE_ON_BILL') $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_BILL", GETPOST('STOCK_CALCULATE_ON_BILL','alpha'),'chaine',0,'',$conf->entity);
if ($action == 'STOCK_CALCULATE_ON_VALIDATE_ORDER') $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_VALIDATE_ORDER", GETPOST('STOCK_CALCULATE_ON_VALIDATE_ORDER','alpha'),'chaine',0,'',$conf->entity);
if ($action == 'STOCK_CALCULATE_ON_SHIPMENT') $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_SHIPMENT", GETPOST('STOCK_CALCULATE_ON_SHIPMENT','alpha'),'chaine',0,'',$conf->entity);
+ if ($action == 'STOCK_CALCULATE_ON_SHIPMENT_CLOSE') $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_SHIPMENT_CLOSE", GETPOST('STOCK_CALCULATE_ON_SHIPMENT_CLOSE','alpha'),'chaine',0,'',$conf->entity);
}
// Mode of stock increase
if ($action == 'STOCK_CALCULATE_ON_SUPPLIER_BILL'
@@ -203,6 +206,26 @@ else
print "\n\n";
$found++;
+$var=!$var;
+print "
";
+print '| '.$langs->trans("DeStockOnShipmentOnClosing").' | ';
+print '';
+if (! empty($conf->expedition->enabled))
+{
+ print "\n";
+}
+else
+{
+ print $langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module80Name"));
+}
+print " | \n
\n";
+$found++;
+
/*if (! $found)
{
$var=!$var;
diff --git a/htdocs/commande/list.php b/htdocs/commande/list.php
index 78dedadea43..46ae367b887 100644
--- a/htdocs/commande/list.php
+++ b/htdocs/commande/list.php
@@ -745,7 +745,7 @@ if ($resql)
// stock order and stock order_supplier
$stock_order=0;
$stock_order_supplier=0;
- if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT)) // What about other options ?
+ if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)) // What about other options ?
{
if (! empty($conf->commande->enabled))
{
diff --git a/htdocs/core/class/conf.class.php b/htdocs/core/class/conf.class.php
index a127c05bf3c..cfb4ff4f9cf 100644
--- a/htdocs/core/class/conf.class.php
+++ b/htdocs/core/class/conf.class.php
@@ -405,6 +405,7 @@ class Conf
$this->global->STOCK_CALCULATE_ON_BILL=0;
$this->global->STOCK_CALCULATE_ON_VALIDATE_ORDER=0;
$this->global->STOCK_CALCULATE_ON_SHIPMENT=1;
+ $this->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE=0;
$this->global->STOCK_CALCULATE_ON_SUPPLIER_BILL=0;
$this->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER=0;
$this->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER=1;
diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php
index a938fe82922..1e29a2a36f6 100644
--- a/htdocs/expedition/class/expedition.class.php
+++ b/htdocs/expedition/class/expedition.class.php
@@ -1800,6 +1800,7 @@ class Expedition extends CommonObject
*/
function setClosed()
{
+ global $conf,$langs,$user;
$error=0;
@@ -1813,28 +1814,104 @@ class Expedition extends CommonObject
{
// TODO: Add option/checkbox to set order billed if 100% of order is shipped
$this->statut=2;
-
- // Call trigger
- $result=$this->call_trigger('SHIPPING_CLOSED',$user);
- if ($result < 0) {
- $error++;
+
+ // If stock increment is done on closing
+ if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE))
+ {
+ require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
+
+ $langs->load("agenda");
+
+ // Loop on each product line to add a stock movement
+ // TODO possibilite d'expedier a partir d'une propale ou autre origine
+ $sql = "SELECT cd.fk_product, cd.subprice,";
+ $sql.= " ed.rowid, ed.qty, ed.fk_entrepot,";
+ $sql.= " edb.rowid as edbrowid, edb.eatby, edb.sellby, edb.batch, edb.qty as edbqty, edb.fk_origin_stock";
+ $sql.= " FROM ".MAIN_DB_PREFIX."commandedet as cd,";
+ $sql.= " ".MAIN_DB_PREFIX."expeditiondet as ed";
+ $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."expeditiondet_batch as edb on edb.fk_expeditiondet = ed.rowid";
+ $sql.= " WHERE ed.fk_expedition = ".$this->id;
+ $sql.= " AND cd.rowid = ed.fk_origin_line";
+
+ dol_syslog(get_class($this)."::valid select details", LOG_DEBUG);
+ $resql=$this->db->query($sql);
+ if ($resql)
+ {
+ $cpt = $this->db->num_rows($resql);
+ for ($i = 0; $i < $cpt; $i++)
+ {
+ $obj = $this->db->fetch_object($resql);
+ if (empty($obj->edbrowid))
+ {
+ $qty = $obj->qty;
+ }
+ else
+ {
+ $qty = $obj->edbqty;
+ }
+ if ($qty <= 0) continue;
+ dol_syslog(get_class($this)."::valid movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid);
+
+ $mouvS = new MouvementStock($this->db);
+ $mouvS->origin = &$this;
+
+ if (empty($obj->edbrowid))
+ {
+ // line without batch detail
+
+ // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record
+ $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ShipmentClassifyClosedInDolibarr",$numref));
+ if ($result < 0) {
+ $this->error = $mouvS->error;
+ $this->errors = $mouvS->errors;
+ $error++; break;
+ }
+ }
+ else
+ {
+ // line with batch detail
+
+ // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record
+ $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ShipmentClassifyClosedInDolibarr",$numref), '', $obj->eatby, $obj->sellby, $obj->batch, $obj->fk_origin_stock);
+ if ($result < 0) {
+ $this->error = $mouvS->error;
+ $this->errors = $mouvS->errors;
+ $error++; break;
+ }
+ }
+ }
+ }
+ else
+ {
+ $this->error=$this->db->lasterror();
+ $error++;
+ }
}
- } else {
- $error++;
- $this->errors[]=$this->db->lasterror;
- }
-
- if (empty($error)) {
- $this->db->commit();
- return 1;
+ // Call trigger
+ if (! $error)
+ {
+ $result=$this->call_trigger('SHIPPING_CLOSED',$user);
+ if ($result < 0) {
+ $error++;
+ }
+ }
}
else
{
- $this->db->rollback();
dol_print_error($this->db);
-
- return -1;
+ $error++;
+ }
+
+ if (! $error)
+ {
+ $this->db->commit();
+ return 1;
+ }
+ else
+ {
+ $this->db->rollback();
+ return -1;
}
}
@@ -1876,8 +1953,6 @@ class Expedition extends CommonObject
else
{
$this->db->rollback();
- dol_print_error($this->db);
-
return -1;
}
}
@@ -1889,6 +1964,7 @@ class Expedition extends CommonObject
*/
function reOpen()
{
+ global $conf,$langs,$user;
$error=0;
@@ -1903,26 +1979,102 @@ class Expedition extends CommonObject
$this->statut=1;
$this->billed=0;
- // Call trigger
- $result=$this->call_trigger('SHIPPING_REOPEN',$user);
- if ($result < 0) {
- $error++;
+ // If stock increment is done on closing
+ if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE))
+ {
+ require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
+
+ $langs->load("agenda");
+
+ // Loop on each product line to add a stock movement
+ // TODO possibilite d'expedier a partir d'une propale ou autre origine
+ $sql = "SELECT cd.fk_product, cd.subprice,";
+ $sql.= " ed.rowid, ed.qty, ed.fk_entrepot,";
+ $sql.= " edb.rowid as edbrowid, edb.eatby, edb.sellby, edb.batch, edb.qty as edbqty, edb.fk_origin_stock";
+ $sql.= " FROM ".MAIN_DB_PREFIX."commandedet as cd,";
+ $sql.= " ".MAIN_DB_PREFIX."expeditiondet as ed";
+ $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."expeditiondet_batch as edb on edb.fk_expeditiondet = ed.rowid";
+ $sql.= " WHERE ed.fk_expedition = ".$this->id;
+ $sql.= " AND cd.rowid = ed.fk_origin_line";
+
+ dol_syslog(get_class($this)."::valid select details", LOG_DEBUG);
+ $resql=$this->db->query($sql);
+ if ($resql)
+ {
+ $cpt = $this->db->num_rows($resql);
+ for ($i = 0; $i < $cpt; $i++)
+ {
+ $obj = $this->db->fetch_object($resql);
+ if (empty($obj->edbrowid))
+ {
+ $qty = $obj->qty;
+ }
+ else
+ {
+ $qty = $obj->edbqty;
+ }
+ if ($qty <= 0) continue;
+ dol_syslog(get_class($this)."::reopen expedition movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid);
+
+ //var_dump($this->lines[$i]);
+ $mouvS = new MouvementStock($this->db);
+ $mouvS->origin = &$this;
+
+ if (empty($obj->edbrowid))
+ {
+ // line without batch detail
+
+ // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record
+ $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ShipmentUnClassifyCloseddInDolibarr",$numref));
+ if ($result < 0) {
+ $this->error = $mouvS->error;
+ $this->errors = $mouvS->errors;
+ $error++; break;
+ }
+ }
+ else
+ {
+ // line with batch detail
+
+ // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record
+ $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ShipmentUnClassifyCloseddInDolibarr",$numref), '', $obj->eatby, $obj->sellby, $obj->batch, $obj->fk_origin_stock);
+ if ($result < 0) {
+ $this->error = $mouvS->error;
+ $this->errors = $mouvS->errors;
+ $error++; break;
+ }
+ }
+ }
+ }
+ else
+ {
+ $this->error=$this->db->lasterror();
+ $error++;
+ }
}
+ if (! $error)
+ {
+ // Call trigger
+ $result=$this->call_trigger('SHIPPING_REOPEN',$user);
+ if ($result < 0) {
+ $error++;
+ }
+ }
+
} else {
$error++;
- $this->errors[]=$this->db->lasterror;
+ $this->errors[]=$this->db->lasterror();
}
-
- if (empty($error)) {
+
+ if (! $error)
+ {
$this->db->commit();
return 1;
}
else
{
$this->db->rollback();
- dol_print_error($this->db);
-
return -1;
}
}
diff --git a/htdocs/langs/en_US/other.lang b/htdocs/langs/en_US/other.lang
index af0aea4c274..c8bde912cdd 100644
--- a/htdocs/langs/en_US/other.lang
+++ b/htdocs/langs/en_US/other.lang
@@ -231,6 +231,8 @@ MemberResiliatedInDolibarr=Member %s resiliated
MemberDeletedInDolibarr=Member %s deleted
MemberSubscriptionAddedInDolibarr=Subscription for member %s added
ShipmentValidatedInDolibarr=Shipment %s validated
+ShipmentClassifyClosedInDolibarr=Shipment %s classify billed
+ShipmentUnClassifyCloseddInDolibarr=Shipment %s classify reopened
ShipmentDeletedInDolibarr=Shipment %s deleted
##### Export #####
Export=Export
diff --git a/htdocs/langs/en_US/stocks.lang b/htdocs/langs/en_US/stocks.lang
index 3416d1b1909..6b1a28eae17 100644
--- a/htdocs/langs/en_US/stocks.lang
+++ b/htdocs/langs/en_US/stocks.lang
@@ -59,6 +59,7 @@ RuleForStockManagementIncrease=Rule for automatic stock management increase (man
DeStockOnBill=Decrease real stocks on customers invoices/credit notes validation
DeStockOnValidateOrder=Decrease real stocks on customers orders validation
DeStockOnShipment=Decrease real stocks on shipping validation
+DeStockOnShipmentOnClosing=Decrease real stocks on shipping classification closed
ReStockOnBill=Increase real stocks on suppliers invoices/credit notes validation
ReStockOnValidateOrder=Increase real stocks on suppliers orders approbation
ReStockOnDispatchOrder=Increase real stocks on manual dispatching into warehouses, after supplier order receiving
diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php
index 50f5cd0c19a..84d11e3ff99 100644
--- a/htdocs/product/class/product.class.php
+++ b/htdocs/product/class/product.class.php
@@ -3477,7 +3477,7 @@ class Product extends CommonObject
}
// Stock decrease mode
- if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT)) {
+ if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)) {
$this->stock_theorique=$this->stock_reel-$stock_commande_client+$stock_sending_client;
}
if (! empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER)) {
diff --git a/htdocs/product/stock/product.php b/htdocs/product/stock/product.php
index 1b4c159b1d6..56504432840 100644
--- a/htdocs/product/stock/product.php
+++ b/htdocs/product/stock/product.php
@@ -496,7 +496,7 @@ if ($id > 0 || $ref)
// Real stock
$text_stock_options = '';
- $text_stock_options.= (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT)?$langs->trans("DeStockOnShipment").'
':'');
+ $text_stock_options.= (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)?$langs->trans("DeStockOnShipment").'
':'');
$text_stock_options.= (! empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER)?$langs->trans("DeStockOnValidateOrder").'
':'');
$text_stock_options.= (! empty($conf->global->STOCK_CALCULATE_ON_BILL)?$langs->trans("DeStockOnBill").'
':'');
$text_stock_options.= (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL)?$langs->trans("ReStockOnBill").'
':'');
diff --git a/htdocs/product/stock/replenish.php b/htdocs/product/stock/replenish.php
index 21f492e0c00..aed3f5ed73c 100644
--- a/htdocs/product/stock/replenish.php
+++ b/htdocs/product/stock/replenish.php
@@ -71,7 +71,9 @@ if (!$sortorder) {
// Define virtualdiffersfromphysical
$virtualdiffersfromphysical=0;
-if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER))
+if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT)
+|| ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)
+|| ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)
{
$virtualdiffersfromphysical=1; // According to increase/decrease stock options, virtual and physical stock may differs.
}