Marwan Alwali ab2c4a36c5 update
2025-10-02 10:13:03 +03:00

190 lines
6.0 KiB
Python

"""
Constants for radiology app.
Centralized choices and validators for consistency across models.
"""
from django.db import models
from django.core.validators import RegexValidator
class RadiologyChoices:
"""Centralized choices for radiology models."""
class Modality(models.TextChoices):
CR = 'CR', 'Computed Radiography'
CT = 'CT', 'Computed Tomography'
MR = 'MR', 'Magnetic Resonance'
US = 'US', 'Ultrasound'
XA = 'XA', 'X-Ray Angiography'
RF = 'RF', 'Radiofluoroscopy'
DX = 'DX', 'Digital Radiography'
MG = 'MG', 'Mammography'
NM = 'NM', 'Nuclear Medicine'
PT = 'PT', 'Positron Emission Tomography'
OT = 'OT', 'Other'
class BodyPart(models.TextChoices):
HEAD = 'HEAD', 'Head'
NECK = 'NECK', 'Neck'
CHEST = 'CHEST', 'Chest'
ABDOMEN = 'ABDOMEN', 'Abdomen'
PELVIS = 'PELVIS', 'Pelvis'
SPINE = 'SPINE', 'Spine'
EXTREMITY = 'EXTREMITY', 'Extremity'
BREAST = 'BREAST', 'Breast'
HEART = 'HEART', 'Heart'
BRAIN = 'BRAIN', 'Brain'
WHOLE_BODY = 'WHOLE_BODY', 'Whole Body'
OTHER = 'OTHER', 'Other'
class Priority(models.TextChoices):
ROUTINE = 'ROUTINE', 'Routine'
URGENT = 'URGENT', 'Urgent'
STAT = 'STAT', 'STAT'
EMERGENCY = 'EMERGENCY', 'Emergency'
class ImageQuality(models.TextChoices):
EXCELLENT = 'EXCELLENT', 'Excellent'
GOOD = 'GOOD', 'Good'
ADEQUATE = 'ADEQUATE', 'Adequate'
POOR = 'POOR', 'Poor'
UNACCEPTABLE = 'UNACCEPTABLE', 'Unacceptable'
class StudyStatus(models.TextChoices):
SCHEDULED = 'SCHEDULED', 'Scheduled'
ARRIVED = 'ARRIVED', 'Arrived'
IN_PROGRESS = 'IN_PROGRESS', 'In Progress'
COMPLETED = 'COMPLETED', 'Completed'
INTERPRETED = 'INTERPRETED', 'Interpreted'
FINALIZED = 'FINALIZED', 'Finalized'
CANCELLED = 'CANCELLED', 'Cancelled'
class OrderStatus(models.TextChoices):
PENDING = 'PENDING', 'Pending'
SCHEDULED = 'SCHEDULED', 'Scheduled'
IN_PROGRESS = 'IN_PROGRESS', 'In Progress'
COMPLETED = 'COMPLETED', 'Completed'
CANCELLED = 'CANCELLED', 'Cancelled'
ON_HOLD = 'ON_HOLD', 'On Hold'
class ReportStatus(models.TextChoices):
DRAFT = 'DRAFT', 'Draft'
PRELIMINARY = 'PRELIMINARY', 'Preliminary'
FINAL = 'FINAL', 'Final'
AMENDED = 'AMENDED', 'Amended'
CORRECTED = 'CORRECTED', 'Corrected'
class CompletionStatus(models.TextChoices):
COMPLETE = 'COMPLETE', 'Complete'
PARTIAL = 'PARTIAL', 'Partial'
INCOMPLETE = 'INCOMPLETE', 'Incomplete'
class PatientPosition(models.TextChoices):
HFP = 'HFP', 'Head First-Prone'
HFS = 'HFS', 'Head First-Supine'
HFDR = 'HFDR', 'Head First-Decubitus Right'
HFDL = 'HFDL', 'Head First-Decubitus Left'
FFP = 'FFP', 'Feet First-Prone'
FFS = 'FFS', 'Feet First-Supine'
FFDR = 'FFDR', 'Feet First-Decubitus Right'
FFDL = 'FFDL', 'Feet First-Decubitus Left'
class ContrastRoute(models.TextChoices):
IV = 'IV', 'Intravenous'
ORAL = 'ORAL', 'Oral'
RECTAL = 'RECTAL', 'Rectal'
INTRATHECAL = 'INTRATHECAL', 'Intrathecal'
INTRA_ARTICULAR = 'INTRA_ARTICULAR', 'Intra-articular'
OTHER = 'OTHER', 'Other'
class RadiologyValidators:
"""Validators for radiology-specific fields."""
# DICOM UID validator - must be numeric with dots
dicom_uid_validator = RegexValidator(
regex=r'^[0-9]+(\.[0-9]+)*$',
message='Invalid DICOM UID format. Must contain only numbers and dots.'
)
# Accession number validator
accession_number_validator = RegexValidator(
regex=r'^[A-Z]{2,4}-\d{8}-\d{4}$',
message='Invalid accession number format. Expected format: RAD-YYYYMMDD-NNNN'
)
# Order number validator
order_number_validator = RegexValidator(
regex=r'^[A-Z]{3}-\d+-\d{6}$',
message='Invalid order number format. Expected format: IMG-TENANT-NNNNNN'
)
# DICOM Standard Constants
class DICOMConstants:
"""DICOM standard constants and mappings."""
# Common SOP Class UIDs
SOP_CLASS_UIDS = {
'CT_IMAGE': '1.2.840.10008.5.1.4.1.1.2',
'MR_IMAGE': '1.2.840.10008.5.1.4.1.1.4',
'US_IMAGE': '1.2.840.10008.5.1.4.1.1.6.1',
'CR_IMAGE': '1.2.840.10008.5.1.4.1.1.1',
'DX_IMAGE': '1.2.840.10008.5.1.4.1.1.1.1',
}
# Transfer Syntax UIDs
TRANSFER_SYNTAX_UIDS = {
'IMPLICIT_VR_LITTLE_ENDIAN': '1.2.840.10008.1.2',
'EXPLICIT_VR_LITTLE_ENDIAN': '1.2.840.10008.1.2.1',
'EXPLICIT_VR_BIG_ENDIAN': '1.2.840.10008.1.2.2',
'JPEG_BASELINE': '1.2.840.10008.1.2.4.50',
'JPEG_LOSSLESS': '1.2.840.10008.1.2.4.70',
}
# Standard image types
IMAGE_TYPES = {
'ORIGINAL': 'Original image',
'DERIVED': 'Derived image',
'SECONDARY': 'Secondary capture',
}
# Business Rules Constants
class RadiologyBusinessRules:
"""Business rules and constraints for radiology workflow."""
# Status transition rules
VALID_STATUS_TRANSITIONS = {
'SCHEDULED': ['ARRIVED', 'CANCELLED'],
'ARRIVED': ['IN_PROGRESS', 'CANCELLED'],
'IN_PROGRESS': ['COMPLETED', 'CANCELLED'],
'COMPLETED': ['INTERPRETED'],
'INTERPRETED': ['FINALIZED'],
'FINALIZED': ['AMENDED'],
'CANCELLED': [], # Terminal state
}
# Priority escalation rules
PRIORITY_ESCALATION_HOURS = {
'ROUTINE': 24,
'URGENT': 4,
'STAT': 1,
'EMERGENCY': 0.5,
}
# Critical finding communication requirements
CRITICAL_COMMUNICATION_TIMEFRAMES = {
'EMERGENCY': 15, # minutes
'STAT': 30, # minutes
'URGENT': 60, # minutes
'ROUTINE': 120, # minutes
}
# Quality thresholds
QUALITY_THRESHOLDS = {
'MIN_ACCEPTABLE': 'ADEQUATE',
'PREFERRED': 'GOOD',
'EXCELLENT': 'EXCELLENT',
}