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 committed Sep 5, 2023
2 parents 3cda2eb + 1a8e0ce commit ac5c0b3
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 131 deletions.
12 changes: 12 additions & 0 deletions care/facility/api/serializers/prescription.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django.shortcuts import get_object_or_404
from django.utils import timezone
from rest_framework import serializers

from care.facility.models import MedibaseMedicine, MedicineAdministration, Prescription
Expand Down Expand Up @@ -77,6 +78,17 @@ class MedicineAdministrationSerializer(serializers.ModelSerializer):
administered_by = UserBaseMinimumSerializer(read_only=True)
prescription = PrescriptionSerializer(read_only=True)

def validate_administered_date(self, value):
if value > timezone.now():
raise serializers.ValidationError(
"Administered Date cannot be in the future."
)
if self.context["prescription"].created_date > value:
raise serializers.ValidationError(
"Administered Date cannot be before Prescription Date."
)
return value

class Meta:
model = MedicineAdministration
exclude = ("deleted",)
Expand Down
18 changes: 10 additions & 8 deletions care/facility/api/viewsets/facility_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@

from care.facility.models.facility import Facility
from care.users.api.serializers.user import UserAssignedSerializer
from care.users.models import Skill, User
from care.users.models import User, UserSkill


class UserFilter(filters.FilterSet):
user_type = filters.TypedChoiceFilter(
choices=[(key, key) for key in User.TYPE_VALUE_MAP.keys()],
choices=[(key, key) for key in User.TYPE_VALUE_MAP],
coerce=lambda role: User.TYPE_VALUE_MAP[role],
)

Expand All @@ -33,14 +33,16 @@ class FacilityUserViewSet(GenericViewSet, mixins.ListModelMixin):
def get_queryset(self):
try:
facility = Facility.objects.get(
external_id=self.kwargs.get("facility_external_id")
external_id=self.kwargs.get("facility_external_id"),
)
queryset = facility.users.filter(deleted=False).order_by("-last_login")
queryset = queryset.prefetch_related(
queryset = facility.users.filter(
deleted=False,
).order_by("-last_login")
return queryset.prefetch_related(
Prefetch(
"skills", queryset=Skill.objects.filter(userskill__deleted=False)
)
"skills",
queryset=UserSkill.objects.filter(skill__deleted=False),
),
)
return queryset
except Facility.DoesNotExist:
raise ValidationError({"Facility": "Facility not found"})
19 changes: 17 additions & 2 deletions care/facility/api/viewsets/prescription.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def inverse_choices(choices):

class MedicineAdminstrationFilter(filters.FilterSet):
prescription = filters.UUIDFilter(field_name="prescription__external_id")
administered_date = filters.DateFromToRangeFilter(field_name="administered_date")


class MedicineAdministrationViewSet(
Expand Down Expand Up @@ -112,7 +113,14 @@ def discontinue(self, request, *args, **kwargs):
)
def administer(self, request, *args, **kwargs):
prescription_obj = self.get_object()
serializer = MedicineAdministrationSerializer(data=request.data)
if prescription_obj.discontinued:
return Response(
{"error": "Administering discontinued prescriptions is not allowed"},
status=status.HTTP_400_BAD_REQUEST,
)
serializer = MedicineAdministrationSerializer(
data=request.data, context={"prescription": prescription_obj}
)
serializer.is_valid(raise_exception=True)
serializer.save(prescription=prescription_obj, administered_by=request.user)
return Response(serializer.data, status=status.HTTP_201_CREATED)
Expand Down Expand Up @@ -177,10 +185,17 @@ def list(self, request):

queryset = MedibaseMedicineTable

limit = request.query_params.get("limit", 30)
if type := request.query_params.get("type"):
queryset = [x for x in queryset if x[2] == type]

if query := request.query_params.get("query"):
query = query.strip().lower()
queryset = [x for x in queryset if query in f"{x[1]} {x[3]} {x[4]}".lower()]
queryset = self.sort(query, queryset)

try:
limit = min(int(request.query_params.get("limit", 30)), 100)
except ValueError:
limit = 30

return Response(self.serailize_data(queryset[:limit]))
58 changes: 58 additions & 0 deletions care/facility/tests/test_medicine_administrations_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from django.utils import timezone
from rest_framework import status

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


class MedicineAdministrationsApiTestCase(TestBase):
def setUp(self) -> None:
super().setUp()
self.normal_prescription = self.create_prescription()

