mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-14 15:11:52 +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
|
return
|
||||||
|
|
||||||
precision = self.precision("process_loss_qty")
|
precision = self.precision("process_loss_qty")
|
||||||
if self.work_order:
|
process_loss_qty = self.get_pending_process_loss_qty()
|
||||||
data = frappe.get_all(
|
if process_loss_qty and flt(self.process_loss_qty, precision) != flt(process_loss_qty, precision):
|
||||||
"Work Order Operation",
|
self.process_loss_qty = flt(process_loss_qty, precision)
|
||||||
filters={"parent": self.work_order},
|
|
||||||
fields=[{"MAX": "process_loss_qty", "as": "process_loss_qty"}],
|
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:
|
if data and data[0].process_loss_qty:
|
||||||
process_loss_qty = 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):
|
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
|
_("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:
|
if not self.process_loss_percentage and not self.process_loss_qty:
|
||||||
self.process_loss_percentage = frappe.get_cached_value(
|
self.process_loss_percentage = frappe.get_cached_value(
|
||||||
"BOM", self.bom_no, "process_loss_percentage"
|
"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
|
(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):
|
def set_work_order_details(self):
|
||||||
if not getattr(self, "pro_doc", None):
|
if not getattr(self, "pro_doc", None):
|
||||||
self.pro_doc = frappe._dict()
|
self.pro_doc = frappe._dict()
|
||||||
|
|||||||
Reference in New Issue
Block a user