[
{
"name": "\u00a39,535 in equal thirds: the odd penny on the first instalment",
"args": [
{
"minor": 953500,
"currency": "GBP"
},
[
1,
1,
1
],
[
"2025-10-01",
"2026-01-15",
"2026-04-20"
]
],
"expect": [
{
"number": 1,
"dueDate": "2025-10-01",
"amount": {
"minor": 317834,
"currency": "GBP"
},
"cumulative": {
"minor": 317834,
"currency": "GBP"
},
"remaining": {
"minor": 635666,
"currency": "GBP"
}
},
{
"number": 2,
"dueDate": "2026-01-15",
"amount": {
"minor": 317833,
"currency": "GBP"
},
"cumulative": {
"minor": 635667,
"currency": "GBP"
},
"remaining": {
"minor": 317833,
"currency": "GBP"
}
},
{
"number": 3,
"dueDate": "2026-04-20",
"amount": {
"minor": 317833,
"currency": "GBP"
},
"cumulative": {
"minor": 953500,
"currency": "GBP"
},
"remaining": {
"minor": 0,
"currency": "GBP"
}
}
]
},
{
"name": "\u00a39,535 split 25/25/50 across three terms",
"args": [
{
"minor": 953500,
"currency": "GBP"
},
[
25,
25,
50
],
[
"2025-10-01",
"2026-01-15",
"2026-04-20"
]
],
"expect": [
{
"number": 1,
"dueDate": "2025-10-01",
"amount": {
"minor": 238375,
"currency": "GBP"
},
"cumulative": {
"minor": 238375,
"currency": "GBP"
},
"remaining": {
"minor": 715125,
"currency": "GBP"
}
},
{
"number": 2,
"dueDate": "2026-01-15",
"amount": {
"minor": 238375,
"currency": "GBP"
},
"cumulative": {
"minor": 476750,
"currency": "GBP"
},
"remaining": {
"minor": 476750,
"currency": "GBP"
}
},
{
"number": 3,
"dueDate": "2026-04-20",
"amount": {
"minor": 476750,
"currency": "GBP"
},
"cumulative": {
"minor": 953500,
"currency": "GBP"
},
"remaining": {
"minor": 0,
"currency": "GBP"
}
}
]
},
{
"name": "\u00a31,000.01 split 25/25/50: the odd penny goes to the 50% share, the largest remainder, not the first",
"args": [
{
"minor": 100001,
"currency": "GBP"
},
[
25,
25,
50
],
[
"2025-10-01",
"2026-01-15",
"2026-04-20"
]
],
"expect": [
{
"number": 1,
"dueDate": "2025-10-01",
"amount": {
"minor": 25000,
"currency": "GBP"
},
"cumulative": {
"minor": 25000,
"currency": "GBP"
},
"remaining": {
"minor": 75001,
"currency": "GBP"
}
},
{
"number": 2,
"dueDate": "2026-01-15",
"amount": {
"minor": 25000,
"currency": "GBP"
},
"cumulative": {
"minor": 50000,
"currency": "GBP"
},
"remaining": {
"minor": 50001,
"currency": "GBP"
}
},
{
"number": 3,
"dueDate": "2026-04-20",
"amount": {
"minor": 50001,
"currency": "GBP"
},
"cumulative": {
"minor": 100001,
"currency": "GBP"
},
"remaining": {
"minor": 0,
"currency": "GBP"
}
}
]
},
{
"name": "shares in basis points give the same schedule",
"args": [
{
"minor": 100001,
"currency": "GBP"
},
[
2500,
2500,
5000
],
[
"2025-10-01",
"2026-01-15",
"2026-04-20"
]
],
"expect": [
{
"number": 1,
"dueDate": "2025-10-01",
"amount": {
"minor": 25000,
"currency": "GBP"
},
"cumulative": {
"minor": 25000,
"currency": "GBP"
},
"remaining": {
"minor": 75001,
"currency": "GBP"
}
},
{
"number": 2,
"dueDate": "2026-01-15",
"amount": {
"minor": 25000,
"currency": "GBP"
},
"cumulative": {
"minor": 50000,
"currency": "GBP"
},
"remaining": {
"minor": 50001,
"currency": "GBP"
}
},
{
"number": 3,
"dueDate": "2026-04-20",
"amount": {
"minor": 50001,
"currency": "GBP"
},
"cumulative": {
"minor": 100001,
"currency": "GBP"
},
"remaining": {
"minor": 0,
"currency": "GBP"
}
}
]
},
{
"name": "\u00a3100 in thirds: 33.34, 33.33, 33.33",
"args": [
{
"minor": 10000,
"currency": "GBP"
},
[
1,
1,
1
],
[
"2025-10-01",
"2026-01-15",
"2026-04-20"
]
],
"expect": [
{
"number": 1,
"dueDate": "2025-10-01",
"amount": {
"minor": 3334,
"currency": "GBP"
},
"cumulative": {
"minor": 3334,
"currency": "GBP"
},
"remaining": {
"minor": 6666,
"currency": "GBP"
}
},
{
"number": 2,
"dueDate": "2026-01-15",
"amount": {
"minor": 3333,
"currency": "GBP"
},
"cumulative": {
"minor": 6667,
"currency": "GBP"
},
"remaining": {
"minor": 3333,
"currency": "GBP"
}
},
{
"number": 3,
"dueDate": "2026-04-20",
"amount": {
"minor": 3333,
"currency": "GBP"
},
"cumulative": {
"minor": 10000,
"currency": "GBP"
},
"remaining": {
"minor": 0,
"currency": "GBP"
}
}
]
},
{
"name": "\u00a3100.01 in thirds: the two leftover pennies to the first two",
"args": [
{
"minor": 10001,
"currency": "GBP"
},
[
1,
1,
1
],
[
"2025-10-01",
"2026-01-15",
"2026-04-20"
]
],
"expect": [
{
"number": 1,
"dueDate": "2025-10-01",
"amount": {
"minor": 3334,
"currency": "GBP"
},
"cumulative": {
"minor": 3334,
"currency": "GBP"
},
"remaining": {
"minor": 6667,
"currency": "GBP"
}
},
{
"number": 2,
"dueDate": "2026-01-15",
"amount": {
"minor": 3334,
"currency": "GBP"
},
"cumulative": {
"minor": 6668,
"currency": "GBP"
},
"remaining": {
"minor": 3333,
"currency": "GBP"
}
},
{
"number": 3,
"dueDate": "2026-04-20",
"amount": {
"minor": 3333,
"currency": "GBP"
},
"cumulative": {
"minor": 10001,
"currency": "GBP"
},
"remaining": {
"minor": 0,
"currency": "GBP"
}
}
]
},
{
"name": "a single payment in full",
"args": [
{
"minor": 925000,
"currency": "GBP"
},
[
1
],
[
"2025-09-22"
]
],
"expect": [
{
"number": 1,
"dueDate": "2025-09-22",
"amount": {
"minor": 925000,
"currency": "GBP"
},
"cumulative": {
"minor": 925000,
"currency": "GBP"
},
"remaining": {
"minor": 0,
"currency": "GBP"
}
}
]
},
{
"name": "a zero share collects nothing",
"args": [
{
"minor": 900000,
"currency": "GBP"
},
[
0,
1,
1
],
[
"2025-10-01",
"2026-01-15",
"2026-04-20"
]
],
"expect": [
{
"number": 1,
"dueDate": "2025-10-01",
"amount": {
"minor": 0,
"currency": "GBP"
},
"cumulative": {
"minor": 0,
"currency": "GBP"
},
"remaining": {
"minor": 900000,
"currency": "GBP"
}
},
{
"number": 2,
"dueDate": "2026-01-15",
"amount": {
"minor": 450000,
"currency": "GBP"
},
"cumulative": {
"minor": 450000,
"currency": "GBP"
},
"remaining": {
"minor": 450000,
"currency": "GBP"
}
},
{
"number": 3,
"dueDate": "2026-04-20",
"amount": {
"minor": 450000,
"currency": "GBP"
},
"cumulative": {
"minor": 900000,
"currency": "GBP"
},
"remaining": {
"minor": 0,
"currency": "GBP"
}
}
]
},
{
"name": "a zero fee is a schedule of zeros",
"args": [
{
"minor": 0,
"currency": "GBP"
},
[
1,
1
],
[
"2025-10-01",
"2026-01-15"
]
],
"expect": [
{
"number": 1,
"dueDate": "2025-10-01",
"amount": {
"minor": 0,
"currency": "GBP"
},
"cumulative": {
"minor": 0,
"currency": "GBP"
},
"remaining": {
"minor": 0,
"currency": "GBP"
}
},
{
"number": 2,
"dueDate": "2026-01-15",
"amount": {
"minor": 0,
"currency": "GBP"
},
"cumulative": {
"minor": 0,
"currency": "GBP"
},
"remaining": {
"minor": 0,
"currency": "GBP"
}
}
]
},
{
"name": "euros keep their currency",
"args": [
{
"minor": 1000,
"currency": "EUR"
},
[
1,
1,
1
],
[
"2025-10-01",
"2026-01-15",
"2026-04-20"
]
],
"expect": [
{
"number": 1,
"dueDate": "2025-10-01",
"amount": {
"minor": 334,
"currency": "EUR"
},
"cumulative": {
"minor": 334,
"currency": "EUR"
},
"remaining": {
"minor": 666,
"currency": "EUR"
}
},
{
"number": 2,
"dueDate": "2026-01-15",
"amount": {
"minor": 333,
"currency": "EUR"
},
"cumulative": {
"minor": 667,
"currency": "EUR"
},
"remaining": {
"minor": 333,
"currency": "EUR"
}
},
{
"number": 3,
"dueDate": "2026-04-20",
"amount": {
"minor": 333,
"currency": "EUR"
},
"cumulative": {
"minor": 1000,
"currency": "EUR"
},
"remaining": {
"minor": 0,
"currency": "EUR"
}
}
]
},
{
"name": "ten monthly payments of \u00a3925",
"args": [
{
"minor": 925000,
"currency": "GBP"
},
[
1,
1,
1,
1,
1,
1,
1,
1,
1,
1
],
[
"2025-10-01",
"2025-11-01",
"2025-12-01",
"2026-01-01",
"2026-02-01",
"2026-03-01",
"2026-04-01",
"2026-05-01",
"2026-06-01",
"2026-07-01"
]
],
"expect": [
{
"number": 1,
"dueDate": "2025-10-01",
"amount": {
"minor": 92500,
"currency": "GBP"
},
"cumulative": {
"minor": 92500,
"currency": "GBP"
},
"remaining": {
"minor": 832500,
"currency": "GBP"
}
},
{
"number": 2,
"dueDate": "2025-11-01",
"amount": {
"minor": 92500,
"currency": "GBP"
},
"cumulative": {
"minor": 185000,
"currency": "GBP"
},
"remaining": {
"minor": 740000,
"currency": "GBP"
}
},
{
"number": 3,
"dueDate": "2025-12-01",
"amount": {
"minor": 92500,
"currency": "GBP"
},
"cumulative": {
"minor": 277500,
"currency": "GBP"
},
"remaining": {
"minor": 647500,
"currency": "GBP"
}
},
{
"number": 4,
"dueDate": "2026-01-01",
"amount": {
"minor": 92500,
"currency": "GBP"
},
"cumulative": {
"minor": 370000,
"currency": "GBP"
},
"remaining": {
"minor": 555000,
"currency": "GBP"
}
},
{
"number": 5,
"dueDate": "2026-02-01",
"amount": {
"minor": 92500,
"currency": "GBP"
},
"cumulative": {
"minor": 462500,
"currency": "GBP"
},
"remaining": {
"minor": 462500,
"currency": "GBP"
}
},
{
"number": 6,
"dueDate": "2026-03-01",
"amount": {
"minor": 92500,
"currency": "GBP"
},
"cumulative": {
"minor": 555000,
"currency": "GBP"
},
"remaining": {
"minor": 370000,
"currency": "GBP"
}
},
{
"number": 7,
"dueDate": "2026-04-01",
"amount": {
"minor": 92500,
"currency": "GBP"
},
"cumulative": {
"minor": 647500,
"currency": "GBP"
},
"remaining": {
"minor": 277500,
"currency": "GBP"
}
},
{
"number": 8,
"dueDate": "2026-05-01",
"amount": {
"minor": 92500,
"currency": "GBP"
},
"cumulative": {
"minor": 740000,
"currency": "GBP"
},
"remaining": {
"minor": 185000,
"currency": "GBP"
}
},
{
"number": 9,
"dueDate": "2026-06-01",
"amount": {
"minor": 92500,
"currency": "GBP"
},
"cumulative": {
"minor": 832500,
"currency": "GBP"
},
"remaining": {
"minor": 92500,
"currency": "GBP"
}
},
{
"number": 10,
"dueDate": "2026-07-01",
"amount": {
"minor": 92500,
"currency": "GBP"
},
"cumulative": {
"minor": 925000,
"currency": "GBP"
},
"remaining": {
"minor": 0,
"currency": "GBP"
}
}
]
},
{
"name": "a negative total is an error",
"args": [
{
"minor": -100,
"currency": "GBP"
},
[
1,
1
],
[
"2025-10-01",
"2026-01-15"
]
],
"expectError": "total must not be negative, received -100"
},
{
"name": "more shares than dates is an error",
"args": [
{
"minor": 100,
"currency": "GBP"
},
[
1,
1,
1
],
[
"2025-10-01",
"2026-01-15"
]
],
"expectError": "shares and dueDates must be the same length, received 3 and 2"
},
{
"name": "no instalments is an error",
"args": [
{
"minor": 100,
"currency": "GBP"
},
[],
[]
],
"expectError": "shares must name at least one instalment"
},
{
"name": "a negative share is an error",
"args": [
{
"minor": 100,
"currency": "GBP"
},
[
1,
-1
],
[
"2025-10-01",
"2026-01-15"
]
],
"expectError": "each share must be a whole number of 0 or more, received -1"
},
{
"name": "a fractional share is an error",
"args": [
{
"minor": 100,
"currency": "GBP"
},
[
1,
1.5
],
[
"2025-10-01",
"2026-01-15"
]
],
"expectError": "each share must be a whole number of 0 or more, received 1.5"
},
{
"name": "all-zero shares are an error",
"args": [
{
"minor": 100,
"currency": "GBP"
},
[
0,
0
],
[
"2025-10-01",
"2026-01-15"
]
],
"expectError": "shares must not all be zero"
},
{
"name": "dates out of order are an error",
"args": [
{
"minor": 100,
"currency": "GBP"
},
[
1,
1
],
[
"2026-01-15",
"2025-10-01"
]
],
"expectError": "dueDates must be in strictly ascending order: 2025-10-01 follows 2026-01-15"
},
{
"name": "two instalments on one day are an error",
"args": [
{
"minor": 100,
"currency": "GBP"
},
[
1,
1
],
[
"2025-10-01",
"2025-10-01"
]
],
"expectError": "dueDates must be in strictly ascending order"
},
{
"name": "an impossible due date is an error",
"args": [
{
"minor": 100,
"currency": "GBP"
},
[
1
],
[
"2026-02-30"
]
],
"expectError": "\"2026-02-30\" is not a real calendar date"
}
]