From 3f3b163202d293685a1343ac48c1bfc1109696d3 Mon Sep 17 00:00:00 2001
From: Piotr Gawron <piotr.gawron@uni.lu>
Date: Fri, 27 Oct 2017 17:28:54 +0200
Subject: [PATCH] filtering by visit status types is possible for multiple
 visits

---
 smash/web/api_views/subject.py | 34 ++++++++++++++++++++++------------
 1 file changed, 22 insertions(+), 12 deletions(-)

diff --git a/smash/web/api_views/subject.py b/smash/web/api_views/subject.py
index d598319e..02bd657c 100644
--- a/smash/web/api_views/subject.py
+++ b/smash/web/api_views/subject.py
@@ -1,7 +1,8 @@
 import logging
 
-from django.db.models import Q
 from django.contrib.auth.decorators import login_required
+from django.db.models import Count, Case, When, Min
+from django.db.models import Q
 from django.http import JsonResponse
 
 from web.models import Subject, Visit, Appointment
@@ -10,8 +11,6 @@ from web.views import e500_error
 from web.views.notifications import get_subjects_with_no_visit, get_subjects_with_reminder, get_today_midnight_date
 from web.views.subject import SUBJECT_LIST_GENERIC, SUBJECT_LIST_NO_VISIT, SUBJECT_LIST_REQUIRE_CONTACT
 
-from django.db.models import Count, Case, When, Min
-
 logger = logging.getLogger(__name__)
 
 
@@ -103,46 +102,58 @@ def get_subjects_order(subjects_to_be_ordered, order_column, order_direction):
 
 
 def filter_by_visit(result, visit_number, visit_type):
+    # we need to give custom names for filtering params that contain visit_number in it
+    # because we might want to filter by few visits  and they shouldn't collide
     datetime_begin_filter = 'visit_' + str(visit_number) + '_datetime_begin'
     datetime_end_filter = 'visit_' + str(visit_number) + '_datetime_end'
     is_finished_filter = 'visit_' + str(visit_number) + '_is_finished'
     finished_appointments_filter = 'visit_' + str(visit_number) + '_finished_appointments'
     scheduled_appointments_filter = 'visit_' + str(visit_number) + '_scheduled_appointments'
 
+    # this is hack... instead of providing True/False value this field contain 1/0 value, the problem is that we need
+    # to provide aggregate function for the interacting parameter
+    # If we try to assign it with pure Case(When...) (without Count/Min/Max/Avg) we obtain duplicates
+    # of the results which are later on messing up with the subject list
     result = result.annotate(**{
-        is_finished_filter: Case(When(visit__visit_number=visit_number, then='visit__is_finished'))
+        is_finished_filter: Count(Case(When(Q(visit__is_finished=True) & Q(visit__visit_number=visit_number), then=1)))
     })
+
+    # number of finished appointments
     result = result.annotate(**{finished_appointments_filter: Count(Case(When(
         Q(visit__appointment__status=Appointment.APPOINTMENT_STATUS_FINISHED) & Q(visit__visit_number=visit_number),
         then=1)))})
+    # number of scheduled appointments
     result = result.annotate(**{scheduled_appointments_filter: Count(Case(When(
         Q(visit__appointment__status=Appointment.APPOINTMENT_STATUS_SCHEDULED) & Q(visit__visit_number=visit_number),
         then=1)))})
+
+    # when visit starts
     result = result.annotate(
-        **{datetime_begin_filter: Case(When(visit__visit_number=visit_number, then='visit__datetime_begin'))})
+        **{datetime_begin_filter: Min(Case(When(visit__visit_number=visit_number, then='visit__datetime_begin')))})
+    # when visit finish
     result = result.annotate(
-        **{datetime_end_filter: Case(When(visit__visit_number=visit_number, then='visit__datetime_end'))})
+        **{datetime_end_filter: Min(Case(When(visit__visit_number=visit_number, then='visit__datetime_end')))})
 
     if visit_type == "DONE":
         result = result.filter(**{datetime_begin_filter + "__lt": get_today_midnight_date()}). \
-            filter(**{is_finished_filter: True}). \
+            filter(**{is_finished_filter + "__gt": 0}). \
             filter(**{finished_appointments_filter + "__gt": 0})
     elif visit_type == "MISSED":
         result = result.filter(**{datetime_begin_filter + "__lt": get_today_midnight_date()}). \
-            filter(**{is_finished_filter: True}). \
+            filter(**{is_finished_filter + "__gt": 0}). \
             filter(**{finished_appointments_filter: 0})
     elif visit_type == "EXCEED":
         result = result.filter(**{datetime_begin_filter + "__lt": get_today_midnight_date()}). \
-            filter(**{is_finished_filter: False}). \
+            filter(**{is_finished_filter: 0}). \
             filter(**{datetime_end_filter + "__lt": get_today_midnight_date()})
     elif visit_type == "IN_PROGRESS":
         result = result.filter(**{datetime_begin_filter + "__lt": get_today_midnight_date()}). \
-            filter(**{is_finished_filter: False}). \
+            filter(**{is_finished_filter: 0}). \
             filter(**{datetime_end_filter + "__gt": get_today_midnight_date()}). \
             filter(**{scheduled_appointments_filter + "__gt": 0})
     elif visit_type == "SHOULD_BE_IN_PROGRESS":
         result = result.filter(**{datetime_begin_filter + "__lt": get_today_midnight_date()}). \
-            filter(**{is_finished_filter: False}). \
+            filter(**{is_finished_filter: 0}). \
             filter(**{datetime_end_filter + "__gt": get_today_midnight_date()}). \
             filter(**{scheduled_appointments_filter: 0})
     elif visit_type == "UPCOMING":
@@ -202,7 +213,6 @@ def get_subjects_filtered(subjects_to_be_filtered, filters):
                 message += str(column)
             logger.warn(message)
 
-    print result.query
     return result
 
 
-- 
GitLab