1use serde::{Deserialize, Serialize};
48use std::collections::HashMap;
49use std::fmt::Debug;
50
51pub mod errors;
52pub mod fields;
53pub mod headers;
54pub mod messages;
55pub mod parser;
56
57pub use errors::{ParseError, Result, ValidationError};
59pub use headers::{ApplicationHeader, BasicHeader, Trailer, UserHeader};
60pub use parser::SwiftParser;
61
62pub use swift_mt_message_macros::{SwiftField, SwiftMessage, field, serde_swift_fields};
64
65pub type SwiftResult<T> = std::result::Result<T, crate::errors::ParseError>;
67
68pub trait SwiftField: Serialize + for<'de> Deserialize<'de> + Clone + std::fmt::Debug {
70 fn parse(value: &str) -> Result<Self>
72 where
73 Self: Sized;
74
75 fn to_swift_string(&self) -> String;
77
78 fn validate(&self) -> ValidationResult;
80
81 fn format_spec() -> &'static str;
83}
84
85pub trait SwiftMessageBody: Debug + Clone + Send + Sync + Serialize + std::any::Any {
87 fn message_type() -> &'static str;
89
90 fn from_fields(fields: HashMap<String, Vec<String>>) -> SwiftResult<Self>
92 where
93 Self: Sized;
94
95 fn to_fields(&self) -> HashMap<String, Vec<String>>;
97
98 fn required_fields() -> Vec<&'static str>;
100
101 fn optional_fields() -> Vec<&'static str>;
103
104 fn is_cover_message(&self) -> bool {
106 false
107 }
108
109 fn has_reject_codes(&self) -> bool {
110 false
111 }
112
113 fn has_return_codes(&self) -> bool {
114 false
115 }
116
117 fn is_stp_message(&self) -> bool {
118 false
119 }
120}
121
122#[derive(Debug, Clone, Serialize)]
124pub struct SwiftMessage<T: SwiftMessageBody> {
125 pub basic_header: BasicHeader,
127
128 pub application_header: ApplicationHeader,
130
131 #[serde(skip_serializing_if = "Option::is_none")]
133 pub user_header: Option<UserHeader>,
134
135 #[serde(skip_serializing_if = "Option::is_none")]
137 pub trailer: Option<Trailer>,
138
139 pub blocks: RawBlocks,
141
142 pub message_type: String,
144
145 pub field_order: Vec<String>,
147
148 pub fields: T,
150}
151
152#[derive(Debug, Clone, Serialize, Deserialize, Default)]
154pub struct RawBlocks {
155 #[serde(skip_serializing_if = "Option::is_none")]
156 pub block1: Option<String>,
157 #[serde(skip_serializing_if = "Option::is_none")]
158 pub block2: Option<String>,
159 #[serde(skip_serializing_if = "Option::is_none")]
160 pub block3: Option<String>,
161 pub block4: String,
162 #[serde(skip_serializing_if = "Option::is_none")]
163 pub block5: Option<String>,
164}
165
166#[derive(Debug, Clone, Serialize, Deserialize)]
168pub struct ValidationResult {
169 pub is_valid: bool,
170 pub errors: Vec<ValidationError>,
171 pub warnings: Vec<String>,
172}
173
174impl ValidationResult {
175 pub fn valid() -> Self {
176 Self {
177 is_valid: true,
178 errors: Vec::new(),
179 warnings: Vec::new(),
180 }
181 }
182
183 pub fn with_error(error: ValidationError) -> Self {
184 Self {
185 is_valid: false,
186 errors: vec![error],
187 warnings: Vec::new(),
188 }
189 }
190
191 pub fn with_errors(errors: Vec<ValidationError>) -> Self {
192 Self {
193 is_valid: errors.is_empty(),
194 errors,
195 warnings: Vec::new(),
196 }
197 }
198}
199
200#[derive(Debug, Clone, Serialize)]
202#[serde(tag = "message_type")]
203pub enum ParsedSwiftMessage {
204 #[serde(rename = "103")]
205 MT103(Box<SwiftMessage<messages::MT103>>),
206 #[serde(rename = "202")]
207 MT202(Box<SwiftMessage<messages::MT202>>),
208 #[serde(rename = "205")]
209 MT205(Box<SwiftMessage<messages::MT205>>),
210}
211
212impl ParsedSwiftMessage {
213 pub fn message_type(&self) -> &'static str {
215 match self {
216 ParsedSwiftMessage::MT103(_) => "103",
217 ParsedSwiftMessage::MT202(_) => "202",
218 ParsedSwiftMessage::MT205(_) => "205",
219 }
220 }
221
222 pub fn as_mt103(&self) -> Option<&SwiftMessage<messages::MT103>> {
224 match self {
225 ParsedSwiftMessage::MT103(msg) => Some(msg),
226 _ => None,
227 }
228 }
229
230 pub fn as_mt202(&self) -> Option<&SwiftMessage<messages::MT202>> {
231 match self {
232 ParsedSwiftMessage::MT202(msg) => Some(msg),
233 _ => None,
234 }
235 }
236
237 pub fn as_mt205(&self) -> Option<&SwiftMessage<messages::MT205>> {
238 match self {
239 ParsedSwiftMessage::MT205(msg) => Some(msg),
240 _ => None,
241 }
242 }
243
244 pub fn into_mt103(self) -> Option<SwiftMessage<messages::MT103>> {
246 match self {
247 ParsedSwiftMessage::MT103(msg) => Some(*msg),
248 _ => None,
249 }
250 }
251
252 pub fn into_mt202(self) -> Option<SwiftMessage<messages::MT202>> {
253 match self {
254 ParsedSwiftMessage::MT202(msg) => Some(*msg),
255 _ => None,
256 }
257 }
258
259 pub fn into_mt205(self) -> Option<SwiftMessage<messages::MT205>> {
260 match self {
261 ParsedSwiftMessage::MT205(msg) => Some(*msg),
262 _ => None,
263 }
264 }
265}
266
267impl<T: SwiftMessageBody> SwiftMessage<T> {
268 pub fn has_reject_codes(&self) -> bool {
275 if let Some(ref user_header) = self.user_header {
277 if let Some(ref mur) = user_header.message_user_reference {
278 if mur.to_uppercase().contains("REJT") {
279 return true;
280 }
281 }
282 }
283
284 if T::has_reject_codes(&self.fields) {
285 return true;
286 }
287
288 false
289 }
290
291 pub fn has_return_codes(&self) -> bool {
298 if let Some(ref user_header) = self.user_header {
300 if let Some(ref mur) = user_header.message_user_reference {
301 if mur.to_uppercase().contains("RETN") {
302 return true;
303 }
304 }
305 }
306
307 if T::has_return_codes(&self.fields) {
308 return true;
309 }
310
311 false
312 }
313
314 pub fn is_cover_message(&self) -> bool {
315 if T::message_type() == "202"
316 && T::is_cover_message(&self.fields)
317 && T::is_cover_message(&self.fields)
318 {
319 return true;
320 }
321
322 false
323 }
324
325 pub fn is_stp_message(&self) -> bool {
326 if T::message_type() == "103" && T::is_stp_message(&self.fields) {
327 return true;
328 }
329
330 false
331 }
332
333 pub fn validate_business_rules(&self) -> ValidationResult {
337 let validation_rules = match T::message_type() {
339 "103" => messages::MT103::validation_rules(),
340 "202" => messages::MT202::validation_rules(),
341 "205" => messages::MT205::validation_rules(),
342 "104" => messages::MT104::validation_rules(),
343 "107" => messages::MT107::validation_rules(),
344 "110" => messages::MT110::validation_rules(),
345 "111" => messages::MT111::validation_rules(),
346 "112" => messages::MT112::validation_rules(),
347 "210" => messages::MT210::validation_rules(),
348 "900" => messages::MT900::validation_rules(),
349 "910" => messages::MT910::validation_rules(),
350 "920" => messages::MT920::validation_rules(),
351 "935" => messages::MT935::validation_rules(),
352 "940" => messages::MT940::validation_rules(),
353 "941" => messages::MT941::validation_rules(),
354 "942" => messages::MT942::validation_rules(),
355 "950" => messages::MT950::validation_rules(),
356 _ => {
357 return ValidationResult::with_error(ValidationError::BusinessRuleValidation {
358 rule_name: "UNSUPPORTED_MESSAGE_TYPE".to_string(),
359 message: format!(
360 "No validation rules defined for message type {}",
361 T::message_type()
362 ),
363 });
364 }
365 };
366
367 let rules_json: serde_json::Value = match serde_json::from_str(validation_rules) {
369 Ok(json) => json,
370 Err(e) => {
371 return ValidationResult::with_error(ValidationError::BusinessRuleValidation {
372 rule_name: "JSON_PARSE".to_string(),
373 message: format!("Failed to parse validation rules JSON: {}", e),
374 });
375 }
376 };
377
378 let rules = match rules_json.get("rules").and_then(|r| r.as_array()) {
380 Some(rules) => rules,
381 None => {
382 return ValidationResult::with_error(ValidationError::BusinessRuleValidation {
383 rule_name: "RULES_FORMAT".to_string(),
384 message: "Validation rules must contain a 'rules' array".to_string(),
385 });
386 }
387 };
388
389 let constants = rules_json
391 .get("constants")
392 .and_then(|c| c.as_object())
393 .cloned()
394 .unwrap_or_default();
395
396 let context_value = match self.create_validation_context(&constants) {
398 Ok(context) => context,
399 Err(e) => {
400 return ValidationResult::with_error(ValidationError::BusinessRuleValidation {
401 rule_name: "CONTEXT_CREATION".to_string(),
402 message: format!("Failed to create validation context: {}", e),
403 });
404 }
405 };
406
407 let mut errors = Vec::new();
409 let mut warnings = Vec::new();
410
411 for (rule_index, rule) in rules.iter().enumerate() {
412 let rule_id = rule
413 .get("id")
414 .and_then(|id| id.as_str())
415 .map(|s| s.to_string())
416 .unwrap_or_else(|| format!("RULE_{}", rule_index));
417
418 let rule_description = rule
419 .get("description")
420 .and_then(|desc| desc.as_str())
421 .unwrap_or("No description");
422
423 if let Some(condition) = rule.get("condition") {
424 let dl = datalogic_rs::DataLogic::new();
426 match dl.evaluate_json(condition, &context_value, None) {
427 Ok(result) => {
428 match result.as_bool() {
429 Some(true) => {
430 continue;
432 }
433 Some(false) => {
434 errors.push(ValidationError::BusinessRuleValidation {
436 rule_name: rule_id.clone(),
437 message: format!(
438 "Business rule validation failed: {} - {}",
439 rule_id, rule_description
440 ),
441 });
442 }
443 None => {
444 warnings.push(format!(
446 "Rule {} returned non-boolean value: {:?}",
447 rule_id, result
448 ));
449 }
450 }
451 }
452 Err(e) => {
453 errors.push(ValidationError::BusinessRuleValidation {
455 rule_name: rule_id.clone(),
456 message: format!(
457 "JSONLogic evaluation error for rule {}: {}",
458 rule_id, e
459 ),
460 });
461 }
462 }
463 } else {
464 warnings.push(format!("Rule {} has no condition", rule_id));
465 }
466 }
467
468 ValidationResult {
469 is_valid: errors.is_empty(),
470 errors,
471 warnings,
472 }
473 }
474
475 fn create_validation_context(
477 &self,
478 constants: &serde_json::Map<String, serde_json::Value>,
479 ) -> Result<serde_json::Value> {
480 let full_message_data = match serde_json::to_value(self) {
482 Ok(data) => data,
483 Err(e) => {
484 return Err(ParseError::SerializationError {
485 message: format!("Failed to serialize complete message: {}", e),
486 });
487 }
488 };
489
490 let mut data_context = serde_json::Map::new();
492
493 if let serde_json::Value::Object(msg_obj) = full_message_data {
495 for (key, value) in msg_obj {
496 data_context.insert(key, value);
497 }
498 }
499
500 for (key, value) in constants {
502 data_context.insert(key.clone(), value.clone());
503 }
504
505 let (sender_country, receiver_country) = self.extract_country_codes_from_bics();
507
508 data_context.insert("message_context".to_string(), serde_json::json!({
510 "message_type": self.message_type,
511 "sender_country": sender_country,
512 "receiver_country": receiver_country,
513 "sender_bic": self.basic_header.logical_terminal,
514 "receiver_bic": &self.application_header.destination_address,
515 "message_priority": &self.application_header.priority,
516 "delivery_monitoring": self.application_header.delivery_monitoring.as_ref().unwrap_or(&"3".to_string()),
517 }));
518
519 Ok(serde_json::Value::Object(data_context))
520 }
521
522 fn extract_country_codes_from_bics(&self) -> (String, String) {
524 let sender_country = if self.basic_header.logical_terminal.len() >= 6 {
526 self.basic_header.logical_terminal[4..6].to_string()
527 } else {
528 "XX".to_string() };
530
531 let receiver_country = if self.application_header.destination_address.len() >= 6 {
533 self.application_header.destination_address[4..6].to_string()
534 } else {
535 "XX".to_string()
536 };
537
538 (sender_country, receiver_country)
539 }
540}