Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
import re
from typing import Sequence
from .charity_gasds_data import GASDS_LIMITS, GASDS_LIMITS_HISTORY, GasdsLimit ← this capability’s own data, compiled from data/gasds-limits.json into the same file by fune build
from .charity_gasds_types import GasdsClaim
from .charity_gift_aid import gift_aid ← from charity.gift-aid ^1.0.0 · built alongside by fune
from .money_amount import Money, money ← from money.amount ^1.0.0 · built alongside by fune
ISO_DATE = re.compile(r"[0-9]{4}-[0-9]{2}-[0-9]{2}")
def _limits_on(on_date: str) -> GasdsLimit:
for row in GASDS_LIMITS:
if row.valid_from <= on_date and (row.valid_to is None or on_date <= row.valid_to):
return row
if GASDS_LIMITS_HISTORY != "full" and len(GASDS_LIMITS) > 0:
earliest = min(row.valid_from for row in GASDS_LIMITS)
if on_date < earliest:
raise ValueError(
"no GASDS limits on %s: this build was installed with history=%s, so it only carries rules from %s. "
"Reinstall with history=full for earlier tax years." % (on_date, GASDS_LIMITS_HISTORY, earliest)
)
raise ValueError("no GASDS limits on %s" % (on_date,))
def _check_amount(name: str, amount: Money) -> None:
if amount.currency != "GBP":
raise ValueError("GASDS amounts must be in GBP, received %s for %s" % (amount.currency, name))
if amount.minor < 0:
raise ValueError("%s must not be negative, received %d" % (name, amount.minor))
def gasds(
small_donations: Money,
gift_aid_donations: Money,
community_building_donations: Sequence[Money],
on_date: str,
) -> GasdsClaim:
"""The GASDS top-up for one tax year (Small Charitable Donations Act 2012
s1): paid on small donations up to the lower of 10 times the Gift Aid
donations claimed in the same year (the matching rule) and the specified
amount, which for a charity active in more than one community building may
be the sum of each building's local donations, up to £8,000 each (s6).
"""
_check_amount("smallDonations", small_donations)
_check_amount("giftAidDonations", gift_aid_donations)
for d in community_building_donations:
_check_amount("communityBuildingDonations", d)
if not isinstance(on_date, str) or not ISO_DATE.fullmatch(on_date):
raise ValueError('onDate must be an ISO date (YYYY-MM-DD), received "%s"' % (on_date,))
rule = _limits_on(on_date)
if len(community_building_donations) > 0 and not rule.community_buildings:
raise ValueError("community building claims before 6 April 2017 are not supported, received a claim for %s" % (on_date,))
in_buildings = sum(d.minor for d in community_building_donations)
if in_buildings > small_donations.minor:
raise ValueError(
"communityBuildingDonations total %d, more than smallDonations of %d" % (in_buildings, small_donations.minor)
)
specified = rule.specified_amount
used_community_buildings = False
# s6 applies only to a charity active in more than one community building.
if len(community_building_donations) >= 2:
buildings = sum(min(d.minor, rule.specified_amount) for d in community_building_donations)
if buildings > specified:
specified = buildings
used_community_buildings = True
maximum = min(10 * gift_aid_donations.minor, specified)
eligible = min(small_donations.minor, maximum)
return GasdsClaim(
eligible_donations=money(eligible, "GBP"),
top_up=gift_aid(money(eligible, "GBP"), on_date).tax_reclaimable,
maximum_donations=money(maximum, "GBP"),
specified_amount=money(specified, "GBP"),
small_donation_limit=money(rule.small_donation_limit, "GBP"),
used_community_buildings=used_community_buildings,
)