Skip to content

Commit

Permalink
Cleanup discharge summary APIs (#2828)
Browse files Browse the repository at this point in the history
* Cleanup discharge summary APIs

* cleanup encounter viewset
  • Loading branch information
sainak authored Feb 12, 2025
1 parent 28a0c7c commit 52e2e1f
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 140 deletions.
114 changes: 12 additions & 102 deletions care/emr/api/viewsets/encounter.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -24,7 +23,6 @@
Encounter,
EncounterOrganization,
FacilityOrganization,
FileUpload,
Patient,
)
from care.emr.reports import discharge_summary
Expand All @@ -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

Expand Down Expand Up @@ -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={
Expand All @@ -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,
)

Expand Down
8 changes: 8 additions & 0 deletions care/emr/api/viewsets/file_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
15 changes: 0 additions & 15 deletions care/emr/reports/discharge_summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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()
Expand Down
24 changes: 1 addition & 23 deletions care/emr/tasks/discharge_summary.py
Original file line number Diff line number Diff line change
@@ -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__)
Expand All @@ -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

0 comments on commit 52e2e1f

Please sign in to comment.