Files
accounted/lib/invoices/rounding.ts
T
Mattsson 0ee5219b6c feat(invoices): implement öresavrundning logic and next invoice numbe… (#429)
* feat(invoices): implement öresavrundning logic and next invoice number preview

- Added `getDisplayTotal` utility to handle rounding for SEK invoices based on company settings.
- Updated `InvoicesPage` to utilize the new rounding logic when displaying totals.
- Introduced `peek_next_invoice_number` function to allow previewing the next invoice number without consuming the sequence.
- Modified invoice number generation to remove the year prefix and prevent truncation of numbers exceeding three digits.
- Enhanced tests for invoice number generation and rounding functionality to ensure correctness.
- Updated PDF template to reflect new rounding logic for totals and display appropriate values.
- Adjusted company switcher to hide options in sandbox mode.
- Improved error handling and logging in sandbox seeding process.

* fix(skatteverket): remove unused scope labels from SCOPE_LABELS and DEFAULT_SCOPES
2026-05-10 14:21:26 +02:00

40 lines
1.5 KiB
TypeScript

import type { Invoice, CompanySettings } from '@/types'
type InvoiceTotalShape = Pick<Invoice, 'total' | 'currency'>
type CompanyRoundingShape = Pick<CompanySettings, 'ore_rounding'>
export interface DisplayTotal {
/** Total to render to the user (rounded if öresavrundning applies, raw otherwise). */
displayed: number
/** displayed - raw total. Zero when rounding does not apply or the total is already an integer. */
roundingDelta: number
/** True when both the company setting is on, currency is SEK, and there are öre to round. */
applies: boolean
}
/**
* Single source of truth for öresavrundning display logic. Mirrors the rule
* baked into the PDF template since day one: only SEK invoices, only when
* the company has the setting enabled, and only when there's actually a
* non-integer total to round. The helper centralizes the rule so the list,
* detail page, and PDF cannot drift apart.
*/
export function getDisplayTotal(
invoice: InvoiceTotalShape,
company: CompanyRoundingShape | null | undefined,
): DisplayTotal {
const enabled = company?.ore_rounding ?? true
if (!enabled || invoice.currency !== 'SEK') {
return { displayed: invoice.total, roundingDelta: 0, applies: false }
}
const rounded = Math.round(invoice.total)
if (rounded === invoice.total) {
return { displayed: invoice.total, roundingDelta: 0, applies: false }
}
return {
displayed: rounded,
roundingDelta: Math.round((rounded - invoice.total) * 100) / 100,
applies: true,
}
}