def create_prescription(self, **kwargs):
data = {
"consultation": self.create_consultation(),
"medicine": MedibaseMedicine.objects.first(),
"prescription_type": "REGULAR",
"dosage": "1 mg",
"frequency": "OD",
"is_prn": False,
}
return Prescription.objects.create(
**{**data, **kwargs, "prescribed_by": self.user}
)

def test_administer(self):
prescription = self.normal_prescription
res = self.client.post(
f"/api/v1/consultation/{prescription.consultation.external_id}/prescriptions/{prescription.external_id}/administer/",
{"notes": "Test Notes"},
)
self.assertEqual(res.status_code, status.HTTP_201_CREATED)

def test_administer_in_future(self):
prescription = self.normal_prescription
res = self.client.post(
f"/api/v1/consultation/{prescription.consultation.external_id}/prescriptions/{prescription.external_id}/administer/",
{"notes": "Test Notes", "administered_date": "2300-09-01T16:34"},
)
self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST)

def test_administer_in_past(self):
prescription = self.normal_prescription
res = self.client.post(
f"/api/v1/consultation/{prescription.consultation.external_id}/prescriptions/{prescription.external_id}/administer/",
{"notes": "Test Notes", "administered_date": "2019-09-01T16:34"},
)
self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST)

def test_administer_discontinued(self):
prescription = self.create_prescription(
discontinued=True, discontinued_date=timezone.now()
)
res = self.client.post(
f"/api/v1/consultation/{prescription.consultation.external_id}/prescriptions/{prescription.external_id}/administer/",
{"notes": "Test Notes"},
)
self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST)
14 changes: 12 additions & 2 deletions care/users/api/serializers/skill.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from rest_framework.serializers import ModelSerializer, UUIDField
from rest_framework.serializers import CharField, ModelSerializer, UUIDField

from care.users.models import Skill
from care.users.models import Skill, UserSkill


class SkillSerializer(ModelSerializer):
Expand All @@ -9,3 +9,13 @@ class SkillSerializer(ModelSerializer):
class Meta:
model = Skill
fields = ("id", "name", "description")


class UserSkillSerializer(ModelSerializer):
id = UUIDField(source="skill.external_id", read_only=True)
name = CharField(source="skill.name", read_only=True)
description = CharField(source="skill.description", read_only=True)

class Meta:
model = UserSkill
fields = ("id", "name", "description")
67 changes: 38 additions & 29 deletions care/users/api/serializers/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
LocalBodySerializer,
StateSerializer,
)
from care.users.api.serializers.skill import SkillSerializer
from care.users.api.serializers.skill import UserSkillSerializer
from care.users.models import GENDER_CHOICES
from care.utils.queryset.facility import get_home_facility_queryset
from care.utils.serializer.external_id_field import ExternalIdSerializerField
Expand Down Expand Up @@ -60,28 +60,28 @@ def validate(self, attrs):
raise serializers.ValidationError(
{
"doctor_qualification": "Field required for Doctor User Type",
}
},
)

if not attrs.get("doctor_experience_commenced_on"):
raise serializers.ValidationError(
{
"doctor_experience_commenced_on": "Field required for Doctor User Type",
}
},
)

if attrs["doctor_experience_commenced_on"] > date.today():
raise serializers.ValidationError(
{
"doctor_experience_commenced_on": "Experience cannot be in the future",
}
},
)

if not attrs.get("doctor_medical_council_registration"):
raise serializers.ValidationError(
{
"doctor_medical_council_registration": "Field required for Doctor User Type",
}
},
)

return validated
Expand All @@ -90,10 +90,14 @@ def validate(self, attrs):
class UserCreateSerializer(SignUpSerializer):
password = serializers.CharField(required=False)
facilities = serializers.ListSerializer(
child=serializers.UUIDField(), required=False, allow_empty=True, write_only=True
child=serializers.UUIDField(),
required=False,
allow_empty=True,
write_only=True,
)
home_facility = ExternalIdSerializerField(
queryset=Facility.objects.all(), required=False
queryset=Facility.objects.all(),
required=False,
)

class Meta:
Expand All @@ -119,11 +123,11 @@ def validate_facilities(self, facility_ids):
!= Facility.objects.filter(external_id__in=facility_ids).count()
):
available_facility_ids = Facility.objects.filter(
external_id__in=facility_ids
external_id__in=facility_ids,
).values_list("external_id", flat=True)
not_found_ids = list(set(facility_ids) - set(available_facility_ids))
raise serializers.ValidationError(
f"Some facilities are not available - {', '.join([str(_id) for _id in not_found_ids])}"
f"Some facilities are not available - {', '.join([str(_id) for _id in not_found_ids])}",
)
return facility_ids

