diff --git a/erpnext/stock/report/serial_no_ledger/serial_no_ledger.py b/erpnext/stock/report/serial_no_ledger/serial_no_ledger.py index c927f3d6d9e..b73f8dde3b2 100644 --- a/erpnext/stock/report/serial_no_ledger/serial_no_ledger.py +++ b/erpnext/stock/report/serial_no_ledger/serial_no_ledger.py @@ -7,6 +7,7 @@ import frappe from frappe import _ from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos as get_serial_nos_from_sle +from erpnext.stock.serial_batch_bundle import get_serial_no_status from erpnext.stock.stock_ledger import get_stock_ledger_entries BUYING_VOUCHER_TYPES = ["Purchase Invoice", "Purchase Receipt", "Subcontracting Receipt"] @@ -111,7 +112,7 @@ def get_data(filters): "posting_time": row.posting_time, "voucher_type": row.voucher_type, "voucher_no": row.voucher_no, - "status": "Active" if row.actual_qty > 0 else "Delivered", + "status": get_serial_no_status(row), "company": row.company, "warehouse": row.warehouse, "qty": 1 if row.actual_qty > 0 else -1, diff --git a/erpnext/stock/serial_batch_bundle.py b/erpnext/stock/serial_batch_bundle.py index 84535372b4b..b2eba994538 100644 --- a/erpnext/stock/serial_batch_bundle.py +++ b/erpnext/stock/serial_batch_bundle.py @@ -15,6 +15,45 @@ from erpnext.stock.deprecated_serial_batch import ( ) from erpnext.stock.valuation import round_off_if_near_zero +CONSUMED_SERIAL_NO_STOCK_ENTRY_PURPOSES = ( + "Manufacture", + "Material Issue", + "Repack", + "Material Consumption for Manufacture", +) +INACTIVE_SERIAL_NO_STOCK_ENTRY_PURPOSES = ("Disassemble", "Material Receipt") + + +def get_serial_no_status(sle): + warehouse = sle.warehouse if sle.actual_qty > 0 else None + if warehouse: + return "Active" + + status = get_status_for_serial_nos(sle) + if sle.voucher_type == "Stock Entry" and sle.actual_qty < 0: + purpose = frappe.get_cached_value("Stock Entry", sle.voucher_no, "purpose") + if purpose in INACTIVE_SERIAL_NO_STOCK_ENTRY_PURPOSES: + status = "Inactive" + + return status + + +def get_status_for_serial_nos(sle): + status = "Inactive" + if sle.actual_qty < 0: + status = "Delivered" + if sle.voucher_type == "Stock Entry": + purpose = frappe.get_cached_value("Stock Entry", sle.voucher_no, "purpose") + if purpose in CONSUMED_SERIAL_NO_STOCK_ENTRY_PURPOSES: + status = "Consumed" + + if sle.is_cancelled == 1 and ( + sle.voucher_type in ["Purchase Invoice", "Purchase Receipt"] or status == "Consumed" + ): + status = "Inactive" + + return status + class SerialBatchBundle: def __init__(self, **kwargs): @@ -410,25 +449,7 @@ class SerialBatchBundle: self.update_serial_no_status_warehouse(self.sle, serial_nos) def get_status_for_serial_nos(self, sle): - status = "Inactive" - if sle.actual_qty < 0: - status = "Delivered" - if sle.voucher_type == "Stock Entry": - purpose = frappe.get_cached_value("Stock Entry", sle.voucher_no, "purpose") - if purpose in [ - "Manufacture", - "Material Issue", - "Repack", - "Material Consumption for Manufacture", - ]: - status = "Consumed" - - if sle.is_cancelled == 1 and ( - sle.voucher_type in ["Purchase Invoice", "Purchase Receipt"] or status == "Consumed" - ): - status = "Inactive" - - return status + return get_status_for_serial_nos(sle) def update_serial_no_status_warehouse(self, sle, serial_nos): warehouse = sle.warehouse if sle.actual_qty > 0 else None @@ -436,19 +457,12 @@ class SerialBatchBundle: if isinstance(serial_nos, str): serial_nos = [serial_nos] - status = "Active" - if not warehouse: - status = self.get_status_for_serial_nos(sle) + status = get_serial_no_status(sle) customer = None if sle.voucher_type in ["Sales Invoice", "Delivery Note"] and sle.actual_qty < 0: customer = frappe.get_cached_value(sle.voucher_type, sle.voucher_no, "customer") - if sle.voucher_type in ["Stock Entry"] and sle.actual_qty < 0: - purpose = frappe.get_cached_value("Stock Entry", sle.voucher_no, "purpose") - if purpose in ["Disassemble", "Material Receipt"]: - status = "Inactive" - sn_table = frappe.qb.DocType("Serial No") query = (