From 52e2e1fbba44c5b6a6213741f3d757818c6b7836 Mon Sep 17 00:00:00 2001 From: Aakash Singh Date: Wed, 12 Feb 2025 11:25:32 +0530 Subject: [PATCH] Cleanup discharge summary APIs (#2828) * Cleanup discharge summary APIs * cleanup encounter viewset --- care/emr/api/viewsets/encounter.py | 114 +++----------------------- care/emr/api/viewsets/file_upload.py | 8 ++ care/emr/reports/discharge_summary.py | 15 ---- care/emr/tasks/discharge_summary.py | 24 +----- 4 files changed, 21 insertions(+), 140 deletions(-) diff --git a/care/emr/api/viewsets/encounter.py b/care/emr/api/viewsets/encounter.py index fc521bb6f7..b83dae8124 100644 --- a/care/emr/api/viewsets/encounter.py +++ b/care/emr/api/viewsets/encounter.py @@ -1,12 +1,11 @@ import tempfile -from django.core.validators import validate_email as django_validate_email from django.db import transaction from django.http import HttpResponse from django.utils import timezone from django_filters import rest_framework as filters from drf_spectacular.utils import extend_schema -from pydantic import UUID4, BaseModel, field_validator +from pydantic import UUID4, BaseModel from rest_framework import status from rest_framework.decorators import action from rest_framework.exceptions import PermissionDenied, ValidationError @@ -24,7 +23,6 @@ Encounter, EncounterOrganization, FacilityOrganization, - FileUpload, Patient, ) from care.emr.reports import discharge_summary @@ -36,15 +34,7 @@ EncounterUpdateSpec, ) from care.emr.resources.facility_organization.spec import FacilityOrganizationReadSpec -from care.emr.resources.file_upload.spec import ( - FileCategoryChoices, - FileTypeChoices, - FileUploadRetrieveSpec, -) -from care.emr.tasks.discharge_summary import ( - email_discharge_summary_task, - generate_discharge_summary_task, -) +from care.emr.tasks.discharge_summary import generate_discharge_summary_task from care.facility.models import Facility from care.security.authorization import AuthorizationController @@ -230,30 +220,6 @@ def organizations_remove(self, request, *args, **kwargs): ).delete() return Response({}) - def _check_discharge_summary_access(self, encounter): - if not AuthorizationController.call( - "can_view_clinical_data", self.request.user, encounter.patient - ): - raise PermissionDenied("Permission denied to user") - - def _generate_discharge_summary(self, encounter_ext_id: str): - if current_progress := discharge_summary.get_progress(encounter_ext_id): - return Response( - { - "detail": ( - "Discharge Summary is already being generated, " - f"current progress {current_progress}%" - ) - }, - status=status.HTTP_406_NOT_ACCEPTABLE, - ) - discharge_summary.set_lock(encounter_ext_id, 1) - generate_discharge_summary_task.delay(encounter_ext_id) - return Response( - {"detail": "Discharge Summary will be generated shortly"}, - status=status.HTTP_202_ACCEPTED, - ) - @extend_schema( description="Generate a discharge summary", responses={ @@ -264,81 +230,25 @@ def _generate_discharge_summary(self, encounter_ext_id: str): @action(detail=True, methods=["POST"]) def generate_discharge_summary(self, request, *args, **kwargs): encounter = self.get_object() - self._check_discharge_summary_access(encounter) - return self._generate_discharge_summary(encounter.external_id) - - @extend_schema( - description="Get the discharge summary", - responses={200: "Success"}, - tags=["encounter"], - ) - @action(detail=True, methods=["GET"]) - def preview_discharge_summary(self, request, *args, **kwargs): - encounter = self.get_object() - self._check_discharge_summary_access(encounter) - summary_file = ( - FileUpload.objects.filter( - file_type=FileTypeChoices.encounter.value, - file_category=FileCategoryChoices.discharge_summary.value, - associating_id=encounter.external_id, - upload_completed=True, - ) - .order_by("id") - .last() - ) - if summary_file: - return Response(FileUploadRetrieveSpec.serialize(summary_file).to_json()) - return self._generate_discharge_summary(encounter.external_id) - - class EmailDischargeSummarySpec(BaseModel): - email: str - - @field_validator("email") - @classmethod - def validate_email(cls, value): - django_validate_email(value) - return value - - @extend_schema( - request=EmailDischargeSummarySpec, - ) - @action(detail=True, methods=["POST"]) - def email_discharge_summary(self, request, *args, **kwargs): - encounter = self.get_object() - self._check_discharge_summary_access(encounter) + if not AuthorizationController.call( + "can_view_clinical_data", self.request.user, encounter.patient + ): + raise PermissionDenied("Permission denied to user") encounter_ext_id = encounter.external_id - if existing_progress := discharge_summary.get_progress(encounter_ext_id): + if current_progress := discharge_summary.get_progress(encounter_ext_id): return Response( { "detail": ( "Discharge Summary is already being generated, " - f"current progress {existing_progress}%" + f"current progress {current_progress}%" ) }, - status=status.HTTP_406_NOT_ACCEPTABLE, + status=status.HTTP_409_CONFLICT, ) - - request_data = self.EmailDischargeSummarySpec(**request.data) - email = request_data.email - summary_file = ( - FileUpload.objects.filter( - file_type=FileTypeChoices.encounter.value, - file_category=FileCategoryChoices.discharge_summary.value, - associating_id=encounter_ext_id, - upload_completed=True, - ) - .order_by("id") - .last() - ) - if not summary_file: - ( - generate_discharge_summary_task.s(encounter_ext_id) - | email_discharge_summary_task.s(emails=[email]) - ).delay() - else: - email_discharge_summary_task.delay(summary_file.id, [email]) + discharge_summary.set_lock(encounter_ext_id, 1) + generate_discharge_summary_task.delay(encounter_ext_id) return Response( - {"detail": "Discharge Summary will be emailed shortly"}, + {"detail": "Discharge Summary will be generated shortly"}, status=status.HTTP_202_ACCEPTED, ) diff --git a/care/emr/api/viewsets/file_upload.py b/care/emr/api/viewsets/file_upload.py index eb1a7845bc..73c2061c08 100644 --- a/care/emr/api/viewsets/file_upload.py +++ b/care/emr/api/viewsets/file_upload.py @@ -54,8 +54,16 @@ def file_authorizer(user, file_type, associating_id, permission): raise PermissionDenied("Cannot View File") +class FileCategoryFilter(filters.CharFilter): + def filter(self, qs, value): + if value: + return qs.filter(file_category__in=value.split(",")) + return qs + + class FileUploadFilter(filters.FilterSet): is_archived = filters.BooleanFilter(field_name="is_archived") + file_category = FileCategoryFilter() class FileUploadViewSet( diff --git a/care/emr/reports/discharge_summary.py b/care/emr/reports/discharge_summary.py index 7b8252daf7..38273d3108 100644 --- a/care/emr/reports/discharge_summary.py +++ b/care/emr/reports/discharge_summary.py @@ -2,13 +2,11 @@ import subprocess import tempfile import time -from collections.abc import Iterable from pathlib import Path from uuid import uuid4 from django.conf import settings from django.core.cache import cache -from django.core.mail import EmailMessage from django.template.loader import render_to_string from django.utils import timezone @@ -228,19 +226,6 @@ def generate_and_upload_discharge_summary(encounter: Encounter): return summary_file -def email_discharge_summary(summary_file: FileUpload, emails: Iterable[str]): - msg = EmailMessage( - "Patient Discharge Summary", - "Please find the attached file", - settings.DEFAULT_FROM_EMAIL, - emails, - ) - msg.content_subtype = "html" - _, data = summary_file.files_manager.file_contents(summary_file) - msg.attach(summary_file.name, data, "application/pdf") - return msg.send() - - def generate_discharge_report_signed_url(patient_external_id: str): encounter = ( Encounter() diff --git a/care/emr/tasks/discharge_summary.py b/care/emr/tasks/discharge_summary.py index 5ab69192ef..30fe5c8a46 100644 --- a/care/emr/tasks/discharge_summary.py +++ b/care/emr/tasks/discharge_summary.py @@ -1,17 +1,11 @@ -from collections.abc import Iterable from logging import Logger -from smtplib import SMTPException from botocore.exceptions import ClientError from celery import shared_task from celery.utils.log import get_task_logger from care.emr.models.encounter import Encounter -from care.emr.models.file_upload import FileUpload -from care.emr.reports.discharge_summary import ( - email_discharge_summary, - generate_and_upload_discharge_summary, -) +from care.emr.reports.discharge_summary import generate_and_upload_discharge_summary from care.utils.exceptions import CeleryTaskError logger: Logger = get_task_logger(__name__) @@ -37,19 +31,3 @@ def generate_discharge_summary_task(encounter_ext_id: str): raise CeleryTaskError(msg) return summary_file.id - - -@shared_task( - autoretry_for=(ClientError, SMTPException), - retry_kwargs={"max_retries": 3}, - expires=10 * 60, -) -def email_discharge_summary_task(file_id: int, emails: Iterable[str]): - logger.info("Emailing Discharge Summary %s to %s", file_id, emails) - try: - summary = FileUpload.objects.get(id=file_id) - except FileUpload.DoesNotExist: - logger.error("Summary %s does not exist", file_id) - return False - email_discharge_summary(summary, emails) - return True