diff --git a/app/main/views/dashboard.py b/app/main/views/dashboard.py
index 4c2b05b91..b21bf0fdf 100644
--- a/app/main/views/dashboard.py
+++ b/app/main/views/dashboard.py
@@ -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
}
diff --git a/app/templates/views/usage-with-letters.html b/app/templates/views/usage-with-letters.html
new file mode 100644
index 000000000..7d26976d6
--- /dev/null
+++ b/app/templates/views/usage-with-letters.html
@@ -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 %}
+
+
Usage
+
+
+ {{ pill(years, selected_year, big_number_args={'smallest': True}) }}
+
+
+
+
+
Emails
+
+ {{ big_number(emails_sent, 'sent', smaller=True) }}
+ {{ big_number("Unlimited", 'free allowance', smaller=True) }}
+
+
+
+
Text messages
+
+ {{ 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 %}
+
+
+
+
Letters
+
+ {{ big_number(letter_sent, 'sent', smaller=True) }}
+
+
+
+
+
+
+
+
+ {{ big_number(
+ (sms_chargeable * sms_rate),
+ 'spent',
+ currency="£",
+ smaller=True
+ ) }}
+
+
+
+
+ {{ big_number(
+ letter_cost,
+ 'spent',
+ currency="£",
+ smaller=True
+ ) }}
+
+
+
+
+
+ {% if months %}
+
+ {% 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
+ ) }}
+
+ {% if month.free %}
+ - {{ "{:,}".format(month.free) }} free text messages
+ {% endif %}
+ {% if month.paid %}
+ - {{ "{:,}".format(month.paid) }} text messages at
+ {{- ' {:.2f}p'.format(sms_rate * 100) }}
+ {% endif %}
+ {% if not (month.free or month.paid) %}
+ - –
+ {% endif %}
+
+
+ {% for letter in month.letters%}
+ {% if letter[0] %}
+ - {{ "{:,}".format(letter[0])}} letters at {{ '{:.0f}p'.format(letter[1] * 100) }}
+
+ {% endif %}
+ {% endfor %}
+
+ {% endcall %}
+ {% endcall %}
+
+ {% endif %}
+
+
+
+
+
+ Financial year ends 31 March.
+
+
+
+
+ What counts as 1 text message?
+ See pricing.
+
+
+
+
+{% endblock %}
diff --git a/app/templates/views/usage.html b/app/templates/views/usage.html
index 3b8fe412d..85fbf32c3 100644
--- a/app/templates/views/usage.html
+++ b/app/templates/views/usage.html
@@ -113,4 +113,4 @@
-{% endblock %}
+{% endblock %}
\ No newline at end of file
diff --git a/tests/app/main/views/test_dashboard.py b/tests/app/main/views/test_dashboard.py
index a98a4b72a..66163724b 100644
--- a/tests/app/main/views/test_dashboard.py
+++ b/tests/app/main/views/test_dashboard.py
@@ -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]
diff --git a/tests/conftest.py b/tests/conftest.py
index 88ed70fb8..3e9c5c466 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -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(