diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index 9b6f95f25df..268918eca00 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -2433,24 +2433,27 @@ def make_stock_entry( @frappe.whitelist() <<<<<<< HEAD +<<<<<<< HEAD def get_default_warehouse(company): ======= def get_disassembly_available_qty(stock_entry_name: str) -> float: +======= +def get_disassembly_available_qty(stock_entry_name: str, current_se_name: str | None = None) -> float: +>>>>>>> 6394dead72 (fix: validate qty that can be disassembled from source stock entry.) se = frappe.db.get_value("Stock Entry", stock_entry_name, ["fg_completed_qty"], as_dict=True) if not se: return 0.0 - already_disassembled = flt( - frappe.db.get_value( - "Stock Entry", - { - "source_stock_entry": stock_entry_name, - "purpose": "Disassemble", - "docstatus": 1, - }, - [{"SUM": "fg_completed_qty"}], - ) - ) + filters = { + "source_stock_entry": stock_entry_name, + "purpose": "Disassemble", + "docstatus": 1, + } + + if current_se_name: + filters["name"] = ("!=", current_se_name) + + already_disassembled = flt(frappe.db.get_value("Stock Entry", filters, [{"SUM": "fg_completed_qty"}])) return flt(se.fg_completed_qty) - already_disassembled diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 8d5c1fe60dc..c1eeec3eaf4 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -247,6 +247,7 @@ class StockEntry(StockController, SubcontractingInwardController): self.validate_warehouse() self.validate_warehouse_of_sabb() self.validate_work_order() + self.validate_source_stock_entry() self.validate_bom() self.set_process_loss_qty() self.validate_purchase_order() @@ -847,6 +848,26 @@ class StockEntry(StockController, SubcontractingInwardController): elif self.purpose != "Material Transfer": self.work_order = None + def validate_source_stock_entry(self): + if not self.get("source_stock_entry"): + return + + from erpnext.manufacturing.doctype.work_order.work_order import get_disassembly_available_qty + + available_qty = get_disassembly_available_qty(self.source_stock_entry, self.name) + + if flt(self.fg_completed_qty) > available_qty: + frappe.throw( + _( + "Cannot disassemble {0} qty against Stock Entry {1}. Only {2} qty available to disassemble." + ).format( + self.fg_completed_qty, + self.source_stock_entry, + available_qty, + ), + title=_("Excess Disassembly"), + ) + def check_if_operations_completed(self): """Check if Time Sheets are completed against before manufacturing to capture operating costs.""" prod_order = frappe.get_doc("Work Order", self.work_order)