ensure fetch_sms_free_allowance_remainder always returns

if there are no rows for a service in ft_billing, we should still
return their allowance (with 0 fragments used).

To do this, we need to build the query starting from AnnualBilling and
joining onto FactBilling, rather than the other way round. Also, we
need to account for the possibility of the sums being null by
coalescing them to 0
This commit is contained in:
Leo Hemsted
2019-08-29 17:55:50 +01:00
parent b46eed1423
commit 48e96f253b

View File

@@ -3,7 +3,7 @@ from datetime import datetime, timedelta, time
from flask import current_app
from notifications_utils.timezones import convert_bst_to_utc, convert_utc_to_bst
from sqlalchemy.dialects.postgresql import insert
from sqlalchemy import func, case, desc, Date, Integer
from sqlalchemy import func, case, desc, Date, Integer, and_
from app import db
from app.dao.date_util import (
@@ -35,22 +35,27 @@ def fetch_sms_free_allowance_remainder(start_date):
# ASSUMPTION: AnnualBilling has been populated for year.
billing_year = get_financial_year_for_datetime(start_date)
start_of_year = convert_utc_to_bst(financial_year_start(billing_year))
billable_units = func.coalesce(func.sum(FactBilling.billable_units * FactBilling.rate_multiplier), 0)
query = db.session.query(
FactBilling.service_id.label("service_id"),
AnnualBilling.service_id.label("service_id"),
AnnualBilling.free_sms_fragment_limit,
func.sum(FactBilling.billable_units * FactBilling.rate_multiplier).label('billable_units'),
func.greatest((AnnualBilling.free_sms_fragment_limit -
func.sum(FactBilling.billable_units * FactBilling.rate_multiplier)
).cast(Integer), 0).label('sms_remainder')
).join(
AnnualBilling, FactBilling.service_id == AnnualBilling.service_id,
billable_units.label('billable_units'),
func.greatest((AnnualBilling.free_sms_fragment_limit - billable_units).cast(Integer), 0).label('sms_remainder')
).outerjoin(
# if there are no ft_billing rows for a service we still want to return the annual billing so we can use the
# free_sms_fragment_limit)
FactBilling, and_(
AnnualBilling.service_id == FactBilling.service_id,
FactBilling.bst_date >= start_of_year,
FactBilling.bst_date < start_date,
FactBilling.notification_type == SMS_TYPE,
)
).filter(
FactBilling.bst_date >= start_of_year,
FactBilling.bst_date < start_date,
FactBilling.notification_type == SMS_TYPE,
AnnualBilling.financial_year_start == billing_year,
).group_by(
FactBilling.service_id,
AnnualBilling.service_id,
AnnualBilling.free_sms_fragment_limit,
)
return query