mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-07-27 19:29:11 -04:00
Merge pull request #1722 from alphagov/letter-on-usage-page
Letters on usage page
This commit is contained in:
@@ -135,12 +135,18 @@ def usage(service_id):
|
||||
year, current_financial_year = requested_and_current_financial_year(request)
|
||||
|
||||
free_sms_allowance = billing_api_client.get_free_sms_fragment_limit_for_year(service_id, year)
|
||||
units = billing_api_client.get_billable_units(service_id, year)
|
||||
yearly_usage = billing_api_client.get_service_usage(service_id, year)
|
||||
|
||||
usage_template = 'views/usage.html'
|
||||
if 'letter' in current_service['permissions']:
|
||||
usage_template = 'views/usage-with-letters.html'
|
||||
return render_template(
|
||||
'views/usage.html',
|
||||
usage_template,
|
||||
months=list(get_free_paid_breakdown_for_billable_units(
|
||||
year,
|
||||
free_sms_allowance,
|
||||
billing_api_client.get_billable_units(service_id, year)
|
||||
units
|
||||
)),
|
||||
selected_year=year,
|
||||
years=get_tuples_of_financial_years(
|
||||
@@ -148,7 +154,7 @@ def usage(service_id):
|
||||
start=current_financial_year - 1,
|
||||
end=current_financial_year + 1,
|
||||
),
|
||||
**calculate_usage(billing_api_client.get_service_usage(service_id, year),
|
||||
**calculate_usage(yearly_usage,
|
||||
free_sms_allowance)
|
||||
)
|
||||
|
||||
@@ -335,6 +341,11 @@ def calculate_usage(usage, free_sms_fragment_limit):
|
||||
emails = [breakdown["billing_units"] for breakdown in usage if breakdown['notification_type'] == 'email']
|
||||
emails_sent = 0 if len(emails) == 0 else emails[0]
|
||||
|
||||
letters = [(breakdown["billing_units"], breakdown['letter_total']) for breakdown in usage if
|
||||
breakdown['notification_type'] == 'letter']
|
||||
letter_sent = 0 if len(letters) == 0 else letters[0][0]
|
||||
letter_cost = 0 if len(letters) == 0 else letters[0][1]
|
||||
|
||||
return {
|
||||
'emails_sent': emails_sent,
|
||||
'sms_free_allowance': sms_free_allowance,
|
||||
@@ -342,6 +353,8 @@ def calculate_usage(usage, free_sms_fragment_limit):
|
||||
'sms_allowance_remaining': max(0, (sms_free_allowance - sms_sent)),
|
||||
'sms_chargeable': max(0, sms_sent - sms_free_allowance),
|
||||
'sms_rate': sms_rate,
|
||||
'letter_sent': letter_sent,
|
||||
'letter_cost': letter_cost
|
||||
}
|
||||
|
||||
|
||||
@@ -396,18 +409,30 @@ def get_sum_billing_units(billing_units, month=None):
|
||||
|
||||
def get_free_paid_breakdown_for_billable_units(year, free_sms_fragment_limit, billing_units):
|
||||
cumulative = 0
|
||||
letter_cumulative = 0
|
||||
sms_units = [x for x in billing_units if x['notification_type'] == 'sms']
|
||||
letter_units = [x for x in billing_units if x['notification_type'] == 'letter']
|
||||
for month in get_months_for_financial_year(year):
|
||||
previous_cumulative = cumulative
|
||||
monthly_usage = get_sum_billing_units(billing_units, month)
|
||||
monthly_usage = get_sum_billing_units(sms_units, month)
|
||||
cumulative += monthly_usage
|
||||
breakdown = get_free_paid_breakdown_for_month(
|
||||
free_sms_fragment_limit, cumulative, previous_cumulative,
|
||||
[billing_month for billing_month in billing_units if billing_month['month'] == month]
|
||||
[billing_month for billing_month in sms_units if billing_month['month'] == month]
|
||||
)
|
||||
letter_billing = [(x['billing_units'], x['rate'], (x['billing_units'] * x['rate']))
|
||||
for x in letter_units if x['month'] == month]
|
||||
letter_total = 0
|
||||
for x in letter_billing:
|
||||
letter_total += x[2]
|
||||
letter_cumulative += letter_total
|
||||
yield {
|
||||
'name': month,
|
||||
'letter_total': letter_total,
|
||||
'letter_cumulative': letter_cumulative,
|
||||
'paid': breakdown['paid'],
|
||||
'free': breakdown['free']
|
||||
'free': breakdown['free'],
|
||||
'letters': letter_billing
|
||||
}
|
||||
|
||||
|
||||
|
||||
141
app/templates/views/usage-with-letters.html
Normal file
141
app/templates/views/usage-with-letters.html
Normal file
@@ -0,0 +1,141 @@
|
||||
{% from "components/big-number.html" import big_number %}
|
||||
{% from "components/table.html" import list_table, field, hidden_field_heading, row_heading, text_field %}
|
||||
{% from "components/pill.html" import pill %}
|
||||
|
||||
{% extends "withnav_template.html" %}
|
||||
|
||||
{% block service_page_title %}
|
||||
Usage
|
||||
{% endblock %}
|
||||
|
||||
{% block maincolumn_content %}
|
||||
|
||||
<h1 class='heading-large'>Usage</h1>
|
||||
|
||||
<div class="bottom-gutter">
|
||||
{{ pill(years, selected_year, big_number_args={'smallest': True}) }}
|
||||
</div>
|
||||
<div id='pill-selected-item'>
|
||||
<div class='grid-row'>
|
||||
<div class='column-one-third'>
|
||||
<h2 class='heading-small'>Emails</h2>
|
||||
<div class="keyline-block">
|
||||
{{ big_number(emails_sent, 'sent', smaller=True) }}
|
||||
{{ big_number("Unlimited", 'free allowance', smaller=True) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class='column-one-third'>
|
||||
<h2 class='heading-small'>Text messages</h2>
|
||||
<div class="keyline-block">
|
||||
{{ big_number(sms_sent, 'sent', smaller=True) }}
|
||||
{{ big_number(sms_free_allowance, 'free allowance', smaller=True) }}
|
||||
{{ big_number(sms_allowance_remaining, 'free allowance remaining', smaller=True) }}
|
||||
{% if sms_chargeable %}
|
||||
{{ big_number(
|
||||
sms_chargeable,
|
||||
'at {:.2f} pence per message'.format(sms_rate * 100),
|
||||
smaller=True
|
||||
) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class='column-one-third'>
|
||||
<h2 class='heading-small'>Letters</h2>
|
||||
<div class="keyline-block">
|
||||
{{ big_number(letter_sent, 'sent', smaller=True) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='grid-row'>
|
||||
<div class='column-one-third'>
|
||||
<div class="keyline-block">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class='column-one-third'>
|
||||
<div class="keyline-block">
|
||||
{{ big_number(
|
||||
(sms_chargeable * sms_rate),
|
||||
'spent',
|
||||
currency="£",
|
||||
smaller=True
|
||||
) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class='column-one-third'>
|
||||
<div class="keyline-block">
|
||||
{{ big_number(
|
||||
letter_cost,
|
||||
'spent',
|
||||
currency="£",
|
||||
smaller=True
|
||||
) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{% if months %}
|
||||
<div class="dashboard-table body-copy-table">
|
||||
{% call(month, row_index) list_table(
|
||||
months,
|
||||
caption="Total spend",
|
||||
caption_visible=False,
|
||||
empty_message='',
|
||||
field_headings=[
|
||||
'By month',
|
||||
hidden_field_heading('Cost'),
|
||||
],
|
||||
field_headings_visible=True
|
||||
) %}
|
||||
{% call row_heading() %}
|
||||
{{ month.name }}
|
||||
{% endcall %}
|
||||
{% call field(align='left') %}
|
||||
{{ big_number(
|
||||
(sms_rate * month.paid) + month.letter_total,
|
||||
currency="£",
|
||||
smallest=True
|
||||
) }}
|
||||
<ul>
|
||||
{% if month.free %}
|
||||
<li class="tabular-numbers">{{ "{:,}".format(month.free) }} free text messages</li>
|
||||
{% endif %}
|
||||
{% if month.paid %}
|
||||
<li class="tabular-numbers">{{ "{:,}".format(month.paid) }} text messages at
|
||||
{{- ' {:.2f}p'.format(sms_rate * 100) }}</li>
|
||||
{% endif %}
|
||||
{% if not (month.free or month.paid) %}
|
||||
<li aria-hidden="true">–</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
<ul>
|
||||
{% for letter in month.letters%}
|
||||
{% if letter[0] %}
|
||||
<li class="tabular-numbers">{{ "{:,}".format(letter[0])}} letters at {{ '{:.0f}p'.format(letter[1] * 100) }}
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endcall %}
|
||||
{% endcall %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="grid-row">
|
||||
<div class="column-half">
|
||||
<p class="align-with-heading-copy">
|
||||
Financial year ends 31 March.
|
||||
</p>
|
||||
</div>
|
||||
<div class="column-half">
|
||||
<p class="align-with-heading-copy">
|
||||
What counts as 1 text message?<br />
|
||||
See <a href="{{ url_for('.pricing') }}">pricing</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -113,4 +113,4 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -616,7 +616,6 @@ def test_usage_page(
|
||||
assert '249,860 free text messages' in table
|
||||
assert '40 free text messages' in table
|
||||
assert '960 text messages at 1.65p' in table
|
||||
|
||||
assert 'April' in table
|
||||
assert 'February' in table
|
||||
assert 'March' in table
|
||||
@@ -626,6 +625,50 @@ def test_usage_page(
|
||||
assert '1,230 text messages at 1.65p' in table
|
||||
|
||||
|
||||
@freeze_time("2012-03-31 12:12:12")
|
||||
def test_usage_page_with_letters(
|
||||
logged_in_client,
|
||||
service_one,
|
||||
mock_get_usage,
|
||||
mock_get_billable_units,
|
||||
mock_get_free_sms_fragment_limit
|
||||
):
|
||||
service_one['permissions'].append('letter')
|
||||
response = logged_in_client.get(url_for('main.usage', service_id=SERVICE_ONE_ID))
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
mock_get_billable_units.assert_called_once_with(SERVICE_ONE_ID, 2011)
|
||||
mock_get_usage.assert_called_once_with(SERVICE_ONE_ID, 2011)
|
||||
mock_get_free_sms_fragment_limit.assert_called_with(SERVICE_ONE_ID, 2011)
|
||||
|
||||
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
|
||||
|
||||
cols = page.find_all('div', {'class': 'column-one-third'})
|
||||
nav = page.find('ul', {'class': 'pill', 'role': 'tablist'})
|
||||
nav_links = nav.find_all('a')
|
||||
|
||||
assert normalize_spaces(nav_links[0].text) == '2010 to 2011 financial year'
|
||||
assert normalize_spaces(nav.find('li', {'aria-selected': 'true'}).text) == '2011 to 2012 financial year'
|
||||
assert normalize_spaces(nav_links[1].text) == '2012 to 2013 financial year'
|
||||
assert '252,190' in cols[1].text
|
||||
assert 'Text messages' in cols[1].text
|
||||
|
||||
table = page.find('table').text.strip()
|
||||
|
||||
assert '249,860 free text messages' in table
|
||||
assert '40 free text messages' in table
|
||||
assert '960 text messages at 1.65p' in table
|
||||
assert 'April' in table
|
||||
assert 'February' in table
|
||||
assert 'March' in table
|
||||
assert '£18.94' in table
|
||||
assert '140 free text messages' in table
|
||||
assert '£20.30' in table
|
||||
assert '1,230 text messages at 1.65p' in table
|
||||
assert '10 letters at 31p' in table
|
||||
|
||||
|
||||
def test_usage_page_with_year_argument(
|
||||
logged_in_client,
|
||||
mock_get_usage,
|
||||
@@ -986,18 +1029,18 @@ def test_get_free_paid_breakdown_for_billable_units(now, expected_number_of_mont
|
||||
]
|
||||
)
|
||||
assert list(billing_units) == [
|
||||
{'free': 100000, 'name': 'April', 'paid': 0},
|
||||
{'free': 100000, 'name': 'May', 'paid': 0},
|
||||
{'free': 50000, 'name': 'June', 'paid': 50000},
|
||||
{'free': 0, 'name': 'July', 'paid': 0},
|
||||
{'free': 0, 'name': 'August', 'paid': 0},
|
||||
{'free': 0, 'name': 'September', 'paid': 0},
|
||||
{'free': 0, 'name': 'October', 'paid': 0},
|
||||
{'free': 0, 'name': 'November', 'paid': 0},
|
||||
{'free': 0, 'name': 'December', 'paid': 0},
|
||||
{'free': 0, 'name': 'January', 'paid': 0},
|
||||
{'free': 0, 'name': 'February', 'paid': 2000},
|
||||
{'free': 0, 'name': 'March', 'paid': 0}
|
||||
{'free': 100000, 'name': 'April', 'paid': 0, 'letter_total': 0, 'letters': [], 'letter_cumulative': 0},
|
||||
{'free': 100000, 'name': 'May', 'paid': 0, 'letter_total': 0, 'letters': [], 'letter_cumulative': 0},
|
||||
{'free': 50000, 'name': 'June', 'paid': 50000, 'letter_total': 0, 'letters': [], 'letter_cumulative': 0},
|
||||
{'free': 0, 'name': 'July', 'paid': 0, 'letter_total': 0, 'letters': [], 'letter_cumulative': 0},
|
||||
{'free': 0, 'name': 'August', 'paid': 0, 'letter_total': 0, 'letters': [], 'letter_cumulative': 0},
|
||||
{'free': 0, 'name': 'September', 'paid': 0, 'letter_total': 0, 'letters': [], 'letter_cumulative': 0},
|
||||
{'free': 0, 'name': 'October', 'paid': 0, 'letter_total': 0, 'letters': [], 'letter_cumulative': 0},
|
||||
{'free': 0, 'name': 'November', 'paid': 0, 'letter_total': 0, 'letters': [], 'letter_cumulative': 0},
|
||||
{'free': 0, 'name': 'December', 'paid': 0, 'letter_total': 0, 'letters': [], 'letter_cumulative': 0},
|
||||
{'free': 0, 'name': 'January', 'paid': 0, 'letter_total': 0, 'letters': [], 'letter_cumulative': 0},
|
||||
{'free': 0, 'name': 'February', 'paid': 2000, 'letter_total': 0, 'letters': [], 'letter_cumulative': 0},
|
||||
{'free': 0, 'name': 'March', 'paid': 0, 'letter_total': 0, 'letters': [], 'letter_cumulative': 0}
|
||||
][:expected_number_of_months]
|
||||
|
||||
|
||||
|
||||
@@ -2155,7 +2155,14 @@ def mock_get_billable_units(mocker):
|
||||
'rate': 0.0165,
|
||||
'billing_units': 100
|
||||
},
|
||||
|
||||
{
|
||||
'month': 'February',
|
||||
'international': False,
|
||||
'rate_multiplier': 1,
|
||||
'notification_type': 'letter',
|
||||
'rate': 0.31,
|
||||
'billing_units': 10
|
||||
}
|
||||
]
|
||||
|
||||
return mocker.patch(
|
||||
|
||||
Reference in New Issue
Block a user