Skip to content

Commit

Permalink
feat: added health details and medical history API
Browse files Browse the repository at this point in the history
  • Loading branch information
aeswibon committed Jul 8, 2023
1 parent 5b9b57f commit 2f23b31
Show file tree
Hide file tree
Showing 9 changed files with 879 additions and 90 deletions.
55 changes: 55 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
argon2-cffi = "==21.3.0"
authlib = "==1.2.0"
boto3 = "==1.26.157"
pillow = "==9.5.0"
python-slugify = "==8.0.1"
pyjwt = "==2.7.0"
redis = {version = "==4.5.5", extras = ["hiredis"]}
requests = "==2.31.0"
whitenoise = "==6.4.0"
psycopg = "==3.1.9"
django = "==4.2.2"
django-environ = "==0.10.0"
django-model-utils = "==4.3.1"
djangorestframework = "==3.14.0"
djangorestframework-simplejwt = "==5.2.2"
drf-spectacular = "==0.26.2"
django-filter = "==23.2"
drf-nested-routers = "==0.93.3"
django-multiselectfield = "==0.1.12"
django-simple-history = "==3.3.0"
django-ratelimit = "==4.0.0"
django-cors-headers = "==4.0.0"
django-maintenance-mode = "==0.18.0"
django-queryset-csv = "==1.1.0"
django-rest-passwordreset = "==1.3.0"
djangoql = "==0.17.1"
healthy-django = ">=0.1.0"
django-redis = "==5.2.0"
django-hardcopy = "==0.1.4"
dry-rest-permissions = "==0.1.10"
django-storages = "==1.9.1"
jsonschema = "==3.2.0"
typed-ast = "==1.5.4"
littletable = "==2.0.7"
celery = "==5.3.0"
pywebpush = "==1.11.0"
"fhir.resources" = "==6.5.0"
pydantic = "==1.*"
jwcrypto = "==1.5.0"
pycryptodome = "==3.16.0"
pycryptodomex = "==3.16.0"
gunicorn = "==20.1.0"
sentry-sdk = "==1.25.1"
newrelic = "*"

[dev-packages]

[requires]
python_version = "3.11"
83 changes: 83 additions & 0 deletions care/facility/api/serializers/health_details.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
from django.db import transaction
from django.forms import ChoiceField
from rest_framework import serializers

from care.facility.models import PatientConsultation, PatientHealthDetails
from care.facility.models.patient import VaccinationHistory
from care.facility.models.patient_base import BLOOD_GROUP_CHOICES
from care.utils.queryset.facility import get_home_facility_queryset
from care.utils.serializer.external_id_field import ExternalIdSerializerField


class VaccinationHistorySerializer(serializers.ModelSerializer):
doses = serializers.IntegerField(required=False, default=0)
date = serializers.DateField()

class Meta:
model = VaccinationHistory
fields = ("vaccine", "doses", "date", "precision")


class PatientHealthDetailsSerializer(serializers.ModelSerializer):
id = serializers.UUIDField(source="external_id", read_only=True)

consultation = ExternalIdSerializerField(
queryset=PatientConsultation.objects.all(), required=False
)
blood_group = ChoiceField(choices=BLOOD_GROUP_CHOICES, required=True)

vaccination_history = serializers.ListSerializer(
child=VaccinationHistorySerializer(), required=False
)

class Meta:
model = PatientHealthDetails
exclude = ("deleted", "external_id")

def create(self, validated_data):
with transaction.atomic():
consultation = validated_data["consultation"]
vaccination_history = validated_data.pop("vaccination_history", [])
allowed_facilities = get_home_facility_queryset(
self.context["request"].user
)
if not allowed_facilities.filter(id=consultation.facility.id).exists():
raise serializers.ValidationError(
{
"patient": "Patient Health Details creates are only allowed in home facility"
}
)

health_details = super().create(validated_data)
vaccines = []
for vaccine in vaccination_history:
vaccines.append(
VaccinationHistory(
health_details=health_details,
**vaccine,
)
)
if vaccines:
VaccinationHistory.objects.bulk_create(vaccines, ignore_conflicts=True)
consultation.health_details = health_details
consultation.save(update_fields=["health_details"])
return health_details

