From 0ae61c49211f837f1e64dc43f7102677515ecb00 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 16 Jun 2026 17:27:27 +0530 Subject: [PATCH 1/3] fix: provision to recalculate valuation rate during reposting --- .../repost_item_valuation.js | 10 ++++ .../repost_item_valuation.json | 14 ++++- .../repost_item_valuation.py | 13 +++++ .../test_repost_item_valuation.py | 56 +++++++++++++++++++ erpnext/stock/stock_ledger.py | 2 +- 5 files changed, 92 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js index 134903f2309..fd2e217a31e 100644 --- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js +++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js @@ -92,6 +92,8 @@ frappe.ui.form.on("Repost Item Valuation", { }).addClass("btn-primary"); } + frm.trigger("show_update_valuation_field"); + if (frm.doc.status !== "Completed") { frm.trigger("show_reposting_progress"); } @@ -101,6 +103,13 @@ frappe.ui.form.on("Repost Item Valuation", { } }, + show_update_valuation_field(frm) { + frm.toggle_display( + "recalculate_valuation_rate", + ["Purchase Receipt", "Purchase Invoice", "Stock Entry"].includes(frm.doc.voucher_type) + ); + }, + execute_reposting(frm) { frm.add_custom_button(__("Start Reposting"), () => { frappe.call({ @@ -161,6 +170,7 @@ frappe.ui.form.on("Repost Item Valuation", { voucher_type: function (frm) { frm.trigger("set_company_on_transaction"); + frm.trigger("show_update_valuation_field"); }, voucher_no: function (frm) { diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.json b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.json index ce43ae3a54f..a9b68760e90 100644 --- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.json +++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.json @@ -1,5 +1,6 @@ { "actions": [], + "allow_bulk_edit": 1, "allow_import": 1, "autoname": "hash", "creation": "2022-01-11 15:03:38.273179", @@ -23,7 +24,7 @@ "via_landed_cost_voucher", "allow_zero_rate", "recreate_stock_ledgers", - "amended_from", + "recalculate_valuation_rate", "error_section", "error_log", "reposting_info_section", @@ -34,6 +35,7 @@ "gl_reposting_index", "reposting_data_file", "vouchers_based_on_item_and_warehouse_section", + "amended_from", "total_vouchers", "column_break_yqwo", "vouchers_posted" @@ -256,13 +258,21 @@ "label": "Reposting Data File", "no_copy": 1, "read_only": 1 + }, + { + "default": "0", + "description": "Only works for Purchase Receipt, Purchase Invoice and Stock Entry", + "fieldname": "recalculate_valuation_rate", + "fieldtype": "Check", + "label": "Recalculate Valuation Rate", + "show_description_on_click": 1 } ], "grid_page_length": 50, "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2026-03-27 18:59:58.637964", + "modified": "2026-06-16 17:30:42.715321", "modified_by": "Administrator", "module": "Stock", "name": "Repost Item Valuation", diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py index 1828528866f..b393c2bba45 100644 --- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py +++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py @@ -47,6 +47,7 @@ class RepostItemValuation(Document): items_to_be_repost: DF.Code | None posting_date: DF.Date posting_time: DF.Time | None + recalculate_valuation_rate: DF.Check recreate_stock_ledgers: DF.Check repost_only_accounting_ledgers: DF.Check reposting_data_file: DF.Attach | None @@ -343,6 +344,12 @@ class RepostItemValuation(Document): filters, ) + def _recalculate_valuation_rate(self): + doc = frappe.get_doc(self.voucher_type, self.voucher_no) + doc.update_valuation_rate() + for item in doc.items: + item.db_set("valuation_rate", item.valuation_rate) + def recreate_stock_ledger_entries(self): """Recreate Stock Ledger Entries for the transaction.""" if self.based_on == "Transaction" and self.recreate_stock_ledgers: @@ -384,6 +391,12 @@ def repost(doc): if not frappe.in_test: frappe.db.commit() + if ( + doc.voucher_type in ["Purchase Receipt", "Purchase Invoice", "Stock Entry"] + and doc.recalculate_valuation_rate + ): + doc._recalculate_valuation_rate() + if doc.recreate_stock_ledgers: doc.recreate_stock_ledger_entries() 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 82b2dbe6e45..64b303c5d92 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 @@ -419,6 +419,62 @@ class TestRepostItemValuation(ERPNextTestSuite, StockTestMixin): self.assertRaises(frappe.ValidationError, riv.save) doc.cancel() + def test_recalculate_valuation_rate_for_purchase_receipt(self): + item = self.make_item().name + + # receive item at rate 100 + pr = make_purchase_receipt(item_code=item, qty=1, rate=100) + self.assertSLEs(pr, [{"incoming_rate": 100}]) + + # change the rate from 100 to 150 + pr.load_from_db() + pr.items[0].db_set( + { + "base_net_amount": 150, + "net_rate": 150, + } + ) + + # repost with recalculate valuation rate + riv = frappe.get_doc( + doctype="Repost Item Valuation", + based_on="Transaction", + voucher_type=pr.doctype, + voucher_no=pr.name, + recalculate_valuation_rate=1, + posting_date=pr.posting_date, + posting_time=pr.posting_time, + ) + riv.submit() + + # incoming rate after reposting should be 150 + self.assertSLEs(pr, [{"incoming_rate": 150}]) + + def test_recalculate_valuation_rate_for_stock_entry(self): + item = self.make_item().name + + # receive item at rate 100 + se = make_stock_entry(item_code=item, target="_Test Warehouse - _TC", qty=1, rate=100) + self.assertSLEs(se, [{"incoming_rate": 100}]) + + # change the rate from 100 to 150 + se.items[0].db_set("basic_rate", 150) + + # repost with recalculate valuation rate + riv = frappe.get_doc( + doctype="Repost Item Valuation", + based_on="Transaction", + voucher_type=se.doctype, + voucher_no=se.name, + recalculate_valuation_rate=1, + posting_date=se.posting_date, + posting_time=se.posting_time, + ) + riv.submit() + + # incoming rate after reposting should be 150 + self.assertSLEs(se, [{"incoming_rate": 150}]) + def test_remove_attached_file(self): item_code = make_item("_Test Remove Attached File Item", properties={"is_stock_item": 1}) diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 5ab109ab04a..91c9a36ee77 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -1194,7 +1194,7 @@ class update_entries_after: sle.recalculate_rate or self.has_landed_cost_based_on_pi(sle) or (sle.voucher_type == "Stock Entry" and sle.actual_qty > 0 and is_repack_entry(sle.voucher_no)) - or (sle.voucher_type in ("Purchase Receipt", "Purchase Invoice")) + or (self.repost_doc and self.repost_doc.get("recalculate_valuation_rate")) ): rate = self.get_incoming_outgoing_rate_from_transaction(sle) From 28992eb2f49648541cafad60084e0cd3818f0ff8 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 16 Jun 2026 19:53:27 +0530 Subject: [PATCH 2/3] test: reset dont_execute_stock_reposts flag in tearDown The test_prevention_of_cancelled_transaction_riv test sets frappe.flags.dont_execute_stock_reposts = True without resetting it, which leaked into the recalculate_valuation_rate tests and made repost() a no-op (incoming rate stayed unchanged). Reset the flag in tearDown so reposts run for subsequent tests. Co-Authored-By: Claude Opus 4.8 --- .../repost_item_valuation/test_repost_item_valuation.py | 3 +++ 1 file changed, 3 insertions(+) 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 64b303c5d92..f4af5054f62 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 @@ -22,6 +22,9 @@ from erpnext.tests.utils import ERPNextTestSuite class TestRepostItemValuation(ERPNextTestSuite, StockTestMixin): + def tearDown(self): + frappe.flags.dont_execute_stock_reposts = False + def test_repost_time_slot(self): repost_settings = frappe.get_doc("Stock Reposting Settings") From e183e326193f0e7d92b80bee565e32d586171d12 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 16 Jun 2026 20:09:44 +0530 Subject: [PATCH 3/3] fix: test case --- .../repost_item_valuation/test_repost_item_valuation.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 f4af5054f62..40df17a061d 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 @@ -22,9 +22,6 @@ from erpnext.tests.utils import ERPNextTestSuite class TestRepostItemValuation(ERPNextTestSuite, StockTestMixin): - def tearDown(self): - frappe.flags.dont_execute_stock_reposts = False - def test_repost_time_slot(self): repost_settings = frappe.get_doc("Stock Reposting Settings") @@ -198,6 +195,7 @@ class TestRepostItemValuation(ERPNextTestSuite, StockTestMixin): @ERPNextTestSuite.change_settings("Stock Reposting Settings", {"item_based_reposting": 0}) def test_prevention_of_cancelled_transaction_riv(self): frappe.flags.dont_execute_stock_reposts = True + self.addCleanup(frappe.flags.pop, "dont_execute_stock_reposts") item = make_item() warehouse = "_Test Warehouse - _TC"