From 0d90608bc133b4e92da65f2fe071eaa2f5fd936e Mon Sep 17 00:00:00 2001 From: Pandiyan P Date: Thu, 27 Aug 2026 12:12:46 +0530 Subject: [PATCH] fix(manufacturing): account for pending job card qty (#58466) --- .../doctype/job_card/job_card.py | 19 +++++++------ .../doctype/job_card/test_job_card.py | 28 +++++++++++++++---- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py index ca803d71a89..47eb7909b5a 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.py +++ b/erpnext/manufacturing/doctype/job_card/job_card.py @@ -259,15 +259,16 @@ class JobCard(Document): return wo_qty + (wo_qty * over_production_percentage / 100) def get_total_job_card_qty(self): - job_card_qty = frappe.get_all( - "Job Card", - fields=[{"SUM": "for_quantity"}], - filters={ - "work_order": self.work_order, - "operation_id": self.operation_id, - "docstatus": ["!=", 2], - }, - as_list=1, + job_card = frappe.qb.DocType("Job Card") + job_card_qty = ( + frappe.qb.from_(job_card) + .select(Sum(job_card.for_quantity - IfNull(job_card.pending_qty, 0))) + .where( + (job_card.work_order == self.work_order) + & (job_card.operation_id == self.operation_id) + & (job_card.docstatus != 2) + ) + .run() ) return flt(job_card_qty[0][0]) if job_card_qty else 0 diff --git a/erpnext/manufacturing/doctype/job_card/test_job_card.py b/erpnext/manufacturing/doctype/job_card/test_job_card.py index 215e2d4c907..248b2f85ba4 100644 --- a/erpnext/manufacturing/doctype/job_card/test_job_card.py +++ b/erpnext/manufacturing/doctype/job_card/test_job_card.py @@ -21,7 +21,7 @@ from erpnext.manufacturing.doctype.job_card.mapper import ( make_stock_entry as make_stock_entry_from_jc, ) from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record -from erpnext.manufacturing.doctype.work_order.work_order import WorkOrder, make_work_order +from erpnext.manufacturing.doctype.work_order.work_order import WorkOrder, make_job_card, make_work_order from erpnext.manufacturing.doctype.workstation.test_workstation import make_workstation from erpnext.stock.doctype.item.test_item import create_item from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry @@ -1815,16 +1815,16 @@ class TestJobCard(ERPNextTestSuite): job_card.save() job_card.complete_job_card( - qty=3, + qty=2, for_quantity=5, - pending_qty=2, + pending_qty=3, process_loss_qty=0, end_time="2024-04-01 09:00:00", ) job_card.reload() self.assertEqual(flt(job_card.for_quantity), 5) - self.assertEqual(flt(job_card.pending_qty), 2) + self.assertEqual(flt(job_card.pending_qty), 3) self.assertEqual(flt(job_card.process_loss_qty), 0) job_card.submit() @@ -1832,13 +1832,29 @@ class TestJobCard(ERPNextTestSuite): manufacturing_entry = frappe.get_doc(job_card.make_stock_entry_for_semi_fg_item()) finished_item = next(row for row in manufacturing_entry.items if row.is_finished_item) - self.assertEqual(flt(finished_item.qty), 3) + self.assertEqual(flt(finished_item.qty), 2) manufacturing_entry.submit() job_card.reload() - self.assertEqual(flt(job_card.manufactured_qty), 3) + self.assertEqual(flt(job_card.manufactured_qty), 2) self.assertEqual(job_card.status, "Completed") + make_job_card( + work_order.name, + [ + { + "name": work_order.operations[0].name, + "operation": "Pending Qty Op A", + "qty": 3, + "pending_qty": 3, + } + ], + ) + follow_up_job_card = frappe.get_last_doc( + "Job Card", {"work_order": work_order.name, "operation_id": work_order.operations[0].name} + ) + self.assertEqual(flt(follow_up_job_card.for_quantity), 3) + def test_semi_fg_process_loss_rolls_up_to_work_order(self): from erpnext.manufacturing.doctype.operation.test_operation import make_operation from erpnext.stock.doctype.item.test_item import make_item