Skip to content

Commit

Permalink
Merge pull request #2401 from ohcnetwork/staging
Browse files Browse the repository at this point in the history
Production release v24.35.0
  • Loading branch information
gigincg committed Aug 26, 2024
2 parents 92d12ae + f7b3d33 commit 66a0a8b
Show file tree
Hide file tree
Showing 18 changed files with 354 additions and 45 deletions.
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ default_stages: [commit]

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v4.6.0
hooks:
- id: no-commit-to-branch
args: [--branch, develop, --branch, staging, --branch, production]
Expand All @@ -23,13 +23,13 @@ repos:
additional_dependencies: ["isort[pyproject]"]

- repo: https://github.com/psf/black
rev: 24.4.0
rev: 24.4.2
hooks:
- id: black
args: ["--config=pyproject.toml"]

- repo: https://github.com/PyCQA/flake8
rev: 6.0.0
rev: 7.1.0
hooks:
- id: flake8
args: ["--config=.flake8"]
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2023 Open Healthcare Network
Copyright (c) 2024 Open Healthcare Network

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
26 changes: 26 additions & 0 deletions care/facility/api/serializers/asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,32 @@ def update(self, instance: Asset, validated_data):
return updated_instance


class AssetPublicSerializer(ModelSerializer):
id = UUIDField(source="external_id", read_only=True)
status = ChoiceField(choices=StatusChoices, read_only=True)
asset_type = ChoiceField(choices=AssetTypeChoices)
location_object = AssetLocationSerializer(source="current_location", read_only=True)

class Meta:
model = Asset
fields = (
"id",
"name",
"location_object",
"serial_number",
"warranty_details",
"warranty_amc_end_of_validity",
"asset_type",
"asset_class",
"vendor_name",
"support_name",
"support_email",
"support_phone",
"is_working",
"status",
)


class AssetConfigSerializer(ModelSerializer):
id = UUIDField(source="external_id")
type = CharField(source="asset_class")
Expand Down
17 changes: 15 additions & 2 deletions care/facility/api/serializers/facility.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ class FacilityBasicInfoSerializer(serializers.ModelSerializer):
state_object = StateSerializer(source="state", read_only=True)
facility_type = serializers.SerializerMethodField()
read_cover_image_url = serializers.CharField(read_only=True)
features = serializers.MultipleChoiceField(choices=FEATURE_CHOICES)
features = serializers.ListField(
child=serializers.ChoiceField(choices=FEATURE_CHOICES),
required=False,
)
patient_count = serializers.SerializerMethodField()
bed_count = serializers.SerializerMethodField()

Expand Down Expand Up @@ -96,7 +99,10 @@ class FacilitySerializer(FacilityBasicInfoSerializer):
# }
read_cover_image_url = serializers.URLField(read_only=True)
# location = PointField(required=False)
features = serializers.MultipleChoiceField(choices=FEATURE_CHOICES)
features = serializers.ListField(
child=serializers.ChoiceField(choices=FEATURE_CHOICES),
required=False,
)
bed_count = serializers.SerializerMethodField()

class Meta:
Expand Down Expand Up @@ -148,6 +154,13 @@ def validate_middleware_address(self, value):
MiddlewareDomainAddressValidator()(value)
return value

def validate_features(self, value):
if len(value) != len(set(value)):
raise serializers.ValidationError(
"Features should not contain duplicate values."
)
return value

