hospital-management/tools/markdown/tenhal_detailed_refactor_plan.md
Marwan Alwali 263292f6be update
2025-11-04 00:50:06 +03:00

38 KiB

Tenhal — Detailed Step-by-Step Refactor Plan (Auto-generated)

Source artifacts: /mnt/data/model_map.json, /mnt/data/overlaps.json

This document details, model-by-model and field-by-field, what to add, what to remove, and how to route behavior via canonical services.

Apps scanned: 20
Total models found: 153 Name collisions: 4
Inventory leak flags: 6
Canonical conflicts: 1

Execution Order (Top-Level)

  1. Create canonical documentation/ app (models + services).
  2. Add/extend inventory/services.py (record_stock_movement).
  3. Resolve name collisions (keep canonical, remove others).
  4. Fix inventory leaks (remove stock-like fields in clinical apps; add FKs to inventory; route via services).
  5. Centralize notes/reports → replace with documentation.Document + DocumentLink.
  6. Resolve canonical conflicts (move models to expected owners).
  7. Drop DB, run migrations, and reseed; then smoke-test flows.

A) Name Collisions — Keep One Canonical Owner

Model App Action File Fields FKs M2Ms Canonical Owner
IntegrationLog core REMOVE (replace with FK/API to canonical) core/models.py tenant:ForeignKey, log_id:UUIDField, integration_type:CharField, direction:CharField, external_system:CharField, endpoint:CharField, message_type:CharField, message_id:CharField, correlation_id:UUIDField, request_data:TextField, response_data:TextField, status:CharField, error_code:CharField, error_message:TextField, processing_time_ms:PositiveIntegerField, timestamp:DateTimeField, created_at:DateTimeField Tenant none integration
IntegrationLog integration KEEP (canonical owner) integration/models.py log_id:UUIDField, external_system:ForeignKey, endpoint:ForeignKey, execution:ForeignKey, level:CharField, category:CharField, message:TextField, details:JSONField, correlation_id:CharField, user:ForeignKey, timestamp:DateTimeField, metadata:JSONField ExternalSystem, IntegrationEndpoint, IntegrationExecution, settings.AUTH_USER_MODEL none integration
InventoryLocation blood_bank REMOVE (replace with FK/API to canonical) blood_bank/models.py name:CharField, location_type:CharField, temperature_range:CharField, temperature:FloatField, capacity:PositiveIntegerField, current_stock:PositiveIntegerField, is_active:BooleanField, notes:TextField none none inventory
InventoryLocation inventory KEEP (canonical owner) inventory/models.py tenant:ForeignKey, location_id:UUIDField, location_code:CharField, name:CharField, description:TextField, location_type:CharField, building:CharField, floor:CharField, room:CharField, zone:CharField, aisle:CharField, shelf:CharField, bin:CharField, capacity_cubic_feet:DecimalField, max_weight_pounds:DecimalField, temperature_controlled:BooleanField, temperature_min:DecimalField, temperature_max:DecimalField, humidity_controlled:BooleanField, humidity_min:PositiveIntegerField, humidity_max:PositiveIntegerField, secure_location:BooleanField, access_control:CharField, is_active:BooleanField, parent_location:ForeignKey, location_manager:ForeignKey, notes:TextField, created_at:DateTimeField, updated_at:DateTimeField, created_by:ForeignKey core.Tenant, self, settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL none inventory
QualityControl blood_bank REMOVE (replace with FK/API to canonical) blood_bank/models.py test_type:CharField, test_date:DateTimeField, equipment_tested:CharField, parameters_tested:TextField, expected_results:TextField, actual_results:TextField, status:CharField, performed_by:ForeignKey, reviewed_by:ForeignKey, review_date:DateTimeField, review_notes:TextField, corrective_action:TextField, next_test_date:DateTimeField, capa_initiated:BooleanField, capa_number:CharField, capa_priority:CharField, capa_initiated_by:ForeignKey, capa_date:DateTimeField, capa_assessment:TextField, capa_status:CharField settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL none laboratory
QualityControl laboratory KEEP (canonical owner) laboratory/models.py tenant:ForeignKey, test:ForeignKey, result:ForeignKey, qc_id:UUIDField, control_material:CharField, control_lot:CharField, control_level:CharField, target_value:DecimalField, acceptable_range_low:DecimalField, acceptable_range_high:DecimalField, run_datetime:DateTimeField, observed_value:DecimalField, status:CharField, performed_by:ForeignKey, reviewed_by:ForeignKey, analyzer:CharField, comments:TextField, corrective_action:TextField, created_at:DateTimeField, updated_at:DateTimeField core.Tenant, LabTest, LabResult, settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL none laboratory
InsuranceClaim patients REMOVE (replace with FK/API to canonical) patients/models.py claim_number:CharField, patient:ForeignKey, insurance_info:ForeignKey, claim_type:CharField, status:CharField, priority:CharField, service_date:DateField, service_provider:CharField, service_provider_license:CharField, facility_name:CharField, facility_license:CharField, primary_diagnosis_code:CharField, primary_diagnosis_description:TextField, secondary_diagnosis_codes:JSONField, procedure_codes:JSONField, billed_amount:DecimalField, approved_amount:DecimalField, paid_amount:DecimalField, patient_responsibility:DecimalField, discount_amount:DecimalField, submitted_date:DateTimeField, processed_date:DateTimeField, payment_date:DateTimeField, saudi_id_number:CharField, insurance_card_number:CharField, authorization_number:CharField, denial_reason:TextField, denial_code:CharField, appeal_date:DateTimeField, appeal_reason:TextField, notes:TextField, attachments:JSONField, created_at:DateTimeField, updated_at:DateTimeField, created_by:ForeignKey PatientProfile, InsuranceInfo, settings.AUTH_USER_MODEL none billing
InsuranceClaim billing KEEP (canonical owner) billing/models.py medical_bill:ForeignKey, claim_id:UUIDField, claim_number:CharField, insurance_info:ForeignKey, claim_type:CharField, submission_date:DateField, service_date_from:DateField, service_date_to:DateField, billed_amount:DecimalField, allowed_amount:DecimalField, paid_amount:DecimalField, patient_responsibility:DecimalField, deductible_amount:DecimalField, coinsurance_amount:DecimalField, copay_amount:DecimalField, status:CharField, clearinghouse:CharField, batch_number:CharField, response_date:DateField, check_number:CharField, check_date:DateField, denial_reason:CharField, denial_code:CharField, prior_auth_number:CharField, notes:TextField, original_claim:ForeignKey, resubmission_count:PositiveIntegerField, created_at:DateTimeField, updated_at:DateTimeField, created_by:ForeignKey MedicalBill, patients.InsuranceInfo, self, settings.AUTH_USER_MODEL none billing

