diff --git a/care/emr/api/viewsets/inventory/delivery_order.py b/care/emr/api/viewsets/inventory/delivery_order.py index 28fefd6eba..051a544eeb 100644 --- a/care/emr/api/viewsets/inventory/delivery_order.py +++ b/care/emr/api/viewsets/inventory/delivery_order.py @@ -92,6 +92,15 @@ def authorize_location_write(self, location_obj, raise_error=True): return False return True + def authorize_location_medication_return(self, location_obj, raise_error=True): + if not AuthorizationController.call( + "can_write_facility_medication_return", self.request.user, location_obj + ): + if raise_error: + raise PermissionDenied("Cannot write medication return") + return False + return True + def authorize_location_external_write(self, location_obj, raise_error=True): if not AuthorizationController.call( "can_write_facility_external_supply_delivery", @@ -116,6 +125,10 @@ def perform_create(self, instance): def authorize_order_write(self, order): if order.origin: allowed = self.authorize_location_write(order.origin, raise_error=False) + elif order.patient: + allowed = self.authorize_location_medication_return( + order.destination, raise_error=False + ) else: allowed = self.authorize_location_external_write( order.destination, raise_error=False @@ -167,6 +180,11 @@ def authorize_create(self, instance): FacilityLocation, external_id=instance.origin ) self.authorize_location_write(origin_location) + elif instance.patient: + destination_location = get_object_or_404( + FacilityLocation, external_id=instance.destination + ) + self.authorize_location_medication_return(destination_location) else: destination_location = get_object_or_404( FacilityLocation, external_id=instance.destination diff --git a/care/emr/api/viewsets/inventory/supply_delivery.py b/care/emr/api/viewsets/inventory/supply_delivery.py index 8e465eab6d..cd9674e70a 100644 --- a/care/emr/api/viewsets/inventory/supply_delivery.py +++ b/care/emr/api/viewsets/inventory/supply_delivery.py @@ -181,6 +181,15 @@ def authorize_location_external_write(self, location_obj, raise_error=True): return False return True + def authorize_location_medication_return(self, location_obj, raise_error=True): + if not AuthorizationController.call( + "can_write_facility_medication_return", self.request.user, location_obj + ): + if raise_error: + raise PermissionDenied("Cannot write medication return") + return False + return True + def authorize_order_read(self, order): allowed = False if order.origin: @@ -202,6 +211,10 @@ def authorize_order_write(self, order): allowed = allowed or self.authorize_location_write( order.destination, raise_error=False ) + if order.patient: + allowed = allowed or self.authorize_location_medication_return( + order.destination, raise_error=False + ) else: allowed = allowed or self.authorize_location_external_write( order.destination, raise_error=False diff --git a/care/emr/tests/test_delivery_order_api.py b/care/emr/tests/test_delivery_order_api.py index 7f16e93531..e73567be12 100644 --- a/care/emr/tests/test_delivery_order_api.py +++ b/care/emr/tests/test_delivery_order_api.py @@ -1000,6 +1000,7 @@ def setUp(self): SupplyDeliveryPermissions.can_write_external_supply_delivery.name, InvoicePermissions.can_read_invoice.name, InvoicePermissions.can_write_invoice.name, + SupplyDeliveryPermissions.can_write_medication_return.name, ChargeItemPermissions.can_read_charge_item.name, ] ) diff --git a/care/emr/tests/test_supply_delivery.py b/care/emr/tests/test_supply_delivery.py index 65951669fc..4a1f6856c7 100644 --- a/care/emr/tests/test_supply_delivery.py +++ b/care/emr/tests/test_supply_delivery.py @@ -16,6 +16,11 @@ SupplyDeliveryStatusOptions, SupplyDeliveryTypeOptions, ) +from care.emr.signals.patient.facility_name_identifier import ( + FacilityPatientNameIdentifierConfig, +) +from care.emr.signals.patient.name_identifier import NameIdentifierConfig +from care.emr.signals.patient.phone_number_identifier import PhoneNumberIdentifierConfig from care.security.permissions.supply_delivery import SupplyDeliveryPermissions from care.utils.tests.base import CareAPITestBase @@ -212,6 +217,9 @@ def create_supply_delivery(self, **kwargs): class TestSupplyDeliveryViewSet(TestSupplyDeliveryViewSetBase): def setUp(self): super().setUp() + NameIdentifierConfig.CACHED_CONFIG = {} + PhoneNumberIdentifierConfig.CACHED_CONFIG = {} + FacilityPatientNameIdentifierConfig.CACHED_CONFIG = {} def test_create_supply_delivery_internally_as_superuser(self): """ @@ -559,6 +567,82 @@ def test_create_supply_delivery_with_entered_in_error_order(self): status_code=400, ) + def test_create_supply_delivery_for_medication_return(self): + """ + Test creating a supply delivery as a superuser for medication return + """ + medication_return_order = self.create_delivery_order( + patient=self.patient, destination=self.destination + ) + self.client.force_authenticate(user=self.superuser) + data = self.create_supply_delivery_data( + order=medication_return_order.external_id, + supplied_item=self.product.external_id, + delivery_type=SupplyDeliveryTypeOptions.product.value, + ) + response = self.client.post(self.base_url, data, format="json") + self.assertEqual(response.status_code, 200) + get_response = self.client.get(self.get_detail_url(response.data["id"])) + self.assertEqual(get_response.status_code, 200) + self.assertEqual(get_response.data["supplied_item_quantity"], "50.000000") + self.assertEqual( + get_response.data["status"], SupplyDeliveryStatusOptions.in_progress.value + ) + + def test_create_supply_delivery_for_medication_return_without_permission(self): + """ + Test creating a supply delivery as a superuser for medication return without patient + """ + medication_return_order = self.create_delivery_order( + destination=self.destination + ) + self.client.force_authenticate(user=self.user) + data = self.create_supply_delivery_data( + order=medication_return_order.external_id, + supplied_item=self.product.external_id, + delivery_type=SupplyDeliveryTypeOptions.product.value, + ) + response = self.client.post(self.base_url, data, format="json") + self.assertEqual(response.status_code, 403) + self.assertContains( + response, + "Cannot write supply requests", + status_code=403, + ) + + def test_create_supply_delivery_for_medication_return_with_permission(self): + """ + Test creating a supply delivery for medication return as a user with permission + """ + medication_return_order = self.create_delivery_order( + patient=self.patient, destination=self.destination + ) + self.client.force_authenticate(user=self.user) + role = self.create_role_with_permissions( + permissions=[ + SupplyDeliveryPermissions.can_read_supply_delivery.name, + SupplyDeliveryPermissions.can_write_medication_return.name, + ] + ) + self.attach_role_facility_organization_user( + facility_organization=self.facility_organization, + user=self.user, + role=role, + ) + data = self.create_supply_delivery_data( + order=medication_return_order.external_id, + supplied_item=self.product.external_id, + delivery_type=SupplyDeliveryTypeOptions.product.value, + ) + response = self.client.post(self.base_url, data, format="json") + self.assertEqual(response.status_code, 200) + get_response = self.client.get(self.get_detail_url(response.data["id"])) + self.assertEqual(get_response.status_code, 200) + self.assertEqual(get_response.data["supplied_item_quantity"], "50.000000") + self.assertEqual( + get_response.data["status"], SupplyDeliveryStatusOptions.in_progress.value + ) + # Testcases for update supply delivery def test_update_supply_delivery_as_superuser(self): diff --git a/care/security/authorization/supply_delivery.py b/care/security/authorization/supply_delivery.py index 1a6c646a6c..7a9ca80221 100644 --- a/care/security/authorization/supply_delivery.py +++ b/care/security/authorization/supply_delivery.py @@ -34,5 +34,15 @@ def can_write_facility_external_supply_delivery(self, user, location): orgs=location.facility_organization_cache, ) + def can_write_facility_medication_return(self, user, location): + """ + Check if the user has permission to write medication return in the location + """ + return self.check_permission_in_facility_organization( + [SupplyDeliveryPermissions.can_write_medication_return.name], + user, + orgs=location.facility_organization_cache, + ) + AuthorizationController.register_internal_controller(SupplyDeliveryAccess) diff --git a/care/security/permissions/supply_delivery.py b/care/security/permissions/supply_delivery.py index 5bd4d25f3b..89285316cb 100644 --- a/care/security/permissions/supply_delivery.py +++ b/care/security/permissions/supply_delivery.py @@ -41,3 +41,10 @@ class SupplyDeliveryPermissions(enum.Enum): PermissionContext.FACILITY, [FACILITY_ADMIN_ROLE, ADMIN_ROLE], ) + + can_write_medication_return = Permission( + "Can Create Medication Return on Facility", + "", + PermissionContext.FACILITY, + [FACILITY_ADMIN_ROLE, ADMIN_ROLE, PHARMACIST_ROLE], + )