libeufin

Integration and sandbox testing for FinTech APIs and data formats
Log | Files | Refs | Submodules | README | LICENSE

commit cc0ccb35adb2e4854168f409156c9318f7508319
parent 76572686b1e5947afa1a36329ceddc90b15c9875
Author: Antoine A <>
Date:   Thu, 30 Oct 2025 11:57:28 +0100

nexus: fix pain.002 parsing for valiant

Diffstat:
Anexus/sample/platform/valiant_pain002.xml | 25+++++++++++++++++++++++++
Mnexus/src/main/kotlin/tech/libeufin/nexus/cli/EbicsSetup.kt | 8++++----
Mnexus/src/main/kotlin/tech/libeufin/nexus/iso20022/camt.kt | 21++++++++-------------
Mnexus/src/main/kotlin/tech/libeufin/nexus/iso20022/pain002.kt | 19+++++++++++--------
4 files changed, 48 insertions(+), 25 deletions(-)

diff --git a/nexus/sample/platform/valiant_pain002.xml b/nexus/sample/platform/valiant_pain002.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.002.001.10"> + <CstmrPmtStsRpt> + <GrpHdr> + <MsgId>pain.002/20251030/104854310674000</MsgId> + <CreDtTm>2025-10-30T10:48:54+01:00</CreDtTm> + <InitgPty> + <Id> + <OrgId> + <AnyBIC>VABECH22XXX</AnyBIC> + </OrgId> + </Id> + </InitgPty> + </GrpHdr> + <OrgnlGrpInfAndSts> + <OrgnlMsgId>5HIS3433VVIBAANHW3GX9DR1AXRS43KZ4U</OrgnlMsgId> + <OrgnlMsgNmId>pain.001</OrgnlMsgNmId> + <GrpSts>ACCP</GrpSts> + <StsRsnInf> + <AddtlInf>PN10630020F0297329.20251030104613.EBTUAAAC.PN1.0002372</AddtlInf> + </StsRsnInf> + </OrgnlGrpInfAndSts> + </CstmrPmtStsRpt> +</Document> +\ No newline at end of file diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/cli/EbicsSetup.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/cli/EbicsSetup.kt @@ -264,15 +264,15 @@ class EbicsSetup: TalerCmd() { if (partner.name != null) { append("'") append(partner.name) - append("' - ") + append("'") } for ((currency, iban, bic) in partner.accounts) { + append(' ') append(currency) - append('_') + append('-') append(iban) - append('_') + append('-') append(bic) - append(' ') } append('\n') } diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/iso20022/camt.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/iso20022/camt.kt @@ -120,11 +120,8 @@ data class BatchId( ): OutId { fun ref(): String = msgId override fun toString(): String = buildString { - append('(') - if (msgId != null) { - append("msg=") - append(msgId.toString()) - } + append("(msg=") + append(msgId) if (acctSvcrRef != null) { if (length != 1) append(" ") append("ref=") @@ -277,7 +274,7 @@ private fun XmlDestructor.outgoingId(ref: String?): OutId = } else { OutgoingId(msgId, endToEndId, ref) } - } ?: OutgoingId(null, null, ref) + } ?: OutgoingId(acctSvcrRef = ref) /** Parse transaction ids as provided by bank*/ private fun XmlDestructor.incomingId(ref: String?): IncomingId = @@ -285,7 +282,7 @@ private fun XmlDestructor.incomingId(ref: String?): IncomingId = val uetr = opt("UETR")?.uuid() val txId = opt("TxId")?.text() IncomingId(uetr, txId, ref) - } ?: IncomingId(null, null, ref) + } ?: IncomingId(acctSvcrRef = ref) /** Parse and format transaction return reasons */ @@ -445,7 +442,7 @@ private fun XmlDestructor.optBankTransactionCode(): BankTransactionCode? { /** Parse transaction wire transfer subject */ private fun XmlDestructor.wireTransferSubject(): String? = opt("RmtInf") { - map("Ustrd") { text() }?.joinToString("")?.trim() + map("Ustrd") { text() }.joinToString("").trim() } /** Parse account information */ @@ -532,17 +529,15 @@ fun parseTx(notifXml: InputStream, dialect: Dialect): List<AccountTransactions> // Amount val txAmount = complexAmount() val amount = if (unique) { - if (entryAmount != null && txAmount != null) { + if (txAmount != null) { entryAmount.resolve(txAmount) } else { - requireNotNull(entryAmount ?: txAmount) { "Missing unique tx amount" } + entryAmount } } else { requireNotNull(txAmount) { "Missing batch tx amount" } } - if (entryAmount != null) { - totalAmount = totalAmount?.let { it + amount.amount } ?: amount.amount - } + totalAmount = totalAmount?.let { it + amount.amount } ?: amount.amount // Ref val txRef = opt("Refs")?.opt("AcctSvcrRef")?.text() diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/iso20022/pain002.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/iso20022/pain002.kt @@ -36,12 +36,15 @@ private fun fmtMsg(code: String?, description: String?, reasons: List<Reason>) = } for (reason in reasons) { append(" ") - append(reason.code.isoCode) - append(" '") - append(reason.code.description) - append("'") - if (reason.information.isNotEmpty()) { + if (reason.code != null) { + append(reason.code.isoCode) append(" '") + append(reason.code.description) + append("'") + } + if (reason.information.isNotEmpty()) { + if (reason.code != null) append(" ") + append("'") append(reason.information) append("'") } @@ -103,11 +106,11 @@ data class TxStatus( val code: ExternalPaymentTransactionStatusCode, val reasons: List<Reason> ) { - fun msg() = fmtMsg(code?.isoCode, code?.description, reasons) + fun msg() = fmtMsg(code.isoCode, code.description, reasons) } data class Reason ( - val code: ExternalStatusReasonCode, + val code: ExternalStatusReasonCode?, val information: String ) @@ -115,7 +118,7 @@ data class Reason ( fun parseCustomerPaymentStatusReport(xml: InputStream): MsgStatus { fun XmlDestructor.reasons(): List<Reason> { return map("StsRsnInf") { - val code = one("Rsn").one("Cd").enum<ExternalStatusReasonCode>() + val code = opt("Rsn")?.one("Cd")?.enum<ExternalStatusReasonCode>() val info = map("AddtlInf") { text() }.joinToString("") Reason(code, info) }