From 259d4a05692eb6c9cda94a14001fa537070a9858 Mon Sep 17 00:00:00 2001 From: Leo Hemsted Date: Thu, 7 Apr 2022 17:52:37 +0100 Subject: [PATCH] add new daily sms provider volume report code generally lifted almost exactly from the daily_volumes_report, but per provider and only for SMS. --- app/dao/fact_billing_dao.py | 25 +++++++++ app/platform_stats/rest.py | 22 ++++++++ tests/app/dao/test_ft_billing_dao.py | 79 +++++++++++++++++++++++++++ tests/app/platform_stats/test_rest.py | 21 +++++++ 4 files changed, 147 insertions(+) diff --git a/app/dao/fact_billing_dao.py b/app/dao/fact_billing_dao.py index d07acd47d..aba110721 100644 --- a/app/dao/fact_billing_dao.py +++ b/app/dao/fact_billing_dao.py @@ -779,6 +779,31 @@ def fetch_daily_volumes_for_platform(start_date, end_date): return aggregated_totals +def fetch_daily_sms_provider_volumes_for_platform(start_date, end_date): + # query to return the total notifications sent per day for each channel. NB start and end dates are inclusive + + daily_volume_stats = db.session.query( + FactBilling.bst_date, + FactBilling.provider, + func.sum(FactBilling.notifications_sent).label('sms_totals'), + func.sum(FactBilling.billable_units).label('sms_fragment_totals'), + func.sum(FactBilling.billable_units * FactBilling.rate_multiplier).label('sms_chargeable_units'), + func.sum(FactBilling.billable_units * FactBilling.rate_multiplier * FactBilling.rate).label('sms_cost'), + ).filter( + FactBilling.notification_type == SMS_TYPE, + FactBilling.bst_date >= start_date, + FactBilling.bst_date <= end_date, + ).group_by( + FactBilling.bst_date, + FactBilling.provider, + ).order_by( + FactBilling.bst_date, + FactBilling.provider, + ).all() + + return daily_volume_stats + + def fetch_volumes_by_service(start_date, end_date): # query to return the volume totals by service aggregated for the date range given # start and end dates are inclusive. diff --git a/app/platform_stats/rest.py b/app/platform_stats/rest.py index 0ffc75e77..859dd8cbe 100644 --- a/app/platform_stats/rest.py +++ b/app/platform_stats/rest.py @@ -5,6 +5,7 @@ from flask import Blueprint, jsonify, request from app.dao.date_util import get_financial_year_for_datetime from app.dao.fact_billing_dao import ( fetch_billing_details_for_all_services, + fetch_daily_sms_provider_volumes_for_platform, fetch_daily_volumes_for_platform, fetch_letter_costs_and_totals_for_all_services, fetch_letter_line_items_for_all_services, @@ -161,6 +162,27 @@ def daily_volumes_report(): return jsonify(report) +@platform_stats_blueprint.route('daily-sms-provider-volumes-report') +def daily_sms_provider_volumes_report(): + start_date = validate_date_format(request.args.get('start_date')) + end_date = validate_date_format(request.args.get('end_date')) + + daily_volumes = fetch_daily_sms_provider_volumes_for_platform(start_date, end_date) + report = [] + + for row in daily_volumes: + report.append({ + 'day': row.bst_date.isoformat(), + 'provider': row.provider, + 'sms_totals': int(row.sms_totals), + 'sms_fragment_totals': int(row.sms_fragment_totals), + 'sms_chargeable_units': int(row.sms_chargeable_units), + # convert from Decimal to float as it's not json serialisable + 'sms_cost': float(row.sms_cost), + }) + return jsonify(report) + + @platform_stats_blueprint.route('volumes-by-service') def volumes_by_service_report(): start_date = validate_date_format(request.args.get('start_date')) diff --git a/tests/app/dao/test_ft_billing_dao.py b/tests/app/dao/test_ft_billing_dao.py index a1945cdfa..8f305b48c 100644 --- a/tests/app/dao/test_ft_billing_dao.py +++ b/tests/app/dao/test_ft_billing_dao.py @@ -10,6 +10,7 @@ from app.dao.fact_billing_dao import ( delete_billing_data_for_service_for_day, fetch_billing_data_for_day, fetch_billing_totals_for_year, + fetch_daily_sms_provider_volumes_for_platform, fetch_daily_volumes_for_platform, fetch_letter_costs_and_totals_for_all_services, fetch_letter_line_items_for_all_services, @@ -856,6 +857,84 @@ def test_fetch_daily_volumes_for_platform( assert results[1].letter_sheet_totals == 40 +def test_fetch_daily_sms_provider_volumes_for_platform_groups_values_by_provider( + notify_db_session, +): + services = [ + create_service(service_name='a'), + create_service(service_name='b') + ] + templates = [ + create_template(services[0]), + create_template(services[1]) + ] + + create_ft_billing('2022-02-01', templates[0], provider='foo', notifications_sent=1, billable_unit=2) + create_ft_billing('2022-02-01', templates[1], provider='foo', notifications_sent=4, billable_unit=8) + + create_ft_billing('2022-02-01', templates[0], provider='bar', notifications_sent=16, billable_unit=32) + create_ft_billing('2022-02-01', templates[1], provider='bar', notifications_sent=64, billable_unit=128) + + results = fetch_daily_sms_provider_volumes_for_platform(start_date='2022-02-01', end_date='2022-02-01') + + assert len(results) == 2 + assert results[0].provider == 'bar' + assert results[0].sms_totals == 80 + assert results[0].sms_fragment_totals == 160 + + assert results[1].provider == 'foo' + assert results[1].sms_totals == 5 + assert results[1].sms_fragment_totals == 10 + + +def test_fetch_daily_sms_provider_volumes_for_platform_for_platform_calculates_chargeable_units_and_costs( + sample_template, +): + create_ft_billing('2022-02-01', sample_template, rate_multiplier=3, rate=1.5, notifications_sent=1, billable_unit=2) + + results = fetch_daily_sms_provider_volumes_for_platform(start_date='2022-02-01', end_date='2022-02-01') + + assert len(results) == 1 + assert results[0].sms_totals == 1 + assert results[0].sms_fragment_totals == 2 + assert results[0].sms_chargeable_units == 6 + assert results[0].sms_cost == 9 + + +def test_fetch_daily_sms_provider_volumes_for_platform_for_platform_searches_dates_inclusively(sample_template): + # too early + create_ft_billing('2022-02-02', sample_template) + + # just right + create_ft_billing('2022-02-03', sample_template) + create_ft_billing('2022-02-04', sample_template) + create_ft_billing('2022-02-05', sample_template) + + # too late + create_ft_billing('2022-02-06', sample_template) + + results = fetch_daily_sms_provider_volumes_for_platform(start_date='2022-02-03', end_date='2022-02-05') + + assert len(results) == 3 + assert results[0].bst_date == date(2022, 2, 3) + assert results[-1].bst_date == date(2022, 2, 5) + + +def test_fetch_daily_sms_provider_volumes_for_platform_for_platform_only_returns_sms( + sample_template, + sample_email_template, + sample_letter_template +): + create_ft_billing('2022-02-01', sample_template, notifications_sent=1) + create_ft_billing('2022-02-01', sample_email_template, notifications_sent=2) + create_ft_billing('2022-02-01', sample_letter_template, notifications_sent=4) + + results = fetch_daily_sms_provider_volumes_for_platform(start_date='2022-02-01', end_date='2022-02-01') + + assert len(results) == 1 + assert results[0].sms_totals == 1 + + def test_fetch_volumes_by_service(notify_db_session): set_up_usage_data(datetime(2022, 2, 1)) diff --git a/tests/app/platform_stats/test_rest.py b/tests/app/platform_stats/test_rest.py index f8bbf19ea..27ba169e0 100644 --- a/tests/app/platform_stats/test_rest.py +++ b/tests/app/platform_stats/test_rest.py @@ -9,6 +9,7 @@ from app.platform_stats.rest import ( validate_date_range_is_within_a_financial_year, ) from tests.app.db import ( + create_ft_billing, create_ft_notification_status, create_notification, create_service, @@ -238,3 +239,23 @@ def test_volumes_by_service_report( 'service_id': str(fixture['service_with_sms_within_allowance'].id), 'service_name': fixture['service_with_sms_within_allowance'].name, 'sms_chargeable_units': 0, 'sms_notifications': 0} + + +def test_daily_sms_provider_volumes_report(admin_request, sample_template): + + create_ft_billing('2022-03-01', sample_template, provider='foo', rate=1.5, notifications_sent=1, billable_unit=3) + resp = admin_request.get( + 'platform_stats.daily_sms_provider_volumes_report', + start_date='2022-03-01', + end_date='2022-03-01' + ) + + assert len(resp) == 1 + assert resp[0] == { + 'day': '2022-03-01', + 'provider': 'foo', + 'sms_totals': 1, + 'sms_fragment_totals': 3, + 'sms_chargeable_units': 3, + 'sms_cost': 4.5, + }