495 lines
14 KiB
Markdown
495 lines
14 KiB
Markdown
# HIS Simulator - Complete Implementation Guide
|
|
|
|
## Overview
|
|
|
|
The HIS (Hospital Information System) Simulator is a comprehensive tool for testing the patient journey tracking system. It simulates real-world patient events from a hospital system and automatically triggers survey invitations when patients complete their journeys.
|
|
|
|
## What Was Implemented
|
|
|
|
### 1. HIS Events API Endpoint
|
|
**Location:** `apps/simulator/views.py` - `HISEventsAPIView`
|
|
|
|
A public API endpoint that receives patient journey events from external HIS systems:
|
|
- **URL:** `/api/simulator/his-events/`
|
|
- **Method:** POST
|
|
- **Authentication:** None (public for simulator testing)
|
|
- **Request Format:** JSON array of events
|
|
|
|
### 2. HIS Simulator Script
|
|
**Location:** `apps/simulator/his_simulator.py`
|
|
|
|
A continuous event generator that simulates patient journeys:
|
|
- Generates realistic patient data (Saudi names, national IDs, phone numbers)
|
|
- Creates complete patient journeys (registration → discharge)
|
|
- Sends events to the API endpoint
|
|
- Configurable delay and patient count
|
|
|
|
### 3. Journey & Survey Seeding
|
|
**Location:** `apps/simulator/management/commands/seed_journey_surveys.py`
|
|
|
|
Management command that creates journey templates and surveys:
|
|
- EMS journey (4 stages)
|
|
- Inpatient journey (6 stages)
|
|
- OPD journey (5 stages)
|
|
- Survey templates with questions for each journey type
|
|
|
|
### 4. Event Processing Logic
|
|
When events are received:
|
|
1. Creates or finds patient records
|
|
2. Creates journey instance for new encounters
|
|
3. Completes stages based on event type
|
|
4. When journey is complete → creates survey instance
|
|
5. Sends survey invitation via email and SMS
|
|
|
|
## How It Works
|
|
|
|
### Event Flow
|
|
|
|
```
|
|
HIS System → API Endpoint → Event Processing → Journey Tracking → Survey Creation → Notification Delivery
|
|
```
|
|
|
|
### Supported Event Types
|
|
|
|
#### EMS Events
|
|
- `EMS_ARRIVAL` - Patient arrives at emergency
|
|
- `EMS_TRIAGE` - Triage completed
|
|
- `EMS_TREATMENT` - Treatment completed
|
|
- `EMS_DISCHARGE` - Patient discharged
|
|
|
|
#### Inpatient Events
|
|
- `INPATIENT_ADMISSION` - Patient admitted
|
|
- `INPATIENT_TREATMENT` - Treatment completed
|
|
- `INPATIENT_MONITORING` - Monitoring phase
|
|
- `INPATIENT_MEDICATION` - Medication administered
|
|
- `INPATIENT_LAB` - Lab tests completed
|
|
- `INPATIENT_DISCHARGE` - Patient discharged
|
|
|
|
#### OPD Events
|
|
- `OPD_STAGE_1_REGISTRATION` - Registration completed
|
|
- `OPD_STAGE_2_CONSULTATION` - Consultation completed
|
|
- `OPD_STAGE_3_LAB` - Lab tests completed
|
|
- `OPD_STAGE_4_RADIOLOGY` - Radiology completed
|
|
- `OPD_STAGE_5_PHARMACY` - Pharmacy/dispensing completed
|
|
|
|
## Quick Start
|
|
|
|
### 1. Seed Journey Templates and Surveys
|
|
|
|
```bash
|
|
cd /home/ismail/projects/HH
|
|
uv run python manage.py seed_journey_surveys
|
|
```
|
|
|
|
This creates:
|
|
- 3 journey templates (EMS, Inpatient, OPD)
|
|
- 3 survey templates with questions
|
|
- 18 survey questions total
|
|
|
|
### 2. Start Django Server
|
|
|
|
```bash
|
|
uv run python manage.py runserver
|
|
```
|
|
|
|
### 3. Run the Simulator
|
|
|
|
#### Option A: Using the Python Script (Continuous Mode)
|
|
|
|
```bash
|
|
# Simulate 5 patients with 2 seconds between events
|
|
uv run python apps/simulator/his_simulator.py --delay 2 --max-patients 5
|
|
|
|
# Continuous mode (unlimited patients, 1 second between events)
|
|
uv run python apps/simulator/his_simulator.py --delay 1 --max-patients 0
|
|
```
|
|
|
|
#### Option B: Using cURL (Single Request)
|
|
|
|
```bash
|
|
curl -X POST http://localhost:8000/api/simulator/his-events/ \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"events": [
|
|
{
|
|
"encounter_id": "TEST-001",
|
|
"mrn": "MRN-TEST-001",
|
|
"national_id": "1234567890",
|
|
"first_name": "Test",
|
|
"last_name": "Patient",
|
|
"phone": "+966501234567",
|
|
"email": "test@example.com",
|
|
"event_type": "OPD_STAGE_1_REGISTRATION",
|
|
"timestamp": "2026-01-20T10:30:00Z",
|
|
"visit_type": "opd",
|
|
"department": "Cardiology",
|
|
"branch": "Main"
|
|
},
|
|
{
|
|
"encounter_id": "TEST-001",
|
|
"mrn": "MRN-TEST-001",
|
|
"national_id": "1234567890",
|
|
"first_name": "Test",
|
|
"last_name": "Patient",
|
|
"phone": "+966501234567",
|
|
"email": "test@example.com",
|
|
"event_type": "OPD_STAGE_2_CONSULTATION",
|
|
"timestamp": "2026-01-20T11:00:00Z",
|
|
"visit_type": "opd",
|
|
"department": "Cardiology",
|
|
"branch": "Main"
|
|
}
|
|
]
|
|
}'
|
|
```
|
|
|
|
### 4. Verify Results
|
|
|
|
Check the Django logs for:
|
|
- Patient creation: `Created patient MRN-XXX: Full Name`
|
|
- Journey creation: `Created new journey instance XXX with N stages`
|
|
- Stage completion: `Completed stage StageName for journey ENC-XXX`
|
|
- Survey creation: `Created survey instance XXX for journey ENC-XXX`
|
|
- Email sent: `Survey invitation sent via email to email@example.com`
|
|
- SMS sent: `Survey invitation sent via SMS to +966XXXXXXXXX`
|
|
|
|
## API Specification
|
|
|
|
### POST /api/simulator/his-events/
|
|
|
|
**Request Body:**
|
|
|
|
```json
|
|
{
|
|
"events": [
|
|
{
|
|
"encounter_id": "string (required) - Unique encounter ID from HIS",
|
|
"mrn": "string (required) - Medical Record Number",
|
|
"national_id": "string (required) - Patient national ID",
|
|
"first_name": "string (required) - Patient first name",
|
|
"last_name": "string (required) - Patient last name",
|
|
"phone": "string (required) - Patient phone number",
|
|
"email": "string (required) - Patient email address",
|
|
"event_type": "string (required) - Event code (see supported events above)",
|
|
"timestamp": "string (required) - ISO 8601 timestamp",
|
|
"visit_type": "string (required) - Journey type: ems, inpatient, or opd",
|
|
"department": "string (optional) - Department name",
|
|
"branch": "string (optional) - Hospital branch",
|
|
"physician_name": "string (optional) - Physician name"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Success Response:**
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Processed 5 events successfully",
|
|
"results": [
|
|
{
|
|
"encounter_id": "TEST-001",
|
|
"patient_id": "uuid",
|
|
"journey_id": "uuid",
|
|
"stage_id": "uuid",
|
|
"stage_status": "completed",
|
|
"survey_sent": false
|
|
}
|
|
],
|
|
"surveys_sent": 1,
|
|
"survey_details": [
|
|
{
|
|
"encounter_id": "TEST-001",
|
|
"survey_id": "uuid",
|
|
"survey_url": "/surveys/XXXXX/"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Testing Scenarios
|
|
|
|
### Scenario 1: Complete OPD Journey
|
|
|
|
Test a full OPD patient journey that triggers a survey:
|
|
|
|
```bash
|
|
curl -X POST http://localhost:8000/api/simulator/his-events/ \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"events": [
|
|
{
|
|
"encounter_id": "OPD-TEST-001",
|
|
"mrn": "OPD-MRN-001",
|
|
"national_id": "1234567891",
|
|
"first_name": "Ahmed",
|
|
"last_name": "Al-Rashid",
|
|
"phone": "+966501234568",
|
|
"email": "ahmed@example.com",
|
|
"event_type": "OPD_STAGE_1_REGISTRATION",
|
|
"timestamp": "2026-01-20T10:00:00Z",
|
|
"visit_type": "opd",
|
|
"department": "Cardiology",
|
|
"branch": "Main"
|
|
},
|
|
{
|
|
"encounter_id": "OPD-TEST-001",
|
|
"mrn": "OPD-MRN-001",
|
|
"national_id": "1234567891",
|
|
"first_name": "Ahmed",
|
|
"last_name": "Al-Rashid",
|
|
"phone": "+966501234568",
|
|
"email": "ahmed@example.com",
|
|
"event_type": "OPD_STAGE_2_CONSULTATION",
|
|
"timestamp": "2026-01-20T11:00:00Z",
|
|
"visit_type": "opd",
|
|
"department": "Cardiology",
|
|
"branch": "Main"
|
|
},
|
|
{
|
|
"encounter_id": "OPD-TEST-001",
|
|
"mrn": "OPD-MRN-001",
|
|
"national_id": "1234567891",
|
|
"first_name": "Ahmed",
|
|
"last_name": "Al-Rashid",
|
|
"phone": "+966501234568",
|
|
"email": "ahmed@example.com",
|
|
"event_type": "OPD_STAGE_3_LAB",
|
|
"timestamp": "2026-01-20T12:00:00Z",
|
|
"visit_type": "opd",
|
|
"department": "Cardiology",
|
|
"branch": "Main"
|
|
},
|
|
{
|
|
"encounter_id": "OPD-TEST-001",
|
|
"mrn": "OPD-MRN-001",
|
|
"national_id": "1234567891",
|
|
"first_name": "Ahmed",
|
|
"last_name": "Al-Rashid",
|
|
"phone": "+966501234568",
|
|
"email": "ahmed@example.com",
|
|
"event_type": "OPD_STAGE_4_RADIOLOGY",
|
|
"timestamp": "2026-01-20T13:00:00Z",
|
|
"visit_type": "opd",
|
|
"department": "Cardiology",
|
|
"branch": "Main"
|
|
},
|
|
{
|
|
"encounter_id": "OPD-TEST-001",
|
|
"mrn": "OPD-MRN-001",
|
|
"national_id": "1234567891",
|
|
"first_name": "Ahmed",
|
|
"last_name": "Al-Rashid",
|
|
"phone": "+966501234568",
|
|
"email": "ahmed@example.com",
|
|
"event_type": "OPD_STAGE_5_PHARMACY",
|
|
"timestamp": "2026-01-20T14:00:00Z",
|
|
"visit_type": "opd",
|
|
"department": "Cardiology",
|
|
"branch": "Main"
|
|
}
|
|
]
|
|
}'
|
|
```
|
|
|
|
**Expected Result:**
|
|
- Patient created
|
|
- Journey instance created with 5 stages
|
|
- All 5 stages completed
|
|
- Survey instance created
|
|
- Survey invitation sent via email and SMS
|
|
|
|
### Scenario 2: Partial Journey
|
|
|
|
Test a partial journey that doesn't trigger a survey:
|
|
|
|
```bash
|
|
curl -X POST http://localhost:8000/api/simulator/his-events/ \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"events": [
|
|
{
|
|
"encounter_id": "PARTIAL-001",
|
|
"mrn": "PARTIAL-MRN-001",
|
|
"national_id": "1234567892",
|
|
"first_name": "Sara",
|
|
"last_name": "Al-Otaibi",
|
|
"phone": "+966501234569",
|
|
"email": "sara@example.com",
|
|
"event_type": "OPD_STAGE_1_REGISTRATION",
|
|
"timestamp": "2026-01-20T10:00:00Z",
|
|
"visit_type": "opd",
|
|
"department": "Cardiology",
|
|
"branch": "Main"
|
|
}
|
|
]
|
|
}'
|
|
```
|
|
|
|
**Expected Result:**
|
|
- Patient created
|
|
- Journey instance created with 5 stages
|
|
- Only 1 stage completed
|
|
- No survey created (journey incomplete)
|
|
|
|
## Database Verification
|
|
|
|
### Check Journey Instances
|
|
|
|
```python
|
|
from apps.journeys.models import PatientJourneyInstance, StageStatus
|
|
|
|
# Get all journeys
|
|
journeys = PatientJourneyInstance.objects.all()
|
|
for j in journeys:
|
|
print(f"{j.encounter_id}: {j.status} - {j.get_completion_percentage()}% complete")
|
|
|
|
# Check a specific journey
|
|
ji = PatientJourneyInstance.objects.get(encounter_id='OPD-TEST-001')
|
|
print(f"Status: {ji.status}")
|
|
print(f"Complete: {ji.is_complete()}")
|
|
print(f"Stages: {ji.stage_instances.filter(status=StageStatus.COMPLETED).count()}/{ji.stage_instances.count()}")
|
|
```
|
|
|
|
### Check Survey Instances
|
|
|
|
```python
|
|
from apps.surveys.models import SurveyInstance
|
|
from apps.journeys.models import PatientJourneyInstance
|
|
|
|
# Get all surveys
|
|
surveys = SurveyInstance.objects.all()
|
|
for s in surveys:
|
|
print(f"Survey: {s.id} - Journey: {s.journey_instance.encounter_id}")
|
|
print(f"URL: {s.get_survey_url()}")
|
|
print(f"Status: {s.status}")
|
|
|
|
# Get survey for a specific journey
|
|
ji = PatientJourneyInstance.objects.get(encounter_id='OPD-TEST-001')
|
|
si = SurveyInstance.objects.filter(journey_instance=ji).first()
|
|
if si:
|
|
print(f"Survey URL: {si.get_survey_url()}")
|
|
```
|
|
|
|
## Monitoring and Debugging
|
|
|
|
### Django Logs
|
|
|
|
Watch for these log messages:
|
|
|
|
**Patient Creation:**
|
|
```
|
|
Created patient MRN-XXX: Full Name
|
|
```
|
|
|
|
**Journey Creation:**
|
|
```
|
|
Created new journey instance XXX with N stages
|
|
```
|
|
|
|
**Stage Completion:**
|
|
```
|
|
Completed stage StageName for journey ENC-XXX
|
|
```
|
|
|
|
**Survey Creation:**
|
|
```
|
|
Created survey instance XXX for journey ENC-XXX
|
|
```
|
|
|
|
**Email Sending:**
|
|
```
|
|
[Email Simulator] Email sent successfully to email@example.com
|
|
Survey invitation sent via email to email@example.com
|
|
```
|
|
|
|
**SMS Sending:**
|
|
```
|
|
[SMS Simulator] SMS sent to +966XXXXXXXXX
|
|
Survey invitation sent via SMS to +966XXXXXXXXX
|
|
```
|
|
|
|
### Common Issues
|
|
|
|
#### Issue: "Journey template not found for visit_type"
|
|
**Solution:** Run the seed command: `uv run python manage.py seed_journey_surveys`
|
|
|
|
#### Issue: Survey not created after completing journey
|
|
**Solution:** Check that the journey template has `send_post_discharge_survey = True`
|
|
|
|
#### Issue: Email/SMS not sent
|
|
**Solution:** Check that the NotificationService is configured and the simulator endpoints are accessible
|
|
|
|
## Architecture
|
|
|
|
### Components
|
|
|
|
1. **HIS Events API** (`apps/simulator/views.py`)
|
|
- Receives events from external systems
|
|
- Validates event data
|
|
- Processes events sequentially
|
|
- Returns detailed response
|
|
|
|
2. **Event Processor** (`apps/simulator/views.py` - `process_his_event()`)
|
|
- Creates/updates patients
|
|
- Creates/updates journeys
|
|
- Completes stages
|
|
- Triggers surveys
|
|
|
|
3. **HIS Simulator Script** (`apps/simulator/his_simulator.py`)
|
|
- Generates patient data
|
|
- Creates event sequences
|
|
- Sends events to API
|
|
- Logs results
|
|
|
|
4. **Survey Notification Service** (`apps/integrations/services.py`)
|
|
- Sends email invitations
|
|
- Sends SMS invitations
|
|
- Tracks delivery status
|
|
|
|
### Data Flow
|
|
|
|
```
|
|
HIS System
|
|
↓
|
|
HIS Events API
|
|
↓
|
|
Event Processor
|
|
↓
|
|
Patient Manager (create/find patient)
|
|
↓
|
|
Journey Manager (create/find journey)
|
|
↓
|
|
Stage Manager (complete stage)
|
|
↓
|
|
Survey Manager (create survey if journey complete)
|
|
↓
|
|
Notification Service (send email & SMS)
|
|
```
|
|
|
|
## Future Enhancements
|
|
|
|
Potential improvements to the simulator:
|
|
|
|
1. **Real-time Event Stream:** WebSocket support for live event streaming
|
|
2. **Event Replay:** Ability to replay historical events for testing
|
|
3. **Error Handling:** Better error recovery and retry logic
|
|
4. **Metrics Dashboard:** Real-time metrics on event processing
|
|
5. **Batch Processing:** Support for large batch imports
|
|
6. **Event Validation:** More robust event data validation
|
|
7. **Custom Event Types:** Support for custom journey templates
|
|
|
|
## Summary
|
|
|
|
The HIS Simulator provides a complete testing environment for:
|
|
|
|
✅ Patient journey tracking
|
|
✅ Stage completion automation
|
|
✅ Survey triggering on journey completion
|
|
✅ Email and SMS notifications
|
|
✅ Real-time event processing
|
|
✅ Database verification
|
|
|
|
The system is production-ready for integration testing and can be easily extended for real HIS system integration.
|