Key takeaways
We have three pages that define the metrics: wrench time, overall labor effectiveness and maintenance cost as a percent of RAV.
This page specifies the single record all three are computed from, field by field, with the rules that decide what each number means.
It is worth being honest about why it exists. Nobody searches for a labour booking schema, and this page is here because it is the missing table under several pages that people do read.
A labour booking is one row that says: this person, on this job, spent this many minutes doing this kind of work.
The grain is one row per person, per activity, per pay band, per job. Any coarser and you lose a distinction you will be asked for within a month.
| Field | Why it is mandatory |
|---|---|
| booking_ | Own key. One row per person per activity |
| wo_ | The job the time is charged to |
| technician_ | A real row, never a typed name |
| activity_ | What kind of time this is |
| start_ | Start, with the time zone stored |
| end_ | End, with the time zone stored |
| booking_ | Stored, not only derived |
| labour_ | The rate bucket this hour belongs to |
Eight fields, and every one of them is load bearing. Drop activity_code and wrench time stops existing as a measurement.
Drop labour_class_id and a fitter's hour and an apprentice's hour cost the same. Drop the time zone and a night shift crossing a clock change books negative minutes twice a year.
| Field | Rule |
|---|---|
| pay_ | Set from the shift calendar, never typed |
| rate_ | The rate used, frozen at approval |
| cost_ | minutes ÷ 60 × rate_ |
| cost_ | base, loaded or invoiced |
| approved_ | Supervisor, above an agreed threshold |
| approved_ | When the hours were accepted |
| corrected_ | The booking this row replaces |
| invoice_ | Mandatory when the class is a contractor |
rate_snapshot is the field that stops last year's closed work orders from changing price when finance raises rates in April.
Without it, every historic cost report is recomputed at today's rate, and a trend line that should be flat bends upwards on its own.
corrected_from matters more than it looks. A technician who books four hours to the wrong work order must be able to fix it without anyone deleting a row.
| Field | When it is used |
|---|---|
| task_ | When the work order has named tasks |
| asset_ | Copied from the work order, for reporting |
| headcount | 1 by default. Above 1 only for a uniform crew |
| entry_ | timer, manual or imported |
| entered_ | Who typed it, when not the technician |
| wait_ | The part request this waiting time belongs to |
| is_ | Contract or inter-company work |
| skill_ | When one person books under two classes |
entry_method is the quiet quality field. A month where 90% of bookings were typed the following week is a month whose durations are round numbers and whose activity split is invented.
The obvious design is to compute minutes as end_ts minus start_ts and store nothing.
| Case | What breaks |
|---|---|
| Booked later as a duration | There is no honest start_ |
| Split across a pay band | Segment minutes do not equal the parent span |
| A break inside the job | Elapsed time is longer than worked time |
Store the minutes the plant is charged for, and keep the timestamps as evidence of when the work happened. Treating one as a formula over the other is how a lunch break ends up costed as repair time.
A booking is only as good as the three rows it references.
| Field | What it holds |
|---|---|
| labour_ | Key: FIT, ELE, APP, CON |
| class_ | Fitter, Electrician, Apprentice, Contractor |
| valid_ | A rate has a life. Old bookings keep the old rate |
| valid_ | Null while the rate is current |
| base_ | Hourly pay rate, owned by finance |
| loaded_ | Multiplier for employment on-costs |
| overhead_ | Fixed addition per hour worked |
| is_ | Cost comes from an invoice, not a rate |
Say this out loud before anyone builds it: a rate is a finance input, not a maintenance measurement.
The maintenance system owns the hours, the person and the activity. The money per hour is somebody else's number, and it arrives from the general ledger or the payroll system.
That has a practical consequence. If your policy forbids pay data in a maintenance tool, put only the class code on the booking and do the cost join in finance.
| Field | What it holds |
|---|---|
| technician_ | Stable key, survives a name change |
| display_ | What the app shows |
| default_ | The class most of their hours book under |
| crew_ | The team the person books within |
| shift_ | Which calendar defines their pay bands |
| employment_ | employee, agency or contractor |
| active_ | First day bookings are allowed |
| active_ | Last day. Never delete a leaver |
Never delete a technician who leaves. Close them with active_to, because three years of bookings point at that row and a warranty question may need the name.
shift_pattern_id is the field that makes the overtime split possible at all, and it comes from the shift calendar, not from the person.
| Field | What it decides |
|---|---|
| activity_ | Short key, picked in one tap |
| category | hands-on, support, waiting, indirect |
| counts_ | The single field wrench time depends on |
| requires_ | Waiting codes must carry a reason |
| links_ | Optional pointer to another record |
| charge_ | Whether this code needs a work order |
| active | Retire a code, never reuse its key |
counts_as_wrench is the most consequential boolean in maintenance reporting, and almost every plant leaves it as an opinion held at report time.
Set it once, on the code, under a named owner. Then print the list of codes that carry it in the header of every wrench time report.
Three different quantities get called "the technician's time", and the confusion between them is why labour KPIs rarely survive a challenge.
| Quantity | What it counts |
|---|---|
| Clock time | Paid attendance, from the shift record |
| Booked time | Minutes written against a code |
| Wrench time | Booked minutes whose code is hands-on |
Clock time belongs to attendance and payroll. It is the hours the plant paid for, and it does not know what anyone was doing.
Booked time is what the maintenance system holds. It is always less than or equal to clock time, and the difference is the part of the day nobody wrote down.
Wrench time is a subset of booked time, filtered by counts_as_wrench. It is a numerator, and it is meaningless until you name its denominator.
| Measure | Formula |
|---|---|
| Booking coverage | booked ÷ attendance × 100 |
| Wrench time, attendance basis | hands-on ÷ attendance × 100 |
| Wrench time, work order basis | hands-on ÷ work order booked × 100 |
| Indirect share | indirect ÷ attendance × 100 |
Booking coverage is the measure to build first, before anyone quotes a wrench time at all.
It answers whether the team writes down what it did. A wrench time computed on 60% coverage is a statement about 60% of the month, whatever the report header claims.
The two wrench time rows are both defensible and they are not interchangeable. The first says "of every paid hour", the second says "of every hour we charged to a job".
| Quantity | Measurable without a stopwatch |
|---|---|
| Attendance hours | Yes, from clock in and clock out |
| Booked hours | Yes, if a booking is required to close |
| Split by activity | Only to the granularity people code |
| True tool-in-hand minutes | No. That needs work sampling |
This is the honest line most vendors will not give you. A booking-derived wrench time is an approximation, and its error is the size of the blocks people code as one lump.
A technician who books a single four hour WRK row for a job that contained forty minutes of walking has told you the truth about the job and a lie about the wrench time.
A classical work sampling study still beats both, because an observer records what is happening at a random instant with no incentive attached. Use bookings for the trend and a study when you need the level.
Take one repair: a seized bearing on a conveyor drive, four hours, one fitter, no contractor on site.
| Input | Value |
|---|---|
| Fitter base rate | 18.00 EUR per hour |
| Loaded factor | 1.40 |
| Overhead per hour | 9.00 EUR |
| Contractor rate | 55.00 EUR per hour |
| Contractor call-out | 45.00 EUR, fixed |
| Basis | Arithmetic and result |
|---|---|
| Internal base rate | 4.0 × 18.00 = 72.00 EUR |
| Fully loaded cost | 18.00 × 1.40 = 25.20, plus 9.00 = 34.20 per hour 4.0 × 34.20 = 136.80 EUR |
| Contractor invoice | 4.0 × 55.00 = 220.00, plus 45.00 = 265.00 EUR |
The same four hours of the same repair cost 72.00, 136.80 or 265.00 EUR. The loaded figure is 1.90 times the base figure, and the contractor invoice is 3.68 times it.
The loaded factor of 1.40 covers employer social contributions, paid holiday, sick cover and the non-productive time the plant pays for anyway.
The overhead per hour of 9.00 EUR covers supervision, the workshop, vehicles, tools, personal protective equipment and training.
Neither is a maintenance number. Both are given to maintenance by finance, and they should arrive with a date and an owner attached.
| Report | Basis to use |
|---|---|
| Cost per work order | Fully loaded, or the invoice |
| Maintenance cost against RAV | Fully loaded, or the invoice |
| Labour cost per unit produced | Fully loaded, or the invoice |
| Make or buy against a contractor | Fully loaded only |
| Hours variance inside one team | Hours, no rate at all |
The base rate belongs in no maintenance report. It is a payroll figure that answers what one person was paid, and it is the wrong answer to every question a maintenance manager asks.
The make or buy row is where the damage happens. Compared at the base rate, the contractor looks 3.68 times more expensive than doing it in house.
Compared at the fully loaded rate, the contractor is 265.00 against 136.80, which is 1.94 times. That is a different decision, and it is the correct one.
On this single job, using the base rate understates in-house labour by 64.80 EUR. Multiply that by a few hundred jobs a year before you argue about whether it matters.
The percentage of replacement asset value is the report that punishes this hardest, because a single basis has to hold for years (maintenance cost as a percent of RAV).
A booking that starts inside a normal band and ends inside an overtime band is two bookings wearing one row.
Take a fitter called out at 14:00 who finishes at 19:30, with the normal band ending at 18:00 and overtime paid at 1.5 times base.
| Segment | Hours and rate |
|---|---|
| 14:00 to 18:00, normal | 4.0 h at 34.20 = 136.80 EUR |
| 18:00 to 19:30, overtime | 1.5 h at 46.80 = 70.20 EUR |
| Split total | 5.5 h = 207.00 EUR |
| One row at the normal rate | 5.5 h at 34.20 = 188.10 EUR |
The overtime hourly figure is built from the base pay only: 18.00 × 1.5 = 27.00, then × 1.40 = 37.80, then plus 9.00 overhead = 46.80 EUR.
The premium applies to pay, not to the workshop. Your vehicle does not cost half as much again because the clock passed six.
That detail is worth arguing about once and then writing down. A plant that multiplies the whole loaded rate by 1.5 gets 51.30 EUR per hour and overstates every call-out.
One row at the normal rate reports 188.10 EUR against a true 207.00 EUR, an understatement of 18.90 EUR.
That is 9.13% of the cost of this job, hidden inside a record that looks complete and balances against attendance.
The per hour gap is 46.80 minus 34.20, which is 12.60 EUR. In the worked example below, the team books 34.0 overtime hours in a month.
Unsplit, that month's labour cost is understated by 34.0 × 12.60 = 428.40 EUR. Scale it across a year and four crews before deciding it is a rounding error.
| Band | Who sets it |
|---|---|
| normal | Shift pattern of the technician |
| overtime_ | Calendar rule on hours past the shift |
| overtime_ | Calendar rule, deeper band |
| night | Calendar rule on the clock |
| weekend | Calendar rule on the date |
| holiday | Plant holiday table |
Let the person type the band and the split becomes a negotiation. Let the calendar derive it and the split becomes arithmetic.
Wrench time only means something if the non-wrench time is coded into named categories.
Leave it as a residual and you get one undifferentiated block called "the other 44%", which no manager has ever been able to act on.
| Code | Category and meaning |
|---|---|
| WRK | Hands-on: the repair or the PM task |
| DGN | Hands-on: fault finding at the machine |
| TST | Hands-on: test, run up and handover |
| TRV | Support: travel between shop and asset |
| FCH | Support: fetching parts or tools |
| DOC | Support: permits, records, handover notes |
| WAI | Waiting: machine, permit or another trade |
| WPT | Waiting: a spare part |
| IND | Indirect: training, meetings, standby |
Three codes carry counts_as_wrench: WRK, DGN and TST. The other six do not, and that single assignment defines the metric for the whole plant.
WAI and WPT must carry a reason, because a waiting hour with no reason is indistinguishable from a padded booking.
Time spent waiting for a spare part is a real, measurable category, and it is measured twice by two different records.
The part request has its own wait clock, specified in our guide to spare parts availability and downtime: it starts when the part is needed and stops when it is in the technician's hand.
| Clock | What it measures |
|---|---|
| Part request wait | The asset waited, whether or not anyone stood there |
| WPT booking | A paid technician was held and could not move on |
A part ordered at 16:00 and delivered at 01:00 gives a part request wait of 9.0 hours. If the technician was released at 17:30 and went to another job, the WPT booking is 1.5 hours.
Both numbers are correct and they answer different questions. The 9.0 hours belongs to asset availability, the 1.5 hours belongs to labour productivity.
Never add them, and never let one substitute for the other in a report. Link them with wait_ref so the two can be reconciled when somebody inevitably asks why they differ.
Three technicians attend one job. There are two ways to record it, and they are not equivalent.
Job WO‑26‑0412, a gearbox change, with the crew on site from 14:00. The electrician arrives an hour late because of a permit.
| Field | Value |
|---|---|
| technician_ | TECH-07, the crew leader |
| headcount | 3 |
| booking_ | 180 |
| labour_ | FIT, at 34.20 per hour |
| Labour hours | 3 × 3.0 = 9.0 h |
| Cost | 9.0 × 34.20 = 307.80 EUR |
| Technician and class | Hours and cost |
|---|---|
| TECH-07, Fitter, 34.20 | 3.0 h = 102.60 EUR |
| TECH-11, Electrician, 39.80 | 2.0 h = 79.60 EUR |
| TECH-19, Apprentice, 25.80 | 3.0 h = 77.40 EUR |
| Total | 8.0 h = 259.60 EUR |
The electrician's loaded rate comes from a base of 22.00: 22.00 × 1.40 = 30.80, plus 9.00 = 39.80 EUR. The apprentice's comes from a base of 12.00: 12.00 × 1.40 = 16.80, plus 9.00 = 25.80 EUR.
| Metric | Shape A against Shape B |
|---|---|
| Labour hours | 9.0 h against 8.0 h, 12.5% high |
| Cost | 307.80 against 259.60, 18.57% high |
| Utilisation, TECH-11 | 2.0 booked hours vanish entirely |
| Wrench time per person | Not computable from Shape A |
Shape A is over by 1.0 hour and 48.20 EUR on a single three hour job, and both errors point the same way.
The utilisation damage is worse than the cost damage. TECH‑11's two hours are credited to TECH‑07, so one technician looks over-utilised and another looks idle.
Wrench time per person is simply not available. You cannot compute a per-technician figure from a row that names one person and counts three.
Allow headcount above 1 only when every member is the same labour class and worked the same minutes.
A maintenance team of four in a packaging plant, over one month of twenty working days.
| Line | Hours |
|---|---|
| 4 technicians × 20 days × 8.0 h | 640.0 |
| Less annual leave, 3 days | 24.0 |
| Plus overtime worked | 34.0 |
| Attendance | 650.0 |
640.0 minus 24.0 is 616.0, and 616.0 plus 34.0 is 650.0 hours. This figure comes from the attendance system, not from maintenance.
| Activity | Hours |
|---|---|
| WRK, repair work | 238.0 |
| WRK, PM tasks | 126.0 |
| TRV, travel | 52.0 |
| WAI, machine or permit | 36.0 |
| WPT, waiting for a part | 29.0 |
| FCH, fetching parts and tools | 21.0 |
| DOC, records and permits | 18.0 |
| Booked to work orders | 520.0 |
| Line | Hours |
|---|---|
| Booked to work orders | 520.0 |
| IND, training, meetings, standby | 82.0 |
| Total booked | 602.0 |
| Unbooked attendance | 48.0 |
| Attendance | 650.0 |
The seven work order activities add to 520.0 hours, and 520.0 plus 82.0 of indirect time is 602.0 hours booked.
Attendance was 650.0, so 48.0 hours are unbooked and booking coverage is 602.0 ÷ 650.0 = 92.62%.
Hands-on time is the two WRK lines: 238.0 plus 126.0 = 364.0 hours. Those are the only hours that carry counts_as_wrench in this scheme.
The team closed 96 work orders in the month, so direct labour per work order is 520.0 ÷ 96 = 5.42 hours. Print the 96 next to the 5.42 or the average means nothing.
| Definition | Arithmetic and result |
|---|---|
| A. Attendance basis | 364.0 ÷ 650.0 = 56.00% |
| B. Work order basis | 364.0 ÷ 520.0 = 70.00% |
Definition A says: of every hour the plant paid for, 56.00% was hands-on at a machine.
Definition B says: of every hour charged to a job, 70.00% was hands-on. Both are computed from the same bookings, by the same team, in the same month.
The gap is 14.0 percentage points. Nothing on the floor is different between the two figures.
| Item | Value |
|---|---|
| Numerator, both definitions | 364.0 h |
| Denominator A | 650.0 h |
| Denominator B | 520.0 h |
| Denominator difference | 130.0 h |
| Result difference | 14.0 points |
The denominators differ by 130.0 hours, which is the 82.0 hours of indirect time plus the 48.0 unbooked hours.
Put the same gap in hands-on hours instead. To make definition A read 70.00%, the team would have to book 0.70 × 650.0 = 455.0 hours of hands-on work.
That is 91.0 hours more than the 364.0 they actually booked, roughly eleven working days of one technician.
So the choice of denominator is worth 91.0 hours of hypothetical productivity. The definition moved the number, not the team.
Neither definition is wrong. Quoting either one without naming its denominator is, and that is the entire content of most wrench time debates.
Our page on wrench time covers what to do about a low figure. This page is about making sure the figure means one thing.
The 48.0 unbooked hours are the most interesting line in the whole example, and most reports never show them.
At the fitter's loaded rate of 34.20 EUR, they are 48.0 × 34.20 = 1,641.60 EUR of paid time with no record attached.
They are not necessarily waste. They are attendance the maintenance system cannot explain, which is a different and more fixable problem.
Print booking coverage on every labour report, right under the headline figure. A wrench time that rises while coverage falls is a paperwork trend, not a performance trend.
The same three lines feed overall labor effectiveness and the labour part of the RAV percentage, which is why one weak booking habit damages four reports at once.
It also feeds the backlog arithmetic, because a backlog in hours is only comparable with capacity in hours if both come from the same record (maintenance backlog).
Question four is the one that separates the tools. Any system will show you a wrench time, and very few will tell you which codes went into it.
Question three is the one that separates the finance-literate ones. A system that recomputes closed costs at today's rate cannot support a multi-year cost trend (equipment maintenance software).
Fabrico is an OEE platform with a full CMMS built in, so the hours your team books sit next to the machine data that explains why the job existed.
Work orders carry task level detail, an auto-timer, and allocation with an over-allocation warning above eight hours. Your team books time from the iOS, Android or web app, with QR codes to open the right record without typing.
Work shifts, approval workflows and a personal working card give each technician a defined pattern and their own job list. The analytics include per-employee productivity and task distribution alongside downtime, MTTR and MTBF by machine.
What Fabrico is not: it is not a payroll, HR or time-and-attendance system, and it is not where your employees' wage rates belong.
The rate is a finance input. Fabrico holds the hours, the person, the shift and the job, and you join them to a rate in finance using Excel export, the REST API or the SAP and ERP connectors.
Want your labour hours captured at the grain this page specifies? Book a 30 minute demo with a Fabrico consultant, no commitment, or contact us with your questions.
Create it with booking_id, wo_no, technician_id, activity_code, start_ts, end_ts, booking_minutes and labour_class_id. Close it with pay_band, rate_snapshot, cost_amount, cost_basis, approved_by, approved_ts, corrected_from and invoice_ref where a contractor was used.
Clock time is paid attendance, booked time is the minutes written against a code, and wrench time is the subset of booked minutes whose activity code is hands-on. In the worked example they are 650.0, 602.0 and 364.0 hours.
The fully loaded rate, or the contractor invoice where one exists. The base pay rate belongs in payroll, and using it understates the four hour repair above by 64.80 EUR.
As two segments, split at the band boundary by the shift calendar rather than by the technician. Kept as one row at the normal rate, the example job reports 188.10 EUR instead of 207.00 EUR.
Three, unless all three share one labour class and worked identical minutes. A single headcount row charges 9.0 hours at the crew leader's rate, 307.80 EUR, against a true 8.0 hours and 259.60 EUR.