Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return files with consent lists and consent filters #2255

Merged
merged 10 commits into from
Jul 13, 2024
17 changes: 16 additions & 1 deletion care/facility/api/serializers/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
PatientRegistration,
)
from care.facility.models.bed import ConsultationBed
from care.facility.models.file_upload import FileUpload
from care.facility.models.notification import Notification
from care.facility.models.patient import PatientNotesEdit
from care.facility.models.patient_base import (
Expand All @@ -37,7 +38,10 @@
DiseaseStatusEnum,
NewDischargeReasonEnum,
)
from care.facility.models.patient_consultation import PatientConsultation
from care.facility.models.patient_consultation import (
PatientConsent,
PatientConsultation,
)
from care.facility.models.patient_external_test import PatientExternalTest
from care.hcx.models.claim import Claim
from care.hcx.models.policy import Policy
Expand Down Expand Up @@ -75,6 +79,7 @@ class PatientListSerializer(serializers.ModelSerializer):
state_object = StateSerializer(source="state", read_only=True)

last_consultation = PatientConsultationSerializer(read_only=True)
has_consents = serializers.SerializerMethodField(read_only=True)

blood_group = ChoiceField(choices=BLOOD_GROUP_CHOICES, required=True)
disease_status = ChoiceField(
Expand All @@ -101,6 +106,16 @@ def get_has_eligible_policy(self, patient):
"get_approved_claim_amount", read_only=True
)

def get_has_consents(self, patient: PatientRegistration):
consents = PatientConsent.objects.filter(
consultation=patient.last_consultation, archived=False
).values_list("external_id", flat=True)
return FileUpload.objects.filter(
associating_id__in=list(consents),
file_type=FileUpload.FileType.CONSENT_RECORD,
is_archived=False,
).exists()

def get_approved_claim_amount(self, patient):
if patient.last_consultation is not None:
claim = (
Expand Down
20 changes: 20 additions & 0 deletions care/facility/api/serializers/patient_consultation.py
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,7 @@ class PatientConsentSerializer(serializers.ModelSerializer):
id = serializers.CharField(source="external_id", read_only=True)
created_by = UserBaseMinimumSerializer(read_only=True)
archived_by = UserBaseMinimumSerializer(read_only=True)
files = serializers.SerializerMethodField()

class Meta:
model = PatientConsent
Expand All @@ -869,6 +870,7 @@ class Meta:
"id",
"type",
"patient_code_status",
"files",
"archived",
"archived_by",
"archived_date",
Expand All @@ -878,13 +880,31 @@ class Meta:

read_only_fields = (
"id",
"files",
"created_by",
"created_date",
"archived",
"archived_by",
"archived_date",
)

def get_files(self, obj):
from care.facility.api.serializers.file_upload import (
FileUploadListSerializer,
check_permissions,
)

user = self.context["request"].user
file_type = FileUpload.FileType.CONSENT_RECORD
if check_permissions(file_type, obj.external_id, user, "read"):
return FileUploadListSerializer(
FileUpload.objects.filter(
associating_id=obj.external_id, file_type=file_type
),
many=True,
).data
return None

def validate_patient_code_status(self, value):
if value == PatientCodeStatusType.NOT_SPECIFIED:
raise ValidationError(
Expand Down
53 changes: 52 additions & 1 deletion care/facility/api/viewsets/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
)
from care.facility.models.base import covert_choice_dict
from care.facility.models.bed import AssetBed
from care.facility.models.file_upload import FileUpload
from care.facility.models.icd11_diagnosis import (
INACTIVE_CONDITION_VERIFICATION_STATUSES,
ConditionVerificationStatus,
Expand All @@ -78,7 +79,10 @@
DISEASE_STATUS_DICT,
NewDischargeReasonEnum,
)
from care.facility.models.patient_consultation import PatientConsultation
from care.facility.models.patient_consultation import (
PatientConsent,
PatientConsultation,
)
from care.users.models import User
from care.utils.cache.cache_allowed_facilities import get_accessible_facilities
from care.utils.filters.choicefilter import CareChoiceFilter
Expand Down Expand Up @@ -279,6 +283,53 @@ def filter_by_diagnoses(self, queryset, name, value):
)
return queryset.filter(filter_q)

last_consultation__consent_types = MultiSelectFilter(
method="filter_by_has_consents"
)

