[ { "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\"" } ]