Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prescription: Titrated drug dose #1692

Merged
merged 31 commits into from
Mar 17, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
8ac9459
adds titrated prescription
GokulramGHV Oct 30, 2023
6ba692d
fix linting
GokulramGHV Oct 30, 2023
ad069bc
optimize prn copy query in migration
GokulramGHV Oct 30, 2023
608ffaa
fix reverse migration
GokulramGHV Oct 30, 2023
eb1fd59
added tests and implemented suggested changes
GokulramGHV Nov 5, 2023
22a8baa
Merge branch 'master' into fix-issue-6432
GokulramGHV Nov 5, 2023
16e8115
fix lint errors
GokulramGHV Nov 6, 2023
6071f17
Add titration dosage information to patient
GokulramGHV Nov 8, 2023
1c9977a
Refactor prescription serializer validation
GokulramGHV Nov 12, 2023
47b1661
Merge branch 'master' into fix-issue-6432
GokulramGHV Nov 13, 2023
158fd0a
Merge two facility migrations
GokulramGHV Nov 13, 2023
f688f48
Fix validation for titrated prescriptions in
GokulramGHV Nov 16, 2023
76e9270
recreated migrations
GokulramGHV Nov 16, 2023
a39e484
Merge branch 'master' into fix-issue-6432
GokulramGHV Nov 16, 2023
f4c7a84
Refactor prescription serializers and models
GokulramGHV Dec 7, 2023
9e52b82
Merge branch 'master' into fix-issue-6432
GokulramGHV Dec 9, 2023
1ea6cfb
fix migrations
GokulramGHV Dec 9, 2023
cdc65b6
Merge branch 'master' into fix-issue-6432
GokulramGHV Dec 14, 2023
b045add
update tests and redo migration
GokulramGHV Dec 14, 2023
cd2749c
Merge branch 'master' into fix-issue-6432
GokulramGHV Dec 20, 2023
37d2bc2
fix: imports that are incorrectly sorted and/or formatted
GokulramGHV Dec 20, 2023
03d53e2
Merge branch 'master' into fix-issue-6432
GokulramGHV Dec 24, 2023
ee29de2
rebase migrations
GokulramGHV Dec 24, 2023
9a48f8e
Merge branch 'master' into fix-issue-6432
Ashesh3 Dec 26, 2023
e980da4
Rename dosage field to base_dosage and add dosage_type field in dummy…
GokulramGHV Dec 26, 2023
faf7ce7
Merge branch 'master' into fix-issue-6432
sainak Jan 22, 2024
687efd7
Merge remote-tracking branch 'origin/master' into fix-issue-6432
sainak Feb 10, 2024
f5d36ae
update migrations
sainak Feb 10, 2024
42aeb66
Merge branch 'master' into fix-issue-6432
rithviknishad Feb 20, 2024
533ec90
Rebase migrations and adds missing custom migration for setting dosag…
rithviknishad Feb 26, 2024
d7f6824
Merge branch 'master' into fix-issue-6432
sainak Mar 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 19 additions & 12 deletions care/facility/api/serializers/patient_consultation.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
Facility,
PatientRegistration,
Prescription,
PrescriptionDosageType,
PrescriptionType,
)
from care.facility.models.bed import Bed, ConsultationBed
Expand Down Expand Up @@ -109,17 +110,20 @@ class PatientConsultationSerializer(serializers.ModelSerializer):
medico_legal_case = serializers.BooleanField(default=False, required=False)

def get_discharge_prescription(self, consultation):
return Prescription.objects.filter(
consultation=consultation,
prescription_type=PrescriptionType.DISCHARGE.value,
is_prn=False,
).values()
return (
Prescription.objects.filter(
consultation=consultation,
prescription_type=PrescriptionType.DISCHARGE.value,
)
.exclude(dosage_type=PrescriptionDosageType.PRN.value)
.values()
)

def get_discharge_prn_prescription(self, consultation):
return Prescription.objects.filter(
consultation=consultation,
prescription_type=PrescriptionType.DISCHARGE.value,
is_prn=True,
dosage_type=PrescriptionDosageType.PRN.value,
).values()

