# """ # 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 #