Files
accounted/lib/salary/account-mapping.ts
T
Mattsson 0ef3c03904 fix(salary): book net deductions as settlement lines so salary entries balance (#1374)
* fix(salary): book net deductions as settlement lines so salary entries balance

Net deduction line items were skipped entirely in createSalaryEntry, so the
credit side (2710 tax + 1930 net) fell short of the gross debit by exactly
the deducted amount and the balance trigger rejected the voucher.

Net deductions now book on their mapped settlement account (1613 advance
repayment, 2794 union fee, 7385 benefit co-payment, 2799 other; explicit
account_number overrides), aggregated and undimensioned like the other
settlement legs. The default mapping in account-mapping.ts moves off 7210
so payslip lines, the booking preview and the voucher all agree.

Fixes #316

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(salary): address compliance review on net-deduction accounts

Label 7385 with its BAS 2026 name (Kostnader för fri bil) instead of the
benefit-generic Bilförmån, document why the single benefit-payment item
type defaults to 7385 with per-line override for other benefit kinds, and
add a repayment-direction test (positive net deduction books as debit).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 18:51:53 +02:00

122 lines
4.2 KiB
TypeScript

import type { SalaryLineItemType } from '@/types'
/**
* Salary account mapping: maps line item types and calculation results
* to BAS accounts per Swedish chart of accounts standards.
*/
/** Default BAS account for each salary line item type */
const LINE_ITEM_ACCOUNTS: Record<SalaryLineItemType, string> = {
// Salary components
monthly_salary: '7210',
hourly_salary: '7210',
overtime: '7210',
overtime_50: '7210',
overtime_100: '7210',
// OB-tillägg: bookat på samma lönekonto som grundlönen; differentieras via
// rad-text på verifikatet och lönespecifikationen.
ob_weekday_evening: '7210',
ob_weekend: '7210',
ob_night: '7210',
ob_holiday: '7210',
bonus: '7210',
commission: '7210',
// Gross deductions
gross_deduction_pension: '7218',
gross_deduction_other: '7210',
// Benefits (förmånsvärden: not a cash payment, just tax base)
benefit_car: '7385',
benefit_housing: '7381',
benefit_meals: '7382',
benefit_wellness: '7699',
benefit_bike: '7388',
benefit_other: '7389',
// Absence
sick_karens: '7281',
sick_day2_14: '7281',
sick_day15_plus: '7281',
vab: '7210',
parental_leave: '7210',
unpaid_leave: '7210',
vacation: '7285',
semesterersattning: '7285',
// Travel
traktamente_taxfree: '7321',
traktamente_taxable: '7322',
mileage_taxfree: '7331',
mileage_taxable: '7332',
// Net deductions (nettolöneavdrag): withheld from the payout and owed to a
// third party, so the default account is the credit-side settlement account,
// not a 7xxx salary expense. Advance repayments credit the receivable (1613),
// union fees credit 2794, everything unmapped lands on 2799 Övriga
// löneavdrag. There is a single benefit-payment item type, so its default
// credits 7385 Kostnader för fri bil, the dominant co-payment case;
// co-payments for other benefit kinds must set account_number on the line
// (7381/7382/7388/7389/7699).
net_deduction_advance: '1613',
net_deduction_union: '2794',
net_deduction_benefit_payment: '7385',
net_deduction_other: '2799',
// Other
correction: '7210',
other: '7210',
}
/**
* Get the BAS account number for a salary line item type.
* Can be overridden per line item via account_number field.
*/
export function getLineItemAccount(
itemType: SalaryLineItemType,
employmentType: string = 'employee'
): string {
// Company owner uses 7220 instead of 7210
if (employmentType === 'company_owner') {
const baseAccount = LINE_ITEM_ACCOUNTS[itemType]
if (baseAccount === '7210') return '7220'
if (baseAccount === '7281') return '7282'
if (baseAccount === '7285') return '7286'
}
// Board member uses 7240
if (employmentType === 'board_member') {
const baseAccount = LINE_ITEM_ACCOUNTS[itemType]
if (baseAccount === '7210') return '7240'
}
return LINE_ITEM_ACCOUNTS[itemType]
}
/** Journal entry accounts for salary booking */
export const SALARY_ACCOUNTS = {
// Salary expense (debit)
SALARY_EMPLOYEE: '7210', // Löner till tjänstemän
SALARY_OWNER: '7220', // Löner till företagsledare
SALARY_BOARD: '7240', // Styrelsearvoden
SICK_PAY: '7281', // Sjuklöner
VACATION_PAY: '7285', // Semesterlöner
// Tax withholding (credit)
TAX_WITHHELD: '2710', // Personalskatt
// Bank / payment (credit)
BANK: '1930', // Företagskonto
// Employer contributions
AVGIFTER_EXPENSE: '7510', // Lagstadgade sociala avgifter (debit)
AVGIFTER_LIABILITY: '2731', // Avräkning sociala avgifter (credit)
// Vacation accrual
VACATION_ACCRUAL_EXPENSE: '7290', // Förändring semesterlöneskuld (debit)
VACATION_ACCRUAL_LIABILITY: '2920', // Upplupna semesterlöner (credit)
// Vacation accrual avgifter
VACATION_AVGIFTER_EXPENSE: '7519', // Sociala avgifter semester (debit)
VACATION_AVGIFTER_LIABILITY: '2940', // Upplupna sociala avgifter (credit)
// Pension provisions (löneväxling)
PENSION_EXPENSE: '7410', // Pensionsförsäkringspremier (debit)
PENSION_LIABILITY: '2740', // Skuld pensionsförsäkringar (credit)
SLP_EXPENSE: '7533', // Särskild löneskatt på pensionskostnader (debit)
SLP_LIABILITY: '2514', // Beräknad särskild löneskatt (credit)
} as const