Skip to content

Commit

Permalink
Merge pull request #1252 from coronasafe/feat/discharge-summary
Browse files Browse the repository at this point in the history
refactor discharge summary endpoints
  • Loading branch information
rithviknishad authored May 16, 2023
2 parents 1cca352 + 2e85e0c commit e658eee
Show file tree
Hide file tree
Showing 13 changed files with 1,168 additions and 785 deletions.
64 changes: 64 additions & 0 deletions .github/workflows/deployment-lambda.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Lambda Deployment

on:
workflow_dispatch:

pull_request:
branches:
- devops/lambda-changes
paths-ignore:
- "docs/**"

jobs:

build-image:
name: Build & Push Staging to container registries
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Docker meta
id: meta
uses: docker/metadata-action@v4
with:
images: |
ghcr.io/${{ github.repository }}
tags: |
type=raw,value=${{ github.head_ref}}-${{ github.run_number }}
type=raw,value=${{ github.head_ref}}
flavor: |
latest=true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2

- name: Cache Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ hashFiles('r*/base.txt', 'r*/production.txt', 'Dockerfile') }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build image
uses: docker/build-push-action@v3
with:
context: .
file: lambda_Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,mode=max,dest=/tmp/.buildx-cache-new

- name: Move cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ default_stages: [commit]

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.2.0
rev: v4.4.0
hooks:
- id: check-merge-conflict
- id: end-of-file-fixer
Expand All @@ -12,19 +12,19 @@ repos:
args: [--markdown-linebreak-ext=md]

- repo: https://github.com/PyCQA/isort
rev: 5.10.1
rev: 5.11.5
hooks:
- id: isort
additional_dependencies: ["isort[pyproject]"]

- repo: https://github.com/psf/black
rev: 22.3.0
rev: 23.3.0
hooks:
- id: black
args: ["--config=pyproject.toml"]

- repo: https://github.com/PyCQA/flake8
rev: 4.0.1
rev: 6.0.0
hooks:
- id: flake8
args: ["--config=.flake8"]
Expand Down
13 changes: 13 additions & 0 deletions care/facility/api/serializers/facility_capacity.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,19 @@ class FacilityCapacitySerializer(serializers.ModelSerializer):
room_type_text = ChoiceField(choices=ROOM_TYPES, read_only=True, source="room_type")
id = serializers.UUIDField(source="external_id", read_only=True)

def validate(self, data):
if (
data.get("current_capacity")
and data.get("total_capacity")
and data["current_capacity"] > data["total_capacity"]
):
raise serializers.ValidationError(
{
"current_capacity": "Current capacity cannot be greater than total capacity."
}
)
return data

class Meta:
model = FacilityCapacity
read_only_fields = (
Expand Down
73 changes: 59 additions & 14 deletions care/facility/api/serializers/patient_consultation.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from datetime import timedelta

from django.db import transaction
from django.utils.timezone import localtime, now
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
Expand All @@ -22,6 +23,7 @@
SuggestionChoices,
)
from care.facility.models.patient_consultation import PatientConsultation
from care.facility.static_data.icd11 import get_icd11_diagnoses_objects_by_ids
from care.users.api.serializers.user import (
UserAssignedSerializer,
UserBaseMinimumSerializer,
Expand Down Expand Up @@ -97,23 +99,11 @@ class PatientConsultationSerializer(serializers.ModelSerializer):
read_only=True
)

def get_icd11_diagnoses_objects_by_ids(self, diagnoses_ids):
from care.facility.static_data.icd11 import ICDDiseases

diagnosis_objects = []
for diagnosis in diagnoses_ids:
try:
diagnosis_object = ICDDiseases.by.id[diagnosis].__dict__
diagnosis_objects.append(diagnosis_object)
except BaseException:
pass
return diagnosis_objects

def get_icd11_diagnoses_object(self, consultation):
return self.get_icd11_diagnoses_objects_by_ids(consultation.icd11_diagnoses)
return get_icd11_diagnoses_objects_by_ids(consultation.icd11_diagnoses)

