swift_mt_message/
swift_message.rs1use crate::{
6 ValidationError, ValidationResult,
7 headers::{ApplicationHeader, BasicHeader, Trailer, UserHeader},
8 traits::SwiftMessageBody,
9};
10use serde::{Deserialize, Serialize};
11use std::any::Any;
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct SwiftMessage<T: SwiftMessageBody> {
16 pub basic_header: BasicHeader,
18
19 pub application_header: ApplicationHeader,
21
22 #[serde(skip_serializing_if = "Option::is_none")]
24 pub user_header: Option<UserHeader>,
25
26 #[serde(skip_serializing_if = "Option::is_none")]
28 pub trailer: Option<Trailer>,
29
30 pub message_type: String,
32
33 pub fields: T,
35}
36
37impl<T: SwiftMessageBody> SwiftMessage<T> {
38 pub fn has_reject_codes(&self) -> bool {
40 if let Some(ref user_header) = self.user_header
42 && let Some(ref mur) = user_header.message_user_reference
43 && mur.to_uppercase().contains("REJT")
44 {
45 return true;
46 }
47
48 if let Some(mt103_fields) =
49 (&self.fields as &dyn Any).downcast_ref::<crate::messages::MT103>()
50 {
51 return mt103_fields.has_reject_codes();
52 } else if let Some(mt202_fields) =
53 (&self.fields as &dyn Any).downcast_ref::<crate::messages::MT202>()
54 {
55 return mt202_fields.has_reject_codes();
56 } else if let Some(mt205_fields) =
57 (&self.fields as &dyn Any).downcast_ref::<crate::messages::MT205>()
58 {
59 return mt205_fields.has_reject_codes();
60 }
61
62 false
63 }
64
65 pub fn has_return_codes(&self) -> bool {
67 if let Some(ref user_header) = self.user_header
69 && let Some(ref mur) = user_header.message_user_reference
70 && mur.to_uppercase().contains("RETN")
71 {
72 return true;
73 }
74
75 if let Some(mt103_fields) =
76 (&self.fields as &dyn Any).downcast_ref::<crate::messages::MT103>()
77 {
78 return mt103_fields.has_return_codes();
79 } else if let Some(mt202_fields) =
80 (&self.fields as &dyn Any).downcast_ref::<crate::messages::MT202>()
81 {
82 return mt202_fields.has_return_codes();
83 } else if let Some(mt205_fields) =
84 (&self.fields as &dyn Any).downcast_ref::<crate::messages::MT205>()
85 {
86 return mt205_fields.has_return_codes();
87 }
88
89 false
90 }
91
92 pub fn is_cover_message(&self) -> bool {
93 if let Some(mt202_fields) =
94 (&self.fields as &dyn Any).downcast_ref::<crate::messages::MT202>()
95 {
96 return mt202_fields.is_cover_message();
97 }
98 if let Some(mt205_fields) =
99 (&self.fields as &dyn Any).downcast_ref::<crate::messages::MT205>()
100 {
101 return mt205_fields.is_cover_message();
102 }
103
104 false
105 }
106
107 pub fn is_stp_message(&self) -> bool {
108 if let Some(mt103_fields) =
109 (&self.fields as &dyn Any).downcast_ref::<crate::messages::MT103>()
110 {
111 return mt103_fields.is_stp_compliant();
112 }
113
114 false
115 }
116
117 pub fn validate(&self) -> ValidationResult {
119 let validation_errors = self.fields.validate_network_rules(false);
121
122 let errors: Vec<ValidationError> = validation_errors
124 .into_iter()
125 .map(|swift_error| {
126 let message = format!("{}", swift_error);
127 ValidationError::BusinessRuleValidation {
128 rule_name: swift_error.error_code().to_string(),
129 message,
130 }
131 })
132 .collect();
133
134 ValidationResult {
135 is_valid: errors.is_empty(),
136 errors,
137 warnings: Vec::new(),
138 }
139 }
140
141 pub fn to_mt_message(&self) -> String {
142 let mut swift_message = String::with_capacity(2200);
145
146 let block1 = &self.basic_header.to_string();
148 swift_message.push_str(&format!("{{1:{block1}}}\n"));
149
150 let block2 = &self.application_header.to_string();
152 swift_message.push_str(&format!("{{2:{block2}}}\n"));
153
154 if let Some(ref user_header) = self.user_header {
156 let block3 = &user_header.to_string();
157 swift_message.push_str(&format!("{{3:{block3}}}\n"));
158 }
159
160 let mut block4_content = self.fields.to_mt_string();
163
164 if block4_content.contains("\r\n") {
166 block4_content = block4_content.replace("\r\n", "\n");
167 }
168
169 let block4 = if block4_content.starts_with('\n') {
171 block4_content
172 } else {
173 format!("\n{}", block4_content)
174 };
175
176 swift_message.push_str(&format!("{{4:{block4}\n-}}\n"));
177
178 if let Some(ref trailer) = self.trailer {
180 let block5 = &trailer.to_string();
181 swift_message.push_str(&format!("{{5:{block5}}}\n"));
182 }
183
184 swift_message
185 }
186}