From 988ed9c7015b441ceb8f065b4aa26247b8176b8f Mon Sep 17 00:00:00 2001 From: Jacobjohnjeevan Date: Thu, 17 Oct 2024 13:05:40 +0530 Subject: [PATCH 1/4] CNS location - Add a parameter to filter for locations with no monitors - Also filter for monitors without paitents --- care/facility/api/viewsets/asset.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/care/facility/api/viewsets/asset.py b/care/facility/api/viewsets/asset.py index 15dd00e2a..896ce3204 100644 --- a/care/facility/api/viewsets/asset.py +++ b/care/facility/api/viewsets/asset.py @@ -58,6 +58,7 @@ AvailabilityRecord, StatusChoices, ) +from care.facility.models.bed import AssetBed, ConsultationBed from care.users.models import User from care.utils.assetintegration.asset_classes import AssetClasses from care.utils.cache.cache_allowed_facilities import get_accessible_facilities @@ -82,6 +83,22 @@ def delete_asset_cache(sender, instance, created, **kwargs): cache.delete("asset:qr:" + str(instance.qr_code_id)) cache.delete("asset:qr:" + str(instance.id)) +class AssetLocationFilter(filters.FilterSet): + bed_is_occupied = filters.BooleanFilter(method="filter_bed_is_occupied") + + def filter_bed_is_occupied(self, queryset, name, value): + asset_locations = AssetBed.objects.select_related("asset","bed").filter(asset__asset_class="HL7MONITOR").values_list("bed__location_id", "bed__id") + if value: + asset_locations = asset_locations.filter( + bed__id__in=Subquery( + ConsultationBed.objects.filter( + bed__id=OuterRef("bed__id"), end_date__isnull=value + ).values("bed__id") + ) + ) + asset_locations = asset_locations.values_list("bed__location_id", flat=True) + return queryset.filter(id__in=asset_locations) + class AssetLocationViewSet( ListModelMixin, @@ -100,8 +117,9 @@ class AssetLocationViewSet( ) serializer_class = AssetLocationSerializer lookup_field = "external_id" - filter_backends = (drf_filters.SearchFilter,) + filter_backends = (filters.DjangoFilterBackend, drf_filters.SearchFilter) search_fields = ["name"] + filterset_class = AssetLocationFilter def get_serializer_context(self): facility = self.get_facility() From 84f7ad9f318b624c9ed7c42a1bccd93ffd8d6f71 Mon Sep 17 00:00:00 2001 From: Jacobjohnjeevan Date: Thu, 17 Oct 2024 18:02:52 +0530 Subject: [PATCH 2/4] Added new test cases for asset locations --- .../facility/tests/test_asset_location_api.py | 33 ++++++++++++++++++- care/utils/tests/test_utils.py | 12 ++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/care/facility/tests/test_asset_location_api.py b/care/facility/tests/test_asset_location_api.py index c2f95b894..9caf08cb9 100644 --- a/care/facility/tests/test_asset_location_api.py +++ b/care/facility/tests/test_asset_location_api.py @@ -15,8 +15,9 @@ def setUpTestData(cls) -> None: cls.asset_location = cls.create_asset_location(cls.facility) cls.asset_location_with_linked_bed = cls.create_asset_location(cls.facility) cls.asset_location_with_linked_asset = cls.create_asset_location(cls.facility) - cls.asset = cls.create_asset(cls.asset_location_with_linked_asset) + cls.asset = cls.create_asset(cls.asset_location_with_linked_asset, asset_class="HL7MONITOR") cls.bed = cls.create_bed(cls.facility, cls.asset_location_with_linked_bed) + cls.asset_bed = cls.create_asset_bed(cls.asset, cls.bed) cls.patient = cls.create_patient(cls.district, cls.facility) cls.consultation = cls.create_consultation(cls.patient, cls.facility) cls.consultation_bed = cls.create_consultation_bed(cls.consultation, cls.bed) @@ -24,6 +25,10 @@ def setUpTestData(cls) -> None: cls.deleted_asset = cls.create_asset(cls.asset_location) cls.deleted_asset.deleted = True cls.deleted_asset.save() + cls.asset_second_location = cls.create_asset_location(cls.facility, name="asset2 location") + cls.asset_second = cls.create_asset(cls.asset_second_location, asset_class="HL7MONITOR") + cls.asset_bed_second = cls.create_bed(cls.facility, cls.asset_second_location) + cls.assetbed_second = cls.create_asset_bed(cls.asset_second, cls.asset_bed_second) def test_list_asset_locations(self): response = self.client.get( @@ -31,6 +36,32 @@ def test_list_asset_locations(self): ) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertContains(response, self.asset_location.external_id) + self.assertContains(response, self.asset_second_location.external_id) + + def test_asset_locations_get_monitors_all(self): + response = self.client.get( + f"/api/v1/facility/{self.facility.external_id}/asset_location/?bed_is_occupied=false" + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertContains(response, self.asset_location_with_linked_bed.external_id) + self.assertContains(response, self.asset_second_location.external_id) + + def test_asset_locations_get_monitors_only_consultation_bed(self): + response = self.client.get( + f"/api/v1/facility/{self.facility.external_id}/asset_location/?bed_is_occupied=true" + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertContains(response, self.asset_location_with_linked_bed.external_id) + + def test_asset_locations_get_only_monitors(self): + self.asset.asset_class = "VENTILATOR" + self.asset.save() + response = self.client.get( + f"/api/v1/facility/{self.facility.external_id}/asset_location/?bed_is_occupied=false" + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertContains(response, self.asset_second_location.external_id) + self.assertEqual(len(response.data["results"]), 1) def test_retrieve_asset_location(self): response = self.client.get( diff --git a/care/utils/tests/test_utils.py b/care/utils/tests/test_utils.py index 1f858c725..a781e49a2 100644 --- a/care/utils/tests/test_utils.py +++ b/care/utils/tests/test_utils.py @@ -38,7 +38,7 @@ Ward, ) from care.facility.models.asset import Asset, AssetLocation -from care.facility.models.bed import Bed, ConsultationBed +from care.facility.models.bed import AssetBed, Bed, ConsultationBed from care.facility.models.facility import FacilityUser from care.facility.models.icd11_diagnosis import ( ConditionVerificationStatus, @@ -446,6 +446,16 @@ def create_bed(cls, facility: Facility, location: AssetLocation, **kwargs): data.update(kwargs) return Bed.objects.create(**data) + @classmethod + def create_asset_bed(cls, asset: Asset, bed: Bed, **kwargs): + data = { + "meta": "{}", + "asset": asset, + "bed": bed, + } + data.update(kwargs) + return AssetBed.objects.create(**data) + @classmethod def create_consultation_bed( cls, From 28c56ec7b2e3820c9cca74f16a212bc65eda4866 Mon Sep 17 00:00:00 2001 From: Jacobjohnjeevan Date: Thu, 17 Oct 2024 18:15:03 +0530 Subject: [PATCH 3/4] using asset class instead of string --- care/facility/api/viewsets/asset.py | 2 +- care/facility/tests/test_asset_location_api.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/care/facility/api/viewsets/asset.py b/care/facility/api/viewsets/asset.py index 896ce3204..9bd36c60b 100644 --- a/care/facility/api/viewsets/asset.py +++ b/care/facility/api/viewsets/asset.py @@ -87,7 +87,7 @@ class AssetLocationFilter(filters.FilterSet): bed_is_occupied = filters.BooleanFilter(method="filter_bed_is_occupied") def filter_bed_is_occupied(self, queryset, name, value): - asset_locations = AssetBed.objects.select_related("asset","bed").filter(asset__asset_class="HL7MONITOR").values_list("bed__location_id", "bed__id") + asset_locations = AssetBed.objects.select_related("asset","bed").filter(asset__asset_class=AssetClasses.HL7MONITOR.name).values_list("bed__location_id", "bed__id") if value: asset_locations = asset_locations.filter( bed__id__in=Subquery( diff --git a/care/facility/tests/test_asset_location_api.py b/care/facility/tests/test_asset_location_api.py index 9caf08cb9..a891b09c4 100644 --- a/care/facility/tests/test_asset_location_api.py +++ b/care/facility/tests/test_asset_location_api.py @@ -1,6 +1,7 @@ from rest_framework import status from rest_framework.test import APITestCase +from care.utils.assetintegration.asset_classes import AssetClasses from care.utils.tests.test_utils import TestUtils @@ -15,7 +16,7 @@ def setUpTestData(cls) -> None: cls.asset_location = cls.create_asset_location(cls.facility) cls.asset_location_with_linked_bed = cls.create_asset_location(cls.facility) cls.asset_location_with_linked_asset = cls.create_asset_location(cls.facility) - cls.asset = cls.create_asset(cls.asset_location_with_linked_asset, asset_class="HL7MONITOR") + cls.asset = cls.create_asset(cls.asset_location_with_linked_asset, asset_class=AssetClasses.HL7MONITOR.name) cls.bed = cls.create_bed(cls.facility, cls.asset_location_with_linked_bed) cls.asset_bed = cls.create_asset_bed(cls.asset, cls.bed) cls.patient = cls.create_patient(cls.district, cls.facility) @@ -26,7 +27,7 @@ def setUpTestData(cls) -> None: cls.deleted_asset.deleted = True cls.deleted_asset.save() cls.asset_second_location = cls.create_asset_location(cls.facility, name="asset2 location") - cls.asset_second = cls.create_asset(cls.asset_second_location, asset_class="HL7MONITOR") + cls.asset_second = cls.create_asset(cls.asset_second_location, asset_class=AssetClasses.HL7MONITOR.name) cls.asset_bed_second = cls.create_bed(cls.facility, cls.asset_second_location) cls.assetbed_second = cls.create_asset_bed(cls.asset_second, cls.asset_bed_second) @@ -54,7 +55,7 @@ def test_asset_locations_get_monitors_only_consultation_bed(self): self.assertContains(response, self.asset_location_with_linked_bed.external_id) def test_asset_locations_get_only_monitors(self): - self.asset.asset_class = "VENTILATOR" + self.asset.asset_class = AssetClasses.VENTILATOR.name self.asset.save() response = self.client.get( f"/api/v1/facility/{self.facility.external_id}/asset_location/?bed_is_occupied=false" From 4d363ab12aeb565f75e8b7b5563c927dd458c0e2 Mon Sep 17 00:00:00 2001 From: Jacobjohnjeevan Date: Thu, 17 Oct 2024 18:24:18 +0530 Subject: [PATCH 4/4] fix formatting --- care/facility/api/viewsets/asset.py | 7 ++++++- care/facility/tests/test_asset_location_api.py | 17 +++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/care/facility/api/viewsets/asset.py b/care/facility/api/viewsets/asset.py index 9bd36c60b..09dfe1018 100644 --- a/care/facility/api/viewsets/asset.py +++ b/care/facility/api/viewsets/asset.py @@ -83,11 +83,16 @@ def delete_asset_cache(sender, instance, created, **kwargs): cache.delete("asset:qr:" + str(instance.qr_code_id)) cache.delete("asset:qr:" + str(instance.id)) + class AssetLocationFilter(filters.FilterSet): bed_is_occupied = filters.BooleanFilter(method="filter_bed_is_occupied") def filter_bed_is_occupied(self, queryset, name, value): - asset_locations = AssetBed.objects.select_related("asset","bed").filter(asset__asset_class=AssetClasses.HL7MONITOR.name).values_list("bed__location_id", "bed__id") + asset_locations = ( + AssetBed.objects.select_related("asset", "bed") + .filter(asset__asset_class=AssetClasses.HL7MONITOR.name) + .values_list("bed__location_id", "bed__id") + ) if value: asset_locations = asset_locations.filter( bed__id__in=Subquery( diff --git a/care/facility/tests/test_asset_location_api.py b/care/facility/tests/test_asset_location_api.py index a891b09c4..9e8280d61 100644 --- a/care/facility/tests/test_asset_location_api.py +++ b/care/facility/tests/test_asset_location_api.py @@ -16,7 +16,10 @@ def setUpTestData(cls) -> None: cls.asset_location = cls.create_asset_location(cls.facility) cls.asset_location_with_linked_bed = cls.create_asset_location(cls.facility) cls.asset_location_with_linked_asset = cls.create_asset_location(cls.facility) - cls.asset = cls.create_asset(cls.asset_location_with_linked_asset, asset_class=AssetClasses.HL7MONITOR.name) + cls.asset = cls.create_asset( + cls.asset_location_with_linked_asset, + asset_class=AssetClasses.HL7MONITOR.name, + ) cls.bed = cls.create_bed(cls.facility, cls.asset_location_with_linked_bed) cls.asset_bed = cls.create_asset_bed(cls.asset, cls.bed) cls.patient = cls.create_patient(cls.district, cls.facility) @@ -26,10 +29,16 @@ def setUpTestData(cls) -> None: cls.deleted_asset = cls.create_asset(cls.asset_location) cls.deleted_asset.deleted = True cls.deleted_asset.save() - cls.asset_second_location = cls.create_asset_location(cls.facility, name="asset2 location") - cls.asset_second = cls.create_asset(cls.asset_second_location, asset_class=AssetClasses.HL7MONITOR.name) + cls.asset_second_location = cls.create_asset_location( + cls.facility, name="asset2 location" + ) + cls.asset_second = cls.create_asset( + cls.asset_second_location, asset_class=AssetClasses.HL7MONITOR.name + ) cls.asset_bed_second = cls.create_bed(cls.facility, cls.asset_second_location) - cls.assetbed_second = cls.create_asset_bed(cls.asset_second, cls.asset_bed_second) + cls.assetbed_second = cls.create_asset_bed( + cls.asset_second, cls.asset_bed_second + ) def test_list_asset_locations(self): response = self.client.get(