From 3fab303e510575c612b498ed4abaa84c7e445661 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Sat, 1 Aug 2026 11:34:46 +0530 Subject: [PATCH] fix(job_card): leave the pending qty out of the job card's own output Pending qty is the part of a job card handed over to another job card, but the status and the manufacturing entry still measured the card against its full for_quantity. A card submitted with 3 completed and 2 pending was stuck at Work In Progress with no way to change it, and its manufacturing entry was built for the full 5. Measure both against for_quantity minus pending qty, so the card reaches To Manufacture on submission, its manufacturing entry covers the completed qty, and it is Completed once that qty is manufactured. --- .../manufacturing/doctype/job_card/job_card.js | 3 ++- .../manufacturing/doctype/job_card/job_card.py | 15 +++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/erpnext/manufacturing/doctype/job_card/job_card.js b/erpnext/manufacturing/doctype/job_card/job_card.js index 378fbb5c69e..74ec603da34 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.js +++ b/erpnext/manufacturing/doctype/job_card/job_card.js @@ -99,7 +99,8 @@ frappe.ui.form.on("Job Card", { doc.docstatus === 1 && !doc.is_subcontracted && (doc.skip_material_transfer || doc.transferred_qty > 0) && - flt(doc.manufactured_qty) + flt(doc.process_loss_qty) < flt(doc.for_quantity); + flt(doc.manufactured_qty) + flt(doc.process_loss_qty) < + flt(doc.for_quantity) - flt(doc.pending_qty); if (!can_make_stock_entry) return; diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py index 65742de6d86..509650a7618 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.py +++ b/erpnext/manufacturing/doctype/job_card/job_card.py @@ -1310,11 +1310,17 @@ class JobCard(Document): if self.workstation: self.update_workstation_status() + def get_qty_to_produce(self): + """Qty this job card is expected to produce, the pending qty is left to another job card.""" + return flt(self.for_quantity) - flt(self.pending_qty) + def set_finished_good_status(self): # Only reached for a submitted job card (docstatus == 1) with a finished good, see set_status(). - if (self.manufactured_qty + self.process_loss_qty) >= self.for_quantity: + qty_to_produce = self.get_qty_to_produce() + + if (self.manufactured_qty + self.process_loss_qty) >= qty_to_produce: self.status = "Completed" - elif (self.total_completed_qty + self.process_loss_qty) >= self.for_quantity: + elif (self.total_completed_qty + self.process_loss_qty) >= qty_to_produce: # Production is done and the card is submitted, but the finished goods have not been # booked into stock yet (Manufacture Stock Entry pending) — distinct from active WIP. self.status = "To Manufacture" @@ -1344,7 +1350,8 @@ class JobCard(Document): self.status = "Work In Progress" if self.docstatus == 1 and ( - self.for_quantity <= (self.total_completed_qty + self.process_loss_qty) or not self.items + self.get_qty_to_produce() <= (self.total_completed_qty + self.process_loss_qty) + or not self.items ): self.status = "Completed" @@ -1752,7 +1759,7 @@ class JobCard(Document): return ManufactureEntry( { - "for_quantity": self.for_quantity - self.manufactured_qty, + "for_quantity": self.get_qty_to_produce() - self.manufactured_qty, "process_loss_qty": max(self.process_loss_qty - self.get_consumed_process_loss(), 0), "job_card": self.name, "skip_material_transfer": self.skip_material_transfer,