def create(self, validated_data):
validated_data["created_by"] = self.context["request"].user
return super().create(validated_data)
Expand Down
5 changes: 3 additions & 2 deletions care/facility/api/viewsets/asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from care.facility.api.serializers.asset import (
AssetConfigSerializer,
AssetLocationSerializer,
AssetPublicSerializer,
AssetSerializer,
AssetServiceSerializer,
AssetTransactionSerializer,
Expand Down Expand Up @@ -187,7 +188,7 @@ def filter_is_permanent(self, queryset, _, value):

class AssetPublicViewSet(GenericViewSet):
queryset = Asset.objects.all()
serializer_class = AssetSerializer
serializer_class = AssetPublicSerializer
lookup_field = "external_id"

def retrieve(self, request, *args, **kwargs):
Expand All @@ -205,7 +206,7 @@ def retrieve(self, request, *args, **kwargs):

class AssetPublicQRViewSet(GenericViewSet):
queryset = Asset.objects.all()
serializer_class = AssetSerializer
serializer_class = AssetPublicSerializer
lookup_field = "qr_code_id"

def retrieve(self, request, *args, **kwargs):
Expand Down
1 change: 0 additions & 1 deletion care/facility/api/viewsets/icd.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ def list(self, request):

query = [
ICD11.has_code == 1,
ICD11.chapter != "null", # noqa: E711
]
if q := request.query_params.get("query"):
query.append(ICD11.vec % query_builder(q))
Expand Down
2 changes: 1 addition & 1 deletion care/facility/management/commands/load_event_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ class Command(BaseCommand):
"fields": (
"bilateral_air_entry",
"etco2",
"ventilator_fi02",
"ventilator_fio2",
"ventilator_interface",
"ventilator_mean_airway_pressure",
"ventilator_mode",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ class Command(BaseCommand):
"21 Symptoms, signs or clinical findings, not elsewhere classified": "Others",
"22 Injury, poisoning or certain other consequences of external causes": "Injury, Poisoning",
"23 External causes of morbidity or mortality": "External Causes of Injury",
"24 Factors influencing health status or contact with health services": None,
"24 Factors influencing health status or contact with health services": "Reason for contact with Health Services",
"25 Codes for special purposes": "Codes for special purposes",
"26 Supplementary Chapter Traditional Medicine Conditions - Module I": None,
"26 Supplementary Chapter Traditional Medicine Conditions - Module I": "Supplementary chapter",
"V Supplementary section for functioning assessment": "Functioning assessment",
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Generated by Django 4.2.10 on 2024-06-03 06:24

import django.contrib.postgres.fields
from django.db import migrations, models


def convert_features_to_array(apps, schema_editor):
Facility = apps.get_model("facility", "Facility")

facilities_to_update = Facility.objects.filter(old_features__isnull=False)

updated_facilities = []

for facility in facilities_to_update:
try:
facility.features = list(facility.old_features)
updated_facilities.append(facility)
except ValueError:
print(f"facility '{facility.name}' has invalid facility features")

if updated_facilities:
Facility.objects.bulk_update(updated_facilities, ["features"])


class Migration(migrations.Migration):
dependencies = [
("facility", "0447_patientconsultationevent_taken_at"),
]

operations = [
migrations.RenameField(
model_name="facility",
old_name="features",
new_name="old_features",
),
migrations.AddField(
model_name="facility",
name="features",
field=django.contrib.postgres.fields.ArrayField(
base_field=models.SmallIntegerField(
choices=[
(1, "CT Scan Facility"),
(2, "Maternity Care"),
(3, "X-Ray Facility"),
(4, "Neonatal Care"),
(5, "Operation Theater"),
(6, "Blood Bank"),
]
),
blank=True,
null=True,
size=None,
),
),
migrations.RunPython(convert_features_to_array),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Generated by Django 4.2.10 on 2024-08-13 10:36

from django.core.paginator import Paginator
from django.db import migrations


class Migration(migrations.Migration):
def forward_rename_dailyround_events(apps, schema_editor):
EventType = apps.get_model("facility", "EventType")
PatientConsultationEvent = apps.get_model(
"facility", "PatientConsultationEvent"
)

event_type = EventType.objects.filter(name="RESPIRATORY_SUPPORT")
if not event_type.exists():
return
event_type_id = event_type.first().id

paginator = Paginator(
PatientConsultationEvent.objects.filter(
object_model="DailyRound",
event_type_id=event_type_id,
value__has_key="ventilator_fi02",
).order_by("id"),
1000,
)

for page_number in paginator.page_range:
bulk = []
for instance in paginator.page(page_number).object_list:
instance.value["ventilator_fio2"] = instance.value.pop(
"ventilator_fi02"
)
bulk.append(instance)
PatientConsultationEvent.objects.bulk_update(bulk, ["value"])

def reverse_rename_dailyround_events(apps, schema_editor):
EventType = apps.get_model("facility", "EventType")
PatientConsultationEvent = apps.get_model(
"facility", "PatientConsultationEvent"
)

event_type = EventType.objects.filter(name="RESPIRATORY_SUPPORT")
if not event_type.exists():
return
event_type_id = event_type.first().id

paginator = Paginator(
PatientConsultationEvent.objects.filter(
object_model="DailyRound",
event_type_id=event_type_id,
value__has_key="ventilator_fio2",
).order_by("id"),
1000,
)

for page_number in paginator.page_range:
bulk = []
for instance in paginator.page(page_number).object_list:
instance.value["ventilator_fi02"] = instance.value.pop(
"ventilator_fio2"
)
bulk.append(instance)
PatientConsultationEvent.objects.bulk_update(bulk, ["value"])

dependencies = [
("facility", "0447_patientconsultationevent_taken_at"),
]

operations = [
migrations.RenameField(
model_name="dailyround",
old_name="ventilator_fi02",
new_name="ventilator_fio2",
),
migrations.RunPython(
forward_rename_dailyround_events,
reverse_code=reverse_rename_dailyround_events,
),
]
12 changes: 12 additions & 0 deletions care/facility/migrations/0449_merge_20240822_1343.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Generated by Django 4.2.10 on 2024-08-22 08:13

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("facility", "0448_rename_features_facility_old_features"),
("facility", "0448_rename_ventilator_fi02_dailyround_ventilator_fio2"),
]

operations = []
2 changes: 1 addition & 1 deletion care/facility/models/daily_round.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ class InsulinIntakeFrequencyType(enum.Enum):
null=True,
validators=[MinValueValidator(0), MaxValueValidator(70)],
)
ventilator_fi02 = models.IntegerField(
ventilator_fio2 = models.IntegerField(
default=None,
null=True,
validators=[MinValueValidator(21), MaxValueValidator(100)],
Expand Down
27 changes: 25 additions & 2 deletions care/facility/models/facility.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.postgres.fields import ArrayField
from django.core.validators import MinValueValidator
from django.db import models
from multiselectfield import MultiSelectField
Expand Down Expand Up @@ -38,6 +39,7 @@
(70, "KASP Ventilator beds"),
]

# to be removed in further PR
FEATURE_CHOICES = [
(1, "CT Scan Facility"),
(2, "Maternity Care"),
Expand All @@ -47,9 +49,20 @@
(6, "Blood Bank"),
]


class FacilityFeature(models.IntegerChoices):
CT_SCAN_FACILITY = 1, "CT Scan Facility"
MATERNITY_CARE = 2, "Maternity Care"
X_RAY_FACILITY = 3, "X-Ray Facility"
NEONATAL_CARE = 4, "Neonatal Care"
OPERATION_THEATER = 5, "Operation Theater"
BLOOD_BANK = 6, "Blood Bank"


ROOM_TYPES.extend(BASE_ROOM_TYPES)

REVERSE_ROOM_TYPES = reverse_choices(ROOM_TYPES)
REVERSE_FEATURE_CHOICES = reverse_choices(FEATURE_CHOICES)

FACILITY_TYPES = [
(1, "Educational Inst"),
Expand Down Expand Up @@ -160,13 +173,17 @@ class Facility(FacilityBaseModel, FacilityPermissionMixin):
verified = models.BooleanField(default=False)
facility_type = models.IntegerField(choices=FACILITY_TYPES)
kasp_empanelled = models.BooleanField(default=False, blank=False, null=False)
features = MultiSelectField(
features = ArrayField(
models.SmallIntegerField(choices=FacilityFeature.choices),
blank=True,
null=True,
)
old_features = MultiSelectField(
choices=FEATURE_CHOICES,
null=True,
blank=True,
max_length=get_max_length(FEATURE_CHOICES, None),
)

longitude = models.DecimalField(
max_digits=22, decimal_places=16, null=True, blank=True
)
Expand Down Expand Up @@ -243,6 +260,12 @@ def save(self, *args, **kwargs) -> None:
facility=self, user=self.created_by, created_by=self.created_by
)

@property
def get_features_display(self):
if not self.features:
return []
return [FacilityFeature(f).label for f in self.features]

CSV_MAPPING = {
"name": "Facility Name",
"facility_type": "Facility Type",
Expand Down
Loading

0 comments on commit 66a0a8b

Please sign in to comment.