Functional Weave
Code in Rust

payroll.national-insurance@1.0.0

vectors.json

10,171 bytes · view raw

[
 {
  "name": "category A, monthly, 2026-27: 8% over the primary threshold, 15% over the secondary",
  "args": [
   {
    "minor": 300000,
    "currency": "GBP"
   },
   "A",
   "monthly",
   "2026-05-28",
   null
  ],
  "expect": {
   "employee": {
    "minor": 15616,
    "currency": "GBP"
   },
   "employer": {
    "minor": 38745,
    "currency": "GBP"
   },
   "lowerEarningsLimitReached": true
  }
 },
 {
  "name": "above the UEL: exact method gives 277.17 and 759.94 where HMRC's printed tables give 277.16 and 759.90",
  "args": [
   {
    "minor": 548329,
    "currency": "GBP"
   },
   "A",
   "monthly",
   "2025-06-27",
   null
  ],
  "expect": {
   "employee": {
    "minor": 27717,
    "currency": "GBP"
   },
   "employer": {
    "minor": 75994,
    "currency": "GBP"
   },
   "lowerEarningsLimitReached": true
  }
 },
 {
  "name": "a half penny rounds up, once, on the total: 251.285 becomes 251.29",
  "args": [
   {
    "minor": 418925,
    "currency": "GBP"
   },
   "A",
   "monthly",
   "2026-06-26",
   null
  ],
  "expect": {
   "employee": {
    "minor": 25129,
    "currency": "GBP"
   },
   "employer": {
    "minor": 56584,
    "currency": "GBP"
   },
   "lowerEarningsLimitReached": true
  }
 },
 {
  "name": "below the lower earnings limit: no employee NI, but employer NI above the \u00a396 secondary threshold",
  "args": [
   {
    "minor": 10000,
    "currency": "GBP"
   },
   "A",
   "weekly",
   "2026-06-05",
   null
  ],
  "expect": {
   "employee": {
    "minor": 0,
    "currency": "GBP"
   },
   "employer": {
    "minor": 60,
    "currency": "GBP"
   },
   "lowerEarningsLimitReached": false
  }
 },
 {
  "name": "exactly the lower earnings limit counts as reaching it",
  "args": [
   {
    "minor": 12900,
    "currency": "GBP"
   },
   "A",
   "weekly",
   "2026-06-05",
   null
  ],
  "expect": {
   "employee": {
    "minor": 0,
    "currency": "GBP"
   },
   "employer": {
    "minor": 495,
    "currency": "GBP"
   },
   "lowerEarningsLimitReached": true
  }
 },
 {
  "name": "fortnightly uses twice the weekly thresholds",
  "args": [
   {
    "minor": 100000,
    "currency": "GBP"
   },
   "A",
   "fortnightly",
   "2026-06-05",
   null
  ],
  "expect": {
   "employee": {
    "minor": 4128,
    "currency": "GBP"
   },
   "employer": {
    "minor": 12120,
    "currency": "GBP"
   },
   "lowerEarningsLimitReached": true
  }
 },
 {
  "name": "four-weekly uses four times the weekly thresholds",
  "args": [
   {
    "minor": 200000,
    "currency": "GBP"
   },
   "A",
   "four-weekly",
   "2026-06-05",
   null
  ],
  "expect": {
   "employee": {
    "minor": 8256,
    "currency": "GBP"
   },
   "employer": {
    "minor": 24240,
    "currency": "GBP"
   },
   "lowerEarningsLimitReached": true
  }
 },
 {
  "name": "category B married women's reduced rate 1.85%",
  "args": [
   {
    "minor": 200000,
    "currency": "GBP"
   },
   "B",
   "monthly",
   "2026-07-28",
   null
  ],
  "expect": {
   "employee": {
    "minor": 1761,
    "currency": "GBP"
   },
   "employer": {
    "minor": 23745,
    "currency": "GBP"
   },
   "lowerEarningsLimitReached": true
  }
 },
 {
  "name": "category C over State Pension age: no employee NI, employer still pays",
  "args": [
   {
    "minor": 50000,
    "currency": "GBP"
   },
   "C",
   "weekly",
   "2026-07-03",
   null
  ],
  "expect": {
   "employee": {
    "minor": 0,
    "currency": "GBP"
   },
   "employer": {
    "minor": 6060,
    "currency": "GBP"
   },
   "lowerEarningsLimitReached": true
  }
 },
 {
  "name": "category M under 21: employer pays only above the upper secondary threshold",
  "args": [
   {
    "minor": 500000,
    "currency": "GBP"
   },
   "M",
   "monthly",
   "2026-07-28",
   null
  ],
  "expect": {
   "employee": {
    "minor": 26750,
    "currency": "GBP"
   },
   "employer": {
    "minor": 12165,
    "currency": "GBP"
   },
   "lowerEarningsLimitReached": true
  }
 },
 {
  "name": "category F freeport: employer pays only above the \u00a325,000 freeport threshold",
  "args": [
   {
    "minor": 300000,
    "currency": "GBP"
   },
   "F",
   "monthly",
   "2026-07-28",
   null
  ],
  "expect": {
   "employee": {
    "minor": 15616,
    "currency": "GBP"
   },
   "employer": {
    "minor": 13755,
    "currency": "GBP"
   },
   "lowerEarningsLimitReached": true
  }
 },
 {
  "name": "category H apprentice under 25 in 2024-25: no employer NI below the upper secondary threshold",
  "args": [
   {
    "minor": 60000,
    "currency": "GBP"
   },
   "H",
   "weekly",
   "2024-10-04",
   null
  ],
  "expect": {
   "employee": {
    "minor": 2864,
    "currency": "GBP"
   },
   "employer": {
    "minor": 0,
    "currency": "GBP"
   },
   "lowerEarningsLimitReached": true
  }
 },
 {
  "name": "category J deferment in 2025-26: 2% main rate",
  "args": [
   {
    "minor": 50000,
    "currency": "GBP"
   },
   "J",
   "weekly",
   "2025-07-04",
   null
  ],
  "expect": {
   "employee": {
    "minor": 516,
    "currency": "GBP"
   },
   "employer": {
    "minor": 6060,
    "currency": "GBP"
   },
   "lowerEarningsLimitReached": true
  }
 },
 {
  "name": "category Z in 2025-26: 2% employee, no employer NI below the UST",
  "args": [
   {
    "minor": 300000,
    "currency": "GBP"
   },
   "Z",
   "monthly",
   "2025-07-28",
   null
  ],
  "expect": {
   "employee": {
    "minor": 3904,
    "currency": "GBP"
   },
   "employer": {
    "minor": 0,
    "currency": "GBP"
   },
   "lowerEarningsLimitReached": true
  }
 },
 {
  "name": "2024-25: 8% employee, 13.8% employer over a \u00a3758 monthly secondary threshold",
  "args": [
   {
    "minor": 250000,
    "currency": "GBP"
   },
   "A",
   "monthly",
   "2024-07-26",
   null
  ],
  "expect": {
   "employee": {
    "minor": 11616,
    "currency": "GBP"
   },
   "employer": {
    "minor": 24040,
    "currency": "GBP"
   },
   "lowerEarningsLimitReached": true
  }
 },
 {
  "name": "2023-24 before 6 January 2024: 12% main rate",
  "args": [
   {
    "minor": 250000,
    "currency": "GBP"
   },
   "A",
   "monthly",
   "2023-12-28",
   null
  ],
  "expect": {
   "employee": {
    "minor": 17424,
    "currency": "GBP"
   },
   "employer": {
    "minor": 24040,
    "currency": "GBP"
   },
   "lowerEarningsLimitReached": true
  }
 },
 {
  "name": "2023-24 from 6 January 2024: 10% main rate",
  "args": [
   {
    "minor": 250000,
    "currency": "GBP"
   },
   "A",
   "monthly",
   "2024-01-26",
   null
  ],
  "expect": {
   "employee": {
    "minor": 14520,
    "currency": "GBP"
   },
   "employer": {
    "minor": 24040,
    "currency": "GBP"
   },
   "lowerEarningsLimitReached": true
  }
 },
 {
  "name": "the day the 2023-24 main rate fell: 10% to the weekly UEL, 2% above it",
  "args": [
   {
    "minor": 100000,
    "currency": "GBP"
   },
   "A",
   "weekly",
   "2024-01-06",
   null
  ],
  "expect": {
   "employee": {
    "minor": 7316,
    "currency": "GBP"
   },
   "employer": {
    "minor": 11385,
    "currency": "GBP"
   },
   "lowerEarningsLimitReached": true
  }
 },
 {
  "name": "director annual method 2026-27: NI on the year to date less what was already paid",
  "args": [
   {
    "minor": 2000000,
    "currency": "GBP"
   },
   "A",
   "monthly",
   "2026-09-30",
   {
    "previousEarnings": {
     "minor": 1000000,
     "currency": "GBP"
    },
    "previousEmployee": {
     "minor": 0,
     "currency": "GBP"
    },
    "previousEmployer": {
     "minor": 75000,
     "currency": "GBP"
    }
   }
  ],
  "expect": {
   "employee": {
    "minor": 139440,
    "currency": "GBP"
   },
   "employer": {
    "minor": 300000,
    "currency": "GBP"
   },
   "lowerEarningsLimitReached": true
  }
 },
 {
  "name": "director annual method 2023-24 uses the whole-year 11.5% rate",
  "args": [
   {
    "minor": 6000000,
    "currency": "GBP"
   },
   "A",
   "monthly",
   "2023-06-30",
   {
    "previousEarnings": {
     "minor": 0,
     "currency": "GBP"
    },
    "previousEmployee": {
     "minor": 0,
     "currency": "GBP"
    },
    "previousEmployer": {
     "minor": 0,
     "currency": "GBP"
    }
   }
  ],
  "expect": {
   "employee": {
    "minor": 453010,
    "currency": "GBP"
   },
   "employer": {
    "minor": 702420,
    "currency": "GBP"
   },
   "lowerEarningsLimitReached": true
  }
 },
 {
  "name": "director below the annual thresholds pays nothing yet",
  "args": [
   {
    "minor": 500000,
    "currency": "GBP"
   },
   "A",
   "monthly",
   "2026-05-28",
   {
    "previousEarnings": {
     "minor": 0,
     "currency": "GBP"
    },
    "previousEmployee": {
     "minor": 0,
     "currency": "GBP"
    },
    "previousEmployer": {
     "minor": 0,
     "currency": "GBP"
    }
   }
  ],
  "expect": {
   "employee": {
    "minor": 0,
    "currency": "GBP"
   },
   "employer": {
    "minor": 0,
    "currency": "GBP"
   },
   "lowerEarningsLimitReached": false
  }
 },
 {
  "name": "category N did not exist in 2023-24",
  "args": [
   {
    "minor": 250000,
    "currency": "GBP"
   },
   "N",
   "monthly",
   "2023-12-28",
   null
  ],
  "expectError": "no National Insurance rates for category N"
 },
 {
  "name": "an unknown category letter is an error",
  "args": [
   {
    "minor": 250000,
    "currency": "GBP"
   },
   "Q",
   "monthly",
   "2026-05-28",
   null
  ],
  "expectError": "no National Insurance rates for category Q"
 },
 {
  "name": "a date before the rules this package carries",
  "args": [
   {
    "minor": 250000,
    "currency": "GBP"
   },
   "A",
   "monthly",
   "2023-04-05",
   null
  ],
  "expectError": "no National Insurance thresholds"
 },
 {
  "name": "negative earnings are refused",
  "args": [
   {
    "minor": -100,
    "currency": "GBP"
   },
   "A",
   "monthly",
   "2026-05-28",
   null
  ],
  "expectError": "earnings must not be negative"
 },
 {
  "name": "another currency is refused",
  "args": [
   {
    "minor": 100,
    "currency": "EUR"
   },
   "A",
   "monthly",
   "2026-05-28",
   null
  ],
  "expectError": "must be in GBP"
 },
 {
  "name": "an unknown frequency is refused",
  "args": [
   {
    "minor": 100,
    "currency": "GBP"
   },
   "A",
   "daily",
   "2026-05-28",
   null
  ],
  "expectError": "unknown pay frequency"
 }
]