Merge pull request #2338 from alphagov/expected-letter-rate

1st class expected letter delivery
This commit is contained in:
Leo Hemsted
2018-10-01 14:20:36 +01:00
committed by GitHub
10 changed files with 92 additions and 180 deletions

View File

@@ -12,6 +12,7 @@ from flask import (
url_for,
)
from flask_login import current_user, login_required
from notifications_utils.letter_timings import get_letter_timings
from notifications_utils.template import Template, WithSubjectTemplate
from app import (
@@ -28,7 +29,6 @@ from app.utils import (
generate_next_dict,
generate_notifications_csv,
generate_previous_dict,
get_letter_timings,
get_page_from_request,
get_time_left,
parse_filter_args,
@@ -380,10 +380,16 @@ def get_job_partials(job, template):
)
if template['template_type'] == 'letter':
# there might be no notifications if the job has only just been created and the tasks haven't run yet
if notifications['notifications']:
postage = notifications['notifications'][0]['postage']
else:
postage = current_service.postage
counts = render_template(
'partials/jobs/count-letters.html',
total=job.get('notification_count', 0),
delivery_estimate=get_letter_timings(job['created_at']).earliest_delivery,
delivery_estimate=get_letter_timings(job['created_at'], postage=postage).earliest_delivery,
)
else:
counts = render_template(

View File

@@ -16,6 +16,7 @@ from flask import (
)
from flask_login import login_required
from notifications_python_client.errors import APIError
from notifications_utils.letter_timings import get_letter_timings
from notifications_utils.pdf import pdf_page_count
from app import (
@@ -33,7 +34,6 @@ from app.utils import (
FAILURE_STATUSES,
generate_notifications_csv,
get_help_argument,
get_letter_timings,
get_template,
parse_filter_args,
set_status_filters,
@@ -90,7 +90,10 @@ def view_notification(service_id, notification_id):
created_by=notification.get('created_by'),
created_at=notification['created_at'],
help=get_help_argument(),
estimated_letter_delivery_date=get_letter_timings(notification['created_at']).earliest_delivery,
estimated_letter_delivery_date=get_letter_timings(
notification['created_at'],
postage=notification['postage']
).earliest_delivery,
notification_id=notification['id'],
postage=notification['postage'],
can_receive_inbound=(current_service.has_permission('inbound_sms')),

View File

@@ -2,7 +2,6 @@ import csv
import os
import re
import unicodedata
from collections import namedtuple
from datetime import datetime, timedelta, timezone
from functools import wraps
from io import StringIO
@@ -356,37 +355,6 @@ 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)

View File

@@ -20,5 +20,7 @@ notifications-python-client==5.2.0
# PaaS
awscli-cwlogs>=1.4,<1.5
awscli==1.15.82
botocore<1.11.0
git+https://github.com/alphagov/notifications-utils.git@30.3.1#egg=notifications-utils==30.3.1
git+https://github.com/alphagov/notifications-utils.git@30.4.0#egg=notifications-utils==30.4.0

View File

@@ -22,17 +22,17 @@ notifications-python-client==5.2.0
# PaaS
awscli-cwlogs>=1.4,<1.5
awscli==1.15.82
botocore<1.11.0
git+https://github.com/alphagov/notifications-utils.git@30.3.1#egg=notifications-utils==30.3.1
git+https://github.com/alphagov/notifications-utils.git@30.4.0#egg=notifications-utils==30.4.0
## The following requirements were added by pip freeze:
awscli==1.16.20
bleach==2.1.3
boto3==1.6.16
botocore==1.12.10
certifi==2018.8.24
chardet==3.0.4
click==6.7
Click==7.0
colorama==0.3.9
dnspython==1.15.0
docopt==0.6.2
@@ -52,7 +52,7 @@ lxml==4.2.5
MarkupSafe==1.0
mistune==0.8.3
monotonic==1.5
openpyxl==2.5.7
openpyxl==2.5.8
orderedset==2.0.1
phonenumbers==8.9.4
pyasn1==0.4.4
@@ -61,7 +61,7 @@ PyJWT==1.6.4
PyPDF2==1.26.0
python-dateutil==2.7.3
python-json-logger==0.1.8
PyYAML==3.12
PyYAML==3.13
redis==2.10.6
requests==2.19.1
rsa==3.4.2

View File

@@ -390,7 +390,7 @@ def notification_json(
status = 'delivered'
links = {}
if template_type == 'letter':
postage = 'second'
postage = postage or 'second'
if with_links:
links = {

View File

@@ -440,3 +440,48 @@ def test_should_show_updates_for_one_job_as_json(
@freeze_time("2016-01-10 12:00:00.000000")
def test_time_left(job_created_at, expected_message):
assert get_time_left(job_created_at) == expected_message
@freeze_time("2016-01-01 11:09:00.061258")
def test_should_show_letter_job_with_first_class_if_notifications_are_first_class(
client_request,
mock_get_service_letter_template,
mock_get_job,
fake_uuid,
active_user_with_permissions,
mocker,
):
mock_get_notifications(
mocker,
active_user_with_permissions,
diff_template_type='letter',
postage='first'
)
page = client_request.get(
'main.view_job',
service_id=SERVICE_ONE_ID,
job_id=fake_uuid,
)
assert normalize_spaces(page.select('.keyline-block')[1].text) == '5 January Estimated delivery date'
@freeze_time("2016-01-01 11:09:00.061258")
def test_should_show_letter_job_with_first_class_if_no_notifications(
client_request,
mock_get_service_letter_template,
mock_get_job,
fake_uuid,
mock_get_notifications_with_no_notifications,
mocker
):
mocker.patch('app.main.views.jobs.current_service', postage='first')
page = client_request.get(
'main.view_job',
service_id=SERVICE_ONE_ID,
job_id=fake_uuid,
)
assert normalize_spaces(page.select('.keyline-block')[1].text) == '5 January Estimated delivery date'

View File

@@ -141,7 +141,7 @@ def test_notification_page_shows_page_for_letter_notification(
count_of_pages = 3
mock_get_notification(mocker, fake_uuid, template_type='letter')
mock_get_notification(mocker, fake_uuid, template_type='letter', postage='second')
mocker.patch(
'app.main.views.notifications.get_page_count_for_letter',
return_value=count_of_pages
@@ -174,6 +174,25 @@ def test_notification_page_shows_page_for_letter_notification(
)
@freeze_time("2016-01-01 01:01")
def test_notification_page_shows_page_for_first_class_letter_notification(
client_request,
mocker,
fake_uuid,
):
mock_get_notification(mocker, fake_uuid, template_type='letter', postage='first')
mocker.patch('app.main.views.notifications.get_page_count_for_letter', return_value=3)
page = client_request.get(
'main.view_notification',
service_id=SERVICE_ONE_ID,
notification_id=fake_uuid,
)
assert normalize_spaces(page.select('main p:nth-of-type(2)')[0].text) == 'Postage: first class'
assert normalize_spaces(page.select('main p:nth-of-type(3)')[0].text) == 'Estimated delivery date: 5 January'
@pytest.mark.parametrize('filetype', [
'pdf', 'png'
])

View File

@@ -17,7 +17,6 @@ from app.utils import (
generate_notifications_csv,
generate_previous_dict,
get_cdn_domain,
get_letter_timings,
)
from tests.conftest import fake_uuid
@@ -277,140 +276,6 @@ def test_generate_notifications_csv_calls_twice_if_next_link(
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
def test_get_cdn_domain_on_localhost(client, mocker):
mocker.patch.dict('app.current_app.config', values={'ADMIN_BASE_URL': 'http://localhost:6012'})
domain = get_cdn_domain()

View File

@@ -1838,6 +1838,7 @@ def mock_get_notifications(
is_precompiled_letter=False,
client_reference=None,
noti_status=None,
postage=None,
):
def _get_notifications(
service_id,
@@ -1882,6 +1883,7 @@ def mock_get_notifications(
client_reference=client_reference,
status=noti_status,
created_by_name='Firstname Lastname',
postage=postage
)
return mocker.patch(
@@ -2643,6 +2645,7 @@ def mock_get_notification(
template_name='sample template',
is_precompiled_letter=False,
key_type=None,
postage=None
):
def _get_notification(
service_id,
@@ -2653,6 +2656,7 @@ def mock_get_notification(
rows=1,
status=notification_status,
template_type=template_type,
postage=postage
)['notifications'][0]
noti['id'] = notification_id