From b140ce71d75fdc6c24664c2ec68a693a63e9d0f8 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Tue, 4 Feb 2025 10:54:57 +0530 Subject: [PATCH 1/3] fix: fetch rate from item price list when document is saved (cherry picked from commit 1e4b9fbdf09aa998da5f829303a4c859f341e484) --- erpnext/controllers/accounts_controller.py | 2 +- erpnext/stock/get_item_details.py | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 2aadd6b584e..87671568bd8 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -817,7 +817,7 @@ class AccountsController(TransactionBase): item.get(fieldname) is None or fieldname in force_item_fields or ( - fieldname in ["serial_no", "batch_no"] + fieldname in ["serial_no", "batch_no", "rate", "price_list_rate"] and item.get("use_serial_batch_fields") ) ): diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index c604c4cd87c..e565b5c6015 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -206,13 +206,21 @@ def update_stock(ctx, out, doc=None): filter_batches(batches, doc) for batch_no, batch_qty in batches.items(): + rate = get_batch_based_item_price( + {"price_list": doc.selling_price_list, "uom": out.uom, "batch_no": batch_no}, + out.item_code, + ) if batch_qty >= qty: out.update({"batch_no": batch_no, "actual_batch_qty": qty}) + if rate: + out.update({"rate": rate, "price_list_rate": rate}) break else: qty -= batch_qty - out.update({"batch_no": batch_no, "actual_batch_qty": batch_qty}) + out.update({"batch_no": batch_no, "actual_batch_qty": qty}) + if rate: + out.update({"rate": rate, "price_list_rate": rate}) if out.has_serial_no and out.has_batch_no and has_incorrect_serial_nos(ctx, out): kwargs["batches"] = [ctx.get("batch_no")] if ctx.get("batch_no") else [out.get("batch_no")] From 6a03f995463d76e95c09543160addc9ea8b26283 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Tue, 4 Feb 2025 11:46:11 +0530 Subject: [PATCH 2/3] fix: logical error failing tests (cherry picked from commit fee318a275f30e86fccff1d6e16aae8d1b091212) --- erpnext/controllers/accounts_controller.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 87671568bd8..715a73e0da6 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -817,10 +817,13 @@ class AccountsController(TransactionBase): item.get(fieldname) is None or fieldname in force_item_fields or ( - fieldname in ["serial_no", "batch_no", "rate", "price_list_rate"] + fieldname in ["serial_no", "batch_no"] and item.get("use_serial_batch_fields") ) ): + if fieldname == "batch_no" and not item.batch_no: + item.set("rate", ret.get("rate")) + item.set("price_list_rate", ret.get("price_list_rate")) item.set(fieldname, value) elif fieldname in ["cost_center", "conversion_factor"] and not item.get( From 25075e5981de3c6722c5d03027c52c349f6ff172 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Wed, 5 Feb 2025 13:12:25 +0530 Subject: [PATCH 3/3] test: added test (cherry picked from commit 07adfadd5804f1871b4964602c98490c1cb4d1bf) --- erpnext/stock/tests/test_get_item_details.py | 63 ++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/erpnext/stock/tests/test_get_item_details.py b/erpnext/stock/tests/test_get_item_details.py index 30f748a65e0..fc19bac0a44 100644 --- a/erpnext/stock/tests/test_get_item_details.py +++ b/erpnext/stock/tests/test_get_item_details.py @@ -34,3 +34,66 @@ class TestGetItemDetail(FrappeTestCase): ) details = get_item_details(args) self.assertEqual(details.get("price_list_rate"), 100) + + # making this test in get_item_details test file as feat/fix is present in that method + def test_fetch_price_from_list_rate_on_doc_save(self): + # create item + item = frappe.get_doc( + { + "doctype": "Item", + "item_code": "Test Item with Batch", + "item_name": "Test Item with Batch", + "item_group": "All Item Groups", + "is_stock_item": 1, + "has_batch_no": 1, + } + ).insert() + + # create batch + frappe.get_doc( + { + "doctype": "Batch", + "batch_id": "BATCH01", + "item": item, + } + ).insert() + + # create item price + frappe.get_doc( + { + "doctype": "Item Price", + "price_list": "Standard Selling", + "item_code": item.item_code, + "price_list_rate": 50, + "batch_no": "BATCH01", + } + ).insert() + + # create purchase receipt to have some stock for delivery + from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt + + make_purchase_receipt( + item_code=item.item_code, + warehouse="_Test Warehouse - _TC", + qty=100, + rate=100, + batch_no="BATCH01", + ) + + # creating sales order just to create delivery note from it + from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order + + so = make_sales_order(item_code=item.item_code, qty=2, rate=75) + + from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note + + dn = make_delivery_note(so.name) + + # Test 1 : On creation of DN, item's batch won't be fetched and rate will remaing the same as in SO + self.assertIsNone(dn.items[0].batch_no) + self.assertEqual(dn.items[0].rate, 75) + + # Test 2 : On saving the DN, item's batch will be fetched and rate will be updated from Item Price + dn.save() + self.assertEqual(dn.items[0].batch_no, "BATCH01") + self.assertEqual(dn.items[0].rate, 50)