swift_mt_message/messages/mt101.rs
1use crate::fields::*;
2use serde::{Deserialize, Serialize};
3use swift_mt_message_macros::{SwiftMessage, serde_swift_fields};
4
5/// MT101: Request for Transfer
6///
7/// ## Purpose
8/// Used to request the movement of funds from the ordering customer's account(s) serviced at the receiving financial institution.
9/// This message enables institutions and authorized parties to initiate multiple transactions in a single message with comprehensive transfer details.
10///
11/// ## Scope
12/// This message is:
13/// - Sent by financial institutions on behalf of non-financial account owners
14/// - Sent by non-financial institution account owners or authorized parties
15/// - Used for moving funds between ordering customer accounts or to third parties
16/// - Applicable for both domestic and cross-border payment requests
17/// - Compatible with bulk payment processing and corporate treasury operations
18/// - Subject to comprehensive network validation rules for transaction integrity
19///
20/// ## Key Features
21/// - **Multi-Transaction Support**: Single message can contain multiple transaction requests
22/// - **Dual Sequence Architecture**: Sequence A (general info) and Sequence B (transaction details)
23/// - **Flexible Party Specification**: Ordering customer can be specified in either sequence
24/// - **Foreign Exchange Support**: Built-in support for currency conversion instructions
25/// - **Chained Message Capability**: Support for large transaction sets across multiple messages
26/// - **Regulatory Compliance**: Includes regulatory reporting fields for compliance requirements
27///
28/// ## Common Use Cases
29/// - Corporate bulk payment processing for payroll and supplier payments
30/// - Treasury operations requiring multiple fund transfers
31/// - Cross-border payment requests with currency conversion
32/// - Inter-company fund transfers within corporate groups
33/// - Standing instruction execution for recurring payments
34/// - Cash management and liquidity optimization transfers
35/// - Trade finance settlement instructions
36///
37/// ## Message Structure
38/// ### Sequence A (General Information - Mandatory, Single)
39/// - **Field 20**: Sender's Reference (mandatory) - Unique message identifier
40/// - **Field 21R**: Customer Specified Reference (optional) - Customer reference for all transactions
41/// - **Field 28D**: Message Index/Total (mandatory) - For chained messages
42/// - **Field 50**: Instructing Party/Ordering Customer (optional) - Party initiating request
43/// - **Field 52A**: Account Servicing Institution (optional) - Institution holding accounts
44/// - **Field 51A**: Sending Institution (optional) - Institution sending the message
45/// - **Field 30**: Requested Execution Date (mandatory) - When transfers should be executed
46/// - **Field 25**: Account Identification (optional) - Account to be debited
47///
48/// ### Sequence B (Transaction Details - Mandatory, Repetitive)
49/// - **Field 21**: Transaction Reference (mandatory) - Unique transaction identifier
50/// - **Field 21F**: F/X Deal Reference (optional) - Foreign exchange deal reference
51/// - **Field 23E**: Instruction Code (optional) - Special processing instructions
52/// - **Field 32B**: Currency/Transaction Amount (mandatory) - Transfer amount and currency
53/// - **Field 50**: Ordering Customer (optional) - Customer specific to this transaction
54/// - **Field 52**: Account Servicing Institution (optional) - Institution for this transaction
55/// - **Field 56**: Intermediary Institution (optional) - Intermediary in payment chain
56/// - **Field 57**: Account With Institution (optional) - Crediting institution
57/// - **Field 59**: Beneficiary Customer (mandatory) - Final beneficiary of funds
58/// - **Field 70**: Remittance Information (optional) - Payment purpose and details
59/// - **Field 77B**: Regulatory Reporting (optional) - Compliance reporting information
60/// - **Field 33B**: Currency/Original Amount (optional) - For currency conversion
61/// - **Field 71A**: Details of Charges (mandatory) - Charge allocation instructions
62/// - **Field 25A**: Charges Account (optional) - Account for charge debiting
63/// - **Field 36**: Exchange Rate (optional) - Rate for currency conversion
64///
65/// ## Network Validation Rules
66/// - **Foreign Exchange Logic**: If field 36 present, field 21F mandatory (C1)
67/// - **Currency Conversion**: If field 33B present and amount ≠ 0, field 36 mandatory (C2)
68/// - **Party Specification**: Field 50a placement rules between sequences (C3, C4)
69/// - **Currency Consistency**: Currency in field 33B must differ from field 32B (C5)
70/// - **Institution Chain**: If field 56a present, field 57a mandatory (C7)
71/// - **Cross-Transaction**: If field 21R present, all 32B currencies must match (C8)
72/// - **Chained Messages**: All must have same sender's reference (field 20)
73///
74/// ## SRG2025 Status
75/// - **Structural Changes**: None - MT101 format remains stable
76/// - **Enhanced Validation**: Strengthened rules for cross-border transfers
77/// - **Regulatory Reporting**: Enhanced field 77B validation for compliance
78/// - **API Integration**: Improved support for modern banking APIs
79///
80/// ## Integration Considerations
81/// - **Banking Systems**: Compatible with core banking and payment processing systems
82/// - **API Integration**: RESTful API support for modern corporate banking platforms
83/// - **Processing Requirements**: Supports both real-time and batch processing modes
84/// - **Compliance Integration**: Built-in regulatory reporting and sanctions screening hooks
85///
86/// ## Relationship to Other Messages
87/// - **Triggers**: Often triggered by corporate ERP systems or treasury management platforms
88/// - **Responses**: Generates MT103 (customer credit transfer) for each transaction
89/// - **Related**: Works with MT202 for institutional settlement and MT940/MT950 for reporting
90/// - **Alternatives**: MT100 for single transfers, MT204 for direct debit instructions
91/// - **Status Updates**: May receive MT192/MT196/MT199 for status notifications
92#[serde_swift_fields]
93#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, SwiftMessage)]
94#[validation_rules(MT101_VALIDATION_RULES)]
95pub struct MT101 {
96 #[field("20")]
97 pub field_20: Field20, // Sender's Reference
98
99 #[field("21R")]
100 pub field_21r: Option<Field21R>, // Customer Specified Reference
101
102 #[field("28D")]
103 pub field_28d: Field28D, // Message Index/Total
104
105 #[field("50#1")]
106 pub field_50_instructing_party: Option<Field50InstructingParty>, // Instructing Party
107
108 #[field("50#2")]
109 pub field_50_ordering_customer: Option<Field50OrderingCustomerFGH>, // Ordering Customer
110
111 #[field("52")]
112 pub field_52a: Option<Field52AccountServicingInstitution>, // Account Servicing Institution (Seq A)
113
114 #[field("51A")]
115 pub field_51a: Option<Field51A>, // Sending Institution
116
117 #[field("30")]
118 pub field_30: Field30, // Requested Execution Date
119
120 #[field("25")]
121 pub field_25: Option<Field25NoOption>,
122
123 #[field("#")]
124 pub transactions: Vec<MT101Transaction>,
125}
126
127/// MT101 Transaction (Sequence B)
128///
129/// ## Purpose
130/// Represents a single transaction within an MT101 message. Each occurrence provides
131/// details for one individual funds transfer request.
132///
133/// ## Field Details
134/// - **21**: Transaction Reference (mandatory) - Unique reference for this transaction
135/// - **21F**: F/X Deal Reference - Required when field 36 is present (NVR C1)
136/// - **23E**: Instruction Code - Special instructions (e.g., EQUI for equivalent transfers)
137/// - **32B**: Currency/Transaction Amount - The amount to be transferred
138/// - **33B**: Currency/Original Amount - Used for currency conversions (NVR C2, C5)
139/// - **36**: Exchange Rate - Required when 33B present and amount ≠ 0 (NVR C2)
140///
141/// ## Party Chain
142/// The transaction flow follows: Instructing Party → Ordering Customer →
143/// Account Servicing Institution → Intermediary → Account With Institution → Beneficiary
144///
145/// ## Validation Notes
146/// - If 36 present, 21F must be present (C1)
147/// - If 33B present and 32B amount ≠ 0, then 36 mandatory (C2)
148/// - Currency in 33B must differ from 32B (C5)
149/// - If 56a present, 57a must be present (C7)
150#[serde_swift_fields]
151#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, SwiftMessage)]
152pub struct MT101Transaction {
153 #[field("21")]
154 pub field_21: Field21NoOption, // Transaction Reference
155
156 #[field("21F")]
157 pub field_21f: Option<Field21F>, // F/X Deal Reference
158
159 #[field("23E")]
160 pub field_23e: Option<Vec<Field23E>>, // Instruction Code
161
162 #[field("32B")]
163 pub field_32b: Field32B, // Currency/Amount
164
165 #[field("50#1")]
166 pub field_50_instructing_party: Option<Field50InstructingParty>, // Instructing Party
167
168 #[field("50#2")]
169 pub field_50_ordering_customer: Option<Field50OrderingCustomerFGH>, // Ordering Customer
170
171 #[field("52")]
172 pub field_52: Option<Field52AccountServicingInstitution>, // Account Servicing Institution
173
174 #[field("56")]
175 pub field_56: Option<Field56Intermediary>, // Intermediary
176
177 #[field("57")]
178 pub field_57: Option<Field57AccountWithInstitution>, // Account With Institution
179
180 #[field("59")]
181 pub field_59: Field59, // Beneficiary Customer
182
183 #[field("70")]
184 pub field_70: Option<Field70>, // Remittance Information
185
186 #[field("77B")]
187 pub field_77b: Option<Field77B>, // Regulatory Reporting
188
189 #[field("33B")]
190 pub field_33b: Option<Field33B>, // Currency/Original Amount
191
192 #[field("71A")]
193 pub field_71a: Field71A, // Details of Charges
194
195 #[field("25A")]
196 pub field_25a: Option<Field25A>, // Charges Account
197
198 #[field("36")]
199 pub field_36: Option<Field36>, // Exchange Rate
200}
201
202/// Comprehensive MT101 validation rules based on SRG2025 specification
203const MT101_VALIDATION_RULES: &str = r#"{
204 "rules": [
205 {
206 "id": "C1",
207 "description": "If an exchange rate is given in field 36, the corresponding forex deal must be referenced in field 21F",
208 "condition": {
209 "all": [
210 {"var": "fields.#"},
211 {
212 "if": [
213 {"exists": ["fields", "36"]},
214 {"exists": ["fields", "21F"]},
215 true
216 ]
217 }
218 ]
219 }
220 },
221 {
222 "id": "C2",
223 "description": "In each occurrence of sequence B, if field 33B is present and amount in field 32B is not equal to zero, then field 36 must be present, otherwise field 36 is not allowed",
224 "condition": {
225 "all": [
226 {"var": "fields.#"},
227 {
228 "or": [
229 {
230 "and": [
231 {"exists": ["fields", "33B", "currency"]},
232 {"!=": [{"var": "32B.amount"}, 0]},
233 {"exists": ["fields", "36", "rate"]}
234 ]
235 },
236 {
237 "and": [
238 {"exists": ["fields", "33B", "currency"]},
239 {"==": [{"var": "32B.amount"}, 0]},
240 {"!": {"exists": ["fields", "36", "rate"]}}
241 ]
242 },
243 {
244 "and": [
245 {"!": {"exists": ["fields", "33B", "currency"]}},
246 {"!": {"exists": ["fields", "36", "rate"]}}
247 ]
248 }
249 ]
250 }
251 ]
252 }
253 },
254 {
255 "id": "C3",
256 "description": "Field 50a (option F, G or H) must be present in either sequence A or in each occurrence of sequence B, but must never be present in both sequences",
257 "condition": {
258 "or": [
259 {
260 "and": [
261 {"exists": ["fields", "50#2"]},
262 {
263 "all": [
264 {"var": "fields.#"},
265 {"!": {"exists": ["fields", "50#2"]}}
266 ]
267 }
268 ]
269 },
270 {
271 "and": [
272 {"!": {"exists": ["fields", "50#2"]}},
273 {
274 "all": [
275 {"var": "fields.#"},
276 {"exists": ["fields", "50#2"]}
277 ]
278 }
279 ]
280 }
281 ]
282 }
283 },
284 {
285 "id": "C4",
286 "description": "Field 50a (option C or L) may be present in either sequence A or in one or more occurrences of sequence B, but must not be present in both sequences",
287 "condition": {
288 "if": [
289 {"exists": ["fields", "50#1"]},
290 {
291 "all": [
292 {"var": "fields.#"},
293 {"!": {"exists": ["fields", "50"]}}
294 ]
295 },
296 true
297 ]
298 }
299 },
300 {
301 "id": "C5",
302 "description": "If field 33B is present in sequence B, its currency code must be different from the currency code in field 32B",
303 "condition": {
304 "all": [
305 {"var": "fields.#"},
306 {
307 "if": [
308 {"exists": ["fields", "33B"]},
309 {"!=": [{"var": "33B.currency"}, {"var": "32B.currency"}]},
310 true
311 ]
312 }
313 ]
314 }
315 },
316 {
317 "id": "C6",
318 "description": "Field 52a may be present in either sequence A or in one or more occurrences of sequence B, but must not be present in both sequences",
319 "condition": {
320 "if": [
321 {"exists": ["fields", "52"]},
322 {
323 "all": [
324 {"var": "fields.#"},
325 {"!": {"exists": ["fields", "52"]}}
326 ]
327 },
328 true
329 ]
330 }
331 },
332 {
333 "id": "C7",
334 "description": "If field 56a is present, field 57a must also be present",
335 "condition": {
336 "all": [
337 {"var": "fields.#"},
338 {
339 "if": [
340 {"exists": ["fields", "56"]},
341 {"exists": ["fields", "57"]},
342 true
343 ]
344 }
345 ]
346 }
347 },
348 {
349 "id": "C8",
350 "description": "If field 21R is present in sequence A, then in each occurrence of sequence B, the currency code in fields 32B must be the same",
351 "condition": {
352 "if": [
353 {"exists": ["fields", "21R"]},
354 {
355 "or": [
356 {"<=": [{"var": "fields.#.length"}, 1]},
357 {
358 "all": [
359 {"var": "fields.#"},
360 {"==": [{"var": "32B.currency"}, {"var": "fields.#.0.32B.currency"}]}
361 ]
362 }
363 ]
364 },
365 true
366 ]
367 }
368 },
369 {
370 "id": "C9",
371 "description": "In each occurrence of sequence B, the presence of fields 33B and 21F is dependent on the presence and value of fields 32B and 23E",
372 "condition": {
373 "all": [
374 {"var": "fields.#"},
375 {
376 "if": [
377 {"==": [{"var": "32B.amount"}, 0]},
378 {
379 "if": [
380 {"and": [
381 {"exists": ["fields", "23E"]},
382 {
383 "some": [
384 {"var": "23E"},
385 {"==": [{"var": "instruction_code"}, "EQUI"]}
386 ]
387 }
388 ]},
389 {"exists": ["fields", "33B"]},
390 {
391 "and": [
392 {"!": {"exists": ["fields", "33B"]}},
393 {"!": {"exists": ["fields", "21F"]}}
394 ]
395 }
396 ]
397 },
398 true
399 ]
400 }
401 ]
402 }
403 },
404 {
405 "id": "REFERENCE_FORMAT",
406 "description": "Reference fields must not contain invalid patterns",
407 "condition": {
408 "and": [
409 {"!=": [{"var": "fields.20.reference"}, ""]},
410 {"!": {"in": ["//", {"var": "fields.20.reference"}]}},
411 {
412 "all": [
413 {"var": "fields.#"},
414 {
415 "and": [
416 {"!=": [{"var": "21.reference"}, ""]},
417 {"!": {"in": ["//", {"var": "21.reference"}]}}
418 ]
419 }
420 ]
421 }
422 ]
423 }
424 },
425 {
426 "id": "AMOUNT_CONSISTENCY",
427 "description": "All amounts must be properly formatted",
428 "condition": {
429 "all": [
430 {"var": "fields.#"},
431 {
432 "and": [
433 {">": [{"var": "32B.amount"}, -1]},
434 {
435 "if": [
436 {"exists": ["fields", "33B"]},
437 {">": [{"var": "33B.amount"}, -1]},
438 true
439 ]
440 }
441 ]
442 }
443 ]
444 }
445 },
446 {
447 "id": "CURRENCY_CODE_VALIDATION",
448 "description": "All currency codes must be valid ISO 4217 3-letter codes",
449 "condition": {
450 "all": [
451 {"var": "fields.#"},
452 {
453 "and": [
454 {"!=": [{"var": "32B.currency"}, ""]},
455 {
456 "if": [
457 {"exists": ["fields", "33B"]},
458 {"!=": [{"var": "33B.currency"}, ""]},
459 true
460 ]
461 }
462 ]
463 }
464 ]
465 }
466 },
467 {
468 "id": "MESSAGE_INDEX_TOTAL",
469 "description": "Message index must not exceed total",
470 "condition": {
471 "and": [
472 {"exists": ["fields", "28D"]},
473 {"<=": [{"var": "fields.28D.index"}, {"var": "fields.28D.total"}]},
474 {">": [{"var": "fields.28D.index"}, 0]},
475 {">": [{"var": "fields.28D.total"}, 0]}
476 ]
477 }
478 },
479 {
480 "id": "EXECUTION_DATE",
481 "description": "Requested execution date must be valid",
482 "condition": {
483 "and": [
484 {"exists": ["fields", "30"]},
485 {"!=": [{"var": "fields.30.execution_date"}, ""]}
486 ]
487 }
488 },
489 {
490 "id": "INSTRUCTION_CODE_VALIDATION",
491 "description": "23E instruction codes must be valid when present",
492 "condition": {
493 "all": [
494 {"var": "fields.#"},
495 {
496 "if": [
497 {"exists": ["fields", "23E"]},
498 {
499 "all": [
500 {"var": "23E"},
501 {"in": [{"var": "instruction_code"}, ["EQUI", "RTGS", "URGP", "CORT", "INTC", "SDVA"]]}
502 ]
503 },
504 true
505 ]
506 }
507 ]
508 }
509 }
510 ],
511 "constants": {
512 "VALID_CHARGE_CODES": ["OUR", "SHA", "BEN"],
513 "VALID_INSTRUCTION_CODES_MT101": ["EQUI", "RTGS", "URGP", "CORT", "INTC", "SDVA"]
514 }
515}"#;