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

Module

BOM module (bom)

Module page for bom, the bills of materials per product breakdown, their versions and items, templates, explosion, and the reads that feed routings.

The bom module in src/cluster_erp/modules/bom/ holds the bill of materials (BOM) of each manufactured product breakdown. A BOM card names the product, model, and version it builds; it has numbered versions that move from draft to active to superseded, and each version has a tree of items. The module explodes a version into effective quantities for costing, production, and planning, and it serves the BOM tree that the routing scaffold of the production module reads to derive the operation BOM (eBOM).

At a glance

Item Value Source
Package src/cluster_erp/modules/bom/ folder
Module class Module src/cluster_erp/modules/bom/module.py:19
name / version bom / 0.1.0 src/cluster_erp/modules/bom/module.py:20-26
API prefix /api/v1/bom (ModuleBase.api_prefix) src/cluster_erp/core/module_base.py:37-38
Sub-modules 4: boms, bom_versions, bom_items, bom_templates folder listing
Tables 5: bom_boms, bom_bom_versions, bom_bom_items, bom_bom_templates, bom_bom_template_items __tablename__ in the four models.py files
Entities in metadata 5: bom, bom_version, bom_item, bom_template, bom_template_item src/cluster_erp/modules/bom/module.py:898-904
Routes 39 route decorators in the package grep for @router.
Web app presence Catalogue app bom, with the custom widget bom_explorer from a gated bundle src/cluster_erp/modules/app_store/catalog.json (entry bom), gated_apps/bom/app.js
Desktop presence src/cluster_erp/desktop/modules/bom/ (bom_explorer.py, bom_builder.py) folder

What the module does

  • Keeps one BOM card per product breakdown with a base quantity, a usage type, and a status (src/cluster_erp/modules/bom/boms/models.py:17-79).
  • Versions the structure: only drafts are editable, and at most one version per BOM is active (src/cluster_erp/modules/bom/bom_versions/models.py:19-42).
  • Stores items as a tree inside a version, with find number, quantity, unit, scrap factor, cut sizes, make-or-buy choice, stock material, effectivity dates, and per-unit labour and cost figures (src/cluster_erp/modules/bom/bom_items/models.py:18-142).
  • Copies reusable templates into a draft version (src/cluster_erp/modules/bom/bom_versions/services.py:544-651).
  • Explodes a version into effective quantities and a rollup per breakdown (src/cluster_erp/modules/bom/bom_versions/services.py:722-820).
  • Serves the explorer tree, where-used data, and a purchasing coverage snapshot (src/cluster_erp/modules/bom/bom_versions/services.py:822-836, src/cluster_erp/modules/bom/bom_versions/services.py:1141-1151, src/cluster_erp/modules/bom/bom_versions/services.py:1519-1520).
  • Creates a BOM card with a first draft version when a design with a part is approved (src/cluster_erp/modules/bom/module.py:667-775).

Sub-modules

Sub-module Purpose Main entities Router Source
boms BOM cards Bom /api/v1/bom/boms src/cluster_erp/modules/bom/boms/routes.py:31
bom_versions Versions, lifecycle, explosion, tree, coverage, where-used BomVersion /api/v1/bom/bom-versions src/cluster_erp/modules/bom/bom_versions/routes.py:26
bom_items Items of a version BomItem /api/v1/bom/bom-items src/cluster_erp/modules/bom/bom_items/routes.py:31
bom_templates Templates and their items BomTemplate, BomTemplateItem /api/v1/bom/bom-templates src/cluster_erp/modules/bom/bom_templates/routes.py:29

Data model

Entity Table Key fields Notes Source
Bom bom_boms bom_code, name, product_id, product_model_id, product_version_id, owner_design_id, base_quantity, usage_type, status, extra the three breakdown ids are required src/cluster_erp/modules/bom/boms/models.py:17-79
BomVersion bom_bom_versions bom_id, version_no, status, created_from_template_id, total_weight_kg, total_labor_min, total_material_cost, total_labor_cost, approved_by, approved_at, valid_from one live active version per BOM; version_no unique per BOM src/cluster_erp/modules/bom/bom_versions/models.py:19-98
BomItem bom_bom_items bom_version_id, parent_item_id, part_id, part_model_id, part_version_id, find_number, qty, uom, level, effective_from, effective_to, cut_length_mm, cut_width_mm, sourcing, stock_material_id triple, scrap_factor, is_phantom, cost and labour per unit, source part_id is a product id src/cluster_erp/modules/bom/bom_items/models.py:18-142
BomTemplate bom_bom_templates template_code, name, family, description src/cluster_erp/modules/bom/bom_templates/models.py:13-31
BomTemplateItem bom_bom_template_items template_id, parent_item_id, part_id, find_number, qty, uom, cut_length_mm, is_phantom no model or version column src/cluster_erp/modules/bom/bom_templates/models.py:34-81

