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}