Material requirements planning (MRP) lives in src/cluster_erp/modules/procurement/mrp/. A planning run (MrpRun) compares demand with stock and open supply for each product, explodes bills of materials, and stores one result row (MrpRunItem) per product with a proposal and an exception message. This page explains how a run works and how its results are used. Field lists are on the procurement module page and in the source; the BOM explosion is described on the BOM module.
In short¶
- A run has seven phases: init, demand, supply, low-level coding, netting, exceptions, and result assembly (
src/cluster_erp/modules/procurement/mrp/engine.py:1-19). - Only one run can be
runningat a time; a database advisory lock guards the check (src/cluster_erp/modules/procurement/mrp/services.py:157-176). - All data from other modules arrives through EventBus queries such as
GetOpenSalesOrderDemand,GetBulkStockLevels, andGetBomExplosion(src/cluster_erp/modules/procurement/mrp/engine.py:871,src/cluster_erp/modules/procurement/mrp/engine.py:1325,src/cluster_erp/modules/procurement/mrp/engine.py:1720). - Stock and production events mark the run stale and flag products in a planning file for the next net-change run (
src/cluster_erp/modules/procurement/module.py:863-1003). - Run items become purchase requests or production orders by explicit actions (
src/cluster_erp/modules/procurement/mrp/services.py:331,src/cluster_erp/modules/procurement/mrp/routes.py:359-375).
How it works¶
A run starts with POST /mrp/runs (synchronous) or POST /mrp/runs/background (returns at once with status running) and the parameters of MrpRunCreate (src/cluster_erp/modules/procurement/mrp/routes.py:105-121, src/cluster_erp/modules/procurement/mrp/schemas.py:28-70). The diagram shows the phases.
flowchart TD P0["_phase0_init: MrpRun status running"] --> PM["planning_mode: delete_and_recreate or normal"] PM --> P1["_phase1_demand: sales, production, PIR, safety stock"] P1 --> P2["_phase2_supply: stock, open POs, production supply, vendors"] P2 --> P3["_phase3_llc: low-level codes from active BOMs"] P3 --> P4["_phase4_net_requirements: netting, lot sizing, dates"] P4 --> P5["_phase5_exceptions: action messages"] P5 --> P7["_phase7_assemble: MrpRunItem rows, totals"] P7 --> E["MrpRunCompleted and CriticalMaterialAlert"] P7 --> PR["purchase requests when output_type is purchase_requisition"]
In prose:
- Init. The engine creates the run with status
runningand snapshots the parameters (src/cluster_erp/modules/procurement/mrp/engine.py:769-823). Withdelete_and_recreate, the items of the previous completed run are bulk-deleted and one summary change-history row is written; withnormal, the BOM cache of the previous run is preloaded (src/cluster_erp/modules/procurement/mrp/engine.py:555-562,src/cluster_erp/modules/procurement/mrp/engine.py:697-767). - Demand. Demand comes from open sales orders, open production order components, planned independent requirements (PIRs), safety stock deficits, and reorder points. A run with scope
projectfirst derives its product list from the project's demand (src/cluster_erp/modules/procurement/mrp/engine.py:824-977,src/cluster_erp/modules/procurement/mrp/engine.py:1059). - Supply. Stock levels, open purchase orders, production supply, production versions, vendors, and substitutes are read in bulk (
src/cluster_erp/modules/procurement/mrp/engine.py:1311-1626). - Low-level coding. Each manufactured product gets the active BOM version, and the BOM is exploded to assign low-level codes; the scope grows with BOM children (
src/cluster_erp/modules/procurement/mrp/engine.py:1627-1920). - Netting. Requirements are netted per time bucket with dependent demand from BOMs, phantoms, substitution, lot sizing, scrap, lead-time offset, and vendor selection (
src/cluster_erp/modules/procurement/mrp/engine.py:1921-2599). Lot sizing uses the run's rule, or the setting for the product's ABC class (src/cluster_erp/modules/procurement/mrp/engine.py:3037-3093). Lead-time dates use the vendor's working calendar first, then the company group calendar, throughGetOwnerWorkingDays(src/cluster_erp/modules/procurement/mrp/engine.py:3247-3287). - Exceptions. Each product gets at most one main exception:
new_order,reschedule_in,reschedule_out,cancel,decrease_qty,increase_qty, orexpedite. Damping margins come from settings (src/cluster_erp/modules/procurement/mrp/engine.py:3405-3600,src/cluster_erp/modules/procurement/mrp/engine.py:2817). - Assembly. Items are stored in chunks, run totals are updated, the status becomes
completedorsimulation, andMrpRunCompletedandCriticalMaterialAlertare emitted (src/cluster_erp/modules/procurement/mrp/engine.py:3880-4118).
If a phase fails, the run gets status failed with the error message and duration (src/cluster_erp/modules/procurement/mrp/engine.py:594-607). When output_type is purchase_requisition, a completed run creates purchase requests at once (src/cluster_erp/modules/procurement/mrp/services.py:188-189).
Why it is built this way¶
The module docstring of the engine names the seven-phase algorithm and the netting method (src/cluster_erp/modules/procurement/mrp/engine.py:1-19). Code comments give two reasons: bulk deletion of previous run items avoids per-row history for regenerable rows (src/cluster_erp/modules/procurement/mrp/engine.py:718-721), and a net-change baseline is taken only from a run that carries a plan (src/cluster_erp/modules/procurement/mrp/engine.py:2835-2842). Other rationale is not stated in code or in the project's written engineering rules.
Rules and boundaries¶
run_typeisregenerativeornet_change;planning_modeisnormal,re_explode_bom, ordelete_and_recreate;scheduling_methodisbackward,forward,lead_time, orbasic_date;lot_size_ruleisdefault,lot_for_lot,fixed_order,period_order, oreoq;scopeisall,abc_class,product,product_group,warehouse,project, ormps_items(src/cluster_erp/modules/procurement/mrp/schemas.py:28-67).- A simulation run does not touch previous items (
src/cluster_erp/modules/procurement/mrp/engine.py:556). - A purchase request can be made only from a
completedrun (src/cluster_erp/modules/procurement/mrp/services.py:331-345). - Converting a planned order to a production order outside the opening period needs
force; the conversion is the queryCreateProductionOrderFromPlanned(src/cluster_erp/modules/procurement/mrp/routes.py:359-447). POST /mrp/runs/{run_id}/materializereruns a simulation as a real run with the same parameters (src/cluster_erp/modules/procurement/mrp/routes.py:545-560).- Deleting a run sets
deleted_aton the run and its items; a running run cannot be deleted (src/cluster_erp/modules/procurement/mrp/services.py:1217-1246). - Run items can be firmed and unfirmed; firmed items are loaded by later runs (
src/cluster_erp/modules/procurement/mrp/services.py:1284-1368,src/cluster_erp/modules/procurement/mrp/engine.py:2966). - The run stores quantities and costs as
Numeric, and durations are rounded withROUND_HALF_EVEN(src/cluster_erp/modules/procurement/mrp/engine.py:599-602).
Interaction with other parts¶
| Contract | Direction | Purpose | Source |
|---|---|---|---|
GetOpenSalesOrderDemand, GetOpenProductionDemand |
query | demand | src/cluster_erp/modules/procurement/mrp/engine.py:871, src/cluster_erp/modules/procurement/mrp/engine.py:911 |
GetBulkStockLevels, GetBatchExpirySchedule |
query to inventory |
stock | src/cluster_erp/modules/procurement/mrp/engine.py:1325 |
GetBulkOpenPos, GetProductionSupply, GetProductionVersionsBulk |
query | open supply | src/cluster_erp/modules/procurement/mrp/engine.py:1526, src/cluster_erp/modules/procurement/mrp/engine.py:1542, src/cluster_erp/modules/procurement/mrp/engine.py:1421 |
GetActiveBomVersionForProduct, GetBomExplosion |
query to bom |
structure | src/cluster_erp/modules/procurement/mrp/engine.py:1649, src/cluster_erp/modules/procurement/mrp/engine.py:1720 |
GetBulkProductVendors, GetProductPlanningData |
query to products_and_services |
vendors and planning data | src/cluster_erp/modules/procurement/mrp/engine.py:1561 |
GetOwnerWorkingDays |
query to calendars |
lead-time calendar | src/cluster_erp/modules/procurement/mrp/engine.py:3271 |
MrpRunCompleted, CriticalMaterialAlert |
emit | results | src/cluster_erp/modules/procurement/mrp/engine.py:4073, src/cluster_erp/modules/procurement/mrp/engine.py:4106 |
The run reads the working-time rules described on working time. The web app shows results in seven custom widgets; see the procurement module page.
Limits and open points¶
Terms introduced¶
| Term | Code identifier | Definition | Turkish term | Source |
|---|---|---|---|---|
| MRP run | MrpRun |
One execution of the planning algorithm with its parameters and totals. | MRP çalıştırması | src/cluster_erp/modules/procurement/mrp/models.py:26 |
| run item | MrpRunItem |
The planning result of one product in one run, with proposal and exception. | Çalıştırma kalemi | src/cluster_erp/modules/procurement/mrp/models.py:201 |
| planned independent requirement | PlannedIndependentRequirement |
A forecast demand quantity for a product and period. | Tahmin (PIR) | src/cluster_erp/modules/procurement/mrp/models.py:535 |
| low-level code | bom_level |
The deepest BOM level at which a product appears, which orders the netting. | Düşük seviye kodu | src/cluster_erp/modules/procurement/mrp/models.py:235 |
| planning file | MrpPlanningFileEntry |
A flag that a product changed and must be replanned by a net-change run. | Planlama dosyası | src/cluster_erp/modules/procurement/mrp/models.py:584 |
| exception message | exception_type |
The action MRP proposes for a product, such as expedite or new_order. |
İstisna mesajı | src/cluster_erp/modules/procurement/mrp/models.py:349 |
Related pages¶
- Procurement module
- Critical materials and substitution
- Purchase requests
- BOM module
- Production module
- Working time
Verified against commit 92f8051 on 2026-11-13.