Skip to content

Commit

Permalink
Merge pull request #2195 from coronasafe/staging
Browse files Browse the repository at this point in the history
Production Release v24.22.0
  • Loading branch information
gigincg authored May 27, 2024
2 parents 191855c + b3a9f79 commit a631cbc
Show file tree
Hide file tree
Showing 13 changed files with 169 additions and 95 deletions.
24 changes: 0 additions & 24 deletions care/abdm/api/viewsets/consent.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,30 +140,6 @@ def fetch(self, request, pk):
ConsentRequestSerializer(consent).data, status=status.HTTP_200_OK
)

def list(self, request, *args, **kwargs):
if ratelimit(request, "consent__list", [request.user.username]):
raise CaptchaRequiredException(
detail={
"status": 429,
"detail": f"Request limit reached. Try after {USER_READABLE_RATE_LIMIT_TIME}",
},
code=status.HTTP_429_TOO_MANY_REQUESTS,
)

return super().list(request, *args, **kwargs)

def retrieve(self, request, *args, **kwargs):
if ratelimit(request, "consent__retrieve", [kwargs["pk"]]):
raise CaptchaRequiredException(
detail={
"status": 429,
"detail": f"Request limit reached. Try after {USER_READABLE_RATE_LIMIT_TIME}",
},
code=status.HTTP_429_TOO_MANY_REQUESTS,
)

return super().retrieve(request, *args, **kwargs)


class ConsentCallbackViewSet(GenericViewSet):
permission_classes = (IsAuthenticated,)
Expand Down
9 changes: 0 additions & 9 deletions care/abdm/api/viewsets/health_information.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,6 @@ class HealthInformationViewSet(GenericViewSet):
permission_classes = (IsAuthenticated,)

def retrieve(self, request, pk):
if ratelimit(request, "health_information__retrieve", [pk]):
raise CaptchaRequiredException(
detail={
"status": 429,
"detail": f"Request limit reached. Try after {USER_READABLE_RATE_LIMIT_TIME}",
},
code=status.HTTP_429_TOO_MANY_REQUESTS,
)

