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

V0.3.5.rc1 #458

Merged
merged 21 commits into from
Aug 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
f4b1a02
changes the initial patient load so that it will not be updated by th…
fredkingham Jul 18, 2018
4696ce7
adds munin to the fabfile nginx conf template
fredkingham Jul 18, 2018
ae1812f
Changes the spark lines to be 3 weeks long refs #430
fredkingham Jul 18, 2018
472bb3f
Merge branch '430-3-week-sparklines' into v0.3.5.rc1
fredkingham Jul 19, 2018
b2a8a68
Merge branch 'add-munin-to-the-nginx-conf-deployment' into v0.3.5.rc1
fredkingham Jul 19, 2018
8d2d17d
Merge branch '427-initial-patient-load-update-fix' into v0.3.5.rc1
fredkingham Jul 19, 2018
1c4a22c
adds-in-a-json-view-for-download-lab-test-data
fredkingham Jul 19, 2018
b88b2fa
Merge branch 'load-tests-in-from-json' into v0.3.5.rc1
fredkingham Jul 19, 2018
3c8efdd
fixes the management command to allow the loading in of tests via json
fredkingham Jul 19, 2018
6827a87
make sure we handle numbers with letters in them correctly refs #433
fredkingham Jul 20, 2018
3cbadc9
Merge branch '433-floats-in-obs-results' into v0.3.5.rc1
fredkingham Jul 20, 2018
e22dd29
adds a copy to clipboard to the antimicrobial record panel refs #436
fredkingham Jul 20, 2018
6c352ed
Merge branch '436-copy-to-clipboard-antimicrobials' into v0.3.5.rc1
fredkingham Jul 20, 2018
3a9801b
Merge branch 'load-tests-in-from-json' into v0.3.5.rc1
fredkingham Jul 20, 2018
f4b04ec
adds the antimicrobial header to the copy function
fredkingham Jul 25, 2018
4705038
Merge branch '436-copy-to-clipboard-antimicrobials' into v0.3.5.rc1
fredkingham Jul 25, 2018
df0465c
Merge branch 'v0.3.5' into v0.3.5.rc1
fredkingham Jul 26, 2018
f551424
handles ambiguous timezones
fredkingham Jul 31, 2018
0569d27
Merge branch '454-handle-ambiguous-tz' into v0.3.5.rc1
fredkingham Jul 31, 2018
c5bd4c7
If the hospital number changes, make sure the world does not fall ove…
fredkingham Aug 1, 2018
732c133
Merge branch '456-changed-hospital-number' into v0.3.5.rc1
fredkingham Aug 1, 2018
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: 5 additions & 12 deletions elcid/api.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import datetime
import re
from operator import itemgetter
from collections import defaultdict
from django.conf import settings
from django.utils.text import slugify
from django.http import HttpResponseBadRequest
from django.db.models import Q
from intrahospital_api import loader
from rest_framework import viewsets
from opal.core.api import OPALRouter
from opal.core.api import patient_from_pk, LoginRequiredViewset
from opal.core.views import json_response
from opal.core import serialization
from elcid import models as emodels
from lab import models as lmodels
from elcid.utils import timing
from opal import models as omodels


