Skip to content

Commit 1e962ec

Browse files
shivankackersainak
andauthored
Add Consent Model (#2209)
* added migrations * updates * updates * v-comparision * fixing files * complete? * added tests * fixed test * made changes * updated migrations and used bulk updates * Update care/facility/api/serializers/patient_consultation.py * fixed * fixed permissions and router * fixes * cleanup queryset * rebase migrations * allow only home facility users to create or update consent * fixes * add is_migrated field * fix permission * remove types from migrations --------- Co-authored-by: Aakash Singh <[email protected]>
1 parent 369b9df commit 1e962ec

12 files changed

+693
-40
lines changed

care/facility/admin.py

+8
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66
from care.facility.models.ambulance import Ambulance, AmbulanceDriver
77
from care.facility.models.asset import Asset
88
from care.facility.models.bed import AssetBed, Bed
9+
from care.facility.models.file_upload import FileUpload
10+
from care.facility.models.patient_consultation import (
11+
PatientConsent,
12+
PatientConsultation,
13+
)
914
from care.facility.models.patient_sample import PatientSample
1015

1116
from .models import (
@@ -209,3 +214,6 @@ class FacilityUserAdmin(DjangoQLSearchMixin, admin.ModelAdmin, ExportCsvMixin):
209214
admin.site.register(AssetBed)
210215
admin.site.register(Asset)
211216
admin.site.register(Bed)
217+
admin.site.register(PatientConsent)
218+
admin.site.register(FileUpload)
219+
admin.site.register(PatientConsultation)

care/facility/api/serializers/file_upload.py

+8-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
from care.facility.models.facility import Facility
88
from care.facility.models.file_upload import FileUpload
99
from care.facility.models.patient import PatientRegistration
10-
from care.facility.models.patient_consultation import PatientConsultation
10+
from care.facility.models.patient_consultation import (
11+
PatientConsent,
12+
PatientConsultation,
13+
)
1114
from care.facility.models.patient_sample import PatientSample
1215
from care.users.api.serializers.user import UserBaseMinimumSerializer
1316
from care.users.models import User
@@ -53,9 +56,9 @@ def check_permissions(file_type, associating_id, user, action="create"):
5356
raise Exception("No Permission")
5457
return consultation.id
5558
elif file_type == FileUpload.FileType.CONSENT_RECORD.value:
56-
consultation = PatientConsultation.objects.get(
57-
consent_records__contains=[{"id": associating_id}]
58-
)
59+
consultation = PatientConsent.objects.get(
60+
external_id=associating_id
61+
).consultation
5962
if consultation.discharge_date and not action == "read":
6063
raise serializers.ValidationError(
6164
{
@@ -173,6 +176,7 @@ class Meta:
173176
fields = (
174177
"id",
175178
"name",
179+
"associating_id",
176180
"uploaded_by",
177181
"archived_by",
178182
"archived_datetime",

care/facility/api/serializers/patient_consultation.py

+112-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from django.conf import settings
55
from django.db import transaction
6+
from django.utils import timezone
67
from django.utils.timezone import localtime, make_aware, now
78
from rest_framework import serializers
89
from rest_framework.exceptions import ValidationError
@@ -41,6 +42,7 @@
4142
EncounterSymptom,
4243
Symptom,
4344
)
45+
from care.facility.models.file_upload import FileUpload
4446
from care.facility.models.icd11_diagnosis import (
4547
ConditionVerificationStatus,
4648
ConsultationDiagnosis,
@@ -51,7 +53,11 @@
5153
RouteToFacility,
5254
SuggestionChoices,
5355
)
54-
from care.facility.models.patient_consultation import PatientConsultation
56+
from care.facility.models.patient_consultation import (
57+
ConsentType,
58+
PatientConsent,
59+
PatientConsultation,
60+
)
5561
from care.users.api.serializers.user import (
5662
UserAssignedSerializer,
5763
UserBaseMinimumSerializer,
@@ -848,3 +854,108 @@ def validate(self, attrs):
848854
class Meta:
849855
model = PatientConsultation
850856
fields = ("email",)
857+
858+
859+
class PatientConsentSerializer(serializers.ModelSerializer):
860+
id = serializers.CharField(source="external_id", read_only=True)
861+
created_by = UserBaseMinimumSerializer(read_only=True)
862+
archived_by = UserBaseMinimumSerializer(read_only=True)
863+
864+
class Meta:
865+
model = PatientConsent
866+
867+
fields = (
868+
"id",
869+
"type",
870+
"patient_code_status",
871+
"archived",
872+
"archived_by",
873+
"archived_date",
874+
"created_by",
875+
"created_date",
876+
)
877+
878+
read_only_fields = (
879+
"id",
880+
"created_by",
881+
"created_date",
882+
"archived",
883+
"archived_by",
884+
"archived_date",
885+
)
886+
887+
def validate(self, attrs):
888+
user = self.context["request"].user
889+
if (
890+
user.user_type < User.TYPE_VALUE_MAP["DistrictAdmin"]
891+
and self.context["consultation"].facility_id != user.home_facility_id
892+
):
893+
raise ValidationError(
894+
"Only Home Facility Staff can create consent for a Consultation"
895+
)
896+
897+
if attrs.get("type") == ConsentType.PATIENT_CODE_STATUS and not attrs.get(
898+
"patient_code_status"
899+
):
900+
raise ValidationError(
901+
{
902+
"patient_code_status": [
903+
"This field is required for Patient Code Status Consent"
904+
]
905+
}
906+
)
907+
908+
if attrs.get("type") != ConsentType.PATIENT_CODE_STATUS and attrs.get(
909+
"patient_code_status"
910+
):
911+
raise ValidationError(
912+
{
913+
"patient_code_status": [
914+
"This field is not required for this type of Consent"
915+
]
916+
}
917+
)
918+
return attrs
919+
920+
def clear_existing_records(self, consultation, type, user, self_id=None):
921+
consents = PatientConsent.objects.filter(
922+
consultation=consultation, type=type
923+
).exclude(id=self_id)
924+
925+
archived_date = timezone.now()
926+
consents.update(
927+
archived=True,
928+
archived_by=user,
929+
archived_date=archived_date,
930+
)
931+
FileUpload.objects.filter(
932+
associating_id__in=list(consents.values_list("external_id", flat=True)),
933+
file_type=FileUpload.FileType.CONSENT_RECORD,
934+
is_archived=False,
935+
).update(
936+
is_archived=True,
937+
archived_datetime=archived_date,
938+
archive_reason="Consent Archived",
939+
archived_by=user,
940+
)
941+
942+
def create(self, validated_data):
943+
with transaction.atomic():
944+
self.clear_existing_records(
945+
consultation=self.context["consultation"],
946+
type=validated_data["type"],
947+
user=self.context["request"].user,
948+
)
949+
validated_data["consultation"] = self.context["consultation"]
950+
validated_data["created_by"] = self.context["request"].user
951+
return super().create(validated_data)
952+
953+
def update(self, instance, validated_data):
954+
with transaction.atomic():
955+
self.clear_existing_records(
956+
consultation=instance.consultation,
957+
type=instance.type,
958+
user=self.context["request"].user,
959+
self_id=instance.id,
960+
)
961+
return super().update(instance, validated_data)

care/facility/api/viewsets/file_upload.py

+11-5
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,19 @@ def get_queryset(self):
8383
{"associating_id": "associating_id missing in request params"}
8484
)
8585
file_type = self.request.GET["file_type"]
86-
associating_id = self.request.GET["associating_id"]
86+
associating_ids = self.request.GET["associating_id"].split(",")
8787
if file_type not in FileUpload.FileType.__members__:
8888
raise ValidationError({"file_type": "invalid file type"})
8989
file_type = FileUpload.FileType[file_type].value
90-
associating_internal_id = check_permissions(
91-
file_type, associating_id, self.request.user, "read"
92-
)
90+
91+
associating_internal_ids = []
92+
93+
for associating_id in associating_ids:
94+
associating_internal_id = check_permissions(
95+
file_type, associating_id, self.request.user, "read"
96+
)
97+
associating_internal_ids.append(associating_internal_id)
98+
9399
return self.queryset.filter(
94-
file_type=file_type, associating_id=associating_internal_id
100+
file_type=file_type, associating_id__in=associating_internal_ids
95101
)

care/facility/api/viewsets/patient_consultation.py

+42-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from django.db.models import Prefetch
22
from django.db.models.query_utils import Q
3-
from django.shortcuts import render
3+
from django.shortcuts import get_object_or_404, render
44
from django_filters import rest_framework as filters
55
from drf_spectacular.utils import extend_schema
66
from dry_rest_permissions.generics import DRYPermissions
@@ -14,6 +14,7 @@
1414
from care.facility.api.serializers.file_upload import FileUploadRetrieveSerializer
1515
from care.facility.api.serializers.patient_consultation import (
1616
EmailDischargeSummarySerializer,
17+
PatientConsentSerializer,
1718
PatientConsultationDischargeSerializer,
1819
PatientConsultationIDSerializer,
1920
PatientConsultationSerializer,
@@ -22,14 +23,18 @@
2223
from care.facility.models.bed import AssetBed, ConsultationBed
2324
from care.facility.models.file_upload import FileUpload
2425
from care.facility.models.mixins.permissions.asset import IsAssetUser
25-
from care.facility.models.patient_consultation import PatientConsultation
26+
from care.facility.models.patient_consultation import (
27+
PatientConsent,
28+
PatientConsultation,
29+
)
2630
from care.facility.tasks.discharge_summary import (
2731
email_discharge_summary_task,
2832
generate_discharge_summary_task,
2933
)
3034
from care.facility.utils.reports import discharge_summary
3135
from care.users.models import Skill, User
3236
from care.utils.cache.cache_allowed_facilities import get_accessible_facilities
37+
from care.utils.queryset.consultation import get_consultation_queryset
3338

3439

3540
class PatientConsultationFilter(filters.FilterSet):
@@ -287,3 +292,38 @@ def dev_preview_discharge_summary(request, consultation_id):
287292
raise NotFound({"detail": "Consultation not found"})
288293
data = discharge_summary.get_discharge_summary_data(consultation)
289294
return render(request, "reports/patient_discharge_summary_pdf.html", data)
295+
296+
297+
class PatientConsentViewSet(
298+
AssetUserAccessMixin,
299+
mixins.CreateModelMixin,
300+
mixins.ListModelMixin,
301+
mixins.RetrieveModelMixin,
302+
mixins.UpdateModelMixin,
303+
GenericViewSet,
304+
):
305+
lookup_field = "external_id"
306+
serializer_class = PatientConsentSerializer
307+
permission_classes = (
308+
IsAuthenticated,
309+
DRYPermissions,
310+
)
311+
queryset = PatientConsent.objects.all().select_related("consultation")
312+
filter_backends = (filters.DjangoFilterBackend,)
313+
314+
filterset_fields = ("archived",)
315+
316+
def get_consultation_obj(self):
317+
return get_object_or_404(
318+
get_consultation_queryset(self.request.user).filter(
319+
external_id=self.kwargs["consultation_external_id"]
320+
)
321+
)
322+
323+
def get_queryset(self):
324+
return self.queryset.filter(consultation=self.get_consultation_obj())
325+
326+
def get_serializer_context(self):
327+
data = super().get_serializer_context()
328+
data["consultation"] = self.get_consultation_obj()
329+
return data

0 commit comments

Comments
 (0)