def get_icd11_diagnoses_object(self, consultation):
Expand Down Expand Up @@ -503,17 +507,20 @@ class PatientConsultationDischargeSerializer(serializers.ModelSerializer):
)

def get_discharge_prescription(self, consultation):
return Prescription.objects.filter(
consultation=consultation,
prescription_type=PrescriptionType.DISCHARGE.value,
is_prn=False,
).values()
return (
Prescription.objects.filter(
consultation=consultation,
prescription_type=PrescriptionType.DISCHARGE.value,
)
.exclude(dosage_type=PrescriptionDosageType.PRN.value)
.values()
)

def get_discharge_prn_prescription(self, consultation):
return Prescription.objects.filter(
consultation=consultation,
prescription_type=PrescriptionType.DISCHARGE.value,
is_prn=True,
dosage_type=PrescriptionDosageType.PRN.value,
).values()

class Meta:
Expand Down
40 changes: 36 additions & 4 deletions care/facility/api/serializers/prescription.py
rithviknishad marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,18 @@ class Meta:
class PrescriptionSerializer(serializers.ModelSerializer):
id = serializers.UUIDField(source="external_id", read_only=True)
prescribed_by = UserBaseMinimumSerializer(read_only=True)
last_administered_on = serializers.SerializerMethodField()
last_administration = serializers.SerializerMethodField()
rithviknishad marked this conversation as resolved.
Show resolved Hide resolved
medicine_object = MedibaseMedicineSerializer(read_only=True, source="medicine")
medicine = serializers.UUIDField(write_only=True)

def get_last_administered_on(self, obj):
def get_last_administration(self, obj):
last_administration = (
MedicineAdministration.objects.filter(prescription=obj)
.order_by("-administered_date")
.first()
)
if last_administration:
return last_administration.administered_date
return LastAdministrationSerializer(last_administration).data
rithviknishad marked this conversation as resolved.
Show resolved Hide resolved
return None

class Meta:
Expand Down Expand Up @@ -75,7 +75,21 @@ def validate(self, attrs):
}
)

if attrs.get("is_prn"):
if attrs.get("dosage_type") == "TITRATED":
if not attrs.get("base_dosage"):
raise serializers.ValidationError(
{
"base_dosage": "Base dosage should be set for titrated prescriptions."
}
)
rithviknishad marked this conversation as resolved.
Show resolved Hide resolved
if not attrs.get("target_dosage"):
raise serializers.ValidationError(
{
"target_dosage": "Target dosage should be set for titrated prescriptions."
}
)

if attrs.get("dosage_type") == "PRN":
if not attrs.get("indicator"):
raise serializers.ValidationError(
{"indicator": "Indicator should be set for PRN prescriptions."}
Expand Down Expand Up @@ -119,3 +133,21 @@ class Meta:
"modified_date",
"prescription",
)


class LastAdministrationSerializer(serializers.ModelSerializer):
id = serializers.UUIDField(source="external_id", read_only=True)
administered_by = UserBaseMinimumSerializer(read_only=True)

class Meta:
model = MedicineAdministration
exclude = ("deleted",)
read_only_fields = (
"external_id",
"administered_by",
"archived_by",
"archived_on",
"created_date",
"modified_date",
"prescription",
)
7 changes: 6 additions & 1 deletion care/facility/api/viewsets/prescription.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from care.facility.models import (
MedicineAdministration,
Prescription,
PrescriptionDosageType,
PrescriptionType,
generate_choices,
)
Expand All @@ -30,6 +31,9 @@ def inverse_choices(choices):


inverse_prescription_type = inverse_choices(generate_choices(PrescriptionType))
inverse_prescription_dosage_type = inverse_choices(
generate_choices(PrescriptionDosageType)
)


class MedicineAdminstrationFilter(filters.FilterSet):
Expand Down Expand Up @@ -79,7 +83,8 @@ def archive(self, request, *args, **kwargs):


