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)
- Create canonical
documentation/app (models + services). - Add/extend
inventory/services.py(record_stock_movement). - Resolve name collisions (keep canonical, remove others).
- Fix inventory leaks (remove stock-like fields in clinical apps; add FKs to inventory; route via services).
- Centralize notes/reports → replace with
documentation.Document+DocumentLink. - Resolve canonical conflicts (move models to expected owners).
- 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):
IntegrationLog→ integrationInventoryLocation→ inventoryQualityControl→ laboratoryInsuranceClaim→ billing
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_byas 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_byas 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_byas 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_byas 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_byas 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_byas 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_byas 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_byas 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_byas 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_byas 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_byas 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/ApprovalCommunicationLogF) 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 withdocumentation.Document; link viaDocumentLink.ReportExecution: replace withdocumentation.Document; link viaDocumentLink.
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 fieldscurrent_stock; add inventory FKs; userecord_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 withdocumentation.Document; link viaDocumentLink.NoteTemplate: replace withdocumentation.Document; link viaDocumentLink.
- Canonical conflicts:
Encounter: move tocore
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 withdocumentation.Document; link viaDocumentLink.
insurance_approvals
- Models detected (5):
InsuranceApprovalRequest,ApprovalDocument,ApprovalStatusHistory,ApprovalCommunicationLog,ApprovalTemplate - Inventory leak fixes:
InsuranceApprovalRequest: remove fieldsrequested_quantity,approved_quantity; add inventory FKs; userecord_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 fieldsquantity_used; add inventory FKs; userecord_stock_movement.
- Notes centralization:
SurgicalNote: replace withdocumentation.Document; link viaDocumentLink.SurgicalNoteTemplate: replace withdocumentation.Document; link viaDocumentLink.
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 withdocumentation.Document; link viaDocumentLink.
pharmacy
- Models detected (6):
Medication,Prescription,MedicationInventoryItem,DispenseRecord,MedicationAdministration,DrugInteraction - Inventory leak fixes:
Prescription: remove fieldsquantity_prescribed,quantity_unit; add inventory FKs; userecord_stock_movement.MedicationInventoryItem: remove fieldsmax_dispense_quantity; add inventory FKs; userecord_stock_movement.DispenseRecord: remove fieldsinventory_stock,quantity_dispensed,quantity_remaining; add inventory FKs; userecord_stock_movement.
quality
- Models detected (7):
QualityIndicator,QualityMeasurement,IncidentReport,RiskAssessment,AuditPlan,AuditFinding,ImprovementProject - Notes centralization:
IncidentReport: replace withdocumentation.Document; link viaDocumentLink.
radiology
- Models detected (6):
ImagingStudy,ImagingSeries,DICOMImage,RadiologyReport,ReportTemplate,ImagingOrder - Notes centralization:
RadiologyReport: replace withdocumentation.Document; link viaDocumentLink.ReportTemplate: replace withdocumentation.Document; link viaDocumentLink.
H) Smoke Tests (Post-Reset)
- Create Patient + Encounter.
- Inpatients: create Admission → create
ADMISSIONDocument linked to Admission. - Radiology: finalize Study →
RADIOLOGY_REPORTDocument linked as result. - Laboratory: publish narrative →
LAB_REPORTDocument linked to Order. - Pharmacy: dispense Item →
record_stock_movementISSUE; on_hand decreases; ledger row created. - Billing: create Claim → appears only in
billing; no duplicates inpatients. - Patient timeline: fetch all
documentation.Documentfor patient; verify docs appear.