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, andproduct_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_servicesmodule over the EventBus withValidateProductBreakdown(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.pycomputes how many pieces fit into one bar or sheet, and how many stock units an order needs, withDecimalarithmetic (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:
- No product: model and version must also be empty, else
VALIDATION_ERRORwith HTTP 422 (src/cluster_erp/core/product_breakdown.py:103-110). - A product without a model or a version:
VALIDATION_ERRORwith HTTP 422 (src/cluster_erp/core/product_breakdown.py:112-118). - All three present: the function queries
ValidateProductBreakdown. If the answer is notok, it raises the returned code,PRODUCT_MODEL_PRODUCT_MISMATCHorPRODUCT_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
Noneinstead 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
Decimalonly (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
FieldMetaandForeignKeySource. - MRP is documented in MRP.
Limits and open points¶
pieces_per_stock_unit_from_planningreturnsNonefor a stock form other thanlengthorsheet, and for a sheet whose dimension unit is notmm(src/cluster_erp/core/stock_conversion.py:103-120). How each caller treatsNonewas 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 |
Related pages¶
Verified against commit 92f8051 on 2026-11-13.