swift_mt_message/messages/
mt950.rs

1use crate::fields::*;
2use serde::{Deserialize, Serialize};
3use swift_mt_message_macros::{SwiftMessage, serde_swift_fields};
4
5/// # MT950: Statement Message
6///
7/// This message is used by financial institutions to send account statements
8/// to correspondent banks or financial institutions for nostro account management.
9/// Unlike MT940 which is used for customer statements, MT950 is specifically
10/// designed for inter-bank statement reporting and nostro account reconciliation.
11///
12/// ## Key Features
13/// - **Nostro account statements**: Inter-bank account statement reporting
14/// - **Correspondent banking**: Statement exchange between financial institutions
15/// - **Account reconciliation**: Detailed transaction history for reconciliation
16/// - **Multi-currency support**: Statement reporting in various currencies
17/// - **Transaction details**: Complete transaction information with narrative
18/// - **Balance tracking**: Opening and closing balance information
19///
20/// ## Field Structure
21/// All fields follow the enhanced macro system with proper validation rules.
22/// The message supports repetitive statement lines for multiple transactions.
23///
24/// ## Business Rules
25/// - All balance fields must use the same currency
26/// - Each transaction line (Field 61) may have accompanying narrative (Field 86)
27/// - Statement supports multi-part statements via Field 28C
28/// - Balances use comma as decimal separator
29#[serde_swift_fields]
30#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, SwiftMessage)]
31#[validation_rules(MT950_VALIDATION_RULES)]
32pub struct MT950 {
33    /// **Transaction Reference Number** - Field 20
34    ///
35    /// Unique reference for this statement message.
36    /// Used for tracking and referencing this specific statement.
37    #[field("20", mandatory)]
38    pub field_20: GenericReferenceField,
39
40    /// **Related Reference** - Field 21 (Optional)
41    ///
42    /// Links to MT920 request if applicable.
43    /// Provides connection to statement request that triggered this response.
44    #[field("21", optional)]
45    pub field_21: Option<GenericReferenceField>,
46
47    /// **Account Identification** - Field 25
48    ///
49    /// IBAN or nostro account identifier.
50    /// Identifies the correspondent account for which statement is provided.
51    #[field("25", mandatory)]
52    pub field_25: GenericTextField,
53
54    /// **Statement/Sequence Number** - Field 28C
55    ///
56    /// Statement sequence number and optional page number.
57    /// Enables proper sequencing of multi-part statements.
58    #[field("28C", mandatory)]
59    pub field_28c: Field28C,
60
61    /// **Opening Balance** - Field 60F or 60M
62    ///
63    /// Opening balance at start of statement period.
64    /// May be booked (60F) or interim (60M) balance.
65    #[field("60", mandatory)]
66    pub field_60: GenericBalanceField,
67
68    /// **Statement Lines** (Repetitive)
69    ///
70    /// Transaction lines with optional accompanying narrative.
71    /// Each line represents one transaction with optional Field 86.
72    #[field("STATEMENT_LINES", repetitive)]
73    pub statement_lines: Vec<MT950StatementLine>,
74
75    /// **Closing Balance** - Field 62F or 62M
76    ///
77    /// Closing balance at end of statement period.
78    /// May be booked (62F) or interim (62M) balance.
79    #[field("62", mandatory)]
80    pub field_62: GenericBalanceField,
81
82    /// **Closing Available Balance** - Field 64 (Optional)
83    ///
84    /// Available funds at close of statement period.
85    /// Shows actual spendable balance for the nostro account.
86    #[field("64", optional)]
87    pub field_64: Option<GenericBalanceField>,
88
89    /// **Forward Available Balance** - Field 65 (Optional)
90    ///
91    /// Value-dated available balance for future periods.
92    /// Shows projected available funds considering pending transactions.
93    #[field("65", optional)]
94    pub field_65: Option<GenericBalanceField>,
95}
96
97/// # MT950 Statement Line
98///
99/// Represents a single transaction line (Field 61) with optional
100/// accompanying information (Field 86) for nostro account statements.
101/// Enhanced with SwiftMessage derive for automatic parsing and validation.
102#[serde_swift_fields]
103#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, SwiftMessage)]
104#[validation_rules(MT950_STATEMENT_LINE_VALIDATION_RULES)]
105pub struct MT950StatementLine {
106    /// **Statement Line** - Field 61
107    ///
108    /// Transaction details including value date, amount, and transaction type.
109    /// Contains the core transaction information for nostro account activity.
110    #[field("61", mandatory)]
111    pub field_61: Field61,
112
113    /// **Info to Account Owner** - Field 86 (Optional)
114    ///
115    /// Narrative details for the transaction.
116    /// Provides additional context and description for nostro transactions.
117    #[field("86", optional)]
118    pub field_86: Option<GenericMultiLineTextField<6, 65>>,
119}
120
121/// Enhanced validation rules for MT950
122const MT950_VALIDATION_RULES: &str = r#"{
123  "rules": [
124    {
125      "id": "CURRENCY_CONSISTENCY",
126      "description": "Opening and closing balances must have consistent currency",
127      "condition": {
128        "==": [
129          {"var": "field_60.currency"},
130          {"var": "field_62.currency"}
131        ]
132      }
133    },
134    {
135      "id": "AVAILABLE_BALANCE_CURRENCY",
136      "description": "Available balances must use same currency as main balances",
137      "condition": {
138        "and": [
139          {
140            "if": [
141              {"var": "field_64.is_some"},
142              {"==": [
143                {"var": "field_60.currency"},
144                {"var": "field_64.currency"}
145              ]},
146              true
147            ]
148          },
149          {
150            "if": [
151              {"var": "field_65.is_some"},
152              {"==": [
153                {"var": "field_60.currency"},
154                {"var": "field_65.currency"}
155              ]},
156              true
157            ]
158          }
159        ]
160      }
161    },
162    {
163      "id": "REF_FORMAT",
164      "description": "Transaction reference must not have invalid slash patterns",
165      "condition": {
166        "and": [
167          {"!": {"startsWith": [{"var": "field_20.value"}, "/"]}},
168          {"!": {"endsWith": [{"var": "field_20.value"}, "/"]}},
169          {"!": {"includes": [{"var": "field_20.value"}, "//"]}}
170        ]
171      }
172    },
173    {
174      "id": "REQUIRED_FIELDS",
175      "description": "All mandatory fields must be present and non-empty",
176      "condition": {
177        "and": [
178          {"!=": [{"var": "field_20.value"}, ""]},
179          {"!=": [{"var": "field_25.value"}, ""]},
180          {"var": "field_28c.is_valid"},
181          {"var": "field_60.is_valid"},
182          {"var": "field_62.is_valid"}
183        ]
184      }
185    }
186  ]
187}"#;
188
189/// Validation rules specific to MT950 statement lines
190const MT950_STATEMENT_LINE_VALIDATION_RULES: &str = r#"{
191  "rules": [
192    {
193      "id": "STATEMENT_LINE_VALID",
194      "description": "Statement line must be valid",
195      "condition": {
196        "var": "field_61.is_valid"
197      }
198    }
199  ]
200}"#;