class ConsultationPrescriptionFilter(filters.FilterSet):
is_prn = filters.BooleanFilter()
# is_prn = filters.BooleanFilter()
rithviknishad marked this conversation as resolved.
Show resolved Hide resolved
dosage_type = CareChoiceFilter(choice_dict=inverse_prescription_dosage_type)
prescription_type = CareChoiceFilter(choice_dict=inverse_prescription_type)
discontinued = filters.BooleanFilter()

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Generated by Django 4.2.5 on 2023-10-30 09:52

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("facility", "0392_alter_dailyround_consciousness_level"),
]

def copy_prn_to_dosage_type(apps, schema_editor):
Prescription = apps.get_model("facility", "Prescription")
Prescription.objects.filter(is_prn=True).update(dosage_type="PRN")

def reverse_copy_prn_to_dosage_type(apps, schema_editor):
Prescription = apps.get_model("facility", "Prescription")
Prescription.objects.filter(dosage_type="PRN").update(is_prn=True)
rithviknishad marked this conversation as resolved.
Show resolved Hide resolved

operations = [
migrations.RenameField(
model_name="prescription",
old_name="dosage",
new_name="base_dosage",
),
migrations.AddField(
model_name="prescription",
name="dosage_type",
field=models.CharField(
choices=[
("REGULAR", "REGULAR"),
("TITRATED", "TITRATED"),
("PRN", "PRN"),
],
default="REGULAR",
max_length=100,
),
),
migrations.RunPython(
copy_prn_to_dosage_type, reverse_code=reverse_copy_prn_to_dosage_type
),
migrations.RemoveField(
model_name="prescription",
name="is_prn",
),
migrations.AddField(
model_name="prescription",
name="instruction_on_titration",
field=models.TextField(blank=True, null=True),
),
migrations.AddField(
model_name="prescription",
name="target_dosage",
field=models.CharField(blank=True, max_length=100, null=True),
),
migrations.AddField(
model_name="medicineadministration",
name="dosage",
field=models.CharField(blank=True, max_length=100, null=True),
),
]
18 changes: 16 additions & 2 deletions care/facility/models/prescription.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ class PrescriptionType(enum.Enum):
REGULAR = "REGULAR"


class PrescriptionDosageType(enum.Enum):
sainak marked this conversation as resolved.
Show resolved Hide resolved
REGULAR = "REGULAR"
TITRATED = "TITRATED"
PRN = "PRN"


def generate_choices(enum_class):
return [(tag.name, tag.value) for tag in enum_class]

Expand Down Expand Up @@ -92,9 +98,16 @@ class Prescription(BaseModel):
blank=True,
null=True,
)
dosage = models.CharField(max_length=100, blank=True, null=True)
base_dosage = models.CharField(max_length=100, blank=True, null=True)
rithviknishad marked this conversation as resolved.
Show resolved Hide resolved
dosage_type = models.CharField(
max_length=100,
choices=generate_choices(PrescriptionDosageType),
sainak marked this conversation as resolved.
Show resolved Hide resolved
default=PrescriptionDosageType.REGULAR.value,
)

is_prn = models.BooleanField(default=False)
# titrated fields
target_dosage = models.CharField(max_length=100, blank=True, null=True)
rithviknishad marked this conversation as resolved.
Show resolved Hide resolved
instruction_on_titration = models.TextField(blank=True, null=True)

# non prn fields
frequency = models.CharField(
Expand Down Expand Up @@ -148,6 +161,7 @@ class MedicineAdministration(BaseModel):
on_delete=models.PROTECT,
related_name="administrations",
)
dosage = models.CharField(max_length=100, blank=True, null=True)
Copy link
Member

@rithviknishad rithviknishad Nov 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we consider populating this with the base_dosage value from the related prescription for non-titrated prescriptions?

Suggested change
dosage = models.CharField(max_length=100, blank=True, null=True)
dosage = models.CharField(max_length=100)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc: @gigincg

