Add usage to the dashboard

Takes the number of emails and SMS fragments sent from:
https://github.com/alphagov/notifications-api/pull/273

Using these numbers it’s possible to show:
- how much of your allowance is left
- or how much you have spent

For now the allowance and rates are hard coded.

Only for users that have manage service.
This commit is contained in:
Chris Hill-Scott
2016-04-20 15:37:17 +01:00
parent f6ba5ec8d0
commit 00030bc254
14 changed files with 197 additions and 13 deletions

View File

@@ -35,6 +35,11 @@
padding-right: 2px;
}
.align-with-heading-copy {
display: block;
margin-top: 45px;
}
.global-cookie-message {
p {
@extend %site-width-container;

View File

@@ -11,6 +11,12 @@
}
.big-number-right-aligned {
@extend %big-number;
@include bold-36($tabular-numbers: true);
text-align: right;
}
.big-number-with-status {
@extend %big-number;

View File

@@ -54,6 +54,7 @@ $path: '/static/images/';
@import 'views/job';
@import 'views/edit-template';
@import 'views/documenation';
@import 'views/dashboard';
// TODO: break this up
@import 'app';

View File

@@ -0,0 +1,20 @@
.dashboard {
table th {
@include bold-19;
}
}
.keyline-block {
border-top: 1px solid $border-colour;
padding-top: $gutter-half;
&-show-more-link {
@include core-16;
border-top: 1px solid $border-colour;
border-bottom: 1px solid $border-colour;
padding: 10px 0;
text-align: center;
}
}

View File

@@ -80,6 +80,16 @@ def template_history(service_id):
)
@main.route("/services/<service_id>/usage")
@login_required
@user_has_permissions('manage_settings', admin_override=True)
def usage(service_id):
return render_template(
'views/usage.html',
**get_dashboard_statistics_for_service(service_id)
)
def add_rates_to(delivery_statistics):
keys = [
@@ -148,11 +158,25 @@ def aggregate_usage(template_statistics):
def get_dashboard_statistics_for_service(service_id):
usage = service_api_client.get_service_usage(service_id)
sms_free_allowance = 250000
sms_rate = 0.018
sms_sent = usage['data'].get('sms_count', 0)
emails_sent = usage['data'].get('email_count', 0)
return {
'statistics': add_rates_to(
statistics_api_client.get_statistics_for_service(service_id, limit_days=7)['data']
),
'template_statistics': aggregate_usage(
template_statistics_client.get_template_statistics_for_service(service_id, limit_days=7)
)
),
'emails_sent': emails_sent,
'sms_free_allowance': sms_free_allowance,
'sms_sent': sms_sent,
'sms_allowance_remaining': max(0, (sms_free_allowance - sms_sent)),
'sms_chargeable': max(0, sms_sent - sms_free_allowance),
'sms_rate': sms_rate,
}

View File

@@ -159,6 +159,9 @@ class ServiceAPIClient(NotificationsAPIClient):
def get_service_history(self, service_id):
return self.get('/service/{0}/history'.format(service_id))
def get_service_usage(self, service_id):
return self.get('/service/{0}/fragment/aggregate_statistics'.format(service_id))
class ServicesBrowsableItem(BrowsableItem):

View File

@@ -1,7 +1,11 @@
{% macro big_number(number, label, label_link=None) %}
{% macro big_number(number, label, label_link=None, currency='', right_aligned=False) %}
<div class="big-number{% if right_aligned %}-right-aligned{% endif %}">
{% if number is number %}
{{ "{:,}".format(number) }}
{% if currency %}
{{ "{}{:,.2f}".format(currency, number) }}
{% else %}
{{ "{}{:,}".format(currency, number) }}
{% endif %}
{% else %}
{{ number }}
{% endif %}

View File

@@ -6,7 +6,7 @@
{% block maincolumn_content %}
<h1 class='heading-large'>
Templates used this year
Templates sent this year
</h1>
<p>
1 April 2016 to date

View File

@@ -6,6 +6,8 @@
{% block maincolumn_content %}
<div class="dashboard">
{% if not templates and current_user.has_permissions(['send_texts', 'send_emails', 'send_letters'], any_=True) %}
{% include 'views/dashboard/get-started.html' %}
{% elif current_user.has_permissions([
@@ -20,4 +22,6 @@
{% include 'views/dashboard/today.html' %}
</div>
{% endblock %}

View File

@@ -1,4 +1,4 @@
{% from "components/big-number.html" import big_number_with_status %}
{% from "components/big-number.html" import big_number, big_number_with_status %}
<div
data-module="update-content"
@@ -38,6 +38,36 @@
{% include 'views/dashboard/template-statistics.html' %}
{% endwith %}
<p class='table-show-more-link'>
<a href="{{ url_for('.template_history', service_id=current_service.id) }}">See all templates used this year</a>
<a href="{{ url_for('.template_history', service_id=current_service.id) }}">See all templates sent this year</a>
</p>
{% if current_user.has_permissions(['manage_settings'], admin_override=True) %}
<h2 class='heading-medium' style="margin-top: 30px;">This year</h2>
<div class='grid-row'>
<div class='column-half'>
<div class="keyline-block">
{{ big_number("Unlimited", 'free email allowance', right_aligned=True) }}
</div>
</div>
<div class='column-half'>
<div class="keyline-block">
{% if sms_chargeable %}
{{ big_number(
(sms_chargeable * sms_rate),
'spent on text messages',
currency="£",
right_aligned=True
) }}
{% else %}
{{ big_number(sms_allowance_remaining, 'free text messages left', right_aligned=True) }}
{% endif %}
</div>
</div>
</div>
<div class="keyline-block-show-more-link">
<a href="{{ url_for(".usage", service_id=current_service['id']) }}">See usage</a>
</div>
{% endif %}
</div>

View File

@@ -0,0 +1,67 @@
{% from "components/big-number.html" import big_number %}
{% extends "withnav_template.html" %}
{% block page_title %}
Billing GOV.UK Notify
{% endblock %}
{% block maincolumn_content %}
<div class='grid-row'>
<div class='column-half'>
<h2 class='heading-large'>Usage</h2>
</div>
<div class='column-half'>
<span class="align-with-heading-copy">1 April 2016 to date</span>
</div>
</div>
<div class='grid-row'>
<div class='column-half'>
<h2 class='heading-small'>Emails</h2>
<div class="keyline-block">
{{ big_number(emails_sent, 'sent', right_aligned=True) }}
{{ big_number("Unlimited", 'free allowance', right_aligned=True) }}
</div>
</div>
<div class='column-half'>
<h2 class='heading-small'>Text messages</h2>
<div class="keyline-block">
{{ big_number(sms_sent, 'sent', right_aligned=True) }}
{{ big_number(sms_free_allowance, 'free allowance', right_aligned=True) }}
{{ big_number(sms_allowance_remaining, 'free allowance remaining', right_aligned=True) }}
{% if sms_chargeable %}
{{ big_number(
sms_chargeable,
'at {:.1f}p per message'.format(sms_rate * 100),
right_aligned=True
) }}
{% endif %}
</div>
</div>
</div>
<div class='grid-row'>
<div class='column-half'>
<div class="keyline-block">
&nbsp;
</div>
</div>
<div class='column-half'>
<div class="keyline-block bottom-gutter">
{{ big_number(
(sms_chargeable * sms_rate),
'spent',
currency="£",
right_aligned=True
) }}
</div>
<p>
What counts as 1 text message?<br />
See <a href="{{ url_for('.pricing') }}">pricing</a>.
</p>
</div>
</div>
{% endblock %}

View File

@@ -65,7 +65,8 @@ def test_should_show_recent_templates_on_dashboard(app_,
mock_get_user_by_email,
mock_login,
mock_get_jobs,
mock_has_permissions):
mock_has_permissions,
mock_get_usage):
mock_template_stats = mocker.patch('app.template_statistics_client.get_template_statistics_for_service',
return_value=copy.deepcopy(stub_template_stats))
@@ -164,7 +165,8 @@ def test_menu_send_messages(mocker,
service_one,
mock_get_service_templates,
mock_get_jobs,
mock_get_template_statistics):
mock_get_template_statistics,
mock_get_usage):
with app_.test_request_context():
resp = _test_dashboard_menu(
@@ -197,7 +199,8 @@ def test_menu_manage_service(mocker,
service_one,
mock_get_service_templates,
mock_get_jobs,
mock_get_template_statistics):
mock_get_template_statistics,
mock_get_usage):
with app_.test_request_context():
resp = _test_dashboard_menu(
mocker,
@@ -229,7 +232,8 @@ def test_menu_manage_api_keys(mocker,
service_one,
mock_get_service_templates,
mock_get_jobs,
mock_get_template_statistics):
mock_get_template_statistics,
mock_get_usage):
with app_.test_request_context():
resp = _test_dashboard_menu(
mocker,
@@ -260,7 +264,8 @@ def test_menu_all_services_for_platform_admin_user(mocker,
service_one,
mock_get_service_templates,
mock_get_jobs,
mock_get_template_statistics):
mock_get_template_statistics,
mock_get_usage):
with app_.test_request_context():
resp = _test_dashboard_menu(
mocker,
@@ -295,7 +300,8 @@ def test_route_for_service_permissions(mocker,
mock_get_service_templates,
mock_get_jobs,
mock_get_service_statistics,
mock_get_template_statistics):
mock_get_template_statistics,
mock_get_usage):
routes = [
'main.service_dashboard']
with app_.test_request_context():

View File

@@ -20,7 +20,8 @@ def test_sign_out_user(app_,
mock_get_service_statistics,
mock_get_jobs,
mock_has_permissions,
mock_get_template_statistics):
mock_get_template_statistics,
mock_get_usage):
with app_.test_request_context():
with app_.test_client() as client:
client.login(api_user_active)

View File

@@ -898,6 +898,19 @@ def mock_get_template_statistics(mocker, service_one, fake_uuid):
'app.template_statistics_client.get_template_statistics_for_service', side_effect=_get_stats)
@pytest.fixture(scope='function')
def mock_get_usage(mocker, service_one, fake_uuid):
def _get_usage(service_id):
return {'data': {
"sms_count": 123,
"email_count": 456
}}
return mocker.patch(
'app.service_api_client.get_service_usage', side_effect=_get_usage)
@pytest.fixture(scope='function')
def mock_events(mocker):