Files
accounted/lib/salary/payroll-config.ts
T
Mattsson 04dbb31d7e Salary module (#245)
* feat: implement salary module with personnummer encryption, salary entries, tax tables, and AGI tracking

- Added personnummer encryption and decryption functions for secure storage.
- Created salary entries handling for journal entries including gross salary, tax withholding, and employer contributions.
- Implemented tax table lookup functionality for calculating tax amounts based on monthly income.
- Developed SQL migration for salary module including tables for payroll configuration, tax rates, employees, salary runs, salary run employees, salary line items, and AGI declarations.
- Established row-level security policies for all new tables to ensure company-scoped access.

* feat: add salary calculation modules for 2026

- Implemented engångsskatt calculation for one-time payments with tax brackets.
- Added löneväxling functionality for salary sacrifice to pension, including employer savings and warnings.
- Created pain.001 generator for salary batch payments in compliance with Swedish banking standards.
- Developed PDF template for payslips, including detailed breakdowns and employer costs.
- Generated seed data for Swedish tax tables for 2026, including SQL insert statements.
- Implemented traktamente calculations for per diem and mileage allowances, adhering to Skatteverket regulations.
- Added seed script for populating tax tables in the database.

* feat: Update meal reduction percentages in traktamente calculation

fix: Remove obsolete seed script for 2026 tax tables

feat: Extend SalaryRunStatus type to include 'corrected' status

feat: Implement KU10 XML generation endpoint for annual employee income statements

feat: Add endpoint for creating corrections to booked salary runs

feat: Implement endpoint for sending payslip PDFs to employees

feat: Create KU10 XML generator for annual reporting

feat: Add salary transaction matcher for auto-linking bank transactions to salary entries

chore: Add database migration for salary correction support

* feat: replace select elements with custom Select component for employment and salary types

* feat: enhance salary calculations with pension entry and avgifter category support
2026-04-15 11:17:39 +02:00

107 lines
3.6 KiB
TypeScript

import type { SupabaseClient } from '@supabase/supabase-js'
export interface PayrollConfig {
configYear: number
avgifterTotal: number
avgifterAlderspension: number
avgifterSjukforsakring: number
avgifterForaldraforsakring: number
avgifterEfterlevandepension: number
avgifterArbetsmarknad: number
avgifterArbetsskada: number
avgifterAllmanLoneavgift: number
avgifterReduced65plus: number
avgifterYouthRate: number | null
avgifterYouthSalaryCap: number | null
avgifterVaxaStodRate: number | null
avgifterVaxaStodCap: number | null
avgifterMinimumAnnual: number
egenavgifterTotal: number
slpRate: number
prisbasbelopp: number
inkomstbasbelopp: number
maxPgi: number
sgiCeiling: number
statligSkattBrytpunkt: number
traktamenteHeldag: number
traktamenteHalvdag: number
traktamenteNatt: number
milersattningEgenBil: number
milersattningFormansbilFossil: number
milersattningFormansbilEl: number
kostformanHeldag: number
kostformanLunch: number
kostformanFrukost: number
friskvardCap: number
bilformanSlr: number
sjuklonRate: number
karensavdragFactor: number
maxKarensavdragPerYear: number
reducedAvgiftAge: number
}
/**
* Load payroll configuration for a given year.
*/
export async function loadPayrollConfig(
supabase: SupabaseClient,
year: number
): Promise<PayrollConfig> {
const { data, error } = await supabase
.from('salary_payroll_config')
.select('*')
.eq('config_year', year)
.single()
if (error || !data) {
throw new Error(`Payroll configuration not found for year ${year}`)
}
return {
configYear: data.config_year,
avgifterTotal: data.avgifter_total,
avgifterAlderspension: data.avgifter_alderspension,
avgifterSjukforsakring: data.avgifter_sjukforsakring,
avgifterForaldraforsakring: data.avgifter_foraldraforsakring,
avgifterEfterlevandepension: data.avgifter_efterlevandepension,
avgifterArbetsmarknad: data.avgifter_arbetsmarknad,
avgifterArbetsskada: data.avgifter_arbetsskada,
avgifterAllmanLoneavgift: data.avgifter_allman_loneavgift,
avgifterReduced65plus: data.avgifter_reduced_65plus,
avgifterYouthRate: data.avgifter_youth_rate,
avgifterYouthSalaryCap: data.avgifter_youth_salary_cap,
avgifterVaxaStodRate: data.avgifter_vaxa_stod_rate,
avgifterVaxaStodCap: data.avgifter_vaxa_stod_cap,
avgifterMinimumAnnual: data.avgifter_minimum_annual,
egenavgifterTotal: data.egenavgifter_total,
slpRate: data.slp_rate,
prisbasbelopp: data.prisbasbelopp,
inkomstbasbelopp: data.inkomstbasbelopp,
maxPgi: data.max_pgi,
sgiCeiling: data.sgi_ceiling,
statligSkattBrytpunkt: data.statlig_skatt_brytpunkt,
traktamenteHeldag: data.traktamente_heldag,
traktamenteHalvdag: data.traktamente_halvdag,
traktamenteNatt: data.traktamente_natt,
milersattningEgenBil: data.milersattning_egen_bil,
milersattningFormansbilFossil: data.milersattning_formansbil_fossil,
milersattningFormansbilEl: data.milersattning_formansbil_el,
kostformanHeldag: data.kostforman_heldag,
kostformanLunch: data.kostforman_lunch,
kostformanFrukost: data.kostforman_frukost,
friskvardCap: data.friskvard_cap,
bilformanSlr: data.bilforman_slr,
sjuklonRate: data.sjuklon_rate,
karensavdragFactor: data.karensavdrag_factor,
maxKarensavdragPerYear: data.max_karensavdrag_per_year,
reducedAvgiftAge: data.reduced_avgift_age,
}
}
/**
* Serialize payroll config for snapshot storage in salary_runs.calculation_params.
*/
export function serializePayrollConfig(config: PayrollConfig): Record<string, unknown> {
return { ...config }
}