HH/apps/integrations/serializers.py
2026-03-28 14:03:56 +03:00

261 lines
9.2 KiB
Python

"""
Integrations serializers
"""
from rest_framework import serializers
from .models import EventMapping, InboundEvent, IntegrationConfig, SurveyTemplateMapping
class InboundEventSerializer(serializers.ModelSerializer):
"""Inbound event serializer"""
class Meta:
model = InboundEvent
fields = [
"id",
"source_system",
"event_code",
"encounter_id",
"patient_identifier",
"payload_json",
"status",
"received_at",
"processed_at",
"error",
"processing_attempts",
"physician_license",
"department_code",
"metadata",
"created_at",
"updated_at",
]
read_only_fields = [
"id",
"status",
"received_at",
"processed_at",
"error",
"processing_attempts",
"metadata",
"created_at",
"updated_at",
]
class InboundEventCreateSerializer(serializers.ModelSerializer):
"""
Serializer for creating inbound events via API.
External systems POST to /api/integrations/events/ with:
{
"source_system": "his",
"event_code": "OPD_VISIT_COMPLETED",
"encounter_id": "ENC123456",
"patient_identifier": "MRN789",
"payload_json": {
"physician_license": "PHY001",
"department_code": "DEPT_OPD",
"timestamp": "2025-12-14T10:30:00Z",
...
}
}
"""
class Meta:
model = InboundEvent
fields = ["source_system", "event_code", "encounter_id", "patient_identifier", "payload_json"]
def create(self, validated_data):
"""
Create event and extract context from payload.
Event will be processed asynchronously by Celery task.
"""
payload = validated_data.get("payload_json", {})
# Extract physician and department from payload
validated_data["physician_license"] = payload.get("physician_license", "")
validated_data["department_code"] = payload.get("department_code", "")
event = InboundEvent.objects.create(**validated_data)
# Queue event for processing (will be implemented in tasks.py)
# from apps.integrations.tasks import process_inbound_event
# process_inbound_event.delay(event.id)
return event
class InboundEventListSerializer(serializers.ModelSerializer):
"""Simplified inbound event serializer for list views"""
class Meta:
model = InboundEvent
fields = ["id", "source_system", "event_code", "encounter_id", "status", "processing_attempts", "received_at"]
class EventMappingSerializer(serializers.ModelSerializer):
"""Event mapping serializer"""
integration_name = serializers.CharField(source="integration_config.name", read_only=True)
class Meta:
model = EventMapping
fields = [
"id",
"integration_config",
"integration_name",
"external_event_code",
"internal_event_code",
"field_mappings",
"is_active",
"created_at",
"updated_at",
]
read_only_fields = ["id", "created_at", "updated_at"]
class SurveyTemplateMappingSerializer(serializers.ModelSerializer):
"""Survey template mapping serializer"""
hospital_name = serializers.CharField(source="hospital.name", read_only=True)
survey_template_name = serializers.CharField(source="survey_template.name", read_only=True)
patient_type_display = serializers.CharField(source="get_patient_type_display", read_only=True)
class Meta:
model = SurveyTemplateMapping
fields = [
"id",
"hospital",
"hospital_name",
"patient_type",
"patient_type_display",
"survey_template",
"survey_template_name",
"is_active",
"created_at",
"updated_at",
]
read_only_fields = ["id", "created_at", "updated_at"]
class IntegrationConfigSerializer(serializers.ModelSerializer):
"""Integration configuration serializer"""
event_mappings = EventMappingSerializer(many=True, read_only=True)
class Meta:
model = IntegrationConfig
fields = [
"id",
"name",
"source_system",
"description",
"api_url",
"is_active",
"config_json",
"event_mappings",
"last_sync_at",
"created_at",
"updated_at",
]
read_only_fields = ["id", "last_sync_at", "created_at", "updated_at"]
extra_kwargs = {
"api_key": {"write_only": True} # Don't expose API key in responses
}
class HISPatientDemographicSerializer(serializers.Serializer):
"""Serializer for HIS patient demographic data"""
Type = serializers.CharField()
PatientID = serializers.CharField()
AdmissionID = serializers.CharField()
HospitalID = serializers.CharField(required=False, allow_blank=True)
HospitalName = serializers.CharField()
PatientType = serializers.CharField(required=False, allow_blank=True)
AdmitDate = serializers.CharField()
DischargeDate = serializers.CharField(required=False, allow_blank=True, allow_null=True)
RegCode = serializers.CharField(required=False, allow_blank=True)
SSN = serializers.CharField(required=False, allow_blank=True)
PatientName = serializers.CharField()
GenderID = serializers.CharField(required=False, allow_blank=True)
Gender = serializers.CharField(required=False, allow_blank=True)
FullAge = serializers.CharField(required=False, allow_blank=True)
PatientNationality = serializers.CharField(required=False, allow_blank=True)
MobileNo = serializers.CharField()
DOB = serializers.CharField(required=False, allow_blank=True)
ConsultantID = serializers.CharField(required=False, allow_blank=True)
PrimaryDoctor = serializers.CharField(required=False, allow_blank=True)
CompanyID = serializers.CharField(required=False, allow_blank=True)
GradeID = serializers.CharField(required=False, allow_blank=True)
CompanyName = serializers.CharField(required=False, allow_blank=True)
GradeName = serializers.CharField(required=False, allow_blank=True)
InsuranceCompanyName = serializers.CharField(required=False, allow_blank=True)
BillType = serializers.CharField(required=False, allow_blank=True)
IsVIP = serializers.CharField(required=False, allow_blank=True)
class HISVisitDataSerializer(serializers.Serializer):
"""Serializer for HIS visit/timeline data"""
Type = serializers.CharField()
BillDate = serializers.CharField()
PatientType = serializers.CharField(required=False, allow_blank=True)
AdmissionID = serializers.CharField(required=False, allow_blank=True)
PatientID = serializers.CharField(required=False, allow_blank=True)
RegCode = serializers.CharField(required=False, allow_blank=True)
SSN = serializers.CharField(required=False, allow_blank=True)
MobileNo = serializers.CharField(required=False, allow_blank=True)
class HISPatientDataSerializer(serializers.Serializer):
"""
Serializer for real HIS patient data format.
This validates the structure of HIS data received from the simulator
or actual HIS system.
Example structure:
{
"FetchPatientDataTimeStampList": [{...patient demographics...}],
"FetchPatientDataTimeStampVisitEDDataList": [...],
"FetchPatientDataTimeStampVisitIPDataList": [...],
"FetchPatientDataTimeStampVisitOPDataList": [...],
"Code": 200,
"Status": "Success",
"Message": "",
"Message2L": "",
"MobileNo": "",
"ValidateMessage": ""
}
"""
FetchPatientDataTimeStampList = HISPatientDemographicSerializer(many=True)
FetchPatientDataTimeStampVisitEDDataList = HISVisitDataSerializer(many=True, required=False)
FetchPatientDataTimeStampVisitIPDataList = HISVisitDataSerializer(many=True, required=False)
FetchPatientDataTimeStampVisitOPDataList = HISVisitDataSerializer(many=True, required=False)
FetchPatientDataTimeStampVisitDataList = HISVisitDataSerializer(many=True, required=False)
Code = serializers.IntegerField()
Status = serializers.CharField()
Message = serializers.CharField(required=False, allow_blank=True)
Message2L = serializers.CharField(required=False, allow_blank=True)
MobileNo = serializers.CharField(required=False, allow_blank=True)
ValidateMessage = serializers.CharField(required=False, allow_blank=True)
def validate(self, data):
"""Validate HIS data structure"""
# Validate status
if data.get("Code") != 200:
raise serializers.ValidationError(f"HIS returned error code: {data.get('Code')}")
if data.get("Status") != "Success":
raise serializers.ValidationError(f"HIS status not successful: {data.get('Status')}")
# Ensure patient data exists
patient_list = data.get("FetchPatientDataTimeStampList", [])
if not patient_list:
raise serializers.ValidationError("No patient data found in FetchPatientDataTimeStampList")
return data