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

Foreign Key to User for Consultation Verified By #1567

Merged
merged 12 commits into from
Sep 7, 2023
6 changes: 5 additions & 1 deletion care/abdm/utils/fhir.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,11 @@ def _practioner(self):

id = str(uuid())
name = (
self.consultation.verified_by
(
self.consultation.verified_by
and f"{self.consultation.verified_by.first_name} {self.consultation.verified_by.last_name}"
rithviknishad marked this conversation as resolved.
Show resolved Hide resolved
)
or self.consultation.deprecated_verified_by
or f"{self.consultation.created_by.first_name} {self.consultation.created_by.last_name}"
)
self._practitioner_profile = Practitioner(
Expand Down
21 changes: 20 additions & 1 deletion care/facility/api/serializers/patient_consultation.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,15 @@ class PatientConsultationSerializer(serializers.ModelSerializer):
facility = ExternalIdSerializerField(read_only=True)

assigned_to_object = UserAssignedSerializer(source="assigned_to", read_only=True)

assigned_to = serializers.PrimaryKeyRelatedField(
queryset=User.objects.all(), required=False, allow_null=True
)

verified_by_object = UserBaseMinimumSerializer(source="verified_by", read_only=True)
verified_by = serializers.PrimaryKeyRelatedField(
queryset=User.objects.all(), required=True, allow_null=False
)

discharge_reason = serializers.ChoiceField(
choices=DISCHARGE_REASON_CHOICES, read_only=True, required=False
)
Expand Down Expand Up @@ -132,6 +136,7 @@ class Meta:
"last_edited_by",
"created_by",
"kasp_enabled_date",
"deprecated_verified_by",
)
exclude = ("deleted", "external_id")

Expand Down Expand Up @@ -313,6 +318,20 @@ def validate(self, attrs):
validated = super().validate(attrs)
# TODO Add Bed Authorisation Validation

if not validated["verified_by"].user_type == User.TYPE_VALUE_MAP["Doctor"]:
raise ValidationError("Only Doctors can verify a Consultation")

facility = (
self.instance and self.instance.facility or validated["patient"].facility
)
if (
validated["verified_by"].home_facility
and validated["verified_by"].home_facility != facility
):
raise ValidationError(
"Home Facility of the Doctor must be the same as the Consultation Facility"
)

if "suggestion" in validated:
if validated["suggestion"] is SuggestionChoices.R:
if not validated.get("referred_to") and not validated.get(
Expand Down
7 changes: 6 additions & 1 deletion care/facility/api/viewsets/facility_users.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.db.models import Prefetch
from django_filters import rest_framework as filters
from drf_spectacular.utils import extend_schema, extend_schema_view
from rest_framework import filters as drf_filters
from rest_framework import mixins
from rest_framework.exceptions import ValidationError
from rest_framework.permissions import IsAuthenticated
Expand Down Expand Up @@ -28,7 +29,11 @@ class FacilityUserViewSet(GenericViewSet, mixins.ListModelMixin):
filterset_class = UserFilter
queryset = User.objects.all()
permission_classes = [IsAuthenticated]
filter_backends = [filters.DjangoFilterBackend]
filter_backends = [
filters.DjangoFilterBackend,
drf_filters.SearchFilter,
]
search_fields = ["first_name", "last_name", "username"]

def get_queryset(self):
try:
Expand Down
30 changes: 30 additions & 0 deletions care/facility/migrations/0384_patientconsultation_verified_by.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Generated by Django 4.2.2 on 2023-08-31 04:31

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("facility", "0383_patientconsultation_icd11_principal_diagnosis"),
]

operations = [
migrations.RenameField(
model_name="patientconsultation",
old_name="verified_by",
new_name="deprecated_verified_by",
),
migrations.AddField(
model_name="patientconsultation",
name="verified_by",
field=models.ForeignKey(
null=True,
blank=False,
on_delete=django.db.models.deletion.SET_NULL,
to=settings.AUTH_USER_MODEL,
),
),
]
5 changes: 4 additions & 1 deletion care/facility/models/patient_consultation.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,10 @@ class PatientConsultation(PatientBaseModel, PatientRelatedPermissionMixin):
related_name="patient_assigned_to",
)

verified_by = models.TextField(default="", null=True, blank=True)
deprecated_verified_by = models.TextField(default="", null=True, blank=True)
verified_by = models.ForeignKey(
User, on_delete=models.SET_NULL, null=True, blank=False
)