Canonical Owner Decisions (per duplicated model):

  • IntegrationLogintegration
  • InventoryLocationinventory
  • QualityControllaboratory
  • InsuranceClaimbilling

B) Inventory Leaks in Clinical Apps — Field-by-Field Remediation

blood_bank.InventoryLocation

File: blood_bank/models.py

  • Tokens detected: stock
  • Remove/rename fields (move semantics to Inventory): current_stock
  • Add FKs:
    • ForeignKey('inventory.Item', on_delete=PROTECT) # replace local item/sku fields
    • ForeignKey('inventory.StockLocation', on_delete=PROTECT) # replace local location/warehouse fields
  • Behavior: call inventory.services.record_stock_movement(...) instead of mutating local stock fields.

pharmacy.Prescription

File: pharmacy/models.py

  • Tokens detected: quantity
  • Remove/rename fields (move semantics to Inventory): quantity_prescribed, quantity_unit
  • Add FKs:
    • ForeignKey('inventory.Item', on_delete=PROTECT) # replace local item/sku fields
    • ForeignKey('inventory.StockLocation', on_delete=PROTECT) # replace local location/warehouse fields
  • Behavior: call inventory.services.record_stock_movement(...) instead of mutating local stock fields.

pharmacy.MedicationInventoryItem

File: pharmacy/models.py

  • Tokens detected: quantity
  • Remove/rename fields (move semantics to Inventory): max_dispense_quantity
  • Add FKs:
    • ForeignKey('inventory.Item', on_delete=PROTECT) # replace local item/sku fields
    • ForeignKey('inventory.StockLocation', on_delete=PROTECT) # replace local location/warehouse fields
  • Behavior: call inventory.services.record_stock_movement(...) instead of mutating local stock fields.

pharmacy.DispenseRecord

File: pharmacy/models.py

  • Tokens detected: quantity, stock
  • Remove/rename fields (move semantics to Inventory): inventory_stock, quantity_dispensed, quantity_remaining
  • Add FKs:
    • ForeignKey('inventory.Item', on_delete=PROTECT) # replace local item/sku fields
    • ForeignKey('inventory.StockLocation', on_delete=PROTECT) # replace local location/warehouse fields
  • Behavior: call inventory.services.record_stock_movement(...) instead of mutating local stock fields.

operating_theatre.EquipmentUsage

File: operating_theatre/models.py

  • Tokens detected: quantity
  • Remove/rename fields (move semantics to Inventory): quantity_used
  • Add FKs:
    • ForeignKey('inventory.Item', on_delete=PROTECT) # replace local item/sku fields
    • ForeignKey('inventory.StockLocation', on_delete=PROTECT) # replace local location/warehouse fields
  • Behavior: call inventory.services.record_stock_movement(...) instead of mutating local stock fields.

insurance_approvals.InsuranceApprovalRequest

File: insurance_approvals/models.py

  • Tokens detected: quantity
  • Remove/rename fields (move semantics to Inventory): requested_quantity, approved_quantity
  • Add FKs:
    • ForeignKey('inventory.Item', on_delete=PROTECT) # replace local item/sku fields
    • ForeignKey('inventory.StockLocation', on_delete=PROTECT) # replace local location/warehouse fields
  • Behavior: call inventory.services.record_stock_movement(...) instead of mutating local stock fields.

