BOM Low Level Code Calculator Script (Python Generator)
Low level codes decide the order in which MRP plans items. When you need to check them, audit a migration or build your own planning model, this script computes them from a plain parent and component extract.
Fill in
Python script
import csv
import sys
from collections import defaultdict
sys.setrecursionlimit(10000)
edges = defaultdict(list)
with open("bom_edges.csv", newline="", encoding="utf-8-sig") as f:
for row in csv.DictReader(f):
parent = row["parent_item"].strip()
child = row["component_item"].strip()
if parent and child:
edges[parent].append(child)
items = set(edges.keys())
for kids in edges.values():
items.update(kids)
level = {}
def walk(node, depth, path):
if node in path:
raise ValueError("BOM loop: " + " > ".join(path + [node]))
if depth <= level.get(node, -1):
return
level[node] = depth
for child in edges.get(node, []):
walk(child, depth + 1, path + [node])
children = set()
for kids in edges.values():
children.update(kids)
roots = sorted(items - children)
for root in roots:
walk(root, 0, [])
if len(level) < len(items):
print("Warning: items only in a loop have no level:", sorted(items - set(level)))
with open("low_level_codes.csv", "w", newline="", encoding="utf-8") as out:
w = csv.writer(out)
w.writerow(["item", "low_level_code"])
for item in sorted(level, key=lambda i: (level[i], i)):
w.writerow([item, level[item]])
print("Items:", len(items), "End items:", len(roots), "Max level:", max(level.values()))The CSV needs one row per parent and component pair. Quantities, effectivity dates and phantom handling are not considered, so filter your extract to one effective date first. Variables in the script use plain names, and you should test on a small extract before running on the full BOM. Recursion depth is raised for deep BOMs; extremely wide BOMs run slower because shared subassemblies are re-walked when a deeper level is found.
BOM structure validation help
Optional: help checking BOM structures during an ERP migration or clean-up.
Optional. The tool and every export work without this. No spam.
How to use the script
Export your BOM structure to a CSV with at least a parent and a component column. Enter the file name and column headers above, choose whether end items are level 0 or level 1, and copy the generated script. Save it as a .py file next to the CSV and run it with Python 3. It writes a second CSV of item and low level code, sorted by level.
The rule behind low level codes
An item's low level code is the deepest level at which it appears in any BOM. If a screw is used on a top assembly at level 1 and in a subassembly at level 3, its code is 3. MRP processes level 0 first, then level 1, and so on, so all demand for the screw has been collected before it is netted. The script walks the structure from each end item and keeps the greatest depth seen per item.
Loops and data problems
A BOM that contains itself makes low level codes impossible, so the script stops with the path that closes the loop.
- Check any item used as its own component through several levels.
- Remove obsolete or expired lines before running.
- Items that appear only inside a loop get no level and are listed in the warning.
- Phantom items still carry a level because MRP explodes through them.
- Compare results with your ERP's stored codes after a mass BOM change.
Frequently Asked Questions
Do I need to run this if my ERP already calculates low level codes?
Usually not for daily work. It is useful for audits, for migration validation, for ERPs where the codes go stale after mass BOM changes, and for analysts who model planning outside the ERP.
What does level 0 mean?
Level 0 is the end item, the top of the structure that is not used in any other BOM. Some systems start at 1 instead. The generator lets you pick, and the order of items stays the same either way.
What if the script reports a BOM loop?
The printed path shows the items that call each other. Engineering must correct the structure, because an item cannot be both above and below itself. Fix the loop in the BOM master and re-extract before running again.
Does it handle effectivity dates and alternates?
No. It takes the edges you give it. Filter your extract to one effective date and one alternate first, otherwise unrelated structures are merged and levels may be deeper than any single real BOM.
If you are migrating BOMs between ERPs and want automated structure checks, we can help build those validations for your data.
Related Tools
MRP Net Requirements SQL Generator
Fill in your table and column names and get a SQL query that computes projected available balance and the shortage per item and bucket.
ERP OperationsMRP Master Data Readiness Checklist
Check item, BOM, lead time, supplier and inventory data against what MRP needs before a go-live or a clean-up.
Supply Chain & InventoryMRP Planning Terms Glossary Reference
A searchable glossary of the terms MRP planners use every day, with the plain meaning and how each term shows up in a planning run.
Supply Chain & InventoryMRP Planner Practice Self-Assessment
A 10-question assessment of how well your team operates MRP day to day, with a score and practical next steps.
More Developer Tools tools
See all- SAP Sales Order ABAP SELECT Generator (VBAK, VBAP, VBFA)
- SAP Sales Order Create BAPI ABAP Generator (BAPI_SALESORDER_CREATEFROMDAT2)
- SAP ABAP Open Items SELECT Generator
- SAP ACDOCA SQL Query Generator
- SAP QM Inspection Lot ABAP SELECT Generator
- SAP Quality Notification Pareto SQL Query Generator
- SAP QM Usage Decision BAPI Skeleton
- ABAP Custom Exception Class Generator
- ABAP Unit Test Class Generator