commit 9adbdbe59b7a865fa61881ba4a3c60f847bfa413
parent 9076c7a1b22c87e27feb2e1a99a22d6566ad7034
Author: MS <ms@taler.net>
Date: Tue, 30 May 2023 10:49:24 +0200
PostFinance connection.
Testing the ingestion (including deduplication) of
outgoing payments.
Diffstat:
4 files changed, 182 insertions(+), 17 deletions(-)
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/iso20022/Iso20022.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/iso20022/Iso20022.kt
@@ -972,6 +972,9 @@ fun ingestCamtMessageIntoAccount(
// https://bugs.gnunet.org/view.php?id=6381
continue@txloop
}
+ /* Checking for the unstructured remittance information before
+ storing the payment in the database. */
+ val paymentSubject = entry.getSingletonSubject() // throws if not found.
val rawEntity = NexusBankTransactionEntity.new {
bankAccount = acct
accountTransactionId = paymentUid
@@ -983,7 +986,7 @@ fun ingestCamtMessageIntoAccount(
}
rawEntity.flush()
newTransactions++
- newPaymentsLog += "\n- ${entry.getSingletonSubject()}"
+ newPaymentsLog += "\n- $paymentSubject"
// This block tries to acknowledge a former outgoing payment as booked.
if (singletonBatchedTransaction.creditDebitIndicator == CreditDebitIndicator.DBIT) {
diff --git a/nexus/src/test/kotlin/Iso20022Test.kt b/nexus/src/test/kotlin/Iso20022Test.kt
@@ -9,7 +9,8 @@ import org.junit.Ignore
import org.junit.Test
import org.w3c.dom.Document
import poFiCamt052
-import poFiCamt054_2019
+import poFiCamt054_2019_incoming
+import poFiCamt054_2019_outgoing
import prepNexusDb
import tech.libeufin.nexus.bankaccount.getBankAccount
import tech.libeufin.nexus.iso20022.*
@@ -119,23 +120,63 @@ class Iso20022Test {
@Test
fun parsePoFiCamt054() {
- val doc = XMLUtil.parseStringIntoDom(poFiCamt054_2019)
+ val doc = XMLUtil.parseStringIntoDom(poFiCamt054_2019_incoming)
parseCamtMessage(doc, dialect = "pf")
}
- // TODO: test deduplication here.
+ /**
+ * Testing how outgoing payments get ingested and how their
+ * deduplication logic reacts, given that sometimes camt.054
+ * was seen without the AcctSvcrRef.
+ */
+ @Test
+ fun ingestPoFiCamt054_outgoing() {
+ val doc = XMLUtil.parseStringIntoDom(poFiCamt054_2019_outgoing)
+ withTestDatabase {
+ prepNexusDb()
+ transaction { assert(NexusBankTransactionEntity.all().count() == 0L) }
+ ingestCamtMessageIntoAccount(
+ "foo",
+ doc,
+ FetchLevel.NOTIFICATION,
+ dialect = "pf"
+ )
+ transaction { assert(NexusBankTransactionEntity.all().count() == 1L) }
+ // Checking that the payment doesn't get stored twice.
+ ingestCamtMessageIntoAccount(
+ "foo",
+ doc,
+ FetchLevel.NOTIFICATION,
+ dialect = "pf"
+ )
+ transaction { assert(NexusBankTransactionEntity.all().count() == 1L) }
+ }
+ }
@Test
fun ingestPoFiCamt054() {
- val doc = XMLUtil.parseStringIntoDom(poFiCamt054_2019)
+ val doc = XMLUtil.parseStringIntoDom(poFiCamt054_2019_incoming)
withTestDatabase {
prepNexusDb()
+ // Checking that no transactions exist already in the database.
+ transaction { assert(NexusBankTransactionEntity.all().count() == 0L) }
+ ingestCamtMessageIntoAccount(
+ "foo",
+ doc,
+ FetchLevel.NOTIFICATION,
+ dialect = "pf"
+ )
+ // Checking that now ONE transaction exist in the database.
+ transaction { assert(NexusBankTransactionEntity.all().count() == 1L) }
+ // Checking now that the same payment doesn't get ingested twice.
ingestCamtMessageIntoAccount(
"foo",
doc,
FetchLevel.NOTIFICATION,
dialect = "pf"
)
+ // The count should have stayed the same.
+ transaction { assert(NexusBankTransactionEntity.all().count() == 1L) }
}
}
// Checks that the 2019 pain.001 version validates.
diff --git a/nexus/src/test/kotlin/MakeEnv.kt b/nexus/src/test/kotlin/MakeEnv.kt
@@ -494,10 +494,140 @@ fun genNexusIncomingCamt(
)
)
+val poFiCamt054_2019_outgoing: String = """
+ <?xml version="1.0" encoding="UTF-8"?>
+ <Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.054.001.08" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:camt.054.001.08 file:///C:/Users/burkhalterl/Documents/Musterfiles%20ISOV19/Schemen/camt.054.001.08.xsd">
+ <BkToCstmrDbtCdtNtfctn>
+ <GrpHdr>
+ <MsgId>20200618375204295372463</MsgId>
+ <CreDtTm>2022-03-10T23:40:14</CreDtTm>
+ <MsgPgntn>
+ <PgNb>1</PgNb>
+ <LastPgInd>true</LastPgInd>
+ </MsgPgntn>
+ <AddtlInf>SPS/2.0/PROD</AddtlInf>
+ </GrpHdr>
+ <Ntfctn>
+ <Id>20200618375204295372465</Id>
+ <CreDtTm>2022-03-10T23:40:14</CreDtTm>
+ <FrToDt>
+ <FrDtTm>2022-03-10T00:00:00</FrDtTm>
+ <ToDtTm>2022-03-10T23:59:59</ToDtTm>
+ </FrToDt>
+ <Acct>
+ <Id>
+ <IBAN>${FOO_USER_IBAN}</IBAN>
+ </Id>
+ <Ccy>CHF</Ccy>
+ <Ownr>
+ <Nm>Robert Schneider SA Grands magasins Biel/Bienne</Nm>
+ </Ownr>
+ </Acct>
+ <Ntry>
+ <NtryRef>CH2909000000250094239</NtryRef>
+ <Amt Ccy="CHF">522.10</Amt>
+ <CdtDbtInd>DBIT</CdtDbtInd>
+ <RvslInd>false</RvslInd>
+ <Sts>
+ <Cd>BOOK</Cd>
+ </Sts>
+ <BookgDt>
+ <Dt>2022-03-10</Dt>
+ </BookgDt>
+ <ValDt>
+ <Dt>2022-03-10</Dt>
+ </ValDt>
+ <AcctSvcrRef>1000000000000000</AcctSvcrRef>
+ <BkTxCd>
+ <Domn>
+ <Cd>PMNT</Cd>
+ <Fmly>
+ <Cd>RCDT</Cd>
+ <SubFmlyCd>ATXN</SubFmlyCd>
+ </Fmly>
+ </Domn>
+ </BkTxCd>
+ <NtryDtls>
+ <Btch>
+ <NbOfTxs>1</NbOfTxs>
+ </Btch>
+ <TxDtls>
+ <Refs>
+ <InstrId>1006265-25bbb3b1a</InstrId>
+ <EndToEndId>client-generated</EndToEndId>
+ <UETR>b009c997-97b3-4a9c-803c-d645a7276bf0</UETR>
+ <Prtry>
+ <Tp>00</Tp>
+ <Ref>00000000000000000000020</Ref>
+ </Prtry>
+ </Refs>
+ <Amt Ccy="CHF">522.10</Amt>
+ <CdtDbtInd>DBIT</CdtDbtInd>
+ <BkTxCd>
+ <Domn>
+ <Cd>PMNT</Cd>
+ <Fmly>
+ <Cd>RCDT</Cd>
+ <SubFmlyCd>ATXN</SubFmlyCd>
+ </Fmly>
+ </Domn>
+ </BkTxCd>
+ <RltdPties>
+ <Dbtr>
+ <Pty>
+ <Nm>Bernasconi Maria</Nm>
+ <PstlAdr>
+ <AdrLine>Place de la Gare 12</AdrLine>
+ <AdrLine>2502 Biel/Bienne</AdrLine>
+ </PstlAdr>
+ </Pty>
+ </Dbtr>
+ <DbtrAcct>
+ <Id>
+ <IBAN>CH5109000000250092291</IBAN>
+ </Id>
+ </DbtrAcct>
+ <CdtrAcct>
+ <Id>
+ <IBAN>CH2909000000250094239</IBAN>
+ </Id>
+ </CdtrAcct>
+ </RltdPties>
+ <RltdAgts>
+ <DbtrAgt>
+ <FinInstnId>
+ <BICFI>POFICHBEXXX</BICFI>
+ <Nm>POSTFINANCE AG</Nm>
+ <PstlAdr>
+ <AdrLine>MINGERSTRASSE 20</AdrLine>
+ <AdrLine>3030 BERNE</AdrLine>
+ </PstlAdr>
+ </FinInstnId>
+ </DbtrAgt>
+ </RltdAgts>
+ <RmtInf>
+ <Strd>
+ <AddtlRmtInf>?REJECT?0</AddtlRmtInf>
+ <AddtlRmtInf>?ERROR?000</AddtlRmtInf>
+ </Strd>
+ <Ustrd>Reserve pub.</Ustrd>
+ </RmtInf>
+ <RltdDts>
+ <AccptncDtTm>2022-03-10T20:00:00</AccptncDtTm>
+ </RltdDts>
+ </TxDtls>
+ </NtryDtls>
+ <AddtlNtryInf>GUTSCHRIFT AUFTRAGGEBER: Bernasconi Maria Place de la Gare 12 2502 Biel/Bienne REFERENZEN: NOTPROVIDED 1006265-25bbb3b1a 2000000000000000</AddtlNtryInf>
+ </Ntry>
+ </Ntfctn>
+ </BkToCstmrDbtCdtNtfctn>
+ </Document>
+""".trimIndent()
+
// Comes from a "mit Sammelbuchung" sample.
// "mit Einzelbuchung" sample didn't have the "Ustrd"
// See: https://www.postfinance.ch/de/support/services/dokumente/musterfiles-fuer-geschaeftskunden.html
-val poFiCamt054_2019: String = """
+val poFiCamt054_2019_incoming: String = """
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.054.001.08" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:camt.054.001.08 file:///C:/Users/burkhalterl/Documents/Musterfiles%20ISOV19/Schemen/camt.054.001.08.xsd">
<BkToCstmrDbtCdtNtfctn>
@@ -627,7 +757,6 @@ val poFiCamt054_2019: String = """
</Ntfctn>
</BkToCstmrDbtCdtNtfctn>
</Document>
-
""".trimIndent()
val poFiCamt054_2013: String = """
diff --git a/nexus/src/test/kotlin/PostFinance.kt b/nexus/src/test/kotlin/PostFinance.kt
@@ -103,14 +103,6 @@ fun main() {
fooBankAccount.iban = "CH9789144829733648596"
}
}
- // uploadPain001Payment() // XE2
- // downloadPayment() // Z54.
- /*runBlocking {
- (ebicsConn as EbicsBankConnectionProtocol).fetchPaymentReceipt(
- FetchSpecLatestJson(FetchLevel.RECEIPT, null),
- HttpClient(),
- "postfinance",
- "foo"
- )
- }*/
+ // uploadQrrPayment()
+ // downloadPayment()
}
\ No newline at end of file