C) Notes & Reports Centralization — Model Replacement Plan

All the models below should be replaced by creating documentation.Document records and linking back via DocumentLink. Suggested mapping of field semantics:

patients.PatientNote

File: patients/models.py

  • Likely narrative fields → Document.body_markdown/body_json: title, content, category, priority
  • Keep metadata (author, timestamps) by setting authored_by, authored_at, signed_at/signed_by as needed.
  • Link to source domain object via DocumentLink(role='source'|'result'|'context').
  • Action: delete this model post-migration (DB reset allowed).

inpatients.DischargeSummary

File: inpatients/models.py

  • Likely narrative fields → Document.body_markdown/body_json: admission_diagnosis, final_diagnosis, secondary_diagnoses, procedures_performed, hospital_course, complications, discharge_medications, medication_changes, activity_restrictions, diet_instructions, wound_care, special_instructions, follow_up_appointments, follow_up_instructions, warning_signs, when_to_call, discharge_disposition, discharge_location, transportation_method, durable_medical_equipment, supplies_provided, education_provided, education_materials, patient_understanding, readmission_risk
  • Keep metadata (author, timestamps) by setting authored_by, authored_at, signed_at/signed_by as needed.
  • Link to source domain object via DocumentLink(role='source'|'result'|'context').
  • Action: delete this model post-migration (DB reset allowed).

emr.ClinicalNote

File: emr/models.py

  • Likely narrative fields → Document.body_markdown/body_json: note_type, title, content, structured_data, status, signature_method, amendment_reason, compliance_flags, access_restrictions
  • Keep metadata (author, timestamps) by setting authored_by, authored_at, signed_at/signed_by as needed.
  • Link to source domain object via DocumentLink(role='source'|'result'|'context').
  • Action: delete this model post-migration (DB reset allowed).

emr.NoteTemplate

File: emr/models.py

  • Likely narrative fields → Document.body_markdown/body_json: name, description, note_type, specialty, template_content, structured_fields, version, quality_indicators, compliance_requirements
  • Keep metadata (author, timestamps) by setting authored_by, authored_at, signed_at/signed_by as needed.
  • Link to source domain object via DocumentLink(role='source'|'result'|'context').
  • Action: delete this model post-migration (DB reset allowed).

radiology.RadiologyReport

File: radiology/models.py

  • Likely narrative fields → Document.body_markdown/body_json: clinical_history, technique, findings, impression, recommendations, status, structured_data, addendum
  • Keep metadata (author, timestamps) by setting authored_by, authored_at, signed_at/signed_by as needed.
  • Link to source domain object via DocumentLink(role='source'|'result'|'context').
  • Action: delete this model post-migration (DB reset allowed).

radiology.ReportTemplate

File: radiology/models.py

  • Likely narrative fields → Document.body_markdown/body_json: name, description, modality, body_part, clinical_history_template, technique_template, findings_template, impression_template, recommendations_template, structured_fields
  • Keep metadata (author, timestamps) by setting authored_by, authored_at, signed_at/signed_by as needed.
  • Link to source domain object via DocumentLink(role='source'|'result'|'context').
  • Action: delete this model post-migration (DB reset allowed).

operating_theatre.SurgicalNote

File: operating_theatre/models.py

  • Likely narrative fields → Document.body_markdown/body_json: preoperative_diagnosis, planned_procedure, indication, procedure_performed, surgical_approach, findings, technique, postoperative_diagnosis, condition, disposition, complications, blood_transfusion, specimens, implants, drains, closure, postop_instructions, follow_up, status
  • Keep metadata (author, timestamps) by setting authored_by, authored_at, signed_at/signed_by as needed.
  • Link to source domain object via DocumentLink(role='source'|'result'|'context').
  • Action: delete this model post-migration (DB reset allowed).

operating_theatre.SurgicalNoteTemplate

File: operating_theatre/models.py

  • Likely narrative fields → Document.body_markdown/body_json: name, description, procedure_type, specialty, preoperative_diagnosis_template, planned_procedure_template, indication_template, procedure_performed_template, surgical_approach_template, findings_template, technique_template, postoperative_diagnosis_template, complications_template, specimens_template, implants_template, closure_template, postop_instructions_template
  • Keep metadata (author, timestamps) by setting authored_by, authored_at, signed_at/signed_by as needed.
  • Link to source domain object via DocumentLink(role='source'|'result'|'context').
  • Action: delete this model post-migration (DB reset allowed).

analytics.Report

File: analytics/models.py

  • Likely narrative fields → Document.body_markdown/body_json: name, description, report_type, query_config, output_format, template_config, schedule_type, schedule_config, recipients, distribution_config
  • Keep metadata (author, timestamps) by setting authored_by, authored_at, signed_at/signed_by as needed.
  • Link to source domain object via DocumentLink(role='source'|'result'|'context').
  • Action: delete this model post-migration (DB reset allowed).

analytics.ReportExecution

