* fix(vat): complete account treatment enforcement * docs(api): refresh account endpoint skill * fix(mcp): preserve ruta 05 compatibility * test(vat): seed migration constraint fixtures * docs(vat): clarify treatment precedence --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
148 lines
4.4 KiB
TypeScript
148 lines
4.4 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import {
|
|
applyVatTreatmentReview,
|
|
enrichChangedAccountMappingWithVat,
|
|
enrichAccountMappingsWithVat,
|
|
} from '../account-vat-treatment'
|
|
import type { AccountMapping } from '../types'
|
|
|
|
function mapping(account: string, name: string): AccountMapping {
|
|
return {
|
|
sourceAccount: account,
|
|
sourceName: name,
|
|
targetAccount: account,
|
|
targetName: name,
|
|
confidence: 1,
|
|
matchType: 'exact',
|
|
isOverride: false,
|
|
}
|
|
}
|
|
|
|
describe('enrichAccountMappingsWithVat', () => {
|
|
it('marks label suggestions for user review', () => {
|
|
const [result] = enrichAccountMappingsWithVat(
|
|
[mapping('4056', 'Inköp varor 25% EU')],
|
|
[],
|
|
)
|
|
expect(result).toMatchObject({
|
|
defaultVatTreatment: 'reverse_charge_eu_goods',
|
|
defaultVatRate: 0.25,
|
|
vatTreatmentSuggested: true,
|
|
vatTreatmentReviewed: false,
|
|
requiresVatTreatmentReview: true,
|
|
})
|
|
})
|
|
|
|
it('keeps an existing account treatment without asking again', () => {
|
|
const [result] = enrichAccountMappingsWithVat(
|
|
[mapping('3041', 'Försäljning tjänst 25% sv')],
|
|
[{
|
|
account_number: '3041',
|
|
default_vat_treatment: 'standard_25',
|
|
default_vat_rate: 0.25,
|
|
} as never],
|
|
)
|
|
expect(result).toMatchObject({
|
|
defaultVatTreatment: 'standard_25',
|
|
vatTreatmentSuggested: false,
|
|
vatTreatmentReviewed: true,
|
|
requiresVatTreatmentReview: false,
|
|
})
|
|
})
|
|
|
|
it('preserves an existing booking rate when suggesting a missing treatment', () => {
|
|
const [result] = enrichAccountMappingsWithVat(
|
|
[mapping('3041', 'Försäljning tjänst 25% sv')],
|
|
[{
|
|
account_number: '3041',
|
|
default_vat_treatment: null,
|
|
default_vat_rate: 0.12,
|
|
} as never],
|
|
)
|
|
expect(result.defaultVatTreatment).toBe('standard_25')
|
|
expect(result.defaultVatRate).toBe(0.12)
|
|
})
|
|
|
|
it('requires review for a suggested class 6 service treatment', () => {
|
|
const [result] = enrichAccountMappingsWithVat(
|
|
[mapping('6545', 'Inköp tjänster utanför EU 25%')],
|
|
[],
|
|
)
|
|
expect(result).toMatchObject({
|
|
defaultVatTreatment: 'reverse_charge_non_eu_services',
|
|
requiresVatTreatmentReview: true,
|
|
vatTreatmentReviewed: false,
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('applyVatTreatmentReview', () => {
|
|
it('persists a suggestion only after an explicit row confirmation', () => {
|
|
const mappings = enrichAccountMappingsWithVat([
|
|
mapping('4056', 'Inköp varor 25% EU'),
|
|
], [])
|
|
|
|
expect(mappings[0].vatTreatmentReviewed).toBe(false)
|
|
const reviewed = applyVatTreatmentReview(
|
|
mappings,
|
|
'4056',
|
|
mappings[0].defaultVatTreatment ?? null,
|
|
mappings[0].defaultVatRate ?? null,
|
|
)
|
|
expect(reviewed[0]).toMatchObject({
|
|
defaultVatTreatment: 'reverse_charge_eu_goods',
|
|
vatTreatmentReviewed: true,
|
|
vatTreatmentSuggested: false,
|
|
})
|
|
})
|
|
|
|
it('clears hidden review state on remap and restores it on identity mapping', () => {
|
|
const [suggested] = enrichAccountMappingsWithVat([
|
|
mapping('4056', 'Inköp varor 25% EU'),
|
|
], [])
|
|
|
|
const [remapped] = enrichAccountMappingsWithVat([{
|
|
...suggested,
|
|
targetAccount: '4010',
|
|
targetName: 'Inköp material',
|
|
}], [])
|
|
expect(remapped).toMatchObject({
|
|
defaultVatTreatment: null,
|
|
requiresVatTreatmentReview: false,
|
|
vatTreatmentReviewed: true,
|
|
})
|
|
|
|
const [identity] = enrichAccountMappingsWithVat([{
|
|
...remapped,
|
|
targetAccount: '4056',
|
|
targetName: 'Inköp varor 25% EU',
|
|
}], [])
|
|
expect(identity).toMatchObject({
|
|
defaultVatTreatment: 'reverse_charge_eu_goods',
|
|
requiresVatTreatmentReview: true,
|
|
vatTreatmentReviewed: false,
|
|
})
|
|
})
|
|
|
|
it('preserves another row review when one mapping changes', () => {
|
|
const initial = enrichAccountMappingsWithVat([
|
|
mapping('3041', 'Försäljning tjänst 25% sv'),
|
|
mapping('4056', 'Inköp varor 25% EU'),
|
|
], [])
|
|
const reviewed = applyVatTreatmentReview(initial, '3041', 'exempt', 0)
|
|
const remapped = enrichChangedAccountMappingWithVat(
|
|
reviewed.map((item) => item.sourceAccount === '4056'
|
|
? { ...item, targetAccount: '4010', targetName: 'Inköp material' }
|
|
: item),
|
|
'4056',
|
|
[],
|
|
)
|
|
|
|
expect(remapped[0]).toMatchObject({
|
|
defaultVatTreatment: 'exempt',
|
|
defaultVatRate: 0,
|
|
vatTreatmentReviewed: true,
|
|
})
|
|
})
|
|
})
|