CriticalReport Proxy
The CriticalReport Django proxy — parameter evaluation, email notification, single-report notify flow, and ES sync.
CriticalReport Proxy
File: report/proxies/critical_reports.py
CriticalReport is a Django proxy model that extends both LabReportRelation and AbstractEmail. It does not add DB columns — it adds behaviour on top of the existing LabReportRelation row.
class CriticalReport(LabReportRelation, AbstractEmail):
category_id_mapper = {"critical_notification": 648}
class Meta:
proxy = TrueMethod overview
| Method | Purpose |
|---|---|
get_critical_notification_setting() | Reads critical_notification_settings from Preferences (cached per lab) |
get_critical_report_params() | Evaluates each parameter against normal + critical bounds. Returns only critical parameters |
process_list_field() | Handles qualitative/list-type parameters — checks defaultDescription for is_critical == 2 flag |
notify_by_email() | Assembles recipient list, renders Jinja template, calls send_email() |
notify_organisation_by_email() | Org-specific email using CommunicationVariant if configured, falls back to orgEmail |
notify() | Single-report callout — sets status to CALLOUT_DONE, saves callout record, logs activity |
prepare_message() | Builds human-readable text for the activity log |
prepare_activity_log_dumped_json() | Builds structured JSON for ActivityLog.dumped_json |
save_critical_callout() | Thin delegate to CriticalCallout.save_critical_callout() |
after_save() | ES sync — pushes criticalValues + lastUpdated to patient_reports index |
Parameter evaluation
get_critical_report_params() is the core logic that determines which parameters in a report are in the critical range. It is called both for single-report notify and for the bulk manager's batch fetch.
Normal range check: lower_bound <= val <= upper_bound → skip (normal)
Critical range check: critical_lower <= val <= critical_upper → skip (abnormal but not critical)
If neither check passes, the parameter is critical.
Age and sex-aware bounds
When reportID.ageFlag is true, ValueRanges records are fetched filtered by lowerAge < patient.age <= upperAge. Matching age ranges override the format's bound fields before evaluation.
Bounds are gender-specific:
lowerBoundMale/upperBoundMale/criticalLowerMale/criticalUpperMalelowerBoundFemale/upperBoundFemale/criticalLowerFemale/criticalUpperFemale
Output per parameter
{
"value": 75.0,
"parameter_name": "WBC Count",
"reference_range": "100.0 - 200.0",
"critical_lower_bound": 50.0,
"critical_upper_bound": 250.0,
}Email notification
notify_by_email()
Builds the recipient list from the callout payload flags:
| Flag | Recipient email |
|---|---|
is_referral | bill.docId.docEmail |
is_patient | userDetailsId.email |
other.enable | other.email |
is_organization | orgId.orgEmail (comma-separated) or via CommunicationVariant |
HIPAA mode (show_patient_name=True): patient name is appended to the email subject.
share_comment setting: comment is passed into the Jinja template only if the lab setting is on.
Email subject for single-report callout:
Critical Results Alert from {lab_name} for Accession Number {accession_no}The subject is overridden by the bulk manager when called from BulkCriticalCalloutManager.trigger_email():
Critical Results Alert from {lab_name} for Order ID - {labBillId}notify_organisation_by_email()
If the organisation has a CommunicationVariant configured for EMAIL_TRIGGERS.ORGANIZATION_CRITICAL_CALLOUT, it uses that variant's custom subject and template. Otherwise falls through to orgEmail in the main flow.
Single-report notify() flow
notify() is the legacy single-report path. The bulk manager bypasses it and calls notify_by_email() directly.
after_save() — ES sync
Called automatically by the Django model save() hook. Updates the patient_reports Elasticsearch index for the saved report:
client.update_by_query(
index="patient_reports",
filters={"bool": {"filter": [
{"term": {"labReportId": self.labReportId}},
{"term": {"labId": self.labId_id}},
]}},
payload={
"criticalValues": self.criticalValues,
"lastUpdated": "<ISO timestamp>",
},
)This keeps the worklist's Elasticsearch data in sync after every single-report status change. For bulk callouts, BillSplitManager.sync_lab_reports() handles the full bill-level sync.