Skip to content

Commit

Permalink
Bed Revision v1 (#715)
Browse files Browse the repository at this point in the history
Co-authored-by: Arpan Abhishek <[email protected]>
Co-authored-by: Gigin George <[email protected]>
  • Loading branch information
3 people authored Apr 22, 2022
1 parent f71b399 commit 9277da5
Show file tree
Hide file tree
Showing 13 changed files with 336 additions and 138 deletions.
61 changes: 60 additions & 1 deletion care/facility/api/serializers/bed.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
from care.facility.api.serializers import TIMESTAMP_FIELDS
from care.facility.api.serializers.asset import AssetLocationSerializer, AssetSerializer
from care.facility.models.asset import Asset, AssetLocation
from care.facility.models.bed import AssetBed, Bed
from care.facility.models.bed import AssetBed, Bed, ConsultationBed
from care.facility.models.facility import Facility
from care.facility.models.patient_consultation import PatientConsultation
from care.utils.queryset.consultation import get_consultation_queryset
from care.utils.queryset.facility import get_facility_queryset
from care.utils.serializer.external_id_field import ExternalIdSerializerField
from config.serializers import ChoiceField


Expand Down Expand Up @@ -74,3 +77,59 @@ def validate(self, attrs):
else:
raise ValidationError({"asset": "Field is Required", "bed": "Field is Required"})
return super().validate(attrs)


class ConsultationBedSerializer(ModelSerializer):
id = UUIDField(source="external_id", read_only=True)

bed_object = BedSerializer(source="bed", read_only=True)

consultation = ExternalIdSerializerField(queryset=PatientConsultation.objects.all(), write_only=True, required=True)
bed = ExternalIdSerializerField(queryset=Bed.objects.all(), write_only=True, required=True)

class Meta:
model = ConsultationBed
exclude = ("deleted", "external_id")
read_only_fields = TIMESTAMP_FIELDS

def validate(self, attrs):
user = self.context["request"].user
if "consultation" in attrs and "bed" in attrs and "start_date" in attrs:
bed = attrs["bed"]
facilities = get_facility_queryset(user)
permitted_consultations = get_consultation_queryset(user)
consultation = get_object_or_404(permitted_consultations.filter(id=attrs["consultation"].id))
if not facilities.filter(id=bed.facility.id).exists():
raise PermissionError()
if consultation.facility.id != bed.facility.id:
raise ValidationError({"consultation": "Should be in the same facility as the bed"})
start_date = attrs["start_date"]
end_date = attrs.get("end_date", None)
existing_qs = ConsultationBed.objects.filter(consultation=consultation, bed=bed)
# Conflict checking logic
if existing_qs.objects.filter(start_date__gt=start_date, end_date__lt=start_date).exists():
raise ValidationError({"start_date": "Cannot create conflicting entry"})
if end_date:
if existing_qs.objects.filter(start_date__gt=end_date, end_date__lt=end_date).exists():
raise ValidationError({"end_date": "Cannot create conflicting entry"})

raise ValidationError(
{
"consultation": "Field is Required",
"bed": "Field is Required",
"start_date": "Field is Required",
}
)
return super().validate(attrs)

def create(self, validated_data):
consultation = validated_data["consultation"]
bed = validated_data["bed"]
existing_qs = ConsultationBed.objects.filter(consultation=consultation, bed=bed)
if existing_qs.exists():
existing_qs.end_date = validated_data["start_date"]
existing_qs.save()
obj = super().create(validated_data)
consultation.current_bed = obj # This needs better logic, when an update occurs and the latest bed is no longer the last bed consultation relation added.
consultation.save(update_fields=["current_bed"])
return obj
7 changes: 2 additions & 5 deletions care/facility/api/serializers/daily_round.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from rest_framework.exceptions import ValidationError
from rest_framework.generics import get_object_or_404

from care.facility.api.serializers.bed import BedSerializer
# from care.facility.api.serializers.bed import BedSerializer
from care.facility.models import CATEGORY_CHOICES, PatientRegistration
from care.facility.models.bed import Bed
from care.facility.models.daily_round import DailyRound
Expand All @@ -25,7 +25,6 @@ class DailyRoundSerializer(serializers.ModelSerializer):
additional_symptoms = serializers.MultipleChoiceField(choices=SYMPTOM_CHOICES, required=False)
patient_category = ChoiceField(choices=CATEGORY_CHOICES, required=False)
current_health = ChoiceField(choices=CURRENT_HEALTH_CHOICES, required=False)
admitted_to = ChoiceField(choices=ADMIT_CHOICES, required=False)

action = ChoiceField(choices=PatientRegistration.ActionChoices, write_only=True, required=False)
review_time = serializers.IntegerField(default=-1, write_only=True, required=False)
Expand Down Expand Up @@ -54,9 +53,7 @@ class DailyRoundSerializer(serializers.ModelSerializer):
last_edited_by = UserBaseMinimumSerializer(read_only=True)
created_by = UserBaseMinimumSerializer(read_only=True)

bed_object = BedSerializer(read_only=True)

bed = serializers.UUIDField(source="bed.external_id", allow_null=True, required=False)
# bed_object = BedSerializer(read_only=True)

class Meta:
model = DailyRound
Expand Down
16 changes: 8 additions & 8 deletions care/facility/api/serializers/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ class Meta:
fields = "__all__"

phone_number = PhoneNumberIsPossibleField()
facility = serializers.UUIDField(source="facility.external_id", allow_null=True, required=False)

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 Down Expand Up @@ -156,10 +157,10 @@ class Meta:
# return None
# return PatientConsultationSerializer(last_consultation).data

def validate_facility(self, value):
if value is not None and Facility.objects.filter(id=value).first() is None:
raise serializers.ValidationError("facility not found")
return value
# def validate_facility(self, value):
# if value is not None and Facility.objects.filter(external_id=value).first() is None:
# raise serializers.ValidationError("facility not found")
# return value

def validate_countries_travelled(self, value):
if not value:
Expand Down Expand Up @@ -192,9 +193,8 @@ def create(self, validated_data):
contacted_patients = validated_data.pop("contacted_patients", [])

if "facility" in validated_data:
external_id = validated_data.pop("facility")["external_id"]
if external_id:
validated_data["facility_id"] = Facility.objects.get(external_id=external_id).id
pass
# TODO Facility Authorization

if "srf_id" in validated_data:
if validated_data["srf_id"]:
Expand Down
48 changes: 28 additions & 20 deletions care/facility/api/serializers/patient_consultation.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
from rest_framework.exceptions import ValidationError

from care.facility.api.serializers import TIMESTAMP_FIELDS
from care.facility.api.serializers.bed import ConsultationBedSerializer
from care.facility.api.serializers.daily_round import DailyRoundSerializer
from care.facility.api.serializers.facility import FacilityBasicInfoSerializer
from care.facility.models import CATEGORY_CHOICES, Facility, PatientRegistration
from care.facility.models.bed import Bed, ConsultationBed
from care.facility.models.notification import Notification
from care.facility.models.patient_base import ADMIT_CHOICES, SYMPTOM_CHOICES, SuggestionChoices
from care.facility.models.patient_base import SYMPTOM_CHOICES, SuggestionChoices
from care.facility.models.patient_consultation import PatientConsultation
from care.users.api.serializers.user import UserAssignedSerializer, UserBaseMinimumSerializer
from care.users.models import User
Expand All @@ -19,17 +21,13 @@


class PatientConsultationSerializer(serializers.ModelSerializer):

id = serializers.CharField(source="external_id", read_only=True)
facility_name = serializers.CharField(source="facility.name", read_only=True)
suggestion_text = ChoiceField(
choices=PatientConsultation.SUGGESTION_CHOICES,
read_only=True,
source="suggestion",
)
suggestion_text = ChoiceField(choices=PatientConsultation.SUGGESTION_CHOICES, read_only=True, source="suggestion",)

symptoms = serializers.MultipleChoiceField(choices=SYMPTOM_CHOICES)
category = ChoiceField(choices=CATEGORY_CHOICES, required=False)
admitted_to = ChoiceField(choices=ADMIT_CHOICES, required=False)

referred_to_object = FacilityBasicInfoSerializer(source="referred_to", read_only=True)
referred_to = ExternalIdSerializerField(queryset=Facility.objects.all(), required=False)
Expand All @@ -47,6 +45,10 @@ class PatientConsultationSerializer(serializers.ModelSerializer):
created_by = UserBaseMinimumSerializer(read_only=True)
last_daily_round = DailyRoundSerializer(read_only=True)

current_bed = ConsultationBedSerializer(read_only=True)

bed = ExternalIdSerializerField(queryset=Bed.objects.all(), required=False)

class Meta:
model = PatientConsultation
read_only_fields = TIMESTAMP_FIELDS + (
Expand Down Expand Up @@ -107,10 +109,7 @@ def update(self, instance, validated_data):
caused_by=self.context["request"].user,
caused_object=instance,
facility=instance.patient.facility,
notification_mediums=[
Notification.Medium.SYSTEM,
Notification.Medium.WHATSAPP,
],
notification_mediums=[Notification.Medium.SYSTEM, Notification.Medium.WHATSAPP,],
).generate()

NotificationGenerator(
Expand Down Expand Up @@ -145,11 +144,21 @@ def create(self, validated_data):
if validated_data["is_kasp"]:
validated_data["kasp_enabled_date"] = localtime(now())

bed = validated_data.pop("bed", None)

consultation = super().create(validated_data)
consultation.created_by = self.context["request"].user
consultation.last_edited_by = self.context["request"].user
consultation.save()

if bed:
consultation_bed = ConsultationBed(
bed=bed, consultation=consultation, start_date=consultation.created_date
)
consultation_bed.save()
consultation.current_bed = consultation_bed
consultation.save(update_fields=["current_bed"])

patient = consultation.patient
if consultation.suggestion == SuggestionChoices.OP:
consultation.discharge_date = localtime(now())
Expand Down Expand Up @@ -177,16 +186,15 @@ def create(self, validated_data):
caused_by=self.context["request"].user,
caused_object=consultation,
facility=consultation.patient.facility,
notification_mediums=[
Notification.Medium.SYSTEM,
Notification.Medium.WHATSAPP,
],
notification_mediums=[Notification.Medium.SYSTEM, Notification.Medium.WHATSAPP,],
).generate()

return consultation

def validate(self, obj):
validated = super().validate(obj)
def validate(self, attrs):
validated = super().validate(attrs)
# TODO Add Bed Authorisation Validation

if "suggestion" in validated:
if validated["suggestion"] is SuggestionChoices.R and not validated.get("referred_to"):
raise ValidationError(
Expand All @@ -197,14 +205,14 @@ def validate(self, obj):
and validated.get("admitted")
and not validated.get("admission_date")
):
raise ValidationError({"admission_date": [f"This field is required as the patient has been admitted."]})
raise ValidationError({"admission_date": ["This field is required as the patient has been admitted."]})

if "action" in validated:
if validated["action"] == PatientRegistration.ActionEnum.REVIEW:
if "review_time" not in validated:
raise ValidationError(
{"review_time": [f"This field is required as the patient has been requested Review."]}
{"review_time": ["This field is required as the patient has been requested Review."]}
)
if validated["review_time"] <= 0:
raise ValidationError({"review_time": [f"This field value is must be greater than 0."]})
raise ValidationError({"review_time": ["This field value is must be greater than 0."]})
return validated
30 changes: 28 additions & 2 deletions care/facility/api/viewsets/bed.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
from rest_framework.permissions import IsAuthenticated
from rest_framework.viewsets import GenericViewSet

from care.facility.api.serializers.bed import AssetBedSerializer, BedSerializer
from care.facility.models.bed import AssetBed, Bed
from care.facility.api.serializers.bed import AssetBedSerializer, BedSerializer, ConsultationBedSerializer
from care.facility.models.bed import AssetBed, Bed, ConsultationBed
from care.users.models import User
from care.utils.cache.cache_allowed_facilities import get_accessible_facilities
from care.utils.filters.choicefilter import CareChoiceFilter, inverse_choices
Expand Down Expand Up @@ -75,3 +75,29 @@ def get_queryset(self):
allowed_facilities = get_accessible_facilities(user)
queryset = queryset.filter(bed__facility__id__in=allowed_facilities)
return queryset


class ConsultationBedFilter(filters.FilterSet):
consultation = filters.UUIDFilter(field_name="consultation__external_id")
bed = filters.UUIDFilter(field_name="bed__external_id")


class ConsultationBedViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, GenericViewSet):
queryset = ConsultationBed.objects.all().select_related("consultation", "bed").order_by("-created_date")
serializer_class = ConsultationBedSerializer
filter_backends = (filters.DjangoFilterBackend,)
filterset_class = ConsultationBedFilter

