remove unneeded govuk dependencies

This commit is contained in:
Kenneth Kehl
2024-08-12 10:22:52 -07:00
parent f501b82313
commit 5ffab276ce
4 changed files with 1 additions and 470 deletions

View File

@@ -1,177 +0,0 @@
from collections import namedtuple
from datetime import time, timedelta
import pytz
from govuk_bank_holidays.bank_holidays import BankHolidays
from app.utils import utc_now
from notifications_utils.countries.data import Postage
from notifications_utils.timezones import utc_string_to_aware_gmt_datetime
LETTER_PROCESSING_DEADLINE = time(17, 30)
CANCELLABLE_JOB_LETTER_STATUSES = [
"created",
"cancelled",
"virus-scan-failed",
"validation-failed",
"technical-failure",
"pending-virus-check",
]
non_working_days_dvla = BankHolidays(
use_cached_holidays=True,
weekend=(5, 6),
)
non_working_days_royal_mail = BankHolidays(
use_cached_holidays=True,
weekend=(6,), # Only Sunday (day 6 of the week) is a non-working day
)
def set_gmt_hour(day, hour):
return (
day.astimezone(pytz.timezone("Europe/London"))
.replace(hour=hour, minute=0)
.astimezone(pytz.utc)
)
def get_next_work_day(date, non_working_days):
next_day = date + timedelta(days=1)
if non_working_days.is_work_day(
date=next_day.date(),
division=BankHolidays.ENGLAND_AND_WALES,
):
return next_day
return get_next_work_day(next_day, non_working_days)
def get_next_dvla_working_day(date):
"""
Printing takes place monday to friday, excluding bank holidays
"""
return get_next_work_day(date, non_working_days=non_working_days_dvla)
def get_next_royal_mail_working_day(date):
"""
Royal mail deliver letters on monday to saturday
"""
return get_next_work_day(date, non_working_days=non_working_days_royal_mail)
def get_delivery_day(date, *, days_to_deliver):
next_day = get_next_royal_mail_working_day(date)
if days_to_deliver == 1:
return next_day
return get_delivery_day(next_day, days_to_deliver=(days_to_deliver - 1))
def get_min_and_max_days_in_transit(postage):
return {
# first class post is printed earlier in the day, so will
# actually transit on the printing day, and be delivered the next
# day, so effectively spends no full days in transit
"first": (0, 0),
"second": (1, 2),
Postage.EUROPE: (3, 5),
Postage.REST_OF_WORLD: (5, 7),
}[postage]
def get_earliest_and_latest_delivery(print_day, postage):
for days_to_transit in get_min_and_max_days_in_transit(postage):
yield get_delivery_day(print_day, days_to_deliver=1 + days_to_transit)
def get_letter_timings(upload_time, postage):
LetterTimings = namedtuple(
"LetterTimings", "printed_by, is_printed, earliest_delivery, latest_delivery"
)
# shift anything after 5:30pm to the next day
processing_day = utc_string_to_aware_gmt_datetime(upload_time) + timedelta(
hours=6, minutes=30
)
print_day = get_next_dvla_working_day(processing_day)
earliest_delivery, latest_delivery = get_earliest_and_latest_delivery(
print_day, postage
)
# print deadline is 3pm BST
printed_by = set_gmt_hour(print_day, hour=15)
now = utc_now().replace(tzinfo=pytz.utc).astimezone(pytz.timezone("Europe/London"))
return LetterTimings(
printed_by=printed_by,
is_printed=(now > printed_by),
earliest_delivery=set_gmt_hour(earliest_delivery, hour=16),
latest_delivery=set_gmt_hour(latest_delivery, hour=16),
)
def letter_can_be_cancelled(notification_status, notification_created_at):
"""
If letter does not have status of created or pending-virus-check
=> can't be cancelled (it has already been processed)
If it's after 5.30pm local time and the notification was created today before 5.30pm local time
=> can't be cancelled (it will already be zipped up to be sent)
"""
if notification_status not in ("created", "pending-virus-check"):
return False
if too_late_to_cancel_letter(notification_created_at):
return False
return True
def too_late_to_cancel_letter(notification_created_at):
time_created_at = notification_created_at
day_created_on = time_created_at.date()
current_time = utc_now()
current_day = current_time.date()
if (
_after_letter_processing_deadline()
and _notification_created_before_today_deadline(notification_created_at)
):
return True
if (
_notification_created_before_that_day_deadline(notification_created_at)
and day_created_on < current_day
):
return True
if (current_day - day_created_on).days > 1:
return True
def _after_letter_processing_deadline():
current_utc_datetime = utc_now()
bst_time = current_utc_datetime.time()
return bst_time >= LETTER_PROCESSING_DEADLINE
def _notification_created_before_today_deadline(notification_created_at):
current_bst_datetime = utc_now()
todays_deadline = current_bst_datetime.replace(
hour=LETTER_PROCESSING_DEADLINE.hour,
minute=LETTER_PROCESSING_DEADLINE.minute,
)
notification_created_at_in_bst = notification_created_at
return notification_created_at_in_bst <= todays_deadline
def _notification_created_before_that_day_deadline(notification_created_at):
notification_created_at_bst_datetime = notification_created_at
created_at_day_deadline = notification_created_at_bst_datetime.replace(
hour=LETTER_PROCESSING_DEADLINE.hour,
minute=LETTER_PROCESSING_DEADLINE.minute,
)
return notification_created_at_bst_datetime <= created_at_day_deadline

