diff --git a/app/main/views/platform_admin.py b/app/main/views/platform_admin.py
index 23018ee94..ad966de70 100644
--- a/app/main/views/platform_admin.py
+++ b/app/main/views/platform_admin.py
@@ -313,6 +313,74 @@ def get_billing_report():
return render_template('views/platform-admin/get-billing-report.html', form=form)
+@main.route("/platform-admin/reports/volumes-by-service", methods=['GET', 'POST'])
+@user_is_platform_admin
+def get_volumes_by_service():
+ form = BillingReportDateFilterForm()
+
+ if form.validate_on_submit():
+ start_date = form.start_date.data
+ end_date = form.end_date.data
+ headers = [
+ "organisation id", "organisation name", "service id", "service name",
+ "free allowance", "sms notifications", "sms chargeable units", "email totals",
+ "letter totals", "letter cost", "letter sheet totals"
+ ]
+ result = billing_api_client.get_data_for_volumes_by_service_report(start_date, end_date)
+
+ rows = [
+ [
+ r["organisation_id"], r["organisation_name"], r["service_id"], r["service_name"],
+ r["free_allowance"], r["sms_notifications"], r["sms_chargeable_units"], r["email_totals"],
+ r["letter_totals"], r["letter_cost"], r["letter_sheet_totals"]
+ ]
+ for r in result
+ ]
+ if rows:
+ return Spreadsheet.from_rows([headers] + rows).as_csv_data, 200, {
+ 'Content-Type': 'text/csv; charset=utf-8',
+ 'Content-Disposition': 'attachment; filename="Volumes by service report from {} to {}.csv"'.format(
+ start_date, end_date
+ )
+ }
+ else:
+ flash('No results for dates')
+ return render_template('views/platform-admin/volumes-by-service-report.html', form=form)
+
+
+@main.route("/platform-admin/reports/daily-volumes-report", methods=['GET', 'POST'])
+@user_is_platform_admin
+def get_daily_volumes():
+ form = BillingReportDateFilterForm()
+
+ if form.validate_on_submit():
+ start_date = form.start_date.data
+ end_date = form.end_date.data
+ headers = [
+ "day", "sms totals", "sms fragment totals", "sms chargeable units",
+ "email totals", "letter totals", "letter sheet totals"
+ ]
+ result = billing_api_client.get_data_for_daily_volumes_report(start_date, end_date)
+
+ rows = [
+ [
+ r["day"], r["sms_totals"], r["sms_fragment_totals"], r["sms_chargeable_units"],
+ r["email_totals"], r["letter_totals"], r["letter_sheet_totals"]
+ ]
+ for r in result
+ ]
+ if rows:
+ return Spreadsheet.from_rows([headers] + rows).as_csv_data, 200, {
+ 'Content-Type': 'text/csv; charset=utf-8',
+ 'Content-Disposition': 'attachment; filename="Daily volumes report from {} to {}.csv"'.format(
+ start_date, end_date
+ )
+ }
+ else:
+ flash('No results for dates')
+ return render_template('views/platform-admin/daily-volumes-report.html', form=form)
+
+
@main.route("/platform-admin/complaints")
@user_is_platform_admin
def platform_admin_list_complaints():
diff --git a/app/navigation.py b/app/navigation.py
index 7a72749c6..110a1557a 100644
--- a/app/navigation.py
+++ b/app/navigation.py
@@ -92,6 +92,8 @@ class HeaderNavigation(Navigation):
'live_services_csv',
'notifications_sent_by_service',
'get_billing_report',
+ 'get_daily_volumes',
+ 'get_volumes_by_service',
'organisations',
'platform_admin',
'platform_admin_list_complaints',
diff --git a/app/notify_client/billing_api_client.py b/app/notify_client/billing_api_client.py
index ed083692e..08b5ce52c 100644
--- a/app/notify_client/billing_api_client.py
+++ b/app/notify_client/billing_api_client.py
@@ -41,5 +41,19 @@ class BillingAPIClient(NotifyAdminAPIClient):
'end_date': str(end_date),
})
+ def get_data_for_volumes_by_service_report(self, start_date, end_date):
+ return self.get(url='/platform-stats/volumes-by-service',
+ params={
+ 'start_date': str(start_date),
+ 'end_date': str(end_date),
+ })
+
+ def get_data_for_daily_volumes_report(self, start_date, end_date):
+ return self.get(url='/platform-stats/daily-volumes-report',
+ params={
+ 'start_date': str(start_date),
+ 'end_date': str(end_date),
+ })
+
billing_api_client = BillingAPIClient()
diff --git a/app/templates/views/platform-admin/daily-volumes-report.html b/app/templates/views/platform-admin/daily-volumes-report.html
new file mode 100644
index 000000000..827720e26
--- /dev/null
+++ b/app/templates/views/platform-admin/daily-volumes-report.html
@@ -0,0 +1,48 @@
+{% extends "views/platform-admin/_base_template.html" %}
+{% from "components/form.html" import form_wrapper %}
+{% from "components/table.html" import mapping_table, row, text_field %}
+
+{% block per_page_title %}
+ Daily volumes report
+{% endblock %}
+
+{% block platform_admin_content %}
+
+
+ Daily volumes Report
+
+
+ {% call form_wrapper() %}
+ {{ form.start_date(param_extensions={"hint": {"text": "Use the format YYYY-MM-DD"}}) }}
+ {{ form.end_date(param_extensions={"hint": {"text": "Use the format YYYY-MM-DD"}}) }}
+ {{ page_footer('Download report') }}
+ {% endcall %}
+
+
+ Data included in the report
+
+
+ {% call mapping_table(
+ caption='Descriptions of daily volumes data',
+ field_headings=['Name', 'Description'],
+ field_headings_visible=True,
+ caption_visible=False
+ ) %}
+ {% for message_length, charge in [
+ ('day', 'The whole business day in BST.'),
+ ('sms totals', 'The number of text messages sent'),
+ ('sms fragments', 'The number of text message fragments sent times the rate multiplier'),
+ ('sms chargeable units', 'The number of text message fragments sent'),
+ ('email totals', 'The number of emails sent'),
+ ('letter totals', 'The number of letters sent'),
+ ('letter sheet totals', 'The number of sheets sent')
+ ] %}
+ {% call row() %}
+ {{ text_field(message_length) }}
+ {{ text_field(charge | safe) }}
+ {% endcall %}
+ {% endfor %}
+ {% endcall %}
+
+
+{% endblock %}
diff --git a/app/templates/views/platform-admin/reports.html b/app/templates/views/platform-admin/reports.html
index 8d56460a9..dda3f18ff 100644
--- a/app/templates/views/platform-admin/reports.html
+++ b/app/templates/views/platform-admin/reports.html
@@ -19,4 +19,10 @@
Billing Report
+
+ Volumes by service Report
+
+
+ Daily volumes Report
+
{% endblock %}
diff --git a/app/templates/views/platform-admin/volumes-by-service-report.html b/app/templates/views/platform-admin/volumes-by-service-report.html
new file mode 100644
index 000000000..91c70fca2
--- /dev/null
+++ b/app/templates/views/platform-admin/volumes-by-service-report.html
@@ -0,0 +1,48 @@
+{% extends "views/platform-admin/_base_template.html" %}
+{% from "components/form.html" import form_wrapper %}
+{% from "components/table.html" import mapping_table, row, text_field %}
+
+{% block per_page_title %}
+ Volumes by service report
+{% endblock %}
+
+{% block platform_admin_content %}
+
+
+ Volumes by service Report
+
+
+ {% call form_wrapper() %}
+ {{ form.start_date(param_extensions={"hint": {"text": "Use the format YYYY-MM-DD"}}) }}
+ {{ form.end_date(param_extensions={"hint": {"text": "Use the format YYYY-MM-DD"}}) }}
+ {{ page_footer('Download report') }}
+ {% endcall %}
+
+
+ Data included in the report
+
+
+ {% call mapping_table(
+ caption='Descriptions of volumes by service data',
+ field_headings=['Name', 'Description'],
+ field_headings_visible=True,
+ caption_visible=False
+ ) %}
+ {% for message_length, charge in [
+ ('free allowance', 'Free allowance set for the service. This is the latest free allowance for the date range given'),
+ ('sms notifications', 'The number of text messages sent by the service.'),
+ ('sms chargeable units', 'The number of text message fragments times the rate multiplier sent by the service.'),
+ ('email totals', 'The number of emails sent by a service'),
+ ('letter totals', 'The number of letters sent by a service'),
+ ('letter costs', 'The cost of the letters, rate * letter totals'),
+ ('letter sheet totals', 'The number of sheet sent by a service')
+ ] %}
+ {% call row() %}
+ {{ text_field(message_length) }}
+ {{ text_field(charge | safe) }}
+ {% endcall %}
+ {% endfor %}
+ {% endcall %}
+
+
+{% endblock %}
diff --git a/tests/app/main/views/test_platform_admin.py b/tests/app/main/views/test_platform_admin.py
index d0fb1160b..b106d4255 100644
--- a/tests/app/main/views/test_platform_admin.py
+++ b/tests/app/main/views/test_platform_admin.py
@@ -1014,3 +1014,102 @@ def test_get_notifications_sent_by_service_calls_api_and_downloads_data(
'2019-01-01,596364a0-858e-42c8-9062-a8fe822260eb,service one,sms,42,0,0,8,0,0\r\n'
'2019-01-01,147ad62a-2951-4fa1-9ca0-093cd1a52c52,service two,email,3,1,0,2,0,0\r\n'
)
+
+
+def test_get_volumes_by_service_report_when_calls_api_and_download_data(
+ client_request,
+ platform_admin_user,
+ mocker
+):
+ mocker.patch(
+ "app.main.views.platform_admin.billing_api_client.get_data_for_volumes_by_service_report",
+ return_value=[{
+ "organisation_id": "7832a1be-a1f0-4f2a-982f-05adfd3d6354",
+ "organisation_name": "Org name",
+ "service_id": "48e82ac0-c8c4-4e46-8712-c83c35a94006",
+ "service_name": "service name",
+ "free_allowance": 10000,
+ "sms_notifications": 10,
+ "sms_chargeable_units": 20,
+ "email_totals": 8,
+ "letter_totals": 10,
+ "letter_cost": 4.5,
+ "letter_sheet_totals": 10
+ }]
+ )
+
+ client_request.login(platform_admin_user)
+ response = client_request.post_response(
+ 'main.get_volumes_by_service',
+ _data={'start_date': '2019-01-01', 'end_date': '2019-03-31'},
+ _expected_status=200,
+ )
+
+ assert response.content_type == 'text/csv; charset=utf-8'
+ assert response.headers['Content-Disposition'] == (
+ 'attachment; filename="Volumes by service report from {} to {}.csv"'.format('2019-01-01', '2019-03-31')
+ )
+
+ assert response.get_data(as_text=True) == (
+ "organisation id,organisation name,service id,service name,free allowance,sms notifications," +
+ "sms chargeable units,email totals,letter totals,letter cost,letter sheet totals\r\n" +
+
+ '7832a1be-a1f0-4f2a-982f-05adfd3d6354,' +
+ 'Org name,' +
+ '48e82ac0-c8c4-4e46-8712-c83c35a94006,' +
+ 'service name,' +
+ '10000,' +
+ '10,' +
+ '20,' +
+ '8,' +
+ '10,' +
+ '4.5,' +
+ '10'
+
+ '\r\n'
+ )
+
+
+def test_get_daily_volumes_report_when_calls_api_and_download_data(
+ client_request,
+ platform_admin_user,
+ mocker
+):
+ mocker.patch(
+ "app.main.views.platform_admin.billing_api_client.get_data_for_daily_volumes_report",
+ return_value=[{
+ "day": '2019-01-01',
+ "sms_totals": 20,
+ "sms_fragment_totals": 40,
+ "sms_chargeable_units": 60,
+ "email_totals": 100,
+ "letter_totals": 10,
+ "letter_sheet_totals": 20
+ }]
+ )
+
+ client_request.login(platform_admin_user)
+ response = client_request.post_response(
+ 'main.get_daily_volumes',
+ _data={'start_date': '2019-01-01', 'end_date': '2019-03-31'},
+ _expected_status=200,
+ )
+
+ assert response.content_type == 'text/csv; charset=utf-8'
+ assert response.headers['Content-Disposition'] == (
+ 'attachment; filename="Daily volumes report from {} to {}.csv"'.format('2019-01-01', '2019-03-31')
+ )
+
+ assert response.get_data(as_text=True) == (
+ "day,sms totals,sms fragment totals,sms chargeable units,email totals,letter totals,letter sheet totals\r\n" +
+
+ '2019-01-01,' +
+ '20,' +
+ '40,' +
+ '60,' +
+ '100,' +
+ '10,' +
+ '20'
+
+ '\r\n'
+ )
diff --git a/tests/app/notify_client/test_billing_client.py b/tests/app/notify_client/test_billing_client.py
index e29a80bdc..b3c29509b 100644
--- a/tests/app/notify_client/test_billing_client.py
+++ b/tests/app/notify_client/test_billing_client.py
@@ -41,3 +41,21 @@ def test_post_free_sms_fragment_limit_for_year_endpoint(mocker, api_user_active)
url='/service/{}/billing/free-sms-fragment-limit'.format(service_id),
data=sms_limit_data
)
+
+
+def test_get_data_for_volumes_by_service_report(mocker, api_user_active):
+ mock_get = mocker.patch('app.notify_client.billing_api_client.BillingAPIClient.get')
+ client = BillingAPIClient()
+
+ client.get_data_for_volumes_by_service_report('2022-03-01', '2022-03-31')
+ mock_get.assert_called_once_with(url='/platform-stats/volumes-by-service',
+ params={'start_date': '2022-03-01', 'end_date': '2022-03-31'})
+
+
+def test_get_data_for_daily_volumes_report(mocker, api_user_active):
+ mock_get = mocker.patch('app.notify_client.billing_api_client.BillingAPIClient.get')
+ client = BillingAPIClient()
+
+ client.get_data_for_daily_volumes_report('2022-03-01', '2022-03-31')
+ mock_get.assert_called_once_with(url='/platform-stats/daily-volumes-report',
+ params={'start_date': '2022-03-01', 'end_date': '2022-03-31'})
diff --git a/tests/app/test_navigation.py b/tests/app/test_navigation.py
index 4cb615f34..8477a9581 100644
--- a/tests/app/test_navigation.py
+++ b/tests/app/test_navigation.py
@@ -131,6 +131,8 @@ EXCLUDED_ENDPOINTS = tuple(map(Navigation.get_endpoint_with_blueprint, {
'find_users_by_email',
'forgot_password',
'get_billing_report',
+ 'get_daily_volumes',
+ 'get_volumes_by_service',
'get_example_csv',
'get_notifications_as_json',
'get_started',