swift_mt_message/messages/mt940.rs
1use crate::fields::*;
2use serde::{Deserialize, Serialize};
3use swift_mt_message_macros::{SwiftMessage, serde_swift_fields};
4
5/// # MT940: Customer Statement Message
6///
7/// This message is used by financial institutions to send customer account statements
8/// containing transaction details and balance information. This message provides
9/// a detailed view of account activity over a specific period.
10///
11/// ## Key Features
12/// - **Account statements**: Detailed transaction history for customer accounts
13/// - **Balance information**: Opening and closing balance details
14/// - **Transaction details**: Individual transaction lines with narrative
15/// - **Multi-part statements**: Support for statement sequencing
16/// - **Available balance**: Optional closing available balance reporting
17/// - **Reconciliation support**: Comprehensive data for account reconciliation
18///
19/// ## Field Structure
20/// All fields follow the enhanced macro system with proper validation rules.
21/// The message supports repetitive statement lines for multiple transactions.
22///
23/// ## Business Rules
24/// - Opening balance (60F) and closing balance (62F) must be in consistent currency
25/// - Each Field 61 (transaction line) may be followed by optional Field 86
26/// - Balances use comma as decimal separator
27/// - Statement supports multi-part statements via Field 28C
28#[serde_swift_fields]
29#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, SwiftMessage)]
30#[validation_rules(MT940_VALIDATION_RULES)]
31pub struct MT940 {
32 /// **Transaction Reference Number** - Field 20
33 ///
34 /// Unique ID for this statement, no leading/trailing slashes.
35 /// Used for tracking and referencing this specific statement.
36 #[field("20", mandatory)]
37 pub field_20: GenericReferenceField,
38
39 /// **Related Reference** - Field 21 (Optional)
40 ///
41 /// Links to MT920 if applicable.
42 /// Provides connection to statement request that triggered this response.
43 #[field("21", optional)]
44 pub field_21: Option<GenericReferenceField>,
45
46 /// **Account Identification** - Field 25
47 ///
48 /// IBAN or account identifier, BIC optional.
49 /// Identifies the account for which this statement is provided.
50 #[field("25", mandatory)]
51 pub field_25: GenericTextField,
52
53 /// **Statement/Sequence Number** - Field 28C
54 ///
55 /// Statement and sub-sequence numbers for multi-part statements.
56 /// Enables tracking of statement parts and sequencing.
57 #[field("28C", mandatory)]
58 pub field_28c: Field28C,
59
60 /// **Opening Balance** - Field 60F
61 ///
62 /// Booked opening balance at start of statement period.
63 /// Must be consistent with currency used in closing balance.
64 #[field("60F", mandatory)]
65 pub field_60f: GenericBalanceField,
66
67 /// **Statement Lines** (Repetitive)
68 ///
69 /// Transaction lines with optional accompanying Field 86.
70 /// Each statement line represents one transaction with optional narrative.
71 #[field("STATEMENT_LINES", repetitive)]
72 pub statement_lines: Vec<MT940StatementLine>,
73
74 /// **Closing Balance** - Field 62F
75 ///
76 /// Booked closing balance at end of statement period.
77 /// Must be consistent with currency used in opening balance.
78 #[field("62F", mandatory)]
79 pub field_62f: GenericBalanceField,
80
81 /// **Closing Available Balance** - Field 64 (Optional)
82 ///
83 /// Cash availability balance showing funds available for use.
84 /// Provides additional liquidity information beyond booked balance.
85 #[field("64", optional)]
86 pub field_64: Option<GenericBalanceField>,
87
88 /// **Forward Available Balance** - Field 65 (Optional)
89 ///
90 /// Value-dated available funds for future periods.
91 /// Shows expected available balance considering future value dates.
92 #[field("65", optional)]
93 pub field_65: Option<GenericBalanceField>,
94}
95
96/// # MT940 Statement Line
97///
98/// Represents a single transaction line (Field 61) with optional
99/// accompanying information (Field 86).
100/// Enhanced with SwiftMessage derive for automatic parsing and validation.
101#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, SwiftMessage)]
102#[validation_rules(MT940_STATEMENT_LINE_VALIDATION_RULES)]
103pub struct MT940StatementLine {
104 /// **Statement Line** - Field 61
105 ///
106 /// Transaction details including value date, amount, and transaction type.
107 /// Contains the core transaction information.
108 #[field("61", mandatory)]
109 pub field_61: Field61,
110
111 /// **Info to Account Owner** - Field 86 (Optional)
112 ///
113 /// Narrative details for the transaction.
114 /// Provides additional context and description for the transaction.
115 #[field("86", optional)]
116 pub field_86: Option<GenericMultiLineTextField<6, 65>>,
117}
118
119/// Enhanced validation rules for MT940
120const MT940_VALIDATION_RULES: &str = r#"{
121 "rules": [
122 {
123 "id": "CURRENCY_CONSISTENCY",
124 "description": "Opening and closing balances must have consistent currency",
125 "condition": {
126 "==": [
127 {"var": "field_60f.currency"},
128 {"var": "field_62f.currency"}
129 ]
130 }
131 },
132 {
133 "id": "REF_FORMAT",
134 "description": "Transaction reference must not have invalid slash patterns",
135 "condition": {
136 "and": [
137 {"!": {"startsWith": [{"var": "field_20.value"}, "/"]}},
138 {"!": {"endsWith": [{"var": "field_20.value"}, "/"]}},
139 {"!": {"includes": [{"var": "field_20.value"}, "//"]}}
140 ]
141 }
142 },
143 {
144 "id": "REQUIRED_FIELDS",
145 "description": "All mandatory fields must be present and non-empty",
146 "condition": {
147 "and": [
148 {"!=": [{"var": "field_20.value"}, ""]},
149 {"!=": [{"var": "field_25.value"}, ""]},
150 {"var": "field_28c.is_valid"},
151 {"var": "field_60f.is_valid"},
152 {"var": "field_62f.is_valid"}
153 ]
154 }
155 }
156 ]
157}"#;
158
159/// Validation rules specific to MT940 statement lines
160const MT940_STATEMENT_LINE_VALIDATION_RULES: &str = r#"{
161 "rules": [
162 {
163 "id": "STATEMENT_LINE_VALID",
164 "description": "Statement line must be valid",
165 "condition": {
166 "var": "field_61.is_valid"
167 }
168 }
169 ]
170}"#;