From d730d6e5c760c8a98081cfe325b47a9beebddd7f Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 2 Nov 2023 15:15:53 +0530 Subject: [PATCH] fix: remove voucher type and no for Item and Warehouse based reposting (backport #37849) (#37850) * fix: remove voucher type and no for Item and Warehouse based reposting (cherry picked from commit 0104897d693ca98796536eac7a9edadc58c64fff) * chore: fix test cases --------- Co-authored-by: Rohit Waghchaure (cherry picked from commit e19cade12d59ec439e2e1141e929c4d846935013) # Conflicts: # erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py # erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py # erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.json --- erpnext/controllers/stock_controller.py | 2 - .../test_repost_item_valuation.py | 7 + .../doctype/stock_entry/test_stock_entry.py | 1 + .../test_stock_reconciliation.py | 310 ++++++++++++++++++ .../stock_reposting_settings.json | 6 +- 5 files changed, 323 insertions(+), 3 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index c866f6d37272..450d3a279b1c 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -914,8 +914,6 @@ def create_item_wise_repost_entries(voucher_type, voucher_no, allow_zero_rate=Fa repost_entry = frappe.new_doc("Repost Item Valuation") repost_entry.based_on = "Item and Warehouse" - repost_entry.voucher_type = voucher_type - repost_entry.voucher_no = voucher_no repost_entry.item_code = sle.item_code repost_entry.warehouse = sle.warehouse diff --git a/erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py index 78d6417bfa89..88eb50b551c5 100644 --- a/erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py +++ b/erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py @@ -5,9 +5,14 @@ from unittest.mock import MagicMock, call import frappe +<<<<<<< HEAD from frappe.tests.utils import FrappeTestCase from frappe.utils import nowdate from frappe.utils.data import add_to_date, today +======= +from frappe.tests.utils import FrappeTestCase, change_settings +from frappe.utils import add_days, add_to_date, now, nowdate, today +>>>>>>> e19cade12d (fix: remove voucher type and no for Item and Warehouse based reposting (backport #37849) (#37850)) from erpnext.accounts.utils import repost_gle_for_stock_vouchers from erpnext.controllers.stock_controller import create_item_wise_repost_entries @@ -173,6 +178,7 @@ def test_stock_freeze_validation(self): riv.set_status("Skipped") + @change_settings("Stock Reposting Settings", {"item_based_reposting": 0}) def test_prevention_of_cancelled_transaction_riv(self): frappe.flags.dont_execute_stock_reposts = True @@ -295,6 +301,7 @@ def test_account_freeze_validation(self): accounts_settings.acc_frozen_upto = "" accounts_settings.save() + @change_settings("Stock Reposting Settings", {"item_based_reposting": 0}) def test_create_repost_entry_for_cancelled_document(self): pr = make_purchase_receipt( company="_Test Company with perpetual inventory", diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py index 99de4c1844f4..7203c482f962 100644 --- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py @@ -1414,6 +1414,7 @@ def test_stock_entry_item_details(self): self.assertEqual(se.items[0].item_name, item.item_name) self.assertEqual(se.items[0].stock_uom, item.stock_uom) + @change_settings("Stock Reposting Settings", {"item_based_reposting": 0}) def test_reposting_for_depedent_warehouse(self): from erpnext.stock.doctype.repost_item_valuation.repost_item_valuation import repost_sl_entries from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py index a09ad9461553..b3e7c17e5b7a 100644 --- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py @@ -677,6 +677,316 @@ def test_serial_no_batch_no_item(self): self.assertEqual(flt(sl_entry.actual_qty), 1.0) self.assertEqual(flt(sl_entry.qty_after_transaction), 1.0) +<<<<<<< HEAD +======= + @change_settings("Stock Reposting Settings", {"item_based_reposting": 0}) + def test_backdated_stock_reco_entry(self): + from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry + + item_code = self.make_item( + "Test New Batch Item ABCV", + { + "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 + se1 = make_stock_entry( + item_code=item_code, posting_time="09:00:00", target=warehouse, qty=100, basic_rate=700 + ) + + # Removed 50 Qty, Balace Qty 50 + se2 = make_stock_entry( + item_code=item_code, + batch_no=se1.items[0].batch_no, + posting_time="10:00:00", + source=warehouse, + qty=50, + basic_rate=700, + ) + + # Stock Reco for 100, Balace Qty 100 + stock_reco = create_stock_reconciliation( + item_code=item_code, + posting_time="11:00:00", + warehouse=warehouse, + batch_no=se1.items[0].batch_no, + qty=100, + rate=100, + ) + + # Removed 50 Qty, Balace Qty 50 + make_stock_entry( + item_code=item_code, + batch_no=se1.items[0].batch_no, + posting_time="12:00:00", + source=warehouse, + qty=50, + basic_rate=700, + ) + + self.assertFalse(frappe.db.exists("Repost Item Valuation", {"voucher_no": stock_reco.name})) + + # Cancel the backdated Stock Entry se2, + # Since Stock Reco entry in the future the Balace Qty should remain as it's (50) + + se2.cancel() + + sle = frappe.get_all( + "Stock Ledger Entry", + filters={"item_code": item_code, "warehouse": warehouse, "is_cancelled": 0}, + fields=["qty_after_transaction"], + order_by="posting_time desc, creation desc", + ) + + self.assertEqual(flt(sle[0].qty_after_transaction), flt(50.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", "batch_no"], + filters={"voucher_no": stock_reco.name, "is_cancelled": 0}, + ) + + self.assertEqual(len(sles), 1) + + # Stock Reco for 100, Balace Qty 100 + create_stock_reconciliation( + item_code=item_code, + posting_date=add_days(nowdate(), -1), + posting_time="11:00:00", + batch_no=sles[0].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}, + ) + + 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 + + item_code = self.make_item().name + warehouse = "_Test Warehouse - _TC" + + # Stock Value => 100 * 100 = 10000 + se = make_stock_entry( + item_code=item_code, + target=warehouse, + qty=100, + basic_rate=100, + posting_time="10:00:00", + ) + + # Stock Value => 100 * 200 = 20000 + # Value Change => 20000 - 10000 = 10000 + sr1 = create_stock_reconciliation( + item_code=item_code, + warehouse=warehouse, + qty=100, + rate=200, + posting_time="12:00:00", + ) + self.assertEqual(sr1.difference_amount, 10000) + + # Stock Value => 50 * 50 = 2500 + # Value Change => 2500 - 10000 = -7500 + sr2 = create_stock_reconciliation( + item_code=item_code, + warehouse=warehouse, + qty=50, + rate=50, + posting_time="11:00:00", + ) + self.assertEqual(sr2.difference_amount, -7500) + + sr1.load_from_db() + self.assertEqual(sr1.difference_amount, 17500) + + sr2.cancel() + 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 test_batch_item_validation(self): + from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry + + item_code = self.make_item( + "Test Batch Item Original", + { + "is_stock_item": 1, + "has_batch_no": 1, + "batch_number_series": "BNS9.####", + "create_new_batch": 1, + }, + ).name + + sr = make_stock_entry( + item_code=item_code, + target="_Test Warehouse - _TC", + qty=100, + basic_rate=100, + posting_date=nowdate(), + ) + + new_item_code = self.make_item( + "Test Batch Item New 1", + { + "is_stock_item": 1, + "has_batch_no": 1, + }, + ).name + + sr = create_stock_reconciliation( + item_code=new_item_code, + warehouse="_Test Warehouse - _TC", + qty=10, + rate=100, + batch_no=sr.items[0].batch_no, + do_not_save=True, + ) + + self.assertRaises(frappe.ValidationError, sr.save) + + @change_settings("Stock Settings", {"allow_negative_stock": 0}) + def test_backdated_stock_reco_for_batch_item_dont_have_future_sle(self): + # Step - 1: Create a Batch Item + from erpnext.stock.doctype.item.test_item import make_item + + item = make_item( + properties={ + "is_stock_item": 1, + "has_batch_no": 1, + "create_new_batch": 1, + "batch_number_series": "TEST-BATCH-.###", + } + ).name + + # Step - 2: Create Opening Stock Reconciliation + sr1 = create_stock_reconciliation( + item_code=item, + warehouse="_Test Warehouse - _TC", + qty=10, + purpose="Opening Stock", + posting_date=add_days(nowdate(), -2), + ) + + # Step - 3: Create Stock Entry (Material Receipt) + from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry + + se1 = make_stock_entry( + item_code=item, + target="_Test Warehouse - _TC", + qty=100, + ) + + # Step - 4: Create Stock Entry (Material Issue) + make_stock_entry( + item_code=item, + source="_Test Warehouse - _TC", + qty=100, + batch_no=se1.items[0].batch_no, + purpose="Material Issue", + ) + + # Step - 5: Create Stock Reconciliation (Backdated) after the Stock Reconciliation 1 (Step - 2) + sr2 = create_stock_reconciliation( + item_code=item, + warehouse="_Test Warehouse - _TC", + qty=5, + batch_no=sr1.items[0].batch_no, + posting_date=add_days(nowdate(), -1), + ) + + self.assertEqual(sr2.docstatus, 1) + +>>>>>>> e19cade12d (fix: remove voucher type and no for Item and Warehouse based reposting (backport #37849) (#37850)) 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/doctype/stock_reposting_settings/stock_reposting_settings.json b/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.json index 0facae8d3b88..2d80ec17057c 100644 --- a/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.json +++ b/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.json @@ -48,7 +48,7 @@ "label": "Limit timeslot for Stock Reposting" }, { - "default": "0", + "default": "1", "fieldname": "item_based_reposting", "fieldtype": "Check", "label": "Use Item based reposting" @@ -57,7 +57,11 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], +<<<<<<< HEAD "modified": "2021-11-02 01:22:45.155841", +======= + "modified": "2023-11-01 16:14:29.080697", +>>>>>>> e19cade12d (fix: remove voucher type and no for Item and Warehouse based reposting (backport #37849) (#37850)) "modified_by": "Administrator", "module": "Stock", "name": "Stock Reposting Settings",