# Complaint Category and Subcategory Structure Examination ## Executive Summary This document provides a comprehensive examination of the complaint category and subcategory structure in the PX360 system, including the 4-level SHCT taxonomy implementation and a diagnosis of the domain dropdown issue. --- ## 1. Taxonomy Structure Overview The complaint taxonomy follows a **4-level hierarchical structure** based on SHCT (Saudi Health Commission for Tourism) standards: ### Level 1: DOMAIN (3 domains) - **CLINICAL** (سريري) - Medical and healthcare-related complaints - **MANAGEMENT** (إداري) - Administrative and operational complaints - **RELATIONSHIPS** (علاقات) - Staff-patient relationship complaints ### Level 2: CATEGORY (8 categories) These are specific areas within each domain. Examples include: - Under CLINICAL: "Medical Treatment", "Diagnosis", "Medication" - Under MANAGEMENT: "Billing", "Scheduling", "Facilities" - Under RELATIONSHIPS: "Staff Behavior", "Communication" ### Level 3: SUBCATEGORY (20 subcategories) More detailed classifications within each category. Examples: - Under "Medical Treatment": "Treatment Delay", "Treatment Quality" - Under "Billing": "Incorrect Charges", "Payment Issues" ### Level 4: CLASSIFICATION (75 classifications) The most granular level, providing specific complaint types. Examples: - Under "Treatment Delay": "Emergency Room", "Outpatient" - Under "Incorrect Charges": "Insurance", "Self-Pay" --- ## 2. Database Schema ### ComplaintCategory Model ```python class ComplaintCategory(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) # Taxonomy fields level = models.IntegerField( choices=[ (1, "DOMAIN"), (2, "CATEGORY"), (3, "SUBCATEGORY"), (4, "CLASSIFICATION") ], db_index=True ) parent_id = models.UUIDField(null=True, blank=True, db_index=True) domain_type = models.CharField( max_length=50, choices=[ ('CLINICAL', 'Clinical'), ('MANAGEMENT', 'Management'), ('RELATIONSHIPS', 'Relationships') ] ) # Bilingual fields name_en = models.CharField(max_length=200) name_ar = models.CharField(max_length=200) description_en = models.TextField(blank=True) description_ar = models.TextField(blank=True) # SHCT code code = models.CharField(max_length=50, unique=True) # Hospital-specific categories (optional) hospitals = models.ManyToManyField( Hospital, blank=True, related_name='complaint_categories' ) # Ordering and status order = models.IntegerField(default=0) is_active = models.BooleanField(default=True) # Metadata created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) ``` ### Complaint Model (4-level taxonomy) ```python class Complaint(models.Model): # Level 1: Domain (FK to ComplaintCategory) domain = models.ForeignKey( ComplaintCategory, on_delete=models.PROTECT, related_name='complaints_as_domain', null=True, blank=True ) # Level 2: Category (FK to ComplaintCategory) category = models.ForeignKey( ComplaintCategory, on_delete=models.PROTECT, related_name='complaints_as_category', null=True, blank=True ) # Level 3: Subcategory (stored as code) subcategory = models.CharField(max_length=50, blank=True) # Level 4: Classification (stored as code) classification = models.CharField(max_length=50, blank=True) ``` --- ## 3. Current Taxonomy Data Status ### Database Statistics (as of latest diagnostic) - **Total Categories**: 106 - **Level 1 (Domains)**: 3 - **Level 2 (Categories)**: 8 - **Level 3 (Subcategories)**: 20 - **Level 4 (Classifications)**: 75 - **Active Hospitals**: 1 (Alhammadi Hospital) ### Level 1 Domains in Database 1. **CLINICAL** (سريري) - ID: 3ab92484-840b-4f81-b50a-b51d1d807929 - Type: CLINICAL - Active: True 2. **MANAGEMENT** (إداري) - ID: 1dc25dd0-a550-4cbe-9af1-0a5f8a71ce69 - Type: MANAGEMENT - Active: True 3. **RELATIONSHIPS** (علاقات) - ID: 537132ad-0035-4a1e-bea5-8ebee3c7d5af - Type: RELATIONSHIPS - Active: True ### Category Visibility - All 106 categories are **system-wide** (not hospital-specific) - All categories have `is_active=True` - The hospital "Alhammadi Hospital" has 0 hospital-specific categories --- ## 4. API Endpoint Analysis ### Endpoint: `/complaints/public/api/load-categories/` **Method**: GET **Authentication**: Not required (public form) **Parameters**: - `hospital_id` (optional): UUID of selected hospital **Response Format**: ```json { "categories": [ { "id": "uuid", "name_en": "CLINICAL", "name_ar": "سريري", "code": "CLINICAL", "parent_id": null, "level": 1, "domain_type": "CLINICAL", "description_en": "...", "description_ar": "..." }, ... ] } ``` ### Query Logic ```python if hospital_id: # Return hospital-specific + system-wide categories categories_queryset = ( ComplaintCategory.objects.filter( Q(hospitals__id=hospital_id) | Q(hospitals__isnull=True), is_active=True ) .distinct() .order_by("level", "order", "name_en") ) else: # Return only system-wide categories categories_queryset = ComplaintCategory.objects.filter( hospitals__isnull=True, is_active=True ).order_by("level", "order", "name_en") ``` ### Diagnostic Results ✓ API query returns **106 categories** for Alhammadi Hospital ✓ API query returns **3 Level 1 domains** for dropdown ✓ All domains are active and visible --- ## 5. Frontend Implementation ### Public Complaint Form Template Location: `templates/complaints/public_complaint_form.html` ### JavaScript Dependencies - **jQuery 3.7.1** - Loaded via CDN in `templates/layouts/public_base.html` - **SweetAlert2** - Loaded for user feedback - **Bootstrap 5** - UI framework ### Cascading Dropdown Logic The form implements a 4-level cascading dropdown system: 1. **Hospital Selection** → Triggers Domain load 2. **Domain Selection** → Triggers Category load (filtered by domain) 3. **Category Selection** → Triggers Subcategory load (filtered by category) 4. **Subcategory Selection** → Triggers Classification load (filtered by subcategory) ### Key JavaScript Functions #### loadDomains(hospitalId) ```javascript function loadDomains(hospitalId) { if (!hospitalId) { // Clear all dropdowns $('#id_domain').find('option:not(:first)').remove(); $('#category_container').hide(); $('#subcategory_container').hide(); $('#classification_container').hide(); return; } $.ajax({ url: '{% url "complaints:api_load_categories" %}', type: 'GET', data: { hospital_id: hospitalId }, success: function(response) { allCategories = response.categories; const domainSelect = $('#id_domain'); domainSelect.find('option:not(:first)').remove(); // Only show level 1 categories (Domains) allCategories.forEach(function(category) { if (category.level === 1) { domainSelect.append($('