_LAB_TEST_TAGS = {
Expand Down Expand Up @@ -67,16 +65,11 @@ def extract_observation_value(observation_value):
if its >12 return >12
else return None
"""
obs_result = observation_value.split("~")[0]
try:
# we return None if its not numeric
regex = r'^[0-9][0-9.]*$'
obs_result = observation_value.strip()
obs_result = obs_result.split("~")[0].strip("<").strip(">").strip()
if re.match(regex, obs_result):
return float(obs_result)
except ValueError:
try:
float(obs_result.strip("<").strip(">").strip())
return obs_result
except ValueError:
return None


def get_observation_value(observation):
Expand Down
22 changes: 20 additions & 2 deletions elcid/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.db import models
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.utils import timezone
from lab import models as lmodels
import opal.models as omodels

Expand Down Expand Up @@ -132,6 +134,22 @@ def update_from_dict(self, data, *args, **kwargs):
"""
pass

def set_datetime_ordered(self, value, *args, **kwargs):
if value is None:
self.datetime_ordered = None
elif isinstance(value, datetime.datetime):
self.datetime_ordered = value
else:
input_format = settings.DATETIME_INPUT_FORMATS[0]

# never use DST, if we're an hour back, we're an hour back
with_tz = timezone.make_aware(
datetime.datetime.strptime(value, input_format),
timezone.get_current_timezone(),
is_dst=False
)
self.datetime_ordered = with_tz

def update_from_api_dict(self, patient, data, user):
"""
This is the updateFromDict of the the UpstreamLabTest
Expand Down Expand Up @@ -221,10 +239,10 @@ def get_relevant_tests(self, patient):
"GENTAMICIN LEVEL",
"CLOTTING SCREEN"
]
six_months_ago = datetime.date.today() - datetime.timedelta(6*30)
three_weeks_ago = timezone.now() - datetime.timedelta(3*7)
qs = UpstreamLabTest.objects.filter(
patient=patient,
datetime_ordered__gt=six_months_ago
datetime_ordered__gt=three_weeks_ago
).order_by("datetime_ordered")
return [i for i in qs if i.extras.get("test_name") in relevent_tests]

Expand Down
2 changes: 1 addition & 1 deletion elcid/templates/detail/inpatient.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
</div>

{% record_panel models.Line %}
{% record_panel models.Antimicrobial %}
{% include "partials/antimicrobial_panel.html" %}
{% record_panel models.Imaging %}
{% include "partials/blood_culture_result_display.html" %}
{% if permissions.view_lab_test_trends %}
Expand Down
31 changes: 31 additions & 0 deletions elcid/templates/partials/antimicrobial_panel.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{% with name=models.Antimicrobial.get_api_name %}
<div ng-repeat="parent in [episode]">
<div class="panel panel-default record-panel antimicrobial-panel">
<div class="panel-heading">
<h3>
<i class="{{ models.Antimicrobial.get_icon }}"></i> {{ models.Antimicrobial.get_display_name }}
<span>
<i class="fa fa-plus-circle edit pull-right pointer"
ng-click="parent.recordEditor.newItem('{{ name }}')"></i>
<i ng-show="parent.{{ name }}.length" class="fa fa-clipboard edit pull-right pointer" clipboard data-clipboard-target=".antimicrobial-panel"></i>
</span>
</h3>
</div>
<ul class="list-group">
<li class="list-group-item" ng-repeat="item in parent.{{ name }}">
<div class="row">
<div class="col-md-9">
{% include models.Antimicrobial.get_display_template %}
</div>
<div class="col-md-3">
<span>
<i class="fa fa-pencil edit pull-right pointer"
ng-click="parent.recordEditor.editItem('{{ name }}', $index)"></i>
</span>
</div>
</div>
</li>
</ul>
</div>
</div>
{% endwith %}
2 changes: 1 addition & 1 deletion elcid/templates/partials/lab_test_sparklines.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ <h2 class="text-center no-results">No results found</h2>
[[ date | shortDate ]]
</th>
<th class="text-center">
3 month trend
3 week trend
</th>
</tr>
</thead>
Expand Down
18 changes: 18 additions & 0 deletions elcid/test/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,27 @@
BloodCultureResultApi, UpstreamBloodCultureApi
)
from elcid import models as emodels
from elcid import api
from django.test import override_settings


class ExtractObservationValueTestCase(OpalTestCase):
def test_extract_observation_value(self):
inputs_to_expected_results = (
("<1", float(1),),
("1>", float(1),),
(" 1 ", float(1),),
("< 1", float(1),),
(" < 1", float(1),),
(".1 ", None),
("0.1 ", 0.1),
("1E", None),
("'1'", None),
)
for input, expected in inputs_to_expected_results:
self.assertEqual(api.extract_observation_value(input), expected)


class UpstreamBloodCultureApiTestCase(OpalTestCase):
def setUp(self):
self.api = UpstreamBloodCultureApi()
Expand Down
91 changes: 90 additions & 1 deletion elcid/test/test_models.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import datetime

from django.test import TestCase
from django.utils import timezone
from django.contrib.contenttypes.models import ContentType
from django.utils import timezone
from django.conf import settings

from opal.core import exceptions
from opal.core.test import OpalTestCase
Expand Down Expand Up @@ -325,6 +327,42 @@ def test_update_from_api_dict_repeated(self):
found_hl7_result.status, emodels.UpstreamLabTest.COMPLETE
)

def test_set_datetime_ordered_none(self):
lab_test = emodels.UpstreamLabTest(patient=self.patient)
lab_test.datetime_ordered = timezone.now()
lab_test.set_datetime_ordered(None)
self.assertIsNone(lab_test.datetime_ordered)

def test_set_datetime_ordered_datetime(self):
lab_test = emodels.UpstreamLabTest(patient=self.patient)
now = timezone.now()
lab_test.set_datetime_ordered(now)
self.assertEqual(
lab_test.datetime_ordered, now
)

def test_set_datetime_ordered_string(self):
lab_test = emodels.UpstreamLabTest(patient=self.patient)
date_str = "29/10/2017 10:00:00"
lab_test.set_datetime_ordered(date_str)
dt = datetime.datetime(2017, 10, 29, 10, 0)
dt = timezone.make_aware(dt)
self.assertEqual(
lab_test.datetime_ordered,
dt
)

def test_set_datetime_ordered_dst(self):
lab_test = emodels.UpstreamLabTest(patient=self.patient)
date_str = "29/10/2017 1:00:00"
lab_test.set_datetime_ordered(date_str)
as_str = lab_test.datetime_ordered.strftime(
settings.DATETIME_INPUT_FORMATS[0]
)
self.assertEqual(
as_str, "29/10/2017 01:00:00"
)

def test_update_from_api_dict_first_time(self):
update_dict = dict(
external_identifier="1",
Expand Down Expand Up @@ -364,6 +402,57 @@ def test_update_from_dict(self):
# validate that is hasn't been saved
self.assertIsNone(hl7_result.id)

def test_get_relevant_tests(self):
patient, _ = self.new_patient_and_episode_please()
upstream_lab_test = emodels.UpstreamLabTest(patient=patient)
yesterday = timezone.now() - datetime.timedelta(
1
)
upstream_lab_test.datetime_ordered = yesterday
upstream_lab_test.extras = dict(test_name="C REACTIVE PROTEIN")
upstream_lab_test.save()

relevant = emodels.UpstreamLabTest.get_relevant_tests(patient)
self.assertEqual(
len(relevant), 1
)
self.assertEqual(
relevant[0].datetime_ordered, yesterday
)
self.assertEqual(
relevant[0].extras["test_name"], "C REACTIVE PROTEIN"
)

def test_get_relevant_tests_over_three_weeks(self):
patient, _ = self.new_patient_and_episode_please()
upstream_lab_test = emodels.UpstreamLabTest(patient=patient)
four_weeks_ago = timezone.now() - datetime.timedelta(
4 * 7
)
upstream_lab_test.datetime_ordered = four_weeks_ago
upstream_lab_test.extras = dict(test_name="C REACTIVE PROTEIN")
upstream_lab_test.save()

relevant = emodels.UpstreamLabTest.get_relevant_tests(patient)
self.assertEqual(
len(relevant), 0
)

def test_get_not_relevant_tests(self):
patient, _ = self.new_patient_and_episode_please()
upstream_lab_test = emodels.UpstreamLabTest(patient=patient)
yesterday = timezone.now() - datetime.timedelta(
1
)
upstream_lab_test.datetime_ordered = yesterday
upstream_lab_test.extras = dict(test_name="SOME OTHER TEST")
upstream_lab_test.save()

relevant = emodels.UpstreamLabTest.get_relevant_tests(patient)
self.assertEqual(
len(relevant), 0
)


class DiagnosisTest(OpalTestCase, AbstractEpisodeTestCase):

Expand Down
6 changes: 5 additions & 1 deletion etc/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ server {
server_name elcid-rfh-test.openhealthcare.org.uk;
access_log /usr/lib/ohc/log/nginx.log timed_combined;

location /static {
location /himunin {
alias /var/cache/munin/www;
}

location /static {
alias /var/www/media/static;
}

Expand Down
14 changes: 14 additions & 0 deletions intrahospital_api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from opal.core import subrecords
from lab import models as lmodels
from elcid.episode_serialization import serialize
from intrahospital_api import get_api


def patient_to_dict(patient, user):
Expand Down Expand Up @@ -49,6 +50,19 @@ def patient_to_dict(patient, user):
return d


class UpstreamDataViewset(viewsets.ViewSet):
base_name = 'upstream'
permission_classes = (IsAuthenticated,)

def retrieve(self, request, pk=None):
patient = get_object_or_404(
omodels.Patient.objects.all(), pk=pk
)
api = get_api()
hospital_number = patient.demographics_set.first().hospital_number
return json_response(api.results_for_hospital_number(hospital_number))


class PatientViewSet(viewsets.ViewSet):
base_name = 'patient'
permission_classes = (IsAuthenticated,)
Expand Down
21 changes: 12 additions & 9 deletions intrahospital_api/management/commands/load_tests_from_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,20 @@
"""
import json
from django.core.management.base import BaseCommand
from django.contrib.auth.models import User
from django.db import transaction
from opal import models
from elcid import models as emodels
from lab import models as lmodels
from intrahospital_api import loader
from intrahospital_api import update_lab_tests


class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument('patient_id', type=int)
parser.add_argument('file_name', type=str)

def handle(self, patient_id, file_name, *args, **options):
# we assume that there is a user called super
# which there won't be on prod, but we shouldn't
# be running this on prod
user = User.objects.get(username="super")
patient = models.Patient.objects.get(id=patient_id)
@transaction.atomic
def process(self, patient, results):
lmodels.LabTest.objects.filter(
patient=patient
).filter(
Expand All @@ -30,7 +26,14 @@ def handle(self, patient_id, file_name, *args, **options):
emodels.UpstreamBloodCulture.get_display_name(),
]
).delete()
update_lab_tests.update_tests(patient, results)

