from datetime import datetime, timedelta
import pytz
from dateutil import parser
from flask import url_for
from notifications_utils.formatters import unescaped_formatted_list
from notifications_utils.letter_timings import letter_can_be_cancelled
from notifications_utils.postal_address import PostalAddress
from notifications_utils.timezones import (
convert_bst_to_utc,
convert_utc_to_bst,
utc_string_to_aware_gmt_datetime,
)
def printing_today_or_tomorrow(created_at):
print_cutoff = convert_bst_to_utc(
convert_utc_to_bst(datetime.utcnow()).replace(hour=17, minute=30)
).replace(tzinfo=pytz.utc)
created_at = utc_string_to_aware_gmt_datetime(created_at)
if created_at < print_cutoff:
return 'today'
else:
return 'tomorrow'
def get_letter_printing_statement(status, created_at, long_form=True):
created_at_dt = parser.parse(created_at).replace(tzinfo=None)
if letter_can_be_cancelled(status, created_at_dt):
decription = 'Printing starts' if long_form else 'Printing'
return f'{decription} {printing_today_or_tomorrow(created_at)} at 5:30pm'
else:
printed_datetime = utc_string_to_aware_gmt_datetime(created_at) + timedelta(hours=6, minutes=30)
if printed_datetime.date() == datetime.now().date():
return 'Printed today at 5:30pm'
elif printed_datetime.date() == datetime.now().date() - timedelta(days=1):
return 'Printed yesterday at 5:30pm'
printed_date = printed_datetime.strftime('%d %B').lstrip('0')
description = 'Printed on' if long_form else 'Printed'
return f'{description} {printed_date} at 5:30pm'
LETTER_VALIDATION_MESSAGES = {
'letter-not-a4-portrait-oriented': {
'title': 'Your letter is not A4 portrait size',
'detail': (
'You need to change the size or orientation of {invalid_pages}.
'
'Files must meet our '
''
'letter specification'
'.'
),
'summary': (
'Validation failed because {invalid_pages} {invalid_pages_are_or_is} not A4 portrait size.
'
'Files must meet our '
''
'letter specification'
'.'
),
},
'content-outside-printable-area': {
'title': 'Your content is outside the printable area',
'detail': (
'You need to edit {invalid_pages}.
'
'Files must meet our '
''
'letter specification'
'.'
),
'summary': (
'Validation failed because content is outside the printable area on {invalid_pages}.
'
'Files must meet our '
''
'letter specification'
'.'
),
},
'letter-too-long': {
'title': 'Your letter is too long',
'detail': (
'Letters must be 10 pages or less (5 double-sided sheets of paper).
'
'Your letter is {page_count} pages long.'
),
'summary': (
'Validation failed because this letter is {page_count} pages long.
'
'Letters must be 10 pages or less (5 double-sided sheets of paper).'
),
},
'no-encoded-string': {
'title': 'Sanitise failed - No encoded string'
},
'unable-to-read-the-file': {
'title': 'There’s a problem with your file',
'detail': (
'Notify cannot read this PDF.'
'
Save a new copy of your file and try again.'
),
'summary': (
'Validation failed because Notify cannot read this PDF.
'
'Save a new copy of your file and try again.'
),
},
'address-is-empty': {
'title': 'The address block is empty',
'detail': (
'You need to add a recipient address.
'
'Files must meet our '
''
'letter specification'
'.'
),
'summary': (
'Validation failed because the address block is empty.
'
'Files must meet our '
''
'letter specification'
'.'
),
},
'not-a-real-uk-postcode': {
'title': 'There’s a problem with the address for this letter',
'detail': (
'The last line of the address must be a real UK postcode.'
),
'summary': (
'Validation failed because the last line of the address is not a real UK postcode.'
),
},
'cant-send-international-letters': {
'title': 'There’s a problem with the address for this letter',
'detail': (
'You do not have permission to send letters to other countries.'
),
'summary': (
'Validation failed because your service cannot send letters to other countries.'
),
},
'not-a-real-uk-postcode-or-country': {
'title': 'There’s a problem with the address for this letter',
'detail': (
'The last line of the address must be a UK postcode or '
'another country.'
),
'summary': (
'Validation failed because the last line of the address is '
'not a UK postcode or another country.'
),
},
'not-enough-address-lines': {
'title': 'There’s a problem with the address for this letter',
'detail': (
f'The address must be at least {PostalAddress.MIN_LINES} '
f'lines long.'
),
'summary': (
f'Validation failed because the address must be at least '
f'{PostalAddress.MIN_LINES} lines long.'
),
},
'too-many-address-lines': {
'title': 'There’s a problem with the address for this letter',
'detail': (
f'The address must be no more than {PostalAddress.MAX_LINES} '
f'lines long.'
),
'summary': (
f'Validation failed because the address must be no more '
f'than {PostalAddress.MAX_LINES} lines long.'
),
},
'invalid-char-in-address': {
'title': 'There’s a problem with the address for this letter',
'detail': (
"Address lines must not start with any of the following characters: @ ( ) = [ ] ” \\ / , < > ~"
),
'summary': (
"Validation failed because address lines must not start with any of the "
"following characters: @ ( ) = [ ] ” \\ / , < > ~"
),
},
'notify-tag-found-in-content': {
'title': 'There’s a problem with your letter',
'detail': (
'Your file includes a letter you’ve downloaded from Notify.
'
'You need to edit {invalid_pages}.'
),
'summary': (
'Validation failed because your file includes a letter '
'you’ve downloaded from Notify on {invalid_pages}.'
)
},
}
def get_letter_validation_error(validation_message, invalid_pages=None, page_count=None):
if not invalid_pages:
invalid_pages = []
if validation_message not in LETTER_VALIDATION_MESSAGES:
return {'title': 'Validation failed'}
invalid_pages_are_or_is = 'is' if len(invalid_pages) == 1 else 'are'
invalid_pages = unescaped_formatted_list(
invalid_pages,
before_each='',
after_each='',
prefix='page',
prefix_plural='pages'
)
return {
'title': LETTER_VALIDATION_MESSAGES[validation_message]['title'],
'detail': LETTER_VALIDATION_MESSAGES[validation_message]['detail'].format(
invalid_pages=invalid_pages,
invalid_pages_are_or_is=invalid_pages_are_or_is,
page_count=page_count,
letter_spec_guidance=url_for('.letter_specification')
),
'summary': LETTER_VALIDATION_MESSAGES[validation_message]['summary'].format(
invalid_pages=invalid_pages,
invalid_pages_are_or_is=invalid_pages_are_or_is,
page_count=page_count,
letter_spec_guidance=url_for('.letter_specification'),
),
}