Functional Weave
Code in TypeScript

hospitality.bill-split@1.0.0

README.md

1,965 bytes · view raw

# hospitality.bill-split

Splits a restaurant bill between diners so the shares add up to the bill
exactly, to the penny. Diners are numbered from 0. Each gets their share of
the items, their share of the service charge, and a total.

## Three methods

- **even**: the whole bill (items plus service) is split into near-equal
  totals with `money.allocate`, so no two diners' totals differ by more than
  a penny. The odd pennies go to the lowest-numbered diners.
- **by-item**: each item is paid for by the diners listed on it (`diners`),
  split evenly between them with `money.split-even`. An empty list means the
  whole table shared it. The odd penny of a shared item goes to the first
  diner *listed on that item*, so the caller can decide who picks it up.
- **by-share**: like even, but weighted: `shares` `[2, 1, 1]` means diner 0
  pays half. A share of 0 pays nothing.

`shares` is only for by-share and must be `[]` otherwise. `BillItem.diners` is
only read by by-item.

## The service charge

In every method the service charge is shared in proportion to what each diner
pays for. Nobody pays service on someone else's steak, and in an even split
the service shares follow the totals, so the totals stay within a penny.
Splitting items and service separately and adding them up is the naive way,
and it can leave even totals two pennies apart (5.07 and 5.05 on a 10.12 bill,
where this gives 5.06 each).

Work the charge out first with `hospitality.service-charge`, then split.

## Edge cases and errors

- A bill with no items splits to zero for everyone. Any service charge on it is
  split evenly or by share, but refused by item, since there is nothing to
  share it by.
- Item amounts and the service charge must not be negative. Apply a voucher
  before splitting, or split it as its own by-share bill.
- Every amount must be in the service charge's currency.
- A diner number outside 0 to diners - 1, or listed twice on one item, is an
  error.