diff --git a/app/main/views/dashboard.py b/app/main/views/dashboard.py
index 72f8f62b8..1aa5c1c37 100644
--- a/app/main/views/dashboard.py
+++ b/app/main/views/dashboard.py
@@ -418,8 +418,8 @@ def get_months_for_year(start, end, year):
def get_sum_billing_units(billing_units, month=None):
if month:
- return sum(b['billing_units'] * b.get('rate_multiplier', 1) for b in billing_units if b['month'] == month)
- return sum(b['billing_units'] * b.get('rate_multiplier', 1) for b in billing_units)
+ return sum(b['billing_units'] for b in billing_units if b['month'] == month)
+ return sum(b['billing_units'] for b in billing_units)
def get_free_paid_breakdown_for_billable_units(year, free_sms_fragment_limit, billing_units):
@@ -435,8 +435,12 @@ def get_free_paid_breakdown_for_billable_units(year, free_sms_fragment_limit, bi
free_sms_fragment_limit, cumulative, previous_cumulative,
[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']))
+ letter_billing = [(x['billing_units'], x['rate'], (x['billing_units'] * x['rate']), x['postage'])
for x in letter_units if x['month'] == month]
+
+ if letter_billing:
+ letter_billing.sort(key=lambda x: (x[3], x[1]))
+
letter_total = 0
for x in letter_billing:
letter_total += x[2]
diff --git a/app/templates/views/usage-with-letters.html b/app/templates/views/usage-with-letters.html
index 7d26976d6..ea5e06678 100644
--- a/app/templates/views/usage-with-letters.html
+++ b/app/templates/views/usage-with-letters.html
@@ -1,4 +1,5 @@
{% from "components/big-number.html" import big_number %}
+{% from "components/message-count-label.html" import message_count_label %}
{% from "components/table.html" import list_table, field, hidden_field_heading, row_heading, text_field %}
{% from "components/pill.html" import pill %}
@@ -100,10 +101,10 @@
) }}
{% if month.free %}
- - {{ "{:,}".format(month.free) }} free text messages
+ - {{ "{:,}".format(month.free) }} free {{ message_count_label(month.free, 'sms', '') }}
{% endif %}
{% if month.paid %}
- - {{ "{:,}".format(month.paid) }} text messages at
+
- {{ "{:,}".format(month.paid) }} {{ message_count_label(month.paid, 'sms', '') }}at
{{- ' {:.2f}p'.format(sms_rate * 100) }}
{% endif %}
{% if not (month.free or month.paid) %}
@@ -113,8 +114,8 @@
{% for letter in month.letters%}
{% if letter[0] %}
- - {{ "{:,}".format(letter[0])}} letters at {{ '{:.0f}p'.format(letter[1] * 100) }}
-
+ - {{ "{:,} {}".format(letter[0], letter[3])}} class {{ message_count_label(letter[0], 'letter', '') }}at
+ {{ '{:.0f}p'.format(letter[1] * 100) }}
{% endif %}
{% endfor %}
diff --git a/app/templates/views/usage.html b/app/templates/views/usage.html
index 85fbf32c3..f85bd07c4 100644
--- a/app/templates/views/usage.html
+++ b/app/templates/views/usage.html
@@ -1,4 +1,5 @@
{% from "components/big-number.html" import big_number %}
+{% from "components/message-count-label.html" import message_count_label %}
{% from "components/table.html" import list_table, field, hidden_field_heading, row_heading, text_field %}
{% from "components/pill.html" import pill %}
@@ -83,10 +84,10 @@
) }}
{% if month.free %}
- - {{ "{:,}".format(month.free) }} free text messages
+ - {{ "{:,}".format(month.free) }} free {{ message_count_label(month.free, 'sms', '') }}
{% endif %}
{% if month.paid %}
- - {{ "{:,}".format(month.paid) }} text messages at
+
- {{ "{:,}".format(month.paid) }} {{ message_count_label(month.free, 'sms', '') }}at
{{- ' {:.2f}p'.format(sms_rate * 100) }}
{% endif %}
{% if not (month.free or month.paid) %}
@@ -113,4 +114,4 @@
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/tests/app/main/views/test_dashboard.py b/tests/app/main/views/test_dashboard.py
index 0cac648ea..862206efb 100644
--- a/tests/app/main/views/test_dashboard.py
+++ b/tests/app/main/views/test_dashboard.py
@@ -808,8 +808,35 @@ def test_usage_page_with_letters(
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
- assert '5 letters at 33p' in table
+ assert '10 second class letters at 31p' in normalize_spaces(table)
+ assert '5 first class letters at 33p' in normalize_spaces(table)
+
+
+@freeze_time("2012-04-30 12:12:12")
+def test_usage_page_displays_letters_ordered_by_postage(
+ mocker,
+ logged_in_client,
+ service_one,
+ mock_get_usage,
+ mock_get_free_sms_fragment_limit
+):
+ billable_units_resp = [
+ {'month': 'April', 'notification_type': 'letter', 'rate': 0.5, 'billing_units': 1, 'postage': 'second'},
+ {'month': 'April', 'notification_type': 'letter', 'rate': 0.3, 'billing_units': 3, 'postage': 'second'},
+ {'month': 'April', 'notification_type': 'letter', 'rate': 0.5, 'billing_units': 1, 'postage': 'first'},
+ ]
+ mocker.patch('app.billing_api_client.get_billable_units_ft', return_value=billable_units_resp)
+ service_one['permissions'].append('letter')
+ response = logged_in_client.get(url_for('main.usage', service_id=SERVICE_ONE_ID))
+
+ page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
+ row_for_april = page.find('table').find('tr', class_='table-row')
+ postage_details = row_for_april.find_all('li', class_='tabular-numbers')
+
+ assert len(postage_details) == 3
+ assert normalize_spaces(postage_details[0].text) == '1 first class letter at 50p'
+ assert normalize_spaces(postage_details[1].text) == '3 second class letters at 30p'
+ assert normalize_spaces(postage_details[2].text) == '1 second class letter at 50p'
def test_usage_page_with_year_argument(
diff --git a/tests/conftest.py b/tests/conftest.py
index 66cd2ccce..cb43e4387 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -2278,16 +2278,11 @@ def mock_get_template_statistics_for_template(mocker, service_one):
def mock_get_usage(mocker, service_one, fake_uuid):
def _get_usage(service_id, year=None):
return [
- {"international": False, "rate": 0.00, "notification_type": "email",
- "rate_multiplier": None, "billing_units": 1000},
- {"international": False, "rate": 0.0165, "rate_multiplier": 1,
- "notification_type": "sms", "billing_units": 251500},
- {"international": True, "rate": 0.0165, "rate_multiplier": 1,
- "notification_type": "sms", "billing_units": 300},
- {"international": True, "rate": 0.0165, "rate_multiplier": 2,
- "notification_type": "sms", "billing_units": 150},
- {"international": True, "rate": 0.0165, "rate_multiplier": 3,
- "notification_type": "sms", "billing_units": 30},
+ {"notification_type": "email", "billing_units": 1000, "rate": 0.00, "letter_total": 0},
+ {"notification_type": "sms", "billing_units": 251500, "rate": 0.0165, "letter_total": 0},
+ {"notification_type": "sms", "billing_units": 300, "rate": 0.0165, "letter_total": 0},
+ {"notification_type": "sms", "billing_units": 300, "rate": 0.0165, "letter_total": 0},
+ {"notification_type": "sms", "billing_units": 90, "rate": 0.0165, "letter_total": 0}
]
return mocker.patch(
@@ -2300,99 +2295,87 @@ def mock_get_billable_units(mocker):
return [
{
'month': 'April',
- 'international': False,
- 'rate_multiplier': 1,
'notification_type': 'sms',
'rate': 0.0165,
- 'billing_units': 249500
+ 'billing_units': 249500,
+ 'postage': 'none',
},
{
'month': 'April',
- 'international': True,
- 'rate_multiplier': 1,
'notification_type': 'sms',
'rate': 0.0165,
- 'billing_units': 100
+ 'billing_units': 100,
+ 'postage': 'none',
},
{
'month': 'April',
- 'international': True,
- 'rate_multiplier': 2,
'notification_type': 'sms',
'rate': 0.0165,
- 'billing_units': 100
+ 'billing_units': 200,
+ 'postage': 'none',
},
{
'month': 'April',
- 'international': True,
- 'rate_multiplier': 3,
'notification_type': 'sms',
'rate': 0.0165,
- 'billing_units': 20
+ 'billing_units': 60,
+ 'postage': 'none',
},
{
'month': 'March',
- 'international': False,
- 'rate_multiplier': 1,
'notification_type': 'sms',
'rate': 0.0165,
- 'billing_units': 1000
+ 'billing_units': 1000,
+ 'postage': 'none',
},
{
'month': 'March',
- 'international': True,
- 'rate_multiplier': 1,
'notification_type': 'sms',
'rate': 0.0165,
- 'billing_units': 100
+ 'billing_units': 100,
+ 'postage': 'none',
},
{
'month': 'March',
- 'international': True,
- 'rate_multiplier': 2,
'notification_type': 'sms',
'rate': 0.0165,
- 'billing_units': 50
+ 'billing_units': 100,
+ 'postage': 'none',
},
{
'month': 'March',
- 'international': True,
- 'rate_multiplier': 3,
'notification_type': 'sms',
'rate': 0.0165,
- 'billing_units': 10
+ 'billing_units': 30,
+ 'postage': 'none',
},
{
'month': 'February',
- 'international': False,
- 'rate_multiplier': 1,
'notification_type': 'sms',
'rate': 0.0165,
- 'billing_units': 1000
+ 'billing_units': 1000,
+ 'postage': 'none',
},
{
'month': 'February',
- 'international': True,
- 'rate_multiplier': 1,
'notification_type': 'sms',
'rate': 0.0165,
- 'billing_units': 100
+ 'billing_units': 100,
+ 'postage': 'none',
},
{
'month': 'February',
- 'international': False,
- 'rate_multiplier': 1,
'notification_type': 'letter',
'rate': 0.31,
- 'billing_units': 10
+ 'billing_units': 10,
+ 'postage': 'second',
},
{
'month': 'February',
- 'international': False,
- 'rate_multiplier': 1,
'notification_type': 'letter',
'rate': 0.33,
- 'billing_units': 5
+ 'billing_units': 5,
+ 'postage': 'first',
}
]
@@ -2405,12 +2388,12 @@ def mock_get_future_usage(mocker, service_one, fake_uuid):
def _get_usage(service_id, year=None):
return [
{
- 'notification_type': 'sms', 'international': False,
- 'credits': 0, 'rate_multiplier': 1, 'rate': 0.0158, 'billing_units': 0
+ 'notification_type': 'sms', 'billing_units': 0,
+ 'rate': 0.0158, 'letter_total': 0
},
{
- 'notification_type': 'email', 'international': False,
- 'credits': 0, 'rate_multiplier': 1, 'rate': 0, 'billing_units': 0
+ 'notification_type': 'email', 'billing_units': 0,
+ 'rate': 0.0, 'letter_total': 0
}
]