mirror of
https://github.com/GSA/notifications-api.git
synced 2026-08-23 07:46:06 -04:00
Compare commits
1 Commits
free-allow
...
remove-unu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d59736654 |
@@ -12,40 +12,30 @@ create_or_update_free_sms_fragment_limit_schema = {
|
||||
}
|
||||
|
||||
|
||||
def serialize_ft_billing_remove_emails(rows):
|
||||
return [
|
||||
{
|
||||
"month": (datetime.strftime(row.month, "%B")),
|
||||
"notification_type": row.notification_type,
|
||||
# TEMPORARY: while we migrate to "chargeable_units" in the Admin app
|
||||
"billing_units": row.billable_units,
|
||||
"chargeable_units": row.chargeable_units,
|
||||
"rate": float(row.rate),
|
||||
"postage": row.postage,
|
||||
"cost": float(row.cost),
|
||||
"free_chargeable_units": row.free_chargeable_units,
|
||||
"charged_units": row.charged_units,
|
||||
"notifications_sent": row.notifications_sent,
|
||||
def serialize_ft_billing_remove_emails(data):
|
||||
results = []
|
||||
billed_notifications = [x for x in data if x.notification_type != 'email']
|
||||
for notification in billed_notifications:
|
||||
json_result = {
|
||||
"month": (datetime.strftime(notification.month, "%B")),
|
||||
"notification_type": notification.notification_type,
|
||||
"billing_units": notification.billable_units,
|
||||
"rate": float(notification.rate),
|
||||
"postage": notification.postage,
|
||||
}
|
||||
for row in rows
|
||||
if row.notification_type != 'email'
|
||||
]
|
||||
results.append(json_result)
|
||||
return results
|
||||
|
||||
|
||||
def serialize_ft_billing_yearly_totals(rows):
|
||||
return [
|
||||
{
|
||||
"notification_type": row.notification_type,
|
||||
# TEMPORARY: while we migrate to "chargeable_units" in the Admin app
|
||||
"billing_units": row.billable_units,
|
||||
"chargeable_units": row.chargeable_units,
|
||||
"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,
|
||||
"cost": float(row.cost),
|
||||
"free_chargeable_units": row.free_chargeable_units,
|
||||
"charged_units": row.charged_units,
|
||||
"notifications_sent": row.notifications_sent,
|
||||
def serialize_ft_billing_yearly_totals(data):
|
||||
yearly_totals = []
|
||||
for total in data:
|
||||
json_result = {
|
||||
"notification_type": total.notification_type,
|
||||
"billing_units": total.billable_units,
|
||||
"rate": float(total.rate),
|
||||
"letter_total": float(total.billable_units * total.rate) if total.notification_type == 'letter' else 0
|
||||
}
|
||||
for row in rows
|
||||
]
|
||||
yearly_totals.append(json_result)
|
||||
|
||||
return yearly_totals
|
||||
|
||||
@@ -30,6 +30,7 @@ billing_blueprint = Blueprint(
|
||||
register_errors(billing_blueprint)
|
||||
|
||||
|
||||
@billing_blueprint.route('/ft-monthly-usage')
|
||||
@billing_blueprint.route('/monthly-usage')
|
||||
def get_yearly_usage_by_monthly_from_ft_billing(service_id):
|
||||
try:
|
||||
@@ -41,6 +42,7 @@ def get_yearly_usage_by_monthly_from_ft_billing(service_id):
|
||||
return jsonify(data)
|
||||
|
||||
|
||||
@billing_blueprint.route('/ft-yearly-usage-summary')
|
||||
@billing_blueprint.route('/yearly-usage-summary')
|
||||
def get_yearly_billing_usage_summary_from_ft_billing(service_id):
|
||||
try:
|
||||
|
||||
@@ -114,7 +114,7 @@ class Config(object):
|
||||
|
||||
# URL of redis instance
|
||||
REDIS_URL = os.getenv('REDIS_URL')
|
||||
REDIS_ENABLED = True
|
||||
REDIS_ENABLED = os.getenv('REDIS_ENABLED') == '1'
|
||||
EXPIRE_CACHE_TEN_MINUTES = 600
|
||||
EXPIRE_CACHE_EIGHT_DAYS = 8 * 24 * 60 * 60
|
||||
|
||||
@@ -404,8 +404,6 @@ class Development(Config):
|
||||
DEBUG = True
|
||||
SQLALCHEMY_ECHO = False
|
||||
|
||||
REDIS_ENABLED = os.getenv('REDIS_ENABLED') == '1'
|
||||
|
||||
CSV_UPLOAD_BUCKET_NAME = 'development-notifications-csv-upload'
|
||||
CONTACT_LIST_BUCKET_NAME = 'development-contact-list'
|
||||
TEST_LETTERS_BUCKET_NAME = 'development-test-letters'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from datetime import date, datetime, time, timedelta
|
||||
|
||||
import pytz
|
||||
from notifications_utils.timezones import convert_bst_to_utc, convert_utc_to_bst
|
||||
from notifications_utils.timezones import convert_bst_to_utc
|
||||
|
||||
|
||||
def get_months_for_financial_year(year):
|
||||
@@ -22,15 +22,6 @@ def get_financial_year(year):
|
||||
return get_april_fools(year), get_april_fools(year + 1) - timedelta(microseconds=1)
|
||||
|
||||
|
||||
def get_financial_year_dates(year):
|
||||
year_start_datetime, year_end_datetime = get_financial_year(year)
|
||||
|
||||
return (
|
||||
convert_utc_to_bst(year_start_datetime).date(),
|
||||
convert_utc_to_bst(year_end_datetime).date()
|
||||
)
|
||||
|
||||
|
||||
def get_current_financial_year():
|
||||
now = datetime.utcnow()
|
||||
current_month = int(now.strftime('%-m'))
|
||||
|
||||
@@ -11,10 +11,6 @@ def dao_get_email_branding_by_id(email_branding_id):
|
||||
return EmailBranding.query.filter_by(id=email_branding_id).one()
|
||||
|
||||
|
||||
def dao_get_email_branding_by_name(email_branding_name):
|
||||
return EmailBranding.query.filter_by(name=email_branding_name).first()
|
||||
|
||||
|
||||
@autocommit
|
||||
def dao_create_email_branding(email_branding):
|
||||
db.session.add(email_branding)
|
||||
|
||||
@@ -2,13 +2,13 @@ from datetime import date, datetime, timedelta
|
||||
|
||||
from flask import current_app
|
||||
from notifications_utils.timezones import convert_utc_to_bst
|
||||
from sqlalchemy import Date, Integer, and_, desc, func, union
|
||||
from sqlalchemy import Date, Integer, and_, desc, func
|
||||
from sqlalchemy.dialects.postgresql import insert
|
||||
from sqlalchemy.sql.expression import case, literal
|
||||
|
||||
from app import db
|
||||
from app.dao.date_util import (
|
||||
get_financial_year_dates,
|
||||
get_financial_year,
|
||||
get_financial_year_for_datetime,
|
||||
)
|
||||
from app.dao.organisation_dao import dao_get_organisation_live_services
|
||||
@@ -197,179 +197,111 @@ def fetch_letter_line_items_for_all_services(start_date, end_date):
|
||||
|
||||
|
||||
def fetch_billing_totals_for_year(service_id, year):
|
||||
return db.session.query(
|
||||
union(*[
|
||||
db.session.query(
|
||||
func.sum(query.c.notifications_sent).label("notifications_sent"),
|
||||
# TEMPORARY: while we switch to "chargeable units"
|
||||
func.sum(query.c.billable_units).label("billable_units"),
|
||||
func.sum(query.c.chargeable_units).label("chargeable_units"),
|
||||
query.c.rate.label("rate"),
|
||||
query.c.notification_type.label("notification_type"),
|
||||
func.sum(query.c.cost).label("cost"),
|
||||
func.sum(query.c.free_chargeable_units).label("free_chargeable_units"),
|
||||
func.sum(query.c.charged_units).label("charged_units"),
|
||||
).group_by(
|
||||
query.c.rate,
|
||||
query.c.notification_type
|
||||
)
|
||||
for query in [
|
||||
query_service_sms_usage_for_year(service_id, year).subquery(),
|
||||
query_service_email_usage_for_year(service_id, year).subquery(),
|
||||
query_service_letter_usage_for_year(service_id, year).subquery(),
|
||||
]
|
||||
]).subquery()
|
||||
).order_by(
|
||||
"notification_type",
|
||||
"rate",
|
||||
year_start_date, year_end_date = get_financial_year(year)
|
||||
"""
|
||||
Billing for email: only record the total number of emails.
|
||||
Billing for letters: The billing units is used to fetch the correct rate for the sheet count of the letter.
|
||||
Total cost is notifications_sent * rate.
|
||||
Rate multiplier does not apply to email or letters.
|
||||
"""
|
||||
email_and_letters = db.session.query(
|
||||
func.sum(FactBilling.notifications_sent).label("notifications_sent"),
|
||||
func.sum(FactBilling.notifications_sent).label("billable_units"),
|
||||
FactBilling.rate.label('rate'),
|
||||
FactBilling.notification_type.label('notification_type')
|
||||
).filter(
|
||||
FactBilling.service_id == service_id,
|
||||
FactBilling.bst_date >= year_start_date,
|
||||
FactBilling.bst_date <= year_end_date,
|
||||
FactBilling.notification_type.in_([EMAIL_TYPE, LETTER_TYPE])
|
||||
).group_by(
|
||||
FactBilling.rate,
|
||||
FactBilling.notification_type
|
||||
)
|
||||
"""
|
||||
Billing for SMS using the billing_units * rate_multiplier. Billing unit of SMS is the fragment count of a message
|
||||
"""
|
||||
sms = db.session.query(
|
||||
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_date,
|
||||
FactBilling.bst_date <= year_end_date,
|
||||
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()
|
||||
|
||||
return yearly_data
|
||||
|
||||
|
||||
def fetch_monthly_billing_for_year(service_id, year):
|
||||
_, year_end = get_financial_year_dates(year)
|
||||
today = convert_utc_to_bst(datetime.utcnow()).date()
|
||||
year_start_datetime, year_end_datetime = get_financial_year(year)
|
||||
|
||||
year_start_date = convert_utc_to_bst(year_start_datetime).date()
|
||||
year_end_date = convert_utc_to_bst(year_end_datetime).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 >= today:
|
||||
if year_end_date >= today:
|
||||
data = fetch_billing_data_for_day(process_day=today, service_id=service_id, check_permissions=True)
|
||||
for d in data:
|
||||
update_fact_billing(data=d, process_day=today)
|
||||
|
||||
return db.session.query(
|
||||
union(*[
|
||||
db.session.query(
|
||||
func.date_trunc('month', query.c.bst_date).cast(Date).label("month"),
|
||||
func.sum(query.c.notifications_sent).label("notifications_sent"),
|
||||
# TEMPORARY: while we switch to "chargeable units"
|
||||
func.sum(query.c.billable_units).label("billable_units"),
|
||||
func.sum(query.c.chargeable_units).label("chargeable_units"),
|
||||
query.c.rate.label("rate"),
|
||||
query.c.postage.label("postage"),
|
||||
query.c.notification_type.label("notification_type"),
|
||||
func.sum(query.c.cost).label("cost"),
|
||||
func.sum(query.c.free_chargeable_units).label("free_chargeable_units"),
|
||||
func.sum(query.c.charged_units).label("charged_units"),
|
||||
).group_by(
|
||||
query.c.rate,
|
||||
query.c.notification_type,
|
||||
query.c.postage,
|
||||
'month',
|
||||
)
|
||||
for query in [
|
||||
query_service_sms_usage_for_year(service_id, year).subquery(),
|
||||
query_service_email_usage_for_year(service_id, year).subquery(),
|
||||
query_service_letter_usage_for_year(service_id, year).subquery(),
|
||||
]
|
||||
]).subquery()
|
||||
).order_by(
|
||||
"month",
|
||||
"notification_type",
|
||||
"rate",
|
||||
email_and_letters = db.session.query(
|
||||
func.date_trunc('month', FactBilling.bst_date).cast(Date).label("month"),
|
||||
func.sum(FactBilling.notifications_sent).label("notifications_sent"),
|
||||
func.sum(FactBilling.notifications_sent).label("billable_units"),
|
||||
FactBilling.rate.label('rate'),
|
||||
FactBilling.notification_type.label('notification_type'),
|
||||
FactBilling.postage
|
||||
).filter(
|
||||
FactBilling.service_id == service_id,
|
||||
FactBilling.bst_date >= year_start_date,
|
||||
FactBilling.bst_date <= year_end_date,
|
||||
FactBilling.notification_type.in_([EMAIL_TYPE, LETTER_TYPE])
|
||||
).group_by(
|
||||
'month',
|
||||
FactBilling.rate,
|
||||
FactBilling.notification_type,
|
||||
FactBilling.postage
|
||||
)
|
||||
|
||||
sms = db.session.query(
|
||||
func.date_trunc('month', FactBilling.bst_date).cast(Date).label("month"),
|
||||
func.sum(FactBilling.notifications_sent).label("notifications_sent"),
|
||||
func.sum(FactBilling.billable_units * FactBilling.rate_multiplier).label("billable_units"),
|
||||
FactBilling.rate,
|
||||
FactBilling.notification_type,
|
||||
FactBilling.postage
|
||||
).filter(
|
||||
FactBilling.service_id == service_id,
|
||||
FactBilling.bst_date >= year_start_date,
|
||||
FactBilling.bst_date <= year_end_date,
|
||||
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()
|
||||
|
||||
|
||||
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,
|
||||
)
|
||||
return yearly_data
|
||||
|
||||
|
||||
def delete_billing_data_for_service_for_day(process_day, service_id):
|
||||
@@ -717,12 +649,15 @@ def fetch_sms_billing_for_organisation(organisation_id, start_date, end_date):
|
||||
|
||||
|
||||
def fetch_usage_year_for_organisation(organisation_id, year):
|
||||
year_start, year_end = get_financial_year_dates(year)
|
||||
year_start_datetime, year_end_datetime = get_financial_year(year)
|
||||
|
||||
year_start_date = convert_utc_to_bst(year_start_datetime).date()
|
||||
year_end_date = convert_utc_to_bst(year_end_datetime).date()
|
||||
|
||||
today = convert_utc_to_bst(datetime.utcnow()).date()
|
||||
services = dao_get_organisation_live_services(organisation_id)
|
||||
|
||||
# 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 >= today:
|
||||
if year_end_date >= today:
|
||||
for service in services:
|
||||
data = fetch_billing_data_for_day(process_day=today, service_id=service.id)
|
||||
for d in data:
|
||||
@@ -742,9 +677,9 @@ def fetch_usage_year_for_organisation(organisation_id, year):
|
||||
'emails_sent': 0,
|
||||
'active': service.active
|
||||
}
|
||||
sms_usages = fetch_sms_billing_for_organisation(organisation_id, year_start, year_end)
|
||||
letter_usages = fetch_letter_costs_for_organisation(organisation_id, year_start, year_end)
|
||||
email_usages = fetch_email_usage_for_organisation(organisation_id, year_start, year_end)
|
||||
sms_usages = fetch_sms_billing_for_organisation(organisation_id, year_start_date, year_end_date)
|
||||
letter_usages = fetch_letter_costs_for_organisation(organisation_id, year_start_date, year_end_date)
|
||||
email_usages = fetch_email_usage_for_organisation(organisation_id, year_start_date, year_end_date)
|
||||
for usage in sms_usages:
|
||||
service_with_usage[str(usage.service_id)] = {
|
||||
'service_id': usage.service_id,
|
||||
|
||||
@@ -9,7 +9,7 @@ from sqlalchemy.sql.expression import and_, asc, case, func
|
||||
from app import db
|
||||
from app.dao.dao_utils import VersionOptions, autocommit, version_class
|
||||
from app.dao.date_util import get_current_financial_year
|
||||
from app.dao.email_branding_dao import dao_get_email_branding_by_name
|
||||
from app.dao.email_branding_dao import dao_get_email_branding_by_id
|
||||
from app.dao.letter_branding_dao import dao_get_letter_branding_by_name
|
||||
from app.dao.organisation_dao import dao_get_organisation_by_email_address
|
||||
from app.dao.service_sms_sender_dao import insert_service_sms_sender
|
||||
@@ -326,7 +326,7 @@ def dao_create_service(
|
||||
service.letter_branding = organisation.letter_branding
|
||||
|
||||
elif service.organisation_type in NHS_ORGANISATION_TYPES or email_address_is_nhs(user.email_address):
|
||||
service.email_branding = dao_get_email_branding_by_name('NHS')
|
||||
service.email_branding = dao_get_email_branding_by_id(current_app.config['NHS_EMAIL_BRANDING_ID'])
|
||||
service.letter_branding = dao_get_letter_branding_by_name('NHS')
|
||||
|
||||
if organisation:
|
||||
|
||||
@@ -122,7 +122,6 @@ applications:
|
||||
ROUTE_SECRET_KEY_1: '{{ ROUTE_SECRET_KEY_1 }}'
|
||||
ROUTE_SECRET_KEY_2: '{{ ROUTE_SECRET_KEY_2 }}'
|
||||
CRONITOR_KEYS: '{{ CRONITOR_KEYS | tojson }}'
|
||||
METRICS_BASIC_AUTH_TOKEN: {{ METRICS_BASIC_AUTH_TOKEN }}
|
||||
|
||||
HIGH_VOLUME_SERVICE: '{{ HIGH_VOLUME_SERVICE | tojson }}'
|
||||
|
||||
@@ -145,6 +144,8 @@ applications:
|
||||
FIRETEXT_INTERNATIONAL_API_KEY: '{{ FIRETEXT_INTERNATIONAL_API_KEY }}'
|
||||
FIRETEXT_INBOUND_SMS_AUTH: '{{ FIRETEXT_INBOUND_SMS_AUTH | tojson }}'
|
||||
|
||||
REDIS_ENABLED: '{{ REDIS_ENABLED }}'
|
||||
|
||||
TEMPLATE_PREVIEW_API_HOST: '{{ TEMPLATE_PREVIEW_API_HOST }}'
|
||||
TEMPLATE_PREVIEW_API_KEY: '{{ TEMPLATE_PREVIEW_API_KEY }}'
|
||||
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
"""
|
||||
|
||||
Revision ID: 0369_update_sms_rates
|
||||
Revises: 0368_move_orgs_to_nhs_branding
|
||||
Create Date: 2022-04-26 09:39:45.260951
|
||||
|
||||
"""
|
||||
import uuid
|
||||
|
||||
from alembic import op
|
||||
|
||||
revision = '0369_update_sms_rates'
|
||||
down_revision = '0368_move_orgs_to_nhs_branding'
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.execute(
|
||||
"INSERT INTO rates(id, valid_from, rate, notification_type) "
|
||||
f"VALUES('{uuid.uuid4()}', '2022-04-30 23:00:00', 0.0172, 'sms')"
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
pass
|
||||
@@ -5,6 +5,5 @@ env =
|
||||
MMG_API_KEY=mmg-secret-key
|
||||
FIRETEXT_API_KEY=Firetext
|
||||
NOTIFICATION_QUEUE_PREFIX=testing
|
||||
REDIS_ENABLED=0
|
||||
addopts = -p no:warnings
|
||||
xfail_strict = true
|
||||
|
||||
@@ -33,4 +33,4 @@ notifications-utils @ git+https://github.com/alphagov/notifications-utils.git@55
|
||||
|
||||
# gds-metrics requires prometheseus 0.2.0, override that requirement as 0.7.1 brings significant performance gains
|
||||
prometheus-client==0.14.1
|
||||
git+https://github.com/alphagov/gds_metrics_python.git@6f1840a57b6fb1ee40b7e84f2f18ec229de8aa72
|
||||
gds-metrics==0.2.4
|
||||
|
||||
@@ -98,16 +98,14 @@ flask-sqlalchemy @ git+https://github.com/mitsuhiko/flask-sqlalchemy.git@500e732
|
||||
# flask-migrate
|
||||
fqdn==1.5.1
|
||||
# via jsonschema
|
||||
gds-metrics @ git+https://github.com/alphagov/gds_metrics_python.git@6f1840a57b6fb1ee40b7e84f2f18ec229de8aa72
|
||||
gds-metrics==0.2.4
|
||||
# via -r requirements.in
|
||||
geojson==2.5.0
|
||||
# via notifications-utils
|
||||
govuk-bank-holidays==0.10
|
||||
# via notifications-utils
|
||||
greenlet==1.1.2
|
||||
# via
|
||||
# eventlet
|
||||
# sqlalchemy
|
||||
# via eventlet
|
||||
gunicorn @ git+https://github.com/benoitc/gunicorn.git@1299ea9e967a61ae2edebe191082fd169b864c64
|
||||
# via -r requirements.in
|
||||
idna==3.3
|
||||
|
||||
411
tests/app/billing/test_billing.py
Normal file
411
tests/app/billing/test_billing.py
Normal file
@@ -0,0 +1,411 @@
|
||||
import json
|
||||
from calendar import monthrange
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import pytest
|
||||
from freezegun import freeze_time
|
||||
|
||||
from app.billing.rest import update_free_sms_fragment_limit_data
|
||||
from app.dao.annual_billing_dao import dao_get_free_sms_fragment_limit_for_year
|
||||
from app.dao.date_util import (
|
||||
get_current_financial_year_start_year,
|
||||
get_month_start_and_end_date_in_utc,
|
||||
)
|
||||
from app.models import FactBilling
|
||||
from tests import create_admin_authorization_header
|
||||
from tests.app.db import (
|
||||
create_annual_billing,
|
||||
create_ft_billing,
|
||||
create_notification,
|
||||
create_rate,
|
||||
create_service,
|
||||
create_template,
|
||||
)
|
||||
|
||||
APR_2016_MONTH_START = datetime(2016, 3, 31, 23, 00, 00)
|
||||
APR_2016_MONTH_END = datetime(2016, 4, 30, 22, 59, 59, 99999)
|
||||
|
||||
IN_MAY_2016 = datetime(2016, 5, 10, 23, 00, 00)
|
||||
IN_JUN_2016 = datetime(2016, 6, 3, 23, 00, 00)
|
||||
|
||||
|
||||
def test_create_update_free_sms_fragment_limit_invalid_schema(client, sample_service):
|
||||
|
||||
response = client.post('service/{}/billing/free-sms-fragment-limit'.format(sample_service.id),
|
||||
data={},
|
||||
headers=[('Content-Type', 'application/json'), create_admin_authorization_header()])
|
||||
json_resp = json.loads(response.get_data(as_text=True))
|
||||
|
||||
assert response.status_code == 400
|
||||
assert 'JSON' in json_resp['message']
|
||||
|
||||
|
||||
def test_create_free_sms_fragment_limit_current_year_updates_future_years(admin_request, sample_service):
|
||||
current_year = get_current_financial_year_start_year()
|
||||
future_billing = create_annual_billing(sample_service.id, 1, current_year + 1)
|
||||
|
||||
admin_request.post(
|
||||
'billing.create_or_update_free_sms_fragment_limit',
|
||||
service_id=sample_service.id,
|
||||
_data={'free_sms_fragment_limit': 9999},
|
||||
_expected_status=201
|
||||
)
|
||||
|
||||
current_billing = dao_get_free_sms_fragment_limit_for_year(sample_service.id, current_year)
|
||||
assert future_billing.free_sms_fragment_limit == 9999
|
||||
assert current_billing.financial_year_start == current_year
|
||||
assert current_billing.free_sms_fragment_limit == 9999
|
||||
|
||||
|
||||
@pytest.mark.parametrize('update_existing', [True, False])
|
||||
def test_create_or_update_free_sms_fragment_limit_past_year_doenst_update_other_years(
|
||||
admin_request,
|
||||
sample_service,
|
||||
update_existing
|
||||
):
|
||||
current_year = get_current_financial_year_start_year()
|
||||
create_annual_billing(sample_service.id, 1, current_year)
|
||||
if update_existing:
|
||||
create_annual_billing(sample_service.id, 1, current_year - 1)
|
||||
|
||||
data = {'financial_year_start': current_year - 1, 'free_sms_fragment_limit': 9999}
|
||||
admin_request.post(
|
||||
'billing.create_or_update_free_sms_fragment_limit',
|
||||
service_id=sample_service.id,
|
||||
_data=data,
|
||||
_expected_status=201)
|
||||
|
||||
assert dao_get_free_sms_fragment_limit_for_year(sample_service.id, current_year - 1).free_sms_fragment_limit == 9999
|
||||
assert dao_get_free_sms_fragment_limit_for_year(sample_service.id, current_year).free_sms_fragment_limit == 1
|
||||
|
||||
|
||||
def test_create_free_sms_fragment_limit_updates_existing_year(admin_request, sample_service):
|
||||
current_year = get_current_financial_year_start_year()
|
||||
annual_billing = create_annual_billing(sample_service.id, 1, current_year)
|
||||
|
||||
admin_request.post(
|
||||
'billing.create_or_update_free_sms_fragment_limit',
|
||||
service_id=sample_service.id,
|
||||
_data={'financial_year_start': current_year, 'free_sms_fragment_limit': 2},
|
||||
_expected_status=201)
|
||||
|
||||
assert annual_billing.free_sms_fragment_limit == 2
|
||||
|
||||
|
||||
@freeze_time('2021-04-02 13:00')
|
||||
def test_get_free_sms_fragment_limit(
|
||||
client, sample_service
|
||||
):
|
||||
create_annual_billing(service_id=sample_service.id, free_sms_fragment_limit=11000, financial_year_start=2021)
|
||||
response_get = client.get(
|
||||
'service/{}/billing/free-sms-fragment-limit'.format(sample_service.id),
|
||||
headers=[('Content-Type', 'application/json'), create_admin_authorization_header()])
|
||||
|
||||
json_resp = json.loads(response_get.get_data(as_text=True))
|
||||
assert response_get.status_code == 200
|
||||
assert json_resp['financial_year_start'] == 2021
|
||||
assert json_resp['free_sms_fragment_limit'] == 11000
|
||||
|
||||
|
||||
@freeze_time('2021-04-02 13:00')
|
||||
def test_get_free_sms_fragment_limit_current_year_creates_new_row_if_annual_billing_is_missing(
|
||||
client, sample_service
|
||||
):
|
||||
response_get = client.get(
|
||||
'service/{}/billing/free-sms-fragment-limit'.format(sample_service.id),
|
||||
headers=[('Content-Type', 'application/json'), create_admin_authorization_header()])
|
||||
|
||||
json_resp = json.loads(response_get.get_data(as_text=True))
|
||||
assert response_get.status_code == 200
|
||||
assert json_resp['financial_year_start'] == 2021
|
||||
assert json_resp['free_sms_fragment_limit'] == 10000 # based on other organisation type
|
||||
|
||||
|
||||
def test_update_free_sms_fragment_limit_data(client, sample_service):
|
||||
current_year = get_current_financial_year_start_year()
|
||||
create_annual_billing(sample_service.id, free_sms_fragment_limit=250000, financial_year_start=current_year - 1)
|
||||
|
||||
update_free_sms_fragment_limit_data(sample_service.id, 9999, current_year)
|
||||
|
||||
annual_billing = dao_get_free_sms_fragment_limit_for_year(sample_service.id, current_year)
|
||||
assert annual_billing.free_sms_fragment_limit == 9999
|
||||
|
||||
|
||||
@freeze_time('2018-04-21 14:00')
|
||||
def test_get_yearly_usage_by_monthly_from_ft_billing_populates_deltas(client, notify_db_session):
|
||||
service = create_service()
|
||||
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_notification(template=sms_template, status='delivered')
|
||||
|
||||
assert FactBilling.query.count() == 0
|
||||
|
||||
response = client.get('service/{}/billing/ft-monthly-usage?year=2018'.format(service.id),
|
||||
headers=[('Content-Type', 'application/json'), create_admin_authorization_header()])
|
||||
|
||||
assert response.status_code == 200
|
||||
assert len(json.loads(response.get_data(as_text=True))) == 1
|
||||
fact_billing = FactBilling.query.all()
|
||||
assert len(fact_billing) == 1
|
||||
assert fact_billing[0].notification_type == 'sms'
|
||||
|
||||
|
||||
def test_get_yearly_usage_by_monthly_from_ft_billing(client, notify_db_session):
|
||||
service = create_service()
|
||||
sms_template = create_template(service=service, template_type="sms")
|
||||
email_template = create_template(service=service, template_type="email")
|
||||
letter_template = create_template(service=service, template_type="letter")
|
||||
for month in range(1, 13):
|
||||
mon = str(month).zfill(2)
|
||||
for day in range(1, monthrange(2016, month)[1] + 1):
|
||||
d = str(day).zfill(2)
|
||||
create_ft_billing(bst_date='2016-{}-{}'.format(mon, d),
|
||||
template=sms_template,
|
||||
billable_unit=1,
|
||||
rate=0.162)
|
||||
create_ft_billing(bst_date='2016-{}-{}'.format(mon, d),
|
||||
template=email_template,
|
||||
rate=0)
|
||||
create_ft_billing(bst_date='2016-{}-{}'.format(mon, d),
|
||||
template=letter_template,
|
||||
billable_unit=1,
|
||||
rate=0.33,
|
||||
postage='second')
|
||||
|
||||
response = client.get('service/{}/billing/ft-monthly-usage?year=2016'.format(service.id),
|
||||
headers=[('Content-Type', 'application/json'), create_admin_authorization_header()])
|
||||
|
||||
json_resp = json.loads(response.get_data(as_text=True))
|
||||
ft_letters = [x for x in json_resp if x['notification_type'] == 'letter']
|
||||
ft_sms = [x for x in json_resp if x['notification_type'] == 'sms']
|
||||
ft_email = [x for x in json_resp if x['notification_type'] == 'email']
|
||||
keys = [x.keys() for x in ft_sms][0]
|
||||
expected_sms_april = {"month": "April",
|
||||
"notification_type": "sms",
|
||||
"billing_units": 30,
|
||||
"rate": 0.162,
|
||||
"postage": "none"
|
||||
}
|
||||
expected_letter_april = {"month": "April",
|
||||
"notification_type": "letter",
|
||||
"billing_units": 30,
|
||||
"rate": 0.33,
|
||||
"postage": "second"
|
||||
}
|
||||
|
||||
for k in keys:
|
||||
assert ft_sms[0][k] == expected_sms_april[k]
|
||||
assert ft_letters[0][k] == expected_letter_april[k]
|
||||
assert len(ft_email) == 0
|
||||
|
||||
|
||||
def set_up_yearly_data():
|
||||
service = create_service()
|
||||
sms_template = create_template(service=service, template_type="sms")
|
||||
email_template = create_template(service=service, template_type="email")
|
||||
letter_template = create_template(service=service, template_type="letter")
|
||||
for month in range(1, 13):
|
||||
mon = str(month).zfill(2)
|
||||
for day in range(1, monthrange(2016, month)[1] + 1):
|
||||
d = str(day).zfill(2)
|
||||
create_ft_billing(bst_date='2016-{}-{}'.format(mon, d),
|
||||
template=sms_template,
|
||||
rate=0.0162)
|
||||
create_ft_billing(bst_date='2016-{}-{}'.format(mon, d),
|
||||
template=sms_template,
|
||||
rate_multiplier=2,
|
||||
rate=0.0162)
|
||||
create_ft_billing(bst_date='2016-{}-{}'.format(mon, d),
|
||||
template=email_template,
|
||||
billable_unit=0,
|
||||
rate=0)
|
||||
create_ft_billing(bst_date='2016-{}-{}'.format(mon, d),
|
||||
template=letter_template,
|
||||
rate=0.33,
|
||||
postage='second')
|
||||
start_date, end_date = get_month_start_and_end_date_in_utc(datetime(2016, int(mon), 1))
|
||||
return service
|
||||
|
||||
|
||||
def test_get_yearly_billing_usage_summary_from_ft_billing_returns_400_if_missing_year(client, sample_service):
|
||||
response = client.get(
|
||||
'/service/{}/billing/ft-yearly-usage-summary'.format(sample_service.id),
|
||||
headers=[create_admin_authorization_header()]
|
||||
)
|
||||
assert response.status_code == 400
|
||||
assert json.loads(response.get_data(as_text=True)) == {
|
||||
'message': 'No valid year provided', 'result': 'error'
|
||||
}
|
||||
|
||||
|
||||
def test_get_yearly_billing_usage_summary_from_ft_billing_returns_empty_list_if_no_billing_data(
|
||||
client, sample_service
|
||||
):
|
||||
response = client.get(
|
||||
'/service/{}/billing/ft-yearly-usage-summary?year=2016'.format(sample_service.id),
|
||||
headers=[create_admin_authorization_header()]
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert json.loads(response.get_data(as_text=True)) == []
|
||||
|
||||
|
||||
def test_get_yearly_billing_usage_summary_from_ft_billing(client, notify_db_session):
|
||||
service = set_up_yearly_data()
|
||||
|
||||
response = client.get('/service/{}/billing/ft-yearly-usage-summary?year=2016'.format(service.id),
|
||||
headers=[create_admin_authorization_header()]
|
||||
)
|
||||
assert response.status_code == 200
|
||||
json_response = json.loads(response.get_data(as_text=True))
|
||||
assert len(json_response) == 3
|
||||
assert json_response[0]['notification_type'] == 'email'
|
||||
assert json_response[0]['billing_units'] == 275
|
||||
assert json_response[0]['rate'] == 0
|
||||
assert json_response[0]['letter_total'] == 0
|
||||
assert json_response[1]['notification_type'] == 'letter'
|
||||
assert json_response[1]['billing_units'] == 275
|
||||
assert json_response[1]['rate'] == 0.33
|
||||
assert json_response[1]['letter_total'] == 90.75
|
||||
assert json_response[2]['notification_type'] == 'sms'
|
||||
assert json_response[2]['billing_units'] == 825
|
||||
assert json_response[2]['rate'] == 0.0162
|
||||
assert json_response[2]['letter_total'] == 0
|
||||
|
||||
|
||||
def test_get_yearly_usage_by_monthly_from_ft_billing_all_cases(client, notify_db_session):
|
||||
service = set_up_data_for_all_cases()
|
||||
response = client.get('service/{}/billing/ft-monthly-usage?year=2018'.format(service.id),
|
||||
headers=[('Content-Type', 'application/json'), create_admin_authorization_header()])
|
||||
|
||||
assert response.status_code == 200
|
||||
json_response = json.loads(response.get_data(as_text=True))
|
||||
assert len(json_response) == 5
|
||||
assert json_response[0]['month'] == 'May'
|
||||
assert json_response[0]['notification_type'] == 'letter'
|
||||
assert json_response[0]['rate'] == 0.33
|
||||
assert json_response[0]['billing_units'] == 1
|
||||
assert json_response[0]['postage'] == 'second'
|
||||
|
||||
assert json_response[1]['month'] == 'May'
|
||||
assert json_response[1]['notification_type'] == 'letter'
|
||||
assert json_response[1]['rate'] == 0.36
|
||||
assert json_response[1]['billing_units'] == 1
|
||||
assert json_response[1]['postage'] == 'second'
|
||||
|
||||
assert json_response[2]['month'] == 'May'
|
||||
assert json_response[2]['notification_type'] == 'letter'
|
||||
assert json_response[2]['rate'] == 0.39
|
||||
assert json_response[2]['billing_units'] == 1
|
||||
assert json_response[2]['postage'] == 'first'
|
||||
|
||||
assert json_response[3]['month'] == 'May'
|
||||
assert json_response[3]['notification_type'] == 'sms'
|
||||
assert json_response[3]['rate'] == 0.0150
|
||||
assert json_response[3]['billing_units'] == 4
|
||||
assert json_response[3]['postage'] == 'none'
|
||||
|
||||
assert json_response[4]['month'] == 'May'
|
||||
assert json_response[4]['notification_type'] == 'sms'
|
||||
assert json_response[4]['rate'] == 0.162
|
||||
assert json_response[4]['billing_units'] == 5
|
||||
assert json_response[4]['postage'] == 'none'
|
||||
|
||||
|
||||
def test_get_yearly_billing_usage_summary_from_ft_billing_all_cases(client, notify_db_session):
|
||||
service = set_up_data_for_all_cases()
|
||||
response = client.get('/service/{}/billing/ft-yearly-usage-summary?year=2018'.format(service.id),
|
||||
headers=[create_admin_authorization_header()])
|
||||
assert response.status_code == 200
|
||||
json_response = json.loads(response.get_data(as_text=True))
|
||||
|
||||
assert len(json_response) == 6
|
||||
assert json_response[0]["notification_type"] == 'email'
|
||||
assert json_response[0]["billing_units"] == 1
|
||||
assert json_response[0]["rate"] == 0
|
||||
assert json_response[0]["letter_total"] == 0
|
||||
|
||||
assert json_response[1]["notification_type"] == 'letter'
|
||||
assert json_response[1]["billing_units"] == 1
|
||||
assert json_response[1]["rate"] == 0.33
|
||||
assert json_response[1]["letter_total"] == 0.33
|
||||
|
||||
assert json_response[2]["notification_type"] == 'letter'
|
||||
assert json_response[2]["billing_units"] == 1
|
||||
assert json_response[2]["rate"] == 0.36
|
||||
assert json_response[2]["letter_total"] == 0.36
|
||||
|
||||
assert json_response[3]["notification_type"] == 'letter'
|
||||
assert json_response[3]["billing_units"] == 1
|
||||
assert json_response[3]["rate"] == 0.39
|
||||
assert json_response[3]["letter_total"] == 0.39
|
||||
|
||||
assert json_response[4]["notification_type"] == 'sms'
|
||||
assert json_response[4]["billing_units"] == 4
|
||||
assert json_response[4]["rate"] == 0.0150
|
||||
assert json_response[4]["letter_total"] == 0
|
||||
|
||||
assert json_response[5]["notification_type"] == 'sms'
|
||||
assert json_response[5]["billing_units"] == 5
|
||||
assert json_response[5]["rate"] == 0.162
|
||||
assert json_response[5]["letter_total"] == 0
|
||||
|
||||
|
||||
def set_up_data_for_all_cases():
|
||||
service = create_service()
|
||||
sms_template = create_template(service=service, template_type="sms")
|
||||
email_template = create_template(service=service, template_type="email")
|
||||
letter_template = create_template(service=service, template_type="letter")
|
||||
create_ft_billing(bst_date='2018-05-16',
|
||||
template=sms_template,
|
||||
rate_multiplier=1,
|
||||
international=False,
|
||||
rate=0.162,
|
||||
billable_unit=1,
|
||||
notifications_sent=1)
|
||||
create_ft_billing(bst_date='2018-05-17',
|
||||
template=sms_template,
|
||||
rate_multiplier=2,
|
||||
international=False,
|
||||
rate=0.162,
|
||||
billable_unit=2,
|
||||
notifications_sent=1)
|
||||
create_ft_billing(bst_date='2018-05-16',
|
||||
template=sms_template,
|
||||
rate_multiplier=2,
|
||||
international=False,
|
||||
rate=0.0150,
|
||||
billable_unit=2,
|
||||
notifications_sent=1)
|
||||
create_ft_billing(bst_date='2018-05-16',
|
||||
template=email_template,
|
||||
rate_multiplier=1,
|
||||
international=False,
|
||||
rate=0,
|
||||
billable_unit=0,
|
||||
notifications_sent=1)
|
||||
create_ft_billing(bst_date='2018-05-16',
|
||||
template=letter_template,
|
||||
rate_multiplier=1,
|
||||
international=False,
|
||||
rate=0.33,
|
||||
billable_unit=1,
|
||||
notifications_sent=1,
|
||||
postage='second')
|
||||
create_ft_billing(bst_date='2018-05-17',
|
||||
template=letter_template,
|
||||
rate_multiplier=1,
|
||||
international=False,
|
||||
rate=0.36,
|
||||
billable_unit=2,
|
||||
notifications_sent=1,
|
||||
postage='second')
|
||||
create_ft_billing(bst_date='2018-05-18',
|
||||
template=letter_template,
|
||||
rate_multiplier=1,
|
||||
international=False,
|
||||
rate=0.39,
|
||||
billable_unit=3,
|
||||
notifications_sent=1,
|
||||
postage='first')
|
||||
return service
|
||||
@@ -1,288 +0,0 @@
|
||||
from calendar import monthrange
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
from freezegun import freeze_time
|
||||
|
||||
from app.billing.rest import update_free_sms_fragment_limit_data
|
||||
from app.dao.annual_billing_dao import dao_get_free_sms_fragment_limit_for_year
|
||||
from app.dao.date_util import (
|
||||
get_current_financial_year_start_year,
|
||||
get_month_start_and_end_date_in_utc,
|
||||
)
|
||||
from tests.app.db import (
|
||||
create_annual_billing,
|
||||
create_ft_billing,
|
||||
create_service,
|
||||
create_template,
|
||||
)
|
||||
|
||||
APR_2016_MONTH_START = datetime(2016, 3, 31, 23, 00, 00)
|
||||
APR_2016_MONTH_END = datetime(2016, 4, 30, 22, 59, 59, 99999)
|
||||
|
||||
IN_MAY_2016 = datetime(2016, 5, 10, 23, 00, 00)
|
||||
IN_JUN_2016 = datetime(2016, 6, 3, 23, 00, 00)
|
||||
|
||||
|
||||
def test_create_update_free_sms_fragment_limit_invalid_schema(admin_request, sample_service):
|
||||
json_response = admin_request.post(
|
||||
'billing.create_or_update_free_sms_fragment_limit',
|
||||
service_id=sample_service.id,
|
||||
_data={},
|
||||
_expected_status=400
|
||||
)
|
||||
|
||||
assert 'errors' in json_response
|
||||
|
||||
|
||||
def test_create_free_sms_fragment_limit_current_year_updates_future_years(admin_request, sample_service):
|
||||
current_year = get_current_financial_year_start_year()
|
||||
future_billing = create_annual_billing(sample_service.id, 1, current_year + 1)
|
||||
|
||||
admin_request.post(
|
||||
'billing.create_or_update_free_sms_fragment_limit',
|
||||
service_id=sample_service.id,
|
||||
_data={'free_sms_fragment_limit': 9999},
|
||||
_expected_status=201
|
||||
)
|
||||
|
||||
current_billing = dao_get_free_sms_fragment_limit_for_year(sample_service.id, current_year)
|
||||
assert future_billing.free_sms_fragment_limit == 9999
|
||||
assert current_billing.financial_year_start == current_year
|
||||
assert current_billing.free_sms_fragment_limit == 9999
|
||||
|
||||
|
||||
@pytest.mark.parametrize('update_existing', [True, False])
|
||||
def test_create_or_update_free_sms_fragment_limit_past_year_doenst_update_other_years(
|
||||
admin_request,
|
||||
sample_service,
|
||||
update_existing
|
||||
):
|
||||
current_year = get_current_financial_year_start_year()
|
||||
create_annual_billing(sample_service.id, 1, current_year)
|
||||
if update_existing:
|
||||
create_annual_billing(sample_service.id, 1, current_year - 1)
|
||||
|
||||
data = {'financial_year_start': current_year - 1, 'free_sms_fragment_limit': 9999}
|
||||
admin_request.post(
|
||||
'billing.create_or_update_free_sms_fragment_limit',
|
||||
service_id=sample_service.id,
|
||||
_data=data,
|
||||
_expected_status=201)
|
||||
|
||||
assert dao_get_free_sms_fragment_limit_for_year(sample_service.id, current_year - 1).free_sms_fragment_limit == 9999
|
||||
assert dao_get_free_sms_fragment_limit_for_year(sample_service.id, current_year).free_sms_fragment_limit == 1
|
||||
|
||||
|
||||
def test_create_free_sms_fragment_limit_updates_existing_year(admin_request, sample_service):
|
||||
current_year = get_current_financial_year_start_year()
|
||||
annual_billing = create_annual_billing(sample_service.id, 1, current_year)
|
||||
|
||||
admin_request.post(
|
||||
'billing.create_or_update_free_sms_fragment_limit',
|
||||
service_id=sample_service.id,
|
||||
_data={'financial_year_start': current_year, 'free_sms_fragment_limit': 2},
|
||||
_expected_status=201)
|
||||
|
||||
assert annual_billing.free_sms_fragment_limit == 2
|
||||
|
||||
|
||||
@freeze_time('2021-04-02 13:00')
|
||||
def test_get_free_sms_fragment_limit(
|
||||
admin_request, sample_service
|
||||
):
|
||||
create_annual_billing(service_id=sample_service.id, free_sms_fragment_limit=11000, financial_year_start=2021)
|
||||
|
||||
json_response = admin_request.get(
|
||||
'billing.get_free_sms_fragment_limit',
|
||||
service_id=sample_service.id
|
||||
)
|
||||
|
||||
assert json_response['financial_year_start'] == 2021
|
||||
assert json_response['free_sms_fragment_limit'] == 11000
|
||||
|
||||
|
||||
@freeze_time('2021-04-02 13:00')
|
||||
def test_get_free_sms_fragment_limit_current_year_creates_new_row_if_annual_billing_is_missing(
|
||||
admin_request, sample_service
|
||||
):
|
||||
json_response = admin_request.get(
|
||||
'billing.get_free_sms_fragment_limit',
|
||||
service_id=sample_service.id
|
||||
)
|
||||
|
||||
assert json_response['financial_year_start'] == 2021
|
||||
assert json_response['free_sms_fragment_limit'] == 10000 # based on other organisation type
|
||||
|
||||
|
||||
def test_update_free_sms_fragment_limit_data(client, sample_service):
|
||||
current_year = get_current_financial_year_start_year()
|
||||
create_annual_billing(sample_service.id, free_sms_fragment_limit=250000, financial_year_start=current_year - 1)
|
||||
|
||||
update_free_sms_fragment_limit_data(sample_service.id, 9999, current_year)
|
||||
|
||||
annual_billing = dao_get_free_sms_fragment_limit_for_year(sample_service.id, current_year)
|
||||
assert annual_billing.free_sms_fragment_limit == 9999
|
||||
|
||||
|
||||
def set_up_monthly_data():
|
||||
service = create_service()
|
||||
sms_template = create_template(service=service, template_type="sms")
|
||||
email_template = create_template(service=service, template_type="email")
|
||||
letter_template = create_template(service=service, template_type="letter")
|
||||
|
||||
for month in range(1, 13):
|
||||
mon = str(month).zfill(2)
|
||||
for day in range(1, monthrange(2016, month)[1] + 1):
|
||||
d = str(day).zfill(2)
|
||||
create_ft_billing(bst_date='2016-{}-{}'.format(mon, d),
|
||||
template=sms_template,
|
||||
billable_unit=1,
|
||||
rate=0.162)
|
||||
create_ft_billing(bst_date='2016-{}-{}'.format(mon, d),
|
||||
template=email_template,
|
||||
rate=0)
|
||||
create_ft_billing(bst_date='2016-{}-{}'.format(mon, d),
|
||||
template=letter_template,
|
||||
billable_unit=1,
|
||||
rate=0.33,
|
||||
postage='second')
|
||||
|
||||
create_annual_billing(service_id=service.id, free_sms_fragment_limit=4, financial_year_start=2016)
|
||||
return service
|
||||
|
||||
|
||||
def test_get_yearly_usage_by_monthly_from_ft_billing(admin_request, notify_db_session):
|
||||
service = set_up_monthly_data()
|
||||
|
||||
json_response = admin_request.get(
|
||||
'billing.get_yearly_usage_by_monthly_from_ft_billing',
|
||||
service_id=service.id,
|
||||
year=2016
|
||||
)
|
||||
|
||||
assert len(json_response) == 18
|
||||
|
||||
email_rows = [row for row in json_response if row['notification_type'] == 'email']
|
||||
assert len(email_rows) == 0
|
||||
|
||||
letter_row = next(x for x in json_response if x['notification_type'] == 'letter')
|
||||
sms_row = next(x for x in json_response if x['notification_type'] == 'sms')
|
||||
|
||||
assert letter_row["month"] == "April"
|
||||
assert letter_row["notification_type"] == "letter"
|
||||
assert letter_row["billing_units"] == 30
|
||||
assert letter_row["chargeable_units"] == 30
|
||||
assert letter_row["rate"] == 0.33
|
||||
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["notification_type"] == "sms"
|
||||
assert sms_row["billing_units"] == 30
|
||||
assert sms_row["chargeable_units"] == 30
|
||||
assert sms_row["rate"] == 0.162
|
||||
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():
|
||||
service = create_service()
|
||||
sms_template = create_template(service=service, template_type="sms")
|
||||
email_template = create_template(service=service, template_type="email")
|
||||
letter_template = create_template(service=service, template_type="letter")
|
||||
|
||||
for month in range(1, 13):
|
||||
mon = str(month).zfill(2)
|
||||
for day in range(1, monthrange(2016, month)[1] + 1):
|
||||
d = str(day).zfill(2)
|
||||
create_ft_billing(bst_date='2016-{}-{}'.format(mon, d),
|
||||
template=sms_template,
|
||||
rate=0.0162)
|
||||
create_ft_billing(bst_date='2016-{}-{}'.format(mon, d),
|
||||
template=sms_template,
|
||||
rate_multiplier=2,
|
||||
rate=0.0162)
|
||||
create_ft_billing(bst_date='2016-{}-{}'.format(mon, d),
|
||||
template=email_template,
|
||||
billable_unit=0,
|
||||
rate=0)
|
||||
create_ft_billing(bst_date='2016-{}-{}'.format(mon, d),
|
||||
template=letter_template,
|
||||
rate=0.33,
|
||||
postage='second')
|
||||
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
|
||||
|
||||
|
||||
def test_get_yearly_billing_usage_summary_from_ft_billing_returns_400_if_missing_year(admin_request, sample_service):
|
||||
json_response = admin_request.get(
|
||||
'billing.get_yearly_billing_usage_summary_from_ft_billing',
|
||||
service_id=sample_service.id,
|
||||
_expected_status=400
|
||||
)
|
||||
assert json_response == {
|
||||
'message': 'No valid year provided', 'result': 'error'
|
||||
}
|
||||
|
||||
|
||||
def test_get_yearly_billing_usage_summary_from_ft_billing_returns_empty_list_if_no_billing_data(
|
||||
admin_request, sample_service
|
||||
):
|
||||
json_response = admin_request.get(
|
||||
'billing.get_yearly_billing_usage_summary_from_ft_billing',
|
||||
service_id=sample_service.id,
|
||||
year=2016
|
||||
)
|
||||
assert json_response == []
|
||||
|
||||
|
||||
def test_get_yearly_billing_usage_summary_from_ft_billing(admin_request, notify_db_session):
|
||||
service = set_up_yearly_data()
|
||||
|
||||
json_response = admin_request.get(
|
||||
'billing.get_yearly_billing_usage_summary_from_ft_billing',
|
||||
service_id=service.id,
|
||||
year=2016
|
||||
)
|
||||
|
||||
assert len(json_response) == 3
|
||||
|
||||
assert json_response[0]['notification_type'] == 'email'
|
||||
assert json_response[0]['billing_units'] == 275
|
||||
assert json_response[0]['chargeable_units'] == 275
|
||||
assert json_response[0]['rate'] == 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]['billing_units'] == 275
|
||||
assert json_response[1]['chargeable_units'] == 275
|
||||
assert json_response[1]['rate'] == 0.33
|
||||
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]['billing_units'] == 825
|
||||
assert json_response[2]['chargeable_units'] == 825
|
||||
assert json_response[2]['rate'] == 0.0162
|
||||
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
|
||||
@@ -1,6 +1,5 @@
|
||||
from app.dao.email_branding_dao import (
|
||||
dao_get_email_branding_by_id,
|
||||
dao_get_email_branding_by_name,
|
||||
dao_get_email_branding_options,
|
||||
dao_update_email_branding,
|
||||
)
|
||||
@@ -27,14 +26,6 @@ def test_get_email_branding_by_id_gets_correct_email_branding(notify_db, notify_
|
||||
assert email_branding_from_db == email_branding
|
||||
|
||||
|
||||
def test_get_email_branding_by_name_gets_correct_email_branding(notify_db, notify_db_session):
|
||||
email_branding = create_email_branding(name="Crystal Gems")
|
||||
|
||||
email_branding_from_db = dao_get_email_branding_by_name("Crystal Gems")
|
||||
|
||||
assert email_branding_from_db == email_branding
|
||||
|
||||
|
||||
def test_update_email_branding(notify_db, notify_db_session):
|
||||
updated_name = 'new name'
|
||||
create_email_branding()
|
||||
|
||||
@@ -45,16 +45,8 @@ def set_up_yearly_data():
|
||||
email_template = create_template(service=service, template_type="email")
|
||||
letter_template = create_template(service=service, template_type="letter")
|
||||
|
||||
# use different rates for adjacent financial years to make sure the query
|
||||
# doesn't accidentally bleed over into them
|
||||
for dt in (date(2016, 3, 31), date(2017, 4, 1)):
|
||||
create_ft_billing(bst_date=dt, template=sms_template, rate=0.163)
|
||||
create_ft_billing(bst_date=dt, template=email_template, rate=0)
|
||||
create_ft_billing(bst_date=dt, template=letter_template, rate=0.34, postage='second')
|
||||
create_ft_billing(bst_date=dt, template=letter_template, rate=0.31, postage='second')
|
||||
|
||||
start_date = date(2016, 4, 1)
|
||||
end_date = date(2017, 4, 1)
|
||||
start_date = date(2016, 3, 31)
|
||||
end_date = date(2017, 4, 2)
|
||||
|
||||
for n in range((end_date - start_date).days):
|
||||
dt = start_date + timedelta(days=n)
|
||||
@@ -63,20 +55,6 @@ def set_up_yearly_data():
|
||||
create_ft_billing(bst_date=dt, template=email_template, rate=0)
|
||||
create_ft_billing(bst_date=dt, template=letter_template, rate=0.33, postage='second')
|
||||
create_ft_billing(bst_date=dt, template=letter_template, rate=0.30, postage='second')
|
||||
|
||||
return service
|
||||
|
||||
|
||||
def set_up_yearly_data_variable_rates():
|
||||
service = create_service()
|
||||
sms_template = create_template(service=service, template_type="sms")
|
||||
letter_template = create_template(service=service, template_type="letter")
|
||||
|
||||
create_ft_billing(bst_date='2018-05-16', template=sms_template, rate=0.162)
|
||||
create_ft_billing(bst_date='2018-05-17', template=sms_template, rate_multiplier=2, rate=0.162, billable_unit=2)
|
||||
create_ft_billing(bst_date='2018-05-16', template=sms_template, rate_multiplier=2, rate=0.0150, billable_unit=2)
|
||||
create_ft_billing(bst_date='2018-05-16', template=letter_template, rate=0.33, postage='second')
|
||||
create_ft_billing(bst_date='2018-05-17', template=letter_template, rate=0.36, billable_unit=2, postage='second')
|
||||
return service
|
||||
|
||||
|
||||
@@ -416,229 +394,107 @@ def test_get_rate_for_letters_when_page_count_is_zero(notify_db_session):
|
||||
|
||||
|
||||
def test_fetch_monthly_billing_for_year(notify_db_session):
|
||||
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)
|
||||
service = create_service()
|
||||
template = create_template(service=service, template_type="sms")
|
||||
for i in range(1, 31):
|
||||
create_ft_billing(bst_date='2018-06-{}'.format(i),
|
||||
template=template,
|
||||
rate_multiplier=2,
|
||||
rate=0.162)
|
||||
for i in range(1, 32):
|
||||
create_ft_billing(bst_date='2018-07-{}'.format(i),
|
||||
template=template,
|
||||
rate=0.158)
|
||||
|
||||
assert len(results) == 48
|
||||
results = fetch_monthly_billing_for_year(service_id=service.id, year=2018)
|
||||
|
||||
assert str(results[0].month) == "2016-04-01"
|
||||
assert results[0].notification_type == 'email'
|
||||
assert len(results) == 2
|
||||
assert str(results[0].month) == "2018-06-01"
|
||||
assert results[0].notifications_sent == 30
|
||||
assert results[0].billable_units == 30
|
||||
assert results[0].chargeable_units == 30
|
||||
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 results[0].billable_units == Decimal('60')
|
||||
assert results[0].rate == Decimal('0.162')
|
||||
assert results[0].notification_type == 'sms'
|
||||
assert results[0].postage == 'none'
|
||||
|
||||
assert str(results[1].month) == "2016-04-01"
|
||||
assert results[1].notification_type == 'letter'
|
||||
assert results[1].notifications_sent == 30
|
||||
assert results[1].billable_units == 30
|
||||
assert results[1].chargeable_units == 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 results[2].notification_type == 'letter'
|
||||
assert results[2].notifications_sent == 30
|
||||
assert results[2].billable_units == 30
|
||||
assert results[2].chargeable_units == 30
|
||||
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 results[3].notification_type == 'sms'
|
||||
assert results[3].notifications_sent == 30
|
||||
assert results[3].billable_units == 30
|
||||
assert results[3].chargeable_units == 30
|
||||
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[47].month) == "2017-03-01"
|
||||
|
||||
|
||||
def test_fetch_monthly_billing_for_year_variable_rates(notify_db_session):
|
||||
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)
|
||||
|
||||
# Test data is only for the month of May
|
||||
assert len(results) == 4
|
||||
|
||||
assert str(results[0].month) == "2018-05-01"
|
||||
assert results[0].notification_type == 'letter'
|
||||
assert results[0].notifications_sent == 1
|
||||
assert results[0].billable_units == 1
|
||||
assert results[0].chargeable_units == 1
|
||||
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 results[1].notification_type == 'letter'
|
||||
assert results[1].notifications_sent == 1
|
||||
assert results[1].billable_units == 1
|
||||
assert results[1].chargeable_units == 2
|
||||
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 results[2].notification_type == 'sms'
|
||||
assert results[2].notifications_sent == 1
|
||||
assert results[2].billable_units == 4
|
||||
assert results[2].chargeable_units == 4
|
||||
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 results[3].notification_type == 'sms'
|
||||
assert results[3].notifications_sent == 2
|
||||
assert results[3].billable_units == 5
|
||||
assert results[3].chargeable_units == 5
|
||||
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
|
||||
assert str(results[1].month) == "2018-07-01"
|
||||
assert results[1].notifications_sent == 31
|
||||
assert results[1].billable_units == Decimal('31')
|
||||
assert results[1].rate == Decimal('0.158')
|
||||
assert results[1].notification_type == 'sms'
|
||||
assert results[1].postage == 'none'
|
||||
|
||||
|
||||
@freeze_time('2018-08-01 13:30:00')
|
||||
def test_fetch_monthly_billing_for_year_adds_data_for_today(notify_db_session):
|
||||
service = create_service()
|
||||
template = create_template(service=service, template_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)
|
||||
|
||||
template = create_template(service=service, template_type="email")
|
||||
for i in range(1, 32):
|
||||
create_ft_billing(bst_date='2018-07-{}'.format(i), template=template)
|
||||
|
||||
create_notification(template=template, status='delivered')
|
||||
|
||||
assert db.session.query(FactBilling.bst_date).count() == 31
|
||||
results = fetch_monthly_billing_for_year(service_id=service.id, year=2018)
|
||||
|
||||
results = fetch_monthly_billing_for_year(service_id=service.id,
|
||||
year=2018)
|
||||
assert db.session.query(FactBilling.bst_date).count() == 32
|
||||
assert len(results) == 2
|
||||
|
||||
|
||||
def test_fetch_monthly_billing_for_year_return_financial_year(notify_db_session):
|
||||
service = set_up_yearly_data()
|
||||
|
||||
results = fetch_monthly_billing_for_year(service.id, 2016)
|
||||
# returns 3 rows, per month, returns financial year april to end of march
|
||||
# Orders by Month
|
||||
|
||||
assert len(results) == 48
|
||||
assert str(results[0].month) == "2016-04-01"
|
||||
assert results[0].notification_type == 'email'
|
||||
assert results[0].notifications_sent == 30
|
||||
assert results[0].billable_units == 30
|
||||
assert results[0].rate == Decimal('0')
|
||||
assert str(results[1].month) == "2016-04-01"
|
||||
assert results[1].notification_type == 'letter'
|
||||
assert results[1].notifications_sent == 30
|
||||
assert results[1].billable_units == 30
|
||||
assert results[1].rate == Decimal('0.30')
|
||||
assert str(results[1].month) == "2016-04-01"
|
||||
assert results[2].notification_type == 'letter'
|
||||
assert results[2].notifications_sent == 30
|
||||
assert results[2].billable_units == 30
|
||||
assert results[2].rate == Decimal('0.33')
|
||||
assert str(results[3].month) == "2016-04-01"
|
||||
assert results[3].notification_type == 'sms'
|
||||
assert results[3].notifications_sent == 30
|
||||
assert results[3].billable_units == 30
|
||||
assert results[3].rate == Decimal('0.162')
|
||||
assert str(results[4].month) == "2016-05-01"
|
||||
assert str(results[47].month) == "2017-03-01"
|
||||
|
||||
|
||||
def test_fetch_billing_totals_for_year(notify_db_session):
|
||||
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)
|
||||
|
||||
assert len(results) == 4
|
||||
assert results[0].notification_type == 'email'
|
||||
assert results[0].notifications_sent == 365
|
||||
assert results[0].billable_units == 365
|
||||
assert results[0].chargeable_units == 365
|
||||
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].notifications_sent == 365
|
||||
assert results[1].billable_units == 365
|
||||
assert results[1].chargeable_units == 365
|
||||
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].notifications_sent == 365
|
||||
assert results[2].billable_units == 365
|
||||
assert results[2].chargeable_units == 365
|
||||
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].notifications_sent == 365
|
||||
assert results[3].billable_units == 365
|
||||
assert results[3].chargeable_units == 365
|
||||
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):
|
||||
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)
|
||||
|
||||
assert len(results) == 4
|
||||
assert results[0].notification_type == 'letter'
|
||||
assert results[0].notifications_sent == 1
|
||||
assert results[0].billable_units == 1
|
||||
assert results[0].chargeable_units == 1
|
||||
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].notifications_sent == 1
|
||||
assert results[1].billable_units == 1
|
||||
assert results[1].chargeable_units == 2
|
||||
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].notifications_sent == 1
|
||||
assert results[2].billable_units == 4
|
||||
assert results[2].chargeable_units == 4
|
||||
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].notifications_sent == 2
|
||||
assert results[3].billable_units == 5
|
||||
assert results[3].chargeable_units == 5
|
||||
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):
|
||||
|
||||
Reference in New Issue
Block a user