From 0a49403838c9e919270de8c509d59bbec5d7c9f7 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Tue, 2 Jun 2026 14:48:42 +0530 Subject: [PATCH] fix: unable to submit subcontracted job card (#55537) --- .../controllers/subcontracting_controller.py | 11 +++++++--- .../tests/test_subcontracting_controller.py | 21 ++++++++++++++++--- .../doctype/job_card/job_card.py | 6 ++---- .../subcontracting_order.js | 17 ++++++--------- .../test_subcontracting_order.py | 7 ++++++- 5 files changed, 40 insertions(+), 22 deletions(-) diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py index d7cc6b427d0..29fd2ad83d3 100644 --- a/erpnext/controllers/subcontracting_controller.py +++ b/erpnext/controllers/subcontracting_controller.py @@ -7,6 +7,7 @@ from collections import defaultdict import frappe from frappe import _ +from frappe.model.document import Document from frappe.model.mapper import get_mapped_doc from frappe.utils import cint, flt, get_link_to_form @@ -1529,9 +1530,13 @@ def make_return_stock_entry_for_subcontract( @frappe.whitelist() -def get_materials_from_supplier( - subcontract_order: str, rm_details: str | list, order_doctype: str = "Subcontracting Order" -): +def get_materials_from_supplier(source_name: str, target_doc: Document | str | None = None): + args = frappe.flags.args or {} + + subcontract_order = args.get("subcontract_order") or source_name + rm_details = args.get("rm_details") + order_doctype = args.get("order_doctype") or "Subcontracting Order" + if isinstance(rm_details, str): rm_details = json.loads(rm_details) diff --git a/erpnext/controllers/tests/test_subcontracting_controller.py b/erpnext/controllers/tests/test_subcontracting_controller.py index 0dbacb3c22d..1b5f94b42cc 100644 --- a/erpnext/controllers/tests/test_subcontracting_controller.py +++ b/erpnext/controllers/tests/test_subcontracting_controller.py @@ -347,7 +347,12 @@ class TestSubcontractingController(ERPNextTestSuite): sco.load_from_db() self.assertEqual(sco.supplied_items[0].consumed_qty, 5) - doc = get_materials_from_supplier(sco.name, [d.name for d in sco.supplied_items]) + frappe.flags.args = frappe._dict( + subcontract_order=sco.name, + rm_details=[d.name for d in sco.supplied_items], + order_doctype=sco.doctype, + ) + doc = get_materials_from_supplier(sco.name) doc.save() self.assertEqual(doc.items[0].qty, 1) self.assertEqual(doc.items[0].s_warehouse, "_Test Warehouse 1 - _TC") @@ -404,7 +409,12 @@ class TestSubcontractingController(ERPNextTestSuite): sco.load_from_db() self.assertEqual(sco.supplied_items[0].consumed_qty, 5) - doc = get_materials_from_supplier(sco.name, [d.name for d in sco.supplied_items]) + frappe.flags.args = frappe._dict( + subcontract_order=sco.name, + rm_details=[d.name for d in sco.supplied_items], + order_doctype=sco.doctype, + ) + doc = get_materials_from_supplier(sco.name) self.assertEqual(doc.items[0].qty, 1) self.assertEqual(doc.items[0].s_warehouse, "_Test Warehouse 1 - _TC") self.assertEqual(doc.items[0].t_warehouse, "_Test Warehouse - _TC") @@ -1133,7 +1143,12 @@ class TestSubcontractingController(ERPNextTestSuite): sco.load_from_db() self.assertEqual(sco.supplied_items[0].consumed_qty, 5) - doc = get_materials_from_supplier(sco.name, [d.name for d in sco.supplied_items]) + frappe.flags.args = frappe._dict( + subcontract_order=sco.name, + rm_details=[d.name for d in sco.supplied_items], + order_doctype=sco.doctype, + ) + doc = get_materials_from_supplier(sco.name) self.assertEqual(doc.items[0].qty, 1) self.assertEqual(doc.items[0].s_warehouse, "_Test Warehouse 1 - _TC") self.assertEqual(doc.items[0].t_warehouse, "_Test Warehouse - _TC") diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py index d1dc17e26eb..9d2270f2ce5 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.py +++ b/erpnext/manufacturing/doctype/job_card/job_card.py @@ -177,7 +177,7 @@ class JobCard(Document): self.validate_semi_finished_goods() def validate_semi_finished_goods(self): - if not self.track_semi_finished_goods: + if not self.track_semi_finished_goods or self.is_subcontracted: return if self.items and not self.transferred_qty and not self.skip_material_transfer: @@ -1579,9 +1579,7 @@ def make_subcontracting_po(source_name: str, target_doc: Document | str | None = "Job Card", source_name, { - "Job Card": { - "doctype": "Purchase Order", - }, + "Job Card": {"doctype": "Purchase Order", "field_no_map": ["naming_series"]}, }, target_doc, set_missing_values, diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js index 76f1cc52094..3e0d15cf553 100644 --- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js +++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js @@ -577,7 +577,7 @@ frappe.ui.form.on("Subcontracting Order", { }, get_materials_from_supplier: function (frm) { - let sco_rm_details = []; + const sco_rm_details = []; if (frm.doc.status != "Closed" && frm.doc.supplied_items) { frm.doc.supplied_items.forEach((d) => { @@ -591,21 +591,16 @@ frappe.ui.form.on("Subcontracting Order", { frm.add_custom_button( __("Return of Components"), () => { - frm.call({ + frappe.model.open_mapped_doc({ method: "erpnext.controllers.subcontracting_controller.get_materials_from_supplier", - freeze: true, - freeze_message: __("Creating Stock Entry"), + frm: frm, args: { subcontract_order: frm.doc.name, rm_details: sco_rm_details, - order_doctype: cur_frm.doc.doctype, - }, - callback: function (r) { - if (r && r.message) { - const doc = frappe.model.sync(r.message); - frappe.set_route("Form", doc[0].doctype, doc[0].name); - } + order_doctype: frm.doc.doctype, }, + freeze: true, + freeze_message: __("Creating Return of Components ..."), }); }, __("Create") diff --git a/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py b/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py index 4303d4d0717..68af5555d28 100644 --- a/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py +++ b/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py @@ -554,7 +554,12 @@ class TestSubcontractingOrder(ERPNextTestSuite): scr.submit() # Get RM from Supplier - ste = get_materials_from_supplier(sco.name, [d.name for d in sco.supplied_items]) + frappe.flags.args = frappe._dict( + subcontract_order=sco.name, + rm_details=[d.name for d in sco.supplied_items], + order_doctype=sco.doctype, + ) + ste = get_materials_from_supplier(sco.name) ste.save() ste.submit()