BOM
Bill of Materials — recipes linking input materials and/or input SKUs (with quantities) to an output SKU. One BOM per output SKU.
Tables owned
| Table | Purpose |
|---|---|
org.boms | BOM header. One row per output SKU that has a recipe defined. |
org.bom_items | Composition lines. Polymorphic input (material_id XOR input_sku_id) with quantity. |
Operations
Writes
createBom(conn, { outputSkuId })→Bom. Creates the BOM header for a SKU. Items added separately.deleteBom(conn, bomId)→void. Cascades to items.replaceBomItems(conn, bomId, items)→BomItem[]. Replaces the full composition atomically (delete-then-insert in a single statement).items:Array<{ materialId?, inputSkuId?, quantity }>.addBomItem(conn, bomId, item)→BomItem. Single-line append (used by editor incremental adds).updateBomItem(conn, bomItemId, patch)→BomItem. Edits quantity (input identity stays fixed).removeBomItem(conn, bomItemId)→void.
Reads
listBoms(conn)→Bom[]. One row per output SKU with a BOM.getBomById(conn, bomId)→Bom | null.getBomForSku(conn, outputSkuId)→Bom | null. The standard lookup.listBomItems(conn, bomId)→BomItem[]. Composition for one BOM.getBomsForSkus(conn, outputSkuIds)→Map<skuId, Bom>. Batch hydration (used by WO creation snapshot workflow in L3).getBomItemsForBoms(conn, bomIds)→Map<bomId, BomItem[]>. Batch hydration paired with above.
Notes
- BOMs are read by
WorkOrders(at WO creation, to populatework_order_inputssnapshot) — but reads go through L3, which callsBOM.getBomForSkuand thenWorkOrders.createWorkOrderInputs. No direct cross-component calls. - The
material_id XOR input_sku_idinvariant is a DB check constraint, restated here for clarity.