Skip to content

Commit

Permalink
fix: regression from #715 (#924)
Browse files Browse the repository at this point in the history
* cleanup admitted_to

* moved BedType out of med model

* fixed CSV fields for patient summary

* fix patent summarization

* avoid Redefining built-in 'filter'

* refactor

* removed admitted_to reference from tests

* revert the removal of bed counts from district patient summary

* remove setup.cfg

* run pre-commit

Co-authored-by: Ashesh3 <3626859+Ashesh3@users.noreply.github.com>
  • Loading branch information
2 people authored and vigneshhari committed Sep 15, 2022
1 parent f710318 commit 87a55ca
Show file tree
Hide file tree
Showing 19 changed files with 455 additions and 262 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ repos:
rev: 4.0.1
hooks:
- id: flake8
args: ["--config=pyproject.toml"]
args: ["--config=.flake8"]
additional_dependencies: [flake8-isort]

ci:
Expand Down
10 changes: 5 additions & 5 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
Care
====

Care is a Corona Care Center management app for the Govt of Kerala
====

Auto Deployed to https://careapi.coronasafe.in for master Branch.
Auto Deployed to https://careapi.coronasafe.in for master Branch.

Documentation is available at https://care-be-docs.coronasafe.network

.. image:: https://circleci.com/gh/coronasafe/care.svg?style=svg
:alt: CircleCI Badge
:target: https://circleci.com/gh/coronasafe/care_fe
\

.. image:: https://api.codacy.com/project/badge/Grade/3ca2f379f8494605b52b382639510e0a
:alt: Codacy Badge
:target: https://app.codacy.com/gh/coronasafe/care?utm_source=github.com&utm_medium=referral&utm_content=coronasafe/care&utm_campaign=Badge_Grade_Dashboard
.. image:: https://img.shields.io/circleci/build/github/coronasafe/care/master?style=flat-square
:alt: Circle CI build
:target: https://circleci.com/gh/coronasafe/care
:target: https://circleci.com/gh/coronasafe/care
.. image:: https://github.com/coronasafe/care/workflows/Code%20scanning%20-%20action/badge.svg
:alt: Code scanning


.. image:: https://img.shields.io/badge/built%20with-Cookiecutter%20Django-ff69b4.svg
:target: https://github.com/pydanny/cookiecutter-django/
:alt: Built with Cookiecutter Django
Expand Down
3 changes: 2 additions & 1 deletion care/facility/api/serializers/bed.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from care.facility.models.asset import Asset, AssetLocation
from care.facility.models.bed import AssetBed, Bed, ConsultationBed
from care.facility.models.facility import Facility
from care.facility.models.patient_base import BedTypeChoices
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
Expand All @@ -16,7 +17,7 @@

class BedSerializer(ModelSerializer):
id = UUIDField(source="external_id", read_only=True)
bed_type = ChoiceField(choices=Bed.BedTypeChoices)
bed_type = ChoiceField(choices=BedTypeChoices)

location_object = AssetLocationSerializer(source="location", read_only=True)

Expand Down
24 changes: 14 additions & 10 deletions care/facility/api/viewsets/asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class AssetFilter(filters.FilterSet):
location = filters.UUIDFilter(field_name="current_location__external_id")
asset_type = CareChoiceFilter(choice_dict=inverse_asset_type)
status = CareChoiceFilter(choice_dict=inverse_asset_status)
is_working = filters.BooleanFilter()
is_working = filters.BooleanFilter()
qr_code_id = filters.CharFilter(field_name="qr_code_id", lookup_expr="icontains")


Expand All @@ -110,11 +110,13 @@ def retrieve(self, request, *args, **kwargs):
if not hit:
instance = self.get_object()
serializer = self.get_serializer(instance)
cache.set(key, serializer.data, 60 * 60 * 24) # Cache the asset details for 24 hours
cache.set(
key, serializer.data, 60 * 60 * 24
) # Cache the asset details for 24 hours
return Response(serializer.data)
return Response(hit)


