fix(skattekonto): route AGI draw back to 2731 to match salary module (#1905)

* fix(skattekonto): route AGI draw back to 2731 to match salary module (#1870)

Migration 20260519160000 moved the skattekonto AGI seed to 2730 while the
salary module kept crediting 2731, splitting the employer-contribution
liability across two accounts that never net at account level (both carry
SRU 7231, so only huvudbok reconciliation exposes the drift). Revert the
system seed to 2731: BAS 2026 defines 2731 as the reported-but-unpaid
arbetsgivaravgift liability (the accrual account is 2940), and the salary
ore-residual logic is built around 2731.

Historical 2730 debits since 2026-05-19 are left for per-company reclass
verifikat; the migration touches the system seed only.

Fixes #1870

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(skattekonto): bump migration version to avoid collision with 20260825120000_create_company_for_user

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(payroll): align remaining 2730 guidance surfaces on 2731 (#1870)

Skeptic regression finding: companies booking salary manually were taught
7510/2730 by in-product guidance, so the seed revert alone would re-create
the #1870 split mirrored for them. Align every guidance surface on 2731:

- packs/loneutbetalning.yaml legal_note
- MCP payroll-monthly skill (booking recipe and rate notes)
- swedish-payroll SKILL.md + references/bas-7xxx.md (2731 convention, 2730
  group-account alternative, never mixed; accrual is 2940) + regenerated
  agent atom seed (skills:generate -> 20260825180001)
- public/docs/systemdokumentation-mall.md

Also addresses the compliance review finding that the swedish-payroll skill
contradicted the migration.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Mattsson
2026-08-25 19:30:39 +02:00
committed by GitHub
co-authored by Claude Fable 5
parent a82328da84
commit 436cbf5304
10 changed files with 17619 additions and 16 deletions
+1 -1
View File
@@ -91,7 +91,7 @@ Karensavdrag = 20% of one week's sjuklön (80% of weekly pay). Day 2-14: 80% of
### Standard monthly journal entries
1. Gross salary: Debit 7210 / Credit 2710 (tax) + Credit 1930 (net pay)
2. Employer avgifter: Debit 7510 / Credit 2730
2. Employer avgifter: Debit 7510 / Credit 2731 (Avräkning lagstadgade sociala avgifter; this codebase's convention, cleared by the skattekonto AGI draw. 2730 is the group account: a legitimate simplification, but never mix the two within one company, see issue #1870. The accrual account is 2940, not 2731.)
3. Vacation accrual: Debit 7290 / Credit 2920
4. Avgifter on accrual: Debit 7519 / Credit 2940
5. Pension premiums: Debit 7410 / Credit 2440/2740
@@ -79,7 +79,8 @@
| Account | Name | Purpose |
|---|---|---|
| 2710 | Personalskatt | Tax withholding liability |
| 2730 | Lagstadgade sociala avgifter | Employer contribution liability |
| 2730 | Lagstadgade sociala avgifter och särskild löneskatt | Employer contribution liability (group account) |
| 2731 | Avräkning lagstadgade sociala avgifter | Reported-but-unpaid arbetsgivaravgifter; the account this codebase books and the skattekonto AGI draw clears. Use 2731 or 2730 consistently, never both in one company (issue #1870) |
| 2820/2821 | Löneskulder | Net pay liability |
| 2920 | Upplupna semesterlöner | Vacation pay liability |
| 2940/2941 | Upplupna lagstadgade sociala avgifter | Social charges on vacation liability |
@@ -88,7 +89,7 @@
## Standard monthly journal entry flow
1. Gross salary: Debit 7210 / Credit 2710 (tax withheld) + Credit 1930 (net pay)
2. Employer social charges: Debit 7510 / Credit 2730
2. Employer social charges: Debit 7510 / Credit 2731 (this codebase's convention; 2730 is the group-account alternative, never mixed with 2731 in the same company)
3. Vacation accrual: Debit 7290 / Credit 2920
4. Social charges on accrual: Debit 7519 / Credit 2940
5. Pension premiums: Debit 7410 / Credit 2440 or 2740
+1
View File
@@ -1237,4 +1237,5 @@ One line per decision: `[YYYY-MM-DD] <decision>: <why>`. Appended by agents and
[2026-08-25] Risk ID RISK-2026-08-25-INVOICE-BACKFILL-SNAPSHOT treatment record (PR #1901): Risk Owner and follow-up owner Emil; classification restricted financial remediation evidence pending BFL review; treatment preserves all 337 rows and merges only the anonymous-access containment; BFL retention/rattelse review deadline 2026-09-25; residual risk after containment Low, explicitly including postgres-owner bypass until that review. Retention or deletion requires the separate reviewed follow-up, and this PR must not delete or alter snapshot rows. This entry and PR #1901 are the repository-native Risk Treatment Plan reference because the repository has no risk register.
[2026-08-25] Supabase Auth bot protection uses dependency-free Cloudflare Turnstile with a two-step rollout: a missing public site key keeps existing Auth flows available, while a configured client fails closed until it has a token; provider enforcement is enabled only after the client deploy is verified. The generic Docker image always permits Cloudflare's script and frame origins because its optional site key is substituted at runtime, after the CSP has been built.
[2026-08-25] Plugin distribution goes through the Claude plugin directory (public GitHub link, claude plugin validate, submit from claude.ai admin-settings or Console), not an organisation marketplace: org marketplaces accept private/internal repos only and require the Claude GitHub App, so a public monorepo can never pass that dialog (the 'Repository not accessible' error is misleading). Install-time guidance is a /accounted:setup slash command, the convention Anthropic's own plugins use (commands/*-setup.md); no SETUP.md mechanism exists in the plugin spec.
[2026-08-25] Issue #1870: skattekonto AGI seed reverted 2730 -> 2731 (salary side kept on 2731), not the alternative of moving SALARY_ACCOUNTS.AVGIFTER_LIABILITY to 2730: BAS 2026 defines 2731 as exactly the reported-but-unpaid arbetsgivaravgift liability (the accrual account is 2940), and the salary module's whole-krona/ore-residual logic (PR #1609, 2026-08-14 decisions) is built around 2731. The 20260519160000 migration's rationale mislabeled 2731 as the accrual account; a one-sided flip either way reintroduces the split. Historical 2730 debits since 2026-05-19 are left for per-company reclass verifikat, not repaired in-migration.
[2026-08-25] The marketplace entry for the Accounted plugin is a git-subdir source (public repo URL + path claude-plugin), not the relative path ./claude-plugin: relative sources only resolve when the whole marketplace repo is cloned (Claude Code), while Claude.ai's Add-marketplace backend fetches the manifest and resolves each plugin source as a repository, which surfaced as 'Repository not accessible' on a public repo. git-subdir is also the form the plugin-directory catalog uses for monorepos.
@@ -52,7 +52,7 @@ Variable lines (overtime, weekend supplement, milage, traktamente, förmåner) a
- **Skatteavdrag**: tax-table lookup (skattetabell + kolumn → table column for the gross level)
- **Nettolön** (net): bruttolön − skatteavdrag
- **Sociala avgifter (arbetsgivaravgifter)**: 31.42 % of bruttolön (standard 2025). Reduced rates apply to specific age groups: always check the current statutory rates before relying on these:
- **Born 1937 or earlier**: **0 %**: no avgifter at all (oldest cohort, never paid into the modern pension system). Easy to miss; the BAS journal entries for 7510/2730 simply don't apply for these employees.
- **Born 1937 or earlier**: **0 %**: no avgifter at all (oldest cohort, never paid into the modern pension system). Easy to miss; the BAS journal entries for 7510/2731 simply don't apply for these employees.
- **Age 66+ on 1 January of the income year (67+ from income year 2026)**: 10.21 % (only ålderspensionsavgift). The threshold rises with the riktålder; verify the cohort year for the current run rather than hard-coding a birth year.
- **växa-stöd / temporary youth reduction**: ages 19-23, salary ≤ 25 000 SEK/month, capped duration. The exact rate and window vary year-over-year (e.g. 20.81 % during 1 Apr 2026: 30 Sep 2027 per Prop. 2025/26:34): confirm against Skatteverket's current published table before applying.
- **Semesterlöneskuld** (vacation accrual): 12 % of bruttolön (default). Booked monthly to 2920.
@@ -73,11 +73,11 @@ Errors at this stage usually mean missing tax-table data: fall back to \`getDefa
- Debit **7210** (lön tjänstemän) or **7010** (lön arbetare): bruttolön
- Debit **7510** (sociala avgifter): \`avgift_base × applicable_rate\`: **per employee**, using the rate from Step 4 (default 31.42 %, or a reduced rate when applicable: 10.21 % for 66+, växa-stöd, etc.)
- Credit **2710** (källskatt): skatteavdrag
- Credit **2730** (lagstadgade arbetsgivaravgifter): same amount as the 7510 debit (the avgift cost is the same number as the avgift liability)
- Credit **2731** (avräkning lagstadgade sociala avgifter): same amount as the 7510 debit (the avgift cost is the same number as the avgift liability). 2731 is what the engine books and what the skattekonto AGI draw debits; crediting the group account 2730 instead splits the liability across two accounts (issue #1870)
- Credit **2920** (semesterlöneskuld): 12 % × bruttolön (debit 7290 to balance)
- Credit **1930** (bank): nettolön (when paid)
When a run mixes full-rate and reduced-rate employees, the 7510/2730 lines are summed across all employees: the *total* avgift line equals \`Σ(per-employee avgift_base × per-employee rate)\`, **not** \`Σ bruttolön × 31.42 %\`. \`gnubok_calculate_salary_run\` already does this aggregation.
When a run mixes full-rate and reduced-rate employees, the 7510/2731 lines are summed across all employees: the *total* avgift line equals \`Σ(per-employee avgift_base × per-employee rate)\`, **not** \`Σ bruttolön × 31.42 %\`. \`gnubok_calculate_salary_run\` already does this aggregation.
### Step 7: Generate AGI
@@ -31,7 +31,7 @@ const SEED_RULES = [
{
id: 'sys-4', priority: 20, pattern: 'arbetsgivaravgift,sociala avgifter,agi',
amount_min: null, amount_max: null, company_type: 'all',
counter_account: '2730', counter_account_ef: null,
counter_account: '2731', counter_account_ef: null,
label: 'Arbetsgivaravgifter', active: true, requires_employer: false,
},
{
@@ -135,17 +135,19 @@ describe('guessCounterAccount', () => {
).toBe('2013')
})
it('routes employer payroll taxes to 2730 (clearing/redovisningskonto, not 2731 accrual)', async () => {
// 2731 matches the salary module's AVGIFTER_LIABILITY credit so the SKV draw
// clears the same account (issue #1870); the accrual account is 2940, not 2731.
it('routes employer payroll taxes to 2731 (same account the salary module credits)', async () => {
const { supabase, enqueue } = makeSupabase()
enqueue({ data: SEED_RULES })
expect(
(await guessCounterAccount(supabase as unknown as SupabaseClient, 'company-1', 'Arbetsgivaravgifter januari', 'aktiebolag'))?.account,
).toBe('2730')
).toBe('2731')
enqueue({ data: SEED_RULES })
expect(
(await guessCounterAccount(supabase as unknown as SupabaseClient, 'company-1', 'Sociala avgifter Q1', 'aktiebolag'))?.account,
).toBe('2730')
).toBe('2731')
})
it('routes deducted income tax to 2710 for an aktiebolag', async () => {
+1 -1
View File
@@ -12,7 +12,7 @@ meta:
Bruttolön debiteras 7010, avdragen personalskatt krediteras 2710 och
nettolönen krediteras 1930. Skatteandelen här är schablonmässiga 30 %:
justera raderna efter det faktiska skatteavdraget enligt skattetabell.
Arbetsgivaravgifter (7510/2730) och semesterlöneskuld (7290/2920) bokas
Arbetsgivaravgifter (7510/2731) och semesterlöneskuld (7290/2920) bokas
som egna verifikat, inte i den här mallen.
lines:
- account: '7010'
+1 -1
View File
@@ -116,7 +116,7 @@ Följande delsystem matar journalen:
| Banktransaktioner | Synkroniserade via PSD2 (Enable Banking) eller importerade bankfiler | Kontering via kategoriseringsregler och konteringsmallar |
| Kvitto- och underlagshantering | Uppladdade eller inmejlade underlag, maskinellt avlästa | Kontering efter granskning |
| Kreditnotor | Kreditering av utgående och inkommande fakturor | Omvänd kontering av originalfaktura |
| Löner | Lönekörningar, arbetsgivardeklaration (AGI) | Debet 7xxx + 7510, kredit 2710/2730/1930 |
| Löner | Lönekörningar, arbetsgivardeklaration (AGI) | Debet 7xxx + 7510, kredit 2710/2731/1930 |
| Anläggningstillgångar | Anläggningsregister med årliga avskrivningar | Debet 78xx, kredit 12xx |
| Periodiseringar | Periodiseringsscheman över flera perioder | Debet/kredit 17xx respektive 29xx |
+4 -4
View File
@@ -100,16 +100,16 @@
"version": 2
},
"horizontal/swedish-payroll": {
"hash": "8cbedb0245ae1f3a042bc2310d9563424ed58ef9fc6f3e853693844323653faa",
"version": 4
"hash": "b9d3a10d1c949b01185df001b08f150ebbaeca88bb837913bd9edab6f90e3859",
"version": 5
},
"horizontal/swedish-payroll/agi-filing": {
"hash": "91aa490472fafff434088301dd193ed474589b36ae22bdaab640b42bc3b3c255",
"version": 1
},
"horizontal/swedish-payroll/bas-7xxx": {
"hash": "6e7167788b3d2f9442163e29b77e79703bfc3394ff90223d2d9d096554638437",
"version": 1
"hash": "61464f317f81e9bb55d6d65a747a457b85440b076145ed44cd4055b2f0d3c324",
"version": 2
},
"horizontal/swedish-payroll/benefits": {
"hash": "bb4ead2f45691bc84c09b7433e3b2c719c93b54f702978cfd362b125ae9c8ca2",
@@ -0,0 +1,44 @@
-- Migration: revert arbetsgivaravgifter mapping 2730 -> 2731 (issue #1870)
--
-- Why this exists: 20260519160000_skattekonto_rules_arbetsgivaravgift_2730.sql
-- moved the AGI / arbetsgivaravgifter / sociala avgifter system seed from 2731
-- to 2730, citing a compliance review finding. That change was based on an
-- incorrect premise and split the liability across two accounts:
--
-- * The salary module credits 2731 when a salary run is booked
-- (SALARY_ACCOUNTS.AVGIFTER_LIABILITY in lib/salary/account-mapping.ts),
-- and the whole-krona / ore-residual logic is built around 2731.
-- * The skattekonto AGI draw debited 2730 after that migration, so for any
-- company using both subsystems the two legs never meet: 2731 accumulates
-- credits, 2730 accumulates debits, and only the 27-group sum is correct.
-- SRU code is 7231 for both, so SRU/INK2 and the balance sheet hide it;
-- only an account-level huvudbok reconciliation exposes the drift.
--
-- The old migration's rationale ("2731 is the period-end accrual posting
-- target / interimsskuld") contradicts BAS 2026 itself: 2731 Avrakning
-- lagstadgade sociala avgifter is "arbetsgivaravgifter redovisade men annu
-- inte inbetalda till Skatteverket", which is exactly the salary module's
-- monthly credit. The accrual account is 2940 Upplupna lagstadgade sociala
-- och andra avgifter, which the salary module already uses for the vacation
-- accrual leg (VACATION_AVGIFTER_LIABILITY). Booking directly on the group
-- account 2730 is a legitimate simplification, but the two subsystems must
-- agree on one account, and 2731 matches both BAS praxis and the existing
-- salary bookings.
--
-- NOTE for future compliance reviews: do not flip this back to 2730 without
-- also changing SALARY_ACCOUNTS.AVGIFTER_LIABILITY and migrating existing
-- 2731 balances; a one-sided change reintroduces issue #1870.
--
-- Scope: system seed only (company_id IS NULL). Per-company override rules
-- have lower priority numbers and are untouched. Historical entries booked
-- against 2730 since 2026-05-19 are NOT repaired here; affected companies
-- clear the offset with a reclass verifikat (debit 2731 / credit 2730).
UPDATE public.skattekonto_rules
SET counter_account = '2731',
updated_at = now()
WHERE company_id IS NULL
AND counter_account = '2730'
AND pattern = 'arbetsgivaravgift,sociala avgifter,agi';
NOTIFY pgrst, 'reload schema';
File diff suppressed because it is too large Load Diff