-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into fix/formatter-check-in-ci
- Loading branch information
Showing
19 changed files
with
974 additions
and
194 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
from datetime import datetime | ||
|
||
from notifications_utils.clients.redis import ( | ||
email_daily_count_cache_key, | ||
sms_daily_count_cache_key, | ||
) | ||
|
||
from app import redis_client, service_api_client, template_statistics_client | ||
from app.models.service import Service | ||
|
||
|
||
class NotificationCounts: | ||
def get_all_notification_counts_for_today(self, service_id): | ||
# try to get today's stats from redis | ||
todays_sms = redis_client.get(sms_daily_count_cache_key(service_id)) | ||
todays_sms = int(todays_sms) if todays_sms is not None else None | ||
|
||
todays_email = redis_client.get(email_daily_count_cache_key(service_id)) | ||
todays_email = int(todays_email) if todays_email is not None else None | ||
|
||
if todays_sms is not None and todays_email is not None: | ||
return {"sms": todays_sms, "email": todays_email} | ||
# fallback to the API if the stats are not in redis | ||
else: | ||
stats = template_statistics_client.get_template_statistics_for_service(service_id, limit_days=1) | ||
transformed_stats = _aggregate_notifications_stats(stats) | ||
|
||
return transformed_stats | ||
|
||
def get_all_notification_counts_for_year(self, service_id, year): | ||
""" | ||
Get total number of notifications by type for the current service for the current year | ||
Return value: | ||
{ | ||
'sms': int, | ||
'email': int | ||
} | ||
""" | ||
stats_today = self.get_all_notification_counts_for_today(service_id) | ||
stats_this_year = service_api_client.get_monthly_notification_stats(service_id, year)["data"] | ||
stats_this_year = _aggregate_stats_from_service_api(stats_this_year) | ||
# aggregate stats_today and stats_this_year | ||
for template_type in ["sms", "email"]: | ||
stats_this_year[template_type] += stats_today[template_type] | ||
|
||
return stats_this_year | ||
|
||
def get_limit_stats(self, service: Service): | ||
""" | ||
Get the limit stats for the current service, by notification type, including: | ||
- how many notifications were sent today and this year | ||
- the monthy and daily limits | ||
- the number of notifications remaining today and this year | ||
Returns: | ||
dict: A dictionary containing the limit stats for email and SMS notifications. The structure is as follows: | ||
{ | ||
"email": { | ||
"annual": { | ||
"limit": int, # The annual limit for email notifications | ||
"sent": int, # The number of email notifications sent this year | ||
"remaining": int, # The number of email notifications remaining this year | ||
}, | ||
"daily": { | ||
"limit": int, # The daily limit for email notifications | ||
"sent": int, # The number of email notifications sent today | ||
"remaining": int, # The number of email notifications remaining today | ||
}, | ||
}, | ||
"sms": { | ||
"annual": { | ||
"limit": int, # The annual limit for SMS notifications | ||
"sent": int, # The number of SMS notifications sent this year | ||
"remaining": int, # The number of SMS notifications remaining this year | ||
}, | ||
"daily": { | ||
"limit": int, # The daily limit for SMS notifications | ||
"sent": int, # The number of SMS notifications sent today | ||
"remaining": int, # The number of SMS notifications remaining today | ||
}, | ||
} | ||
} | ||
""" | ||
|
||
sent_today = self.get_all_notification_counts_for_today(service.id) | ||
sent_thisyear = self.get_all_notification_counts_for_year(service.id, datetime.now().year) | ||
|
||
limit_stats = { | ||
"email": { | ||
"annual": { | ||
"limit": service.email_annual_limit, | ||
"sent": sent_thisyear["email"], | ||
"remaining": service.email_annual_limit - sent_thisyear["email"], | ||
}, | ||
"daily": { | ||
"limit": service.message_limit, | ||
"sent": sent_today["email"], | ||
"remaining": service.message_limit - sent_today["email"], | ||
}, | ||
}, | ||
"sms": { | ||
"annual": { | ||
"limit": service.sms_annual_limit, | ||
"sent": sent_thisyear["sms"], | ||
"remaining": service.sms_annual_limit - sent_thisyear["sms"], | ||
}, | ||
"daily": { | ||
"limit": service.sms_daily_limit, | ||
"sent": sent_today["sms"], | ||
"remaining": service.sms_daily_limit - sent_today["sms"], | ||
}, | ||
}, | ||
} | ||
|
||
return limit_stats | ||
|
||
|
||
# TODO: consolidate this function and other functions that transform the results of template_statistics_client calls | ||
def _aggregate_notifications_stats(template_statistics): | ||
template_statistics = _filter_out_cancelled_stats(template_statistics) | ||
notifications = {"sms": 0, "email": 0} | ||
for stat in template_statistics: | ||
notifications[stat["template_type"]] += stat["count"] | ||
|
||
return notifications | ||
|
||
|
||
def _filter_out_cancelled_stats(template_statistics): | ||
return [s for s in template_statistics if s["status"] != "cancelled"] | ||
|
||
|
||
def _aggregate_stats_from_service_api(stats): | ||
"""Aggregate monthly notification stats excluding cancelled""" | ||
total_stats = {"sms": {}, "email": {}} | ||
|
||
for month_data in stats.values(): | ||
for msg_type in ["sms", "email"]: | ||
if msg_type in month_data: | ||
for status, count in month_data[msg_type].items(): | ||
if status != "cancelled": | ||
if status not in total_stats[msg_type]: | ||
total_stats[msg_type][status] = 0 | ||
total_stats[msg_type][status] += count | ||
|
||
return {msg_type: sum(counts.values()) for msg_type, counts in total_stats.items()} | ||
|
||
|
||
notification_counts_client = NotificationCounts() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
app/templates/partials/check/too-many-messages-annual.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
{% from "components/links.html" import content_link %} | ||
|
||
{% if template.template_type == 'email' %} | ||
{% set units = _('email messages') %} | ||
{% else %} | ||
{% set units = _('text messages') %} | ||
{% endif %} | ||
|
||
<p data-testid="exceeds-annual"> | ||
{%- if current_service.trial_mode %} | ||
{{ _("Your service is in trial mode. To send more messages, <a href='{}'>request to go live</a>").format(url_for('main.request_to_go_live', service_id=current_service.id)) }} | ||
{% else %} | ||
{% if recipients_remaining_messages > 0 %} | ||
<p>{{ _('<strong>{}</strong> can only send <strong>{}</strong> more {} until annual limit resets'.format(current_service.name, recipients_remaining_messages, units)) }}</p> | ||
<p> | ||
{{ _('To send some of these messages now, edit the spreadsheet to <strong>{}</strong> recipients maximum. '.format(recipients_remaining_messages)) }} | ||
{{ _('To send to recipients you removed, wait until <strong>April 1, {}</strong> or contact them some other way.'.format(now().year)) }} | ||
</p> | ||
{% else %} | ||
<p>{{ _('<strong>{}</strong> cannot send any more {} until <strong>April 1, {}</strong>'.format(current_service.name, units, now().year)) }}</p> | ||
<p>{{ _('For more information, visit the <a href={}>usage report for {}</a>.'.format(url_for('.monthly', service_id=current_service.id), current_service.name)) }}</p> | ||
{% endif %} | ||
{%- endif -%} | ||
</p> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,9 @@ | ||
{% from "components/links.html" import content_link %} | ||
|
||
<p> | ||
<p data-testid="exceeds-daily"> | ||
{%- if current_service.trial_mode %} | ||
{{ _("Your service is in trial mode. To send more messages, <a href='{}'>request to go live</a>").format(url_for('main.request_to_go_live', service_id=current_service.id)) }} | ||
{% else %} | ||
{{ _("To request a daily limit above {} text messages, {}").format(current_service.sms_daily_limit, content_link(_("contact us"), url_for('main.contact'), is_external_link=true)) }} | ||
{%- endif -%} | ||
</p> | ||
</p> |
Oops, something went wrong.