From c2d0cc92d88a69bf8da38b053ff3dc1e03219c48 Mon Sep 17 00:00:00 2001
From: Ashesh <3626859+Ashesh3@users.noreply.github.com>
Date: Wed, 10 Jan 2024 00:03:31 +0530
Subject: [PATCH] Data Migration to Support New Discharge Reason Field (#1773)
* Migrate data to new_discharge_reason
* Rename Enum
* Update care/facility/api/serializers/patient_consultation.py
Co-authored-by: Aakash Singh
* Apply suggestions from code review
Co-authored-by: Aakash Singh
* Update migrations
* remove unused import
---------
Co-authored-by: Aakash Singh
---
care/facility/api/serializers/patient.py | 3 +-
.../api/serializers/patient_consultation.py | 16 +++----
care/facility/api/serializers/shifting.py | 5 ++-
care/facility/api/viewsets/patient.py | 9 +++-
care/facility/api/viewsets/shifting.py | 10 ++++-
.../migrations/0405_auto_20231211_1930.py | 42 +++++++++++++++++++
care/facility/models/patient_base.py | 4 +-
care/facility/tests/test_patient_api.py | 7 +++-
.../tests/test_patient_consultation_api.py | 31 +++++++-------
.../patient_discharge_summary_pdf.html | 8 ++--
10 files changed, 98 insertions(+), 37 deletions(-)
create mode 100644 care/facility/migrations/0405_auto_20231211_1930.py
diff --git a/care/facility/api/serializers/patient.py b/care/facility/api/serializers/patient.py
index 6e9aa27e50..58f1cd7e55 100644
--- a/care/facility/api/serializers/patient.py
+++ b/care/facility/api/serializers/patient.py
@@ -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
@@ -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()
diff --git a/care/facility/api/serializers/patient_consultation.py b/care/facility/api/serializers/patient_consultation.py
index 401d9f3539..216871954b 100644
--- a/care/facility/api/serializers/patient_consultation.py
+++ b/care/facility/api/serializers/patient_consultation.py
@@ -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,
)
@@ -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)
@@ -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)
@@ -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",
@@ -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():
diff --git a/care/facility/api/serializers/shifting.py b/care/facility/api/serializers/shifting.py
index 8951a7691b..4a82b39923 100644
--- a/care/facility/api/serializers/shifting.py
+++ b/care/facility/api/serializers/shifting.py
@@ -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
@@ -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
diff --git a/care/facility/api/viewsets/patient.py b/care/facility/api/viewsets/patient.py
index 982b3d18b8..7608d177fe 100644
--- a/care/facility/api/viewsets/patient.py
+++ b/care/facility/api/viewsets/patient.py
@@ -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
@@ -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"
)
diff --git a/care/facility/api/viewsets/shifting.py b/care/facility/api/viewsets/shifting.py
index e5e40d1b54..f2f18f57ee 100644
--- a/care/facility/api/viewsets/shifting.py
+++ b/care/facility/api/viewsets/shifting.py
@@ -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
@@ -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,
diff --git a/care/facility/migrations/0405_auto_20231211_1930.py b/care/facility/migrations/0405_auto_20231211_1930.py
new file mode 100644
index 0000000000..eb5ee0445f
--- /dev/null
+++ b/care/facility/migrations/0405_auto_20231211_1930.py
@@ -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),
+ ]
diff --git a/care/facility/models/patient_base.py b/care/facility/models/patient_base.py
index e47e461100..cc05c59766 100644
--- a/care/facility/models/patient_base.py
+++ b/care/facility/models/patient_base.py
@@ -81,7 +81,7 @@ def reverse_choices(choices):
]
-class NewDiseaseReasonEnum(IntegerChoices):
+class NewDischargeReasonEnum(IntegerChoices):
UNKNOWN = -1, _("Unknown")
RECOVERED = 1, _("Recovered")
REFERRED = 2, _("Referred")
@@ -89,7 +89,7 @@ class NewDiseaseReasonEnum(IntegerChoices):
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):
diff --git a/care/facility/tests/test_patient_api.py b/care/facility/tests/test_patient_api.py
index da621e6b28..0167300fb4 100644
--- a/care/facility/tests/test_patient_api.py
+++ b/care/facility/tests/test_patient_api.py
@@ -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
@@ -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)
@@ -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):
diff --git a/care/facility/tests/test_patient_consultation_api.py b/care/facility/tests/test_patient_consultation_api.py
index 37ad1a702b..08f649ed2b 100644
--- a/care/facility/tests/test_patient_consultation_api.py
+++ b/care/facility/tests/test_patient_consultation_api.py
@@ -8,6 +8,7 @@
ConditionVerificationStatus,
ICD11Diagnosis,
)
+from care.facility.models.patient_base import NewDischargeReasonEnum
from care.facility.models.patient_consultation import (
CATEGORY_CHOICES,
PatientConsultation,
@@ -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",
)
@@ -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",
)
@@ -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",
)
@@ -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",
@@ -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",
@@ -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",
@@ -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",
@@ -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,
@@ -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="",
@@ -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,
@@ -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",
@@ -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,
)
@@ -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,
@@ -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,
@@ -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",
)
diff --git a/care/templates/reports/patient_discharge_summary_pdf.html b/care/templates/reports/patient_discharge_summary_pdf.html
index 8f8ae45cd0..1fbc572e26 100644
--- a/care/templates/reports/patient_discharge_summary_pdf.html
+++ b/care/templates/reports/patient_discharge_summary_pdf.html
@@ -848,7 +848,7 @@
Discharge Reason: {{consultation.get_discharge_reason_display}}
- {% if consultation.discharge_reason == 'REC' %}
+ {% if consultation.new_discharge_reason == 1 %}
{% if discharge_prescriptions %}
Discharge Prescription Medication:
@@ -962,9 +962,9 @@
{% 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 %}