diff --git a/smash/web/statistics.py b/smash/web/statistics.py index 0de80c539f380d7c016101fd7520a09c1ac4b8d8..0792d080645e86a8fd6faa46725bbe0bd98b3377 100644 --- a/smash/web/statistics.py +++ b/smash/web/statistics.py @@ -12,28 +12,32 @@ from .models import AppointmentType, Appointment, Visit __author__ = 'Valentin Grouès' QUERY_VISITS_RANKS = """ -SELECT DISTINCT(rank() OVER (PARTITION BY subject_id ORDER BY datetime_begin)) AS rank FROM web_visit +SELECT DISTINCT(rank() OVER (PARTITION BY subject_id ORDER BY datetime_begin)) AS rank FROM web_visit """ QUERY_APPOINTMENTS_COUNT = """ -SELECT count(*) FROM web_appointment LEFT JOIN (SELECT id, rank() +SELECT count(*) FROM web_appointment LEFT JOIN (SELECT id, subject_id, rank() OVER (PARTITION BY subject_id ORDER BY datetime_begin) AS rnk FROM web_visit) -a ON a.id = web_appointment.visit_id WHERE a.rnk = %s +a ON a.id = web_appointment.visit_id +LEFT JOIN web_subject ON web_subject.id = subject_id +WHERE a.rnk = %s AND EXTRACT(MONTH FROM web_appointment.datetime_when) = %s AND EXTRACT(YEAR FROM web_appointment.datetime_when) = %s """ QUERY_VISITS_ENDED_COUNT = """ -SELECT count(*) FROM (SELECT id, datetime_begin, datetime_end, rank() +SELECT count(*) FROM (SELECT id, subject_id, datetime_begin, datetime_end, rank() OVER (PARTITION BY subject_id ORDER BY datetime_begin) AS rnk FROM web_visit) a +LEFT JOIN web_subject ON web_subject.id = subject_id WHERE a.rnk = %s AND EXTRACT(MONTH FROM a.datetime_end) = %s AND EXTRACT(YEAR FROM a.datetime_end) = %s """ QUERY_VISITS_STARTED_COUNT = """ -SELECT count(*) FROM (SELECT id, datetime_begin, datetime_end, rank() +SELECT count(*) FROM (SELECT id, subject_id, datetime_begin, datetime_end, rank() OVER (PARTITION BY subject_id ORDER BY datetime_begin) AS rnk FROM web_visit) a +LEFT JOIN web_subject ON web_subject.id = subject_id WHERE a.rnk = %s AND EXTRACT(MONTH FROM a.datetime_begin) = %s AND EXTRACT(YEAR FROM a.datetime_begin) = %s @@ -41,12 +45,15 @@ EXTRACT(YEAR FROM a.datetime_begin) = %s QUERY_APPOINTMENTS = """ SELECT types.appointmenttype_id, web_appointment.status, count(*) FROM web_appointment -LEFT JOIN (SELECT id, rank() OVER (PARTITION BY subject_id ORDER BY datetime_begin) AS rnk +LEFT JOIN (SELECT id, subject_id, rank() OVER (PARTITION BY subject_id ORDER BY datetime_begin) AS rnk FROM web_visit) a ON a.id = web_appointment.visit_id LEFT JOIN web_appointment_appointment_types types -ON types.appointment_id = web_appointment.id WHERE a.rnk = %s +ON types.appointment_id = web_appointment.id +LEFT JOIN web_subject ON web_subject.id = subject_id +WHERE a.rnk = %s AND EXTRACT(MONTH FROM web_appointment.datetime_when) = %s AND EXTRACT(YEAR FROM web_appointment.datetime_when) = %s -GROUP BY types.appointmenttype_id, web_appointment.status +{} +GROUP BY TYPES.appointmenttype_id, web_appointment.status """ @@ -54,11 +61,11 @@ class StatisticsManager(object): def __init__(self): self.appointment_types = {appointment_type.id: appointment_type for appointment_type in AppointmentType.objects.all()} - self.visits_ranks = self._get_visits_ranks() self.statuses_list = Appointment.objects.filter().values_list('status', flat=True).distinct().order_by( 'status').all() self.statuses_labels = [Appointment.APPOINTMENT_STATUS_CHOICES.get(status, status.title()) for status in self.statuses_list] + self.visits_ranks = self._get_visits_ranks() def get_statistics_for_month(self, month, year, subject_type=None, visit=None): """ @@ -85,10 +92,12 @@ class StatisticsManager(object): filters_month_year_appointments, filters_month_year_visits_ended, filters_month_year_visits_started = self._build_filters( month, subject_type, year) - number_of_appointments = self._get_number_of_appointments(filters_month_year_appointments, visit, month, year) + number_of_appointments = self._get_number_of_appointments(filters_month_year_appointments, visit, month, year, + subject_type) number_of_visits_started = self._get_number_visits_started(filters_month_year_visits_started, visit, month, - year) - number_of_visits_ended = self._get_number_visits_ended(filters_month_year_visits_ended, visit, month, year) + year, subject_type) + number_of_visits_ended = self._get_number_visits_ended(filters_month_year_visits_ended, visit, month, year, + subject_type) general_results["appointments"] = number_of_appointments general_results["visits_started"] = number_of_visits_started @@ -97,7 +106,7 @@ class StatisticsManager(object): results["general"] = general_results results_appointments = self.get_appointments_per_type_and_status(filters_month_year_appointments, month, - self.statuses_list, visit, year) + self.statuses_list, visit, year, subject_type) results["appointments"] = results_appointments results["statuses_list"] = self.statuses_labels appointment_types_values = map(attrgetter('code'), self.appointment_types.values()) @@ -105,7 +114,8 @@ class StatisticsManager(object): results["appointments_types_list"] = sorted_appointment_types_values return results - def get_appointments_per_type_and_status(self, filters_month_year_appointments, month, statuses_list, visit, year): + def get_appointments_per_type_and_status(self, filters_month_year_appointments, month, statuses_list, visit, year, + subject_type=None): if not visit: results_appointments = {} for appointment_type in self.appointment_types.values(): @@ -123,8 +133,13 @@ class StatisticsManager(object): results_appointments[appointment_type.code] = results_appointment else: results_appointment_set = defaultdict(dict) + query = QUERY_APPOINTMENTS + subject_type_clause = "" + if subject_type is not None: + subject_type_clause = " AND web_subject.type = '{}'".format(subject_type) + query = query.format(subject_type_clause) with connection.cursor() as cursor: - cursor.execute(QUERY_APPOINTMENTS, [visit, month, year]) + cursor.execute(query, [visit, month, year]) rows = cursor.fetchall() for row in rows: appointment_type_id, status, count = row @@ -141,8 +156,10 @@ class StatisticsManager(object): return results_appointments @staticmethod - def _get_count_from_filters_or_sql(model, filters, query, visit, month, year): + def _get_count_from_filters_or_sql(model, filters, query, visit, month, year, subject_type): if visit: + if subject_type is not None: + query += " AND web_subject.type = '{}'".format(subject_type) with connection.cursor() as cursor: cursor.execute( query, @@ -153,16 +170,17 @@ class StatisticsManager(object): count = model.objects.filter(filters).count() return count - def _get_number_visits_started(self, filters_month_year_visits_started, visit, month, year): + def _get_number_visits_started(self, filters_month_year_visits_started, visit, month, year, subject_type=None): return self._get_count_from_filters_or_sql(Visit, filters_month_year_visits_started, QUERY_VISITS_STARTED_COUNT, - visit, month, year) + visit, month, year, subject_type) - def _get_number_visits_ended(self, filters_month_year_visits_ended, visit, month, year): + def _get_number_visits_ended(self, filters_month_year_visits_ended, visit, month, year, subject_type=None): return self._get_count_from_filters_or_sql(Visit, filters_month_year_visits_ended, QUERY_VISITS_ENDED_COUNT, - visit, month, year) + visit, month, year, subject_type) - def _get_number_of_appointments(self, filters, visit, month, year): - return self._get_count_from_filters_or_sql(Appointment, filters, QUERY_APPOINTMENTS_COUNT, visit, month, year) + def _get_number_of_appointments(self, filters, visit, month, year, subject_type=None): + return self._get_count_from_filters_or_sql(Appointment, filters, QUERY_APPOINTMENTS_COUNT, visit, month, year, + subject_type) @staticmethod def _build_filters(month, subject_type, year): @@ -187,10 +205,14 @@ class StatisticsManager(object): return filters_month_year_appointments, filters_month_year_visits_ended, filters_month_year_visits_started @staticmethod - def _get_visits_ranks(): + def _get_visits_ranks(subject_type=None): + query = QUERY_VISITS_RANKS + if subject_type is not None: + query += " LEFT JOIN web_subject ON web_subject.id = web_visit.subject_id WHERE web_subject.type = '{}'".format( + subject_type) with connection.cursor() as cursor: cursor.execute( - QUERY_VISITS_RANKS, + query, []) rows = cursor.fetchall() diff --git a/smash/web/tests/test_statistics.py b/smash/web/tests/test_statistics.py index b4302710970e9ee95ba81df297f26ed238f5a117..2b675d3bcff2e1c66353127bb507b2bc85427ffe 100644 --- a/smash/web/tests/test_statistics.py +++ b/smash/web/tests/test_statistics.py @@ -57,6 +57,15 @@ class TestStatistics(TestCase): statistics = self.statistics_manager.get_statistics_for_month(self.now.month, self.now.year, subject_type="P") self.check_statistics(statistics, 0, 0, 0, {"C": [0, 0]}, ['Scheduled']) + def test_get_statistics_for_month_one_appointment_subject_type_and_visit(self): + statistics = self.statistics_manager.get_statistics_for_month(self.now.month, self.now.year, subject_type="C", + visit='1') + self.check_statistics(statistics, 0, 0, 1, {"C": [1, 1]}, ['Scheduled']) + + statistics = self.statistics_manager.get_statistics_for_month(self.now.month, self.now.year, subject_type="P", + visit='1') + self.check_statistics(statistics, 0, 0, 0, {"C": [0, 0]}, ['Scheduled']) + def test_get_statistics_for_month_multiple_visits(self): second_visit = Visit.objects.create(datetime_begin=self.now + datetime.timedelta(days=-32), datetime_end=self.now + datetime.timedelta(days=31),