swift_mt_message/fields/
field34.rs1use super::swift_utils::{parse_amount, parse_currency};
2use crate::errors::ParseError;
3use crate::traits::SwiftField;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
19pub struct Field34F {
20    pub currency: String,
22
23    pub indicator: Option<char>,
25
26    pub amount: f64,
28}
29
30impl SwiftField for Field34F {
31    fn parse(input: &str) -> crate::Result<Self>
32    where
33        Self: Sized,
34    {
35        if input.len() < 4 {
37            return Err(ParseError::InvalidFormat {
39                message: format!(
40                    "Field 34F must be at least 4 characters, found {}",
41                    input.len()
42                ),
43            });
44        }
45
46        let currency = parse_currency(&input[0..3])?;
48
49        let (indicator, amount_start) = if input.len() > 3 {
51            let fourth_char = input.chars().nth(3).unwrap();
52            if fourth_char == 'D' || fourth_char == 'C' {
53                (Some(fourth_char), 4)
54            } else {
55                (None, 3)
56            }
57        } else {
58            (None, 3)
59        };
60
61        let amount_str = &input[amount_start..];
63        if amount_str.is_empty() {
64            return Err(ParseError::InvalidFormat {
65                message: "Field 34F amount cannot be empty".to_string(),
66            });
67        }
68
69        let amount = parse_amount(amount_str)?;
70
71        if amount <= 0.0 {
73            return Err(ParseError::InvalidFormat {
74                message: "Field 34F amount must be greater than zero".to_string(),
75            });
76        }
77
78        Ok(Field34F {
79            currency,
80            indicator,
81            amount,
82        })
83    }
84
85    fn to_swift_string(&self) -> String {
86        let indicator_str = self.indicator.map_or(String::new(), |c| c.to_string());
87        format!(
88            ":34F:{}{}{}",
89            self.currency,
90            indicator_str,
91            super::swift_utils::format_swift_amount(self.amount, 2)
92        )
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99
100    #[test]
101    fn test_field34f_valid() {
102        let field = Field34F::parse("USD5000,00").unwrap();
104        assert_eq!(field.currency, "USD");
105        assert_eq!(field.indicator, None);
106        assert_eq!(field.amount, 5000.00);
107        assert_eq!(field.to_swift_string(), ":34F:USD5000,00");
108
109        let field = Field34F::parse("USDD2500,00").unwrap();
111        assert_eq!(field.currency, "USD");
112        assert_eq!(field.indicator, Some('D'));
113        assert_eq!(field.amount, 2500.00);
114
115        let field = Field34F::parse("EURC1000,00").unwrap();
117        assert_eq!(field.currency, "EUR");
118        assert_eq!(field.indicator, Some('C'));
119        assert_eq!(field.amount, 1000.00);
120
121        let field = Field34F::parse("GBP10000,00").unwrap();
123        assert_eq!(field.currency, "GBP");
124        assert_eq!(field.indicator, None);
125        assert_eq!(field.amount, 10000.00);
126    }
127
128    #[test]
129    fn test_field34f_invalid() {
130        assert!(Field34F::parse("12A100").is_err());
132        assert!(Field34F::parse("US100").is_err());
133
134        assert!(Field34F::parse("USDX100").is_err());
136
137        assert!(Field34F::parse("USD0").is_err());
139        assert!(Field34F::parse("USDD0").is_err());
140
141        assert!(Field34F::parse("USD-100").is_err());
143
144        assert!(Field34F::parse("USD").is_err());
146        assert!(Field34F::parse("USDD").is_err());
147    }
148}