Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple referrals #353

Open
wants to merge 27 commits into
base: multiple-episodes-branch
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
07d25b0
Remove the field employment from the referral
May 16, 2022
1904150
Changes employment into a singleton and removers the ability to edit …
May 16, 2022
6e0eb2a
Renames summary to referrals
May 16, 2022
b424b2a
Iterate over different episodes as different referrals in the UI unde…
May 16, 2022
c39fc7d
Adds in a custom javascript controller to order the referrals by the …
May 17, 2022
3869adc
Adds a migration to make a new episodes from patients with multiple r…
May 17, 2022
1aa2a1b
Only show the clinic information if there is any clinic information t…
May 17, 2022
6c22fe8
Adds the ability to delete an episode
May 17, 2022
9721dac
Do not show the delete button if there is only a single referral
May 17, 2022
3508727
Show the full name of the patient in the delete episode modal
May 17, 2022
4ca2b7e
Fix the cancel button on the delete episode modal, and fix the error …
May 17, 2022
50c4f8c
Adds in the add episode (or add referral) flow
May 17, 2022
028e440
Change referrals to be a singleton
May 17, 2022
4017e12
Merge branch 'v1.30' into multiple-referrals
May 17, 2022
861af8f
the create singletons signals do not fire in the migrations when we c…
May 17, 2022
4be56f8
Fixes the word casing in the add episode/delete episode modals
May 18, 2022
4fc0cfb
Invert the order of the referrals so the first one would be 3/3 and s…
May 18, 2022
7c3b106
Shrink the referral bar and make the buttons look like the links in t…
May 18, 2022
94b8252
Adds a missing migration to rbhl that changes the choice 'no relevant…
May 18, 2022
9587bf4
Adds consistency tokens to singletons that have been imported via imp…
May 18, 2022
b955cd2
Add a full list of everything that will be deleted when you delete a …
May 18, 2022
3d6c077
After we create an episode, open the edit item modal
May 18, 2022
e90fc35
switch the order of the add referral/delete referral buttons
May 18, 2022
3d79585
Fix up the lab views to work correctly with the reference to employme…
May 18, 2022
dccdaf6
if they patient does not have any tests make sure we don't fail when …
May 27, 2022
13f23db
Make the add clinic data button small
May 27, 2022
0b5b8a7
change the multiple episode load to use multiple referral dates when …
May 27, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions plugins/lab/migrations/0016_remove_bloods_employment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 2.2.16 on 2022-05-16 13:29

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
('rbhl', '0063_create_multiple_episodes'),
('lab', '0015_auto_20220511_1354'),
]

