mirror of
https://github.com/GSA/notifications-api.git
synced 2026-08-25 08:43:55 -04:00
Compare commits
8 Commits
31e13ff067
...
free-allow
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
99b2b4642e | ||
|
|
2bdaeabbaa | ||
|
|
2999fa6714 | ||
|
|
ff32000180 | ||
|
|
e276e8a15c | ||
|
|
106da583ea | ||
|
|
0af791e417 | ||
|
|
646de16ace |
@@ -17,9 +17,15 @@ 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 to "chargeable_units" in the Admin app
|
||||||
"billing_units": row.billable_units,
|
"billing_units": row.billable_units,
|
||||||
|
"chargeable_units": row.chargeable_units,
|
||||||
"rate": float(row.rate),
|
"rate": float(row.rate),
|
||||||
"postage": row.postage,
|
"postage": row.postage,
|
||||||
|
"cost": float(row.cost),
|
||||||
|
"free_chargeable_units": row.free_chargeable_units,
|
||||||
|
"charged_units": row.charged_units,
|
||||||
|
"notifications_sent": row.notifications_sent,
|
||||||
}
|
}
|
||||||
for row in rows
|
for row in rows
|
||||||
if row.notification_type != 'email'
|
if row.notification_type != 'email'
|
||||||
@@ -30,9 +36,16 @@ def serialize_ft_billing_yearly_totals(rows):
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
"notification_type": row.notification_type,
|
"notification_type": row.notification_type,
|
||||||
|
# TEMPORARY: while we migrate to "chargeable_units" in the Admin app
|
||||||
"billing_units": row.billable_units,
|
"billing_units": row.billable_units,
|
||||||
|
"chargeable_units": row.chargeable_units,
|
||||||
"rate": float(row.rate),
|
"rate": float(row.rate),
|
||||||
|
# TEMPORARY: while we migrate to "cost" in the Admin app
|
||||||
"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,
|
||||||
|
"cost": float(row.cost),
|
||||||
|
"free_chargeable_units": row.free_chargeable_units,
|
||||||
|
"charged_units": row.charged_units,
|
||||||
|
"notifications_sent": row.notifications_sent,
|
||||||
}
|
}
|
||||||
for row in rows
|
for row in rows
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from datetime import date, datetime, timedelta
|
|||||||
|
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from notifications_utils.timezones import convert_utc_to_bst
|
from notifications_utils.timezones import convert_utc_to_bst
|
||||||
from sqlalchemy import Date, Integer, and_, desc, func
|
from sqlalchemy import Date, Integer, and_, desc, func, union
|
||||||
from sqlalchemy.dialects.postgresql import insert
|
from sqlalchemy.dialects.postgresql import insert
|
||||||
from sqlalchemy.sql.expression import case, literal
|
from sqlalchemy.sql.expression import case, literal
|
||||||
|
|
||||||
@@ -197,55 +197,36 @@ def fetch_letter_line_items_for_all_services(start_date, end_date):
|
|||||||
|
|
||||||
|
|
||||||
def fetch_billing_totals_for_year(service_id, year):
|
def fetch_billing_totals_for_year(service_id, year):
|
||||||
year_start, year_end = get_financial_year_dates(year)
|
return db.session.query(
|
||||||
"""
|
union(*[
|
||||||
Billing for email: only record the total number of emails.
|
db.session.query(
|
||||||
Billing for letters: The billing units is used to fetch the correct rate for the sheet count of the letter.
|
func.sum(query.c.notifications_sent).label("notifications_sent"),
|
||||||
Total cost is notifications_sent * rate.
|
# TEMPORARY: while we switch to "chargeable units"
|
||||||
Rate multiplier does not apply to email or letters.
|
func.sum(query.c.billable_units).label("billable_units"),
|
||||||
"""
|
func.sum(query.c.chargeable_units).label("chargeable_units"),
|
||||||
email_and_letters = db.session.query(
|
query.c.rate.label("rate"),
|
||||||
func.sum(FactBilling.notifications_sent).label("notifications_sent"),
|
query.c.notification_type.label("notification_type"),
|
||||||
func.sum(FactBilling.notifications_sent).label("billable_units"),
|
func.sum(query.c.cost).label("cost"),
|
||||||
FactBilling.rate.label('rate'),
|
func.sum(query.c.free_chargeable_units).label("free_chargeable_units"),
|
||||||
FactBilling.notification_type.label('notification_type')
|
func.sum(query.c.charged_units).label("charged_units"),
|
||||||
).filter(
|
).group_by(
|
||||||
FactBilling.service_id == service_id,
|
query.c.rate,
|
||||||
FactBilling.bst_date >= year_start,
|
query.c.notification_type
|
||||||
FactBilling.bst_date <= year_end,
|
)
|
||||||
FactBilling.notification_type.in_([EMAIL_TYPE, LETTER_TYPE])
|
for query in [
|
||||||
).group_by(
|
query_service_sms_usage_for_year(service_id, year).subquery(),
|
||||||
FactBilling.rate,
|
query_service_email_usage_for_year(service_id, year).subquery(),
|
||||||
FactBilling.notification_type
|
query_service_letter_usage_for_year(service_id, year).subquery(),
|
||||||
)
|
]
|
||||||
"""
|
]).subquery()
|
||||||
Billing for SMS using the billing_units * rate_multiplier. Billing unit of SMS is the fragment count of a message
|
).order_by(
|
||||||
"""
|
"notification_type",
|
||||||
sms = db.session.query(
|
"rate",
|
||||||
func.sum(FactBilling.notifications_sent).label("notifications_sent"),
|
|
||||||
func.sum(FactBilling.billable_units * FactBilling.rate_multiplier).label("billable_units"),
|
|
||||||
FactBilling.rate,
|
|
||||||
FactBilling.notification_type
|
|
||||||
).filter(
|
|
||||||
FactBilling.service_id == service_id,
|
|
||||||
FactBilling.bst_date >= year_start,
|
|
||||||
FactBilling.bst_date <= year_end,
|
|
||||||
FactBilling.notification_type == SMS_TYPE
|
|
||||||
).group_by(
|
|
||||||
FactBilling.rate,
|
|
||||||
FactBilling.notification_type
|
|
||||||
)
|
|
||||||
|
|
||||||
yearly_data = email_and_letters.union_all(sms).order_by(
|
|
||||||
'notification_type',
|
|
||||||
'rate'
|
|
||||||
).all()
|
).all()
|
||||||
|
|
||||||
return yearly_data
|
|
||||||
|
|
||||||
|
|
||||||
def fetch_monthly_billing_for_year(service_id, year):
|
def fetch_monthly_billing_for_year(service_id, year):
|
||||||
year_start, year_end = get_financial_year_dates(year)
|
_, year_end = get_financial_year_dates(year)
|
||||||
today = convert_utc_to_bst(datetime.utcnow()).date()
|
today = convert_utc_to_bst(datetime.utcnow()).date()
|
||||||
|
|
||||||
# if year end date is less than today, we are calculating for data in the past and have no need for deltas.
|
# if year end date is less than today, we are calculating for data in the past and have no need for deltas.
|
||||||
@@ -254,51 +235,141 @@ def fetch_monthly_billing_for_year(service_id, year):
|
|||||||
for d in data:
|
for d in data:
|
||||||
update_fact_billing(data=d, process_day=today)
|
update_fact_billing(data=d, process_day=today)
|
||||||
|
|
||||||
email_and_letters = db.session.query(
|
return db.session.query(
|
||||||
func.date_trunc('month', FactBilling.bst_date).cast(Date).label("month"),
|
union(*[
|
||||||
func.sum(FactBilling.notifications_sent).label("notifications_sent"),
|
db.session.query(
|
||||||
func.sum(FactBilling.notifications_sent).label("billable_units"),
|
func.date_trunc('month', query.c.bst_date).cast(Date).label("month"),
|
||||||
FactBilling.rate.label('rate'),
|
func.sum(query.c.notifications_sent).label("notifications_sent"),
|
||||||
FactBilling.notification_type.label('notification_type'),
|
# TEMPORARY: while we switch to "chargeable units"
|
||||||
FactBilling.postage
|
func.sum(query.c.billable_units).label("billable_units"),
|
||||||
).filter(
|
func.sum(query.c.chargeable_units).label("chargeable_units"),
|
||||||
FactBilling.service_id == service_id,
|
query.c.rate.label("rate"),
|
||||||
FactBilling.bst_date >= year_start,
|
query.c.postage.label("postage"),
|
||||||
FactBilling.bst_date <= year_end,
|
query.c.notification_type.label("notification_type"),
|
||||||
FactBilling.notification_type.in_([EMAIL_TYPE, LETTER_TYPE])
|
func.sum(query.c.cost).label("cost"),
|
||||||
).group_by(
|
func.sum(query.c.free_chargeable_units).label("free_chargeable_units"),
|
||||||
'month',
|
func.sum(query.c.charged_units).label("charged_units"),
|
||||||
FactBilling.rate,
|
).group_by(
|
||||||
FactBilling.notification_type,
|
query.c.rate,
|
||||||
FactBilling.postage
|
query.c.notification_type,
|
||||||
)
|
query.c.postage,
|
||||||
|
'month',
|
||||||
sms = db.session.query(
|
)
|
||||||
func.date_trunc('month', FactBilling.bst_date).cast(Date).label("month"),
|
for query in [
|
||||||
func.sum(FactBilling.notifications_sent).label("notifications_sent"),
|
query_service_sms_usage_for_year(service_id, year).subquery(),
|
||||||
func.sum(FactBilling.billable_units * FactBilling.rate_multiplier).label("billable_units"),
|
query_service_email_usage_for_year(service_id, year).subquery(),
|
||||||
FactBilling.rate,
|
query_service_letter_usage_for_year(service_id, year).subquery(),
|
||||||
FactBilling.notification_type,
|
]
|
||||||
FactBilling.postage
|
]).subquery()
|
||||||
).filter(
|
).order_by(
|
||||||
FactBilling.service_id == service_id,
|
"month",
|
||||||
FactBilling.bst_date >= year_start,
|
"notification_type",
|
||||||
FactBilling.bst_date <= year_end,
|
"rate",
|
||||||
FactBilling.notification_type == SMS_TYPE
|
|
||||||
).group_by(
|
|
||||||
'month',
|
|
||||||
FactBilling.rate,
|
|
||||||
FactBilling.notification_type,
|
|
||||||
FactBilling.postage
|
|
||||||
)
|
|
||||||
|
|
||||||
yearly_data = email_and_letters.union_all(sms).order_by(
|
|
||||||
'month',
|
|
||||||
'notification_type',
|
|
||||||
'rate'
|
|
||||||
).all()
|
).all()
|
||||||
|
|
||||||
return yearly_data
|
|
||||||
|
def query_service_email_usage_for_year(service_id, year):
|
||||||
|
year_start, year_end = get_financial_year_dates(year)
|
||||||
|
|
||||||
|
return db.session.query(
|
||||||
|
FactBilling.bst_date,
|
||||||
|
FactBilling.postage, # should always be "none"
|
||||||
|
FactBilling.notifications_sent,
|
||||||
|
# TEMPORARY: while we switch to "chargeable units"
|
||||||
|
FactBilling.notifications_sent.label("billable_units"),
|
||||||
|
FactBilling.billable_units.label("chargeable_units"),
|
||||||
|
FactBilling.rate,
|
||||||
|
FactBilling.notification_type,
|
||||||
|
FactBilling.notifications_sent.label("charged_units"),
|
||||||
|
literal(0).label("free_chargeable_units"),
|
||||||
|
literal(0).label("cost"),
|
||||||
|
).filter(
|
||||||
|
FactBilling.service_id == service_id,
|
||||||
|
FactBilling.bst_date >= year_start,
|
||||||
|
FactBilling.bst_date <= year_end,
|
||||||
|
FactBilling.notification_type == EMAIL_TYPE
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def query_service_letter_usage_for_year(service_id, year):
|
||||||
|
year_start, year_end = get_financial_year_dates(year)
|
||||||
|
|
||||||
|
return db.session.query(
|
||||||
|
FactBilling.bst_date,
|
||||||
|
FactBilling.postage,
|
||||||
|
FactBilling.notifications_sent,
|
||||||
|
# TEMPORARY: while we switch to "chargeable units"
|
||||||
|
FactBilling.notifications_sent.label("billable_units"),
|
||||||
|
FactBilling.billable_units.label("chargeable_units"),
|
||||||
|
FactBilling.rate,
|
||||||
|
FactBilling.notification_type,
|
||||||
|
FactBilling.notifications_sent.label("charged_units"),
|
||||||
|
literal(0).label("free_chargeable_units"),
|
||||||
|
(FactBilling.notifications_sent * FactBilling.rate).label("cost"),
|
||||||
|
).filter(
|
||||||
|
FactBilling.service_id == service_id,
|
||||||
|
FactBilling.bst_date >= year_start,
|
||||||
|
FactBilling.bst_date <= year_end,
|
||||||
|
FactBilling.notification_type == LETTER_TYPE
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def query_service_sms_usage_for_year(service_id, year):
|
||||||
|
year_start, year_end = get_financial_year_dates(year)
|
||||||
|
chargeable_units = FactBilling.billable_units * FactBilling.rate_multiplier
|
||||||
|
|
||||||
|
# Subquery for the number of chargeable units in all rows preceding this one,
|
||||||
|
# which might be none if this is the first row (hence the "coalesce").
|
||||||
|
cumulative_chargeable_units = func.coalesce(
|
||||||
|
func.sum(chargeable_units).over(
|
||||||
|
order_by=[
|
||||||
|
FactBilling.bst_date, # order is "ASC" by default
|
||||||
|
FactBilling.rate # ensures test stability for rows on the same day
|
||||||
|
],
|
||||||
|
rows=(None, -1) # ROWS BETWEEN UNBOUNDED PRECEDING AND 1 ROW PRECEDING
|
||||||
|
),
|
||||||
|
literal(0)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Subquery for how much free allowance we have left before the current row,
|
||||||
|
# so we can work out the cost for this row after taking it into account.
|
||||||
|
cumulative_free_remainder = func.greatest(
|
||||||
|
AnnualBilling.free_sms_fragment_limit - cumulative_chargeable_units,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
|
||||||
|
charged_units = func.greatest(
|
||||||
|
chargeable_units - cumulative_free_remainder,
|
||||||
|
literal(0)
|
||||||
|
).cast(Integer) # for some reason the result is a String!
|
||||||
|
|
||||||
|
free_chargeable_units = func.least(
|
||||||
|
cumulative_free_remainder,
|
||||||
|
chargeable_units,
|
||||||
|
).cast(Integer) # for some reason the result is a Decimal
|
||||||
|
|
||||||
|
return db.session.query(
|
||||||
|
FactBilling.bst_date,
|
||||||
|
FactBilling.postage, # should always be "none"
|
||||||
|
FactBilling.notifications_sent,
|
||||||
|
# TEMPORARY: while we switch to "chargeable units"
|
||||||
|
chargeable_units.label("billable_units"),
|
||||||
|
chargeable_units.label("chargeable_units"),
|
||||||
|
FactBilling.rate,
|
||||||
|
FactBilling.notification_type,
|
||||||
|
charged_units.label("charged_units"),
|
||||||
|
free_chargeable_units.label("free_chargeable_units"),
|
||||||
|
(charged_units * FactBilling.rate).label("cost")
|
||||||
|
).outerjoin(
|
||||||
|
AnnualBilling,
|
||||||
|
AnnualBilling.service_id == service_id
|
||||||
|
).filter(
|
||||||
|
FactBilling.service_id == service_id,
|
||||||
|
FactBilling.bst_date >= year_start,
|
||||||
|
FactBilling.bst_date <= year_end,
|
||||||
|
FactBilling.notification_type == SMS_TYPE,
|
||||||
|
AnnualBilling.financial_year_start == year,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def delete_billing_data_for_service_for_day(process_day, service_id):
|
def delete_billing_data_for_service_for_day(process_day, service_id):
|
||||||
|
|||||||
@@ -147,6 +147,8 @@ def set_up_monthly_data():
|
|||||||
billable_unit=1,
|
billable_unit=1,
|
||||||
rate=0.33,
|
rate=0.33,
|
||||||
postage='second')
|
postage='second')
|
||||||
|
|
||||||
|
create_annual_billing(service_id=service.id, free_sms_fragment_limit=4, financial_year_start=2016)
|
||||||
return service
|
return service
|
||||||
|
|
||||||
|
|
||||||
@@ -170,14 +172,25 @@ 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["rate"] == 0.33
|
assert letter_row["rate"] == 0.33
|
||||||
assert letter_row["postage"] == "second"
|
assert letter_row["postage"] == "second"
|
||||||
|
assert letter_row["cost"] == 9.9
|
||||||
|
assert letter_row["free_chargeable_units"] == 0
|
||||||
|
assert letter_row["charged_units"] == 30
|
||||||
|
assert letter_row["notifications_sent"] == 30
|
||||||
|
|
||||||
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["rate"] == 0.162
|
assert sms_row["rate"] == 0.162
|
||||||
assert sms_row["postage"] == "none"
|
assert sms_row["postage"] == "none"
|
||||||
|
# free allowance is 4, so (30 - 4) * 0.162
|
||||||
|
assert sms_row["cost"] == 4.212
|
||||||
|
assert sms_row["free_chargeable_units"] == 4
|
||||||
|
assert sms_row["charged_units"] == 26
|
||||||
|
assert sms_row["notifications_sent"] == 30
|
||||||
|
|
||||||
|
|
||||||
def set_up_yearly_data():
|
def set_up_yearly_data():
|
||||||
@@ -185,6 +198,7 @@ def set_up_yearly_data():
|
|||||||
sms_template = create_template(service=service, template_type="sms")
|
sms_template = create_template(service=service, template_type="sms")
|
||||||
email_template = create_template(service=service, template_type="email")
|
email_template = create_template(service=service, template_type="email")
|
||||||
letter_template = create_template(service=service, template_type="letter")
|
letter_template = create_template(service=service, template_type="letter")
|
||||||
|
|
||||||
for month in range(1, 13):
|
for month in range(1, 13):
|
||||||
mon = str(month).zfill(2)
|
mon = str(month).zfill(2)
|
||||||
for day in range(1, monthrange(2016, month)[1] + 1):
|
for day in range(1, monthrange(2016, month)[1] + 1):
|
||||||
@@ -205,6 +219,8 @@ def set_up_yearly_data():
|
|||||||
rate=0.33,
|
rate=0.33,
|
||||||
postage='second')
|
postage='second')
|
||||||
start_date, end_date = get_month_start_and_end_date_in_utc(datetime(2016, int(mon), 1))
|
start_date, end_date = get_month_start_and_end_date_in_utc(datetime(2016, int(mon), 1))
|
||||||
|
|
||||||
|
create_annual_billing(service_id=service.id, free_sms_fragment_limit=4, financial_year_start=2016)
|
||||||
return service
|
return service
|
||||||
|
|
||||||
|
|
||||||
@@ -240,15 +256,33 @@ 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'] == 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[0]['cost'] == 0
|
||||||
|
assert json_response[0]['free_chargeable_units'] == 0
|
||||||
|
assert json_response[0]['charged_units'] == 275
|
||||||
|
assert json_response[0]['notifications_sent'] == 275
|
||||||
|
|
||||||
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]['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[1]['cost'] == 90.75
|
||||||
|
assert json_response[1]['free_chargeable_units'] == 0
|
||||||
|
assert json_response[1]['charged_units'] == 275
|
||||||
|
assert json_response[1]['notifications_sent'] == 275
|
||||||
|
|
||||||
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]['rate'] == 0.0162
|
assert json_response[2]['rate'] == 0.0162
|
||||||
assert json_response[2]['letter_total'] == 0
|
assert json_response[2]['letter_total'] == 0
|
||||||
|
assert json_response[2]['cost'] == 13.3002
|
||||||
|
assert json_response[2]['free_chargeable_units'] == 4
|
||||||
|
assert json_response[2]['charged_units'] == 821
|
||||||
|
assert json_response[2]['notifications_sent'] == 825
|
||||||
|
|||||||
@@ -417,6 +417,7 @@ def test_get_rate_for_letters_when_page_count_is_zero(notify_db_session):
|
|||||||
|
|
||||||
def test_fetch_monthly_billing_for_year(notify_db_session):
|
def test_fetch_monthly_billing_for_year(notify_db_session):
|
||||||
service = set_up_yearly_data()
|
service = set_up_yearly_data()
|
||||||
|
create_annual_billing(service_id=service.id, free_sms_fragment_limit=10, financial_year_start=2016)
|
||||||
results = fetch_monthly_billing_for_year(service.id, 2016)
|
results = fetch_monthly_billing_for_year(service.id, 2016)
|
||||||
|
|
||||||
assert len(results) == 48
|
assert len(results) == 48
|
||||||
@@ -425,25 +426,42 @@ 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 == 30
|
||||||
assert results[0].rate == Decimal('0')
|
assert results[0].rate == Decimal('0')
|
||||||
|
assert results[0].cost == Decimal('0')
|
||||||
|
assert results[0].free_chargeable_units == 0
|
||||||
|
assert results[0].charged_units == 30
|
||||||
|
|
||||||
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 results[1].cost == Decimal('9')
|
||||||
|
assert results[1].free_chargeable_units == 0
|
||||||
|
assert results[1].charged_units == 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 results[2].cost == Decimal('9.9')
|
||||||
|
assert results[2].free_chargeable_units == 0
|
||||||
|
assert results[2].charged_units == 30
|
||||||
|
|
||||||
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')
|
||||||
|
# free allowance is 10, so (30 - 10) * 0.162
|
||||||
|
assert results[3].cost == Decimal('3.24')
|
||||||
|
assert results[3].free_chargeable_units == 10
|
||||||
|
assert results[3].charged_units == 20
|
||||||
|
|
||||||
assert str(results[4].month) == "2016-05-01"
|
assert str(results[4].month) == "2016-05-01"
|
||||||
assert str(results[47].month) == "2017-03-01"
|
assert str(results[47].month) == "2017-03-01"
|
||||||
@@ -451,6 +469,7 @@ def test_fetch_monthly_billing_for_year(notify_db_session):
|
|||||||
|
|
||||||
def test_fetch_monthly_billing_for_year_variable_rates(notify_db_session):
|
def test_fetch_monthly_billing_for_year_variable_rates(notify_db_session):
|
||||||
service = set_up_yearly_data_variable_rates()
|
service = set_up_yearly_data_variable_rates()
|
||||||
|
create_annual_billing(service_id=service.id, free_sms_fragment_limit=6, financial_year_start=2018)
|
||||||
results = fetch_monthly_billing_for_year(service.id, 2018)
|
results = fetch_monthly_billing_for_year(service.id, 2018)
|
||||||
|
|
||||||
# Test data is only for the month of May
|
# Test data is only for the month of May
|
||||||
@@ -460,25 +479,43 @@ 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 results[0].cost == Decimal('0.33')
|
||||||
|
assert results[0].free_chargeable_units == 0
|
||||||
|
assert results[0].charged_units == 1
|
||||||
|
|
||||||
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 == 1
|
assert results[1].notifications_sent == 1
|
||||||
assert results[1].billable_units == 1
|
assert results[1].billable_units == 1
|
||||||
|
assert results[1].chargeable_units == 2
|
||||||
assert results[1].rate == Decimal('0.36')
|
assert results[1].rate == Decimal('0.36')
|
||||||
|
assert results[1].cost == Decimal('0.36')
|
||||||
|
assert results[1].free_chargeable_units == 0
|
||||||
|
assert results[1].charged_units == 1
|
||||||
|
|
||||||
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')
|
||||||
|
# 4 free units sent on the 16th, 0 on the 17th
|
||||||
|
assert results[2].cost == Decimal('0')
|
||||||
|
assert results[2].free_chargeable_units == 4
|
||||||
|
assert results[2].charged_units == 0
|
||||||
|
|
||||||
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')
|
||||||
|
# 1 free unit on the 16th, 1 on the 17th (+ 3 paid)
|
||||||
|
assert results[3].cost == Decimal('0.486')
|
||||||
|
assert results[3].free_chargeable_units == 2
|
||||||
|
assert results[3].charged_units == 3
|
||||||
|
|
||||||
|
|
||||||
@freeze_time('2018-08-01 13:30:00')
|
@freeze_time('2018-08-01 13:30:00')
|
||||||
@@ -487,6 +524,7 @@ def test_fetch_monthly_billing_for_year_adds_data_for_today(notify_db_session):
|
|||||||
template = create_template(service=service, template_type="sms")
|
template = create_template(service=service, template_type="sms")
|
||||||
|
|
||||||
create_rate(start_date=datetime.utcnow() - timedelta(days=1), value=0.158, notification_type='sms')
|
create_rate(start_date=datetime.utcnow() - timedelta(days=1), value=0.158, notification_type='sms')
|
||||||
|
create_annual_billing(service_id=service.id, free_sms_fragment_limit=1000, financial_year_start=2018)
|
||||||
|
|
||||||
for i in range(1, 32):
|
for i in range(1, 32):
|
||||||
create_ft_billing(bst_date='2018-07-{}'.format(i), template=template)
|
create_ft_billing(bst_date='2018-07-{}'.format(i), template=template)
|
||||||
@@ -502,54 +540,105 @@ def test_fetch_monthly_billing_for_year_adds_data_for_today(notify_db_session):
|
|||||||
|
|
||||||
def test_fetch_billing_totals_for_year(notify_db_session):
|
def test_fetch_billing_totals_for_year(notify_db_session):
|
||||||
service = set_up_yearly_data()
|
service = set_up_yearly_data()
|
||||||
|
create_annual_billing(service_id=service.id, free_sms_fragment_limit=1000, financial_year_start=2016)
|
||||||
results = fetch_billing_totals_for_year(service_id=service.id, year=2016)
|
results = fetch_billing_totals_for_year(service_id=service.id, year=2016)
|
||||||
|
|
||||||
assert len(results) == 4
|
assert len(results) == 4
|
||||||
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 == 365
|
||||||
assert results[0].rate == Decimal('0')
|
assert results[0].rate == Decimal('0')
|
||||||
|
assert results[0].cost == Decimal('0')
|
||||||
|
assert results[0].free_chargeable_units == 0
|
||||||
|
assert results[0].charged_units == 365
|
||||||
|
|
||||||
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[1].cost == Decimal('109.5')
|
||||||
|
assert results[1].free_chargeable_units == 0
|
||||||
|
assert results[1].charged_units == 365
|
||||||
|
|
||||||
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[2].cost == Decimal('120.45')
|
||||||
|
assert results[2].free_chargeable_units == 0
|
||||||
|
assert results[2].charged_units == 365
|
||||||
|
|
||||||
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')
|
||||||
|
assert results[3].cost == Decimal('0')
|
||||||
|
assert results[3].free_chargeable_units == 365
|
||||||
|
assert results[3].charged_units == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_fetch_billing_totals_for_year_uses_current_annual_billing(notify_db_session):
|
||||||
|
service = set_up_yearly_data()
|
||||||
|
create_annual_billing(service_id=service.id, free_sms_fragment_limit=400, financial_year_start=2015)
|
||||||
|
create_annual_billing(service_id=service.id, free_sms_fragment_limit=0, financial_year_start=2016)
|
||||||
|
|
||||||
|
result = next(
|
||||||
|
result for result in
|
||||||
|
fetch_billing_totals_for_year(service_id=service.id, year=2016)
|
||||||
|
if result.notification_type == 'sms'
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result.chargeable_units == 365
|
||||||
|
assert result.cost > 0
|
||||||
|
|
||||||
|
|
||||||
def test_fetch_billing_totals_for_year_variable_rates(notify_db_session):
|
def test_fetch_billing_totals_for_year_variable_rates(notify_db_session):
|
||||||
service = set_up_yearly_data_variable_rates()
|
service = set_up_yearly_data_variable_rates()
|
||||||
|
create_annual_billing(service_id=service.id, free_sms_fragment_limit=6, financial_year_start=2018)
|
||||||
results = fetch_billing_totals_for_year(service_id=service.id, year=2018)
|
results = fetch_billing_totals_for_year(service_id=service.id, year=2018)
|
||||||
|
|
||||||
assert len(results) == 4
|
assert len(results) == 4
|
||||||
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[0].cost == Decimal('0.33')
|
||||||
|
assert results[0].free_chargeable_units == 0
|
||||||
|
assert results[0].charged_units == 1
|
||||||
|
|
||||||
assert results[1].notification_type == 'letter'
|
assert results[1].notification_type == 'letter'
|
||||||
assert results[1].notifications_sent == 1
|
assert results[1].notifications_sent == 1
|
||||||
assert results[1].billable_units == 1
|
assert results[1].billable_units == 1
|
||||||
|
assert results[1].chargeable_units == 2
|
||||||
assert results[1].rate == Decimal('0.36')
|
assert results[1].rate == Decimal('0.36')
|
||||||
|
assert results[1].cost == Decimal('0.36')
|
||||||
|
assert results[1].free_chargeable_units == 0
|
||||||
|
assert results[1].charged_units == 1
|
||||||
|
|
||||||
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')
|
||||||
|
# 4 units sent on the 16th, 0 on the 17th
|
||||||
|
assert results[2].cost == Decimal('0')
|
||||||
|
assert results[2].free_chargeable_units == 4
|
||||||
|
assert results[2].charged_units == 0
|
||||||
|
|
||||||
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')
|
||||||
|
# 1 free unit on the 16th, 1 on the 17th (+ 3 paid)
|
||||||
|
assert results[3].cost == Decimal('0.486') # (5 - 2) * 0.162
|
||||||
|
assert results[3].free_chargeable_units == 2
|
||||||
|
assert results[3].charged_units == 3
|
||||||
|
|
||||||
|
|
||||||
def test_delete_billing_data(notify_db_session):
|
def test_delete_billing_data(notify_db_session):
|
||||||
|
|||||||
Reference in New Issue
Block a user