fix(settings): show series names in the verifikationsserie per typ picker (#2295)
* fix(settings): show series names in the verifikationsserie per typ picker The "Verifikationsserier per typ" selects offered bare letters A to Z while the manual verifikat dialog and the per-bankkonto picker already show the letter with its Swedish name. Use the same closed preset list here, keep any letter the company already uses so no saved value drops out, and correct the help text, which named series that contradicted the presets. Reported by a byrå partner on 2026-09-03. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017othUwkVfteSUf5q1CxPeC * fix(settings): keep saved non-preset series selectable and name the convention Seed the extras from the saved per-type map as well as the draft, so a non-preset letter stays in the list after the user changes that row away from it (a misclick could otherwise not be undone without a reload) and a letter that lands in settings after mount is offered. Tie the help text to the Fortnox convention instead of claiming general Swedish practice: the SIE-world convention differs and the letter is a free choice. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017othUwkVfteSUf5q1CxPeC --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
a870c7f03e
commit
abaab1bf8d
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { useTranslations } from 'next-intl'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { useToast } from '@/components/ui/use-toast'
|
||||
@@ -13,9 +13,10 @@ import {
|
||||
} from '@/components/settings/SettingsRows'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { getErrorMessage } from '@/lib/errors/get-error-message'
|
||||
import { VOUCHER_SERIES_PRESETS } from '@/lib/bookkeeping/voucher-series-resolver'
|
||||
import type { CompanySettings, JournalEntrySourceType } from '@/types'
|
||||
|
||||
const SERIES_OPTIONS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('')
|
||||
const SERIES_LETTER_RE = /^[A-Z]$/
|
||||
|
||||
// Subset of source_types presented to the user. The DB column accepts every
|
||||
// JournalEntrySourceType, but several values (storno, correction, etc.) are
|
||||
@@ -82,6 +83,29 @@ export function VoucherSeriesPerSourceTypeForm({ settings, onSettingsUpdated }:
|
||||
const [isSaving, setIsSaving] = useState(false)
|
||||
const [showAll, setShowAll] = useState(false)
|
||||
|
||||
// Same closed list as the manual verifikat form and the per-bankkonto
|
||||
// picker: the fixed Swedish presets, then any letter already configured in
|
||||
// settings that the presets do not cover. The saved map is read alongside
|
||||
// the draft so a non-preset letter stays selectable after the user changes
|
||||
// that row away from it (otherwise a misclick could not be undone without
|
||||
// a reload) and so a letter that lands in settings after mount is offered.
|
||||
// A free A-Z list would let a typo start an undocumented series.
|
||||
const seriesOptions = useMemo(() => {
|
||||
const preset = new Set(VOUCHER_SERIES_PRESETS.map((p) => p.letter))
|
||||
const extras = [
|
||||
settings.default_voucher_series,
|
||||
...Object.values(settings.default_voucher_series_per_source_type ?? {}),
|
||||
...Object.values(draft),
|
||||
].filter(
|
||||
(v): v is string => typeof v === 'string' && SERIES_LETTER_RE.test(v) && !preset.has(v),
|
||||
)
|
||||
const uniqueExtras = Array.from(new Set(extras)).sort()
|
||||
return [
|
||||
...VOUCHER_SERIES_PRESETS,
|
||||
...uniqueExtras.map((letter) => ({ letter, label: '' })),
|
||||
]
|
||||
}, [settings.default_voucher_series, settings.default_voucher_series_per_source_type, draft])
|
||||
|
||||
const handleChange = (sourceType: JournalEntrySourceType, value: string) => {
|
||||
setDraft((prev) => ({ ...prev, [sourceType]: value }))
|
||||
}
|
||||
@@ -142,9 +166,9 @@ export function VoucherSeriesPerSourceTypeForm({ settings, onSettingsUpdated }:
|
||||
onChange={(e) => handleChange(key, e.target.value)}
|
||||
className="font-mono"
|
||||
>
|
||||
{SERIES_OPTIONS.map((letter) => (
|
||||
<option key={letter} value={letter}>
|
||||
{letter}
|
||||
{seriesOptions.map((option) => (
|
||||
<option key={option.letter} value={option.letter}>
|
||||
{option.label ? `${option.letter} ${option.label}` : option.letter}
|
||||
</option>
|
||||
))}
|
||||
</SettingsSelect>
|
||||
@@ -157,7 +181,7 @@ export function VoucherSeriesPerSourceTypeForm({ settings, onSettingsUpdated }:
|
||||
return (
|
||||
<SettingsGroup
|
||||
label="Verifikationsserier per typ"
|
||||
help="Tilldela en standardserie per typ av verifikat. Vanlig svensk praxis: leverantörsfakturor på serie B, löner på serie C, övrigt på serie A. Kan alltid ändras per verifikat när du bokför."
|
||||
help="Tilldela en standardserie per typ av verifikat. Namnen i listan följer Fortnox-konventionen: kundfakturor på serie B, leverantörsfakturor på serie D, löner på serie K, övrigt på serie A. Andra program använder andra bokstäver; bokstaven är ett fritt val. Kan alltid ändras per verifikat när du bokför."
|
||||
>
|
||||
{alwaysVisible.map((entry, i) =>
|
||||
// The last always-visible row sits right above the fold toggle:
|
||||
|
||||
Reference in New Issue
Block a user