fix(bookkeeping): restore Swedish characters in seed_chart_of_accounts (#510)
* fix(bookkeeping): restore Swedish characters in seed_chart_of_accounts
The seed function for new companies' chart of accounts was written with
every å/ä/ö/Å/Ä/Ö stripped from its SQL string literals — 'Arets
resultat' instead of 'Årets resultat', 'Avrakning socialavgifter'
instead of 'Avräkning socialavgifter', 'Utgaende moms forsaljning' on
the VAT accounts, and so on. Every new company has been getting 24
starter rows with mangled Swedish names visible in the UI, reports,
and SIE exports.
SIE-imported accounts were unaffected because that path reads names
from lib/bookkeeping/bas-data/. Only seeded rows looked wrong, which
is why "SRU-mapped" imports rendered correctly while the seeded
baseline did not.
Diacritics are restored on the 24 affected names. The seed's
K1-friendly short forms are kept ('Varuinköp', not BAS-canonical
'Inköp av handelsvaror (gruppkonto)') — only the spelling is fixed.
Two adjacent improvements in the same function definition:
- sru_code is now populated on every seeded row from BAS reference
data. Previously NULL on seeded rows, which broke SRU/INK2 tax
filing for users who never import a SIE file.
- SET search_path = public pins resolution inside the function body,
closing Supabase linter 0011. This attribute was silently dropped
when the seed was DROP/REPLACE'd in 20260330130000 and again in
20260513120100 without re-declaring it.
Existing companies are intentionally not backfilled. Only new
companies created from this point see the fix.
Verified with extended pg-test (9 cases, including the 2 pre-existing
canaries) at supabase/migrations/__tests__/seed-chart-of-accounts.pg.test.ts.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(bookkeeping): address greptile review on PR #510
- NULL out sru_code for enskild_firma equity accounts (2010, 2013, 2018).
BAS reference maps these to INK2 SRU 7221 ("Övrigt eget kapital"), but
EF entities file NE-bilaga instead. Emitting `#SRU 2013 7221` in SIE
exports would steer downstream tax software to report owner drawings
as balance-sheet equity, which is wrong for sole traders.
- Re-add GRANT EXECUTE ON FUNCTION ... TO authenticated, restoring the
privilege silently dropped by each DROP+CREATE since 20260330130000.
Application paths via service-role bypass RLS and didn't break, but
direct RPC calls from the authenticated role had been failing with
permission errors since 2026-03-30.
- Test: lock in sru_code = NULL on the three EF equity rows.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(migrations): rename to avoid timestamp collision with PR #508
20260516120000 was already taken by assets_and_depreciation from PR #508
once that merged to main. schema_migrations uses the timestamp as primary
key, so `supabase db reset` fails with a duplicate-key error when both
files share a version.
Bump to 20260516130000 to slot between assets_and_depreciation (120000)
and depreciation_schedules_updated_at (140000).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
-- Restore Swedish characters (å/ä/ö/Å/Ä/Ö) in seed_chart_of_accounts and
|
||||
-- populate sru_code from BAS 2026 reference data. Previously the account
|
||||
-- names were inserted as ASCII-folded literals (e.g. 'Arets resultat'),
|
||||
-- which left every newly-created company with chart-of-accounts rows
|
||||
-- missing diacritics. SIE-imported accounts were unaffected because that
|
||||
-- path reads names from lib/bookkeeping/bas-data/.
|
||||
--
|
||||
-- SRU codes are populated from lib/bookkeeping/bas-data/ so the seeded
|
||||
-- chart can produce valid SRU/INK2 filings for users who never import a
|
||||
-- SIE file.
|
||||
--
|
||||
-- This migration only changes the function definition. Existing companies
|
||||
-- with broken seed rows are intentionally NOT backfilled here.
|
||||
|
||||
DROP FUNCTION IF EXISTS public.seed_chart_of_accounts(uuid, text);
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.seed_chart_of_accounts(p_company_id uuid, p_entity_type text)
|
||||
RETURNS void
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
AS $$
|
||||
DECLARE
|
||||
v_account_count integer;
|
||||
v_user_id uuid;
|
||||
BEGIN
|
||||
SELECT created_by INTO v_user_id FROM public.companies WHERE id = p_company_id;
|
||||
|
||||
SELECT count(*) INTO v_account_count
|
||||
FROM public.chart_of_accounts
|
||||
WHERE company_id = p_company_id;
|
||||
|
||||
IF v_account_count > 0 THEN
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
-- Assets (1xxx)
|
||||
INSERT INTO public.chart_of_accounts (user_id, company_id, account_number, account_name, account_class, account_group, account_type, normal_balance, plan_type, is_system_account, sru_code)
|
||||
VALUES
|
||||
(v_user_id, p_company_id, '1510', 'Kundfordringar', 1, '15', 'asset', 'debit', 'k1', true, '7211'),
|
||||
(v_user_id, p_company_id, '1910', 'Kassa', 1, '19', 'asset', 'debit', 'k1', true, '7212'),
|
||||
(v_user_id, p_company_id, '1930', 'Företagskonto / checkkonto', 1, '19', 'asset', 'debit', 'k1', true, '7212'),
|
||||
(v_user_id, p_company_id, '1940', 'Övriga bankkonton', 1, '19', 'asset', 'debit', 'k1', true, '7212');
|
||||
|
||||
-- Equity (2xxx)
|
||||
IF p_entity_type = 'enskild_firma' THEN
|
||||
-- Enskild firma equity accounts: sru_code intentionally NULL.
|
||||
-- BAS reference maps these to INK2 SRU 7221 ("Övrigt eget kapital"),
|
||||
-- which is the aktiebolag tax form. EF entities file NE-bilaga, not
|
||||
-- INK2, and owner drawings/contributions on 2013/2018 must not be
|
||||
-- reported as balance-sheet equity by SIE/INK2 consumers.
|
||||
INSERT INTO public.chart_of_accounts (user_id, company_id, account_number, account_name, account_class, account_group, account_type, normal_balance, plan_type, is_system_account, sru_code)
|
||||
VALUES
|
||||
(v_user_id, p_company_id, '2010', 'Eget kapital', 2, '20', 'equity', 'credit', 'k1', true, NULL),
|
||||
(v_user_id, p_company_id, '2013', 'Övriga egna uttag', 2, '20', 'equity', 'credit', 'k1', true, NULL),
|
||||
(v_user_id, p_company_id, '2018', 'Övriga egna insättningar', 2, '20', 'equity', 'credit', 'k1', true, NULL);
|
||||
END IF;
|
||||
|
||||
IF p_entity_type = 'aktiebolag' THEN
|
||||
INSERT INTO public.chart_of_accounts (user_id, company_id, account_number, account_name, account_class, account_group, account_type, normal_balance, plan_type, is_system_account, sru_code)
|
||||
VALUES
|
||||
(v_user_id, p_company_id, '2081', 'Aktiekapital', 2, '20', 'equity', 'credit', 'k1', true, '7220'),
|
||||
(v_user_id, p_company_id, '2091', 'Balanserat resultat', 2, '20', 'equity', 'credit', 'k1', true, '7221'),
|
||||
(v_user_id, p_company_id, '2099', 'Årets resultat', 2, '20', 'equity', 'credit', 'k1', true, '7222');
|
||||
END IF;
|
||||
|
||||
-- Liabilities (2xxx) — BAS 2026 VAT account labels
|
||||
INSERT INTO public.chart_of_accounts (user_id, company_id, account_number, account_name, account_class, account_group, account_type, normal_balance, plan_type, is_system_account, sru_code)
|
||||
VALUES
|
||||
(v_user_id, p_company_id, '2440', 'Leverantörsskulder', 2, '24', 'liability', 'credit', 'k1', true, '7230'),
|
||||
(v_user_id, p_company_id, '2611', 'Utgående moms försäljning inom Sverige, 25%', 2, '26', 'liability', 'credit', 'k1', true, '7231'),
|
||||
(v_user_id, p_company_id, '2621', 'Utgående moms försäljning inom Sverige, 12%', 2, '26', 'liability', 'credit', 'k1', true, '7231'),
|
||||
(v_user_id, p_company_id, '2631', 'Utgående moms försäljning inom Sverige, 6%', 2, '26', 'liability', 'credit', 'k1', true, '7231'),
|
||||
(v_user_id, p_company_id, '2641', 'Debiterad ingående moms', 2, '26', 'liability', 'credit', 'k1', true, '7231'),
|
||||
(v_user_id, p_company_id, '2650', 'Redovisningskonto för moms', 2, '26', 'liability', 'credit', 'k1', true, '7231'),
|
||||
(v_user_id, p_company_id, '2710', 'Personalskatt', 2, '27', 'liability', 'credit', 'k1', true, '7231'),
|
||||
(v_user_id, p_company_id, '2731', 'Avräkning socialavgifter', 2, '27', 'liability', 'credit', 'k1', true, '7231');
|
||||
|
||||
IF p_entity_type = 'aktiebolag' THEN
|
||||
INSERT INTO public.chart_of_accounts (user_id, company_id, account_number, account_name, account_class, account_group, account_type, normal_balance, plan_type, is_system_account, sru_code)
|
||||
VALUES
|
||||
(v_user_id, p_company_id, '2893', 'Skuld till aktieägare', 2, '28', 'liability', 'credit', 'k1', true, '7231');
|
||||
END IF;
|
||||
|
||||
-- Revenue (3xxx)
|
||||
INSERT INTO public.chart_of_accounts (user_id, company_id, account_number, account_name, account_class, account_group, account_type, normal_balance, plan_type, is_system_account, sru_code)
|
||||
VALUES
|
||||
(v_user_id, p_company_id, '3001', 'Försäljning tjänster 25%', 3, '30', 'revenue', 'credit', 'k1', true, '7310'),
|
||||
(v_user_id, p_company_id, '3002', 'Försäljning varor 25%', 3, '30', 'revenue', 'credit', 'k1', true, '7310'),
|
||||
(v_user_id, p_company_id, '3100', 'Momsfri försäljning', 3, '31', 'revenue', 'credit', 'k1', true, '7311'),
|
||||
(v_user_id, p_company_id, '3900', 'Övriga rörelseintäkter', 3, '39', 'revenue', 'credit', 'k1', true, '7311'),
|
||||
(v_user_id, p_company_id, '3960', 'Valutakursvinster', 3, '39', 'revenue', 'credit', 'k1', true, '7310');
|
||||
|
||||
-- COGS (4xxx)
|
||||
INSERT INTO public.chart_of_accounts (user_id, company_id, account_number, account_name, account_class, account_group, account_type, normal_balance, plan_type, is_system_account, sru_code)
|
||||
VALUES
|
||||
(v_user_id, p_company_id, '4000', 'Varuinköp', 4, '40', 'expense', 'debit', 'k1', true, '7320');
|
||||
|
||||
-- External expenses (5xxx-6xxx)
|
||||
INSERT INTO public.chart_of_accounts (user_id, company_id, account_number, account_name, account_class, account_group, account_type, normal_balance, plan_type, is_system_account, sru_code)
|
||||
VALUES
|
||||
(v_user_id, p_company_id, '5010', 'Lokalhyra', 5, '50', 'expense', 'debit', 'k1', true, '7321'),
|
||||
(v_user_id, p_company_id, '5410', 'Förbrukningsinventarier', 5, '54', 'expense', 'debit', 'k1', true, '7321'),
|
||||
(v_user_id, p_company_id, '5420', 'Programvaror', 5, '54', 'expense', 'debit', 'k1', true, '7321'),
|
||||
(v_user_id, p_company_id, '5460', 'Förbrukningsmaterial', 5, '54', 'expense', 'debit', 'k1', true, '7321'),
|
||||
(v_user_id, p_company_id, '5800', 'Resekostnader', 5, '58', 'expense', 'debit', 'k1', true, '7321'),
|
||||
(v_user_id, p_company_id, '5910', 'Annonsering', 5, '59', 'expense', 'debit', 'k1', true, '7321'),
|
||||
(v_user_id, p_company_id, '6071', 'Representation avdragsgill', 6, '60', 'expense', 'debit', 'k1', true, '7321'),
|
||||
(v_user_id, p_company_id, '6110', 'Kontorsmateriel', 6, '61', 'expense', 'debit', 'k1', true, '7321'),
|
||||
(v_user_id, p_company_id, '6212', 'Mobiltelefon', 6, '62', 'expense', 'debit', 'k1', true, '7321'),
|
||||
(v_user_id, p_company_id, '6230', 'Datakommunikation', 6, '62', 'expense', 'debit', 'k1', true, '7321'),
|
||||
(v_user_id, p_company_id, '6530', 'Redovisningstjänster', 6, '65', 'expense', 'debit', 'k1', true, '7321'),
|
||||
(v_user_id, p_company_id, '6570', 'Bankavgifter', 6, '65', 'expense', 'debit', 'k1', true, '7321'),
|
||||
(v_user_id, p_company_id, '6991', 'Övriga avdragsgilla kostnader', 6, '69', 'expense', 'debit', 'k1', true, '7330');
|
||||
|
||||
-- Personnel (7xxx)
|
||||
IF p_entity_type = 'aktiebolag' THEN
|
||||
INSERT INTO public.chart_of_accounts (user_id, company_id, account_number, account_name, account_class, account_group, account_type, normal_balance, plan_type, is_system_account, sru_code)
|
||||
VALUES
|
||||
(v_user_id, p_company_id, '7010', 'Löner', 7, '70', 'expense', 'debit', 'k1', true, '7322'),
|
||||
(v_user_id, p_company_id, '7210', 'Semesterlöner', 7, '72', 'expense', 'debit', 'k1', true, '7322'),
|
||||
(v_user_id, p_company_id, '7510', 'Arbetsgivaravgifter', 7, '75', 'expense', 'debit', 'k1', true, '7322');
|
||||
END IF;
|
||||
|
||||
INSERT INTO public.chart_of_accounts (user_id, company_id, account_number, account_name, account_class, account_group, account_type, normal_balance, plan_type, is_system_account, sru_code)
|
||||
VALUES
|
||||
(v_user_id, p_company_id, '7960', 'Valutakursförluster', 7, '79', 'expense', 'debit', 'k1', true, '7360');
|
||||
|
||||
-- Financial (8xxx)
|
||||
INSERT INTO public.chart_of_accounts (user_id, company_id, account_number, account_name, account_class, account_group, account_type, normal_balance, plan_type, is_system_account, sru_code)
|
||||
VALUES
|
||||
(v_user_id, p_company_id, '8310', 'Ränteintäkter', 8, '83', 'revenue', 'credit', 'k1', true, '7313'),
|
||||
(v_user_id, p_company_id, '8410', 'Räntekostnader', 8, '84', 'expense', 'debit', 'k1', true, '7323');
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- Restore the EXECUTE grant. Each prior DROP/CREATE has silently dropped
|
||||
-- the grant originally established in 20240101000009; SECURITY DEFINER
|
||||
-- callers via service role still work, but RPC calls from the
|
||||
-- authenticated role have been failing with permission errors since
|
||||
-- 20260330130000. Match the original grant from migration 009.
|
||||
GRANT EXECUTE ON FUNCTION public.seed_chart_of_accounts(uuid, text) TO authenticated;
|
||||
|
||||
NOTIFY pgrst, 'reload schema';
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { seedCompany } from '@/tests/pg/fixtures'
|
||||
import { insertAuthUser, insertCompany, seedCompany } from '@/tests/pg/fixtures'
|
||||
import { getPool } from '@/tests/pg/setup'
|
||||
|
||||
/**
|
||||
@@ -11,8 +11,40 @@ import { getPool } from '@/tests/pg/setup'
|
||||
* the VAT-rutor mapping both route by account number, so a mislabel in this
|
||||
* function never breaks any other test — only the chart-of-accounts UI shows
|
||||
* the wrong text. This test is the canary.
|
||||
*
|
||||
* The diacritic + SRU groups below cover the 2026-05-16 migration that
|
||||
* restored å/ä/ö in account names and started populating sru_code from BAS
|
||||
* reference. Both are bytes-on-disk concerns the engine never reads but the
|
||||
* UI and tax-filing exports do.
|
||||
*/
|
||||
|
||||
interface AccountRow {
|
||||
account_number: string
|
||||
account_name: string
|
||||
sru_code: string | null
|
||||
}
|
||||
|
||||
async function callSeed(
|
||||
companyId: string,
|
||||
entityType: 'aktiebolag' | 'enskild_firma',
|
||||
): Promise<void> {
|
||||
await getPool().query(
|
||||
`SELECT public.seed_chart_of_accounts($1::uuid, $2::text)`,
|
||||
[companyId, entityType],
|
||||
)
|
||||
}
|
||||
|
||||
async function getAccounts(companyId: string): Promise<AccountRow[]> {
|
||||
const res = await getPool().query<AccountRow>(
|
||||
`SELECT account_number, account_name, sru_code
|
||||
FROM public.chart_of_accounts
|
||||
WHERE company_id = $1
|
||||
ORDER BY account_number`,
|
||||
[companyId],
|
||||
)
|
||||
return res.rows
|
||||
}
|
||||
|
||||
describe('seed_chart_of_accounts', () => {
|
||||
it('seeds 26xx VAT accounts with BAS-correct labels', async () => {
|
||||
const { companyId } = await seedCompany()
|
||||
@@ -64,3 +96,164 @@ describe('seed_chart_of_accounts', () => {
|
||||
expect(rows[0].account_name).toMatch(/[Ii]ng.*moms/)
|
||||
})
|
||||
})
|
||||
|
||||
describe('seed_chart_of_accounts — Swedish characters', () => {
|
||||
it('inserts Swedish-character account names byte-for-byte for aktiebolag', async () => {
|
||||
const { companyId } = await seedCompany()
|
||||
await callSeed(companyId, 'aktiebolag')
|
||||
const byNum = new Map((await getAccounts(companyId)).map((r) => [r.account_number, r]))
|
||||
|
||||
// Spot-check every row whose name contains å/ä/ö/Å/Ä/Ö. If diacritics
|
||||
// were stripped during insertion these assertions are the ones that
|
||||
// would fail.
|
||||
const expected: Record<string, string> = {
|
||||
'1930': 'Företagskonto / checkkonto',
|
||||
'1940': 'Övriga bankkonton',
|
||||
'2099': 'Årets resultat',
|
||||
'2440': 'Leverantörsskulder',
|
||||
'2611': 'Utgående moms försäljning inom Sverige, 25%',
|
||||
'2621': 'Utgående moms försäljning inom Sverige, 12%',
|
||||
'2631': 'Utgående moms försäljning inom Sverige, 6%',
|
||||
'2641': 'Debiterad ingående moms',
|
||||
'2650': 'Redovisningskonto för moms',
|
||||
'2731': 'Avräkning socialavgifter',
|
||||
'2893': 'Skuld till aktieägare',
|
||||
'3001': 'Försäljning tjänster 25%',
|
||||
'3002': 'Försäljning varor 25%',
|
||||
'3100': 'Momsfri försäljning',
|
||||
'3900': 'Övriga rörelseintäkter',
|
||||
'4000': 'Varuinköp',
|
||||
'5410': 'Förbrukningsinventarier',
|
||||
'5460': 'Förbrukningsmaterial',
|
||||
'6530': 'Redovisningstjänster',
|
||||
'6991': 'Övriga avdragsgilla kostnader',
|
||||
'7010': 'Löner',
|
||||
'7210': 'Semesterlöner',
|
||||
'7960': 'Valutakursförluster',
|
||||
'8310': 'Ränteintäkter',
|
||||
'8410': 'Räntekostnader',
|
||||
}
|
||||
|
||||
for (const [num, name] of Object.entries(expected)) {
|
||||
const row = byNum.get(num)
|
||||
expect(row, `account ${num} should be seeded`).toBeDefined()
|
||||
expect(row!.account_name, `account ${num} name`).toBe(name)
|
||||
}
|
||||
})
|
||||
|
||||
it('inserts Swedish-character account names for enskild_firma equity accounts', async () => {
|
||||
// seedCompany() defaults to aktiebolag, so go direct for the EF case.
|
||||
const userId = await insertAuthUser()
|
||||
const companyId = await insertCompany({ createdBy: userId, entityType: 'enskild_firma' })
|
||||
await callSeed(companyId, 'enskild_firma')
|
||||
const byNum = new Map((await getAccounts(companyId)).map((r) => [r.account_number, r]))
|
||||
|
||||
expect(byNum.get('2013')?.account_name).toBe('Övriga egna uttag')
|
||||
expect(byNum.get('2018')?.account_name).toBe('Övriga egna insättningar')
|
||||
|
||||
// AB-only equity accounts must not appear for enskild_firma.
|
||||
expect(byNum.has('2081')).toBe(false)
|
||||
expect(byNum.has('2091')).toBe(false)
|
||||
expect(byNum.has('2099')).toBe(false)
|
||||
|
||||
// EF equity accounts must NOT carry the AB-oriented INK2 SRU code 7221.
|
||||
// EF entities file NE-bilaga instead of INK2; emitting `#SRU 2013 7221`
|
||||
// in a SIE export would steer downstream tax software to report owner
|
||||
// drawings as balance-sheet equity, which is wrong for sole traders.
|
||||
expect(byNum.get('2010')?.sru_code).toBeNull()
|
||||
expect(byNum.get('2013')?.sru_code).toBeNull()
|
||||
expect(byNum.get('2018')?.sru_code).toBeNull()
|
||||
})
|
||||
|
||||
it('stores diacritics as multi-byte UTF-8, not as ASCII folds', async () => {
|
||||
// octet_length > char_length holds only when the string contains
|
||||
// multi-byte UTF-8 code units. If a future regression strips å/ä/ö
|
||||
// again the lengths would become equal and this fails loudly.
|
||||
const { companyId } = await seedCompany()
|
||||
await callSeed(companyId, 'aktiebolag')
|
||||
const res = await getPool().query<{
|
||||
account_number: string
|
||||
octets: number
|
||||
chars: number
|
||||
}>(
|
||||
`SELECT account_number,
|
||||
octet_length(account_name) AS octets,
|
||||
char_length(account_name) AS chars
|
||||
FROM public.chart_of_accounts
|
||||
WHERE company_id = $1
|
||||
AND account_number IN ('2099', '2440', '2611', '2731', '7010', '8410')`,
|
||||
[companyId],
|
||||
)
|
||||
expect(res.rows.length).toBe(6)
|
||||
for (const row of res.rows) {
|
||||
expect(
|
||||
row.octets,
|
||||
`account ${row.account_number}: octet_length must exceed char_length`,
|
||||
).toBeGreaterThan(row.chars)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('seed_chart_of_accounts — SRU codes', () => {
|
||||
it('populates sru_code for every seeded account so the K1 chart can produce SRU/INK2 filings', async () => {
|
||||
const { companyId } = await seedCompany()
|
||||
await callSeed(companyId, 'aktiebolag')
|
||||
const rows = await getAccounts(companyId)
|
||||
|
||||
const missing = rows.filter((r) => r.sru_code === null)
|
||||
expect(
|
||||
missing,
|
||||
`every seeded row must have sru_code populated. Missing: ${missing
|
||||
.map((r) => `${r.account_number} (${r.account_name})`)
|
||||
.join(', ')}`,
|
||||
).toHaveLength(0)
|
||||
})
|
||||
|
||||
it('maps representative accounts to the SRU codes from BAS reference', async () => {
|
||||
const { companyId } = await seedCompany()
|
||||
await callSeed(companyId, 'aktiebolag')
|
||||
const byNum = new Map((await getAccounts(companyId)).map((r) => [r.account_number, r]))
|
||||
|
||||
// Spot-check values pulled from lib/bookkeeping/bas-data/. These three
|
||||
// map to Skatteverket SRU fields in INK2; getting them wrong would
|
||||
// silently break tax filing.
|
||||
expect(byNum.get('2099')?.sru_code).toBe('7222')
|
||||
expect(byNum.get('2611')?.sru_code).toBe('7231')
|
||||
expect(byNum.get('2731')?.sru_code).toBe('7231')
|
||||
expect(byNum.get('1930')?.sru_code).toBe('7212')
|
||||
expect(byNum.get('3001')?.sru_code).toBe('7310')
|
||||
expect(byNum.get('7010')?.sru_code).toBe('7322')
|
||||
})
|
||||
})
|
||||
|
||||
describe('seed_chart_of_accounts — invariants', () => {
|
||||
it('is idempotent: a second call on a company that already has accounts is a no-op', async () => {
|
||||
const { companyId } = await seedCompany()
|
||||
await callSeed(companyId, 'aktiebolag')
|
||||
const firstCount = (await getAccounts(companyId)).length
|
||||
|
||||
await callSeed(companyId, 'aktiebolag')
|
||||
const secondCount = (await getAccounts(companyId)).length
|
||||
|
||||
expect(secondCount).toBe(firstCount)
|
||||
})
|
||||
|
||||
it('seeds plan_type=k1 and is_system_account=true on every starter account', async () => {
|
||||
// These two flags are what the SIE importer's existing-account
|
||||
// short-circuit relies on to distinguish seeded rows from imported
|
||||
// ones. Drifting away from them would change the importer's
|
||||
// behaviour for existing companies silently.
|
||||
const { companyId } = await seedCompany()
|
||||
await callSeed(companyId, 'aktiebolag')
|
||||
const res = await getPool().query<{ bad_plan: number; bad_flag: number }>(
|
||||
`SELECT
|
||||
count(*) FILTER (WHERE plan_type IS DISTINCT FROM 'k1')::int AS bad_plan,
|
||||
count(*) FILTER (WHERE is_system_account IS DISTINCT FROM true)::int AS bad_flag
|
||||
FROM public.chart_of_accounts
|
||||
WHERE company_id = $1`,
|
||||
[companyId],
|
||||
)
|
||||
expect(res.rows[0]!.bad_plan).toBe(0)
|
||||
expect(res.rows[0]!.bad_flag).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user