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 + ) }} + + + {% 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(