'use client' import Link from 'next/link' import { useState } from 'react' import { useTranslations } from 'next-intl' import { SettingsFormWrapper } from '@/components/settings/SettingsFormWrapper' import { SettingsLoadError } from '@/components/settings/SettingsLoadError' import { SettingsLoadingSkeleton } from '@/components/settings/SettingsLoadingSkeleton' import { PeriodLockingSettings } from '@/components/settings/PeriodLockingSettings' import { FiscalYearsManager } from '@/components/settings/FiscalYearsManager' import { VoucherSeriesManager } from '@/components/settings/VoucherSeriesManager' import { VoucherSeriesPerSourceTypeForm } from '@/components/settings/VoucherSeriesPerSourceTypeForm' import { applyDefaultSeriesToMap } from '@/lib/bookkeeping/voucher-series-resolver' import { PeriodiseringAutoDetectToggle } from '@/components/settings/PeriodiseringAutoDetectToggle' import { DimensionsToggle } from '@/components/settings/DimensionsToggle' import { AccountingFrameworkForm } from '@/components/settings/AccountingFrameworkForm' import { SettingsGroup, SettingsRow, SettingsSectionHeader, SettingsSelect, } from '@/components/settings/SettingsRows' import { useSettings } from '@/components/settings/useSettings' import { useCompany } from '@/contexts/CompanyContext' import { ExternalLink } from 'lucide-react' import type { AccountingFramework, CompanySettings } from '@/types' const SERIES_OPTIONS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('') export function BookkeepingSettingsContent() { const t = useTranslations('settings_bookkeeping') const tNav = useTranslations('settings_nav') const tIntro = useTranslations('settings_intro') const { settings, isLoading, updateSettings, refetch } = useSettings() const { company } = useCompany() // Local mirror of the company-level accounting_framework so the K2/K3 // selector can reflect its own saves without waiting for the layout to // re-render through the server. Falls back to k2 (matches the column // default) until the company row is loaded. const [framework, setFramework] = useState( company?.accounting_framework ?? 'k2', ) if (isLoading) return if (!settings) return function handleSave(formData: FormData) { const autoLockValue = formData.get('auto_lock_period_days') as string const lockedThrough = (formData.get('bookkeeping_locked_through') as string) || null const accountingMethod = (formData.get('accounting_method') as string) || 'accrual' const defaultVoucherSeries = (formData.get('default_voucher_series') as string) || 'A' // Deferred booking is an accrual-only concept (#967): normalize to false // under kontantmetoden so switching back to accrual can never re-activate // a stale flag the user set in a mode where it had no effect. const deferInvoiceBooking = accountingMethod === 'accrual' && formData.get('defer_invoice_booking') === 'true' const updates: Record = { bookkeeping_locked_through: lockedThrough, auto_lock_period_days: autoLockValue === 'none' ? null : parseInt(autoLockValue), accounting_method: accountingMethod, default_voucher_series: defaultVoucherSeries, defer_invoice_booking: deferInvoiceBooking, } // Write-through: the booking engine resolves the series from the // per-source-type map, NOT from default_voucher_series. So when the user // changes the global default, propagate it across the map, but only for // types that were still following the previous default, leaving explicit // per-type overrides (set via VoucherSeriesPerSourceTypeForm) untouched. // Without this the "Standardserie" dropdown is a no-op for bookkeeping. // Only runs when the series actually changed, so saving the form for an // unrelated reason (e.g. the lock date) never rewrites the map. const prevDefault = settings?.default_voucher_series || 'A' const currentMap = settings?.default_voucher_series_per_source_type if (currentMap && defaultVoucherSeries !== prevDefault) { updates.default_voucher_series_per_source_type = applyDefaultSeriesToMap( currentMap, prevDefault, defaultVoucherSeries, ) } return { updates, onSuccess: (data: Record) => { updateSettings(data as Partial) }, } } // K2/K3 selector is only meaningful for AB. EF stays on EF rules and never // picks a framework. Use the company row (source of truth) since // company_settings.entity_type can be stale on legacy data. const isAktiebolag = company?.entity_type === 'aktiebolag' return (
{/* Grunder: framework (AB only), method, deferred booking, default series. The framework row saves through its own PATCH and opts out of this wrapper's dirty tracking; the rest read via FormData. */} {isAktiebolag && ( setFramework(next)} /> )} {/* #967: register/send without booking; ekonomi books in a separate explicit step. Only meaningful under faktureringsmetoden. */} {SERIES_OPTIONS.map((letter) => ( ))} {t('related_chart_of_accounts')}
) }