# BOM Low Level Code Calculator Script (Python Generator)

> Source: https://netray.co/tools/bom-low-level-code-python-generator
> Publisher: Netray (netray.co), AI and integration engineering for ERP and manufacturing systems.
> Section: Free Tools

## Short answer

Fill in your CSV file and column names and get a Python script that assigns low level codes and flags circular BOMs.

## Category

developer

## Audience

- ERP developer
- Data analyst
- Planning analyst

## Tool

**Kind:** template

**Output:** code

**Language:** python

**Fields:**

#### Input CSV file

**Key:** csv_file

**Type:** text

**Default:** bom_edges.csv

#### Parent column header

**Key:** parent_col

**Type:** text

**Default:** parent_item

#### Child column header

**Key:** child_col

**Type:** text

**Default:** component_item

#### Level of end items

**Key:** start_level

**Type:** select

**Options:**

- 0
- 1

**Default:** 0

#### Output CSV file

**Key:** out_file

**Type:** text

**Default:** low_level_codes.csv

**Blocks:**

#### Python script

**Body:** import csv
import sys
from collections import defaultdict

sys.setrecursionlimit(10000)

edges = defaultdict(list)
with open("{{csv_file}}", newline="", encoding="utf-8-sig") as f:
    for row in csv.DictReader(f):
        parent = row["{{parent_col}}"].strip()
        child = row["{{child_col}}"].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, {{start_level}}, [])

if len(level) < len(items):
    print("Warning: items only in a loop have no level:", sorted(items - set(level)))

with open("{{out_file}}", "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()))

**Notes:** 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.

## Content

**Intro:** 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.

**Sections:**

#### How to use the script

**Body:** 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

**Body:** 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

**Body:** A BOM that contains itself makes low level codes impossible, so the script stops with the path that closes the loop.

**Bullets:**

- 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.

**Cta:** If you are migrating BOMs between ERPs and want automated structure checks, we can help build those validations for your data.

**Faq:**

#### Do I need to run this if my ERP already calculates low level codes?

**Answer:** 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?

**Answer:** 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?

**Answer:** 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?

**Answer:** 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.

## Search terms

low level code calculation, bom low level code python, bom loop detection, mrp low level code, bom explosion python script, parent child bom csv, circular bom check, bom level calculation

---
Talk to an engineer: https://netray.co/contact?intent=erp_ai | Machine catalog: https://netray.co/agent/catalog.json