File: analytics/models.py

  • Likely narrative fields → Document.body_markdown/body_json: execution_type, status, error_message, output_file_path, execution_parameters
  • Keep metadata (author, timestamps) by setting authored_by, authored_at, signed_at/signed_by as needed.
  • Link to source domain object via DocumentLink(role='source'|'result'|'context').
  • Action: delete this model post-migration (DB reset allowed).

quality.IncidentReport

File: quality/models.py

  • Likely narrative fields → Document.body_markdown/body_json: incident_number, title, description, incident_type, severity, category, location, witness_information, status, priority, root_cause, contributing_factors, corrective_actions, preventive_actions
  • Keep metadata (author, timestamps) by setting authored_by, authored_at, signed_at/signed_by as needed.
  • Link to source domain object via DocumentLink(role='source'|'result'|'context').
  • Action: delete this model post-migration (DB reset allowed).

D) Canonical Ownership Conflicts — Move to Expected App

Model Current App Expected Owner(s) File Fields FKs M2Ms
Encounter emr core emr/models.py objects:EncounterManager, tenant:ForeignKey, encounter_id:UUIDField, patient:ForeignKey, provider:ForeignKey, encounter_type:CharField, encounter_class:CharField, start_datetime:DateTimeField, end_datetime:DateTimeField, status:CharField, location:CharField, room_number:CharField, appointment:ForeignKey, admission:ForeignKey, chief_complaint:TextField, reason_for_visit:TextField, priority:CharField, acuity_level:PositiveIntegerField, documentation_complete:BooleanField, signed_off:BooleanField, signed_by:ForeignKey, signed_datetime:DateTimeField, billable:BooleanField, billing_codes:JSONField, quality_measures:JSONField, created_at:DateTimeField, updated_at:DateTimeField, created_by:ForeignKey core.Tenant, patients.PatientProfile, settings.AUTH_USER_MODEL, appointments.AppointmentRequest, inpatients.Admission, settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL none

Action: move the model(s) to listed expected owner apps; update all FKs/imports accordingly.

E) Reverse Dependency Hints (what references what)

