diff --git a/care/facility/api/viewsets/asset.py b/care/facility/api/viewsets/asset.py index fc66eff4bf..8b24bebb51 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 @@ -84,6 +85,27 @@ def delete_asset_cache(sender, instance, created, **kwargs): 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") + ) + 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, RetrieveModelMixin, @@ -101,8 +123,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() diff --git a/care/facility/tests/test_asset_location_api.py b/care/facility/tests/test_asset_location_api.py index c2f95b8940..9e8280d617 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,8 +16,12 @@ 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=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) cls.consultation = cls.create_consultation(cls.patient, cls.facility) cls.consultation_bed = cls.create_consultation_bed(cls.consultation, cls.bed) @@ -24,6 +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_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 +46,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 = AssetClasses.VENTILATOR.name + 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(