diff --git a/smash/web/api_views/subject.py b/smash/web/api_views/subject.py index 170367b0a5999c0cd91a42329efd0b83f08cf6ab..946b45b25de13468f0322604072b172b1fa9581a 100644 --- a/smash/web/api_views/subject.py +++ b/smash/web/api_views/subject.py @@ -1,11 +1,11 @@ import logging from django.contrib.auth.decorators import login_required -from django.db.models import Count, Case, When, Min +from django.db.models import Count, Case, When, Min, Max from django.db.models import Q from django.http import JsonResponse -from web.models import StudySubject, Visit, Appointment, Subject, SubjectColumns, StudyColumns, Study +from web.models import StudySubject, Visit, Appointment, Subject, SubjectColumns, StudyColumns, Study, ContactAttempt from web.models.constants import SUBJECT_TYPE_CHOICES, GLOBAL_STUDY_ID from web.models.study_subject_list import SUBJECT_LIST_GENERIC, SUBJECT_LIST_NO_VISIT, SUBJECT_LIST_REQUIRE_CONTACT, \ StudySubjectList @@ -51,11 +51,13 @@ def add_column(result, name, field_name, column_list, param, columns_used_in_stu @login_required def get_subject_columns(request, subject_list_type): study = Study.objects.filter(id=GLOBAL_STUDY_ID)[0] - study_subject_list = StudySubjectList.objects.filter(study=study, type=subject_list_type) - if len(study_subject_list) > 0: - subject_columns = study_subject_list[0].visible_subject_columns - study_subject_columns = study_subject_list[0].visible_subject_study_columns + study_subject_lists = StudySubjectList.objects.filter(study=study, type=subject_list_type) + if len(study_subject_lists) > 0: + study_subject_list = study_subject_lists[0] + subject_columns = study_subject_list.visible_subject_columns + study_subject_columns = study_subject_list.visible_subject_study_columns else: + study_subject_list = StudySubjectList() subject_columns = SubjectColumns() study_subject_columns = StudyColumns() @@ -65,6 +67,8 @@ def get_subject_columns(request, subject_list_type): add_column(result, "First name", "first_name", subject_columns, "string_filter") add_column(result, "Last name", "last_name", subject_columns, "string_filter") add_column(result, "Date of birth", "date_born", subject_columns, None) + add_column(result, "Contact on", "datetime_contact_reminder", study_subject_columns, None) + add_column(result, "Last contact attempt", "last_contact_attempt", study_subject_list, None) add_column(result, "Location", "default_location", study_subject_columns, "location_filter", study.columns) add_column(result, "Deceased", "dead", subject_columns, "yes_no_filter") add_column(result, "Resigned", "resigned", study_subject_columns, "yes_no_filter", study.columns) @@ -132,6 +136,12 @@ def get_subjects_order(subjects_to_be_ordered, order_column, order_direction): result = subjects_to_be_ordered.order_by(order_direction + 'id') elif order_column == "date_born": result = subjects_to_be_ordered.order_by(order_direction + 'subject__date_born') + elif order_column == "datetime_contact_reminder": + result = subjects_to_be_ordered.order_by(order_direction + 'datetime_contact_reminder') + elif order_column == "last_contact_attempt": + # noinspection SpellCheckingInspection + result = subjects_to_be_ordered.annotate(sort_contact_attempt=Max("contactattempt__datetime_when")).order_by( + order_direction + 'sort_contact_attempt') elif str(order_column).startswith("visit_"): visit_number = get_visit_number_from_visit_x_string(order_column) result = order_by_visit(subjects_to_be_ordered, order_direction, visit_number) @@ -340,11 +350,24 @@ def serialize_subject(study_subject): "datetime_start": visit.datetime_begin.strftime('%Y-%m-%d'), "datetime_end": visit.datetime_end.strftime('%Y-%m-%d'), }) + contact_reminder = study_subject.datetime_contact_reminder + if contact_reminder is not None: + contact_reminder = contact_reminder.strftime('%Y-%m-%d %H:%M') + contact_attempts = ContactAttempt.objects.filter(subject=study_subject).order_by("-datetime_when") + if len(contact_attempts) > 0: + last_contact_attempt = contact_attempts[0] + last_contact_attempt_string = last_contact_attempt.datetime_when.strftime( + '%Y-%m-%d %H:%M') + "<br/>" + str(last_contact_attempt.worker) + "<br/> Success: " + get_yes_no( + last_contact_attempt.success) + "<br/>" + last_contact_attempt.comment + else: + last_contact_attempt_string = "" result = { "first_name": study_subject.subject.first_name, "last_name": study_subject.subject.last_name, "date_born": study_subject.subject.date_born, + "datetime_contact_reminder": contact_reminder, + "last_contact_attempt": last_contact_attempt_string, "nd_number": study_subject.nd_number, "screening_number": study_subject.screening_number, "default_location": location, diff --git a/smash/web/migrations/0080_auto_20171204_1341.py b/smash/web/migrations/0080_auto_20171204_1341.py new file mode 100644 index 0000000000000000000000000000000000000000..e513330345951900260658d4cd4940c0005d2bed --- /dev/null +++ b/smash/web/migrations/0080_auto_20171204_1341.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-12-04 13:41 +from __future__ import unicode_literals + +from django.db import migrations, models + + +# noinspection PyUnusedLocal +# noinspection PyPep8Naming +def create_default_columns_for_SUBJECT_LIST_REQUIRE_CONTACT(apps, schema_editor): + # We can't import the Study model directly as it may be a newer + # version than this migration expects. We use the historical version. + SubjectColumns = apps.get_model("web", "SubjectColumns") + subject_columns = SubjectColumns.objects.create() + subject_columns.sex = False + subject_columns.first_name = True + subject_columns.last_name = True + subject_columns.languages = False + subject_columns.default_written_communication_language = True + subject_columns.phone_number = False + subject_columns.phone_number_2 = False + subject_columns.phone_number_3 = False + subject_columns.email = False + subject_columns.date_born = False + subject_columns.address = False + subject_columns.postal_code = False + subject_columns.city = False + subject_columns.country = False + subject_columns.dead = False + subject_columns.save() + + StudyColumns = apps.get_model("web", "StudyColumns") + study_columns = StudyColumns.objects.create() + study_columns.postponed = False + study_columns.datetime_contact_reminder = True + study_columns.type = False + study_columns.default_location = False + study_columns.flying_team = False + study_columns.screening_number = False + study_columns.nd_number = False + study_columns.mpower_id = False + study_columns.comments = False + study_columns.referral = False + study_columns.diagnosis = False + study_columns.year_of_diagnosis = False + study_columns.information_sent = False + study_columns.pd_in_family = False + study_columns.resigned = False + study_columns.resign_reason = False + study_columns.save() + + +class Migration(migrations.Migration): + dependencies = [ + ('web', '0079_auto_20171204_1235'), + ] + + operations = [ + migrations.AlterField( + model_name='studycolumns', + name='datetime_contact_reminder', + field=models.BooleanField(choices=[(True, b'Yes'), (False, b'No')], default=True, + verbose_name=b'Last contact attempt'), + ), + migrations.RunSQL('UPDATE web_studycolumns SET datetime_contact_reminder =FALSE WHERE ' + + 'NOT(id IN (SELECT columns_id FROM web_study));'), + + migrations.RunPython(create_default_columns_for_SUBJECT_LIST_REQUIRE_CONTACT), + + migrations.RunSQL('INSERT INTO web_studysubjectlist (' + + 'study_id, ' + + 'visible_subject_study_columns_id, ' + + 'visible_subject_columns_id, ' + + 'type) ' + + "SELECT " + + "1, " + + "max(web_studycolumns.id), " + + "max(web_subjectcolumns.id), " + + "'REQUIRE_CONTACT' FROM web_studycolumns, web_subjectcolumns;"), + ] diff --git a/smash/web/migrations/0081_studysubjectlist_last_contact_attempt.py b/smash/web/migrations/0081_studysubjectlist_last_contact_attempt.py new file mode 100644 index 0000000000000000000000000000000000000000..571ce6737560d8d0f74f5689d790ff29202f8867 --- /dev/null +++ b/smash/web/migrations/0081_studysubjectlist_last_contact_attempt.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-12-04 14:31 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ('web', '0080_auto_20171204_1341'), + ] + + operations = [ + migrations.AddField( + model_name='studysubjectlist', + name='last_contact_attempt', + field=models.BooleanField(default=False, verbose_name=b'Last contact attempt'), + ), + migrations.RunSQL("UPDATE web_studysubjectlist SET last_contact_attempt=TRUE WHERE type='REQUIRE_CONTACT'"), + ] diff --git a/smash/web/models/study_columns.py b/smash/web/models/study_columns.py index 15142bd56913678159e4d92ef53928d0f7440ad0..7700a61be37532167f324d701fd8c771d9aecbe1 100644 --- a/smash/web/models/study_columns.py +++ b/smash/web/models/study_columns.py @@ -77,3 +77,8 @@ class StudyColumns(models.Model): default=True, verbose_name='Resign reason' ) + + datetime_contact_reminder = models.BooleanField(choices=BOOL_CHOICES, + default=True, + verbose_name='Last contact attempt' + ) diff --git a/smash/web/models/study_subject_list.py b/smash/web/models/study_subject_list.py index fae16c14fb03cecdcae5d75adaffcf746c217513..887f7719e46aa3b7951909693ddbbf3465e89840 100644 --- a/smash/web/models/study_subject_list.py +++ b/smash/web/models/study_subject_list.py @@ -36,6 +36,11 @@ class StudySubjectList(models.Model): null=False, ) + last_contact_attempt = models.BooleanField( + default=False, + verbose_name='Last contact attempt' + ) + type = models.CharField(max_length=50, choices=SUBJECT_LIST_CHOICES.items(), verbose_name='Type o list', diff --git a/smash/web/tests/api_views/test_subject.py b/smash/web/tests/api_views/test_subject.py index 7dc320a195db39709542773cd26735e09dfc0cdd..71f3adc756e5c49e2cd25ceba76ad23e3aacdc78 100644 --- a/smash/web/tests/api_views/test_subject.py +++ b/smash/web/tests/api_views/test_subject.py @@ -14,7 +14,7 @@ from web.models.constants import GLOBAL_STUDY_ID from web.models.study_subject_list import SUBJECT_LIST_GENERIC, SUBJECT_LIST_NO_VISIT, SUBJECT_LIST_REQUIRE_CONTACT, \ StudySubjectList from web.tests.functions import create_study_subject, create_worker, create_get_suffix, create_visit, \ - create_appointment, create_empty_study_columns + create_appointment, create_empty_study_columns, create_contact_attempt from web.views.notifications import get_today_midnight_date logger = logging.getLogger(__name__) @@ -57,6 +57,18 @@ class TestApi(TestCase): columns = json.loads(response.content)['columns'] self.assertTrue(len(columns) >= 20) + def test_get_columns_for_require_contact(self): + response = self.client.get( + reverse('web.api.subjects.columns', kwargs={'subject_list_type': SUBJECT_LIST_REQUIRE_CONTACT})) + self.assertEqual(response.status_code, 200) + + columns = json.loads(response.content)['columns'] + visible_columns = 0 + for column in columns: + if column["visible"]: + visible_columns += 1 + self.assertTrue(visible_columns < 20) + def test_get_columns_when_no_list_is_available(self): StudySubjectList.objects.all().delete() response = self.client.get( @@ -179,6 +191,17 @@ class TestApi(TestCase): self.check_subject_ordered("date_born", [subject, subject2]) + def test_subjects_sort_contact_on(self): + subject = self.study_subject + subject.datetime_contact_reminder = get_today_midnight_date() + subject.save() + + subject2 = create_study_subject(2) + subject2.datetime_contact_reminder = get_today_midnight_date() + datetime.timedelta(days=1) + subject2.save() + + self.check_subject_ordered("datetime_contact_reminder", [subject, subject2]) + def test_subjects_sort_default_location(self): subject = self.study_subject @@ -323,6 +346,8 @@ class TestApi(TestCase): def test_serialize_subject(self): study_subject = self.study_subject study_subject.subject.dead = True + create_contact_attempt(subject=study_subject) + create_visit(subject=study_subject) subject_json = serialize_subject(study_subject) self.assertEqual("YES", subject_json["dead"]) @@ -456,3 +481,11 @@ class TestApi(TestCase): def test_invalid_order(self): self.check_subject_ordered(None, [self.study_subject]) + + def test_subjects_ordered_by_contact_attempt(self): + subject = self.study_subject + subject2 = create_study_subject(2) + + create_contact_attempt(subject=subject) + + self.check_subject_ordered("last_contact_attempt", [subject, subject2])