fix: support quality inspection for stock entry by purpose

Fetch QI items by warehouse direction per inspection_type, require QI on
the correct rows per stock entry purpose (finished good for Manufacture,
inward goods for Receipt/Repack, outgoing rows for issue/transfer), and
show the QI field only on those rows.
This commit is contained in:
Sudharsanan11
2026-06-25 11:51:00 +05:30
parent ead694c9cb
commit 2373db06ec
5 changed files with 59 additions and 18 deletions

View File

@@ -405,7 +405,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
} }
const incoming_doctypes = ["Purchase Receipt", "Purchase Invoice", "Subcontracting Receipt"]; const incoming_doctypes = ["Purchase Receipt", "Purchase Invoice", "Subcontracting Receipt"];
const incoming_purposes = ["Manufacture", "Material Receipt"]; const incoming_purposes = ["Manufacture", "Material Receipt", "Repack"];
const inspection_type = const inspection_type =
incoming_doctypes.includes(this.frm.doc.doctype) || incoming_doctypes.includes(this.frm.doc.doctype) ||
(this.frm.doc.doctype === "Stock Entry" && incoming_purposes.includes(this.frm.doc.purpose)) (this.frm.doc.doctype === "Stock Entry" && incoming_purposes.includes(this.frm.doc.purpose))
@@ -2967,7 +2967,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
const me = this; const me = this;
const incoming_doctypes = ["Purchase Receipt", "Purchase Invoice", "Subcontracting Receipt"]; const incoming_doctypes = ["Purchase Receipt", "Purchase Invoice", "Subcontracting Receipt"];
const incoming_purposes = ["Manufacture", "Material Receipt"]; const incoming_purposes = ["Manufacture", "Material Receipt", "Repack"];
const inspection_type = const inspection_type =
incoming_doctypes.includes(this.frm.doc.doctype) || incoming_doctypes.includes(this.frm.doc.doctype) ||
(this.frm.doc.doctype === "Stock Entry" && incoming_purposes.includes(this.frm.doc.purpose)) (this.frm.doc.doctype === "Stock Entry" && incoming_purposes.includes(this.frm.doc.purpose))
@@ -3065,13 +3065,20 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
} }
has_inspection_required(item) { has_inspection_required(item) {
if (this.frm.doc.doctype === "Stock Entry" && this.frm.doc.purpose == "Manufacture") { if (item.quality_inspection) {
if (item.is_finished_item && !item.quality_inspection) { return false;
return true; }
} if (this.frm.doc.doctype !== "Stock Entry") {
} else if (!item.quality_inspection) {
return true; return true;
} }
const purpose = this.frm.doc.purpose;
if (purpose === "Manufacture") {
return !!item.is_finished_item;
}
if (["Material Receipt", "Repack"].includes(purpose)) {
return !!item.t_warehouse;
}
return !!item.s_warehouse && item.s_warehouse !== item.t_warehouse;
} }
get_method_for_payment() { get_method_for_payment() {

View File

@@ -387,12 +387,29 @@ def item_query(doctype: Any, txt: str | None, searchfield: Any, start: int, page
] ]
if reference_doctype == "Stock Entry": if reference_doctype == "Stock Entry":
my_filters.extend( if filters.get("inspection_type") == "Incoming":
[ purpose = frappe.db.get_value("Stock Entry", filters.get("reference_name"), "purpose")
"and", if purpose == "Manufacture":
["items.t_warehouse", "is", "not set"], my_filters.extend(
] [
) "and",
["items.is_finished_item", "=", 1],
]
)
else:
my_filters.extend(
[
"and",
["items.t_warehouse", "is", "set"],
]
)
elif filters.get("inspection_type") == "Outgoing":
my_filters.extend(
[
"and",
["items.s_warehouse", "is", "set"],
]
)
elif filters.get("inspection_type") != "In Process": elif filters.get("inspection_type") != "In Process":
my_filters.extend( my_filters.extend(
[ [

View File

@@ -199,6 +199,17 @@ frappe.ui.form.on("Stock Entry", {
}, },
setup_quality_inspection: function (frm) { setup_quality_inspection: function (frm) {
const incoming_purposes = ["Manufacture", "Material Receipt", "Repack"];
// Show the Quality Inspection field only on rows that require inspection.
frm.get_docfield("items", "quality_inspection").depends_on = (row) =>
frm.doc.inspection_required &&
(frm.doc.purpose === "Manufacture"
? row.is_finished_item
: incoming_purposes.includes(frm.doc.purpose)
? row.t_warehouse
: row.s_warehouse && row.s_warehouse !== row.t_warehouse);
if (!frm.doc.inspection_required) { if (!frm.doc.inspection_required) {
return; return;
} }
@@ -216,7 +227,6 @@ frappe.ui.form.on("Stock Entry", {
} }
let quality_inspection_field = frm.get_docfield("items", "quality_inspection"); let quality_inspection_field = frm.get_docfield("items", "quality_inspection");
const incoming_purposes = ["Manufacture", "Material Receipt"];
quality_inspection_field.get_route_options_for_new_doc = function (row) { quality_inspection_field.get_route_options_for_new_doc = function (row) {
if (frm.is_new()) return {}; if (frm.is_new()) return {};
return { return {

View File

@@ -324,7 +324,6 @@
"options": "Batch" "options": "Batch"
}, },
{ {
"depends_on": "eval:parent.inspection_required && doc.t_warehouse",
"fieldname": "quality_inspection", "fieldname": "quality_inspection",
"fieldtype": "Link", "fieldtype": "Link",
"label": "Quality Inspection", "label": "Quality Inspection",
@@ -679,7 +678,7 @@
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2026-06-01 10:00:00.000000", "modified": "2026-06-25 11:39:55.152526",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Stock Entry Detail", "name": "Stock Entry Detail",

View File

@@ -49,8 +49,16 @@ class QualityInspectionService:
"Item", row.item_code, inspection_required_fieldname "Item", row.item_code, inspection_required_fieldname
): ):
qi_required = True qi_required = True
elif self.doc.doctype == "Stock Entry" and row.t_warehouse: elif self.doc.doctype == "Stock Entry":
qi_required = True # inward stock needs inspection if self.doc.purpose == "Manufacture":
# only the finished good needs inspection
if row.is_finished_item:
qi_required = True
elif self.doc.purpose in ["Material Receipt", "Repack"]:
if row.t_warehouse:
qi_required = True
elif row.s_warehouse and row.s_warehouse != row.t_warehouse:
qi_required = True
if row.get("secondary_item_type") or row.get("is_legacy_scrap_item"): if row.get("secondary_item_type") or row.get("is_legacy_scrap_item"):
continue continue