swift_mt_message/fields/
field90.rs1use super::swift_utils::{parse_amount, parse_currency, parse_swift_digits};
13use crate::errors::ParseError;
14use crate::traits::SwiftField;
15use serde::{Deserialize, Serialize};
16
17#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
28pub struct Field90D {
29 pub number: u32,
31
32 pub currency: String,
34
35 pub amount: f64,
37}
38
39impl SwiftField for Field90D {
40 fn parse(input: &str) -> crate::Result<Self>
41 where
42 Self: Sized,
43 {
44 let mut remaining = input;
45
46 if remaining.len() < 8 {
48 return Err(ParseError::InvalidFormat {
49 message: "Field90D requires at least 8 characters (5n + 3!a)".to_string(),
50 });
51 }
52
53 let mut number_end = 0;
55 for (i, c) in remaining.char_indices() {
56 if !c.is_ascii_digit() {
57 number_end = i;
58 break;
59 }
60 if i >= 4 {
61 number_end = i + 1;
63 break;
64 }
65 }
66
67 if number_end == 0 {
68 return Err(ParseError::InvalidFormat {
69 message: "Field90D number part not found".to_string(),
70 });
71 }
72
73 let number_str = &remaining[..number_end];
74 if number_str.len() > 5 {
75 return Err(ParseError::InvalidFormat {
76 message: "Field90D number cannot exceed 5 digits".to_string(),
77 });
78 }
79
80 parse_swift_digits(number_str, "Field90D number")?;
81 let number: u32 = number_str.parse().map_err(|_| ParseError::InvalidFormat {
82 message: "Invalid number in Field90D".to_string(),
83 })?;
84
85 remaining = &remaining[number_end..];
86
87 if remaining.len() < 3 {
89 return Err(ParseError::InvalidFormat {
90 message: "Field90D requires currency code".to_string(),
91 });
92 }
93
94 let currency = parse_currency(&remaining[..3])?;
95 remaining = &remaining[3..];
96
97 if remaining.is_empty() {
99 return Err(ParseError::InvalidFormat {
100 message: "Field90D requires amount".to_string(),
101 });
102 }
103
104 let amount = parse_amount(remaining)?;
105
106 Ok(Field90D {
107 number,
108 currency,
109 amount,
110 })
111 }
112
113 fn to_swift_string(&self) -> String {
114 let amount_str = format!("{:.2}", self.amount).replace('.', ",");
115 format!(":90D:{}{}{}", self.number, self.currency, amount_str)
116 }
117}
118
119#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
130pub struct Field90C {
131 pub number: u32,
133
134 pub currency: String,
136
137 pub amount: f64,
139}
140
141impl SwiftField for Field90C {
142 fn parse(input: &str) -> crate::Result<Self>
143 where
144 Self: Sized,
145 {
146 let mut remaining = input;
147
148 if remaining.len() < 8 {
150 return Err(ParseError::InvalidFormat {
151 message: "Field90C requires at least 8 characters (5n + 3!a)".to_string(),
152 });
153 }
154
155 let mut number_end = 0;
157 for (i, c) in remaining.char_indices() {
158 if !c.is_ascii_digit() {
159 number_end = i;
160 break;
161 }
162 if i >= 4 {
163 number_end = i + 1;
165 break;
166 }
167 }
168
169 if number_end == 0 {
170 return Err(ParseError::InvalidFormat {
171 message: "Field90C number part not found".to_string(),
172 });
173 }
174
175 let number_str = &remaining[..number_end];
176 if number_str.len() > 5 {
177 return Err(ParseError::InvalidFormat {
178 message: "Field90C number cannot exceed 5 digits".to_string(),
179 });
180 }
181
182 parse_swift_digits(number_str, "Field90C number")?;
183 let number: u32 = number_str.parse().map_err(|_| ParseError::InvalidFormat {
184 message: "Invalid number in Field90C".to_string(),
185 })?;
186
187 remaining = &remaining[number_end..];
188
189 if remaining.len() < 3 {
191 return Err(ParseError::InvalidFormat {
192 message: "Field90C requires currency code".to_string(),
193 });
194 }
195
196 let currency = parse_currency(&remaining[..3])?;
197 remaining = &remaining[3..];
198
199 if remaining.is_empty() {
201 return Err(ParseError::InvalidFormat {
202 message: "Field90C requires amount".to_string(),
203 });
204 }
205
206 let amount = parse_amount(remaining)?;
207
208 Ok(Field90C {
209 number,
210 currency,
211 amount,
212 })
213 }
214
215 fn to_swift_string(&self) -> String {
216 let amount_str = format!("{:.2}", self.amount).replace('.', ",");
217 format!(":90C:{}{}{}", self.number, self.currency, amount_str)
218 }
219}
220
221#[cfg(test)]
222mod tests {
223 use super::*;
224
225 #[test]
226 fn test_field90d_parsing_basic() {
227 let value = "2GBP250050";
228 match Field90D::parse(value) {
229 Ok(field) => {
230 assert_eq!(field.number, 2);
231 assert_eq!(field.currency, "GBP");
232 assert_eq!(field.amount, 250050.0);
233 }
234 Err(e) => {
235 panic!("Failed to parse Field90D '{}': {:?}", value, e);
236 }
237 }
238 }
239}