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 }