From df820aece678ab6d18a54eb491a72066c6002d5d Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 11 Dec 2025 13:43:58 +0530 Subject: [PATCH] fix: putaway rule not applying on serial nos (cherry picked from commit 6bb0bdcdcac7bf0d65a7640ab3c2aff650312957) --- .../doctype/putaway_rule/putaway_rule.py | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/erpnext/stock/doctype/putaway_rule/putaway_rule.py b/erpnext/stock/doctype/putaway_rule/putaway_rule.py index 53af3e12896..a335d19afa5 100644 --- a/erpnext/stock/doctype/putaway_rule/putaway_rule.py +++ b/erpnext/stock/doctype/putaway_rule/putaway_rule.py @@ -11,6 +11,7 @@ from frappe import _ from frappe.model.document import Document from frappe.utils import cint, cstr, floor, flt, nowdate +from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos from erpnext.stock.utils import get_stock_balance @@ -119,13 +120,19 @@ def apply_putaway_rule(doctype, items, company, sync=None, purpose=None): item = frappe._dict(item) source_warehouse = item.get("s_warehouse") + serial_nos = [] + if item.get("serial_no"): + serial_nos = get_serial_nos(item.get("serial_no")) + item.conversion_factor = flt(item.conversion_factor) or 1.0 pending_qty, item_code = flt(item.qty), item.item_code pending_stock_qty = flt(item.transfer_qty) if doctype == "Stock Entry" else flt(item.stock_qty) uom_must_be_whole_number = frappe.db.get_value("UOM", item.uom, "must_be_whole_number") if not pending_qty or not item_code: - updated_table = add_row(item, pending_qty, source_warehouse or item.warehouse, updated_table) + updated_table = add_row( + item, pending_qty, source_warehouse or item.warehouse, updated_table, serial_nos=serial_nos + ) continue at_capacity, rules = get_ordered_putaway_rules(item_code, company, source_warehouse=source_warehouse) @@ -141,7 +148,7 @@ def apply_putaway_rule(doctype, items, company, sync=None, purpose=None): # rules available, but no free space items_not_accomodated.append([item_code, pending_qty]) else: - updated_table = add_row(item, pending_qty, warehouse, updated_table) + updated_table = add_row(item, pending_qty, warehouse, updated_table, serial_nos=serial_nos) continue # maintain item/item-warehouse wise rules, to handle if item is entered twice @@ -167,7 +174,9 @@ def apply_putaway_rule(doctype, items, company, sync=None, purpose=None): if not qty_to_allocate: break - updated_table = add_row(item, qty_to_allocate, rule.warehouse, updated_table, rule.name) + updated_table = add_row( + item, qty_to_allocate, rule.warehouse, updated_table, rule.name, serial_nos=serial_nos + ) pending_stock_qty -= stock_qty_to_allocate pending_qty -= qty_to_allocate @@ -265,7 +274,7 @@ def get_ordered_putaway_rules(item_code, company, source_warehouse=None): return False, vacant_rules -def add_row(item, to_allocate, warehouse, updated_table, rule=None): +def add_row(item, to_allocate, warehouse, updated_table, rule=None, serial_nos=None): new_updated_table_row = copy.deepcopy(item) new_updated_table_row.idx = 1 if not updated_table else cint(updated_table[-1].idx) + 1 new_updated_table_row.name = None @@ -283,6 +292,9 @@ def add_row(item, to_allocate, warehouse, updated_table, rule=None): if rule: new_updated_table_row.putaway_rule = rule + if serial_nos: + new_updated_table_row.serial_no = get_serial_nos_to_allocate(serial_nos, to_allocate) + new_updated_table_row.serial_and_batch_bundle = "" updated_table.append(new_updated_table_row) @@ -311,3 +323,12 @@ def show_unassigned_items_message(items_not_accomodated): """.format(_("Item"), _("Unassigned Qty"), formatted_item_rows) frappe.msgprint(msg, title=_("Insufficient Capacity"), is_minimizable=True, wide=True) + + +def get_serial_nos_to_allocate(serial_nos, to_allocate): + if serial_nos: + allocated_serial_nos = serial_nos[0 : cint(to_allocate)] + serial_nos[:] = serial_nos[cint(to_allocate) :] # pop out allocated serial nos and modify list + return "\n".join(allocated_serial_nos) if allocated_serial_nos else "" + else: + return ""