From a22b83a97fe1dcf957d3d9b8bba7240c63640a82 Mon Sep 17 00:00:00 2001 From: pandiyan Date: Fri, 19 Jun 2026 17:42:17 +0530 Subject: [PATCH] fix: add partially transferred status and fix button visibility for partial material transfer on job card --- .../doctype/job_card/job_card.js | 14 ++++++------- .../doctype/job_card/job_card.json | 4 ++-- .../doctype/job_card/job_card.py | 21 ++++++++++++++++++- .../doctype/job_card/job_card_list.js | 1 + 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/erpnext/manufacturing/doctype/job_card/job_card.js b/erpnext/manufacturing/doctype/job_card/job_card.js index 5457e0a93dc..0a80976c6e2 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.js +++ b/erpnext/manufacturing/doctype/job_card/job_card.js @@ -207,7 +207,9 @@ frappe.ui.form.on("Job Card", { if (frm.is_new() || doc.skip_material_transfer || doc.docstatus >= 2) return; const excess_transfer_allowed = doc.__onload.job_card_excess_transfer; - const to_request = doc.for_quantity > doc.transferred_qty; + const to_transfer = + has_items && doc.items.some((row) => flt(row.transferred_qty) < flt(row.required_qty)); + const to_request = to_transfer; if (has_items && (to_request || excess_transfer_allowed)) { frm.add_custom_button( @@ -217,9 +219,6 @@ frappe.ui.form.on("Job Card", { ); } - // check if any row has untransferred materials in case of multiple items in JC - const to_transfer = doc.items.some((row) => row.transferred_qty < row.required_qty); - if (has_items && (to_transfer || excess_transfer_allowed)) { frm.add_custom_button( __("Material Transfer"), @@ -586,11 +585,10 @@ frappe.ui.form.on("Job Card", { // ── Determine which action buttons to show ──────────────────────── const has_remaining_qty = doc.for_quantity + doc.process_loss_qty > doc.total_completed_qty; + const pending_transfer = + has_items && doc.items.some((row) => flt(row.transferred_qty) < flt(row.required_qty)); const materials_ready = - doc.skip_material_transfer || - doc.transferred_qty >= doc.for_quantity + doc.process_loss_qty || - !doc.finished_good || - !has_items?.length; + doc.skip_material_transfer || !pending_transfer || !doc.finished_good || !has_items; let last_row = {}; const has_sub_ops_or_pending_qty = doc.sub_operations?.length || doc.pending_qty > 0; diff --git a/erpnext/manufacturing/doctype/job_card/job_card.json b/erpnext/manufacturing/doctype/job_card/job_card.json index 69a156009b1..c215aee42d4 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.json +++ b/erpnext/manufacturing/doctype/job_card/job_card.json @@ -272,7 +272,7 @@ "fieldtype": "Select", "label": "Status", "no_copy": 1, - "options": "Open\nWork In Progress\nMaterial Transferred\nOn Hold\nSubmitted\nCancelled\nCompleted", + "options": "Open\nWork In Progress\nPartially Transferred\nMaterial Transferred\nOn Hold\nSubmitted\nCancelled\nCompleted", "read_only": 1 }, { @@ -695,7 +695,7 @@ "grid_page_length": 50, "is_submittable": 1, "links": [], - "modified": "2026-05-21 18:37:05.688342", + "modified": "2026-06-19 17:39:42.293242", "modified_by": "Administrator", "module": "Manufacturing", "name": "Job Card", diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py index f74b9f4adb9..51ca3180948 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.py +++ b/erpnext/manufacturing/doctype/job_card/job_card.py @@ -127,6 +127,7 @@ class JobCard(Document): status: DF.Literal[ "Open", "Work In Progress", + "Partially Transferred", "Material Transferred", "On Hold", "Submitted", @@ -1195,6 +1196,8 @@ class JobCard(Document): frappe.db.set_value("Job Card Item", row.job_card_item, "transferred_qty", flt(transferred_qty)) + self.set_status(update_status=True) + def get_job_card_items_transferred_qty(self, ste_doc): from frappe.query_builder.functions import Sum @@ -1305,7 +1308,22 @@ class JobCard(Document): self.status = "Work In Progress" def set_non_semi_fg_status(self): - if flt(self.for_quantity) <= flt(self.transferred_qty): + if self.items: + item_data = frappe.get_all( + "Job Card Item", + filters={"parent": self.name}, + fields=["transferred_qty", "required_qty"], + ) + all_transferred = item_data and all( + flt(d.transferred_qty) >= flt(d.required_qty) for d in item_data + ) + any_transferred = any(flt(d.transferred_qty) > 0 for d in item_data) + + if all_transferred: + self.status = "Material Transferred" + elif any_transferred: + self.status = "Partially Transferred" + elif flt(self.for_quantity) <= flt(self.transferred_qty): self.status = "Material Transferred" if self.time_logs: @@ -1829,6 +1847,7 @@ def get_calendar_event(d): event_color = { "Completed": "#cdf5a6", "Material Transferred": "#ffdd9e", + "Partially Transferred": "#ffe5b4", "Work In Progress": "#D3D3D3", } diff --git a/erpnext/manufacturing/doctype/job_card/job_card_list.js b/erpnext/manufacturing/doctype/job_card/job_card_list.js index e417b7f576d..bddb11d00bb 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card_list.js +++ b/erpnext/manufacturing/doctype/job_card/job_card_list.js @@ -7,6 +7,7 @@ frappe.listview_settings["Job Card"] = { Completed: "green", Cancelled: "red", "Material Transferred": "blue", + "Partially Transferred": "yellow", Open: "red", }; const status = doc.status || "Open";