diff --git a/app/notifications/validators.py b/app/notifications/validators.py index 3b1e5624d7..3aee7486d6 100644 --- a/app/notifications/validators.py +++ b/app/notifications/validators.py @@ -176,7 +176,7 @@ def send_warning_email_limit_emails_if_needed(service: Service) -> None: if bool_nearing_email_daily_limit: cache_key = near_email_daily_limit_cache_key(service.id) if not redis_store.get(cache_key): - send_near_email_limit_email(service) + send_near_email_limit_email(service, todays_current_email_count) redis_store.set(cache_key, current_time, ex=cache_expiration) # Send a warning when reaching the daily message limit @@ -198,7 +198,7 @@ def send_warning_sms_limit_emails_if_needed(service: Service): if nearing_sms_daily_limit: cache_key = near_sms_daily_limit_cache_key(service.id) if not redis_store.get(cache_key): - send_near_sms_limit_email(service) + send_near_sms_limit_email(service, todays_requested_sms) redis_store.set(cache_key, current_time, ex=cache_expiration) # Send a warning when reaching the daily message limit @@ -257,6 +257,7 @@ def warn_about_daily_message_limit(service: Service, messages_sent): template_id=current_app.config["NEAR_DAILY_LIMIT_TEMPLATE_ID"], personalisation={ "service_name": service.name, + "count": messages_sent, "contact_url": f"{current_app.config['ADMIN_BASE_URL']}/contact", "message_limit_en": "{:,}".format(service.message_limit), "message_limit_fr": "{:,}".format(service.message_limit).replace(",", " "), @@ -293,14 +294,19 @@ def warn_about_daily_message_limit(service: Service, messages_sent): raise LiveServiceTooManyRequestsError(service.message_limit) -def send_near_sms_limit_email(service: Service): +def send_near_sms_limit_email(service: Service, sms_sent): limit_reset_time_et = get_limit_reset_time_et() + sms_remaining = service.sms_daily_limit - sms_sent send_notification_to_service_users( service_id=service.id, template_id=current_app.config["NEAR_DAILY_SMS_LIMIT_TEMPLATE_ID"], personalisation={ "service_name": service.name, "contact_url": f"{current_app.config['ADMIN_BASE_URL']}/contact", + "count_en": "{:,}".format(sms_sent), + "count_fr": "{:,}".format(sms_sent).replace(",", " "), + "remaining_en": "{:,}".format(sms_remaining), + "remaining_fr": "{:,}".format(sms_remaining).replace(",", " "), "message_limit_en": "{:,}".format(service.sms_daily_limit), "message_limit_fr": "{:,}".format(service.sms_daily_limit).replace(",", " "), "limit_reset_time_et_12hr": limit_reset_time_et["12hr"], @@ -311,18 +317,23 @@ def send_near_sms_limit_email(service: Service): current_app.logger.info(f"service {service.id} is approaching its daily sms limit of {service.sms_daily_limit}") -def send_near_email_limit_email(service: Service) -> None: +def send_near_email_limit_email(service: Service, emails_sent) -> None: """ Send an email to service users when nearing the daily email limit. """ limit_reset_time_et = get_limit_reset_time_et() + emails_remaining = service.message_limit - emails_sent send_notification_to_service_users( service_id=service.id, template_id=current_app.config["NEAR_DAILY_EMAIL_LIMIT_TEMPLATE_ID"], personalisation={ "service_name": service.name, "contact_url": f"{current_app.config['ADMIN_BASE_URL']}/contact", + "count_en": "{:,}".format(emails_sent), + "count_fr": "{:,}".format(emails_sent).replace(",", " "), + "remaining_en": "{:,}".format(emails_remaining), + "remaining_fr": "{:,}".format(emails_remaining).replace(",", " "), "message_limit_en": "{:,}".format(service.message_limit), "message_limit_fr": "{:,}".format(service.message_limit).replace(",", " "), "limit_reset_time_et_12hr": limit_reset_time_et["12hr"], diff --git a/migrations/versions/0434_update_email_templates_sms.py b/migrations/versions/0434_update_email_templates_sms.py index b7453949d1..aaff5b3ea1 100644 --- a/migrations/versions/0434_update_email_templates_sms.py +++ b/migrations/versions/0434_update_email_templates_sms.py @@ -29,7 +29,7 @@ "", "Bonjour ((name)),", "", - "((service_name)) peut envoyer ((message_limit_fr)) messages texte par jour. Si vous atteignez cette limite avant ((limit_reset_time_et_24hr)) heures, heure de l’Est, vos envois seront bloqués. Comparez [les heures officielles au Canada](https://nrc.canada.ca/fr/horloge-web/).", + "((service_name)) peut envoyer ((message_limit_fr)) messages texte par jour. Si vous atteignez cette limite avant ((limit_reset_time_et_24hr)) heures, heure de l’Est, vos envois seront bloqués. Comparez [les heures officielles au Canada](https://nrc.canada.ca/fr/horloge-web/).", "", "Veuillez [nous contacter](((contact_url))) si vous désirez augmenter votre limite d’envoi. Nous vous répondrons en un jour ouvrable.", "", diff --git a/migrations/versions/0437_email_templates_msgs_left.py b/migrations/versions/0437_email_templates_msgs_left.py new file mode 100644 index 0000000000..a9543a0b52 --- /dev/null +++ b/migrations/versions/0437_email_templates_msgs_left.py @@ -0,0 +1,101 @@ +""" + +Revision ID: 0437_email_templates_msgs_left +Revises: 0436_add_columns_api_keys +Create Date: 2023-10-05 00:00:00 + +""" +from datetime import datetime + +from alembic import op +from flask import current_app + +revision = "0437_email_templates_msgs_left" +down_revision = "0436_add_columns_api_keys" + +near_content = "\n".join( + [ + "(la version française suit)", + "", + "Hello ((name)),", + "", + "((service_name)) has sent ((count_en)) out of its limit of ((message_limit_en)) emails per 24 hours.", + "", + "**((service_name)) can send ((remaining_en)) more messages until your limit resets at ((limit_reset_time_et_12hr)) Eastern Time.** Compare official times across Canada](https://nrc.canada.ca/en/web-clock/).", + "", + "To request a limit increase, [contact us](((contact_url))). We’ll respond within 1 business day.", + "", + "The GC Notify team", + "", + "---", + "", + "Bonjour ((name)),", + "", + "((service_name)) a envoyé ((count_fr)) courriels de sa limite de ((message_limit_fr)) courriels par 24 heures.", + "", + "**((service_name)) peut encore envoyer ((remaining_fr)) messages d’ici à ce que votre limite de courriels soit réinitialisée à ((limit_reset_time_et_24hr)), heure de l’Est.** Comparez les heures officielles à travers le Canada.", + "", + "Pour demander une augmentation de votre limite, [veuillez nous joindre](((contact_url))). Nous vous répondrons en un jour ouvrable.", + "", + "L’équipe Notification GC", + ] +) + +templates = [ + { + "id": current_app.config["NEAR_DAILY_EMAIL_LIMIT_TEMPLATE_ID"], + "name": "Near daily EMAIL limit", + "template_type": "email", + "content": near_content, + "subject": "((service_name)) is near its daily limit for emails. | La limite quotidienne d’envoi de courriels est presque atteinte pour ((service_name)).", + "process_type": "priority", + }, +] + + +def upgrade(): + conn = op.get_bind() + + for template in templates: + current_version = conn.execute("select version from templates where id='{}'".format(template["id"])).fetchone() + template["version"] = current_version[0] + 1 + + template_update = """ + UPDATE templates SET content = '{}', subject = '{}', version = '{}', updated_at = '{}' + WHERE id = '{}' + """ + template_history_insert = """ + INSERT INTO templates_history (id, name, template_type, created_at, content, archived, service_id, subject, + created_by_id, version, process_type, hidden) + VALUES ('{}', '{}', '{}', '{}', '{}', False, '{}', '{}', '{}', {}, '{}', false) + """ + + for template in templates: + op.execute( + template_update.format( + template["content"], + template["subject"], + template["version"], + datetime.utcnow(), + template["id"], + ) + ) + + op.execute( + template_history_insert.format( + template["id"], + template["name"], + template["template_type"], + datetime.utcnow(), + template["content"], + current_app.config["NOTIFY_SERVICE_ID"], + template["subject"], + current_app.config["NOTIFY_USER_ID"], + template["version"], + template["process_type"], + ) + ) + + +def downgrade(): + pass diff --git a/migrations/versions/0438_sms_templates_msgs_left.py b/migrations/versions/0438_sms_templates_msgs_left.py new file mode 100644 index 0000000000..131352bd70 --- /dev/null +++ b/migrations/versions/0438_sms_templates_msgs_left.py @@ -0,0 +1,102 @@ +""" + +Revision ID: 0438_sms_templates_msgs_left +Revises: 0437_email_templates_msgs_left +Create Date: 2023-10-05 00:00:00 + +""" +from datetime import datetime + +from alembic import op +from flask import current_app + +revision = "0438_sms_templates_msgs_left" +down_revision = "0437_email_templates_msgs_left" + +near_content = "\n".join( + [ + "(la version française suit)", + "", + "Hello ((name)),", + "", + "((service_name)) has sent ((count_en)) out of its limit of ((message_limit_en)) text messages per 24 hours.", + "", + "**((service_name)) can send ((remaining_en)) more messages until your limit resets at ((limit_reset_time_et_12hr)) Eastern Time.** Compare [official times across Canada](https://nrc.canada.ca/en/web-clock/).", + "", + "To request a limit increase, [contact us](((contact_url))). We’ll respond within 1 business day.", + "", + "The GC Notify team", + "---", + "", + "Bonjour ((name)),", + "", + "((service_name)) a envoyé ((count_fr)) messages de sa limite de ((message_limit_fr)) messages texte par 24 heures.", + "", + "**((service_name)) peut encore envoyer ((remaining_fr)) messages d’ici à ce que votre limite de messages texte soit réinitialisée à ((limit_reset_time_et_24hr)), heure de l’Est.** Comparez les [heures officielles à travers le Canada](https://nrc.canada.ca/en/web-clock/).", + "", + "Pour demander une augmentation de votre limite, [veuillez nous joindre](((contact_url))). Nous vous répondrons en un jour ouvrable.", + "", + "L’équipe Notification GC", + ] +) + + +templates = [ + { + "id": current_app.config["NEAR_DAILY_SMS_LIMIT_TEMPLATE_ID"], + "template_type": "email", + "subject": "((service_name)) is near its daily limit for text messages. | La limite quotidienne d’envoi de messages texte est presque atteinte pour ((service_name)).", + "content": near_content, + "process_type": "priority", + }, +] + + +def upgrade(): + conn = op.get_bind() + + for template in templates: + current_version = conn.execute("select version from templates where id='{}'".format(template["id"])).fetchone() + name = conn.execute("select name from templates where id='{}'".format(template["id"])).fetchone() + template["version"] = current_version[0] + 1 + template["name"] = name[0] + + template_update = """ + UPDATE templates SET content = '{}', subject = '{}', version = '{}', updated_at = '{}' + WHERE id = '{}' + """ + template_history_insert = """ + INSERT INTO templates_history (id, name, template_type, created_at, content, archived, service_id, subject, + created_by_id, version, process_type, hidden) + VALUES ('{}', '{}', '{}', '{}', '{}', False, '{}', '{}', '{}', {}, '{}', false) + """ + + for template in templates: + op.execute( + template_update.format( + template["content"], + template["subject"], + template["version"], + datetime.utcnow(), + template["id"], + ) + ) + + op.execute( + template_history_insert.format( + template["id"], + template["name"], + template["template_type"], + datetime.utcnow(), + template["content"], + current_app.config["NOTIFY_SERVICE_ID"], + template["subject"], + current_app.config["NOTIFY_USER_ID"], + template["version"], + template["process_type"], + ) + ) + + +def downgrade(): + pass diff --git a/tests/app/notifications/test_validators.py b/tests/app/notifications/test_validators.py index 9ba51920c1..24175b431e 100644 --- a/tests/app/notifications/test_validators.py +++ b/tests/app/notifications/test_validators.py @@ -211,7 +211,7 @@ def test_check_service_message_limit_records_nearing_daily_limit( service = create_sample_service(notify_db, notify_db_session, restricted=True, limit=5, sms_limit=5) template = create_sample_template(notify_db, notify_db_session, service=service, template_type=limit_type) - for x in range(4): + for x in range(5): create_sample_notification(notify_db, notify_db_session, service=service, template=template) if limit_type == "sms": @@ -232,6 +232,10 @@ def test_check_service_message_limit_records_nearing_daily_limit( personalisation={ "service_name": service.name, "contact_url": f"{current_app.config['ADMIN_BASE_URL']}/contact", + "count_en": "4", + "count_fr": "4", + "remaining_en": "1", + "remaining_fr": "1", "message_limit_en": "5", "message_limit_fr": "5", **kwargs,