Functional Weave
Code in Python

legal.court-deadline@1.0.1

impl/python.py

2,562 bytes · the Python implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

from typing import Dict, Sequence, Set

from .dates_add_days import add_days, parse_iso_date  ← from dates.add-days ^1.0.0 · built alongside by fune
from .dates_bank_holidays import bank_holidays  ← from dates.bank-holidays ^1.0.0 · built alongside by fune
from .dates_day_of_week import day_of_week  ← from dates.day-of-week ^1.0.0 · built alongside by fune
from .legal_court_deadline_types import CourtDeadline, DeadlineRule


def court_deadline(
    trigger_date: str,
    days: int,
    rule: DeadlineRule,
    at_court_office: bool,
    court_closed_days: Sequence[str],
) -> CourtDeadline:
    """A deadline in days by CPR 2.8: clear days, short periods, court-office closures."""
    parse_iso_date(trigger_date)
    if isinstance(days, bool) or not isinstance(days, int) or days < 1:
        raise ValueError("days must be an integer of at least 1, received %s" % (days,))
    if rule not in ("within", "at-least-after", "at-least-before"):
        raise ValueError('unknown deadline rule "%s": expected within, at-least-after or at-least-before' % (rule,))
    if at_court_office and rule != "within":
        raise ValueError("atCourtOffice applies only to a within period (CPR 2.8(5))")
    if not at_court_office and len(court_closed_days) > 0:
        raise ValueError("courtClosedDays only apply when atCourtOffice is true")
    for d in court_closed_days:
        parse_iso_date(d)

    # England and Wales holidays by year, fetched only for the years a count touches.
    holidays: Dict[int, Set[str]] = {}

    def is_holiday(iso: str) -> bool:
        year = int(iso[0:4])
        if year not in holidays:
            holidays[year] = {h.date for h in bank_holidays("england-and-wales", year)}
        return iso in holidays[year]

    def is_non_working(iso: str) -> bool:
        return day_of_week(iso) >= 6 or is_holiday(iso)

    short_period = days <= 5
    step = -1 if rule == "at-least-before" else 1
    # Walk the clear days: the trigger day is never one, and in a short period
    # weekends and bank holidays are passed over without counting.
    cursor = trigger_date
    counted = 0
    while counted < days:
        cursor = add_days(cursor, step)
        if not short_period or not is_non_working(cursor):
            counted += 1
    if rule != "within":
        # The act or event falls on the day beyond the last clear day.
        return CourtDeadline(date=add_days(cursor, step), short_period=short_period, extended=False)
    date = cursor
    extended = False
    if at_court_office:
        while is_non_working(date) or date in court_closed_days:
            date = add_days(date, 1)
            extended = True
    return CourtDeadline(date=date, short_period=short_period, extended=extended)