created_by = models.ForeignKey(
User, on_delete=models.SET_NULL, null=True, related_name="created_user"
Expand Down
43 changes: 33 additions & 10 deletions care/facility/tests/test_patient_consultation_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from care.facility.api.viewsets.facility_users import FacilityUserViewSet
from care.facility.api.viewsets.patient_consultation import PatientConsultationViewSet
from care.facility.models.facility import Facility
from care.facility.models import Facility, User
from care.facility.models.patient_consultation import (
CATEGORY_CHOICES,
PatientConsultation,
Expand Down Expand Up @@ -58,25 +58,33 @@ def test_get_queryset_with_prefetching(self):


class TestPatientConsultation(TestBase, TestClassMixin, APITestCase):
default_data = {
"symptoms": [1],
"category": CATEGORY_CHOICES[0][0],
"examination_details": "examination_details",
"history_of_present_illness": "history_of_present_illness",
"treatment_plan": "treatment_plan",
"suggestion": PatientConsultation.SUGGESTION_CHOICES[0][0],
}
def get_default_data(self):
return {
"symptoms": [1],
"category": CATEGORY_CHOICES[0][0],
"examination_details": "examination_details",
"history_of_present_illness": "history_of_present_illness",
"treatment_plan": "treatment_plan",
"suggestion": PatientConsultation.SUGGESTION_CHOICES[0][0],
"verified_by": self.doctor.id,
}

def setUp(self):
self.factory = APIRequestFactory()
self.doctor = self.create_user(
username="doctor1",
district=self.district,
user_type=User.TYPE_VALUE_MAP["Doctor"],
)

self.consultation = self.create_consultation(
suggestion="A",
admission_date=make_aware(datetime.datetime(2020, 4, 1, 15, 30, 00)),
)

def create_admission_consultation(self, patient=None, **kwargs):
patient = patient or self.create_patient(facility_id=self.facility.id)
data = self.default_data.copy()
data = self.get_default_data()
kwargs.update(
{
"patient": patient.external_id,
Expand All @@ -93,6 +101,15 @@ def create_admission_consultation(self, patient=None, **kwargs):
)
return PatientConsultation.objects.get(external_id=res.data["id"])

def update_consultation(self, consultation, **kwargs):
return self.new_request(
(self.get_url(consultation), kwargs, "json"),
{"patch": "partial_update"},
PatientConsultationViewSet,
self.state_admin,
{"external_id": consultation.external_id},
)

def get_url(self, consultation=None):
if consultation:
return f"/api/v1/consultation/{consultation.external_id}"
Expand All @@ -107,6 +124,12 @@ def discharge(self, consultation, **kwargs):
{"external_id": consultation.external_id},
)

def test_create_consultation_verified_by_invalid_user(self):
res = self.update_consultation(
self.consultation, verified_by=self.state_admin.id
)
self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST)

def test_discharge_as_recovered_preadmission(self):
consultation = self.create_admission_consultation(
suggestion="A",
Expand Down
6 changes: 5 additions & 1 deletion care/templates/reports/patient_discharge_summary_pdf.html
Original file line number Diff line number Diff line change
Expand Up @@ -945,7 +945,11 @@ <h4 class="font-medium text-gray-500">
Verified By
</div>
<div class="mt-1 text-sm leading-5 text-gray-900">
{{consultation.verified_by|linebreaks}}
{% if consultation.verified_by %}
{{ consultation.verified_by.first_name }} {{ consultation.verified_by.last_name }}
{% else %}
-
{% endif %}
</div>
</div>
</body>
Expand Down
3 changes: 3 additions & 0 deletions care/users/api/viewsets/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ class UserFilterSet(filters.FilterSet):
)
last_login = filters.DateFromToRangeFilter(field_name="last_login")
district_id = filters.NumberFilter(field_name="district_id", lookup_expr="exact")
home_facility = filters.UUIDFilter(
field_name="home_facility__external_id", lookup_expr="exact"
)

def get_user_type(
self,
Expand Down
1 change: 0 additions & 1 deletion data/dummy/facility.json
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,6 @@
"is_telemedicine": false,
"last_updated_by_telemedicine": false,
"assigned_to": null,
"verified_by": "",
"created_by": 2,
"last_edited_by": 2,
"last_daily_round": null,
Expand Down