fix(mcp): correct e-invoice capability guidance (#1580)

Closes #1577. Native Peppol and EN 16931 support remains tracked in #546.
This commit is contained in:
Mattsson
2026-08-13 15:29:32 +02:00
committed by GitHub
parent 9c891ee72d
commit 36393b1f8d
7 changed files with 17588 additions and 9 deletions
@@ -164,7 +164,9 @@ Electronics >100k SEK/invoice?
---
## Peppol essentials (for Accounted e-invoice generation)
## Peppol essentials for externally delivered e-invoices
Accounted currently creates PDF invoices and can send them by email. It does not generate e-invoice XML or deliver invoices through Peppol. If a customer requires a structured e-invoice, use an external e-invoice provider for delivery, then record the delivery with `gnubok_mark_invoice_as_sent`.
Format: UBL 2.1 XML, profile Peppol BIS Billing 3.0.
TypeCodes: **380** = invoice, **381** = credit note, **389** = self-billing.
@@ -207,4 +209,4 @@ These values change. Always verify against the reference file or search current
- Combined max: 75,000 SEK (separated in 2024 H2)
- Electronics RC threshold: 100,000 SEK excl. VAT per invoice
- Skattetillägg VAT: 20% (periodization: 2-5%)
- Archive retention: 7 years (BFL 7 kap)
- Archive retention: 7 years (BFL 7 kap)
+2
View File
@@ -2,6 +2,8 @@
One line per decision: `[YYYY-MM-DD] <decision>: <why>`. Appended by agents and humans when a non-obvious choice is made (approach picked over an alternative, dependency declined, action stopped by a CLAUDE.md rule). Read before re-litigating a past decision.
[2026-08-13] E-invoice product-truth correction covers the MCP workflow skills and the MCP-exposed swedish-invoice-compliance atom: the atom's "for Accounted e-invoice generation" heading made the same unsupported product claim as issue #1577, so all active guidance now directs external delivery followed by gnubok_mark_invoice_as_sent; Peppol implementation remains tracked in #546.
[2026-08-03] Issue #317 derives löneväxling pension and SLP at the shared salary-entry boundary from the frozen salary_runs.calculation_params rate snapshot: this fixes dashboard, MCP, and v1 booking without a schema migration, and prevents a live config change from altering an already reviewed run between calculation and posting.
[2026-08-01] Invoice payment dates stored in timestamptz use a shared UTC-noon representation: `paid_at` has date-only business semantics, and noon preserves the selected or bank transaction date when formatted in UTC, Europe/Stockholm, and all negative UTC offsets through UTC-12; UTC midnight displays as the prior day in American time zones.
@@ -1,6 +1,8 @@
/**
* Tests for skills over MCP: registry, discovery tools, and resource exposure.
*/
import { readFileSync } from 'node:fs'
import { join } from 'node:path'
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { tools } from '../server'
import { workflowSkills, findSkill, SKILL_URI_PREFIX, skillUri, __resetAtomCache } from '../skills'
@@ -138,6 +140,25 @@ describe('Skills registry', () => {
}
})
it('does not advertise unsupported built-in e-invoice delivery', () => {
const invoiceComplianceAtom = readFileSync(
join(process.cwd(), '.claude/skills/swedish-invoice-compliance/SKILL.md'),
'utf8',
)
const allBodies = [...skills.map((skill) => skill.body), invoiceComplianceAtom].join('\n')
expect(allBodies).not.toMatch(/Accounted\s+(?:renders|generates|produces)[^.\n]*EN\s*16931/i)
expect(allBodies).not.toMatch(/Accounted\s+(?:handles|sends|delivers)[^.\n]*Peppol/i)
for (const slug of ['invoicing-rules', 'customer-onboarding']) {
const skill = skills.find((candidate) => candidate.slug === slug)
expect(skill?.body).toMatch(/external e-invoice provider/i)
expect(skill?.body).toContain('gnubok_mark_invoice_as_sent')
}
expect(invoiceComplianceAtom).toMatch(/external e-invoice provider/i)
expect(invoiceComplianceAtom).toContain('gnubok_mark_invoice_as_sent')
})
it('findSkill resolves the workflow skill or null (sync workflow lookup)', async () => {
const supabase = makeSupabaseWithEmptyAtomRegistry()
expect(await findSkill('month-end-close', supabase as never)).toBeTruthy()
@@ -30,7 +30,7 @@ later: much cheaper to ask the customer once at onboarding.
**Special cases:**
- **B2G (Swedish municipality/agency)**: still \`swedish_business\`, but the invoice must be Peppol-formatted (legal requirement since 2019-04-01). Accounted handles Peppol when the customer record has a Peppol endpoint configured.
- **B2G (Swedish municipality/agency)**: still \`swedish_business\`. If the customer requires Peppol or another e-invoice format, deliver the invoice through an external e-invoice provider, then use \`gnubok_mark_invoice_as_sent\` to record delivery. Accounted currently creates PDF/email invoices and does not generate or send Peppol invoices.
- **Consumer customer in another EU country (B2C distance sale)**: \`eu_business\` does NOT apply. Charge Swedish VAT (25/12/6 %) below the OSS threshold; above the threshold the company must register for OSS. This is rare for sole traders: flag the user if turnover suggests they're approaching the threshold.
## Workflow
@@ -79,7 +79,7 @@ Returns staged operation. User approves in web app → invoice number is allocat
\`gnubok_send_invoice(invoice_id)\`: emails the PDF to the customer. Requires email service configured (Resend) and customer email on file.
If the user delivered the invoice manually (printed, e-faktura via Peppol, etc.), use \`gnubok_mark_invoice_as_sent\` instead: same booking effect, no email.
If the user delivered the invoice manually (printed or sent through an external e-invoice provider), use \`gnubok_mark_invoice_as_sent\` instead: same booking effect, no email.
### Step 5: Record payment
@@ -110,9 +110,9 @@ For consumer-targeted services (RUT: städning, RUT) or construction (ROT):
This data goes on the invoice; Accounted's invoice template renders it automatically when set on the customer.
## Peppol / e-invoicing (B2G)
## External e-invoicing (including B2G)
Swedish authorities require e-invoices via Peppol BIS Billing 3.0 (Lag 2018:1277). For private B2B, the buyer's preference governs but Peppol is preferred. Accounted renders an EN 16931-compliant XML on demand.
Accounted currently creates PDF invoices and can send them by email. It does not generate e-invoice XML or deliver invoices through Peppol. If the customer requires an e-invoice, deliver it through an external e-invoice provider, then use \`gnubok_mark_invoice_as_sent\` to record the delivery and apply the same booking effect without sending another email.
## Critical rules
@@ -142,7 +142,7 @@ Swedish authorities require e-invoices via Peppol BIS Billing 3.0 (Lag 2018:1277
export const invoicingRulesSkill: Skill = {
slug: 'invoicing-rules',
name: 'Invoicing Rules',
summary: 'Mandatory invoice fields (ML 17 kap. 24 §), VAT treatment per customer type, ROT/RUT, Peppol, kreditfaktura.',
summary: 'Mandatory invoice fields (ML 17 kap. 24 §), VAT treatment, ROT/RUT, external e-invoicing, kreditfaktura.',
tags: ['invoicing', 'vat', 'compliance', 'eu', 'rot-rut'],
body,
tier: 'workflow',
+2 -2
View File
@@ -92,8 +92,8 @@
"version": 1
},
"horizontal/swedish-invoice-compliance": {
"hash": "e59a5cad1da2e4d21cdc495939c92f457280020da82e3c3b84ee830c08d72398",
"version": 5
"hash": "1ce94ae22e82bec31fdcfbf28d95d225097d150e1be0631bb1c3c41aa172bd44",
"version": 6
},
"horizontal/swedish-invoice-compliance/invoice-rules": {
"hash": "00f8b5a1e2883595f470216f1200d88481de9dc6aab3520bac7ab4589922a386",
File diff suppressed because it is too large Load Diff