16
poetry.lock generated
View File

@@ -1562,20 +1562,6 @@ files = [
{file = "geojson-3.1.0.tar.gz", hash = "sha256:58a7fa40727ea058efc28b0e9ff0099eadf6d0965e04690830208d3ef571adac"},
]
[[package]]
name = "govuk-bank-holidays"
version = "0.14"
description = "Tool to load UK bank holidays from GOV.UK"
optional = false
python-versions = ">=3.6"
files = [
{file = "govuk-bank-holidays-0.14.tar.gz", hash = "sha256:ce85102423b72908957d25981f616494729686515d5d66c09a1d35a354ce20a6"},
{file = "govuk_bank_holidays-0.14-py3-none-any.whl", hash = "sha256:da485c4a40c6c874c925916e492e3f20b807cffba7eed5f07fb69327aef6b10b"},
]
[package.dependencies]
requests = "*"
[[package]]
name = "greenlet"
version = "3.0.3"
@@ -4739,4 +4725,4 @@ multidict = ">=4.0"
[metadata]
lock-version = "2.0"
python-versions = "^3.12.2"
content-hash = "89b99841ebd4bd735104048c8f8f0a35bfedb700a7a5648ecabe713816e25579"
content-hash = "8fa243a938720113dd0999656594d7d3660a1e6202a4f26b9e9abe25d19b0cc0"

View File

@@ -52,7 +52,6 @@ faker = "^26.0.0"
async-timeout = "^4.0.3"
bleach = "^6.1.0"
geojson = "^3.1.0"
govuk-bank-holidays = "^0.14"
numpy = "^1.26.4"
ordered-set = "^4.1.0"
phonenumbers = "^8.13.42"

View File

