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:
co-authored by
Claude Opus 4.6
parent
565d956371
commit
0ba1db1c21
@@ -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++])
|
||||
|
||||
Reference in New Issue
Block a user