swift_mt_message/messages/
mt205.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 MT205 {
15 #[serde(rename = "20")]
17 pub transaction_reference: Field20,
18
19 #[serde(rename = "21")]
21 pub related_reference: Field21NoOption,
22
23 #[serde(rename = "13C", skip_serializing_if = "Option::is_none")]
25 pub time_indication: Option<Vec<Field13C>>,
26
27 #[serde(rename = "23B", skip_serializing_if = "Option::is_none")]
29 pub bank_operation_code: Option<Field23B>,
30
31 #[serde(rename = "32A")]
33 pub value_date_amount: Field32A,
34
35 #[serde(rename = "33B", skip_serializing_if = "Option::is_none")]
37 pub instructed_amount: Option<Field33B>,
38
39 #[serde(flatten, skip_serializing_if = "Option::is_none")]
41 pub ordering_institution: Option<Field52OrderingInstitution>,
42
43 #[serde(flatten, skip_serializing_if = "Option::is_none")]
45 pub senders_correspondent: Option<Field53>,
46
47 #[serde(flatten, skip_serializing_if = "Option::is_none")]
49 pub receivers_correspondent: Option<Field54>,
50
51 #[serde(flatten, skip_serializing_if = "Option::is_none")]
53 pub intermediary: Option<Field56>,
54
55 #[serde(flatten, skip_serializing_if = "Option::is_none")]
57 pub account_with_institution: Option<Field57>,
58
59 #[serde(flatten)]
61 pub beneficiary_institution: Field58,
62
63 #[serde(rename = "72", skip_serializing_if = "Option::is_none")]
65 pub sender_to_receiver: Option<Field72>,
66}
67
68impl MT205 {
69 pub fn parse_from_block4(block4: &str) -> Result<Self, ParseError> {
71 let mut parser = MessageParser::new(block4, "205");
72
73 let transaction_reference = parser.parse_field::<Field20>("20")?;
75 let related_reference = parser.parse_field::<Field21NoOption>("21")?;
76
77 parser = parser.with_duplicates(true);
79 let mut time_indications = Vec::new();
80 while let Ok(field) = parser.parse_field::<Field13C>("13C") {
81 time_indications.push(field);
82 }
83 parser = parser.with_duplicates(false);
84
85 let time_indication = if time_indications.is_empty() {
86 None
87 } else {
88 Some(time_indications)
89 };
90
91 let bank_operation_code = parser.parse_optional_field::<Field23B>("23B")?;
93
94 let value_date_amount = parser.parse_field::<Field32A>("32A")?;
96
97 let instructed_amount = parser.parse_optional_field::<Field33B>("33B")?;
99
100 let ordering_institution =
102 parser.parse_optional_variant_field::<Field52OrderingInstitution>("52")?;
103 let senders_correspondent = parser.parse_optional_variant_field::<Field53>("53")?;
104 let receivers_correspondent = parser.parse_optional_variant_field::<Field54>("54")?;
105 let intermediary = parser.parse_optional_variant_field::<Field56>("56")?;
106 let account_with_institution = parser.parse_optional_variant_field::<Field57>("57")?;
107
108 let beneficiary_institution = parser.parse_variant_field::<Field58>("58")?;
110
111 let sender_to_receiver = parser.parse_optional_field::<Field72>("72")?;
113
114 Ok(MT205 {
115 transaction_reference,
116 related_reference,
117 time_indication,
118 bank_operation_code,
119 value_date_amount,
120 instructed_amount,
121 ordering_institution,
122 senders_correspondent,
123 receivers_correspondent,
124 intermediary,
125 account_with_institution,
126 beneficiary_institution,
127 sender_to_receiver,
128 })
129 }
130
131 pub fn has_reject_codes(&self) -> bool {
133 if let Some(ref info) = self.sender_to_receiver {
134 info.information
135 .iter()
136 .any(|line| line.contains("/REJT/") || line.contains("/RJT/"))
137 } else {
138 false
139 }
140 }
141
142 pub fn has_return_codes(&self) -> bool {
144 if let Some(ref info) = self.sender_to_receiver {
145 info.information
146 .iter()
147 .any(|line| line.contains("/RETN/") || line.contains("/RET/"))
148 } else {
149 false
150 }
151 }
152
153 pub fn is_cover_message(&self) -> bool {
155 if let Some(ref info) = self.sender_to_receiver {
156 info.information
157 .iter()
158 .any(|line| line.contains("/COV/") || line.contains("/COVER/"))
159 } else {
160 false
161 }
162 }
163
164 fn validate_c1_intermediary_account_with(&self) -> Option<SwiftValidationError> {
175 if self.intermediary.is_some() && self.account_with_institution.is_none() {
176 return Some(SwiftValidationError::content_error(
177 "C81",
178 "57a",
179 "",
180 "Field 57a (Account With Institution) is mandatory when field 56a (Intermediary) is present",
181 "If field 56a is present, then field 57a must also be present",
182 ));
183 }
184
185 None
186 }
187
188 pub fn validate_network_rules(&self, stop_on_first_error: bool) -> Vec<SwiftValidationError> {
191 let mut all_errors = Vec::new();
192
193 if let Some(error) = self.validate_c1_intermediary_account_with() {
195 all_errors.push(error);
196 if stop_on_first_error {
197 return all_errors;
198 }
199 }
200
201 all_errors
202 }
203}
204
205impl crate::traits::SwiftMessageBody for MT205 {
206 fn message_type() -> &'static str {
207 "205"
208 }
209
210 fn parse_from_block4(block4: &str) -> Result<Self, crate::errors::ParseError> {
211 Self::parse_from_block4(block4)
212 }
213
214 fn to_mt_string(&self) -> String {
215 let mut result = String::new();
216
217 append_field(&mut result, &self.transaction_reference);
218 append_field(&mut result, &self.related_reference);
219 append_vec_field(&mut result, &self.time_indication);
220 append_optional_field(&mut result, &self.bank_operation_code);
221 append_field(&mut result, &self.value_date_amount);
222 append_optional_field(&mut result, &self.instructed_amount);
223 append_optional_field(&mut result, &self.ordering_institution);
224 append_optional_field(&mut result, &self.senders_correspondent);
225 append_optional_field(&mut result, &self.receivers_correspondent);
226 append_optional_field(&mut result, &self.intermediary);
227 append_optional_field(&mut result, &self.account_with_institution);
228 append_field(&mut result, &self.beneficiary_institution);
229 append_optional_field(&mut result, &self.sender_to_receiver);
230
231 finalize_mt_string(result, false)
232 }
233
234 fn validate_network_rules(&self, stop_on_first_error: bool) -> Vec<SwiftValidationError> {
235 MT205::validate_network_rules(self, stop_on_first_error)
237 }
238}