Services Crelio App Architecture App Modules report Lab reports, signing workflow, smart reports, and reflex testing
Lab reports (LabReportRelation) - Report lifecycle and signing
Report values - Test results and parameters
Smart reports - AI-generated interpretive reports
Reflex testing - Automatic test triggering
Report formats - Display templates
Amendments - Report corrections and history
core/ - BaseModel, utilities
admin/ - Tests, doctors, departments
patient/ - Patient details
finance/ - Bill for report context
Billing logic (belongs in finance/)
Patient demographics (belongs in patient/)
Device interfacing (belongs in interfacing/)
Model Responsibility Key Fields Cross-App Relations LabReportRelationCore report entity isSigned, isApproved, syncStatuspatient.UserDetails, finance.BillingSmartReportInterpretive reports name, template, test_idsadmin.AllTestsReflexTestConfigurationAuto-trigger rules test, parameter_rules, is_activeadmin.AllTestsReportFormatDisplay configuration format_type, ranges, templateadmin.AllTestsReportAmendmentHistoryAudit trail previous_values, amended_byLabReportRelation
Key Methods:
Method Purpose after_save()Post-save processing validate_hooks()Validate report generation hooks prepare_report_filters()Build query filters fetch_org_records()Organization-scoped queries fetch_staff_records()Staff-scoped queries prepare_department_filters()Department access control update_lab_report_and_report_value_with_path()Update file paths
Status Fields:
Field Values Meaning isSigned0/1 Report signed by doctor isPartialSigned0/1 Partially signed isApproved0/1 Approved for release syncStatusVarious ES sync status
Key Methods:
Method Purpose before_save()Set timestamps after_save()Activity logging get_critical_parameters()Find out-of-range values compute_department_stats()Statistics by department prepare_context()Build report context generate_report()Render HTML/PDF get_graph()Generate matplotlib charts get_components()Fetch template components render_component()Render individual component
Key Methods:
Method Purpose validate_payload()Comprehensive validation save_reflex_test_config()Create configuration update_reflex_test_config()Update with rules get_reflex_test_configs()Fetch configurations create_parameter_rules()Create rule relations check_and_trigger_reflex_tests()Auto-trigger logic
Report logic is complex with:
Multiple signing states and workflows
Rule-based auto-triggering
Complex rendering with graphs
Department-based access control
All this requires consistent logic regardless of entry point.
Rule Type Trigger Condition RANGEValue in/out of normal range LISTValue matches list item DESCRIPTIVEText contains pattern CUSTOM_RANGEValue in custom bounds
# report/models/reflex_test_config.py
@ classmethod
def validate_payload (cls, payload, lab_id):
# Required fields
if not payload.get( "test_id" ):
raise ValidationError( "test_id is required" )
# Parameter rules validation
cls ._validate_range_parameter_rules(rules)
cls ._validate_reflex_tests_uniqueness(rules)
cls ._validate_test_ids_exist(test_id, reflex_ids, lab_id)
# report/models/reflex_test_config.py
@ classmethod
def get_reflex_test_configs (cls, lab_id, reflex_test_id = None ):
qs = cls .objects.filter(
lab_id = lab_id, is_active = True
).select_related(
"test"
).prefetch_related(
"reflextestparameterrules_set" ,
"reflextestparameterrules_set__reflex_tests"
)
return qs
# report/models/reflex_test_config.py
@ classmethod
@transaction.atomic
def update_reflex_test_config (cls, payload, reflex_test_id, session):
instance = cls .objects.get( id = reflex_test_id)
# Delete old rules
instance.reflextestparameterrules_set.all().delete()
# Create new rules
cls .create_parameter_rules(instance, rules)
instance.add_activity_log( "updated" , session = session)
Endpoint View Model Method GET /report/listReportListViewLabReportRelation.fetch_*_records()POST /report/signReportSignViewVia device results POST /report/amendAmendReportViewAtomic update GET /report/smart/{id}SmartReportViewSmartReport.generate_report()POST /report/reflexReflexConfigViewReflexTestConfiguration.save_*()
# report/views/smart_report.py
class SmartReportView ( GenericView ):
@transaction.atomic
def get (self, request, smart_report_id, bill_id, * args, ** kwargs):
smart_report = SmartReport.objects.get( id = smart_report_id)
bill = Billing.objects.get( pk = bill_id)
html = smart_report.generate_report(
request, bill, is_pdf = False
)
return HttpResponse(html)
Integration Direction Purpose Elasticsearch Outbound Report search/sync Fusion Worker Outbound Report notifications PDF Renderer Internal Report generation Matplotlib Internal Chart generation
Reports trigger notifications via CommunicationBase:
SMS on sign completion
WhatsApp with report link
Email with PDF attachment
# report/models/lab_report_relation.py
def after_save (self, * args, ** kwargs):
# Activity logging
# ES sync (if enabled)
# Webhook triggers
Import Used For patient.models.user_details.UserDetailsPatient info finance.models.billing.BillingBill context admin.masters.models.all_tests.AllTestsTest catalog admin.account.models.departments.DepartmentsAccess control
Table Volume Concern labReportRelationVery high Many per bill reportFormatHigh Per test/parameter smartReportMedium Per lab
[!WARNING]
SmartReport.generate_report() does synchronous matplotlib rendering. For large reports, consider:
Caching generated images
Async generation via Fusion
Pre-computing common graphs
# Use department filters
LabReportRelation.objects.filter(
labId_id = lab_id,
department_id__in = user_departments
).select_related(
"userDetailsId" ,
"billId"
)
Add model or extend LabReportRelation
Add format handling in ReportFormat
Create view for rendering
Register in URL patterns
Add to parameter type choices
Add validation in _validate_*_parameter_rules()
Add trigger logic in check_and_trigger_reflex_tests()
Create component template
Link via SmartReportComponentDetails
Implement render method
Use @transaction.atomic for rule updates
Validate rules before saving
Log activities for audit
Synchronous PDF generation in hot paths
N+1 queries in report lists
Skipping department access checks