Files
notifications-api/app/service/statistics.py
Beverly Nguyen 88c3da5579 add testing
2025-01-13 13:39:34 -08:00

141 lines
4.9 KiB
Python

from collections import defaultdict
from datetime import datetime
from app.dao.date_util import get_months_for_financial_year
from app.enums import (
KeyType,
NotificationStatus,
NotificationType,
StatisticsType,
TemplateType,
)
def format_statistics(statistics, total_notifications=None):
# statistics come in a named tuple with uniqueness from 'notification_type', 'status' - however missing
# statuses/notification types won't be represented and the status types need to be simplified/summed up
# so we can return emails/sms * created, sent, and failed
counts = create_zeroed_stats_dicts()
for row in statistics:
# any row could be null, if the service either has no notifications in the notifications table,
# or no historical data in the ft_notification_status table.
if row.notification_type:
_update_statuses_from_row(
counts[row.notification_type],
row,
)
if NotificationType.SMS in counts and total_notifications is not None:
sms_dict = counts[NotificationType.SMS]
delivered_count = sms_dict[StatisticsType.DELIVERED]
failed_count = sms_dict[StatisticsType.FAILURE]
sms_dict[StatisticsType.PENDING] = calculate_pending_stats(
delivered_count, failed_count, total_notifications
)
return counts
def calculate_pending_stats(delivered_count, failed_count, total_notifications):
pending_count = total_notifications - (delivered_count + failed_count)
return max(0, pending_count)
def format_admin_stats(statistics):
counts = create_stats_dict()
for row in statistics:
if row.key_type == KeyType.TEST:
counts[row.notification_type]["test-key"] += row.count
else:
counts[row.notification_type]["total"] += row.count
if row.status in (
NotificationStatus.TECHNICAL_FAILURE,
NotificationStatus.PERMANENT_FAILURE,
NotificationStatus.TEMPORARY_FAILURE,
NotificationStatus.VIRUS_SCAN_FAILED,
):
counts[row.notification_type]["failures"][row.status] += row.count
return counts
def create_stats_dict():
stats_dict = {}
for template in (TemplateType.SMS, TemplateType.EMAIL):
stats_dict[template] = {}
for status in ("total", "test-key"):
stats_dict[template][status] = 0
stats_dict[template]["failures"] = {
NotificationStatus.TECHNICAL_FAILURE: 0,
NotificationStatus.PERMANENT_FAILURE: 0,
NotificationStatus.TEMPORARY_FAILURE: 0,
NotificationStatus.VIRUS_SCAN_FAILED: 0,
}
return stats_dict
def format_monthly_template_notification_stats(year, rows):
stats = {
datetime.strftime(date, "%Y-%m"): {}
for date in [datetime(year, month, 1) for month in range(4, 13)]
+ [datetime(year + 1, month, 1) for month in range(1, 4)]
}
for row in rows:
formatted_month = row.month.strftime("%Y-%m")
if str(row.template_id) not in stats[formatted_month]:
stats[formatted_month][str(row.template_id)] = {
"name": row.name,
"type": row.template_type,
"counts": dict.fromkeys(list(NotificationStatus), 0),
}
stats[formatted_month][str(row.template_id)]["counts"][row.status] += row.count
return stats
def create_zeroed_stats_dicts():
return {
template_type: {status: 0 for status in StatisticsType}
for template_type in (TemplateType.SMS, TemplateType.EMAIL)
}
def _update_statuses_from_row(update_dict, row):
if row.status != NotificationStatus.CANCELLED:
update_dict[StatisticsType.REQUESTED] += row.count
if row.status in (NotificationStatus.DELIVERED, NotificationStatus.SENT):
update_dict[StatisticsType.DELIVERED] += row.count
elif row.status in (
NotificationStatus.FAILED,
NotificationStatus.TECHNICAL_FAILURE,
NotificationStatus.TEMPORARY_FAILURE,
NotificationStatus.PERMANENT_FAILURE,
NotificationStatus.VALIDATION_FAILED,
NotificationStatus.VIRUS_SCAN_FAILED,
):
update_dict[StatisticsType.FAILURE] += row.count
def create_empty_monthly_notification_status_stats_dict(year):
utc_month_starts = get_months_for_financial_year(year)
# nested dicts - data[month][template type][status] = count
return {
start.strftime("%Y-%m"): {
template_type: defaultdict(int)
for template_type in (TemplateType.SMS, TemplateType.EMAIL)
}
for start in utc_month_starts
}
def add_monthly_notification_status_stats(data, stats):
for row in stats:
month = row.month.strftime("%Y-%m")
data[month][row.notification_type][row.notification_status] += row.count
data[month][row.notification_type][StatisticsType.REQUESTED] += row.count
return data