[
{
"name": "1,000.00 with 400.00 of materials at the standard rate: 20% of the 600.00 labour only",
"args": [
{
"minor": 100000,
"currency": "GBP"
},
{
"minor": 40000,
"currency": "GBP"
},
"standard",
"2026-09-23",
"down"
],
"expect": {
"payment": {
"minor": 100000,
"currency": "GBP"
},
"materials": {
"minor": 40000,
"currency": "GBP"
},
"labour": {
"minor": 60000,
"currency": "GBP"
},
"basisPoints": 2000,
"deduction": {
"minor": 12000,
"currency": "GBP"
},
"netPayment": {
"minor": 88000,
"currency": "GBP"
}
}
},
{
"name": "the same payment to an unmatched subcontractor: 30% of the labour",
"args": [
{
"minor": 100000,
"currency": "GBP"
},
{
"minor": 40000,
"currency": "GBP"
},
"higher",
"2026-09-23",
"down"
],
"expect": {
"payment": {
"minor": 100000,
"currency": "GBP"
},
"materials": {
"minor": 40000,
"currency": "GBP"
},
"labour": {
"minor": 60000,
"currency": "GBP"
},
"basisPoints": 3000,
"deduction": {
"minor": 18000,
"currency": "GBP"
},
"netPayment": {
"minor": 82000,
"currency": "GBP"
}
}
},
{
"name": "gross payment status: nothing withheld",
"args": [
{
"minor": 100000,
"currency": "GBP"
},
{
"minor": 40000,
"currency": "GBP"
},
"gross",
"2026-09-23",
"down"
],
"expect": {
"payment": {
"minor": 100000,
"currency": "GBP"
},
"materials": {
"minor": 40000,
"currency": "GBP"
},
"labour": {
"minor": 60000,
"currency": "GBP"
},
"basisPoints": 0,
"deduction": {
"minor": 0,
"currency": "GBP"
},
"netPayment": {
"minor": 100000,
"currency": "GBP"
}
}
},
{
"name": "labour only: 20% of 2,500.00",
"args": [
{
"minor": 250000,
"currency": "GBP"
},
{
"minor": 0,
"currency": "GBP"
},
"standard",
"2026-09-23",
"down"
],
"expect": {
"payment": {
"minor": 250000,
"currency": "GBP"
},
"materials": {
"minor": 0,
"currency": "GBP"
},
"labour": {
"minor": 250000,
"currency": "GBP"
},
"basisPoints": 2000,
"deduction": {
"minor": 50000,
"currency": "GBP"
},
"netPayment": {
"minor": 200000,
"currency": "GBP"
}
}
},
{
"name": "not 20% of the whole invoice: 1,500.00 with 900.00 materials withholds 120.00, not 300.00",
"args": [
{
"minor": 150000,
"currency": "GBP"
},
{
"minor": 90000,
"currency": "GBP"
},
"standard",
"2026-09-23",
"half-up"
],
"expect": {
"payment": {
"minor": 150000,
"currency": "GBP"
},
"materials": {
"minor": 90000,
"currency": "GBP"
},
"labour": {
"minor": 60000,
"currency": "GBP"
},
"basisPoints": 2000,
"deduction": {
"minor": 12000,
"currency": "GBP"
},
"netPayment": {
"minor": 138000,
"currency": "GBP"
}
}
},
{
"name": "123.48 at 20% is 24.696: down gives 24.69",
"args": [
{
"minor": 12348,
"currency": "GBP"
},
{
"minor": 0,
"currency": "GBP"
},
"standard",
"2026-09-23",
"down"
],
"expect": {
"payment": {
"minor": 12348,
"currency": "GBP"
},
"materials": {
"minor": 0,
"currency": "GBP"
},
"labour": {
"minor": 12348,
"currency": "GBP"
},
"basisPoints": 2000,
"deduction": {
"minor": 2469,
"currency": "GBP"
},
"netPayment": {
"minor": 9879,
"currency": "GBP"
}
}
},
{
"name": "123.48 at 20% is 24.696: half-up gives 24.70",
"args": [
{
"minor": 12348,
"currency": "GBP"
},
{
"minor": 0,
"currency": "GBP"
},
"standard",
"2026-09-23",
"half-up"
],
"expect": {
"payment": {
"minor": 12348,
"currency": "GBP"
},
"materials": {
"minor": 0,
"currency": "GBP"
},
"labour": {
"minor": 12348,
"currency": "GBP"
},
"basisPoints": 2000,
"deduction": {
"minor": 2470,
"currency": "GBP"
},
"netPayment": {
"minor": 9878,
"currency": "GBP"
}
}
},
{
"name": "100.01 at 30% is 30.003: up gives 30.01",
"args": [
{
"minor": 10001,
"currency": "GBP"
},
{
"minor": 0,
"currency": "GBP"
},
"higher",
"2026-09-23",
"up"
],
"expect": {
"payment": {
"minor": 10001,
"currency": "GBP"
},
"materials": {
"minor": 0,
"currency": "GBP"
},
"labour": {
"minor": 10001,
"currency": "GBP"
},
"basisPoints": 3000,
"deduction": {
"minor": 3001,
"currency": "GBP"
},
"netPayment": {
"minor": 7000,
"currency": "GBP"
}
}
},
{
"name": "all materials: no labour, no deduction",
"args": [
{
"minor": 50000,
"currency": "GBP"
},
{
"minor": 50000,
"currency": "GBP"
},
"standard",
"2026-09-23",
"down"
],
"expect": {
"payment": {
"minor": 50000,
"currency": "GBP"
},
"materials": {
"minor": 50000,
"currency": "GBP"
},
"labour": {
"minor": 0,
"currency": "GBP"
},
"basisPoints": 2000,
"deduction": {
"minor": 0,
"currency": "GBP"
},
"netPayment": {
"minor": 50000,
"currency": "GBP"
}
}
},
{
"name": "zero payment",
"args": [
{
"minor": 0,
"currency": "GBP"
},
{
"minor": 0,
"currency": "GBP"
},
"higher",
"2026-09-23",
"down"
],
"expect": {
"payment": {
"minor": 0,
"currency": "GBP"
},
"materials": {
"minor": 0,
"currency": "GBP"
},
"labour": {
"minor": 0,
"currency": "GBP"
},
"basisPoints": 3000,
"deduction": {
"minor": 0,
"currency": "GBP"
},
"netPayment": {
"minor": 0,
"currency": "GBP"
}
}
},
{
"name": "the first day of the 2007 scheme: 20%",
"args": [
{
"minor": 100000,
"currency": "GBP"
},
{
"minor": 0,
"currency": "GBP"
},
"standard",
"2007-04-06",
"down"
],
"expect": {
"payment": {
"minor": 100000,
"currency": "GBP"
},
"materials": {
"minor": 0,
"currency": "GBP"
},
"labour": {
"minor": 100000,
"currency": "GBP"
},
"basisPoints": 2000,
"deduction": {
"minor": 20000,
"currency": "GBP"
},
"netPayment": {
"minor": 80000,
"currency": "GBP"
}
}
},
{
"name": "the last day of the old scheme: 18% for a CIS4 card holder",
"args": [
{
"minor": 100000,
"currency": "GBP"
},
{
"minor": 0,
"currency": "GBP"
},
"standard",
"2007-04-05",
"down"
],
"expect": {
"payment": {
"minor": 100000,
"currency": "GBP"
},
"materials": {
"minor": 0,
"currency": "GBP"
},
"labour": {
"minor": 100000,
"currency": "GBP"
},
"basisPoints": 1800,
"deduction": {
"minor": 18000,
"currency": "GBP"
},
"netPayment": {
"minor": 82000,
"currency": "GBP"
}
}
},
{
"name": "a 2003 payment to a CIS6 certificate holder: gross",
"args": [
{
"minor": 100000,
"currency": "GBP"
},
{
"minor": 0,
"currency": "GBP"
},
"gross",
"2003-01-15",
"down"
],
"expect": {
"payment": {
"minor": 100000,
"currency": "GBP"
},
"materials": {
"minor": 0,
"currency": "GBP"
},
"labour": {
"minor": 100000,
"currency": "GBP"
},
"basisPoints": 0,
"deduction": {
"minor": 0,
"currency": "GBP"
},
"netPayment": {
"minor": 100000,
"currency": "GBP"
}
}
},
{
"name": "there was no higher rate before 6 April 2007",
"args": [
{
"minor": 100000,
"currency": "GBP"
},
{
"minor": 0,
"currency": "GBP"
},
"higher",
"2006-06-01",
"down"
],
"expectError": "no CIS rate for higher on 2006-06-01"
},
{
"name": "before the 2000 rates this registry carries",
"args": [
{
"minor": 100000,
"currency": "GBP"
},
{
"minor": 0,
"currency": "GBP"
},
"standard",
"1999-12-31",
"down"
],
"expectError": "no CIS rate for standard on 1999-12-31"
},
{
"name": "materials above the payment",
"args": [
{
"minor": 10000,
"currency": "GBP"
},
{
"minor": 10001,
"currency": "GBP"
},
"standard",
"2026-09-23",
"down"
],
"expectError": "materials (10001) cannot exceed the payment (10000)"
},
{
"name": "a negative payment",
"args": [
{
"minor": -100,
"currency": "GBP"
},
{
"minor": 0,
"currency": "GBP"
},
"standard",
"2026-09-23",
"down"
],
"expectError": "payment must not be negative"
},
{
"name": "negative materials",
"args": [
{
"minor": 100,
"currency": "GBP"
},
{
"minor": -1,
"currency": "GBP"
},
"standard",
"2026-09-23",
"down"
],
"expectError": "materials must not be negative"
},
{
"name": "payment and materials in different currencies",
"args": [
{
"minor": 100,
"currency": "GBP"
},
{
"minor": 10,
"currency": "EUR"
},
"standard",
"2026-09-23",
"down"
],
"expectError": "currency mismatch"
},
{
"name": "a date that is not ISO",
"args": [
{
"minor": 100,
"currency": "GBP"
},
{
"minor": 0,
"currency": "GBP"
},
"standard",
"23/09/2026",
"down"
],
"expectError": "onDate must be an ISO date"
},
{
"name": "an unknown status",
"args": [
{
"minor": 100,
"currency": "GBP"
},
{
"minor": 0,
"currency": "GBP"
},
"registered",
"2026-09-23",
"down"
],
"expectError": "unknown CIS status \"registered\""
},
{
"name": "an unknown rounding mode",
"args": [
{
"minor": 12348,
"currency": "GBP"
},
{
"minor": 0,
"currency": "GBP"
},
"standard",
"2026-09-23",
"nearest"
],
"expectError": "unknown rounding mode \"nearest\""
},
{
"name": "a trailing newline after onDate is not an ISO date",
"args": [
{
"minor": 100,
"currency": "GBP"
},
{
"minor": 0,
"currency": "GBP"
},
"standard",
"2026-09-16\n",
"down"
],
"expectError": "onDate must be an ISO date"
},
{
"name": "Arabic-Indic digits in onDate are not an ISO date",
"args": [
{
"minor": 100,
"currency": "GBP"
},
{
"minor": 0,
"currency": "GBP"
},
"standard",
"٢٠٢٦-09-16",
"down"
],
"expectError": "onDate must be an ISO date"
}
]