Skip to content

Commit

Permalink
fix: allow negative stock condition for batch item (#36586)
Browse files Browse the repository at this point in the history
* fix: allow negative stock condition for batch item

* fix: test case
  • Loading branch information
rohitwaghchaure authored Aug 11, 2023
1 parent 5488785 commit ee04c6d
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 18 deletions.
24 changes: 13 additions & 11 deletions erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,11 +282,7 @@ def update_stock_ledger(self):
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()
Expand Down Expand Up @@ -457,10 +453,7 @@ def make_sle_on_cancel(self):
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
Expand Down Expand Up @@ -574,6 +567,7 @@ def recalculate_current_qty(self, voucher_detail_no, sle_creation, add_new_sle=F
from erpnext.stock.stock_ledger import get_valuation_rate

sl_entries = []

for row in self.items:
if voucher_detail_no != row.name:
continue
Expand Down Expand Up @@ -619,10 +613,18 @@ def recalculate_current_qty(self, voucher_detail_no, sle_creation, add_new_sle=F
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -769,8 +769,6 @@ def test_backdated_stock_reco_entry(self):
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",
{
Expand Down Expand Up @@ -868,6 +866,56 @@ def test_update_stock_reconciliation_while_reposting(self):
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)
Expand All @@ -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,
)

Expand Down
5 changes: 1 addition & 4 deletions erpnext/stock/stock_ledger.py
Original file line number Diff line number Diff line change
Expand Up @@ -635,17 +635,14 @@ def process_sle(self, sle):

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 = (
flt(frappe.db.get_value("Stock Reconciliation Item", sle.voucher_detail_no, "current_qty"))
* -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
Expand Down

0 comments on commit ee04c6d

Please sign in to comment.