feat(transactions): AI booking proposal in the quick-review dialog (cascade step 3) (#1782)
Wires the auto-booking cascade to the UI. When the quick-review dialog opens
for a transaction, AiCategorizeProposal fetches POST /api/agent/categorize
(Tier 1 deterministic candidates → Tier 2 model selector, provider-agnostic)
and:
- pre-fills the dialog's account + VAT from the model's pick (through
handleAccountChange, so class-2 VAT clearing is preserved),
- shows a confidence band (säker / trolig / välj konto), a short "Varför", and
the candidate alternatives (click one to re-apply),
- falls back SILENTLY to the deterministic defaults on error, and shows a soft
note when no AI backend is configured — the dialog always works without AI.
Surfaced inside the existing dialog (not a new card) so it reuses the proven,
balanced commit path. No silent auto-posting: "säker" is pre-filled and booked
with the dialog's existing one-tap Bokför; hands-off auto-book waits for
calibration (avoids any storno-on-undo).
lint + guards clean; 94 transaction/categorize tests green (no regressions).
Strings inline Swedish for now (lift to messages/{sv,en} pre-merge). UI PR:
awaiting founder visual sign-off before merge.
Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Jakob Wennberg
Claude Opus 4.8
parent
e7a5e65ecf
commit
0531576807
@@ -27,6 +27,7 @@ import InboxDocumentPicker from '@/components/bookkeeping/InboxDocumentPicker'
|
||||
import type { UploadedFile } from '@/components/bookkeeping/DocumentUploadZone'
|
||||
import type { AvailableInboxDoc } from '@/components/bookkeeping/InboxDocumentPicker'
|
||||
import VatTreatmentSelect from './VatTreatmentSelect'
|
||||
import AiCategorizeProposal from './AiCategorizeProposal'
|
||||
import { VAT_TREATMENT_OPTIONS } from './transaction-types'
|
||||
import type { TransactionWithInvoice } from './transaction-types'
|
||||
import type { TransactionCategory, VatTreatment, BASAccount, EntityType, LinePatternEntry } from '@/types'
|
||||
@@ -439,6 +440,22 @@ export default function QuickReviewDialog({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* AI booking proposal: pre-fills account + VAT and explains why.
|
||||
Falls back silently to the deterministic defaults on error. */}
|
||||
{tx.id && (
|
||||
<AiCategorizeProposal
|
||||
key={tx.id}
|
||||
transactionId={tx.id}
|
||||
open={open}
|
||||
onApply={(account, vat) => {
|
||||
handleAccountChange(account)
|
||||
// handleAccountChange clears VAT for class-2 accounts; for the
|
||||
// rest, apply the proposed treatment.
|
||||
if (!account.startsWith('2')) setVatTreatment(vat)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Template or Category */}
|
||||
<div>
|
||||
<label className="text-sm font-medium text-muted-foreground">
|
||||
|
||||
Reference in New Issue
Block a user