def filter_by_has_consents(self, queryset, name, value: str):
shivankacker marked this conversation as resolved.
Show resolved Hide resolved

if not value:
return queryset

values = value.split(",")

filter_q = Q()

consultation_consent_files = (
FileUpload.objects.filter(
file_type=FileUpload.FileType.CONSENT_RECORD,
is_archived=False,
)
.order_by("associating_id")
.distinct("associating_id")
shivankacker marked this conversation as resolved.
Show resolved Hide resolved
.values_list("associating_id", flat=True)
)

consultations = PatientConsent.objects.filter(
external_id__in=[x for x in list(consultation_consent_files)],
shivankacker marked this conversation as resolved.
Show resolved Hide resolved
archived=False,
)

if "None" in values:
filter_q |= ~Q(
last_consultation__id__in=list(
consultations.values_list("consultation_id", flat=True)
)
shivankacker marked this conversation as resolved.
Show resolved Hide resolved
)
values.remove("None")

if values:
filter_q |= Q(
last_consultation__id__in=list(
shivankacker marked this conversation as resolved.
Show resolved Hide resolved
consultations.filter(type__in=values).values_list(
"consultation_id", flat=True
)
)
)

return queryset.filter(filter_q)


class PatientDRYFilter(DRYPermissionFiltersBase):
def filter_queryset(self, request, queryset, view):
Expand Down
194 changes: 190 additions & 4 deletions care/facility/tests/test_patient_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from rest_framework.test import APITestCase

from care.facility.models import PatientNoteThreadChoices
from care.facility.models.file_upload import FileUpload
from care.facility.models.icd11_diagnosis import (
ConditionVerificationStatus,
ICD11Diagnosis,
Expand Down Expand Up @@ -282,6 +283,112 @@ def test_patient_note_edit(self):
self.assertEqual(data[1]["note"], note_content)


class PatientTestCase(TestUtils, APITestCase):
@classmethod
def setUpTestData(cls):
cls.state = cls.create_state()
cls.district = cls.create_district(cls.state)
cls.local_body = cls.create_local_body(cls.district)
cls.super_user = cls.create_super_user("su", cls.district)
cls.facility = cls.create_facility(cls.super_user, cls.district, cls.local_body)
cls.user = cls.create_user(
"doctor1", cls.district, home_facility=cls.facility, user_type=15
)
cls.patient = cls.create_patient(cls.district, cls.facility)
cls.consultation = cls.create_consultation(
patient_no="IP5678",
patient=cls.patient,
facility=cls.facility,
created_by=cls.user,
suggestion="A",
encounter_date=now(),
)
cls.patient_2 = cls.create_patient(cls.district, cls.facility)
cls.consultation_2 = cls.create_consultation(
patient_no="IP5679",
patient=cls.patient_2,
facility=cls.facility,
created_by=cls.user,
suggestion="A",
encounter_date=now(),
)

cls.consent = cls.create_patient_consent(cls.consultation, created_by=cls.user)
FileUpload.objects.create(
internal_name="test.pdf",
file_type=FileUpload.FileType.CONSENT_RECORD,
name="Test File",
associating_id=cls.consent.external_id,
file_category=FileUpload.FileCategory.UNSPECIFIED,
)

def get_base_url(self) -> str:
return "/api/v1/patient/"

def test_has_consent(self):
self.client.force_authenticate(user=self.user)
response = self.client.get(self.get_base_url())
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["count"], 2)
patient_1_response = [
x
for x in response.data["results"]
if x["id"] == str(self.patient.external_id)
][0]
patient_2_response = [
x
for x in response.data["results"]
if x["id"] == str(self.patient_2.external_id)
][0]
self.assertEqual(patient_1_response["has_consents"], True)
self.assertEqual(patient_2_response["has_consents"], False)

def test_has_consents_archived(self):
self.client.force_authenticate(user=self.user)
consent = self.create_patient_consent(self.consultation_2, created_by=self.user)
file = FileUpload.objects.create(
internal_name="test.pdf",
file_type=FileUpload.FileType.CONSENT_RECORD,
name="Test File",
associating_id=consent.external_id,
file_category=FileUpload.FileCategory.UNSPECIFIED,
)
response = self.client.get(self.get_base_url())
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["count"], 2)
patient_1_response = [
x
for x in response.data["results"]
if x["id"] == str(self.patient.external_id)
][0]
patient_2_response = [
x
for x in response.data["results"]
if x["id"] == str(self.patient_2.external_id)
][0]
self.assertEqual(patient_1_response["has_consents"], True)
self.assertEqual(patient_2_response["has_consents"], True)

