from rest_framework import serializers from ..models import LabTest, LabOrder, Specimen, LabResult, QualityControl, ReferenceRange class BaseSerializer(serializers.ModelSerializer): """Base serializer with common functionality""" class Meta: fields = ['id'] read_only_fields = ['created_at', 'updated_at'] class LabTestSerializer(serializers.ModelSerializer): """Serializer for LabTest model""" category_display = serializers.CharField(source='get_category_display', read_only=True) specimen_type_display = serializers.CharField(source='get_specimen_type_display', read_only=True) class Meta: model = LabTest fields = [ 'test_id', 'code', 'name', 'description', 'category', 'category_display', 'specimen_type', 'specimen_type_display', 'specimen_volume', 'collection_instructions', 'processing_instructions', 'methodology', 'turnaround_time_hours', 'critical_value_low', 'critical_value_high', 'units', 'reference_range_text', 'interpretation_notes', 'requires_fasting', 'temperature_requirements', 'stability_hours', 'cost', 'cpt_code', 'loinc_code', 'is_active', 'created_at', 'updated_at' ] read_only_fields = ['test_id', 'created_at', 'updated_at'] class LabOrderSerializer(serializers.ModelSerializer): """Serializer for LabOrder model""" patient_name = serializers.CharField(source='patient.get_full_name', read_only=True) patient_mrn = serializers.CharField(source='patient.mrn', read_only=True) ordering_provider_name = serializers.CharField(source='ordering_provider.get_full_name', read_only=True) status_display = serializers.CharField(source='get_status_display', read_only=True) priority_display = serializers.CharField(source='get_priority_display', read_only=True) class Meta: model = LabOrder fields = [ 'order_id', 'order_number', 'patient', 'patient_name', 'patient_mrn', 'encounter', 'ordering_provider', 'ordering_provider_name', 'order_date', 'collection_scheduled_date', 'collection_date', 'collected_by', 'status', 'status_display', 'priority', 'priority_display', 'clinical_info', 'diagnosis_codes', 'fasting_required', 'special_instructions', 'collection_location', 'external_order_id', 'insurance_authorization', 'estimated_cost', 'notes', 'created_at', 'updated_at' ] read_only_fields = ['order_id', 'order_number', 'created_at', 'updated_at'] class SpecimenSerializer(serializers.ModelSerializer): """Serializer for Specimen model""" lab_order_number = serializers.CharField(source='lab_order.order_number', read_only=True) patient_name = serializers.CharField(source='lab_order.patient.get_full_name', read_only=True) specimen_type_display = serializers.CharField(source='get_specimen_type_display', read_only=True) status_display = serializers.CharField(source='get_status_display', read_only=True) collected_by_name = serializers.CharField(source='collected_by.get_full_name', read_only=True) received_by_name = serializers.CharField(source='received_by.get_full_name', read_only=True) class Meta: model = Specimen fields = [ 'specimen_id', 'specimen_number', 'lab_order', 'lab_order_number', 'patient_name', 'specimen_type', 'specimen_type_display', 'collection_date', 'collection_time', 'collected_by', 'collected_by_name', 'collection_site', 'collection_method', 'container_type', 'volume_collected', 'received_date', 'received_by', 'received_by_name', 'processing_started_date', 'processed_by', 'status', 'status_display', 'rejection_reason', 'rejected_by', 'rejected_date', 'storage_location', 'temperature_log', 'chain_of_custody', 'comments', 'created_at', 'updated_at' ] read_only_fields = ['specimen_id', 'specimen_number', 'created_at', 'updated_at'] class ReferenceRangeSerializer(serializers.ModelSerializer): """Serializer for ReferenceRange model""" lab_test_name = serializers.CharField(source='lab_test.name', read_only=True) class Meta: model = ReferenceRange fields = [ 'range_id', 'lab_test', 'lab_test_name', 'age_min', 'age_max', 'gender', 'reference_low', 'reference_high', 'critical_low', 'critical_high', 'units', 'population', 'methodology', 'effective_date', 'expiration_date', 'is_active', 'created_at', 'updated_at' ] read_only_fields = ['range_id', 'created_at', 'updated_at'] class LabResultSerializer(serializers.ModelSerializer): """Serializer for LabResult model""" lab_order_number = serializers.CharField(source='lab_order.order_number', read_only=True) patient_name = serializers.CharField(source='lab_order.patient.get_full_name', read_only=True) test_name = serializers.CharField(source='lab_test.name', read_only=True) specimen_number = serializers.CharField(source='specimen.specimen_number', read_only=True) status_display = serializers.CharField(source='get_status_display', read_only=True) result_status_display = serializers.CharField(source='get_result_status_display', read_only=True) performed_by_name = serializers.CharField(source='performed_by.get_full_name', read_only=True) verified_by_name = serializers.CharField(source='verified_by.get_full_name', read_only=True) is_critical = serializers.BooleanField(read_only=True) is_abnormal = serializers.BooleanField(read_only=True) class Meta: model = LabResult fields = [ 'result_id', 'lab_order', 'lab_order_number', 'patient_name', 'lab_test', 'test_name', 'specimen', 'specimen_number', 'result_value', 'result_text', 'units', 'reference_range', 'abnormal_flag', 'critical_flag', 'status', 'status_display', 'result_status', 'result_status_display', 'performed_date', 'performed_by', 'performed_by_name', 'verified_date', 'verified_by', 'verified_by_name', 'instrument_id', 'method_used', 'dilution_factor', 'quality_control_passed', 'comments', 'interpretation', 'is_critical', 'is_abnormal', 'created_at', 'updated_at' ] read_only_fields = [ 'result_id', 'is_critical', 'is_abnormal', 'created_at', 'updated_at' ] class QualityControlSerializer(serializers.ModelSerializer): """Serializer for QualityControl model""" lab_test_name = serializers.CharField(source='lab_test.name', read_only=True) control_type_display = serializers.CharField(source='get_control_type_display', read_only=True) status_display = serializers.CharField(source='get_status_display', read_only=True) performed_by_name = serializers.CharField(source='performed_by.get_full_name', read_only=True) class Meta: model = QualityControl fields = [ 'qc_id', 'lab_test', 'lab_test_name', 'control_type', 'control_type_display', 'control_lot', 'control_level', 'expected_value', 'acceptable_range_low', 'acceptable_range_high', 'measured_value', 'run_date', 'performed_by', 'performed_by_name', 'instrument_id', 'status', 'status_display', 'deviation_reason', 'corrective_action', 'comments', 'created_at', 'updated_at' ] read_only_fields = ['qc_id', 'created_at', 'updated_at'] class LabStatsSerializer(serializers.Serializer): """Serializer for laboratory statistics""" total_orders = serializers.IntegerField() pending_orders = serializers.IntegerField() completed_today = serializers.IntegerField() specimens_collected = serializers.IntegerField() results_pending = serializers.IntegerField() critical_results = serializers.IntegerField() turnaround_time_avg = serializers.FloatField() qc_pass_rate = serializers.FloatField() order_types = serializers.DictField() status_breakdown = serializers.DictField() class SpecimenCollectionSerializer(serializers.Serializer): """Serializer for specimen collection""" order_id = serializers.IntegerField() specimen_type = serializers.CharField() collection_site = serializers.CharField() collection_method = serializers.CharField() container_type = serializers.CharField() volume_collected = serializers.DecimalField(max_digits=8, decimal_places=2) comments = serializers.CharField(required=False, allow_blank=True) def validate_order_id(self, value): """Validate that the order exists and can have specimens collected""" try: order = LabOrder.objects.get(id=value) if order.status not in ['PENDING', 'SCHEDULED']: raise serializers.ValidationError( "Cannot collect specimen for order with current status." ) return value except LabOrder.DoesNotExist: raise serializers.ValidationError("Invalid order ID.") class ResultEntrySerializer(serializers.Serializer): """Serializer for entering lab results""" specimen_id = serializers.IntegerField() lab_test_id = serializers.IntegerField() result_value = serializers.CharField(required=False, allow_blank=True) result_text = serializers.CharField(required=False, allow_blank=True) abnormal_flag = serializers.CharField(required=False, allow_blank=True) critical_flag = serializers.BooleanField(default=False) instrument_id = serializers.CharField(required=False, allow_blank=True) method_used = serializers.CharField(required=False, allow_blank=True) comments = serializers.CharField(required=False, allow_blank=True) def validate(self, data): """Validate that either result_value or result_text is provided""" if not data.get('result_value') and not data.get('result_text'): raise serializers.ValidationError( "Either result_value or result_text must be provided." ) return data def validate_specimen_id(self, value): """Validate that the specimen exists and is ready for results""" try: specimen = Specimen.objects.get(id=value) if specimen.status != 'PROCESSING': raise serializers.ValidationError( "Specimen must be in processing status to enter results." ) return value except Specimen.DoesNotExist: raise serializers.ValidationError("Invalid specimen ID.") class ResultVerificationSerializer(serializers.Serializer): """Serializer for verifying lab results""" result_id = serializers.IntegerField() verification_comments = serializers.CharField(required=False, allow_blank=True) def validate_result_id(self, value): """Validate that the result exists and can be verified""" try: result = LabResult.objects.get(id=value) if result.status != 'PENDING_VERIFICATION': raise serializers.ValidationError( "Result must be pending verification to verify." ) return value except LabResult.DoesNotExist: raise serializers.ValidationError("Invalid result ID.")