Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor!: dynamically compute bom_level (backport #29522) #29540

Merged
merged 5 commits into from
Jan 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 2 additions & 9 deletions erpnext/manufacturing/doctype/bom/bom.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
"inspection_required",
"quality_inspection_template",
"column_break_31",
"bom_level",
"section_break_33",
"items",
"scrap_section",
Expand Down Expand Up @@ -522,13 +521,6 @@
"fieldname": "column_break_31",
"fieldtype": "Column Break"
},
{
"default": "0",
"fieldname": "bom_level",
"fieldtype": "Int",
"label": "BOM Level",
"read_only": 1
},
{
"fieldname": "section_break_33",
"fieldtype": "Section Break",
Expand All @@ -540,7 +532,7 @@
"image_field": "image",
"is_submittable": 1,
"links": [],
"modified": "2021-11-18 13:04:16.271975",
"modified": "2022-01-30 21:27:54.727298",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM",
Expand Down Expand Up @@ -577,5 +569,6 @@
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
17 changes: 0 additions & 17 deletions erpnext/manufacturing/doctype/bom/bom.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,6 @@ def validate(self):
self.update_stock_qty()
self.validate_scrap_items()
self.update_cost(update_parent=False, from_child_bom=True, update_hour_rate = False, save=False)
self.set_bom_level()


def get_context(self, context):
context.parents = [{'name': 'boms', 'title': _('All BOMs') }]
Expand Down Expand Up @@ -704,7 +702,6 @@ def validate_operations(self):
if not d.batch_size or d.batch_size <= 0:
d.batch_size = 1


def validate_scrap_items(self):
for item in self.scrap_items:
msg = ""
Expand Down Expand Up @@ -735,20 +732,6 @@ def get_tree_representation(self) -> BOMTree:
"""Get a complete tree representation preserving order of child items."""
return BOMTree(self.name)

def set_bom_level(self, update=False):
levels = []

self.bom_level = 0
for row in self.items:
if row.bom_no:
levels.append(frappe.get_cached_value("BOM", row.bom_no, "bom_level") or 0)

if levels:
self.bom_level = max(levels) + 1

if update:
self.db_set("bom_level", self.bom_level)

def get_bom_item_rate(args, bom_doc):
if bom_doc.rm_cost_as_per == 'Valuation Rate':
rate = get_valuation_rate(args) * (args.get("conversion_factor") or 1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -560,9 +560,11 @@ def get_sub_assembly_items(self, manufacturing_type=None):
get_sub_assembly_items(row.bom_no, bom_data, row.planned_qty)
self.set_sub_assembly_items_based_on_level(row, bom_data, manufacturing_type)

def set_sub_assembly_items_based_on_level(self, row, bom_data, manufacturing_type=None):
bom_data = sorted(bom_data, key = lambda i: i.bom_level)
self.sub_assembly_items.sort(key= lambda d: d.bom_level, reverse=True)
for idx, row in enumerate(self.sub_assembly_items, start=1):
row.idx = idx

def set_sub_assembly_items_based_on_level(self, row, bom_data, manufacturing_type=None):
for data in bom_data:
data.qty = data.stock_qty
data.production_plan_item = row.name
Expand Down Expand Up @@ -1005,9 +1007,6 @@ def get_sub_assembly_items(bom_no, bom_data, to_produce_qty, indent=0):
for d in data:
if d.expandable:
parent_item_code = frappe.get_cached_value("BOM", bom_no, "item")
bom_level = (frappe.get_cached_value("BOM", d.value, "bom_level")
if d.value else 0)

stock_qty = (d.stock_qty / d.parent_bom_qty) * flt(to_produce_qty)
bom_data.append(frappe._dict({
'parent_item_code': parent_item_code,
Expand All @@ -1018,7 +1017,7 @@ def get_sub_assembly_items(bom_no, bom_data, to_produce_qty, indent=0):
'uom': d.stock_uom,
'bom_no': d.value,
'is_sub_contracted_item': d.is_sub_contracted_item,
'bom_level': bom_level,
'bom_level': indent,
'indent': indent,
'stock_qty': stock_qty
}))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,45 @@ def test_get_sales_order_with_variant(self):

frappe.db.rollback()

def test_subassmebly_sorting(self):
""" Test subassembly sorting in case of multiple items with nested BOMs"""
from erpnext.manufacturing.doctype.bom.test_bom import create_nested_bom

prefix = "_TestLevel_"
boms = {
"Assembly": {
"SubAssembly1": {"ChildPart1": {}, "ChildPart2": {},},
"SubAssembly2": {"ChildPart3": {}},
"SubAssembly3": {"SubSubAssy1": {"ChildPart4": {}}},
"ChildPart5": {},
"ChildPart6": {},
"SubAssembly4": {"SubSubAssy2": {"ChildPart7": {}}},
},
"MegaDeepAssy": {
"SecretSubassy": {"SecretPart": {"VerySecret" : { "SuperSecret": {"Classified": {}}}},},
# ^ assert that this is
# first item in subassy table
}
}
create_nested_bom(boms, prefix=prefix)

items = [prefix + item_code for item_code in boms.keys()]
plan = create_production_plan(item_code=items[0], do_not_save=True)
plan.append("po_items", {
'use_multi_level_bom': 1,
'item_code': items[1],
'bom_no': frappe.db.get_value('Item', items[1], 'default_bom'),
'planned_qty': 1,
'planned_start_date': now_datetime()
})
plan.get_sub_assembly_items()

bom_level_order = [d.bom_level for d in plan.sub_assembly_items]
self.assertEqual(bom_level_order, sorted(bom_level_order, reverse=True))
# lowest most level of subassembly should be first
self.assertIn("SuperSecret", plan.sub_assembly_items[0].production_item)


def create_production_plan(**args):
args = frappe._dict(args)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@
},
{
"columns": 1,
"fetch_from": "bom_no.bom_level",
"fieldname": "bom_level",
"fieldtype": "Int",
"in_list_view": 1,
Expand Down Expand Up @@ -189,7 +188,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-06-28 20:10:56.296410",
"modified": "2022-01-30 21:31:10.527559",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Production Plan Sub Assembly Item",
Expand All @@ -198,5 +197,6 @@
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
5 changes: 2 additions & 3 deletions erpnext/manufacturing/report/bom_explorer/bom_explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ def get_exploded_items(bom, data, indent=0, qty=1):
'item_code': item.item_code,
'item_name': item.item_name,
'indent': indent,
'bom_level': (frappe.get_cached_value("BOM", item.bom_no, "bom_level")
if item.bom_no else ""),
'bom_level': indent,
'bom': item.bom_no,
'qty': item.qty * qty,
'uom': item.uom,
Expand Down Expand Up @@ -73,7 +72,7 @@ def get_columns():
},
{
"label": "BOM Level",
"fieldtype": "Data",
"fieldtype": "Int",
"fieldname": "bom_level",
"width": 100
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def get_production_plan_item_details(filters, data, order_details):
"qty": row.planned_qty,
"document_type": "Work Order",
"document_name": work_order or "",
"bom_level": frappe.get_cached_value("BOM", row.bom_no, "bom_level"),
"bom_level": 0,
"produced_qty": order_details.get((work_order, row.item_code), {}).get("produced_qty", 0),
"pending_qty": flt(row.planned_qty) - flt(order_details.get((work_order, row.item_code), {}).get("produced_qty", 0))
})
Expand Down
1 change: 0 additions & 1 deletion erpnext/patches.txt
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,6 @@ erpnext.patches.v13_0.set_training_event_attendance
erpnext.patches.v13_0.rename_issue_status_hold_to_on_hold
erpnext.patches.v13_0.bill_for_rejected_quantity_in_purchase_invoice
erpnext.patches.v13_0.update_job_card_details
erpnext.patches.v13_0.update_level_in_bom #1234sswef
erpnext.patches.v13_0.create_gst_payment_entry_fields #27-11-2021
erpnext.patches.v13_0.add_missing_fg_item_for_stock_entry
erpnext.patches.v13_0.update_subscription_status_in_memberships
Expand Down
31 changes: 0 additions & 31 deletions erpnext/patches/v13_0/update_level_in_bom.py

This file was deleted.