file.is_archived = True
file.save()

response = self.client.get(self.get_base_url())
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["count"], 2)
patient_1_response = [
x
for x in response.data["results"]
if x["id"] == str(self.patient.external_id)
][0]
patient_2_response = [
x
for x in response.data["results"]
if x["id"] == str(self.patient_2.external_id)
][0]
self.assertEqual(patient_1_response["has_consents"], True)
self.assertEqual(patient_2_response["has_consents"], False)


class PatientFilterTestCase(TestUtils, APITestCase):
@classmethod
def setUpTestData(cls):
Expand Down Expand Up @@ -331,6 +438,49 @@ def setUpTestData(cls):
verification_status=ConditionVerificationStatus.UNCONFIRMED,
)

cls.consent = cls.create_patient_consent(
cls.consultation, created_by=cls.user, type=1, patient_code_status=None
)

cls.patient_2 = cls.create_patient(cls.district, cls.facility)
cls.consultation_2 = cls.create_consultation(
patient_no="IP5679",
patient=cls.patient_2,
facility=cls.facility,
created_by=cls.user,
suggestion="A",
encounter_date=now(),
)
cls.consent2 = cls.create_patient_consent(
cls.consultation_2, created_by=cls.user
)

cls.patient_3 = cls.create_patient(cls.district, cls.facility)
cls.consultation_3 = cls.create_consultation(
patient_no="IP5680",
patient=cls.patient_3,
facility=cls.facility,
created_by=cls.user,
suggestion="A",
encounter_date=now(),
)

FileUpload.objects.create(
internal_name="test.pdf",
file_type=FileUpload.FileType.CONSENT_RECORD,
name="Test File",
associating_id=cls.consent.external_id,
file_category=FileUpload.FileCategory.UNSPECIFIED,
)

FileUpload.objects.create(
internal_name="test.pdf",
file_type=FileUpload.FileType.CONSENT_RECORD,
name="Test File",
associating_id=cls.consent2.external_id,
file_category=FileUpload.FileCategory.UNSPECIFIED,
)

def get_base_url(self) -> str:
return "/api/v1/patient/"

Expand All @@ -353,10 +503,8 @@ def test_filter_by_location(self):
},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["count"], 1)
self.assertEqual(
response.data["results"][0]["id"], str(self.patient.external_id)
)
self.assertEqual(response.data["count"], 3)
self.assertContains(response, str(self.patient.external_id))

def test_filter_by_diagnoses(self):
self.client.force_authenticate(user=self.user)
Expand Down Expand Up @@ -431,6 +579,44 @@ def test_filter_by_review_missed(self):
else:
self.assertIsNone(patient["review_time"])

def test_filter_by_has_consents(self):

choices = ["1", "2", "3", "4", "5", "None"]

self.client.force_authenticate(user=self.user)
res = self.client.get(
self.get_base_url(), {"last_consultation__consent_types": choices[5]}
)

self.assertEqual(res.status_code, status.HTTP_200_OK)
self.assertEqual(res.json()["count"], 1)
self.assertContains(res, self.patient_3.external_id)

res = self.client.get(
self.get_base_url(),
{"last_consultation__consent_types": ",".join(choices[:4])},
)

self.assertEqual(res.status_code, status.HTTP_200_OK)
self.assertEqual(res.json()["count"], 2)
self.assertContains(res, self.patient.external_id)
self.assertContains(res, self.patient_2.external_id)

res = self.client.get(
self.get_base_url(), {"last_consultation__consent_types": choices[0]}
)

self.assertEqual(res.status_code, status.HTTP_200_OK)
self.assertEqual(res.json()["count"], 1)
self.assertContains(res, self.patient.external_id)

res = self.client.get(
self.get_base_url(), {"last_consultation__consent_types": ",".join(choices)}
)

self.assertEqual(res.status_code, status.HTTP_200_OK)
self.assertEqual(res.json()["count"], 3)


class PatientTransferTestCase(TestUtils, APITestCase):
@classmethod
Expand Down
Loading