files = FileUpload.objects.filter(
Q(internal_name=f"{pk}.json") | Q(associating_id=pk),
file_type=FileUpload.FileType.ABDM_HEALTH_INFORMATION.value,
Expand Down
15 changes: 15 additions & 0 deletions care/facility/api/viewsets/bed.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,21 @@ class BedFilter(filters.FilterSet):
facility = filters.UUIDFilter(field_name="facility__external_id")
location = filters.UUIDFilter(field_name="location__external_id")
bed_type = CareChoiceFilter(choice_dict=inverse_bed_type)
not_occupied_by_asset_type = filters.CharFilter(
method="filter_bed_is_not_occupied_by_asset_type"
)

def filter_bed_is_not_occupied_by_asset_type(self, queryset, name, value):
if value:
return queryset.filter(
~Exists(
AssetBed.objects.filter(
bed__id=OuterRef("id"),
asset__asset_class=value,
)
)
)
return queryset


class BedViewSet(
Expand Down
65 changes: 15 additions & 50 deletions care/facility/api/viewsets/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -602,55 +602,6 @@ def transfer(self, request, *args, **kwargs):
return Response(data=response_serializer.data, status=status.HTTP_200_OK)


class FacilityDischargedPatientFilterSet(filters.FilterSet):
disease_status = CareChoiceFilter(choice_dict=DISEASE_STATUS_DICT)
phone_number = filters.CharFilter(field_name="phone_number")
emergency_phone_number = filters.CharFilter(field_name="emergency_phone_number")
name = filters.CharFilter(field_name="name", lookup_expr="icontains")
gender = filters.NumberFilter(field_name="gender")
age = filters.NumberFilter(field_name="age")
age_min = filters.NumberFilter(field_name="age", lookup_expr="gte")
age_max = filters.NumberFilter(field_name="age", lookup_expr="lte")
created_date = filters.DateFromToRangeFilter(field_name="created_date")
modified_date = filters.DateFromToRangeFilter(field_name="modified_date")
srf_id = filters.CharFilter(field_name="srf_id")
is_declared_positive = filters.BooleanFilter(field_name="is_declared_positive")
date_declared_positive = filters.DateFromToRangeFilter(
field_name="date_declared_positive"
)
date_of_result = filters.DateFromToRangeFilter(field_name="date_of_result")
last_vaccinated_date = filters.DateFromToRangeFilter(
field_name="last_vaccinated_date"
)
is_antenatal = filters.BooleanFilter(field_name="is_antenatal")
last_menstruation_start_date = filters.DateFromToRangeFilter(
field_name="last_menstruation_start_date"
)
date_of_delivery = filters.DateFromToRangeFilter(field_name="date_of_delivery")
# Location Based Filtering
district = filters.NumberFilter(field_name="district__id")
district_name = filters.CharFilter(
field_name="district__name", lookup_expr="icontains"
)
local_body = filters.NumberFilter(field_name="local_body__id")
local_body_name = filters.CharFilter(
field_name="local_body__name", lookup_expr="icontains"
)
state = filters.NumberFilter(field_name="state__id")
state_name = filters.CharFilter(field_name="state__name", lookup_expr="icontains")
# Vaccination Filters
covin_id = filters.CharFilter(field_name="covin_id")
is_vaccinated = filters.BooleanFilter(field_name="is_vaccinated")
number_of_doses = filters.NumberFilter(field_name="number_of_doses")
last_consultation__new_discharge_reason = filters.ChoiceFilter(
field_name="last_consultation__new_discharge_reason",
choices=NewDischargeReasonEnum.choices,
)
last_consultation_discharge_date = filters.DateFromToRangeFilter(
field_name="last_consultation__discharge_date"
)


@extend_schema_view(tags=["patient"])
class FacilityDischargedPatientViewSet(GenericViewSet, mixins.ListModelMixin):
permission_classes = (IsAuthenticated, DRYPermissions)
Expand All @@ -661,7 +612,7 @@ class FacilityDischargedPatientViewSet(GenericViewSet, mixins.ListModelMixin):
rest_framework_filters.OrderingFilter,
PatientCustomOrderingFilter,
)
filterset_class = FacilityDischargedPatientFilterSet
filterset_class = PatientFilterSet
queryset = (
PatientRegistration.objects.select_related(
"local_body",
Expand Down Expand Up @@ -714,11 +665,25 @@ class FacilityDischargedPatientViewSet(GenericViewSet, mixins.ListModelMixin):
)
)

date_range_fields = [
"created_date",
"modified_date",
"date_declared_positive",
"date_of_result",
"last_vaccinated_date",
"last_consultation_encounter_date",
"last_consultation_discharge_date",
"last_consultation_symptoms_onset_date",
]

ordering_fields = [
"id",
"name",
"created_date",
"modified_date",
"review_time",
"last_consultation__current_bed__bed__name",
"date_declared_positive",
]

def get_queryset(self) -> QuerySet:
Expand Down
10 changes: 8 additions & 2 deletions care/facility/management/commands/load_event_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,14 @@ class Command(BaseCommand):
"fields": ("course_in_facility",),
},
{
"name": "TREATING_PHYSICIAN",
"fields": ("treating_physician",),
"name": "INVESTIGATION",
"fields": ("investigation",),
},
# disabling until we have a better way to serialize user objects
# {
# "name": "TREATING_PHYSICIAN",
# "fields": ("treating_physician",),
# },
),
},
{
Expand Down Expand Up @@ -240,6 +245,7 @@ class Command(BaseCommand):
"RESPIRATORY",
"INTAKE_OUTPUT",
"VENTILATOR_MODES",
"TREATING_PHYSICIAN",
)

def create_objects(
Expand Down
27 changes: 27 additions & 0 deletions care/facility/migrations/0437_alter_dailyround_rounds_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by Django 4.2.8 on 2024-05-17 04:55

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("facility", "0436_remove_dailyround_temperature_measured_at"),
]

