Status state machine, stepper, entry points & sub-workflows — auto-extracted from source
8 statuses defined in ComplaintStatus (models.py:25). Transition map enforced at complaint_service.py:284 — only via ComplaintService.change_status. PX Admins bypass.
stateDiagram-v2
[*] --> open
open --> in_progress : activate
open --> cancelled
in_progress --> partially_resolved
in_progress --> resolved
in_progress --> cancelled
in_progress --> pending_external
in_progress --> ovr_pending : escalate
partially_resolved --> resolved
partially_resolved --> in_progress
partially_resolved --> cancelled
partially_resolved --> pending_external
resolved --> closed
resolved --> in_progress : reopen
closed --> in_progress : reopen
cancelled --> open
cancelled --> in_progress
pending_external --> resolved
pending_external --> in_progress
pending_external --> cancelled
pending_external --> closed
ovr_pending --> in_progress : approve / reject
ovr_pending --> resolved
ovr_pending --> cancelled
closed --> [*]
| From | Allowed Next Statuses |
|---|---|
open | in_progress, cancelled |
in_progress | partially_resolved, resolved, cancelled, pending_external, ovr_pending |
partially_resolved | resolved, in_progress, cancelled, pending_external |
resolved | closed, in_progress |
closed | in_progress |
cancelled | open, in_progress |
pending_external | resolved, in_progress, cancelled, closed |
ovr_pending | in_progress, resolved, cancelled |
is_active_status)| Active | Inactive |
|---|---|
| open in_progress partially_resolved pending_external | resolved closed cancelled ovr_pending ⚠️ |
ovr_pending is treated as inactive by is_active_status even though it's a mid-lifecycle state. Service methods guarding on active status would reject operations on OVR-pending complaints.
6 ordered progress flags rendered inline in complaint_detail.html:147. Driven by a boolean dict built at ui_views.py:745. Hidden when status is cancelled.
| # | Step | Flag | Icon | Action when not done |
|---|---|---|---|---|
| 1 | Created | always green | check | — |
| 2 | Activate | activated_at | play | "Activate this complaint" → complaint_activate |
| 3 | Taxonomy | taxonomy_reviewed_at | clipboard-check | "Review taxonomy" → confirm_taxonomy |
| 4 | Send to Dept | sent_to_department / forwarded_to_dept_at | send | "Send to department" modal |
| 5 | Response | explanation used OR dept responded | message-square | "Awaiting department response" |
| 6 | Resolve | status in (resolved, closed) | check-circle-2 | "Generate Resolution" |
status ∈ (resolved, closed), regardless of path taken.
Code paths that modify complaint.status. Only ComplaintService.change_status enforces the transition map — the rest set status directly.
| Action | Location | Transition enforced? |
|---|---|---|
| Generic change status | ui_views.py:1365 | Yes |
| Activate (open→in_progress) | ui_views.py:2125 | service guard |
| Assign / reopen-on-assign | ui_views.py:851 | service guard |
| Reopen as new complaint | ui_views.py:1777 | service guard |
| OVR toggle | ui_views.py:1549 | direct |
| OVR approve | ui_views.py:1640 | direct |
| OVR reject | ui_views.py:1755 | direct |
| API auto-resolve | views.py:2040 | direct |
| Convert to appreciation | views.py:2198 | direct |
| Meeting auto-resolve | views.py:3279 | direct |
| Bulk status change | utils.py:263 | direct |
close_stale_complaints cmd | close_stale_complaints.py:113 | direct (bulk UPDATE) |
Independent state machines attached to a complaint, each with its own field/model.
graph TD
C[COMPLAINT
status: 8 states]
C --> DR["Dept Routing
routing_status"]
C --> CI["Champion Investigation
status"]
C --> MR["Manager Review
manager_review_status"]
C --> PC["Patient Contact
patient_contact_status"]
C --> SA["Satisfaction
satisfaction"]
C --> AA["Adverse Action
verification_status"]
DR --> |sent| DR2["accepted / rejected"]
CI --> |questions_sent| CI2["answers_received"]
CI2 --> CI3["reply_submitted / direct_reply_in_progress"]
MR --> |pending| MR2["approved / rejected"]
PC --> |not_contacted| PC2["contacted / no_response"]
SA --> SA2["satisfied / neutral / dissatisfied / no_response"]
AA --> |reported| AA2["under_investigation"]
AA2 --> AA3["verified / unfounded / resolved"]
style C fill:#0a1e3f,color:#fff,stroke:none
style DR fill:#dbeafe,stroke:#007bbd
style CI fill:#dcfce7,stroke:#16a34a
style MR fill:#fef3c7,stroke:#d97706
style PC fill:#fce7f3,stroke:#db2777
style SA fill:#ede9fe,stroke:#7c3aed
style AA fill:#fee2e2,stroke:#dc2626
ComplaintInvolvedDepartment.routing_statusChampionInvestigation.statusComplaintInvolvedDepartment.manager_review_statusComplaint.patient_contact_statusComplaint.satisfactionComplaintAdverseAction.verification_status