Work Order Lifecycle
A work order is a unit of dispatchable work. It's born when there's a job to do, it travels through a series of statuses as the work happens, and it ends in either completed (and eventually billed) or cancelled. The full set of statuses, who can move between them, and what each one actually means is below.
The eight statuses
| Status | Meaning |
|---|---|
unassigned | Created, but no technician picked. Sits in the dispatch queue. |
pending | Assigned to a technician, but the tech hasn't started yet. |
ongoing | Tech has started. Clock is running. |
waiting_approval | Tech submitted the work for office review (parts used, photos, signoff). |
paused | Started but interrupted — waiting on parts, customer access, weather. |
cancelled | Closed without doing the work. |
completed | Office approved the submission. Work is done. |
billed | An invoice has been issued for this work order. |
The statuses are codified — you can't add new ones from settings. The names you see in the UI are exactly the labels above.
The transition graph
Not every status can move to every other status. Transitions are gated by role:
Technician transitions
A technician (with work_orders.edit but not work_orders.supervise) can move work orders along the happy path:
pending->ongoing(start work)ongoing->waiting_approval(submit for review)ongoing->paused(pause work)paused->ongoing(resume work)
That's it. A technician can't cancel, can't approve their own submission, and can't reopen a completed work order. This is intentional — the office controls the gates that cost money or close the job.
Supervisor / office transitions
A supervisor (work_orders.supervise) gets the technician transitions plus:
pending->cancelledongoing->cancelledpaused->cancelledwaiting_approval->ongoing(reject the submission, send back)waiting_approval->completed(approve and close)waiting_approval->cancelledcompleted->billed(after invoicing — manual)
There's no transition out of cancelled or billed. Once a work order ends, it ends.
Visualizing the path
Most work orders follow a simple path:
unassigned -> pending -> ongoing -> waiting_approval -> completed -> billed
The branches off that line handle the messy real-world cases:
- Pause and resume —
ongoing -> paused -> ongoing - Send back for fixes —
waiting_approval -> ongoing -> waiting_approval - Cancel — at any point during the work, the office can take the work order out of play
Status history
Every transition writes a row to the work order status history. Each row captures:
- The from and to status
- Who triggered the transition
- When it happened
- Optional note ("paused — waiting on R32 charge")
The history isn't editable — once a transition is logged, it's logged. This makes the audit trail trustworthy when you need to defend timing on a billing dispute or a warranty claim.
Why waiting_approval exists
The waiting_approval status is the one that confuses new operators most often. The temptation is to skip it — let the tech mark the work completed and move on. TuffOps doesn't allow that, for a few reasons:
- Submissions usually include line items the tech added on-site (parts used, extra labor). The office needs a chance to review these before they hit a customer invoice.
- Photos and customer signoff get gathered at submit-time. The office checks they're complete.
- If the work needs the customer's approval (large parts, scope changes),
waiting_approvalis where it sits while approval is collected.
Skipping the gate would mean techs implicitly approve their own work. Keeping the gate keeps office authority over what's billed.
When a work order ends
A work order leaves the active pipeline in one of two ways:
cancelled— the work didn't happen (or won't). No invoice. No further action.completed->billed— the work happened, the office approved it, and the office has marked it billed.
billed is a manual transition. After an invoice is created against a completed work order, a supervisor uses the Mark as Billed action on the work order to move it to billed. This separation keeps the invoicing surface (which talks to your external billing system) independent from the work-order status, so you can keep track of which invoiced jobs you still consider open versus closed without coupling those two state machines.