f33628f005
* feat(import): say in the SIE wizard that the chart and fiscal year come along The preview scored the file's accounts against the BAS reference and said "matchas mot din kontoplan", so a consultant with a 41-account seeded company read "150 mappade" as "the file's chart replaces mine". A fiscal-year overlap with a non-empty period was only refused after the mapping step. - Parse route adds preview.chart (accounts new to THIS company vs already present, with a sample) via planChartChanges, and preview.fiscalYear from precheckFiscalPeriod: the containment/overlap verdict extracted out of ensureFiscalPeriod, which now consumes it, so preview and import cannot drift. - Preview card renamed to Kontoplan with the counts and the fiscal-year verdict (match / create / conflict with the import's own refusal text). - Review step lists the chart among "Vad händer när du importerar?". - executeSIEImport reports accountsCreated from the account sync; the result grid gets a Konton skapade card. No import logic changed; no migration. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014MgxEaU52nJgDQA41svdtC * fix(import): preview refuses what the import refuses, and the chart card survives "Skapa saknade konton" Skeptic pass on #2307 refuted the first cut twice: - "Skapas vid import" was shown for a #RAR the import then refuses under BFL 3 kap. (19 months, non-month-end finish, mid-month start after an earlier year). The shape rules move into precheckFiscalPeriod as a fourth verdict 'invalid' with the same refusal text; ensureFiscalPeriod stays a consumer of one verdict, same query order. - The Kontoplan card counted unmapped sources under "Läggs till" and kept listing them after the create button, while the result said 0 created. planChartChanges (now client-safe in lib/import/chart-plan.ts) counts mapped targets only; the create button moves those accounts from "Ej mappade" to "Finns redan" in place. - The review line claimed existing accounts keep their name unless you opt in; the switch defaults to on. Reworded to match. - Sample names follow the file for identity mappings, as the sync does. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014MgxEaU52nJgDQA41svdtC --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
68 lines
2.3 KiB
TypeScript
68 lines
2.3 KiB
TypeScript
/**
|
|
* Pure preview of what the SIE import does to the company's chart of
|
|
* accounts. Client-safe (types only): the import wizard recomputes it in the
|
|
* browser after "Skapa saknade konton", and the parse route computes it on
|
|
* the server. The insert itself lives in account-sync.ts (syncMappedAccounts).
|
|
*/
|
|
|
|
import type { AccountMapping } from './types'
|
|
|
|
/** How many accounts are shown by number in the preview's chart card. */
|
|
export const CHART_SAMPLE_SIZE = 8
|
|
|
|
export interface ChartPlan {
|
|
/** Distinct mapped target accounts absent from chart_of_accounts today. */
|
|
toCreate: number
|
|
/** Distinct mapped target accounts already present in chart_of_accounts. */
|
|
existing: number
|
|
/** First few accounts that will be created, for the preview card. */
|
|
sample: { number: string; name: string }[]
|
|
}
|
|
|
|
/**
|
|
* Split the distinct target accounts of `mappings` into those absent from the
|
|
* company's chart and those already present.
|
|
*
|
|
* Only mapped accounts count: syncMappedAccounts inserts targets, and the
|
|
* import refuses to run while any account is unmapped. An unmapped source is
|
|
* therefore neither "läggs till" nor "finns redan"; it stays in the card's
|
|
* "Ej mappade" count until the user creates it or maps it.
|
|
*
|
|
* Counts targets, not sources, so two sources remapped onto one target count
|
|
* once, the same way the insert pass dedupes.
|
|
*
|
|
* The sample shows the name the import will give the account: the file's
|
|
* #KONTO name for an identity mapping (the default, "Använd kontonamn från
|
|
* filen" on), else the BAS name the mapping resolved to.
|
|
*/
|
|
export function planChartChanges(
|
|
mappings: AccountMapping[],
|
|
existingNumbers: ReadonlySet<string>,
|
|
): ChartPlan {
|
|
const seen = new Set<string>()
|
|
const toCreate: { number: string; name: string }[] = []
|
|
let existing = 0
|
|
|
|
for (const m of mappings) {
|
|
const number = m.targetAccount
|
|
if (!number || seen.has(number)) continue
|
|
seen.add(number)
|
|
if (existingNumbers.has(number)) {
|
|
existing += 1
|
|
} else {
|
|
const fileName = m.sourceName?.trim()
|
|
const name =
|
|
m.sourceAccount === m.targetAccount && fileName ? fileName : m.targetName || fileName || ''
|
|
toCreate.push({ number, name })
|
|
}
|
|
}
|
|
|
|
toCreate.sort((a, b) => a.number.localeCompare(b.number))
|
|
|
|
return {
|
|
toCreate: toCreate.length,
|
|
existing,
|
|
sample: toCreate.slice(0, CHART_SAMPLE_SIZE),
|
|
}
|
|
}
|