mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-13 06:31:48 +00:00
fix: stop asking for a manufacturing entry when process loss explains the shortfall
When a previous operation manufactured less than the current job card
is completing, the error always said 'Submit the manufacturing entry
for the operation first' — even when the entry was already submitted
and the missing quantity was booked as process loss, which made the
advice a dead end.
Sum the process loss of the previous operation's job cards alongside
the manufactured quantity. When manufactured + process loss covers the
requested quantity, say the shortfall is process loss so the user
knows to reduce the completed quantity; keep the submit-first message
for genuinely pending manufacturing entries.
(cherry picked from commit 1e22695eae)
# Conflicts:
# erpnext/manufacturing/doctype/job_card/job_card.py
This commit is contained in:
@@ -1342,6 +1342,57 @@ class JobCard(Document):
|
||||
if not (self.work_order and self.sequence_id):
|
||||
return
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
current_operation_qty = self.get_current_operation_completed_qty()
|
||||
|
||||
for row in self.get_previous_operations():
|
||||
if self.track_semi_finished_goods:
|
||||
self.validate_previous_operation_manufactured_qty(row, current_operation_qty)
|
||||
else:
|
||||
self.validate_previous_operation(row, current_operation_qty)
|
||||
|
||||
def get_previous_operations(self):
|
||||
previous_operations = frappe.get_all(
|
||||
"Work Order Operation",
|
||||
fields=["name", "operation", "status", "completed_qty", "sequence_id", "finished_good"],
|
||||
filters={"docstatus": 1, "parent": self.work_order, "sequence_id": ("<", self.sequence_id)},
|
||||
order_by="sequence_id, idx",
|
||||
)
|
||||
|
||||
if self.track_semi_finished_goods and previous_operations:
|
||||
totals = self.get_manufactured_qty_per_operation([row.name for row in previous_operations])
|
||||
|
||||
for row in previous_operations:
|
||||
operation_totals = totals.get(row.name)
|
||||
row.manufactured_qty = flt(operation_totals and operation_totals.manufactured_qty)
|
||||
row.process_loss_qty = flt(operation_totals and operation_totals.process_loss_qty)
|
||||
|
||||
return previous_operations
|
||||
|
||||
def get_manufactured_qty_per_operation(self, operation_ids):
|
||||
job_card = frappe.qb.DocType("Job Card")
|
||||
|
||||
data = (
|
||||
frappe.qb.from_(job_card)
|
||||
.select(
|
||||
job_card.operation_id,
|
||||
Sum(job_card.manufactured_qty).as_("manufactured_qty"),
|
||||
Sum(job_card.process_loss_qty).as_("process_loss_qty"),
|
||||
)
|
||||
.where(
|
||||
(job_card.work_order == self.work_order)
|
||||
& (job_card.docstatus == 1)
|
||||
& (IfNull(job_card.is_corrective_job_card, 0) == 0)
|
||||
& (job_card.operation_id.isin(operation_ids))
|
||||
)
|
||||
.groupby(job_card.operation_id)
|
||||
).run(as_dict=True)
|
||||
|
||||
return {row.operation_id: row for row in data}
|
||||
|
||||
def get_current_operation_completed_qty(self):
|
||||
>>>>>>> 1e22695eae (fix: stop asking for a manufacturing entry when process loss explains the shortfall)
|
||||
current_operation_qty = 0.0
|
||||
data = self.get_current_operation_data()
|
||||
if data and len(data) > 0:
|
||||
@@ -1377,6 +1428,7 @@ class JobCard(Document):
|
||||
OperationSequenceError,
|
||||
)
|
||||
|
||||
<<<<<<< HEAD
|
||||
if row.completed_qty < current_operation_qty:
|
||||
frappe.throw(
|
||||
_(
|
||||
@@ -1388,6 +1440,49 @@ class JobCard(Document):
|
||||
bold(row.operation),
|
||||
)
|
||||
)
|
||||
=======
|
||||
if not manufactured_qty:
|
||||
frappe.throw(
|
||||
_(
|
||||
"Job Card {0}: As per the sequence of the operations in the work order {1}, submit the manufacturing entry for the operation {2} before the operation {3}."
|
||||
).format(
|
||||
bold(self.name),
|
||||
bold(get_link_to_form("Work Order", self.work_order)),
|
||||
bold(row.operation),
|
||||
bold(self.operation),
|
||||
),
|
||||
OperationSequenceError,
|
||||
)
|
||||
|
||||
if manufactured_qty >= current_operation_qty:
|
||||
return
|
||||
|
||||
if manufactured_qty + flt(row.process_loss_qty) >= current_operation_qty:
|
||||
frappe.throw(
|
||||
_(
|
||||
"The completed quantity {0} of an operation {1} cannot be greater than the manufactured quantity {2} of a previous operation {3}, as {4} was booked as process loss there."
|
||||
).format(
|
||||
bold(self.get_qty_with_uom(current_operation_qty)),
|
||||
bold(self.operation),
|
||||
bold(self.get_qty_with_uom(manufactured_qty, row.finished_good)),
|
||||
bold(row.operation),
|
||||
bold(self.get_qty_with_uom(flt(row.process_loss_qty), row.finished_good)),
|
||||
),
|
||||
OperationSequenceError,
|
||||
)
|
||||
>>>>>>> 1e22695eae (fix: stop asking for a manufacturing entry when process loss explains the shortfall)
|
||||
|
||||
frappe.throw(
|
||||
_(
|
||||
"The completed quantity {0} of an operation {1} cannot be greater than the manufactured quantity {2} of a previous operation {3}. Submit the manufacturing entry for the operation {3} first."
|
||||
).format(
|
||||
bold(self.get_qty_with_uom(current_operation_qty)),
|
||||
bold(self.operation),
|
||||
bold(self.get_qty_with_uom(manufactured_qty, row.finished_good)),
|
||||
bold(row.operation),
|
||||
),
|
||||
OperationSequenceError,
|
||||
)
|
||||
|
||||
def validate_work_order(self):
|
||||
if self.is_work_order_closed():
|
||||
|
||||
Reference in New Issue
Block a user