diff --git a/care/facility/api/viewsets/patient.py b/care/facility/api/viewsets/patient.py index 85f7936304..aa702d2ace 100644 --- a/care/facility/api/viewsets/patient.py +++ b/care/facility/api/viewsets/patient.py @@ -34,8 +34,8 @@ from care.facility.api.viewsets.mixins.history import HistoryMixin from care.facility.models import ( CATEGORY_CHOICES, - FACILITY_TYPES, DISCHARGE_REASON_CHOICES, + FACILITY_TYPES, Facility, FacilityPatientStatsHistory, PatientConsultation, @@ -52,7 +52,11 @@ from care.utils.cache.cache_allowed_facilities import get_accessible_facilities from care.utils.filters import CareChoiceFilter, MultiSelectFilter from care.utils.queryset.patient import get_patient_queryset -from config.authentication import CustomBasicAuthentication, CustomJWTAuthentication, MiddlewareAuthentication +from config.authentication import ( + CustomBasicAuthentication, + CustomJWTAuthentication, + MiddlewareAuthentication, +) REVERSE_FACILITY_TYPES = covert_choice_dict(FACILITY_TYPES) DISCHARGE_REASONS = [choice[0] for choice in DISCHARGE_REASON_CHOICES] @@ -62,31 +66,45 @@ class PatientFilterSet(filters.FilterSet): source = filters.ChoiceFilter(choices=PatientRegistration.SourceChoices) disease_status = CareChoiceFilter(choice_dict=DISEASE_STATUS_DICT) facility = filters.UUIDFilter(field_name="facility__external_id") - facility_type = CareChoiceFilter(field_name="facility__facility_type", choice_dict=REVERSE_FACILITY_TYPES) + facility_type = CareChoiceFilter( + field_name="facility__facility_type", choice_dict=REVERSE_FACILITY_TYPES + ) phone_number = filters.CharFilter(field_name="phone_number") emergency_phone_number = filters.CharFilter(field_name="emergency_phone_number") allow_transfer = filters.BooleanFilter(field_name="allow_transfer") name = filters.CharFilter(field_name="name", lookup_expr="icontains") - ip_no = filters.CharFilter(field_name="last_consultation__ip_no", lookup_expr="icontains") + ip_no = filters.CharFilter( + field_name="last_consultation__ip_no", lookup_expr="icontains" + ) gender = filters.NumberFilter(field_name="gender") age = filters.NumberFilter(field_name="age") age_min = filters.NumberFilter(field_name="age", lookup_expr="gt") age_max = filters.NumberFilter(field_name="age", lookup_expr="lt") - category = filters.ChoiceFilter(field_name="last_consultation__category", choices=CATEGORY_CHOICES) + category = filters.ChoiceFilter( + field_name="last_consultation__category", choices=CATEGORY_CHOICES + ) 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_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") + last_vaccinated_date = filters.DateFromToRangeFilter( + field_name="last_vaccinated_date" + ) is_antenatal = filters.BooleanFilter(field_name="is_antenatal") is_active = filters.BooleanFilter(field_name="is_active") # Location Based Filtering district = filters.NumberFilter(field_name="district__id") - district_name = filters.CharFilter(field_name="district__name", lookup_expr="icontains") + 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") + 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") # Consultation Fields @@ -94,15 +112,27 @@ class PatientFilterSet(filters.FilterSet): last_consultation_kasp_enabled_date = filters.DateFromToRangeFilter( field_name="last_consultation__kasp_enabled_date" ) - last_consultation_admission_date = filters.DateFromToRangeFilter(field_name="last_consultation__admission_date") - last_consultation_discharge_date = filters.DateFromToRangeFilter(field_name="last_consultation__discharge_date") + last_consultation_admission_date = filters.DateFromToRangeFilter( + field_name="last_consultation__admission_date" + ) + last_consultation_discharge_date = filters.DateFromToRangeFilter( + field_name="last_consultation__discharge_date" + ) last_consultation_symptoms_onset_date = filters.DateFromToRangeFilter( field_name="last_consultation__symptoms_onset_date" ) - last_consultation_admitted_to_list = MultiSelectFilter(field_name="last_consultation__admitted_to") - last_consultation_admitted_to = filters.NumberFilter(field_name="last_consultation__admitted_to") - last_consultation_assigned_to = filters.NumberFilter(field_name="last_consultation__assigned_to") - last_consultation_is_telemedicine = filters.BooleanFilter(field_name="last_consultation__is_telemedicine") + last_consultation_admitted_to_list = MultiSelectFilter( + field_name="last_consultation__admitted_to" + ) + last_consultation_admitted_to = filters.NumberFilter( + field_name="last_consultation__admitted_to" + ) + last_consultation_assigned_to = filters.NumberFilter( + field_name="last_consultation__assigned_to" + ) + last_consultation_is_telemedicine = filters.BooleanFilter( + field_name="last_consultation__is_telemedicine" + ) # Vaccination Filters covin_id = filters.CharFilter(field_name="covin_id") @@ -111,10 +141,13 @@ class PatientFilterSet(filters.FilterSet): # Permission Filters assigned_to = filters.NumberFilter(field_name="assigned_to") # Other Filters - has_bed = filters.BooleanFilter(field_name="has_bed", method='filter_bed_not_null') + has_bed = filters.BooleanFilter(field_name="has_bed", method="filter_bed_not_null") def filter_bed_not_null(self, queryset, name, value): - return queryset.filter(last_consultation__bed_number__isnull=value, last_consultation__discharge_date__isnull=True) + return queryset.filter( + last_consultation__bed_number__isnull=value, + last_consultation__discharge_date__isnull=True, + ) class PatientDRYFilter(DRYPermissionFiltersBase): @@ -144,7 +177,9 @@ def filter_queryset(self, request, queryset, view): def filter_list_queryset(self, request, queryset, view): try: - show_without_facility = json.loads(request.query_params.get("without_facility")) + show_without_facility = json.loads( + request.query_params.get("without_facility") + ) except ( JSONDecodeError, TypeError, @@ -162,7 +197,11 @@ class PatientViewSet( GenericViewSet, ): - authentication_classes = [CustomBasicAuthentication, CustomJWTAuthentication, MiddlewareAuthentication] + authentication_classes = [ + CustomBasicAuthentication, + CustomJWTAuthentication, + MiddlewareAuthentication, + ] permission_classes = (IsAuthenticated, DRYPermissions) lookup_field = "external_id" queryset = PatientRegistration.objects.all().select_related( @@ -253,29 +292,42 @@ def list(self, request, *args, **kwargs): """ if settings.CSV_REQUEST_PARAMETER in request.GET: # Start Date Validation - temp = filters.DjangoFilterBackend().get_filterset(self.request, self.queryset, self) + temp = filters.DjangoFilterBackend().get_filterset( + self.request, self.queryset, self + ) temp.is_valid() within_limits = False for field in self.date_range_fields: slice_obj = temp.form.cleaned_data.get(field) if slice_obj: if not slice_obj.start or not slice_obj.stop: - raise ValidationError({field: f"both starting and ending date must be provided for export"}) + raise ValidationError( + { + field: "both starting and ending date must be provided for export" + } + ) days_difference = ( - temp.form.cleaned_data.get(field).stop - temp.form.cleaned_data.get(field).start + temp.form.cleaned_data.get(field).stop + - temp.form.cleaned_data.get(field).start ).days if days_difference <= self.CSV_EXPORT_LIMIT: within_limits = True else: raise ValidationError( - {field: f"Cannot export more than {self.CSV_EXPORT_LIMIT} days at a time"} + { + field: f"Cannot export more than {self.CSV_EXPORT_LIMIT} days at a time" + } ) if not within_limits: raise ValidationError( - {"date": f"Atleast one date field must be filtered to be within {self.CSV_EXPORT_LIMIT} days"} + { + "date": f"Atleast one date field must be filtered to be within {self.CSV_EXPORT_LIMIT} days" + } ) # End Date Limiting Validation - queryset = self.filter_queryset(self.get_queryset()).values(*PatientRegistration.CSV_MAPPING.keys()) + queryset = self.filter_queryset(self.get_queryset()).values( + *PatientRegistration.CSV_MAPPING.keys() + ) return render_to_csv_response( queryset, field_header_map=PatientRegistration.CSV_MAPPING, @@ -341,8 +393,11 @@ def discharge_patient(self, request, *args, **kwargs): patient = self.get_object() patient.is_active = discharged patient.allow_transfer = not discharged - patient.save(update_fields=["allow_transfer", "is_active"]) - last_consultation = PatientConsultation.objects.filter(patient=patient).order_by("-id").first() + patient.assigned_to = None + patient.save(update_fields=["allow_transfer", "is_active", "assigned_to"]) + last_consultation = ( + PatientConsultation.objects.filter(patient=patient).order_by("-id").first() + ) current_time = localtime(now()) if last_consultation: reason = request.data.get("discharge_reason") @@ -356,9 +411,9 @@ def discharge_patient(self, request, *args, **kwargs): if last_consultation.discharge_date is None: last_consultation.discharge_date = current_time last_consultation.save() - ConsultationBed.objects.filter(consultation=last_consultation, end_date__isnull=True).update( - end_date=current_time - ) + ConsultationBed.objects.filter( + consultation=last_consultation, end_date__isnull=True + ).update(end_date=current_time) return Response(status=status.HTTP_200_OK) @@ -396,7 +451,9 @@ def transfer(self, request, *args, **kwargs): response_serializer = self.get_serializer_class()(patient) # Update all Active Shifting Request to Rejected - for shifting_request in ShiftingRequest.objects.filter(~Q(status__in=[30, 50, 80]), patient=patient): + for shifting_request in ShiftingRequest.objects.filter( + ~Q(status__in=[30, 50, 80]), patient=patient + ): shifting_request.status = 30 shifting_request.comments = ( shifting_request.comments @@ -416,7 +473,9 @@ class FacilityPatientStatsHistoryViewSet(viewsets.ModelViewSet): IsAuthenticated, DRYPermissions, ) - queryset = FacilityPatientStatsHistory.objects.filter(facility__deleted=False).order_by("-entry_date") + queryset = FacilityPatientStatsHistory.objects.filter( + facility__deleted=False + ).order_by("-entry_date") serializer_class = FacilityPatientStatsHistorySerializer filter_backends = (filters.DjangoFilterBackend,) filterset_class = FacilityPatientStatsHistoryFilterSet @@ -424,7 +483,9 @@ class FacilityPatientStatsHistoryViewSet(viewsets.ModelViewSet): def get_queryset(self): user = self.request.user - queryset = self.queryset.filter(facility__external_id=self.kwargs.get("facility_external_id")) + queryset = self.queryset.filter( + facility__external_id=self.kwargs.get("facility_external_id") + ) if user.is_superuser: return queryset elif self.request.user.user_type >= User.TYPE_VALUE_MAP["DistrictLabAdmin"]: @@ -434,10 +495,14 @@ def get_queryset(self): return queryset.filter(facility__users__id__exact=user.id) def get_object(self): - return get_object_or_404(self.get_queryset(), external_id=self.kwargs.get("external_id")) + return get_object_or_404( + self.get_queryset(), external_id=self.kwargs.get("external_id") + ) def get_facility(self): - facility_qs = Facility.objects.filter(external_id=self.kwargs.get("facility_external_id")) + facility_qs = Facility.objects.filter( + external_id=self.kwargs.get("facility_external_id") + ) if not self.request.user.is_superuser: facility_qs.filter(users__id__exact=self.request.user.id) return get_object_or_404(facility_qs) @@ -454,7 +519,9 @@ def list(self, request, *args, **kwargs): - entry_date_before: date in YYYY-MM-DD format, inclusive of this date """ - return super(FacilityPatientStatsHistoryViewSet, self).list(request, *args, **kwargs) + return super(FacilityPatientStatsHistoryViewSet, self).list( + request, *args, **kwargs + ) class PatientSearchSetPagination(PageNumberPagination): @@ -472,7 +539,9 @@ def get_queryset(self): if self.action != "list": return super(PatientSearchViewSet, self).get_queryset() else: - serializer = PatientSearchSerializer(data=self.request.query_params, partial=True) + serializer = PatientSearchSerializer( + data=self.request.query_params, partial=True + ) serializer.is_valid(raise_exception=True) if self.request.user.user_type >= User.TYPE_VALUE_MAP["DistrictLabAdmin"]: search_keys = [ @@ -485,11 +554,17 @@ def get_queryset(self): else: search_keys = ["date_of_birth", "year_of_birth", "phone_number", "age"] search_fields = { - key: serializer.validated_data[key] for key in search_keys if serializer.validated_data.get(key) + key: serializer.validated_data[key] + for key in search_keys + if serializer.validated_data.get(key) } if not search_fields: raise serializers.ValidationError( - {"detail": [f"None of the search keys provided. Available: {', '.join(search_keys)}"]} + { + "detail": [ + f"None of the search keys provided. Available: {', '.join(search_keys)}" + ] + } ) # if not self.request.user.is_superuser: @@ -537,14 +612,22 @@ def list(self, request, *args, **kwargs): return super(PatientSearchViewSet, self).list(request, *args, **kwargs) -class PatientNotesViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, GenericViewSet): - queryset = PatientNotes.objects.all().select_related("facility", "patient", "created_by").order_by("-created_date") +class PatientNotesViewSet( + ListModelMixin, RetrieveModelMixin, CreateModelMixin, GenericViewSet +): + queryset = ( + PatientNotes.objects.all() + .select_related("facility", "patient", "created_by") + .order_by("-created_date") + ) serializer_class = PatientNotesSerializer permission_classes = (IsAuthenticated, DRYPermissions) def get_queryset(self): user = self.request.user - queryset = self.queryset.filter(patient__external_id=self.kwargs.get("patient_external_id")) + queryset = self.queryset.filter( + patient__external_id=self.kwargs.get("patient_external_id") + ) if not user.is_superuser: return queryset if user.user_type >= User.TYPE_VALUE_MAP["StateLabAdmin"]: @@ -561,8 +644,14 @@ def get_queryset(self): def perform_create(self, serializer): patient = get_object_or_404( - get_patient_queryset(self.request.user).filter(external_id=self.kwargs.get("patient_external_id")) + get_patient_queryset(self.request.user).filter( + external_id=self.kwargs.get("patient_external_id") + ) ) if not patient.is_active: - raise ValidationError({"patient": "Only active patients data can be updated"}) - return serializer.save(facility=patient.facility, patient=patient, created_by=self.request.user) + raise ValidationError( + {"patient": "Only active patients data can be updated"} + ) + return serializer.save( + facility=patient.facility, patient=patient, created_by=self.request.user + )