def update(self, instance, validated_data):
with transaction.atomic():
vaccination_history = validated_data.pop("vaccination_history", [])
health_details = super().update(instance, validated_data)
VaccinationHistory.objects.filter(health_details=health_details).update(
deleted=True
)
vaccines = []
for vaccine in vaccination_history:
vaccines.append(
VaccinationHistory(
health_details=health_details,
**vaccine,
)
)
if vaccines:
VaccinationHistory.objects.bulk_create(vaccines, ignore_conflicts=True)
return health_details
73 changes: 73 additions & 0 deletions care/facility/api/serializers/medical_history.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
from django.db import transaction
from rest_framework import serializers

from care.facility.models import MedicalHistory
from care.facility.models.patient import Disease
from care.facility.models.patient_consultation import PatientConsultation
from care.utils.serializer.external_id_field import ExternalIdSerializerField


class DiseaseSerializer(serializers.ModelSerializer):
date = serializers.DateField()

class Meta:
model = Disease
fields = (
"disease",
"details",
"date",
"precision",
)


class MedicalHistorySerializer(serializers.ModelSerializer):
id = serializers.UUIDField(source="external_id", read_only=True)

consultation = ExternalIdSerializerField(
queryset=PatientConsultation.objects.all(), required=False
)

patient_diseases = serializers.ListSerializer(
child=DiseaseSerializer(),
required=False,
)

class Meta:
model = MedicalHistory
exclude = ("deleted", "external_id")

def create(self, validated_data):
with transaction.atomic():
consultation = validated_data["consultation"]
patient_diseases = validated_data.pop("patient_diseases", [])
medical_history = super().create(validated_data)
diseases = []
for disease in patient_diseases:
diseases.append(
Disease(
medical_history=medical_history,
**disease,
)
)
if diseases:
Disease.objects.bulk_create(diseases, ignore_conflicts=True)
consultation.medical_history = medical_history
consultation.save(update_fields=["medical_history"])
return medical_history

def update(self, instance, validated_data):
with transaction.atomic():
patient_diseases = validated_data.pop("patient_diseases", [])
medical_history = super().update(instance, validated_data)
Disease.objects.filter(medical_history=medical_history).update(deleted=True)
diseases = []
for disease in patient_diseases:
diseases.append(
Disease(
medical_history=medical_history,
**disease,
)
)
if diseases:
Disease.objects.bulk_create(diseases, ignore_conflicts=True)
return medical_history
51 changes: 10 additions & 41 deletions care/facility/api/serializers/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
PatientConsultationSerializer,
)
from care.facility.models import (
DISEASE_CHOICES,
GENDER_CHOICES,
Disease,
Facility,
FacilityPatientStatsHistory,
PatientContactDetails,
Expand All @@ -26,11 +24,7 @@
PatientRegistration,
)
from care.facility.models.notification import Notification
from care.facility.models.patient_base import (
BLOOD_GROUP_CHOICES,
DISEASE_STATUS_CHOICES,
DiseaseStatusEnum,
)
from care.facility.models.patient_base import DISEASE_STATUS_CHOICES, DiseaseStatusEnum
from care.facility.models.patient_consultation import PatientConsultation
from care.facility.models.patient_external_test import PatientExternalTest
from care.facility.models.patient_tele_consultation import PatientTeleConsultation
Expand Down Expand Up @@ -71,9 +65,9 @@ class PatientListSerializer(serializers.ModelSerializer):

last_consultation = PatientConsultationSerializer(read_only=True)

blood_group = ChoiceField(choices=BLOOD_GROUP_CHOICES, required=True)
disease_status = ChoiceField(
choices=DISEASE_STATUS_CHOICES, default=DiseaseStatusEnum.SUSPECTED.value
choices=DISEASE_STATUS_CHOICES,
default=DiseaseStatusEnum.SUSPECTED.value,
)
source = ChoiceField(choices=PatientRegistration.SourceChoices)

Expand Down Expand Up @@ -151,10 +145,6 @@ def to_internal_value(self, data):


