Implementing BOM Explosion and MRP in a Web ERP
BOM explosion and MRP are where an ERP's manufacturing module earns its keep — and where naive implementations fall apart on real data. A finished product with a ten-level BOM repeated across hundreds of orders explodes into tens of thousands of component lines. This article walks through the data model and algorithms we use, tuned for a web architecture where planners expect results in seconds.
Modeling the BOM
The BOM is a directed acyclic graph, stored as an edge table: (parent_item_id, component_item_id, quantity, scrap_rate, version, effective_dates). Three modeling decisions matter:
- Versions and effectivity dates — a component change must not rewrite history. Each BOM edge carries a version and a validity window; explosion always takes "the version effective on the planned date".
- Scrap / yield on the edge — consuming 1.06 units because 6% is lost in an operation is edge data, not something MRP should guess.
- Phantom items — subassemblies that are never stocked should be marked
phantomand exploded straight through, otherwise MRP generates plan orders for things nobody builds separately.
Explosion: recursive, memoized, cycle-guarded
Explosion multiplies quantities down the tree. Two non-negotiable guards:
- Cycle detection — maintain a visited set per path; an item re-appearing on its own path means bad master data, and the run must abort with a clear message naming the cycle, not recurse until stack overflow.
- Memoization — the same semi-finished subassembly often appears in many branches. Cache the exploded subtree per item (keyed by item, version and quantity factor) and the run collapses from exponential to roughly linear in distinct items.
In practice, an explosion that touches 5,000 distinct items completes in well under a second server-side. The result is stored as a snapshot so planners can audit exactly what the MRP run saw.
Netting: from gross requirements to planned orders
Classic MRP netting per item, per planning bucket (usually per day or week):
- Gross requirements — sum of exploded demand plus independent demand (sales forecasts, spare parts).
- Scheduled receipts — open purchase orders and firm planned orders arriving in the bucket.
- Projected available — on-hand minus safety stock, carried bucket to bucket.
- Net requirement — when projected available goes negative, a planned order is created with the item's lot-sizing rule (lot-for-lot, fixed lot, or minimum quantity) and lead time offsetting.
Process items in low-level-code order (components after their parents) so every parent demand is known before a component is netted. Compute low-level codes once per BOM version change, not per MRP run.
Keeping it fast
- Run MRP as a batch job, snapshotting inputs (inventory, open orders, BOM versions) at start. Interactive runs against live data produce irreproducible results and angry planners.
- Incremental regeneration — re-run only items under a changed BOM subtree or with changed demand; full runs nightly, incremental runs on demand.
- Expose results as data, not as magic — every planned order links back to its pegging information (which parent orders drove it), so planners can trace a number instead of trusting it.
From planned orders to the shop floor
Planned orders become work orders when a planner firms them. Work orders carry their own BOM snapshot (a copy, not a reference — the design BOM will drift) and route; material issues and completions feed back into inventory, which posts through the same financial pipeline described in Integrating General Ledger with Business Documents. Scrap and rework are recorded against the work order so costing reflects reality. For approvals on work-order release, we reuse the same workflow engine described in Building a Visual Approval Workflow Engine — one engine, many document types.
Conclusion
BOM and MRP reward boring engineering: an edge table with versions and effectivity, a memoized explosion with a cycle guard, level-by-level netting with clear pegging, and batch runs against snapshots. Nail the data model and the algorithms stay small; skip them and no amount of UI polish will save the manufacturing module.