524 lines
17 KiB
Python
524 lines
17 KiB
Python
# """
|
|
# Viewflow workflows for laboratory app.
|
|
# Provides lab test ordering, specimen processing, and result reporting workflows.
|
|
# """
|
|
#
|
|
# from viewflow import Flow, lock
|
|
# from viewflow.base import this, flow_func
|
|
# from viewflow.contrib import celery
|
|
# from viewflow.decorators import flow_view
|
|
# from viewflow.fields import CharField, ModelField
|
|
# from viewflow.forms import ModelForm
|
|
# from viewflow.views import CreateProcessView, UpdateProcessView
|
|
# from viewflow.models import Process, Task
|
|
# from django.contrib.auth.models import User
|
|
# from django.urls import reverse_lazy
|
|
# from django.utils import timezone
|
|
# from django.db import transaction
|
|
# from django.core.mail import send_mail
|
|
#
|
|
# from .models import LabOrder, Specimen, LabResult, LabTest
|
|
# from .views import (
|
|
# LabOrderCreationView, SpecimenCollectionView, SpecimenReceiptView,
|
|
# TestProcessingView, ResultEntryView, ResultVerificationView,
|
|
# ResultReportingView
|
|
# )
|
|
#
|
|
#
|
|
# class LabOrderProcess(Process):
|
|
# """
|
|
# Viewflow process model for laboratory test orders
|
|
# """
|
|
# lab_order = ModelField(LabOrder, help_text='Associated lab order')
|
|
#
|
|
# # Process status tracking
|
|
# order_created = models.BooleanField(default=False)
|
|
# specimen_collected = models.BooleanField(default=False)
|
|
# specimen_received = models.BooleanField(default=False)
|
|
# tests_processed = models.BooleanField(default=False)
|
|
# results_verified = models.BooleanField(default=False)
|
|
# results_reported = models.BooleanField(default=False)
|
|
#
|
|
# class Meta:
|
|
# verbose_name = 'Lab Order Process'
|
|
# verbose_name_plural = 'Lab Order Processes'
|
|
#
|
|
#
|
|
# class LabOrderFlow(Flow):
|
|
# """
|
|
# Laboratory Test Order Workflow
|
|
#
|
|
# This flow manages the complete laboratory testing process from
|
|
# order creation through result reporting.
|
|
# """
|
|
#
|
|
# process_class = LabOrderProcess
|
|
#
|
|
# # Flow definition
|
|
# start = (
|
|
# flow_func(this.start_lab_order)
|
|
# .Next(this.create_order)
|
|
# )
|
|
#
|
|
# create_order = (
|
|
# flow_view(LabOrderCreationView)
|
|
# .Permission('laboratory.can_create_orders')
|
|
# .Next(this.schedule_collection)
|
|
# )
|
|
#
|
|
# schedule_collection = (
|
|
# flow_func(this.schedule_specimen_collection)
|
|
# .Next(this.collect_specimen)
|
|
# )
|
|
#
|
|
# collect_specimen = (
|
|
# flow_view(SpecimenCollectionView)
|
|
# .Permission('laboratory.can_collect_specimens')
|
|
# .Next(this.transport_specimen)
|
|
# )
|
|
#
|
|
# transport_specimen = (
|
|
# flow_func(this.handle_specimen_transport)
|
|
# .Next(this.receive_specimen)
|
|
# )
|
|
#
|
|
# receive_specimen = (
|
|
# flow_view(SpecimenReceiptView)
|
|
# .Permission('laboratory.can_receive_specimens')
|
|
# .Next(this.check_specimen_quality)
|
|
# )
|
|
#
|
|
# check_specimen_quality = (
|
|
# flow_func(this.validate_specimen_quality)
|
|
# .Next(this.process_tests)
|
|
# )
|
|
#
|
|
# process_tests = (
|
|
# flow_view(TestProcessingView)
|
|
# .Permission('laboratory.can_process_tests')
|
|
# .Next(this.enter_results)
|
|
# )
|
|
#
|
|
# enter_results = (
|
|
# flow_view(ResultEntryView)
|
|
# .Permission('laboratory.can_enter_results')
|
|
# .Next(this.verify_results)
|
|
# )
|
|
#
|
|
# verify_results = (
|
|
# flow_view(ResultVerificationView)
|
|
# .Permission('laboratory.can_verify_results')
|
|
# .Next(this.check_critical_values)
|
|
# )
|
|
#
|
|
# check_critical_values = (
|
|
# flow_func(this.check_for_critical_values)
|
|
# .Next(this.report_results)
|
|
# )
|
|
#
|
|
# report_results = (
|
|
# flow_view(ResultReportingView)
|
|
# .Permission('laboratory.can_report_results')
|
|
# .Next(this.finalize_order)
|
|
# )
|
|
#
|
|
# finalize_order = (
|
|
# flow_func(this.complete_lab_order)
|
|
# .Next(this.end)
|
|
# )
|
|
#
|
|
# end = flow_func(this.end_lab_order)
|
|
#
|
|
# # Flow functions
|
|
# def start_lab_order(self, activation):
|
|
# """Initialize the lab order process"""
|
|
# process = activation.process
|
|
# lab_order = process.lab_order
|
|
#
|
|
# # Update order status
|
|
# lab_order.status = 'PENDING'
|
|
# lab_order.save()
|
|
#
|
|
# # Send notification to lab staff
|
|
# self.notify_lab_staff(lab_order)
|
|
#
|
|
# def schedule_specimen_collection(self, activation):
|
|
# """Schedule specimen collection based on order priority"""
|
|
# process = activation.process
|
|
# lab_order = process.lab_order
|
|
#
|
|
# # Calculate collection time based on priority
|
|
# if lab_order.priority == 'STAT':
|
|
# collection_time = timezone.now() + timezone.timedelta(minutes=15)
|
|
# elif lab_order.priority == 'URGENT':
|
|
# collection_time = timezone.now() + timezone.timedelta(hours=1)
|
|
# else:
|
|
# collection_time = timezone.now() + timezone.timedelta(hours=4)
|
|
#
|
|
# # Update order with scheduled collection time
|
|
# lab_order.collection_datetime = collection_time
|
|
# lab_order.save()
|
|
#
|
|
# # Notify collection staff
|
|
# self.notify_collection_staff(lab_order)
|
|
#
|
|
# def handle_specimen_transport(self, activation):
|
|
# """Handle specimen transport to laboratory"""
|
|
# process = activation.process
|
|
# lab_order = process.lab_order
|
|
#
|
|
# # Update specimen status to in transit
|
|
# for specimen in lab_order.specimens.all():
|
|
# specimen.status = 'IN_TRANSIT'
|
|
# specimen.save()
|
|
#
|
|
# # Schedule transport based on priority
|
|
# if lab_order.priority in ['STAT', 'URGENT']:
|
|
# # Immediate transport
|
|
# self.notify_transport_team(lab_order, urgent=True)
|
|
# else:
|
|
# # Regular transport schedule
|
|
# self.schedule_regular_transport(lab_order)
|
|
#
|
|
# def validate_specimen_quality(self, activation):
|
|
# """Validate specimen quality and reject if necessary"""
|
|
# process = activation.process
|
|
# lab_order = process.lab_order
|
|
#
|
|
# rejected_specimens = []
|
|
#
|
|
# for specimen in lab_order.specimens.all():
|
|
# if specimen.quality == 'REJECTED':
|
|
# rejected_specimens.append(specimen)
|
|
#
|
|
# # Notify ordering physician of rejection
|
|
# self.notify_specimen_rejection(specimen)
|
|
#
|
|
# # Request new specimen collection
|
|
# self.request_recollection(specimen)
|
|
#
|
|
# if rejected_specimens:
|
|
# # Update order status if specimens rejected
|
|
# lab_order.status = 'SPECIMEN_REJECTED'
|
|
# lab_order.save()
|
|
# else:
|
|
# # Proceed with processing
|
|
# lab_order.status = 'PROCESSING'
|
|
# lab_order.save()
|
|
#
|
|
# process.specimen_received = True
|
|
# process.save()
|
|
#
|
|
# def check_for_critical_values(self, activation):
|
|
# """Check for critical values and alert if found"""
|
|
# process = activation.process
|
|
# lab_order = process.lab_order
|
|
#
|
|
# critical_results = []
|
|
#
|
|
# for result in lab_order.results.all():
|
|
# if self.is_critical_value(result):
|
|
# critical_results.append(result)
|
|
#
|
|
# if critical_results:
|
|
# # Immediate notification for critical values
|
|
# self.notify_critical_values(lab_order, critical_results)
|
|
#
|
|
# # Mark as critical in order
|
|
# lab_order.has_critical_values = True
|
|
# lab_order.save()
|
|
#
|
|
# def complete_lab_order(self, activation):
|
|
# """Finalize the lab order process"""
|
|
# process = activation.process
|
|
# lab_order = process.lab_order
|
|
#
|
|
# # Update order status
|
|
# lab_order.status = 'COMPLETED'
|
|
# lab_order.completed_datetime = timezone.now()
|
|
# lab_order.save()
|
|
#
|
|
# # Mark process as completed
|
|
# process.results_reported = True
|
|
# process.save()
|
|
#
|
|
# # Send completion notifications
|
|
# self.notify_order_completion(lab_order)
|
|
#
|
|
# def end_lab_order(self, activation):
|
|
# """End the lab order workflow"""
|
|
# process = activation.process
|
|
#
|
|
# # Generate order summary report
|
|
# self.generate_order_summary(process.lab_order)
|
|
#
|
|
# # Helper methods
|
|
# def notify_lab_staff(self, lab_order):
|
|
# """Notify laboratory staff of new order"""
|
|
# from django.contrib.auth.models import Group
|
|
#
|
|
# lab_staff = User.objects.filter(
|
|
# groups__name='Laboratory Staff'
|
|
# )
|
|
#
|
|
# for staff in lab_staff:
|
|
# send_mail(
|
|
# subject=f'New Lab Order: {lab_order.order_number}',
|
|
# message=f'New {lab_order.get_priority_display()} lab order for {lab_order.patient.get_full_name()}.',
|
|
# from_email='laboratory@hospital.com',
|
|
# recipient_list=[staff.email],
|
|
# fail_silently=True
|
|
# )
|
|
#
|
|
# def notify_collection_staff(self, lab_order):
|
|
# """Notify specimen collection staff"""
|
|
# collection_staff = User.objects.filter(
|
|
# groups__name='Specimen Collection'
|
|
# )
|
|
#
|
|
# for staff in collection_staff:
|
|
# send_mail(
|
|
# subject=f'Specimen Collection Required: {lab_order.order_number}',
|
|
# message=f'Specimen collection scheduled for {lab_order.collection_datetime}.',
|
|
# from_email='laboratory@hospital.com',
|
|
# recipient_list=[staff.email],
|
|
# fail_silently=True
|
|
# )
|
|
#
|
|
# def notify_transport_team(self, lab_order, urgent=False):
|
|
# """Notify transport team for specimen pickup"""
|
|
# transport_staff = User.objects.filter(
|
|
# groups__name='Transport Team'
|
|
# )
|
|
#
|
|
# priority_text = "URGENT" if urgent else "ROUTINE"
|
|
#
|
|
# for staff in transport_staff:
|
|
# send_mail(
|
|
# subject=f'{priority_text} Transport: {lab_order.order_number}',
|
|
# message=f'Specimen transport required for lab order {lab_order.order_number}.',
|
|
# from_email='transport@hospital.com',
|
|
# recipient_list=[staff.email],
|
|
# fail_silently=True
|
|
# )
|
|
#
|
|
# def schedule_regular_transport(self, lab_order):
|
|
# """Schedule regular transport pickup"""
|
|
# # This would integrate with transport scheduling system
|
|
# pass
|
|
#
|
|
# def notify_specimen_rejection(self, specimen):
|
|
# """Notify ordering physician of specimen rejection"""
|
|
# if specimen.order.ordering_physician and specimen.order.ordering_physician.email:
|
|
# send_mail(
|
|
# subject=f'Specimen Rejected: {specimen.specimen_number}',
|
|
# message=f'Specimen rejected due to: {specimen.rejection_reason}. Please reorder.',
|
|
# from_email='laboratory@hospital.com',
|
|
# recipient_list=[specimen.order.ordering_physician.email],
|
|
# fail_silently=True
|
|
# )
|
|
#
|
|
# def request_recollection(self, specimen):
|
|
# """Request new specimen collection"""
|
|
# # This would trigger a new collection workflow
|
|
# pass
|
|
#
|
|
# def is_critical_value(self, result):
|
|
# """Check if result value is critical"""
|
|
# # This would implement critical value checking logic
|
|
# # based on test-specific critical ranges
|
|
# return False # Placeholder
|
|
#
|
|
# def notify_critical_values(self, lab_order, critical_results):
|
|
# """Notify physicians of critical values immediately"""
|
|
# if lab_order.ordering_physician and lab_order.ordering_physician.email:
|
|
# result_details = "\n".join([
|
|
# f"{result.test.test_name}: {result.result_value} {result.result_unit}"
|
|
# for result in critical_results
|
|
# ])
|
|
#
|
|
# send_mail(
|
|
# subject=f'CRITICAL VALUES: {lab_order.order_number}',
|
|
# message=f'Critical values detected:\n{result_details}',
|
|
# from_email='laboratory@hospital.com',
|
|
# recipient_list=[lab_order.ordering_physician.email],
|
|
# fail_silently=True
|
|
# )
|
|
#
|
|
# def notify_order_completion(self, lab_order):
|
|
# """Notify ordering physician of completed results"""
|
|
# if lab_order.ordering_physician and lab_order.ordering_physician.email:
|
|
# send_mail(
|
|
# subject=f'Lab Results Available: {lab_order.order_number}',
|
|
# message=f'Laboratory results are now available for {lab_order.patient.get_full_name()}.',
|
|
# from_email='laboratory@hospital.com',
|
|
# recipient_list=[lab_order.ordering_physician.email],
|
|
# fail_silently=True
|
|
# )
|
|
#
|
|
# def generate_order_summary(self, lab_order):
|
|
# """Generate lab order summary report"""
|
|
# # This would generate a comprehensive lab order report
|
|
# pass
|
|
#
|
|
#
|
|
# class QualityControlProcess(Process):
|
|
# """
|
|
# Viewflow process model for quality control procedures
|
|
# """
|
|
# qc_batch = CharField(max_length=50, help_text='QC batch identifier')
|
|
#
|
|
# # Process status tracking
|
|
# qc_samples_prepared = models.BooleanField(default=False)
|
|
# qc_tests_run = models.BooleanField(default=False)
|
|
# qc_results_reviewed = models.BooleanField(default=False)
|
|
# qc_approved = models.BooleanField(default=False)
|
|
#
|
|
# class Meta:
|
|
# verbose_name = 'Quality Control Process'
|
|
# verbose_name_plural = 'Quality Control Processes'
|
|
#
|
|
#
|
|
# class QualityControlFlow(Flow):
|
|
# """
|
|
# Laboratory Quality Control Workflow
|
|
#
|
|
# This flow manages quality control procedures for laboratory testing.
|
|
# """
|
|
#
|
|
# process_class = QualityControlProcess
|
|
#
|
|
# # Flow definition
|
|
# start = (
|
|
# flow_func(this.start_qc_process)
|
|
# .Next(this.prepare_qc_samples)
|
|
# )
|
|
#
|
|
# prepare_qc_samples = (
|
|
# flow_view(QCSamplePreparationView)
|
|
# .Permission('laboratory.can_prepare_qc_samples')
|
|
# .Next(this.run_qc_tests)
|
|
# )
|
|
#
|
|
# run_qc_tests = (
|
|
# flow_view(QCTestExecutionView)
|
|
# .Permission('laboratory.can_run_qc_tests')
|
|
# .Next(this.review_qc_results)
|
|
# )
|
|
#
|
|
# review_qc_results = (
|
|
# flow_view(QCResultReviewView)
|
|
# .Permission('laboratory.can_review_qc_results')
|
|
# .Next(this.approve_qc)
|
|
# )
|
|
#
|
|
# approve_qc = (
|
|
# flow_view(QCApprovalView)
|
|
# .Permission('laboratory.can_approve_qc')
|
|
# .Next(this.finalize_qc)
|
|
# )
|
|
#
|
|
# finalize_qc = (
|
|
# flow_func(this.complete_qc_process)
|
|
# .Next(this.end)
|
|
# )
|
|
#
|
|
# end = flow_func(this.end_qc_process)
|
|
#
|
|
# # Flow functions
|
|
# def start_qc_process(self, activation):
|
|
# """Initialize the QC process"""
|
|
# process = activation.process
|
|
#
|
|
# # Notify QC staff
|
|
# self.notify_qc_staff(process.qc_batch)
|
|
#
|
|
# def complete_qc_process(self, activation):
|
|
# """Finalize the QC process"""
|
|
# process = activation.process
|
|
#
|
|
# # Mark QC as approved
|
|
# process.qc_approved = True
|
|
# process.save()
|
|
#
|
|
# # Release patient results if QC passed
|
|
# self.release_patient_results(process.qc_batch)
|
|
#
|
|
# def end_qc_process(self, activation):
|
|
# """End the QC workflow"""
|
|
# process = activation.process
|
|
#
|
|
# # Generate QC summary report
|
|
# self.generate_qc_summary(process.qc_batch)
|
|
#
|
|
# # Helper methods
|
|
# def notify_qc_staff(self, qc_batch):
|
|
# """Notify QC staff of new QC batch"""
|
|
# qc_staff = User.objects.filter(
|
|
# groups__name='Quality Control'
|
|
# )
|
|
#
|
|
# for staff in qc_staff:
|
|
# send_mail(
|
|
# subject=f'QC Batch Ready: {qc_batch}',
|
|
# message=f'Quality control batch {qc_batch} is ready for processing.',
|
|
# from_email='laboratory@hospital.com',
|
|
# recipient_list=[staff.email],
|
|
# fail_silently=True
|
|
# )
|
|
#
|
|
# def release_patient_results(self, qc_batch):
|
|
# """Release patient results after QC approval"""
|
|
# # This would release held patient results
|
|
# pass
|
|
#
|
|
# def generate_qc_summary(self, qc_batch):
|
|
# """Generate QC summary report"""
|
|
# # This would generate a comprehensive QC report
|
|
# pass
|
|
#
|
|
#
|
|
# # Celery tasks for background processing
|
|
# @celery.job
|
|
# def auto_schedule_collection(order_id):
|
|
# """Background task to automatically schedule specimen collection"""
|
|
# try:
|
|
# lab_order = LabOrder.objects.get(id=order_id)
|
|
#
|
|
# # Auto-assign collection staff based on location and availability
|
|
# collection_staff = User.objects.filter(
|
|
# groups__name='Specimen Collection',
|
|
# is_active=True
|
|
# ).first()
|
|
#
|
|
# if collection_staff:
|
|
# # Create collection task
|
|
# # This would integrate with task management system
|
|
# return True
|
|
#
|
|
# return False
|
|
# except LabOrder.DoesNotExist:
|
|
# return False
|
|
#
|
|
#
|
|
# @celery.job
|
|
# def process_batch_results(batch_id):
|
|
# """Background task to process batch of test results"""
|
|
# try:
|
|
# # This would process a batch of results
|
|
# # and perform automated quality checks
|
|
# return True
|
|
# except Exception:
|
|
# return False
|
|
#
|
|
#
|
|
# @celery.job
|
|
# def generate_daily_qc_report():
|
|
# """Background task to generate daily QC report"""
|
|
# try:
|
|
# # This would generate daily QC summary
|
|
# return True
|
|
# except Exception:
|
|
# return False
|
|
#
|