mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-13 06:31:48 +00:00
fix(job_card): apply the completion dialog's qty to manufacture (#57685)
* fix(job_card): apply the completion dialog's qty to manufacture
Both the desk dialog and the shop floor session dialog send for_quantity when
completing a job card, but complete_job_card dropped it. Reducing Qty to
Manufacture to 3 on a job card of 5 left for_quantity at 5, so set_process_loss
turned the untouched 2 into process loss on the next save.
The dialog qty covers the current cycle, so add it to the qty already completed
by the earlier cycles of the job card instead of overwriting for_quantity, and
validate the pending qty against the result.
* test(job_card): cover qty to manufacture from the completion dialog
Reducing the dialog qty resizes the job card without inventing process loss, and
a pending qty split across two cycles leaves for_quantity untouched.
(cherry picked from commit 0e1bc58b2e)
# Conflicts:
# erpnext/manufacturing/doctype/job_card/job_card.py
This commit is contained in:
@@ -1514,8 +1514,28 @@ class JobCard(Document):
|
|||||||
if isinstance(kwargs, dict):
|
if isinstance(kwargs, dict):
|
||||||
kwargs = frappe._dict(kwargs)
|
kwargs = frappe._dict(kwargs)
|
||||||
|
|
||||||
|
self.set_for_quantity(kwargs)
|
||||||
self.validate_complete_job_card_qty(kwargs)
|
self.validate_complete_job_card_qty(kwargs)
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
self.pending_qty = flt(kwargs.pending_qty)
|
||||||
|
self.process_loss_qty = flt(kwargs.process_loss_qty)
|
||||||
|
|
||||||
|
self.add_completion_time_logs(kwargs)
|
||||||
|
|
||||||
|
if kwargs.auto_submit:
|
||||||
|
self.auto_submit_job_card(kwargs.auto_submit)
|
||||||
|
|
||||||
|
def set_for_quantity(self, kwargs):
|
||||||
|
"""Qty to Manufacture of the completion dialog covers the current cycle only,
|
||||||
|
so the qty completed by the earlier cycles of this job card is kept."""
|
||||||
|
if not flt(kwargs.for_quantity):
|
||||||
|
return
|
||||||
|
|
||||||
|
self.for_quantity = flt(self.total_completed_qty) + flt(kwargs.for_quantity)
|
||||||
|
|
||||||
|
>>>>>>> 0e1bc58b2e (fix(job_card): apply the completion dialog's qty to manufacture (#57685))
|
||||||
def validate_docstatus(self):
|
def validate_docstatus(self):
|
||||||
if self.docstatus == 2:
|
if self.docstatus == 2:
|
||||||
frappe.throw(_("Cancelled Job Card cannot be processed."))
|
frappe.throw(_("Cancelled Job Card cannot be processed."))
|
||||||
|
|||||||
@@ -888,6 +888,74 @@ class TestJobCard(ERPNextTestSuite):
|
|||||||
self.assertEqual(wo_doc.process_loss_qty, 2)
|
self.assertEqual(wo_doc.process_loss_qty, 2)
|
||||||
self.assertEqual(wo_doc.status, "Completed")
|
self.assertEqual(wo_doc.status, "Completed")
|
||||||
|
|
||||||
|
def get_first_job_card(self, work_order):
|
||||||
|
return frappe.get_doc(
|
||||||
|
"Job Card",
|
||||||
|
frappe.get_all(
|
||||||
|
"Job Card",
|
||||||
|
filters={"work_order": work_order},
|
||||||
|
order_by="sequence_id, creation",
|
||||||
|
limit=1,
|
||||||
|
pluck="name",
|
||||||
|
)[0],
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_completion_qty_reduces_for_quantity_without_process_loss(self):
|
||||||
|
work_order = make_wo_order_test_record(item="_Test FG Item 2", qty=5)
|
||||||
|
|
||||||
|
job_card = self.get_first_job_card(work_order.name)
|
||||||
|
job_card.append("time_logs", {"from_time": "2024-03-01 08:00:00"})
|
||||||
|
job_card.save()
|
||||||
|
|
||||||
|
job_card.complete_job_card(
|
||||||
|
qty=3,
|
||||||
|
for_quantity=3,
|
||||||
|
pending_qty=0,
|
||||||
|
process_loss_qty=0,
|
||||||
|
end_time="2024-03-01 09:00:00",
|
||||||
|
)
|
||||||
|
|
||||||
|
job_card.reload()
|
||||||
|
self.assertEqual(flt(job_card.for_quantity), 3)
|
||||||
|
self.assertEqual(flt(job_card.total_completed_qty), 3)
|
||||||
|
self.assertEqual(flt(job_card.process_loss_qty), 0)
|
||||||
|
|
||||||
|
def test_completion_qty_keeps_for_quantity_across_cycles(self):
|
||||||
|
work_order = make_wo_order_test_record(item="_Test FG Item 2", qty=5)
|
||||||
|
|
||||||
|
job_card = self.get_first_job_card(work_order.name)
|
||||||
|
job_card.append("time_logs", {"from_time": "2024-03-02 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-03-02 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.append("time_logs", {"from_time": "2024-03-02 10:00:00"})
|
||||||
|
job_card.save()
|
||||||
|
|
||||||
|
job_card.complete_job_card(
|
||||||
|
qty=2,
|
||||||
|
for_quantity=2,
|
||||||
|
pending_qty=0,
|
||||||
|
process_loss_qty=0,
|
||||||
|
end_time="2024-03-02 11:00:00",
|
||||||
|
)
|
||||||
|
|
||||||
|
job_card.reload()
|
||||||
|
self.assertEqual(flt(job_card.for_quantity), 5)
|
||||||
|
self.assertEqual(flt(job_card.total_completed_qty), 5)
|
||||||
|
self.assertEqual(flt(job_card.process_loss_qty), 0)
|
||||||
|
|
||||||
def test_op_cost_calculation(self):
|
def test_op_cost_calculation(self):
|
||||||
from erpnext.manufacturing.doctype.routing.test_routing import (
|
from erpnext.manufacturing.doctype.routing.test_routing import (
|
||||||
create_routing,
|
create_routing,
|
||||||
|
|||||||
Reference in New Issue
Block a user