Skip to content

Commit

Permalink
Data Migration to Support New Discharge Reason Field (#1773)
Browse files Browse the repository at this point in the history
* Migrate data to new_discharge_reason

* Rename Enum

* Update care/facility/api/serializers/patient_consultation.py

Co-authored-by: Aakash Singh <[email protected]>

* Apply suggestions from code review

Co-authored-by: Aakash Singh <[email protected]>

* Update migrations

* remove unused import

---------

Co-authored-by: Aakash Singh <[email protected]>
  • Loading branch information
Ashesh3 and sainak authored Jan 9, 2024
1 parent 50924ae commit c2d0cc9
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 37 deletions.
3 changes: 2 additions & 1 deletion care/facility/api/serializers/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
BLOOD_GROUP_CHOICES,
DISEASE_STATUS_CHOICES,
DiseaseStatusEnum,
NewDischargeReasonEnum,
)
from care.facility.models.patient_consultation import PatientConsultation
from care.facility.models.patient_external_test import PatientExternalTest
Expand Down Expand Up @@ -462,7 +463,7 @@ def save(self, **kwargs):

if consultation:
consultation.discharge_date = now()
consultation.discharge_reason = "REF"
consultation.new_discharge_reason = NewDischargeReasonEnum.REFERRED
consultation.current_bed = None
consultation.save()

Expand Down
16 changes: 8 additions & 8 deletions care/facility/api/serializers/patient_consultation.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
)
from care.facility.models.notification import Notification
from care.facility.models.patient_base import (
DISCHARGE_REASON_CHOICES,
SYMPTOM_CHOICES,
NewDischargeReasonEnum,
RouteToFacility,
SuggestionChoices,
)
Expand Down Expand Up @@ -111,8 +111,8 @@ class PatientConsultationSerializer(serializers.ModelSerializer):
queryset=User.objects.all(), required=False, allow_null=True
)

discharge_reason = serializers.ChoiceField(
choices=DISCHARGE_REASON_CHOICES, read_only=True, required=False
new_discharge_reason = serializers.ChoiceField(
choices=NewDischargeReasonEnum.choices, read_only=True, required=False
)
discharge_notes = serializers.CharField(read_only=True)

Expand Down Expand Up @@ -558,8 +558,8 @@ def validate(self, attrs):


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

Expand Down Expand Up @@ -596,7 +596,7 @@ def get_discharge_prn_prescription(self, consultation):
class Meta:
model = PatientConsultation
fields = (
"discharge_reason",
"new_discharge_reason",
"referred_to",
"referred_to_external",
"discharge_notes",
Expand All @@ -619,11 +619,11 @@ def validate(self, attrs):
],
}
)
if attrs.get("discharge_reason") != "EXP":
if attrs.get("new_discharge_reason") != NewDischargeReasonEnum.EXPIRED:
attrs.pop("death_datetime", None)
attrs.pop("death_confirmed_doctor", None)

