/** * Vela Payroll Engine — Singapore Tax Jurisdiction * * Based on IRAS Year of Assessment 2025 (income earned in 2024). * Source: https://www.iras.gov.sg/taxes/individual-income-tax/basic-individual-income-tax/individual-income-tax-rates * * IMPORTANT: Singapore does NOT use payroll withholding (PAYE). * Employees file and pay their own taxes directly to IRAS. * There is NO income tax deduction from the payslip. * * CPF (Central Provident Fund) — Mandatory savings for * Singapore Citizens and Permanent Residents. * Foreign employees (EP, S Pass) are NOT subject to CPF. * * Employee CPF Contributions (2025, age ≤ 55) * ┌─────────────────────────────┬──────────────┬────────────────┐ * │ Monthly Wages │ Employee │ Employer │ * │ │ Rate │ Rate │ * ├─────────────────────────────┼──────────────┼────────────────┤ * │ ≤ $750 │ 0% │ 0% │ * │ > $750 │ 20% │ 17% │ * └─────────────────────────────┴──────────────┴────────────────┘ * * Ordinary Wage Ceiling: $6,800/month ($81,600/year) * Additional Wage Ceiling: $102,000/year - OW for the year * (For MVP, we only handle ordinary wages / annual salary) * * Source: https://www.cpf.gov.sg/service/faq/employer/employer-contributions */ import { TaxJurisdiction, DeductionLineItem, EmployerContribution, round2, } from "../types"; const CPF_EMPLOYEE_RATE = 0.20; // 20% employee contribution const CPF_EMPLOYER_RATE = 0.17; // 17% employer contribution const CPF_OW_MONTHLY_CEILING = 6_800; const MIN_WAGE_THRESHOLD = 750; // No CPF below $750/month export interface SingaporeTaxOptions { /** Is the employee a Singapore Citizen or PR? CPF only applies if true. */ isCPRorSC?: boolean; /** Employee age group for CPF rate tiers (simplified). */ ageGroup?: "55-and-below" | "55-to-60" | "60-to-65" | "above-65"; } export class SingaporeTax implements TaxJurisdiction { readonly name = "Singapore"; readonly countryCode = "SG"; readonly currency = "SGD"; private isCPRorSC: boolean; constructor(options?: SingaporeTaxOptions) { this.isCPRorSC = options?.isCPRorSC ?? true; } calculate(grossAnnual: number): { deductions: DeductionLineItem[]; employerContributions: EmployerContribution[]; } { const monthlyWage = grossAnnual / 12; // Singapore has NO payroll withholding — income tax is self-filed // So there are NO tax deductions from the payslip let employeeCPF = 0; let employerCPF = 0; if (this.isCPRorSC && monthlyWage > MIN_WAGE_THRESHOLD) { // CPF is calculated on wages up to the OW ceiling const cpfWage = Math.min(monthlyWage, CPF_OW_MONTHLY_CEILING); employeeCPF = cpfWage * CPF_EMPLOYEE_RATE; employerCPF = cpfWage * CPF_EMPLOYER_RATE; // Annualise employeeCPF = round2(employeeCPF * 12); employerCPF = round2(employerCPF * 12); } const deductions: DeductionLineItem[] = []; const employerContributions: EmployerContribution[] = []; if (employeeCPF > 0) { deductions.push({ name: "CPF (Employee)", amount: employeeCPF, type: "pension", description: `Central Provident Fund — 20% employee contribution`, }); } if (employerCPF > 0) { employerContributions.push({ name: "CPF (Employer)", amount: employerCPF, description: "Central Provident Fund — 17% employer contribution", }); } // Note: Income tax is self-filed, not deducted at source if (this.isCPRorSC) { deductions.push({ name: "Income Tax", amount: 0, type: "tax", description: "Self-filed directly with IRAS — not deducted from payslip", }); } return { deductions, employerContributions }; } }