https://github.com/emisso-ai/emisso-payroll
Chilean payroll calculation engine — AFP, health, tax, unemployment, Previred, finiquito
https://github.com/emisso-ai/emisso-payroll
afp chile latam open-source payroll previred remuneraciones sdk typescript
Last synced: 2 months ago
JSON representation
Chilean payroll calculation engine — AFP, health, tax, unemployment, Previred, finiquito
- Host: GitHub
- URL: https://github.com/emisso-ai/emisso-payroll
- Owner: emisso-ai
- Created: 2026-03-13T01:24:39.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-03-17T02:59:09.000Z (3 months ago)
- Last Synced: 2026-03-17T14:20:09.964Z (3 months ago)
- Topics: afp, chile, latam, open-source, payroll, previred, remuneraciones, sdk, typescript
- Language: TypeScript
- Size: 269 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# @emisso/payroll-cl
Chilean payroll calculation engine — AFP, health insurance, income tax, unemployment, gratification, family allowance, pension reform (Law 21.720), finiquito, and Previred DDJJ file generation.
## When to Use This
- You need to **calculate Chilean payroll** (sueldos, remuneraciones) in a TypeScript/Node.js application
- You want to **generate Previred DDJJ files** for monthly social security declarations
- You need **finiquito (severance) calculations** including indemnización por años de servicio and unused vacation
- You want a **net-to-gross reverse solver** — "I want to pay 1.2M líquido, what's the gross?"
- You're building an **HR/payroll SaaS** for Chilean companies and need a calculation engine with a self-hosted API
- You need to handle **AFP, Fonasa/Isapre, income tax, unemployment insurance, gratification**, and all Chilean payroll rules in code
## Packages
| Package | Description | Install |
|---------|-------------|---------|
| `@emisso/payroll-cl` | Pure calculation engine (zero I/O) | `npm install @emisso/payroll-cl` |
| `@emisso/payroll-api` | Full-stack API layer (Drizzle + Effect) | `npm install @emisso/payroll-api` |
| `@emisso/payroll-cli` | Command-line interface | `npm install -g @emisso/payroll-cli` |
## Quick Start — Engine
```bash
npm install @emisso/payroll-cl
```
```typescript
import {
calculateEmployeePayroll,
DEFAULT_REFERENCE_DATA,
} from "@emisso/payroll-cl";
const result = calculateEmployeePayroll(
{
employeeId: "1",
rut: "12.345.678-9",
firstName: "Juan",
lastName: "Pérez",
baseSalary: 1_500_000,
gratificationType: "legal",
colacion: 50_000,
movilizacion: 30_000,
afpCode: "habitat",
afpFund: "b",
healthPlan: "fonasa",
familyAllowanceLoads: 2,
contractType: "indefinido",
earnings: [],
deductions: [],
},
DEFAULT_REFERENCE_DATA
);
console.log(result.netPay); // Líquido a pagar
console.log(result.deductions.afp); // AFP deduction
console.log(result.employerCosts); // Employer cost breakdown
```
> `DEFAULT_REFERENCE_DATA` uses Feb 2026 values. For production, fetch live indicators:
>
> ```typescript
> import { fetchCurrentIndicators } from "@emisso/payroll-cl/providers";
> const indicators = await fetchCurrentIndicators();
> ```
### Batch Payroll
```typescript
import { calculatePayroll, DEFAULT_REFERENCE_DATA } from "@emisso/payroll-cl";
const results = await calculatePayroll({
employees: [employee1, employee2, employee3],
referenceData: DEFAULT_REFERENCE_DATA,
periodYear: 2026,
periodMonth: 3,
});
```
### Previred File
```typescript
import { generatePreviredFile, validatePreviredData } from "@emisso/payroll-cl";
const errors = validatePreviredData(previredData);
if (errors.length === 0) {
const fileContent = generatePreviredFile(previredData);
// Write to .txt for upload to previred.com
}
```
### Net-to-Gross
```typescript
import { calculateNetToGross, DEFAULT_REFERENCE_DATA } from "@emisso/payroll-cl";
// "I want to pay 1.2M líquido — what's the gross?"
const gross = calculateNetToGross(1_200_000, {
afpCode: "habitat",
healthPlan: "fonasa",
referenceData: DEFAULT_REFERENCE_DATA,
});
```
### Finiquito
```typescript
import { calculateFiniquito } from "@emisso/payroll-cl";
const finiquito = calculateFiniquito({
baseSalary: 1_500_000,
startDate: new Date("2020-01-15"),
endDate: new Date("2026-03-13"),
terminationType: "employer_needs",
unusedVacationDays: 12,
referenceData: DEFAULT_REFERENCE_DATA,
});
```
## Quick Start — Self-Hosted API
For teams that need a REST API with persistence, multi-tenant, and employee management.
```bash
npm install @emisso/payroll-api
```
**1. Set environment variables:**
```bash
# .env.local
EMISSO_DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
```
**2. Run migrations:**
```bash
npx @emisso/payroll-api migrate
```
**3. Mount in your Next.js app:**
```typescript
// app/api/payroll/[...path]/route.ts
import { createPayrollRouter } from "@emisso/payroll-api/next";
export const { GET, POST, PUT, DELETE } = createPayrollRouter({
databaseUrl: process.env.EMISSO_DATABASE_URL!,
basePath: "/api/payroll",
resolveTenantId: async (req) => {
const session = await getSession(req); // your auth
return session.tenantId;
},
});
```
**4. Use the API:**
```bash
# Create employee
curl -X POST http://localhost:3000/api/payroll/employees \
-H "Content-Type: application/json" \
-d '{"rut":"12.345.678-9","firstName":"Juan","lastName":"Pérez","baseSalary":1500000}'
# Run payroll
curl -X POST http://localhost:3000/api/payroll/runs \
-H "Content-Type: application/json" \
-d '{"period":"2026-03"}'
```
## API Reference
### Engine Exports (`@emisso/payroll-cl`)
| Export | Description |
|--------|-------------|
| `calculatePayroll(input)` | Batch calculation for multiple employees |
| `calculateEmployeePayroll(employee, refData)` | Single employee calculation |
| `calculateNetToGross(netPay, options)` | Reverse calculation: net → gross |
| `calculateFiniquito(input)` | Severance/termination calculation |
| `calculateOvertime(hours, baseSalary, type)` | Overtime pay calculation |
| `generatePreviredFile(data)` | Generate Previred DDJJ text file |
| `validatePreviredData(data)` | Validate data before Previred generation |
| `DEFAULT_REFERENCE_DATA` | Default economic indicators (Feb 2026) |
| `formatRut(rut)` / `validateRut(rut)` | RUT utilities |
### Providers (`@emisso/payroll-cl/providers`)
| Export | Description |
|--------|-------------|
| `fetchCurrentIndicators()` | UF, UTM, UTA, IMM from mindicador.cl |
| `fetchIndicatorsFromSII()` | Indicators from SII RSS feed |
| `fetchAFPRates()` | Current AFP commission rates |
## Payroll Rules
| Rule | Module | Description |
|------|--------|-------------|
| AFP | `rules/afp` | Mandatory pension (10% + commission) |
| Health | `rules/health` | Fonasa (7%) or Isapre (7% + additional UF) |
| Income Tax | `rules/income-tax` | Progressive brackets in UTM |
| Unemployment | `rules/unemployment` | Employee + employer portions by contract type |
| Gratification | `rules/gratification` | Legal (Art. 50, capped at 4.75 IMM) or convenida |
| Family Allowance | `rules/family-allowance` | Brackets by income level |
| SIS | `rules/sis` | Employer disability/survival insurance |
| Mutual | `rules/mutual` | Workplace accident insurance |
| APV | `rules/apv` | Voluntary pension savings |
| Pension Reform | `rules/employer-pension-reform` | Law 21.720 employer contribution |
| Overtime | `rules/overtime` | 50% surcharge calculation |
| Finiquito | `rules/finiquito` | Severance: indemnización, vacaciones, etc. |
## CLI
```bash
npm install -g @emisso/payroll-cli
```
### Commands
| Command | Description |
|---------|-------------|
| `payroll calculate -i batch.json` | Batch payroll calculation from JSON file |
| `payroll calculate-employee --base-salary 1500000 --afp habitat --health fonasa` | Single employee calculation |
| `payroll net-to-gross --target-net 1200000 --afp habitat --health fonasa` | Reverse solver: net → gross |
| `payroll finiquito --hire-date 2020-01-15 --termination-date 2026-03-15 --type despido_sin_causa --base-salary 1500000` | Severance calculation |
| `payroll overtime --hours 10 --base-salary 1000000` | Overtime pay calculation |
| `payroll indicators --source defaults` | Show economic indicators (UF, UTM, IMM) |
| `payroll previred generate -i data.json -o ddjj.txt` | Generate Previred DDJJ file |
| `payroll previred validate -i data.json` | Validate Previred data |
| `payroll rut validate 12345678-5` | Validate Chilean RUT |
| `payroll rut format 123456785` | Format RUT with dots and dash |
| `payroll doctor` | Check system health and dependencies |
### Output Formats
All commands support `--format table|csv|json` and `--json` shorthand. Defaults to table for TTY, CSV for pipes.
```bash
payroll calculate-employee --base-salary 1500000 --afp habitat --health fonasa --json
payroll calculate -i batch.json --format csv > output.csv
```
## Development
```bash
pnpm install
pnpm build # Build all packages
pnpm test # Run all tests
pnpm lint # Typecheck all packages
```
## FAQ
**What is the best TypeScript library for Chilean payroll calculation?**
[@emisso/payroll-cl](https://github.com/emisso-ai/emisso-payroll) is an MIT-licensed TypeScript engine that calculates AFP, health insurance (Fonasa/Isapre), income tax, unemployment, gratification, family allowance, pension reform (Law 21.720), finiquito, and generates Previred DDJJ files. It's a pure calculation engine with zero I/O.
**How do I calculate remuneraciones in Node.js?**
Install `@emisso/payroll-cl` and call `calculateEmployeePayroll(employee, referenceData)`. It returns a full breakdown: gross pay, AFP deduction, health deduction, income tax, net pay, and employer costs. Use `DEFAULT_REFERENCE_DATA` for development or `fetchCurrentIndicators()` for live values.
**How do I generate a Previred file in TypeScript?**
Use `generatePreviredFile(data)` from `@emisso/payroll-cl`. It produces the fixed-width text file that Previred's portal expects. Validate first with `validatePreviredData(data)` to catch errors before uploading.
**Can I calculate finiquito (severance) programmatically?**
Yes. `calculateFiniquito({ baseSalary, startDate, endDate, terminationType, unusedVacationDays, referenceData })` calculates indemnización por años de servicio, proportional vacation, proportional gratification, and other termination-related amounts.
**Does this handle the 2024 pension reform (Law 21.720)?**
Yes. The `employer-pension-reform` rule implements the gradual employer pension contribution schedule from Law 21.720, which phases in from 2025 to 2035.
**How do I get live economic indicators (UF, UTM, IMM)?**
Import `fetchCurrentIndicators()` from `@emisso/payroll-cl/providers`. It fetches current UF, UTM, UTA, and IMM values from mindicador.cl. Alternative: `fetchIndicatorsFromSII()` for SII's RSS feed.
## Alternatives
| Library | Language | Payroll Calc | Previred | Finiquito | Open Source | Self-Hosted API |
|---------|----------|:---:|:---:|:---:|:---:|:---:|
| **@emisso/payroll-cl** | TypeScript | ✅ | ✅ | ✅ | ✅ MIT | ✅ |
| Talana | SaaS | ✅ | ✅ | ✅ | ❌ | ❌ |
| Nubox Remuneraciones | Desktop/.NET | ✅ | ✅ | ✅ | ❌ | ❌ |
| Remuner | SaaS | ✅ | ✅ | ❌ | ❌ | ❌ |
## License
MIT — [Emisso](https://emisso.ai)