All checks were successful
Build and Push Docker Image / build (push) Successful in 4m14s
Reference numbers (unified scheme PREFIX-YYYYMM-HOSP-NNNN, e.g. CMP-202606-HHN-0001): - new ReferenceSequence model + generate_reference() helper (apps/core) - Complaint/Inquiry/Observation/Appreciation/Suggestion emit unified refs via save() - prefix-based auto-routing in public track API (CMP/INQ/OBS trackable; APR/SGT internal-only) - removed legacy CMP-/INQ- generators in ui_views, integrations, px_sources - migrations: core.0003_referencesequence, appreciation.0006, feedback.0008, observations.0012 - unit tests (format, sanitization, monthly reset, 40-thread concurrency) QA audit: - isolated E2E hospital sandbox mirroring HH-N + 10 role users (create_e2e_isolated_env) - feedback-modules-audit.spec.ts + audit helper (headed, run-to-completion) - reports/feedback-modules-qa-report.md Also bundles accumulated in-progress work across complaints, observations, organizations, templates, and other modules.
602 lines
6.6 KiB
Markdown
602 lines
6.6 KiB
Markdown
# PX360 Organization Hierarchy Refactor Plan
|
|
|
|
## Objective
|
|
|
|
Simplify the current Department Hierarchy implementation and establish a single source of truth for complaint routing, reporting, escalation, and ownership.
|
|
|
|
The current implementation successfully migrated data but carries excessive legacy concepts into the active business model.
|
|
|
|
The goal is to:
|
|
|
|
* Use the new organizational structure as the only operational hierarchy.
|
|
* Preserve legacy complaint information only for audit/reference purposes.
|
|
* Eliminate dependency on legacy hierarchy fields for reporting.
|
|
* Simplify routing and ownership logic.
|
|
* Align the system with how the hospital currently operates.
|
|
|
|
---
|
|
|
|
# Business Understanding
|
|
|
|
## Legacy Structure
|
|
|
|
Old complaints were created using:
|
|
|
|
```text
|
|
Location
|
|
└── Main Section
|
|
└── Sub Section
|
|
```
|
|
|
|
Example:
|
|
|
|
```text
|
|
Outpatient
|
|
└── Medical
|
|
└── Radiology
|
|
```
|
|
|
|
In practice:
|
|
|
|
```text
|
|
Legacy SubSection
|
|
```
|
|
|
|
was the actual operational unit receiving complaints.
|
|
|
|
---
|
|
|
|
## New Structure
|
|
|
|
The new organization file defines:
|
|
|
|
```text
|
|
Location
|
|
└── Area
|
|
└── Department
|
|
└── Section
|
|
```
|
|
|
|
Example:
|
|
|
|
```text
|
|
Outpatient
|
|
└── Medical
|
|
└── Pharmacy
|
|
├── ER Pharmacy
|
|
├── OPD Pharmacy
|
|
└── Pediatric Pharmacy
|
|
```
|
|
|
|
---
|
|
|
|
## Complaint Ownership Rules
|
|
|
|
A complaint may be owned by:
|
|
|
|
* A Department
|
|
* A Section
|
|
|
|
Departments always have a Champion.
|
|
|
|
Sections may optionally have a Champion.
|
|
|
|
Routing rules:
|
|
|
|
```text
|
|
Section Champion
|
|
↓
|
|
Department Champion
|
|
```
|
|
|
|
If a Section has no Champion, responsibility falls back to the Department Champion.
|
|
|
|
---
|
|
|
|
# Target Data Model
|
|
|
|
## Area
|
|
|
|
```python
|
|
class Area(models.Model):
|
|
hospital
|
|
name
|
|
name_en
|
|
name_ar
|
|
code
|
|
status
|
|
```
|
|
|
|
Represents:
|
|
|
|
```text
|
|
Medical
|
|
Non-Medical
|
|
Nursing
|
|
Support Services
|
|
```
|
|
|
|
---
|
|
|
|
## Department
|
|
|
|
```python
|
|
class Department(models.Model):
|
|
area = ForeignKey(Area)
|
|
|
|
name
|
|
code
|
|
|
|
champion
|
|
manager
|
|
manager_1st
|
|
manager_2nd
|
|
manager_3rd
|
|
|
|
deputy_manager
|
|
supervisor
|
|
deputy_supervisor
|
|
```
|
|
|
|
Examples:
|
|
|
|
```text
|
|
Pharmacy
|
|
Radiology
|
|
Laboratory
|
|
Emergency Department
|
|
```
|
|
|
|
---
|
|
|
|
## Section
|
|
|
|
Rename:
|
|
|
|
```python
|
|
OrgSubSection
|
|
```
|
|
|
|
to:
|
|
|
|
```python
|
|
Section
|
|
```
|
|
|
|
Model:
|
|
|
|
```python
|
|
class Section(models.Model):
|
|
department = ForeignKey(Department)
|
|
|
|
name
|
|
code
|
|
|
|
champion = FK(Staff, null=True)
|
|
|
|
status
|
|
```
|
|
|
|
Examples:
|
|
|
|
```text
|
|
ER Pharmacy
|
|
OPD Pharmacy
|
|
Pediatric Pharmacy
|
|
```
|
|
|
|
---
|
|
|
|
## Remove Sub-Section Layer
|
|
|
|
Current:
|
|
|
|
```python
|
|
OrgSubSubSection
|
|
```
|
|
|
|
Business review determined:
|
|
|
|
* Mostly empty
|
|
* Not used for reporting
|
|
* Not used for routing
|
|
* Not used for ownership
|
|
|
|
Action:
|
|
|
|
```text
|
|
Deprecate and remove
|
|
```
|
|
|
|
after data validation.
|
|
|
|
---
|
|
|
|
# Complaint Model
|
|
|
|
## Target Structure
|
|
|
|
```python
|
|
class Complaint(models.Model):
|
|
|
|
department = FK(Department)
|
|
|
|
section = FK(
|
|
Section,
|
|
null=True,
|
|
blank=True
|
|
)
|
|
|
|
legacy_mapping = FK(
|
|
LegacyHierarchyMapping,
|
|
null=True,
|
|
blank=True
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## Ownership Resolution
|
|
|
|
Implement:
|
|
|
|
```python
|
|
Complaint.get_owner()
|
|
```
|
|
|
|
Logic:
|
|
|
|
```python
|
|
if complaint.section and complaint.section.champion:
|
|
return complaint.section.champion
|
|
|
|
return complaint.department.champion
|
|
```
|
|
|
|
This becomes the single ownership rule used everywhere.
|
|
|
|
---
|
|
|
|
# Legacy Data Strategy
|
|
|
|
## Important Rule
|
|
|
|
Legacy hierarchy is no longer part of the operational model.
|
|
|
|
Legacy hierarchy exists only to explain historical complaints.
|
|
|
|
---
|
|
|
|
## Keep Mapping Table
|
|
|
|
Retain:
|
|
|
|
```python
|
|
LegacyHierarchyMapping
|
|
```
|
|
|
|
Refactor to:
|
|
|
|
```python
|
|
class LegacyHierarchyMapping(models.Model):
|
|
|
|
old_location
|
|
old_main_section
|
|
old_subsection
|
|
|
|
department
|
|
section
|
|
```
|
|
|
|
Purpose:
|
|
|
|
```text
|
|
Legacy Complaint
|
|
↓
|
|
Legacy Mapping
|
|
↓
|
|
Department / Section
|
|
```
|
|
|
|
---
|
|
|
|
## Remove Operational Usage Of
|
|
|
|
```python
|
|
legacy_location
|
|
legacy_main_section
|
|
legacy_subsection
|
|
```
|
|
|
|
from:
|
|
|
|
* Reporting
|
|
* Routing
|
|
* Dashboards
|
|
* KPIs
|
|
* Escalation
|
|
* Filters
|
|
|
|
They may remain temporarily for audit/reference only.
|
|
|
|
---
|
|
|
|
# Reporting Refactor
|
|
|
|
## New Reporting Rule
|
|
|
|
All reports must use:
|
|
|
|
```python
|
|
complaint.department
|
|
complaint.section
|
|
```
|
|
|
|
only.
|
|
|
|
Never use:
|
|
|
|
```python
|
|
legacy_location
|
|
legacy_main_section
|
|
legacy_subsection
|
|
```
|
|
|
|
for any new report.
|
|
|
|
---
|
|
|
|
## Report Grouping
|
|
|
|
Department-level:
|
|
|
|
```python
|
|
values("department__name")
|
|
```
|
|
|
|
Section-level:
|
|
|
|
```python
|
|
values("section__name")
|
|
```
|
|
|
|
Area-level:
|
|
|
|
```python
|
|
values("department__area__name")
|
|
```
|
|
|
|
---
|
|
|
|
## Dashboard Refactor
|
|
|
|
Replace:
|
|
|
|
```python
|
|
location__name_en
|
|
main_section
|
|
legacy_main_section
|
|
```
|
|
|
|
with:
|
|
|
|
```python
|
|
department
|
|
department__area
|
|
section
|
|
```
|
|
|
|
---
|
|
|
|
# Routing Refactor
|
|
|
|
## Send To Department
|
|
|
|
Current behavior should become:
|
|
|
|
```python
|
|
owner = complaint.get_owner()
|
|
```
|
|
|
|
No custom routing logic should duplicate ownership checks.
|
|
|
|
---
|
|
|
|
## Escalation
|
|
|
|
Escalation should work against:
|
|
|
|
```python
|
|
Department
|
|
Section
|
|
```
|
|
|
|
only.
|
|
|
|
Legacy hierarchy must never influence escalation.
|
|
|
|
---
|
|
|
|
# Forms Refactor
|
|
|
|
Replace all remaining legacy hierarchy forms.
|
|
|
|
Current:
|
|
|
|
```text
|
|
Location
|
|
Main Section
|
|
Sub Section
|
|
```
|
|
|
|
New:
|
|
|
|
```text
|
|
Area
|
|
Department
|
|
Section
|
|
```
|
|
|
|
Fields:
|
|
|
|
```python
|
|
area
|
|
department
|
|
section
|
|
```
|
|
|
|
Section optional.
|
|
|
|
---
|
|
|
|
# Naming Cleanup
|
|
|
|
Rename:
|
|
|
|
```python
|
|
OrgSubSection
|
|
```
|
|
|
|
→
|
|
|
|
```python
|
|
Section
|
|
```
|
|
|
|
Rename related:
|
|
|
|
```python
|
|
org_subsections
|
|
```
|
|
|
|
→
|
|
|
|
```python
|
|
sections
|
|
```
|
|
|
|
Update:
|
|
|
|
* serializers
|
|
* views
|
|
* APIs
|
|
* templates
|
|
* services
|
|
|
|
---
|
|
|
|
# Migration Steps
|
|
|
|
## Phase 1
|
|
|
|
Create:
|
|
|
|
```python
|
|
Area
|
|
```
|
|
|
|
model.
|
|
|
|
Populate from Department records.
|
|
|
|
---
|
|
|
|
## Phase 2
|
|
|
|
Rename:
|
|
|
|
```python
|
|
OrgSubSection
|
|
```
|
|
|
|
to:
|
|
|
|
```python
|
|
Section
|
|
```
|
|
|
|
Update all references.
|
|
|
|
---
|
|
|
|
## Phase 3
|
|
|
|
Backfill:
|
|
|
|
```python
|
|
complaint.department
|
|
complaint.section
|
|
```
|
|
|
|
for all historical complaints.
|
|
|
|
Target:
|
|
|
|
```text
|
|
100%
|
|
```
|
|
|
|
coverage.
|
|
|
|
---
|
|
|
|
## Phase 4
|
|
|
|
Update:
|
|
|
|
* dashboards
|
|
* exports
|
|
* KPI services
|
|
* analytics
|
|
|
|
to use new hierarchy only.
|
|
|
|
---
|
|
|
|
## Phase 5
|
|
|
|
Update:
|
|
|
|
* complaint forms
|
|
* inquiry forms
|
|
* observation forms
|
|
* government ticket forms
|
|
|
|
to use:
|
|
|
|
```text
|
|
Area → Department → Section
|
|
```
|
|
|
|
---
|
|
|
|
## Phase 6
|
|
|
|
Mark legacy hierarchy fields as deprecated.
|
|
|
|
No new writes allowed.
|
|
|
|
---
|
|
|
|
# Success Criteria
|
|
|
|
The implementation is complete when:
|
|
|
|
✓ All complaints have Department assigned.
|
|
|
|
✓ Reporting uses only Department/Section hierarchy.
|
|
|
|
✓ Routing uses only Department/Section ownership.
|
|
|
|
✓ Dashboards use only Department/Section hierarchy.
|
|
|
|
✓ Legacy hierarchy is retained only for historical reference.
|
|
|
|
✓ OrgSubSubSection is removed.
|
|
|
|
✓ OrgSubSection is renamed to Section.
|
|
|
|
✓ Area is a first-class model.
|
|
|
|
✓ There is only one source of truth for complaint ownership.
|