operations = [
migrations.RemoveField(
model_name='bloods',
name='employment',
),
]
6 changes: 2 additions & 4 deletions plugins/lab/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,8 @@ class Bloods(RbhlSubrecord, models.PatientSubrecord):
blood_date = fields.DateField(
blank=True, null=True, verbose_name="Sample received"
)
blood_number = fields.CharField(blank=True, null=True,
max_length=200)
employment = fields.ForeignKey(
"rbhl.Employment", blank=True, null=True, on_delete=fields.SET_NULL
blood_number = fields.CharField(
blank=True, null=True, max_length=200
)
referral = fields.ForeignKey(
"rbhl.Referral", blank=True, null=True, on_delete=fields.SET_NULL
Expand Down
19 changes: 1 addition & 18 deletions plugins/lab/static/js/lab/controllers/bloods.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ angular.module('opal.controllers').controller(
var init = function(){
var bloodTest;
scope.bloodTest = null;
scope.patient_id = scope.episode.demographics[0].patient_id;
var id = $location.search().id;
if(!id){
bloodTest = {};
Expand All @@ -22,24 +23,6 @@ angular.module('opal.controllers').controller(
scope.bloodTest = {bloods: bloodTest};
}

scope.employment_display = function(employment){
/*
* Options do not allow if statements so we format the display
* name of the employment in here.
*/
var result;
if(employment.employer && employment.oh_provider){
result = employment.employer + "/" + employment.oh_provider;
}
else{
result = employment.employer || employment.oh_provider;
}
if(employment.job_title){
result += " (" + employment.job_title + ")";
}
return result;
}

scope.referral_display = function(referral){
/*
* Options do not allow if statements so we format the display
Expand Down
4 changes: 2 additions & 2 deletions plugins/lab/templates/lab_report.html
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
Employer:
</div>
<div class="col-xs-7 col-md-9">
{{ object.employment.employer }}
{{ object.referral.episode.employment_set.get.employer }}
</div>
</div>
</div>
Expand All @@ -97,7 +97,7 @@
OH Provider:
</div>
<div class="col-xs-7 col-md-9">
{{ object.employment.oh_provider }}
{{ object.referral.episode.employment_set.get.oh_provider }}
</div>
</div>
</div>
Expand Down
22 changes: 3 additions & 19 deletions plugins/lab/templates/pathway/bloods_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,6 @@
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="horizontal-form">
<label class="control-label">
Employment
</label>
<select name="bloods_employment" class="form-control" ng-model="editing.bloods.employment_id" convert-to-number>
<option value="">---------</option>
<option value="[[ i.id ]]" ng-if="employment_display(i)" ng-repeat="i in episode.employment">
[[ employment_display(i) ]]
</option>
</select>
<span class="help-block">
Or <a class="pointer" ng-click="addSubrecord('employment')">add a new employment</a>
</span>
</div>
</div>
<div class="col-md-6">
<div class="horizontal-form">
<label class="control-label">
Expand All @@ -43,17 +27,17 @@
</option>
</select>
<span class="help-block">
Or <a class="pointer" ng-click="addSubrecord('referral')">add a new referral</a>
Or <a class="pointer" href="/#/patient/[[ patient_id ]]/">add a new referral</a>
</span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="horizontal-form">
{% datepicker field="Bloods.blood_date" style="vertical" %}
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="horizontal-form">
{% checkbox field="Bloods.store" style="vertical" %}
Expand Down
14 changes: 9 additions & 5 deletions plugins/lab/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,10 @@ def get_requests_by_oh_provider(self):
if blood.blood_number in blood_nums_seen:
continue
blood_nums_seen.add(blood.blood_number)
employment = blood.employment
employment = None
employer_referrer = None
if blood.referral:
employment = blood.referral.episode.employment_set.all()[0]
if employment and employment.employer and employment.oh_provider:
employer_referrer = "{}/{}".format(
employment.employer, employment.oh_provider
Expand Down Expand Up @@ -384,16 +386,18 @@ def get_rows(self, month, year):
bloods = Bloods.objects.filter(blood_date__month=month).filter(
blood_date__year=year
).select_related(
"employment", "referral"
"referral"
).prefetch_related(
'patient__demographics_set'
'patient__demographics_set',
'referral__episode__employment_set'
).order_by("blood_date")
result = []
for blood in bloods:
patient_id = blood.patient_id
episode_id = blood.patient.episode_set.last().id
employment = blood.employment
employer = "No employer"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we still want this?

employment = None
if blood.referral:
employment = blood.referral.episode.employment_set.all()[0]
oh_provider = "No OH provider"
if employment and employment.employer:
employer = employment.employer
Expand Down
3 changes: 3 additions & 0 deletions rbhl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ class Application(application.OpalApplication):
'js/rbhl/services/demographics_search_lookup.js',
'js/rbhl/controllers/peak_flow_step.js',
'js/rbhl/controllers/delete_patient.js',
'js/rbhl/controllers/delete_episode.js',
'js/rbhl/controllers/add_occld_episode.js',
'js/rbhl/controllers/occld_helper.js',
]
styles = [
'css/rbhl.css'
Expand Down
25 changes: 24 additions & 1 deletion rbhl/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@
API endpoints for RBHL
"""
from collections import defaultdict
from django.shortcuts import get_object_or_404
from rest_framework import status
import itertools
from decimal import Decimal
from opal.core.views import json_response
from opal.core.api import (
LoginRequiredViewset, episode_from_pk, patient_from_pk
)
from rbhl import models
from rbhl import models, episode_categories
from opal.core.api import OPALRouter
from opal import models as opal_models


def get_ranges(numbers):
Expand Down Expand Up @@ -160,6 +162,27 @@ def destroy(self, request, patient):
return json_response('deleted', status_code=status.HTTP_202_ACCEPTED)


class OCCLDEpisodeViewset(LoginRequiredViewset):
basename = "occld_episode"

@episode_from_pk
def destroy(self, _, episode):
episode.delete()
return json_response('deleted', status_code=status.HTTP_202_ACCEPTED)

def create(self, request, *args, **kwargs):
patient_id = request.data.get('patient_id')
patient = get_object_or_404(opal_models.Patient, id=patient_id)
created_episode = patient.episode_set.create(
category_name=episode_categories.OccupationalLungDiseaseEpisode.display_name
)
return json_response(
{"id": created_episode.id},
status_code=status.HTTP_201_CREATED
)


indigo_router = OPALRouter()
indigo_router.register(PeakFlowGraphData.basename, PeakFlowGraphData)
indigo_router.register(DeletePatientViewset.basename, DeletePatientViewset)
indigo_router.register(OCCLDEpisodeViewset.basename, OCCLDEpisodeViewset)
1 change: 1 addition & 0 deletions rbhl/migrations/0062_cliniclog_sword.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class Migration(migrations.Migration):

dependencies = [
('rbhl', '0061_auto_20220509_1240'),

]

operations = [
Expand Down
135 changes: 135 additions & 0 deletions rbhl/migrations/0063_create_multiple_episodes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# Generated by Django 2.2.16 on 2022-05-16 16:43

from django.db import migrations
from django.db.models import Count
from django.core import management



# Generated by Django 2.2.16 on 2021-11-26 13:50

from django.db import migrations


def get_episode_ids_with_duplicate_referrals(Episode):
"""
Returns episode ids of patients that seem to have
duplicate referrals because they have the same
date of referral or date of first appointment.
"""
result = set()
multiple_referral_episodes = Episode.objects.annotate(cnt=Count('referral')).filter(cnt__gt=1)
multiple_referral_episodes = multiple_referral_episodes.prefetch_related('referral_set')
for episode in multiple_referral_episodes:
referrals = episode.referral_set.all()
referral_dates = [i.date_of_referral for i in referrals if i.date_of_referral]
if referral_dates and not len(referral_dates) == len(set(referral_dates)):
result.add(episode.id)
else:
dates_of_first_clinic = [
i.date_first_appointment for i in referrals if i.date_first_appointment
]
if dates_of_first_clinic:
if not len(dates_of_first_clinic) == len(set(dates_of_first_clinic)):
result.add(episode.id)
return result


def get_closest_referral(episode):
"""
Returns the closest referral within a year before the clinic date
"""
referrals = episode.referral_set.all()
clinic_log = episode.cliniclog_set.all()[0]
if not clinic_log.clinic_date:
return
referrals_with_dates = [
i for i in referrals if i.date_of_referral if i.date_of_referral
]
closest = None
closest_diff = None
for referral in referrals_with_dates:
if not referral.date_of_referral:
continue
if referral.date_of_referral > clinic_log.clinic_date:
continue
days_diff = (clinic_log.clinic_date - referral.date_of_referral).days
if days_diff > 365:
continue
if not closest:
closest = referral
closest_diff = days_diff
elif closest_diff > days_diff:
closest = referral
closest_diff = days_diff
return closest


def create_episode_from_referral(patient, referral):
episode = patient.episode_set.create()
bloods = referral.bloods_set.all()
referral.episode = episode
referral.save()
if bloods:
for blood in bloods:
if blood.employment:
employment = blood.employment
employment.episode = episode
employment.save()


def create_episodes(episode):
"""
If there is no clinic log date then this is a sign that its
a patient who has only been seen by the lab. Create an episode
for each referral after the initial.

If there is a clinic log date then create episides for all
referrals apart from the one closest the clinic log date.

Otherwise create an episode for each referral after the initial
"""
clinic_log = episode.cliniclog_set.all()[0]

if not clinic_log.clinic_date:
referrals_that_need_episodes = list(episode.referral_set.all())[1:]
else:
closest_referral = get_closest_referral(episode)
if closest_referral:
referrals_that_need_episodes = [
i for i in episode.referral_set.all() if not i.id == closest_referral.id
]
else:
referrals_that_need_episodes = list(episode.referral_set.all())[1:]
for referral in referrals_that_need_episodes:
create_episode_from_referral(episode.patient, referral)


def forwards(apps, schema_editor):
Episode = apps.get_model('opal', 'Episode')
episodes_with_duplicate_referrals = get_episode_ids_with_duplicate_referrals(Episode)
episodes_with_multiple_referrals = Episode.objects.annotate(
cnt=Count('referral')
).filter(
cnt__gt=1
).exclude(
id__in=episodes_with_duplicate_referrals
).prefetch_related(
'referral_set', 'cliniclog_set'
)
for episode in episodes_with_multiple_referrals:
create_episodes(episode)
management.call_command('create_singletons')


class Migration(migrations.Migration):
dependencies = [
('rbhl', '0062_cliniclog_sword'),
]


operations = [
migrations.RunPython(
forwards
)
]
18 changes: 18 additions & 0 deletions rbhl/migrations/0064_auto_20220518_1141.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 2.2.16 on 2022-05-18 11:41
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this migration from something else?


from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('rbhl', '0063_create_multiple_episodes'),
]

operations = [
migrations.AlterField(
model_name='cliniclog',
name='sword',
field=models.CharField(blank=True, choices=[('Not relevant', 'Not relevant'), ('Needs to be reported', 'Needs to be reported'), ('Reported', 'Reported')], max_length=256, null=True, verbose_name='SWORD'),
),
]
Loading