1use crate::errors::SwiftValidationError;
2use crate::fields::*;
3use crate::parser::utils::*;
4use serde::{Deserialize, Serialize};
5use std::collections::HashSet;
6
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
9pub struct MT101Transaction {
10    #[serde(rename = "21")]
12    pub field_21: Field21NoOption,
13
14    #[serde(rename = "21F")]
16    pub field_21f: Option<Field21F>,
17
18    #[serde(rename = "23E")]
20    pub field_23e: Option<Vec<Field23E>>,
21
22    #[serde(rename = "32B")]
24    pub field_32b: Field32B,
25
26    #[serde(flatten)]
28    pub instructing_party_tx: Option<Field50InstructingParty>,
29
30    #[serde(flatten)]
32    pub ordering_customer_tx: Option<Field50OrderingCustomerFGH>,
33
34    #[serde(flatten)]
36    pub field_52: Option<Field52AccountServicingInstitution>,
37
38    #[serde(flatten)]
40    pub field_56: Option<Field56Intermediary>,
41
42    #[serde(flatten)]
44    pub field_57: Option<Field57AccountWithInstitution>,
45
46    #[serde(flatten)]
48    pub field_59: Field59,
49
50    #[serde(rename = "70")]
52    pub field_70: Option<Field70>,
53
54    #[serde(rename = "77B")]
56    pub field_77b: Option<Field77B>,
57
58    #[serde(rename = "33B")]
60    pub field_33b: Option<Field33B>,
61
62    #[serde(rename = "71A")]
64    pub field_71a: Field71A,
65
66    #[serde(rename = "25A")]
68    pub field_25a: Option<Field25A>,
69
70    #[serde(rename = "36")]
72    pub field_36: Option<Field36>,
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
83pub struct MT101 {
84    #[serde(rename = "20")]
86    pub field_20: Field20,
87
88    #[serde(rename = "21R")]
90    pub field_21r: Option<Field21R>,
91
92    #[serde(rename = "28D")]
94    pub field_28d: Field28D,
95
96    #[serde(flatten)]
98    pub instructing_party: Option<Field50InstructingParty>,
99
100    #[serde(flatten)]
102    pub ordering_customer: Option<Field50OrderingCustomerFGH>,
103
104    #[serde(flatten)]
106    pub field_52a: Option<Field52AccountServicingInstitution>,
107
108    #[serde(rename = "51A")]
110    pub field_51a: Option<Field51A>,
111
112    #[serde(rename = "30")]
114    pub field_30: Field30,
115
116    #[serde(rename = "25")]
118    pub field_25: Option<Field25NoOption>,
119
120    #[serde(rename = "#")]
122    pub transactions: Vec<MT101Transaction>,
123}
124
125impl MT101 {
126    pub fn parse_from_block4(block4: &str) -> Result<Self, crate::errors::ParseError> {
128        let mut parser = crate::parser::MessageParser::new(block4, "101");
129
130        let field_20 = parser.parse_field::<Field20>("20")?;
132        let field_21r = parser.parse_optional_field::<Field21R>("21R")?;
133        let field_28d = parser.parse_field::<Field28D>("28D")?;
134
135        let (instructing_party, ordering_customer) = {
139            let mut instructing = None;
140            let mut ordering = None;
141
142            if let Some(variant) = parser.detect_variant_optional("50") {
144                match variant.as_str() {
145                    "C" | "L" => {
146                        instructing =
148                            parser.parse_optional_variant_field::<Field50InstructingParty>("50")?;
149                    }
150                    "F" | "G" | "H" => {
151                        ordering = parser
153                            .parse_optional_variant_field::<Field50OrderingCustomerFGH>("50")?;
154                    }
155                    _ => {
156                        if let Ok(Some(field)) =
158                            parser.parse_optional_variant_field::<Field50InstructingParty>("50")
159                        {
160                            instructing = Some(field);
161                        } else {
162                            ordering = parser
163                                .parse_optional_variant_field::<Field50OrderingCustomerFGH>("50")?;
164                        }
165                    }
166                }
167            }
168
169            (instructing, ordering)
170        };
171
172        let field_52a =
173            parser.parse_optional_variant_field::<Field52AccountServicingInstitution>("52")?;
174        let field_51a = parser.parse_optional_field::<Field51A>("51A")?;
175        let field_30 = parser.parse_field::<Field30>("30")?;
176        let field_25 = parser.parse_optional_field::<Field25NoOption>("25")?;
177
178        let mut transactions = Vec::new();
180
181        parser = parser.with_duplicates(true);
183
184        while parser.detect_field("21") {
186            let field_21 = parser.parse_field::<Field21NoOption>("21")?;
187            let field_21f = parser.parse_optional_field::<Field21F>("21F")?;
188
189            let field_23e = if parser.detect_field("23E") {
192                let mut codes = Vec::new();
193                while parser.detect_field("23E") {
194                    if let Ok(field) = parser.parse_field::<Field23E>("23E") {
195                        codes.push(field);
196                    } else {
197                        break;
198                    }
199                }
200                if !codes.is_empty() { Some(codes) } else { None }
201            } else {
202                None
203            };
204
205            let field_32b = parser.parse_field::<Field32B>("32B")?;
206
207            let instructing_party_tx =
209                parser.parse_optional_variant_field::<Field50InstructingParty>("50")?;
210            let ordering_customer_tx =
211                parser.parse_optional_variant_field::<Field50OrderingCustomerFGH>("50")?;
212
213            let field_52 =
214                parser.parse_optional_variant_field::<Field52AccountServicingInstitution>("52")?;
215            let field_56 = parser.parse_optional_variant_field::<Field56Intermediary>("56")?;
216            let field_57 =
217                parser.parse_optional_variant_field::<Field57AccountWithInstitution>("57")?;
218            let field_59 = parser.parse_variant_field::<Field59>("59")?;
219            let field_70 = parser.parse_optional_field::<Field70>("70")?;
220            let field_77b = parser.parse_optional_field::<Field77B>("77B")?;
221            let field_33b = parser.parse_optional_field::<Field33B>("33B")?;
222            let field_71a = parser.parse_field::<Field71A>("71A")?; let field_25a = parser.parse_optional_field::<Field25A>("25A")?;
224            let field_36 = parser.parse_optional_field::<Field36>("36")?;
225
226            transactions.push(MT101Transaction {
227                field_21,
228                field_21f,
229                field_23e,
230                field_32b,
231                instructing_party_tx,
232                ordering_customer_tx,
233                field_52,
234                field_56,
235                field_57,
236                field_59,
237                field_70,
238                field_77b,
239                field_33b,
240                field_71a,
241                field_25a,
242                field_36,
243            });
244        }
245
246        verify_parser_complete(&parser)?;
248
249        Ok(Self {
250            field_20,
251            field_21r,
252            field_28d,
253            instructing_party,
254            ordering_customer,
255            field_52a,
256            field_51a,
257            field_30,
258            field_25,
259            transactions,
260        })
261    }
262
263    pub fn parse(input: &str) -> Result<Self, crate::errors::ParseError> {
265        let block4 = extract_block4(input)?;
266        Self::parse_from_block4(&block4)
267    }
268
269    pub fn to_mt_string(&self) -> String {
271        let mut result = String::new();
272
273        append_field(&mut result, &self.field_20);
275        append_optional_field(&mut result, &self.field_21r);
276        append_field(&mut result, &self.field_28d);
277        append_optional_field(&mut result, &self.instructing_party);
278        append_optional_field(&mut result, &self.ordering_customer);
279        append_optional_field(&mut result, &self.field_52a);
280        append_optional_field(&mut result, &self.field_51a);
281        append_field(&mut result, &self.field_30);
282        append_optional_field(&mut result, &self.field_25);
283
284        for transaction in &self.transactions {
286            append_field(&mut result, &transaction.field_21);
287            append_optional_field(&mut result, &transaction.field_21f);
288            append_vec_field(&mut result, &transaction.field_23e);
289            append_field(&mut result, &transaction.field_32b);
290            append_optional_field(&mut result, &transaction.instructing_party_tx);
291            append_optional_field(&mut result, &transaction.ordering_customer_tx);
292            append_optional_field(&mut result, &transaction.field_52);
293            append_optional_field(&mut result, &transaction.field_56);
294            append_optional_field(&mut result, &transaction.field_57);
295            append_field(&mut result, &transaction.field_59);
296            append_optional_field(&mut result, &transaction.field_70);
297            append_optional_field(&mut result, &transaction.field_77b);
298            append_optional_field(&mut result, &transaction.field_33b);
299            append_field(&mut result, &transaction.field_71a);
300            append_optional_field(&mut result, &transaction.field_25a);
301            append_optional_field(&mut result, &transaction.field_36);
302        }
303
304        finalize_mt_string(result, false)
305    }
306
307    const MT101_VALID_23E_CODES: &'static [&'static str] = &[
313        "CHQB", "CMSW", "CMTO", "CMZB", "CORT", "EQUI", "INTC", "NETS", "OTHR", "PHON", "REPA",
314        "RTGS", "URGP",
315    ];
316
317    const CODES_WITH_ADDITIONAL_INFO: &'static [&'static str] = &["CMTO", "PHON", "OTHR", "REPA"];
319
320    const INVALID_23E_COMBINATIONS: &'static [(&'static str, &'static [&'static str])] = &[
322        (
323            "CHQB",
324            &[
325                "CMSW", "CMTO", "CMZB", "CORT", "NETS", "PHON", "REPA", "RTGS", "URGP",
326            ],
327        ),
328        ("CMSW", &["CMTO", "CMZB"]),
329        ("CMTO", &["CMZB"]),
330        ("CORT", &["CMSW", "CMTO", "CMZB", "REPA"]),
331        ("EQUI", &["CMSW", "CMTO", "CMZB"]),
332        ("NETS", &["RTGS"]),
333    ];
334
335    fn has_ordering_customer_in_seq_a(&self) -> bool {
341        self.ordering_customer.is_some()
342    }
343
344    fn has_ordering_customer_in_all_seq_b(&self) -> bool {
346        !self.transactions.is_empty()
347            && self
348                .transactions
349                .iter()
350                .all(|tx| tx.ordering_customer_tx.is_some())
351    }
352
353    fn has_ordering_customer_in_any_seq_b(&self) -> bool {
355        self.transactions
356            .iter()
357            .any(|tx| tx.ordering_customer_tx.is_some())
358    }
359
360    fn has_instructing_party_in_seq_a(&self) -> bool {
362        self.instructing_party.is_some()
363    }
364
365    fn has_instructing_party_in_any_seq_b(&self) -> bool {
367        self.transactions
368            .iter()
369            .any(|tx| tx.instructing_party_tx.is_some())
370    }
371
372    fn has_account_servicing_in_seq_a(&self) -> bool {
374        self.field_52a.is_some()
375    }
376
377    fn has_account_servicing_in_any_seq_b(&self) -> bool {
379        self.transactions.iter().any(|tx| tx.field_52.is_some())
380    }
381
382    fn validate_c1_fx_deal_reference(&self) -> Vec<SwiftValidationError> {
389        let mut errors = Vec::new();
390
391        for (idx, transaction) in self.transactions.iter().enumerate() {
392            if transaction.field_36.is_some() && transaction.field_21f.is_none() {
393                errors.push(SwiftValidationError::content_error(
394                    "D54",
395                    "21F",
396                    "",
397                    &format!(
398                        "Transaction {}: Field 21F (F/X Deal Reference) is mandatory when field 36 (Exchange Rate) is present",
399                        idx + 1
400                    ),
401                    "If an exchange rate is given in field 36, the corresponding forex deal must be referenced in field 21F",
402                ));
403            }
404        }
405
406        errors
407    }
408
409    fn validate_c2_amount_exchange(&self) -> Vec<SwiftValidationError> {
412        let mut errors = Vec::new();
413
414        for (idx, transaction) in self.transactions.iter().enumerate() {
415            if let Some(ref _field_33b) = transaction.field_33b {
416                let amount_is_zero = transaction.field_32b.amount.abs() < 0.01;
418
419                if amount_is_zero {
420                    if transaction.field_36.is_some() {
422                        errors.push(SwiftValidationError::content_error(
423                            "D60",
424                            "36",
425                            "",
426                            &format!(
427                                "Transaction {}: Field 36 (Exchange Rate) is not allowed when field 33B is present and amount in field 32B is zero",
428                                idx + 1
429                            ),
430                            "When field 33B is present and amount in field 32B equals zero, field 36 must not be present",
431                        ));
432                    }
433                } else {
434                    if transaction.field_36.is_none() {
436                        errors.push(SwiftValidationError::content_error(
437                            "D60",
438                            "36",
439                            "",
440                            &format!(
441                                "Transaction {}: Field 36 (Exchange Rate) is mandatory when field 33B is present and amount in field 32B is not zero",
442                                idx + 1
443                            ),
444                            "When field 33B is present and amount in field 32B is not equal to zero, field 36 must be present",
445                        ));
446                    }
447                }
448            } else {
449                if transaction.field_36.is_some() {
451                    errors.push(SwiftValidationError::content_error(
452                        "D60",
453                        "36",
454                        "",
455                        &format!(
456                            "Transaction {}: Field 36 (Exchange Rate) is not allowed when field 33B is not present",
457                            idx + 1
458                        ),
459                        "Field 36 is only allowed when field 33B is present",
460                    ));
461                }
462            }
463        }
464
465        errors
466    }
467
468    fn validate_c3_ordering_customer(&self) -> Option<SwiftValidationError> {
471        let in_seq_a = self.has_ordering_customer_in_seq_a();
472        let in_all_seq_b = self.has_ordering_customer_in_all_seq_b();
473        let in_any_seq_b = self.has_ordering_customer_in_any_seq_b();
474
475        if in_seq_a && in_any_seq_b {
476            return Some(SwiftValidationError::content_error(
478                "D61",
479                "50a",
480                "",
481                "Field 50a (Ordering Customer F/G/H) must not be present in both Sequence A and Sequence B",
482                "If single debit account, field 50a (F/G/H) must be in Sequence A only. If multiple debit accounts, field 50a (F/G/H) must be in every Sequence B transaction only",
483            ));
484        }
485
486        if !in_seq_a && !in_all_seq_b {
487            if in_any_seq_b {
489                return Some(SwiftValidationError::content_error(
491                    "D61",
492                    "50a",
493                    "",
494                    "Field 50a (Ordering Customer F/G/H) must be present in every Sequence B transaction when using multiple debit accounts",
495                    "When field 50a (F/G/H) is not in Sequence A, it must be present in every occurrence of Sequence B",
496                ));
497            } else {
498                return Some(SwiftValidationError::content_error(
500                    "D61",
501                    "50a",
502                    "",
503                    "Field 50a (Ordering Customer F/G/H) must be present in either Sequence A or in every Sequence B transaction",
504                    "Field 50a (F/G/H) must be present in either Sequence A (single debit account) or in each occurrence of Sequence B (multiple debit accounts)",
505                ));
506            }
507        }
508
509        None
510    }
511
512    fn validate_c4_instructing_party(&self) -> Option<SwiftValidationError> {
515        let in_seq_a = self.has_instructing_party_in_seq_a();
516        let in_any_seq_b = self.has_instructing_party_in_any_seq_b();
517
518        if in_seq_a && in_any_seq_b {
519            return Some(SwiftValidationError::content_error(
520                "D62",
521                "50a",
522                "",
523                "Field 50a (Instructing Party C/L) must not be present in both Sequence A and Sequence B",
524                "Field 50a (C/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",
525            ));
526        }
527
528        None
529    }
530
531    fn validate_c5_currency_codes(&self) -> Vec<SwiftValidationError> {
534        let mut errors = Vec::new();
535
536        for (idx, transaction) in self.transactions.iter().enumerate() {
537            if let Some(ref field_33b) = transaction.field_33b {
538                let currency_32b = &transaction.field_32b.currency;
539                let currency_33b = &field_33b.currency;
540
541                if currency_32b == currency_33b {
542                    errors.push(SwiftValidationError::content_error(
543                        "D68",
544                        "33B",
545                        currency_33b,
546                        &format!(
547                            "Transaction {}: Currency code in field 33B ({}) must be different from currency code in field 32B ({})",
548                            idx + 1, currency_33b, currency_32b
549                        ),
550                        "When field 33B is present, its currency code must differ from the currency code in field 32B within the same transaction",
551                    ));
552                }
553            }
554        }
555
556        errors
557    }
558
559    fn validate_c6_account_servicing(&self) -> Option<SwiftValidationError> {
562        let in_seq_a = self.has_account_servicing_in_seq_a();
563        let in_any_seq_b = self.has_account_servicing_in_any_seq_b();
564
565        if in_seq_a && in_any_seq_b {
566            return Some(SwiftValidationError::content_error(
567                "D64",
568                "52a",
569                "",
570                "Field 52a (Account Servicing Institution) must not be present in both Sequence A and Sequence B",
571                "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",
572            ));
573        }
574
575        None
576    }
577
578    fn validate_c7_intermediary(&self) -> Vec<SwiftValidationError> {
581        let mut errors = Vec::new();
582
583        for (idx, transaction) in self.transactions.iter().enumerate() {
584            if transaction.field_56.is_some() && transaction.field_57.is_none() {
585                errors.push(SwiftValidationError::content_error(
586                    "D65",
587                    "57a",
588                    "",
589                    &format!(
590                        "Transaction {}: Field 57a (Account With Institution) is mandatory when field 56a (Intermediary) is present",
591                        idx + 1
592                    ),
593                    "If field 56a is present, field 57a must also be present",
594                ));
595            }
596        }
597
598        errors
599    }
600
601    fn validate_c8_currency_consistency(&self) -> Option<SwiftValidationError> {
604        self.field_21r.as_ref()?;
605
606        if self.transactions.is_empty() {
607            return None;
608        }
609
610        let first_currency = &self.transactions[0].field_32b.currency;
612
613        for (idx, transaction) in self.transactions.iter().enumerate().skip(1) {
615            if &transaction.field_32b.currency != first_currency {
616                return Some(SwiftValidationError::content_error(
617                    "D98",
618                    "32B",
619                    &transaction.field_32b.currency,
620                    &format!(
621                        "Transaction {}: Currency code in field 32B ({}) must be the same as in other transactions ({}) when field 21R is present",
622                        idx + 1,
623                        transaction.field_32b.currency,
624                        first_currency
625                    ),
626                    "When field 21R is present in Sequence A, the currency code in field 32B must be the same in all occurrences of Sequence B",
627                ));
628            }
629        }
630
631        None
632    }
633
634    fn validate_c9_zero_amount(&self) -> Vec<SwiftValidationError> {
637        let mut errors = Vec::new();
638
639        for (idx, transaction) in self.transactions.iter().enumerate() {
640            let amount_is_zero = transaction.field_32b.amount.abs() < 0.01;
642
643            if amount_is_zero {
644                let has_equi = transaction
646                    .field_23e
647                    .as_ref()
648                    .is_some_and(|codes| codes.iter().any(|code| code.instruction_code == "EQUI"));
649
650                if has_equi {
651                    if transaction.field_33b.is_none() {
653                        errors.push(SwiftValidationError::relation_error(
654                            "E54",
655                            "33B",
656                            vec!["32B".to_string(), "23E".to_string()],
657                            &format!(
658                                "Transaction {}: Field 33B is mandatory when amount in field 32B is zero and field 23E contains code EQUI",
659                                idx + 1
660                            ),
661                            "When amount in field 32B equals zero and field 23E is present with code EQUI, field 33B is mandatory",
662                        ));
663                    }
664                } else {
665                    if transaction.field_33b.is_some() {
667                        errors.push(SwiftValidationError::relation_error(
668                            "E54",
669                            "33B",
670                            vec!["32B".to_string(), "23E".to_string()],
671                            &format!(
672                                "Transaction {}: Field 33B is not allowed when amount in field 32B is zero and field 23E does not contain code EQUI",
673                                idx + 1
674                            ),
675                            "When amount in field 32B equals zero and field 23E is not present or does not contain code EQUI, field 33B must not be present",
676                        ));
677                    }
678                    if transaction.field_21f.is_some() {
679                        errors.push(SwiftValidationError::relation_error(
680                            "E54",
681                            "21F",
682                            vec!["32B".to_string(), "23E".to_string()],
683                            &format!(
684                                "Transaction {}: Field 21F is not allowed when amount in field 32B is zero and field 23E does not contain code EQUI",
685                                idx + 1
686                            ),
687                            "When amount in field 32B equals zero and field 23E is not present or does not contain code EQUI, field 21F must not be present",
688                        ));
689                    }
690                }
691            }
692        }
693
694        errors
695    }
696
697    fn validate_field_23e(&self) -> Vec<SwiftValidationError> {
700        let mut errors = Vec::new();
701
702        for (idx, transaction) in self.transactions.iter().enumerate() {
703            if let Some(ref field_23e_vec) = transaction.field_23e {
704                let mut seen_codes = HashSet::new();
705
706                for field_23e in field_23e_vec {
707                    let code = &field_23e.instruction_code;
708
709                    if !Self::MT101_VALID_23E_CODES.contains(&code.as_str()) {
711                        errors.push(SwiftValidationError::format_error(
712                            "T47",
713                            "23E",
714                            code,
715                            &format!("One of: {}", Self::MT101_VALID_23E_CODES.join(", ")),
716                            &format!(
717                                "Transaction {}: Instruction code '{}' is not valid for MT101. Valid codes: {}",
718                                idx + 1,
719                                code,
720                                Self::MT101_VALID_23E_CODES.join(", ")
721                            ),
722                        ));
723                    }
724
725                    if field_23e.additional_info.is_some()
727                        && !Self::CODES_WITH_ADDITIONAL_INFO.contains(&code.as_str())
728                    {
729                        errors.push(SwiftValidationError::content_error(
730                            "D66",
731                            "23E",
732                            code,
733                            &format!(
734                                "Transaction {}: Additional information is only allowed for codes: {}. Code '{}' does not allow additional information",
735                                idx + 1,
736                                Self::CODES_WITH_ADDITIONAL_INFO.join(", "),
737                                code
738                            ),
739                            "Additional information in field 23E is only allowed for codes: CMTO, PHON, OTHR, REPA",
740                        ));
741                    }
742
743                    if code != "OTHR" {
745                        if seen_codes.contains(code) {
746                            errors.push(SwiftValidationError::relation_error(
747                                "E46",
748                                "23E",
749                                vec![],
750                                &format!(
751                                    "Transaction {}: Instruction code '{}' appears more than once. Same code must not be repeated except OTHR",
752                                    idx + 1, code
753                                ),
754                                "When field 23E is repeated in Sequence B, the same code must not be present more than once, except for code OTHR which may be repeated",
755                            ));
756                        }
757                        seen_codes.insert(code.clone());
758                    }
759                }
760
761                for field_23e in field_23e_vec {
763                    let code = &field_23e.instruction_code;
764
765                    for &(base_code, forbidden_codes) in Self::INVALID_23E_COMBINATIONS {
766                        if code == base_code {
767                            for other_field in field_23e_vec {
769                                let other_code = &other_field.instruction_code;
770                                if forbidden_codes.contains(&other_code.as_str()) {
771                                    errors.push(SwiftValidationError::content_error(
772                                        "D67",
773                                        "23E",
774                                        code,
775                                        &format!(
776                                            "Transaction {}: Instruction code '{}' cannot be combined with code '{}'. Invalid combination",
777                                            idx + 1, code, other_code
778                                        ),
779                                        &format!(
780                                            "Code '{}' cannot be combined with: {}",
781                                            base_code,
782                                            forbidden_codes.join(", ")
783                                        ),
784                                    ));
785                                }
786                            }
787                        }
788                    }
789                }
790            }
791        }
792
793        errors
794    }
795
796    pub fn validate_network_rules(&self, stop_on_first_error: bool) -> Vec<SwiftValidationError> {
799        let mut all_errors = Vec::new();
800
801        let c1_errors = self.validate_c1_fx_deal_reference();
803        all_errors.extend(c1_errors);
804        if stop_on_first_error && !all_errors.is_empty() {
805            return all_errors;
806        }
807
808        let c2_errors = self.validate_c2_amount_exchange();
810        all_errors.extend(c2_errors);
811        if stop_on_first_error && !all_errors.is_empty() {
812            return all_errors;
813        }
814
815        if let Some(error) = self.validate_c3_ordering_customer() {
817            all_errors.push(error);
818            if stop_on_first_error {
819                return all_errors;
820            }
821        }
822
823        if let Some(error) = self.validate_c4_instructing_party() {
825            all_errors.push(error);
826            if stop_on_first_error {
827                return all_errors;
828            }
829        }
830
831        let c5_errors = self.validate_c5_currency_codes();
833        all_errors.extend(c5_errors);
834        if stop_on_first_error && !all_errors.is_empty() {
835            return all_errors;
836        }
837
838        if let Some(error) = self.validate_c6_account_servicing() {
840            all_errors.push(error);
841            if stop_on_first_error {
842                return all_errors;
843            }
844        }
845
846        let c7_errors = self.validate_c7_intermediary();
848        all_errors.extend(c7_errors);
849        if stop_on_first_error && !all_errors.is_empty() {
850            return all_errors;
851        }
852
853        if let Some(error) = self.validate_c8_currency_consistency() {
855            all_errors.push(error);
856            if stop_on_first_error {
857                return all_errors;
858            }
859        }
860
861        let c9_errors = self.validate_c9_zero_amount();
863        all_errors.extend(c9_errors);
864        if stop_on_first_error && !all_errors.is_empty() {
865            return all_errors;
866        }
867
868        let f23e_errors = self.validate_field_23e();
870        all_errors.extend(f23e_errors);
871
872        all_errors
873    }
874}
875
876impl crate::traits::SwiftMessageBody for MT101 {
877    fn message_type() -> &'static str {
878        "101"
879    }
880
881    fn parse_from_block4(block4: &str) -> Result<Self, crate::errors::ParseError> {
882        MT101::parse_from_block4(block4)
884    }
885
886    fn to_mt_string(&self) -> String {
887        MT101::to_mt_string(self)
889    }
890
891    fn validate_network_rules(&self, stop_on_first_error: bool) -> Vec<SwiftValidationError> {
892        MT101::validate_network_rules(self, stop_on_first_error)
894    }
895}