Merge pull request #1362 from alphagov/letter-delivery-estimates

Add function to estimate letter delivery date
This commit is contained in:
Chris Hill-Scott
2017-07-18 09:44:56 +01:00
committed by GitHub
3 changed files with 179 additions and 8 deletions

View File

@@ -7,7 +7,6 @@ from time import monotonic
import dateutil
import itertools
import pytz
import ago
from flask import (
Flask,
@@ -55,6 +54,8 @@ from app.notify_client.organisations_client import OrganisationsClient
from app.notify_client.models import AnonymousUser
from app.notify_client.letter_jobs_client import LetterJobsClient
from app.utils import gmt_timezones
login_manager = LoginManager()
csrf = CsrfProtect()
@@ -212,12 +213,6 @@ def syntax_highlight_json(code):
return Markup(highlight(code, JavascriptLexer(), HtmlFormatter(noclasses=True)))
def gmt_timezones(date):
date = dateutil.parser.parse(date)
forced_utc = date.replace(tzinfo=pytz.utc)
return forced_utc.astimezone(pytz.timezone('Europe/London'))
def format_datetime(date):
return '{} at {}'.format(
format_date(date),

View File

@@ -1,10 +1,13 @@
import re
import csv
import pytz
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
import dateutil
import ago
@@ -324,3 +327,40 @@ def get_time_left(created_at):
def email_or_sms_not_enabled(template_type, permissions):
return (template_type in ['email', 'sms']) and (template_type not in permissions)
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))
print_day, earliest_delivery, latest_delivery = (
processing_day + timedelta(days=days)
for days in {
'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,
)
def gmt_timezones(date):
date = dateutil.parser.parse(date)
forced_utc = date.replace(tzinfo=pytz.utc)
return forced_utc.astimezone(pytz.timezone('Europe/London'))

View File

@@ -5,13 +5,15 @@ from csv import DictReader
import pytest
from collections import OrderedDict
from freezegun import freeze_time
from app.utils import (
email_safe,
generate_notifications_csv,
generate_previous_dict,
generate_next_dict,
Spreadsheet
Spreadsheet,
get_letter_timings,
)
from tests import notification_json, single_notification_json
@@ -154,3 +156,137 @@ def test_generate_notifications_csv_calls_twice_if_next_link(mocker):
# mock_calls[0][2] is the kwargs from first call
assert mock_get_notifications.mock_calls[0][2]['page'] == 1
assert mock_get_notifications.mock_calls[1][2]['page'] == 2
@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',
'Tuesday 15:00',
True,
'Thursday 2017-07-13',
'Friday 2017-07-14'
),
# Monday at 16:59 BST
(
'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',
'Wednesday 15:00',
True,
'Friday 2017-07-14',
'Saturday 2017-07-15'
),
# Tuesday before 17:00 BST
(
'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',
'Thursday 15:00',
True,
'Saturday 2017-07-15',
'Monday 2017-07-17'
),
# Thursday before 17:00 BST
(
'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',
'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',
'Monday 15:00',
False,
'Wednesday 2017-07-19',
'Thursday 2017-07-20'
),
# Sunday before 1700 BST
(
'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',
'Tuesday 15:00',
False,
'Thursday 2017-07-20',
'Friday 2017-07-21'
),
# GMT
# ==================================================================
# Monday at 16:59 GMT
(
'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',
'Wednesday 15:00',
True,
'Friday 2017-01-06',
'Saturday 2017-01-07',
),
])
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