libeufin

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

Iso20022Test.kt (34588B)


      1 /*
      2  * This file is part of LibEuFin.
      3  * Copyright (C) 2024, 2025, 2026 Taler Systems S.A.
      4 
      5  * LibEuFin is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU Affero General Public License as
      7  * published by the Free Software Foundation; either version 3, or
      8  * (at your option) any later version.
      9 
     10  * LibEuFin is distributed in the hope that it will be useful, but
     11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General
     13  * Public License for more details.
     14 
     15  * You should have received a copy of the GNU Affero General Public
     16  * License along with LibEuFin; see the file COPYING.  If not, see
     17  * <http://www.gnu.org/licenses/>
     18  */
     19 
     20 import org.junit.Test
     21 import tech.libeufin.common.*
     22 import tech.libeufin.nexus.*
     23 import tech.libeufin.nexus.iso20022.*
     24 import tech.libeufin.ebics.*
     25 import kotlin.io.path.*
     26 import kotlin.test.*
     27 import java.time.Instant
     28 
     29 class Iso20022Test {
     30     @Test
     31     fun pain001() {
     32         val creditor = IbanAccountMetadata(
     33             iban = "CH4189144589712575493",
     34             bic = null,
     35             name = "Test"
     36         )
     37         val msg = Pain001Msg(
     38             messageId = "MESSAGE_ID",
     39             timestamp = dateToInstant("2024-09-09"),
     40             debtor = IbanAccountMetadata(
     41                 iban = "CH7789144474425692816",
     42                 bic = "BIC",
     43                 name = "myname"
     44             ),
     45             sum = TalerAmount("CHF:47.32"),
     46             txs = listOf(
     47                 Pain001Tx(
     48                     creditor = creditor,
     49                     amount = TalerAmount("CHF:42"),
     50                     subject = "Test 42",
     51                     endToEndId = "TX_FIRST"
     52                 ),
     53                 Pain001Tx(
     54                     creditor = creditor,
     55                     amount = TalerAmount("CHF:5.11"),
     56                     subject = "Test 5.11",
     57                     endToEndId = "TX_SECOND"
     58                 ),
     59                 Pain001Tx(
     60                     creditor = creditor,
     61                     amount = TalerAmount("CHF:0.21"),
     62                     subject = "Test 0.21",
     63                     endToEndId = "TX_THIRD"
     64                 )
     65             )
     66         )
     67         for (dialect in Dialect.entries) {
     68             assertEquals(
     69                 Path("sample/platform/${dialect}_pain001.xml").readText().replace("VERSION", VERSION),
     70                 createPain001(msg, dialect, false).asUtf8()
     71             )
     72         }
     73     }
     74 
     75     @Test
     76     fun hac() {
     77         assertContentEquals(
     78             parseCustomerAck(Path("sample/platform/hac.xml").inputStream()),
     79             listOf(
     80                 CustomerAck(
     81                     actionType = HacAction.FILE_DOWNLOAD,
     82                     orderId = null,
     83                     code = ExternalStatusReasonCode.TS01,
     84                     info = "",
     85                     timestamp = dateTimeToInstant("2024-09-02T15:47:30.350Z")
     86                 ),
     87                 CustomerAck(
     88                     actionType = HacAction.FILE_UPLOAD,
     89                     orderId = "ORDER_SUCCESS",
     90                     code = ExternalStatusReasonCode.TS01,
     91                     info = "",
     92                     timestamp = dateTimeToInstant("2024-09-02T20:48:43.153Z")
     93                 ),
     94                 CustomerAck(
     95                     actionType = HacAction.ES_VERIFICATION,
     96                     orderId = "ORDER_SUCCESS",
     97                     code = ExternalStatusReasonCode.DS01,
     98                     info = "",
     99                     timestamp = dateTimeToInstant("2024-09-02T20:48:43.153Z")
    100                 ),
    101                 CustomerAck(
    102                     actionType = HacAction.ORDER_HAC_FINAL_POS,
    103                     orderId = "ORDER_SUCCESS",
    104                     code = null,
    105                     info = "Some multiline info",
    106                     timestamp = dateTimeToInstant("2024-09-02T20:48:43.153Z")
    107                 ),
    108                 CustomerAck(
    109                     actionType = HacAction.FILE_DOWNLOAD,
    110                     orderId = null,
    111                     code = ExternalStatusReasonCode.TD01,
    112                     info = "",
    113                     timestamp = dateTimeToInstant("2024-09-02T15:47:31.754Z")
    114                 ),
    115                 CustomerAck(
    116                     actionType = HacAction.FILE_UPLOAD,
    117                     orderId = "ORDER_FAILURE",
    118                     code = ExternalStatusReasonCode.TS01,
    119                     info = "",
    120                     timestamp = dateTimeToInstant("2024-08-23T15:34:11.987")
    121                 ),
    122                 CustomerAck(
    123                     actionType = HacAction.ES_VERIFICATION,
    124                     orderId = "ORDER_FAILURE",
    125                     code = ExternalStatusReasonCode.TD03,
    126                     info = "",
    127                     timestamp = dateTimeToInstant("2024-08-23T15:34:13.307")
    128                 ),
    129                 CustomerAck(
    130                     actionType = HacAction.ORDER_HAC_FINAL_NEG,
    131                     orderId = "ORDER_FAILURE",
    132                     code = null,
    133                     info = "",
    134                     timestamp = dateTimeToInstant("2024-08-23T15:34:13.307")
    135                 ),
    136             )
    137         )
    138     }
    139 
    140     @Test
    141     fun postfinance_camt054() {
    142         assertContentEquals(
    143             parseTx(Path("sample/platform/postfinance_camt054.xml").inputStream()),
    144             listOf(AccountTransactions(
    145                 iban = "CH9289144596463965762",
    146                 currency = "CHF",
    147                 txs = listOf(
    148                     OutgoingPayment(
    149                         id = OutgoingId("ZS1PGNTSV0ZNDFAJBBWWB8015G", "ZS1PGNTSV0ZNDFAJBBWWB8015G", null),
    150                         amount = TalerAmount("CHF:3.00"),
    151                         subject = null,
    152                         executionTime = dateToInstant("2024-01-15"),
    153                         creditor = null
    154                     ),
    155                     IncomingPayment(
    156                         id = IncomingId("62e2b511-7313-4ccd-8d40-c9d8e612cd71", null, "231121CH0AZWCR9T"),
    157                         amount = TalerAmount("CHF:10"),
    158                         subject = "G1XTY6HGWGMVRM7E6XQ4JHJK561ETFDFTJZ7JVGV543XZCB27YBG",
    159                         executionTime = dateToInstant("2023-12-19"),
    160                         debtor = ibanPayto("CH7389144832588726658", "Mr Test")
    161                     ),
    162                     IncomingPayment(
    163                         id = IncomingId("62e2b511-7313-4ccd-8d40-c9d8e612cd71", null, "231121CH0AZWCVR1"),
    164                         amount = TalerAmount("CHF:2.53"),
    165                         subject = "G1XTY6HGWGMVRM7E6XQ4JHJK561ETFDFTJZ7JVGV543XZCB27YB",
    166                         executionTime = dateToInstant("2023-12-19"),
    167                         debtor = ibanPayto("CH7389144832588726658", "Mr Test")
    168                     ),
    169                     OutgoingReversal(
    170                         endToEndId = "50820f78-9024-44ff-978d-63a18c",
    171                         msgId = "50820f78-9024-44ff-978d-63a18c",
    172                         reason = "",
    173                         executionTime = dateToInstant("2024-01-15")
    174                     ),
    175                     OutgoingBatch(
    176                         msgId = "ZS1PGNTSV0ZNDFAJBBWWB8015G",
    177                         executionTime = dateToInstant("2024-01-15")
    178                     )
    179                 )
    180             ))
    181         )
    182     }
    183 
    184     @Test
    185     fun postfinance_camt053() {
    186         assertContentEquals(
    187             parseTx(Path("sample/platform/postfinance_camt053.xml").inputStream()),
    188             listOf(AccountTransactions(
    189                 iban = "CH9289144596463965762",
    190                 currency = "CHF",
    191                 txs = listOf(
    192                     OutgoingReversal(
    193                         endToEndId = "889d1a80-1267-49bd-8fcc-85701a",
    194                         msgId = "889d1a80-1267-49bd-8fcc-85701a",
    195                         reason = "InconsistenWithEndCustomer 'Identification of end customer is not consistent with associated account number, organisation ID or private ID.' - 'more info here ...'",
    196                         executionTime = dateToInstant("2023-11-22")
    197                     ),
    198                     OutgoingReversal(
    199                         endToEndId = "4cc61cc7-6230-49c2-b5e2-b40bbb",
    200                         msgId = "4cc61cc7-6230-49c2-b5e2-b40bbb",
    201                         reason = "MissingCreditorNameOrAddress 'Specification of the creditor’s name and/or address needed for regulatory requirements is insufficient or missing.' - 'more info here ...'",
    202                         executionTime = dateToInstant("2023-11-22")
    203                     ),
    204                     OutgoingBatch(
    205                         msgId = "EB4D22D428214261B2B3012D2A8CEC36",
    206                         executionTime = dateToInstant("2024-08-26")
    207                     )
    208                 )
    209             ))
    210         )
    211     }
    212 
    213     @Test
    214     fun valiant_camt052() {
    215         assertContentEquals(
    216             parseTx(Path("sample/platform/valiant_camt052.xml").inputStream()),
    217             listOf(AccountTransactions(
    218                 iban = "CH7389144832588726658",
    219                 currency = "CHF",
    220                 txs = listOf(
    221                     OutgoingPayment(
    222                         id = OutgoingId("MJDJO2BDDBL7YSL2P96SXHG3TQZEZQD26L", "4UWWIDGTEIGDU6Z721QE95PYJSIEA48PYE", "ZV20251030/511372/1"),
    223                         amount = TalerAmount("CHF:0.1"),
    224                         creditor = ibanPayto("CH7389144832588726658", "Grothoff Hans"),
    225                         subject = "single 2025-10-30T09:46:04.55293090 9Z",
    226                         executionTime = dateToInstant("2025-10-30")
    227                     ),
    228                     OutgoingPayment(
    229                         id = OutgoingId("5HIS3433VVIBAANHW3GX9DR1AXRS43KZ4U", "SKMU2891PAAYBDW22DBWX2W7KTFZ1CDFO8", "ZV20251030/511373/1"),
    230                         amount = TalerAmount("CHF:0.1"),
    231                         creditor = ibanPayto("CH7389144832588726658", "Grothoff Hans"),
    232                         subject = "multi 0 2025-10-30T09:46:10.3877961 30Z",
    233                         executionTime = dateToInstant("2025-10-30")
    234                     ),
    235                     OutgoingPayment(
    236                         id = OutgoingId("5HIS3433VVIBAANHW3GX9DR1AXRS43KZ4U", "RC9YD301NZ17YKD6WDWLNOROFHIIN29VJN", "ZV20251030/511373/2"),
    237                         amount = TalerAmount("CHF:0.11"),
    238                         creditor = ibanPayto("CH7389144832588726658", "Grothoff Hans"),
    239                         subject = "multi 1 2025-10-30T09:46:10.3877961 30Z",
    240                         executionTime = dateToInstant("2025-10-30")
    241                     ),
    242                     OutgoingPayment(
    243                         id = OutgoingId("5HIS3433VVIBAANHW3GX9DR1AXRS43KZ4U", "GKDGTHLB82X6XVHBJIJ1CK8MEGU9XJ2EL7", "ZV20251030/511373/3"),
    244                         amount = TalerAmount("CHF:0.12"),
    245                         creditor = ibanPayto("CH7389144832588726658", "Grothoff Hans"),
    246                         subject = "multi 2 2025-10-30T09:46:10.3877961 30Z",
    247                         executionTime = dateToInstant("2025-10-30")
    248                     ),
    249                     OutgoingPayment(
    250                         id = OutgoingId("5HIS3433VVIBAANHW3GX9DR1AXRS43KZ4U", "PXCH2VVVTXEXBVDWICP23HZ4NV0H2CWW28", "ZV20251030/511373/4"),
    251                         amount = TalerAmount("CHF:0.13"),
    252                         creditor = ibanPayto("CH7389144832588726658", "Grothoff Hans"),
    253                         subject = "multi 3 2025-10-30T09:46:10.3877961 30Z",
    254                         executionTime = dateToInstant("2025-10-30")
    255                     ),
    256                     IncomingPayment(
    257                         id = IncomingId(null, "51030655601.0001", "ZV20251030/514778/1"),
    258                         amount = TalerAmount("CHF:0.85"),
    259                         subject = "fun stuff",
    260                         executionTime = dateToInstant("2025-10-30"),
    261                         debtor = ibanPayto("CH7389144832588726658", "Grothoff Hans"),
    262                     ),
    263                     IncomingPayment(
    264                         id = IncomingId(null, "51030655601.0002", "ZV20251030/514779/1"),
    265                         amount = TalerAmount("CHF:0.95"),
    266                         subject = "Taler PC2MKG0B7CK32K1T7DP08P6E1B7FHB6HY6R Q0PT3VTPBPRPYM1B0",
    267                         executionTime = dateToInstant("2025-10-30"),
    268                         debtor = ibanPayto("CH7389144832588726658", "Grothoff Hans"),
    269                     ),
    270                     OutgoingPayment(
    271                         id = OutgoingId("X166701F6RV59LP71RVWVIW9SV2AFZYLG4", "R48UBIIB7B4LX0DMVOSI0ZTJWMMG8FMNKX", "ZV20251030/524078/1"),
    272                         amount = TalerAmount("CHF:0.21"),
    273                         creditor = ibanPayto("CH6208704048981247126", "John Smith"),
    274                         subject = "bad name 2025-10-30T12:03:24.997478 811Z",
    275                         executionTime = dateToInstant("2025-10-30")
    276                     ),
    277                     OutgoingPayment(
    278                         id = OutgoingId("6OZN5T9W7MK6BIZYE01E62NHGP5JLMUD4X", "02WDIX4J90Z1M1WNFHLNSXY59SHXQTQCMQ", "ZV20251030/524079/1"),
    279                         amount = TalerAmount("CHF:0.1"),
    280                         creditor = ibanPayto("CH7389144832588726658", "Grothoff Hans"),
    281                         subject = "single 2025-10-30T12:04:00.37042083 6Z",
    282                         executionTime = dateToInstant("2025-10-30")
    283                     ),
    284                     OutgoingPayment(
    285                         id = OutgoingId("6OZN5T9W7MK6BIZYE01E62NHGP5JLMUD4X", "XAP5L7HVWPLCEMECU4GZK6GKUPBL0TD13Y", "ZV20251030/524079/2"),
    286                         amount = TalerAmount("CHF:0.21"),
    287                         creditor = ibanPayto("CH6208704048981247126", "John Smith"),
    288                         subject = "bad name 2025-10-30T12:03:53.042190 686Z",
    289                         executionTime = dateToInstant("2025-10-30")
    290                     ),
    291                     OutgoingReversal(
    292                         endToEndId = "XAP5L7HVWPLCEMECU4GZK6GKUPBL0TD13Y",
    293                         reason = "Error msg in german",
    294                         executionTime = dateToInstant("2025-10-30")
    295                     ),
    296                     OutgoingReversal(
    297                         endToEndId = "R48UBIIB7B4LX0DMVOSI0ZTJWMMG8FMNKX",
    298                         reason = "Error msg in german",
    299                         executionTime = dateToInstant("2025-10-30")
    300                     ),
    301                     OutgoingPayment(
    302                         id = OutgoingId("OLAMDPI6YPMNRZHQ5PQ6JCVUQV2AN5NW6P", "TU2WJ54DR9Z6HT5VE494BNH4EXUSM0DRF7", "ZV20251030/524077/1"),
    303                         amount = TalerAmount("CHF:0.23"),
    304                         debitFee = TalerAmount("CHF:5"),
    305                         creditor = ibanPayto("DE48330605920000686018", "Christian Grothoff"),
    306                         subject = "foreign iban 2025-10-30T12:03:44.0972 63765Z",
    307                         executionTime = dateToInstant("2025-10-30")
    308                     ),
    309                     OutgoingPayment(
    310                         id = OutgoingId("6OZN5T9W7MK6BIZYE01E62NHGP5JLMUD4X", "GM8I8GIETR72LP6CFBGRBUDKNO2CEQBGOE", "ZV20251030/524080/1"),
    311                         amount = TalerAmount("CHF:0.23"),
    312                         debitFee = TalerAmount("CHF:5"),
    313                         creditor = ibanPayto("DE48330605920000686018", "Christian Grothoff"),
    314                         subject = "foreign iban 2025-10-30T12:03:58.0046 73747Z",
    315                         executionTime = dateToInstant("2025-10-30")
    316                     ),
    317                     IncomingPayment(
    318                         id = IncomingId("7b76d488-05d5-44ab-9d77-31d4165ec158", "00204EQY370", "ZV20251118/685062/1"),
    319                         amount = TalerAmount("CHF:4.55"),
    320                         subject = "TEST",
    321                         executionTime = dateToInstant("2025-11-18"),
    322                         debtor = null
    323                     ),
    324                 )
    325             ))
    326         )
    327     }
    328 
    329     @Test
    330     fun raiffeisen_camt053() {
    331         assertContentEquals(
    332             parseTx(Path("sample/platform/raiffeisen_camt053.xml").inputStream()),
    333             listOf(AccountTransactions(
    334                 iban = "CH7389144832588726658",
    335                 currency = null,
    336                 txs = listOf(
    337                     IncomingPayment(
    338                         id = IncomingId(null, null, "A200020494367552"),
    339                         amount = TalerAmount("CHF:20000"),
    340                         subject = "1. TZ 2025",
    341                         executionTime = dateToInstant("2025-12-23"),
    342                         debtor = ibanPayto("CH7389144832588726658", "KANTON BERN")
    343                     ),
    344                     OutgoingPayment(
    345                         id = OutgoingId(null, null, "19868398389"),
    346                         amount = TalerAmount("CHF:15"),
    347                         executionTime = dateToInstant("2025-12-31"),
    348                         subject = null,
    349                         creditor = null
    350                     ),
    351                     OutgoingPayment(
    352                         id = OutgoingId(null, null, "19890406743"),
    353                         amount = TalerAmount("CHF:2"),
    354                         executionTime = dateToInstant("2025-12-31"),
    355                         subject = null,
    356                         creditor = null
    357                     ),
    358                       OutgoingPayment(
    359                         id = OutgoingId(null, null, "19885172770"),
    360                         amount = TalerAmount("CHF:3"),
    361                         executionTime = dateToInstant("2025-12-31"),
    362                         subject = null,
    363                         creditor = null
    364                     ),
    365                 )
    366             ))
    367         )
    368     }
    369 
    370     @Test
    371     fun gls_camt052() {
    372         assertContentEquals(
    373             parseTx(Path("sample/platform/gls_camt052.xml").inputStream()),
    374             listOf(AccountTransactions(
    375                 iban = "DE84500105177118117964",
    376                 currency = "EUR",
    377                 txs = listOf(
    378                     OutgoingPayment(
    379                         id = OutgoingId("COMPAT_SUCCESS", "COMPAT_SUCCESS", "2024041801514102000"),
    380                         amount = TalerAmount("EUR:2"),
    381                         subject = "TestABC123",
    382                         executionTime = dateToInstant("2024-04-18"),
    383                         creditor = ibanPayto("DE20500105172419259181", "John Smith")
    384                     ),
    385                     OutgoingReversal(
    386                         endToEndId = "8XK8Z7RAX224FGWK832FD40GYC",
    387                         reason = "IncorrectAccountNumber 'Format of the account number specified is not correct' - 'IBAN fehlerhaft und ungültig'",
    388                         executionTime = dateToInstant("2024-09-05")
    389                     ),
    390                     IncomingPayment(
    391                         id = IncomingId(null, "BYLADEM1WOR-G2910276709458A2", "2024041210041357000"),
    392                         amount = TalerAmount("EUR:3"),
    393                         subject = "Taler FJDQ7W6G7NWX4H9M1MKA12090FRC9K7DA6N0FANDZZFXTR6QHX5G Test.,-",
    394                         executionTime = dateToInstant("2024-04-12"),
    395                         debtor = ibanPayto("DE84500105177118117964", "John Smith")
    396                     ),
    397                     OutgoingReversal(
    398                         endToEndId = "COMPAT_FAILURE",
    399                         reason = "IncorrectAccountNumber 'Format of the account number specified is not correct' - 'IBAN ...'",
    400                         executionTime = dateToInstant("2024-04-12")
    401                     ),
    402                     OutgoingPayment(
    403                         id = OutgoingId("BATCH_SINGLE_SUCCESS", "FD622SMXKT5QWSAHDY0H8NYG3G", "2024090216552232000"),
    404                         amount = TalerAmount("EUR:1.1"),
    405                         subject = "single 2024-09-02T14:29:52.875253314Z",
    406                         executionTime = dateToInstant("2024-09-02"),
    407                         creditor = ibanPayto("DE89500105173198527518", "Grothoff Hans")
    408                     ),
    409                     OutgoingPayment(
    410                         id = OutgoingId("YF5QBARGQ0MNY0VK59S477VDG4", "YF5QBARGQ0MNY0VK59S477VDG4", "2024041810552821000"),
    411                         amount = TalerAmount("EUR:1.1"),
    412                         subject = "Simple tx",
    413                         executionTime = dateToInstant("2024-04-18"),
    414                         creditor = ibanPayto("DE20500105172419259181", "John Smith")
    415                     ),
    416                     OutgoingBatch(
    417                         msgId = "BATCH_MANY_SUCCESS",
    418                         executionTime = dateToInstant("2024-09-20"),
    419                     ),
    420                     OutgoingPayment(
    421                         id = OutgoingId("BATCH_SINGLE_RETURN", "KLJJ28S1LVNDK1R2HCHLN884M7EKM5XGM5", "2024092100252498000"),
    422                         amount = TalerAmount("EUR:0.42"),
    423                         subject = "This should fail because bad iban",
    424                         executionTime = dateToInstant("2024-09-23"),
    425                         creditor = ibanPayto("DE18500105173385245163", "John Smith")
    426                     ),
    427                     OutgoingReversal(
    428                         endToEndId = "KLJJ28S1LVNDK1R2HCHLN884M7EKM5XGM5",
    429                         reason = "IncorrectAccountNumber 'Format of the account number specified is not correct' - 'IBAN fehlerhaft und ungültig'",
    430                         executionTime = dateToInstant("2024-09-24")
    431                     ),
    432                 )
    433             ))
    434         )
    435     }
    436 
    437     @Test
    438     fun gls_camt053() {
    439         assertContentEquals(
    440             parseTx(Path("sample/platform/gls_camt053.xml").inputStream()),
    441             listOf(AccountTransactions(
    442                 iban = "DE84500105177118117964",
    443                 currency = "EUR",
    444                 txs = listOf(
    445                     OutgoingPayment(
    446                         id = OutgoingId("COMPAT_SUCCESS", "COMPAT_SUCCESS", "2024041801514102000"),
    447                         amount = TalerAmount("EUR:2"),
    448                         subject = "TestABC123",
    449                         executionTime = dateToInstant("2024-04-18"),
    450                         creditor = ibanPayto("DE20500105172419259181", "John Smith")
    451                     ),
    452                     OutgoingReversal(
    453                         endToEndId = "KGTDBASWTJ6JM89WXD3Q5KFQC4",
    454                         reason = "Retoure aus SEPA Überweisung multi line",
    455                         executionTime = dateToInstant("2024-09-04")
    456                     ),
    457                     OutgoingBatch(
    458                         msgId = "BATCH_MANY_PART",
    459                         executionTime = dateToInstant("2024-09-04")
    460                     ),
    461                     IncomingPayment(
    462                         id = IncomingId(null, "BYLADEM1WOR-G2910276709458A2", "2024041210041357000"),
    463                         amount = TalerAmount("EUR:3"),
    464                         subject = "Taler FJDQ7W6G7NWX4H9M1MKA12090FRC9K7DA6N0FANDZZFXTR6QHX5G Test.,-",
    465                         executionTime = dateToInstant("2024-04-12"),
    466                         debtor = ibanPayto("DE84500105177118117964", "John Smith")
    467                     ),
    468                     OutgoingReversal(
    469                         endToEndId = "COMPAT_FAILURE",
    470                         reason = "IncorrectAccountNumber 'Format of the account number specified is not correct' - 'IBAN ...'",
    471                         executionTime = dateToInstant("2024-04-12")
    472                     ),
    473                     OutgoingPayment(
    474                         id = OutgoingId("BATCH_SINGLE_SUCCESS", "FD622SMXKT5QWSAHDY0H8NYG3G", "2024090216552232000"),
    475                         amount = TalerAmount("EUR:1.1"),
    476                         subject = "single 2024-09-02T14:29:52.875253314Z",
    477                         executionTime = dateToInstant("2024-09-02"),
    478                         creditor = ibanPayto("DE89500105173198527518", "Grothoff Hans")
    479                     ),
    480                     OutgoingPayment(
    481                         id = OutgoingId("YF5QBARGQ0MNY0VK59S477VDG4", "YF5QBARGQ0MNY0VK59S477VDG4", "2024041810552821000"),
    482                         amount = TalerAmount("EUR:1.1"),
    483                         subject = "Simple tx",
    484                         executionTime = dateToInstant("2024-04-18"),
    485                         creditor = ibanPayto("DE20500105172419259181", "John Smith")
    486                     ),
    487                 ))
    488             )
    489         )
    490     }
    491 
    492     @Test
    493     fun gls_camt054() {
    494         assertContentEquals(
    495             parseTx(Path("sample/platform/gls_camt054.xml").inputStream()),
    496             listOf(AccountTransactions(
    497                 iban = "DE84500105177118117964",
    498                 currency = "EUR",
    499                 txs = listOf<TxNotification>(
    500                     IncomingPayment(
    501                         id = IncomingId(null, "IS11PGENODEFF2DA8899900378806", null),
    502                         amount = TalerAmount("EUR:2.5"),
    503                         subject = "Test ICT",
    504                         executionTime = dateToInstant("2024-05-05"),
    505                         debtor = ibanPayto("DE84500105177118117964", "Mr Test")
    506                     )
    507                 )
    508             ))
    509         )
    510     }
    511 
    512     @Test
    513     fun maerki_baumann_camt053() {
    514         assertContentEquals(
    515             parseTx(Path("sample/platform/maerki_baumann_camt053.xml").inputStream()),
    516             listOf(AccountTransactions(
    517                 iban = "CH7389144832588726658",
    518                 currency = "CHF",
    519                 txs = listOf<TxNotification>(
    520                     IncomingPayment(
    521                         id = IncomingId("adbe4a5a-6cea-4263-b259-8ab964561a32", "41103099704.0002", "ZV20241104/765446/1"),
    522                         amount = TalerAmount("CHF:1"),
    523                         creditFee = TalerAmount("CHF:0.2"),
    524                         subject = "SFHP6H24C16A5J05Q3FJW2XN1PB3EK70ZPY 5SJ30ADGY68FWN68G",
    525                         executionTime = dateToInstant("2024-11-04"),
    526                         debtor = ibanPayto("CH7389144832588726658", "Mr Test")
    527                     ),
    528                     IncomingPayment(
    529                         id = IncomingId("7371795e-62fa-42dd-93b7-da89cc120faa", "41103099704.0003", "ZV20241104/765447/1"),
    530                         amount = TalerAmount("CHF:1"),
    531                         creditFee = TalerAmount("CHF:0.2"),
    532                         subject = "Random subject",
    533                         executionTime = dateToInstant("2024-11-04"),
    534                         debtor = ibanPayto("CH7389144832588726658", "Mr Test")
    535                     ),
    536                     IncomingPayment(
    537                         id = IncomingId(null, "50523424675.0001", "ZV20250523/851716/1"),
    538                         amount = TalerAmount("CHF:0.5"),
    539                         creditFee = TalerAmount("CHF:0.2"),
    540                         subject = null,
    541                         executionTime = dateToInstant("2025-05-23"),
    542                         debtor = ibanPayto("CH7389144832588726658", "Grothoff Hans")
    543                     ),
    544                     OutgoingPayment(
    545                         id = OutgoingId("BATCH_SINGLE_REPORTING", "5IBJZOWESQGPCSOXSNNBBY49ZURI5W7Q4H", "ZV20241121/773541/1"),
    546                         amount = TalerAmount("CHF:0.1"),
    547                         subject = "multi 0 2024-11-21T15:21:59.8859234 63Z",
    548                         executionTime = dateToInstant("2024-11-27"),
    549                         creditor = ibanPayto("CH7389144832588726658", "Grothoff Hans")
    550                     ),
    551                     OutgoingPayment(
    552                         id = OutgoingId("BATCH_SINGLE_REPORTING", "XZ15UR0XU52QWI7Q4XB88EDS44PLH7DYXH", "ZV20241121/773541/4"),
    553                         amount = TalerAmount("CHF:0.13"),
    554                         subject = "multi 3 2024-11-21T15:21:59.8859234 63Z",
    555                         executionTime = dateToInstant("2024-11-27"),
    556                         creditor = ibanPayto("CH7389144832588726658", "Grothoff Hans")
    557                     ),
    558                     OutgoingPayment(
    559                         id = OutgoingId("BATCH_SINGLE_REPORTING", "A09R35EW0359SZ51464E7TC37A0P2CBK04", "ZV20241121/773541/3"),
    560                         amount = TalerAmount("CHF:0.12"),
    561                         subject = "multi 2 2024-11-21T15:21:59.8859234 63Z",
    562                         executionTime = dateToInstant("2024-11-27"),
    563                         creditor = ibanPayto("CH7389144832588726658", "Grothoff Hans")
    564                     ),
    565                     OutgoingPayment(
    566                         id = OutgoingId("BATCH_SINGLE_REPORTING", "UYXZ78LE9KAIMBY6UNXFYT1K8KNY8VLZLT", "ZV20241121/773541/2"),
    567                         amount = TalerAmount("CHF:0.11"),
    568                         subject = "multi 1 2024-11-21T15:21:59.8859234 63Z",
    569                         executionTime = dateToInstant("2024-11-27"),
    570                         creditor = ibanPayto("CH7389144832588726658", "Grothoff Hans")
    571                     ),
    572                     IncomingPayment(
    573                         id = IncomingId("f203fbb4-6e13-4c78-9b2a-d852fea6374a", "41202060702.0001", "ZV20241202/778108/1"),
    574                         amount = TalerAmount("CHF:0.05"),
    575                         creditFee = TalerAmount("CHF:0.2"),
    576                         subject = "mini",
    577                         executionTime = dateToInstant("2024-12-02"),
    578                         debtor = ibanPayto("CH7389144832588726658", "Grothoff Hans")
    579                     ),
    580                     IncomingPayment(
    581                         id = IncomingId("81b0d8c6-a677-4577-b75e-a639dcc03681", "41120636093.0001", "ZV20241121/773118/1"),
    582                         amount = TalerAmount("CHF:0.1"),
    583                         creditFee = TalerAmount("CHF:0.2"),
    584                         subject = "small transfer test",
    585                         executionTime = dateToInstant("2024-11-21"),
    586                         debtor = ibanPayto("CH7389144832588726658", "Grothoff Hans")
    587                     ),
    588                     OutgoingPayment(
    589                         id = OutgoingId(null, null, "GB20241220/205792/1"),
    590                         amount = TalerAmount("CHF:3000"),
    591                         subject = null,
    592                         executionTime = dateToInstant("2024-12-20"),
    593                         creditor = null
    594                     ),
    595                     IncomingPayment(
    596                         id = IncomingId(null, null, "ZV20250114/796191/1"),
    597                         amount = TalerAmount("CHF:3003"),
    598                         subject = "Fix bad payment by MB.",
    599                         executionTime = dateToInstant("2025-01-27"),
    600                         debtor = null
    601                     ),
    602                     IncomingPayment(
    603                         id = IncomingId(null, "F000787951230001", "ZV20250526/852733/1"),
    604                         amount = TalerAmount("CHF:1.38"),
    605                         creditFee = TalerAmount("CHF:0.2"),
    606                         subject = "Taler XT3D9MADR4V85JBWX47SMJFDQD2FDZDHHPH8R25YDG1KNVTSEH6G",
    607                         executionTime = dateToInstant("2025-05-26"),
    608                         debtor = ibanPayto("DE20500105172419259181", "Mr German")
    609                     ),
    610                 )
    611             ))
    612         )
    613     }
    614 
    615     @Test
    616     fun pain002() {
    617         assertEquals(
    618             parseCustomerPaymentStatusReport(Path("sample/platform/pain002_part.xml").inputStream()),
    619             MsgStatus(
    620                 id = "05BD4C5B4A2649B5B08F6EF6A31F197A",
    621                 code = ExternalPaymentGroupStatusCode.PART,
    622                 reasons = emptyList(),
    623                 payments = listOf(
    624                     PmtStatus(
    625                         id = "NOTPROVIDED",
    626                         code = ExternalPaymentGroupStatusCode.PART,
    627                         reasons = listOf(
    628                             Reason(
    629                                 code = ExternalStatusReasonCode.DT06,
    630                                 information = "Due date is not a working day. Order will be executed on the next working day"
    631                             )
    632                         ),
    633                         transactions = listOf(
    634                             TxStatus(
    635                                 id = "AQCXNCPWD8PHW5JTN65Y5XTF7R",
    636                                 endToEndId = "AQCXNCPWD8PHW5JTN65Y5XTF7R",
    637                                 code = ExternalPaymentTransactionStatusCode.RJCT, 
    638                                 reasons = listOf(
    639                                     Reason(
    640                                         code = ExternalStatusReasonCode.AC04, 
    641                                         information = "Error message"
    642                                     )
    643                                 )
    644                             ),
    645                             TxStatus(
    646                                 id = "EE9SX76FC5YSC657EK3GMVZ9TC",
    647                                 endToEndId = "EE9SX76FC5YSC657EK3GMVZ9TC",
    648                                 code = ExternalPaymentTransactionStatusCode.RJCT,
    649                                 reasons = listOf(
    650                                     Reason(
    651                                         code = ExternalStatusReasonCode.MS03,
    652                                         information = "Error message"
    653                                     )
    654                                 )
    655                             ),
    656                             TxStatus(
    657                                 id = "V5B3MXPEWES9VQW1JDRD6VAET4",
    658                                 endToEndId = "V5B3MXPEWES9VQW1JDRD6VAET4",
    659                                 code = ExternalPaymentTransactionStatusCode.RJCT,
    660                                 reasons = listOf(
    661                                     Reason(
    662                                         code = ExternalStatusReasonCode.RR02,
    663                                         information = "Error message"
    664                                     )
    665                                 )
    666                             )
    667                         )
    668                     )
    669                 )
    670             )
    671         )
    672         assertEquals(
    673             parseCustomerPaymentStatusReport(Path("sample/platform/pain002_accp.xml").inputStream()),
    674             MsgStatus(
    675                 id = "5HIS3433VVIBAANHW3GX9DR1AXRS43KZ4U",
    676                 code = ExternalPaymentGroupStatusCode.ACCP,
    677                 reasons = listOf(
    678                     Reason(
    679                         code = null,
    680                         information = "PN10630020F0297329.20251030104613.EBTUAAAC.PN1.0002372"
    681                     )
    682                 ),
    683                 payments = emptyList()
    684             )
    685         )
    686     }
    687 }