Workflows¶
This page walks through the five concrete scenarios that cover roughly 95% of how a Thai BME department uses the repair workflow on any given day.
Scenario 1 — Corrective repair (the canonical flow)¶
A ward nurse reports a broken infusion pump. The ticket starts in Submitted and walks the standard five-stage path:
sequenceDiagram
participant W as Ward staff
participant M as BME Manager
participant T as BME Technician
participant S as BME Mgr (sign-off)
W->>+M: Submit ticket [Submitted, SLA 4h]
M->>M: Triage, assign tech [Pending Review, SLA 8h]
M->>+T: Assign
T->>T: Diagnose + repair [In Repair, SLA 24h]
T->>-S: Repair done
S->>S: Verify + sign off [Awaiting Pickup, SLA 8h]
S-->>W: Notify ready for pickup
W->>W: Collect equipment [Received - DONE] Typical timing (well-run BME team):
| Stage | Median time | SLA | Breach signal |
|---|---|---|---|
| Submitted | 1–2 h | 4 h | Manager hasn't triaged |
| Pending Review | 2–6 h | 8 h | Manager hasn't assigned tech |
| In Repair | 8–18 h | 24 h | Repair stuck / parts missing |
| Awaiting Pickup | 1–4 h | 8 h | Ward not notified |
| Received | — | — | — |
A request that breaches at any stage flips the red banner on the form, the red row decoration on the list, and the red SLA badge on the kanban card. The badge clears as soon as the stage advances because the timer resets on every transition.
Scenario 2 — PM-generated request¶
The OCA maintenance_plan cron fires daily at 04:00 and creates a maintenance.request for every equipment whose plan reaches its next-due-date. Thanks to roots_hemms_pm, those requests land in PM Scheduled instead of Submitted:
stateDiagram-v2
direction LR
[*] --> PM_Scheduled: maintenance_plan cron
PM_Scheduled --> Pending_Review: Tech acknowledges
Pending_Review --> In_Repair: Tech starts PM work
In_Repair --> Awaiting_Pickup: PM complete
Awaiting_Pickup --> Received: Equipment back in service
Received --> [*]
PM_Scheduled: PM Scheduled\n(SLA 72h — 3 days) The flow is identical from Pending Review onwards — the only difference is the entry point. The 72-hour SLA on PM Scheduled gives the BME team 3 working days to acknowledge a PM job before it shows up on the breach dashboard.
Skipping Pending Review for routine PM
For low-criticality green-tier equipment, some hospitals move PM requests directly from PM Scheduled to In Repair, skipping the manager-triage step. The workflow allows this — there is no rule blocking sequence skips. The audit log will still record the move (from=PM Scheduled, to=In Repair).
See Preventive Maintenance → Workflows for the full PM lifecycle including kind selection and plan configuration.
Scenario 3 — Stuck at Pending Review¶
A ticket has been sitting in รอตรวจสอบ (Pending Review) for two days. The SLA badge has been red for 40 hours.
How to find it¶
Two filters surface this immediately:
- Maintenance → Maintenance → search bar → Filters → SLA Breached → switches the list/kanban to only breached cards
- Group By → Stage then count cards in Pending Review
The list view's red row decoration is the fastest visual scan.
What to do¶
The workflow itself doesn't auto-escalate — it surfaces the breach and waits for a human. Recommended human protocol:
- BME Manager opens the ticket, reads the chatter for context
- Either assigns a technician (writes Responsible = tech), then moves to In Repair — the move itself is the "I've handled this" signal; or
- If the request is incorrectly classified, edits Kind / description, and either bounces back to Submitted with a chatter note (the backward move is logged) or forward to In Repair
- The audit log captures the move regardless
Don't 'fix' a breach by editing roots_stage_entered_at
Tempting if a manager forgot to triage and the timestamp looks bad. Don't. The field is the source of truth for the Time-in-Stage compute and for the audit log's prev-stage duration. Edit it and you corrupt the trail. Just advance the stage — the breach metric will recover naturally as the request moves forward.
Scenario 4 — Cancelled / abandoned request¶
The workflow module does not ship a Cancelled stage. The default Odoo maintenance.request model has an archive action (via active=False) that hides the request from the kanban, and that's what we recommend using.
Recommended pattern¶
- Manager opens the request
- Action menu → Archive — the request disappears from active views but survives in the audit log
- The current stage (whatever it is) is preserved
The audit log retains every transition up to the archive moment, so surveyors asking "why was this ticket cancelled?" can read the chatter for the explanation and the log for the timing.
If you really need a Cancelled stage¶
A hospital that needs a visible Cancelled column can add a custom stage (see Configuration):
- Name:
ยกเลิก (Cancelled) - Sequence:
90(after Received) - Fold: True
- Done: True (so the request is considered closed)
- Is Done Stage: True
- SLA Hours: 0
Then move cancelled tickets there manually. The audit log will show the move and surveyors will see explicit cancellations.
Scenario 5 — Vendor-handled request (under warranty / MA)¶
When a request opens on equipment covered by an active service contract, the coverage banner above the title (added by roots_hemms_service_contracts) spells out who pays. The workflow itself is unchanged — the BME team still walks through the same five stages — but the In Repair stage is performed by the vendor's field engineer instead of in-house.
sequenceDiagram
participant W as Ward staff
participant M as BME Manager
participant V as Vendor (e.g., GE)
participant S as BME Mgr (sign-off)
W->>M: Submit ticket
M->>M: Triage [Pending Review]
Note over M: Coverage banner:<br/>✓ Covered by SC/2026/00003<br/>vendor pays
M->>+V: Open ticket with vendor (out-of-band)
V->>V: Field service [In Repair]
V->>-S: Equipment fixed
S->>S: Sign off [Awaiting Pickup]
S->>W: Ready for pickup [Received] Two coordination points:
- In Repair is the stage that maps to vendor field-service time — the technician assignment can be a "Vendor" pseudo-user, or the field can be left blank and the chatter used for vendor contact notes
- Awaiting Pickup is when the BME manager has signed off the vendor's repair report (the vendor signature is the gating artifact — the workflow stage is the in-system shadow of it)
See Service Contracts → Workflows for the coverage matrix and how roots_is_billable_to_hospital is set on the request.
Scenario 6 — Bulk transitions¶
The workflow module does not ship a custom bulk action. But two patterns work today:
Kanban drag-select¶
In the maintenance kanban, select multiple cards (click and Ctrl/Cmd + click). Drag the selection to a different column. Odoo's standard batch write applies — the workflow _write override runs once per record in the same transaction, so every move is logged.
List-view server action¶
For larger batches (50+ records):
- Switch to list view
- Tick the rows you want to move
- Action → "Update Stage" (Odoo's built-in bulk-edit on
stage_id) - Pick the target stage; click Apply
This triggers one ORM write() call with vals = {"stage_id": X} on the full recordset. The workflow override iterates the recordset to compute per-record time_in_previous_stage_hours, then bulk-creates audit log rows in one create() call. Performance scales linearly with batch size; we've tested up to 500 records in one move without issue.
Why bulk moves are still logged correctly
The write() override iterates self before calling super, capturing each record's individual stage_id and roots_stage_entered_at. Then it calls super once. Then it bulk-creates the log rows with one create(). Atomicity is preserved — if super raises, no log rows are created.
Anti-pattern: skipping the audit log via sudo()¶
If you write a custom server action that does:
the audit log row is still created — the write() override runs regardless of sudo. Do not try to bypass it. The chatter message is also posted (with subtype mail.mt_note). If you need a truly silent move (don't), you must explicitly disable_logging — which we have not implemented and won't.
Related pages¶
- Configuration — SLA tuning, custom stages
- Reporting — surveyor evidence + KPIs
- Preventive Maintenance → Workflows — PM lifecycle details
- Service Contracts → Workflows — coverage matrix