def get_queryset(self):
user = self.request.user
queryset = self.queryset
if user.is_superuser:
pass
elif user.user_type >= User.TYPE_VALUE_MAP["StateLabAdmin"]:
queryset = queryset.filter(bed__facility__state=user.state)
elif user.user_type >= User.TYPE_VALUE_MAP["DistrictLabAdmin"]:
queryset = queryset.filter(bed__facility__district=user.district)
else:
allowed_facilities = get_accessible_facilities(user)
queryset = queryset.filter(bed__facility__id__in=allowed_facilities)
return queryset
8 changes: 6 additions & 2 deletions care/facility/api/viewsets/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
ShiftingRequest,
)
from care.facility.models.base import covert_choice_dict
from care.facility.models.bed import AssetBed
from care.facility.models.bed import AssetBed, ConsultationBed
from care.facility.models.patient_base import DISEASE_STATUS_DICT
from care.facility.tasks.patient.discharge_report import generate_discharge_report
from care.users.models import User
Expand Down Expand Up @@ -335,10 +335,14 @@ def discharge_patient(self, request, *args, **kwargs):
patient.allow_transfer = not discharged
patient.save(update_fields=["allow_transfer", "is_active"])
last_consultation = PatientConsultation.objects.filter(patient=patient).order_by("-id").first()
current_time = localtime(now())
if last_consultation:
if last_consultation.discharge_date is None:
last_consultation.discharge_date = localtime(now())
last_consultation.discharge_date = current_time
last_consultation.save()
ConsultationBed.objects.filter(consultation=last_consultation, end_date__isnull=True).update(
end_date=current_time
)

