mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-13 06:31:48 +00:00
fix: scope manufacture entry process loss to its own job card
set_process_loss_qty stamped MAX(process_loss_qty) across every
operation of the work order onto each manufacture entry. With semi
finished goods tracking, one operation's process loss leaked into the
entries of every other operation: validate_fg_completed_qty then
rejected the entry when it had a BOM, or the wrong loss was recorded
silently when it did not, double-counting the loss across operations.
When the entry belongs to a job card, use that job card's loss net of
what its earlier entries already booked. The MAX fallback stays for
work-order level entries without a job card.
Fixes frappe/erpnext#57892
(cherry picked from commit 1b335973b7)
# Conflicts:
# erpnext/stock/doctype/stock_entry/stock_entry.py
This commit is contained in:
@@ -3192,13 +3192,16 @@ class StockEntry(StockController, SubcontractingInwardController):
|
||||
return
|
||||
|
||||
precision = self.precision("process_loss_qty")
|
||||
if self.work_order:
|
||||
data = frappe.get_all(
|
||||
"Work Order Operation",
|
||||
filters={"parent": self.work_order},
|
||||
fields=[{"MAX": "process_loss_qty", "as": "process_loss_qty"}],
|
||||
process_loss_qty = self.get_pending_process_loss_qty()
|
||||
if process_loss_qty and flt(self.process_loss_qty, precision) != flt(process_loss_qty, precision):
|
||||
self.process_loss_qty = flt(process_loss_qty, precision)
|
||||
|
||||
frappe.msgprint(
|
||||
_("The Process Loss Qty has been reset as per the job card's Process Loss Qty"),
|
||||
alert=True,
|
||||
)
|
||||
|
||||
<<<<<<< HEAD
|
||||
if data and data[0].process_loss_qty:
|
||||
process_loss_qty = data[0].process_loss_qty
|
||||
if flt(self.process_loss_qty, precision) != flt(process_loss_qty, precision):
|
||||
@@ -3208,6 +3211,8 @@ class StockEntry(StockController, SubcontractingInwardController):
|
||||
_("The Process Loss Qty has reset as per job cards Process Loss Qty"), alert=True
|
||||
)
|
||||
|
||||
=======
|
||||
>>>>>>> 1b335973b7 (fix: scope manufacture entry process loss to its own job card)
|
||||
if not self.process_loss_percentage and not self.process_loss_qty:
|
||||
self.process_loss_percentage = frappe.get_cached_value(
|
||||
"BOM", self.bom_no, "process_loss_percentage"
|
||||
@@ -3222,6 +3227,23 @@ class StockEntry(StockController, SubcontractingInwardController):
|
||||
(flt(self.process_loss_qty) / flt(self.fg_completed_qty)) * 100
|
||||
)
|
||||
|
||||
def get_pending_process_loss_qty(self):
|
||||
"""Loss this entry should still book: the job card's unbooked loss when the entry
|
||||
belongs to one, else the largest operation loss on the work order (legacy flow)."""
|
||||
if self.job_card:
|
||||
job_card = frappe.get_doc("Job Card", self.job_card)
|
||||
return max(flt(job_card.process_loss_qty) - flt(job_card.get_consumed_process_loss()), 0)
|
||||
|
||||
if self.work_order:
|
||||
data = frappe.get_all(
|
||||
"Work Order Operation",
|
||||
filters={"parent": self.work_order},
|
||||
fields=[{"MAX": "process_loss_qty", "as": "process_loss_qty"}],
|
||||
)
|
||||
return flt(data[0].process_loss_qty) if data else 0
|
||||
|
||||
return 0
|
||||
|
||||
def set_work_order_details(self):
|
||||
if not getattr(self, "pro_doc", None):
|
||||
self.pro_doc = frappe._dict()
|
||||
|
||||
Reference in New Issue
Block a user