Quantities and money are Numeric: item quantity Numeric(18, 4), costs Numeric(18, 4), scrap factor Numeric(6, 4) (src/cluster_erp/modules/bom/bom_items/models.py:62-128). The product ids are plain UUID columns; the bom module checks them through the EventBus, not through database foreign keys (src/cluster_erp/modules/bom/boms/services.py:203-213).

Screens and metadata

get_metadata declares a sidebar group BOM Management (Turkish Ürün Ağacı Yönetimi) with four sections: BOM Explorer (the custom widget bom_explorer), Bills of Materials, BOM Versions, and BOM Templates (src/cluster_erp/modules/bom/module.py:838-905). The explorer tabs are labelled Product Tree · BOM (webapp/i18n/en.json key bom_explorer.tab.cs03) and Operation BOM · eBOM (webapp/i18n/en.json key bom_explorer.tab.ca03). The product card shows a read-only Bill of Materials tab for manufacturable products (src/cluster_erp/modules/products_and_services/products/metadata.py:276-285). Gated bundles are described on gated app bundles; the desktop explorer on desktop module screens.

Status and actions

A BOM card is active or archived; its usage type is manufacturing, engineering, or costing (src/cluster_erp/modules/bom/boms/schemas.py:10-11). A version moves from draft to active to superseded (src/cluster_erp/modules/bom/bom_versions/models.py:20-24).

Action Label Condition Endpoint Permission Source
activate Activate status is draft POST /bom-versions/{id}/activate bom.activate src/cluster_erp/modules/bom/bom_versions/metadata.py:48-58, src/cluster_erp/modules/bom/bom_versions/routes.py:145-154
copy_from_template Copy from Template status is draft POST /bom-versions/{id}/copy-from-template bom.create src/cluster_erp/modules/bom/bom_versions/metadata.py:59-85, src/cluster_erp/modules/bom/bom_versions/routes.py:187-201
supersede Supersede status is active POST /bom-versions/{id}/supersede bom.activate src/cluster_erp/modules/bom/bom_versions/metadata.py:86-116, src/cluster_erp/modules/bom/bom_versions/routes.py:170-184

The diagram shows a version's lifecycle.

stateDiagram-v2
 [*] --> draft: create, clone, or auto-BOM
 draft --> active: activate
 active --> superseded: supersede with a draft successor
 draft --> [*]: delete
 superseded --> [*]

In prose: a version is created as draft (src/cluster_erp/modules/bom/bom_versions/services.py:231-274). activate needs a draft with at least one live item and no other active version on the BOM (src/cluster_erp/modules/bom/bom_versions/services.py:417-474). supersede turns the active version into superseded and a draft of the same BOM into active in one call (src/cluster_erp/modules/bom/bom_versions/services.py:476-542). Only a draft can be deleted, and its items go with it (src/cluster_erp/modules/bom/bom_versions/services.py:305-333).

Business rules

  • Creating or changing a BOM card checks that the product exists and that model and version belong to it (src/cluster_erp/modules/bom/boms/services.py:80-108, src/cluster_erp/modules/bom/boms/services.py:130-139).
  • An archived BOM can only be set back to active (src/cluster_erp/modules/bom/boms/services.py:120-124).
  • A BOM with an active or superseded version cannot be deleted; deleting a BOM soft-deletes its versions and their items (src/cluster_erp/modules/bom/boms/services.py:159-176, src/cluster_erp/modules/bom/boms/services.py:215-267).
  • Items can be added or changed only in a draft version (src/cluster_erp/modules/bom/bom_items/services.py:135-137).
  • A zero quantity is refused; a negative quantity is a co-product (src/cluster_erp/modules/bom/bom_items/services.py:139-146).
  • Each item's breakdown is validated; a stock material without model and version takes the product's default ones (src/cluster_erp/modules/bom/bom_items/services.py:91-128, src/cluster_erp/modules/bom/bom_items/services.py:158-169).
  • The item level comes from the parent chain; the chain may not loop or go deeper than MAX_BOM_DEPTH, which is 10 (src/cluster_erp/modules/bom/bom_items/services.py:32, src/cluster_erp/modules/bom/bom_items/services.py:430-470).
  • A missing scrap factor becomes DEFAULT_SCRAP_FACTOR, 0.0300 (src/cluster_erp/modules/bom/bom_items/services.py:33, src/cluster_erp/modules/bom/bom_items/services.py:180-181).
  • clone copies any version into a new draft with the next version number and all items (src/cluster_erp/modules/bom/bom_versions/services.py:335-415).
  • Version totals: labour minutes and labour cost are per-unit figures times quantity; material cost is per-unit cost times quantity divided by one minus the scrap factor; weight sums the net weight of leaf items from the product master (src/cluster_erp/modules/bom/bom_versions/services.py:671-718).
  • bom_code comes from the yearly sequence bom, and template_code from bom_template (src/cluster_erp/modules/bom/boms/services.py:89, src/cluster_erp/modules/bom/bom_templates/services.py:101).

