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