Created new queries to return the rate with the sum of billable units for the year totals.

Once we have the new columns in notifications table, the query will need to include the rate multiplier and if the number is international.
The monthly billing query will be built next.
This commit is contained in:
Rebecca Law
2017-04-26 14:16:47 +01:00
committed by Ken Tsang
parent 93287719e4
commit 6dc336ad6c
10 changed files with 210 additions and 67 deletions

18
app/dao/date_util.py Normal file
View File

@@ -0,0 +1,18 @@
from datetime import datetime
import pytz
def get_financial_year(year):
return get_april_fools(year), get_april_fools(year + 1)
def get_april_fools(year):
"""
This function converts the start of the financial year April 1, 00:00 as BST (British Standard Time) to UTC,
the tzinfo is lastly removed from the datetime becasue the database stores the timestamps without timezone.
:param year: the year to calculate the April 1, 00:00 BST for
:return: the datetime of April 1 for the given year, for example 2016 = 2016-03-31 23:00:00
"""
return pytz.timezone('Europe/London').localize(datetime(year, 4, 1, 0, 0, 0)).astimezone(pytz.UTC).replace(
tzinfo=None)

View File

@@ -0,0 +1,69 @@
from decimal import Decimal
from sqlalchemy import func
from app import db
from app.dao.date_util import get_financial_year
from app.models import (NotificationHistory,
Rate,
NOTIFICATION_STATUS_TYPES_BILLABLE,
KEY_TYPE_TEST,
SMS_TYPE,
EMAIL_TYPE)
from app.statsd_decorators import statsd
@statsd(namespace="dao")
def get_yearly_billing_data(service_id, year):
start_date, end_date = get_financial_year(year)
rates = get_rates_for_year(start_date, end_date, SMS_TYPE)
result = []
for r, n in zip(rates, rates[1:]):
result.append(
sms_billing_data_query(str(r.rate), service_id, r.valid_from, n.valid_from))
result.append(sms_billing_data_query(str(rates[-1].rate), service_id, rates[-1].valid_from, end_date))
result.append(email_billing_data_query(service_id, start_date, end_date))
return result
def billing_data_filter(notification_type, start_date, end_date, service_id):
return [NotificationHistory.notification_type == notification_type,
NotificationHistory.created_at >= start_date,
NotificationHistory.created_at < end_date,
NotificationHistory.service_id == service_id,
NotificationHistory.status.in_(NOTIFICATION_STATUS_TYPES_BILLABLE),
NotificationHistory.key_type != KEY_TYPE_TEST
]
def email_billing_data_query(service_id, start_date, end_date):
result = db.session.query(func.count(NotificationHistory.id),
NotificationHistory.notification_type,
"0"
).filter(*billing_data_filter(EMAIL_TYPE, start_date, end_date, service_id)
).group_by(NotificationHistory.notification_type).first()
if not result:
return 0, EMAIL_TYPE, Decimal("0")
else:
return result
def sms_billing_data_query(rate, service_id, start_date, end_date):
result = db.session.query(func.sum(NotificationHistory.billable_units),
NotificationHistory.notification_type,
rate
).filter(*billing_data_filter(SMS_TYPE, start_date, end_date, service_id)
).group_by(NotificationHistory.notification_type).first()
if not result:
return 0, SMS_TYPE, Decimal("0")
else:
return result
def get_rates_for_year(start_date, end_date, notification_type):
return Rate.query.filter(Rate.valid_from >= start_date, Rate.valid_from < end_date,
Rate.notification_type == notification_type).order_by(Rate.valid_from).all()

View File

@@ -1,5 +1,4 @@
import functools
import pytz
from datetime import (
datetime,
timedelta,
@@ -12,6 +11,7 @@ from sqlalchemy.orm import joinedload
from app import db, create_uuid
from app.dao import days_ago
from app.dao.date_util import get_financial_year
from app.models import (
Service,
Notification,
@@ -243,13 +243,15 @@ def get_notifications_for_job(service_id, job_id, filter_dict=None, page=1, page
def get_notification_billable_unit_count_per_month(service_id, year):
month = get_london_month_from_utc_column(NotificationHistory.created_at)
start_date, end_date = get_financial_year(year)
notifications = db.session.query(
month,
func.sum(NotificationHistory.billable_units)
).filter(
NotificationHistory.billable_units != 0,
NotificationHistory.service_id == service_id,
NotificationHistory.created_at.between(*get_financial_year(year)),
NotificationHistory.created_at >= start_date,
NotificationHistory.created_at < end_date
).group_by(
month
).order_by(
@@ -410,21 +412,6 @@ def dao_timeout_notifications(timeout_period_in_seconds):
return updated
def get_financial_year(year):
return get_april_fools(year), get_april_fools(year + 1)
def get_april_fools(year):
"""
This function converts the start of the financial year April 1, 00:00 as BST (British Standard Time) to UTC,
the tzinfo is lastly removed from the datetime becasue the database stores the timestamps without timezone.
:param year: the year to calculate the April 1, 00:00 BST for
:return: the datetime of April 1 for the given year, for example 2016 = 2016-03-31 23:00:00
"""
return pytz.timezone('Europe/London').localize(datetime(year, 4, 1, 0, 0, 0)).astimezone(pytz.UTC).replace(
tzinfo=None)
def get_total_sent_notifications_in_date_range(start_date, end_date, notification_type):
result = db.session.query(
func.count(NotificationHistory.id).label('count')

View File

@@ -1,11 +0,0 @@
from sqlalchemy import desc
from app import db
from app.models import Rate
def get_rate_for_type_and_date(notification_type, date_sent):
return db.session.query(Rate).filter(Rate.notification_type == notification_type,
Rate.valid_from <= date_sent
).order_by(Rate.valid_from.desc()
).limit(1).first()

View File

@@ -229,6 +229,7 @@ def _stats_for_service_query(service_id):
def dao_fetch_monthly_historical_stats_by_template_for_service(service_id, year):
month = get_london_month_from_utc_column(NotificationHistory.created_at)
start_date, end_date = get_financial_year(year)
sq = db.session.query(
NotificationHistory.template_id,
NotificationHistory.status,
@@ -236,7 +237,9 @@ def dao_fetch_monthly_historical_stats_by_template_for_service(service_id, year)
func.count().label('count')
).filter(
NotificationHistory.service_id == service_id,
NotificationHistory.created_at.between(*get_financial_year(year))
NotificationHistory.created_at >= start_date,
NotificationHistory.created_at < end_date
).group_by(
month,
NotificationHistory.template_id,
@@ -262,6 +265,7 @@ def dao_fetch_monthly_historical_stats_by_template_for_service(service_id, year)
def dao_fetch_monthly_historical_stats_for_service(service_id, year):
month = get_london_month_from_utc_column(NotificationHistory.created_at)
start_date, end_date = get_financial_year(year)
rows = db.session.query(
NotificationHistory.notification_type,
NotificationHistory.status,
@@ -269,7 +273,8 @@ def dao_fetch_monthly_historical_stats_for_service(service_id, year):
func.count(NotificationHistory.id).label('count')
).filter(
NotificationHistory.service_id == service_id,
NotificationHistory.created_at.between(*get_financial_year(year)),
NotificationHistory.created_at >= start_date,
NotificationHistory.created_at < end_date
).group_by(
NotificationHistory.notification_type,
NotificationHistory.status,