if attrs.get("discharge_reason") == "EXP":
if attrs.get("new_discharge_reason") == NewDischargeReasonEnum.EXPIRED:
if not attrs.get("death_datetime"):
raise ValidationError({"death_datetime": "This field is required"})
if attrs.get("death_datetime") > now():
Expand Down
5 changes: 3 additions & 2 deletions care/facility/api/serializers/shifting.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
)
from care.facility.models.bed import ConsultationBed
from care.facility.models.notification import Notification
from care.facility.models.patient_base import NewDischargeReasonEnum
from care.facility.models.patient_consultation import PatientConsultation
from care.users.api.serializers.user import UserBaseMinimumSerializer
from care.utils.notification_handler import NotificationGenerator
Expand Down Expand Up @@ -70,9 +71,9 @@ def discharge_patient(patient: PatientRegistration):
PatientConsultation.objects.filter(patient=patient).order_by("-id").first()
)
if last_consultation:
reason = "REF"
reason = NewDischargeReasonEnum.REFERRED
notes = "Patient Shifted to another facility"
last_consultation.discharge_reason = reason
last_consultation.new_discharge_reason = reason
last_consultation.discharge_notes = notes
last_consultation.discharge_date = current_time
last_consultation.current_bed = None
Expand Down
9 changes: 8 additions & 1 deletion care/facility/api/viewsets/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@
from care.facility.models.base import covert_choice_dict
from care.facility.models.bed import AssetBed
from care.facility.models.notification import Notification
from care.facility.models.patient_base import DISEASE_STATUS_DICT
from care.facility.models.patient_base import (
DISEASE_STATUS_DICT,
NewDischargeReasonEnum,
)
from care.users.models import User
from care.utils.cache.cache_allowed_facilities import get_accessible_facilities
from care.utils.filters.choicefilter import CareChoiceFilter
Expand Down Expand Up @@ -181,6 +184,10 @@ def filter_by_bed_type(self, queryset, name, value):
field_name="last_consultation__discharge_reason",
choices=DISCHARGE_REASON_CHOICES,
)
last_consultation_discharge_reason = filters.ChoiceFilter(
field_name="last_consultation__discharge_reason",
choices=NewDischargeReasonEnum.choices,
)
last_consultation_assigned_to = filters.NumberFilter(
field_name="last_consultation__assigned_to"
)
Expand Down
10 changes: 8 additions & 2 deletions care/facility/api/viewsets/shifting.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@
ShiftingRequestComment,
User,
)
from care.facility.models.patient_base import DISEASE_STATUS_DICT
from care.facility.models.patient_base import (
DISEASE_STATUS_DICT,
NewDischargeReasonEnum,
)
from care.utils.cache.cache_allowed_facilities import get_accessible_facilities
from care.utils.filters.choicefilter import CareChoiceFilter
from care.utils.queryset.shifting import get_shifting_queryset
Expand Down Expand Up @@ -155,7 +158,10 @@ def transfer(self, request, *args, **kwargs):
# Discharge from all other active consultations
PatientConsultation.objects.filter(
patient=patient, discharge_date__isnull=True
).update(discharge_date=localtime(now()), discharge_reason="REF")
).update(
discharge_date=localtime(now()),
new_discharge_reason=NewDischargeReasonEnum.REFERRED,
)
ConsultationBed.objects.filter(
consultation=patient.last_consultation,
end_date__isnull=True,
Expand Down
42 changes: 42 additions & 0 deletions care/facility/migrations/0405_auto_20231211_1930.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Generated by Django 4.2.6 on 2023-12-11 14:00

from django.db import migrations
from django.db.models import Case, Value, When


def migrate_to_temp_field(apps, schema_editor):
PatientConsultation = apps.get_model("facility", "PatientConsultation")
mapping = {
"REC": 1,
"REF": 2,
"EXP": 3,
"LAMA": 4,
"": -1,
}

cases = [When(discharge_reason=k, then=Value(v)) for k, v in mapping.items()]
PatientConsultation.objects.filter(discharge_reason__isnull=False).update(
new_discharge_reason=Case(*cases, default=Value(-1))
)


def reverse_migration(apps, schema_editor):
PatientConsultation = apps.get_model("facility", "PatientConsultation")
reverse_mapping = {1: "REC", 2: "REF", 3: "EXP", 4: "LAMA", -1: ""}

cases = [
When(discharge_reason=k, then=Value(v)) for k, v in reverse_mapping.items()
]
PatientConsultation.objects.filter(new_discharge_reason__isnull=False).update(
discharge_reason=Case(*cases, default=Value(""))
)


class Migration(migrations.Migration):
dependencies = [
("facility", "0404_merge_20231220_2227"),
]

operations = [
migrations.RunPython(migrate_to_temp_field, reverse_code=reverse_migration),
]
4 changes: 2 additions & 2 deletions care/facility/models/patient_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,15 @@ def reverse_choices(choices):
]


class NewDiseaseReasonEnum(IntegerChoices):
class NewDischargeReasonEnum(IntegerChoices):
UNKNOWN = -1, _("Unknown")
RECOVERED = 1, _("Recovered")
REFERRED = 2, _("Referred")
EXPIRED = 3, _("Expired")
LAMA = 4, _("LAMA")


NEW_DISCHARGE_REASON_CHOICES = [(e.value, e.name) for e in NewDiseaseReasonEnum]
NEW_DISCHARGE_REASON_CHOICES = [(e.value, e.name) for e in NewDischargeReasonEnum]


