ServicesCrelio AppArchitectureApp Modules

interfacing

Lab device integration, HL7/ASTM parsing, and result validation

Interfacing App Architecture

Domain Responsibility

What This App Owns

  • Device management - Lab analyzer configuration
  • Result parsing - HL7/ASTM message parsing
  • Result validation - Manual/auto review workflow
  • Format mapping - Device code to test mapping
  • QC integration - Quality control data

What It Depends On

  • core/ - BaseModel, utilities
  • admin/ - Tests, departments, labs
  • report/ - Lab reports for result assignment
  • finance/ - Billing for result context

What Should NOT Be Added Here

  • External vendor APIs (belongs in integration/)
  • Report rendering (belongs in report/)
  • Sample collection (belongs in accession/)

Model-Centric Design (Fat Models)

Key Models

ModelResponsibilityLinesKey Fields
DeviceAnalyzer configuration57772name, type, connection, lab_id
DeviceResultsValidationResult review workflow3338sample_id, parameter_code, value, status
DeviceFormatMappingCode translation11029device_code, test_id, format_id
DeviceTestMappingTest association6526device_id, test_id, machine_code
DeviceQcResultsValidationQC workflow15452QC-specific validation

Business Logic in Models

DeviceResultsValidation (interfacing/models/device_results_validation.py) - 3338 lines

Key Methods:

MethodPurposeLines
save_device_results()Store incoming results76-278
get_device_wise_results()Dashboard summary280-462
get_device_results()Fetch pending results464-565
release_parameters()Release to reports567-803
release_tox_parameters()Toxicology release805-1057
post_process_report()Auto-sign logic1117-1194
sign_or_save_report()Report signing1196-1302

Result Flow:

DeviceFormatMapping (interfacing/models/device_format_mapping.py) - 11029 lines

Purpose: Translate device-specific codes to internal test/parameter IDs.

MethodPurpose
get_mapping()Lookup by device code
create_or_update_mapping()Configure translation
validate_mapping()Check consistency

Why Fat Model Style Here

Device integration is complex:

  1. Multiple message formats (HL7, ASTM, proprietary)
  2. Two-phase validation (receive → validate → release)
  3. Post-processing rules (auto-sign, auto-approve)
  4. QC integration

All logic must be traceable for regulatory compliance.


Invariants & Data Rules

Validation States

StatusMeaningNext Action
PENDINGAwaiting reviewManual validation
VALIDATEDReviewed, ready to releaserelease_parameters()
RELEASEDAssigned to reportView report
REJECTEDRejected during reviewInvestigate/rerun

Device Rules

RuleEnforcement
Unique device code per labDB constraint
Valid format mapping requiredValidation before release
QC values within control limitsDeviceQcResultsValidation

Data Access Patterns

High-Volume Queries

# Get pending validation results
DeviceResultsValidation.objects.filter(
    device_id=device_id,
    lab_id=lab_id,
    status="PENDING",
    received_date__range=(from_date, to_date)
).select_related(
    "device",
    "lab_report_relation"
).order_by("-received_date")

Transaction Pattern

# interfacing/models/device_results_validation.py
@classmethod
def release_parameters(cls, lab_details, device_id, parameters):
    """Atomic release of validated parameters"""
    with transaction.atomic():
        # Update validation records
        for param in parameters:
            validation = cls.objects.get(pk=param["id"])
            validation.status = "RELEASED"
            validation.save()
            
            # Update lab report
            report = LabReportRelation.objects.get(pk=param["report_id"])
            report.update_value(param["value"])
            report.save()
        
        # Post-processing
        cls.post_process_report(report_detail, logs, lab_details)

API Layer (Wiring)

Endpoint Map

EndpointViewPurpose
GET /interfacing/devicesDeviceListViewList lab devices
GET /interfacing/results/pendingPendingResultsViewValidation queue
POST /interfacing/results/releaseReleaseViewRelease to reports
POST /interfacing/results/saveSaveResultsViewReceive from device
GET /interfacing/qc/resultsQcResultsViewQC data

Thin View Pattern

class ReleaseParametersView(GenericView):
    
    @transaction.atomic
    def post(self, request, device_id, *args, **kwargs):
        lab_details = {
            "lab_id": self.get_lab_id_from_session(request.session),
            "session": request.session,
            ...
        }
        
        DeviceResultsValidation.release_parameters(
            lab_details=lab_details,
            device_id=device_id,
            parameters=request.data.get("parameters", [])
        )
        
        return JsonResponse({"status": "success"})

Integrations

Device Communication

ProtocolHandlerDirection
HL7 v2.xHL7 parserInbound
ASTMASTM parserInbound
TCP/IPSocket handlerBidirectional
File watchFile processorInbound

Result to Report Flow


Side Effects & Hidden Coupling

Post-Processing Side Effects

# interfacing/models/device_results_validation.py
@classmethod
def post_process_report(cls, report_detail, logs, lab_details):
    """Apply lab-specific post-processing rules"""
    
    post_process_type = lab_details.get("post_process_type")
    
    if post_process_type == "SIGN_AUTOMATICALLY":
        cls.sign_or_save_report(report_detail, is_sign=True, ...)
    elif post_process_type == "SAVE_AND_NOTIFY":
        # Save and trigger notification
        ...

Cross-App Coupling

ImportUsed ForRisk
report.models.lab_report_relationReport updatesHigh
finance.models.billingBill contextMedium
admin.masters.models.all_testsTest mappingLow
admin.account.models.departmentsAccess controlLow

[!WARNING] DeviceResultsValidation has high coupling to report app. Changes to report structure require corresponding updates here.


Performance & Scaling Notes

Hot Tables

TableVolumeIndexes Needed
deviceResultsValidationVery highdevice_id, status, received_date
deviceFormatMappingHighdevice_id, machine_code
deviceLowLab-indexed

Query Optimization

# Use bulk operations for release
DeviceResultsValidation.objects.filter(
    id__in=parameter_ids
).update(status="RELEASED")

Background Jobs

  • Result parsing can be async via Fusion
  • Post-processing should be atomic
  • QC calculations can be batched

Safe Extension Guide

Adding New Device Type

  1. Add device configuration to Device model
  2. Create parser in device_parser.py
  3. Add format mappings
  4. Test with sample messages

Adding New Post-Processing Rule

  1. Add rule type to post_process_type choices
  2. Handle in post_process_report():
    elif post_process_type == "NEW_RULE":
        cls.handle_new_rule(report_detail, ...)

Adding New QC Rule

  1. Extend DeviceQcResultsValidation
  2. Add validation logic
  3. Update QC dashboard

Patterns to Follow

  • Atomic transactions for release/sign
  • Log all device communications
  • Validate mappings before release
  • Use bulk updates for performance

Patterns to Avoid

  • Synchronous parsing in request path
  • N+1 queries in result lists
  • Skipping format validation

File Map

On this page