From 50258502585d30791bd6716b4d2e2935721047f9 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Tue, 17 Oct 2023 12:20:23 +0530 Subject: [PATCH] fix: same Serial No get mapped while creating SO -> DN (#37527) * fix: same Serial No get mapped while creating SO -> DN * test: add test case for DN with repetitive serial item --- erpnext/controllers/accounts_controller.py | 7 +++++ .../delivery_note/test_delivery_note.py | 29 ++++++++++++++++++- erpnext/stock/get_item_details.py | 4 +++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 7ae1b0c1ad2a..c17866162b6c 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -617,6 +617,7 @@ def set_missing_item_details(self, for_validate=False): self.pricing_rules = [] + selected_serial_nos_map = {} for item in self.get("items"): if item.get("item_code"): args = parent_dict.copy() @@ -628,6 +629,7 @@ def set_missing_item_details(self, for_validate=False): args["ignore_pricing_rule"] = ( self.ignore_pricing_rule if hasattr(self, "ignore_pricing_rule") else 0 ) + args["ignore_serial_nos"] = selected_serial_nos_map.get(item.get("item_code")) if not args.get("transaction_date"): args["transaction_date"] = args.get("posting_date") @@ -684,6 +686,11 @@ def set_missing_item_details(self, for_validate=False): if ret.get("pricing_rules"): self.apply_pricing_rule_on_items(item, ret) self.set_pricing_rule_details(item, ret) + + if ret.get("serial_no"): + selected_serial_nos_map.setdefault(item.get("item_code"), []).extend( + ret.get("serial_no").split("\n") + ) else: # Transactions line item without item code diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py index 8ea87f00c5b8..c6f3197a6686 100644 --- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py @@ -5,7 +5,7 @@ import json import frappe -from frappe.tests.utils import FrappeTestCase +from frappe.tests.utils import FrappeTestCase, change_settings from frappe.utils import add_days, cstr, flt, nowdate, nowtime, today from erpnext.accounts.doctype.account.test_account import get_inventory_account @@ -1284,6 +1284,33 @@ def test_packed_items_for_return_delivery_note(self): self.assertEqual(return_dn.packed_items[0].batch_no, dn.packed_items[0].batch_no) self.assertEqual(return_dn.packed_items[1].serial_no, dn.packed_items[1].serial_no) + @change_settings("Stock Settings", {"automatically_set_serial_nos_based_on_fifo": 1}) + def test_delivery_note_for_repetitive_serial_item(self): + # Step - 1: Create Serial Item + item, warehouse = ( + make_item( + properties={"is_stock_item": 1, "has_serial_no": 1, "serial_no_series": "TEST-SERIAL-.###"} + ).name, + "_Test Warehouse - _TC", + ) + + # Step - 2: Inward Stock + make_stock_entry(item_code=item, target=warehouse, qty=5) + + # Step - 3: Create Delivery Note with repetitive Serial Item + dn = create_delivery_note(item_code=item, warehouse=warehouse, qty=2, do_not_save=True) + dn.append("items", dn.items[0].as_dict()) + dn.items[1].qty = 3 + dn.save() + dn.submit() + + # Test - 1: Serial Nos should be different for each line item + serial_nos = [] + for item in dn.items: + for serial_no in item.serial_no.split("\n"): + self.assertNotIn(serial_no, serial_nos) + serial_nos.append(serial_no) + def tearDown(self): frappe.db.rollback() frappe.db.set_single_value("Selling Settings", "dont_reserve_sales_order_qty_on_sales_return", 0) diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 13f484b1c851..92c945b254b8 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -160,6 +160,7 @@ def update_stock(args, out): and out.warehouse and out.stock_qty > 0 ): + out["ignore_serial_nos"] = args.get("ignore_serial_nos") if out.has_batch_no and not args.get("batch_no"): out.batch_no = get_batch_no(out.item_code, out.warehouse, out.qty) @@ -1140,6 +1141,8 @@ def get_serial_nos_by_fifo(args, sales_order=None): query = query.where(sn.sales_order == sales_order) if args.batch_no: query = query.where(sn.batch_no == args.batch_no) + if args.ignore_serial_nos: + query = query.where(sn.name.notin(args.ignore_serial_nos)) serial_nos = query.run(as_list=True) serial_nos = [s[0] for s in serial_nos] @@ -1450,6 +1453,7 @@ def get_serial_no(args, serial_nos=None, sales_order=None): "item_code": args.get("item_code"), "warehouse": args.get("warehouse"), "stock_qty": args.get("stock_qty"), + "ignore_serial_nos": args.get("ignore_serial_nos"), } ) args = process_args(args)