mirror of
https://github.com/GSA/notifications-api.git
synced 2026-06-16 19:28:50 -04:00
calculate free allowance used within ft_billing_subquery
previously we were looking at the chargeable units from within the subquery, and then subtracting those from the free allowance to get the free allowance remaining (sms_remainder). this is fine for the org and service usage reports, which query for an entire financial year. however, the platform admin report is used for smaller periods, generally monthly. this has the problem when we're querying, eg, may 1st to 30th. Lets say a service has a free allowance of 10000 and sends 4000 messages in april and 5000 in may. we should be reporting their sms remainder as 1000. However, when joining to the sms billing subquery we want to filter out rows not in may, so that we can report on their usage that month only. So we put in the bst_date filter - this means that the "sms_billable_units", "chargeable_sms", and "sms_cost" only report on that month. That's good. But remainder we were just looking at chargeable sms and subtracting from the free allowance, ignoring however much had been sent in april. To solve this, move the free allowance remainder calc into the subquery (which runs on the entire financial year, so has context about april's usage as well). Essentially the chargeable_units_used_before_this_row, plus this row.
This commit is contained in:
@@ -70,11 +70,13 @@ def fetch_sms_billing_for_all_services(start_date, end_date):
|
||||
# ASSUMPTION: AnnualBilling has been populated for year.
|
||||
ft_billing_subquery = query_sms_usage_for_year_per_service(financial_year).subquery()
|
||||
|
||||
sms_billable_units = func.sum(func.coalesce(ft_billing_subquery.c.chargeable_units, 0))
|
||||
sms_billable_units = func.sum(ft_billing_subquery.c.chargeable_units)
|
||||
|
||||
# subtract sms_billable_units units accrued since report's start date to get up-to-date
|
||||
# allowance remainder
|
||||
sms_allowance_left = func.greatest(AnnualBilling.free_sms_fragment_limit - sms_billable_units, 0)
|
||||
# get the lowest value allowance (which will be the last date within our filter range)
|
||||
sms_allowance_left = func.greatest(
|
||||
func.min(AnnualBilling.free_sms_fragment_limit - ft_billing_subquery.c.free_allowance_used_to_date),
|
||||
0
|
||||
)
|
||||
|
||||
chargeable_sms = func.sum(ft_billing_subquery.c.charged_units)
|
||||
sms_cost = func.sum(ft_billing_subquery.c.cost)
|
||||
@@ -85,10 +87,10 @@ def fetch_sms_billing_for_all_services(start_date, end_date):
|
||||
Service.name.label("service_name"),
|
||||
Service.id.label("service_id"),
|
||||
AnnualBilling.free_sms_fragment_limit,
|
||||
func.coalesce(sms_allowance_left, 0).label("sms_remainder"),
|
||||
func.coalesce(sms_billable_units, 0).label('sms_billable_units'),
|
||||
func.coalesce(chargeable_sms, 0).label("chargeable_billable_sms"),
|
||||
func.coalesce(sms_cost, 0).label('sms_cost'),
|
||||
sms_allowance_left.label("sms_remainder"),
|
||||
sms_billable_units.label('sms_billable_units'),
|
||||
chargeable_sms.label("chargeable_billable_sms"),
|
||||
sms_cost.label('sms_cost'),
|
||||
).select_from(
|
||||
Service
|
||||
).outerjoin(
|
||||
@@ -99,7 +101,9 @@ def fetch_sms_billing_for_all_services(start_date, end_date):
|
||||
).outerjoin(
|
||||
ft_billing_subquery, Service.id == ft_billing_subquery.c.service_id
|
||||
).filter(
|
||||
Service.restricted.is_(False)
|
||||
Service.restricted.is_(False),
|
||||
ft_billing_subquery.c.bst_date >= start_date,
|
||||
ft_billing_subquery.c.bst_date <= end_date,
|
||||
).group_by(
|
||||
Organisation.name,
|
||||
Organisation.id,
|
||||
@@ -798,12 +802,15 @@ def query_sms_usage_for_year_per_service(year):
|
||||
# for, after taking any remaining free allowance into account.
|
||||
charged_units = func.greatest(this_rows_chargeable_units - remaining_free_allowance_before_this_row, 0)
|
||||
|
||||
free_allowance_used_to_date = chargeable_units_used_before_this_row + this_rows_chargeable_units
|
||||
|
||||
return db.session.query(
|
||||
Service.id.label('service_id'),
|
||||
FactBilling.bst_date,
|
||||
this_rows_chargeable_units.label("chargeable_units"),
|
||||
(charged_units * FactBilling.rate).label("cost"),
|
||||
charged_units.label("charged_units"),
|
||||
free_allowance_used_to_date.label("free_allowance_used_to_date"),
|
||||
).join(
|
||||
AnnualBilling,
|
||||
AnnualBilling.service_id == Service.id
|
||||
|
||||
@@ -708,6 +708,7 @@ def test_fetch_sms_billing_for_all_services_with_remainder(notify_db_session):
|
||||
create_ft_billing(template=template_3, bst_date=datetime(2019, 4, 20), billable_unit=5, rate=0.11)
|
||||
create_ft_billing(template=template_3, bst_date=datetime(2019, 5, 20), billable_unit=7, rate=0.11)
|
||||
|
||||
# this isn't included in results as it doesn't have any SMS rows
|
||||
service_4 = create_service(service_name='d - email only')
|
||||
email_template = create_template(service=service_4, template_type='email')
|
||||
org_4 = create_organisation(name="Org for {}".format(service_4.name))
|
||||
@@ -724,21 +725,21 @@ def test_fetch_sms_billing_for_all_services_with_remainder(notify_db_session):
|
||||
# the requested report's start date.
|
||||
{
|
||||
"organisation_name": org.name, "organisation_id": org.id, "service_name": service_1.name,
|
||||
"service_id": service_1.id, "free_sms_fragment_limit": 10, "sms_rate": Decimal('0.11'), "sms_remainder": 5,
|
||||
"service_id": service_1.id, "free_sms_fragment_limit": 10, "sms_remainder": 5,
|
||||
"sms_billable_units": 3, "chargeable_billable_sms": 0, "sms_cost": Decimal('0.00')
|
||||
},
|
||||
# sms remainder is 0, because this service sent SMS worth 15 billable units, 12 of which were sent
|
||||
# before requested report's start date
|
||||
{
|
||||
"organisation_name": org_2.name, "organisation_id": org_2.id, "service_name": service_2.name,
|
||||
"service_id": service_2.id, "free_sms_fragment_limit": 10, "sms_rate": Decimal('0.11'), "sms_remainder": 0,
|
||||
"service_id": service_2.id, "free_sms_fragment_limit": 10, "sms_remainder": 0,
|
||||
"sms_billable_units": 3, "chargeable_billable_sms": 3, "sms_cost": Decimal('0.33')
|
||||
},
|
||||
# sms remainder is 0, because this service sent SMS worth 12 billable units, 5 of which were sent
|
||||
# before requested report's start date
|
||||
{
|
||||
"organisation_name": org_3.name, "organisation_id": org_3.id, "service_name": service_3.name,
|
||||
"service_id": service_3.id, "free_sms_fragment_limit": 10, "sms_rate": Decimal('0.11'), "sms_remainder": 0,
|
||||
"service_id": service_3.id, "free_sms_fragment_limit": 10, "sms_remainder": 0,
|
||||
"sms_billable_units": 7, "chargeable_billable_sms": 2, "sms_cost": Decimal('0.22')
|
||||
},
|
||||
]
|
||||
@@ -758,7 +759,7 @@ def test_fetch_sms_billing_for_all_services_without_an_organisation_appears(noti
|
||||
"organisation_name": fixtures["org_1"].name, "organisation_id": fixtures["org_1"].id,
|
||||
"service_name": fixtures["service_1_sms_and_letter"].name,
|
||||
"service_id": fixtures["service_1_sms_and_letter"].id,
|
||||
"free_sms_fragment_limit": 10, "sms_rate": Decimal('0.11'), "sms_remainder": 5,
|
||||
"free_sms_fragment_limit": 10, "sms_remainder": 5,
|
||||
"sms_billable_units": 3, "chargeable_billable_sms": 0, "sms_cost": Decimal('0.00')
|
||||
},
|
||||
# sms remainder is 0, because this service sent SMS worth 15 billable units, 12 of which were sent
|
||||
@@ -767,14 +768,14 @@ def test_fetch_sms_billing_for_all_services_without_an_organisation_appears(noti
|
||||
"organisation_name": None, "organisation_id": None,
|
||||
"service_name": fixtures["service_with_sms_without_org"].name,
|
||||
"service_id": fixtures["service_with_sms_without_org"].id, "free_sms_fragment_limit": 10,
|
||||
"sms_rate": Decimal('0.11'), "sms_remainder": 0,
|
||||
"sms_remainder": 0,
|
||||
"sms_billable_units": 3, "chargeable_billable_sms": 3, "sms_cost": Decimal('0.33')
|
||||
},
|
||||
{
|
||||
"organisation_name": None, "organisation_id": None,
|
||||
"service_name": fixtures["service_with_sms_within_allowance"].name,
|
||||
"service_id": fixtures["service_with_sms_within_allowance"].id, "free_sms_fragment_limit": 10,
|
||||
"sms_rate": Decimal('0.11'), "sms_remainder": 8,
|
||||
"sms_remainder": 8,
|
||||
"sms_billable_units": 2, "chargeable_billable_sms": 0, "sms_cost": Decimal('0.00')
|
||||
},
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user