mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-05-29 10:30:20 -04:00
Merge pull request #1255 from alphagov/add-international-usage-stats
Add international usage stats
This commit is contained in:
@@ -113,7 +113,7 @@ def usage(service_id):
|
||||
start=current_financial_year - 1,
|
||||
end=current_financial_year + 1,
|
||||
),
|
||||
**calculate_usage(service_api_client.get_service_usage(service_id, year)['data'])
|
||||
**calculate_usage(service_api_client.get_service_usage(service_id, year))
|
||||
)
|
||||
|
||||
|
||||
@@ -189,7 +189,7 @@ def get_dashboard_partials(service_id):
|
||||
**calculate_usage(service_api_client.get_service_usage(
|
||||
service_id,
|
||||
get_current_financial_year(),
|
||||
)['data'])
|
||||
))
|
||||
),
|
||||
}
|
||||
|
||||
@@ -204,10 +204,11 @@ def get_dashboard_totals(statistics):
|
||||
def calculate_usage(usage):
|
||||
# TODO: Don't hardcode these - get em from the API
|
||||
sms_free_allowance = 250000
|
||||
sms_rate = 0.0165
|
||||
|
||||
sms_sent = usage.get('sms_count', 0)
|
||||
emails_sent = usage.get('email_count', 0)
|
||||
sms_rate = 0 if len(usage) == 0 else usage[0].get("rate", 0)
|
||||
sms_sent = get_sum_billing_units(breakdown for breakdown in usage if breakdown['notification_type'] == 'sms')
|
||||
emails = [breakdown["billing_units"] for breakdown in usage if breakdown['notification_type'] == 'email']
|
||||
emails_sent = 0 if len(emails) == 0 else emails[0]
|
||||
|
||||
return {
|
||||
'emails_sent': emails_sent,
|
||||
@@ -215,7 +216,7 @@ def calculate_usage(usage):
|
||||
'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
|
||||
'sms_rate': sms_rate,
|
||||
}
|
||||
|
||||
|
||||
@@ -262,14 +263,21 @@ def get_months_for_year(start, end, year):
|
||||
return [datetime(year, month, 1) for month in range(start, end)]
|
||||
|
||||
|
||||
def get_free_paid_breakdown_for_billable_units(year, billable_units):
|
||||
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)
|
||||
|
||||
|
||||
def get_free_paid_breakdown_for_billable_units(year, billing_units):
|
||||
cumulative = 0
|
||||
for month in get_months_for_financial_year(year):
|
||||
previous_cumulative = cumulative
|
||||
monthly_usage = billable_units.get(month, 0)
|
||||
monthly_usage = get_sum_billing_units(billing_units, month)
|
||||
cumulative += monthly_usage
|
||||
breakdown = get_free_paid_breakdown_for_month(
|
||||
cumulative, previous_cumulative, monthly_usage
|
||||
cumulative, previous_cumulative,
|
||||
[billing_month for billing_month in billing_units if billing_month['month'] == month]
|
||||
)
|
||||
yield {
|
||||
'name': month,
|
||||
@@ -285,20 +293,23 @@ def get_free_paid_breakdown_for_month(
|
||||
):
|
||||
allowance = 250000
|
||||
|
||||
total_monthly_billing_units = get_sum_billing_units(monthly_usage)
|
||||
|
||||
if cumulative < allowance:
|
||||
return {
|
||||
'paid': 0,
|
||||
'free': monthly_usage,
|
||||
'free': total_monthly_billing_units,
|
||||
}
|
||||
elif previous_cumulative < allowance:
|
||||
remaining_allowance = allowance - previous_cumulative
|
||||
return {
|
||||
'paid': monthly_usage - (allowance - previous_cumulative),
|
||||
'free': allowance - previous_cumulative
|
||||
'paid': total_monthly_billing_units - remaining_allowance,
|
||||
'free': remaining_allowance,
|
||||
}
|
||||
else:
|
||||
return {
|
||||
'paid': monthly_usage,
|
||||
'free': 0
|
||||
'paid': total_monthly_billing_units,
|
||||
'free': 0,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -217,7 +217,7 @@ class ServiceAPIClient(NotifyAdminAPIClient):
|
||||
|
||||
def get_service_usage(self, service_id, year=None):
|
||||
return self.get(
|
||||
'/service/{0}/fragment/aggregate_statistics'.format(service_id),
|
||||
'/service/{0}/yearly-usage'.format(service_id),
|
||||
params=dict(year=year)
|
||||
)
|
||||
|
||||
@@ -231,7 +231,10 @@ class ServiceAPIClient(NotifyAdminAPIClient):
|
||||
return self.put(url='/service/{}/whitelist'.format(service_id), data=data)
|
||||
|
||||
def get_billable_units(self, service_id, year):
|
||||
return self.get(url='/service/{}/billable-units?year={}'.format(service_id, year))
|
||||
return self.get(
|
||||
'/service/{0}/monthly-usage'.format(service_id),
|
||||
params=dict(year=year)
|
||||
)
|
||||
|
||||
|
||||
class ServicesBrowsableItem(BrowsableItem):
|
||||
|
||||
@@ -223,21 +223,22 @@ def test_usage_page(
|
||||
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 '123' in cols[0].text
|
||||
assert 'Emails' in cols[0].text
|
||||
|
||||
assert '456,123' in cols[1].text
|
||||
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 '123 free text messages' in table
|
||||
assert '£3,403.06' in table
|
||||
assert '249,877 free text messages' in table
|
||||
assert '206,246 text messages at 1.65p' in table
|
||||
assert '£15.84' in table
|
||||
assert '140 free text messages' in table
|
||||
assert '£20.30' in table
|
||||
assert '1,230 text messages at 1.65p' in table
|
||||
|
||||
|
||||
def test_usage_page_with_year_argument(
|
||||
@@ -256,6 +257,18 @@ def test_usage_page_for_invalid_year(
|
||||
assert logged_in_client.get(url_for('main.usage', service_id=SERVICE_ONE_ID, year='abcd')).status_code == 404
|
||||
|
||||
|
||||
@freeze_time("2012-03-31 12:12:12")
|
||||
def test_future_usage_page(
|
||||
logged_in_client,
|
||||
mock_get_future_usage,
|
||||
mock_get_future_billable_units,
|
||||
):
|
||||
assert logged_in_client.get(url_for('main.usage', service_id=SERVICE_ONE_ID, year=2014)).status_code == 200
|
||||
|
||||
mock_get_future_billable_units.assert_called_once_with(SERVICE_ONE_ID, 2014)
|
||||
mock_get_future_usage.assert_called_once_with(SERVICE_ONE_ID, 2014)
|
||||
|
||||
|
||||
def _test_dashboard_menu(mocker, app_, usr, service, permissions):
|
||||
with app_.test_request_context():
|
||||
with app_.test_client() as client:
|
||||
@@ -552,26 +565,39 @@ def test_aggregate_status_types(dict_in, expected_failed, expected_requested):
|
||||
)
|
||||
def test_get_free_paid_breakdown_for_billable_units(now, expected_number_of_months):
|
||||
with now:
|
||||
assert list(get_free_paid_breakdown_for_billable_units(
|
||||
2016, {
|
||||
'April': 100000,
|
||||
'May': 100000,
|
||||
'June': 100000,
|
||||
'February': 1234
|
||||
}
|
||||
)) == [
|
||||
{'name': 'April', 'free': 100000, 'paid': 0},
|
||||
{'name': 'May', 'free': 100000, 'paid': 0},
|
||||
{'name': 'June', 'free': 50000, 'paid': 50000},
|
||||
{'name': 'July', 'free': 0, 'paid': 0},
|
||||
{'name': 'August', 'free': 0, 'paid': 0},
|
||||
{'name': 'September', 'free': 0, 'paid': 0},
|
||||
{'name': 'October', 'free': 0, 'paid': 0},
|
||||
{'name': 'November', 'free': 0, 'paid': 0},
|
||||
{'name': 'December', 'free': 0, 'paid': 0},
|
||||
{'name': 'January', 'free': 0, 'paid': 0},
|
||||
{'name': 'February', 'free': 0, 'paid': 1234},
|
||||
{'name': 'March', 'free': 0, 'paid': 0}
|
||||
billing_units = get_free_paid_breakdown_for_billable_units(
|
||||
2016, [
|
||||
{
|
||||
'month': 'April', 'international': False, 'rate_multiplier': 1,
|
||||
'notification_type': 'sms', 'rate': 1.65, 'billing_units': 100000
|
||||
},
|
||||
{
|
||||
'month': 'May', 'international': False, 'rate_multiplier': 1,
|
||||
'notification_type': 'sms', 'rate': 1.65, 'billing_units': 100000
|
||||
},
|
||||
{
|
||||
'month': 'June', 'international': False, 'rate_multiplier': 1,
|
||||
'notification_type': 'sms', 'rate': 1.65, 'billing_units': 100000
|
||||
},
|
||||
{
|
||||
'month': 'February', 'international': False, 'rate_multiplier': 1,
|
||||
'notification_type': 'sms', 'rate': 1.65, 'billing_units': 2000
|
||||
},
|
||||
]
|
||||
)
|
||||
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}
|
||||
][:expected_number_of_months]
|
||||
|
||||
|
||||
|
||||
@@ -1315,10 +1315,18 @@ def mock_get_template_statistics_for_template(mocker, service_one):
|
||||
@pytest.fixture(scope='function')
|
||||
def mock_get_usage(mocker, service_one, fake_uuid):
|
||||
def _get_usage(service_id, year=None):
|
||||
return {'data': {
|
||||
"sms_count": 456123,
|
||||
"email_count": 123
|
||||
}}
|
||||
return [
|
||||
{"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},
|
||||
{"international": False, "rate": 0.0165, "notification_type": "email",
|
||||
"rate_multiplier": None, "billing_units": 1000}
|
||||
]
|
||||
|
||||
return mocker.patch(
|
||||
'app.service_api_client.get_service_usage', side_effect=_get_usage)
|
||||
@@ -1327,10 +1335,116 @@ def mock_get_usage(mocker, service_one, fake_uuid):
|
||||
@pytest.fixture(scope='function')
|
||||
def mock_get_billable_units(mocker):
|
||||
def _get_usage(service_id, year):
|
||||
return {
|
||||
"April": 123,
|
||||
"March": 456123
|
||||
}
|
||||
return [
|
||||
{
|
||||
'month': 'April',
|
||||
'international': False,
|
||||
'rate_multiplier': 1,
|
||||
'notification_type': 'sms',
|
||||
'rate': 1.65,
|
||||
'billing_units': 249500
|
||||
},
|
||||
{
|
||||
'month': 'April',
|
||||
'international': True,
|
||||
'rate_multiplier': 1,
|
||||
'notification_type': 'sms',
|
||||
'rate': 1.65,
|
||||
'billing_units': 100
|
||||
},
|
||||
{
|
||||
'month': 'April',
|
||||
'international': True,
|
||||
'rate_multiplier': 2,
|
||||
'notification_type': 'sms',
|
||||
'rate': 1.65,
|
||||
'billing_units': 100
|
||||
},
|
||||
{
|
||||
'month': 'April',
|
||||
'international': True,
|
||||
'rate_multiplier': 3,
|
||||
'notification_type': 'sms',
|
||||
'rate': 1.65,
|
||||
'billing_units': 20
|
||||
},
|
||||
{
|
||||
'month': 'March',
|
||||
'international': False,
|
||||
'rate_multiplier': 1,
|
||||
'notification_type': 'sms',
|
||||
'rate': 1.65,
|
||||
'billing_units': 1000
|
||||
},
|
||||
{
|
||||
'month': 'March',
|
||||
'international': True,
|
||||
'rate_multiplier': 1,
|
||||
'notification_type': 'sms',
|
||||
'rate': 1.65,
|
||||
'billing_units': 100
|
||||
},
|
||||
{
|
||||
'month': 'March',
|
||||
'international': True,
|
||||
'rate_multiplier': 2,
|
||||
'notification_type': 'sms',
|
||||
'rate': 1.65,
|
||||
'billing_units': 50
|
||||
},
|
||||
{
|
||||
'month': 'March',
|
||||
'international': True,
|
||||
'rate_multiplier': 3,
|
||||
'notification_type': 'sms',
|
||||
'rate': 1.65,
|
||||
'billing_units': 10
|
||||
},
|
||||
{
|
||||
'month': 'February',
|
||||
'international': False,
|
||||
'rate_multiplier': 1,
|
||||
'notification_type': 'sms',
|
||||
'rate': 1.65,
|
||||
'billing_units': 1000
|
||||
},
|
||||
{
|
||||
'month': 'February',
|
||||
'international': True,
|
||||
'rate_multiplier': 1,
|
||||
'notification_type': 'sms',
|
||||
'rate': 1.65,
|
||||
'billing_units': 100
|
||||
},
|
||||
|
||||
]
|
||||
|
||||
return mocker.patch(
|
||||
'app.service_api_client.get_billable_units', side_effect=_get_usage)
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
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': 1.58, 'billing_units': 0
|
||||
},
|
||||
{
|
||||
'notification_type': 'email', 'international': False,
|
||||
'credits': 0, 'rate_multiplier': 1, 'rate': 0, 'billing_units': 0
|
||||
}
|
||||
]
|
||||
|
||||
return mocker.patch(
|
||||
'app.service_api_client.get_service_usage', side_effect=_get_usage)
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def mock_get_future_billable_units(mocker):
|
||||
def _get_usage(service_id, year):
|
||||
return []
|
||||
|
||||
return mocker.patch(
|
||||
'app.service_api_client.get_billable_units', side_effect=_get_usage)
|
||||
|
||||
Reference in New Issue
Block a user