bomSubstore
Resolves and formats Bill of Materials (BOM) tables defined in the Mercura back-office. For each completed configuration, the SDK fetches the BOM definition from the API, combines it with the current form values, quantities, and dynamic prices, and returns channel-specific resolved tables ready to render.
BOM resolution is memoized per config and output channel — it only re-computes when the underlying BOM definition, form data, values, or locale change.
Table of contents
Top-level
Per-config (via useBomByConfigId / useBomByCurrentConfigId)
Top-level
bomConfigs
bomConfigs: Record<number, BomStoreItemVariables>Map from config ID to that config’s raw BOM fetch state.
Each entry is created when configsSubstore.addConfig is called and removed when configsSubstore.removeConfig is called. The BOM definition is fetched automatically via TanStack Query, keyed by formId, language, and country.
Related
configsSubstore.configs— each config ID has a corresponding entry heregetBom— resolves a config’s BOM into renderable tables
getBoms
getBoms: (args: GetBomsArgs) => ResolvedBom[]Returns resolved BOM data for every completed configuration in the session.
type GetBomsArgs = { channel: BomOutputChannel; skipMultiplyConfigQuantity?: boolean; pricesIncludedText?: string;};
type ResolvedBom = { configId: number; bom: ApiResource<TBomFullResolvedData>;};
type BomOutputChannel = "checkout" | "pdf" | "excel" | "email";| Channel | Purpose |
|---|---|
checkout | Real-time UI in the configurator checkout |
pdf | High-fidelity layout for PDF generation |
excel | Tabular format for spreadsheet export |
email | Simplified summary for email output |
The channel controls which BOM elements and columns are visible — each element and column in the back-office definition has per-channel hide_on_* flags.
Quantities are multiplied by config.configQuantity by default. Pass skipMultiplyConfigQuantity: true to get per-unit quantities. Use pricesIncludedText to customise the label shown when a price resolves to zero (defaults to the value passed by your UI).
Returns ResolvedBom[] — one entry per config with status === "completed". Each bom field is an ApiResource with data, isLoading, and error.
Related
getBom— same resolution for a single configfinishedConfigsSubstore.getFinishedConfigs— similar completed-config filterlocalizationSubstore.selectedLanguage— required for resolution; returns loading state when unset
getBom
getBom: ( configId: number, args: GetBomsArgs,) => ApiResource<TBomFullResolvedData>Resolves the BOM for a single configuration.
Same arguments and behaviour as getBoms, but scoped to one configId. Returns { data: undefined, isLoading: false, error: null } when no BOM entry exists for the given config.
Related
getBoms— batch version across all completed configs
Per-config
Access per-config BOM state through the useBomByConfigId or useBomByCurrentConfigId hooks. Both expose a BomStoreItem:
type BomStoreItem = { bomConfig: ApiResource<TBom>; getBom: (args: GetBomsArgs) => ApiResource<TBomFullResolvedData>;};bomConfig
bomConfig: ApiResource<TBom>Raw BOM definition fetched from the API for this config’s form. Includes data, isLoading, and error.
The TBom shape contains tables (with columns, groups, and elements) and an optional summary block. Column field values include sku, label, description, sales_price, cost_price, margin, quantity, property, name, discount, and value.
Related
getBom (per config)— combines this definition with live values
getBom (per config)
getBom: (args: GetBomsArgs) => ApiResource<TBomFullResolvedData>Resolves this config’s BOM into renderable tables and summary rows.
type TBomFullResolvedData = { tables: BomTable[]; summary: TBomSummaryResult | null;};Each BomTable contains headerColumns, groups, and numColumns. Groups contain typed rows:
| Row type | Description |
|---|---|
element-with-options | A form element with one or more selected options; each option is a sub-row with resolved column values |
element-without-options | A form element without options (e.g. text/number); renders a single row with the element label |
text | Static text content defined in the BOM builder |
subtotal | Computed subtotal row for numeric columns |
Each resolved cell includes a formatted value string, a rawValue for calculations, alignment, widthPercentage, and an isMarkdown flag.
The summary block aggregates numeric columns (cost_price, sales_price, margin, discount) and property values across the BOM. Returns null when no summary is configured or all rows are hidden for the channel.
Related
getBoms— top-level equivalentnumberFormatterSubstore— used internally for price and number formatting
Hooks
| Hook | Scope | Description |
|---|---|---|
useBom | Global | Access bomSubstore directly (getBoms, getBom, bomConfigs) |
useBomByConfigId(id, sel) | Per config | Select from a specific config’s BomStoreItem |
useBomByCurrentConfigId(sel) | Current config | Same as above, scoped to configsSubstore.currentConfigId |
Example — render BOM tables at checkout:
const getBoms = sdk.useBom((s) => s.getBoms);
const resolved = getBoms({ channel: "checkout", pricesIncludedText: "included",});
resolved.map(({ configId, bom }) => { if (bom.isLoading) return <p key={configId}>Loading BOM…</p>; if (bom.error) return <p key={configId}>Failed to load BOM</p>; if (!bom.data) return null;
return bom.data.tables.map((table) => ( <BomTableView key={table.id} table={table} /> ));});