class AssetViewSet(
ListModelMixin,
RetrieveModelMixin,
Expand Down Expand Up @@ -181,8 +183,8 @@ def set_default_user_location(self, request, *args, **kwargs):
obj.location = location
obj.save()
return Response(UserDefaultAssetLocationSerializer(obj).data)
except:
raise Http404
except Exception as e:
raise Http404 from e

# Dummy Serializer for Operate Asset
class DummyAssetOperateSerializer(Serializer):
Expand All @@ -206,17 +208,19 @@ def operate_assets(self, request, *args, **kwargs):
action = request.data["action"]
asset: Asset = self.get_object()
asset_class: BaseAssetIntegration = AssetClasses[asset.asset_class].value(
asset.meta)
asset.meta
)
result = asset_class.handle_action(action)
return Response({"result": result}, status=status.HTTP_200_OK)

except ValidationError as e:
return Response({"message": e.detail}, status=status.HTTP_400_BAD_REQUEST)

except KeyError as e:
return Response({
"message": dict((key, "is required") for key in e.args)
}, status=status.HTTP_400_BAD_REQUEST)
return Response(
{"message": dict((key, "is required") for key in e.args)},
status=status.HTTP_400_BAD_REQUEST,
)

except APIException as e:
return Response(e.detail, e.status_code)
Expand Down
62 changes: 50 additions & 12 deletions care/facility/api/viewsets/bed.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
from django.core.exceptions import ValidationError as DjangoValidationError
from django_filters import rest_framework as filters
from rest_framework import filters as drf_filters
from rest_framework.exceptions import PermissionDenied
from rest_framework.exceptions import ValidationError as DRFValidationError
from rest_framework.fields import get_error_detail
from rest_framework.mixins import (CreateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin,
UpdateModelMixin)
from rest_framework.mixins import (
CreateModelMixin,
DestroyModelMixin,
ListModelMixin,
RetrieveModelMixin,
UpdateModelMixin,
)
from rest_framework.permissions import IsAuthenticated
from rest_framework.viewsets import GenericViewSet
from rest_framework.exceptions import PermissionDenied

from care.facility.api.serializers.bed import AssetBedSerializer, BedSerializer, ConsultationBedSerializer
from care.facility.api.serializers.bed import (
AssetBedSerializer,
BedSerializer,
ConsultationBedSerializer,
)
from care.facility.models.bed import AssetBed, Bed, ConsultationBed
from care.facility.models.patient_base import BedTypeChoices
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

inverse_bed_type = inverse_choices(Bed.BedTypeChoices)
inverse_bed_type = inverse_choices(BedTypeChoices)


class BedFilter(filters.FilterSet):
Expand All @@ -24,8 +34,19 @@ class BedFilter(filters.FilterSet):
bed_type = CareChoiceFilter(choice_dict=inverse_bed_type)


class BedViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
queryset = Bed.objects.all().select_related("facility", "location").order_by("-created_date")
class BedViewSet(
ListModelMixin,
RetrieveModelMixin,
CreateModelMixin,
UpdateModelMixin,
DestroyModelMixin,
GenericViewSet,
):
queryset = (
Bed.objects.all()
.select_related("facility", "location")
.order_by("-created_date")
)
serializer_class = BedSerializer
lookup_field = "external_id"
filter_backends = (filters.DjangoFilterBackend, drf_filters.SearchFilter)
Expand All @@ -46,7 +67,7 @@ def get_queryset(self):
allowed_facilities = get_accessible_facilities(user)
queryset = queryset.filter(facility__id__in=allowed_facilities)
return queryset

def destroy(self, request, *args, **kwargs):
if request.user.user_type < User.TYPE_VALUE_MAP["DistrictLabAdmin"]:
raise PermissionDenied()
Expand All @@ -64,9 +85,16 @@ class AssetBedFilter(filters.FilterSet):