return Response(status=status.HTTP_200_OK)

Expand Down
46 changes: 46 additions & 0 deletions care/facility/migrations/0287_auto_20220415_1932.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Generated by Django 2.2.11 on 2022-04-15 14:02

import django.contrib.postgres.fields.jsonb
from django.db import migrations, models
import django.db.models.deletion
import uuid


class Migration(migrations.Migration):

dependencies = [
('facility', '0286_auto_20220316_2004'),
]

operations = [
migrations.RemoveField(
model_name='dailyround',
name='admitted_to',
),
migrations.RemoveField(
model_name='dailyround',
name='bed',
),
migrations.RemoveField(
model_name='patientconsultation',
name='admitted_to',
),
migrations.CreateModel(
name='ConsultationBed',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('external_id', models.UUIDField(db_index=True, default=uuid.uuid4, unique=True)),
('created_date', models.DateTimeField(auto_now_add=True, db_index=True, null=True)),
('modified_date', models.DateTimeField(auto_now=True, db_index=True, null=True)),
('deleted', models.BooleanField(db_index=True, default=False)),
('start_date', models.DateTimeField()),
('end_date', models.DateTimeField(blank=True, default=None, null=True)),
('meta', django.contrib.postgres.fields.jsonb.JSONField(default=dict)),
('bed', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='facility.Bed')),
('consultation', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='facility.PatientConsultation')),
],
options={
'abstract': False,
},
),
]
19 changes: 19 additions & 0 deletions care/facility/migrations/0288_patientconsultation_current_bed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 2.2.11 on 2022-04-15 18:29

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('facility', '0287_auto_20220415_1932'),
]

operations = [
migrations.AddField(
model_name='patientconsultation',
name='current_bed',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.PROTECT, to='facility.ConsultationBed'),
),
]
Loading

0 comments on commit 9277da5

Please sign in to comment.