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.
7.2 KiB
PX360 Organizational Structure Refactor (Final Architecture)
Objective
Refactor the current Department Hierarchy implementation into a simpler and more maintainable model that:
- Uses a single source of truth for routing.
- Uses a single source of truth for reporting.
- Preserves legacy complaint mappings for historical records.
- Removes unnecessary hierarchy levels.
- Aligns with the latest organizational spreadsheet.
- Supports future department and section changes without impacting reporting.
Key Business Findings
After reviewing:
- Legacy complaint hierarchy
- Existing reports
- Final organization spreadsheet
the following conclusions were reached.
Legacy Structure
Historical complaints used:
Location → Main Section → Sub Section
Example:
Outpatient → Medical → Radiology
The old Sub Section was the actual operational unit receiving complaints.
Current Organization Structure
The latest organization file contains:
- Main Section
- Department
- Section
Examples:
Medical → Pharmacy Department → Central Outpatient Pharmacy
Medical → Pharmacy Department → General
Important Discovery
Area is not a valid hierarchy level.
Evidence:
- Frequently empty
- Often duplicates Department concepts
- Not used in reporting
- Not used in routing
- Not used in ownership
Therefore:
Area should not become a first-class model.
Reporting Structure
All management reports are grouped by:
- Medical
- Non-Medical
- Nursing
- Support Services
These values come from:
Main Section
Therefore Main Section is actually the reporting category.
Target Hierarchy
Department Category
Represents:
- Medical
- Non-Medical
- Nursing
- Support Services
Model:
class DepartmentCategory(models.TextChoices):
MEDICAL = "medical"
NON_MEDICAL = "non_medical"
NURSING = "nursing"
SUPPORT_SERVICES = "support_services"
This replaces the old concept of:
Main Section
Department
Primary accountable organizational unit.
Model:
class Department(models.Model):
category
name
code
champion
manager_1st
manager_2nd
manager_3rd
deputy_manager
supervisor
deputy_supervisor
is_active
Examples:
- Pharmacy Department
- Radiology Department
- Laboratory Department
- Emergency Department
Departments always have ownership.
Departments always have a Champion.
Departments are the fallback routing target.
Section
Optional child unit under a Department.
Model:
class Section(models.Model):
department = models.ForeignKey(
Department,
related_name="sections"
)
name
code
champion = models.ForeignKey(
Staff,
null=True,
blank=True
)
location_type
location_code
zone
floor
is_active
Examples:
- Central Outpatient Pharmacy
- ER Pharmacy
- Pediatric Pharmacy
Not every Department requires Sections.
Not every Section requires a Champion.
Remove Sub-Section
Current model:
OrgSubSubSection
Findings:
- Mostly empty in source data.
- Not used in reports.
- Not used in routing.
- Not used in escalation.
Action:
Deprecate and remove.
Complaint Model
Target Structure
class Complaint(models.Model):
department = models.ForeignKey(
Department
)
section = models.ForeignKey(
Section,
null=True,
blank=True
)
legacy_mapping = models.ForeignKey(
LegacyHierarchyMapping,
null=True,
blank=True
)
Ownership Rules
Single ownership strategy.
def get_owner():
if complaint.section and complaint.section.champion:
return complaint.section.champion
return complaint.department.champion
Rules:
- Section Champion takes ownership when available.
- Otherwise Department Champion owns the complaint.
This becomes the only routing rule in the system.
Legacy Data Strategy
Legacy Mapping Table
Keep:
class LegacyHierarchyMapping(models.Model):
old_location
old_main_section
old_subsection
department
section
Purpose:
Legacy Complaint → Legacy Mapping → Department / Section
Legacy Fields
The following fields become historical reference only:
- legacy_location
- legacy_main_section
- legacy_subsection
Rules:
- No reporting usage
- No routing usage
- No escalation usage
- No dashboard usage
May remain temporarily for audit purposes.
Reporting Strategy
Single Source of Truth
All reports must use:
complaint.department
complaint.section
only.
Never use legacy hierarchy fields.
Category Reports
Medical / Nursing / Support Services reports:
Complaint.objects.values(
"department__category"
)
Department Reports
Complaint.objects.values(
"department__name"
)
Section Reports
Complaint.objects.values(
"section__name"
)
Location Handling
Location is metadata.
It is not part of ownership hierarchy.
Examples:
- Outpatient Clinics
- Inpatient
- Emergency
- General Services
Used for:
- Display
- Filtering
- Analytics
Not used for routing ownership.
Location Type
Retain:
- OP
- IP
- ER
- GENERAL
This becomes the preferred reporting dimension instead of string matching location names.
Example:
class LocationType(models.TextChoices):
OP = "OP"
IP = "IP"
ER = "ER"
GENERAL = "GENERAL"
Import Strategy
Department uniqueness:
(category, department_name)
must create a single Department.
Never create duplicate Departments from repeated spreadsheet rows.
Sections:
(department, section_name)
must be unique.
Migration Plan
Phase 1
Create:
- DepartmentCategory
- LocationType enums
Remove Area dependency.
Phase 2
Rename:
OrgSubSection
to:
Section
Update:
- models
- serializers
- views
- APIs
- templates
- services
Phase 3
Deprecate:
OrgSubSubSection
Backfill any valid data.
Remove references.
Phase 4
Backfill all historical complaints.
Populate:
- department
- section
using LegacyHierarchyMapping.
Target:
100% coverage.
Phase 5
Update routing services.
Replace all routing logic with:
complaint.get_owner()
Phase 6
Update:
- Dashboards
- KPI services
- Reports
- Exports
- Analytics
to use:
- Department
- Section
- Department Category
only.
Phase 7
Update forms.
Replace:
Location → Main Section → Sub Section
with:
Category → Department → Section
Section optional.
Phase 8
Mark legacy hierarchy fields as deprecated.
Prevent all new writes.
Keep read-only until final cleanup release.
Success Criteria
✓ Department is the primary accountable entity.
✓ Section is optional.
✓ Reporting uses Department Category.
✓ Routing uses Department / Section only.
✓ Legacy hierarchy is used only for historical mapping.
✓ Area is removed from operational design.
✓ OrgSubSubSection is removed.
✓ OrgSubSection is renamed to Section.
✓ Dashboards no longer depend on legacy hierarchy.
✓ Complaint ownership has a single source of truth.