From 05d5c48d29bfcf2edc63eb720c51d9633d3ef930 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 23 Apr 2024 13:51:16 +0530 Subject: [PATCH] fix: incorrect stock posting for current qty (cherry picked from commit d4fe313de28ebb3910e7f117101f278d54dde9f9) --- .../stock_reconciliation.py | 30 +----- .../test_stock_reconciliation.py | 102 ++++++++---------- erpnext/stock/stock_ledger.py | 2 +- 3 files changed, 44 insertions(+), 90 deletions(-) diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index 64a6b6503cc..f92d7361f41 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -823,11 +823,9 @@ class StockReconciliation(StockController): else: self._cancel() - def recalculate_current_qty(self, voucher_detail_no, sle_creation, add_new_sle=False): + def recalculate_current_qty(self, voucher_detail_no): from erpnext.stock.stock_ledger import get_valuation_rate - sl_entries = [] - for row in self.items: if voucher_detail_no != row.name: continue @@ -881,32 +879,6 @@ class StockReconciliation(StockController): } ) - if ( - add_new_sle - and not frappe.db.get_value( - "Stock Ledger Entry", - {"voucher_detail_no": row.name, "actual_qty": ("<", 0), "is_cancelled": 0}, - "name", - ) - and (not row.current_serial_and_batch_bundle) - ): - self.set_current_serial_and_batch_bundle(voucher_detail_no, save=True) - row.reload() - - if row.current_qty > 0 and row.current_serial_and_batch_bundle: - new_sle = self.get_sle_for_items(row) - new_sle.actual_qty = row.current_qty * -1 - new_sle.valuation_rate = row.current_valuation_rate - new_sle.creation_time = add_to_date(sle_creation, seconds=-1) - new_sle.serial_and_batch_bundle = row.current_serial_and_batch_bundle - new_sle.qty_after_transaction = 0.0 - sl_entries.append(new_sle) - - if sl_entries: - 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 allow_negative_stock: diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py index add8b516e83..92a931036e9 100644 --- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py @@ -756,66 +756,6 @@ class TestStockReconciliation(FrappeTestCase, StockTestMixin): self.assertEqual(flt(sle[0].actual_qty), flt(-100.0)) - def test_backdated_stock_reco_entry_with_batch(self): - 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" - - # Stock Reco for 100, Balace Qty 100 - stock_reco = create_stock_reconciliation( - item_code=item_code, - posting_date=nowdate(), - posting_time="11:00:00", - warehouse=warehouse, - qty=100, - rate=100, - ) - - sles = frappe.get_all( - "Stock Ledger Entry", - fields=["actual_qty"], - filters={"voucher_no": stock_reco.name, "is_cancelled": 0}, - ) - - self.assertEqual(len(sles), 1) - - stock_reco.reload() - batch_no = get_batch_from_bundle(stock_reco.items[0].serial_and_batch_bundle) - - # Stock Reco for 100, Balace Qty 100 - stock_reco1 = create_stock_reconciliation( - item_code=item_code, - posting_date=add_days(nowdate(), -1), - posting_time="11:00:00", - batch_no=batch_no, - warehouse=warehouse, - qty=60, - rate=100, - ) - - sles = frappe.get_all( - "Stock Ledger Entry", - fields=["actual_qty"], - filters={"voucher_no": stock_reco.name, "is_cancelled": 0}, - ) - - stock_reco1.reload() - get_batch_from_bundle(stock_reco1.items[0].serial_and_batch_bundle) - - self.assertEqual(len(sles), 2) - - for row in sles: - if row.actual_qty < 0: - self.assertEqual(row.actual_qty, -60) - def test_update_stock_reconciliation_while_reposting(self): from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry @@ -1088,6 +1028,48 @@ class TestStockReconciliation(FrappeTestCase, StockTestMixin): self.assertEqual(flt(sle[0].qty_after_transaction), flt(100.0)) + def test_stock_reco_and_backdated_purchase_receipt(self): + from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry + + item = self.make_item( + "Test Batch Item Original STOCK RECO Test", + { + "is_stock_item": 1, + "has_batch_no": 1, + "create_new_batch": 1, + "batch_number_series": "TEST-BATCH-SRCOSRWFEE-.###", + }, + ) + + warehouse = "_Test Warehouse - _TC" + + sr = create_stock_reconciliation( + item_code=item.name, + warehouse=warehouse, + qty=100, + rate=100, + ) + + sr.reload() + self.assertTrue(sr.items[0].serial_and_batch_bundle) + self.assertFalse(sr.items[0].current_serial_and_batch_bundle) + batch = get_batch_from_bundle(sr.items[0].serial_and_batch_bundle) + + se1 = make_stock_entry( + item_code=item.name, + target=warehouse, + qty=50, + basic_rate=100, + posting_date=add_days(nowdate(), -2), + ) + + batch1 = get_batch_from_bundle(se1.items[0].serial_and_batch_bundle) + self.assertFalse(batch1 == batch) + + sr.reload() + self.assertTrue(sr.items[0].serial_and_batch_bundle) + self.assertFalse(sr.items[0].current_serial_and_batch_bundle) + def create_batch_item_with_batch(item_name, batch_id): batch_item_doc = create_item(item_name, is_stock_item=1) diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 2bd00fe55d5..5c5fd83af2f 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -840,7 +840,7 @@ class update_entries_after: 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) if sle.actual_qty < 0: sle.actual_qty = (