Show reference map - `core.Tenant` ⟵ core:AuditLogEntry/SystemConfiguration/SystemNotification/IntegrationLog, patients:PatientProfile/ConsentTemplate, appointments:AppointmentRequest/SlotAvailability/WaitingQueue/AppointmentTemplate/WaitingList, inpatients:Ward/Admission, emr:Encounter/ProblemList/CarePlan/NoteTemplate/ClinicalRecommendation/AllergyAlert/TreatmentProtocol/ClinicalGuideline/CriticalAlert/DiagnosticSuggestion, pharmacy:Medication/Prescription/MedicationInventoryItem/DrugInteraction, laboratory:LabTest/LabOrder/QualityControl, radiology:ImagingStudy/ReportTemplate/ImagingOrder, operating_theatre:OperatingRoom/SurgicalNoteTemplate, billing:MedicalBill/BillingConfiguration, inventory:InventoryItem/InventoryLocation/PurchaseOrder/Supplier, hr:Employee/Department/TrainingPrograms, analytics:Dashboard/DataSource/Report/MetricDefinition, communications:Message/NotificationTemplate/AlertRule/CommunicationChannel, integration:ExternalSystem, quality:QualityIndicator/QualityMeasurement/IncidentReport/RiskAssessment/AuditPlan/AuditFinding/ImprovementProject, facility_management:Building/Vendor, insurance_approvals:InsuranceApprovalRequest/ApprovalTemplate - `settings.AUTH_USER_MODEL` ⟵ core:AuditLogEntry/SystemConfiguration/SystemNotification/SystemNotification, blood_bank:Donor/BloodUnit/BloodTest/BloodTest/CrossMatch/CrossMatch/BloodRequest/BloodRequest/BloodRequest/BloodIssue/BloodIssue/Transfusion/Transfusion/Transfusion/Transfusion/AdverseReaction/AdverseReaction/QualityControl/QualityControl/QualityControl, patients:PatientProfile/InsuranceClaim/ClaimDocument/ClaimStatusHistory/ConsentTemplate/ConsentForm/PatientNote, appointments:AppointmentRequest/AppointmentRequest/AppointmentRequest/AppointmentRequest/SlotAvailability/SlotAvailability/WaitingQueue/WaitingQueue/QueueEntry/QueueEntry/TelemedicineSession/AppointmentTemplate/WaitingList/WaitingList/WaitingList/WaitingListContactLog, inpatients:Ward/Ward/Ward/Bed/Bed/Bed/Admission/Admission/Admission/Admission/Admission/DischargeSummary/DischargeSummary/DischargeSummary/DischargeSummary/Transfer/Transfer/Transfer/Transfer, emr:Encounter/Encounter/Encounter/VitalSigns/VitalSigns/ProblemList/ProblemList/ProblemList/ProblemList/CarePlan/CarePlan/CarePlan/CarePlan/ClinicalNote/ClinicalNote/NoteTemplate/ClinicalRecommendation/ClinicalRecommendation/ClinicalRecommendation/ClinicalRecommendation/AllergyAlert/TreatmentProtocol/CriticalAlert/CriticalAlert/DiagnosticSuggestion/DiagnosticSuggestion, pharmacy:Medication/Prescription/Prescription/MedicationInventoryItem/DispenseRecord/DispenseRecord/MedicationAdministration/MedicationAdministration/MedicationAdministration/DrugInteraction, laboratory:LabTest/LabOrder/Specimen/Specimen/LabResult/LabResult/QualityControl/QualityControl/ReferenceRange, radiology:ImagingStudy/ImagingStudy/ImagingStudy/RadiologyReport/RadiologyReport/RadiologyReport/RadiologyReport/ReportTemplate/ImagingOrder, operating_theatre:OperatingRoom/ORBlock/ORBlock/ORBlock/SurgicalCase/SurgicalCase/SurgicalCase/SurgicalCase/SurgicalCase/SurgicalCase/SurgicalNote/EquipmentUsage/SurgicalNoteTemplate, billing:MedicalBill/MedicalBill/MedicalBill/BillLineItem/BillLineItem/InsuranceClaim/Payment/Payment/ClaimStatusUpdate/BillingConfiguration, inventory:InventoryItem/InventoryLocation/InventoryLocation/PurchaseOrder/PurchaseOrder/PurchaseOrder/Supplier, hr:Employee/Employee/Employee/Schedule/Schedule/TimeEntry/PerformanceReview/TrainingPrograms/TrainingSession/TrainingRecord/TrainingCertificates/TrainingCertificates, communications:Message/MessageRecipient/NotificationTemplate/AlertRule/AlertRule/AlertInstance/AlertInstance/CommunicationChannel, integration:ExternalSystem/IntegrationEndpoint/DataMapping/IntegrationExecution/WebhookEndpoint/IntegrationLog, quality:QualityIndicator/QualityMeasurement/QualityMeasurement/IncidentReport/IncidentReport/RiskAssessment/RiskAssessment/AuditPlan/AuditPlan/AuditPlan/AuditFinding/AuditFinding/AuditFinding/ImprovementProject/ImprovementProject/ImprovementProject/ImprovementProject, facility_management:Building/Asset/MaintenanceRequest/MaintenanceRequest/MaintenanceSchedule/ServiceContract/Inspection/EnergyReading/SpaceReservation/SpaceReservation, insurance_approvals:InsuranceApprovalRequest/InsuranceApprovalRequest/InsuranceApprovalRequest/InsuranceApprovalRequest/ApprovalDocument/ApprovalStatusHistory/ApprovalCommunicationLog/ApprovalTemplate - `blood_bank.BloodGroup` ⟵ blood_bank:Donor/BloodUnit/BloodRequest - `blood_bank.Donor` ⟵ blood_bank:BloodUnit - `blood_bank.BloodComponent` ⟵ blood_bank:BloodUnit/BloodRequest - `blood_bank.BloodUnit` ⟵ blood_bank:BloodTest/CrossMatch/BloodIssue - `patients.PatientProfile` ⟵ blood_bank:CrossMatch/BloodRequest, patients:EmergencyContact/InsuranceInfo/InsuranceClaim/ConsentForm/PatientNote, appointments:AppointmentRequest/QueueEntry/WaitingList, inpatients:Admission/Transfer, emr:Encounter/VitalSigns/ProblemList/CarePlan/ClinicalNote/ClinicalRecommendation/AllergyAlert/CriticalAlert/DiagnosticSuggestion, pharmacy:Prescription/MedicationAdministration, laboratory:LabOrder, radiology:ImagingStudy/ImagingOrder, operating_theatre:SurgicalCase, billing:MedicalBill, quality:IncidentReport, insurance_approvals:InsuranceApprovalRequest - `hr.Department` ⟵ blood_bank:BloodRequest, appointments:WaitingList, hr:Employee/ScheduleAssignment/TimeEntry, quality:QualityIndicator/AuditPlan/ImprovementProject - `blood_bank.BloodRequest` ⟵ blood_bank:BloodIssue - `blood_bank.CrossMatch` ⟵ blood_bank:BloodIssue - `blood_bank.BloodIssue` ⟵ blood_bank:Transfusion - `blood_bank.Transfusion` ⟵ blood_bank:AdverseReaction - `hr.Employee` ⟵ patients:InsuranceInfo/ConsentForm, hr:Department/Department/Schedule/TimeEntry/PerformanceReview/TrainingPrograms/TrainingSession/TrainingRecord/TrainingCertificates - `patients.InsuranceInfo` ⟵ patients:InsuranceClaim, billing:MedicalBill/MedicalBill/InsuranceClaim, insurance_approvals:InsuranceApprovalRequest - `patients.InsuranceClaim` ⟵ patients:ClaimDocument/ClaimStatusHistory, billing:Payment/ClaimStatusUpdate - `patients.ConsentTemplate` ⟵ patients:ConsentForm - `appointments.WaitingQueue` ⟵ appointments:QueueEntry - `appointments.AppointmentRequest` ⟵ appointments:QueueEntry/TelemedicineSession/WaitingList, emr:Encounter - `appointments.WaitingList` ⟵ appointments:WaitingListContactLog - `facility_management.Building` ⟵ inpatients:Ward, facility_management:Floor/Asset/MaintenanceRequest/MaintenanceSchedule/ServiceContract/Inspection/EnergyMeter - `facility_management.Floor` ⟵ inpatients:Ward, facility_management:Room/Asset/MaintenanceRequest/Inspection - `inpatients.Ward` ⟵ inpatients:Bed/Admission/Transfer/Transfer - `inpatients.Admission` ⟵ inpatients:Bed/DischargeSummary/Transfer, emr:Encounter, operating_theatre:SurgicalCase, billing:MedicalBill - `facility_management.Asset` ⟵ inpatients:Bed, facility_management:MaintenanceRequest/MaintenanceSchedule/Inspection - `inpatients.Bed` ⟵ inpatients:Admission/Transfer/Transfer - `emr.Encounter` ⟵ emr:VitalSigns/ProblemList/ClinicalNote/ClinicalRecommendation/CriticalAlert, pharmacy:Prescription/MedicationAdministration, laboratory:LabOrder, radiology:ImagingStudy/ImagingOrder, operating_theatre:SurgicalCase, billing:MedicalBill - `emr.ProblemList` ⟵ emr:CarePlan/ClinicalNote/ClinicalRecommendation - `emr.NoteTemplate` ⟵ emr:ClinicalNote - `emr.CarePlan` ⟵ emr:ClinicalNote - `pharmacy.Medication` ⟵ pharmacy:Prescription/MedicationInventoryItem/DrugInteraction/DrugInteraction - `inventory.InventoryItem` ⟵ pharmacy:MedicationInventoryItem, inventory:InventoryStock/PurchaseOrderItem - `pharmacy.Prescription` ⟵ pharmacy:DispenseRecord/MedicationAdministration - `inventory.InventoryStock` ⟵ pharmacy:DispenseRecord - `laboratory.LabTest` ⟵ laboratory:LabOrder/LabResult/QualityControl/ReferenceRange - `laboratory.LabOrder` ⟵ laboratory:Specimen/LabResult - `laboratory.Specimen` ⟵ laboratory:LabResult - `laboratory.LabResult` ⟵ laboratory:QualityControl - `radiology.ImagingOrder` ⟵ radiology:ImagingStudy - `radiology.ImagingStudy` ⟵ radiology:ImagingSeries/RadiologyReport - `radiology.ImagingSeries` ⟵ radiology:DICOMImage - `radiology.ReportTemplate` ⟵ radiology:RadiologyReport - `operating_theatre.OperatingRoom` ⟵ operating_theatre:ORBlock - `operating_theatre.ORBlock` ⟵ operating_theatre:SurgicalCase - `operating_theatre.SurgicalCase` ⟵ operating_theatre:SurgicalNote/EquipmentUsage - `operating_theatre.SurgicalNoteTemplate` ⟵ operating_theatre:SurgicalNote - `billing.MedicalBill` ⟵ billing:BillLineItem/InsuranceClaim/Payment - `inventory.Supplier` ⟵ inventory:InventoryItem/InventoryStock/PurchaseOrder - `blood_bank.InventoryLocation` ⟵ inventory:InventoryStock/PurchaseOrder - `inventory.PurchaseOrder` ⟵ inventory:InventoryStock/PurchaseOrderItem - `hr.Schedule` ⟵ hr:ScheduleAssignment - `hr.TrainingPrograms` ⟵ hr:ProgramModule/ProgramPrerequisite/ProgramPrerequisite/TrainingSession/TrainingRecord/TrainingCertificates - `hr.TrainingSession` ⟵ hr:TrainingRecord - `hr.TrainingRecord` ⟵ hr:TrainingAttendance/TrainingAssessment/TrainingCertificates - `analytics.Dashboard` ⟵ analytics:DashboardWidget - `analytics.DataSource` ⟵ analytics:DashboardWidget/Report/MetricDefinition - `analytics.Report` ⟵ analytics:ReportExecution - `analytics.MetricDefinition` ⟵ analytics:MetricValue - `communications.Message` ⟵ communications:MessageRecipient/DeliveryLog - `communications.NotificationTemplate` ⟵ communications:AlertRule - `communications.AlertRule` ⟵ communications:AlertInstance - `communications.MessageRecipient` ⟵ communications:DeliveryLog - `communications.CommunicationChannel` ⟵ communications:DeliveryLog - `integration.ExternalSystem` ⟵ integration:IntegrationEndpoint/WebhookEndpoint/IntegrationLog - `integration.IntegrationEndpoint` ⟵ integration:DataMapping/IntegrationExecution/IntegrationLog - `integration.DataMapping` ⟵ integration:WebhookEndpoint - `integration.WebhookEndpoint` ⟵ integration:WebhookExecution - `integration.IntegrationExecution` ⟵ integration:IntegrationLog - `quality.QualityIndicator` ⟵ quality:QualityMeasurement - `quality.IncidentReport` ⟵ quality:RiskAssessment - `quality.AuditPlan` ⟵ quality:AuditFinding - `facility_management.AssetCategory` ⟵ facility_management:Asset - `facility_management.Room` ⟵ facility_management:Asset/MaintenanceRequest/MaintenanceSchedule/Inspection/SpaceReservation - `facility_management.MaintenanceType` ⟵ facility_management:MaintenanceRequest/MaintenanceSchedule - `facility_management.Vendor` ⟵ facility_management:ServiceContract - `facility_management.EnergyMeter` ⟵ facility_management:EnergyReading - `insurance_approvals.InsuranceApprovalRequest` ⟵ insurance_approvals:ApprovalDocument/ApprovalStatusHistory/ApprovalCommunicationLog