Explosion and the operation BOM

The diagram shows how a BOM version becomes the explosion that other modules read, and how the routing scaffold reads the tree.

flowchart TD
 V["BomVersion and BomItem rows"] --> F["_filter_effective(as_of)"]
 F --> Q["effective_qty = qty / (1 - scrap), times each parent qty / (1 - parent scrap)"]
 Q --> A["operation_type and work_center_id from production allocations"]
 A --> R["rollup per part, model, version"]
 R --> X["GetBomExplosion answer"]
 X --> C["costing"]
 X --> P["production and MRP"]
 V --> S["GetBomScaffoldTree answer"]
 S --> W["production routing scaffold"]
 W --> I["CreateScaffoldIntermediate to products_and_services"]

In prose: explosion loads the live items of a version and drops items whose effectivity window does not contain the given date, with their whole subtree (src/cluster_erp/modules/bom/bom_versions/services.py:136-159, src/cluster_erp/modules/bom/bom_versions/services.py:734-741). For each item the effective quantity is the quantity divided by one minus its scrap factor, then multiplied by each parent's quantity divided by one minus that parent's scrap factor, rounded to four places with ROUND_HALF_EVEN; a negative co-product quantity takes no scrap (src/cluster_erp/modules/bom/bom_versions/services.py:128-133, src/cluster_erp/modules/bom/bom_versions/services.py:748-767). The operation type and work centre come from the production module's component allocations (src/cluster_erp/modules/bom/bom_versions/services.py:790-796). The rollup sums effective quantities per part, model, and version (src/cluster_erp/modules/bom/bom_versions/services.py:798-820). Other modules ask for it with GetBomExplosion (src/cluster_erp/modules/bom/module.py:217-228). The explosion follows parent links inside one version; the explorer tree additionally expands items that have their own active BOM (src/cluster_erp/modules/bom/bom_versions/services.py:1141-1151).

For the operation BOM, the production module's routing scaffold asks GetBomScaffoldTree with a full product breakdown. The bom module answers with the active version of exactly that breakdown, or a named version, and all its live items with resolved make-or-buy; it does not fall back to a default breakdown (src/cluster_erp/modules/bom/module.py:363-420, src/cluster_erp/modules/production/routings/scaffold.py:185-192). The scaffold turns non-phantom items into inputs of a final joining operation and lifts the children of phantom items; this is described in its module docstring (src/cluster_erp/modules/production/routings/scaffold.py:1-43). When an operation of a routing has an output, the scaffold asks products_and_services to create or reuse an intermediate product with CreateScaffoldIntermediate (src/cluster_erp/modules/production/routings/scaffold.py:2221-2239). The routing side is documented on routings and operation types.

Events and queries

The module consumes 15 contracts and produces 14, counted as on the parties module page. The full list is on the contracts reference.

Direction Contract class Handler or emitter Source
emits BomDraftCreated version create, clone, auto-BOM src/cluster_erp/modules/bom/bom_versions/services.py:256-264, src/cluster_erp/modules/bom/bom_versions/services.py:406-414, src/cluster_erp/modules/bom/module.py:760-768
emits BomActivated, BomVersionActivated activate, supersede src/cluster_erp/modules/bom/bom_versions/services.py:455-473, src/cluster_erp/modules/bom/bom_versions/services.py:523-541
emits BomSuperseded supersede src/cluster_erp/modules/bom/bom_versions/services.py:515-522
emits BomItemChanged item create, update, and move src/cluster_erp/modules/bom/bom_items/services.py:227, src/cluster_erp/modules/bom/bom_items/services.py:324, src/cluster_erp/modules/bom/bom_items/services.py:516
queries GetProductById, GetProductDefaultBreakdown, GetBulkProductDefaultBreakdowns, GetDesignById, and planning reads services and handlers src/cluster_erp/modules/bom/boms/services.py:204-206, src/cluster_erp/modules/bom/bom_versions/services.py:598-608, src/cluster_erp/modules/bom/module.py:686-688
answers query GetBomById, CreateBomForProduct, GetPartUsageCounts, IsBomActive, GetBomExplosion, GetActiveBomVersionForProduct, GetBomVersionsUpdatedAt, GetActiveBomItemsForProduct, GetBomScaffoldTree, GetBomItemDisplay, GetBomMaterials, GetBomVersionDisplay handlers in module.py src/cluster_erp/modules/bom/module.py:85-123
subscribes DesignApproved _handle_design_approved src/cluster_erp/modules/bom/module.py:124, src/cluster_erp/modules/bom/module.py:667-775
subscribes ProductDeleted _handle_product_deleted src/cluster_erp/modules/bom/module.py:125, src/cluster_erp/modules/bom/module.py:777-816
subscribes DescribeFieldConsumers _describe_field_consumers src/cluster_erp/modules/bom/module.py:65, src/cluster_erp/modules/bom/module.py:907-937

