diff --git a/app/dao/notification_usage_dao.py b/app/dao/notification_usage_dao.py index cf90fe499..1d9346df2 100644 --- a/app/dao/notification_usage_dao.py +++ b/app/dao/notification_usage_dao.py @@ -1,20 +1,23 @@ +from collections import namedtuple from datetime import datetime, timedelta -from flask import current_app from sqlalchemy import Float, Integer from sqlalchemy import func, case, cast from sqlalchemy import literal_column from app import db -from app.dao.date_util import get_financial_year, get_month_start_end_date -from app.models import (NotificationHistory, - Rate, - NOTIFICATION_STATUS_TYPES_BILLABLE, - KEY_TYPE_TEST, - SMS_TYPE, - EMAIL_TYPE, Service) +from app.dao.date_util import get_financial_year +from app.models import ( + NotificationHistory, + Rate, + Service, + NOTIFICATION_STATUS_TYPES_BILLABLE, + KEY_TYPE_TEST, + SMS_TYPE, + EMAIL_TYPE +) from app.statsd_decorators import statsd -from app.utils import get_london_month_from_utc_column +from app.utils import get_london_month_from_utc_column, convert_utc_to_bst @statsd(namespace="dao") @@ -48,26 +51,39 @@ def get_yearly_billing_data(service_id, year): ) result.append(email_yearly_billing_data_query(service_id, start_date, end_date)) - return sum(result, []) @statsd(namespace="dao") -def get_billing_data_for_month(service_id, start_date, end_date): - rates = get_rates_for_daterange(start_date, end_date, SMS_TYPE) +def get_billing_data_for_month(service_id, start_date, end_date, notification_type): + results = [] - if not rates: - return [] + if notification_type == EMAIL_TYPE: + return billing_data_per_month_query(0, service_id, start_date, end_date, EMAIL_TYPE) - result = [] - # so the start end date in the query are the valid from the rate, not the month - this is going to take some thought - for r, n in zip(rates, rates[1:]): - result.extend(sms_billing_data_per_month_query(r.rate, service_id, max(r.valid_from, start_date), - min(n.valid_from, end_date))) - result.extend( - sms_billing_data_per_month_query(rates[-1].rate, service_id, max(rates[-1].valid_from, start_date), end_date)) + elif notification_type == SMS_TYPE: + rates = get_rates_for_daterange(start_date, end_date, SMS_TYPE) - return result + if not rates: + return [] + + # so the start end date in the query are the valid from the rate, not the month + # - this is going to take some thought + for r, n in zip(rates, rates[1:]): + results.extend( + billing_data_per_month_query( + r.rate, service_id, max(r.valid_from, start_date), + min(n.valid_from, end_date), SMS_TYPE + ) + ) + results.extend( + billing_data_per_month_query( + rates[-1].rate, service_id, max(rates[-1].valid_from, start_date), + end_date, SMS_TYPE + ) + ) + + return results @statsd(namespace="dao") @@ -80,8 +96,8 @@ def get_monthly_billing_data(service_id, year): result = [] for r, n in zip(rates, rates[1:]): - result.extend(sms_billing_data_per_month_query(r.rate, service_id, r.valid_from, n.valid_from)) - result.extend(sms_billing_data_per_month_query(rates[-1].rate, service_id, rates[-1].valid_from, end_date)) + result.extend(billing_data_per_month_query(r.rate, service_id, r.valid_from, n.valid_from, SMS_TYPE)) + result.extend(billing_data_per_month_query(rates[-1].rate, service_id, rates[-1].valid_from, end_date, SMS_TYPE)) return [(datetime.strftime(x[0], "%B"), x[1], x[2], x[3], x[4], x[5]) for x in result] @@ -143,6 +159,10 @@ def sms_yearly_billing_data_query(rate, service_id, start_date, end_date): def get_rates_for_daterange(start_date, end_date, notification_type): rates = Rate.query.filter(Rate.notification_type == notification_type).order_by(Rate.valid_from).all() + + if not rates: + return [] + results = [] for current_rate, current_rate_expiry_date in zip(rates, rates[1:]): if is_between(current_rate.valid_from, start_date, end_date) or \ @@ -165,7 +185,7 @@ def is_between(date, start_date, end_date): return start_date <= date <= end_date -def sms_billing_data_per_month_query(rate, service_id, start_date, end_date): +def billing_data_per_month_query(rate, service_id, start_date, end_date, notification_type): month = get_london_month_from_utc_column(NotificationHistory.created_at) result = db.session.query( month.label('month'), @@ -175,7 +195,7 @@ def sms_billing_data_per_month_query(rate, service_id, start_date, end_date): NotificationHistory.notification_type, cast(rate, Float()).label('rate') ).filter( - *billing_data_filter(SMS_TYPE, start_date, end_date, service_id) + *billing_data_filter(notification_type, start_date, end_date, service_id) ).group_by( NotificationHistory.notification_type, month, @@ -186,6 +206,16 @@ def sms_billing_data_per_month_query(rate, service_id, start_date, end_date): rate_multiplier() ).all() + if not result and notification_type == EMAIL_TYPE: + start_date = convert_utc_to_bst(start_date) + BillingData = namedtuple( + 'BillingData', + 'start_date billing_units rate_multiplier international notification_type rate' + ) + return [BillingData(start_date, 0, 1, False, notification_type, 0)] + else: + return result + return result diff --git a/tests/app/dao/test_notification_usage_dao.py b/tests/app/dao/test_notification_usage_dao.py index 394c71540..2de3c7e94 100644 --- a/tests/app/dao/test_notification_usage_dao.py +++ b/tests/app/dao/test_notification_usage_dao.py @@ -277,7 +277,7 @@ def test_get_monthly_billing_data_with_multiple_rates(notify_db, notify_db_sessi def test_get_monthly_billing_data_with_no_notifications_for_daterange(notify_db, notify_db_session, sample_template): set_up_rate(notify_db, datetime(2016, 4, 1), 0.014) results = get_monthly_billing_data(sample_template.service_id, 2016) - assert len(results) == 0 + assert results == [] def set_up_rate(notify_db, start_date, value): @@ -768,7 +768,8 @@ def test_get_monthly_billing_data_where_start_date_before_rate_returns_empty( results = get_billing_data_for_month( service_id=sample_template.service_id, start_date=now - timedelta(days=2), - end_date=now - timedelta(days=1) + end_date=now - timedelta(days=1), + notification_type=SMS_TYPE ) assert not results