operations = [
migrations.AlterField(
model_name="dailyround",
name="rounds_type",
field=models.IntegerField(
choices=[
(0, "NORMAL"),
(50, "DOCTORS_LOG"),
(100, "VENTILATOR"),
(200, "ICU"),
(300, "AUTOMATED"),
(400, "TELEMEDICINE"),
],
default=0,
),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Generated by Django 4.2.10 on 2024-05-21 12:29

from django.db import migrations, models


class Migration(migrations.Migration):
def rename_categories_in_events(apps, schema_editor):
PatientConsultationEvent = apps.get_model(
"facility", "PatientConsultationEvent"
)

PatientConsultationEvent.objects.filter(
event_type__name="CATEGORY", value__category="Stable"
).update(value={"category": "Mild"})
PatientConsultationEvent.objects.filter(
event_type__name="PATIENT_CATEGORY", value__category="Stable"
).update(value={"patient_category": "Mild"})
PatientConsultationEvent.objects.filter(
event_type__name="CATEGORY", value__category="Abnormal"
).update(value={"category": "Moderate"})
PatientConsultationEvent.objects.filter(
event_type__name="PATIENT_CATEGORY", value__category="Abnormal"
).update(value={"patient_category": "Moderate"})

dependencies = [
("facility", "0437_alter_dailyround_rounds_type"),
]

operations = [
migrations.AlterField(
model_name="dailyround",
name="patient_category",
field=models.CharField(
choices=[
("Comfort", "Comfort Care"),
("Stable", "Mild"),
("Moderate", "Moderate"),
("Critical", "Critical"),
],
max_length=8,
null=True,
),
),
migrations.AlterField(
model_name="patientconsultation",
name="category",
field=models.CharField(
choices=[
("Comfort", "Comfort Care"),
("Stable", "Mild"),
("Moderate", "Moderate"),
("Critical", "Critical"),
],
max_length=8,
null=True,
),
),
]
1 change: 1 addition & 0 deletions care/facility/models/daily_round.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
class DailyRound(PatientBaseModel):
class RoundsType(enum.Enum):
NORMAL = 0
DOCTORS_LOG = 50
VENTILATOR = 100
ICU = 200
AUTOMATED = 300
Expand Down
4 changes: 2 additions & 2 deletions care/facility/models/patient_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ def reverse_choices(choices):

CATEGORY_CHOICES = [
("Comfort", "Comfort Care"),
("Stable", "Stable"),
("Moderate", "Abnormal"),
("Stable", "Mild"),
("Moderate", "Moderate"),
("Critical", "Critical"),
]

Expand Down
8 changes: 4 additions & 4 deletions care/facility/tasks/asset_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ def check_asset_status():
)
else:
result = asset_class.api_get(asset_class.get_url("devices/status"))
except Exception:
logger.warn(f"Middleware {resolved_middleware} is down", exc_info=True)
except Exception as e:
logger.warn(f"Middleware {resolved_middleware} is down", e)

# If no status is returned, setting default status as down
if not result or "error" in result:
Expand Down Expand Up @@ -116,5 +116,5 @@ def check_asset_status():
status=new_status.value,
timestamp=status_record.get("time", timezone.now()),
)
except Exception:
logger.error("Error in Asset Status Check", exc_info=True)
except Exception as e:
logger.error("Error in Asset Status Check", e)
8 changes: 4 additions & 4 deletions care/facility/tasks/location_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ def check_location_status():
if result:
new_status = AvailabilityStatus.OPERATIONAL

except Exception:
logger.warn(f"Middleware {resolved_middleware} is down", exc_info=True)
except Exception as e:
logger.warn(f"Middleware {resolved_middleware} is down", e)

# Fetching the last record of the location
last_record = (
Expand All @@ -75,5 +75,5 @@ def check_location_status():
timestamp=timezone.now(),
)
logger.info(f"Location {location.external_id} status: {new_status.value}")
except Exception:
logger.error("Error in Location Status Check", exc_info=True)
except Exception as e:
logger.error("Error in Location Status Check", e)
28 changes: 28 additions & 0 deletions care/facility/tests/test_bed_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from rest_framework.test import APITestCase

from care.facility.models import Bed
from care.facility.models.bed import AssetBed
from care.utils.assetintegration.asset_classes import AssetClasses
from care.utils.tests.test_utils import TestUtils


Expand Down Expand Up @@ -36,3 +38,29 @@ def test_list_beds(self):
with self.assertNumQueries(5):
response = self.client.get("/api/v1/bed/")
self.assertEqual(response.status_code, status.HTTP_200_OK)

def test_list_non_occupied_beds(self):
linked_bed = Bed.objects.create(
name="linked_bed",
location=self.asset_location,
facility=self.facility,
)
asset = self.create_asset(
self.asset_location, asset_class=AssetClasses.HL7MONITOR.name
)
AssetBed.objects.create(bed=linked_bed, asset=asset)

# 4 beds 1 linked with HL7MONITOR and 3 created in setup

response = self.client.get("/api/v1/bed/")

# Assert list returns 4 beds
self.assertEqual(response.json()["count"], 4)

response_with_not_occupied_bed = self.client.get(
"/api/v1/bed/",
{"not_occupied_by_asset_type": "HL7MONITOR"},
)

# Assert count of unoccupied beds is 3
self.assertEqual(response_with_not_occupied_bed.json()["count"], 3)
7 changes: 7 additions & 0 deletions care/facility/tests/test_patient_daily_rounds_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,10 @@ def test_log_update_without_bed_for_domiciliary(
format="json",
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)

def test_doctors_log_update(self):
response = self.client.post(
f"/api/v1/consultation/{self.consultation_with_bed.external_id}/daily_rounds/",
data={**self.log_update, "rounds_type": "DOCTORS_LOG"},
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)

0 comments on commit a631cbc

Please sign in to comment.