@@ -1,277 +0,0 @@
from datetime import datetime
import pytest
import pytz
from freezegun import freeze_time
from app.utils import utc_now
from notifications_utils.letter_timings import (
get_letter_timings,
letter_can_be_cancelled,
)
@freeze_time("2017-07-14 13:59:59") # Friday, before print deadline (3PM EST)
@pytest.mark.parametrize(
(
"upload_time",
"expected_print_time",
"is_printed",
"first_class",
"expected_earliest",
"expected_latest",
),
[
# EST
# ==================================================================
# First thing Monday
(
"Monday 2017-07-10 00:00:01",
"Tuesday 2017-07-11 15:00",
True,
"Wednesday 2017-07-12 16:00",
"Thursday 2017-07-13 16:00",
"Friday 2017-07-14 16:00",
),
# Monday at 17:29 EST (sent on monday)
(
"Monday 2017-07-10 16:29:59",
"Tuesday 2017-07-11 15:00",
True,
"Wednesday 2017-07-12 16:00",
"Thursday 2017-07-13 16:00",
"Friday 2017-07-14 16:00",
),
# Monday at 17:30 EST (sent on tuesday)
(
"Monday 2017-07-10 16:30:01",
"Wednesday 2017-07-12 15:00",
True,
"Thursday 2017-07-13 16:00",
"Friday 2017-07-14 16:00",
"Saturday 2017-07-15 16:00",
),
# Tuesday before 17:30 EST
(
"Tuesday 2017-07-11 12:00:00",
"Wednesday 2017-07-12 15:00",
True,
"Thursday 2017-07-13 16:00",
"Friday 2017-07-14 16:00",
"Saturday 2017-07-15 16:00",
),
# Wednesday before 17:30 EST
(
"Wednesday 2017-07-12 12:00:00",
"Thursday 2017-07-13 15:00",
True,
"Friday 2017-07-14 16:00",
"Saturday 2017-07-15 16:00",
"Monday 2017-07-17 16:00",
),
# Thursday before 17:30 EST
(
"Thursday 2017-07-13 12:00:00",
"Friday 2017-07-14 15:00",
False,
"Saturday 2017-07-15 16:00",
"Monday 2017-07-17 16:00",
"Tuesday 2017-07-18 16:00",
),
# Friday anytime
(
"Friday 2017-07-14 00:00:00",
"Monday 2017-07-17 15:00",
False,
"Tuesday 2017-07-18 16:00",
"Wednesday 2017-07-19 16:00",
"Thursday 2017-07-20 16:00",
),
(
"Friday 2017-07-14 12:00:00",
"Monday 2017-07-17 15:00",
False,
"Tuesday 2017-07-18 16:00",
"Wednesday 2017-07-19 16:00",
"Thursday 2017-07-20 16:00",
),
(
"Friday 2017-07-14 22:00:00",
"Monday 2017-07-17 15:00",
False,
"Tuesday 2017-07-18 16:00",
"Wednesday 2017-07-19 16:00",
"Thursday 2017-07-20 16:00",
),
# Saturday anytime
(
"Saturday 2017-07-14 12:00:00",
"Monday 2017-07-17 15:00",
False,
"Tuesday 2017-07-18 16:00",
"Wednesday 2017-07-19 16:00",
"Thursday 2017-07-20 16:00",
),
# Sunday before 1730 EST
(
"Sunday 2017-07-15 15:59:59",
"Monday 2017-07-17 15:00",
False,
"Tuesday 2017-07-18 16:00",
"Wednesday 2017-07-19 16:00",
"Thursday 2017-07-20 16:00",
),
# Sunday after 17:30 EST
(
"Sunday 2017-07-16 16:30:01",
"Tuesday 2017-07-18 15:00",
False,
"Wednesday 2017-07-19 16:00",
"Thursday 2017-07-20 16:00",
"Friday 2017-07-21 16:00",
),
# GMT
# ==================================================================
# Monday at 17:29 GMT
(
"Monday 2017-01-02 17:29:59",
"Tuesday 2017-01-03 15:00",
True,
"Wednesday 2017-01-04 16:00",
"Thursday 2017-01-05 16:00",
"Friday 2017-01-06 16:00",
),
# Monday at 17:00 GMT
(
"Monday 2017-01-02 17:30:01",
"Wednesday 2017-01-04 15:00",
True,
"Thursday 2017-01-05 16:00",
"Friday 2017-01-06 16:00",
"Saturday 2017-01-07 16:00",
),
],
)
@pytest.mark.skip(reason="Letters being developed later")
def test_get_estimated_delivery_date_for_letter(
upload_time,
expected_print_time,
is_printed,
first_class,
expected_earliest,
expected_latest,
):
# remove the day string from the upload_time, which is purely informational
def format_dt(x):
return x.astimezone(pytz.timezone("America/New_York")).strftime(
"%A %Y-%m-%d %H:%M"
)
upload_time = upload_time.split(" ", 1)[1]
timings = get_letter_timings(upload_time, postage="second")
assert format_dt(timings.printed_by) == expected_print_time
assert timings.is_printed == is_printed
assert format_dt(timings.earliest_delivery) == expected_earliest
assert format_dt(timings.latest_delivery) == expected_latest
first_class_timings = get_letter_timings(upload_time, postage="first")
assert format_dt(first_class_timings.printed_by) == expected_print_time
assert first_class_timings.is_printed == is_printed
assert format_dt(first_class_timings.earliest_delivery) == first_class
assert format_dt(first_class_timings.latest_delivery) == first_class
@pytest.mark.parametrize("status", ["sending", "pending"])
def test_letter_cannot_be_cancelled_if_letter_status_is_not_created_or_pending_virus_check(
status,
):
notification_created_at = utc_now()
assert not letter_can_be_cancelled(status, notification_created_at)
@freeze_time("2018-7-7 16:00:00")
@pytest.mark.parametrize(
"notification_created_at",
[
datetime(2018, 7, 6, 18, 0), # created yesterday after 1730
datetime(2018, 7, 7, 12, 0), # created today
],
)
@pytest.mark.skip(reason="Letters not part of release")
def test_letter_can_be_cancelled_if_before_1730_and_letter_created_before_1730(
notification_created_at,
):
notification_status = "pending-virus-check"
assert letter_can_be_cancelled(notification_status, notification_created_at)
@freeze_time("2017-12-12 17:30:00")
@pytest.mark.parametrize(
"notification_created_at",
[
datetime(2017, 12, 12, 17, 0),
datetime(2017, 12, 12, 17, 30),
],
)
@pytest.mark.skip(reason="Letters not part of release")
def test_letter_cannot_be_cancelled_if_1730_exactly_and_letter_created_at_or_before_1730(
notification_created_at,
):
notification_status = "pending-virus-check"
assert not letter_can_be_cancelled(notification_status, notification_created_at)
@freeze_time("2018-7-7 19:00:00")
@pytest.mark.parametrize(
"notification_created_at",
[
datetime(2018, 7, 6, 18, 0), # created yesterday after 1730
datetime(2018, 7, 7, 12, 0), # created today before 1730
],
)
@pytest.mark.skip(reason="Letters not part of release")
def test_letter_cannot_be_cancelled_if_after_1730_and_letter_created_before_1730(
notification_created_at,
):
notification_status = "created"
assert not letter_can_be_cancelled(notification_status, notification_created_at)
@freeze_time("2018-7-7 15:00:00")
@pytest.mark.skip(reason="Letters not part of release")
def test_letter_cannot_be_cancelled_if_before_1730_and_letter_created_before_1730_yesterday():
notification_status = "created"
assert not letter_can_be_cancelled(notification_status, datetime(2018, 7, 6, 14, 0))
@freeze_time("2018-7-7 15:00:00")
@pytest.mark.skip(reason="Letters not part of release")
def test_letter_cannot_be_cancelled_if_before_1730_and_letter_created_after_1730_two_days_ago():
notification_status = "created"
assert not letter_can_be_cancelled(notification_status, datetime(2018, 7, 5, 19, 0))
@freeze_time("2018-7-7 19:00:00")
@pytest.mark.parametrize(
"notification_created_at",
[
datetime(2018, 7, 7, 18, 30),
datetime(2018, 7, 7, 19, 0),
],
)
def test_letter_can_be_cancelled_if_after_1730_and_letter_created_at_1730_today_or_later(
notification_created_at,
):
notification_status = "created"
assert letter_can_be_cancelled(notification_status, notification_created_at)