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}"#;