From 2565a56ade14d232c4a8b1cbbf290f574ee28498 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Sat, 1 Aug 2026 11:34:46 +0530 Subject: [PATCH] test(job_card): cover a job card completed with a pending qty --- .../doctype/job_card/job_card.py | 3 +- .../doctype/job_card/test_job_card.py | 81 +++++++++++++++++++ 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py index 509650a7618..d792a7f6ff5 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.py +++ b/erpnext/manufacturing/doctype/job_card/job_card.py @@ -1350,8 +1350,7 @@ class JobCard(Document): self.status = "Work In Progress" if self.docstatus == 1 and ( - self.get_qty_to_produce() <= (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" diff --git a/erpnext/manufacturing/doctype/job_card/test_job_card.py b/erpnext/manufacturing/doctype/job_card/test_job_card.py index 21096ad54e6..d38f55ff653 100644 --- a/erpnext/manufacturing/doctype/job_card/test_job_card.py +++ b/erpnext/manufacturing/doctype/job_card/test_job_card.py @@ -1358,6 +1358,87 @@ class TestJobCard(ERPNextTestSuite): 8, ) + def test_semi_fg_pending_qty_is_left_to_another_job_card(self): + from erpnext.manufacturing.doctype.operation.test_operation import make_operation + from erpnext.stock.doctype.item.test_item import make_item + + warehouse = "Stores - _TC" + rm = make_item("Pending Qty RM 1", {"is_stock_item": 1}).name + fg = make_item("Pending Qty FG 1", {"is_stock_item": 1}).name + + fg_bom = frappe.new_doc( + "BOM", + company="_Test Company", + item=fg, + quantity=1, + with_operations=1, + track_semi_finished_goods=1, + ) + fg_bom.append("items", {"item_code": rm, "qty": 1, "operation_row_id": 1}) + + operation = { + "operation": "Pending Qty Op A", + "workstation": "_Test Workstation A", + "finished_good": fg, + "finished_good_qty": 1, + "is_final_finished_good": 1, + "sequence_id": 1, + "time_in_mins": 60, + "source_warehouse": warehouse, + "fg_warehouse": warehouse, + "skip_material_transfer": 1, + } + + make_workstation(operation) + make_operation(operation) + fg_bom.append("operations", operation) + fg_bom.insert() + fg_bom.submit() + + work_order = make_wo_order_test_record( + item=fg, + qty=5, + source_warehouse=warehouse, + fg_warehouse=warehouse, + bom_no=fg_bom.name, + skip_transfer=1, + do_not_save=True, + ) + work_order.operations[0].time_in_mins = 60 + work_order.save() + work_order.submit() + + make_stock_entry(item_code=rm, target=warehouse, qty=100, basic_rate=100) + + job_card = self.get_first_job_card(work_order.name) + job_card.append("time_logs", {"from_time": "2024-04-01 08:00:00"}) + job_card.save() + + job_card.complete_job_card( + qty=3, + for_quantity=5, + pending_qty=2, + 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.process_loss_qty), 0) + + job_card.submit() + self.assertEqual(job_card.status, "To Manufacture") + + 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) + manufacturing_entry.submit() + + job_card.reload() + self.assertEqual(flt(job_card.manufactured_qty), 3) + self.assertEqual(job_card.status, "Completed") + def test_semi_fg_sequence_needs_previous_operations_manufactured(self): from erpnext.manufacturing.doctype.operation.test_operation import make_operation from erpnext.stock.doctype.item.test_item import make_item