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 new medical history options #2190

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
7766a2a
add new fields to disease table
AshrafMd-1 May 22, 2024
c586a14
Update patient_base.py
AshrafMd-1 May 22, 2024
2c9a72c
Merge branch 'develop' into medical-history
AshrafMd-1 May 22, 2024
bed4680
fix disease_map
AshrafMd-1 May 23, 2024
5b538f1
add migrations
AshrafMd-1 May 24, 2024
027fc1b
add validation
AshrafMd-1 May 26, 2024
b1c6200
add tests
AshrafMd-1 May 28, 2024
c46e911
Merge branch 'coronasafe:develop' into medical-history
AshrafMd-1 May 29, 2024
2731569
fix lint
AshrafMd-1 Jun 4, 2024
23dc5f1
Merge branch 'develop' into medical-history
AshrafMd-1 Jun 4, 2024
65a5c2c
merge migrations
AshrafMd-1 Jun 4, 2024
ac563dd
Merge branch 'coronasafe:develop' into medical-history
AshrafMd-1 Jun 6, 2024
28c6696
fix lint
AshrafMd-1 Jun 7, 2024
07a07b0
add migrations
AshrafMd-1 Jun 7, 2024
65e1f1e
Merge branch 'develop' into medical-history
AshrafMd-1 Jun 7, 2024
7a1452d
Merge branch 'coronasafe:develop' into medical-history
AshrafMd-1 Jun 13, 2024
fbdeeb7
fix migrations
AshrafMd-1 Jun 15, 2024
bcf4520
Merge branch 'coronasafe:develop' into medical-history
AshrafMd-1 Jul 5, 2024
23e1e8b
fix migration
AshrafMd-1 Jul 5, 2024
98928f6
Merge branch 'develop' into medical-history
AshrafMd-1 Jul 23, 2024
9f1cc6f
new migration
AshrafMd-1 Jul 23, 2024
4dba549
Merge branch 'develop' into medical-history
AshrafMd-1 Jul 23, 2024
74fdd95
Merge branch 'develop' into medical-history
AshrafMd-1 Jul 29, 2024
0050291
Merge branch 'develop' into medical-history
AshrafMd-1 Aug 9, 2024
1c02013
Merge branch 'develop' into medical-history
nihal467 Aug 20, 2024
3f7d38f
Merge branch 'develop' into medical-history
vigneshhari Aug 21, 2024
6cabe89
Merge branch 'coronasafe:develop' into medical-history
AshrafMd-1 Aug 23, 2024
c960888
fix migrations
AshrafMd-1 Aug 23, 2024
61d6a49
fix lint
AshrafMd-1 Aug 23, 2024
b656f93
Merge branch 'develop' into medical-history
AshrafMd-1 Aug 23, 2024
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
47 changes: 47 additions & 0 deletions care/facility/api/serializers/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from care.facility.models.patient import PatientNotesEdit
from care.facility.models.patient_base import (
BLOOD_GROUP_CHOICES,
CANCER_TYPE,
DISEASE_STATUS_CHOICES,
DiseaseStatusEnum,
NewDischargeReasonEnum,
Expand Down Expand Up @@ -158,6 +159,9 @@ class PatientDetailSerializer(PatientListSerializer):
class MedicalHistorySerializer(serializers.Serializer):
disease = ChoiceField(choices=DISEASE_CHOICES)
details = serializers.CharField(required=False, allow_blank=True)
status = serializers.CharField(required=False, allow_null=True)
duration = serializers.CharField(required=False, allow_null=True)
type = serializers.CharField(required=False, allow_null=True)

facility = ExternalIdSerializerField(
queryset=Facility.objects.all(), required=False
Expand Down Expand Up @@ -272,6 +276,49 @@ def validate(self, attrs):
if validated.get("vaccine_name") is None:
raise serializers.ValidationError("Vaccine name cannot be null")

if validated.get("medical_history"):
medical_history = validated["medical_history"]

for disease in medical_history:
disease_id = disease.get("disease")
if disease_id == 1:
continue

# Handle cancer cases
if disease_id == 7:
cancer_type = disease.get("type")
if cancer_type:
gender = validated.get("gender")
if cancer_type not in CANCER_TYPE:
raise serializers.ValidationError("Invalid cancer type")

invalid_gender_type = (
gender == 1 and CANCER_TYPE[cancer_type] in {"1", "5"}
) or (gender == 2 and CANCER_TYPE[cancer_type] == "8")
if invalid_gender_type:
AshrafMd-1 marked this conversation as resolved.
Show resolved Hide resolved
raise serializers.ValidationError(
"Invalid cancer type for specified gender"
)

# Handle TB cases
if disease_id == 14:
AshrafMd-1 marked this conversation as resolved.
Show resolved Hide resolved
status = disease.get("status")
if status and status not in {"Active", "Old"}:
raise serializers.ValidationError("Invalid TB status")

duration = disease.get("duration")
if duration:
AshrafMd-1 marked this conversation as resolved.
Show resolved Hide resolved
try:
duration = float(duration)
if duration < 0:
raise serializers.ValidationError(
"TB duration cannot be negative"
)
except ValueError:
raise serializers.ValidationError(
"Duration must be a number"
)

return validated

def check_external_entry(self, srf_id):
Expand Down
AshrafMd-1 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Generated by Django 4.2.10 on 2024-05-26 08:32

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("facility", "0438_alter_dailyround_patient_category_and_more"),
]

operations = [
migrations.AddField(
model_name="disease",
name="duration",
field=models.IntegerField(blank=True, null=True),
),
migrations.AddField(
model_name="disease",
name="status",
field=models.TextField(blank=True, null=True),
),
migrations.AddField(
model_name="disease",
name="type",
field=models.TextField(blank=True, null=True),
),
migrations.AlterField(
model_name="disease",
name="disease",
field=models.IntegerField(
choices=[
(1, "NO"),
(2, "Diabetes"),
(3, "Heart Disease"),
(4, "HyperTension"),
(5, "Chronic Renal Disease"),
(6, "Other Chronic Lung Diseases"),
(7, "Cancer"),
(8, "OTHER"),
(9, "COPD"),
(10, "Bronchitis"),
(11, "Chronic Neurological Or Neuromuscular Disease"),
(12, "Immunocompromised Condition"),
(13, "Liver Disease"),
(14, "TB"),
(15, "Asthma"),
]
),
),
]
13 changes: 13 additions & 0 deletions care/facility/migrations/0442_merge_20240604_1841.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Generated by Django 4.2.10 on 2024-06-04 13:11

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
("facility", "0439_disease_duration_disease_status_disease_type_and_more"),
("facility", "0441_delete_patientteleconsultation"),
]