class DiseaseStatusEnum(enum.IntEnum):
Expand Down
7 changes: 5 additions & 2 deletions care/facility/tests/test_patient_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from rest_framework import status
from rest_framework.test import APITestCase

from care.facility.models.patient_base import NewDischargeReasonEnum
from care.utils.tests.test_utils import TestUtils


Expand Down Expand Up @@ -289,7 +290,7 @@ def setUpTestData(cls):
suggestion="A",
encounter_date=now(),
discharge_date=None, # Patient is currently admitted
discharge_reason=None,
new_discharge_reason=None,
)
cls.bed = cls.create_bed(cls.facility, cls.location)
cls.consultation_bed = cls.create_consultation_bed(cls.consultation, cls.bed)
Expand Down Expand Up @@ -317,7 +318,9 @@ def test_patient_transfer(self):
self.assertEqual(self.patient.facility, self.destination_facility)

# Assert the consultation discharge reason and date are set correctly
self.assertEqual(self.consultation.discharge_reason, "REF")
self.assertEqual(
self.consultation.new_discharge_reason, NewDischargeReasonEnum.REFERRED
)
self.assertIsNotNone(self.consultation.discharge_date)

def test_transfer_with_active_consultation_same_facility(self):
Expand Down
31 changes: 16 additions & 15 deletions care/facility/tests/test_patient_consultation_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
ConditionVerificationStatus,
ICD11Diagnosis,
)
from care.facility.models.patient_base import NewDischargeReasonEnum
from care.facility.models.patient_consultation import (
CATEGORY_CHOICES,
PatientConsultation,
Expand Down Expand Up @@ -113,7 +114,7 @@ def test_discharge_as_recovered_preadmission(self):
)
res = self.discharge(
consultation,
discharge_reason="REC",
new_discharge_reason=NewDischargeReasonEnum.RECOVERED,
discharge_date="2002-04-01T16:30:00Z",
discharge_notes="Discharge as recovered before admission",
)
Expand All @@ -126,7 +127,7 @@ def test_discharge_as_recovered_future(self):
)
res = self.discharge(
consultation,
discharge_reason="REC",
new_discharge_reason=NewDischargeReasonEnum.RECOVERED,
discharge_date="2319-04-01T15:30:00Z",
discharge_notes="Discharge as recovered in the future",
)
Expand All @@ -139,7 +140,7 @@ def test_discharge_as_recovered_after_admission(self):
)
res = self.discharge(
consultation,
discharge_reason="REC",
new_discharge_reason=NewDischargeReasonEnum.RECOVERED,
discharge_date="2020-04-02T15:30:00Z",
discharge_notes="Discharge as recovered after admission before future",
)
Expand All @@ -152,7 +153,7 @@ def test_discharge_as_expired_pre_admission(self):
)
res = self.discharge(
consultation,
discharge_reason="EXP",
new_discharge_reason=NewDischargeReasonEnum.EXPIRED,
death_datetime="2002-04-01T16:30:00Z",
discharge_notes="Death before admission",
death_confirmed_doctor="Dr. Test",
Expand All @@ -166,7 +167,7 @@ def test_discharge_as_expired_future(self):
)
res = self.discharge(
consultation,
discharge_reason="EXP",
new_discharge_reason=NewDischargeReasonEnum.EXPIRED,
death_datetime="2319-04-01T15:30:00Z",
discharge_notes="Death in the future",
death_confirmed_doctor="Dr. Test",
Expand All @@ -180,7 +181,7 @@ def test_discharge_as_expired_after_admission(self):
)
res = self.discharge(
consultation,
discharge_reason="EXP",
new_discharge_reason=NewDischargeReasonEnum.EXPIRED,
death_datetime="2020-04-02T15:30:00Z",
discharge_notes="Death after admission before future",
death_confirmed_doctor="Dr. Test",
Expand All @@ -195,7 +196,7 @@ def test_discharge_as_recovered_with_expired_fields(self):
)
res = self.discharge(
consultation,
discharge_reason="REC",
new_discharge_reason=NewDischargeReasonEnum.RECOVERED,
discharge_date="2023-04-02T15:30:00Z",
discharge_notes="Discharge as recovered with expired fields",
death_datetime="2023-04-02T15:30:00Z",
Expand All @@ -213,7 +214,7 @@ def test_referred_to_external_null(self):
)
res = self.discharge(
consultation,
discharge_reason="REF",
new_discharge_reason=NewDischargeReasonEnum.REFERRED,
discharge_date="2023-07-01T12:00:00Z",
discharge_notes="Discharged with null referred_to_external",
referred_to_external=None,
Expand All @@ -227,7 +228,7 @@ def test_referred_to_external_empty_string(self):
)
res = self.discharge(
consultation,
discharge_reason="REF",
new_discharge_reason=NewDischargeReasonEnum.REFERRED,
discharge_date="2023-07-01T12:00:00Z",
discharge_notes="Discharged with empty referred_to_external",
referred_to_external="",
Expand All @@ -241,7 +242,7 @@ def test_referred_to_empty_facility(self):
)
res = self.discharge(
consultation,
discharge_reason="REF",
new_discharge_reason=NewDischargeReasonEnum.REFERRED,
discharge_date="2023-07-01T12:00:00Z",
discharge_notes="Discharged with empty referred_to_external",
referred_to=None,
Expand All @@ -255,7 +256,7 @@ def test_referred_to_and_external_together(self):
)
res = self.discharge(
consultation,
discharge_reason="REF",
new_discharge_reason=NewDischargeReasonEnum.REFERRED,
discharge_date="2023-07-01T12:00:00Z",
discharge_notes="Discharged with null referred_to_external",
referred_to_external="External Facility",
Expand All @@ -271,7 +272,7 @@ def test_referred_to_valid_value(self):
referred_to_external = "Test Hospital"
res = self.discharge(
consultation,
discharge_reason="REF",
new_discharge_reason=NewDischargeReasonEnum.REFERRED,
discharge_date="2023-07-01T12:00:00Z",
referred_to_external=referred_to_external,
)
Expand All @@ -285,7 +286,7 @@ def test_referred_to_external_valid_value(self):
referred_to_external = "Test Hospital"
res = self.discharge(
consultation,
discharge_reason="REF",
new_discharge_reason=NewDischargeReasonEnum.REFERRED,
discharge_date="2023-07-01T12:00:00Z",
discharge_notes="Discharged with valid referred_to_external",
referred_to_external=referred_to_external,
Expand Down Expand Up @@ -345,7 +346,7 @@ def test_medico_legal_case(self):
# Test Patch after discharge
response = self.discharge(
consultation,
discharge_reason="REC",
new_discharge_reason=NewDischargeReasonEnum.RECOVERED,
discharge_date="2023-07-01T12:00:00Z",
discharge_notes="Discharged with valid referred_to_external",
medico_legal_case=False,
Expand All @@ -367,7 +368,7 @@ def test_update_consultation_after_discharge(self):
)
res = self.discharge(
consultation,
discharge_reason="REC",
new_discharge_reason=NewDischargeReasonEnum.RECOVERED,
discharge_date="2020-04-02T15:30:00Z",
discharge_notes="Discharge as recovered after admission before future",
)
Expand Down
8 changes: 4 additions & 4 deletions care/templates/reports/patient_discharge_summary_pdf.html
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,7 @@ <h3 class="text-lg leading-6 font-medium text-gray-900">
<span class="text-sm text-gray-500">Discharge Reason:</span> {{consultation.get_discharge_reason_display}}
</p>
</div>
{% if consultation.discharge_reason == 'REC' %}
{% if consultation.new_discharge_reason == 1 %}
{% if discharge_prescriptions %}
<h4 class="mt-6 font-medium text-gray-500">
Discharge Prescription Medication:
Expand Down Expand Up @@ -962,9 +962,9 @@ <h4 class="mt-6 font-medium text-gray-500">
</table>
</div>
{% endif %}
{% elif consultation.discharge_reason == 'REF' %}
{% elif consultation.discharge_reason == 'EXP' %}
{% elif consultation.discharge_reason == 'LAMA' %}
{% elif consultation.new_discharge_reason == 2 %}
{% elif consultation.new_discharge_reason == 3 %}
{% elif consultation.new_discharge_reason == 4 %}
{% endif %}

<p class="mt-6">
Expand Down

0 comments on commit c2d0cc9

Please sign in to comment.