Key takeaways
A filter leaves the storeroom once and never returns. A gearbox leaves, fails, comes off the machine, goes away for repair and arrives back on the same shelf months later.
That difference breaks every piece of quantity based stock logic. Quantity on hand, reorder point and consumption per work order all assume the part is gone.
A rotable is not gone, it is somewhere in a loop. So the record you need is a serialised unit with a state machine on it, plus the events that move it.
Our guide to repairable versus consumable spare parts owns the concept, the economics and why a float exists. This page does not repeat that argument.
This page specifies the record: the fields, the states, the allowed transitions, the pool arithmetic and the year end reconciliation.
Three neighbouring pages own the rest. The downtime consequence of a missing part, including fill rate and the wait reason code, belongs to spare parts availability and downtime.
The storeroom as a whole is spare parts management. Where an installed rotable hangs is the asset hierarchy data model, and the removal itself the equipment failure record data model.
A rotable is three things at different moments, and most systems model one. Fitted, it behaves like an asset, with a position, a meter and a history.
On the shelf it is stock, with a location and a value. In the repair loop it is the subject of a work order, with labour, cost and a test certificate.
Plants that struggle with rotables hold them as a part number with a quantity, and keep the serials in a spreadsheet beside it.
| Record | What it is |
|---|---|
| Rotable pool | The part number and its policy: how many, what turnaround, when to scrap |
| Rotable unit | One serialised physical unit, with a state and a life history |
| Exchange event | One swap: what came off, what went on, when and by whom |
| Repair order | What happened to the removed unit, what it cost, what came back |
The pool holds the policy, the unit holds the truth, the exchange holds the moment, the repair order holds the money.
The pool is the part number level record. It carries no quantity of its own, because the quantity is derived by counting units in the right states.
| Field | Type | Req. |
|---|---|---|
| pool_ | key | Yes |
| part_ | ref | Yes |
| is_ | bool | Yes |
| serialised | bool | Yes |
| positions | int | Yes |
| spares_ | int | Yes |
| pool_ | int | Derived |
| mtbr_ | num | Yes |
| tat_ | int | Yes |
| fill_ | num | Yes |
| replacement_ | num | Yes |
| scrap_ | num | Yes |
| max_ | int | No |
| exchange_ | enum | Yes |
| interchange_ | ref | No |
| owning_ | ref | Yes |
Six of those carry the weight. Skip them and you size the pool by argument instead of arithmetic.
| Field | Why it exists |
|---|---|
| positions | How many units are fitted when every machine runs |
| mtbr_ | Mean time between removals for one fitted unit |
| tat_ | Days from removal to serviceable on the shelf |
| fill_ | Share of removals that must find a unit on the shelf |
| scrap_ | Cumulative repair cost, as a share of replacement, that ends a life |
| interchange_ | Pools whose units can cover each other |
pool_size is derived and never typed. It counts units in any state except scrapped, and a typed copy will disagree with the serials within a month.
This is the serialised individual, and the whole model hangs on it. One row per unit, from purchase to scrap.
| Field | Type | Req. |
|---|---|---|
| unit_ | key | Yes |
| serial_ | text | Yes |
| pool_ | ref | Yes |
| state | enum | Yes |
| state_ | ts | Yes |
| location_ | ref | Yes |
| ownership | enum | Yes |
| asset_ | ref | No |
| position_ | text | No |
| installed_ | ts | No |
| removed_ | ts | No |
| meter_ | num | No |
| meter_ | num | No |
| life_ | num | Derived |
| repair_ | int | Derived |
| cum_ | num | Derived |
| build_ | text | No |
| warranty_ | date | No |
| acquired_ | date | Yes |
| scrapped_ | ts | No |
| scrap_ | enum | No |
Five of these never make the first version, and all five cost money later.
| Field | Why it exists |
|---|---|
| state_ | Ages the state, so a unit cannot sit unnoticed in transit for a year |
| ownership | Plant, vendor exchange or customer, so the count means something |
| life_ | Hours or cycles across every spell fitted, not just this one |
| cum_ | Every repair this serial has had, in money |
| build_ | The modification level, so a unit is not fitted where it does not fit |
life_meter makes a rotable comparable with an asset. A unit fitted for three spells has three readings in and three out, and its life is the sum of the differences.
An exchange is one moment: a unit comes off a position and another goes on. It is where most models are thin.
| Field | Type | Req. |
|---|---|---|
| exchange_ | key | Yes |
| pool_ | ref | Yes |
| asset_ | ref | Yes |
| position_ | text | Yes |
| unit_ | ref | Yes |
| unit_ | ref | Yes |
| exchanged_ | ts | Yes |
| work_ | ref | Yes |
| failure_ | ref | No |
| meter_ | num | Yes |
| meter_ | num | Yes |
| removal_ | enum | Yes |
| exchange_ | enum | Yes |
| core_ | bool | Yes |
| core_ | date | No |
| core_ | ts | No |
| core_ | num | No |
| done_ | ref | Yes |
removal_reason separates a failure from a planned pull. A unit robbed to keep a neighbouring machine running is not a reliability event, and counting it as one ruins the removal rate.
Keep the list short: failed, suspected, planned overhaul, modification, robbed, removed in error. Six reasons a technician can pick in three seconds beat forty nobody reads.
A repair order is a work order whose subject is a part, not a machine. That detail is why many systems cannot hold rotables at all.
| Field | Type | Req. |
|---|---|---|
| repair_ | key | Yes |
| unit_ | ref | Yes |
| raised_ | ts | Yes |
| repair_ | enum | Yes |
| vendor_ | ref | No |
| despatched_ | ts | No |
| received_ | ts | No |
| quoted_ | num | No |
| approved_ | ref | No |
| approved_ | ts | No |
| actual_ | num | No |
| work_ | text | No |
| test_ | text | No |
| outcome | enum | Yes |
| warranty_ | bool | Yes |
| back_ | ts | No |
| tat_ | num | Derived |
tat_days runs from the removal to back_in_store_at, not from the vendor's dates. A vendor measuring goods in to goods out reports a true number that is half the one you live with.
outcome has three values and no fourth: serviceable, beyond economic repair, scrapped. A repair order with no outcome is a unit nobody can find.
Seven states cover a rotable's whole life. The last column is what most systems never model, and it is what makes an availability number honest.
| State | Moved by | Stock? |
|---|---|---|
| Serviceable in store | Storekeeper | Yes |
| Installed | Technician | No |
| Removed unserviceable | Technician | No |
| Awaiting repair | Planner | No |
| In repair | Vendor or shop | No |
| In transit | Carrier | No |
| Scrapped | Engineer | No |
One state out of seven counts as available stock. A system that adds up every row not installed is reporting six states as if they were the first.
In transit is the state plants leave out, and it hides the longest. A unit in a crate is neither on the machine nor on the shelf, and left unmodelled it sits wherever looks tidiest.
A transition that records nothing can be reversed by anyone, with no trace. Each move below has a required payload.
| Move | Must record to leave |
|---|---|
| Serviceable to installed | Asset, position, exchange id, meter in |
| Installed to removed unserviceable | Meter out, removal reason, failure id if failed |
| Removed to awaiting repair | Fault note, repair or scrap decision |
| Awaiting repair to in transit | Despatch note, carrier, exchange type |
| In transit to in repair | Vendor receipt date, repair id |
| In repair to in transit | Actual cost, work done, test cert |
| In transit to serviceable | Goods receipt, inspection, shelf location |
| Any state to scrapped | Scrap authority, cum repair cost, disposal |
| Installed to serviceable | Meter out, reason planned, no fault found |
The last move is legal only when the unit was pulled for access or a modification, then tested. Scrapping is legal from anywhere, because a unit can be condemned on inspection.
Notice that no transition fires by itself. A person moves a unit and the system records what they did, the same rule that governs a work order.
Pool size is a queueing question, not a budget question. Two inputs matter: how often a unit comes off, and how long it takes to come back.
Work it through on one pool. ROT‑4471 is the drive gearbox GBX‑160 fitted to twelve mixer positions in a food plant.
| Input | Value |
|---|---|
| Fitted positions | 12 |
| Mean time between removals | 24 months (assumed) |
| Removals a year | 12 ÷ 2 = 6.0 |
| Repair turnaround | 60 days (assumed) |
| Target fill rate | 95% |
| Replacement cost | 9,400 euro |
Two of those are assumptions, tested later. The 24 month interval and the 60 day turnaround came from the maintenance manager's memory, not from data.
Six removals a year, each away 60 days, means the loop holds 6.0 multiplied by 60 divided by 365 units at any moment.
That is 0.99 units, the pipeline quantity, and it is a long run average rather than a ceiling.
If the number away were always 0.99 you would hold one spare and never be short. Removals arrive at random and cluster.
Model the number away as a Poisson variable with that mean. The fill rate is the chance that it stays at or below the spares you hold.
| Spares held | Fill rate |
|---|---|
| 0 | 37.3% |
| 1 | 74.1% |
| 2 | 92.2% |
| 3 | 98.2% |
Two spares miss the 95% target, three clear it. The pool is 12 fitted plus 3 spares, 15 units.
A stricter convention counts the arriving removal too and adds one spare to every answer. Pick one and write it on the pool record.
Hold the removal rate at 6.0 a year and change only the turnaround.
| Turnaround | Units away | Spares for 95% |
|---|---|---|
| 30 days | 0.49 | 2 |
| 60 days | 0.99 | 3 |
| 92 days | 1.51 | 4 |
| 120 days | 1.97 | 5 |
Halving the turnaround to 30 days saves one spare, 9,400 euro of capital. Doubling it to 120 days costs two more, 18,800 euro, for the same machines and the same failure rate.
At 120 days, four spares give 94.98% and miss the target on the exact figure. A number that rounds to 95.0% has not reached 95%.
Nothing in that arithmetic used the price of the unit. Cost decides whether you can afford the answer, never what the answer is.
Two units of one part number can have completely different histories, and a part number cost report averages them into one harmless figure.
ROT‑4471 has a replacement cost of 9,400 euro and a scrap threshold of 65%, which is 6,110 euro of cumulative repair.
SN‑00318 has been repaired four times, and each repair looked reasonable on its own quote.
| Repair | Cost, euro |
|---|---|
| First | 1,150 |
| Second | 1,320 |
| Third | 1,880 |
| Fourth | 2,240 |
| Cumulative | 6,590 |
| Share of replacement | 70.1% |
The total passed the 6,110 euro threshold at the fourth repair, unseen, because each quote was compared with 9,400 euro rather than with the running total.
The fifth quote is 2,050 euro. Approving it takes the serial to 8,640 euro, or 91.9% of a new one.
SN‑00322 carries the same part number and a very different history.
| Measure | SN-00318 | SN-00322 |
|---|---|---|
| Repairs | 4 | 2 |
| Cum cost | 6,590 | 2,320 |
| Of replacement | 70.1% | 24.7% |
| Days run | 1,180 | 2,060 |
| Cost a day | 5.58 | 1.13 |
| Decision | Scrap | Keep |
SN‑00318 costs 5.58 euro for every day it runs, SN‑00322 costs 1.13 euro, almost five times less, for the same part in the same plant.
Now average them the way a part number report does. The two serials carry 8,910 euro between them, so the average is 4,455 euro, or 47.4% of replacement, under the threshold.
The average says the part number is fine, and both underlying decisions are then wrong. The field that prevents it is cum_repair_cost on the unit, summed from actual_cost on that serial's repair orders.
Scrap when any one of three conditions holds, and record which one fired in scrap_reason.
Some vendors do not repair your unit. They ship a serviceable one from their own pool and expect the failed unit back, which they call the core.
| Exchange type | What happens to the serial |
|---|---|
| Repair and return | The same serial comes back, life and cost carry on |
| Vendor exchange | A different serial arrives, the old one leaves the pool |
| Advance exchange | The replacement arrives first, a core is owed |
The first assumption that breaks is identity. Under vendor exchange the unit you get back is not yours, so a system waiting for SN‑00712 to return will wait forever.
The second is the count. Under advance exchange the replacement lands before the failed unit leaves, so the plant holds both.
Take pool ROT‑4620, a drive motor with nine units. The vendor ships SN‑00905 on day zero against failed unit SN‑00712.
| Event | Day |
|---|---|
| Vendor ships SN-00905 | 0 |
| Fitted, SN-00712 removed | 3 |
| SN-00712 despatched | 9 |
| Vendor books it in | 14 |
| Core accepted, charge cleared | 23 |
| Days the count reads 10 | 23 |
For 23 days the pool holds ten serials and owns nine. A report that counts rows reads one unit too high, every time.
At seven exchanges a year that is 161 unit-days, or 0.44 of a unit the plant does not own. On a float of three spares, that is 15%.
The field that stops it is core_owed, paired with ownership on the unit. While it is true the incoming unit belongs to the vendor and is excluded from the count.
core_due and core_charge close the loop on the money. Miss the return window, typically 30 days, and the vendor invoices the full core charge, here 4,200 euro.
ROT‑4471 from 2025-07-01 to 2026-06-30, which is 365 days. The pool opened with 15 units: twelve fitted and three on the shelf.
The arrangement is repair and return, so the same serials come back and the year reconciles unit by unit.
SN‑00318 was scrapped on 2026-03-31, so it was in the pool for 274 of the 365 days. Every other serial was in the pool for all 365.
| Serial | On machine | Off machine |
|---|---|---|
| SN-00311 | 365 | 0 |
| SN-00312 | 365 | 0 |
| SN-00313 | 274 | 91 |
| SN-00314 | 365 | 0 |
| SN-00315 | 231 | 134 |
| SN-00316 | 365 | 0 |
| SN-00317 | 291 | 74 |
| SN-00318 | 96 | 178 |
| SN-00319 | 365 | 0 |
| SN-00320 | 189 | 176 |
| SN-00321 | 365 | 0 |
| SN-00322 | 365 | 0 |
| SN-00323 | 155 | 210 |
| SN-00324 | 340 | 25 |
| SN-00325 | 165 | 200 |
| Total | 4,296 | 1,088 |
Pool unit-days are 14 multiplied by 365, plus 274 for the scrapped serial, which is 5,384. It reconciles: 4,296 plus 1,088 is 5,384.
Twelve positions across 365 days are 4,380 position-days. Units were fitted for 4,296, so a position stood empty 84 days, or 1.9% of position time.
Those 84 days are machines that could not run for want of a gearbox. What that costs in minutes belongs to spare parts availability and downtime.
The 1,088 off-machine unit-days split across four states. This split decides the availability number.
| State | Unit-days |
|---|---|
| Serviceable in store | 358 |
| Awaiting despatch | 118 |
| In transit | 164 |
| In repair | 448 |
| Total | 1,088 |
The bottom three lines are the repair loop and add to 730 unit-days. Only the top line, 358 unit-days, was a unit anybody could have fitted.
Define pool availability as the share of pool unit-days in which a unit could cover the next removal. Two systems compute it from the same rows and disagree.
| Method | Unit-days | Avail. |
|---|---|---|
| Not fitted, not scrapped | 1,088 | 20.2% |
| Serviceable only | 358 | 6.6% |
| Gap | 730 | 13.6 pp |
The first is what a quantity based system does by default: anything not issued is stock. The second counts only the state that can cover a removal.
In units of the year the gap is exact. 1,088 divided by 365 averages 2.98 units on hand, 358 divided by 365 gives 0.98 units, a difference of 2.00 units.
That gap is the repair loop, to the day. It is why a plant that believes it holds three spares behaves like one holding one.
Neither number is dishonest. Reporting either without naming the states it counted is.
Seven removals happened, against the 6.0 the model predicted. Six loops completed inside the year and one ended in scrap.
| Serial | Days to serviceable |
|---|---|
| SN-00313 | 71 |
| SN-00315 | 104 |
| SN-00317 | 61 |
| SN-00320 | 132 |
| SN-00323 | 96 |
| SN-00325 | 88 |
| Mean | 92.0 |
The assumed turnaround was 60 days and the measured mean is 92.0 days, 53.3% longer. Those six loops add to 552 days, and SN‑00318 spent 178 more before it was condemned.
The removal interval was wrong in the same direction. 4,296 fitted unit-days divided by 7 removals is 613.7 days, which is 20.2 months, not 24.
Run steps one and two again with the measured numbers. Seven removals a year at a 92 day turnaround put 1.76 units in the loop at any moment.
| Spares held | Fill rate |
|---|---|
| 2 | 74.0% |
| 3 | 89.7% |
| 4 | 96.6% |
| 5 | 99.1% |
The plant holds three spares and its own history asks for four. Three buy 89.7%, not the 95% the policy demands.
Five of the seven removals found a unit on the shelf, which is 71.4%. Seven events cannot measure a 90% fill rate, so treat it as a flag.
Two doors are open. A fourth spare costs 9,400 euro, while pulling the turnaround back to 60 days restores the original design with no spare at all.
Look at where the 730 loop days went first. Awaiting despatch and transit are 282 days, or 38.6% of the loop, and neither involves a repair technician.
Ask for a demonstration, not an answer. Each takes five minutes in a real system.
Before a shortlist, read what is a CMMS and equipment maintenance software, then the CMMS data model.
Labour on a repair order follows the maintenance labour data model, and the removal should raise a record in the equipment failure record data model.
Everything above is a specification to test a shortlist against, not one product's feature list. Here is the honest split.
What Fabrico holds today: an inventory catalogue with min and max levels, deliveries, stock-takes, and consumption booked against the work order that used it.
Parts and machines carry QR codes that technicians scan from the iOS, Android or web app. Suppliers are listed in the catalogue, without supplier messaging.
Work orders are raised and confirmed by your team, never by the system on its own. Approvals, the audit log and analytics with Excel export sit behind them.
The REST API and the SAP and ERP connectors are how a separate serialised repair loop would exchange data with it.
What Fabrico does not have today: serial number tracking of individual units, a rotable pool, an exchange record, a repair order whose subject is a part, and core tracking.
None of the fields above exist in Fabrico under those names. Fabrico also does not do predictive maintenance, production planning or scheduling, and it does not reorder parts on its own.
Where it earns its place is the layer underneath: asset history, the work orders that removed and refitted the unit, and parts consumed per job (see spare parts management).
Want to see how far your rotables fit a real storeroom system? Book a 30 minute demo with a Fabrico consultant, no commitment, or contact us with your questions.
unit_id, serial_no, pool_id, state, state_since, location_id, ownership, asset_id, position_code, installed_at, removed_at, meter_in, meter_out, build_standard, warranty_until, acquired_at, scrapped_at and scrap_reason. life_meter, repair_count and cum_repair_cost are derived from the exchange and repair records and should never be typed.
By serial number and by state, never by quantity, because a rotable returns to stock instead of being consumed. Seven states cover its life, and only one of them, serviceable in store, counts as available stock.
Multiply removals per year by the repair turnaround in years to get the units away at any moment, then hold enough spares that the chance of exceeding it meets your fill rate target. In the worked example, 6.0 removals a year at 60 days needs 3 spares for 95%, and the same pool at 120 days needs 5.
When cumulative repair cost on that serial plus the current quote passes your threshold, typically 65% of replacement. In the worked example SN-00318 reached 6,590 euro against a 9,400 euro replacement, which is 70.1%, while SN-00322 at 2,320 euro was still worth repairing.
A core is the failed unit you owe a vendor that shipped a replacement in advance, and core tracking is the core_owed flag, due date and charge that follow it until the vendor accepts it. Without the flag the pool count reads one unit too high for every open exchange, which was 23 days per exchange in the worked example.