diff --git a/app/utils.py b/app/utils.py index b4aafc0d9..56148f262 100644 --- a/app/utils.py +++ b/app/utils.py @@ -5,6 +5,7 @@ from io import StringIO from os import path from functools import wraps import unicodedata +from collections import namedtuple from datetime import datetime, timedelta, timezone from dateutil import parser @@ -328,19 +329,34 @@ def email_or_sms_not_enabled(template_type, permissions): return (template_type in ['email', 'sms']) and (template_type not in permissions) -def get_estimated_delivery_date_for_letters(upload_time): +def get_letter_timings(upload_time): + + LetterTimings = namedtuple( + 'LetterTimings', + 'printed_by, is_printed, earliest_delivery, latest_delivery' + ) # shift anything after 5pm to the next day processing_day = gmt_timezones(upload_time) + timedelta(hours=(7)) - return tuple( + print_day, earliest_delivery, latest_delivery = ( processing_day + timedelta(days=days) for days in { - 'Wednesday': (3, 5), - 'Thursday': (4, 5), - 'Friday': (5, 6), - 'Saturday': (4, 5), - }.get(processing_day.strftime('%A'), (3, 4)) + 'Wednesday': (1, 3, 5), + 'Thursday': (1, 4, 5), + 'Friday': (3, 5, 6), + 'Saturday': (2, 4, 5), + }.get(processing_day.strftime('%A'), (1, 3, 4)) + ) + + printed_by = print_day.astimezone(pytz.timezone('Europe/London')).replace(hour=15, minute=0) + now = datetime.utcnow().replace(tzinfo=pytz.timezone('Europe/London')) + + return LetterTimings( + printed_by=printed_by, + is_printed=(now > printed_by), + earliest_delivery=earliest_delivery, + latest_delivery=latest_delivery, ) diff --git a/tests/app/test_utils.py b/tests/app/test_utils.py index abced152a..d9b754e73 100644 --- a/tests/app/test_utils.py +++ b/tests/app/test_utils.py @@ -5,6 +5,7 @@ from csv import DictReader import pytest from collections import OrderedDict +from freezegun import freeze_time from app.utils import ( email_safe, @@ -12,7 +13,7 @@ from app.utils import ( generate_previous_dict, generate_next_dict, Spreadsheet, - get_estimated_delivery_date_for_letters, + get_letter_timings, ) from tests import notification_json, single_notification_json @@ -157,43 +158,135 @@ def test_generate_notifications_csv_calls_twice_if_next_link(mocker): assert mock_get_notifications.mock_calls[1][2]['page'] == 2 -@pytest.mark.parametrize('upload_time, expected_estimate', [ +@freeze_time('2017-07-14 14:59:59') # Friday, before print deadline +@pytest.mark.parametrize('upload_time, expected_print_time, is_printed, expected_earliest, expected_latest', [ # BST # ================================================================== # First thing Monday - ('2017-07-10 00:00:01', ('Thursday', 'Friday')), + ( + '2017-07-10 00:00:01', + 'Tuesday 15:00', + True, + 'Thursday 2017-07-13', + 'Friday 2017-07-14' + ), # Monday at 16:59 BST - ('2017-07-10 15:59:59', ('Thursday', 'Friday')), + ( + '2017-07-10 15:59:59', + 'Tuesday 15:00', + True, + 'Thursday 2017-07-13', + 'Friday 2017-07-14' + ), # Monday at 17:00 BST - ('2017-07-10 16:00:01', ('Friday', 'Saturday')), + ( + '2017-07-10 16:00:01', + 'Wednesday 15:00', + True, + 'Friday 2017-07-14', + 'Saturday 2017-07-15' + ), # Tuesday before 17:00 BST - ('2017-07-11 12:00:00', ('Friday', 'Saturday')), + ( + '2017-07-11 12:00:00', + 'Wednesday 15:00', + True, + 'Friday 2017-07-14', + 'Saturday 2017-07-15' + ), # Wednesday before 17:00 BST - ('2017-07-12 12:00:00', ('Saturday', 'Monday')), + ( + '2017-07-12 12:00:00', + 'Thursday 15:00', + True, + 'Saturday 2017-07-15', + 'Monday 2017-07-17' + ), # Thursday before 17:00 BST - ('2017-07-13 12:00:00', ('Monday', 'Tuesday')), + ( + '2017-07-13 12:00:00', + 'Friday 15:00', + True, # WRONG + 'Monday 2017-07-17', + 'Tuesday 2017-07-18' + ), # Friday anytime - ('2017-07-14 00:00:00', ('Wednesday', 'Thursday')), - ('2017-07-14 12:00:00', ('Wednesday', 'Thursday')), - ('2017-07-14 22:00:00', ('Wednesday', 'Thursday')), + ( + '2017-07-14 00:00:00', + 'Monday 15:00', + False, + 'Wednesday 2017-07-19', + 'Thursday 2017-07-20' + ), + ( + '2017-07-14 12:00:00', + 'Monday 15:00', + False, + 'Wednesday 2017-07-19', + 'Thursday 2017-07-20' + ), + ( + '2017-07-14 22:00:00', + 'Monday 15:00', + False, + 'Wednesday 2017-07-19', + 'Thursday 2017-07-20' + ), # Saturday anytime - ('2017-07-14 12:00:00', ('Wednesday', 'Thursday')), + ( + '2017-07-14 12:00:00', + 'Monday 15:00', + False, + 'Wednesday 2017-07-19', + 'Thursday 2017-07-20' + ), # Sunday before 1700 BST - ('2017-07-15 15:59:59', ('Wednesday', 'Thursday')), + ( + '2017-07-15 15:59:59', + 'Monday 15:00', + False, + 'Wednesday 2017-07-19', + 'Thursday 2017-07-20' + ), # Sunday after 17:00 BST - ('2017-07-16 16:00:01', ('Thursday', 'Friday')), + ( + '2017-07-16 16:00:01', + 'Tuesday 15:00', + False, + 'Thursday 2017-07-20', + 'Friday 2017-07-21' + ), # GMT # ================================================================== # Monday at 16:59 GMT - ('2017-01-02 16:59:59', ('Thursday', 'Friday')), + ( + '2017-01-02 16:59:59', + 'Tuesday 15:00', + True, + 'Thursday 2017-01-05', + 'Friday 2017-01-06', + ), # Monday at 17:00 GMT - ('2017-01-02 17:00:01', ('Friday', 'Saturday')), + ( + '2017-01-02 17:00:01', + 'Wednesday 15:00', + True, + 'Friday 2017-01-06', + 'Saturday 2017-01-07', + ), ]) -def test_get_estimated_delivery_date_for_letter(upload_time, expected_estimate): - assert tuple( - day.strftime('%A') - for day in get_estimated_delivery_date_for_letters(upload_time) - ) == expected_estimate +def test_get_estimated_delivery_date_for_letter( + upload_time, + expected_print_time, + is_printed, + expected_earliest, + expected_latest, +): + timings = get_letter_timings(upload_time) + assert timings.printed_by.strftime('%A %H:%M') == expected_print_time + assert timings.is_printed == is_printed + assert timings.earliest_delivery.strftime('%A %Y-%m-%d') == expected_earliest + assert timings.latest_delivery.strftime('%A %Y-%m-%d') == expected_latest