rithviknishad marked this conversation as resolved.
Show resolved Hide resolved
notes = models.TextField(default="", blank=True)
administered_by = models.ForeignKey(
"users.User",
Expand Down
4 changes: 2 additions & 2 deletions care/facility/tests/test_medicine_administrations_api.py
rithviknishad marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ def create_prescription(self, **kwargs):
"consultation": self.create_consultation(self.patient, self.facility),
"medicine": MedibaseMedicine.objects.first(),
"prescription_type": "REGULAR",
"dosage": "1 mg",
"base_dosage": "1 mg",
"frequency": "OD",
"is_prn": False,
"dosage_type": "REGULAR",
}
return Prescription.objects.create(
**{**data, **kwargs, "prescribed_by": self.user}
Expand Down
4 changes: 2 additions & 2 deletions care/facility/tests/test_prescriptions_api.py
rithviknishad marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ def setUp(self) -> None:
self.normal_prescription_data = {
"medicine": self.medicine.external_id,
"prescription_type": "REGULAR",
"dosage": "1 mg",
"base_dosage": "1 mg",
"frequency": "OD",
"is_prn": False,
"dosage_type": "REGULAR",
}

def test_create_normal_prescription(self):
Expand Down
12 changes: 6 additions & 6 deletions care/facility/utils/reports/discharge_summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
PatientConsultation,
PatientSample,
Prescription,
PrescriptionDosageType,
PrescriptionType,
)
from care.facility.models.file_upload import FileUpload
Expand Down Expand Up @@ -69,22 +70,21 @@ def get_discharge_summary_data(consultation: PatientConsultation):
prescriptions = Prescription.objects.filter(
consultation=consultation,
prescription_type=PrescriptionType.REGULAR.value,
is_prn=False,
)
).exclude(dosage_type=PrescriptionDosageType.PRN.value)
prn_prescriptions = Prescription.objects.filter(
consultation=consultation,
prescription_type=PrescriptionType.REGULAR.value,
is_prn=True,
dosage_type=PrescriptionDosageType.PRN.value,
)
discharge_prescriptions = Prescription.objects.filter(
consultation=consultation,
prescription_type=PrescriptionType.DISCHARGE.value,
is_prn=False,
)
).exclude(dosage_type=PrescriptionDosageType.PRN.value)

discharge_prn_prescriptions = Prescription.objects.filter(
consultation=consultation,
prescription_type=PrescriptionType.DISCHARGE.value,
is_prn=True,
dosage_type=PrescriptionDosageType.PRN.value,
)
files = FileUpload.objects.filter(
associating_id=consultation.id,
Expand Down
8 changes: 4 additions & 4 deletions care/templates/reports/patient_discharge_summary_pdf.html
rithviknishad marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ <h4 class="mt-6 font-medium text-gray-500">
{{ prescription.medicine_name }}
</td>
<td class="p-1 whitespace-no-wrap text-sm">
{{ prescription.dosage }}
{{ prescription.base_dosage }}
</td>
<td class="p-1 whitespace-no-wrap text-sm">
{{ prescription.route }}
Expand Down Expand Up @@ -466,7 +466,7 @@ <h4 class="mt-6 font-medium text-gray-500">
{{ prescription.medicine_name }}
</td>
<td class="p-1 whitespace-no-wrap text-sm">
{{ prescription.dosage }}
{{ prescription.base_dosage }}
</td>
<td class="p-1 whitespace-no-wrap text-sm">
{{ prescription.max_dosage }}
Expand Down Expand Up @@ -813,7 +813,7 @@ <h4 class="mt-6 font-medium text-gray-500">
{{ prescription.medicine_name }}
</td>
<td class="p-1 whitespace-no-wrap text-sm">
{{ prescription.dosage }}
{{ prescription.base_dosage }}
</td>
<td class="p-1 whitespace-no-wrap text-sm">
{{ prescription.route }}
Expand Down Expand Up @@ -870,7 +870,7 @@ <h4 class="mt-6 font-medium text-gray-500">
{{ prescription.medicine_name }}
</td>
<td class="p-1 whitespace-no-wrap text-sm">
{{ prescription.dosage }}
{{ prescription.base_dosage }}
</td>
<td class="p-1 whitespace-no-wrap text-sm">
{{ prescription.max_dosage }}
Expand Down