WorkOrders
Work order header + items + recipe snapshot + receipts + receipt items. WOs convert materials into finished goods at a work site. The recipe snapshot (work_order_inputs) freezes the BOM at WO creation time so later BOM edits don't affect in-flight WOs.
Tables owned
| Table | Purpose |
|---|---|
org.work_orders | WO header (number, order date, expected delivery, work site location, status enum, notes). |
org.wo_items | Output SKU lines (sku, quantity, material unit cost, conversion cost). |
org.work_order_inputs | Recipe snapshot — copied from bom_items at WO creation. One row per (wo_item, input material or input SKU) with quantity. |
org.wo_receipts | Receipt headers (receipt date, notes). |
org.wo_receipt_items | Per-output-line received quantities. |
Operations
Writes — Header
createWo(conn, input)→WorkOrder.input:{ number, orderDate, expectedDeliveryDate?, workSiteLocationId, status, notes? }.status:wo_statusenum.updateWo(conn, woId, patch)→WorkOrder. Partial update including status transitions.deleteWo(conn, woId)→void. Cascades to items, inputs, receipts.
Writes — Items + recipe snapshot
addItem(conn, woId, item)→WoItem.item:{ skuId, quantity, materialUnitCost, conversionCost }. Recipe snapshot is not created here — L3 callsaddInputsForItemseparately.updateItem(conn, itemId, patch)→WoItem. Edits quantity / costs. Does not touch inputs.removeItem(conn, itemId)→void. Cascades to its inputs.addInputsForItem(conn, woItemId, inputs)→WorkOrderInput[]. Inserts the recipe snapshot rows.inputs:Array<{ materialId? | inputSkuId?, quantity }>. Called by L3 right afteraddItem, using data fromBOM.getBomForSku.
Writes — Receipts
createReceipt(conn, woId, input)→WoReceipt.input:{ receiptDate, notes? }. The associated ledger entries (materialsCONSUME+ FGPRODUCE) are written by L3 calling intoMaterialsInventory/FinishedGoodsInventoryin the same transaction.updateReceipt(conn, receiptId, patch)→WoReceipt.deleteReceipt(conn, receiptId)→void. Cascades to receipt items.addReceiptItem(conn, receiptId, item)→WoReceiptItem.item:{ woItemId, receivedQuantity }.updateReceiptItem(conn, receiptItemId, patch)→WoReceiptItem.removeReceiptItem(conn, receiptItemId)→void.
Reads — Header
listWos(conn, filters?)→WorkOrder[]. Filters:{ status?, workSiteLocationId?, dateFrom?, dateTo? }.getWoById(conn, woId)→WorkOrder | null.getWosByIds(conn, woIds)→WorkOrder[].getWoByNumber(conn, number)→WorkOrder | null.
Reads — Items + inputs
listItemsByWo(conn, woId)→WoItem[].listItemsByWos(conn, woIds)→Map<woId, WoItem[]>.getItemById(conn, itemId)→WoItem | null.listInputsByItem(conn, woItemId)→WorkOrderInput[]. The snapshot for one output line.listInputsByWo(conn, woId)→WorkOrderInput[]. All snapshots for a WO.
Reads — Receipts
listReceiptsByWo(conn, woId)→WoReceipt[].getReceiptById(conn, receiptId)→WoReceipt | null.listReceiptItems(conn, receiptId)→WoReceiptItem[].getReceivedTotalsByWo(conn, woId)→Map<woItemId, string>. For line-balance computation in L3.
Notes
- The recipe snapshot is owned here, not in
BOM. BOM is the live recipe;work_order_inputsis the frozen copy. - Cost cascade (rolling material costs through WO production into FG inventory cost) is an L3 workflow that reads
WorkOrders+MaterialsInventory+FinishedGoodsInventory. No L2 op.