Functional Weave
Code in Rust

education.student-loan-repayment@1.0.0

vectors.json

11,335 bytes · view raw

[
 {
  "name": "GOV.UK's example: plan 1 on \u00a342,000 in 2026/27 repays \u00a31,359",
  "args": [
   {
    "minor": 4200000,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   "plan-1",
   "2026-07-01",
   {
    "minor": 0,
    "currency": "GBP"
   }
  ],
  "expect": {
   "taxYear": "2026/27",
   "threshold": {
    "minor": 2690000,
    "currency": "GBP"
   },
   "basisPoints": 900,
   "countedIncome": {
    "minor": 4200000,
    "currency": "GBP"
   },
   "repayment": {
    "minor": 135900,
    "currency": "GBP"
   },
   "deductedThroughPaye": {
    "minor": 0,
    "currency": "GBP"
   },
   "balance": {
    "minor": 135900,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "the same, with \u00a31,200 already deducted through PAYE: \u00a3159 left to pay",
  "args": [
   {
    "minor": 4200000,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   "plan-1",
   "2026-07-01",
   {
    "minor": 120000,
    "currency": "GBP"
   }
  ],
  "expect": {
   "taxYear": "2026/27",
   "threshold": {
    "minor": 2690000,
    "currency": "GBP"
   },
   "basisPoints": 900,
   "countedIncome": {
    "minor": 4200000,
    "currency": "GBP"
   },
   "repayment": {
    "minor": 135900,
    "currency": "GBP"
   },
   "deductedThroughPaye": {
    "minor": 120000,
    "currency": "GBP"
   },
   "balance": {
    "minor": 15900,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "postgraduate loan: 6% over \u00a321,000",
  "args": [
   {
    "minor": 3000000,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   "postgraduate",
   "2026-07-01",
   {
    "minor": 0,
    "currency": "GBP"
   }
  ],
  "expect": {
   "taxYear": "2026/27",
   "threshold": {
    "minor": 2100000,
    "currency": "GBP"
   },
   "basisPoints": 600,
   "countedIncome": {
    "minor": 3000000,
    "currency": "GBP"
   },
   "repayment": {
    "minor": 54000,
    "currency": "GBP"
   },
   "deductedThroughPaye": {
    "minor": 0,
    "currency": "GBP"
   },
   "balance": {
    "minor": 54000,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "pence are dropped: plan 1 2025/26 on \u00a330,000 is \u00a3354.15, so \u00a3354",
  "args": [
   {
    "minor": 3000000,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   "plan-1",
   "2025-10-01",
   {
    "minor": 0,
    "currency": "GBP"
   }
  ],
  "expect": {
   "taxYear": "2025/26",
   "threshold": {
    "minor": 2606500,
    "currency": "GBP"
   },
   "basisPoints": 900,
   "countedIncome": {
    "minor": 3000000,
    "currency": "GBP"
   },
   "repayment": {
    "minor": 35400,
    "currency": "GBP"
   },
   "deductedThroughPaye": {
    "minor": 0,
    "currency": "GBP"
   },
   "balance": {
    "minor": 35400,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "unearned income of exactly \u00a32,000 is left out",
  "args": [
   {
    "minor": 3000000,
    "currency": "GBP"
   },
   {
    "minor": 200000,
    "currency": "GBP"
   },
   "plan-2",
   "2025-10-01",
   {
    "minor": 0,
    "currency": "GBP"
   }
  ],
  "expect": {
   "taxYear": "2025/26",
   "threshold": {
    "minor": 2847000,
    "currency": "GBP"
   },
   "basisPoints": 900,
   "countedIncome": {
    "minor": 3000000,
    "currency": "GBP"
   },
   "repayment": {
    "minor": 13700,
    "currency": "GBP"
   },
   "deductedThroughPaye": {
    "minor": 0,
    "currency": "GBP"
   },
   "balance": {
    "minor": 13700,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "a penny more and all of it counts",
  "args": [
   {
    "minor": 3000000,
    "currency": "GBP"
   },
   {
    "minor": 200001,
    "currency": "GBP"
   },
   "plan-2",
   "2025-10-01",
   {
    "minor": 0,
    "currency": "GBP"
   }
  ],
  "expect": {
   "taxYear": "2025/26",
   "threshold": {
    "minor": 2847000,
    "currency": "GBP"
   },
   "basisPoints": 900,
   "countedIncome": {
    "minor": 3200001,
    "currency": "GBP"
   },
   "repayment": {
    "minor": 31700,
    "currency": "GBP"
   },
   "deductedThroughPaye": {
    "minor": 0,
    "currency": "GBP"
   },
   "balance": {
    "minor": 31700,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "income below the threshold repays nothing, and PAYE deductions are owed back",
  "args": [
   {
    "minor": 2000000,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   "plan-2",
   "2025-10-01",
   {
    "minor": 5000,
    "currency": "GBP"
   }
  ],
  "expect": {
   "taxYear": "2025/26",
   "threshold": {
    "minor": 2847000,
    "currency": "GBP"
   },
   "basisPoints": 900,
   "countedIncome": {
    "minor": 2000000,
    "currency": "GBP"
   },
   "repayment": {
    "minor": 0,
    "currency": "GBP"
   },
   "deductedThroughPaye": {
    "minor": 5000,
    "currency": "GBP"
   },
   "balance": {
    "minor": -5000,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "income exactly at the threshold repays nothing",
  "args": [
   {
    "minor": 2847000,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   "plan-2",
   "2025-10-01",
   {
    "minor": 0,
    "currency": "GBP"
   }
  ],
  "expect": {
   "taxYear": "2025/26",
   "threshold": {
    "minor": 2847000,
    "currency": "GBP"
   },
   "basisPoints": 900,
   "countedIncome": {
    "minor": 2847000,
    "currency": "GBP"
   },
   "repayment": {
    "minor": 0,
    "currency": "GBP"
   },
   "deductedThroughPaye": {
    "minor": 0,
    "currency": "GBP"
   },
   "balance": {
    "minor": 0,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "plan 5 from 2026/27",
  "args": [
   {
    "minor": 3500000,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   "plan-5",
   "2026-12-31",
   {
    "minor": 0,
    "currency": "GBP"
   }
  ],
  "expect": {
   "taxYear": "2026/27",
   "threshold": {
    "minor": 2500000,
    "currency": "GBP"
   },
   "basisPoints": 900,
   "countedIncome": {
    "minor": 3500000,
    "currency": "GBP"
   },
   "repayment": {
    "minor": 90000,
    "currency": "GBP"
   },
   "deductedThroughPaye": {
    "minor": 0,
    "currency": "GBP"
   },
   "balance": {
    "minor": 90000,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "5 April 2026 is still 2025/26: plan 4 at \u00a332,745",
  "args": [
   {
    "minor": 4000000,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   "plan-4",
   "2026-04-05",
   {
    "minor": 0,
    "currency": "GBP"
   }
  ],
  "expect": {
   "taxYear": "2025/26",
   "threshold": {
    "minor": 3274500,
    "currency": "GBP"
   },
   "basisPoints": 900,
   "countedIncome": {
    "minor": 4000000,
    "currency": "GBP"
   },
   "repayment": {
    "minor": 65200,
    "currency": "GBP"
   },
   "deductedThroughPaye": {
    "minor": 0,
    "currency": "GBP"
   },
   "balance": {
    "minor": 65200,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "6 April 2026 is 2026/27: plan 4 at \u00a333,795",
  "args": [
   {
    "minor": 4000000,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   "plan-4",
   "2026-04-06",
   {
    "minor": 0,
    "currency": "GBP"
   }
  ],
  "expect": {
   "taxYear": "2026/27",
   "threshold": {
    "minor": 3379500,
    "currency": "GBP"
   },
   "basisPoints": 900,
   "countedIncome": {
    "minor": 4000000,
    "currency": "GBP"
   },
   "repayment": {
    "minor": 55800,
    "currency": "GBP"
   },
   "deductedThroughPaye": {
    "minor": 0,
    "currency": "GBP"
   },
   "balance": {
    "minor": 55800,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "2023/24, plan 2 at \u00a327,295",
  "args": [
   {
    "minor": 5000000,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   "plan-2",
   "2023-06-01",
   {
    "minor": 0,
    "currency": "GBP"
   }
  ],
  "expect": {
   "taxYear": "2023/24",
   "threshold": {
    "minor": 2729500,
    "currency": "GBP"
   },
   "basisPoints": 900,
   "countedIncome": {
    "minor": 5000000,
    "currency": "GBP"
   },
   "repayment": {
    "minor": 204300,
    "currency": "GBP"
   },
   "deductedThroughPaye": {
    "minor": 0,
    "currency": "GBP"
   },
   "balance": {
    "minor": 204300,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "no income at all",
  "args": [
   {
    "minor": 0,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   "plan-1",
   "2026-07-01",
   {
    "minor": 0,
    "currency": "GBP"
   }
  ],
  "expect": {
   "taxYear": "2026/27",
   "threshold": {
    "minor": 2690000,
    "currency": "GBP"
   },
   "basisPoints": 900,
   "countedIncome": {
    "minor": 0,
    "currency": "GBP"
   },
   "repayment": {
    "minor": 0,
    "currency": "GBP"
   },
   "deductedThroughPaye": {
    "minor": 0,
    "currency": "GBP"
   },
   "balance": {
    "minor": 0,
    "currency": "GBP"
   }
  }
 },
 {
  "name": "plan 5 before 2026/27 is an error",
  "args": [
   {
    "minor": 3500000,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   "plan-5",
   "2025-10-01",
   {
    "minor": 0,
    "currency": "GBP"
   }
  ],
  "expectError": "no student loan threshold for plan-5 in tax year 2025/26"
 },
 {
  "name": "a tax year before the data is an error",
  "args": [
   {
    "minor": 3500000,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   "plan-1",
   "2022-10-01",
   {
    "minor": 0,
    "currency": "GBP"
   }
  ],
  "expectError": "no student loan threshold for plan-1 in tax year 2022/23"
 },
 {
  "name": "an unknown plan is an error",
  "args": [
   {
    "minor": 3500000,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   "plan-3",
   "2025-10-01",
   {
    "minor": 0,
    "currency": "GBP"
   }
  ],
  "expectError": "unknown student loan plan \"plan-3\""
 },
 {
  "name": "income in euros is an error",
  "args": [
   {
    "minor": 3500000,
    "currency": "EUR"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   "plan-1",
   "2025-10-01",
   {
    "minor": 0,
    "currency": "GBP"
   }
  ],
  "expectError": "earnedIncome must be in GBP, received EUR"
 },
 {
  "name": "negative earned income is an error",
  "args": [
   {
    "minor": -1,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   "plan-1",
   "2025-10-01",
   {
    "minor": 0,
    "currency": "GBP"
   }
  ],
  "expectError": "earnedIncome must not be negative, received -1"
 },
 {
  "name": "negative unearned income is an error",
  "args": [
   {
    "minor": 0,
    "currency": "GBP"
   },
   {
    "minor": -1,
    "currency": "GBP"
   },
   "plan-1",
   "2025-10-01",
   {
    "minor": 0,
    "currency": "GBP"
   }
  ],
  "expectError": "unearnedIncome must not be negative, received -1"
 },
 {
  "name": "a negative PAYE deduction is an error",
  "args": [
   {
    "minor": 0,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   "plan-1",
   "2025-10-01",
   {
    "minor": -1,
    "currency": "GBP"
   }
  ],
  "expectError": "deductedThroughPaye must not be negative, received -1"
 },
 {
  "name": "an impossible date is an error",
  "args": [
   {
    "minor": 0,
    "currency": "GBP"
   },
   {
    "minor": 0,
    "currency": "GBP"
   },
   "plan-1",
   "2025-02-30",
   {
    "minor": 0,
    "currency": "GBP"
   }
  ],
  "expectError": "\"2025-02-30\" is not a real calendar date"
 }
]