Spare Parts & Consumables
In ianaiERP, spare parts aren't a separate entity — they're just Items with the is_spare_part = true flag. This keeps purchasing, vendor catalogs, average costing, lot tracking, and stock locations all working the same way they do for any other inventory item. The EMS suite adds two thin layers on top:
- The
is_spare_partboolean onitem_itemfor filtering. - A
SparePartLinkjoin table that connects a spare-part item to the asset(s) it services, optionally with a usage rate.
This page covers both layers, plus the low-stock alerting cron.
Flagging an item as a spare part
From the Item form
/item → open or create an item → toggle the Spare part switch (Inventory section) → save.
The flag is independent of item category, item type, and stock-tracking mode. A single item can be a finished good and a spare part if it's also used as a service replacement.
Effect on the rest of the app
| Where | Behavior |
|---|---|
Item list /item | A spare-part badge shows in the item row. Filterable. |
| PM Plan form → Tasks linked to parts | (future) Will surface only spare-part items in part pickers. |
| Log Maintenance Event → Parts used | The part-line FetchSelect defaults to filtering is_spare_part = true. You can toggle the filter off to pick non-spare items. |
| Link Spare Part to Asset (Maintenance Hub) | Only is_spare_part = true items appear in the picker. |
| Equipment Hub KPI "Spare Parts Low" | Counts items where is_spare_part = true AND qty_on_hand ≤ safety_stock_qty. |
support-ms 6-hour cron | Scans is_spare_part items for low stock; fires spare_part_low_stock SSE per low item. |
Consumables vs spare parts
ianaiERP uses one boolean (is_spare_part) to cover both:
- Spare parts: replacement components installed during repair (belts, gears, motors, print heads).
- Consumables: things used up during operation or maintenance (oil, lubricant, blades, filters, gloves).
If your accounting needs distinguish them, use Item Category. The EMS suite treats them uniformly because the operational concerns (low stock, link-to-asset, usage rate) are identical.
Linking parts to assets — SparePartLink
A SparePartLink row says "this item is a spare part for that asset". It's a many-to-many relationship: one part can apply to multiple assets (e.g. a generic O-ring), and one asset can have many parts.
Where to create links
Maintenance Hub → Spare Parts tab → + Link Spare Part.
Form fields:
| Field | Notes |
|---|---|
| Spare part | FetchSelect to /item filtered to is_spare_part = true. |
| Asset | The asset the part services. |
| Usage rate / runtime hr | Optional. If set, the cron can project when stock will run out based on the asset's total_operating_hours trajectory. |
Usage rate — how it's used
The usage_rate_per_runtime_hr field is optional. Leave it blank for parts where consumption isn't time-correlated (belts last as long as they last; motors don't have a fixed wear rate).
Set it for genuinely runtime-correlated consumables:
- "Oil filter — replaced every 500 hours" → usage rate =
1 / 500 = 0.002 - "Cutting blade — replaced every 200 hours" → usage rate =
1 / 200 = 0.005
When set, the system can compute:
projected_runout_date = today + (qty_on_hand / usage_rate_per_runtime_hr) / hours_per_day
(hours_per_day derived from the asset's parent WC's rated_hours_per_day.)
This projection isn't currently surfaced in the UI but powers a planned "Project stock-out" report.
Removing a link
From the Spare Parts tab, the row's kebab menu has Unlink. Confirmation dialog before delete. Unlinking doesn't affect the item itself, just the SparePartLink row.
Low-stock alerts
Cron: support-ms every 6 hours (0 */6 * * *).
For each item where is_spare_part = true AND qty_on_hand ≤ safety_stock_qty:
- Fires a
spare_part_low_stockSSE event with severity based on how far below safety stock the count is:- WARNING — between 0 and safety_stock_qty
- CRITICAL — below 0 (back-ordered)
- Updates the Equipment Hub "Spare Parts Low" KPI count.
- Adds an entry to the Alerts Feed.
The cron is deliberately quieter than the 5-minute status rollup — low-stock state changes are not real-time. Six hours catches it before the next shift change in most scenarios.
To configure when an alert fires for a specific item, set its safety_stock_qty on the Item form. The cron uses that threshold per-item; there's no global override.
Where the parts get consumed
| Pathway | Effect on qty_on_hand |
|---|---|
CompleteMaintenanceEvent with parts_used[] lines | Decrements each line's qty atomically. |
| Manual stock adjustment | Standard inventory StockAdjustment flow. |
Issue to a work order (item_transaction) | If the spare part is consumed as a manufacturing component. |
The accounting for spare-part consumption follows the same path as any other inventory issue — there's no separate "maintenance inventory" ledger.
Setup recipe (typical press line)
- Mark these items
is_spare_part = true:- Print head assembly
- Drive belt (multiple sizes)
- Hydraulic oil (consumable)
- Cleaning solvent (consumable)
- Filters A, B, C
- Set
safety_stock_qtyon each based on lead time × consumption rate. - Link each to the asset(s) it services:
- "Print head" → "Heidelberg Press 1" (no usage rate — wear-driven)
- "Drive belt 50mm" → "Folder Unit 7", "Folder Unit 8" (no usage rate)
- "Hydraulic oil" → "Heidelberg Press 1" (usage rate = 0.0005 L/hr — projected runout)
- "Filter A" → "Heidelberg Press 1" (usage rate = 0.002 — replaced every 500hr)
- Confirm the low-stock cron fires by manually adjusting one item to below its safety stock and waiting for the next 6-hour scan (or use
db-queryto check thecommon_notificationtable).
Troubleshooting
| Symptom | Likely cause |
|---|---|
| Item doesn't appear in "Link Spare Part" picker | is_spare_part flag isn't set. Open the item form and toggle it. |
| Low-stock KPI count is wrong | safety_stock_qty isn't set on the items (defaults to 0 → never alerts). |
spare_part_low_stock alerts never fire | Cron not running (support-ms 6-hour). Or no item is below its safety stock. |
| Parts consumed during maintenance don't decrement stock | The event didn't reach status COMPLETE. Inflight events don't move inventory. |
| Same part linked to many assets — too noisy | Use one shared link plus tighter safety_stock_qty rather than separate links per asset. SparePartLink is for traceability, not for separate inventories. |
Related
- Maintenance Events — where parts_used decrements happen
- Asset Management — Spare Parts tab on the asset detail
- Equipment Hub — Spare Parts Low KPI and Alerts Feed