refactor(stock): convert Job Card reference update to qb

Replace the raw f-string UPDATE (name + production_item match) that links a
Quality Inspection back to its Job Card with frappe.qb.update. Same result on
MariaDB; valid under Postgres.

Tests: the Job Card reference update and its production_item scoping.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Mihir Kandoi
2026-06-19 22:11:25 +05:30
parent d955122c88
commit d61720c3e2
2 changed files with 66 additions and 8 deletions

View File

@@ -215,14 +215,13 @@ class QualityInspection(Document):
if self.reference_type == "Job Card":
if self.reference_name:
frappe.db.sql(
f"""
UPDATE `tab{self.reference_type}`
SET quality_inspection = %s, modified = %s
WHERE name = %s and production_item = %s
""",
(quality_inspection, self.modified, self.reference_name, self.item_code),
)
ref = frappe.qb.DocType(self.reference_type)
(
frappe.qb.update(ref)
.set(ref.quality_inspection, quality_inspection)
.set(ref.modified, self.modified)
.where((ref.name == self.reference_name) & (ref.production_item == self.item_code))
).run()
else:
doctype = self.reference_type + " Item"

View File

@@ -279,6 +279,65 @@ class TestQualityInspection(ERPNextTestSuite):
se.delete()
def test_qi_updates_job_card_reference(self):
"""Submitting a QI with reference_type 'Job Card' writes its name onto the
Job Card's quality_inspection field (the Job Card branch of
QualityInspection.update_qc_reference)."""
create_item("_Test Item")
# Job Card whose production_item matches the QI item_code -> must be updated.
matching_jc = make_minimal_job_card(production_item="_Test Item")
# Job Card with a different production_item -> the production_item filter must
# keep it untouched.
other_item = create_item("_Test Item for QC " + frappe.utils.random_string(6)).name
non_matching_jc = make_minimal_job_card(production_item=other_item)
qa = create_quality_inspection(
item_code="_Test Item",
reference_type="Job Card",
reference_name=matching_jc,
)
# The converted UPDATE wrote the QI name onto the matching Job Card.
self.assertEqual(
frappe.db.get_value("Job Card", matching_jc, "quality_inspection"),
qa.name,
)
# The production_item filter excluded the Job Card with a different item.
self.assertFalse(frappe.db.get_value("Job Card", non_matching_jc, "quality_inspection"))
def test_qi_job_card_reference_respects_production_item(self):
"""A QI referencing a Job Card by name but whose item_code does not match the
Job Card's production_item must NOT update that Job Card."""
create_item("_Test Item")
mismatch_item = create_item("_Test Item Mismatch QC " + frappe.utils.random_string(6)).name
# Job Card produces a different item than the QI's item_code.
jc = make_minimal_job_card(production_item=mismatch_item)
create_quality_inspection(
item_code="_Test Item",
reference_type="Job Card",
reference_name=jc,
)
# name matches but production_item != item_code, so the row is left untouched.
self.assertFalse(frappe.db.get_value("Job Card", jc, "quality_inspection"))
def make_minimal_job_card(production_item):
"""db_insert a minimal submitted Job Card row carrying only the columns the
converted UPDATE reads (name, production_item, quality_inspection, modified)."""
jc = frappe.new_doc("Job Card")
jc.name = "_T-Job Card-" + frappe.utils.random_string(10)
jc.flags.name_set = True
jc.production_item = production_item
jc.company = "_Test Company"
jc.for_quantity = 1
jc.docstatus = 1
jc.db_insert()
return jc.name
def create_quality_inspection(**args):
args = frappe._dict(args)