class AssetBedViewSet(
ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet
ListModelMixin,
RetrieveModelMixin,
CreateModelMixin,
UpdateModelMixin,
DestroyModelMixin,
GenericViewSet,
):
queryset = AssetBed.objects.all().select_related("asset", "bed").order_by("-created_date")
queryset = (
AssetBed.objects.all().select_related("asset", "bed").order_by("-created_date")
)
serializer_class = AssetBedSerializer
filter_backends = (filters.DjangoFilterBackend,)
filterset_class = AssetBedFilter
Expand All @@ -92,8 +120,18 @@ class ConsultationBedFilter(filters.FilterSet):
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")
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
Expand Down
3 changes: 1 addition & 2 deletions care/facility/api/viewsets/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,8 +342,7 @@ def discharge_patient(self, request, *args, **kwargs):
patient = self.get_object()
patient.is_active = discharged
patient.allow_transfer = not discharged
patient.assigned_to = None
patient.save(update_fields=["allow_transfer", "is_active", "assigned_to"])
patient.save(update_fields=["allow_transfer", "is_active"])
last_consultation = (
PatientConsultation.objects.filter(patient=patient).order_by("-id").first()
)
Expand Down
44 changes: 33 additions & 11 deletions care/facility/models/asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,12 @@ class RoomType(enum.Enum):

name = models.CharField(max_length=1024, blank=False, null=False)
description = models.TextField(default="", null=True, blank=True)
location_type = models.IntegerField(choices=RoomTypeChoices, default=RoomType.OTHER.value)
facility = models.ForeignKey(Facility, on_delete=models.PROTECT, null=False, blank=False)
location_type = models.IntegerField(
choices=RoomTypeChoices, default=RoomType.OTHER.value
)
facility = models.ForeignKey(
Facility, on_delete=models.PROTECT, null=False, blank=False
)


class Asset(BaseModel):
Expand All @@ -53,19 +57,29 @@ class Status(enum.Enum):

name = models.CharField(max_length=1024, blank=False, null=False)
description = models.TextField(default="", null=True, blank=True)
asset_type = models.IntegerField(choices=AssetTypeChoices, default=AssetType.INTERNAL.value)
asset_class = models.CharField(choices=AssetClassChoices, default=None, null=True, blank=True, max_length=20)
asset_type = models.IntegerField(
choices=AssetTypeChoices, default=AssetType.INTERNAL.value
)
asset_class = models.CharField(
choices=AssetClassChoices, default=None, null=True, blank=True, max_length=20
)
status = models.IntegerField(choices=StatusChoices, default=Status.ACTIVE.value)
current_location = models.ForeignKey(AssetLocation, on_delete=models.PROTECT, null=False, blank=False)
current_location = models.ForeignKey(
AssetLocation, on_delete=models.PROTECT, null=False, blank=False
)
is_working = models.BooleanField(default=None, null=True, blank=True)
not_working_reason = models.CharField(max_length=1024, blank=True, null=True)
serial_number = models.CharField(max_length=1024, blank=True, null=True)
warranty_details = models.TextField(null=True, blank=True, default="") # Deprecated
meta = JSONField(default=dict, blank=True, validators=[JSONFieldSchemaValidator(ASSET_META)])
meta = JSONField(
default=dict, blank=True, validators=[JSONFieldSchemaValidator(ASSET_META)]
)
# Vendor Details
vendor_name = models.CharField(max_length=1024, blank=True, null=True)
support_name = models.CharField(max_length=1024, blank=True, null=True)
support_phone = models.CharField(max_length=14, validators=[phone_number_regex], default="")
support_phone = models.CharField(
max_length=14, validators=[phone_number_regex], default=""
)
support_email = models.EmailField(blank=True, null=True)
qr_code_id = models.CharField(max_length=1024, blank=True, default=None, null=True)
manufacturer = models.CharField(max_length=1024, blank=True, null=True)
Expand All @@ -88,12 +102,18 @@ def __str__(self):

class UserDefaultAssetLocation(BaseModel):
user = models.ForeignKey(User, on_delete=models.PROTECT, null=False, blank=False)
location = models.ForeignKey(AssetLocation, on_delete=models.PROTECT, null=False, blank=False)
location = models.ForeignKey(
AssetLocation, on_delete=models.PROTECT, null=False, blank=False
)


