swift_mt_message/messages/
mod.rs

1//! SWIFT MT message implementations
2
3use serde::{Deserialize, Serialize};
4
5use crate::common::{Field, MessageBlock};
6use crate::error::{MTError, Result};
7
8// Import all message types
9pub mod mt102;
10pub mod mt103;
11pub mod mt192;
12pub mod mt195;
13pub mod mt196;
14pub mod mt197;
15pub mod mt199;
16pub mod mt202;
17pub mod mt202cov;
18pub mod mt210;
19pub mod mt940;
20pub mod mt941;
21pub mod mt942;
22
23// Re-export message types
24pub use mt102::MT102;
25pub use mt103::MT103;
26pub use mt192::MT192;
27pub use mt195::MT195;
28pub use mt196::MT196;
29pub use mt197::MT197;
30pub use mt199::MT199;
31pub use mt202::MT202;
32pub use mt202cov::MT202COV;
33pub use mt210::MT210;
34pub use mt940::MT940;
35pub use mt941::MT941;
36pub use mt942::MT942;
37
38/// Main enum representing all supported MT message types
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub enum MTMessage {
41    /// MT102: Multiple Customer Credit Transfer
42    MT102(MT102),
43    /// MT103: Single Customer Credit Transfer
44    MT103(MT103),
45    /// MT192: Request for Cancellation
46    MT192(MT192),
47    /// MT195: Queries
48    MT195(MT195),
49    /// MT196: Answers
50    MT196(MT196),
51    /// MT197: Copy of a Message
52    MT197(MT197),
53    /// MT199: Free Format Message
54    MT199(MT199),
55    /// MT202: General Financial Institution Transfer
56    MT202(MT202),
57    /// MT202COV: General Financial Institution Transfer (Cover)
58    MT202COV(MT202COV),
59    /// MT210: Notice to Receive
60    MT210(MT210),
61    /// MT940: Customer Statement Message
62    MT940(MT940),
63    /// MT941: Balance Report Message
64    MT941(MT941),
65    /// MT942: Interim Transaction Report
66    MT942(MT942),
67}
68
69impl MTMessage {
70    /// Get the message type as a string
71    pub fn message_type(&self) -> &'static str {
72        match self {
73            MTMessage::MT102(_) => "102",
74            MTMessage::MT103(_) => "103",
75            MTMessage::MT192(_) => "192",
76            MTMessage::MT195(_) => "195",
77            MTMessage::MT196(_) => "196",
78            MTMessage::MT197(_) => "197",
79            MTMessage::MT199(_) => "199",
80            MTMessage::MT202(_) => "202",
81            MTMessage::MT202COV(_) => "202COV",
82            MTMessage::MT210(_) => "210",
83            MTMessage::MT940(_) => "940",
84            MTMessage::MT941(_) => "941",
85            MTMessage::MT942(_) => "942",
86        }
87    }
88
89    /// Get a field by tag from the message
90    pub fn get_field(&self, tag: &str) -> Option<&Field> {
91        match self {
92            MTMessage::MT102(msg) => msg.get_field(tag),
93            MTMessage::MT103(msg) => msg.get_field(tag),
94            MTMessage::MT192(msg) => msg.get_field(tag),
95            MTMessage::MT195(msg) => msg.get_field(tag),
96            MTMessage::MT196(msg) => msg.get_field(tag),
97            MTMessage::MT197(msg) => msg.get_field(tag),
98            MTMessage::MT199(msg) => msg.get_field(tag),
99            MTMessage::MT202(msg) => msg.get_field(tag),
100            MTMessage::MT202COV(msg) => msg.get_field(tag),
101            MTMessage::MT210(msg) => msg.get_field(tag),
102            MTMessage::MT940(msg) => msg.get_field(tag),
103            MTMessage::MT941(msg) => msg.get_field(tag),
104            MTMessage::MT942(msg) => msg.get_field(tag),
105        }
106    }
107
108    /// Get all fields with a specific tag from the message
109    pub fn get_fields(&self, tag: &str) -> Vec<&Field> {
110        match self {
111            MTMessage::MT102(msg) => msg.get_fields(tag),
112            MTMessage::MT103(msg) => msg.get_fields(tag),
113            MTMessage::MT192(msg) => msg.get_fields(tag),
114            MTMessage::MT195(msg) => msg.get_fields(tag),
115            MTMessage::MT196(msg) => msg.get_fields(tag),
116            MTMessage::MT197(msg) => msg.get_fields(tag),
117            MTMessage::MT199(msg) => msg.get_fields(tag),
118            MTMessage::MT202(msg) => msg.get_fields(tag),
119            MTMessage::MT202COV(msg) => msg.get_fields(tag),
120            MTMessage::MT210(msg) => msg.get_fields(tag),
121            MTMessage::MT940(msg) => msg.get_fields(tag),
122            MTMessage::MT941(msg) => msg.get_fields(tag),
123            MTMessage::MT942(msg) => msg.get_fields(tag),
124        }
125    }
126
127    /// Get all fields from the message
128    pub fn get_all_fields(&self) -> Vec<&Field> {
129        match self {
130            MTMessage::MT102(msg) => msg.get_all_fields(),
131            MTMessage::MT103(msg) => msg.get_all_fields(),
132            MTMessage::MT192(msg) => msg.get_all_fields(),
133            MTMessage::MT195(msg) => msg.get_all_fields(),
134            MTMessage::MT196(msg) => msg.get_all_fields(),
135            MTMessage::MT197(msg) => msg.get_all_fields(),
136            MTMessage::MT199(msg) => msg.get_all_fields(),
137            MTMessage::MT202(msg) => msg.get_all_fields(),
138            MTMessage::MT202COV(msg) => msg.get_all_fields(),
139            MTMessage::MT210(msg) => msg.get_all_fields(),
140            MTMessage::MT940(msg) => msg.get_all_fields(),
141            MTMessage::MT941(msg) => msg.get_all_fields(),
142            MTMessage::MT942(msg) => msg.get_all_fields(),
143        }
144    }
145}
146
147/// Common trait for all MT message types
148pub trait MTMessageType: Sized {
149    /// Create an MT message from parsed blocks
150    fn from_blocks(blocks: Vec<MessageBlock>) -> Result<Self>;
151
152    /// Get a field by tag
153    fn get_field(&self, tag: &str) -> Option<&Field>;
154
155    /// Get all fields with a specific tag
156    fn get_fields(&self, tag: &str) -> Vec<&Field>;
157
158    /// Get all fields
159    fn get_all_fields(&self) -> Vec<&Field>;
160
161    /// Get the text fields (from block 4)
162    fn text_fields(&self) -> &[Field];
163}
164
165/// Helper function to extract text block from message blocks
166pub fn extract_text_block(blocks: &[MessageBlock]) -> Result<Vec<Field>> {
167    for block in blocks {
168        if let MessageBlock::TextBlock { fields } = block {
169            return Ok(fields.clone());
170        }
171    }
172    Err(MTError::InvalidMessageStructure {
173        message: "No text block found in message".to_string(),
174    })
175}
176
177/// Helper function to find field by tag in a list of fields
178pub fn find_field<'a>(fields: &'a [Field], tag: &str) -> Option<&'a Field> {
179    fields.iter().find(|field| field.tag.as_str() == tag)
180}
181
182/// Helper function to find all fields with a specific tag
183pub fn find_fields<'a>(fields: &'a [Field], tag: &str) -> Vec<&'a Field> {
184    fields
185        .iter()
186        .filter(|field| field.tag.as_str() == tag)
187        .collect()
188}
189
190/// Helper function to get required field value
191pub fn get_required_field_value(fields: &[Field], tag: &str) -> Result<String> {
192    find_field(fields, tag)
193        .map(|field| field.value().to_string())
194        .ok_or_else(|| MTError::missing_required_field(tag))
195}
196
197/// Helper function to get optional field value
198pub fn get_optional_field_value(fields: &[Field], tag: &str) -> Option<String> {
199    find_field(fields, tag).map(|field| field.value().to_string())
200}