libeufin

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

dialect.rs (6835B)


      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 use crate::ebics::order::{BTF, Order, OrderDoc};
     23 
     24 /** Supported EBICS standard */
     25 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
     26 pub enum Standard {
     27     /// Swiss Payment Standards
     28     SIX,
     29     /// German Banking Industry Committee
     30     GBIC,
     31 }
     32 
     33 impl Standard {
     34     pub fn downloads(&self, doc: &OrderDoc) -> Vec<Order> {
     35         match self {
     36             Standard::SIX => match doc {
     37                 OrderDoc::acknowledgement => vec![Order::HAC],
     38                 OrderDoc::status => vec![Order::BTD(BTF {
     39                     service: "PSR".into(),
     40                     scope: Some("CH".into()),
     41                     option: None,
     42                     container: Some("ZIP".into()),
     43                     msg: "pain.002".into(),
     44                     version: Some("10".into()),
     45                 })],
     46                 OrderDoc::report => vec![Order::BTD(BTF {
     47                     service: "STM".into(),
     48                     scope: Some("CH".into()),
     49                     option: None,
     50                     container: Some("ZIP".into()),
     51                     msg: "camt.052".into(),
     52                     version: Some("08".into()),
     53                 })],
     54                 OrderDoc::statement => vec![Order::BTD(BTF {
     55                     service: "EOP".into(),
     56                     scope: Some("CH".into()),
     57                     option: None,
     58                     container: Some("ZIP".into()),
     59                     msg: "camt.053".into(),
     60                     version: Some("08".into()),
     61                 })],
     62                 OrderDoc::notification => vec![Order::BTD(BTF {
     63                     service: "REP".into(),
     64                     scope: Some("CH".into()),
     65                     option: None,
     66                     container: Some("ZIP".into()),
     67                     msg: "camt.054".into(),
     68                     version: Some("08".into()),
     69                 })],
     70             },
     71             Standard::GBIC => match doc {
     72                 OrderDoc::acknowledgement => vec![Order::HAC],
     73                 OrderDoc::status => vec![
     74                     Order::BTD(BTF {
     75                         service: "REP".into(),
     76                         scope: Some("DE".into()),
     77                         option: Some("SCI".into()),
     78                         container: Some("ZIP".into()),
     79                         msg: "pain.002".into(),
     80                         version: None,
     81                     }),
     82                     Order::BTD(BTF {
     83                         service: "REP".into(),
     84                         scope: Some("DE".into()),
     85                         option: Some("SCT".into()),
     86                         container: Some("ZIP".into()),
     87                         msg: "pain.002".into(),
     88                         version: None,
     89                     }),
     90                 ],
     91                 OrderDoc::report => vec![Order::BTD(BTF {
     92                     service: "STM".into(),
     93                     scope: Some("DE".into()),
     94                     option: None,
     95                     container: Some("ZIP".into()),
     96                     msg: "camt.052".into(),
     97                     version: None,
     98                 })],
     99                 OrderDoc::statement => vec![Order::BTD(BTF {
    100                     service: "EOP".into(),
    101                     scope: Some("DE".into()),
    102                     option: None,
    103                     container: Some("ZIP".into()),
    104                     msg: "camt.053".into(),
    105                     version: None,
    106                 })],
    107                 OrderDoc::notification => vec![
    108                     Order::BTD(BTF {
    109                         service: "STM".into(),
    110                         scope: Some("DE".into()),
    111                         option: None,
    112                         container: Some("ZIP".into()),
    113                         msg: "camt.054".into(),
    114                         version: None,
    115                     }),
    116                     Order::BTD(BTF {
    117                         service: "STM".into(),
    118                         scope: Some("DE".into()),
    119                         option: Some("SCI".into()),
    120                         container: Some("ZIP".into()),
    121                         msg: "camt.054".into(),
    122                         version: None,
    123                     }),
    124                 ],
    125             },
    126         }
    127     }
    128 
    129     pub fn direct_debit(&self) -> Order {
    130         match self {
    131             Standard::SIX => Order::BTU(BTF {
    132                 service: "MCT".into(),
    133                 scope: Some("CH".into()),
    134                 option: None,
    135                 container: None,
    136                 msg: "pain.001".into(),
    137                 version: Some("09".into()),
    138             }),
    139             Standard::GBIC => Order::BTU(BTF {
    140                 service: "SCT".into(),
    141                 scope: None,
    142                 option: None,
    143                 container: None,
    144                 msg: "pain.001".into(),
    145                 version: None,
    146             }),
    147         }
    148     }
    149 
    150     pub fn instant_direct_debit(&self) -> Option<Order> {
    151         match self {
    152             Standard::SIX => None,
    153             Standard::GBIC => Some(Order::BTU(BTF {
    154                 service: "SCI".into(),
    155                 scope: Some("DE".into()),
    156                 option: None,
    157                 container: None,
    158                 msg: "pain.001".into(),
    159                 version: None,
    160             })),
    161         }
    162     }
    163 
    164     /** All orders required for a dialect implementation to work */
    165     pub fn required(&self) -> Vec<Order> {
    166         // Administrative orders
    167         [Order::HAA, Order::HKD]
    168             .into_iter()
    169             // and documents orders
    170             .chain(OrderDoc::entries.iter().flat_map(|o| self.downloads(o)))
    171             .collect()
    172     }
    173 }
    174 
    175 /** Supported bank dialects */
    176 #[derive(Debug, Clone, Copy, PartialEq, Eq, EnumMeta)]
    177 #[enum_meta(Str)]
    178 #[allow(non_camel_case_types)]
    179 pub enum Dialect {
    180     valiant,
    181     raiffeisen,
    182     postfinance,
    183     gls,
    184     maerki_baumann,
    185 }
    186 
    187 impl Dialect {
    188     pub fn standard(&self) -> Standard {
    189         match self {
    190             Self::valiant | Self::raiffeisen | Self::postfinance | Self::maerki_baumann => {
    191                 Standard::SIX
    192             }
    193             Self::gls => Standard::GBIC,
    194         }
    195     }
    196 }