* feat(mcp): add create_voucher + correct_entry MCP tools
The MCP toolset had no way to post a journal entry outside the preset
workflows (categorize_transaction, create_invoice, …). That blocks
legitimate flows the engine already supports — K3 capitalization to BAS
1010, period-end accruals, FX adjustments, prepayments, and rättelseposter
for foreign reverse-charge VAT that landed on 2641 instead of 2614/2645.
create_voucher exposes the existing createJournalEntry() primitive:
arbitrary balanced lines, optional fiscal-period auto-resolution, staged
for human approval. correct_entry exposes correctEntry() (storno + new
corrected entry per BFL 5 kap 5§) so part of a posted verifikation can be
fixed without losing the legs that were right.
Both are HIGH risk in OPERATION_RISK_TIERS — the arbitrary account/amount/
period inputs make them compliance-critical despite being structurally
similar to uncategorize_transaction (medium). Approval flow unchanged; no
auto-commit, regardless of trust level.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(mcp): address PR #448 review — voucher tools hardening
Greptile P1 + compliance bot findings, all in one pass.
commitCreateVoucher (commit.ts):
- Hardcode source_type to 'manual' instead of reading from params. A future
direct-staging path or hand-inserted pending_operations row could
otherwise inject 'bank_transaction'/'invoice_created'/etc. and corrupt
the audit-trail origin.
- Re-validate balance defensively before reaching the engine, so a tampered
params row surfaces a clean Swedish 400 instead of an opaque engine error.
gnubok_create_voucher (server.ts):
- Validate the explicit fiscal_period_id when supplied: confirm it exists,
is open (is_closed = false), and that entry_date falls within its span.
Without this, a closed/locked period was only caught at commit-time with
a generic DB-trigger error.
- Throw at staging when any line targets an account that's missing from
chart_of_accounts or marked inactive, rather than relying on the
approver to spot the advisory flag.
- Remove source_type from the staged params blob entirely — the executor
ignores it anyway, no point letting it travel through.
- Add a comment that the staging-time period-lock check is advisory and
the executor is the authoritative guard, so future cleanup doesn't
remove either as 'redundant'.
Descriptions:
- gnubok_correct_entry now explicitly notes that the storno + corrected
entries land in the original period (defends against compliance bot's
speculative "different period" concern recurring on future reviews).
- Both tools' tax_code field gets a note that the BAS account number
drives momsdeklaration ruta mapping, not tax_code — guards against an
LLM treating tax_code as the VAT-routing dial.
commitCorrectEntry (commit.ts):
- Add a comment pointing at storno-service.ts:99,102,195,198 to make the
"uses original period and date" invariant explicit in this file.
Tests:
- +2 voucher-executors cases: source_type tampering is ignored, unbalanced
params return 400.
- +10 new voucher-tools tests (MCP layer): unbalanced, closed explicit
period, missing explicit period, entry_date outside period, unknown
account, inactive account, happy path + correct_entry registration +
unbalanced replacement.
720 tests pass in the impacted suites; full suite 2998/2998.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>