Skip to content

Commit 4b0e1b7

Browse files
authored
Merge pull request #2148 from coronasafe/staging
Production release v24.20.0
2 parents 0c91be4 + 0240be1 commit 4b0e1b7

File tree

12 files changed

+192
-8
lines changed

12 files changed

+192
-8
lines changed

care/facility/api/serializers/daily_round.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,8 @@ def create(self, validated_data):
268268
review_interval = validated_data.pop(
269269
"consultation__review_interval"
270270
)
271+
validated_data["consultation"].review_interval = review_interval
271272
if review_interval >= 0:
272-
validated_data["consultation"].review_interval = review_interval
273273
patient.review_time = localtime(now()) + timedelta(
274274
minutes=review_interval
275275
)

care/facility/api/viewsets/patient.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ class PatientFilterSet(filters.FilterSet):
109109
allow_transfer = filters.BooleanFilter(field_name="allow_transfer")
110110
name = filters.CharFilter(field_name="name", lookup_expr="icontains")
111111
patient_no = filters.CharFilter(
112-
field_name="last_consultation__patient_no", lookup_expr="icontains"
112+
field_name="last_consultation__patient_no", lookup_expr="iexact"
113113
)
114114
gender = filters.NumberFilter(field_name="gender")
115115
age = filters.NumberFilter(field_name="age")

care/facility/api/viewsets/patient_sample.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,10 @@ def list(self, request, *args, **kwargs):
124124
raise PermissionDenied()
125125

