The SIE-import mapping table was a fixed layout of 1216px, with 144px spent on a four-digit source account and the VAT cell's min-w-72 overflowing 32px into Konfidens, so on a laptop content column it scrolled sideways and read as cramped even after #1684 kept the confirm button reachable. - Column budget ~990px: Källkonto w-20, Källnamn w-40 (existing truncate + tooltip), arrow w-8, Målkonto w-56, VAT w-72 with the treatment select flex-1/min-w-0 and the rate select shrink-0, Konfidens w-24, Bekräfta w-28. - 13px text and px-3 cells, matching the page-level list density. - Bekräfta is an icon-only button (Check) with a tooltip; the header keeps the label and gains an InfoTooltip explaining what confirming does (new chart_of_accounts.vat_treatment_confirm_help, sv + en). Closes #2125 Claude-Session: https://claude.ai/code/session_01WFhSQWzu5SyXB6kG5ActZc Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -1457,6 +1457,7 @@ One line per decision: `[YYYY-MM-DD] <decision>: <why>`. Appended by agents and
|
||||
[2026-09-01] F2 bank-data staleness: ship freshness reads only (last_synced_at/consent_expires/error_message on gnubok_connect_bank + new GET /api/v1/.../bank-connections, scope companies:read mirroring the MCP mapping): the daily cron already syncs server-side, so visibility is what the incident lacked; an agent-triggerable sync is a product bet (EB call cost, runaway agents) and was deferred by Emil.
|
||||
[2026-09-01] Verifikationsserie in the Ny verifikation modal is a closed dropdown instead of a one-letter free-text field: a typo there silently opens a brand-new series with its own number sequence, and the letters only mean anything if everyone uses the same ones. The letters are NOT prescribed by law (BFL 5 kap. 7 § requires only unbroken systematic numbering within each series), and the incumbents disagree: Björn Lundén uses A Huvudserie, F Kundfakturor, I Inbetalningar, L Leverantörsfakturor, N Löner, U Utbetalningar, J Bokslut. We ship FORTNOX's table verbatim (A Redovisning, B Kundfakturor, C Inbetalningar från kunder, D Leverantörsfakturor, E Utbetalningar till leverantörer, F Kassa, G Avskrivning, H Periodisering, I Bokslut, J Revisor, K Lön, L Kontantfaktura, M Momsrapport), from their own Systemdokumentation, because Fortnox is the system most companies migrate here from and an imported ledger should keep its meaning. REJECTED an earlier draft that labelled A as Kundfakturor: A is the general series manual entries land in (the one point Fortnox and BL agree on, and Fortnox allows manuell kontering ONLY in A), and migration 20260526120700 ships every source_type defaulting to 'A', so every existing company's A series already holds everything. Calling it Kundfakturor would mislabel their entire history and the modal's own default. The list is closed but any letter the company already configured, or that a draft was saved with, is appended so no existing value can fall out of the picker. Also: tabbing or clicking into an untouched amount field now proposes the outstanding difference (pre-selected, so typing replaces it) when the row already has an account and the difference belongs on that side. This deliberately reverses part of the note in updateLine that said a balancing amount must never auto-fill: that note was about filling on ACCOUNT selection, which stole the amount before the user had a chance to split it. Filling on focus keeps the split case intact because the proposal is selected text, and it fixes the common moms case where the last line is just the remainder.
|
||||
[2026-09-01] Settings PUT cross-field VAT validations scoped to touched field groups (vat-completeness, 40m-monthly, periodisk sammanstallning), not fixed at onboarding: partial saves from surfaces without VAT fields (invoice bank-details dialog) were hard-blocked by pre-existing vat_registered-without-number state (Marketio Lab case). The invariant still holds on every save that touches its group; explicit null now counts as a clear instead of falling back to the stored value during validation. Onboarding-side VAT number collection left as follow-up.
|
||||
[2026-09-01] #2125 mapping table: kept the 7 columns and shrank the fixed layout from 1216px to ~990px (Källkonto 144->80, Källnamn 256->160 with the existing truncate+tooltip, 13px text, px-3 cells, icon-only Bekräfta with the label in the header + InfoTooltip) instead of folding Källnamn under Källkonto: the reporters asked for narrower columns, closer column 2, an icon confirm and smaller text, and the #1684 sticky-scroll fallback still covers narrower panels (agent dock open). Also dropped the VAT cell's min-w-72, which overflowed 32px into Konfidens under table-fixed.
|
||||
[2026-09-01] #2127 skattekonto bulk: every unbooked, non-ignored skattekonto row in the inbox is selectable (isSkvSelectable); bulk Bokför keeps re-filtering through isSkvBulkEligible (button count, summary and submit read one skvBookableSelectedRows list) and bulk Ignorera spans bank + skattekonto selections in one confirmation, calling the per-row PATCH .../ignore 5-wide since no batch endpoint exists. Bullet 2 of the issue (unbooked skattekonto rows "not in att göra after migration") is scoped out: neither Hem's Att göra (lib/worklist book_transaction) nor the nav badge counts skattekonto_transactions, by construction of the canonical predicate, while the inbox itself lists them regardless of date. Whether skattekonto rows join the Att bokföra count is a founder call; reply asks the reporter where they looked.
|
||||
[2026-09-01] #2128 (row checkbox always visible) left open, no PR: #2093 (merged the same morning, after the Discord report) already made CHECKBOX_REVEAL_CLASS rest at opacity-50 with border-foreground and go solid on hover/focus/checked/coarse pointer, on all 8 list surfaces. The literal ask (fully solid at rest) is a one-token change to that constant but a design change across every list page, so it stays with the founder rather than being bumped in a bug-fix batch.
|
||||
[2026-09-01] #2126 payment-account-missing wording: made the message currency-aware on the client (getErrorMessage branch on details.currency via describeMissingInvoicePaymentAccount) plus a currency-neutral rewrite of the registry entry, instead of threading messageSv/messageEn through the nine server emit sites: every dashboard caller already sends details.currency, API/MCP consumers get the clarified registry text (names bankgiro/plusgiro/Swish for SEK, IBAN otherwise), and the staged-operation commit path (bare string) calls the helper directly. The reporter saw the pre-#2088 text; #2088 added the Inställningar -> Fakturering pointer the same evening, this removes the "valutakonto" reading.
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
import {
|
||||
ArrowRight,
|
||||
Search,
|
||||
Check,
|
||||
CheckCircle,
|
||||
AlertCircle,
|
||||
XCircle,
|
||||
@@ -38,6 +39,7 @@ import {
|
||||
type AccountVatTreatment,
|
||||
} from '@/lib/vat/account-vat-treatment'
|
||||
import {
|
||||
InfoTooltip,
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
@@ -241,20 +243,26 @@ export default function AccountMappingStep({
|
||||
|
||||
{/* Mapping table */}
|
||||
<div className="overflow-hidden rounded-lg border">
|
||||
<Table className="table-fixed">
|
||||
{/* Under table-fixed the header widths ARE the layout: cells never
|
||||
grow them. The budget is ~990px so the table fits a laptop
|
||||
content column at 100 % zoom (#2125: 1216px overflowed, with
|
||||
144px spent on a four-digit source account); beyond that the
|
||||
wrapper scrolls and the confirm column stays sticky (#1668).
|
||||
13px text and px-3 cells match the page-level list density. */}
|
||||
<Table className="table-fixed text-[13px] [&_td]:px-3 [&_th]:px-3">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-36">Källkonto</TableHead>
|
||||
<TableHead className="w-64 max-w-64">Källnamn</TableHead>
|
||||
<TableHead className="w-12"></TableHead>
|
||||
<TableHead className="w-64">Målkonto</TableHead>
|
||||
{/* table-fixed sizes columns from the header's width only:
|
||||
min-w collapsed this column to nothing on laptop widths
|
||||
and its selects overflowed into Konfidens (2026-08-20). */}
|
||||
<TableHead className="w-20">Källkonto</TableHead>
|
||||
<TableHead className="w-40">Källnamn</TableHead>
|
||||
<TableHead className="w-8 !px-0" aria-hidden="true"></TableHead>
|
||||
<TableHead className="w-56">Målkonto</TableHead>
|
||||
<TableHead className="w-72">{t('vat_treatment_column')}</TableHead>
|
||||
<TableHead className="w-24">Konfidens</TableHead>
|
||||
<TableHead className="sticky right-0 z-20 w-32 min-w-32 border-l border-border bg-background text-right">
|
||||
{t('vat_treatment_confirm')}
|
||||
<TableHead className="sticky right-0 z-20 w-28 min-w-28 border-l border-border bg-background text-right">
|
||||
<span className="inline-flex items-center gap-1">
|
||||
{t('vat_treatment_confirm')}
|
||||
<InfoTooltip content={t('vat_treatment_confirm_help')} side="left" />
|
||||
</span>
|
||||
</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
@@ -265,11 +273,11 @@ export default function AccountMappingStep({
|
||||
className={cn('group', !mapping.targetAccount && 'bg-destructive/5')}
|
||||
>
|
||||
<TableCell className="font-mono">{mapping.sourceAccount}</TableCell>
|
||||
<TableCell className="max-w-64 text-muted-foreground">
|
||||
<TableCell className="text-muted-foreground">
|
||||
<TruncatedSourceName sourceName={mapping.sourceName} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<ArrowRight className="h-4 w-4 text-muted-foreground" />
|
||||
<TableCell className="!px-0">
|
||||
<ArrowRight className="mx-auto h-4 w-4 text-muted-foreground" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Select
|
||||
@@ -310,7 +318,7 @@ export default function AccountMappingStep({
|
||||
<TableCell>
|
||||
{mapping.sourceAccount === mapping.targetAccount &&
|
||||
['3', '4', '5', '6'].includes(mapping.sourceAccount.charAt(0)) ? (
|
||||
<div className="flex min-w-72 gap-2">
|
||||
<div className="flex gap-2">
|
||||
<Select
|
||||
value={mapping.defaultVatTreatment ?? 'none'}
|
||||
onValueChange={(value) => {
|
||||
@@ -326,7 +334,12 @@ export default function AccountMappingStep({
|
||||
onVatTreatmentChange(mapping.sourceAccount, treatment, rate)
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className={mapping.requiresVatTreatmentReview ? 'border-warning/60' : ''}>
|
||||
<SelectTrigger
|
||||
className={cn(
|
||||
'min-w-0 flex-1',
|
||||
mapping.requiresVatTreatmentReview && 'border-warning/60',
|
||||
)}
|
||||
>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -350,7 +363,7 @@ export default function AccountMappingStep({
|
||||
value === 'none' ? null : Number(value),
|
||||
)}
|
||||
>
|
||||
<SelectTrigger className="w-24" aria-label={t('vat_rate_label')}>
|
||||
<SelectTrigger className="w-24 shrink-0" aria-label={t('vat_rate_label')}>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -377,26 +390,34 @@ export default function AccountMappingStep({
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className={cn(
|
||||
'sticky right-0 z-10 w-32 min-w-32 border-l border-border transition-colors',
|
||||
'sticky right-0 z-10 w-28 min-w-28 border-l border-border text-right transition-colors',
|
||||
mapping.targetAccount ? 'bg-background' : 'bg-destructive/5',
|
||||
'group-hover:bg-muted/50 group-focus-within:bg-muted/50',
|
||||
)}
|
||||
>
|
||||
{mapping.requiresVatTreatmentReview && !mapping.vatTreatmentReviewed && (
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="min-h-11 w-full sm:min-h-8"
|
||||
aria-label={`${t('vat_treatment_confirm')}: ${mapping.sourceAccount}`}
|
||||
onClick={() => onVatTreatmentChange(
|
||||
mapping.sourceAccount,
|
||||
mapping.defaultVatTreatment ?? null,
|
||||
mapping.defaultVatRate ?? null,
|
||||
)}
|
||||
>
|
||||
{t('vat_treatment_confirm')}
|
||||
</Button>
|
||||
/* Icon-only: the column header carries the label and
|
||||
the tooltip repeats it on hover; the accessible name
|
||||
also says which row. */
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="h-11 w-11 sm:h-8 sm:w-8"
|
||||
aria-label={`${t('vat_treatment_confirm')}: ${mapping.sourceAccount}`}
|
||||
onClick={() => onVatTreatmentChange(
|
||||
mapping.sourceAccount,
|
||||
mapping.defaultVatTreatment ?? null,
|
||||
mapping.defaultVatRate ?? null,
|
||||
)}
|
||||
>
|
||||
<Check className="h-4 w-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="left">{t('vat_treatment_confirm')}</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
||||
+2
-1
@@ -5597,7 +5597,8 @@
|
||||
"vat_review_confirm_all": "Confirm all suggested ({count})",
|
||||
"vat_review_filter": "{count} VAT treatments to review",
|
||||
"vat_treatment_column": "VAT treatment",
|
||||
"vat_treatment_confirm": "Confirm"
|
||||
"vat_treatment_confirm": "Confirm",
|
||||
"vat_treatment_confirm_help": "Accept the VAT code for this row to mark it as reviewed. Change the VAT code or rate first if the suggestion is wrong."
|
||||
},
|
||||
"dimensions": {
|
||||
"new_value": "New value",
|
||||
|
||||
+2
-1
@@ -5597,7 +5597,8 @@
|
||||
"vat_review_confirm_all": "Bekräfta alla föreslagna ({count})",
|
||||
"vat_review_filter": "{count} momskoder att granska",
|
||||
"vat_treatment_column": "Momskod",
|
||||
"vat_treatment_confirm": "Bekräfta"
|
||||
"vat_treatment_confirm": "Bekräfta",
|
||||
"vat_treatment_confirm_help": "Godkänn momskoden för raden så räknas den som granskad. Ändra momskod eller momssats först om förslaget inte stämmer."
|
||||
},
|
||||
"dimensions": {
|
||||
"new_value": "Nytt värde",
|
||||
|
||||
Reference in New Issue
Block a user