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

Add Consent Model #2209

Merged
merged 23 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions care/facility/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
from care.facility.models.ambulance import Ambulance, AmbulanceDriver
from care.facility.models.asset import Asset
from care.facility.models.bed import AssetBed, Bed
from care.facility.models.file_upload import FileUpload
from care.facility.models.patient_consultation import (
PatientConsent,
PatientConsultation,
)
from care.facility.models.patient_sample import PatientSample

from .models import (
Expand Down Expand Up @@ -209,3 +214,6 @@ class FacilityUserAdmin(DjangoQLSearchMixin, admin.ModelAdmin, ExportCsvMixin):
admin.site.register(AssetBed)
admin.site.register(Asset)
admin.site.register(Bed)
admin.site.register(PatientConsent)
admin.site.register(FileUpload)
admin.site.register(PatientConsultation)
12 changes: 8 additions & 4 deletions care/facility/api/serializers/file_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
from care.facility.models.facility import Facility
from care.facility.models.file_upload import FileUpload
from care.facility.models.patient import PatientRegistration
from care.facility.models.patient_consultation import PatientConsultation
from care.facility.models.patient_consultation import (
PatientConsent,
PatientConsultation,
)
from care.facility.models.patient_sample import PatientSample
from care.users.api.serializers.user import UserBaseMinimumSerializer
from care.users.models import User
Expand Down Expand Up @@ -53,9 +56,9 @@ def check_permissions(file_type, associating_id, user, action="create"):
raise Exception("No Permission")
return consultation.id
elif file_type == FileUpload.FileType.CONSENT_RECORD.value:
consultation = PatientConsultation.objects.get(
consent_records__contains=[{"id": associating_id}]
)
consultation = PatientConsent.objects.get(
external_id=associating_id
).consultation
if consultation.discharge_date and not action == "read":
raise serializers.ValidationError(
{
Expand Down Expand Up @@ -173,6 +176,7 @@ class Meta:
fields = (
"id",
"name",
"associating_id",
"uploaded_by",
"archived_by",
"archived_datetime",
Expand Down
113 changes: 112 additions & 1 deletion care/facility/api/serializers/patient_consultation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from django.conf import settings
from django.db import transaction
from django.utils import timezone
from django.utils.timezone import localtime, make_aware, now
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
Expand Down Expand Up @@ -41,6 +42,7 @@
EncounterSymptom,
Symptom,
)
from care.facility.models.file_upload import FileUpload
from care.facility.models.icd11_diagnosis import (
ConditionVerificationStatus,
ConsultationDiagnosis,
Expand All @@ -51,7 +53,11 @@
RouteToFacility,
SuggestionChoices,
)
from care.facility.models.patient_consultation import PatientConsultation
from care.facility.models.patient_consultation import (
ConsentType,
PatientConsent,
PatientConsultation,
)
from care.users.api.serializers.user import (
UserAssignedSerializer,
UserBaseMinimumSerializer,
Expand Down Expand Up @@ -848,3 +854,108 @@ def validate(self, attrs):
class Meta:
model = PatientConsultation
fields = ("email",)


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)

class Meta:
model = PatientConsent

fields = (
"id",
"type",
"patient_code_status",
"archived",
"archived_by",
"archived_date",
"created_by",
"created_date",
)

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

def validate(self, attrs):
user = self.context["request"].user
if (
user.user_type < User.TYPE_VALUE_MAP["DistrictAdmin"]
and self.context["consultation"].facility_id != user.home_facility_id
):
raise ValidationError(
"Only Home Facility Staff can create consent for a Consultation"
)

if attrs.get("type") == ConsentType.PATIENT_CODE_STATUS and not attrs.get(
"patient_code_status"
):
raise ValidationError(
{
"patient_code_status": [
"This field is required for Patient Code Status Consent"
]
}
)

if attrs.get("type") != ConsentType.PATIENT_CODE_STATUS and attrs.get(
"patient_code_status"
):
raise ValidationError(
{
"patient_code_status": [
"This field is not required for this type of Consent"
]
}
)
return attrs

def clear_existing_records(self, consultation, type, user, self_id=None):
consents = PatientConsent.objects.filter(
consultation=consultation, type=type
).exclude(id=self_id)

archived_date = timezone.now()
consents.update(
archived=True,
archived_by=user,
archived_date=archived_date,
)
FileUpload.objects.filter(
associating_id__in=list(consents.values_list("external_id", flat=True)),
file_type=FileUpload.FileType.CONSENT_RECORD,
is_archived=False,
).update(
is_archived=True,
archived_datetime=archived_date,
archive_reason="Consent Archived",
archived_by=user,
)

def create(self, validated_data):
with transaction.atomic():
self.clear_existing_records(
consultation=self.context["consultation"],
type=validated_data["type"],
user=self.context["request"].user,
)
validated_data["consultation"] = self.context["consultation"]
validated_data["created_by"] = self.context["request"].user
return super().create(validated_data)

def update(self, instance, validated_data):
with transaction.atomic():
self.clear_existing_records(
consultation=instance.consultation,
type=instance.type,
user=self.context["request"].user,
self_id=instance.id,
)
return super().update(instance, validated_data)
16 changes: 11 additions & 5 deletions care/facility/api/viewsets/file_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,19 @@ def get_queryset(self):
{"associating_id": "associating_id missing in request params"}
)
file_type = self.request.GET["file_type"]
associating_id = self.request.GET["associating_id"]
associating_ids = self.request.GET["associating_id"].split(",")
if file_type not in FileUpload.FileType.__members__:
raise ValidationError({"file_type": "invalid file type"})
file_type = FileUpload.FileType[file_type].value
associating_internal_id = check_permissions(
file_type, associating_id, self.request.user, "read"
)

associating_internal_ids = []

for associating_id in associating_ids:
associating_internal_id = check_permissions(
file_type, associating_id, self.request.user, "read"
)
associating_internal_ids.append(associating_internal_id)

return self.queryset.filter(
file_type=file_type, associating_id=associating_internal_id
file_type=file_type, associating_id__in=associating_internal_ids
)
44 changes: 42 additions & 2 deletions care/facility/api/viewsets/patient_consultation.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.db.models import Prefetch
from django.db.models.query_utils import Q
from django.shortcuts import render
from django.shortcuts import get_object_or_404, render
from django_filters import rest_framework as filters
from drf_spectacular.utils import extend_schema
from dry_rest_permissions.generics import DRYPermissions
Expand All @@ -14,6 +14,7 @@
from care.facility.api.serializers.file_upload import FileUploadRetrieveSerializer
from care.facility.api.serializers.patient_consultation import (
EmailDischargeSummarySerializer,
PatientConsentSerializer,
PatientConsultationDischargeSerializer,
PatientConsultationIDSerializer,
PatientConsultationSerializer,
Expand All @@ -22,14 +23,18 @@
from care.facility.models.bed import AssetBed, ConsultationBed
from care.facility.models.file_upload import FileUpload
from care.facility.models.mixins.permissions.asset import IsAssetUser
from care.facility.models.patient_consultation import PatientConsultation
from care.facility.models.patient_consultation import (
PatientConsent,
PatientConsultation,
)
from care.facility.tasks.discharge_summary import (
email_discharge_summary_task,
generate_discharge_summary_task,
)
from care.facility.utils.reports import discharge_summary
from care.users.models import Skill, User
from care.utils.cache.cache_allowed_facilities import get_accessible_facilities
from care.utils.queryset.consultation import get_consultation_queryset


class PatientConsultationFilter(filters.FilterSet):
Expand Down Expand Up @@ -287,3 +292,38 @@ def dev_preview_discharge_summary(request, consultation_id):
raise NotFound({"detail": "Consultation not found"})
data = discharge_summary.get_discharge_summary_data(consultation)
return render(request, "reports/patient_discharge_summary_pdf.html", data)


class PatientConsentViewSet(
AssetUserAccessMixin,
mixins.CreateModelMixin,
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
GenericViewSet,
):
lookup_field = "external_id"
serializer_class = PatientConsentSerializer
permission_classes = (
IsAuthenticated,
DRYPermissions,
)
queryset = PatientConsent.objects.all().select_related("consultation")
filter_backends = (filters.DjangoFilterBackend,)

filterset_fields = ("archived",)

def get_consultation_obj(self):
return get_object_or_404(
get_consultation_queryset(self.request.user).filter(
external_id=self.kwargs["consultation_external_id"]
)
)

def get_queryset(self):
return self.queryset.filter(consultation=self.get_consultation_obj())

def get_serializer_context(self):
data = super().get_serializer_context()
data["consultation"] = self.get_consultation_obj()
return data
Loading
Loading