1use serde::{Deserialize, Serialize};
48use std::any::Any;
49use std::collections::HashMap;
50use std::fmt::Debug;
51
52pub mod errors;
53pub mod fields;
54pub mod headers;
55pub mod messages;
56pub mod parser;
57pub mod sample;
58
59pub use errors::{ParseError, Result, ValidationError};
61pub use headers::{ApplicationHeader, BasicHeader, Trailer, UserHeader};
62pub use parser::SwiftParser;
63
64pub use swift_mt_message_macros::{SwiftField, SwiftMessage, field, serde_swift_fields};
66
67pub type SwiftResult<T> = std::result::Result<T, crate::errors::ParseError>;
69
70pub trait SwiftField: Serialize + for<'de> Deserialize<'de> + Clone + std::fmt::Debug {
72 fn parse(value: &str) -> Result<Self>
74 where
75 Self: Sized;
76
77 fn to_swift_string(&self) -> String;
79
80 fn validate(&self) -> ValidationResult;
82
83 fn format_spec() -> &'static str;
85
86 fn sample() -> Self
88 where
89 Self: Sized;
90
91 fn sample_with_config(config: &sample::FieldConfig) -> Self
93 where
94 Self: Sized;
95}
96
97pub trait SwiftMessageBody: Debug + Clone + Send + Sync + Serialize + std::any::Any {
99 fn message_type() -> &'static str;
101
102 fn from_fields(fields: HashMap<String, Vec<String>>) -> SwiftResult<Self>
104 where
105 Self: Sized;
106
107 fn to_fields(&self) -> HashMap<String, Vec<String>>;
109
110 fn required_fields() -> Vec<&'static str>;
112
113 fn optional_fields() -> Vec<&'static str>;
115
116 fn sample() -> Self
118 where
119 Self: Sized;
120
121 fn sample_minimal() -> Self
123 where
124 Self: Sized;
125
126 fn sample_full() -> Self
128 where
129 Self: Sized;
130
131 fn sample_with_config(config: &sample::MessageConfig) -> Self
133 where
134 Self: Sized;
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize)]
139pub struct SwiftMessage<T: SwiftMessageBody> {
140 pub basic_header: BasicHeader,
142
143 pub application_header: ApplicationHeader,
145
146 #[serde(skip_serializing_if = "Option::is_none")]
148 pub user_header: Option<UserHeader>,
149
150 #[serde(skip_serializing_if = "Option::is_none")]
152 pub trailer: Option<Trailer>,
153
154 pub blocks: Option<RawBlocks>,
156
157 pub message_type: String,
159
160 pub field_order: Vec<String>,
162
163 pub fields: T,
165}
166
167#[derive(Debug, Clone, Serialize, Deserialize, Default)]
169pub struct RawBlocks {
170 #[serde(skip_serializing_if = "Option::is_none")]
171 pub block1: Option<String>,
172 #[serde(skip_serializing_if = "Option::is_none")]
173 pub block2: Option<String>,
174 #[serde(skip_serializing_if = "Option::is_none")]
175 pub block3: Option<String>,
176 #[serde(skip_serializing_if = "Option::is_none")]
177 pub block4: Option<String>,
178 #[serde(skip_serializing_if = "Option::is_none")]
179 pub block5: Option<String>,
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize)]
184pub struct ValidationResult {
185 pub is_valid: bool,
186 pub errors: Vec<ValidationError>,
187 pub warnings: Vec<String>,
188}
189
190impl ValidationResult {
191 pub fn valid() -> Self {
192 Self {
193 is_valid: true,
194 errors: Vec::new(),
195 warnings: Vec::new(),
196 }
197 }
198
199 pub fn with_error(error: ValidationError) -> Self {
200 Self {
201 is_valid: false,
202 errors: vec![error],
203 warnings: Vec::new(),
204 }
205 }
206
207 pub fn with_errors(errors: Vec<ValidationError>) -> Self {
208 Self {
209 is_valid: errors.is_empty(),
210 errors,
211 warnings: Vec::new(),
212 }
213 }
214}
215
216#[derive(Debug, Clone, Serialize, Deserialize)]
218#[serde(tag = "message_type")]
219pub enum ParsedSwiftMessage {
220 #[serde(rename = "101")]
221 MT101(Box<SwiftMessage<messages::MT101>>),
222 #[serde(rename = "103")]
223 MT103(Box<SwiftMessage<messages::MT103>>),
224 #[serde(rename = "104")]
225 MT104(Box<SwiftMessage<messages::MT104>>),
226 #[serde(rename = "107")]
227 MT107(Box<SwiftMessage<messages::MT107>>),
228 #[serde(rename = "110")]
229 MT110(Box<SwiftMessage<messages::MT110>>),
230 #[serde(rename = "111")]
231 MT111(Box<SwiftMessage<messages::MT111>>),
232 #[serde(rename = "112")]
233 MT112(Box<SwiftMessage<messages::MT112>>),
234 #[serde(rename = "202")]
235 MT202(Box<SwiftMessage<messages::MT202>>),
236 #[serde(rename = "205")]
237 MT205(Box<SwiftMessage<messages::MT205>>),
238 #[serde(rename = "210")]
239 MT210(Box<SwiftMessage<messages::MT210>>),
240 #[serde(rename = "900")]
241 MT900(Box<SwiftMessage<messages::MT900>>),
242 #[serde(rename = "910")]
243 MT910(Box<SwiftMessage<messages::MT910>>),
244 #[serde(rename = "920")]
245 MT920(Box<SwiftMessage<messages::MT920>>),
246 #[serde(rename = "935")]
247 MT935(Box<SwiftMessage<messages::MT935>>),
248 #[serde(rename = "940")]
249 MT940(Box<SwiftMessage<messages::MT940>>),
250 #[serde(rename = "941")]
251 MT941(Box<SwiftMessage<messages::MT941>>),
252 #[serde(rename = "942")]
253 MT942(Box<SwiftMessage<messages::MT942>>),
254 #[serde(rename = "950")]
255 MT950(Box<SwiftMessage<messages::MT950>>),
256 #[serde(rename = "192")]
257 MT192(Box<SwiftMessage<messages::MT192>>),
258 #[serde(rename = "196")]
259 MT196(Box<SwiftMessage<messages::MT196>>),
260 #[serde(rename = "292")]
261 MT292(Box<SwiftMessage<messages::MT292>>),
262 #[serde(rename = "296")]
263 MT296(Box<SwiftMessage<messages::MT296>>),
264}
265
266impl ParsedSwiftMessage {
267 pub fn message_type(&self) -> &'static str {
269 match self {
270 ParsedSwiftMessage::MT101(_) => "101",
271 ParsedSwiftMessage::MT103(_) => "103",
272 ParsedSwiftMessage::MT104(_) => "104",
273 ParsedSwiftMessage::MT107(_) => "107",
274 ParsedSwiftMessage::MT110(_) => "110",
275 ParsedSwiftMessage::MT111(_) => "111",
276 ParsedSwiftMessage::MT112(_) => "112",
277 ParsedSwiftMessage::MT202(_) => "202",
278 ParsedSwiftMessage::MT205(_) => "205",
279 ParsedSwiftMessage::MT210(_) => "210",
280 ParsedSwiftMessage::MT900(_) => "900",
281 ParsedSwiftMessage::MT910(_) => "910",
282 ParsedSwiftMessage::MT920(_) => "920",
283 ParsedSwiftMessage::MT935(_) => "935",
284 ParsedSwiftMessage::MT940(_) => "940",
285 ParsedSwiftMessage::MT941(_) => "941",
286 ParsedSwiftMessage::MT942(_) => "942",
287 ParsedSwiftMessage::MT950(_) => "950",
288 ParsedSwiftMessage::MT192(_) => "192",
289 ParsedSwiftMessage::MT196(_) => "196",
290 ParsedSwiftMessage::MT292(_) => "292",
291 ParsedSwiftMessage::MT296(_) => "296",
292 }
293 }
294}
295
296impl ParsedSwiftMessage {
297 pub fn as_mt101(&self) -> Option<&SwiftMessage<messages::MT101>> {
299 match self {
300 ParsedSwiftMessage::MT101(msg) => Some(msg),
301 _ => None,
302 }
303 }
304 pub fn as_mt103(&self) -> Option<&SwiftMessage<messages::MT103>> {
305 match self {
306 ParsedSwiftMessage::MT103(msg) => Some(msg),
307 _ => None,
308 }
309 }
310 pub fn as_mt104(&self) -> Option<&SwiftMessage<messages::MT104>> {
311 match self {
312 ParsedSwiftMessage::MT104(msg) => Some(msg),
313 _ => None,
314 }
315 }
316 pub fn as_mt107(&self) -> Option<&SwiftMessage<messages::MT107>> {
317 match self {
318 ParsedSwiftMessage::MT107(msg) => Some(msg),
319 _ => None,
320 }
321 }
322 pub fn as_mt110(&self) -> Option<&SwiftMessage<messages::MT110>> {
323 match self {
324 ParsedSwiftMessage::MT110(msg) => Some(msg),
325 _ => None,
326 }
327 }
328 pub fn as_mt111(&self) -> Option<&SwiftMessage<messages::MT111>> {
329 match self {
330 ParsedSwiftMessage::MT111(msg) => Some(msg),
331 _ => None,
332 }
333 }
334 pub fn as_mt112(&self) -> Option<&SwiftMessage<messages::MT112>> {
335 match self {
336 ParsedSwiftMessage::MT112(msg) => Some(msg),
337 _ => None,
338 }
339 }
340 pub fn as_mt202(&self) -> Option<&SwiftMessage<messages::MT202>> {
341 match self {
342 ParsedSwiftMessage::MT202(msg) => Some(msg),
343 _ => None,
344 }
345 }
346 pub fn as_mt205(&self) -> Option<&SwiftMessage<messages::MT205>> {
347 match self {
348 ParsedSwiftMessage::MT205(msg) => Some(msg),
349 _ => None,
350 }
351 }
352 pub fn as_mt210(&self) -> Option<&SwiftMessage<messages::MT210>> {
353 match self {
354 ParsedSwiftMessage::MT210(msg) => Some(msg),
355 _ => None,
356 }
357 }
358 pub fn as_mt900(&self) -> Option<&SwiftMessage<messages::MT900>> {
359 match self {
360 ParsedSwiftMessage::MT900(msg) => Some(msg),
361 _ => None,
362 }
363 }
364 pub fn as_mt910(&self) -> Option<&SwiftMessage<messages::MT910>> {
365 match self {
366 ParsedSwiftMessage::MT910(msg) => Some(msg),
367 _ => None,
368 }
369 }
370 pub fn as_mt920(&self) -> Option<&SwiftMessage<messages::MT920>> {
371 match self {
372 ParsedSwiftMessage::MT920(msg) => Some(msg),
373 _ => None,
374 }
375 }
376 pub fn as_mt935(&self) -> Option<&SwiftMessage<messages::MT935>> {
377 match self {
378 ParsedSwiftMessage::MT935(msg) => Some(msg),
379 _ => None,
380 }
381 }
382 pub fn as_mt940(&self) -> Option<&SwiftMessage<messages::MT940>> {
383 match self {
384 ParsedSwiftMessage::MT940(msg) => Some(msg),
385 _ => None,
386 }
387 }
388 pub fn as_mt941(&self) -> Option<&SwiftMessage<messages::MT941>> {
389 match self {
390 ParsedSwiftMessage::MT941(msg) => Some(msg),
391 _ => None,
392 }
393 }
394 pub fn as_mt942(&self) -> Option<&SwiftMessage<messages::MT942>> {
395 match self {
396 ParsedSwiftMessage::MT942(msg) => Some(msg),
397 _ => None,
398 }
399 }
400 pub fn as_mt950(&self) -> Option<&SwiftMessage<messages::MT950>> {
401 match self {
402 ParsedSwiftMessage::MT950(msg) => Some(msg),
403 _ => None,
404 }
405 }
406 pub fn as_mt192(&self) -> Option<&SwiftMessage<messages::MT192>> {
407 match self {
408 ParsedSwiftMessage::MT192(msg) => Some(msg),
409 _ => None,
410 }
411 }
412 pub fn as_mt196(&self) -> Option<&SwiftMessage<messages::MT196>> {
413 match self {
414 ParsedSwiftMessage::MT196(msg) => Some(msg),
415 _ => None,
416 }
417 }
418 pub fn as_mt292(&self) -> Option<&SwiftMessage<messages::MT292>> {
419 match self {
420 ParsedSwiftMessage::MT292(msg) => Some(msg),
421 _ => None,
422 }
423 }
424 pub fn as_mt296(&self) -> Option<&SwiftMessage<messages::MT296>> {
425 match self {
426 ParsedSwiftMessage::MT296(msg) => Some(msg),
427 _ => None,
428 }
429 }
430
431 pub fn into_mt101(self) -> Option<SwiftMessage<messages::MT101>> {
433 match self {
434 ParsedSwiftMessage::MT101(msg) => Some(*msg),
435 _ => None,
436 }
437 }
438 pub fn into_mt103(self) -> Option<SwiftMessage<messages::MT103>> {
439 match self {
440 ParsedSwiftMessage::MT103(msg) => Some(*msg),
441 _ => None,
442 }
443 }
444 pub fn into_mt104(self) -> Option<SwiftMessage<messages::MT104>> {
445 match self {
446 ParsedSwiftMessage::MT104(msg) => Some(*msg),
447 _ => None,
448 }
449 }
450 pub fn into_mt107(self) -> Option<SwiftMessage<messages::MT107>> {
451 match self {
452 ParsedSwiftMessage::MT107(msg) => Some(*msg),
453 _ => None,
454 }
455 }
456 pub fn into_mt110(self) -> Option<SwiftMessage<messages::MT110>> {
457 match self {
458 ParsedSwiftMessage::MT110(msg) => Some(*msg),
459 _ => None,
460 }
461 }
462 pub fn into_mt111(self) -> Option<SwiftMessage<messages::MT111>> {
463 match self {
464 ParsedSwiftMessage::MT111(msg) => Some(*msg),
465 _ => None,
466 }
467 }
468 pub fn into_mt112(self) -> Option<SwiftMessage<messages::MT112>> {
469 match self {
470 ParsedSwiftMessage::MT112(msg) => Some(*msg),
471 _ => None,
472 }
473 }
474 pub fn into_mt202(self) -> Option<SwiftMessage<messages::MT202>> {
475 match self {
476 ParsedSwiftMessage::MT202(msg) => Some(*msg),
477 _ => None,
478 }
479 }
480 pub fn into_mt205(self) -> Option<SwiftMessage<messages::MT205>> {
481 match self {
482 ParsedSwiftMessage::MT205(msg) => Some(*msg),
483 _ => None,
484 }
485 }
486 pub fn into_mt210(self) -> Option<SwiftMessage<messages::MT210>> {
487 match self {
488 ParsedSwiftMessage::MT210(msg) => Some(*msg),
489 _ => None,
490 }
491 }
492 pub fn into_mt900(self) -> Option<SwiftMessage<messages::MT900>> {
493 match self {
494 ParsedSwiftMessage::MT900(msg) => Some(*msg),
495 _ => None,
496 }
497 }
498 pub fn into_mt910(self) -> Option<SwiftMessage<messages::MT910>> {
499 match self {
500 ParsedSwiftMessage::MT910(msg) => Some(*msg),
501 _ => None,
502 }
503 }
504 pub fn into_mt920(self) -> Option<SwiftMessage<messages::MT920>> {
505 match self {
506 ParsedSwiftMessage::MT920(msg) => Some(*msg),
507 _ => None,
508 }
509 }
510 pub fn into_mt935(self) -> Option<SwiftMessage<messages::MT935>> {
511 match self {
512 ParsedSwiftMessage::MT935(msg) => Some(*msg),
513 _ => None,
514 }
515 }
516 pub fn into_mt940(self) -> Option<SwiftMessage<messages::MT940>> {
517 match self {
518 ParsedSwiftMessage::MT940(msg) => Some(*msg),
519 _ => None,
520 }
521 }
522 pub fn into_mt941(self) -> Option<SwiftMessage<messages::MT941>> {
523 match self {
524 ParsedSwiftMessage::MT941(msg) => Some(*msg),
525 _ => None,
526 }
527 }
528 pub fn into_mt942(self) -> Option<SwiftMessage<messages::MT942>> {
529 match self {
530 ParsedSwiftMessage::MT942(msg) => Some(*msg),
531 _ => None,
532 }
533 }
534 pub fn into_mt950(self) -> Option<SwiftMessage<messages::MT950>> {
535 match self {
536 ParsedSwiftMessage::MT950(msg) => Some(*msg),
537 _ => None,
538 }
539 }
540 pub fn into_mt192(self) -> Option<SwiftMessage<messages::MT192>> {
541 match self {
542 ParsedSwiftMessage::MT192(msg) => Some(*msg),
543 _ => None,
544 }
545 }
546 pub fn into_mt196(self) -> Option<SwiftMessage<messages::MT196>> {
547 match self {
548 ParsedSwiftMessage::MT196(msg) => Some(*msg),
549 _ => None,
550 }
551 }
552 pub fn into_mt292(self) -> Option<SwiftMessage<messages::MT292>> {
553 match self {
554 ParsedSwiftMessage::MT292(msg) => Some(*msg),
555 _ => None,
556 }
557 }
558 pub fn into_mt296(self) -> Option<SwiftMessage<messages::MT296>> {
559 match self {
560 ParsedSwiftMessage::MT296(msg) => Some(*msg),
561 _ => None,
562 }
563 }
564}
565
566impl<T: SwiftMessageBody> SwiftMessage<T> {
567 pub fn has_reject_codes(&self) -> bool {
574 if let Some(ref user_header) = self.user_header {
576 if let Some(ref mur) = user_header.message_user_reference {
577 if mur.to_uppercase().contains("REJT") {
578 return true;
579 }
580 }
581 }
582
583 if let Some(mt103_fields) =
584 (&self.fields as &dyn Any).downcast_ref::<crate::messages::MT103>()
585 {
586 return mt103_fields.has_reject_codes();
587 } else if let Some(mt202_fields) =
588 (&self.fields as &dyn Any).downcast_ref::<crate::messages::MT202>()
589 {
590 return mt202_fields.has_reject_codes();
591 } else if let Some(mt205_fields) =
592 (&self.fields as &dyn Any).downcast_ref::<crate::messages::MT205>()
593 {
594 return mt205_fields.has_reject_codes();
595 }
596
597 false
598 }
599
600 pub fn has_return_codes(&self) -> bool {
607 if let Some(ref user_header) = self.user_header {
609 if let Some(ref mur) = user_header.message_user_reference {
610 if mur.to_uppercase().contains("RETN") {
611 return true;
612 }
613 }
614 }
615
616 if let Some(mt103_fields) =
617 (&self.fields as &dyn Any).downcast_ref::<crate::messages::MT103>()
618 {
619 return mt103_fields.has_return_codes();
620 } else if let Some(mt202_fields) =
621 (&self.fields as &dyn Any).downcast_ref::<crate::messages::MT202>()
622 {
623 return mt202_fields.has_return_codes();
624 } else if let Some(mt205_fields) =
625 (&self.fields as &dyn Any).downcast_ref::<crate::messages::MT205>()
626 {
627 return mt205_fields.has_return_codes();
628 }
629
630 false
631 }
632
633 pub fn is_cover_message(&self) -> bool {
634 if let Some(mt202_fields) =
635 (&self.fields as &dyn Any).downcast_ref::<crate::messages::MT202>()
636 {
637 return mt202_fields.is_cover_message();
638 }
639 if let Some(mt205_fields) =
640 (&self.fields as &dyn Any).downcast_ref::<crate::messages::MT205>()
641 {
642 return mt205_fields.is_cover_message();
643 }
644
645 false
646 }
647
648 pub fn is_stp_message(&self) -> bool {
649 if let Some(mt103_fields) =
650 (&self.fields as &dyn Any).downcast_ref::<crate::messages::MT103>()
651 {
652 return mt103_fields.is_stp_compliant();
653 }
654
655 false
656 }
657
658 pub fn validate_business_rules(&self) -> ValidationResult {
662 let validation_rules = match T::message_type() {
664 "101" => messages::MT101::validation_rules(),
665 "103" => messages::MT103::validation_rules(),
666 "104" => messages::MT104::validation_rules(),
667 "107" => messages::MT107::validation_rules(),
668 "110" => messages::MT110::validation_rules(),
669 "111" => messages::MT111::validation_rules(),
670 "112" => messages::MT112::validation_rules(),
671 "202" => messages::MT202::validation_rules(),
672 "205" => messages::MT205::validation_rules(),
673 "210" => messages::MT210::validation_rules(),
674 "900" => messages::MT900::validation_rules(),
675 "910" => messages::MT910::validation_rules(),
676 "920" => messages::MT920::validation_rules(),
677 "935" => messages::MT935::validation_rules(),
678 "940" => messages::MT940::validation_rules(),
679 "941" => messages::MT941::validation_rules(),
680 "942" => messages::MT942::validation_rules(),
681 "950" => messages::MT950::validation_rules(),
682 "192" => messages::MT192::validation_rules(),
683 "196" => messages::MT196::validation_rules(),
684 "292" => messages::MT292::validation_rules(),
685 "296" => messages::MT296::validation_rules(),
686 _ => {
687 return ValidationResult::with_error(ValidationError::BusinessRuleValidation {
688 rule_name: "UNSUPPORTED_MESSAGE_TYPE".to_string(),
689 message: format!(
690 "No validation rules defined for message type {}",
691 T::message_type()
692 ),
693 });
694 }
695 };
696
697 let rules_json: serde_json::Value = match serde_json::from_str(validation_rules) {
699 Ok(json) => json,
700 Err(e) => {
701 return ValidationResult::with_error(ValidationError::BusinessRuleValidation {
702 rule_name: "JSON_PARSE".to_string(),
703 message: format!("Failed to parse validation rules JSON: {e}"),
704 });
705 }
706 };
707
708 let rules = match rules_json.get("rules").and_then(|r| r.as_array()) {
710 Some(rules) => rules,
711 None => {
712 return ValidationResult::with_error(ValidationError::BusinessRuleValidation {
713 rule_name: "RULES_FORMAT".to_string(),
714 message: "Validation rules must contain a 'rules' array".to_string(),
715 });
716 }
717 };
718
719 let constants = rules_json
721 .get("constants")
722 .and_then(|c| c.as_object())
723 .cloned()
724 .unwrap_or_default();
725
726 let context_value = match self.create_validation_context(&constants) {
728 Ok(context) => context,
729 Err(e) => {
730 return ValidationResult::with_error(ValidationError::BusinessRuleValidation {
731 rule_name: "CONTEXT_CREATION".to_string(),
732 message: format!("Failed to create validation context: {e}"),
733 });
734 }
735 };
736
737 let mut errors = Vec::new();
739 let mut warnings = Vec::new();
740
741 for (rule_index, rule) in rules.iter().enumerate() {
742 let rule_id = rule
743 .get("id")
744 .and_then(|id| id.as_str())
745 .map(|s| s.to_string())
746 .unwrap_or_else(|| format!("RULE_{rule_index}"));
747
748 let rule_description = rule
749 .get("description")
750 .and_then(|desc| desc.as_str())
751 .unwrap_or("No description");
752
753 if let Some(condition) = rule.get("condition") {
754 let dl = datalogic_rs::DataLogic::new();
756 match dl.evaluate_json(condition, &context_value, None) {
757 Ok(result) => {
758 match result.as_bool() {
759 Some(true) => {
760 continue;
762 }
763 Some(false) => {
764 errors.push(ValidationError::BusinessRuleValidation {
766 rule_name: rule_id.clone(),
767 message: format!(
768 "Business rule validation failed: {rule_id} - {rule_description}"
769 ),
770 });
771 }
772 None => {
773 warnings.push(format!(
775 "Rule {rule_id} returned non-boolean value: {result:?}"
776 ));
777 }
778 }
779 }
780 Err(e) => {
781 errors.push(ValidationError::BusinessRuleValidation {
783 rule_name: rule_id.clone(),
784 message: format!("JSONLogic evaluation error for rule {rule_id}: {e}"),
785 });
786 }
787 }
788 } else {
789 warnings.push(format!("Rule {rule_id} has no condition"));
790 }
791 }
792
793 ValidationResult {
794 is_valid: errors.is_empty(),
795 errors,
796 warnings,
797 }
798 }
799
800 fn create_validation_context(
802 &self,
803 constants: &serde_json::Map<String, serde_json::Value>,
804 ) -> Result<serde_json::Value> {
805 let full_message_data = match serde_json::to_value(self) {
807 Ok(data) => data,
808 Err(e) => {
809 return Err(ParseError::SerializationError {
810 message: format!("Failed to serialize complete message: {e}"),
811 });
812 }
813 };
814
815 let mut data_context = serde_json::Map::new();
817
818 if let serde_json::Value::Object(msg_obj) = full_message_data {
820 for (key, value) in msg_obj {
821 data_context.insert(key, value);
822 }
823 }
824
825 for (key, value) in constants {
827 data_context.insert(key.clone(), value.clone());
828 }
829
830 let (sender_country, receiver_country) = self.extract_country_codes_from_bics();
832
833 data_context.insert("message_context".to_string(), serde_json::json!({
835 "message_type": self.message_type,
836 "sender_country": sender_country,
837 "receiver_country": receiver_country,
838 "sender_bic": self.basic_header.logical_terminal,
839 "receiver_bic": &self.application_header.destination_address,
840 "message_priority": &self.application_header.priority,
841 "delivery_monitoring": self.application_header.delivery_monitoring.as_ref().unwrap_or(&"3".to_string()),
842 }));
843
844 Ok(serde_json::Value::Object(data_context))
845 }
846
847 fn extract_country_codes_from_bics(&self) -> (String, String) {
849 let sender_country = if self.basic_header.logical_terminal.len() >= 6 {
851 self.basic_header.logical_terminal[4..6].to_string()
852 } else {
853 "XX".to_string() };
855
856 let receiver_country = if self.application_header.destination_address.len() >= 6 {
858 self.application_header.destination_address[4..6].to_string()
859 } else {
860 "XX".to_string()
861 };
862
863 (sender_country, receiver_country)
864 }
865
866 pub fn to_mt_message(&self) -> String {
867 let mut swift_message = String::new();
868
869 let block1 = &self.basic_header.to_string();
871 swift_message.push_str(&format!("{{1:{block1}}}\n"));
872
873 let block2 = &self.application_header.to_string();
875 swift_message.push_str(&format!("{{2:{block2}}}\n"));
876
877 if let Some(ref user_header) = self.user_header {
879 let block3 = &user_header.to_string();
880 swift_message.push_str(&format!("{{3:{block3}}}\n"));
881 }
882
883 let field_map = self.fields.to_fields();
885 let mut block4 = String::new();
886
887 let optional_fields: std::collections::HashSet<String> = T::optional_fields()
889 .into_iter()
890 .map(|s| s.to_string())
891 .collect();
892
893 for field_tag in &self.field_order {
895 if let Some(field_values) = field_map.get(field_tag) {
896 for field_value in field_values {
897 if optional_fields.contains(field_tag) && field_value.trim().is_empty() {
899 continue;
900 }
901
902 if field_value.starts_with(':') {
905 block4.push_str(&format!("\n{field_value}"));
907 } else {
908 block4.push_str(&format!("\n:{field_tag}:{field_value}"));
910 }
911 }
912 }
913 }
914
915 for (field_tag, field_values) in &field_map {
917 if !self.field_order.contains(field_tag) {
918 for field_value in field_values {
919 if optional_fields.contains(field_tag) && field_value.trim().is_empty() {
921 continue;
922 }
923
924 if field_value.starts_with(':') {
925 block4.push_str(&format!("\n{field_value}"));
926 } else {
927 block4.push_str(&format!("\n:{field_tag}:{field_value}"));
928 }
929 }
930 }
931 }
932
933 swift_message.push_str(&format!("{{4:{block4}\n-}}"));
934 swift_message.push('\n');
935
936 if let Some(ref trailer) = self.trailer {
938 let block5 = &trailer.to_string();
939 swift_message.push_str(&format!("{{5:{block5}}}\n"));
940 }
941
942 swift_message
943 }
944
945 pub fn sample() -> Self
948 where
949 T: SwiftMessageBody,
950 {
951 Self::sample_with_config(&sample::MessageConfig::default())
952 }
953
954 pub fn sample_minimal() -> Self
957 where
958 T: SwiftMessageBody,
959 {
960 let config = sample::MessageConfig {
961 scenario: Some(sample::MessageScenario::Minimal),
962 ..Default::default()
963 };
964 Self::sample_with_config(&config)
965 }
966
967 pub fn sample_full() -> Self
970 where
971 T: SwiftMessageBody,
972 {
973 let config = sample::MessageConfig {
974 scenario: Some(sample::MessageScenario::Full),
975 include_optional: true,
976 ..Default::default()
977 };
978 Self::sample_with_config(&config)
979 }
980
981 pub fn sample_with_config(config: &sample::MessageConfig) -> Self
984 where
985 T: SwiftMessageBody,
986 {
987 use rand::Rng;
988 let mut rng = rand::thread_rng();
989
990 let fields = match config.scenario {
992 Some(sample::MessageScenario::Minimal) => T::sample_minimal(),
993 Some(sample::MessageScenario::Full) => T::sample_full(),
994 _ => T::sample_with_config(config),
995 };
996
997 let basic_header = BasicHeader::sample();
999 let application_header = ApplicationHeader::sample(T::message_type());
1000
1001 let user_header = Some(UserHeader::sample_with_scenario(config.scenario.as_ref()));
1003
1004 let trailer = if config.scenario == Some(sample::MessageScenario::Full) || rng.gen_bool(0.2)
1006 {
1007 Some(Trailer::sample())
1008 } else {
1009 None
1010 };
1011
1012 let mut field_order = T::required_fields()
1014 .iter()
1015 .map(|s| s.to_string())
1016 .collect::<Vec<_>>();
1017
1018 if config.include_optional || config.scenario == Some(sample::MessageScenario::Full) {
1019 let mut optional_fields = T::optional_fields()
1020 .iter()
1021 .map(|s| s.to_string())
1022 .collect::<Vec<_>>();
1023 field_order.append(&mut optional_fields);
1024 }
1025
1026 field_order.sort_by(|a, b| {
1028 let a_num: u32 = a
1029 .chars()
1030 .take_while(|c| c.is_ascii_digit())
1031 .collect::<String>()
1032 .parse()
1033 .unwrap_or(0);
1034 let b_num: u32 = b
1035 .chars()
1036 .take_while(|c| c.is_ascii_digit())
1037 .collect::<String>()
1038 .parse()
1039 .unwrap_or(0);
1040 a_num.cmp(&b_num)
1041 });
1042
1043 SwiftMessage {
1044 basic_header,
1045 application_header,
1046 user_header,
1047 trailer,
1048 blocks: None,
1049 message_type: T::message_type().to_string(),
1050 field_order,
1051 fields,
1052 }
1053 }
1054}