def handle(self, patient_id, file_name, *args, **options):
# we assume that there is a user called super
# which there won't be on prod, but we shouldn't
# be running this on prod
with open(file_name) as f:
results = json.load(f)
loader.save_lab_tests(patient, results, user)
patient = models.Patient.objects.get(id=patient_id)
self.process(patient, results)
print "success"
7 changes: 6 additions & 1 deletion intrahospital_api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class Meta:


class InitialPatientLoad(PatientLoad, PatientSubrecord):
""" this model is the initial load of a patient
""" This model is the initial load of a patient
future loads are done by the cron batch load
"""

Expand All @@ -96,6 +96,11 @@ def __unicode__(self):
self.started
)

def update_from_dict(self, data, *args, **kwargs):
""" For the purposes of the front end this model is read only.
"""
pass


class BatchPatientLoad(PatientLoad):
""" This is the batch load of all reconciled patients
Expand Down
5 changes: 4 additions & 1 deletion intrahospital_api/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ class IntraHospitalApiPlugin(plugins.OpalPlugin):
'js/intrahospital_api/services/initial_patient_lab_load_status.js'
]
}
apis = [("patient", api.PatientViewSet,)]
apis = [
("patient", api.PatientViewSet,),
("upstream", api.UpstreamDataViewset,)
]
Loading