From e48887d687b6edf1c09152b9a9e1c2346c2057a1 Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Wed, 18 Sep 2024 15:38:30 +0530 Subject: [PATCH] Adds necessary fields for Community Nurse's log update (#2448) * Adds fields for Community Nurses log update * add event types and fixes bladder issue choices * Add tests * switch to integer choices * switch to using `.choices` instead of manually generating choices * update event types and field name --- care/facility/api/serializers/daily_round.py | 21 +++ .../management/commands/load_event_types.py | 20 +++ ...te_dailyround_bladder_drainage_and_more.py | 144 ++++++++++++++++++ care/facility/models/daily_round.py | 80 ++++++++++ .../tests/test_patient_daily_rounds_api.py | 18 +++ 5 files changed, 283 insertions(+) create mode 100644 care/facility/migrations/0456_dailyround_appetite_dailyround_bladder_drainage_and_more.py diff --git a/care/facility/api/serializers/daily_round.py b/care/facility/api/serializers/daily_round.py index 4cf296706f..4f2f61c32b 100644 --- a/care/facility/api/serializers/daily_round.py +++ b/care/facility/api/serializers/daily_round.py @@ -41,6 +41,27 @@ class DailyRoundSerializer(serializers.ModelSerializer): rounds_type = ChoiceField(choices=DailyRound.RoundsTypeChoice, required=True) + # Community Nurse's Log + + bowel_issue = ChoiceField( + choices=DailyRound.BowelDifficultyType.choices, required=False + ) + bladder_drainage = ChoiceField( + choices=DailyRound.BladderDrainageType.choices, required=False + ) + bladder_issue = ChoiceField( + choices=DailyRound.BladderIssueType.choices, required=False + ) + urination_frequency = ChoiceField( + choices=DailyRound.UrinationFrequencyType.choices, required=False + ) + sleep = ChoiceField(choices=DailyRound.SleepType.choices, required=False) + nutrition_route = ChoiceField( + choices=DailyRound.NutritionRouteType.choices, required=False + ) + oral_issue = ChoiceField(choices=DailyRound.OralIssueType.choices, required=False) + appetite = ChoiceField(choices=DailyRound.AppetiteType.choices, required=False) + # Critical Care Components consciousness_level = ChoiceField( diff --git a/care/facility/management/commands/load_event_types.py b/care/facility/management/commands/load_event_types.py index fc9c231372..c6a92064f5 100644 --- a/care/facility/management/commands/load_event_types.py +++ b/care/facility/management/commands/load_event_types.py @@ -217,6 +217,26 @@ class Command(BaseCommand): ), }, {"name": "NURSING", "fields": ("nursing",)}, + { + "name": "ROUTINE", + "children": ( + {"name": "SLEEP_ROUTINE", "fields": ("sleep",)}, + {"name": "BOWEL_ROUTINE", "fields": ("bowel_issue",)}, + { + "name": "BLADDER_ROUTINE", + "fields": ( + "bladder_drainage", + "bladder_issue", + "experiences_dysuria", + "urination_frequency", + ), + }, + { + "name": "NUTRITION_ROUTINE", + "fields": ("nutrition_route", "oral_issue", "appetite"), + }, + ), + }, ), }, { diff --git a/care/facility/migrations/0456_dailyround_appetite_dailyround_bladder_drainage_and_more.py b/care/facility/migrations/0456_dailyround_appetite_dailyround_bladder_drainage_and_more.py new file mode 100644 index 0000000000..71cb7bd793 --- /dev/null +++ b/care/facility/migrations/0456_dailyround_appetite_dailyround_bladder_drainage_and_more.py @@ -0,0 +1,144 @@ +# Generated by Django 4.2.10 on 2024-09-13 07:06 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("facility", "0455_remove_facility_old_features"), + ] + + operations = [ + migrations.AddField( + model_name="dailyround", + name="appetite", + field=models.SmallIntegerField( + blank=True, + choices=[ + (1, "INCREASED"), + (2, "SATISFACTORY"), + (3, "REDUCED"), + (4, "NO_TASTE_FOR_FOOD"), + (5, "CANNOT_BE_ASSESSED"), + ], + default=None, + null=True, + ), + ), + migrations.AddField( + model_name="dailyround", + name="bladder_drainage", + field=models.SmallIntegerField( + blank=True, + choices=[ + (1, "NORMAL"), + (2, "CONDOM_CATHETER"), + (3, "DIAPER"), + (4, "INTERMITTENT_CATHETER"), + (5, "CONTINUOUS_INDWELLING_CATHETER"), + (6, "CONTINUOUS_SUPRAPUBIC_CATHETER"), + (7, "UROSTOMY"), + ], + default=None, + null=True, + ), + ), + migrations.AddField( + model_name="dailyround", + name="bladder_issue", + field=models.SmallIntegerField( + blank=True, + choices=[ + (0, "NO_ISSUES"), + (1, "INCONTINENCE"), + (2, "RETENTION"), + (3, "HESITANCY"), + ], + default=None, + null=True, + ), + ), + migrations.AddField( + model_name="dailyround", + name="bowel_issue", + field=models.SmallIntegerField( + blank=True, + choices=[(0, "NO_DIFFICULTY"), (1, "CONSTIPATION"), (2, "DIARRHOEA")], + default=None, + null=True, + ), + ), + migrations.AddField( + model_name="dailyround", + name="is_experiencing_dysuria", + field=models.BooleanField(blank=True, default=None, null=True), + ), + migrations.AddField( + model_name="dailyround", + name="nutrition_route", + field=models.SmallIntegerField( + blank=True, + choices=[ + (1, "ORAL"), + (2, "RYLES_TUBE"), + (3, "GASTROSTOMY_OR_JEJUNOSTOMY"), + (4, "PEG"), + (5, "PARENTERAL_TUBING_FLUID"), + (6, "PARENTERAL_TUBING_TPN"), + ], + default=None, + null=True, + ), + ), + migrations.AddField( + model_name="dailyround", + name="oral_issue", + field=models.SmallIntegerField( + blank=True, + choices=[(0, "NO_ISSUE"), (1, "DYSPHAGIA"), (2, "ODYNOPHAGIA")], + default=None, + null=True, + ), + ), + migrations.AddField( + model_name="dailyround", + name="sleep", + field=models.SmallIntegerField( + blank=True, + choices=[ + (1, "EXCESSIVE"), + (2, "SATISFACTORY"), + (3, "UNSATISFACTORY"), + (4, "NO_SLEEP"), + ], + default=None, + null=True, + ), + ), + migrations.AddField( + model_name="dailyround", + name="urination_frequency", + field=models.SmallIntegerField( + blank=True, + choices=[(1, "NORMAL"), (2, "DECREASED"), (3, "INCREASED")], + default=None, + null=True, + ), + ), + migrations.AlterField( + model_name="dailyround", + name="rounds_type", + field=models.IntegerField( + choices=[ + (0, "NORMAL"), + (30, "COMMUNITY_NURSES_LOG"), + (50, "DOCTORS_LOG"), + (100, "VENTILATOR"), + (200, "ICU"), + (300, "AUTOMATED"), + (400, "TELEMEDICINE"), + ], + default=0, + ), + ), + ] diff --git a/care/facility/models/daily_round.py b/care/facility/models/daily_round.py index 078709d9c9..58a288ed91 100644 --- a/care/facility/models/daily_round.py +++ b/care/facility/models/daily_round.py @@ -31,6 +31,7 @@ class DailyRound(PatientBaseModel): class RoundsType(enum.Enum): NORMAL = 0 + COMMUNITY_NURSES_LOG = 30 DOCTORS_LOG = 50 VENTILATOR = 100 ICU = 200 @@ -51,6 +52,57 @@ class ConsciousnessType(enum.Enum): ConsciousnessChoice = [(e.value, e.name) for e in ConsciousnessType] + class BowelDifficultyType(models.IntegerChoices): + NO_DIFFICULTY = 0, "NO_DIFFICULTY" + CONSTIPATION = 1, "CONSTIPATION" + DIARRHOEA = 2, "DIARRHOEA" + + class BladderDrainageType(models.IntegerChoices): + NORMAL = 1, "NORMAL" + CONDOM_CATHETER = 2, "CONDOM_CATHETER" + DIAPER = 3, "DIAPER" + INTERMITTENT_CATHETER = 4, "INTERMITTENT_CATHETER" + CONTINUOUS_INDWELLING_CATHETER = 5, "CONTINUOUS_INDWELLING_CATHETER" + CONTINUOUS_SUPRAPUBIC_CATHETER = 6, "CONTINUOUS_SUPRAPUBIC_CATHETER" + UROSTOMY = 7, "UROSTOMY" + + class BladderIssueType(models.IntegerChoices): + NO_ISSUES = 0, "NO_ISSUES" + INCONTINENCE = 1, "INCONTINENCE" + RETENTION = 2, "RETENTION" + HESITANCY = 3, "HESITANCY" + + class UrinationFrequencyType(models.IntegerChoices): + NORMAL = 1, "NORMAL" + DECREASED = 2, "DECREASED" + INCREASED = 3, "INCREASED" + + class SleepType(models.IntegerChoices): + EXCESSIVE = 1, "EXCESSIVE" + SATISFACTORY = 2, "SATISFACTORY" + UNSATISFACTORY = 3, "UNSATISFACTORY" + NO_SLEEP = 4, "NO_SLEEP" + + class NutritionRouteType(models.IntegerChoices): + ORAL = 1, "ORAL" + RYLES_TUBE = 2, "RYLES_TUBE" + GASTROSTOMY_OR_JEJUNOSTOMY = 3, "GASTROSTOMY_OR_JEJUNOSTOMY" + PEG = 4, "PEG" + PARENTERAL_TUBING_FLUID = 5, "PARENTERAL_TUBING_FLUID" + PARENTERAL_TUBING_TPN = 6, "PARENTERAL_TUBING_TPN" + + class OralIssueType(models.IntegerChoices): + NO_ISSUE = 0, "NO_ISSUE" + DYSPHAGIA = 1, "DYSPHAGIA" + ODYNOPHAGIA = 2, "ODYNOPHAGIA" + + class AppetiteType(models.IntegerChoices): + INCREASED = 1, "INCREASED" + SATISFACTORY = 2, "SATISFACTORY" + REDUCED = 3, "REDUCED" + NO_TASTE_FOR_FOOD = 4, "NO_TASTE_FOR_FOOD" + CANNOT_BE_ASSESSED = 5, "CANNOT_BE_ASSESSED" + class PupilReactionType(enum.Enum): UNKNOWN = 0 BRISK = 5 @@ -175,6 +227,34 @@ class InsulinIntakeFrequencyType(enum.Enum): ) is_parsed_by_ocr = models.BooleanField(default=False) + # Community Nurse's Log Attributes + + bowel_issue = models.SmallIntegerField( + choices=BowelDifficultyType.choices, default=None, null=True, blank=True + ) + bladder_drainage = models.SmallIntegerField( + choices=BladderDrainageType.choices, default=None, null=True, blank=True + ) + bladder_issue = models.SmallIntegerField( + choices=BladderIssueType.choices, default=None, null=True, blank=True + ) + is_experiencing_dysuria = models.BooleanField(default=None, null=True, blank=True) + urination_frequency = models.SmallIntegerField( + choices=UrinationFrequencyType.choices, default=None, null=True, blank=True + ) + sleep = models.SmallIntegerField( + choices=SleepType.choices, default=None, null=True, blank=True + ) + nutrition_route = models.SmallIntegerField( + choices=NutritionRouteType.choices, default=None, null=True, blank=True + ) + oral_issue = models.SmallIntegerField( + choices=OralIssueType.choices, default=None, null=True, blank=True + ) + appetite = models.SmallIntegerField( + choices=AppetiteType.choices, default=None, null=True, blank=True + ) + # Critical Care Attributes consciousness_level = models.IntegerField( diff --git a/care/facility/tests/test_patient_daily_rounds_api.py b/care/facility/tests/test_patient_daily_rounds_api.py index 3312a87dbc..1ea519c3eb 100644 --- a/care/facility/tests/test_patient_daily_rounds_api.py +++ b/care/facility/tests/test_patient_daily_rounds_api.py @@ -129,6 +129,24 @@ def test_doctors_log_update(self): ) self.assertEqual(response.status_code, status.HTTP_201_CREATED) + def test_community_nurses_log_update(self): + response = self.client.post( + f"/api/v1/consultation/{self.consultation_with_bed.external_id}/daily_rounds/", + data={ + **self.log_update, + "rounds_type": "COMMUNITY_NURSES_LOG", + "bowel_issue": "NO_DIFFICULTY", + "bladder_drainage": "CONDOM_CATHETER", + "bladder_issue": "NO_ISSUES", + "urination_frequency": "DECREASED", + "sleep": "SATISFACTORY", + "nutrition_route": "ORAL", + "oral_issue": "NO_ISSUE", + "appetite": "INCREASED", + }, + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + def test_invalid_taken_at(self): data = { **self.log_update,