class PatientDetailSerializer(PatientListSerializer):
class MedicalHistorySerializer(serializers.Serializer):
disease = ChoiceField(choices=DISEASE_CHOICES)
details = serializers.CharField(required=False, allow_blank=True)

class PatientTeleConsultationSerializer(serializers.ModelSerializer):
class Meta:
model = PatientTeleConsultation
Expand All @@ -163,9 +153,6 @@ class Meta:
facility = ExternalIdSerializerField(
queryset=Facility.objects.all(), required=False
)
medical_history = serializers.ListSerializer(
child=MedicalHistorySerializer(), required=False
)

tele_consultation_history = serializers.ListSerializer(
child=PatientTeleConsultationSerializer(), read_only=True
Expand All @@ -181,7 +168,8 @@ class Meta:
default=PatientRegistration.SourceEnum.CARE.value,
)
disease_status = ChoiceField(
choices=DISEASE_STATUS_CHOICES, default=DiseaseStatusEnum.SUSPECTED.value
choices=DISEASE_STATUS_CHOICES,
default=DiseaseStatusEnum.SUSPECTED.value,
)

meta_info = PatientMetaInfoSerializer(required=False, allow_null=True)
Expand All @@ -197,9 +185,6 @@ class Meta:

last_edited = UserBaseMinimumSerializer(read_only=True)
created_by = UserBaseMinimumSerializer(read_only=True)
vaccine_name = serializers.ChoiceField(
choices=PatientRegistration.vaccineChoices, required=False, allow_null=True
)

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

Expand All @@ -218,7 +203,11 @@ class Meta:
"external_id",
)
include = ("contacted_patients",)
read_only = TIMESTAMP_FIELDS + ("last_edited", "created_by", "is_active")
read_only = TIMESTAMP_FIELDS + (
"last_edited",
"created_by",
"is_active",
)

# def get_last_consultation(self, obj):
# last_consultation = PatientConsultation.objects.filter(patient=obj).last()
Expand Down Expand Up @@ -249,12 +238,6 @@ def validate(self, attrs):
{"non_field_errors": ["Either age or date_of_birth should be passed"]}
)

if validated.get("is_vaccinated"):
if validated.get("number_of_doses") == 0:
raise serializers.ValidationError("Number of doses cannot be 0")
if validated.get("vaccine_name") is None:
raise serializers.ValidationError("Vaccine name cannot be null")

return validated

def check_external_entry(self, srf_id):
Expand All @@ -265,7 +248,6 @@ def check_external_entry(self, srf_id):

def create(self, validated_data):
with transaction.atomic():
medical_history = validated_data.pop("medical_history", [])
meta_info = validated_data.pop("meta_info", {})
contacted_patients = validated_data.pop("contacted_patients", [])

Expand Down Expand Up @@ -294,12 +276,6 @@ def create(self, validated_data):

validated_data["created_by"] = self.context["request"].user
patient = super().create(validated_data)
diseases = []

for disease in medical_history:
diseases.append(Disease(patient=patient, **disease))
if diseases:
Disease.objects.bulk_create(diseases, ignore_conflicts=True)

if meta_info:
meta_info_obj = PatientMetaInfo.objects.create(**meta_info)
Expand Down Expand Up @@ -327,7 +303,6 @@ def create(self, validated_data):

def update(self, instance, validated_data):
with transaction.atomic():
medical_history = validated_data.pop("medical_history", [])
meta_info = validated_data.pop("meta_info", {})
contacted_patients = validated_data.pop("contacted_patients", [])

Expand All @@ -343,12 +318,6 @@ def update(self, instance, validated_data):
self.check_external_entry(validated_data["srf_id"])

patient = super().update(instance, validated_data)
Disease.objects.filter(patient=patient).update(deleted=True)
diseases = []
for disease in medical_history:
diseases.append(Disease(patient=patient, **disease))
if diseases:
Disease.objects.bulk_create(diseases, ignore_conflicts=True)

if meta_info:
for key, value in meta_info.items():
Expand Down
Loading

0 comments on commit 2f23b31

Please sign in to comment.