Prepare to replace "billing_units" in usage APIs

There is no such thing as a "billing unit". The data this field
contained was also a confusing mixture of two types:

- For emails and letters, it was just "notifications_sent".

- For SMS, it was the "chargeable_units" (billable * multiplier).

This replaces the single, ambiguous "billing_units" field with
"chargeable_units" and "notifications_sent" in both usage APIs.
Once Admin is using them we can remove the old field.
This commit is contained in:
Ben Thorner
2022-04-20 16:55:38 +01:00
parent 80efdd2ec6
commit fc378fed96
4 changed files with 48 additions and 0 deletions

View File

@@ -17,7 +17,10 @@ def serialize_ft_billing_remove_emails(rows):
{ {
"month": (datetime.strftime(row.month, "%B")), "month": (datetime.strftime(row.month, "%B")),
"notification_type": row.notification_type, "notification_type": row.notification_type,
# TEMPORARY: while we migrate away from "billing_units"
"billing_units": row.billable_units, "billing_units": row.billable_units,
"chargeable_units": row.chargeable_units,
"notifications_sent": row.notifications_sent,
"rate": float(row.rate), "rate": float(row.rate),
"postage": row.postage, "postage": row.postage,
} }
@@ -30,7 +33,10 @@ def serialize_ft_billing_yearly_totals(rows):
return [ return [
{ {
"notification_type": row.notification_type, "notification_type": row.notification_type,
# TEMPORARY: while we migrate away from "billing_units"
"billing_units": row.billable_units, "billing_units": row.billable_units,
"chargeable_units": row.chargeable_units,
"notifications_sent": row.notifications_sent,
"rate": float(row.rate), "rate": float(row.rate),
"letter_total": float(row.billable_units * row.rate) if row.notification_type == 'letter' else 0, "letter_total": float(row.billable_units * row.rate) if row.notification_type == 'letter' else 0,
} }

View File

@@ -220,7 +220,9 @@ def fetch_billing_totals_for_year(service_id, year):
query.c.rate.label("rate"), query.c.rate.label("rate"),
func.sum(query.c.notifications_sent).label("notifications_sent"), func.sum(query.c.notifications_sent).label("notifications_sent"),
# TEMPORARY: while we migrate away from "billing_units"
func.sum(query.c.billable_units).label("billable_units"), func.sum(query.c.billable_units).label("billable_units"),
func.sum(query.c.chargeable_units).label("chargeable_units"),
).group_by( ).group_by(
query.c.rate, query.c.rate,
query.c.notification_type query.c.notification_type
@@ -275,7 +277,9 @@ def fetch_monthly_billing_for_year(service_id, year):
func.date_trunc('month', query.c.bst_date).cast(Date).label("month"), func.date_trunc('month', query.c.bst_date).cast(Date).label("month"),
func.sum(query.c.notifications_sent).label("notifications_sent"), func.sum(query.c.notifications_sent).label("notifications_sent"),
# TEMPORARY: while we migrate away from "billing_units"
func.sum(query.c.billable_units).label("billable_units"), func.sum(query.c.billable_units).label("billable_units"),
func.sum(query.c.chargeable_units).label("chargeable_units"),
).group_by( ).group_by(
query.c.rate, query.c.rate,
query.c.notification_type, query.c.notification_type,
@@ -302,7 +306,9 @@ def query_service_email_usage_for_year(service_id, year):
FactBilling.bst_date, FactBilling.bst_date,
FactBilling.postage, # should always be "none" FactBilling.postage, # should always be "none"
FactBilling.notifications_sent, FactBilling.notifications_sent,
# TEMPORARY: while we migrate away from "billing_units"
FactBilling.notifications_sent.label("billable_units"), FactBilling.notifications_sent.label("billable_units"),
FactBilling.billable_units.label("chargeable_units"),
FactBilling.rate, FactBilling.rate,
FactBilling.notification_type, FactBilling.notification_type,
).filter( ).filter(
@@ -320,7 +326,12 @@ def query_service_letter_usage_for_year(service_id, year):
FactBilling.bst_date, FactBilling.bst_date,
FactBilling.postage, FactBilling.postage,
FactBilling.notifications_sent, FactBilling.notifications_sent,
# TEMPORARY: while we migrate away from "billing_units"
FactBilling.notifications_sent.label("billable_units"), FactBilling.notifications_sent.label("billable_units"),
# We can't use billable_units here as it represents the
# sheet count for letters, which is already accounted for
# in the rate. We actually charge per letter, not sheet.
FactBilling.notifications_sent.label("chargeable_units"),
FactBilling.rate, FactBilling.rate,
FactBilling.notification_type, FactBilling.notification_type,
).filter( ).filter(
@@ -339,7 +350,9 @@ def query_service_sms_usage_for_year(service_id, year):
FactBilling.bst_date, FactBilling.bst_date,
FactBilling.postage, # should always be "none" FactBilling.postage, # should always be "none"
FactBilling.notifications_sent, FactBilling.notifications_sent,
# TEMPORARY: while we migrate away from "billing_units"
chargeable_units.label("billable_units"), chargeable_units.label("billable_units"),
chargeable_units.label("chargeable_units"),
FactBilling.rate, FactBilling.rate,
FactBilling.notification_type, FactBilling.notification_type,
).filter( ).filter(

View File

@@ -170,12 +170,16 @@ def test_get_yearly_usage_by_monthly_from_ft_billing(admin_request, notify_db_se
assert letter_row["month"] == "April" assert letter_row["month"] == "April"
assert letter_row["notification_type"] == "letter" assert letter_row["notification_type"] == "letter"
assert letter_row["billing_units"] == 30 assert letter_row["billing_units"] == 30
assert letter_row["chargeable_units"] == 30
assert letter_row["notifications_sent"] == 30
assert letter_row["rate"] == 0.33 assert letter_row["rate"] == 0.33
assert letter_row["postage"] == "second" assert letter_row["postage"] == "second"
assert sms_row["month"] == "April" assert sms_row["month"] == "April"
assert sms_row["notification_type"] == "sms" assert sms_row["notification_type"] == "sms"
assert sms_row["billing_units"] == 30 assert sms_row["billing_units"] == 30
assert sms_row["chargeable_units"] == 30
assert sms_row["notifications_sent"] == 30
assert sms_row["rate"] == 0.162 assert sms_row["rate"] == 0.162
assert sms_row["postage"] == "none" assert sms_row["postage"] == "none"
@@ -240,15 +244,24 @@ def test_get_yearly_billing_usage_summary_from_ft_billing(admin_request, notify_
) )
assert len(json_response) == 3 assert len(json_response) == 3
assert json_response[0]['notification_type'] == 'email' assert json_response[0]['notification_type'] == 'email'
assert json_response[0]['billing_units'] == 275 assert json_response[0]['billing_units'] == 275
assert json_response[0]['chargeable_units'] == 0
assert json_response[0]['notifications_sent'] == 275
assert json_response[0]['rate'] == 0 assert json_response[0]['rate'] == 0
assert json_response[0]['letter_total'] == 0 assert json_response[0]['letter_total'] == 0
assert json_response[1]['notification_type'] == 'letter' assert json_response[1]['notification_type'] == 'letter'
assert json_response[1]['billing_units'] == 275 assert json_response[1]['billing_units'] == 275
assert json_response[1]['chargeable_units'] == 275
assert json_response[1]['notifications_sent'] == 275
assert json_response[1]['rate'] == 0.33 assert json_response[1]['rate'] == 0.33
assert json_response[1]['letter_total'] == 90.75 assert json_response[1]['letter_total'] == 90.75
assert json_response[2]['notification_type'] == 'sms' assert json_response[2]['notification_type'] == 'sms'
assert json_response[2]['billing_units'] == 825 assert json_response[2]['billing_units'] == 825
assert json_response[2]['chargeable_units'] == 825
assert json_response[2]['notifications_sent'] == 550
assert json_response[2]['rate'] == 0.0162 assert json_response[2]['rate'] == 0.0162
assert json_response[2]['letter_total'] == 0 assert json_response[2]['letter_total'] == 0

View File

@@ -434,24 +434,28 @@ def test_fetch_monthly_billing_for_year(notify_db_session):
assert results[0].notification_type == 'email' assert results[0].notification_type == 'email'
assert results[0].notifications_sent == 30 assert results[0].notifications_sent == 30
assert results[0].billable_units == 30 assert results[0].billable_units == 30
assert results[0].chargeable_units == 0
assert results[0].rate == Decimal('0') assert results[0].rate == Decimal('0')
assert str(results[1].month) == "2016-04-01" assert str(results[1].month) == "2016-04-01"
assert results[1].notification_type == 'letter' assert results[1].notification_type == 'letter'
assert results[1].notifications_sent == 30 assert results[1].notifications_sent == 30
assert results[1].billable_units == 30 assert results[1].billable_units == 30
assert results[1].chargeable_units == 30
assert results[1].rate == Decimal('0.30') assert results[1].rate == Decimal('0.30')
assert str(results[1].month) == "2016-04-01" assert str(results[1].month) == "2016-04-01"
assert results[2].notification_type == 'letter' assert results[2].notification_type == 'letter'
assert results[2].notifications_sent == 30 assert results[2].notifications_sent == 30
assert results[2].billable_units == 30 assert results[2].billable_units == 30
assert results[2].chargeable_units == 30
assert results[2].rate == Decimal('0.33') assert results[2].rate == Decimal('0.33')
assert str(results[3].month) == "2016-04-01" assert str(results[3].month) == "2016-04-01"
assert results[3].notification_type == 'sms' assert results[3].notification_type == 'sms'
assert results[3].notifications_sent == 30 assert results[3].notifications_sent == 30
assert results[3].billable_units == 30 assert results[3].billable_units == 30
assert results[3].chargeable_units == 30
assert results[3].rate == Decimal('0.162') assert results[3].rate == Decimal('0.162')
assert str(results[4].month) == "2016-05-01" assert str(results[4].month) == "2016-05-01"
@@ -469,24 +473,28 @@ def test_fetch_monthly_billing_for_year_variable_rates(notify_db_session):
assert results[0].notification_type == 'letter' assert results[0].notification_type == 'letter'
assert results[0].notifications_sent == 1 assert results[0].notifications_sent == 1
assert results[0].billable_units == 1 assert results[0].billable_units == 1
assert results[0].chargeable_units == 1
assert results[0].rate == Decimal('0.33') assert results[0].rate == Decimal('0.33')
assert str(results[1].month) == "2018-05-01" assert str(results[1].month) == "2018-05-01"
assert results[1].notification_type == 'letter' assert results[1].notification_type == 'letter'
assert results[1].notifications_sent == 2 assert results[1].notifications_sent == 2
assert results[1].billable_units == 2 assert results[1].billable_units == 2
assert results[1].chargeable_units == 2
assert results[1].rate == Decimal('0.36') assert results[1].rate == Decimal('0.36')
assert str(results[2].month) == "2018-05-01" assert str(results[2].month) == "2018-05-01"
assert results[2].notification_type == 'sms' assert results[2].notification_type == 'sms'
assert results[2].notifications_sent == 1 assert results[2].notifications_sent == 1
assert results[2].billable_units == 4 assert results[2].billable_units == 4
assert results[2].chargeable_units == 4
assert results[2].rate == Decimal('0.015') assert results[2].rate == Decimal('0.015')
assert str(results[3].month) == "2018-05-01" assert str(results[3].month) == "2018-05-01"
assert results[3].notification_type == 'sms' assert results[3].notification_type == 'sms'
assert results[3].notifications_sent == 2 assert results[3].notifications_sent == 2
assert results[3].billable_units == 5 assert results[3].billable_units == 5
assert results[3].chargeable_units == 5
assert results[3].rate == Decimal('0.162') assert results[3].rate == Decimal('0.162')
@@ -517,21 +525,25 @@ def test_fetch_billing_totals_for_year(notify_db_session):
assert results[0].notification_type == 'email' assert results[0].notification_type == 'email'
assert results[0].notifications_sent == 365 assert results[0].notifications_sent == 365
assert results[0].billable_units == 365 assert results[0].billable_units == 365
assert results[0].chargeable_units == 0
assert results[0].rate == Decimal('0') assert results[0].rate == Decimal('0')
assert results[1].notification_type == 'letter' assert results[1].notification_type == 'letter'
assert results[1].notifications_sent == 365 assert results[1].notifications_sent == 365
assert results[1].billable_units == 365 assert results[1].billable_units == 365
assert results[1].chargeable_units == 365
assert results[1].rate == Decimal('0.3') assert results[1].rate == Decimal('0.3')
assert results[2].notification_type == 'letter' assert results[2].notification_type == 'letter'
assert results[2].notifications_sent == 365 assert results[2].notifications_sent == 365
assert results[2].billable_units == 365 assert results[2].billable_units == 365
assert results[2].chargeable_units == 365
assert results[2].rate == Decimal('0.33') assert results[2].rate == Decimal('0.33')
assert results[3].notification_type == 'sms' assert results[3].notification_type == 'sms'
assert results[3].notifications_sent == 365 assert results[3].notifications_sent == 365
assert results[3].billable_units == 365 assert results[3].billable_units == 365
assert results[3].chargeable_units == 365
assert results[3].rate == Decimal('0.162') assert results[3].rate == Decimal('0.162')
@@ -543,21 +555,25 @@ def test_fetch_billing_totals_for_year_variable_rates(notify_db_session):
assert results[0].notification_type == 'letter' assert results[0].notification_type == 'letter'
assert results[0].notifications_sent == 1 assert results[0].notifications_sent == 1
assert results[0].billable_units == 1 assert results[0].billable_units == 1
assert results[0].chargeable_units == 1
assert results[0].rate == Decimal('0.33') assert results[0].rate == Decimal('0.33')
assert results[1].notification_type == 'letter' assert results[1].notification_type == 'letter'
assert results[1].notifications_sent == 2 assert results[1].notifications_sent == 2
assert results[1].billable_units == 2 assert results[1].billable_units == 2
assert results[1].chargeable_units == 2
assert results[1].rate == Decimal('0.36') assert results[1].rate == Decimal('0.36')
assert results[2].notification_type == 'sms' assert results[2].notification_type == 'sms'
assert results[2].notifications_sent == 1 assert results[2].notifications_sent == 1
assert results[2].billable_units == 4 assert results[2].billable_units == 4
assert results[2].chargeable_units == 4
assert results[2].rate == Decimal('0.015') assert results[2].rate == Decimal('0.015')
assert results[3].notification_type == 'sms' assert results[3].notification_type == 'sms'
assert results[3].notifications_sent == 2 assert results[3].notifications_sent == 2
assert results[3].billable_units == 5 assert results[3].billable_units == 5
assert results[3].chargeable_units == 5
assert results[3].rate == Decimal('0.162') assert results[3].rate == Decimal('0.162')