From a8558d9b4e5a8e9c6e768a5247626f8ddbf6d327 Mon Sep 17 00:00:00 2001
From: Andrew Leith
{%- if current_service.trial_mode %}
{{ _("Your service is in trial mode. To send more messages, request to go live").format(url_for('main.request_to_go_live', service_id=current_service.id)) }}
{% else %}
- {% if send_exceeds_annual_limit %}
-
- {{ _('{} can only send {} more email messages until annual limit resets'.format(current_service.name, recipients_remaining_messages)) }}
- {{ _('To send some of these messages now, edit the spreadsheet to {} recipients maximum. '.format(recipients_remaining_messages)) }}
- {{ _('To send to recipients you removed, wait until April 1, {} or contact them some other way.'.format(now().year)) }}
-
- {{ _("You can try sending these messages after {} Eastern Time. Check {}.").format(time_to_reset[current_lang],
- content_link(_("your current local time"), _('https://nrc.canada.ca/en/web-clock/'), is_external_link=true))}}
- {{ _('You cannot send all these email messages today') }}
-
+
{%- if current_service.trial_mode %} {{ _("Your service is in trial mode. To send more messages, request to go live").format(url_for('main.request_to_go_live', service_id=current_service.id)) }} {% else %} diff --git a/app/templates/views/check/column-errors.html b/app/templates/views/check/column-errors.html index 852d30f0bd..32f2ae9e8e 100644 --- a/app/templates/views/check/column-errors.html +++ b/app/templates/views/check/column-errors.html @@ -10,9 +10,7 @@ {% set prefix_txt = _('a column called') %} {% set prefix_plural_txt = _('columns called') %} -{% if send_exceeds_annual_limit %} - {% set page_title = _('These messages exceed the annual limit') %} -{% elif send_exceeds_daily_limit and (sms_parts_remaining <= 0) %} +{% if send_exceeds_daily_limit and (sms_parts_remaining <= 0) %} {% set page_title = _('These messages exceed your daily limit') %} {% elif send_exceeds_daily_limit or recipients.more_rows_than_can_send %} {% set page_title = _('These messages exceed your daily limit') %} @@ -170,9 +168,20 @@
+ {{ _("You can try sending these messages after {} Eastern Time. Check {}.").format(time_to_reset[current_lang], + content_link(_("your current local time"), _('https://nrc.canada.ca/en/web-clock/'), is_external_link=true))}} +
+ + {% endif %} + + {% if not send_exceeds_daily_limit %} diff --git a/app/translations/csv/fr.csv b/app/translations/csv/fr.csv index fe2c41b635..57aead4f21 100644 --- a/app/translations/csv/fr.csv +++ b/app/translations/csv/fr.csv @@ -2027,8 +2027,4 @@ "Annual usage","Utilisation annuelle" "resets at 7pm Eastern Time","Réinitialisation à 19 h, heure de l’Est" "Visit usage report","Consulter le rapport d’utilisation" -"Month by month totals","Totaux mensuels" -"{} can only send {} more email messages until annual limit resets","FR: {} can only send {} more email messages until annual limit resets" -"To send some of these messages now, edit the spreadsheet to {} recipients maximum. ","FR: To send some of these messages now, edit the spreadsheet to {} recipients maximum. " -"To send to recipients you removed, wait until April 1, {} or contact them some other way.","FR: To send to recipients you removed, wait until April 1, {} or contact them some other way" -"These messages exceed the annual limit","FR: These messages exceed the annual limit" \ No newline at end of file +"Month by month totals","Totaux mensuels" \ No newline at end of file diff --git a/gunicorn_config.py b/gunicorn_config.py index cf6e5e7112..63325ca386 100644 --- a/gunicorn_config.py +++ b/gunicorn_config.py @@ -51,7 +51,6 @@ # Start timer for total running time start_time = time.time() - def on_starting(server): server.log.info("Starting Notifications Admin") diff --git a/tests/app/main/views/test_send.py b/tests/app/main/views/test_send.py index c1350bdb46..78df4b10cc 100644 --- a/tests/app/main/views/test_send.py +++ b/tests/app/main/views/test_send.py @@ -6,7 +6,6 @@ from io import BytesIO from itertools import repeat from os import path -from unittest.mock import patch from uuid import uuid4 from zipfile import BadZipFile @@ -42,7 +41,6 @@ mock_get_service_letter_template, mock_get_service_template, normalize_spaces, - set_config, ) template_types = ["email", "sms"] @@ -2545,7 +2543,6 @@ def test_check_messages_shows_too_many_sms_messages_errors( mock_get_jobs, mock_s3_download, mock_s3_set_metadata, - mock_notification_counts_client, fake_uuid, num_requested, expected_msg, @@ -2563,10 +2560,6 @@ def test_check_messages_shows_too_many_sms_messages_errors( }, ) - mock_notification_counts_client.get_all_notification_counts_for_year.return_value = { - "sms": 0, - "email": 0, - } with client_request.session_transaction() as session: session["file_uploads"] = { fake_uuid: { @@ -2591,30 +2584,6 @@ def test_check_messages_shows_too_many_sms_messages_errors( assert details == expected_msg -@pytest.fixture -def mock_notification_counts_client(): - with patch("app.main.views.send.notification_counts_client") as mock: - yield mock - - -@pytest.fixture -def mock_daily_sms_fragment_count(): - with patch("app.main.views.send.daily_sms_fragment_count") as mock: - yield mock - - -@pytest.fixture -def mock_daily_email_count(): - with patch("app.main.views.send.daily_email_count") as mock: - yield mock - - -@pytest.fixture -def mock_get_service_template_annual_limits(): - with patch("app.service_api_client.get_service_template") as mock: - yield mock - - @pytest.mark.parametrize( "num_requested,expected_msg", [ @@ -2632,7 +2601,6 @@ def test_check_messages_shows_too_many_email_messages_errors( mock_get_template_statistics, mock_get_job_doesnt_exist, mock_get_jobs, - mock_notification_counts_client, fake_uuid, num_requested, expected_msg, @@ -2649,10 +2617,7 @@ def test_check_messages_shows_too_many_email_messages_errors( "email": {"requested": num_requested, "delivered": 0, "failed": 0}, }, ) - mock_notification_counts_client.get_all_notification_counts_for_year.return_value = { - "sms": 0, - "email": 0, - } + with client_request.session_transaction() as session: session["file_uploads"] = { fake_uuid: { @@ -3436,189 +3401,3 @@ class Object(object): multiple_choise_options = [x.text.strip() for x in options] assert multiple_choise_options == expected_filenames - - -class TestAnnualLimitsSend: - @pytest.mark.parametrize( - "num_being_sent, num_sent_today, num_sent_this_year, expect_to_see_annual_limit_msg, expect_to_see_daily_limit_msg", - [ - # annual limit for mock_get_live_service is 10,000email/10,000sms - # daily limit for mock_get_live_service is 1,000email/1,000sms - # 1000 have already been sent today, trying to send 100 more [over both limits] - (100, 1000, 10000, True, False), - # No sent yet today or this year, trying to send 1001 [over both limits] - (10001, 0, 0, True, False), - # 600 have already been sent this year, trying to send 500 more [over annual limit but not daily] - (500, 0, 9600, True, False), - # No sent yet today or this year, trying to send 1001 [over daily limit but not annual] - (1001, 0, 0, False, True), - # No sent yet today or this year, trying to send 100 [over neither limit] - (100, 0, 0, False, False), - ], - ids=[ - "email_over_both_limits", - "email_over_both_limits2", - "email_over_annual_but_not_daily", - "email_over_daily_but_not_annual", - "email_over_neither", - ], - ) - def test_email_send_fails_approrpiately_when_over_limits( - self, - mocker, - client_request, - mock_get_live_service, # set email_annual_limit and sms_annual_limit to 1000 - mock_get_users_by_service, - mock_get_service_email_template_without_placeholders, - mock_get_template_statistics, - mock_get_job_doesnt_exist, - mock_get_jobs, - mock_s3_set_metadata, - mock_notification_counts_client, - mock_daily_sms_fragment_count, - mock_daily_email_count, - fake_uuid, - num_being_sent, - num_sent_today, - num_sent_this_year, - expect_to_see_annual_limit_msg, - expect_to_see_daily_limit_msg, - app_, - ): - with set_config(app_, "FF_ANNUAL_LIMIT", True): - mocker.patch( - "app.main.views.send.s3download", - return_value=",\n".join( - ["email address"] + ([mock_get_users_by_service(None)[0]["email_address"]] * num_being_sent) - ), - ) - - # mock that `num_sent_this_year` have already been sent this year - mock_notification_counts_client.get_all_notification_counts_for_year.return_value = { - "sms": 1000, # not used in test but needs a value - "email": num_sent_this_year, - } - - # mock that we've already sent `emails_sent_today` emails today - mock_daily_email_count.return_value = num_sent_today - mock_daily_sms_fragment_count.return_value = 900 # not used in test but needs a value - - with client_request.session_transaction() as session: - session["file_uploads"] = { - fake_uuid: { - "template_id": fake_uuid, - "notification_count": 1, - "valid": True, - } - } - - page = client_request.get( - "main.check_messages", - service_id=SERVICE_ONE_ID, - template_id=fake_uuid, - upload_id=fake_uuid, - original_file_name="valid.csv", - _test_page_title=False, - ) - - if expect_to_see_annual_limit_msg: - assert page.find(attrs={"data-testid": "exceeds-annual"}) is not None - else: - assert page.find(attrs={"data-testid": "exceeds-annual"}) is None - - if expect_to_see_daily_limit_msg: - assert page.find(attrs={"data-testid": "exceeds-daily"}) is not None - else: - assert page.find(attrs={"data-testid": "exceeds-daily"}) is None - - @pytest.mark.parametrize( - "num_being_sent, num_sent_today, num_sent_this_year, expect_to_see_annual_limit_msg, expect_to_see_daily_limit_msg", - [ - # annual limit for mock_get_live_service is 10,000email/10,000sms - # daily limit for mock_get_live_service is 1,000email/1,000sms - # 1000 have already been sent today, trying to send 100 more [over both limits] - (100, 1000, 10000, True, False), - # No sent yet today or this year, trying to send 1001 [over both limits] - (10001, 0, 0, True, False), - # 600 have already been sent this year, trying to send 500 more [over annual limit but not daily] - (500, 0, 9600, True, False), - # No sent yet today or this year, trying to send 1001 [over daily limit but not annual] - (1001, 0, 0, False, True), - # No sent yet today or this year, trying to send 100 [over neither limit] - (100, 0, 0, False, False), - ], - ids=[ - "sms_over_both_limits", - "sms_over_both_limits2", - "sms_over_annual_but_not_daily", - "sms_over_daily_but_not_annual", - "sms_over_neither", - ], - ) - def test_sms_send_fails_approrpiately_when_over_limits( - self, - mocker, - client_request, - mock_get_live_service, # set email_annual_limit and sms_annual_limit to 1000 - mock_get_users_by_service, - mock_get_service_sms_template_without_placeholders, - mock_get_template_statistics, - mock_get_job_doesnt_exist, - mock_get_jobs, - mock_s3_set_metadata, - mock_notification_counts_client, - mock_daily_sms_fragment_count, - mock_daily_email_count, - fake_uuid, - num_being_sent, - num_sent_today, - num_sent_this_year, - expect_to_see_annual_limit_msg, - expect_to_see_daily_limit_msg, - app_, - ): - with set_config(app_, "FF_ANNUAL_LIMIT", True): # REMOVE LINE WHEN FF REMOVED - mocker.patch( - "app.main.views.send.s3download", - return_value=",\n".join( - ["phone number"] + ([mock_get_users_by_service(None)[0]["mobile_number"]] * num_being_sent) - ), - ) - - # mock that `num_sent_this_year` have already been sent this year - mock_notification_counts_client.get_all_notification_counts_for_year.return_value = { - "sms": num_sent_this_year, - "email": 1000, # not used in test but needs a value - } - - # mock that we've already sent `emails_sent_today` emails today - mock_daily_email_count.return_value = 900 # not used in test but needs a value - mock_daily_sms_fragment_count.return_value = num_sent_today - - with client_request.session_transaction() as session: - session["file_uploads"] = { - fake_uuid: { - "template_id": fake_uuid, - "notification_count": 1, - "valid": True, - } - } - - page = client_request.get( - "main.check_messages", - service_id=SERVICE_ONE_ID, - template_id=fake_uuid, - upload_id=fake_uuid, - original_file_name="valid.csv", - _test_page_title=False, - ) - - if expect_to_see_annual_limit_msg: - assert page.find(attrs={"data-testid": "exceeds-annual"}) is not None - else: - assert page.find(attrs={"data-testid": "exceeds-annual"}) is None - - if expect_to_see_daily_limit_msg: - assert page.find(attrs={"data-testid": "exceeds-daily"}) is not None - else: - assert page.find(attrs={"data-testid": "exceeds-daily"}) is None diff --git a/tests/app/notify_client/test_notification_counts_client.py b/tests/app/notify_client/test_notification_counts_client.py deleted file mode 100644 index fa7183aea8..0000000000 --- a/tests/app/notify_client/test_notification_counts_client.py +++ /dev/null @@ -1,89 +0,0 @@ -from unittest.mock import patch - -import pytest - -from app.notify_client.notification_counts_client import NotificationCounts - - -@pytest.fixture -def mock_redis(): - with patch("app.notify_client.notification_counts_client.redis_client") as mock: - yield mock - - -@pytest.fixture -def mock_template_stats(): - with patch("app.notify_client.notification_counts_client.template_statistics_client") as mock: - yield mock - - -@pytest.fixture -def mock_service_api(): - with patch("app.notify_client.notification_counts_client.service_api_client") as mock: - yield mock - - -class TestNotificationCounts: - def test_get_all_notification_counts_for_today_redis_has_data(self, mock_redis): - # Setup - mock_redis.get.side_effect = [5, 10] # sms, email - wrapper = NotificationCounts() - - # Execute - result = wrapper.get_all_notification_counts_for_today("service-123") - - # Assert - assert result == {"sms": 5, "email": 10} - assert mock_redis.get.call_count == 2 - - @pytest.mark.parametrize( - "redis_side_effect, expected_result", - [ - ([None, None], {"sms": 10, "email": 10}), - ([None, 10], {"sms": 10, "email": 10}), # Falls back to API if either is None - ([10, None], {"sms": 10, "email": 10}), # Falls back to API if either is None - ], - ) - def test_get_all_notification_counts_for_today_redis_missing_data( - self, mock_redis, mock_template_stats, redis_side_effect, expected_result - ): - # Setup - mock_redis.get.side_effect = redis_side_effect - mock_template_stats.get_template_statistics_for_service.return_value = [ - {"template_id": "a1", "template_type": "sms", "count": 3, "status": "delivered"}, - {"template_id": "a2", "template_type": "email", "count": 7, "status": "temporary-failure"}, - {"template_id": "a3", "template_type": "email", "count": 3, "status": "delivered"}, - {"template_id": "a4", "template_type": "sms", "count": 7, "status": "delivered"}, - ] - - wrapper = NotificationCounts() - - # Execute - result = wrapper.get_all_notification_counts_for_today("service-123") - - # Assert - assert result == {"sms": 10, "email": 10} - mock_template_stats.get_template_statistics_for_service.assert_called_once() - - def test_get_all_notification_counts_for_year(self, mock_service_api): - # Setup - mock_service_api.get_monthly_notification_stats.return_value = { - "data": { - "2024-01": { - "sms": {"sent": 1, "temporary-failure:": 22}, - "email": {"delivered": 1, "permanent-failure": 1, "sending": 12, "technical-failure": 1}, - }, - "2024-02": {"sms": {"sent": 1}, "email": {"delivered": 1}}, - } - } - wrapper = NotificationCounts() - - with patch.object(wrapper, "get_all_notification_counts_for_today") as mock_today: - mock_today.return_value = {"sms": 5, "email": 5} - - # Execute - result = wrapper.get_all_notification_counts_for_year("service-123", 2024) - - # Assert - assert result["sms"] == 29 # 1 + 22 + 1 + 5 - assert result["email"] == 21 # 1 + 1 + 12 + 1 + 1 + 5 diff --git a/tests/conftest.py b/tests/conftest.py index 21ed1f782b..94ff0ca5be 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -550,14 +550,7 @@ def fake_uuid(): @pytest.fixture(scope="function") def mock_get_service(mocker, api_user_active): def _get(service_id): - service = service_json( - service_id, - users=[api_user_active["id"]], - message_limit=50, - sms_daily_limit=20, - email_annual_limit=1000, - sms_annual_limit=1000, - ) + service = service_json(service_id, users=[api_user_active["id"]], message_limit=50, sms_daily_limit=20) return {"data": service} return mocker.patch("app.service_api_client.get_service", side_effect=_get) @@ -682,9 +675,7 @@ def mock_service_email_from_is_unique(mocker): @pytest.fixture(scope="function") def mock_get_live_service(mocker, api_user_active): def _get(service_id): - service = service_json( - service_id, users=[api_user_active["id"]], restricted=False, sms_annual_limit=10000, email_annual_limit=10000 - ) + service = service_json(service_id, users=[api_user_active["id"]], restricted=False) return {"data": service} return mocker.patch("app.service_api_client.get_service", side_effect=_get) @@ -980,21 +971,6 @@ def _get(service_id, template_id, version=None): return mocker.patch("app.service_api_client.get_service_template", side_effect=_get) -@pytest.fixture(scope="function") -def mock_get_service_sms_template_without_placeholders(mocker): - def _get(service_id, template_id, version=None): - template = template_json( - service_id, - template_id, - "Two week reminder", - "sms", - "Yo.", - ) - return {"data": template} - - return mocker.patch("app.service_api_client.get_service_template", side_effect=_get) - - @pytest.fixture(scope="function") def mock_get_service_letter_template(mocker, content=None, subject=None, postage="second"): def _get(service_id, template_id, version=None, postage=postage):