Add new total_letters field to the billing report data

This adds total_letters to the data that is returned by the
`/platform-stats/data-for-billing-report` endpoint so that we can add
total letters as a column in the CSV file that can be downloaded.
This commit is contained in:
Katie Smith
2021-06-11 11:11:47 +01:00
parent 6a99a1fbc2
commit 0148b3dba6
4 changed files with 28 additions and 18 deletions

View File

@@ -114,12 +114,13 @@ def fetch_sms_billing_for_all_services(start_date, end_date):
return query.all() return query.all()
def fetch_letter_costs_for_all_services(start_date, end_date): def fetch_letter_costs_and_totals_for_all_services(start_date, end_date):
query = db.session.query( query = db.session.query(
Organisation.name.label("organisation_name"), Organisation.name.label("organisation_name"),
Organisation.id.label("organisation_id"), Organisation.id.label("organisation_id"),
Service.name.label("service_name"), Service.name.label("service_name"),
Service.id.label("service_id"), Service.id.label("service_id"),
func.sum(FactBilling.notifications_sent).label("total_letters"),
func.sum(FactBilling.notifications_sent * FactBilling.rate).label("letter_cost") func.sum(FactBilling.notifications_sent * FactBilling.rate).label("letter_cost")
).select_from( ).select_from(
Service Service

View File

@@ -5,7 +5,7 @@ from flask import Blueprint, jsonify, request
from app.dao.date_util import get_financial_year_for_datetime from app.dao.date_util import get_financial_year_for_datetime
from app.dao.fact_billing_dao import ( from app.dao.fact_billing_dao import (
fetch_billing_details_for_all_services, fetch_billing_details_for_all_services,
fetch_letter_costs_for_all_services, fetch_letter_costs_and_totals_for_all_services,
fetch_letter_line_items_for_all_services, fetch_letter_line_items_for_all_services,
fetch_sms_billing_for_all_services, fetch_sms_billing_for_all_services,
) )
@@ -67,7 +67,7 @@ def get_data_for_billing_report():
start_date, end_date = validate_date_range_is_within_a_financial_year(start_date, end_date) start_date, end_date = validate_date_range_is_within_a_financial_year(start_date, end_date)
sms_costs = fetch_sms_billing_for_all_services(start_date, end_date) sms_costs = fetch_sms_billing_for_all_services(start_date, end_date)
letter_costs = fetch_letter_costs_for_all_services(start_date, end_date) letter_overview = fetch_letter_costs_and_totals_for_all_services(start_date, end_date)
letter_breakdown = fetch_letter_line_items_for_all_services(start_date, end_date) letter_breakdown = fetch_letter_line_items_for_all_services(start_date, end_date)
lb_by_service = [ lb_by_service = [
@@ -85,26 +85,31 @@ def get_data_for_billing_report():
"service_name": s.service_name, "service_name": s.service_name,
"sms_cost": float(s.sms_cost), "sms_cost": float(s.sms_cost),
"sms_fragments": s.chargeable_billable_sms, "sms_fragments": s.chargeable_billable_sms,
"total_letters": 0,
"letter_cost": 0, "letter_cost": 0,
"letter_breakdown": "" "letter_breakdown": ""
} }
combined[s.service_id] = entry combined[s.service_id] = entry
for letter_cost in letter_costs: for data in letter_overview:
if letter_cost.service_id in combined: if data.service_id in combined:
combined[letter_cost.service_id].update({'letter_cost': float(letter_cost.letter_cost)}) combined[data.service_id].update(
{'total_letters': data.total_letters, 'letter_cost': float(data.letter_cost)}
)
else: else:
letter_entry = { letter_entry = {
"organisation_id": str(letter_cost.organisation_id) if letter_cost.organisation_id else "", "organisation_id": str(data.organisation_id) if data.organisation_id else "",
"organisation_name": letter_cost.organisation_name or "", "organisation_name": data.organisation_name or "",
"service_id": str(letter_cost.service_id), "service_id": str(data.service_id),
"service_name": letter_cost.service_name, "service_name": data.service_name,
"sms_cost": 0, "sms_cost": 0,
"sms_fragments": 0, "sms_fragments": 0,
"letter_cost": float(letter_cost.letter_cost), "total_letters": data.total_letters,
"letter_cost": float(data.letter_cost),
"letter_breakdown": "" "letter_breakdown": ""
} }
combined[letter_cost.service_id] = letter_entry combined[data.service_id] = letter_entry
for service_id, breakdown in lb_by_service: for service_id, breakdown in lb_by_service:
combined[service_id]['letter_breakdown'] += (breakdown + '\n') combined[service_id]['letter_breakdown'] += (breakdown + '\n')

View File

@@ -10,7 +10,7 @@ from app.dao.fact_billing_dao import (
delete_billing_data_for_service_for_day, delete_billing_data_for_service_for_day,
fetch_billing_data_for_day, fetch_billing_data_for_day,
fetch_billing_totals_for_year, fetch_billing_totals_for_year,
fetch_letter_costs_for_all_services, fetch_letter_costs_and_totals_for_all_services,
fetch_letter_line_items_for_all_services, fetch_letter_line_items_for_all_services,
fetch_monthly_billing_for_year, fetch_monthly_billing_for_year,
fetch_sms_billing_for_all_services, fetch_sms_billing_for_all_services,
@@ -628,26 +628,26 @@ def test_fetch_sms_billing_for_all_services_without_an_organisation_appears(noti
) )
def test_fetch_letter_costs_for_all_services(notify_db_session): def test_fetch_letter_costs_and_totals_for_all_services(notify_db_session):
fixtures = set_up_usage_data(datetime(2019, 6, 1)) fixtures = set_up_usage_data(datetime(2019, 6, 1))
results = fetch_letter_costs_for_all_services(datetime(2019, 6, 1), datetime(2019, 9, 30)) results = fetch_letter_costs_and_totals_for_all_services(datetime(2019, 6, 1), datetime(2019, 9, 30))
assert len(results) == 3 assert len(results) == 3
assert results[0] == ( assert results[0] == (
fixtures["org_1"].name, fixtures["org_1"].id, fixtures["org_1"].name, fixtures["org_1"].id,
fixtures["service_1_sms_and_letter"].name, fixtures["service_1_sms_and_letter"].id, fixtures["service_1_sms_and_letter"].name, fixtures["service_1_sms_and_letter"].id,
Decimal('3.40') 8, Decimal('3.40')
) )
assert results[1] == ( assert results[1] == (
fixtures["org_for_service_with_letters"].name, fixtures["org_for_service_with_letters"].id, fixtures["org_for_service_with_letters"].name, fixtures["org_for_service_with_letters"].id,
fixtures["service_with_letters"].name, fixtures["service_with_letters"].id, fixtures["service_with_letters"].name, fixtures["service_with_letters"].id,
Decimal('14.00') 22, Decimal('14.00')
) )
assert results[2] == ( assert results[2] == (
None, None, None, None,
fixtures["service_with_letters_without_org"].name, fixtures["service_with_letters_without_org"].id, fixtures["service_with_letters_without_org"].name, fixtures["service_with_letters_without_org"].id,
Decimal('24.45') 18, Decimal('24.45')
) )

View File

@@ -141,6 +141,7 @@ def test_get_data_for_billing_report(notify_db_session, admin_request):
assert response[0]["service_id"] == str(fixtures["service_1_sms_and_letter"].id) assert response[0]["service_id"] == str(fixtures["service_1_sms_and_letter"].id)
assert response[0]["sms_cost"] == 0 assert response[0]["sms_cost"] == 0
assert response[0]["sms_fragments"] == 0 assert response[0]["sms_fragments"] == 0
assert response[0]["total_letters"] == 8
assert response[0]["letter_cost"] == 3.40 assert response[0]["letter_cost"] == 3.40
assert response[0]["letter_breakdown"] == "6 second class letters at 45p\n2 first class letters at 35p\n" assert response[0]["letter_breakdown"] == "6 second class letters at 45p\n2 first class letters at 35p\n"
assert response[0]["purchase_order_number"] == "service purchase order number" assert response[0]["purchase_order_number"] == "service purchase order number"
@@ -152,6 +153,7 @@ def test_get_data_for_billing_report(notify_db_session, admin_request):
assert response[1]["service_id"] == str(fixtures["service_with_letters"].id) assert response[1]["service_id"] == str(fixtures["service_with_letters"].id)
assert response[1]["sms_cost"] == 0 assert response[1]["sms_cost"] == 0
assert response[1]["sms_fragments"] == 0 assert response[1]["sms_fragments"] == 0
assert response[1]["total_letters"] == 22
assert response[1]["letter_cost"] == 14 assert response[1]["letter_cost"] == 14
assert response[1]["letter_breakdown"] == "20 second class letters at 65p\n2 first class letters at 50p\n" assert response[1]["letter_breakdown"] == "20 second class letters at 65p\n2 first class letters at 50p\n"
assert response[1]["purchase_order_number"] == "org3 purchase order number" assert response[1]["purchase_order_number"] == "org3 purchase order number"
@@ -163,6 +165,7 @@ def test_get_data_for_billing_report(notify_db_session, admin_request):
assert response[2]["service_id"] == str(fixtures["service_with_sms_without_org"].id) assert response[2]["service_id"] == str(fixtures["service_with_sms_without_org"].id)
assert response[2]["sms_cost"] == 0.33 assert response[2]["sms_cost"] == 0.33
assert response[2]["sms_fragments"] == 3 assert response[2]["sms_fragments"] == 3
assert response[2]["total_letters"] == 0
assert response[2]["letter_cost"] == 0 assert response[2]["letter_cost"] == 0
assert response[2]["letter_breakdown"] == "" assert response[2]["letter_breakdown"] == ""
assert response[2]["purchase_order_number"] == "sms purchase order number" assert response[2]["purchase_order_number"] == "sms purchase order number"
@@ -174,6 +177,7 @@ def test_get_data_for_billing_report(notify_db_session, admin_request):
assert response[3]["service_id"] == str(fixtures["service_with_letters_without_org"].id) assert response[3]["service_id"] == str(fixtures["service_with_letters_without_org"].id)
assert response[3]["sms_cost"] == 0 assert response[3]["sms_cost"] == 0
assert response[3]["sms_fragments"] == 0 assert response[3]["sms_fragments"] == 0
assert response[3]["total_letters"] == 18
assert response[3]["letter_cost"] == 24.45 assert response[3]["letter_cost"] == 24.45
assert response[3]["letter_breakdown"] == ( assert response[3]["letter_breakdown"] == (
"2 second class letters at 35p\n1 first class letters at 50p\n15 international letters at £1.55\n" "2 second class letters at 35p\n1 first class letters at 50p\n15 international letters at £1.55\n"