Portuguese salary calculator library
npm install saldoA comprehensive TypeScript library for calculating Portuguese taxes for both dependent (category A/H) and independent (category B) workers.
saldo provides accurate calculations for Portuguese income tax and social security:
- Dependent workers: official 2025 retention tables (continent, Azores, Madeira), lunch allowances, and holiday bonus twelfths.
- Independent workers: simplified regime calculations with youth IRS benefits, RNH flat rate, expense caps, social security caps/discounts, and first/second year rules.
- ๐ Dependent worker calculations: 2025 IRS retention tables with regional coverage and twelfths/holiday handling
- ๐ฝ๏ธ Allowances: Meal vouchers vs. cash allowances with the correct taxable/tax-free split
- ๐งฎ Independent worker simulator: Simplified regime with expense caps, specific deductions, and 248 business-day calendar
- ๐ง Youth IRS + RNH: Year-capped youth IRS discounts (per IAS limits) and RNH flat-rate option
- ๐ก๏ธ Social security: Rate overrides, discounts, caps (12ร IAS), and first-12-month exemption for new activities
- ๐ Validation: Detailed input validation errors for misconfigured scenarios
``bash`
pnpm add saldoor
npm install saldoor
yarn add saldo
`typescript
import {
simulateDependentWorker,
simulateIndependentWorker,
Twelfths,
FrequencyChoices,
} from 'saldo';
// Dependent worker (monthly income)
const dependent = simulateDependentWorker({
income: 1500,
twelfths: Twelfths.TWO_MONTHS,
location: 'continent',
});
console.log(Dependent Net Salary: โฌ${dependent.netSalary.toFixed(2)});
// Independent worker (annual income, simplified regime)
const independent = simulateIndependentWorker({
income: 30000,
incomeFrequency: FrequencyChoices.Year,
expenses: 2500,
benefitsOfYouthIrs: true,
yearOfYouthIrs: 1,
});
console.log(Independent Net Income (year): โฌ${independent.netIncome.year.toFixed(2)});`
`typescript
// Married household with dependents
const married = simulateDependentWorker({
income: 2500,
married: true,
numberOfHolders: 2,
numberOfDependents: 2,
location: "continent",
});
// Worker with disability and meal vouchers
const disabled = simulateDependentWorker({
income: 1800,
disabled: true,
partnerDisabled: true,
married: true,
numberOfHolders: 1,
lunchAllowanceDailyValue: 8.5,
lunchAllowanceMode: "salary",
});
// Azores with twelfths distributed
const azores = simulateDependentWorker({
income: 1600,
location: "azores",
twelfths: Twelfths.TWO_MONTHS,
period: "2025-01-01_2025-07-31",
});
`
`typescript
import { FrequencyChoices } from "saldo";
// Monthly freelancer with days off and simplified regime
const freelancer = simulateIndependentWorker({
income: 2500,
incomeFrequency: FrequencyChoices.Month,
nrDaysOff: 25, // yearly days off
expenses: 1800, // declared expenses
ssDiscount: -0.1, // 10% reduction
});
// RNH flat rate with youth IRS benefits
const rnh = simulateIndependentWorker({
income: 45000,
rnh: true,
rnhTax: 0.2,
benefitsOfYouthIrs: true,
yearOfYouthIrs: 2,
});
`
#### Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| income | number | required | Monthly gross income in EUR |married
| | boolean | false | Marital status |disabled
| | boolean | false | Worker disability status |partnerDisabled
| | boolean | false | Partner disability status |location
| | "continent" \| "azores" \| "madeira" | "continent" | Tax location |numberOfHolders
| | number \| null | null | Number of income holders |numberOfDependents
| | number \| null | null | Number of dependents |numberOfDependentsDisabled
| | number \| null | null | Number of disabled dependents |period
| | PeriodT | "2025-01-01_2025-07-31" | Tax period |socialSecurityTaxRate
| | number | 0.11 | Social security tax rate (11%) |twelfths
| | Twelfths | TWO_MONTHS | Holiday bonus distribution |lunchAllowanceDailyValue
| | number | 10.2 | Daily lunch allowance value |lunchAllowanceMode
| | "cupon" \| "salary" | "cupon" | Lunch allowance type |lunchAllowanceDaysCount
| | number | 22 | Monthly lunch allowance days |
#### Returns: DependentWorkerResult
`typescript`
interface DependentWorkerResult {
taxableIncome: number; // Monthly taxable income
grossIncome: number; // Monthly gross income
tax: number; // Monthly tax amount
socialSecurity: number; // Monthly social security contribution
socialSecurityTax: number; // Social security tax rate
netSalary: number; // Monthly net salary
yearlyNetSalary: number; // Yearly net salary (14 months)
yearlyGrossSalary: number; // Yearly gross salary (14 months)
lunchAllowance: LunchAllowance; // Lunch allowance details
}
Key parameters:
- income: Gross income (year/month/day depending on incomeFrequency)incomeFrequency
- : "year" (default), "month", or "day" (248 business days)nrDaysOff
- : Days off for daily calculations (cannot reach/exceed 248)ssTax
- : Social security rate (default 21.4%), ssDiscount: adjustment range -25%..25%currentTaxRankYear
- : 2023/2024/2025 progressive IRS tablesmaxExpensesTax
- : Simplified regime percentage (default 15%) and expenses: declared expensesdateOfOpeningAcivity
- : Determines first/second year factors and first-12-month SS exemptionrnh
- / rnhTax: Apply RNH flat rate instead of progressive bracketsbenefitsOfYouthIrs
- + yearOfYouthIrs: Youth IRS discount with IAS caps (up to 10 years in 2025 tables)
Return highlights:
- grossIncome, taxableIncome, netIncome, ssPay, irsPay (per year/month/day)specificDeductions
- (max of โฌ4104 vs 10% SS)expensesNeeded
- (missing expenses to hit the simplified cap)youthIrsDiscount
- , taxRank, currentIas, maxSsIncomeworkerWithinFirstFinancialYear
- Flags: , workerWithinSecondFinancialYear, workerWithinFirst12Months
- Node.js 18+
- pnpm (recommended)
`bash
pnpm install
$3
- Dependent worker vs. Doutor Finanรงas:
pnpm compare:dependent [-- --tolerance=1 --verbose]
- Independent worker vs. web simulator: pnpm compare:independent [-- --tolerance=1 --verbose]Both suites stream progress and highlight mismatches with detailed diffs.
$3
`
saldo/
โโโ src/ # Library source code
โ โโโ dependent-worker/ # Main calculation logic
โ โโโ data/ # Tax retention tables
โ โโโ tables/ # Tax table utilities
โ โโโ config/ # Configuration and schemas
โโโ docs/ # Documentation website (Next.js)
โโโ scripts/ # Data processing scripts
โโโ raw/ # Raw tax data (unprocessed)
โโโ tests/ # Test files
`๐ข Releasing
This project uses GitHub Actions for automated releases. To create a new release:
1. Go to the Actions tab in the GitHub repository
2. Select the Release workflow in the left sidebar
3. Click Run workflow
4. Choose a version type:
-
patch โ 1.0.0 โ 1.0.1 (bug fixes)
- minor โ 1.0.0 โ 1.1.0 (new features)
- major โ 1.0.0 โ 2.0.0 (breaking changes)
- prerelease โ creates a beta prerelease (e.g., 1.0.0 โ 1.0.1-beta.0)
5. Click Run workflowThe workflow will automatically:
- Run tests
- Build the package
- Bump the version in
package.json
- Create a git tag
- Push changes to main
- Create a GitHub Release
- Publish to NPMNote: Requires
NPM_TOKEN secret to be configured in GitHub repository settings.๐ Documentation
Visit the documentation site for guides, scenarios, and API reference:
`bash
pnpm saldo:docs
`The docs cover dependent and independent simulators, tax tables, lunch allowances, and worked examples.
๐ค Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
1. Fork the project
2. Create your feature branch (
git checkout -b feature/amazing-feature)
3. Commit your changes (git commit -m 'Add some amazing feature')
4. Push to the branch (git push origin feature/amazing-feature`)This project is licensed under the ISC License.
This library uses official Portuguese tax retention tables and follows Portuguese tax law. However, it's provided for informational purposes only. Always consult with a qualified tax professional for official tax advice.
---
Made with โค๏ธ for the Portuguese developer community