F) Service Stubs to Route Behavior

inventory/services.py

from django.db import transaction
from .models import Item, StockLocation, StockLedger

class StockMovementType:
    ISSUE = "ISSUE"
    RECEIPT = "RECEIPT"
    ADJUSTMENT = "ADJUSTMENT"
    TRANSFER = "TRANSFER"

@transaction.atomic
def record_stock_movement(*, tenant, item_id, location_id, qty, movement_type, reference=None, performed_by=None, note=""):
    item = Item.objects.select_for_update().get(id=item_id, tenant=tenant)
    loc = StockLocation.objects.select_for_update().get(id=location_id, tenant=tenant)
    if movement_type == StockMovementType.ISSUE:
        loc.on_hand = (loc.on_hand or 0) - qty
    elif movement_type == StockMovementType.RECEIPT:
        loc.on_hand = (loc.on_hand or 0) + qty
    loc.save(update_fields=["on_hand"])
    StockLedger.objects.create(
        tenant=tenant, item=item, location=loc, qty=qty, movement_type=movement_type,
        reference=str(reference or ""), note=note, performed_by=performed_by)
    return loc.on_hand

documentation/services.py

from django.utils import timezone
from django.contrib.contenttypes.models import ContentType
from .models import Document, DocumentLink, DocumentVersion