Rules carried by the subscriptions:

  • On DesignApproved, the module reads the design's part, takes that product's default model and version, and creates an active BOM card named after the design with a draft version 1. It skips a design without a part, a design that already owns a BOM, and a product without a default breakdown (src/cluster_erp/modules/bom/module.py:667-775).
  • On ProductDeleted, the module soft-deletes the deleted product's items in draft versions only; active and superseded versions keep their rows (src/cluster_erp/modules/bom/module.py:777-816).

Permissions

Permission key Used by Source
bom.read every read route src/cluster_erp/modules/bom/boms/routes.py:51-99, src/cluster_erp/modules/bom/bom_versions/routes.py:35-295, src/cluster_erp/modules/bom/bom_items/routes.py:61-219, src/cluster_erp/modules/bom/bom_templates/routes.py:38-146
bom.create create, update, delete, bulk delete, clone, copy from template, recalculate, item move src/cluster_erp/modules/bom/boms/routes.py:131-170, src/cluster_erp/modules/bom/bom_versions/routes.py:109-207, src/cluster_erp/modules/bom/bom_items/routes.py:233-293, src/cluster_erp/modules/bom/bom_templates/routes.py:107-199
bom.activate activate and supersede src/cluster_erp/modules/bom/bom_versions/routes.py:148, src/cluster_erp/modules/bom/bom_versions/routes.py:174

Privacy, retention, and history

The module stores no personal data and has no privacy_handlers.py. Deletion is soft throughout, and version and item deletions cascade with the same actor (src/cluster_erp/modules/bom/boms/services.py:215-249). Changes are captured by change history.

Analytics facts

This module has no analytics_facts.py.

Settings and reference data

The module has no settings section. The stock-unit arithmetic for make-from-stock items reads the kerf, sheet gap, and edge-margin settings through core/stock_conversion.py (src/cluster_erp/modules/bom/bom_versions/services.py:95-125); see product breakdown and stock conversion.

Tests

Found by a grep for modules.bom in tests/ and by file name in web-client/.

Kind File Covers
pytest tests/test_bom_bugfix_batch_2026_10_08.py unit pickers, item unit, version totals formula, metadata shape (10 tests)
pytest tests/test_record_links.py record links in BOM metadata (3 tests)
e2e web-client/_e2e_bom_app.mjs the BOM app: explorer and registers
e2e web-client/_e2e_bom_me2m.mjs, web-client/_e2e_bom_me2m_matrix.mjs the purchasing coverage tab and its arithmetic
e2e web-client/_e2e_bom_open_in_explorer.mjs opening a BOM from the product card in the explorer
e2e web-client/_e2e_ebom_scaffold.mjs, web-client/_e2e_ebom_wizard.mjs, web-client/_e2e_ebom_operation_staging.mjs the routing scaffold that reads the BOM tree
e2e web-client/_e2e_bom_bugfix_batch.mjs the BOM forms in a browser

Discrepancies

Terms introduced

Term Code identifier Definition Turkish term Source
bill of materials Bom The card that names the product breakdown a structure builds. Ürün ağacı src/cluster_erp/modules/bom/boms/models.py:17
BOM version BomVersion A numbered snapshot of a BOM structure with a lifecycle. Ürün ağacı versiyonu src/cluster_erp/modules/bom/bom_versions/models.py:19
BOM item BomItem One position of a BOM version. Ürün ağacı kalemi src/cluster_erp/modules/bom/bom_items/models.py:18
explosion explosion The flat item list with effective quantities and a rollup per breakdown. Patlatma src/cluster_erp/modules/bom/bom_versions/services.py:722
effective quantity effective_qty Quantity per finished unit after scrap and parent multiplication. Etkin miktar src/cluster_erp/modules/bom/bom_versions/services.py:748-767
co-product negative qty A BOM item with negative quantity, an expected output. Ko-ürün src/cluster_erp/modules/bom/bom_items/services.py:139-146
phantom item is_phantom An item that coverage skips because its children carry the multiplied demand. Hayalet kalem src/cluster_erp/modules/bom/bom_versions/services.py:830-831

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

Verified against commit 92f8051 · 2026-11-13