From b44d7f472f98b2945960d619b95314378f6e72ba Mon Sep 17 00:00:00 2001 From: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Date: Wed, 11 Feb 2026 10:00:47 +0100 Subject: [PATCH] Fix SEPA parser: fallback to Ntry-level AmtDtls (#3182) Some banks (e.g. Raiffeisen) place AmtDtls at the Ntry level instead of NtryDtls.TxDtls. The parser only checked TxDtls, causing txAmount/txCurrency to be NULL. This broke automatic BUY_CRYPTO assignment with a TypeError in getAndCompleteTxRequest. Use NtryDtls.TxDtls.AmtDtls with fallback to Ntry.AmtDtls. --- .../bank-tx/bank-tx/dto/sepa-entry.dto.ts | 13 +++++++++++++ .../bank-tx/services/sepa-parser.service.ts | 17 ++++++++++------- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/subdomains/supporting/bank-tx/bank-tx/dto/sepa-entry.dto.ts b/src/subdomains/supporting/bank-tx/bank-tx/dto/sepa-entry.dto.ts index 11d3b4dbd2..57a92825e9 100644 --- a/src/subdomains/supporting/bank-tx/bank-tx/dto/sepa-entry.dto.ts +++ b/src/subdomains/supporting/bank-tx/bank-tx/dto/sepa-entry.dto.ts @@ -83,5 +83,18 @@ export interface SepaEntry { AddtlTxInf: string; }; }; + AmtDtls: { + InstdAmt: { + Amt: SepaAmount; + }; + TxAmt: { + Amt: SepaAmount; + CcyXchg: { + SrcCcy: string; + TrgtCcy: string; + XchgRate: string; + }; + }; + }; AddtlNtryInf: string; } diff --git a/src/subdomains/supporting/bank-tx/bank-tx/services/sepa-parser.service.ts b/src/subdomains/supporting/bank-tx/bank-tx/services/sepa-parser.service.ts index 70e89ef8fd..9a5ae84558 100644 --- a/src/subdomains/supporting/bank-tx/bank-tx/services/sepa-parser.service.ts +++ b/src/subdomains/supporting/bank-tx/bank-tx/services/sepa-parser.service.ts @@ -80,6 +80,9 @@ export class SepaParser { let data: Partial = {}; try { + // AmtDtls can be at TxDtls level or Ntry level depending on the bank + const amtDtls = entry?.NtryDtls?.TxDtls?.AmtDtls ?? entry?.AmtDtls; + data = { bookingDate: new Date(entry?.BookgDt?.Dt), valueDate: new Date(entry?.ValDt?.Dt), @@ -90,13 +93,13 @@ export class SepaParser { amount: +entry?.NtryDtls?.TxDtls?.Amt?.['#text'], currency, creditDebitIndicator, - instructedAmount: +entry?.NtryDtls?.TxDtls?.AmtDtls?.InstdAmt?.Amt?.['#text'], - instructedCurrency: this.toString(entry?.NtryDtls?.TxDtls?.AmtDtls?.InstdAmt?.Amt?.['@_Ccy']), - txAmount: +entry?.NtryDtls?.TxDtls?.AmtDtls?.TxAmt?.Amt?.['#text'], - txCurrency: this.toString(entry?.NtryDtls?.TxDtls?.AmtDtls?.TxAmt?.Amt?.['@_Ccy']), - exchangeSourceCurrency: this.toString(entry?.NtryDtls?.TxDtls?.AmtDtls?.TxAmt?.CcyXchg?.SrcCcy), - exchangeTargetCurrency: this.toString(entry?.NtryDtls?.TxDtls?.AmtDtls?.TxAmt?.CcyXchg?.TrgtCcy), - exchangeRate: +entry?.NtryDtls?.TxDtls?.AmtDtls?.TxAmt?.CcyXchg?.XchgRate, + instructedAmount: +amtDtls?.InstdAmt?.Amt?.['#text'], + instructedCurrency: this.toString(amtDtls?.InstdAmt?.Amt?.['@_Ccy']), + txAmount: +amtDtls?.TxAmt?.Amt?.['#text'], + txCurrency: this.toString(amtDtls?.TxAmt?.Amt?.['@_Ccy']), + exchangeSourceCurrency: this.toString(amtDtls?.TxAmt?.CcyXchg?.SrcCcy), + exchangeTargetCurrency: this.toString(amtDtls?.TxAmt?.CcyXchg?.TrgtCcy), + exchangeRate: +amtDtls?.TxAmt?.CcyXchg?.XchgRate, ...(await this.getTotalCharge( creditDebitIndicator === SepaCdi.CREDIT ? entry?.NtryDtls?.TxDtls?.Chrgs?.Rcrd : entry?.Chrgs?.Rcrd, currency,