fix: skip BTRANS/RTRANS in SIE parser to prevent false balance errors (#63)

When Fortnox corrects a voucher, the SIE file contains #BTRANS (added)
and #RTRANS (removed) lines alongside #TRANS (final state). The parser
was summing all three, causing corrected vouchers to appear unbalanced.
Only #TRANS represents the final voucher state — BTRANS/RTRANS are
correction audit trail.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jakob Wennberg
2026-03-20 12:10:08 +01:00
committed by GitHub
co-authored by Claude Opus 4.6
parent 565d956371
commit 0ba1db1c21
+13 -5
View File
@@ -574,16 +574,24 @@ export function parseSIEFile(content: string): ParsedSIEFile {
case 'TRANS':
case 'RTRANS':
case 'BTRANS': {
// #TRANS/#RTRANS/#BTRANS accountNumber {objectList} amount [date] [description] [quantity] [signature]
// BTRANS = Added/corrected transaction lines (part of the voucher)
// RTRANS = Removed/reversed transaction lines (amounts already have correct sign)
// All three must be included for vouchers to balance correctly.
// Fortnox/Bokio/Visma only emit #TRANS — this is a no-op for those providers.
// #TRANS = final transaction lines (the current state of the voucher)
// #RTRANS = removed lines (correction audit trail — original lines that were undone)
// #BTRANS = added lines (correction audit trail — new lines that replaced removed ones)
//
// When a voucher has been corrected, Fortnox/Visma emit all three types.
// Only #TRANS represents the final voucher state; #RTRANS and #BTRANS are
// supplementary history. We skip RTRANS/BTRANS to avoid double-counting
// which would make balanced vouchers appear unbalanced.
if (!currentVoucher) {
addIssue(issues, 'error', lineNum, `${tag} outside of VER block`, tag)
break
}
// Skip RTRANS/BTRANS — they are correction audit trail, not final state
if (tag === 'RTRANS' || tag === 'BTRANS') {
break
}
// Parse account and skip object list (in braces)
let fieldIndex = 1
const account = parseStringField(fields[fieldIndex++])