126126
if settings.CSV_REQUEST_PARAMETER in request.GET:
127-
queryset = self.filter_queryset(self.get_queryset()).values(
128-
*PatientSample.CSV_MAPPING.keys()
127+
queryset = (
128+
self.filter_queryset(self.get_queryset())
129+
.annotate(**PatientSample.CSV_ANNOTATE_FIELDS)
130+
.values(*PatientSample.CSV_MAPPING.keys())
129131
)
130132
return render_to_csv_response(
131133
queryset,

care/facility/api/viewsets/prescription.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ class ConsultationPrescriptionFilter(filters.FilterSet):
9191
dosage_type = MultiSelectFilter()
9292
prescription_type = CareChoiceFilter(choice_dict=inverse_prescription_type)
9393
discontinued = filters.BooleanFilter()
94+
medicine = filters.UUIDFilter(field_name="medicine__external_id")
9495

9596

9697
class ConsultationPrescriptionViewSet(

care/facility/api/viewsets/shifting.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,10 @@ def transfer(self, request, *args, **kwargs):
176176

177177
def list(self, request, *args, **kwargs):
178178
if settings.CSV_REQUEST_PARAMETER in request.GET:
179-
queryset = self.filter_queryset(self.get_queryset()).values(
180-
*ShiftingRequest.CSV_MAPPING.keys()
179+
queryset = (
180+
self.filter_queryset(self.get_queryset())
181+
.annotate(**ShiftingRequest.CSV_ANNOTATE_FIELDS)
182+
.values(*ShiftingRequest.CSV_MAPPING.keys())
181183
)
182184
return render_to_csv_response(
183185
queryset,
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# Generated by Django 4.2.10 on 2024-03-12 17:48
2+
3+
from math import ceil
4+
5+
from django.core.paginator import Paginator
6+
from django.db import migrations, models
7+
8+
import care.utils.models.validators
9+
10+
11+
def double_pain_scale(apps, schema_editor):
12+
DailyRound = apps.get_model("facility", "DailyRound")
13+
14+
page = Paginator(
15+
DailyRound.objects.only("id", "pain_scale_enhanced")
16+
.exclude(pain_scale_enhanced__exact=[])
17+
.order_by("id"),
18+
2000,
19+
)
20+
21+
for page_num in page.page_range:
22+
records_to_update = []
23+
for daily_round in page.page(page_num):
24+
for obj in daily_round.pain_scale_enhanced:
25+
try:
26+
obj["scale"] *= 2
27+
except KeyError:
28+
pass
29+
records_to_update.append(daily_round)
30+
DailyRound.objects.bulk_update(records_to_update, ["pain_scale_enhanced"])
31+
32+
33+
def halve_pain_scale(apps, schema_editor):
34+
DailyRound = apps.get_model("facility", "DailyRound")
35+
page = Paginator(
36+
DailyRound.objects.only("id", "pain_scale_enhanced")
37+
.exclude(pain_scale_enhanced__exact=[])
38+
.order_by("id"),
39+
2000,
40+
)
41+
42+
for page_num in page.page_range:
43+
records_to_update = []
44+
for daily_round in page.page(page_num):
45+
for obj in daily_round.pain_scale_enhanced:
46+
try:
47+
obj["scale"] = ceil(obj["scale"] / 2)
48+
except KeyError:
49+
pass
50+
records_to_update.append(daily_round)
51+
DailyRound.objects.bulk_update(records_to_update, ["pain_scale_enhanced"])
52+
53+
54+
class Migration(migrations.Migration):
55+
dependencies = [
56+
("facility", "0428_alter_patientmetainfo_occupation"),
57+
]
58+
59+
operations = [
60+
migrations.AlterField(
61+
model_name="dailyround",
62+
name="pain_scale_enhanced",
63+
field=models.JSONField(
64+
default=list,
65+
validators=[
66+
care.utils.models.validators.JSONFieldSchemaValidator(
67+
{
68+
"$schema": "http://json-schema.org/draft-07/schema#",
69+
"items": [
70+
{
71+
"additionalProperties": False,
72+
"properties": {
73+
"description": {"type": "string"},
74+
"region": {"type": "string"},
75+
"scale": {
76+
"maximum": 10,
77+
"minimum": 1,
78+
"type": "number",
79+
},
80+
},
81+
"required": ["region", "scale"],
82+
"type": "object",
83+
}
84+
],
85+
"type": "array",
86+
}
87+
)
88+
],
89+
),
90+
),
91+
migrations.RunPython(double_pain_scale, reverse_code=halve_pain_scale),
92+
]

care/facility/models/json_schema/daily_round.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@
115115
"type": "object",
116116
"properties": {
117117
"region": {"type": "string"},
118-
"scale": {"type": "number", "minimum": 1, "maximum": 5},
118+
"scale": {"type": "number", "minimum": 1, "maximum": 10},
119119
"description": {"type": "string"},
120120
},
121121
"additionalProperties": False,

care/facility/models/patient.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
from django.contrib.postgres.aggregates import ArrayAgg
55
from django.core.validators import MaxValueValidator, MinValueValidator
66
from django.db import models
7-
from django.db.models import JSONField
7+
from django.db.models import Case, F, Func, JSONField, Value, When
8+
from django.db.models.functions import Coalesce, Now
89
from django.utils import timezone
910
from simple_history.models import HistoricalRecords
1011

@@ -773,3 +774,42 @@ class PatientNotesEdit(models.Model):
773774

774775
class Meta:
775776
ordering = ["-edited_date"]
777+
778+
779+
class PatientAgeFunc(Func):
780+
"""
781+
Expression to calculate the age of a patient based on date of birth/year of
782+
birth and death date time.
783+
784+
Eg:
785+
786+
```
787+
PatientSample.objects.annotate(patient_age=PatientAgeFunc())
788+
```
789+
"""
790+
791+
function = "date_part"
792+
793+
def __init__(self) -> None:
794+
super().__init__(
795+
Value("year"),
796+
Func(
797+
Case(
798+
When(patient__death_datetime__isnull=True, then=Now()),
799+
default=F("patient__death_datetime__date"),
800+
),
801+
Coalesce(
802+
"patient__date_of_birth",
803+
Func(
804+
F("patient__year_of_birth"),
805+
Value(1),
806+
Value(1),
807+
function="MAKE_DATE",
808+
output_field=models.DateField(),
809+
),
810+
output_field=models.DateField(),
811+
),
812+
function="age",
813+
),
814+
output_field=models.IntegerField(),
815+
)

care/facility/models/patient_sample.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from django.db import models
22

33
from care.facility.models import FacilityBaseModel, PatientRegistration, reverse_choices
4+
from care.facility.models.patient import PatientAgeFunc
45
from care.users.models import User
56

67
SAMPLE_TYPE_CHOICES = [
@@ -125,6 +126,10 @@ class PatientSample(FacilityBaseModel):
125126
"date_of_result": "Date of Result",
126127
}
127128

129+
CSV_ANNOTATE_FIELDS = {
130+
"patient__age": PatientAgeFunc(),
131+
}
132+
128133
CSV_MAKE_PRETTY = {
129134
"sample_type": (lambda x: REVERSE_SAMPLE_TYPE_CHOICES.get(x, "-")),
130135
"status": (

care/facility/models/shifting.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from care.facility.models import (
44
FACILITY_TYPES,
55
FacilityBaseModel,
6+
PatientAgeFunc,
67
pretty_boolean,
78
reverse_choices,
89
)
@@ -137,6 +138,10 @@ class ShiftingRequest(FacilityBaseModel):
137138
"reason": "Reason for Shifting",
138139
}
139140

141+
CSV_ANNOTATE_FIELDS = {
142+
"patient__age": PatientAgeFunc(),
143+
}
144+
140145
CSV_MAKE_PRETTY = {
141146
"status": (lambda x: REVERSE_SHIFTING_STATUS_CHOICES.get(x, "-")),
142147
"is_up_shift": pretty_boolean,

care/facility/tests/test_prescriptions_api.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ def setUp(self) -> None:
2020
super().setUp()
2121
self.consultation = self.create_consultation(self.patient, self.facility)
2222
self.medicine = MedibaseMedicine.objects.first()
23+
self.medicine2 = MedibaseMedicine.objects.all()[1]
2324

2425
self.normal_prescription_data = {
2526
"medicine": self.medicine.external_id,
@@ -29,6 +30,14 @@ def setUp(self) -> None:
2930
"dosage_type": "REGULAR",
3031
}
3132

33+
self.normal_prescription_data2 = {
34+
"medicine": self.medicine2.external_id,
35+
"prescription_type": "REGULAR",
36+
"base_dosage": "1 mg",
37+
"frequency": "OD",
38+
"dosage_type": "REGULAR",
39+
}
40+
3241
def test_create_normal_prescription(self):
3342
response = self.client.post(
3443
f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/",
@@ -113,3 +122,30 @@ def test_create_prn_prescription(self):
113122
prn_prescription_data,
114123
)
115124
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
125+
126+
def test_medicine_filter_for_prescription(self):
127+
# post 2 prescriptions with different medicines
128+
self.client.post(
129+
f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/",
130+
self.normal_prescription_data,
131+
)
132+
self.client.post(
133+
f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/",
134+
self.normal_prescription_data2,
135+
)
136+
137+
# get all prescriptions without medicine filter
138+
response = self.client.get(
139+
f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/",
140+
)
141+
self.assertEqual(response.data["count"], 2)
142+
143+
# get all prescriptions with medicine filter
144+
response = self.client.get(
145+
f"/api/v1/consultation/{self.consultation.external_id}/prescriptions/?medicine={self.medicine.external_id}",
146+
)
147+
148+
for prescription in response.data["results"]:
149+
self.assertEqual(
150+
prescription["medicine_object"]["name"], self.medicine.name
151+
)

care/users/api/serializers/user.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ class Meta:
388388
"alt_phone_number",
389389
"user_type",
390390
"last_login",
391+
"gender",
391392
"home_facility_object",
392393
"doctor_qualification",
393394
"doctor_experience_commenced_on",

0 commit comments

Comments
 (0)