Functional Weave
Code in TypeScript

property.service-charge-apportion@1.0.1

README.md

3,264 bytes · view raw

# property.service-charge-apportion

Shares a building's service charge out between its units the way their leases
say, and makes the pennies add up: the lines always total the service charge
exactly, never a penny over or under.

Leases state a unit's share in one of three ways, chosen by `basis`:

- **fraction**: "one-third", "3/20ths". Each unit gives `share` over `of`.
  The fractions must add up to exactly 1, since a lease scheme that does not
  recover the whole cost (or recovers more) is something to raise with the
  landlord, not to paper over.
- **floor-area**: each unit's area, in any one integer unit (square feet,
  square metres, or square metres × 100 for 0.01 m² precision). The share is
  the unit's area over the total area.
- **percentage**: basis points (2500 = 25%), adding up to exactly 10,000.

## Exact to the penny

Each unit's exact share is total × share, and the pennies left over after
rounding every share down are given one at a time to the units with the
largest remainders (ties to the earlier unit), by `money.allocate`. So a
£100.01 charge split 1/3, 1/6, 1/2 is £33.34, £16.67 and £50.00. Rounding each
share to the nearest penny separately would give £33.34, £16.67 and £50.01:
£100.02, a penny that was never spent.

Fractions are brought to a common denominator exactly (with
`math.gcd-lcm`), never converted to decimals.

## Edge cases

- A unit with a zero share pays nothing but still gets a line.
- A negative total (a surplus refunded, a credit) is shared the same way.
- `of` must be null unless the basis is fraction, and must be given (and be
  positive) when it is.
- The shares' total, times the service charge in minor units, must stay below
  2^53, so that every language computes the same split exactly. Denominators
  whose lowest common multiple is too large to share a charge that precisely
  are refused rather than approximated.

## What it does not do

It does not weight different cost heads differently (a lift schedule that
excludes ground-floor flats is a second call with its own units), cap any
unit's contribution, or handle reserve fund contributions separately.

## Before you rely on this

**Not professional advice.** This capability calculates property figures from published rules. It is a software component for developers, not legal or financial advice. Rules change and every rate here has an effective date. Check that the dates cover your case. Verify results against the official sources listed above, and have a conveyancer or tax adviser review how you use it, before anyone relies on the output. Provided "as is" under its licence, without warranty.

**Unreviewed.** This capability's implementations agree in every language and pass its published test vectors, which were worked out from the official sources cited. But no qualified conveyancer or tax adviser has yet checked those vectors, or confirmed that the capability covers the cases it claims. Treat it as a draft. Do not use it for real people, money or decisions without your own expert review. Once a qualified reviewer signs off, this notice is replaced with their name, qualification and the date. Each new version needs fresh sign-off.

1.0.1 marks it unreviewed. The code and the tests are unchanged.