Merge pull request #57737 from mihir-kandoi/fix/secondary-item-must-not-waive-quality-inspection

fix(stock): stop a secondary item type from waiving quality inspection
This commit is contained in:
Mihir Kandoi
2026-08-03 14:59:13 +05:30
committed by GitHub
3 changed files with 55 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

@@ -7,6 +7,7 @@ from frappe.utils import add_days, cstr, flt, get_time, getdate, nowtime, today
from erpnext.accounts.doctype.account.test_account import get_inventory_account
from erpnext.controllers.accounts_controller import InvalidQtyError
from erpnext.exceptions import QualityInspectionRequiredError
from erpnext.stock.doctype.item.test_item import (
create_item,
make_item,
@@ -2728,6 +2729,36 @@ class TestStockEntry(ERPNextTestSuite):
self.assertEqual(fg_sle.incoming_rate, 0)
self.assertEqual(fg_sle.stock_value_difference, 0)
def test_secondary_item_type_does_not_waive_inspection_outside_manufacturing(self):
"""A stray secondary item type must not let a QI-required item through a receipt."""
item = make_item(
properties={
"is_stock_item": 1,
"valuation_rate": 50,
"inspection_required_before_purchase": 1,
}
).name
def receipt(secondary_item_type):
se = frappe.new_doc("Stock Entry")
se.purpose = se.stock_entry_type = "Material Receipt"
se.company = "_Test Company"
se.inspection_required = 1
se.append(
"items",
{
"item_code": item,
"t_warehouse": "_Test Warehouse - _TC",
"qty": 10,
"conversion_factor": 1,
"secondary_item_type": secondary_item_type,
},
)
return se
self.assertRaises(QualityInspectionRequiredError, receipt("").submit)
self.assertRaises(QualityInspectionRequiredError, receipt("Scrap").submit)
def _make_wo_for_free_raw_material(self, rm_item, fg_item, bom_no):
from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
from erpnext.manufacturing.doctype.work_order.work_order import (

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