swift_mt_message/messages/
mt200.rs1use crate::errors::{ParseError, SwiftValidationError};
2use crate::fields::*;
3use crate::parser::MessageParser;
4use crate::parser::utils::*;
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
14pub struct MT200 {
15 #[serde(rename = "20")]
17 pub field_20: Field20,
18
19 #[serde(rename = "32A")]
21 pub field_32a: Field32A,
22
23 #[serde(rename = "53B", skip_serializing_if = "Option::is_none")]
25 pub field_53b: Option<Field53B>,
26
27 #[serde(flatten, skip_serializing_if = "Option::is_none")]
29 pub field_56: Option<Field56IntermediaryAD>,
30
31 #[serde(flatten)]
33 pub field_57: Field57DebtInstitution,
34
35 #[serde(rename = "72", skip_serializing_if = "Option::is_none")]
37 pub field_72: Option<Field72>,
38}
39
40impl MT200 {
41 pub fn parse_from_block4(block4: &str) -> Result<Self, ParseError> {
43 let mut parser = MessageParser::new(block4, "200");
44
45 let field_20 = parser.parse_field::<Field20>("20")?;
47 let field_32a = parser.parse_field::<Field32A>("32A")?;
48
49 let field_53b = parser.parse_optional_field::<Field53B>("53B")?;
51
52 let field_56 = parser.parse_optional_variant_field::<Field56IntermediaryAD>("56")?;
54
55 let field_57 = parser.parse_variant_field::<Field57DebtInstitution>("57")?;
57
58 let field_72 = parser.parse_optional_field::<Field72>("72")?;
60
61 Ok(MT200 {
62 field_20,
63 field_32a,
64 field_53b,
65 field_56,
66 field_57,
67 field_72,
68 })
69 }
70
71 pub fn parse(input: &str) -> Result<Self, crate::errors::ParseError> {
73 let block4 = extract_block4(input)?;
74 Self::parse_from_block4(&block4)
75 }
76
77 pub fn to_mt_string(&self) -> String {
79 let mut result = String::new();
80
81 append_field(&mut result, &self.field_20);
82 append_field(&mut result, &self.field_32a);
83 append_optional_field(&mut result, &self.field_53b);
84 append_optional_field(&mut result, &self.field_56);
85 append_field(&mut result, &self.field_57);
86 append_optional_field(&mut result, &self.field_72);
87
88 result.push('-');
89 result
90 }
91
92 const SPECIAL_72_CODES: &'static [&'static str] = &["REJT", "RETN"];
98
99 fn extract_72_codes(&self) -> Vec<String> {
105 let mut codes = Vec::new();
106
107 if let Some(ref field_72) = self.field_72 {
108 for line in &field_72.information {
110 let trimmed = line.trim();
111 if let Some(without_prefix) = trimmed.strip_prefix('/') {
112 if let Some(end_idx) = without_prefix.find('/') {
113 let code = &without_prefix[..end_idx];
114 codes.push(code.to_uppercase());
115 } else if !without_prefix.is_empty() {
116 if let Some(space_idx) = without_prefix.find(|c: char| c.is_whitespace()) {
118 codes.push(without_prefix[..space_idx].to_uppercase());
119 } else {
120 codes.push(without_prefix.to_uppercase());
121 }
122 }
123 }
124 }
125 }
126
127 codes
128 }
129
130 fn validate_t80_field_72_special_codes(&self) -> Vec<SwiftValidationError> {
137 let mut errors = Vec::new();
138
139 let codes = self.extract_72_codes();
140
141 for code in &codes {
142 if Self::SPECIAL_72_CODES.contains(&code.as_str()) {
143 errors.push(SwiftValidationError::content_error(
147 "T80",
148 "72",
149 code,
150 &format!(
151 "Field 72 contains code /{}/. Message must comply with SWIFT Payments Reject/Return Guidelines",
152 code
153 ),
154 "When field 72 contains /REJT/ or /RETN/, the message must follow SWIFT Payments Reject/Return Guidelines",
155 ));
156 }
157 }
158
159 errors
160 }
161
162 pub fn validate_network_rules(&self, stop_on_first_error: bool) -> Vec<SwiftValidationError> {
165 let mut all_errors = Vec::new();
166
167 let t80_errors = self.validate_t80_field_72_special_codes();
172 all_errors.extend(t80_errors);
173 if stop_on_first_error && !all_errors.is_empty() {
174 return all_errors;
175 }
176
177 all_errors
178 }
179}
180
181impl crate::traits::SwiftMessageBody for MT200 {
182 fn message_type() -> &'static str {
183 "200"
184 }
185
186 fn parse_from_block4(block4: &str) -> Result<Self, crate::errors::ParseError> {
187 MT200::parse_from_block4(block4)
189 }
190
191 fn to_mt_string(&self) -> String {
192 MT200::to_mt_string(self)
194 }
195
196 fn validate_network_rules(&self, stop_on_first_error: bool) -> Vec<SwiftValidationError> {
197 MT200::validate_network_rules(self, stop_on_first_error)
199 }
200}