From 15debe1f45564ee7f810d3ac9b259ca6b71739a5 Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Sun, 22 Sep 2024 22:42:36 +0530 Subject: [PATCH] Prescriptions and MAR: Disallow users to perform edits on discharged encounters (#2133) Prescriptions and MAR: Disallow users to perform edits on discharged encounters (#2133) --------- Co-authored-by: Vignesh Hari <14056798+vigneshhari@users.noreply.github.com> --- care/facility/api/serializers/prescription.py | 15 +- care/facility/api/viewsets/prescription.py | 11 +- .../test_medicine_administrations_api.py | 189 +++++++++++ care/facility/tests/test_medicine_api.py | 298 ------------------ care/facility/tests/test_prescriptions_api.py | 156 ++++++++- 5 files changed, 359 insertions(+), 310 deletions(-) create mode 100644 care/facility/tests/test_medicine_administrations_api.py delete mode 100644 care/facility/tests/test_medicine_api.py diff --git a/care/facility/api/serializers/prescription.py b/care/facility/api/serializers/prescription.py index ed68e772a7..f94d3cccff 100644 --- a/care/facility/api/serializers/prescription.py +++ b/care/facility/api/serializers/prescription.py @@ -57,6 +57,13 @@ def validate(self, attrs): return super().validate(attrs) + def create(self, validated_data): + if validated_data["prescription"].consultation.discharge_date: + raise serializers.ValidationError( + {"consultation": "Not allowed for discharged consultations"} + ) + return super().create(validated_data) + class Meta: model = MedicineAdministration exclude = ("deleted",) @@ -149,4 +156,10 @@ def validate(self, attrs): attrs.pop("target_dosage", None) return super().validate(attrs) - # TODO: Ensure that this medicine is not already prescribed to the same patient and is currently active. + + def create(self, validated_data): + if validated_data["consultation"].discharge_date: + raise serializers.ValidationError( + {"consultation": "Not allowed for discharged consultations"} + ) + return super().create(validated_data) diff --git a/care/facility/api/viewsets/prescription.py b/care/facility/api/viewsets/prescription.py index c949e350e5..a551dd639f 100644 --- a/care/facility/api/viewsets/prescription.py +++ b/care/facility/api/viewsets/prescription.py @@ -8,6 +8,7 @@ from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response +from rest_framework.serializers import ValidationError from rest_framework.viewsets import GenericViewSet, ViewSet from care.facility.api.serializers.prescription import ( @@ -78,6 +79,10 @@ def get_queryset(self): @extend_schema(tags=["prescription_administration"]) @action(methods=["POST"], detail=True) def archive(self, request, *args, **kwargs): + if self.get_consultation_obj().discharge_date: + raise ValidationError( + {"consultation": "Not allowed for discharged consultations"} + ) instance = self.get_object() if instance.archived_on: return Response( @@ -137,12 +142,16 @@ def perform_create(self, serializer): detail=True, ) def discontinue(self, request, *args, **kwargs): + consultation_obj = self.get_consultation_obj() + if consultation_obj.discharge_date: + raise ValidationError( + {"consultation": "Not allowed for discharged consultations"} + ) prescription_obj = self.get_object() prescription_obj.discontinued = True prescription_obj.discontinued_reason = request.data.get( "discontinued_reason", None ) - consultation_obj = self.get_consultation_obj() NotificationGenerator( event=Notification.Event.PATIENT_PRESCRIPTION_UPDATED, caused_by=self.request.user, diff --git a/care/facility/tests/test_medicine_administrations_api.py b/care/facility/tests/test_medicine_administrations_api.py new file mode 100644 index 0000000000..bbac0a5274 --- /dev/null +++ b/care/facility/tests/test_medicine_administrations_api.py @@ -0,0 +1,189 @@ +from django.utils import timezone +from rest_framework import status +from rest_framework.test import APITestCase + +from care.facility.models import ( + MedibaseMedicine, + MedicineAdministration, + Prescription, + PrescriptionDosageType, +) +from care.utils.tests.test_utils import TestUtils + + +class MedicineAdministrationsApiTestCase(TestUtils, APITestCase): + @classmethod + def setUpTestData(cls) -> None: + cls.state = cls.create_state() + cls.district = cls.create_district(cls.state) + cls.local_body = cls.create_local_body(cls.district) + cls.super_user = cls.create_super_user("su", cls.district) + cls.facility = cls.create_facility(cls.super_user, cls.district, cls.local_body) + cls.user = cls.create_user("nurse1", cls.district, home_facility=cls.facility) + cls.patient = cls.create_patient( + cls.district, cls.facility, local_body=cls.local_body + ) + cls.remote_facility = cls.create_facility( + cls.super_user, cls.district, cls.local_body + ) + cls.remote_user = cls.create_user( + "remote-nurse", cls.district, home_facility=cls.remote_facility + ) + cls.discharged_patient = cls.create_patient( + cls.district, cls.facility, local_body=cls.local_body + ) + cls.discharged_consultation = cls.create_consultation( + cls.discharged_patient, cls.facility, discharge_date="2024-01-04T00:00:00Z" + ) + + def setUp(self) -> None: + super().setUp() + self.normal_prescription = self.create_prescription() + self.discharged_prescription = self.create_prescription( + consultation=self.discharged_consultation + ) + self.discharged_administration = self.create_medicine_administration( + prescription=self.discharged_prescription + ) + + def create_prescription(self, **kwargs): + patient = kwargs.pop("patient", self.patient) + consultation = kwargs.pop( + "consultation", self.create_consultation(patient, self.facility) + ) + data = { + "consultation": consultation, + "medicine": MedibaseMedicine.objects.first(), + "prescription_type": "REGULAR", + "base_dosage": "1 mg", + "frequency": "OD", + "dosage_type": kwargs.get( + "dosage_type", PrescriptionDosageType.REGULAR.value + ), + } + return Prescription.objects.create( + **{**data, **kwargs, "prescribed_by": self.user} + ) + + def create_medicine_administration(self, prescription, **kwargs): + return MedicineAdministration.objects.create( + prescription=prescription, administered_by=self.user, **kwargs + ) + + def test_administer_for_discharged_consultations(self): + prescription = self.discharged_prescription + res = self.client.post( + f"/api/v1/consultation/{prescription.consultation.external_id}/prescriptions/{prescription.external_id}/administer/", + ) + self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) + + def test_archive_for_discharged_consultations(self): + res = self.client.post( + f"/api/v1/consultation/{self.discharged_prescription.consultation.external_id}/prescription_administration/{self.discharged_administration.external_id}/archive/" + ) + self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) + + def test_administer_non_home_facility(self): + self.client.force_authenticate(self.remote_user) + prescription = self.discharged_prescription + res = self.client.post( + f"/api/v1/consultation/{prescription.consultation.external_id}/prescriptions/{prescription.external_id}/administer/", + ) + self.assertEqual(res.status_code, status.HTTP_404_NOT_FOUND) + + def test_archive_non_home_facility(self): + self.client.force_authenticate(self.remote_user) + res = self.client.post( + f"/api/v1/consultation/{self.discharged_prescription.consultation.external_id}/prescription_administration/{self.discharged_administration.external_id}/archive/" + ) + self.assertEqual(res.status_code, status.HTTP_404_NOT_FOUND) + + def test_administer_and_archive(self): + # test administer + prescription = self.normal_prescription + res = self.client.post( + f"/api/v1/consultation/{prescription.consultation.external_id}/prescriptions/{prescription.external_id}/administer/", + {"notes": "Test Notes"}, + ) + self.assertEqual(res.status_code, status.HTTP_201_CREATED) + + administration_id = res.data["id"] + + # test archive + archive_path = f"/api/v1/consultation/{prescription.consultation.external_id}/prescription_administration/{administration_id}/archive/" + res = self.client.post(archive_path, {}) + self.assertEqual(res.status_code, status.HTTP_200_OK) + + # test archive again + res = self.client.post(archive_path, {}) + self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) + + # test list administrations + res = self.client.get( + f"/api/v1/consultation/{prescription.consultation.external_id}/prescription_administration/" + ) + self.assertEqual(res.status_code, status.HTTP_200_OK) + self.assertTrue( + any([administration_id == x["id"] for x in res.data["results"]]) + ) + + # test archived list administrations + res = self.client.get( + f"/api/v1/consultation/{prescription.consultation.external_id}/prescription_administration/?archived=true" + ) + self.assertEqual(res.status_code, status.HTTP_200_OK) + self.assertTrue( + any([administration_id == x["id"] for x in res.data["results"]]) + ) + + # test archived list administrations + res = self.client.get( + f"/api/v1/consultation/{prescription.consultation.external_id}/prescription_administration/?archived=false" + ) + self.assertEqual(res.status_code, status.HTTP_200_OK) + self.assertFalse( + any([administration_id == x["id"] for x in res.data["results"]]) + ) + + def test_administer_in_future(self): + prescription = self.normal_prescription + res = self.client.post( + f"/api/v1/consultation/{prescription.consultation.external_id}/prescriptions/{prescription.external_id}/administer/", + {"notes": "Test Notes", "administered_date": "2300-09-01T16:34"}, + ) + self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) + + def test_administer_in_past(self): + prescription = self.normal_prescription + res = self.client.post( + f"/api/v1/consultation/{prescription.consultation.external_id}/prescriptions/{prescription.external_id}/administer/", + {"notes": "Test Notes", "administered_date": "2019-09-01T16:34"}, + ) + self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) + + def test_administer_discontinued(self): + prescription = self.create_prescription( + discontinued=True, discontinued_date=timezone.now() + ) + res = self.client.post( + f"/api/v1/consultation/{prescription.consultation.external_id}/prescriptions/{prescription.external_id}/administer/", + {"notes": "Test Notes"}, + ) + self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) + + def test_administer_titrated_dosage(self): + prescription = self.create_prescription( + dosage_type=PrescriptionDosageType.TITRATED.value, target_dosage="10 mg" + ) + res = self.client.post( + f"/api/v1/consultation/{prescription.consultation.external_id}/prescriptions/{prescription.external_id}/administer/", + {"notes": "Test Notes"}, + ) + self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) + + res = self.client.post( + f"/api/v1/consultation/{prescription.consultation.external_id}/prescriptions/{prescription.external_id}/administer/", + {"notes": "Test Notes", "dosage": "1 mg"}, + ) + + self.assertEqual(res.status_code, status.HTTP_201_CREATED) diff --git a/care/facility/tests/test_medicine_api.py b/care/facility/tests/test_medicine_api.py deleted file mode 100644 index b683a6c22e..0000000000 --- a/care/facility/tests/test_medicine_api.py +++ /dev/null @@ -1,298 +0,0 @@ -from django.utils import timezone -from rest_framework import status -from rest_framework.test import APITestCase - -from care.facility.models import MedibaseMedicine, Prescription, PrescriptionDosageType -from care.utils.tests.test_utils import TestUtils - - -class MedicinePrescriptionApiTestCase(TestUtils, APITestCase): - @classmethod - def setUpTestData(cls) -> None: - cls.state = cls.create_state() - cls.district = cls.create_district(cls.state) - cls.local_body = cls.create_local_body(cls.district) - cls.super_user = cls.create_super_user("su", cls.district) - cls.facility = cls.create_facility(cls.super_user, cls.district, cls.local_body) - cls.user = cls.create_user("staff1", cls.district, home_facility=cls.facility) - cls.patient = cls.create_patient( - cls.district, cls.facility, local_body=cls.local_body - ) - cls.consultation = cls.create_consultation(cls.patient, cls.facility) - meds = MedibaseMedicine.objects.all().values_list("external_id", flat=True)[:2] - cls.medicine1 = str(meds[0]) - - def setUp(self) -> None: - super().setUp() - - def prescription_data(self, **kwargs): - data = { - "medicine": self.medicine1, - "prescription_type": "REGULAR", - "base_dosage": "1 mg", - "frequency": "OD", - "dosage_type": kwargs.get( - "dosage_type", PrescriptionDosageType.REGULAR.value - ), - } - return {**data, **kwargs} - - def test_invalid_dosage(self): - data = self.prescription_data(base_dosage="abc") - res = self.client.post( - f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", - data, - ) - self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual( - res.json()["base_dosage"][0], - "Invalid Input, must be in the format: ", - ) - - def test_dosage_out_of_range(self): - data = self.prescription_data(base_dosage="10000 mg") - res = self.client.post( - f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", - data, - ) - self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual( - res.json()["base_dosage"][0], - "Input amount must be between 0.0001 and 5000", - ) - - data = self.prescription_data(base_dosage="-1 mg") - res = self.client.post( - f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", - data, - ) - self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual( - res.json()["base_dosage"][0], - "Input amount must be between 0.0001 and 5000", - ) - - def test_dosage_precision(self): - data = self.prescription_data(base_dosage="0.300003 mg") - res = self.client.post( - f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", - data, - ) - self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual( - res.json()["base_dosage"][0], - "Input amount must have at most 4 decimal places", - ) - - def test_dosage_unit_invalid(self): - data = self.prescription_data(base_dosage="1 abc") - res = self.client.post( - f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", - data, - ) - self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) - self.assertTrue(res.json()["base_dosage"][0].startswith("Unit must be one of")) - - def test_dosage_leading_zero(self): - data = self.prescription_data(base_dosage="01 mg") - res = self.client.post( - f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", - data, - ) - self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual( - res.json()["base_dosage"][0], - "Input amount must be a valid number without leading or trailing zeroes", - ) - - def test_dosage_trailing_zero(self): - data = self.prescription_data(base_dosage="1.0 mg") - res = self.client.post( - f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", - data, - ) - self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual( - res.json()["base_dosage"][0], - "Input amount must be a valid number without leading or trailing zeroes", - ) - - def test_dosage_validator_clean(self): - data = self.prescription_data(base_dosage=" 1 mg ") - res = self.client.post( - f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", - data, - ) - self.assertEqual(res.status_code, status.HTTP_201_CREATED) - - def test_valid_dosage(self): - data = self.prescription_data(base_dosage="1 mg") - res = self.client.post( - f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", - data, - ) - self.assertEqual(res.status_code, status.HTTP_201_CREATED) - - def test_create_titrated_prescription(self): - titrated_prescription_data = self.prescription_data( - dosage_type=PrescriptionDosageType.TITRATED.value, - target_dosage="2 mg", - instruction_on_titration="Test Instruction", - ) - response = self.client.post( - f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", - titrated_prescription_data, - ) - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - - titrated_prescription_data = self.prescription_data( - dosage_type=PrescriptionDosageType.TITRATED.value, - ) - response = self.client.post( - f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", - titrated_prescription_data, - ) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - def test_create_prn_prescription(self): - prn_prescription_data = self.prescription_data( - dosage_type=PrescriptionDosageType.PRN.value, - indicator="Test Indicator", - ) - response = self.client.post( - f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", - prn_prescription_data, - ) - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - - prn_prescription_data = self.prescription_data( - dosage_type=PrescriptionDosageType.PRN.value, - ) - response = self.client.post( - f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", - prn_prescription_data, - ) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - -class MedicineAdministrationsApiTestCase(TestUtils, APITestCase): - @classmethod - def setUpTestData(cls) -> None: - cls.state = cls.create_state() - cls.district = cls.create_district(cls.state) - cls.local_body = cls.create_local_body(cls.district) - cls.super_user = cls.create_super_user("su", cls.district) - cls.facility = cls.create_facility(cls.super_user, cls.district, cls.local_body) - cls.user = cls.create_user("staff1", cls.district, home_facility=cls.facility) - cls.patient = cls.create_patient( - cls.district, cls.facility, local_body=cls.local_body - ) - - def setUp(self) -> None: - super().setUp() - self.normal_prescription = self.create_prescription() - - def create_prescription(self, **kwargs): - data = { - "consultation": self.create_consultation(self.patient, self.facility), - "medicine": MedibaseMedicine.objects.first(), - "prescription_type": "REGULAR", - "base_dosage": "1 mg", - "frequency": "OD", - "dosage_type": kwargs.get( - "dosage_type", PrescriptionDosageType.REGULAR.value - ), - } - return Prescription.objects.create( - **{**data, **kwargs, "prescribed_by": self.user} - ) - - def test_administer_and_archive(self): - # test administer - prescription = self.normal_prescription - res = self.client.post( - f"/api/v1/consultation/{prescription.consultation.external_id}/prescriptions/{prescription.external_id}/administer/", - {"notes": "Test Notes"}, - ) - self.assertEqual(res.status_code, status.HTTP_201_CREATED) - - administration_id = res.data["id"] - - # test archive - archive_path = f"/api/v1/consultation/{prescription.consultation.external_id}/prescription_administration/{administration_id}/archive/" - res = self.client.post(archive_path, {}) - self.assertEqual(res.status_code, status.HTTP_200_OK) - - # test archive again - res = self.client.post(archive_path, {}) - self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) - - # test list administrations - res = self.client.get( - f"/api/v1/consultation/{prescription.consultation.external_id}/prescription_administration/" - ) - self.assertEqual(res.status_code, status.HTTP_200_OK) - self.assertTrue( - any([administration_id == x["id"] for x in res.data["results"]]) - ) - - # test archived list administrations - res = self.client.get( - f"/api/v1/consultation/{prescription.consultation.external_id}/prescription_administration/?archived=true" - ) - self.assertEqual(res.status_code, status.HTTP_200_OK) - self.assertTrue( - any([administration_id == x["id"] for x in res.data["results"]]) - ) - - # test archived list administrations - res = self.client.get( - f"/api/v1/consultation/{prescription.consultation.external_id}/prescription_administration/?archived=false" - ) - self.assertEqual(res.status_code, status.HTTP_200_OK) - self.assertFalse( - any([administration_id == x["id"] for x in res.data["results"]]) - ) - - def test_administer_in_future(self): - prescription = self.normal_prescription - res = self.client.post( - f"/api/v1/consultation/{prescription.consultation.external_id}/prescriptions/{prescription.external_id}/administer/", - {"notes": "Test Notes", "administered_date": "2300-09-01T16:34"}, - ) - self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) - - def test_administer_in_past(self): - prescription = self.normal_prescription - res = self.client.post( - f"/api/v1/consultation/{prescription.consultation.external_id}/prescriptions/{prescription.external_id}/administer/", - {"notes": "Test Notes", "administered_date": "2019-09-01T16:34"}, - ) - self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) - - def test_administer_discontinued(self): - prescription = self.create_prescription( - discontinued=True, discontinued_date=timezone.now() - ) - res = self.client.post( - f"/api/v1/consultation/{prescription.consultation.external_id}/prescriptions/{prescription.external_id}/administer/", - {"notes": "Test Notes"}, - ) - self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) - - def test_administer_titrated_dosage(self): - prescription = self.create_prescription( - dosage_type=PrescriptionDosageType.TITRATED.value, target_dosage="10 mg" - ) - res = self.client.post( - f"/api/v1/consultation/{prescription.consultation.external_id}/prescriptions/{prescription.external_id}/administer/", - {"notes": "Test Notes"}, - ) - self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) - - res = self.client.post( - f"/api/v1/consultation/{prescription.consultation.external_id}/prescriptions/{prescription.external_id}/administer/", - {"notes": "Test Notes", "dosage": "1 mg"}, - ) - - self.assertEqual(res.status_code, status.HTTP_201_CREATED) diff --git a/care/facility/tests/test_prescriptions_api.py b/care/facility/tests/test_prescriptions_api.py index a357e51a39..3168aeb151 100644 --- a/care/facility/tests/test_prescriptions_api.py +++ b/care/facility/tests/test_prescriptions_api.py @@ -1,7 +1,7 @@ from rest_framework import status from rest_framework.test import APITestCase -from care.facility.models import MedibaseMedicine +from care.facility.models import MedibaseMedicine, Prescription from care.utils.tests.test_utils import TestUtils @@ -13,15 +13,23 @@ def setUpTestData(cls) -> None: cls.local_body = cls.create_local_body(cls.district) cls.super_user = cls.create_super_user("su", cls.district) cls.facility = cls.create_facility(cls.super_user, cls.district, cls.local_body) - cls.user = cls.create_user("staff1", cls.district, home_facility=cls.facility) + cls.user = cls.create_user("nurse1", cls.district, home_facility=cls.facility) + cls.remote_facility = cls.create_facility( + cls.super_user, cls.district, cls.local_body + ) + cls.remote_user = cls.create_user( + "remote-nurse", cls.district, home_facility=cls.remote_facility + ) cls.patient = cls.create_patient(cls.district, cls.facility) + cls.consultation = cls.create_consultation(cls.patient, cls.facility) + cls.discharged_patient = cls.create_patient(cls.district, cls.facility) + cls.discharged_consultation = cls.create_consultation( + cls.patient, cls.facility, discharge_date="2002-04-01T16:30:00Z" + ) def setUp(self) -> None: super().setUp() - self.consultation = self.create_consultation(self.patient, self.facility) - self.medicine = MedibaseMedicine.objects.first() - self.medicine2 = MedibaseMedicine.objects.all()[1] - + self.medicine, self.medicine_2 = MedibaseMedicine.objects.all()[:2] self.normal_prescription_data = { "medicine": self.medicine.external_id, "prescription_type": "REGULAR", @@ -29,14 +37,22 @@ def setUp(self) -> None: "frequency": "OD", "dosage_type": "REGULAR", } - - self.normal_prescription_data2 = { - "medicine": self.medicine2.external_id, + self.normal_prescription_data_2 = { + "medicine": self.medicine_2.external_id, "prescription_type": "REGULAR", "base_dosage": "1 mg", "frequency": "OD", "dosage_type": "REGULAR", } + self.discharged_consultation_prescription = Prescription.objects.create( + consultation=self.discharged_consultation, + medicine=self.medicine, + ) + + def prescription_data(self, **kwargs): + data = self.normal_prescription_data + data.update(**kwargs) + return data def test_create_normal_prescription(self): response = self.client.post( @@ -45,6 +61,126 @@ def test_create_normal_prescription(self): ) self.assertEqual(response.status_code, status.HTTP_201_CREATED) + def test_create_prescription_non_home_facility(self): + self.client.force_authenticate(self.remote_user) + response = self.client.post( + f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", + self.normal_prescription_data, + ) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + def test_create_prescription_on_discharged_consultation(self): + response = self.client.post( + f"/api/v1/consultation/{self.discharged_consultation.external_id}/prescriptions/", + self.normal_prescription_data, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_discontinue_prescription_on_discharged_consultation(self): + res = self.client.post( + f"/api/v1/consultation/{self.discharged_consultation.external_id}/prescriptions/{self.discharged_consultation_prescription.external_id}/discontinue/", + { + "discontinued_reason": "Test Reason", + }, + ) + self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) + + def test_invalid_dosage(self): + data = self.prescription_data(base_dosage="abc") + res = self.client.post( + f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", + data, + ) + self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual( + res.json()["base_dosage"][0], + "Invalid Input, must be in the format: ", + ) + + def test_dosage_out_of_range(self): + data = self.prescription_data(base_dosage="10000 mg") + res = self.client.post( + f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", + data, + ) + self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual( + res.json()["base_dosage"][0], + "Input amount must be between 0.0001 and 5000", + ) + + data = self.prescription_data(base_dosage="-1 mg") + res = self.client.post( + f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", + data, + ) + self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual( + res.json()["base_dosage"][0], + "Input amount must be between 0.0001 and 5000", + ) + + def test_dosage_precision(self): + data = self.prescription_data(base_dosage="0.300003 mg") + res = self.client.post( + f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", + data, + ) + self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual( + res.json()["base_dosage"][0], + "Input amount must have at most 4 decimal places", + ) + + def test_dosage_unit_invalid(self): + data = self.prescription_data(base_dosage="1 abc") + res = self.client.post( + f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", + data, + ) + self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) + self.assertTrue(res.json()["base_dosage"][0].startswith("Unit must be one of")) + + def test_dosage_leading_zero(self): + data = self.prescription_data(base_dosage="01 mg") + res = self.client.post( + f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", + data, + ) + self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual( + res.json()["base_dosage"][0], + "Input amount must be a valid number without leading or trailing zeroes", + ) + + def test_dosage_trailing_zero(self): + data = self.prescription_data(base_dosage="1.0 mg") + res = self.client.post( + f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", + data, + ) + self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual( + res.json()["base_dosage"][0], + "Input amount must be a valid number without leading or trailing zeroes", + ) + + def test_dosage_validator_clean(self): + data = self.prescription_data(base_dosage=" 1 mg ") + res = self.client.post( + f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", + data, + ) + self.assertEqual(res.status_code, status.HTTP_201_CREATED) + + def test_valid_dosage(self): + data = self.prescription_data(base_dosage="1 mg") + res = self.client.post( + f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", + data, + ) + self.assertEqual(res.status_code, status.HTTP_201_CREATED) + def test_prescribe_duplicate_active_medicine_and_discontinue(self): """ 1. Creates a prescription with Medicine A @@ -131,7 +267,7 @@ def test_medicine_filter_for_prescription(self): ) self.client.post( f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/", - self.normal_prescription_data2, + self.normal_prescription_data_2, ) # get all prescriptions without medicine filter