def get_icd11_provisional_diagnoses_object(self, consultation):
return self.get_icd11_diagnoses_objects_by_ids(
return get_icd11_diagnoses_objects_by_ids(
consultation.icd11_provisional_diagnoses
)

Expand Down Expand Up @@ -383,6 +373,61 @@ def validate(self, attrs):
return validated


class PatientConsultationDischargeSerializer(serializers.ModelSerializer):
discharge_reason = serializers.ChoiceField(
choices=DISCHARGE_REASON_CHOICES, required=True
)
discharge_notes = serializers.CharField(required=True)

discharge_date = serializers.DateTimeField(required=False)
discharge_prescription = serializers.JSONField(required=False)
discharge_prn_prescription = serializers.JSONField(required=False)

death_datetime = serializers.DateTimeField(required=False, allow_null=True)
death_confirmed_doctor = serializers.CharField(required=False, allow_null=True)

class Meta:
model = PatientConsultation
fields = (
"discharge_reason",
"discharge_notes",
"discharge_date",
"discharge_prescription",
"discharge_prn_prescription",
"death_datetime",
"death_confirmed_doctor",
)

def validate(self, attrs):
if attrs.get("discharge_reason") == "EXP":
if not attrs.get("death_datetime"):
raise ValidationError({"death_datetime": "This field is required"})
if not attrs.get("death_confirmed_doctor"):
raise ValidationError(
{"death_confirmed_doctor": "This field is required"}
)
attrs["discharge_date"] = now()
elif not attrs.get("discharge_date"):
raise ValidationError({"discharge_date": "This field is required"})
return attrs

def save(self, **kwargs):
with transaction.atomic():
instance = super().save(**kwargs)
patient: PatientRegistration = instance.patient
patient.is_active = False
patient.allow_transfer = True
patient.review_time = None
patient.save(update_fields=["allow_transfer", "is_active", "review_time"])
ConsultationBed.objects.filter(
consultation=self.instance, end_date__isnull=True
).update(end_date=now())
return instance

def create(self, validated_data):
raise NotImplementedError


class PatientConsultationIDSerializer(serializers.ModelSerializer):
consultation_id = serializers.UUIDField(source="external_id", read_only=True)
patient_id = serializers.UUIDField(source="patient.external_id", read_only=True)
Expand Down
88 changes: 4 additions & 84 deletions care/facility/api/viewsets/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@

from django.conf import settings
from django.contrib.postgres.search import TrigramSimilarity
from django.core.validators import validate_email
from django.db import models
from django.db.models import Case, When
from django.db.models.query_utils import Q
from django.utils.timezone import localtime, now
from django_filters import rest_framework as filters
from djqscsv import render_to_csv_response
from dry_rest_permissions.generics import DRYPermissionFiltersBase, DRYPermissions
Expand Down Expand Up @@ -44,16 +42,14 @@
DailyRound,
Facility,
FacilityPatientStatsHistory,
PatientConsultation,
PatientNotes,
PatientRegistration,
PatientSearch,
ShiftingRequest,
)
from care.facility.models.base import covert_choice_dict
from care.facility.models.bed import AssetBed, ConsultationBed
from care.facility.models.bed import AssetBed
from care.facility.models.patient_base import DISEASE_STATUS_DICT
from care.facility.tasks.patient.discharge_report import generate_discharge_report
from care.users.models import User
from care.utils.cache.cache_allowed_facilities import get_accessible_facilities
from care.utils.filters import CareChoiceFilter, MultiSelectFilter
Expand Down Expand Up @@ -397,79 +393,6 @@ def list(self, request, *args, **kwargs):

return super(PatientViewSet, self).list(request, *args, **kwargs)

@action(detail=True, methods=["POST"])
def discharge_patient(self, request, *args, **kwargs):
discharged = bool(request.data.get("discharge", False))
patient = self.get_object()
patient.is_active = discharged
patient.allow_transfer = not discharged
patient.review_time = None
patient.save(update_fields=["allow_transfer", "is_active", "review_time"])
last_consultation = (
PatientConsultation.objects.filter(patient=patient).order_by("-id").first()
)
current_time = localtime(now())
if last_consultation:
reason = request.data.get("discharge_reason")
notes = request.data.get("discharge_notes", "")
if reason not in DISCHARGE_REASONS:
raise serializers.ValidationError(
{"discharge_reason": "discharge reason is not valid"}
)
discharge_date = request.data.get("discharge_date", "")
last_consultation.discharge_reason = reason
last_consultation.discharge_notes = notes
if last_consultation.discharge_date is None:
if discharge_date:
last_consultation.discharge_date = discharge_date
else:
last_consultation.discharge_date = current_time
last_consultation.current_bed = None
if reason == "EXP":
death_datetime = request.data.get("death_datetime")
death_confirmed_doctor = request.data.get("death_confirmed_doctor")
if death_datetime is None:
raise serializers.ValidationError(
{"death_datetime": "Please provide death date and time"}
)
if death_confirmed_doctor is None:
raise serializers.ValidationError(
{"death_confirmed_doctor": "Please provide doctor details"}
)
last_consultation.death_datetime = death_datetime
last_consultation.death_confirmed_doctor = death_confirmed_doctor
if reason == "REC":
discharge_prescription = request.data.get("discharge_prescription", [])
discharge_prn_prescription = request.data.get(
"discharge_prn_prescription", []
)
if discharge_date is None:
raise serializers.ValidationError(
{"discharge_date": "Please set the discharge date"}
)
last_consultation.discharge_prescription = discharge_prescription
last_consultation.discharge_prn_prescription = (
discharge_prn_prescription
)
last_consultation.discharge_date = discharge_date
last_consultation.save()
ConsultationBed.objects.filter(
consultation=last_consultation, end_date__isnull=True
).update(end_date=current_time)

return Response(status=status.HTTP_200_OK)

@action(detail=True, methods=["POST"])
def discharge_summary(self, request, *args, **kwargs):
patient = self.get_object()
email = request.data.get("email", "")
try:
validate_email(email)
except Exception:
email = request.user.email
generate_discharge_report.delay(patient.id, email)
return Response(status=status.HTTP_200_OK)

@action(detail=True, methods=["POST"])
def transfer(self, request, *args, **kwargs):
patient = PatientRegistration.objects.get(
Expand All @@ -481,9 +404,9 @@ def transfer(self, request, *args, **kwargs):
{"Patient": "Cannot Transfer Patient , Source Facility Does Not Allow"},
status=status.HTTP_406_NOT_ACCEPTABLE,
)
patient.is_active = True
patient.allow_transfer = False
serializer = self.get_serializer(patient, data=request.data)
patient.is_active = True
serializer = self.get_serializer_class()(patient, data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()

Expand All @@ -497,10 +420,7 @@ def transfer(self, request, *args, **kwargs):
~Q(status__in=[30, 50, 80]), patient=patient
):
shifting_request.status = 30
shifting_request.comments = (
shifting_request.comments
+ f"\n The shifting request was auto rejected by the system as the patient was moved to {patient.facility.name}"
)
shifting_request.comments = f"{shifting_request.comments}\n The shifting request was auto rejected by the system as the patient was moved to {patient.facility.name}"
shifting_request.save(update_fields=["status", "comments"])
return Response(data=response_serializer.data, status=status.HTTP_200_OK)

Expand Down
Loading

0 comments on commit e658eee

Please sign in to comment.