swift_mt_message/fields/
field54.rs1use super::field_utils::{parse_name_and_address, parse_party_identifier};
2use super::swift_utils::{parse_bic, parse_max_length};
3use crate::errors::ParseError;
4use crate::traits::SwiftField;
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12pub struct Field54A {
13 pub party_identifier: Option<String>,
15
16 pub bic: String,
18}
19
20impl SwiftField for Field54A {
21 fn parse(input: &str) -> crate::Result<Self>
22 where
23 Self: Sized,
24 {
25 let lines: Vec<&str> = input.split('\n').collect();
26
27 if lines.is_empty() {
28 return Err(ParseError::InvalidFormat {
29 message: "Field 54A requires input".to_string(),
30 });
31 }
32
33 let mut line_idx = 0;
34 let mut party_identifier = None;
35
36 if let Some(party_id) = parse_party_identifier(lines[0])? {
38 party_identifier = Some(format!("/{}", party_id));
39 line_idx = 1;
40 }
41
42 if line_idx >= lines.len() {
44 return Err(ParseError::InvalidFormat {
45 message: "Field 54A requires BIC code after party identifier".to_string(),
46 });
47 }
48
49 let bic = parse_bic(lines[line_idx])?;
51
52 Ok(Field54A {
53 party_identifier,
54 bic,
55 })
56 }
57
58 fn to_swift_string(&self) -> String {
59 let mut result = String::from(":54A:");
60 if let Some(ref party_id) = self.party_identifier {
61 result.push_str(party_id);
62 result.push('\n');
63 }
64 result.push_str(&self.bic);
65 result
66 }
67}
68
69#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
74pub struct Field54B {
75 pub party_identifier: Option<String>,
77
78 pub location: Option<String>,
80}
81
82impl SwiftField for Field54B {
83 fn parse(input: &str) -> crate::Result<Self>
84 where
85 Self: Sized,
86 {
87 if input.is_empty() {
88 return Ok(Field54B {
89 party_identifier: None,
90 location: None,
91 });
92 }
93
94 let lines: Vec<&str> = input.split('\n').collect();
95 let mut party_identifier = None;
96 let mut location = None;
97 let mut line_idx = 0;
98
99 if !lines.is_empty() && lines[0].starts_with('/') {
101 party_identifier = Some(lines[0].to_string());
102 line_idx = 1;
103 }
104
105 if line_idx < lines.len() && !lines[line_idx].is_empty() {
107 location = Some(parse_max_length(lines[line_idx], 35, "Field54B location")?);
108 }
109
110 Ok(Field54B {
111 party_identifier,
112 location,
113 })
114 }
115
116 fn to_swift_string(&self) -> String {
117 let mut result = String::from(":54B:");
118 if let Some(ref party_id) = self.party_identifier {
119 result.push_str(party_id);
120 if self.location.is_some() {
121 result.push('\n');
122 }
123 }
124 if let Some(ref loc) = self.location {
125 result.push_str(loc);
126 }
127 result
128 }
129}
130
131#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
136pub struct Field54D {
137 pub party_identifier: Option<String>,
139
140 pub name_and_address: Vec<String>,
142}
143
144impl SwiftField for Field54D {
145 fn parse(input: &str) -> crate::Result<Self>
146 where
147 Self: Sized,
148 {
149 let lines: Vec<&str> = input.split('\n').collect();
150
151 if lines.is_empty() {
152 return Err(ParseError::InvalidFormat {
153 message: "Field 54D requires at least one line".to_string(),
154 });
155 }
156
157 let mut party_identifier = None;
158 let mut start_idx = 0;
159
160 if let Some(party_id) = parse_party_identifier(lines[0])? {
162 party_identifier = Some(format!("/{}", party_id));
163 start_idx = 1;
164 }
165
166 let name_and_address = parse_name_and_address(&lines, start_idx, "Field54D")?;
168
169 Ok(Field54D {
170 party_identifier,
171 name_and_address,
172 })
173 }
174
175 fn to_swift_string(&self) -> String {
176 let mut result = String::from(":54D:");
177 if let Some(ref party_id) = self.party_identifier {
178 result.push_str(party_id);
179 result.push('\n');
180 }
181 for (i, line) in self.name_and_address.iter().enumerate() {
182 if i > 0 {
183 result.push('\n');
184 }
185 result.push_str(line);
186 }
187 result
188 }
189}
190
191#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
192pub enum Field54ReceiverCorrespondent {
193 #[serde(rename = "54A")]
194 A(Field54A),
195 #[serde(rename = "54B")]
196 B(Field54B),
197 #[serde(rename = "54D")]
198 D(Field54D),
199}
200
201impl SwiftField for Field54ReceiverCorrespondent {
202 fn parse(input: &str) -> crate::Result<Self>
203 where
204 Self: Sized,
205 {
206 let lines: Vec<&str> = input.split('\n').collect();
212 let last_line = lines.last().unwrap_or(&"");
213
214 if (8..=11).contains(&last_line.len())
216 && last_line
217 .chars()
218 .all(|c| c.is_ascii_uppercase() || c.is_ascii_digit())
219 {
220 if let Ok(field) = Field54A::parse(input) {
222 return Ok(Field54ReceiverCorrespondent::A(field));
223 }
224 }
225
226 if lines.len() > 2 || (lines.len() == 2 && !lines[0].starts_with('/')) {
228 if let Ok(field) = Field54D::parse(input) {
230 return Ok(Field54ReceiverCorrespondent::D(field));
231 }
232 }
233
234 if let Ok(field) = Field54B::parse(input) {
236 return Ok(Field54ReceiverCorrespondent::B(field));
237 }
238
239 if let Ok(field) = Field54A::parse(input) {
241 return Ok(Field54ReceiverCorrespondent::A(field));
242 }
243 if let Ok(field) = Field54D::parse(input) {
244 return Ok(Field54ReceiverCorrespondent::D(field));
245 }
246
247 Err(ParseError::InvalidFormat {
248 message: "Field 54 could not be parsed as any valid option (A, B, or D)".to_string(),
249 })
250 }
251
252 fn to_swift_string(&self) -> String {
253 match self {
254 Field54ReceiverCorrespondent::A(field) => field.to_swift_string(),
255 Field54ReceiverCorrespondent::B(field) => field.to_swift_string(),
256 Field54ReceiverCorrespondent::D(field) => field.to_swift_string(),
257 }
258 }
259
260 fn get_variant_tag(&self) -> Option<&'static str> {
261 match self {
262 Field54ReceiverCorrespondent::A(_) => Some("A"),
263 Field54ReceiverCorrespondent::B(_) => Some("B"),
264 Field54ReceiverCorrespondent::D(_) => Some("D"),
265 }
266 }
267}
268
269pub type Field54 = Field54ReceiverCorrespondent;
271
272#[cfg(test)]
273mod tests {
274 use super::*;
275
276 #[test]
277 fn test_field54a_valid() {
278 let field = Field54A::parse("DEUTDEFFXXX").unwrap();
280 assert_eq!(field.bic, "DEUTDEFFXXX");
281 assert_eq!(field.party_identifier, None);
282 assert_eq!(field.to_swift_string(), ":54A:DEUTDEFFXXX");
283
284 let field = Field54A::parse("/A/987654321\nDEUTDEFF").unwrap();
286 assert_eq!(field.bic, "DEUTDEFF");
287 assert_eq!(field.party_identifier, Some("/A/987654321".to_string()));
288 assert_eq!(field.to_swift_string(), ":54A:/A/987654321\nDEUTDEFF");
289 }
290
291 #[test]
292 fn test_field54b_valid() {
293 let field = Field54B::parse("FRANKFURT BRANCH").unwrap();
295 assert_eq!(field.location, Some("FRANKFURT BRANCH".to_string()));
296 assert_eq!(field.party_identifier, None);
297
298 let field = Field54B::parse("/B/11223344\nFRANKFURT").unwrap();
300 assert_eq!(field.party_identifier, Some("/B/11223344".to_string()));
301 assert_eq!(field.location, Some("FRANKFURT".to_string()));
302
303 let field = Field54B::parse("").unwrap();
305 assert_eq!(field.party_identifier, None);
306 assert_eq!(field.location, None);
307 }
308
309 #[test]
310 fn test_field54d_valid() {
311 let field = Field54D::parse("/A/987654321\nRECEIVER BANK\n456 BANK ST\nFRANKFURT\nGERMANY")
313 .unwrap();
314 assert_eq!(field.party_identifier, Some("/A/987654321".to_string()));
315 assert_eq!(field.name_and_address.len(), 4);
316 assert_eq!(field.name_and_address[0], "RECEIVER BANK");
317 assert_eq!(field.name_and_address[3], "GERMANY");
318
319 let field = Field54D::parse("RECEIVER BANK\nFRANKFURT").unwrap();
321 assert_eq!(field.party_identifier, None);
322 assert_eq!(field.name_and_address.len(), 2);
323 }
324
325 #[test]
326 fn test_field54_enum() {
327 let field = Field54ReceiverCorrespondent::parse("DEUTDEFFXXX").unwrap();
329 assert!(matches!(field, Field54ReceiverCorrespondent::A(_)));
330
331 let field = Field54ReceiverCorrespondent::parse("FRANKFURT BRANCH").unwrap();
333 assert!(matches!(field, Field54ReceiverCorrespondent::B(_)));
334
335 let field = Field54ReceiverCorrespondent::parse("BANK NAME\nADDRESS LINE 1\nCITY").unwrap();
337 assert!(matches!(field, Field54ReceiverCorrespondent::D(_)));
338 }
339}