Skip to content

Commit

Permalink
Merge branch 'master' into sainak/fix/beds
Browse files Browse the repository at this point in the history
  • Loading branch information
sainak authored Sep 6, 2023
2 parents 21e50f0 + 0749c8d commit 973e716
Show file tree
Hide file tree
Showing 14 changed files with 278 additions and 42 deletions.
1 change: 1 addition & 0 deletions care/abdm/api/serializers/health_facility.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

class HealthFacilitySerializer(serializers.ModelSerializer):
id = serializers.CharField(source="external_id", read_only=True)
registered = serializers.BooleanField(read_only=True)

class Meta:
model = HealthFacility
Expand Down
81 changes: 45 additions & 36 deletions care/abdm/api/viewsets/health_facility.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from django.shortcuts import get_object_or_404
from celery import shared_task
from dry_rest_permissions.generics import DRYPermissions
from rest_framework.decorators import action
from rest_framework.mixins import (
CreateModelMixin,
ListModelMixin,
Expand All @@ -15,6 +17,36 @@
from care.utils.queryset.facility import get_facility_queryset


@shared_task
def register_health_facility_as_service(facility_external_id):
health_facility = HealthFacility.objects.filter(
facility__external_id=facility_external_id
).first()

if not health_facility:
return False

if health_facility.registered:
return True

response = Bridge().add_update_service(
{
"id": health_facility.hf_id,
"name": health_facility.facility.name,
"type": "HIP",
"active": True,
"alias": ["CARE_HIP"],
}
)

if response.status_code == 200:
health_facility.registered = True
health_facility.save()
return True

return False


class HealthFacilityViewSet(
GenericViewSet,
CreateModelMixin,
Expand All @@ -25,48 +57,25 @@ class HealthFacilityViewSet(
serializer_class = HealthFacilitySerializer
model = HealthFacility
queryset = HealthFacility.objects.all()
permission_classes = (IsAuthenticated,)
permission_classes = (IsAuthenticated, DRYPermissions)
lookup_field = "facility__external_id"

def get_queryset(self):
queryset = self.queryset
facilities = get_facility_queryset(self.request.user)
return queryset.filter(facility__in=facilities)

def get_facility(self, facility_external_id):
facilities = get_facility_queryset(self.request.user)
return get_object_or_404(facilities.filter(external_id=facility_external_id))

def link_health_facility(self, hf_id, facility_id):
facility = self.get_facility(facility_id)
return Bridge().add_update_service(
{
"id": hf_id,
"name": facility.name,
"type": "HIP",
"active": True,
"alias": ["CARE_HIP"],
}
)

def create(self, request, *args, **kwargs):
if (
self.link_health_facility(
request.data["hf_id"], request.data["facility"]
).status_code
== 200
):
return super().create(request, *args, **kwargs)
@action(detail=True, methods=["POST"])
def register_service(self, request, facility__external_id):
registered = register_health_facility_as_service(facility__external_id)

return Response({"message": "Error linking health facility"}, status=400)
return Response({"registered": registered})

def update(self, request, *args, **kwargs):
if (
self.link_health_facility(
request.data["hf_id"], kwargs["facility__external_id"]
).status_code
== 200
):
return super().update(request, *args, **kwargs)
def perform_create(self, serializer):
instance = serializer.save()
register_health_facility_as_service.delay(instance.facility.external_id)

return Response({"message": "Error linking health facility"}, status=400)
def perform_update(self, serializer):
serializer.validated_data["registered"] = False
instance = serializer.save()
register_health_facility_as_service.delay(instance.facility.external_id)
17 changes: 17 additions & 0 deletions care/abdm/migrations/0010_healthfacility_registered.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.2.2 on 2023-09-05 06:42

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("abdm", "0009_healthfacility"),
]

operations = [
migrations.AddField(
model_name="healthfacility",
name="registered",
field=models.BooleanField(default=False),
),
]
4 changes: 3 additions & 1 deletion care/abdm/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from django.db import models

from care.abdm.permissions import HealthFacilityPermissions
from care.utils.models.base import BaseModel


Expand Down Expand Up @@ -37,8 +38,9 @@ def __str__(self):
return self.abha_number


class HealthFacility(BaseModel):
class HealthFacility(BaseModel, HealthFacilityPermissions):
hf_id = models.CharField(max_length=50, unique=True)
registered = models.BooleanField(default=False)
facility = models.OneToOneField(
"facility.Facility", on_delete=models.PROTECT, to_field="external_id"
)
Expand Down
29 changes: 29 additions & 0 deletions care/abdm/permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from care.facility.models.mixins.permissions.base import BasePermissionMixin
from care.users.models import User


class HealthFacilityPermissions(BasePermissionMixin):
"""
Permissions for HealthFacilityViewSet
"""

def has_object_read_permission(self, request):
return self.facility.has_object_read_permission(request)

def has_object_write_permission(self, request):
allowed_user_types = [
User.TYPE_VALUE_MAP["WardAdmin"],
User.TYPE_VALUE_MAP["LocalBodyAdmin"],
User.TYPE_VALUE_MAP["DistrictAdmin"],
User.TYPE_VALUE_MAP["StateAdmin"],
]
return request.user.is_superuser or (
request.user.user_type in allowed_user_types
and self.facility.has_object_write_permission(request)
)

def has_object_update_permission(self, request):
return self.has_object_write_permission(request)

def has_object_destroy_permission(self, request):
return self.has_object_write_permission(request)
43 changes: 42 additions & 1 deletion care/facility/api/serializers/patient_consultation.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,10 +361,14 @@ def validate(self, attrs):
)
from care.facility.static_data.icd11 import ICDDiseases

final_diagnosis = []
provisional_diagnosis = []

if "icd11_diagnoses" in validated:
for diagnosis in validated["icd11_diagnoses"]:
try:
ICDDiseases.by.id[diagnosis]
final_diagnosis.append(diagnosis)
except BaseException:
raise ValidationError(
{
Expand All @@ -378,6 +382,7 @@ def validate(self, attrs):
for diagnosis in validated["icd11_provisional_diagnoses"]:
try:
ICDDiseases.by.id[diagnosis]
provisional_diagnosis.append(diagnosis)
except BaseException:
raise ValidationError(
{
Expand All @@ -386,6 +391,41 @@ def validate(self, attrs):
]
}
)

if (
"icd11_principal_diagnosis" in validated
and validated.get("suggestion") != SuggestionChoices.DD
):
if len(final_diagnosis):
if validated["icd11_principal_diagnosis"] not in final_diagnosis:
raise ValidationError(
{
"icd11_principal_diagnosis": [
"Principal Diagnosis must be one of the Final Diagnosis"
]
}
)
elif len(provisional_diagnosis):
if validated["icd11_principal_diagnosis"] not in provisional_diagnosis:
raise ValidationError(
{
"icd11_principal_diagnosis": [
"Principal Diagnosis must be one of the Provisional Diagnosis"
]
}
)
else:
raise ValidationError(
{
"icd11_diagnoses": [
"Atleast one diagnosis is required for final diagnosis"
],
"icd11_provisional_diagnoses": [
"Atleast one diagnosis is required for provisional diagnosis"
],
}
)

return validated


Expand Down Expand Up @@ -525,10 +565,11 @@ def create(self, validated_data):
class PatientConsultationIDSerializer(serializers.ModelSerializer):
consultation_id = serializers.UUIDField(source="external_id", read_only=True)
patient_id = serializers.UUIDField(source="patient.external_id", read_only=True)
bed_id = serializers.UUIDField(source="current_bed.bed.external_id", read_only=True)

class Meta:
model = PatientConsultation
fields = ("consultation_id", "patient_id")
fields = ("consultation_id", "patient_id", "bed_id")


class EmailDischargeSummarySerializer(serializers.Serializer):
Expand Down
17 changes: 17 additions & 0 deletions care/facility/api/serializers/prescription.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,23 @@ def validate(self, attrs):
MedibaseMedicine, external_id=attrs["medicine"]
)

if not self.instance:
if Prescription.objects.filter(
consultation__external_id=self.context["request"].parser_context[
"kwargs"
]["consultation_external_id"],
medicine=attrs["medicine"],
discontinued=False,
).exists():
raise serializers.ValidationError(
{
"medicine": (
"This medicine is already prescribed to this patient. "
"Please discontinue the existing prescription to prescribe again."
)
}
)

if attrs.get("is_prn"):
if not attrs.get("indicator"):
raise serializers.ValidationError(
Expand Down
2 changes: 1 addition & 1 deletion care/facility/api/viewsets/prescription.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def discontinue(self, request, *args, **kwargs):
"discontinued_reason", None
)
prescription_obj.save()
return Response({}, status=status.HTTP_201_CREATED)
return Response({}, status=status.HTTP_200_OK)

@extend_schema(tags=["prescriptions"])
@action(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.2.2 on 2023-09-04 09:49

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("facility", "0382_assetservice_remove_asset_last_serviced_on_and_more"),
]

operations = [
migrations.AddField(
model_name="patientconsultation",
name="icd11_principal_diagnosis",
field=models.CharField(blank=True, default="", max_length=100, null=True),
),
]
3 changes: 3 additions & 0 deletions care/facility/models/patient_consultation.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ class PatientConsultation(PatientBaseModel, PatientRelatedPermissionMixin):
icd11_diagnoses = ArrayField(
models.CharField(max_length=100), default=list, blank=True, null=True
)
icd11_principal_diagnosis = models.CharField(
max_length=100, default="", blank=True, null=True
)
symptoms = MultiSelectField(
choices=SYMPTOM_CHOICES,
default=1,
Expand Down
61 changes: 61 additions & 0 deletions care/facility/tests/test_prescriptions_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from rest_framework import status

from care.facility.models import MedibaseMedicine
from care.utils.tests.test_base import TestBase


class PrescriptionsApiTestCase(TestBase):
def setUp(self) -> None:
super().setUp()
self.medicine = MedibaseMedicine.objects.first()

self.normal_prescription_data = {
"medicine": self.medicine.external_id,
"prescription_type": "REGULAR",
"dosage": "1 mg",
"frequency": "OD",
"is_prn": False,
}

def test_create_normal_prescription(self):
consultation = self.create_consultation()
response = self.client.post(
f"/api/v1/consultation/{consultation.external_id}/prescriptions/",
self.normal_prescription_data,
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)

def test_prescribe_duplicate_active_medicine_and_discontinue(self):
"""
1. Creates a prescription with Medicine A
2. Attempts to create another prescription with Medicine A (expecting failure)
3. Discontinues the first prescription
4. Re-attempts to create another prescription with Medicine A (expecting success)
"""
consultation = self.create_consultation()
res = self.client.post(
f"/api/v1/consultation/{consultation.external_id}/prescriptions/",
self.normal_prescription_data,
)
self.assertEqual(res.status_code, status.HTTP_201_CREATED)
discontinue_prescription_id = res.data["id"]

res = self.client.post(
f"/api/v1/consultation/{consultation.external_id}/prescriptions/",
self.normal_prescription_data,
)
self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST)

res = self.client.post(
f"/api/v1/consultation/{consultation.external_id}/prescriptions/{discontinue_prescription_id}/discontinue/",
{
"discontinued_reason": "Test Reason",
},
)
self.assertEqual(res.status_code, status.HTTP_200_OK)

res = self.client.post(
f"/api/v1/consultation/{consultation.external_id}/prescriptions/",
self.normal_prescription_data,
)
self.assertEqual(res.status_code, status.HTTP_201_CREATED)
Loading

0 comments on commit 973e716

Please sign in to comment.