Expand All @@ -147,7 +151,7 @@ def validate_local_body(self, value):
>= User.TYPE_VALUE_MAP["DistrictAdmin"]
):
raise serializers.ValidationError(
"Cannot create for a different local body"
"Cannot create for a different local body",
)
return value

Expand All @@ -172,24 +176,24 @@ def validate_state(self, value):
return value

def validate(self, attrs):
validated = super(UserCreateSerializer, self).validate(attrs)
validated = super().validate(attrs)
if "home_facility" in validated:
allowed_facilities = get_home_facility_queryset(self.context["created_by"])
if not allowed_facilities.filter(id=validated["home_facility"].id).exists():
raise exceptions.ValidationError(
{
"home_facility": "Cannot create users with different Home Facility"
}
"home_facility": "Cannot create users with different Home Facility",
},
)

if self.context["created_by"].user_type in READ_ONLY_USER_TYPES:
if validated["user_type"] not in READ_ONLY_USER_TYPES:
raise exceptions.ValidationError(
{
"user_type": [
"Read only users can create other read only users only"
]
}
"Read only users can create other read only users only",
],
},
)

if (
Expand All @@ -204,9 +208,9 @@ def validate(self, attrs):
raise exceptions.ValidationError(
{
"user_type": [
"User cannot create another user with higher permissions"
]
}
"User cannot create another user with higher permissions",
],
},
)

if (
Expand All @@ -216,7 +220,7 @@ def validate(self, attrs):
and not validated.get("state")
):
raise exceptions.ValidationError(
{"__all__": ["One of ward, local body, district or state is required"]}
{"__all__": ["One of ward, local body, district or state is required"]},
)

return validated
Expand All @@ -239,7 +243,9 @@ def create(self, validated_data):
with transaction.atomic():
facilities = validated_data.pop("facilities", [])
user = User.objects.create_user(
created_by=self.context["created_by"], verified=True, **validated_data
created_by=self.context["created_by"],
verified=True,
**validated_data,
)
facility_query = self.facility_query(self.context["created_by"])
if facilities:
Expand All @@ -265,7 +271,8 @@ class UserSerializer(SignUpSerializer):
district_object = DistrictSerializer(source="district", read_only=True)
state_object = StateSerializer(source="state", read_only=True)
home_facility_object = FacilityBareMinimumSerializer(
source="home_facility", read_only=True
source="home_facility",
read_only=True,
)

home_facility = ExternalIdSerializerField(queryset=Facility.objects.all())
Expand Down Expand Up @@ -318,16 +325,16 @@ class Meta:
extra_kwargs = {"url": {"lookup_field": "username"}}

def validate(self, attrs):
validated = super(UserSerializer, self).validate(attrs)
validated = super().validate(attrs)
if "home_facility" in validated:
allowed_facilities = get_home_facility_queryset(
self.context["request"].user
self.context["request"].user,
)
if not allowed_facilities.filter(id=validated["home_facility"].id).exists():
raise exceptions.ValidationError(
{
"home_facility": "Cannot create users with different Home Facility"
}
"home_facility": "Cannot create users with different Home Facility",
},
)
return validated

Expand All @@ -351,9 +358,10 @@ class Meta:
class UserAssignedSerializer(serializers.ModelSerializer):
user_type = ChoiceField(choices=User.TYPE_CHOICES, read_only=True)
home_facility_object = FacilityBareMinimumSerializer(
source="home_facility", read_only=True
source="home_facility",
read_only=True,
)
skills = SkillSerializer(many=True, read_only=True)
skills = UserSkillSerializer(many=True, read_only=True)

class Meta:
model = User
Expand Down Expand Up @@ -381,7 +389,8 @@ class UserListSerializer(serializers.ModelSerializer):
user_type = ChoiceField(choices=User.TYPE_CHOICES, read_only=True)
created_by = serializers.CharField(source="created_by_user", read_only=True)
home_facility_object = FacilityBareMinimumSerializer(
source="home_facility", read_only=True
source="home_facility",
read_only=True,
)
home_facility = ExternalIdSerializerField(queryset=Facility.objects.all())

Expand Down
Loading

0 comments on commit ac5c0b3

Please sign in to comment.