def create_document_and_link(*, tenant, patient, encounter=None, doc_type:str,
                             title:str, body_markdown:str="", body_json=None,
                             links=None, author=None, sign=False):
    doc = Document.objects.create(
        tenant=tenant, patient=patient, encounter=encounter,
        doc_type=doc_type, title=title, body_markdown=body_markdown,
        body_json=body_json or {}, authored_by=author,
        status="final" if sign else "draft",
        signed_at=timezone.now() if sign else None, signed_by=author if sign else None
    )
    DocumentVersion.objects.create(document=doc, version=1,
                                   snapshot_markdown=body_markdown,
                                   snapshot_json=body_json or {}, changed_by=author)
    for ln in links or []:
        ct = ContentType.objects.get(app_label=ln["app_label"], model=ln["model"].lower())
        DocumentLink.objects.create(document=doc, content_type=ct, object_id=str(ln["pk"]),
                                    role=ln.get("role", "context"))
    return doc

integration/services.py

def log_event(*, tenant, channel, payload, direction, status, ref=""):
    from .models import IntegrationLog
    return IntegrationLog.objects.create(
        tenant=tenant, channel=channel, payload=payload,
        direction=direction, status=status, ref=ref)

G) Per-App Checklist (Add / Remove / Modify)

accounts

  • Models detected (4): TwoFactorDevice, SocialAccount, UserSession, PasswordHistory

analytics

  • Models detected (7): Dashboard, DashboardWidget, DataSource, Report, ReportExecution, MetricDefinition, MetricValue
  • Notes centralization:
    • Report: replace with documentation.Document; link via DocumentLink.
    • ReportExecution: replace with documentation.Document; link via DocumentLink.

appointments

  • Models detected (8): AppointmentRequest, SlotAvailability, WaitingQueue, QueueEntry, TelemedicineSession, AppointmentTemplate, WaitingList, WaitingListContactLog

billing

  • Models detected (6): MedicalBill, BillLineItem, InsuranceClaim, Payment, ClaimStatusUpdate, BillingConfiguration
  • Collision actions:
    • InsuranceClaim → KEEP (canonical owner) (canonical: billing)

blood_bank

  • Models detected (12): BloodGroup, Donor, BloodComponent, BloodUnit, BloodTest, CrossMatch, BloodRequest, BloodIssue, Transfusion, AdverseReaction, InventoryLocation, QualityControl
  • Collision actions:
    • InventoryLocation → REMOVE (replace with FK/API to canonical) (canonical: inventory)
    • QualityControl → REMOVE (replace with FK/API to canonical) (canonical: laboratory)
  • Inventory leak fixes:
    • InventoryLocation: remove fields current_stock; add inventory FKs; use record_stock_movement.

communications

  • Models detected (7): Message, MessageRecipient, NotificationTemplate, AlertRule, AlertInstance, CommunicationChannel, DeliveryLog

core

  • Models detected (5): Tenant, AuditLogEntry, SystemConfiguration, SystemNotification, IntegrationLog
  • Collision actions:
    • IntegrationLog → REMOVE (replace with FK/API to canonical) (canonical: integration)

