From 59d5b7b3665ff69c2ebbee3e96a200661f433eca Mon Sep 17 00:00:00 2001 From: Mattsson <111893710+mattssonn@users.noreply.github.com> Date: Tue, 8 Sep 2026 13:34:50 +0200 Subject: [PATCH] fix(bookkeeping): name 1249/1259/1269 after their BAS 2026 free heads, drop retired 12xx sub-accounts (#2419) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(bookkeeping): name 1249/1259/1269 after their BAS 2026 free heads, drop retired 12xx sub-accounts A sole trader booking a tractor activated 1240 and 1249 from the account picker and got a machinery head labelled "(Fritt konto för Maskiner och andra tekniska anläggningar)" next to a contra account labelled "Ack. avskrivningar på bilar och andra transportmedel". Why it occurred: BAS 2026 restructured kontogrupp 12. Bilar and datorer moved under 1210 (för produktion) and 1220 (ej för produktion), and 1230/1240/1250/1260 became free heads. The catalog in lib/bookkeeping/bas-data/ followed for the heads (#463) but kept seven sub-accounts the official chart no longer has (1241, 1242, 1249, 1251, 1259, 1261, 1269) with their pre-2026 names. Every picker activation of a 12xx contra account therefore produced the contradiction; prod carries the 1240/1249 pair in 173 charts, 1250/1259 in 153 and 1260/1269 in 78. What was removed instead of patched: 1241, 1242, 1251 and 1261 leave the catalog entirely (bas.se BAS 2026 v2 has no such accounts; the SIE mapper already self-maps unknown sub-accounts by number). 1249/1259/1269 stay because the asset module's vehicle and computer defaults and 31 live assets in prod depend on them; they are renamed after their heads so the pair reads as one thing. Why this and not the proposal: the reporter asked for 1249 to be renamed to "ack. avskr. maskiner", which fixes one number and leaves 1259/1269 and the four retired asset accounts contradicting their heads. Dropping 1249/1259/1269 and moving the asset defaults to BAS 2026 (1226/1224 on 1229) is the right long-term shape but changes what a new vehicle or computer asset books to; that decision is the founder's and is tracked in #2414. The migration renames a contra account only when its name is byte-identical to one of the two catalog literals AND the company's head carries the BAS 2026 free label, so old-BAS imports (1240 "Bilar och andra transportmedel") and every user rename stay untouched. Applied and pg-tested on staging. Fixes #2413 Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01NXSuVejFCvRDyNXF1otEPd * fix(bookkeeping): skip 12xx contra accounts with journal lines in the label backfill Skeptic refutation: lib/import/account-sync.ts creates missing accounts with the catalog name when the SIE #KONTO names are not carried, so an old-BAS vehicle chart can hold the exact free-head + bilar-contra pair with years of depreciation booked on 1249 (8 such charts in prod). The backfill now also requires that the contra account has no journal lines: a label with history is the user's to change. Migration re-issued under a fresh version, applied and pg-tested on staging. Refs #2413 Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01NXSuVejFCvRDyNXF1otEPd * fix(bookkeeping): lock journal_entry_lines while the 12xx label backfill checks history CodeRabbit (Major): under READ COMMITTED a posting could commit between the NOT EXISTS history check and the rename. A SHARE lock on journal_entry_lines for the migration transaction makes the two atomic; inserts wait milliseconds, reads are unaffected. Migration re-issued under a fresh version, applied and pg-tested on staging. Refs #2413 Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01NXSuVejFCvRDyNXF1otEPd --------- Co-authored-by: Claude Fable 5.1 --- DECISIONS.md | 1 + .../__tests__/bas-reference.test.ts | 32 +++ lib/bookkeeping/bas-account-numbers.ts | 206 +++++++++--------- lib/bookkeeping/bas-data/class-1-assets.ts | 56 +---- ...3_backfill_bas2026_retired_12xx_labels.sql | 97 +++++++++ .../pg/bas2026-retired-12xx-labels.pg.test.ts | 171 +++++++++++++++ 6 files changed, 410 insertions(+), 153 deletions(-) create mode 100644 supabase/migrations/20260908113353_backfill_bas2026_retired_12xx_labels.sql create mode 100644 tests/pg/bas2026-retired-12xx-labels.pg.test.ts diff --git a/DECISIONS.md b/DECISIONS.md index d12d54df..e07f6788 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -1662,3 +1662,4 @@ One line per decision: `[YYYY-MM-DD] : `. Appended by agents and [2026-09-08] #2391 skeptic pass: orgNumberKey only strips hyphens and spaces and only unprefixes 12-digit values behind 16/18/19/20. Reason: 26 prod supplier rows hold a VAT number (orgnr + 01, prefixes 55/52/87) in org_number, and 'last 10 of any 12 digits' would have rewritten them to another company's identity; letters stay because BE0123456789 is not the Swedish 0123456789. The matcher scans live suppliers only (archived_at IS NULL), the list and v1 search compare without separators, the CSV import and the provider migration orchestrator key and write through the same rule. [2026-09-08] correctEntry re-points the original entry's transaction_voucher_links rows to the corrected entry (lib/core/bookkeeping/storno-service.ts relinkTransactionsToEntry) instead of deleting them as issue #2364 proposed. Why: for a samlingsverifikat (bulk-book N>1) the junction is the row's only anchor, so deleting it would push rows the corrected verifikat still explains back into Att bokföra; the pointer column already follows the correction and the junction now follows it the same way, so every reader (is_transaction_booked, fetchJunctionLinkedTxIds, the bulk_book RPC) sees one live anchor. Rejected: a relink_entry_anchors RPC moving pointer and junction atomically (a migration plus pg test for a path that is already best-effort across five other statements; revisit if a partial failure ever shows up in the surfaced transactionRelinkError). Prod repair (planned, runs after merge on the founder's go; completion gets its own dated entry): the 7 stale links (3 companies) all sit on rows whose pointer names a posted entry (4 on a correction chain, 3 from a June 2026 samlingsverifikat storno that predates the junction cleanup and were re-booked 1:1); they will be re-pointed to the pointer's entry, the same rule the fix applies, rather than deleted. [2026-09-08] delete_last_voucher returns a correction's bank anchors (transactions.journal_entry_id and transaction_voucher_links rows) to correction_of_id before the row is deleted (migration 20260908095907). Why: the #2364 skeptic showed that once the junction follows the correction, the two-step undo (delete the correction, then the storno) cascaded the links away and restored an original that explains bank rows nobody points at, so the rows surfaced as bookable again; before, the links had stayed on the original by accident. Chosen over releasing the rows (the restored original would still explain them, same trap) and over a TS pre-step in the DELETE route (not atomic with the RPC's own guards: a refused delete would leave anchors on a reversed entry). A duplicate of a link the original already holds is dropped, not re-pointed (UNIQUE (transaction_id, journal_entry_id)). +[2026-09-08] Issue #2413 BAS 2026 kontogrupp 12: kept 1249/1259/1269 in the catalog renamed after their free heads and dropped only 1241/1242/1251/1261, instead of removing all seven retired sub-accounts and moving the asset module's vehicle/computer defaults to BAS 2026 (1226/1224 on 1229): the asset module's DEFAULT_ACCOUNTS_BY_CATEGORY still books vehicles on 1240/1249 and computers on 1250/1259 (31 live assets in prod, guard test requires the triple in BAS_REFERENCE), so dropping the contra accounts would have forced a depreciation-default change into a label fix; that change is the founder's call and lives in #2414. The prod backfill renames only the exact catalog literal next to a free-labelled head, so old-BAS imports (1240 Bilar + 1249 Ack. avskr. bilar) and user renames stay untouched. diff --git a/lib/bookkeeping/__tests__/bas-reference.test.ts b/lib/bookkeeping/__tests__/bas-reference.test.ts index 3b5f7c86..30f0b13f 100644 --- a/lib/bookkeeping/__tests__/bas-reference.test.ts +++ b/lib/bookkeeping/__tests__/bas-reference.test.ts @@ -82,6 +82,38 @@ describe('Non-standard accounts removed', () => { } }) +// BAS 2026 restructured kontogrupp 12: bilar/datorer moved under 1210 (för +// produktion) and 1220 (ej för produktion), and 1230/1240/1250/1260 became +// free heads. The pre-2026 sub-accounts under those heads are gone from the +// official chart (bas.se BAS 2026 v2), so the catalog must not hand them out +// with their old names next to a head that says "fritt konto" (#2413). +describe('BAS 2026 kontogrupp 12: free heads and their contra accounts agree', () => { + const retired = ['1241', '1242', '1251', '1261'] + for (const num of retired) { + it(`${num} (retired in BAS 2026) is not in the catalog`, () => { + expect(isStandardBASAccount(num)).toBe(false) + }) + } + + const pairs: Array<[head: string, contra: string]> = [ + ['1240', '1249'], + ['1250', '1259'], + ['1260', '1269'], + ] + for (const [head, contra] of pairs) { + it(`${contra} is named after the free head ${head}, not a retired bilar/datorer account`, () => { + const headName = getBASReference(head)?.account_name ?? '' + const contraName = getBASReference(contra)?.account_name ?? '' + expect(headName.startsWith('(Fritt konto för ')).toBe(true) + // "(Fritt konto för X)" on the head; "... (fritt konto för X)" on the contra. + const subject = headName.slice('(Fritt konto för '.length, -1) + expect(contraName).toContain(`(fritt konto för ${subject})`) + expect(contraName).toMatch(/^Ackumulerade avskrivningar/) + expect(contraName.toLowerCase()).not.toMatch(/bilar|datorer|inventarier och verktyg$/) + }) + } +}) + describe('Class 2 account_type correctness', () => { it('20xx accounts are equity', () => { const group20 = BAS_REFERENCE.filter((a) => a.account_group === '20') diff --git a/lib/bookkeeping/bas-account-numbers.ts b/lib/bookkeeping/bas-account-numbers.ts index cf81b5e0..e681821b 100644 --- a/lib/bookkeeping/bas-account-numbers.ts +++ b/lib/bookkeeping/bas-account-numbers.ts @@ -11,109 +11,109 @@ export const BAS_ACCOUNT_NUMBERS: readonly string[] = [ '1081', '1088', '1090', '1092', '1098', '1099', '1110', '1111', '1112', '1118', '1119', '1120', '1129', '1130', '1140', '1150', '1158', '1159', '1180', '1181', '1188', '1210', '1211', '1212', '1214', '1216', '1217', '1218', '1219', '1220', '1221', '1222', '1224', '1226', '1227', '1228', - '1229', '1230', '1240', '1241', '1242', '1249', '1250', '1251', '1259', '1260', '1261', '1269', - '1280', '1281', '1288', '1290', '1291', '1292', '1298', '1299', '1310', '1311', '1312', '1313', - '1314', '1316', '1317', '1318', '1320', '1321', '1322', '1323', '1328', '1330', '1331', '1332', - '1333', '1334', '1336', '1337', '1340', '1341', '1342', '1343', '1344', '1346', '1347', '1350', - '1351', '1352', '1353', '1354', '1356', '1357', '1358', '1360', '1369', '1370', '1380', '1381', - '1382', '1383', '1384', '1385', '1387', '1388', '1389', '1410', '1419', '1420', '1429', '1440', - '1449', '1450', '1459', '1460', '1465', '1466', '1467', '1469', '1470', '1471', '1478', '1479', - '1480', '1481', '1489', '1490', '1491', '1492', '1493', '1510', '1511', '1512', '1513', '1516', - '1518', '1519', '1520', '1525', '1529', '1530', '1531', '1532', '1536', '1539', '1550', '1560', - '1561', '1562', '1563', '1568', '1569', '1570', '1571', '1572', '1573', '1610', '1611', '1612', - '1613', '1614', '1619', '1620', '1630', '1640', '1650', '1660', '1661', '1662', '1663', '1670', - '1671', '1672', '1673', '1680', '1681', '1682', '1683', '1684', '1685', '1686', '1687', '1688', - '1689', '1690', '1710', '1720', '1730', '1740', '1750', '1760', '1770', '1780', '1790', '1810', - '1820', '1830', '1860', '1880', '1886', '1889', '1890', '1910', '1911', '1912', '1913', '1920', - '1930', '1940', '1950', '1960', '1970', '1972', '1973', '1974', '1979', '1980', '1990', '2010', - '2011', '2013', '2017', '2018', '2019', '2020', '2021', '2023', '2027', '2028', '2029', '2030', - '2031', '2033', '2037', '2038', '2039', '2040', '2041', '2043', '2047', '2048', '2049', '2050', - '2060', '2061', '2064', '2065', '2066', '2067', '2068', '2069', '2070', '2071', '2072', '2080', - '2081', '2082', '2083', '2084', '2085', '2086', '2087', '2088', '2089', '2090', '2091', '2092', - '2093', '2094', '2095', '2096', '2097', '2098', '2099', '2110', '2120', '2121', '2122', '2123', - '2124', '2125', '2126', '2127', '2129', '2130', '2131', '2132', '2133', '2134', '2135', '2136', - '2137', '2139', '2150', '2151', '2152', '2153', '2160', '2161', '2162', '2164', '2190', '2196', - '2199', '2210', '2220', '2230', '2240', '2250', '2252', '2253', '2290', '2310', '2320', '2321', - '2322', '2323', '2324', '2330', '2340', '2350', '2351', '2355', '2359', '2360', '2361', '2362', - '2363', '2370', '2371', '2372', '2373', '2390', '2391', '2392', '2393', '2394', '2395', '2396', - '2397', '2399', '2410', '2411', '2412', '2417', '2419', '2420', '2421', '2429', '2430', '2431', - '2438', '2439', '2440', '2441', '2443', '2445', '2448', '2450', '2460', '2461', '2462', '2463', - '2470', '2471', '2472', '2473', '2480', '2490', '2491', '2492', '2499', '2510', '2512', '2513', - '2514', '2515', '2517', '2518', '2610', '2611', '2612', '2613', '2614', '2615', '2616', '2618', - '2620', '2621', '2622', '2623', '2624', '2625', '2626', '2628', '2630', '2631', '2632', '2633', - '2634', '2635', '2636', '2638', '2640', '2641', '2642', '2645', '2646', '2647', '2648', '2649', - '2650', '2660', '2670', '2710', '2730', '2731', '2732', '2740', '2750', '2760', '2761', '2762', - '2790', '2791', '2792', '2793', '2794', '2795', '2799', '2810', '2811', '2812', '2820', '2821', - '2822', '2823', '2829', '2830', '2840', '2841', '2849', '2850', '2852', '2860', '2861', '2862', - '2863', '2870', '2871', '2872', '2873', '2880', '2890', '2891', '2892', '2893', '2895', '2897', - '2898', '2899', '2910', '2911', '2912', '2919', '2920', '2930', '2931', '2940', '2941', '2942', - '2943', '2944', '2950', '2951', '2959', '2960', '2970', '2971', '2972', '2979', '2980', '2990', - '2991', '2992', '2993', '2995', '2998', '2999', '3000', '3001', '3002', '3003', '3004', '3100', - '3105', '3106', '3108', '3200', '3211', '3212', '3231', '3300', '3305', '3308', '3400', '3401', - '3402', '3403', '3404', '3500', '3510', '3511', '3518', '3520', '3521', '3522', '3530', '3540', - '3541', '3542', '3550', '3560', '3561', '3562', '3563', '3570', '3590', '3600', '3610', '3611', - '3612', '3613', '3619', '3620', '3630', '3670', '3671', '3672', '3679', '3680', '3690', '3700', - '3710', '3730', '3731', '3732', '3740', '3750', '3751', '3752', '3790', '3800', '3840', '3850', - '3870', '3900', '3910', '3911', '3912', '3913', '3914', '3920', '3921', '3922', '3925', '3940', - '3950', '3960', '3970', '3971', '3972', '3973', '3980', '3981', '3985', '3987', '3988', '3989', - '3990', '3991', '3992', '3993', '3994', '3995', '3996', '3997', '3998', '3999', '4000', '4010', - '4060', '4065', '4066', '4067', '4070', '4075', '4076', '4077', '4078', '4080', '4085', '4086', - '4087', '4090', '4091', '4092', '4099', '4200', '4210', '4211', '4212', '4300', '4310', '4400', - '4410', '4415', '4416', '4417', '4420', '4425', '4426', '4427', '4500', '4510', '4515', '4516', - '4517', '4518', '4530', '4531', '4532', '4533', '4535', '4536', '4537', '4538', '4540', '4545', - '4546', '4547', '4598', '4600', '4610', '4670', '4700', '4730', '4731', '4732', '4739', '4800', - '4810', '4820', '4830', '4840', '4890', '4900', '4910', '4920', '4940', '4944', '4945', '4947', - '4950', '4960', '4970', '4974', '4975', '4977', '4980', '4981', '4987', '4988', '5000', '5010', - '5011', '5012', '5013', '5019', '5020', '5030', '5040', '5050', '5060', '5061', '5062', '5064', - '5065', '5069', '5070', '5090', '5100', '5110', '5120', '5130', '5131', '5132', '5139', '5140', - '5160', '5161', '5162', '5164', '5165', '5169', '5170', '5190', '5191', '5192', '5193', '5198', - '5200', '5210', '5220', '5250', '5290', '5300', '5310', '5320', '5330', '5340', '5350', '5360', - '5370', '5380', '5390', '5400', '5410', '5411', '5412', '5420', '5430', '5440', '5460', '5480', - '5500', '5510', '5520', '5530', '5550', '5580', '5590', '5600', '5610', '5611', '5612', '5613', - '5615', '5616', '5619', '5620', '5621', '5622', '5623', '5625', '5626', '5629', '5630', '5631', - '5632', '5633', '5635', '5639', '5640', '5641', '5642', '5643', '5645', '5646', '5649', '5650', - '5651', '5652', '5653', '5655', '5656', '5659', '5670', '5671', '5672', '5673', '5675', '5679', - '5680', '5681', '5682', '5683', '5685', '5689', '5690', '5691', '5692', '5693', '5695', '5696', - '5699', '5700', '5710', '5711', '5712', '5720', '5721', '5722', '5729', '5730', '5790', '5800', - '5810', '5820', '5830', '5831', '5832', '5890', '5900', '5910', '5920', '5930', '5940', '5950', - '5960', '5970', '5980', '5981', '5982', '5990', '6000', '6010', '6020', '6030', '6040', '6050', - '6055', '6059', '6060', '6061', '6062', '6063', '6064', '6069', '6070', '6071', '6072', '6080', - '6090', '6100', '6110', '6150', '6200', '6210', '6211', '6212', '6219', '6230', '6250', '6290', - '6300', '6310', '6320', '6330', '6340', '6341', '6342', '6350', '6351', '6352', '6360', '6361', - '6362', '6370', '6380', '6390', '6391', '6392', '6400', '6420', '6421', '6422', '6423', '6424', - '6430', '6440', '6450', '6490', '6500', '6510', '6520', '6530', '6540', '6550', '6551', '6552', - '6553', '6554', '6555', '6556', '6559', '6560', '6570', '6580', '6590', '6700', '6710', '6800', - '6810', '6820', '6830', '6840', '6850', '6860', '6870', '6880', '6890', '6900', '6910', '6920', - '6930', '6940', '6950', '6970', '6980', '6981', '6982', '6990', '6991', '6992', '6993', '6996', - '6997', '6998', '6999', '7000', '7010', '7011', '7012', '7013', '7017', '7018', '7019', '7030', - '7031', '7032', '7037', '7038', '7039', '7080', '7081', '7082', '7083', '7089', '7090', '7200', - '7210', '7211', '7212', '7213', '7217', '7218', '7219', '7220', '7221', '7222', '7227', '7228', - '7229', '7230', '7231', '7232', '7237', '7238', '7239', '7240', '7280', '7281', '7282', '7283', - '7284', '7285', '7286', '7288', '7289', '7290', '7291', '7292', '7300', '7310', '7311', '7312', - '7313', '7314', '7315', '7316', '7317', '7318', '7319', '7320', '7321', '7322', '7323', '7324', - '7330', '7331', '7332', '7333', '7350', '7370', '7380', '7381', '7382', '7383', '7384', '7385', - '7386', '7387', '7388', '7389', '7390', '7391', '7392', '7400', '7410', '7411', '7412', '7420', - '7430', '7440', '7441', '7448', '7460', '7461', '7462', '7463', '7470', '7490', '7500', '7510', - '7511', '7512', '7515', '7516', '7518', '7519', '7530', '7531', '7532', '7533', '7550', '7551', - '7552', '7553', '7554', '7570', '7571', '7572', '7580', '7581', '7582', '7583', '7589', '7590', - '7600', '7610', '7620', '7621', '7622', '7623', '7630', '7631', '7632', '7650', '7670', '7671', - '7678', '7690', '7691', '7692', '7693', '7699', '7710', '7720', '7730', '7731', '7732', '7733', - '7740', '7760', '7770', '7780', '7781', '7782', '7783', '7790', '7810', '7811', '7812', '7813', - '7814', '7815', '7816', '7817', '7819', '7820', '7821', '7824', '7829', '7830', '7831', '7832', - '7836', '7839', '7840', '7940', '7960', '7970', '7971', '7972', '7973', '7990', '8010', '8012', - '8016', '8020', '8030', '8070', '8072', '8076', '8077', '8080', '8082', '8086', '8087', '8110', - '8111', '8112', '8113', '8116', '8117', '8118', '8120', '8121', '8122', '8123', '8130', '8131', - '8132', '8133', '8170', '8171', '8172', '8173', '8174', '8176', '8177', '8180', '8181', '8182', - '8183', '8184', '8186', '8187', '8210', '8212', '8216', '8220', '8221', '8222', '8223', '8230', - '8231', '8236', '8240', '8250', '8251', '8252', '8254', '8255', '8260', '8261', '8262', '8263', - '8270', '8271', '8272', '8273', '8280', '8281', '8282', '8283', '8290', '8291', '8295', '8310', - '8311', '8312', '8313', '8314', '8317', '8319', '8320', '8321', '8325', '8330', '8331', '8336', - '8340', '8350', '8360', '8361', '8362', '8363', '8370', '8380', '8390', '8400', '8410', '8411', - '8412', '8413', '8415', '8417', '8418', '8419', '8420', '8421', '8422', '8423', '8424', '8429', - '8430', '8431', '8436', '8440', '8450', '8451', '8455', '8460', '8461', '8462', '8463', '8480', - '8490', '8491', '8810', '8811', '8819', '8820', '8830', '8840', '8850', '8851', '8852', '8853', - '8860', '8861', '8862', '8864', '8865', '8866', '8869', '8890', '8892', '8896', '8899', '8910', - '8920', '8930', '8940', '8980', '8990', '8999', + '1229', '1230', '1240', '1249', '1250', '1259', '1260', '1269', '1280', '1281', '1288', '1290', + '1291', '1292', '1298', '1299', '1310', '1311', '1312', '1313', '1314', '1316', '1317', '1318', + '1320', '1321', '1322', '1323', '1328', '1330', '1331', '1332', '1333', '1334', '1336', '1337', + '1340', '1341', '1342', '1343', '1344', '1346', '1347', '1350', '1351', '1352', '1353', '1354', + '1356', '1357', '1358', '1360', '1369', '1370', '1380', '1381', '1382', '1383', '1384', '1385', + '1387', '1388', '1389', '1410', '1419', '1420', '1429', '1440', '1449', '1450', '1459', '1460', + '1465', '1466', '1467', '1469', '1470', '1471', '1478', '1479', '1480', '1481', '1489', '1490', + '1491', '1492', '1493', '1510', '1511', '1512', '1513', '1516', '1518', '1519', '1520', '1525', + '1529', '1530', '1531', '1532', '1536', '1539', '1550', '1560', '1561', '1562', '1563', '1568', + '1569', '1570', '1571', '1572', '1573', '1610', '1611', '1612', '1613', '1614', '1619', '1620', + '1630', '1640', '1650', '1660', '1661', '1662', '1663', '1670', '1671', '1672', '1673', '1680', + '1681', '1682', '1683', '1684', '1685', '1686', '1687', '1688', '1689', '1690', '1710', '1720', + '1730', '1740', '1750', '1760', '1770', '1780', '1790', '1810', '1820', '1830', '1860', '1880', + '1886', '1889', '1890', '1910', '1911', '1912', '1913', '1920', '1930', '1940', '1950', '1960', + '1970', '1972', '1973', '1974', '1979', '1980', '1990', '2010', '2011', '2013', '2017', '2018', + '2019', '2020', '2021', '2023', '2027', '2028', '2029', '2030', '2031', '2033', '2037', '2038', + '2039', '2040', '2041', '2043', '2047', '2048', '2049', '2050', '2060', '2061', '2064', '2065', + '2066', '2067', '2068', '2069', '2070', '2071', '2072', '2080', '2081', '2082', '2083', '2084', + '2085', '2086', '2087', '2088', '2089', '2090', '2091', '2092', '2093', '2094', '2095', '2096', + '2097', '2098', '2099', '2110', '2120', '2121', '2122', '2123', '2124', '2125', '2126', '2127', + '2129', '2130', '2131', '2132', '2133', '2134', '2135', '2136', '2137', '2139', '2150', '2151', + '2152', '2153', '2160', '2161', '2162', '2164', '2190', '2196', '2199', '2210', '2220', '2230', + '2240', '2250', '2252', '2253', '2290', '2310', '2320', '2321', '2322', '2323', '2324', '2330', + '2340', '2350', '2351', '2355', '2359', '2360', '2361', '2362', '2363', '2370', '2371', '2372', + '2373', '2390', '2391', '2392', '2393', '2394', '2395', '2396', '2397', '2399', '2410', '2411', + '2412', '2417', '2419', '2420', '2421', '2429', '2430', '2431', '2438', '2439', '2440', '2441', + '2443', '2445', '2448', '2450', '2460', '2461', '2462', '2463', '2470', '2471', '2472', '2473', + '2480', '2490', '2491', '2492', '2499', '2510', '2512', '2513', '2514', '2515', '2517', '2518', + '2610', '2611', '2612', '2613', '2614', '2615', '2616', '2618', '2620', '2621', '2622', '2623', + '2624', '2625', '2626', '2628', '2630', '2631', '2632', '2633', '2634', '2635', '2636', '2638', + '2640', '2641', '2642', '2645', '2646', '2647', '2648', '2649', '2650', '2660', '2670', '2710', + '2730', '2731', '2732', '2740', '2750', '2760', '2761', '2762', '2790', '2791', '2792', '2793', + '2794', '2795', '2799', '2810', '2811', '2812', '2820', '2821', '2822', '2823', '2829', '2830', + '2840', '2841', '2849', '2850', '2852', '2860', '2861', '2862', '2863', '2870', '2871', '2872', + '2873', '2880', '2890', '2891', '2892', '2893', '2895', '2897', '2898', '2899', '2910', '2911', + '2912', '2919', '2920', '2930', '2931', '2940', '2941', '2942', '2943', '2944', '2950', '2951', + '2959', '2960', '2970', '2971', '2972', '2979', '2980', '2990', '2991', '2992', '2993', '2995', + '2998', '2999', '3000', '3001', '3002', '3003', '3004', '3100', '3105', '3106', '3108', '3200', + '3211', '3212', '3231', '3300', '3305', '3308', '3400', '3401', '3402', '3403', '3404', '3500', + '3510', '3511', '3518', '3520', '3521', '3522', '3530', '3540', '3541', '3542', '3550', '3560', + '3561', '3562', '3563', '3570', '3590', '3600', '3610', '3611', '3612', '3613', '3619', '3620', + '3630', '3670', '3671', '3672', '3679', '3680', '3690', '3700', '3710', '3730', '3731', '3732', + '3740', '3750', '3751', '3752', '3790', '3800', '3840', '3850', '3870', '3900', '3910', '3911', + '3912', '3913', '3914', '3920', '3921', '3922', '3925', '3940', '3950', '3960', '3970', '3971', + '3972', '3973', '3980', '3981', '3985', '3987', '3988', '3989', '3990', '3991', '3992', '3993', + '3994', '3995', '3996', '3997', '3998', '3999', '4000', '4010', '4060', '4065', '4066', '4067', + '4070', '4075', '4076', '4077', '4078', '4080', '4085', '4086', '4087', '4090', '4091', '4092', + '4099', '4200', '4210', '4211', '4212', '4300', '4310', '4400', '4410', '4415', '4416', '4417', + '4420', '4425', '4426', '4427', '4500', '4510', '4515', '4516', '4517', '4518', '4530', '4531', + '4532', '4533', '4535', '4536', '4537', '4538', '4540', '4545', '4546', '4547', '4598', '4600', + '4610', '4670', '4700', '4730', '4731', '4732', '4739', '4800', '4810', '4820', '4830', '4840', + '4890', '4900', '4910', '4920', '4940', '4944', '4945', '4947', '4950', '4960', '4970', '4974', + '4975', '4977', '4980', '4981', '4987', '4988', '5000', '5010', '5011', '5012', '5013', '5019', + '5020', '5030', '5040', '5050', '5060', '5061', '5062', '5064', '5065', '5069', '5070', '5090', + '5100', '5110', '5120', '5130', '5131', '5132', '5139', '5140', '5160', '5161', '5162', '5164', + '5165', '5169', '5170', '5190', '5191', '5192', '5193', '5198', '5200', '5210', '5220', '5250', + '5290', '5300', '5310', '5320', '5330', '5340', '5350', '5360', '5370', '5380', '5390', '5400', + '5410', '5411', '5412', '5420', '5430', '5440', '5460', '5480', '5500', '5510', '5520', '5530', + '5550', '5580', '5590', '5600', '5610', '5611', '5612', '5613', '5615', '5616', '5619', '5620', + '5621', '5622', '5623', '5625', '5626', '5629', '5630', '5631', '5632', '5633', '5635', '5639', + '5640', '5641', '5642', '5643', '5645', '5646', '5649', '5650', '5651', '5652', '5653', '5655', + '5656', '5659', '5670', '5671', '5672', '5673', '5675', '5679', '5680', '5681', '5682', '5683', + '5685', '5689', '5690', '5691', '5692', '5693', '5695', '5696', '5699', '5700', '5710', '5711', + '5712', '5720', '5721', '5722', '5729', '5730', '5790', '5800', '5810', '5820', '5830', '5831', + '5832', '5890', '5900', '5910', '5920', '5930', '5940', '5950', '5960', '5970', '5980', '5981', + '5982', '5990', '6000', '6010', '6020', '6030', '6040', '6050', '6055', '6059', '6060', '6061', + '6062', '6063', '6064', '6069', '6070', '6071', '6072', '6080', '6090', '6100', '6110', '6150', + '6200', '6210', '6211', '6212', '6219', '6230', '6250', '6290', '6300', '6310', '6320', '6330', + '6340', '6341', '6342', '6350', '6351', '6352', '6360', '6361', '6362', '6370', '6380', '6390', + '6391', '6392', '6400', '6420', '6421', '6422', '6423', '6424', '6430', '6440', '6450', '6490', + '6500', '6510', '6520', '6530', '6540', '6550', '6551', '6552', '6553', '6554', '6555', '6556', + '6559', '6560', '6570', '6580', '6590', '6700', '6710', '6800', '6810', '6820', '6830', '6840', + '6850', '6860', '6870', '6880', '6890', '6900', '6910', '6920', '6930', '6940', '6950', '6970', + '6980', '6981', '6982', '6990', '6991', '6992', '6993', '6996', '6997', '6998', '6999', '7000', + '7010', '7011', '7012', '7013', '7017', '7018', '7019', '7030', '7031', '7032', '7037', '7038', + '7039', '7080', '7081', '7082', '7083', '7089', '7090', '7200', '7210', '7211', '7212', '7213', + '7217', '7218', '7219', '7220', '7221', '7222', '7227', '7228', '7229', '7230', '7231', '7232', + '7237', '7238', '7239', '7240', '7280', '7281', '7282', '7283', '7284', '7285', '7286', '7288', + '7289', '7290', '7291', '7292', '7300', '7310', '7311', '7312', '7313', '7314', '7315', '7316', + '7317', '7318', '7319', '7320', '7321', '7322', '7323', '7324', '7330', '7331', '7332', '7333', + '7350', '7370', '7380', '7381', '7382', '7383', '7384', '7385', '7386', '7387', '7388', '7389', + '7390', '7391', '7392', '7400', '7410', '7411', '7412', '7420', '7430', '7440', '7441', '7448', + '7460', '7461', '7462', '7463', '7470', '7490', '7500', '7510', '7511', '7512', '7515', '7516', + '7518', '7519', '7530', '7531', '7532', '7533', '7550', '7551', '7552', '7553', '7554', '7570', + '7571', '7572', '7580', '7581', '7582', '7583', '7589', '7590', '7600', '7610', '7620', '7621', + '7622', '7623', '7630', '7631', '7632', '7650', '7670', '7671', '7678', '7690', '7691', '7692', + '7693', '7699', '7710', '7720', '7730', '7731', '7732', '7733', '7740', '7760', '7770', '7780', + '7781', '7782', '7783', '7790', '7810', '7811', '7812', '7813', '7814', '7815', '7816', '7817', + '7819', '7820', '7821', '7824', '7829', '7830', '7831', '7832', '7836', '7839', '7840', '7940', + '7960', '7970', '7971', '7972', '7973', '7990', '8010', '8012', '8016', '8020', '8030', '8070', + '8072', '8076', '8077', '8080', '8082', '8086', '8087', '8110', '8111', '8112', '8113', '8116', + '8117', '8118', '8120', '8121', '8122', '8123', '8130', '8131', '8132', '8133', '8170', '8171', + '8172', '8173', '8174', '8176', '8177', '8180', '8181', '8182', '8183', '8184', '8186', '8187', + '8210', '8212', '8216', '8220', '8221', '8222', '8223', '8230', '8231', '8236', '8240', '8250', + '8251', '8252', '8254', '8255', '8260', '8261', '8262', '8263', '8270', '8271', '8272', '8273', + '8280', '8281', '8282', '8283', '8290', '8291', '8295', '8310', '8311', '8312', '8313', '8314', + '8317', '8319', '8320', '8321', '8325', '8330', '8331', '8336', '8340', '8350', '8360', '8361', + '8362', '8363', '8370', '8380', '8390', '8400', '8410', '8411', '8412', '8413', '8415', '8417', + '8418', '8419', '8420', '8421', '8422', '8423', '8424', '8429', '8430', '8431', '8436', '8440', + '8450', '8451', '8455', '8460', '8461', '8462', '8463', '8480', '8490', '8491', '8810', '8811', + '8819', '8820', '8830', '8840', '8850', '8851', '8852', '8853', '8860', '8861', '8862', '8864', + '8865', '8866', '8869', '8890', '8892', '8896', '8899', '8910', '8920', '8930', '8940', '8980', + '8990', '8999', ] const BAS_ACCOUNT_NUMBER_SET: ReadonlySet = new Set(BAS_ACCOUNT_NUMBERS) diff --git a/lib/bookkeeping/bas-data/class-1-assets.ts b/lib/bookkeeping/bas-data/class-1-assets.ts index 97fdf798..d158536b 100644 --- a/lib/bookkeeping/bas-data/class-1-assets.ts +++ b/lib/bookkeeping/bas-data/class-1-assets.ts @@ -697,36 +697,14 @@ export const CLASS_1_ACCOUNTS: BASReferenceAccount[] = [ sru_code: '7202', k2_excluded: false, }, - { - account_number: '1241', - account_name: 'Personbilar', - account_class: 1, - account_group: '12', - account_type: 'asset', - normal_balance: 'debit', - description: 'Personbilar', - sru_code: '7202', - k2_excluded: false, - }, - { - account_number: '1242', - account_name: 'Lastbilar och andra transportmedel', - account_class: 1, - account_group: '12', - account_type: 'asset', - normal_balance: 'debit', - description: 'Lastbilar och andra transportmedel', - sru_code: '7202', - k2_excluded: false, - }, { account_number: '1249', - account_name: 'Ack. avskrivningar på bilar och andra transportmedel', + account_name: 'Ackumulerade avskrivningar (fritt konto för Maskiner och andra tekniska anläggningar)', account_class: 1, account_group: '12', account_type: 'asset', normal_balance: 'credit', - description: 'Ackumulerade avskrivningar på bilar och andra transportmedel (kontra-tillgång)', + description: 'Ackumulerade avskrivningar på det fria maskinkontot 1240 (kontra-tillgång). BAS 2026 har inga bilkonton i 124x; bilar är 1216 eller 1226.', sru_code: '7202', k2_excluded: false, }, @@ -741,25 +719,14 @@ export const CLASS_1_ACCOUNTS: BASReferenceAccount[] = [ sru_code: '7215', k2_excluded: false, }, - { - account_number: '1251', - account_name: 'Inventarier', - account_class: 1, - account_group: '12', - account_type: 'asset', - normal_balance: 'debit', - description: 'Inventarier', - sru_code: '7215', - k2_excluded: false, - }, { account_number: '1259', - account_name: 'Ack. avskrivningar på inventarier och verktyg', + account_name: 'Ackumulerade avskrivningar (fritt konto för Inventarier, verktyg och installationer)', account_class: 1, account_group: '12', account_type: 'asset', normal_balance: 'credit', - description: 'Ackumulerade avskrivningar på inventarier och verktyg (kontra-tillgång)', + description: 'Ackumulerade avskrivningar på det fria inventariekontot 1250 (kontra-tillgång). BAS 2026 har inga datorkonton i 125x; datorer är 1214 eller 1224.', sru_code: '7215', k2_excluded: false, }, @@ -774,25 +741,14 @@ export const CLASS_1_ACCOUNTS: BASReferenceAccount[] = [ sru_code: '7215', k2_excluded: false, }, - { - account_number: '1261', - account_name: 'Datorer, bärbara', - account_class: 1, - account_group: '12', - account_type: 'asset', - normal_balance: 'debit', - description: 'Datorer, bärbara', - sru_code: '7215', - k2_excluded: false, - }, { account_number: '1269', - account_name: 'Ack. avskrivningar på datorer', + account_name: 'Ackumulerade avskrivningar (fritt konto för Inventarier, verktyg och installationer)', account_class: 1, account_group: '12', account_type: 'asset', normal_balance: 'credit', - description: 'Ackumulerade avskrivningar på datorer (kontra-tillgång)', + description: 'Ackumulerade avskrivningar på det fria inventariekontot 1260 (kontra-tillgång). BAS 2026 har inga leasingkonton i 126x; leasade tillgångar är 1217 eller 1227.', sru_code: '7215', k2_excluded: false, }, diff --git a/supabase/migrations/20260908113353_backfill_bas2026_retired_12xx_labels.sql b/supabase/migrations/20260908113353_backfill_bas2026_retired_12xx_labels.sql new file mode 100644 index 00000000..3dc29318 --- /dev/null +++ b/supabase/migrations/20260908113353_backfill_bas2026_retired_12xx_labels.sql @@ -0,0 +1,97 @@ +-- Backfill: retire the pre-2026 labels on 1249/1259/1269 where the company's +-- head account already carries the BAS 2026 free-account label (#2413). +-- +-- BAS 2026 restructured kontogrupp 12: 1210 (maskiner, för produktion) and +-- 1220 (inventarier, ej för produktion) got the bilar/datorer sub-accounts, +-- while 1230/1240 became "(Fritt konto för Maskiner och andra tekniska +-- anläggningar)" and 1250/1260 "(Fritt konto för Inventarier, verktyg och +-- installationer)". The catalog in lib/bookkeeping/bas-data/ followed for the +-- heads but kept the retired contra accounts 1249/1259/1269 with their old +-- names, so a company that activated 1240 + 1249 from the picker got a free +-- machinery account whose only contra account said "bilar". The catalog now +-- names those contra accounts after their heads; this backfill does the same +-- for charts that already carry the contradictory pair. +-- +-- Safety: a row is renamed only when BOTH hold: its name is byte-identical to +-- one of the two catalog literals it could have been seeded with, AND the +-- company's head account (1240/1250/1260) carries the BAS 2026 free label. +-- A chart imported from an older BAS (1240 "Bilar och andra transportmedel") +-- is internally consistent and is left alone, as is every user rename. +-- +-- Third guard: the contra account has no journal lines. A SIE import whose +-- #KONTO names were not carried creates BOTH rows from the catalog +-- (lib/import/account-sync.ts create pass), so an old-BAS vehicle chart can +-- hold exactly the pair above with years of "Avskrivningar bil" postings on +-- 1249. A label with history is the user's to change; this backfill only +-- corrects the label the picker handed out before anything was booked on it. +-- No row is deleted; bookings key on account_number, never on the label. +-- +-- The migration runs in one transaction (Supabase CLI wraps it). The SHARE +-- lock below makes the "no journal lines" check and the rename atomic against +-- concurrent postings: inserts on journal_entry_lines wait the few +-- milliseconds this takes, reads are unaffected. + +LOCK TABLE public.journal_entry_lines IN SHARE MODE; + +UPDATE public.chart_of_accounts a + SET account_name = 'Ackumulerade avskrivningar (fritt konto för Maskiner och andra tekniska anläggningar)', + updated_at = now() + WHERE a.account_number = '1249' + AND a.account_name IN ( + 'Ack. avskrivningar på bilar och andra transportmedel', + 'Ackumulerade avskrivningar på bilar och andra transportmedel' + ) + AND EXISTS ( + SELECT 1 FROM public.chart_of_accounts h + WHERE h.company_id = a.company_id + AND h.account_number = '1240' + AND h.account_name = '(Fritt konto för Maskiner och andra tekniska anläggningar)' + ) + AND NOT EXISTS ( + SELECT 1 FROM public.journal_entry_lines l + JOIN public.journal_entries e ON e.id = l.journal_entry_id + WHERE e.company_id = a.company_id + AND l.account_number = a.account_number + ); + +UPDATE public.chart_of_accounts a + SET account_name = 'Ackumulerade avskrivningar (fritt konto för Inventarier, verktyg och installationer)', + updated_at = now() + WHERE a.account_number = '1259' + AND a.account_name IN ( + 'Ack. avskrivningar på inventarier och verktyg', + 'Ackumulerade avskrivningar på inventarier och verktyg' + ) + AND EXISTS ( + SELECT 1 FROM public.chart_of_accounts h + WHERE h.company_id = a.company_id + AND h.account_number = '1250' + AND h.account_name = '(Fritt konto för Inventarier, verktyg och installationer)' + ) + AND NOT EXISTS ( + SELECT 1 FROM public.journal_entry_lines l + JOIN public.journal_entries e ON e.id = l.journal_entry_id + WHERE e.company_id = a.company_id + AND l.account_number = a.account_number + ); + +UPDATE public.chart_of_accounts a + SET account_name = 'Ackumulerade avskrivningar (fritt konto för Inventarier, verktyg och installationer)', + updated_at = now() + WHERE a.account_number = '1269' + AND a.account_name IN ( + 'Ack. avskrivningar på datorer', + 'Ackumulerade avskrivningar på datorer' + ) + AND EXISTS ( + SELECT 1 FROM public.chart_of_accounts h + WHERE h.company_id = a.company_id + AND h.account_number = '1260' + AND h.account_name = '(Fritt konto för Inventarier, verktyg och installationer)' + ) + AND NOT EXISTS ( + SELECT 1 FROM public.journal_entry_lines l + JOIN public.journal_entries e ON e.id = l.journal_entry_id + WHERE e.company_id = a.company_id + AND l.account_number = a.account_number + ); diff --git a/tests/pg/bas2026-retired-12xx-labels.pg.test.ts b/tests/pg/bas2026-retired-12xx-labels.pg.test.ts new file mode 100644 index 00000000..83001817 --- /dev/null +++ b/tests/pg/bas2026-retired-12xx-labels.pg.test.ts @@ -0,0 +1,171 @@ +import { readFileSync } from 'node:fs' +import { join } from 'node:path' +import { describe, expect, it } from 'vitest' +import { insertPostedJournalEntry, seedCompany } from '@/tests/pg/fixtures' +import { getPool } from '@/tests/pg/setup' + +/** + * pg-real coverage for 20260908113353_backfill_bas2026_retired_12xx_labels.sql + * (#2413). + * + * The backfill renames 1249/1259/1269 only where the chart carries the + * contradictory pair the catalog used to hand out: a BAS 2026 free head + * (1240/1250/1260) next to a contra account still named after the retired + * bilar/inventarier/datorer accounts. Guards under test: + * - the pair is renamed (both catalog literals for the contra name) + * - an old-BAS chart (1240 "Bilar och andra transportmedel") is untouched + * - a user-renamed contra account is untouched + * - a contra account without its head is untouched + * - a contra account with journal lines (old-BAS SIE import re-labelled by + * the catalog on create) is untouched + * - idempotent (re-run is a no-op) + */ + +const BACKFILL_SQL = readFileSync( + join(process.cwd(), 'supabase/migrations/20260908113353_backfill_bas2026_retired_12xx_labels.sql'), + 'utf8', +) + +const FREE_MASKINER = '(Fritt konto för Maskiner och andra tekniska anläggningar)' +const FREE_INVENTARIER = '(Fritt konto för Inventarier, verktyg och installationer)' +const CONTRA_MASKINER = + 'Ackumulerade avskrivningar (fritt konto för Maskiner och andra tekniska anläggningar)' +const CONTRA_INVENTARIER = + 'Ackumulerade avskrivningar (fritt konto för Inventarier, verktyg och installationer)' + +async function runBackfill(): Promise { + await getPool().query(BACKFILL_SQL) +} + +async function insertAccounts( + userId: string, + companyId: string, + rows: Array<[number: string, name: string]>, +): Promise { + for (const [number, name] of rows) { + await getPool().query( + `INSERT INTO public.chart_of_accounts + (user_id, company_id, account_number, account_name, account_class, account_group, + account_type, normal_balance, is_active) + VALUES ($1, $2, $3, $4, 1, '12', 'asset', $5, true)`, + [userId, companyId, number, name, number.endsWith('9') ? 'credit' : 'debit'], + ) + } +} + +async function names(companyId: string): Promise> { + const { rows } = await getPool().query<{ account_number: string; account_name: string }>( + `SELECT account_number, account_name FROM public.chart_of_accounts WHERE company_id = $1`, + [companyId], + ) + return Object.fromEntries(rows.map((r) => [r.account_number, r.account_name])) +} + +describe('backfill_bas2026_retired_12xx_labels', () => { + it('renames the contra account under a BAS 2026 free head, both catalog literals', async () => { + const { userId, companyId } = await seedCompany() + await insertAccounts(userId, companyId, [ + ['1240', FREE_MASKINER], + ['1249', 'Ack. avskrivningar på bilar och andra transportmedel'], + ['1250', FREE_INVENTARIER], + ['1259', 'Ackumulerade avskrivningar på inventarier och verktyg'], + ['1260', FREE_INVENTARIER], + ['1269', 'Ack. avskrivningar på datorer'], + ]) + + await runBackfill() + + const after = await names(companyId) + expect(after['1249']).toBe(CONTRA_MASKINER) + expect(after['1259']).toBe(CONTRA_INVENTARIER) + expect(after['1269']).toBe(CONTRA_INVENTARIER) + expect(after['1240']).toBe(FREE_MASKINER) + }) + + it('leaves an old-BAS chart alone: 1240 Bilar next to 1249 Ack. avskr. bilar is consistent', async () => { + const { userId, companyId } = await seedCompany() + await insertAccounts(userId, companyId, [ + ['1240', 'Bilar och andra transportmedel'], + ['1249', 'Ackumulerade avskrivningar på bilar och andra transportmedel'], + ['1250', 'Datorer'], + ['1259', 'Ackumulerade avskrivningar på datorer'], + ]) + + await runBackfill() + + const after = await names(companyId) + expect(after['1249']).toBe('Ackumulerade avskrivningar på bilar och andra transportmedel') + expect(after['1259']).toBe('Ackumulerade avskrivningar på datorer') + }) + + it('leaves a user rename alone', async () => { + const { userId, companyId } = await seedCompany() + await insertAccounts(userId, companyId, [ + ['1240', FREE_MASKINER], + ['1249', 'Ack. avskrivningar maskiner och andra tekniska anläggningar'], + ]) + + await runBackfill() + + expect((await names(companyId))['1249']).toBe( + 'Ack. avskrivningar maskiner och andra tekniska anläggningar', + ) + }) + + it('leaves a contra account without its free head alone', async () => { + const { userId, companyId } = await seedCompany() + await insertAccounts(userId, companyId, [ + ['1249', 'Ack. avskrivningar på bilar och andra transportmedel'], + ]) + + await runBackfill() + + expect((await names(companyId))['1249']).toBe( + 'Ack. avskrivningar på bilar och andra transportmedel', + ) + }) + + it('leaves a contra account with journal lines alone, even under a free head', async () => { + // lib/import/account-sync.ts creates missing accounts with the catalog + // name when the SIE #KONTO names are not carried, so an old-BAS vehicle + // chart can hold the exact pair with real depreciation booked on 1249. + const { userId, companyId, fiscalPeriodId } = await seedCompany() + await insertAccounts(userId, companyId, [ + ['1240', FREE_MASKINER], + ['1249', 'Ack. avskrivningar på bilar och andra transportmedel'], + ['7832', 'Avskrivningar på inventarier'], + ]) + await insertPostedJournalEntry({ + userId, + companyId, + fiscalPeriodId, + sourceType: 'import', + lines: [ + { accountNumber: '7832', debitAmount: 2500, creditAmount: 0 }, + { accountNumber: '1249', debitAmount: 0, creditAmount: 2500 }, + ], + }) + + await runBackfill() + + expect((await names(companyId))['1249']).toBe( + 'Ack. avskrivningar på bilar och andra transportmedel', + ) + }) + + it('is idempotent', async () => { + const { userId, companyId } = await seedCompany() + await insertAccounts(userId, companyId, [ + ['1260', FREE_INVENTARIER], + ['1269', 'Ackumulerade avskrivningar på datorer'], + ]) + + await runBackfill() + const first = await names(companyId) + await runBackfill() + const second = await names(companyId) + + expect(first['1269']).toBe(CONTRA_INVENTARIER) + expect(second).toEqual(first) + }) +})