fix: allow negative stock condition for batch item (#36586)
* fix: allow negative stock condition for batch item * fix: test case
This commit is contained in:
@@ -282,11 +282,7 @@ class StockReconciliation(StockController):
|
||||
if has_serial_no:
|
||||
sl_entries = self.merge_similar_item_serial_nos(sl_entries)
|
||||
|
||||
allow_negative_stock = False
|
||||
if has_batch_no:
|
||||
allow_negative_stock = True
|
||||
|
||||
self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock)
|
||||
self.make_sl_entries(sl_entries, allow_negative_stock=self.has_negative_stock_allowed())
|
||||
|
||||
if has_serial_no and sl_entries:
|
||||
self.update_valuation_rate_for_serial_no()
|
||||
@@ -457,10 +453,7 @@ class StockReconciliation(StockController):
|
||||
sl_entries = self.merge_similar_item_serial_nos(sl_entries)
|
||||
|
||||
sl_entries.reverse()
|
||||
allow_negative_stock = cint(
|
||||
frappe.db.get_single_value("Stock Settings", "allow_negative_stock")
|
||||
)
|
||||
self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock)
|
||||
self.make_sl_entries(sl_entries, allow_negative_stock=self.has_negative_stock_allowed())
|
||||
|
||||
def merge_similar_item_serial_nos(self, sl_entries):
|
||||
# If user has put the same item in multiple row with different serial no
|
||||
@@ -574,6 +567,7 @@ class StockReconciliation(StockController):
|
||||
from erpnext.stock.stock_ledger import get_valuation_rate
|
||||
|
||||
sl_entries = []
|
||||
|
||||
for row in self.items:
|
||||
if voucher_detail_no != row.name:
|
||||
continue
|
||||
@@ -619,10 +613,18 @@ class StockReconciliation(StockController):
|
||||
sl_entries.append(new_sle)
|
||||
|
||||
if sl_entries:
|
||||
self.make_sl_entries(sl_entries, allow_negative_stock=True)
|
||||
if frappe.db.exists("Repost Item Valuation", {"voucher_no": self.name, "status": "Queued"}):
|
||||
self.make_sl_entries(sl_entries, allow_negative_stock=self.has_negative_stock_allowed())
|
||||
if not frappe.db.exists("Repost Item Valuation", {"voucher_no": self.name, "status": "Queued"}):
|
||||
self.repost_future_sle_and_gle(force=True)
|
||||
|
||||
def has_negative_stock_allowed(self):
|
||||
allow_negative_stock = cint(frappe.db.get_single_value("Stock Settings", "allow_negative_stock"))
|
||||
|
||||
if all(d.batch_no and flt(d.qty) == flt(d.current_qty) for d in self.items):
|
||||
allow_negative_stock = True
|
||||
|
||||
return allow_negative_stock
|
||||
|
||||
|
||||
def get_batch_qty_for_stock_reco(
|
||||
item_code, warehouse, batch_no, posting_date, posting_time, voucher_no
|
||||
|
||||
@@ -769,8 +769,6 @@ class TestStockReconciliation(FrappeTestCase, StockTestMixin):
|
||||
self.assertEqual(flt(sle[0].qty_after_transaction), flt(50.0))
|
||||
|
||||
def test_backdated_stock_reco_entry_with_batch(self):
|
||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
||||
|
||||
item_code = self.make_item(
|
||||
"Test New Batch Item ABCVSD",
|
||||
{
|
||||
@@ -868,6 +866,56 @@ class TestStockReconciliation(FrappeTestCase, StockTestMixin):
|
||||
sr1.load_from_db()
|
||||
self.assertEqual(sr1.difference_amount, 10000)
|
||||
|
||||
@change_settings("Stock Settings", {"allow_negative_stock": 0})
|
||||
def test_negative_stock_reco_for_batch(self):
|
||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
||||
|
||||
item_code = self.make_item(
|
||||
"Test New Batch Item ABCVSD",
|
||||
{
|
||||
"is_stock_item": 1,
|
||||
"has_batch_no": 1,
|
||||
"batch_number_series": "BNS9.####",
|
||||
"create_new_batch": 1,
|
||||
},
|
||||
).name
|
||||
|
||||
warehouse = "_Test Warehouse - _TC"
|
||||
|
||||
# Added 100 Qty, Balace Qty 100
|
||||
se = make_stock_entry(
|
||||
item_code=item_code,
|
||||
target=warehouse,
|
||||
qty=100,
|
||||
basic_rate=100,
|
||||
posting_date=add_days(nowdate(), -2),
|
||||
)
|
||||
|
||||
# Removed 100 Qty, Balace Qty 0
|
||||
make_stock_entry(
|
||||
item_code=item_code,
|
||||
source=warehouse,
|
||||
qty=100,
|
||||
batch_no=se.items[0].batch_no,
|
||||
basic_rate=100,
|
||||
posting_date=nowdate(),
|
||||
)
|
||||
|
||||
# Remove 100 qty, Balace Qty -100
|
||||
sr = create_stock_reconciliation(
|
||||
item_code=item_code,
|
||||
warehouse=warehouse,
|
||||
qty=0,
|
||||
rate=0,
|
||||
batch_no=se.items[0].batch_no,
|
||||
posting_date=add_days(nowdate(), -1),
|
||||
posting_time="11:00:00",
|
||||
do_not_submit=True,
|
||||
)
|
||||
|
||||
# Check if Negative Stock is blocked
|
||||
self.assertRaises(frappe.ValidationError, sr.submit)
|
||||
|
||||
|
||||
def create_batch_item_with_batch(item_name, batch_id):
|
||||
batch_item_doc = create_item(item_name, is_stock_item=1)
|
||||
@@ -891,7 +939,7 @@ def insert_existing_sle(warehouse, item_code="_Test Item"):
|
||||
posting_time="02:00",
|
||||
item_code=item_code,
|
||||
target=warehouse,
|
||||
qty=10,
|
||||
qty=15,
|
||||
basic_rate=700,
|
||||
)
|
||||
|
||||
|
||||
@@ -635,7 +635,7 @@ class update_entries_after(object):
|
||||
|
||||
def reset_actual_qty_for_stock_reco(self, sle):
|
||||
doc = frappe.get_cached_doc("Stock Reconciliation", sle.voucher_no)
|
||||
doc.recalculate_current_qty(sle.voucher_detail_no, sle.creation, sle.actual_qty > 0)
|
||||
doc.recalculate_current_qty(sle.voucher_detail_no, sle.creation, sle.actual_qty >= 0)
|
||||
|
||||
if sle.actual_qty < 0:
|
||||
sle.actual_qty = (
|
||||
@@ -643,9 +643,6 @@ class update_entries_after(object):
|
||||
* -1
|
||||
)
|
||||
|
||||
if abs(sle.actual_qty) == 0.0:
|
||||
sle.is_cancelled = 1
|
||||
|
||||
def validate_negative_stock(self, sle):
|
||||
"""
|
||||
validate negative stock for entries current datetime onwards
|
||||
|
||||
Reference in New Issue
Block a user