From 6d8b017ebb5582a9e5a38bca3b362f67378666ea Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Tue, 5 Dec 2017 18:43:42 +0100 Subject: [PATCH] appointment types are available in visit list but no sorting filtering is possible --- smash/web/api_views/visit.py | 33 ++++++- .../web/migrations/0084_auto_20171205_1640.py | 52 +++++++++++ .../web/migrations/0085_auto_20171205_1650.py | 92 +++++++++++++++++++ smash/web/models/study_subject_list.py | 2 +- smash/web/models/study_visit_list.py | 18 +++- smash/web/models/visit_columns.py | 3 + smash/web/tests/api_views/test_visit.py | 7 ++ 7 files changed, 204 insertions(+), 3 deletions(-) create mode 100644 smash/web/migrations/0084_auto_20171205_1640.py create mode 100644 smash/web/migrations/0085_auto_20171205_1650.py diff --git a/smash/web/api_views/visit.py b/smash/web/api_views/visit.py index 00251938..06ecbaae 100644 --- a/smash/web/api_views/visit.py +++ b/smash/web/api_views/visit.py @@ -1,9 +1,11 @@ import logging from django.contrib.auth.decorators import login_required +from django.db.models import Q from django.http import JsonResponse from web.api_views.serialization_utils import bool_to_yes_no, flying_team_to_str, location_to_str +from web.models import AppointmentType, Appointment from web.models import SubjectColumns from web.models import Visit, Study, VisitColumns, StudyVisitList, StudyColumns from web.models.constants import GLOBAL_STUDY_ID @@ -44,7 +46,7 @@ def get_visit_columns(request, visit_list_type): visit_list = study_visit_lists[0] visit_columns = visit_list.visible_visit_columns visit_subject_columns = visit_list.visible_subject_columns - visit_subject_study_columns = visit_list.visible_subject_study_columns + visit_subject_study_columns = visit_list.visible_study_subject_columns else: visit_list = StudyVisitList() visit_columns = VisitColumns() @@ -63,6 +65,12 @@ def get_visit_columns(request, visit_list_type): add_column(result, "Finished", "is_finished", visit_columns, "yes_no_filter") add_column(result, "Post mail sent", "post_mail_sent", visit_columns, "yes_no_filter") add_column(result, "Visit number", "visit_number", visit_columns, "integer_filter") + add_column(result, "Appointments in progress", "visible_appointment_types_in_progress", visit_list, + "appointment_type_filter") + add_column(result, "Done appointments", "visible_appointment_types_done", visit_list, "appointment_type_filter") + add_column(result, "Missing appointments", "visible_appointment_types_missing", visit_list, + "appointment_type_filter") + add_column(result, "All appointments", "visible_appointment_types", visit_columns, "appointment_type_filter") add_column(result, "Edit", "edit", None, None) return JsonResponse({"columns": result}) @@ -189,10 +197,29 @@ def visits(request, visit_list_type): }) +def appointment_types_to_str(appointment_types): + result = "" + for appointment_type in appointment_types: + result += unicode(appointment_type.code) + ", " + return result + + def serialize_visit(visit): datetime_begin = serialize_date(visit.datetime_begin) datetime_end = serialize_date(visit.datetime_end) + appointment_types = visit.appointment_types.all() + appointment_types_in_progress = AppointmentType.objects.filter(Q(appointmenttypelink__appointment__visit=visit) & Q( + appointmenttypelink__appointment__status=Appointment.APPOINTMENT_STATUS_SCHEDULED)).distinct().all() + appointment_types_done = AppointmentType.objects.filter(Q(appointmenttypelink__appointment__visit=visit) & Q( + appointmenttypelink__appointment__status=Appointment.APPOINTMENT_STATUS_FINISHED)).distinct().all() + + appointment_types_missing = [] + for appointment_type in appointment_types: + if appointment_types_in_progress.filter(id=appointment_type.id).count() == 0 and appointment_types_done.filter( + id=appointment_type.id).count() == 0: + appointment_types_missing.append(appointment_type) + result = { "first_name": visit.subject.subject.first_name, "last_name": visit.subject.subject.last_name, @@ -204,6 +231,10 @@ def serialize_visit(visit): "post_mail_sent": bool_to_yes_no(visit.post_mail_sent), "visit_number": visit.visit_number, "id": visit.id, + "visible_appointment_types_in_progress": appointment_types_to_str(appointment_types_in_progress), + "visible_appointment_types_done": appointment_types_to_str(appointment_types_done), + "visible_appointment_types_missing": appointment_types_to_str(appointment_types_missing), + "visible_appointment_types": appointment_types_to_str(appointment_types), } return result diff --git a/smash/web/migrations/0084_auto_20171205_1640.py b/smash/web/migrations/0084_auto_20171205_1640.py new file mode 100644 index 00000000..10e2c9e1 --- /dev/null +++ b/smash/web/migrations/0084_auto_20171205_1640.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-12-05 16:40 +from __future__ import unicode_literals + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ('web', '0083_auto_20171205_1251'), + ] + + operations = [ + migrations.AddField( + model_name='studyvisitlist', + name='visible_appointment_types_done', + field=models.BooleanField(default=False, verbose_name=b'Done appointments'), + ), + migrations.AddField( + model_name='studyvisitlist', + name='visible_appointment_types_in_progress', + field=models.BooleanField(default=False, verbose_name=b'Appointments in progress'), + ), + migrations.AddField( + model_name='studyvisitlist', + name='visible_appointment_types_missing', + field=models.BooleanField(default=False, verbose_name=b'Missing appointments'), + ), + migrations.AddField( + model_name='studyvisitlist', + name='visible_study_subject_columns', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='web.StudyColumns'), + preserve_default=False, + ), + migrations.AddField( + model_name='visitcolumns', + name='visible_appointment_types', + field=models.BooleanField(default=False, verbose_name=b'All appointments'), + ), + migrations.AlterField( + model_name='studyvisitlist', + name='type', + field=models.CharField(choices=[(b'UNFINISHED', b'unfinished visits'), + (b'APPROACHING_WITHOUT_APPOINTMENTS', b'approaching visits'), + (b'APPROACHING_FOR_MAIL_CONTACT', b'post mail for approaching visits'), + (b'GENERIC', b'Generic'), + (b'MISSING_APPOINTMENTS', b'visits with missing appointments'), + (b'EXCEEDED_TIME', b'exceeded visit time')], max_length=50, + verbose_name=b'Type of list'), + ), + ] diff --git a/smash/web/migrations/0085_auto_20171205_1650.py b/smash/web/migrations/0085_auto_20171205_1650.py new file mode 100644 index 00000000..2ffcafec --- /dev/null +++ b/smash/web/migrations/0085_auto_20171205_1650.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-12-05 16:50 +from __future__ import unicode_literals + +from django.db import migrations, models + +# noinspection PyUnusedLocal +# noinspection PyPep8Naming +def create_default_columns_for_VISIT_LIST_EXCEEDED_TIME(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 = False + 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 = False + study_columns.type = False + study_columns.default_location = True + study_columns.flying_team = True + 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() + + VisitColumns = apps.get_model("web", "VisitColumns") + visit_columns = VisitColumns.objects.create() + visit_columns.datetime_begin = False + visit_columns.datetime_end = True + visit_columns.is_finished = False + visit_columns.post_mail_sent = False + visit_columns.visit_number = True + visit_columns.visible_appointment_types = False + visit_columns.save() + +class Migration(migrations.Migration): + + dependencies = [ + ('web', '0084_auto_20171205_1640'), + ] + + operations = [ + migrations.AlterField( + model_name='studysubjectlist', + name='type', + field=models.CharField(blank=True, choices=[(b'GENERIC', b'Generic'), (b'NO_VISIT', b'Subjects without visit'), (b'REQUIRE_CONTACT', b'Subjects required contact')], max_length=50, null=True, verbose_name=b'Type of list'), + ), + migrations.RunPython(create_default_columns_for_VISIT_LIST_EXCEEDED_TIME), + migrations.RunSQL('INSERT INTO web_studyvisitlist (' + + 'study_id, ' + + 'visible_visit_columns_id, ' + + 'visible_subject_columns_id, ' + + 'visible_study_subject_columns_id, ' + + 'visible_appointment_types_done,' + 'visible_appointment_types_in_progress,' + 'visible_appointment_types_missing,' + 'type) ' + + "SELECT " + + "1, " + + "max(web_visitcolumns.id), " + + "max(web_subjectcolumns.id), " + + "max(web_studycolumns.id), " + + "TRUE, " + + "TRUE, " + + "TRUE, " + + "'EXCEEDED_TIME' FROM web_visitcolumns, web_studycolumns, web_subjectcolumns;"), + ] diff --git a/smash/web/models/study_subject_list.py b/smash/web/models/study_subject_list.py index 1b09054f..cd2f5bbb 100644 --- a/smash/web/models/study_subject_list.py +++ b/smash/web/models/study_subject_list.py @@ -48,7 +48,7 @@ class StudySubjectList(models.Model): type = models.CharField(max_length=50, choices=SUBJECT_LIST_CHOICES.items(), - verbose_name='Type o list', + verbose_name='Type of list', null=True, blank=True ) diff --git a/smash/web/models/study_visit_list.py b/smash/web/models/study_visit_list.py index 10c1bf85..e16c334e 100644 --- a/smash/web/models/study_visit_list.py +++ b/smash/web/models/study_visit_list.py @@ -2,6 +2,7 @@ from django.db import models from web.models import Study, SubjectColumns, VisitColumns +from web.models import StudyColumns VISIT_LIST_GENERIC = "GENERIC" VISIT_LIST_EXCEEDED_TIME = "EXCEEDED_TIME" @@ -41,8 +42,23 @@ class StudyVisitList(models.Model): on_delete=models.CASCADE, null=False, ) + visible_study_subject_columns = models.ForeignKey( + StudyColumns, + on_delete=models.CASCADE, + null=False, + ) + + visible_appointment_types_in_progress = models.BooleanField(default=False, + verbose_name='Appointments in progress' + ) + visible_appointment_types_done = models.BooleanField(default=False, + verbose_name='Done appointments' + ) + visible_appointment_types_missing = models.BooleanField(default=False, + verbose_name='Missing appointments' + ) type = models.CharField(max_length=50, choices=VISIT_LIST_CHOICES.items(), - verbose_name='Type o list', + verbose_name='Type of list', ) diff --git a/smash/web/models/visit_columns.py b/smash/web/models/visit_columns.py index 06958709..6984c6de 100644 --- a/smash/web/models/visit_columns.py +++ b/smash/web/models/visit_columns.py @@ -32,3 +32,6 @@ class VisitColumns(models.Model): verbose_name='Visit number', default=True ) + visible_appointment_types = models.BooleanField(default=False, + verbose_name='All appointments' + ) diff --git a/smash/web/tests/api_views/test_visit.py b/smash/web/tests/api_views/test_visit.py index 63049c96..c77c67ae 100644 --- a/smash/web/tests/api_views/test_visit.py +++ b/smash/web/tests/api_views/test_visit.py @@ -25,6 +25,13 @@ class TestVisitApi(LoggedInWithWorkerTestCase): columns = json.loads(response.content)['columns'] self.assertTrue(len(columns) > 0) + def test_get_columns_for_time_exceeded(self): + response = self.client.get(reverse('web.api.visits.columns', kwargs={'visit_list_type': VISIT_LIST_EXCEEDED_TIME})) + self.assertEqual(response.status_code, 200) + + columns = json.loads(response.content)['columns'] + self.assertTrue(len(columns) > 0) + def test_visits_exceeded(self): response = self.client.get(reverse('web.api.visits', kwargs={'visit_list_type': VISIT_LIST_EXCEEDED_TIME})) self.assertEqual(response.status_code, 200) -- GitLab