swift_mt_message/fields/
field37.rs1use super::swift_utils::parse_amount;
2use crate::errors::ParseError;
3use crate::traits::SwiftField;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
20pub struct Field37H {
21 pub rate_indicator: char,
23
24 pub is_negative: Option<bool>,
26
27 pub rate: f64,
29}
30
31impl SwiftField for Field37H {
32 fn parse(input: &str) -> crate::Result<Self>
33 where
34 Self: Sized,
35 {
36 let mut remaining = input;
37
38 if remaining.is_empty() {
40 return Err(ParseError::InvalidFormat {
41 message: "Field37H requires rate indicator".to_string(),
42 });
43 }
44
45 let rate_indicator = remaining.chars().next().unwrap();
46 if rate_indicator != 'C' && rate_indicator != 'D' {
47 return Err(ParseError::InvalidFormat {
48 message: "Field37H rate indicator must be 'C' or 'D'".to_string(),
49 });
50 }
51 remaining = &remaining[1..];
52
53 let is_negative = if remaining.starts_with('N') {
55 remaining = &remaining[1..];
56 Some(true)
57 } else {
58 None
59 };
60
61 if remaining.is_empty() {
63 return Err(ParseError::InvalidFormat {
64 message: "Field37H requires rate value".to_string(),
65 });
66 }
67
68 let rate = if is_negative.is_some() {
69 -parse_amount(remaining)?
70 } else {
71 parse_amount(remaining)?
72 };
73
74 Ok(Field37H {
75 rate_indicator,
76 is_negative,
77 rate,
78 })
79 }
80
81 fn to_swift_string(&self) -> String {
82 let negative_indicator = if self.is_negative.is_some() { "N" } else { "" };
83 let rate_str = format!("{:.4}", self.rate.abs()).replace('.', ",");
84 format!(
85 ":37H:{}{}{}",
86 self.rate_indicator, negative_indicator, rate_str
87 )
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 #[test]
96 fn test_field37h_parse() {
97 let field = Field37H::parse("C2,5000").unwrap();
99 assert_eq!(field.rate_indicator, 'C');
100 assert_eq!(field.is_negative, None);
101 assert_eq!(field.rate, 2.5);
102
103 let field = Field37H::parse("D3,7500").unwrap();
105 assert_eq!(field.rate_indicator, 'D');
106 assert_eq!(field.is_negative, None);
107 assert_eq!(field.rate, 3.75);
108
109 let field = Field37H::parse("CN0,2500").unwrap();
111 assert_eq!(field.rate_indicator, 'C');
112 assert_eq!(field.is_negative, Some(true));
113 assert_eq!(field.rate, -0.25);
114 }
115
116 #[test]
117 fn test_field37h_to_swift_string() {
118 let field = Field37H {
119 rate_indicator: 'C',
120 is_negative: None,
121 rate: 2.5,
122 };
123 assert_eq!(field.to_swift_string(), ":37H:C2,5000");
124
125 let field = Field37H {
126 rate_indicator: 'D',
127 is_negative: None,
128 rate: 3.75,
129 };
130 assert_eq!(field.to_swift_string(), ":37H:D3,7500");
131
132 let field = Field37H {
133 rate_indicator: 'C',
134 is_negative: Some(true),
135 rate: -0.25,
136 };
137 assert_eq!(field.to_swift_string(), ":37H:CN0,2500");
138 }
139
140 #[test]
141 fn test_field37h_parse_invalid() {
142 assert!(Field37H::parse("X2,5000").is_err());
144
145 assert!(Field37H::parse("C").is_err());
147
148 assert!(Field37H::parse("Cabc").is_err());
150
151 assert!(Field37H::parse("").is_err());
153 }
154}