From a20951e1cd4807e91e495794f27d9babd408b493 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 5 May 2025 13:53:06 +0530 Subject: [PATCH] fix: reserved serial nos validation --- .../serial_and_batch_bundle.py | 33 +++++++++++++++++++ erpnext/stock/stock_ledger.py | 23 ------------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py index 20c4b277a67..11f9ee932ee 100644 --- a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py +++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py @@ -231,6 +231,9 @@ class SerialandBatchBundle(Document): "warehouse": self.warehouse, "check_serial_nos": True, "serial_nos": serial_nos, + "sabb_voucher_type": self.voucher_type, + "sabb_voucher_no": self.voucher_no, + "sabb_voucher_detail_no": self.voucher_detail_no, } if self.voucher_type == "POS Invoice": kwargs["ignore_voucher_nos"] = [self.voucher_no] @@ -1874,9 +1877,16 @@ def get_reserved_serial_nos(kwargs) -> list: ignore_serial_nos.extend(get_reserved_serial_nos_for_pos(kwargs)) reserved_entries = get_reserved_serial_nos_for_sre(kwargs) + if not reserved_entries: + return ignore_serial_nos + + reserved_voucher_details = get_reserved_voucher_details(kwargs) serial_nos = [] for entry in reserved_entries: + if entry.voucher_no in reserved_voucher_details: + continue + if kwargs.get("serial_nos") and entry.serial_no in kwargs.get("serial_nos"): frappe.throw( _( @@ -1893,6 +1903,29 @@ def get_reserved_serial_nos(kwargs) -> list: return ignore_serial_nos +def get_reserved_voucher_details(kwargs): + reserved_voucher_details = [] + + value = { + "Delivery Note": ["Delivery Note Item", "against_sales_order"], + }.get(kwargs.get("voucher_type")) + + if not value or not kwargs.get("sabb_voucher_no"): + return reserved_voucher_details + + reserved_voucher_details = frappe.get_all( + value[0], + pluck=value[1], + filters={ + "name": kwargs.get("sabb_voucher_detail_no"), + "parent": kwargs.get("sabb_voucher_no"), + "docstatus": 1, + }, + ) + + return reserved_voucher_details + + def get_reserved_serial_nos_for_pos(kwargs): from erpnext.controllers.sales_and_purchase_return import get_returned_serial_nos from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 0d8d61470d6..ab83b54ce51 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -2109,29 +2109,6 @@ def get_future_sle_with_negative_batch_qty(sle_args): def validate_reserved_stock(kwargs): - if kwargs.serial_no: - serial_nos = kwargs.serial_no.split("\n") - validate_reserved_serial_nos(kwargs.item_code, kwargs.warehouse, serial_nos) - - elif kwargs.batch_no: - validate_reserved_batch_nos(kwargs.item_code, kwargs.warehouse, [kwargs.batch_no]) - - elif kwargs.serial_and_batch_bundle: - sbb_entries = frappe.db.get_all( - "Serial and Batch Entry", - { - "parenttype": "Serial and Batch Bundle", - "parent": kwargs.serial_and_batch_bundle, - "docstatus": 1, - }, - ["batch_no", "serial_no"], - ) - - if serial_nos := [entry.serial_no for entry in sbb_entries if entry.serial_no]: - validate_reserved_serial_nos(kwargs.item_code, kwargs.warehouse, serial_nos) - elif batch_nos := [entry.batch_no for entry in sbb_entries if entry.batch_no]: - validate_reserved_batch_nos(kwargs.item_code, kwargs.warehouse, batch_nos) - # Qty based validation for non-serial-batch items OR SRE with Reservation Based On Qty. precision = cint(frappe.db.get_default("float_precision")) or 2 balance_qty = get_stock_balance(kwargs.item_code, kwargs.warehouse)