emr

  • Models detected (13): Encounter, VitalSigns, ProblemList, CarePlan, ClinicalNote, NoteTemplate, Icd10, ClinicalRecommendation, AllergyAlert, TreatmentProtocol, ClinicalGuideline, CriticalAlert, DiagnosticSuggestion
  • Notes centralization:
    • ClinicalNote: replace with documentation.Document; link via DocumentLink.
    • NoteTemplate: replace with documentation.Document; link via DocumentLink.
  • Canonical conflicts:
    • Encounter: move to core

facility_management

  • Models detected (14): Building, Floor, Room, AssetCategory, Asset, MaintenanceType, MaintenanceRequest, MaintenanceSchedule, Vendor, ServiceContract, Inspection, EnergyMeter, EnergyReading, SpaceReservation

hr

  • Models detected (14): Employee, Department, Schedule, ScheduleAssignment, TimeEntry, PerformanceReview, TrainingPrograms, ProgramModule, ProgramPrerequisite, TrainingSession, TrainingRecord, TrainingAttendance, TrainingAssessment, TrainingCertificates

inpatients

  • Models detected (5): Ward, Bed, Admission, DischargeSummary, Transfer
  • Notes centralization:
    • DischargeSummary: replace with documentation.Document; link via DocumentLink.

insurance_approvals

  • Models detected (5): InsuranceApprovalRequest, ApprovalDocument, ApprovalStatusHistory, ApprovalCommunicationLog, ApprovalTemplate
  • Inventory leak fixes:
    • InsuranceApprovalRequest: remove fields requested_quantity, approved_quantity; add inventory FKs; use record_stock_movement.

integration

  • Models detected (7): ExternalSystem, IntegrationEndpoint, DataMapping, IntegrationExecution, WebhookEndpoint, WebhookExecution, IntegrationLog
  • Collision actions:
    • IntegrationLog → KEEP (canonical owner) (canonical: integration)

inventory

  • Models detected (6): InventoryItem, InventoryStock, InventoryLocation, PurchaseOrder, PurchaseOrderItem, Supplier
  • Collision actions:
    • InventoryLocation → KEEP (canonical owner) (canonical: inventory)

laboratory

  • Models detected (6): LabTest, LabOrder, Specimen, LabResult, QualityControl, ReferenceRange
  • Collision actions:
    • QualityControl → KEEP (canonical owner) (canonical: laboratory)

operating_theatre

  • Models detected (6): OperatingRoom, ORBlock, SurgicalCase, SurgicalNote, EquipmentUsage, SurgicalNoteTemplate
  • Inventory leak fixes:
    • EquipmentUsage: remove fields quantity_used; add inventory FKs; use record_stock_movement.
  • Notes centralization:
    • SurgicalNote: replace with documentation.Document; link via DocumentLink.
    • SurgicalNoteTemplate: replace with documentation.Document; link via DocumentLink.

patients

  • Models detected (9): PatientProfile, EmergencyContact, InsuranceInfo, InsuranceClaim, ClaimDocument, ClaimStatusHistory, ConsentTemplate, ConsentForm, PatientNote
  • Collision actions:
    • InsuranceClaim → REMOVE (replace with FK/API to canonical) (canonical: billing)
  • Notes centralization:
    • PatientNote: replace with documentation.Document; link via DocumentLink.

pharmacy

  • Models detected (6): Medication, Prescription, MedicationInventoryItem, DispenseRecord, MedicationAdministration, DrugInteraction
  • Inventory leak fixes:
    • Prescription: remove fields quantity_prescribed, quantity_unit; add inventory FKs; use record_stock_movement.
    • MedicationInventoryItem: remove fields max_dispense_quantity; add inventory FKs; use record_stock_movement.
    • DispenseRecord: remove fields inventory_stock, quantity_dispensed, quantity_remaining; add inventory FKs; use record_stock_movement.

quality

  • Models detected (7): QualityIndicator, QualityMeasurement, IncidentReport, RiskAssessment, AuditPlan, AuditFinding, ImprovementProject
  • Notes centralization:
    • IncidentReport: replace with documentation.Document; link via DocumentLink.

radiology

  • Models detected (6): ImagingStudy, ImagingSeries, DICOMImage, RadiologyReport, ReportTemplate, ImagingOrder
  • Notes centralization:
    • RadiologyReport: replace with documentation.Document; link via DocumentLink.
    • ReportTemplate: replace with documentation.Document; link via DocumentLink.

H) Smoke Tests (Post-Reset)

  1. Create Patient + Encounter.
  2. Inpatients: create Admission → create ADMISSION Document linked to Admission.
  3. Radiology: finalize Study → RADIOLOGY_REPORT Document linked as result.
  4. Laboratory: publish narrative → LAB_REPORT Document linked to Order.
  5. Pharmacy: dispense Item → record_stock_movement ISSUE; on_hand decreases; ledger row created.
  6. Billing: create Claim → appears only in billing; no duplicates in patients.
  7. Patient timeline: fetch all documentation.Document for patient; verify docs appear.