From 1e4b9fbdf09aa998da5f829303a4c859f341e484 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 --- 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 2588e2e6f91..de923999f5c 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -819,7 +819,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 f263ec69c92..f44057b2a96 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -212,13 +212,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 fee318a275f30e86fccff1d6e16aae8d1b091212 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 --- 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 de923999f5c..881fc786464 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -819,10 +819,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 07adfadd5804f1871b4964602c98490c1cb4d1bf 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 --- 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 208398303ce..9bf20f2f03f 100644 --- a/erpnext/stock/tests/test_get_item_details.py +++ b/erpnext/stock/tests/test_get_item_details.py @@ -28,3 +28,66 @@ class TestGetItemDetail(IntegrationTestCase): ) 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)