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