* refactor: optimize page loading and data fetching * fix: resolve recurring production runtime errors * feat: add MCP company and customer updates * fix: handle year-end tax adjustments * feat: harden annual report compliance * fix: expand invoice logo and font support * fix: sanitize API route error responses * fix: sanitize user-facing error messages * feat: persist onboarding and tax assessment notices * fix: reduce cloud backup audit churn * feat: refine invoice editor layout * fix: show saved tax adjustments in INK2 * fix: complete annual report API mappings * docs: record operational safeguards and decisions * fix: harden annual report review findings * fix: adjust column span for description based on VAT registration * New css class name
92 lines
2.7 KiB
TypeScript
92 lines
2.7 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
vi.mock('@/lib/reports/trial-balance', () => ({
|
|
generateTrialBalance: vi.fn(),
|
|
}))
|
|
|
|
import { generateTrialBalance } from '@/lib/reports/trial-balance'
|
|
import { loadTaxAdjustmentSnapshot } from '../tax-provision/tax-adjustment-service'
|
|
|
|
function makeClient(rows: unknown[] = []) {
|
|
const result = { data: rows, error: null }
|
|
const handler: ProxyHandler<object> = {
|
|
get(_target, property) {
|
|
if (property === 'then') {
|
|
return (resolve: (value: unknown) => void) => resolve(result)
|
|
}
|
|
return () => new Proxy({}, handler)
|
|
},
|
|
}
|
|
return {
|
|
from: () => new Proxy({}, handler),
|
|
} as unknown as Parameters<typeof loadTaxAdjustmentSnapshot>[0]
|
|
}
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
vi.mocked(generateTrialBalance).mockResolvedValue({
|
|
rows: [
|
|
{
|
|
account_number: '6992',
|
|
closing_debit: 2_994,
|
|
closing_credit: 0,
|
|
},
|
|
{
|
|
account_number: '8423',
|
|
closing_debit: 2_250,
|
|
closing_credit: 0,
|
|
},
|
|
],
|
|
totalDebit: 5_244,
|
|
totalCredit: 0,
|
|
isBalanced: false,
|
|
} as Awaited<ReturnType<typeof generateTrialBalance>>)
|
|
})
|
|
|
|
describe('loadTaxAdjustmentSnapshot', () => {
|
|
it('detects Miles account balances as non-deductible expenses', async () => {
|
|
const snapshot = await loadTaxAdjustmentSnapshot(makeClient(), 'company-1', 'period-1')
|
|
|
|
expect(snapshot.nonDeductibleExpenses).toBe(5_244)
|
|
expect(snapshot.nonTaxableIncome).toBe(0)
|
|
expect(snapshot.items.find((item) => item.accountNumber === '6992')).toMatchObject({
|
|
amount: 2_994,
|
|
included: true,
|
|
})
|
|
expect(snapshot.items.find((item) => item.accountNumber === '8423')).toMatchObject({
|
|
amount: 2_250,
|
|
included: true,
|
|
})
|
|
})
|
|
|
|
it('honors saved exclusions and includes manual adjustments', async () => {
|
|
const snapshot = await loadTaxAdjustmentSnapshot(
|
|
makeClient([
|
|
{
|
|
source_key: 'account:8423',
|
|
adjustment_type: 'non_deductible_expense',
|
|
source: 'detected',
|
|
description: 'Räntekostnader för skatter och avgifter',
|
|
account_number: '8423',
|
|
amount: 2_250,
|
|
included: false,
|
|
},
|
|
{
|
|
source_key: 'manual:non_deductible_expenses',
|
|
adjustment_type: 'non_deductible_expense',
|
|
source: 'manual',
|
|
description: 'Ytterligare ej avdragsgilla kostnader',
|
|
account_number: null,
|
|
amount: 100,
|
|
included: true,
|
|
},
|
|
]),
|
|
'company-1',
|
|
'period-1',
|
|
)
|
|
|
|
expect(snapshot.nonDeductibleExpenses).toBe(3_094)
|
|
expect(snapshot.items.find((item) => item.accountNumber === '8423')?.included).toBe(false)
|
|
})
|
|
})
|