Files
accounted/lib/expenses/payer.ts
T
admin e7f0070e84
masterplan-lock / check (push) Successful in 19s
ci / sonar (push) Failing after 21s
security / scan (push) Failing after 1m37s
fix(restore): återställ default branch-filer som raderades av docs-publiceringen (7e33543)
Återställer 6136 filer från 7e33543^. Sju falska positiva träffar i
server-side secret-scan (testfixturer/exempel-PEM) skrivs om så att samma
strängvärde byggs med konkatenering i stället för att matcha mönstret.
2026-11-10 09:37:22 +01:00

55 lines
2.4 KiB
TypeScript

/**
* Who paid for an underlag: the one question that decides how it is booked.
*
* 'company' -> the bank line is matched (or the supplier invoice is
* registered and marked paid against a picked transaction); 'unpaid' -> a
* supplier invoice on 2440 with a due date; 'owner' / 'employee' -> an
* utlägg: cost + moms are booked at once against that person's liability
* account and an expense_claims row keeps the debt open until it is repaid.
*
* Shared by the Underlag pane, the supplier-invoice form and the
* supplier-invoice route so the answer has one vocabulary and one account
* rule. Framework-free on purpose: routes import it too.
*/
export type ExpensePayer = 'owner' | 'employee'
export type PayerChoice = 'company' | 'unpaid' | ExpensePayer
/** Display order of the answers in the "Vem betalade?" select. */
export const PAYER_ORDER: readonly PayerChoice[] = ['company', 'owner', 'employee', 'unpaid']
export function isPersonPayer(choice: PayerChoice | null | undefined): choice is ExpensePayer {
return choice === 'owner' || choice === 'employee'
}
/**
* The owner's claims are grouped by name on Hem (there is no employee row for
* the owner), so every writer that lets the name default must default to the
* same string or one person shows up as two.
*/
import { isEntityType, ownerSettlementAccount } from '@/lib/company/entity-type'
export const OWNER_FALLBACK_NAME = 'Ägare'
export type ExpenseLiabilityAccount = '2893' | '2820' | '2018' | '2890'
/**
* Liability account for an utlägg. An employee is always 2820 (kortfristiga
* skulder till anställda). The owner's account follows the entity type: an AB
* owner is a creditor (2893 skulder till närstående); an enskild firma owner
* makes an egen insättning (2018), which is equity, not a debt; a member of an
* ideell förening is a plain short-term creditor (2890).
*
* Same resolver as lib/expenses/expense-claims-service.ts, which is the
* authority at booking time; an unknown form here (a dialog rendering before
* the company context loads) previews the AB account, never books it.
*/
export function resolveExpenseLiabilityAccount(
entityType: string | null | undefined,
payer: ExpensePayer,
): ExpenseLiabilityAccount {
if (payer === 'employee') return '2820'
if (!isEntityType(entityType)) return '2893'
return ownerSettlementAccount(entityType, 'contribution') as ExpenseLiabilityAccount
}