commit 5315d262be9ac369d375943d4b3c7f3e5c897a04
parent b771f6976c8f541f23dc5b8f50725174837d63f1
Author: Antoine A <>
Date: Mon, 2 Dec 2024 13:21:19 +0100
nexus: parse maerki_baumann debit confirmation
Diffstat:
4 files changed, 364 insertions(+), 15 deletions(-)
diff --git a/nexus/sample/platform/maerki_baumann_camt053.xml b/nexus/sample/platform/maerki_baumann_camt053.xml
@@ -196,6 +196,261 @@
</NtryDtls>
<AddtlNtryInf>Bank clearing payment Grothoff Hans</AddtlNtryInf>
</Ntry>
+ <Ntry>
+ <Amt Ccy="CHF">.1</Amt>
+ <CdtDbtInd>DBIT</CdtDbtInd>
+ <RvslInd>false</RvslInd>
+ <Sts>
+ <Cd>BOOK</Cd>
+ </Sts>
+ <BookgDt>
+ <Dt>2024-11-27</Dt>
+ </BookgDt>
+ <ValDt>
+ <Dt>2024-11-27</Dt>
+ </ValDt>
+ <BkTxCd>
+ <Domn>
+ <Cd>PMNT</Cd>
+ <Fmly>
+ <Cd>ICDT</Cd>
+ <SubFmlyCd>OTHR</SubFmlyCd>
+ </Fmly>
+ </Domn>
+ </BkTxCd>
+ <NtryDtls>
+ <TxDtls>
+ <Refs>
+ <MsgId>BATCH_SINGLE_REPORTING</MsgId>
+ <AcctSvcrRef>ZV20241121/773541/1</AcctSvcrRef>
+ <PmtInfId>NOTPROVIDED</PmtInfId>
+ <InstrId>5IBJZOWESQGPCSOXSNNBBY49ZURI5W7Q4H</InstrId>
+ <EndToEndId>5IBJZOWESQGPCSOXSNNBBY49ZURI5W7Q4H</EndToEndId>
+ <UETR>30c030ad-01cc-4cbf-b2d4-428cccaa1a85</UETR>
+ </Refs>
+ <Amt Ccy="CHF">.1</Amt>
+ <CdtDbtInd>DBIT</CdtDbtInd>
+ <RltdPties>
+ <Cdtr>
+ <Pty>
+ <Nm>Grothoff Hans</Nm>
+ </Pty>
+ </Cdtr>
+ <CdtrAcct>
+ <Id>
+ <IBAN>CH7389144832588726658</IBAN>
+ </Id>
+ </CdtrAcct>
+ </RltdPties>
+ <RmtInf>
+ <Ustrd>multi 0 2024-11-21T15:21:59.8859234 63Z</Ustrd>
+ </RmtInf>
+ <AddtlTxInf>PAIN-Auftrag Grothoff Hans</AddtlTxInf>
+ </TxDtls>
+ </NtryDtls>
+ <AddtlNtryInf>PAIN-Auftrag Grothoff Hans</AddtlNtryInf>
+ </Ntry>
+ <Ntry>
+ <Amt Ccy="CHF">.13</Amt>
+ <CdtDbtInd>DBIT</CdtDbtInd>
+ <RvslInd>false</RvslInd>
+ <Sts>
+ <Cd>BOOK</Cd>
+ </Sts>
+ <BookgDt>
+ <Dt>2024-11-27</Dt>
+ </BookgDt>
+ <ValDt>
+ <Dt>2024-11-27</Dt>
+ </ValDt>
+ <BkTxCd>
+ <Domn>
+ <Cd>PMNT</Cd>
+ <Fmly>
+ <Cd>ICDT</Cd>
+ <SubFmlyCd>OTHR</SubFmlyCd>
+ </Fmly>
+ </Domn>
+ </BkTxCd>
+ <NtryDtls>
+ <Btch>
+ <NbOfTxs>1</NbOfTxs>
+ <TtlAmt Ccy="CHF">.13</TtlAmt>
+ <CdtDbtInd>DBIT</CdtDbtInd>
+ </Btch>
+ <TxDtls>
+ <Refs>
+ <MsgId>BATCH_SINGLE_REPORTING</MsgId>
+ <AcctSvcrRef>ZV20241121/773541/4</AcctSvcrRef>
+ <PmtInfId>NOTPROVIDED</PmtInfId>
+ <InstrId>XZ15UR0XU52QWI7Q4XB88EDS44PLH7DYXH</InstrId>
+ <EndToEndId>XZ15UR0XU52QWI7Q4XB88EDS44PLH7DYXH</EndToEndId>
+ <UETR>b14d4554-49a0-4c99-a49e-5ebb4fa177d1</UETR>
+ </Refs>
+ <Amt Ccy="CHF">.13</Amt>
+ <CdtDbtInd>DBIT</CdtDbtInd>
+ <AmtDtls>
+ <InstdAmt>
+ <Amt Ccy="CHF">.13</Amt>
+ </InstdAmt>
+ <TxAmt>
+ <Amt Ccy="CHF">.13</Amt>
+ </TxAmt>
+ </AmtDtls>
+ <RltdPties>
+ <Cdtr>
+ <Pty>
+ <Nm>Grothoff Hans</Nm>
+ </Pty>
+ </Cdtr>
+ <CdtrAcct>
+ <Id>
+ <IBAN>CH7389144832588726658</IBAN>
+ </Id>
+ </CdtrAcct>
+ </RltdPties>
+ <RmtInf>
+ <Ustrd>multi 3 2024-11-21T15:21:59.8859234 63Z</Ustrd>
+ </RmtInf>
+ <AddtlTxInf>PAIN-Auftrag Grothoff Hans</AddtlTxInf>
+ </TxDtls>
+ </NtryDtls>
+ <AddtlNtryInf>PAIN-Auftrag Grothoff Hans</AddtlNtryInf>
+ </Ntry>
+ <Ntry>
+ <Amt Ccy="CHF">.12</Amt>
+ <CdtDbtInd>DBIT</CdtDbtInd>
+ <RvslInd>false</RvslInd>
+ <Sts>
+ <Cd>BOOK</Cd>
+ </Sts>
+ <BookgDt>
+ <Dt>2024-11-27</Dt>
+ </BookgDt>
+ <ValDt>
+ <Dt>2024-11-27</Dt>
+ </ValDt>
+ <BkTxCd>
+ <Domn>
+ <Cd>PMNT</Cd>
+ <Fmly>
+ <Cd>ICDT</Cd>
+ <SubFmlyCd>OTHR</SubFmlyCd>
+ </Fmly>
+ </Domn>
+ </BkTxCd>
+ <NtryDtls>
+ <Btch>
+ <NbOfTxs>1</NbOfTxs>
+ <TtlAmt Ccy="CHF">.12</TtlAmt>
+ <CdtDbtInd>DBIT</CdtDbtInd>
+ </Btch>
+ <TxDtls>
+ <Refs>
+ <MsgId>BATCH_SINGLE_REPORTING</MsgId>
+ <AcctSvcrRef>ZV20241121/773541/3</AcctSvcrRef>
+ <PmtInfId>NOTPROVIDED</PmtInfId>
+ <InstrId>A09R35EW0359SZ51464E7TC37A0P2CBK04</InstrId>
+ <EndToEndId>A09R35EW0359SZ51464E7TC37A0P2CBK04</EndToEndId>
+ <UETR>fa3869de-e29b-4163-9ffa-b9c6d6b70d25</UETR>
+ </Refs>
+ <Amt Ccy="CHF">.12</Amt>
+ <CdtDbtInd>DBIT</CdtDbtInd>
+ <AmtDtls>
+ <InstdAmt>
+ <Amt Ccy="CHF">.12</Amt>
+ </InstdAmt>
+ <TxAmt>
+ <Amt Ccy="CHF">.12</Amt>
+ </TxAmt>
+ </AmtDtls>
+ <RltdPties>
+ <Cdtr>
+ <Pty>
+ <Nm>Grothoff Hans</Nm>
+ </Pty>
+ </Cdtr>
+ <CdtrAcct>
+ <Id>
+ <IBAN>CH7389144832588726658</IBAN>
+ </Id>
+ </CdtrAcct>
+ </RltdPties>
+ <RmtInf>
+ <Ustrd>multi 2 2024-11-21T15:21:59.8859234 63Z</Ustrd>
+ </RmtInf>
+ <AddtlTxInf>PAIN-Auftrag Grothoff Hans</AddtlTxInf>
+ </TxDtls>
+ </NtryDtls>
+ <AddtlNtryInf>PAIN-Auftrag Grothoff Hans</AddtlNtryInf>
+ </Ntry>
+ <Ntry>
+ <Amt Ccy="CHF">.11</Amt>
+ <CdtDbtInd>DBIT</CdtDbtInd>
+ <RvslInd>false</RvslInd>
+ <Sts>
+ <Cd>BOOK</Cd>
+ </Sts>
+ <BookgDt>
+ <Dt>2024-11-27</Dt>
+ </BookgDt>
+ <ValDt>
+ <Dt>2024-11-27</Dt>
+ </ValDt>
+ <BkTxCd>
+ <Domn>
+ <Cd>PMNT</Cd>
+ <Fmly>
+ <Cd>ICDT</Cd>
+ <SubFmlyCd>OTHR</SubFmlyCd>
+ </Fmly>
+ </Domn>
+ </BkTxCd>
+ <NtryDtls>
+ <Btch>
+ <NbOfTxs>1</NbOfTxs>
+ <TtlAmt Ccy="CHF">.11</TtlAmt>
+ <CdtDbtInd>DBIT</CdtDbtInd>
+ </Btch>
+ <TxDtls>
+ <Refs>
+ <MsgId>BATCH_SINGLE_REPORTING</MsgId>
+ <AcctSvcrRef>ZV20241121/773541/2</AcctSvcrRef>
+ <PmtInfId>NOTPROVIDED</PmtInfId>
+ <InstrId>UYXZ78LE9KAIMBY6UNXFYT1K8KNY8VLZLT</InstrId>
+ <EndToEndId>UYXZ78LE9KAIMBY6UNXFYT1K8KNY8VLZLT</EndToEndId>
+ <UETR>93b01b18-36f6-4e42-a3bf-e4341b7e64cf</UETR>
+ </Refs>
+ <Amt Ccy="CHF">.11</Amt>
+ <CdtDbtInd>DBIT</CdtDbtInd>
+ <AmtDtls>
+ <InstdAmt>
+ <Amt Ccy="CHF">.11</Amt>
+ </InstdAmt>
+ <TxAmt>
+ <Amt Ccy="CHF">.11</Amt>
+ </TxAmt>
+ </AmtDtls>
+ <RltdPties>
+ <Cdtr>
+ <Pty>
+ <Nm>Grothoff Hans</Nm>
+ </Pty>
+ </Cdtr>
+ <CdtrAcct>
+ <Id>
+ <IBAN>CH7389144832588726658</IBAN>
+ </Id>
+ </CdtrAcct>
+ </RltdPties>
+ <RmtInf>
+ <Ustrd>multi 1 2024-11-21T15:21:59.8859234 63Z</Ustrd>
+ </RmtInf>
+ <AddtlTxInf>PAIN-Auftrag Grothoff Hans</AddtlTxInf>
+ </TxDtls>
+ </NtryDtls>
+ <AddtlNtryInf>PAIN-Auftrag Grothoff Hans</AddtlNtryInf>
+ </Ntry>
</Stmt>
</BkToCstmrStmt>
</Document>
\ No newline at end of file
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/iso20022/camt.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/iso20022/camt.kt
@@ -501,19 +501,36 @@ fun parseTx(notifXml: InputStream, dialect: Dialect): List<AccountTransactions>
val code = optBankTransactionCode() ?: code
val (amount, fee) = amountAndFee()
val subject = wireTransferSubject()
- if (!code.isReversal() && kind == Kind.CRDT) {
- val bankId = opt("Refs")?.opt("UETR")?.text()
- val debtorPayto = payto("Dbtr")
- txsInfo.add(TxInfo.Credit(
- ref = bankId ?: txRef ?: entryRef,
- bookDate = bookDate,
- bankId = bankId,
- amount = amount,
- subject = subject,
- debtorPayto = debtorPayto,
- code = code,
- creditFee = fee
- ))
+ if (!code.isReversal()) {
+ when (kind) {
+ Kind.CRDT -> {
+ val bankId = opt("Refs")?.opt("UETR")?.text()
+ val debtorPayto = payto("Dbtr")
+ txsInfo.add(TxInfo.Credit(
+ ref = bankId ?: txRef ?: entryRef,
+ bookDate = bookDate,
+ bankId = bankId,
+ amount = amount,
+ subject = subject,
+ debtorPayto = debtorPayto,
+ code = code,
+ creditFee = fee
+ ))
+ }
+ Kind.DBIT -> {
+ val outgoingId = outgoingId()
+ val creditorPayto = payto("Cdtr")
+ txsInfo.add(TxInfo.Debit(
+ ref = outgoingId.ref() ?: txRef ?: entryRef,
+ bookDate = bookDate,
+ id = outgoingId,
+ amount = amount,
+ subject = subject,
+ creditorPayto = creditorPayto,
+ code = code
+ ))
+ }
+ }
}
}
}
diff --git a/nexus/src/test/kotlin/Iso20022Test.kt b/nexus/src/test/kotlin/Iso20022Test.kt
@@ -373,6 +373,38 @@ class Iso20022Test {
subject = "Random subject",
executionTime = dateToInstant("2024-11-04"),
debtorPayto = ibanPayto("CH7389144832588726658", "Mr Test")
+ ),
+ OutgoingPayment(
+ endToEndId = "5IBJZOWESQGPCSOXSNNBBY49ZURI5W7Q4H",
+ msgId = "BATCH_SINGLE_REPORTING",
+ amount = TalerAmount("CHF:0.1"),
+ subject = "multi 0 2024-11-21T15:21:59.8859234 63Z",
+ executionTime = dateToInstant("2024-11-27"),
+ creditorPayto = ibanPayto("CH7389144832588726658", "Grothoff Hans")
+ ),
+ OutgoingPayment(
+ endToEndId = "XZ15UR0XU52QWI7Q4XB88EDS44PLH7DYXH",
+ msgId = "BATCH_SINGLE_REPORTING",
+ amount = TalerAmount("CHF:0.13"),
+ subject = "multi 3 2024-11-21T15:21:59.8859234 63Z",
+ executionTime = dateToInstant("2024-11-27"),
+ creditorPayto = ibanPayto("CH7389144832588726658", "Grothoff Hans")
+ ),
+ OutgoingPayment(
+ endToEndId = "A09R35EW0359SZ51464E7TC37A0P2CBK04",
+ msgId = "BATCH_SINGLE_REPORTING",
+ amount = TalerAmount("CHF:0.12"),
+ subject = "multi 2 2024-11-21T15:21:59.8859234 63Z",
+ executionTime = dateToInstant("2024-11-27"),
+ creditorPayto = ibanPayto("CH7389144832588726658", "Grothoff Hans")
+ ),
+ OutgoingPayment(
+ endToEndId = "UYXZ78LE9KAIMBY6UNXFYT1K8KNY8VLZLT",
+ msgId = "BATCH_SINGLE_REPORTING",
+ amount = TalerAmount("CHF:0.11"),
+ subject = "multi 1 2024-11-21T15:21:59.8859234 63Z",
+ executionTime = dateToInstant("2024-11-27"),
+ creditorPayto = ibanPayto("CH7389144832588726658", "Grothoff Hans")
)
)
))
diff --git a/nexus/src/test/kotlin/RegistrationTest.kt b/nexus/src/test/kotlin/RegistrationTest.kt
@@ -405,12 +405,28 @@ class RegistrationTest {
/** Maerki Baumann dialect test */
@Test
fun maerki_baumann() = setup("maerki_baumann.conf") { db, cfg ->
+ db.batches(mapOf(
+ "BATCH_SINGLE_REPORTING" to listOf(
+ genInitPay("5IBJZOWESQGPCSOXSNNBBY49ZURI5W7Q4H"),
+ genInitPay("XZ15UR0XU52QWI7Q4XB88EDS44PLH7DYXH"),
+ genInitPay("A09R35EW0359SZ51464E7TC37A0P2CBK04"),
+ genInitPay("UYXZ78LE9KAIMBY6UNXFYT1K8KNY8VLZLT"),
+ ),
+ ))
+
// Register camt files
db.register(cfg, "sample/platform/maerki_baumann_camt053.xml", OrderDoc.statement)
// Check state
db.check(
- status = emptyMap(),
+ status = mapOf(
+ "BATCH_SINGLE_REPORTING" to Pair(SubmissionState.success, mapOf(
+ "5IBJZOWESQGPCSOXSNNBBY49ZURI5W7Q4H" to SubmissionState.success,
+ "XZ15UR0XU52QWI7Q4XB88EDS44PLH7DYXH" to SubmissionState.success,
+ "A09R35EW0359SZ51464E7TC37A0P2CBK04" to SubmissionState.success,
+ "UYXZ78LE9KAIMBY6UNXFYT1K8KNY8VLZLT" to SubmissionState.success,
+ )),
+ ),
incoming = listOf(
IncomingPayment(
bankId = "adbe4a5a-6cea-4263-b259-8ab964561a32",
@@ -429,7 +445,36 @@ class RegistrationTest {
debtorPayto = ibanPayto("CH7389144832588726658", "Mr Test")
)
),
- outgoing = emptyList()
+ outgoing = listOf(
+ OutgoingPayment(
+ endToEndId = "5IBJZOWESQGPCSOXSNNBBY49ZURI5W7Q4H",
+ amount = TalerAmount("CHF:0.1"),
+ subject = "multi 0 2024-11-21T15:21:59.8859234 63Z",
+ executionTime = dateToInstant("2024-11-27"),
+ creditorPayto = ibanPayto("CH7389144832588726658", "Grothoff Hans")
+ ),
+ OutgoingPayment(
+ endToEndId = "XZ15UR0XU52QWI7Q4XB88EDS44PLH7DYXH",
+ amount = TalerAmount("CHF:0.13"),
+ subject = "multi 3 2024-11-21T15:21:59.8859234 63Z",
+ executionTime = dateToInstant("2024-11-27"),
+ creditorPayto = ibanPayto("CH7389144832588726658", "Grothoff Hans")
+ ),
+ OutgoingPayment(
+ endToEndId = "A09R35EW0359SZ51464E7TC37A0P2CBK04",
+ amount = TalerAmount("CHF:0.12"),
+ subject = "multi 2 2024-11-21T15:21:59.8859234 63Z",
+ executionTime = dateToInstant("2024-11-27"),
+ creditorPayto = ibanPayto("CH7389144832588726658", "Grothoff Hans")
+ ),
+ OutgoingPayment(
+ endToEndId = "UYXZ78LE9KAIMBY6UNXFYT1K8KNY8VLZLT",
+ amount = TalerAmount("CHF:0.11"),
+ subject = "multi 1 2024-11-21T15:21:59.8859234 63Z",
+ executionTime = dateToInstant("2024-11-27"),
+ creditorPayto = ibanPayto("CH7389144832588726658", "Grothoff Hans")
+ )
+ )
)
}
}
\ No newline at end of file