Factorizer/Cluster ERP WikiCluster ERP Türkçe
Home / Platform

Explanation

Product breakdown and stock conversion

The mandatory product, model, and version breakdown in core/product_breakdown.py and the stock-size conversion arithmetic in core/stock_conversion.py.

Every document line that names a product in Cluster ERP must name its model and version too. This page explains the shared form fields and validation in core/product_breakdown.py, and the conversion from part pieces to stock units (bars or sheets) in core/stock_conversion.py. The products, models, and versions themselves are documented on products and services.

In short

  • A product reference is complete only with all three of product_id, product_model_id, and product_version_id, or with none of them (src/cluster_erp/core/product_breakdown.py:94-118).
  • Whether a model belongs to the product and a version belongs to the model is checked by the products_and_services module over the EventBus with ValidateProductBreakdown (src/cluster_erp/core/product_breakdown.py:120-147, src/cluster_erp/modules/products_and_services/module.py:131).
  • product_breakdown_fields() returns the model and version picker fields for any form, each scoped by the field before it (src/cluster_erp/core/product_breakdown.py:31-83).
  • core/stock_conversion.py computes how many pieces fit into one bar or sheet, and how many stock units an order needs, with Decimal arithmetic (src/cluster_erp/core/stock_conversion.py:19-67).

How it works

The breakdown rule

ensure_product_breakdown(bus, product_id, product_model_id, product_version_id, source_module=...) runs these checks:

  1. No product: model and version must also be empty, else VALIDATION_ERROR with HTTP 422 (src/cluster_erp/core/product_breakdown.py:103-110).
  2. A product without a model or a version: VALIDATION_ERROR with HTTP 422 (src/cluster_erp/core/product_breakdown.py:112-118).
  3. All three present: the function queries ValidateProductBreakdown. If the answer is not ok, it raises the returned code, PRODUCT_MODEL_PRODUCT_MISMATCH or PRODUCT_VERSION_MODEL_MISMATCH, with HTTP 422 (src/cluster_erp/core/product_breakdown.py:120-147).

The sequence diagram shows the third case.

sequenceDiagram
 participant S as Document service
 participant C as ensure_product_breakdown
 participant B as EventBus
 participant P as products_and_services
 S->>C: product, model, version ids
 C->>B: query(ValidateProductBreakdown)
 B->>P: handler
 P-->>B: ok, or ok false with code
 B-->>C: result
 C-->>S: return, or raise AppError 422

In prose: a service hands the three ids to the core helper. The helper asks the owning module over the EventBus and either returns or raises a 422 error with the returned code.

23 Python files in 11 modules call ensure_product_breakdown (counted with grep -rln ensure_product_breakdown src/cluster_erp/modules): bom, fleet, inventory, nesting, procurement, production, products_and_services, projects, purchasing_quotations, quotations, and sales_orders.

Shared form fields

product_model_source(product_field) and product_version_source(model_field) build ForeignKeySource objects for the routes /models/ and /versions/ of products_and_services, filtered by the sibling field and by active_only (src/cluster_erp/core/product_breakdown.py:31-48). product_breakdown_fields(...) wraps them in two FieldMeta objects, required by default (src/cluster_erp/core/product_breakdown.py:55-83). The {field:...} parameter syntax lets the client fill the filter from the form; see generic form.

Stock conversion

Function Computes Source
pieces_per_length_unit(stock_length_mm, piece_length_mm, kerf_mm) floor((stock + kerf) / (piece + kerf)); None when no piece fits src/cluster_erp/core/stock_conversion.py:19-32
pieces_per_sheet(sheet_length_mm, sheet_width_mm, piece_length_mm, piece_width_mm, gap_mm, edge_mm) A grid with edge margin and gap, tried straight and rotated by 90 degrees; the larger count wins src/cluster_erp/core/stock_conversion.py:35-62
stock_units_needed(pieces, per_unit) pieces / per_unit rounded up with ROUND_CEILING src/cluster_erp/core/stock_conversion.py:65-67
pieces_per_stock_unit_from_planning(part_plan, stock_plan, kerf_default_mm, sheet_gap_mm, sheet_edge_mm,...) Picks the bar or sheet formula from the stock's stock_form; trusts part dimensions only when their unit is mm; an explicit cut length or width from a BOM line wins src/cluster_erp/core/stock_conversion.py:77-120

The defaults for kerf, sheet gap, and edge margin come from the settings mrp_default_cut_kerf_mm, mrp_sheet_part_gap_mm, and mrp_sheet_edge_margin_mm (src/cluster_erp/config/settings.py:596-598). Three files call the module: src/cluster_erp/modules/bom/bom_versions/services.py, src/cluster_erp/modules/procurement/mrp/engine.py, and src/cluster_erp/modules/production/production_orders/services.py (counted with grep -rln stock_conversion).

Why it is built this way

  • The project's written engineering rules make the product, model, and version breakdown mandatory across the ERP, and forbid a silent fallback to the product when a model or version is missing.
  • The module docstring states that the breakdown is the granularity at which stock is kept, and that validation goes over the EventBus because the products module may not be imported (src/cluster_erp/core/product_breakdown.py:1-14).
  • The stock conversion docstring states that it is the single source for the MRP engine, the BOM tree, and production orders, that the calculation is conservative, and that it returns None instead of assuming when it cannot compute (src/cluster_erp/core/stock_conversion.py:1-8).

Rules and boundaries

  • No fallback: a product without model and version is refused, not completed (src/cluster_erp/core/product_breakdown.py:112-118).
  • Stock conversion uses millimetre values as Decimal only (src/cluster_erp/core/stock_conversion.py:1-8, src/cluster_erp/core/stock_conversion.py:70-74).

Interaction with other parts

  • Event bus carries ValidateProductBreakdown (src/cluster_erp/core/contracts.py:219).
  • Metadata model defines FieldMeta and ForeignKeySource.
  • MRP is documented in MRP.

Limits and open points

  • pieces_per_stock_unit_from_planning returns None for a stock form other than length or sheet, and for a sheet whose dimension unit is not mm (src/cluster_erp/core/stock_conversion.py:103-120). How each caller treats None was not traced for this page.

Terms introduced

Term Code identifier Definition Turkish term Source
product breakdown ensure_product_breakdown The rule that a product reference carries product, model, and version together. ürün kırılımı src/cluster_erp/core/product_breakdown.py:86
kerf kerf_mm The material width lost to one cut. kesim payı src/cluster_erp/core/stock_conversion.py:19-32
stock form stock_form Whether a stock item is a bar (length) or a sheet (sheet). stok biçimi src/cluster_erp/core/stock_conversion.py:103-108

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

Verified against commit 92f8051 · 2026-11-13