libeufin

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

iso20022.rs (5705B)


      1 /*
      2 * This file is part of LibEuFin.
      3 * Copyright (C) 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 use taler_macros::EnumMeta;
     21 
     22 pub mod bank_tx_code;
     23 pub mod camt;
     24 pub mod hac;
     25 pub mod model;
     26 pub mod pain001;
     27 pub mod pain002;
     28 pub mod status_code;
     29 
     30 #[derive(Debug, Clone, Copy, PartialEq, Eq, EnumMeta)]
     31 #[enum_meta(Description, Str)]
     32 #[allow(non_camel_case_types)]
     33 pub enum HacAction {
     34     /// File submitted to the bank
     35     FILE_UPLOAD,
     36     /// File downloaded from the bank
     37     FILE_DOWNLOAD,
     38     /// Electronic signature submitted to the bank
     39     ES_UPLOAD,
     40     /// Electronic signature downloaded from the bank
     41     ES_DOWNLOAD,
     42     /// Signature verification
     43     ES_VERIFICATION,
     44     /// Forwarding to EDS
     45     VEU_FORWARDING,
     46     /// EDS signature verification
     47     VEU_VERIFICATION,
     48     /// Forwarded for postprocessing
     49     VEU_VERIFICATION_END,
     50     /// Cancellation of EDS order
     51     VEU_CANCEL_ORDER,
     52     /// Additional information
     53     ADDITIONAL,
     54     /// HAC end of order (positive)
     55     ORDER_HAC_FINAL_POS,
     56     /// HAC end of order (negative)
     57     ORDER_HAC_FINAL_NEG,
     58     // Not in the spec but Credit Suisse test suite use it
     59     /// HAC end of order
     60     ORDER_HAC_FINAL,
     61 }
     62 
     63 #[derive(Debug, Clone, Copy, PartialEq, Eq, EnumMeta)]
     64 #[enum_meta(Description, Str)]
     65 pub enum ChargeBearer {
     66     /// BorneByDebtor
     67     DEBT,
     68     /// BorneByCreditor
     69     CRED,
     70     /// Shared
     71     SHAR,
     72     /// SLEV
     73     SLEV,
     74 }
     75 
     76 #[cfg(test)]
     77 pub mod test {
     78     use tracing::info;
     79 
     80     use crate::{
     81         ebics::administrative::{parse_haa, parse_hkd},
     82         iso20022::{camt::parse_camt, hac::parse_hac, pain002::parse_pain002},
     83     };
     84 
     85     #[test]
     86     pub fn sample() {
     87         taler_test_utils::setup_tracing();
     88         let mut samples = Vec::new();
     89         for entry in std::fs::read_dir("../testbench/sample").unwrap() {
     90             let entry = entry.unwrap();
     91             let path = entry.path();
     92             if path.is_dir() {
     93                 for entry in std::fs::read_dir(path).unwrap() {
     94                     let entry = entry.unwrap();
     95                     samples.push((entry.path(), entry.file_name()));
     96                 }
     97             } else {
     98                 samples.push((path, entry.file_name()));
     99             }
    100         }
    101         for (path, name) in samples {
    102             let xml = std::fs::read(&path).unwrap();
    103             let name = name.to_string_lossy();
    104 
    105             info!("Parse sample {path:?}");
    106 
    107             if name.contains("hac") {
    108                 parse_hac(&xml).unwrap();
    109             } else if name.contains("camt") {
    110                 parse_camt(&xml).unwrap();
    111             } else if name.contains("pain002") {
    112                 parse_pain002(&xml).unwrap();
    113             } else if name.contains("pain001") {
    114                 // Ignore
    115             } else {
    116                 panic!("Unsupported file type {name}")
    117             }
    118         }
    119     }
    120 
    121     #[test]
    122     pub fn logs() {
    123         taler_test_utils::setup_tracing();
    124 
    125         if !std::fs::exists("testbench/test").unwrap() {
    126             return;
    127         }
    128         for platform in std::fs::read_dir("testbench/test")
    129             .unwrap()
    130             .map(Result::unwrap)
    131         {
    132             let path = platform.path();
    133             if !path.is_dir() || platform.file_name() == "platform" {
    134                 continue;
    135             }
    136 
    137             // List logs
    138             let mut logs = Vec::new();
    139             for date in std::fs::read_dir(path).unwrap().map(Result::unwrap) {
    140                 let path = date.path();
    141                 if !path.is_dir() {
    142                     continue;
    143                 }
    144                 for tx in std::fs::read_dir(path).unwrap().map(Result::unwrap) {
    145                     let payload = tx.path().join("payload");
    146                     if payload.exists() {
    147                         logs.extend(
    148                             std::fs::read_dir(payload)
    149                                 .unwrap()
    150                                 .map(|it| it.unwrap().path()),
    151                         );
    152                     }
    153                     let payload = tx.path().join("payload.xml");
    154                     if payload.exists() {
    155                         logs.push(payload);
    156                     }
    157                 }
    158             }
    159             for path in logs {
    160                 let xml = std::fs::read(&path).unwrap();
    161                 let path = path.to_string_lossy();
    162 
    163                 info!("Parse sample {path:?}");
    164 
    165                 if path.contains("HAC") {
    166                     parse_hac(&xml).unwrap();
    167                 } else if path.contains("HKD") {
    168                     parse_hkd(&xml).unwrap();
    169                 } else if path.contains("HAA") {
    170                     parse_haa(&xml).unwrap();
    171                 } else if path.contains("camt") {
    172                     parse_camt(&xml).unwrap();
    173                 } else if path.contains("pain.002") {
    174                     parse_pain002(&xml).unwrap();
    175                 } else if path.contains("pain.001") {
    176                     // Ignore
    177                 } else {
    178                     panic!("Unsupported file type {path}")
    179                 }
    180             }
    181         }
    182     }
    183 }