Files
accounted/lib/import/account-vat-treatment.ts
T
4e20c9dec4 fix(import): bulk-confirm the VAT-treatment review gate in account mapping (#1723)
* fix(import): bulk-confirm the VAT-treatment review gate in account mapping

A Fortnox chart routinely puts 70+ class 3/4 accounts behind the
vat-treatment review gate, and the only way through was one Bekräfta
click per row across paginated 50-row pages. A live migration
(2026-08-18) died exactly there, stuck at 50 kvar with Continue
disabled and no way to see why.

One outline button next to Continue now accepts the suggested default
for every remaining row, with the exact semantics of the per-row
button batched (defaults kept, rows marked reviewed). Wired in both
the import wizard and the Arcim migration workspace. Strings in sv+en.

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

* fix(guards): two naive-ore-rounds that stacked past the ratchet baseline

#1700 and #1705 each added one Math.round(x*100)/100 and each passed
CI alone against baseline 630; the first branch containing both trips
the ratchet at 631. Convert both to roundOre (629, below baseline).

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

* fix: place the roundOre import on its own line

The previous commit inserted it inside a multi-line import block,
breaking parsing in pdf-template.tsx.

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

* ci: give next build an explicit 8 GB heap

The build worker OOMs on the runner's default Node heap since the
bundle crossed the default old-space ceiling (first branch containing
all of 2026-08-19's merges). Public-repo runners have 16 GB.

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

---------

Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-19 21:26:04 +02:00

109 lines
3.5 KiB
TypeScript

import type { BASAccount } from '@/types'
import {
suggestVatTreatment,
type AccountVatTreatment,
} from '@/lib/vat/account-vat-treatment'
import type { AccountMapping } from './types'
/**
* Add reviewable VAT suggestions to identity mappings. SIE itself has no VAT
* treatment record, so suggestions come only from the account label and are
* never considered reviewed until the user continues from the mapping step.
*/
export function enrichAccountMappingsWithVat(
mappings: AccountMapping[],
existingAccounts: BASAccount[],
): AccountMapping[] {
const existingByNumber = new Map(
existingAccounts.map((account) => [account.account_number, account]),
)
return mappings.map((mapping) => {
if (!mapping.targetAccount || mapping.sourceAccount !== mapping.targetAccount) {
return {
...mapping,
defaultVatTreatment: null,
defaultVatRate: null,
vatTreatmentSuggested: false,
vatTreatmentReviewed: true,
requiresVatTreatmentReview: false,
}
}
const accountClass = Number(mapping.sourceAccount.charAt(0))
if (accountClass < 3 || accountClass > 6) return mapping
const existing = existingByNumber.get(mapping.targetAccount)
if (existing?.default_vat_treatment) {
return {
...mapping,
defaultVatTreatment: existing.default_vat_treatment,
defaultVatRate: existing.default_vat_rate,
vatTreatmentReviewed: true,
vatTreatmentSuggested: false,
requiresVatTreatmentReview: false,
}
}
const suggestion = suggestVatTreatment(mapping.sourceAccount, mapping.sourceName)
return {
...mapping,
defaultVatTreatment: suggestion?.treatment ?? null,
defaultVatRate: existing?.default_vat_rate ?? suggestion?.rate ?? null,
vatTreatmentSuggested: Boolean(suggestion),
vatTreatmentReviewed: false,
requiresVatTreatmentReview: accountClass === 3 || accountClass === 4 || Boolean(suggestion),
}
})
}
export function applyVatTreatmentReview(
mappings: AccountMapping[],
sourceAccount: string,
treatment: AccountVatTreatment | null,
rate: number | null,
): AccountMapping[] {
return mappings.map((mapping) =>
mapping.sourceAccount === sourceAccount
? {
...mapping,
defaultVatTreatment: treatment,
defaultVatRate: rate,
vatTreatmentSuggested: false,
vatTreatmentReviewed: true,
}
: mapping
)
}
export function enrichChangedAccountMappingWithVat(
mappings: AccountMapping[],
sourceAccount: string,
existingAccounts: BASAccount[],
): AccountMapping[] {
return mappings.map((mapping) =>
mapping.sourceAccount === sourceAccount
? enrichAccountMappingsWithVat([mapping], existingAccounts)[0]
: mapping
)
}
/**
* Accept the suggested VAT treatment for every mapping still awaiting review,
* in one action. Exactly the per-row "Bekräfta" semantics batched: each row
* keeps its current suggested default (or null when there is none) and is
* marked reviewed. Added because a Fortnox chart routinely puts 70+ class 3/4
* accounts behind the review gate, and clicking them one by one across
* paginated pages was an observed migration dead end (2026-08-18).
*/
export function applyVatTreatmentReviewAll(mappings: AccountMapping[]): AccountMapping[] {
return mappings.map((mapping) =>
mapping.requiresVatTreatmentReview && !mapping.vatTreatmentReviewed
? {
...mapping,
vatTreatmentSuggested: false,
vatTreatmentReviewed: true,
}
: mapping
)
}