diff --git a/lib/bookkeeping/dimension-rules.ts b/lib/bookkeeping/dimension-rules.ts index 9e8ea62c..b01a4076 100644 --- a/lib/bookkeeping/dimension-rules.ts +++ b/lib/bookkeeping/dimension-rules.ts @@ -186,7 +186,13 @@ export function assertMandatoryDimensions( * result account must not be able to block closing the year * - storno/correction/credit notes are HOW history gets fixed — blocking * them on entries that pre-date a rule would make old mistakes - * permanent (same argument as the commitEntry bypass for reversals) + * permanent (same argument as the commitEntry bypass for reversals). + * Credit notes specifically COPY the original's bags (PR7) so the + * reversal nets against the same dimension cells: if the original + * satisfied the rules, so does the copy (enforcement = no-op); if the + * original pre-dates the rules, enforcing would demand an ASYMMETRIC + * tag — a credit in P001 with no original in P001 — which is exactly + * the project-P&L skew this feature exists to prevent * - accrual dissolutions replay a schedule created before the rule * * Operational sources (manual, bank_transaction, invoice_*, supplier_* diff --git a/lib/bookkeeping/engine.ts b/lib/bookkeeping/engine.ts index 5bd3d883..0ccc1e2e 100644 --- a/lib/bookkeeping/engine.ts +++ b/lib/bookkeeping/engine.ts @@ -592,6 +592,9 @@ export async function commitEntry( // System/correction sources are exempt — see // DIMENSION_RULE_EXEMPT_SOURCE_TYPES (imported history, bokslut // mechanics and credit instruments must never be blocked by policy). + // source_type is a HEADER column (journal_entries) — the join repeats + // the same value on every line, so reading lines[0] IS reading the + // entry header; lines cannot mix source types. if (!isDimensionRuleExemptSource(typedLines[0]?.journal_entries?.source_type)) { assertMandatoryDimensions(typedLines, rules) } diff --git a/lib/import/__tests__/sie-dimensions-roundtrip.test.ts b/lib/import/__tests__/sie-dimensions-roundtrip.test.ts index ea720774..abb8786b 100644 --- a/lib/import/__tests__/sie-dimensions-roundtrip.test.ts +++ b/lib/import/__tests__/sie-dimensions-roundtrip.test.ts @@ -69,11 +69,6 @@ const SOURCE_SIE = [ '#TRANS 5010 {1 "KS01" 2 "KB1" 6 "P001"} 15000.00', '#TRANS 1930 {} -15000.00', '}', - '#VER A 3 20260117 "Avdelningskostnad"', - '{', - '#TRANS 5010 {20 "SYD" 25 "T1"} 800.00', - '#TRANS 1930 {} -800.00', - '}', '#VER A 2 20260116 "Odeklarerat projekt"', '{', // P002 is referenced but never declared via #OBJEKT — import synthesizes @@ -81,6 +76,11 @@ const SOURCE_SIE = [ '#TRANS 5010 {6 "P002"} 500.00', '#TRANS 1930 {} -500.00', '}', + '#VER A 3 20260117 "Avdelningskostnad"', + '{', + '#TRANS 5010 {20 "SYD" 25 "T1"} 800.00', + '#TRANS 1930 {} -800.00', + '}', ].join('\n') describe('SIE dimensions round-trip', () => {