swift_mt_message/messages/mt107.rs
1use crate::fields::*;
2use serde::{Deserialize, Serialize};
3use swift_mt_message_macros::{SwiftMessage, serde_swift_fields};
4
5/// MT107: General Direct Debit Message
6///
7/// ## Purpose
8/// Used for general direct debit instructions where a creditor requests the debit of multiple debtor accounts.
9/// This message provides more flexibility than MT104 for complex direct debit scenarios with enhanced authorization
10/// control and flexible party identification options.
11///
12/// ## Scope
13/// This message is:
14/// - Used for general direct debit processing between financial institutions
15/// - Applicable for bulk direct debit operations with flexible authorization control
16/// - Designed for complex direct debit scenarios requiring detailed transaction control
17/// - Compatible with both domestic and cross-border direct debit schemes
18/// - Subject to authorization validation rules for debtor consent management
19/// - Integrated with return processing mechanisms for failed direct debits
20///
21/// ## Key Features
22/// - **Enhanced Flexibility**: More sophisticated than MT104 for complex direct debit scenarios
23/// - **Authorization Management**: Field 23E supports AUTH/NAUT/OTHR authorization status codes
24/// - **Party Identification Options**: Instructing party can appear in Sequence A or individual transactions
25/// - **Return Processing Support**: Special handling for returned direct debits with RTND codes
26/// - **Settlement Consolidation**: Optional settlement sequence for consolidated settlement details
27/// - **Multi-Transaction Support**: Supports multiple debtor accounts in single message
28///
29/// ## Common Use Cases
30/// - Corporate direct debit collections for subscription services and utilities
31/// - Bulk salary and pension direct debit processing
32/// - Recurring payment collections for insurance and loan payments
33/// - Cross-border direct debit schemes for international service providers
34/// - Return processing for previously failed direct debit attempts
35/// - Multi-party direct debit scenarios with complex authorization requirements
36/// - Government tax and fee collection via direct debit
37///
38/// ## Message Structure
39/// ### Sequence A (General Information)
40/// - **Field 20**: Transaction Reference (mandatory) - Unique message identifier
41/// - **Field 23E**: Instruction Code (optional) - Authorization status (AUTH/NAUT/OTHR/RTND)
42/// - **Field 21E**: Related Reference (optional) - Reference to related message
43/// - **Field 30**: Execution Date (mandatory) - Date for direct debit execution
44/// - **Field 51A**: Sending Institution (optional) - Institution sending the message
45/// - **Field 50**: Instructing Party/Creditor (optional) - Party requesting direct debits
46/// - **Field 52**: Creditor Bank (optional) - Bank of the creditor
47/// - **Field 26T**: Transaction Type Code (optional) - Classification of direct debit type
48/// - **Field 77B**: Regulatory Reporting (optional) - Compliance reporting information
49/// - **Field 71A**: Details of Charges (optional) - Charge allocation instructions
50/// - **Field 72**: Sender to Receiver Information (optional) - Additional processing instructions
51///
52/// ### Sequence B (Transaction Details - Repetitive)
53/// - **Field 21**: Transaction Reference (mandatory) - Unique reference for each direct debit
54/// - **Field 32B**: Currency/Amount (mandatory) - Amount to be debited from each account
55/// - **Field 59**: Debtor (mandatory) - Account and details of party being debited
56/// - **Field 23E**: Instruction Code (optional) - Transaction-level authorization status
57/// - **Field 50**: Instructing Party/Creditor (optional) - Transaction-level party identification
58/// - **Field 57**: Debtor Bank (optional) - Bank holding the debtor account
59/// - **Field 70**: Remittance Information (optional) - Purpose and details of direct debit
60/// - **Field 33B/36**: Currency conversion fields for cross-currency direct debits
61///
62/// ### Sequence C (Settlement Information - Optional)
63/// - **Field 32B**: Settlement Amount (optional) - Total settlement amount
64/// - **Field 19**: Sum of Amounts (optional) - Control total for validation
65/// - **Field 71F/71G**: Charges (optional) - Settlement charges information
66/// - **Field 53**: Sender's Correspondent (optional) - Settlement correspondent
67///
68/// ## Network Validation Rules
69/// - **Authorization Consistency**: If 23E is AUTH/NAUT/OTHR in Sequence A, same restriction applies to Sequence B
70/// - **Party Identification**: Instructing party must appear in exactly one sequence (A or B per transaction)
71/// - **Return Processing**: Field 72 required when 23E = RTND for returned direct debit details
72/// - **Currency Conversion**: Exchange rate (36) required when 33B currency differs from 32B
73/// - **Transaction Limits**: Maximum transaction count per message enforced
74/// - **Reference Validation**: All transaction references must be unique within message
75/// - **Authorization Validation**: Authorization codes must be consistent with regulatory requirements
76///
77/// ## SRG2025 Status
78/// - **Structural Changes**: None - MT107 format remains stable
79/// - **Validation Updates**: Enhanced authorization validation for regulatory compliance
80/// - **Processing Improvements**: Improved handling of return processing scenarios
81/// - **Compliance Notes**: Strengthened regulatory reporting requirements for cross-border transactions
82///
83/// ## Integration Considerations
84/// - **Banking Systems**: Compatible with direct debit processing engines and mandate management systems
85/// - **API Integration**: RESTful API support for modern direct debit collection platforms
86/// - **Processing Requirements**: Supports batch processing with individual transaction validation
87/// - **Compliance Integration**: Built-in mandate validation and regulatory reporting capabilities
88///
89/// ## Relationship to Other Messages
90/// - **Triggers**: Often triggered by direct debit collection schedules or mandate execution systems
91/// - **Responses**: May generate MT900/MT910 (confirmations) or status notification messages
92/// - **Related**: Works with MT104 (simplified direct debits) and account reporting messages
93/// - **Alternatives**: MT104 for simpler direct debit scenarios without complex authorization
94/// - **Status Updates**: May receive return or reject messages for failed direct debit attempts
95#[serde_swift_fields]
96#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, SwiftMessage)]
97#[validation_rules(MT107_VALIDATION_RULES)]
98pub struct MT107 {
99 #[field("20")]
100 pub field_20: Field20,
101
102 #[field("23E")]
103 pub field_23e: Option<Field23E>,
104
105 #[field("21E")]
106 pub field_21e: Option<Field21E>,
107
108 #[field("30")]
109 pub field_30: Field30,
110
111 #[field("51A")]
112 pub field_51a: Option<Field51A>,
113
114 #[field("50#1")]
115 pub field_50_instructing: Option<Field50InstructingParty>,
116
117 #[field("50#2")]
118 pub field_50_creditor: Option<Field50Creditor>,
119
120 #[field("52")]
121 pub field_52: Option<Field52CreditorBank>,
122
123 #[field("26T")]
124 pub field_26t: Option<Field26T>,
125
126 #[field("77B")]
127 pub field_77b: Option<Field77B>,
128
129 #[field("71A")]
130 pub field_71a: Option<Field71A>,
131
132 #[field("72")]
133 pub field_72: Option<Field72>,
134
135 #[field("#")]
136 pub transactions: Vec<MT107Transaction>,
137
138 #[field("32B")]
139 pub field_32b: Option<Field32B>,
140
141 #[field("19")]
142 pub field_19: Option<Field19>,
143
144 #[field("71F")]
145 pub field_71f: Option<Field71F>,
146
147 #[field("71G")]
148 pub field_71g: Option<Field71G>,
149
150 #[field("53")]
151 pub field_53: Option<Field53SenderCorrespondent>,
152}
153
154/// MT107 Transaction (Sequence B)
155///
156/// ## Purpose
157/// Represents a single direct debit transaction within an MT107 message. Each occurrence
158/// provides details for one direct debit request with flexible authorization and processing
159/// options.
160///
161/// ## Field Details
162/// - **21**: Transaction Reference (mandatory) - Unique reference for this direct debit
163/// - **32B**: Currency/Transaction Amount (mandatory) - Amount to be debited
164/// - **59**: Debtor (mandatory) - Account and details of party being debited
165/// - **23E**: Instruction Code - Authorization status (AUTH/NAUT/OTHR) or processing instructions
166/// - **21C/21D/21E**: Various reference fields for transaction linking
167/// - **50**: Instructing Party/Creditor - Can be at transaction level if not in Sequence A
168/// - **33B/36**: Currency conversion fields when amounts differ
169///
170/// ## Authorization Types (23E)
171/// - **AUTH**: Authorized direct debit - pre-authorized by debtor
172/// - **NAUT**: Non-authorized direct debit - requires special handling
173/// - **OTHR**: Other processing instruction - specific business rules apply
174/// - **RTND**: Returned direct debit - previously failed transaction
175///
176/// ## Validation Notes
177/// - Transaction reference (21) must be unique within the message
178/// - If 33B present and amount differs from 32B, exchange rate (36) required
179/// - Authorization status in 23E must be consistent with Sequence A if specified there
180#[serde_swift_fields]
181#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, SwiftMessage)]
182pub struct MT107Transaction {
183 #[field("21")]
184 pub field_21: Field21NoOption,
185
186 #[field("23E")]
187 pub field_23e: Option<Field23E>,
188
189 #[field("21C")]
190 pub field_21c: Option<Field21C>,
191
192 #[field("21D")]
193 pub field_21d: Option<Field21D>,
194
195 #[field("21E")]
196 pub field_21e: Option<Field21E>,
197
198 #[field("32B")]
199 pub field_32b: Field32B,
200
201 #[field("50#1")]
202 pub field_50_instructing: Option<Field50InstructingParty>,
203
204 #[field("50#2")]
205 pub field_50_creditor: Option<Field50Creditor>,
206
207 #[field("52")]
208 pub field_52: Option<Field52CreditorBank>,
209
210 #[field("57")]
211 pub field_57: Option<Field57DebtorBank>,
212
213 #[field("59")]
214 pub field_59: Field59,
215
216 #[field("70")]
217 pub field_70: Option<Field70>,
218
219 #[field("26T")]
220 pub field_26t: Option<Field26T>,
221
222 #[field("77B")]
223 pub field_77b: Option<Field77B>,
224
225 #[field("33B")]
226 pub field_33b: Option<Field33B>,
227
228 #[field("71A")]
229 pub field_71a: Option<Field71A>,
230
231 #[field("71F")]
232 pub field_71f: Option<Field71F>,
233
234 #[field("71G")]
235 pub field_71g: Option<Field71G>,
236
237 #[field("36")]
238 pub field_36: Option<Field36>,
239}
240
241/// Enhanced validation rules with forEach support for repetitive sequences
242const MT107_VALIDATION_RULES: &str = r#"{
243 "rules": [
244 {
245 "id": "C1",
246 "description": "Field 23E and field 50a (option A or K) must appear in Sequence A OR each Sequence B, not both",
247 "condition": {
248 "and": [
249 {
250 "if": [
251 {"exists": ["fields", "23E"]},
252 {
253 "all": [
254 {"var": "fields.#"},
255 {"!": {"exists": ["fields", "23E"]}}
256 ]
257 },
258 true
259 ]
260 },
261 {
262 "if": [
263 {"exists": ["fields", "50#2"]},
264 {
265 "all": [
266 {"var": "fields.#"},
267 {"!": {"exists": ["fields", "50#2"]}}
268 ]
269 },
270 true
271 ]
272 }
273 ]
274 }
275 },
276 {
277 "id": "C2",
278 "description": "Fields 21E, 26T, 77B, 71A, 52a, 50a (option C/L) must appear only in Sequence A or Sequence B, not both",
279 "condition": {
280 "and": [
281 {
282 "if": [
283 {"exists": ["fields", "21E"]},
284 {"all": [{"var": "fields.#"}, {"!": {"exists": ["fields", "21E"]}}]},
285 true
286 ]
287 },
288 {
289 "if": [
290 {"exists": ["fields", "26T"]},
291 {"all": [{"var": "fields.#"}, {"!": {"exists": ["fields", "26T"]}}]},
292 true
293 ]
294 },
295 {
296 "if": [
297 {"exists": ["fields", "77B"]},
298 {"all": [{"var": "fields.#"}, {"!": {"exists": ["fields", "77B"]}}]},
299 true
300 ]
301 },
302 {
303 "if": [
304 {"exists": ["fields", "71A"]},
305 {"all": [{"var": "fields.#"}, {"!": {"exists": ["fields", "71A"]}}]},
306 true
307 ]
308 },
309 {
310 "if": [
311 {"exists": ["fields", "52"]},
312 {"all": [{"var": "fields.#"}, {"!": {"exists": ["fields", "52"]}}]},
313 true
314 ]
315 },
316 {
317 "if": [
318 {"exists": ["fields", "50#1"]},
319 {"all": [{"var": "fields.#"}, {"!": {"exists": ["fields", "50#1"]}}]},
320 true
321 ]
322 }
323 ]
324 }
325 },
326 {
327 "id": "C3",
328 "description": "If 21E is present, then 50a (option A/K) must also be present in the same sequence",
329 "condition": {
330 "and": [
331 {
332 "if": [
333 {"exists": ["fields", "21E"]},
334 {"exists": ["fields", "50#2"]},
335 true
336 ]
337 },
338 {
339 "all": [
340 {"var": "fields.#"},
341 {
342 "if": [
343 {"exists": ["fields", "21E"]},
344 {"exists": ["fields", "50#2"]},
345 true
346 ]
347 }
348 ]
349 }
350 ]
351 }
352 },
353 {
354 "id": "C4",
355 "description": "If 23E = RTND in Sequence A, Field 72 is mandatory; otherwise, 72 is not allowed",
356 "condition": {
357 "if": [
358 {"and": [
359 {"exists": ["fields", "23E"]},
360 {"==": [{"var": "fields.23E.instruction_code"}, "RTND"]}
361 ]},
362 {"exists": ["fields", "72"]},
363 {"!": {"exists": ["fields", "72"]}}
364 ]
365 }
366 },
367 {
368 "id": "C5",
369 "description": "If 71F or 71G present in any B, must also be in Sequence C, and vice versa",
370 "condition": {
371 "and": [
372 {
373 "if": [
374 {"some": [{"var": "fields.#"}, {"exists": ["fields", "71F"]}]},
375 {"exists": ["fields", "71F"]},
376 true
377 ]
378 },
379 {
380 "if": [
381 {"some": [{"var": "fields.#"}, {"exists": ["fields", "71G"]}]},
382 {"exists": ["fields", "71G"]},
383 true
384 ]
385 },
386 {
387 "if": [
388 {"exists": ["fields", "71F"]},
389 {"some": [{"var": "fields.#"}, {"exists": ["fields", "71F"]}]},
390 true
391 ]
392 },
393 {
394 "if": [
395 {"exists": ["fields", "71G"]},
396 {"some": [{"var": "fields.#"}, {"exists": ["fields", "71G"]}]},
397 true
398 ]
399 }
400 ]
401 }
402 },
403 {
404 "id": "C6",
405 "description": "If 33B is present in Sequence B, must differ in either currency or amount from 32B",
406 "condition": {
407 "all": [
408 {"var": "fields.#"},
409 {
410 "if": [
411 {"exists": ["fields", "33B"]},
412 {
413 "or": [
414 {"!=": [{"var": "33B.currency"}, {"var": "32B.currency"}]},
415 {"!=": [{"var": "33B.amount"}, {"var": "32B.amount"}]}
416 ]
417 },
418 true
419 ]
420 }
421 ]
422 }
423 },
424 {
425 "id": "C7",
426 "description": "If 33B and 32B currency differs, then 36 (Exchange Rate) is mandatory; otherwise, 36 must not be present",
427 "condition": {
428 "all": [
429 {"var": "fields.#"},
430 {
431 "if": [
432 {"exists": ["fields", "33B"]},
433 {
434 "if": [
435 {"!=": [{"var": "33B.currency"}, {"var": "32B.currency"}]},
436 {"exists": ["fields", "36"]},
437 {"!": {"exists": ["fields", "36"]}}
438 ]
439 },
440 true
441 ]
442 }
443 ]
444 }
445 },
446 {
447 "id": "C8",
448 "description": "The sum of 32B amounts in B must appear either in C/32B (no charges) or in C/19 (with charges)",
449 "condition": {
450 "or": [
451 {
452 "and": [
453 {"exists": ["fields", "32B"]},
454 {"!": {"exists": ["fields", "19"]}},
455 {
456 "==": [
457 {"var": "fields.32B.amount"},
458 {
459 "reduce": [
460 {"var": "fields.#"},
461 {"+": [{"var": "accumulator"}, {"var": "current.32B.amount"}]},
462 0
463 ]
464 }
465 ]
466 }
467 ]
468 },
469 {
470 "and": [
471 {"exists": ["fields", "19"]},
472 {"!": {"exists": ["fields", "32B"]}},
473 {
474 "==": [
475 {"var": "fields.19.amount"},
476 {
477 "reduce": [
478 {"var": "fields.#"},
479 {"+": [{"var": "accumulator"}, {"var": "current.32B.amount"}]},
480 0
481 ]
482 }
483 ]
484 }
485 ]
486 },
487 {
488 "and": [
489 {"!": {"exists": ["fields", "32B"]}},
490 {"!": {"exists": ["fields", "19"]}}
491 ]
492 }
493 ]
494 }
495 },
496 {
497 "id": "C9",
498 "description": "Currency must be consistent across all instances of 32B, 71F, 71G in B and C",
499 "condition": {
500 "and": [
501 {
502 "if": [
503 {"and": [{"exists": ["fields", "32B"]}, {">=": [{"length": {"var": "fields.#"}}, 1]}]},
504 {
505 "all": [
506 {"var": "fields.#"},
507 {"==": [{"var": "32B.currency"}, {"var": "fields.#.0.32B.currency"}]}
508 ]
509 },
510 true
511 ]
512 },
513 {
514 "if": [
515 {"and": [{"exists": ["fields", "71F"]}, {"some": [{"var": "fields.#"}, {"exists": ["fields", "71F"]}]}]},
516 {
517 "all": [
518 {"var": "fields.#"},
519 {
520 "if": [
521 {"exists": ["fields", "71F"]},
522 {"==": [{"var": "71F.currency"}, {"var": "fields.71F.currency"}]},
523 true
524 ]
525 }
526 ]
527 },
528 true
529 ]
530 },
531 {
532 "if": [
533 {"and": [{"exists": ["fields", "71G"]}, {"some": [{"var": "fields.#"}, {"exists": ["fields", "71G"]}]}]},
534 {
535 "all": [
536 {"var": "fields.#"},
537 {
538 "if": [
539 {"exists": ["fields", "71G"]},
540 {"==": [{"var": "71G.currency"}, {"var": "fields.71G.currency"}]},
541 true
542 ]
543 }
544 ]
545 },
546 true
547 ]
548 }
549 ]
550 }
551 },
552 {
553 "id": "TXN_MIN",
554 "description": "At least one transaction required",
555 "condition": {
556 ">=": [{"length": {"var": "fields.#"}}, 1]
557 }
558 },
559 {
560 "id": "REFERENCE_FORMAT",
561 "description": "Reference fields must not contain invalid patterns",
562 "condition": {
563 "and": [
564 {"!=": [{"var": "fields.20.reference"}, ""]},
565 {"!": {"in": ["//", {"var": "fields.20.reference"}]}},
566 {
567 "all": [
568 {"var": "fields.#"},
569 {
570 "and": [
571 {"!=": [{"var": "21.reference"}, ""]},
572 {"!": {"in": ["//", {"var": "21.reference"}]}}
573 ]
574 }
575 ]
576 }
577 ]
578 }
579 },
580 {
581 "id": "CURRENCY_CODE_VALIDATION",
582 "description": "All currency codes must be valid ISO 4217 3-letter codes",
583 "condition": {
584 "and": [
585 {
586 "all": [
587 {"var": "fields.#"},
588 {
589 "and": [
590 {"!=": [{"var": "32B.currency"}, ""]},
591 {
592 "if": [
593 {"exists": ["fields", "33B"]},
594 {"!=": [{"var": "33B.currency"}, ""]},
595 true
596 ]
597 },
598 {
599 "if": [
600 {"exists": ["fields", "71F"]},
601 {"!=": [{"var": "71F.currency"}, ""]},
602 true
603 ]
604 },
605 {
606 "if": [
607 {"exists": ["fields", "71G"]},
608 {"!=": [{"var": "71G.currency"}, ""]},
609 true
610 ]
611 }
612 ]
613 }
614 ]
615 },
616 {
617 "if": [
618 {"exists": ["fields", "32B"]},
619 {"!=": [{"var": "fields.32B.currency"}, ""]},
620 true
621 ]
622 },
623 {
624 "if": [
625 {"exists": ["fields", "71F"]},
626 {"!=": [{"var": "fields.71F.currency"}, ""]},
627 true
628 ]
629 },
630 {
631 "if": [
632 {"exists": ["fields", "71G"]},
633 {"!=": [{"var": "fields.71G.currency"}, ""]},
634 true
635 ]
636 }
637 ]
638 }
639 },
640 {
641 "id": "AMOUNT_CONSISTENCY",
642 "description": "All amounts must be properly formatted",
643 "condition": {
644 "and": [
645 {
646 "all": [
647 {"var": "fields.#"},
648 {
649 "and": [
650 {">": [{"var": "32B.amount"}, -1]},
651 {
652 "if": [
653 {"exists": ["fields", "33B"]},
654 {">": [{"var": "33B.amount"}, -1]},
655 true
656 ]
657 },
658 {
659 "if": [
660 {"exists": ["fields", "71F"]},
661 {">": [{"var": "71F.amount"}, -1]},
662 true
663 ]
664 },
665 {
666 "if": [
667 {"exists": ["fields", "71G"]},
668 {">": [{"var": "71G.amount"}, -1]},
669 true
670 ]
671 }
672 ]
673 }
674 ]
675 },
676 {
677 "if": [
678 {"exists": ["fields", "32B"]},
679 {">": [{"var": "fields.32B.amount"}, -1]},
680 true
681 ]
682 },
683 {
684 "if": [
685 {"exists": ["fields", "19"]},
686 {">": [{"var": "fields.19.amount"}, -1]},
687 true
688 ]
689 },
690 {
691 "if": [
692 {"exists": ["fields", "71F"]},
693 {">": [{"var": "fields.71F.amount"}, -1]},
694 true
695 ]
696 },
697 {
698 "if": [
699 {"exists": ["fields", "71G"]},
700 {">": [{"var": "fields.71G.amount"}, -1]},
701 true
702 ]
703 }
704 ]
705 }
706 },
707 {
708 "id": "EXECUTION_DATE",
709 "description": "Requested execution date must be valid",
710 "condition": {
711 "and": [
712 {"exists": ["fields", "30"]},
713 {"!=": [{"var": "fields.30.execution_date"}, ""]}
714 ]
715 }
716 }
717 ],
718 "constants": {
719 "VALID_CHARGE_CODES": ["OUR", "SHA", "BEN"],
720 "VALID_INSTRUCTION_CODES_MT107": ["AUTH", "NAUT", "OTHR", "RTND", "SDVA", "INTC", "CORT"]
721 }
722}"#;