* feat(supplier-invoices): show registered invoices under "Att betala" with inline approve Registered supplier invoices are already booked as debt (2440) but were hidden from the "Att betala" tab until approved, which confused users. The tab now shows registered invoices too, marked "Ej godkand" with a compact inline approve button. Approval remains the gate for payment, not visibility; status model and approve API untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(reports): add date range filter to huvudbok (kontoanalys) Mounts the existing ReportDateRange control on /reports/huvudbok so the ledger can be narrowed to any date range within the fiscal year, matching Fortnox kontoanalys. Lines before the range roll into each account's opening balance so running balances stay correct at the range start; lines after the range are dropped. Applies to the XLSX export too. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(invoices): add optional payment link on invoices (paste-link MVP) The user pastes a payment link created in their PSP dashboard (e.g. a Stripe Payment Link) onto an invoice. The recipient gets a "Betala online" button in the invoice email and a QR code + clickable link in the PDF payment box. No PSP integration server-side: this is the demand probe; a future Stripe Connect integration would auto-fill the same column. - invoices.payment_link_url (migration 20260709090000), https-only + 2048-char cap enforced in CreateInvoiceSchema; empty string normalises to undefined and build-invoice-write always writes a concrete value so clearing the field on a draft edit NULLs the column - editor field (real invoices only) with one-link-per-invoice hint; strings in sv+en (messages landed via e0e11066) - email button (customer.language, hidden for credit notes/proforma/ delivery notes, URL escaped for the href attribute) + URL in the plain-text part - PDF QR + link row following the Swish QR pattern; wired into send, download and preview routes - derived documents (credit note, proforma convert, recurring) do NOT copy the link: it encodes one amount for one specific invoice - MCP gnubok_create_invoice accepts payment_link_url (validated at staging and re-checked in the commit executor); v1 API exposes the column; tools/list token ceiling bumped 45K -> 45.5K (ledger entry in payload-size.bench.test.ts, headroom was <10 tokens) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(invoices): show oresavrundning on editor/form totals, supplier list and invoice email The rounding logic (getDisplayTotal) was correct but only applied on the PDF, invoice list/detail and review dialog. The invoice editor summary, the supplier invoice form totals and the supplier invoice list showed the raw ore total right next to the toggle, and the invoice email said "Att betala" with the unrounded invoice.total while the attached PDF showed the rounded amount (and the email also ignored the ROT/RUT deduction). Extract the PDF's Att betala block into getAmountToPay (lib/invoices/rounding.ts) and point PDF + email at it so they cannot drift; behavior-identical refactor for the PDF. Booked amounts stay ore-exact; display-only as designed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(reports): adapt huvudbok date-range tests to the two-step entry-lines fetch The date-range tests (0969168f) mocked the old single-query shape with the parent entry embedded on each line; main's refactor (fetchEntryLines) queries journal_entries first and reattaches. Queue entry rows like the other tests so the merge of the two features is actually exercised. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(invoices): fetch full invoice projection in v1 send so ROT/RUT deduction and payment link reach the PDF and email The v1 send route's hand-rolled column list omitted deduction_total, deduction_personnummer_last4, payment_link_url and the item-level ROT/RUT fields, so invoices sent via the public API overstated 'Att betala' and dropped the deduction box. Reuse the shared INVOICE_FULL_COLUMNS/INVOICE_ITEM_FULL_COLUMNS so the send row can never drift from the GET shape again. Also harden the supplier-invoice inline approve: a thrown fetch left the button stuck spinning; failures now refetch the true server state. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
106 lines
7.1 KiB
TypeScript
106 lines
7.1 KiB
TypeScript
import { describe, it, expect } from 'vitest'
|
|
import { tools, deriveToolMeta } from '../server'
|
|
|
|
describe('tools/list payload size guard', () => {
|
|
it('keeps the projected tools/list payload under the context-budget ceiling', () => {
|
|
// Mirror the real tools/list serializer, including the derived staging
|
|
// _meta (requires_approval / approve_tool / preflight) merged over any
|
|
// literal _meta: otherwise the guard under-measures the wire payload.
|
|
const projection = tools.map((t) => {
|
|
const meta = { ...(deriveToolMeta(t) ?? {}), ...(t._meta ?? {}) }
|
|
return {
|
|
name: t.name,
|
|
...(t.title ? { title: t.title } : {}),
|
|
description: t.description,
|
|
inputSchema: t.inputSchema,
|
|
...(t.outputSchema ? { outputSchema: t.outputSchema } : {}),
|
|
annotations: t.annotations,
|
|
...(Object.keys(meta).length > 0 ? { _meta: meta } : {}),
|
|
}
|
|
})
|
|
const payload = JSON.stringify({ tools: projection })
|
|
const approxTokens = Math.round(payload.length / 4)
|
|
// Ceiling progression: 20K → 25K → 30K → 31K → 31.5K → 32K → 36K.
|
|
// * 20K → 25K when item 8 of the agent-native API plan landed
|
|
// (additionalProperties: false on all inputSchemas + period_status in the
|
|
// staged operation envelope).
|
|
// * 25K → 30K when the agentic branch merged with main: catalog grew from
|
|
// ~75 to 83 tools (added gnubok_create_supplier, gnubok_list_pending_operations,
|
|
// gnubok_approve_pending_operation, gnubok_reject_pending_operation,
|
|
// gnubok_set_inbox_extracted_data from main + gnubok_get_agent_briefing,
|
|
// _remember_fact, _forget_fact, _feedback from the agent branch).
|
|
// * 30K → 31K when gnubok_match_batch_allocate and
|
|
// gnubok_bulk_book_transactions landed (PRs #603/#606/#608/#610). Each
|
|
// adds the shared STAGED_OPERATION_SCHEMA + a non-trivial inputSchema
|
|
// for the multi-tx flows. Descriptions already trimmed to 230-260 chars.
|
|
// * 31K → 31.5K when gnubok_link_transaction_to_journal_entry landed (PR
|
|
// #614). Same family as match_batch_allocate / bulk_book_transactions:
|
|
// closes the MCP parity gap with the existing REST endpoint so agents
|
|
// can attach a bank tx to an already-posted verifikat without creating
|
|
// duplicate bookkeeping. Description trimmed to ~180 chars.
|
|
// * 31.5K → 32K when gnubok_find_voucher_candidates_for_supplier_invoice +
|
|
// gnubok_link_supplier_invoice_to_voucher landed: the supplier-side
|
|
// mirror of the customer find/link voucher tools. The link tool inlines
|
|
// the shared STAGED_OPERATION_SCHEMA. Lets agents mark a leverantörs-
|
|
// faktura paid against an already-posted verifikat (no new bokföring),
|
|
// which is exactly the fix for invoices imported from Fortnox as open
|
|
// payables while their payment already exists in the SIE-imported GL.
|
|
// * 32K → 36K when top-level Tool.title (MCP spec 2025-06-18) landed on all
|
|
// 92 tools for Connectors Directory readiness; the ~10 longest descriptions
|
|
// were trimmed toward 180-200 chars to partly offset. Headroom reserved for
|
|
// the upcoming Skatteverket tools.
|
|
// * Held at 36K when gnubok_list_accrual_schedules (add/bokslut) merged with
|
|
// the categorize vat_amount override (#717): the combination crossed the
|
|
// ceiling by ~75, offset by trimming the 8 longest descriptions to ~200 chars.
|
|
// * 36K → 38K with the MCP legibility pass: the machine-readable staging
|
|
// contract now emits `_meta { requires_approval, approve_tool, preflight }`
|
|
// on every staging write (~40 tools) so an agent can tell: without reading
|
|
// prose: which writes need a follow-up gnubok_approve_pending_operation and
|
|
// which have a pre-flight; gnubok_get_agent_briefing also gained a `company`
|
|
// identity block in its outputSchema. This is wire data the agent depends
|
|
// on, not trimmable prose: hence a bump rather than a description trim.
|
|
// * 38K → 40K as the catalog grew from 92 to 103 tools (gnubok_link_document_
|
|
// to_voucher #804, gnubok_bulk_book_inbox_items, the categorize-core additions,
|
|
// plus per-line supplier-invoice overrides). Each new tool carries its
|
|
// inputSchema + staging _meta; the growth is genuine wire data, not prose,
|
|
// so descriptions are already at their trimmed floor (~180-220 chars).
|
|
// * 40K → 42K with dimensions PR3: gnubok_list_dimensions +
|
|
// gnubok_list_dimension_values (nested registry output schemas) + staged
|
|
// gnubok_create_dimension_value (STAGED_OPERATION_SCHEMA + _meta), the
|
|
// dims bag + default_dimensions on create_voucher/correct_entry, and the
|
|
// agent-briefing dimensions block. Descriptions were trimmed first
|
|
// (~200 tokens recovered); the remainder is schema structure agents
|
|
// depend on for resolve-don't-select, not trimmable prose.
|
|
// * 42K → 43K with dimensions PR4 reports: gnubok_get_dimension_pnl (the
|
|
// value-as-column matrix outputSchema is the wire contract agents read
|
|
// the report through), the shared `dimensions` filter arg + echo props
|
|
// on trial balance / income statement / general ledger, and
|
|
// group_by/group_by_dimension + totals_scope + groups on
|
|
// gnubok_query_journal. Descriptions trimmed first (~100 tokens
|
|
// recovered); the ~55-token remainder is schema structure.
|
|
// * 43K → 44K with dimensions PR7 producers: default_dimensions + per-item/
|
|
// per-line dims bags on gnubok_create_invoice, gnubok_create_supplier_
|
|
// invoice_from_inbox, gnubok_categorize_transaction and
|
|
// gnubok_bulk_book_transactions (8 new object properties). Descriptions
|
|
// already use the compact "Dims bag" form (~90 tokens trimmed first);
|
|
// the remainder is schema structure the resolve-don't-select contract
|
|
// depends on, not trimmable prose.
|
|
// * 44K → 45K when the rot/rut branch merged with main: main's #877 put
|
|
// qualified identifiers in all tool output schemas (+~260 across 103
|
|
// tools: wire contract, not prose) and the branch added
|
|
// gnubok_generate_rot_rut_file (~444: begäran-om-utbetalning file flow,
|
|
// eligible/blocked per-invoice output). Each side alone was under the
|
|
// ceiling; the combination crossed it by ~220. Descriptions are at
|
|
// their trimmed floor per the entries above.
|
|
// * 45K → 45.5K when payment_link_url landed on gnubok_create_invoice
|
|
// (manual payment-link MVP): one optional string property with an
|
|
// already-minimal ~24-token description. Headroom before the change was
|
|
// under 10 tokens, so even this smallest possible addition crossed;
|
|
// other descriptions are at their trimmed floor per the entries above.
|
|
// Long-term answer to growth is leaning harder on gnubok_search_tools: if this
|
|
// fires again, prefer trimming descriptions or making a tool opt-in via search
|
|
// before bumping further.
|
|
expect(approxTokens).toBeLessThan(45_500)
|
|
})
|
|
})
|