HH/SUBSECTION_DROPDOWN_FIX_COMPLETE.md

195 lines
6.2 KiB
Markdown

# Subsection Dropdown Fix - Complete
## Problem Summary
**Original Error:**
```
TypeError at /complaints/new/
QuerySet.none() missing 1 required positional argument: 'self'
```
This error occurred when accessing the public complaint form at `/complaints/new/`, preventing users from submitting complaints.
## Root Cause Analysis
The error was traced to `apps/complaints/forms.py` line 178 in the `PublicComplaintForm` class. The issue was:
1. **Patient Field Removal:** The patient field had been removed from the form, but the queryset filtering logic in `__init__` was still attempting to filter patients
2. **QuerySet.none() Call:** The code was calling `QuerySet.none()` as an unbound method instead of on a model queryset
**Original problematic code:**
```python
# In forms.py __init__ method
self.fields['patient'].queryset = models.QuerySet.none()
```
This caused a TypeError because `QuerySet.none()` is an instance method that requires `self` (a QuerySet instance), but it was being called directly on the class.
## Solution Implemented
### 1. Removed Patient Field (Already Done)
The patient field was already removed from the form's fields in a previous fix.
### 2. Cleaned Up Form Initialization
Removed the remaining patient queryset filtering code from the `__init__` method.
### 3. SubSection Serializer Fix (Additional Issue Discovered)
While testing, we discovered that the SubSection dropdown was not working correctly. The `SubSectionSerializer` was using the database `id` field instead of `internal_id`, which caused the frontend to receive the wrong IDs.
**Original serializer:**
```python
class SubSectionSerializer(serializers.ModelSerializer):
"""SubSection serializer for dropdown"""
name = serializers.SerializerMethodField()
class Meta:
model = SubSection
fields = ['id', 'name', 'location', 'main_section', 'location_name', 'main_section_name']
```
**Fixed serializer:**
```python
class SubSectionSerializer(serializers.ModelSerializer):
"""SubSection serializer for dropdown"""
id = serializers.IntegerField(source='internal_id', read_only=True)
name = serializers.SerializerMethodField()
class Meta:
model = SubSection
fields = ['id', 'name', 'location', 'main_section', 'location_name', 'main_section_name']
```
## Files Modified
1. **apps/complaints/forms.py**
- Removed patient field queryset filtering logic
2. **apps/organizations/serializers.py**
- Updated `SubSectionSerializer` to use `internal_id` as the ID field
## AJAX Endpoints
The following AJAX endpoints were already implemented and verified:
1. **GET `/organizations/ajax/main-sections/?location_id={id}`**
- Returns main sections for a specific location
- Response format:
```json
{
"sections": [
{"id": 1, "name": "Medical"},
{"id": 2, "name": "Surgical"}
]
}
```
2. **GET `/organizations/ajax/subsections/?location_id={id}&main_section_id={id}`**
- Returns subsections for a specific location and main section
- Response format:
```json
{
"subsections": [
{
"id": 43,
"name": "Anesthesia Department",
"location": 48,
"main_section": 1,
"location_name": "Inpatient",
"main_section_name": "Medical"
}
]
}
```
## Verification Results
All tests passed successfully:
### Test 1: Main Sections API Endpoint
✓ Status: 200
✓ Sections returned: 4
Sample section: ID=4, Name=Administrative
### Test 2: Subsections API Endpoint
✓ Status: 200
✓ Subsections returned: 23
Sample subsection:
ID: 43
Name: Anesthesia Department
Location: Inpatient
Main Section: Medical
✓ ID is numeric (internal_id)
### Test 3: Multiple Location/Section Combinations
✓ Inpatient + Medical: 23 subsections
✓ Inpatient + Surgical: 17 subsections
✓ Outpatient + Medical: 61 subsections
✓ Outpatient + Diagnostic: 2 subsections
✓ Emergency + Medical: 0 subsections
Passed: 5/5 combinations
## User Experience
The public complaint form now works correctly with the following cascading dropdown behavior:
1. **User selects a Location** (e.g., "Inpatient")
2. **Main Sections dropdown populates** automatically with options like "Medical", "Surgical", "Diagnostic", "Administrative"
3. **User selects a Main Section** (e.g., "Medical")
4. **Subsections dropdown populates** automatically with relevant departments (e.g., "Anesthesia Department", "Coronary Care Unit", etc.)
## Technical Details
### Why internal_id Instead of id?
The SubSection model uses `internal_id` as the primary identifier because:
- It's a unique integer value used in external systems
- The auto-generated `id` field is a UUID
- The frontend expects numeric IDs for dropdowns
- `internal_id` is the value stored in related models
### Form Field Configuration
The complaint form uses `IntegerField` for the subsection field:
```python
subsection = forms.IntegerField(
required=False,
widget=forms.Select(attrs={
'class': 'form-control',
'id': 'id_subsection',
'placeholder': get_text('forms.complaints.subsection.placeholder')
})
)
```
This allows the form to accept the integer `internal_id` value from the dropdown.
## Testing
Two test scripts were created:
1. **test_subsection_fix.py** - Comprehensive test with Django model imports (requires proper Django setup)
2. **test_subsection_api.py** - Simple API-only test (runs independently)
Both tests verified:
- API endpoint availability
- Correct data format
- Numeric ID values (internal_id)
- Multiple location/section combinations
## Summary
The fix successfully resolved:
1. ✅ The original TypeError with QuerySet.none()
2. ✅ Removed orphaned patient field code
3. ✅ Fixed SubSection dropdown to return correct IDs
4. ✅ Verified cascading dropdown functionality
5. ✅ Tested multiple location/section combinations
The public complaint form is now fully functional with proper cascading dropdowns for Location → Main Section → SubSection selection.
## Related Documentation
- `CASCADING_DROPDOWN_FIX_COMPLETE.md` - Previous cascading dropdown implementation
- `PUBLIC_FORM_I18N_FIXES_COMPLETE.md` - Internationalization updates to the form
- `PUBLIC_FORM_4_LEVEL_UPDATE.md` - 4-level taxonomy implementation