operations = []
13 changes: 13 additions & 0 deletions care/facility/migrations/0444_merge_20240607_1858.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Generated by Django 4.2.10 on 2024-06-07 13:28

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
("facility", "0442_merge_20240604_1841"),
("facility", "0443_remove_patientconsultation_consent_records_and_more"),
]

operations = []
3 changes: 3 additions & 0 deletions care/facility/models/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,9 @@ class Disease(models.Model):
)
disease = models.IntegerField(choices=DISEASE_CHOICES)
details = models.TextField(blank=True, null=True)
status = models.TextField(blank=True, null=True)
duration = models.IntegerField(blank=True, null=True)
type = models.TextField(blank=True, null=True)
deleted = models.BooleanField(default=False)

objects = BaseManager()
Expand Down
29 changes: 27 additions & 2 deletions care/facility/models/patient_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,41 @@ def reverse_choices(choices):
(34, "NEW LOSS OF SMELL"),
]

CANCER_TYPE = {
"Breast": "1",
"Lung": "2",
"Skin": "3",
"Colorectal": "4",
"Uterus": "5",
"Leukaemia": "6",
"Bladder": "7",
"Prostate": "8",
"Melanoma": "9",
"Lymphoma": "10",
"Brain": "11",
"Liver": "12",
"Thyroid": "13",
"Others": "14",
}

DISEASE_CHOICES_MAP = {
"NO": 1,
"Diabetes": 2,
"Heart Disease": 3,
"HyperTension": 4,
"Kidney Diseases": 5,
"Lung Diseases/Asthma": 6,
"Chronic Renal Disease": 5,
"Other Chronic Lung Diseases": 6,
"Cancer": 7,
"OTHER": 8,
"COPD": 9,
"Bronchitis": 10,
"Chronic Neurological Or Neuromuscular Disease": 11,
"Immunocompromised Condition": 12,
"Liver Disease": 13,
"TB": 14,
"Asthma": 15,
}

