mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-13 06:31:48 +00:00
fix: derive operation FG items before material expansion, keep the final one the BOM's item
The finished_good derivation ran in validate_semi_finished_goods,
after set_materials_based_on_operation_bom had already expanded
operation BOM materials. A single-pass insert-and-submit (API or
import) with bom_no set but finished_good empty skipped the expansion,
persisting a submitted BOM without the referenced components. The
derivation also let a final operation inherit another item from its
bom_no, so downstream job cards would produce the wrong item.
Move the derivation into set_operation_finished_goods, called before
the expansion, prefer the BOM's own item for the final operation, and
reject a final operation whose FG item is not the BOM's item.
(cherry picked from commit 1e2e87daac)
# Conflicts:
# erpnext/manufacturing/doctype/bom/bom.py
This commit is contained in:
@@ -282,6 +282,7 @@ class BOM(WebsiteGenerator):
|
||||
self.clear_inspection()
|
||||
self.validate_main_item()
|
||||
self.validate_currency()
|
||||
self.set_operation_finished_goods()
|
||||
self.set_materials_based_on_operation_bom()
|
||||
self.set_conversion_rate()
|
||||
self.set_plc_conversion_rate()
|
||||
@@ -304,8 +305,23 @@ class BOM(WebsiteGenerator):
|
||||
self.set_fg_cost_allocation()
|
||||
self.validate_total_cost_allocation()
|
||||
|
||||
<<<<<<< HEAD
|
||||
if self.docstatus == 1:
|
||||
self.validate_raw_materials_of_operation()
|
||||
=======
|
||||
def set_operation_finished_goods(self):
|
||||
"""Fill each operation's FG item where it is unambiguous: the final operation produces
|
||||
this BOM's item, an operation with a BOM produces that BOM's item. Runs before
|
||||
set_materials_based_on_operation_bom so derived rows get their materials expanded."""
|
||||
if not self.track_semi_finished_goods:
|
||||
return
|
||||
|
||||
for row in self.operations:
|
||||
if row.is_final_finished_good and not row.finished_good:
|
||||
row.finished_good = self.item
|
||||
elif row.bom_no and not row.finished_good:
|
||||
row.finished_good = frappe.get_cached_value("BOM", row.bom_no, "item")
|
||||
>>>>>>> 1e2e87daac (fix: derive operation FG items before material expansion, keep the final one the BOM's item)
|
||||
|
||||
def validate_semi_finished_goods(self):
|
||||
if not self.track_semi_finished_goods or not self.operations:
|
||||
@@ -313,12 +329,6 @@ class BOM(WebsiteGenerator):
|
||||
|
||||
fg_items = []
|
||||
for row in self.operations:
|
||||
if row.bom_no and not row.finished_good:
|
||||
row.finished_good = frappe.get_cached_value("BOM", row.bom_no, "item")
|
||||
|
||||
if row.is_final_finished_good and not row.finished_good:
|
||||
row.finished_good = self.item
|
||||
|
||||
if not row.finished_good:
|
||||
frappe.throw(
|
||||
_(
|
||||
@@ -329,6 +339,13 @@ class BOM(WebsiteGenerator):
|
||||
if not row.is_final_finished_good:
|
||||
continue
|
||||
|
||||
if row.finished_good != self.item:
|
||||
frappe.throw(
|
||||
_(
|
||||
"Row #{0}: The operation {1} has 'Is Final Finished Good' checked, so its FG / Semi FG Item must be {2}."
|
||||
).format(row.idx, bold(row.operation), bold(self.item)),
|
||||
)
|
||||
|
||||
fg_items.append(row.finished_good)
|
||||
|
||||
if not fg_items:
|
||||
|
||||
Reference in New Issue
Block a user