diff --git a/app/dao/notifications_dao.py b/app/dao/notifications_dao.py index c289f60ed..3985f3ea0 100644 --- a/app/dao/notifications_dao.py +++ b/app/dao/notifications_dao.py @@ -7,7 +7,7 @@ from datetime import ( from flask import current_app from werkzeug.datastructures import MultiDict -from sqlalchemy import (desc, func, or_, and_, asc) +from sqlalchemy import (desc, func, or_, and_, asc, cast, Text) from sqlalchemy.orm import joinedload from app import db @@ -209,6 +209,24 @@ def get_notifications_for_job(service_id, job_id, filter_dict=None, page=1, page ) +@statsd(namespace="dao") +def get_notification_billable_unit_count_per_month(service_id, year): + start, end = get_financial_year(year) + return db.session.query( + func.to_char(NotificationHistory.created_at, "FMMonth"), + func.sum(NotificationHistory.billable_units) + ).group_by( + func.to_char(NotificationHistory.created_at, "FMMonth"), + func.to_char(NotificationHistory.created_at, "YYYY-MM") + ).order_by( + func.to_char(NotificationHistory.created_at, "YYYY-MM") + ).filter( + NotificationHistory.service_id == service_id, + NotificationHistory.created_at >= start, + NotificationHistory.created_at < end + ).all() + + @statsd(namespace="dao") def get_notification_with_personalisation(service_id, notification_id, key_type): filter_dict = {'service_id': service_id, 'id': notification_id} @@ -319,3 +337,10 @@ def dao_timeout_notifications(timeout_period_in_seconds): update({'status': NOTIFICATION_TEMPORARY_FAILURE, 'updated_at': update_at}, synchronize_session=False) db.session.commit() return updated + + +def get_financial_year(year): + return ( + date(year, 4, 1), + date(year + 1, 4, 1) + ) diff --git a/tests/app/dao/test_notification_dao.py b/tests/app/dao/test_notification_dao.py index 97885f50a..7e7ac65d8 100644 --- a/tests/app/dao/test_notification_dao.py +++ b/tests/app/dao/test_notification_dao.py @@ -31,13 +31,15 @@ from app.dao.notifications_dao import ( delete_notifications_created_more_than_a_week_ago, get_notification_by_id, get_notification_for_job, + get_notification_billable_unit_count_per_month, get_notification_with_personalisation, get_notifications_for_job, get_notifications_for_service, update_notification_status_by_id, update_notification_status_by_reference, dao_delete_notifications_and_history_by_id, - dao_timeout_notifications) + dao_timeout_notifications, + get_financial_year) from notifications_utils.template import get_sms_fragment_count @@ -685,6 +687,42 @@ def test_get_all_notifications_for_job_by_status(notify_db, notify_db_session, s assert len(notifications(filter_dict={'status': NOTIFICATION_STATUS_TYPES[:3]}).items) == 3 +def test_get_notification_billable_unit_count_per_month(notify_db, notify_db_session, sample_service): + + for year, month, day in ( + (2017, 1, 1), + (2016, 8, 1), + (2016, 7, 31), + (2016, 4, 6), + (2016, 4, 6), + (2016, 4, 1), + (2016, 3, 31), + (2016, 1, 1) + ): + sample_notification( + notify_db, notify_db_session, service=sample_service, + created_at=date(year, month, day) + ) + + for financial_year, months in ( + ( + 2017, + [] + ), + ( + 2016, + [('April', 3), ('July', 1), ('August', 1), ('January', 1)] + ), + ( + 2015, + [('January', 1), ('March', 1)] + ) + ): + assert get_notification_billable_unit_count_per_month( + sample_service.id, financial_year + ) == months + + def test_update_notification(sample_notification, sample_template): assert sample_notification.status == 'created' sample_notification.status = 'failed' @@ -1158,3 +1196,9 @@ def test_should_exclude_test_key_notifications_by_default( all_notifications = get_notifications_for_service(sample_service.id, limit_days=1, key_type=KEY_TYPE_TEST).items assert len(all_notifications) == 1 + + +def test_get_financial_year(): + start, end = get_financial_year(2000) + assert start == date(2000, 4, 1) + assert end == date(2001, 4, 1)