483 lines
12 KiB
Markdown
483 lines
12 KiB
Markdown
# Simplified Survey Integration Documentation
|
|
|
|
## Overview
|
|
|
|
The PX360 survey system has been simplified to directly deliver surveys based on PatientType without the complexity of journey tracking. This document describes the simplified architecture, data flow, and usage.
|
|
|
|
## Architecture
|
|
|
|
### Before (Complex)
|
|
```
|
|
HIS Data → Patient Journey → Journey Stages → Visit Processing → Stage Completion → Survey Creation → SMS Delivery
|
|
```
|
|
|
|
### After (Simplified)
|
|
```
|
|
HIS Data → PatientType Detection → Survey Template Selection → Survey Creation → SMS Delivery
|
|
```
|
|
|
|
## Key Components
|
|
|
|
### 1. HIS Adapter (`apps/integrations/services/his_adapter.py`)
|
|
|
|
The HIS Adapter processes real HIS patient data and creates surveys directly.
|
|
|
|
**Main Functions:**
|
|
|
|
- `map_patient_type_to_survey_type()`: Maps HIS PatientType codes to survey types
|
|
- `get_survey_template()`: Selects appropriate survey template based on PatientType
|
|
- `create_and_send_survey()`: Creates survey instance and triggers SMS delivery
|
|
- `process_his_data()`: Main entry point for processing HIS data
|
|
|
|
**PatientType Mapping:**
|
|
|
|
| HIS Code | Survey Type | Description |
|
|
|----------|-------------|-------------|
|
|
| "1" | INPATIENT | Inpatient visits |
|
|
| "2" or "O" | OPD | Outpatient visits |
|
|
| "3" or "E" | EMS | Emergency visits |
|
|
| unknown | OPD (default) | Falls back to OPD |
|
|
|
|
### 2. HIS Simulator (`apps/simulator/his_simulator.py`)
|
|
|
|
The simulator generates realistic HIS patient data with proper PatientType distribution.
|
|
|
|
**PatientType Distribution:**
|
|
|
|
- OPD: 60% (most common)
|
|
- Inpatient: 30%
|
|
- EMS: 10%
|
|
|
|
**Usage:**
|
|
|
|
```bash
|
|
# Run simulator with default settings (5 patients per minute)
|
|
python apps/simulator/his_simulator.py
|
|
|
|
# Run simulator with custom settings
|
|
python apps/simulator/his_simulator.py --url http://localhost:8000/api/simulator/his-patient-data/ --delay 10 --max-patients 50
|
|
```
|
|
|
|
**Parameters:**
|
|
|
|
- `--url`: API endpoint URL
|
|
- `--delay`: Delay between patients in seconds
|
|
- `--max-patients`: Maximum number of patients (0 = infinite)
|
|
|
|
### 3. Survey Templates
|
|
|
|
Survey templates must be named to match PatientType:
|
|
|
|
- `OPD Survey` or template name containing "OPD"
|
|
- `INPATIENT Survey` or template name containing "INPATIENT"
|
|
- `EMS Survey` or template name containing "EMS"
|
|
|
|
**Example Template Creation:**
|
|
|
|
```python
|
|
from apps.surveys.models import SurveyTemplate
|
|
from apps.organizations.models import Hospital
|
|
|
|
hospital = Hospital.objects.get(code="ALH-main")
|
|
|
|
# OPD Survey
|
|
opd_survey = SurveyTemplate.objects.create(
|
|
name="OPD Survey",
|
|
hospital=hospital,
|
|
description="Outpatient Department Survey",
|
|
is_active=True,
|
|
survey_type="patient_satisfaction"
|
|
)
|
|
|
|
# Inpatient Survey
|
|
inpatient_survey = SurveyTemplate.objects.create(
|
|
name="INPATIENT Survey",
|
|
hospital=hospital,
|
|
description="Inpatient Care Survey",
|
|
is_active=True,
|
|
survey_type="patient_satisfaction"
|
|
)
|
|
|
|
# EMS Survey
|
|
ems_survey = SurveyTemplate.objects.create(
|
|
name="EMS Survey",
|
|
hospital=hospital,
|
|
description="Emergency Medical Services Survey",
|
|
is_active=True,
|
|
survey_type="patient_satisfaction"
|
|
)
|
|
```
|
|
|
|
## Data Flow
|
|
|
|
### 1. HIS Patient Data Reception
|
|
|
|
The system receives HIS data in this format:
|
|
|
|
```json
|
|
{
|
|
"FetchPatientDataTimeStampList": [{
|
|
"PatientID": "123456",
|
|
"AdmissionID": "ADM-001",
|
|
"HospitalID": "1",
|
|
"HospitalName": "Al Hammadi Hospital - Main",
|
|
"PatientType": "2",
|
|
"AdmitDate": "05-Jun-2025 11:06",
|
|
"DischargeDate": "05-Jun-2025 16:30",
|
|
"PatientName": "Ahmed Al-Saud",
|
|
"MobileNo": "0512345678",
|
|
"Email": "ahmed@example.com",
|
|
"InsuranceCompanyName": "Arabian Shield Cooperative Insurance Company",
|
|
...
|
|
}],
|
|
"FetchPatientDataTimeStampVisitDataList": [...],
|
|
"Code": 200,
|
|
"Status": "Success"
|
|
}
|
|
```
|
|
|
|
### 2. Processing Flow
|
|
|
|
```
|
|
1. Receive HIS patient data
|
|
↓
|
|
2. Extract PatientType from data
|
|
↓
|
|
3. Check if patient is discharged (DischargeDate present)
|
|
↓
|
|
4. Get or create patient record
|
|
↓
|
|
5. Select appropriate survey template based on PatientType
|
|
↓
|
|
6. Create survey instance with metadata
|
|
↓
|
|
7. Send survey via SMS using patient's phone number
|
|
↓
|
|
8. Return success/failure status
|
|
```
|
|
|
|
### 3. Survey Creation
|
|
|
|
When a discharged patient is received:
|
|
|
|
```python
|
|
# Survey instance created with:
|
|
{
|
|
"survey_template": <OPD Survey>,
|
|
"patient": <Patient record>,
|
|
"hospital": <Hospital record>,
|
|
"status": "PENDING",
|
|
"delivery_channel": "SMS",
|
|
"recipient_phone": "0512345678",
|
|
"recipient_email": "ahmed@example.com",
|
|
"metadata": {
|
|
"admission_id": "ADM-001",
|
|
"patient_type": "2",
|
|
"hospital_id": "1",
|
|
"insurance_company": "Arabian Shield Cooperative Insurance Company",
|
|
"is_vip": false
|
|
}
|
|
}
|
|
```
|
|
|
|
### 4. SMS Delivery
|
|
|
|
The survey is sent via SMS to the patient's phone number:
|
|
|
|
```python
|
|
from apps.surveys.services import SurveyDeliveryService
|
|
|
|
delivery_success = SurveyDeliveryService.deliver_survey(survey)
|
|
```
|
|
|
|
**SMS Message Format:**
|
|
|
|
```
|
|
Thank you for visiting Al Hammadi Hospital! Please complete our survey at:
|
|
[Survey URL]
|
|
|
|
Your feedback helps us improve our services.
|
|
```
|
|
|
|
## Testing
|
|
|
|
### Automated Tests
|
|
|
|
Run the test script to verify integration:
|
|
|
|
```bash
|
|
python test_simplified_survey_integration.py
|
|
```
|
|
|
|
**Test Coverage:**
|
|
|
|
1. ✅ OPD patients receive OPD surveys
|
|
2. ✅ Inpatient patients receive Inpatient surveys
|
|
3. ✅ EMS patients receive EMS surveys
|
|
4. ✅ Non-discharged patients don't receive surveys
|
|
5. ✅ Alternative PatientType codes (O, E) work correctly
|
|
6. ✅ Survey metadata is stored correctly
|
|
|
|
### Manual Testing
|
|
|
|
**Test 1: OPD Patient Survey**
|
|
|
|
```python
|
|
from apps.integrations.services.his_adapter import HISAdapter
|
|
|
|
his_data = {
|
|
"FetchPatientDataTimeStampList": [{
|
|
"PatientID": "TEST-001",
|
|
"AdmissionID": "ADM-TEST-001",
|
|
"HospitalName": "Al Hammadi Hospital - Main",
|
|
"PatientType": "2", # OPD
|
|
"AdmitDate": "05-Jun-2025 11:06",
|
|
"DischargeDate": "05-Jun-2025 16:30",
|
|
"PatientName": "Test Patient",
|
|
"MobileNo": "0512345678",
|
|
...
|
|
}],
|
|
"FetchPatientDataTimeStampVisitDataList": [],
|
|
"Code": 200,
|
|
"Status": "Success"
|
|
}
|
|
|
|
result = HISAdapter.process_his_data(his_data)
|
|
print(f"Success: {result['success']}")
|
|
print(f"Survey: {result['survey']}")
|
|
print(f"Survey URL: {result['survey_url']}")
|
|
```
|
|
|
|
**Test 2: Non-Discharged Patient**
|
|
|
|
```python
|
|
his_data_no_discharge = {
|
|
"FetchPatientDataTimeStampList": [{
|
|
"PatientID": "TEST-002",
|
|
"AdmissionID": "ADM-TEST-002",
|
|
"HospitalName": "Al Hammadi Hospital - Main",
|
|
"PatientType": "2",
|
|
"AdmitDate": "05-Jun-2025 11:06",
|
|
"DischargeDate": None, # Not discharged
|
|
"PatientName": "Test Patient 2",
|
|
"MobileNo": "0512345679",
|
|
...
|
|
}],
|
|
"FetchPatientDataTimeStampVisitDataList": [],
|
|
"Code": 200,
|
|
"Status": "Success"
|
|
}
|
|
|
|
result = HISAdapter.process_his_data(his_data_no_discharge)
|
|
print(f"Result: {result['message']}")
|
|
# Expected: "Patient not discharged - no survey sent"
|
|
```
|
|
|
|
## Configuration
|
|
|
|
### Required Survey Templates
|
|
|
|
Each hospital must have at least one survey template for each patient type:
|
|
|
|
```bash
|
|
# Check existing survey templates
|
|
python manage.py shell
|
|
>>> from apps.surveys.models import SurveyTemplate
|
|
>>> SurveyTemplate.objects.filter(hospital__code="ALH-main").values_list('name', 'is_active')
|
|
```
|
|
|
|
### SMS Configuration
|
|
|
|
Ensure SMS delivery is configured in `apps/surveys/services.py`:
|
|
|
|
```python
|
|
class SurveyDeliveryService:
|
|
@staticmethod
|
|
def deliver_survey(survey: SurveyInstance) -> bool:
|
|
# SMS delivery implementation
|
|
# Returns True if successful, False otherwise
|
|
pass
|
|
```
|
|
|
|
### Logging
|
|
|
|
Enable logging to track survey delivery:
|
|
|
|
```python
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
logger.info(f"Survey {survey.id} sent to {survey.patient.get_full_name()}")
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Issue: Survey Not Created
|
|
|
|
**Check:**
|
|
1. Patient has discharge date
|
|
2. Survey template exists for PatientType
|
|
3. Hospital is active
|
|
|
|
**Debug:**
|
|
|
|
```python
|
|
result = HISAdapter.process_his_data(his_data)
|
|
print(f"Message: {result['message']}")
|
|
print(f"Success: {result['success']}")
|
|
```
|
|
|
|
### Issue: Wrong Survey Type
|
|
|
|
**Check:**
|
|
1. Survey template name contains PatientType (OPD, INPATIENT, EMS)
|
|
2. Template is active (`is_active=True`)
|
|
3. Template belongs to correct hospital
|
|
|
|
### Issue: SMS Not Delivered
|
|
|
|
**Check:**
|
|
1. Patient phone number is valid
|
|
2. SMS service is configured
|
|
3. Check logs for delivery errors
|
|
|
|
```python
|
|
# Check delivery status
|
|
survey = SurveyInstance.objects.get(id=survey_id)
|
|
print(f"Status: {survey.status}")
|
|
print(f"Delivery Channel: {survey.delivery_channel}")
|
|
```
|
|
|
|
### Issue: Duplicate Surveys
|
|
|
|
The system prevents duplicate surveys for the same admission:
|
|
|
|
```python
|
|
# Check if survey already exists
|
|
existing_survey = SurveyInstance.objects.filter(
|
|
patient=patient,
|
|
hospital=hospital,
|
|
metadata__admission_id="ADM-001"
|
|
).first()
|
|
```
|
|
|
|
## Monitoring
|
|
|
|
### Key Metrics to Track
|
|
|
|
1. **Survey Creation Rate**: Surveys created per day
|
|
2. **Survey Delivery Rate**: SMS delivery success rate
|
|
3. **Survey Response Rate**: Patient response rate
|
|
4. **Patient Type Distribution**: OPD/Inpatient/EMS breakdown
|
|
|
|
### Database Queries
|
|
|
|
```sql
|
|
-- Surveys created today
|
|
SELECT
|
|
COUNT(*) as total_surveys,
|
|
COUNT(DISTINCT patient_id) as unique_patients
|
|
FROM surveys_surveyinstance
|
|
WHERE DATE(created_at) = CURRENT_DATE;
|
|
|
|
-- Surveys by patient type
|
|
SELECT
|
|
JSON_VALUE(metadata, '$.patient_type') as patient_type,
|
|
COUNT(*) as count
|
|
FROM surveys_surveyinstance
|
|
WHERE DATE(created_at) = CURRENT_DATE
|
|
GROUP BY patient_type;
|
|
|
|
-- Survey delivery status
|
|
SELECT
|
|
status,
|
|
COUNT(*) as count
|
|
FROM surveys_surveyinstance
|
|
WHERE DATE(created_at) = CURRENT_DATE
|
|
GROUP BY status;
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
1. **Survey Template Names**: Use clear names containing patient type
|
|
- ✅ "OPD Survey", "INPATIENT Survey", "EMS Survey"
|
|
- ❌ "Patient Survey", "Feedback Survey"
|
|
|
|
2. **Discharge Detection**: Only send surveys after discharge
|
|
- Always check `DischargeDate` field
|
|
- Don't send surveys for active admissions
|
|
|
|
3. **Duplicate Prevention**: Check existing surveys before creating new ones
|
|
- Use `admission_id` in metadata to prevent duplicates
|
|
|
|
4. **Metadata Storage**: Store relevant patient information in metadata
|
|
- PatientType, AdmissionID, InsuranceCompany, VIP status
|
|
|
|
5. **SMS Delivery**: Use reliable SMS service with retry logic
|
|
- Handle delivery failures gracefully
|
|
- Log all delivery attempts
|
|
|
|
## Migration from Journey-Based System
|
|
|
|
If migrating from the complex journey-based system:
|
|
|
|
1. **Keep Journey Models**: Don't delete journey models - they may be useful for analytics
|
|
2. **Update HIS Adapter**: Use simplified `process_his_data()` method
|
|
3. **Remove Journey Creation**: No need to create `PatientJourneyInstance`
|
|
4. **Direct Survey Creation**: Create surveys directly based on PatientType
|
|
5. **Testing**: Run comprehensive tests to ensure surveys are created correctly
|
|
|
|
## API Endpoints
|
|
|
|
### Receive HIS Patient Data
|
|
|
|
**Endpoint:** `POST /api/simulator/his-patient-data/`
|
|
|
|
**Request Body:**
|
|
|
|
```json
|
|
{
|
|
"FetchPatientDataTimeStampList": [{
|
|
"PatientID": "123456",
|
|
"PatientType": "2",
|
|
"DischargeDate": "05-Jun-2025 16:30",
|
|
...
|
|
}],
|
|
"FetchPatientDataTimeStampVisitDataList": [],
|
|
"Code": 200,
|
|
"Status": "Success"
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Patient data processed successfully",
|
|
"patient": {
|
|
"id": 1,
|
|
"name": "Ahmed Al-Saud"
|
|
},
|
|
"survey": {
|
|
"id": 1,
|
|
"status": "SENT",
|
|
"survey_url": "https://example.com/survey/abc123"
|
|
},
|
|
"survey_sent": true
|
|
}
|
|
```
|
|
|
|
## Summary
|
|
|
|
The simplified survey integration:
|
|
|
|
✅ **Direct Survey Delivery**: Surveys created immediately upon discharge
|
|
✅ **PatientType-Based**: Correct survey template selected automatically
|
|
✅ **SMS Delivery**: Surveys sent via SMS to patient's phone
|
|
✅ **Duplicate Prevention**: No duplicate surveys for same admission
|
|
✅ **Metadata Tracking**: Patient information stored for analytics
|
|
✅ **Easy Testing**: Comprehensive test suite available
|
|
✅ **Realistic Simulation**: HIS simulator generates realistic patient data
|
|
|
|
This simplified approach reduces complexity while maintaining all essential functionality for survey delivery based on patient type. |