DISEASE_CHOICES = [(v, k) for k, v in DISEASE_CHOICES_MAP.items()]

COVID_CATEGORY_CHOICES = [
Expand Down
120 changes: 120 additions & 0 deletions care/facility/models/tests/test_patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,123 @@ def test_year_of_birth_validation(self):
response = self.client.post("/api/v1/patient/", sample_data, format="json")
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertIn("year_of_birth", response.data)

def test_cancer_type_is_invalid(self):
dist_admin = self.create_user("dist_admin", self.district, user_type=30)
sample_data = {
"facility": self.facility.external_id,
"blood_group": "AB+",
"gender": 1,
"date_of_birth": None,
"year_of_birth": now().year - 2,
"disease_status": "NEGATIVE",
"emergency_phone_number": "+919000000666",
"is_vaccinated": "false",
"number_of_doses": 0,
"phone_number": "+919000044343",
"medical_history": {
"disease": "Cancer",
"details": "",
"type": "not_cancer",
},
}
self.client.force_authenticate(user=dist_admin)
response = self.client.post("/api/v1/patient/", sample_data, format="json")
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertIn("medical_history", response.data)

def test_cancer_type_wrong_for_gender(self):
dist_admin = self.create_user("dist_admin", self.district, user_type=30)
sample_data = {
"facility": self.facility.external_id,
"blood_group": "AB+",
"gender": 1,
"date_of_birth": None,
"year_of_birth": now().year - 2,
"disease_status": "NEGATIVE",
"emergency_phone_number": "+919000000666",
"is_vaccinated": "false",
"number_of_doses": 0,
"phone_number": "+919000044343",
"medical_history": {
"disease": "Cancer",
"details": "",
"type": "Breast",
},
}
self.client.force_authenticate(user=dist_admin)
response = self.client.post("/api/v1/patient/", sample_data, format="json")
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertIn("medical_history", response.data)

def test_tb_type_invalid(self):
dist_admin = self.create_user("dist_admin", self.district, user_type=30)
sample_data = {
"facility": self.facility.external_id,
"blood_group": "AB+",
"gender": 1,
"date_of_birth": None,
"year_of_birth": now().year - 2,
"disease_status": "NEGATIVE",
"emergency_phone_number": "+919000000666",
"is_vaccinated": "false",
"number_of_doses": 0,
"phone_number": "+919000044343",
"medical_history": {
"disease": "TB",
"details": "",
"status": "not_tb",
},
}
self.client.force_authenticate(user=dist_admin)
response = self.client.post("/api/v1/patient/", sample_data, format="json")
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertIn("medical_history", response.data)

def test_tb_duration_not_numeric(self):
dist_admin = self.create_user("dist_admin", self.district, user_type=30)
sample_data = {
"facility": self.facility.external_id,
"blood_group": "AB+",
"gender": 1,
"date_of_birth": None,
"year_of_birth": now().year - 2,
"disease_status": "NEGATIVE",
"emergency_phone_number": "+919000000666",
"is_vaccinated": "false",
"number_of_doses": 0,
"phone_number": "+919000044343",
"medical_history": {
"disease": "TB",
"details": "",
"duration": "not_numeric",
},
}
self.client.force_authenticate(user=dist_admin)
response = self.client.post("/api/v1/patient/", sample_data, format="json")
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertIn("medical_history", response.data)

def test_tb_duration_not_negative(self):
dist_admin = self.create_user("dist_admin", self.district, user_type=30)
sample_data = {
"facility": self.facility.external_id,
"blood_group": "AB+",
"gender": 1,
"date_of_birth": None,
"year_of_birth": now().year - 2,
"disease_status": "NEGATIVE",
"emergency_phone_number": "+919000000666",
"is_vaccinated": "false",
"number_of_doses": 0,
"phone_number": "+919000044343",
"medical_history": {
"disease": "TB",
"details": "",
"duration": -1,
},
}
self.client.force_authenticate(user=dist_admin)
response = self.client.post("/api/v1/patient/", sample_data, format="json")
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertIn("medical_history", response.data)