[ {"name": "a year's insurance by quarter: by days, not by months, and not a penny lost", "args": [{"minor": 120000, "currency": "GBP"}, "2026-01-01", "2026-12-31", [{"label": "Q1", "start": "2026-01-01", "end": "2026-03-31"}, {"label": "Q2", "start": "2026-04-01", "end": "2026-06-30"}, {"label": "Q3", "start": "2026-07-01", "end": "2026-09-30"}, {"label": "Q4", "start": "2026-10-01", "end": "2026-12-31"}]], "expect": [{"label": "Q1", "days": 90, "amount": {"minor": 29589, "currency": "GBP"}}, {"label": "Q2", "days": 91, "amount": {"minor": 29918, "currency": "GBP"}}, {"label": "Q3", "days": 92, "amount": {"minor": 30247, "currency": "GBP"}}, {"label": "Q4", "days": 92, "amount": {"minor": 30246, "currency": "GBP"}}]}, {"name": "a credit note mirrors its invoice period by period", "args": [{"minor": -120000, "currency": "GBP"}, "2026-01-01", "2026-12-31", [{"label": "Q1", "start": "2026-01-01", "end": "2026-03-31"}, {"label": "Q2", "start": "2026-04-01", "end": "2026-06-30"}, {"label": "Q3", "start": "2026-07-01", "end": "2026-09-30"}, {"label": "Q4", "start": "2026-10-01", "end": "2026-12-31"}]], "expect": [{"label": "Q1", "days": 90, "amount": {"minor": -29589, "currency": "GBP"}}, {"label": "Q2", "days": 91, "amount": {"minor": -29918, "currency": "GBP"}}, {"label": "Q3", "days": 92, "amount": {"minor": -30247, "currency": "GBP"}}, {"label": "Q4", "days": 92, "amount": {"minor": -30246, "currency": "GBP"}}]}, {"name": "a month's service across a year end", "args": [{"minor": 310000, "currency": "GBP"}, "2026-12-15", "2027-01-14", [{"label": "2026-12", "start": "2026-12-01", "end": "2026-12-31"}, {"label": "2027-01", "start": "2027-01-01", "end": "2027-01-31"}]], "expect": [{"label": "2026-12", "days": 17, "amount": {"minor": 170000, "currency": "GBP"}}, {"label": "2027-01", "days": 14, "amount": {"minor": 140000, "currency": "GBP"}}]}, {"name": "periods outside the service are listed with nothing in them", "args": [{"minor": 310000, "currency": "GBP"}, "2026-12-15", "2027-01-14", [{"label": "2026-11", "start": "2026-11-01", "end": "2026-11-30"}, {"label": "2026-12", "start": "2026-12-01", "end": "2026-12-31"}, {"label": "2027-01", "start": "2027-01-01", "end": "2027-01-31"}, {"label": "2027-02", "start": "2027-02-01", "end": "2027-02-28"}]], "expect": [{"label": "2026-11", "days": 0, "amount": {"minor": 0, "currency": "GBP"}}, {"label": "2026-12", "days": 17, "amount": {"minor": 170000, "currency": "GBP"}}, {"label": "2027-01", "days": 14, "amount": {"minor": 140000, "currency": "GBP"}}, {"label": "2027-02", "days": 0, "amount": {"minor": 0, "currency": "GBP"}}]}, {"name": "leap-year February counts 29 days", "args": [{"minor": 60000, "currency": "GBP"}, "2024-02-01", "2024-03-31", [{"label": "Feb", "start": "2024-02-01", "end": "2024-02-29"}, {"label": "Mar", "start": "2024-03-01", "end": "2024-03-31"}]], "expect": [{"label": "Feb", "days": 29, "amount": {"minor": 29000, "currency": "GBP"}}, {"label": "Mar", "days": 31, "amount": {"minor": 31000, "currency": "GBP"}}]}, {"name": "a single day of service", "args": [{"minor": 999, "currency": "GBP"}, "2026-03-31", "2026-03-31", [{"label": "Mar", "start": "2026-03-01", "end": "2026-03-31"}, {"label": "Apr", "start": "2026-04-01", "end": "2026-04-30"}]], "expect": [{"label": "Mar", "days": 1, "amount": {"minor": 999, "currency": "GBP"}}, {"label": "Apr", "days": 0, "amount": {"minor": 0, "currency": "GBP"}}]}, {"name": "odd pennies go to the largest remainders", "args": [{"minor": 100, "currency": "GBP"}, "2026-01-01", "2026-01-03", [{"label": "a", "start": "2026-01-01", "end": "2026-01-01"}, {"label": "b", "start": "2026-01-02", "end": "2026-01-02"}, {"label": "c", "start": "2026-01-03", "end": "2026-01-03"}]], "expect": [{"label": "a", "days": 1, "amount": {"minor": 34, "currency": "GBP"}}, {"label": "b", "days": 1, "amount": {"minor": 33, "currency": "GBP"}}, {"label": "c", "days": 1, "amount": {"minor": 33, "currency": "GBP"}}]}, {"name": "a 4-4-5 quarter", "args": [{"minor": 1300000, "currency": "GBP"}, "2026-01-04", "2026-04-04", [{"label": "P1", "start": "2026-01-04", "end": "2026-01-31"}, {"label": "P2", "start": "2026-02-01", "end": "2026-02-28"}, {"label": "P3", "start": "2026-03-01", "end": "2026-04-04"}]], "expect": [{"label": "P1", "days": 28, "amount": {"minor": 400000, "currency": "GBP"}}, {"label": "P2", "days": 28, "amount": {"minor": 400000, "currency": "GBP"}}, {"label": "P3", "days": 35, "amount": {"minor": 500000, "currency": "GBP"}}]}, {"name": "periods with a gap outside the service are fine", "args": [{"minor": 1000, "currency": "GBP"}, "2026-03-10", "2026-03-19", [{"label": "Jan", "start": "2026-01-01", "end": "2026-01-31"}, {"label": "Mar", "start": "2026-03-01", "end": "2026-03-31"}]], "expect": [{"label": "Jan", "days": 0, "amount": {"minor": 0, "currency": "GBP"}}, {"label": "Mar", "days": 10, "amount": {"minor": 1000, "currency": "GBP"}}]}, {"name": "zero amount", "args": [{"minor": 0, "currency": "GBP"}, "2026-01-01", "2026-12-31", [{"label": "Q1", "start": "2026-01-01", "end": "2026-03-31"}, {"label": "Q2", "start": "2026-04-01", "end": "2026-06-30"}, {"label": "Q3", "start": "2026-07-01", "end": "2026-09-30"}, {"label": "Q4", "start": "2026-10-01", "end": "2026-12-31"}]], "expect": [{"label": "Q1", "days": 90, "amount": {"minor": 0, "currency": "GBP"}}, {"label": "Q2", "days": 91, "amount": {"minor": 0, "currency": "GBP"}}, {"label": "Q3", "days": 92, "amount": {"minor": 0, "currency": "GBP"}}, {"label": "Q4", "days": 92, "amount": {"minor": 0, "currency": "GBP"}}]}, {"name": "a service that ends before it starts is refused", "args": [{"minor": 100, "currency": "GBP"}, "2026-03-10", "2026-03-09", [{"label": "Q1", "start": "2026-01-01", "end": "2026-03-31"}, {"label": "Q2", "start": "2026-04-01", "end": "2026-06-30"}, {"label": "Q3", "start": "2026-07-01", "end": "2026-09-30"}, {"label": "Q4", "start": "2026-10-01", "end": "2026-12-31"}]], "expectError": "service ends 2026-03-09, before it starts 2026-03-10"}, {"name": "no periods is refused", "args": [{"minor": 100, "currency": "GBP"}, "2026-03-10", "2026-03-12", []], "expectError": "at least one accounting period is needed"}, {"name": "a period that ends before it starts is refused", "args": [{"minor": 100, "currency": "GBP"}, "2026-03-10", "2026-03-12", [{"label": "bad", "start": "2026-03-31", "end": "2026-03-01"}]], "expectError": "period bad ends before it starts"}, {"name": "overlapping periods are refused", "args": [{"minor": 100, "currency": "GBP"}, "2026-03-10", "2026-03-12", [{"label": "a", "start": "2026-03-01", "end": "2026-03-15"}, {"label": "b", "start": "2026-03-15", "end": "2026-03-31"}]], "expectError": "period b overlaps or precedes the period before it"}, {"name": "periods out of order are refused", "args": [{"minor": 100, "currency": "GBP"}, "2026-03-10", "2026-03-12", [{"label": "Apr", "start": "2026-04-01", "end": "2026-04-30"}, {"label": "Mar", "start": "2026-03-01", "end": "2026-03-31"}]], "expectError": "period Mar overlaps or precedes the period before it"}, {"name": "days of service outside every period are refused", "args": [{"minor": 100, "currency": "GBP"}, "2026-03-25", "2026-04-05", [{"label": "Mar", "start": "2026-03-01", "end": "2026-03-31"}]], "expectError": "the accounting periods cover 7 of the 12 days of service"}, {"name": "an impossible date is refused", "args": [{"minor": 100, "currency": "GBP"}, "2026-02-29", "2026-03-05", [{"label": "Q1", "start": "2026-01-01", "end": "2026-03-31"}, {"label": "Q2", "start": "2026-04-01", "end": "2026-06-30"}, {"label": "Q3", "start": "2026-07-01", "end": "2026-09-30"}, {"label": "Q4", "start": "2026-10-01", "end": "2026-12-31"}]], "expectError": "not a real calendar date"} ]