fix(stock): stop a secondary item type from waiving quality inspection

The inspection skip for secondary rows applied to every purpose, and in
validate_inspection it skipped the row even when the item itself mandated
inspection. Secondary Item Type is only meaningful on the purposes that
produce secondary items, but nothing clears it elsewhere, since
mark_finished_and_secondary_items runs for Manufacture and Repack alone.

A Material Receipt of an item marked Inspection Required Before Purchase
is blocked without an inspection. Setting Secondary Item Type on the row
submitted it clean.

Limit the exemption to the purposes that produce secondary items, and to
other doctypes such as Subcontracting Receipt, which carry the field with
its intended meaning. The client-side mirror is kept in sync.
This commit is contained in:
Mihir Kandoi
2026-08-03 13:55:26 +05:30
parent c020de5a69
commit dfec7bd5c7
2 changed files with 24 additions and 3 deletions

View File

@@ -18,10 +18,15 @@ erpnext.stock.qi_outgoing_purposes = [
"Subcontracting Delivery",
"Disassemble",
];
erpnext.stock.secondary_item_purposes = ["Manufacture", "Repack", "Disassemble"];
erpnext.stock.is_incoming_qi_purpose = (purpose) =>
purpose === "Manufacture" || erpnext.stock.qi_incoming_purposes.includes(purpose);
erpnext.stock.row_requires_quality_inspection = (purpose, row) => {
if (row.secondary_item_type || row.is_legacy_scrap_item) return false;
if (
erpnext.stock.secondary_item_purposes.includes(purpose) &&
(row.secondary_item_type || row.is_legacy_scrap_item)
)
return false;
if (purpose === "Manufacture") return !!row.is_finished_item;
if (erpnext.stock.qi_incoming_purposes.includes(purpose)) return !!row.t_warehouse;
if (erpnext.stock.qi_outgoing_purposes.includes(purpose))

View File

@@ -50,9 +50,25 @@ QI_OUTGOING_PURPOSES = (
)
SECONDARY_ITEM_PURPOSES = ("Manufacture", "Repack", "Disassemble")
def is_inspection_exempt_secondary_row(doc, row) -> bool:
"""Whether the row is a secondary item on a document that produces secondary items."""
if not (row.get("secondary_item_type") or row.get("is_legacy_scrap_item")):
return False
if doc.doctype == "Stock Entry":
return doc.purpose in SECONDARY_ITEM_PURPOSES
return True
def stock_entry_row_requires_inspection(purpose, row):
"""Check if this Stock Entry row need a Quality Inspection."""
if row.get("secondary_item_type") or row.get("is_legacy_scrap_item"):
if purpose in SECONDARY_ITEM_PURPOSES and (
row.get("secondary_item_type") or row.get("is_legacy_scrap_item")
):
return False
if purpose == "Manufacture":
return bool(row.is_finished_item)
@@ -88,7 +104,7 @@ class QualityInspectionService:
elif self.doc.doctype == "Stock Entry":
qi_required = stock_entry_row_requires_inspection(self.doc.purpose, row)
if row.get("secondary_item_type") or row.get("is_legacy_scrap_item"):
if is_inspection_exempt_secondary_row(self.doc, row):
continue
if qi_required: # validate row only if inspection is required on item level