---
title: "Spare Parts"
description: "The maintenance module doesn't introduce its own stock ledger."
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.beelocity.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Spare Parts

The maintenance module doesn't introduce its own stock ledger. Every spare-part issue, return, and write-off is a regular [stock movement](../inventory/stock-movements.html) tagged with a maintenance reference type, so all your existing lot/serial tracking and location accounting continues to apply unchanged. What the module adds on top is the catalog work to make the right parts available at the right time.

## Asset-to-part associations

You can declare which parts which asset (or asset class) typically consumes. Manage these under **Maintenance → Asset Spare Parts**: the list shows every association with its scope, part, typical quantity, usage pattern, and preferred supplier; the **New** button opens a dedicated page where each association says:

- The **scope** — one specific asset, or a whole asset class. Exactly one of the two.
- The product (and optionally variant) — the spare-part SKU.
- The typical quantity and unit per intervention. This is a **planning hint** — it feeds part suggestions and demand forecasts, and never reserves stock by itself.
- The **usage pattern** — *Every PM* (consumed every preventive service), *Every Nth PM* (every Nth, e.g., gaskets every 4th oil change — the N must be at least 2), *On failure* (only when this part fails), *On inspection* (gathered observationally — air filter checked every time, replaced when dirty).
- An optional preferred supplier, used to default the supplier on auto-emitted purchase requisitions.

Associations attached to an asset class apply to every asset in that class — useful for parts that are class-uniform (every CNC mill takes the same way-cover); associations attached to a specific asset override (this one press has the unique gasket because it's a custom retrofit).

Every asset's detail page also carries a **Parts** tab showing the parts that cover it: the **Scope** column names the machine itself for a row attached to it directly, and reads *Class:* followed by the class name for a row it inherits from its class. Click any row to open and edit the association.

The **Asset spare parts** list narrows on its **filter button** by **Asset**, **Asset Class**, **Product**, **Usage pattern**, **Preferred supplier**, **Active** or a typical-quantity range ([Working with lists](../getting-started/working-with-lists.html#narrowing-the-list)).

## Maintenance kits

A **kit** is a transactional convenience: a named bundle of spare parts that a technician issues to a WO in one click. The forklift 250h kit might bundle engine oil + oil filter + grease + tire gauge. The kit detail page exposes a **Components** tab where each component has:

- Product (and optionally variant), quantity, unit.
- A sequence number for display order.
- An `is_optional` flag — the technician decides per-issue whether to consume.

Issuing a kit expands the components, picks lots FEFO/FIFO from the source warehouse, and emits one stock movement per kit line. The kit itself is a definition, not stock — there's no "kit on hand."

### Preview expansion (dry run)

The kit detail page has a **Preview expansion** button next to Edit. It opens a side drawer that calls the same expansion engine the real kit issue uses — but writes nothing. For every active component you see:

- The component's product, required quantity, and unit.
- The estimated **unit cost** (taken from `products.standard_cost`).
- The **line estimate** = required quantity × unit cost.
- The **available quantity** at the work order's source warehouse (only when a work order is selected; otherwise availability is hidden).
- A **Shortage** badge when required quantity > available. Mandatory shortages would block a full kit issue; optional shortages flag visually but never block.

A footer line sums every component into the **aggregate estimate** — what `actual_parts_cost` will roll up to on the work order once the real kit issue posts (before lot-cost adjustments). The drawer also lets you pick a work order from your active list so the preview is scoped to its warehouse; when no work order is chosen, the unit-cost estimate still renders but availability is suppressed.

Use it before pressing "Issue kit" to spot shortages, decide whether to short-issue or wait for back-order receipts, and confirm the cost the kit will post is the one you expected.

Each planned WO part remembers whether it came from a kit. The `issue_method` on the part line is either:

- **Manual** — the default; the technician issues each unit individually via the per-part issue button.
- **Kit issue** — set when the line came from a kit expansion; the entire kit issues in one click via the work order's "Issue kit" action.

Mixing isn't allowed on a single line — once a line was created from a kit, all subsequent issues on it run through the kit-issue path. Picking the same part ad-hoc on the same WO creates a separate Manual line.

The **Maintenance kits** list filters by **Asset Class** and **Active**.

On a kit, the **Components** tab narrows by **Part**, **Unit**, **Optional**, **Active** or a quantity range.

## Critical-spare policies

Some spares matter so much that running out costs more than carrying stock — the unique gasket for that one critical press, the proprietary bearing the OEM takes 6 weeks to ship. A **critical-spare policy** declares per-product / per-warehouse:

- A **minimum quantity** — when on-hand minus reserved drops below, action is needed.
- A **maximum quantity** — when topping up, order back to here.
- An optional preferred supplier and lead time.

A daily background job walks every active policy. When on-hand minus reserved drops below the minimum (parts sitting in a repair pool don't count toward on-hand), it drafts a purchase requisition for (max − on_hand) units against the preferred supplier. The line is priced from that supplier's own catalogue row — the last price actually paid, or the agreed price where nothing has been bought yet — and where the supplier has a row for the specific variant rather than the whole product, that row is the one used. Where that supplier has no price on file — nothing listed for the part, or a listed zero, which is not a price — the requisition is still raised and the line simply arrives with **Estimated Price** blank. That is not a failure: the line waits on a price exactly as [an approved requisition line does](../procurement/purchase-requisitions.html), and the buyer fills the figure in when placing the order. The PR is created with priority `HIGH`, status `DRAFT`, requested-delivery = today + the policy's lead time, and metadata flagging it as `MAINTENANCE_CRITICAL_SPARE` so procurement knows the trigger source. The job is idempotent — if a DRAFT requisition already exists for the same product, variant, and warehouse, it doesn't create a duplicate.

The **Critical spare policies** list filters by **Product**, **Warehouse**, **Preferred supplier**, **Active**, or a minimum, maximum or lead-time range — `Lead time (days)` above 14 is the list to review before a long holiday.

## Reservation policy

When an MWO is released:

- Non-optional parts are reserved against the source warehouse stock (parts sitting in a repair pool are excluded — they aren't available yet).
- Reserved quantity counts against the on-hand for other reservations (so two parallel WOs can't both reserve the last unit).
- Reservation is keyed by (product, variant, warehouse, lot if lot-tracked). Partial reservations are allowed — if only 3 of 5 needed are available, the WO releases with 3 reserved and the planner sees the shortfall.

Reservations release on:

- Part issuance (reservation decrements, on-hand decrements).
- Part-issue reversal (reservation increments back).
- Work-order cancellation (all remaining reservations release).
- Work-order completion if anything still reserved (it didn't get used, so it's freed).

## Repair pool

Some parts are repairable rather than disposable: an electronic board, a precision gauge, a motor. The flow:

- The technician returns the failed part with `repair_required = true`. The movement is `MAINTENANCE_RETURN` to a sub-location flagged `metadata.is_repair_pool = true`.
- Both reservation (at WO release) and the FEFO issue picker ignore repair-pool stock — these aren't available for new WOs yet.
- After repair (either in-house, with a maintenance WO of its own, or sent out as an external service), the repaired part posts back to general stock with `is_repaired = true`. The new unit cost is the original lot cost plus a per-unit share of the WO's other cost (`actual_other_cost`) — that is, the total repair cost divided across the returned units, not the full amount added to each unit.

Source: https://docs.beelocity.com/en/maintenance/spare-parts/index.mdx