class FacilityDefaultAssetLocation(BaseModel):
facility = models.ForeignKey(Facility, on_delete=models.PROTECT, null=False, blank=False)
location = models.ForeignKey(AssetLocation, on_delete=models.PROTECT, null=False, blank=False)
facility = models.ForeignKey(
Facility, on_delete=models.PROTECT, null=False, blank=False
)
location = models.ForeignKey(
AssetLocation, on_delete=models.PROTECT, null=False, blank=False
)


class AssetTransaction(BaseModel):
Expand All @@ -112,4 +132,6 @@ class AssetTransaction(BaseModel):
null=False,
blank=False,
)
performed_by = models.ForeignKey(User, on_delete=models.PROTECT, null=False, blank=False)
performed_by = models.ForeignKey(
User, on_delete=models.PROTECT, null=False, blank=False
)
40 changes: 21 additions & 19 deletions care/facility/models/bed.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,44 @@
However this is an addon feature and is not required for the regular patient flow,
Leaving scope to build rooms and wards to being even more organization.
"""
import enum

from django.contrib.postgres.fields.jsonb import JSONField
from django.core.exceptions import ValidationError
from django.db import models

from care.facility.models.asset import Asset, AssetLocation
from care.facility.models.facility import Facility
from care.facility.models.patient_base import BedType, BedTypeChoices
from care.facility.models.patient_consultation import PatientConsultation
from care.utils.models.base import BaseModel


class Bed(BaseModel):
class BedType(enum.Enum):
ISOLATION = 1
ICU = 2
ICU_WITH_NON_INVASIVE_VENTILATOR = 3
ICU_WITH_OXYGEN_SUPPORT = 4
ICU_WITH_INVASIVE_VENTILATOR = 5
BED_WITH_OXYGEN_SUPPORT = 6
REGULAR = 7

BedTypeChoices = [(e.value, e.name) for e in BedType]

name = models.CharField(max_length=1024)
description = models.TextField(default="", blank=True)
bed_type = models.IntegerField(choices=BedTypeChoices, default=BedType.REGULAR.value)
facility = models.ForeignKey(Facility, on_delete=models.PROTECT, null=False, blank=False) # Deprecated
bed_type = models.IntegerField(
choices=BedTypeChoices, default=BedType.REGULAR.value
)
facility = models.ForeignKey(
Facility, on_delete=models.PROTECT, null=False, blank=False
) # Deprecated
meta = JSONField(default=dict, blank=True)
assets = models.ManyToManyField(Asset, through="AssetBed")
location = models.ForeignKey(AssetLocation, on_delete=models.PROTECT, null=False, blank=False)
location = models.ForeignKey(
AssetLocation, on_delete=models.PROTECT, null=False, blank=False
)

def __str__(self):
return self.name

def validate(self) -> None:
if Bed.objects.filter(location=self.location, name=self.name).exclude(pk=self.pk).exists():
raise ValidationError({"name": "Bed with same name already exists in location."})
if (
Bed.objects.filter(location=self.location, name=self.name)
.exclude(pk=self.pk)
.exists()
):
raise ValidationError(
{"name": "Bed with same name already exists in location."}
)

def save(self, *args, **kwargs) -> None:
self.validate()
Expand All @@ -58,7 +58,9 @@ def __str__(self):


class ConsultationBed(BaseModel):
consultation = models.ForeignKey(PatientConsultation, on_delete=models.PROTECT, null=False, blank=False)
consultation = models.ForeignKey(
PatientConsultation, on_delete=models.PROTECT, null=False, blank=False
)
bed = models.ForeignKey(Bed, on_delete=models.PROTECT, null=False, blank=False)
start_date = models.DateTimeField(null=False, blank=False)
end_date = models.DateTimeField(null=True, blank=True, default=None)
Expand Down
Loading

0 comments on commit 87a55ca

Please sign in to comment.