chore: resolve conflict

This commit is contained in:
Mihir Kandoi
2026-08-09 20:53:27 +05:30
parent 0c7919429e
commit 1ededb70f4
2 changed files with 15 additions and 194 deletions

View File

@@ -1236,7 +1236,7 @@ class JobCard(Document):
def set_status(self, update_status=False): def set_status(self, update_status=False):
self.status = {0: "Open", 1: "Submitted", 2: "Cancelled"}[self.docstatus or 0] self.status = {0: "Open", 1: "Submitted", 2: "Cancelled"}[self.docstatus or 0]
if self.finished_good and self.docstatus == 1: if self.finished_good and self.docstatus == 1:
if (self.manufactured_qty + self.process_loss_qty) >= self.for_quantity: if (self.manufactured_qty + self.process_loss_qty) >= self.get_qty_to_produce():
self.status = "Completed" self.status = "Completed"
elif self.transferred_qty > 0 or self.skip_material_transfer: elif self.transferred_qty > 0 or self.skip_material_transfer:
self.status = "Work In Progress" self.status = "Work In Progress"
@@ -1267,7 +1267,8 @@ class JobCard(Document):
self.status = "Work In Progress" self.status = "Work In Progress"
if self.docstatus == 1 and ( 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" self.status = "Completed"
@@ -1280,53 +1281,10 @@ class JobCard(Document):
if self.workstation: if self.workstation:
self.update_workstation_status() self.update_workstation_status()
<<<<<<< HEAD
=======
def get_qty_to_produce(self): def get_qty_to_produce(self):
"""Qty this job card is expected to produce, the pending qty is left to another job card.""" """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) 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().
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) >= 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"
elif self.transferred_qty > 0 or self.skip_material_transfer:
self.status = "Work In Progress"
def set_non_semi_fg_status(self):
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:
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.status = "Completed"
>>>>>>> 970039d8ec (fix(job_card): leave the pending qty out of the job card's own output (#57686))
def set_wip_warehouse(self): def set_wip_warehouse(self):
if not self.wip_warehouse: if not self.wip_warehouse:
self.wip_warehouse = frappe.get_cached_value("Company", self.company, "default_wip_warehouse") self.wip_warehouse = frappe.get_cached_value("Company", self.company, "default_wip_warehouse")
@@ -1625,13 +1583,8 @@ class JobCard(Document):
ste = ManufactureEntry( ste = ManufactureEntry(
{ {
<<<<<<< HEAD
"for_quantity": self.for_quantity - self.manufactured_qty,
"process_loss_qty": max(self.process_loss_qty - get_consumed_process_loss(), 0),
=======
"for_quantity": self.get_qty_to_produce() - 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), "process_loss_qty": max(self.process_loss_qty - get_consumed_process_loss(), 0),
>>>>>>> 970039d8ec (fix(job_card): leave the pending qty out of the job card's own output (#57686))
"job_card": self.name, "job_card": self.name,
"skip_material_transfer": self.skip_material_transfer, "skip_material_transfer": self.skip_material_transfer,
"backflush_from_wip_warehouse": self.backflush_from_wip_warehouse, "backflush_from_wip_warehouse": self.backflush_from_wip_warehouse,

View File

@@ -1265,8 +1265,6 @@ class TestJobCard(ERPNextTestSuite):
8, 8,
) )
<<<<<<< HEAD
=======
def test_semi_fg_pending_qty_is_left_to_another_job_card(self): 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.manufacturing.doctype.operation.test_operation import make_operation
from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.doctype.item.test_item import make_item
@@ -1319,7 +1317,16 @@ class TestJobCard(ERPNextTestSuite):
make_stock_entry(item_code=rm, target=warehouse, qty=100, basic_rate=100) 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 = frappe.get_doc(
"Job Card",
frappe.get_all(
"Job Card",
filters={"work_order": work_order.name},
order_by="sequence_id, creation",
limit=1,
pluck="name",
)[0],
)
job_card.append("time_logs", {"from_time": "2024-04-01 08:00:00"}) job_card.append("time_logs", {"from_time": "2024-04-01 08:00:00"})
job_card.save() job_card.save()
@@ -1337,7 +1344,7 @@ class TestJobCard(ERPNextTestSuite):
self.assertEqual(flt(job_card.process_loss_qty), 0) self.assertEqual(flt(job_card.process_loss_qty), 0)
job_card.submit() job_card.submit()
self.assertEqual(job_card.status, "To Manufacture") self.assertEqual(job_card.status, "Work In Progress")
manufacturing_entry = frappe.get_doc(job_card.make_stock_entry_for_semi_fg_item()) 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) finished_item = next(row for row in manufacturing_entry.items if row.is_finished_item)
@@ -1348,145 +1355,6 @@ class TestJobCard(ERPNextTestSuite):
self.assertEqual(flt(job_card.manufactured_qty), 3) self.assertEqual(flt(job_card.manufactured_qty), 3)
self.assertEqual(job_card.status, "Completed") 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
warehouse = "Stores - _TC"
rm1 = make_item("Sequence Check RM 1", {"is_stock_item": 1}).name
rm2 = make_item("Sequence Check RM 2", {"is_stock_item": 1}).name
sfg1 = make_item("Sequence Check SFG 1", {"is_stock_item": 1}).name
sfg2 = make_item("Sequence Check SFG 2", {"is_stock_item": 1}).name
fg = make_item("Sequence Check FG 1", {"is_stock_item": 1}).name
semi_fg_boms = {}
for semi_fg_item, raw_material in ((sfg1, rm1), (sfg2, rm2)):
bom = frappe.new_doc("BOM", company="_Test Company", item=semi_fg_item, quantity=1)
bom.append("items", {"item_code": raw_material, "qty": 1})
bom.insert()
bom.submit()
semi_fg_boms[semi_fg_item] = bom.name
fg_bom = frappe.new_doc(
"BOM",
company="_Test Company",
item=fg,
quantity=1,
with_operations=1,
track_semi_finished_goods=1,
)
operations = [
{
"operation": "Sequence Check Op A",
"finished_good": sfg1,
"bom_no": semi_fg_boms[sfg1],
"sequence_id": 1,
},
{
"operation": "Sequence Check Op B",
"finished_good": sfg2,
"bom_no": semi_fg_boms[sfg2],
"sequence_id": 1,
},
{
"operation": "Sequence Check Op C",
"finished_good": fg,
"is_final_finished_good": 1,
"sequence_id": 2,
},
]
for row in operations:
row.update(
{
"workstation": "_Test Workstation A",
"finished_good_qty": 1,
"time_in_mins": 60,
"source_warehouse": warehouse,
"fg_warehouse": warehouse,
"skip_material_transfer": 1,
}
)
make_workstation(row)
make_operation(row)
fg_bom.append("operations", row)
fg_bom.append("items", {"item_code": sfg1, "qty": 1, "operation_row_id": 3})
fg_bom.append("items", {"item_code": sfg2, "qty": 1, "operation_row_id": 3})
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,
)
for row in work_order.operations:
row.time_in_mins = 60
work_order.save()
work_order.submit()
make_stock_entry(item_code=rm1, target=warehouse, qty=10, basic_rate=100)
make_stock_entry(item_code=rm2, target=warehouse, qty=10, basic_rate=100)
def get_job_card(operation):
return frappe.get_doc(
"Job Card",
frappe.db.get_value(
"Job Card",
{"work_order": work_order.name, "operation": operation, "docstatus": 0},
"name",
),
)
def add_time_log(job_card, day, qty):
job_card.append(
"time_logs",
{
"from_time": f"2024-01-{day} 08:00:00",
"to_time": f"2024-01-{day} 09:00:00",
"completed_qty": qty,
},
)
jc_a = get_job_card("Sequence Check Op A")
jc_a.for_quantity = 3
add_time_log(jc_a, "01", 3)
jc_a.submit()
jc_b = get_job_card("Sequence Check Op B")
add_time_log(jc_b, "02", jc_b.for_quantity)
jc_b.submit()
frappe.get_doc(jc_b.make_stock_entry_for_semi_fg_item()).submit()
jc_c = get_job_card("Sequence Check Op C")
jc_c.for_quantity = 3
add_time_log(jc_c, "03", 3)
self.assertRaises(OperationSequenceError, jc_c.save)
frappe.get_doc(jc_a.make_stock_entry_for_semi_fg_item()).submit()
jc_c.reload()
jc_c.for_quantity = 4
add_time_log(jc_c, "03", 4)
self.assertRaises(OperationSequenceError, jc_c.save)
jc_c.reload()
jc_c.for_quantity = 3
add_time_log(jc_c, "03", 3)
jc_c.submit()
self.assertEqual(jc_c.docstatus, 1)
>>>>>>> 970039d8ec (fix(job_card): leave the pending qty out of the job card's own output (#57686))
def test_semi_fg_batch_auto_pull_on_manufacture(self): def test_semi_fg_batch_auto_pull_on_manufacture(self):
from erpnext.manufacturing.doctype.operation.test_operation import make_operation from erpnext.manufacturing.doctype.operation.test_operation import make_operation
from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.doctype.item.test_item import make_item