Factorizer/Cluster ERP WikiCluster ERP Türkçe
Home / Business modules

Explanation

Material requirements planning

How the MRP run in procurement collects demand and supply, explodes BOMs, nets, sizes lots, raises exceptions, and turns proposals into requests or orders.

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 running at 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, and GetBomExplosion (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:

  1. Init. The engine creates the run with status running and snapshots the parameters (src/cluster_erp/modules/procurement/mrp/engine.py:769-823). With delete_and_recreate, the items of the previous completed run are bulk-deleted and one summary change-history row is written; with normal, 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).
  2. 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 project first 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).
  3. 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).
  4. 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).
  5. 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, through GetOwnerWorkingDays (src/cluster_erp/modules/procurement/mrp/engine.py:3247-3287).
  6. Exceptions. Each product gets at most one main exception: new_order, reschedule_in, reschedule_out, cancel, decrease_qty, increase_qty, or expedite. Damping margins come from settings (src/cluster_erp/modules/procurement/mrp/engine.py:3405-3600, src/cluster_erp/modules/procurement/mrp/engine.py:2817).
  7. Assembly. Items are stored in chunks, run totals are updated, the status becomes completed or simulation, and MrpRunCompleted and CriticalMaterialAlert are 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_type is regenerative or net_change; planning_mode is normal, re_explode_bom, or delete_and_recreate; scheduling_method is backward, forward, lead_time, or basic_date; lot_size_rule is default, lot_for_lot, fixed_order, period_order, or eoq; scope is all, abc_class, product, product_group, warehouse, project, or mps_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 completed run (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 query CreateProductionOrderFromPlanned (src/cluster_erp/modules/procurement/mrp/routes.py:359-447).
  • POST /mrp/runs/{run_id}/materialize reruns 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_at on 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 with ROUND_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

Verified against commit 92f8051 on 2026-11-13.

Verified against commit 92f8051 · 2026-11-13