NEW Add option "Stock can be negative". Off by default.
This commit is contained in:
parent
1195e3bf0c
commit
97b03e225b
@ -323,63 +323,73 @@ $found++;
|
|||||||
|
|
||||||
print '</table>';
|
print '</table>';
|
||||||
|
|
||||||
|
print '<br>';
|
||||||
|
print '<table class="noborder" width="100%">';
|
||||||
|
print '<tr class="liste_titre">';
|
||||||
|
print " <td>".$langs->trans("RuleForStockAvailability")."</td>\n";
|
||||||
|
print " <td align=\"right\" width=\"160\"> </td>\n";
|
||||||
|
print '</tr>'."\n";
|
||||||
|
|
||||||
|
$var=!$var;
|
||||||
|
print "<tr ".$bc[$var].">";
|
||||||
|
print '<td width="60%">'.$langs->trans("WarehouseAllowNegativeTransfer").'</td>';
|
||||||
|
print '<td width="160" align="right">';
|
||||||
|
print "<form method=\"post\" action=\"stock.php\">";
|
||||||
|
print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
|
||||||
|
print "<input type=\"hidden\" name=\"action\" value=\"STOCK_ALLOW_NEGATIVE_TRANSFER\">";
|
||||||
|
print $form->selectyesno("STOCK_ALLOW_NEGATIVE_TRANSFER",$conf->global->STOCK_ALLOW_NEGATIVE_TRANSFER,1);
|
||||||
|
print '<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
|
||||||
|
print '</form>';
|
||||||
|
print "</td>\n";
|
||||||
|
print "</tr>\n";
|
||||||
|
|
||||||
// Option to force stock to be enough before adding a line into document
|
// Option to force stock to be enough before adding a line into document
|
||||||
if ($conf->invoice->enabled || $conf->order->enabled || $conf->expedition->enabled)
|
if($conf->invoice->enabled) {
|
||||||
{
|
$var = !$var;
|
||||||
print '<br>';
|
print "<tr ".$bc[$var].">";
|
||||||
print '<table class="noborder" width="100%">';
|
print '<td width="60%">'.$langs->trans("StockMustBeEnoughForInvoice").'</td>';
|
||||||
print '<tr class="liste_titre">';
|
print '<td width="160" align="right">';
|
||||||
print " <td>".$langs->trans("RuleForStockAvailability")."</td>\n";
|
print "<form method=\"post\" action=\"stock.php\">";
|
||||||
print " <td align=\"right\" width=\"160\"> </td>\n";
|
print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
|
||||||
print '</tr>'."\n";
|
print "<input type=\"hidden\" name=\"action\" value=\"STOCK_MUST_BE_ENOUGH_FOR_INVOICE\">";
|
||||||
|
print $form->selectyesno("STOCK_MUST_BE_ENOUGH_FOR_INVOICE",$conf->global->STOCK_MUST_BE_ENOUGH_FOR_INVOICE,1);
|
||||||
if($conf->invoice->enabled) {
|
print '<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
|
||||||
$var = !$var;
|
print '</form>';
|
||||||
print "<tr ".$bc[$var].">";
|
print "</td>\n";
|
||||||
print '<td width="60%">'.$langs->trans("StockMustBeEnoughForInvoice").'</td>';
|
print "</tr>\n";
|
||||||
print '<td width="160" align="right">';
|
|
||||||
print "<form method=\"post\" action=\"stock.php\">";
|
|
||||||
print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
|
|
||||||
print "<input type=\"hidden\" name=\"action\" value=\"STOCK_MUST_BE_ENOUGH_FOR_INVOICE\">";
|
|
||||||
print $form->selectyesno("STOCK_MUST_BE_ENOUGH_FOR_INVOICE",$conf->global->STOCK_MUST_BE_ENOUGH_FOR_INVOICE,1);
|
|
||||||
print '<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
|
|
||||||
print '</form>';
|
|
||||||
print "</td>\n";
|
|
||||||
print "</tr>\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if($conf->order->enabled) {
|
|
||||||
$var = !$var;
|
|
||||||
print "<tr ".$bc[$var].">";
|
|
||||||
print '<td width="60%">'.$langs->trans("StockMustBeEnoughForOrder").'</td>';
|
|
||||||
print '<td width="160" align="right">';
|
|
||||||
print "<form method=\"post\" action=\"stock.php\">";
|
|
||||||
print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
|
|
||||||
print "<input type=\"hidden\" name=\"action\" value=\"STOCK_MUST_BE_ENOUGH_FOR_ORDER\">";
|
|
||||||
print $form->selectyesno("STOCK_MUST_BE_ENOUGH_FOR_ORDER",$conf->global->STOCK_MUST_BE_ENOUGH_FOR_ORDER,1);
|
|
||||||
print '<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
|
|
||||||
print '</form>';
|
|
||||||
print "</td>\n";
|
|
||||||
print "</tr>\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if($conf->expedition->enabled) {
|
|
||||||
$var = !$var;
|
|
||||||
print "<tr ".$bc[$var].">";
|
|
||||||
print '<td width="60%">'.$langs->trans("StockMustBeEnoughForShipment").'</td>';
|
|
||||||
print '<td width="160" align="right">';
|
|
||||||
print "<form method=\"post\" action=\"stock.php\">";
|
|
||||||
print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
|
|
||||||
print "<input type=\"hidden\" name=\"action\" value=\"STOCK_MUST_BE_ENOUGH_FOR_SHIPMENT\">";
|
|
||||||
print $form->selectyesno("STOCK_MUST_BE_ENOUGH_FOR_SHIPMENT",$conf->global->STOCK_MUST_BE_ENOUGH_FOR_SHIPMENT,1);
|
|
||||||
print '<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
|
|
||||||
print '</form>';
|
|
||||||
print "</td>\n";
|
|
||||||
print "</tr>\n";
|
|
||||||
}
|
|
||||||
print '</table>';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($conf->order->enabled) {
|
||||||
|
$var = !$var;
|
||||||
|
print "<tr ".$bc[$var].">";
|
||||||
|
print '<td width="60%">'.$langs->trans("StockMustBeEnoughForOrder").'</td>';
|
||||||
|
print '<td width="160" align="right">';
|
||||||
|
print "<form method=\"post\" action=\"stock.php\">";
|
||||||
|
print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
|
||||||
|
print "<input type=\"hidden\" name=\"action\" value=\"STOCK_MUST_BE_ENOUGH_FOR_ORDER\">";
|
||||||
|
print $form->selectyesno("STOCK_MUST_BE_ENOUGH_FOR_ORDER",$conf->global->STOCK_MUST_BE_ENOUGH_FOR_ORDER,1);
|
||||||
|
print '<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
|
||||||
|
print '</form>';
|
||||||
|
print "</td>\n";
|
||||||
|
print "</tr>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if($conf->expedition->enabled) {
|
||||||
|
$var = !$var;
|
||||||
|
print "<tr ".$bc[$var].">";
|
||||||
|
print '<td width="60%">'.$langs->trans("StockMustBeEnoughForShipment").'</td>';
|
||||||
|
print '<td width="160" align="right">';
|
||||||
|
print "<form method=\"post\" action=\"stock.php\">";
|
||||||
|
print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
|
||||||
|
print "<input type=\"hidden\" name=\"action\" value=\"STOCK_MUST_BE_ENOUGH_FOR_SHIPMENT\">";
|
||||||
|
print $form->selectyesno("STOCK_MUST_BE_ENOUGH_FOR_SHIPMENT",$conf->global->STOCK_MUST_BE_ENOUGH_FOR_SHIPMENT,1);
|
||||||
|
print '<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
|
||||||
|
print '</form>';
|
||||||
|
print "</td>\n";
|
||||||
|
print "</tr>\n";
|
||||||
|
}
|
||||||
|
print '</table>';
|
||||||
|
|
||||||
$virtualdiffersfromphysical=0;
|
$virtualdiffersfromphysical=0;
|
||||||
if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT)
|
if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT)
|
||||||
|| ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)
|
|| ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)
|
||||||
@ -432,21 +442,6 @@ print '</form>';
|
|||||||
print "</td>\n";
|
print "</td>\n";
|
||||||
print "</tr>\n";
|
print "</tr>\n";
|
||||||
|
|
||||||
$var=!$var;
|
|
||||||
|
|
||||||
print "<tr ".$bc[$var].">";
|
|
||||||
print '<td width="60%">'.$langs->trans("WarehouseAllowNegativeTransfer").'</td>';
|
|
||||||
|
|
||||||
print '<td width="160" align="right">';
|
|
||||||
print "<form method=\"post\" action=\"stock.php\">";
|
|
||||||
print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
|
|
||||||
print "<input type=\"hidden\" name=\"action\" value=\"STOCK_ALLOW_NEGATIVE_TRANSFER\">";
|
|
||||||
print $form->selectyesno("STOCK_ALLOW_NEGATIVE_TRANSFER",$conf->global->STOCK_ALLOW_NEGATIVE_TRANSFER,1);
|
|
||||||
print '<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
|
|
||||||
print '</form>';
|
|
||||||
print "</td>\n";
|
|
||||||
print "</tr>\n";
|
|
||||||
|
|
||||||
print '<br>';
|
print '<br>';
|
||||||
|
|
||||||
/* I keep the option/feature, but hidden to end users for the moment. If feature is used by module, no need to have users see it.
|
/* I keep the option/feature, but hidden to end users for the moment. If feature is used by module, no need to have users see it.
|
||||||
|
|||||||
@ -114,13 +114,13 @@ RecordMovement=Record transfert
|
|||||||
ReceivingForSameOrder=Receipts for this order
|
ReceivingForSameOrder=Receipts for this order
|
||||||
StockMovementRecorded=Stock movements recorded
|
StockMovementRecorded=Stock movements recorded
|
||||||
RuleForStockAvailability=Rules on stock requirements
|
RuleForStockAvailability=Rules on stock requirements
|
||||||
StockMustBeEnoughForInvoice=Stock level must be enough to add product/service to invoice
|
StockMustBeEnoughForInvoice=Stock level must be enough to add product/service to invoice (even if real stock change occurs later on another event)
|
||||||
StockMustBeEnoughForOrder=Stock level must be enough to add product/service to order
|
StockMustBeEnoughForOrder=Stock level must be enough to add product/service to order (even if stock change occurs later on another event)
|
||||||
StockMustBeEnoughForShipment= Stock level must be enough to add product/service to shipment
|
StockMustBeEnoughForShipment= Stock level must be enough to add product/service to shipment (even if stock change occurs later on another event)
|
||||||
MovementLabel=Label of movement
|
MovementLabel=Label of movement
|
||||||
InventoryCode=Movement or inventory code
|
InventoryCode=Movement or inventory code
|
||||||
IsInPackage=Contained into package
|
IsInPackage=Contained into package
|
||||||
WarehouseAllowNegativeTransfer=Allow transfer even without stock
|
WarehouseAllowNegativeTransfer=Stock can be negative
|
||||||
qtyToTranferIsNotEnough=You don't have enough stock from your source warehouse
|
qtyToTranferIsNotEnough=You don't have enough stock from your source warehouse
|
||||||
ShowWarehouse=Show warehouse
|
ShowWarehouse=Show warehouse
|
||||||
MovementCorrectStock=Stock correction for product %s
|
MovementCorrectStock=Stock correction for product %s
|
||||||
|
|||||||
@ -494,11 +494,13 @@ class Productbatch extends CommonObject
|
|||||||
if ($fk_product > 0)
|
if ($fk_product > 0)
|
||||||
{
|
{
|
||||||
$sql.= ", pl.eatby as eatby, pl.sellby as sellby";
|
$sql.= ", pl.eatby as eatby, pl.sellby as sellby";
|
||||||
|
// TODO May add extrafields to ?
|
||||||
}
|
}
|
||||||
$sql.= " FROM ".MAIN_DB_PREFIX."product_batch as t";
|
$sql.= " FROM ".MAIN_DB_PREFIX."product_batch as t";
|
||||||
if ($fk_product > 0)
|
if ($fk_product > 0)
|
||||||
{
|
{
|
||||||
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_lot as pl ON pl.fk_product = ".$fk_product." AND pl.batch = t.batch";
|
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_lot as pl ON pl.fk_product = ".$fk_product." AND pl.batch = t.batch";
|
||||||
|
// TODO May add extrafields to ?
|
||||||
}
|
}
|
||||||
$sql.= " WHERE fk_product_stock=".$fk_product_stock;
|
$sql.= " WHERE fk_product_stock=".$fk_product_stock;
|
||||||
if ($with_qty) $sql.= " AND t.qty <> 0";
|
if ($with_qty) $sql.= " AND t.qty <> 0";
|
||||||
@ -523,7 +525,7 @@ class Productbatch extends CommonObject
|
|||||||
$tmp->qty = $obj->qty;
|
$tmp->qty = $obj->qty;
|
||||||
$tmp->import_key = $obj->import_key;
|
$tmp->import_key = $obj->import_key;
|
||||||
|
|
||||||
array_push($ret,$tmp);
|
$ret[$tmp->batch] = $tmp; // $ret is for a $fk_product_stock and unique key is on $fk_product_stock+batch
|
||||||
$i++;
|
$i++;
|
||||||
}
|
}
|
||||||
$db->free($resql);
|
$db->free($resql);
|
||||||
|
|||||||
@ -240,31 +240,45 @@ class MouvementStock extends CommonObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Check qty is ok for stock move.
|
|
||||||
if (! empty($conf->productbatch->enabled) && $product->hasbatch() && ! $skip_batch)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($conf->global->STOCK_ALLOW_NEGATIVE_TRANSFER) && in_array($type, array(1, 2)))
|
|
||||||
{
|
|
||||||
if (empty($product->stock_warehouse[$entrepot_id]->real) || $product->stock_warehouse[$entrepot_id]->real < abs($qty))
|
|
||||||
{
|
|
||||||
$this->error = $langs->trans('qtyToTranferIsNotEnough');
|
|
||||||
$this->errors[] = $langs->trans('qtyToTranferIsNotEnough');
|
|
||||||
$this->db->rollback();
|
|
||||||
return -8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define if we must make the stock change (If product type is a service or if stock is used also for services)
|
// Define if we must make the stock change (If product type is a service or if stock is used also for services)
|
||||||
$movestock=0;
|
$movestock=0;
|
||||||
if ($product->type != Product::TYPE_SERVICE || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) $movestock=1;
|
if ($product->type != Product::TYPE_SERVICE || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) $movestock=1;
|
||||||
|
|
||||||
|
// Check if stock is enough when qty is < 0
|
||||||
|
// Note that qty should be > 0 with type 0 or 3, < 0 with type 1 or 2.
|
||||||
|
if ($qty < 0 && empty($conf->global->STOCK_ALLOW_NEGATIVE_TRANSFER))
|
||||||
|
{
|
||||||
|
if (! empty($conf->productbatch->enabled) && $product->hasbatch() && ! $skip_batch)
|
||||||
|
{
|
||||||
|
$foundforbatch=0;
|
||||||
|
$qtyisnotenough=0;
|
||||||
|
foreach($product->stock_warehouse[$entrepot_id]->detail_batch as $batchcursor => $prodbatch)
|
||||||
|
{
|
||||||
|
if ($batch != $batchcursor) continue;
|
||||||
|
$foundforbatch=1;
|
||||||
|
if ($prodbatch->qty < abs($qty)) $qtyisnotenough=1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (! $foundforbatch || $qtyisnotenough)
|
||||||
|
{
|
||||||
|
$this->error = $langs->trans('qtyToTranferLotIsNotEnough');
|
||||||
|
$this->errors[] = $langs->trans('qtyToTranferLotIsNotEnough');
|
||||||
|
$this->db->rollback();
|
||||||
|
return -8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (empty($product->stock_warehouse[$entrepot_id]->real) || $product->stock_warehouse[$entrepot_id]->real < abs($qty))
|
||||||
|
{
|
||||||
|
$this->error = $langs->trans('qtyToTranferIsNotEnough');
|
||||||
|
$this->errors[] = $langs->trans('qtyToTranferIsNotEnough');
|
||||||
|
$this->db->rollback();
|
||||||
|
return -8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($movestock && $entrepot_id > 0) // Change stock for current product, change for subproduct is done after
|
if ($movestock && $entrepot_id > 0) // Change stock for current product, change for subproduct is done after
|
||||||
{
|
{
|
||||||
if(!empty($this->origin)) { // This is set by caller for tracking reason
|
if(!empty($this->origin)) { // This is set by caller for tracking reason
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user