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 result.push('-');
305 result
306 }
307
308 const MT101_VALID_23E_CODES: &'static [&'static str] = &[
314 "CHQB", "CMSW", "CMTO", "CMZB", "CORT", "EQUI", "INTC", "NETS", "OTHR", "PHON", "REPA",
315 "RTGS", "URGP",
316 ];
317
318 const CODES_WITH_ADDITIONAL_INFO: &'static [&'static str] = &["CMTO", "PHON", "OTHR", "REPA"];
320
321 const INVALID_23E_COMBINATIONS: &'static [(&'static str, &'static [&'static str])] = &[
323 (
324 "CHQB",
325 &[
326 "CMSW", "CMTO", "CMZB", "CORT", "NETS", "PHON", "REPA", "RTGS", "URGP",
327 ],
328 ),
329 ("CMSW", &["CMTO", "CMZB"]),
330 ("CMTO", &["CMZB"]),
331 ("CORT", &["CMSW", "CMTO", "CMZB", "REPA"]),
332 ("EQUI", &["CMSW", "CMTO", "CMZB"]),
333 ("NETS", &["RTGS"]),
334 ];
335
336 fn has_ordering_customer_in_seq_a(&self) -> bool {
342 self.ordering_customer.is_some()
343 }
344
345 fn has_ordering_customer_in_all_seq_b(&self) -> bool {
347 !self.transactions.is_empty()
348 && self
349 .transactions
350 .iter()
351 .all(|tx| tx.ordering_customer_tx.is_some())
352 }
353
354 fn has_ordering_customer_in_any_seq_b(&self) -> bool {
356 self.transactions
357 .iter()
358 .any(|tx| tx.ordering_customer_tx.is_some())
359 }
360
361 fn has_instructing_party_in_seq_a(&self) -> bool {
363 self.instructing_party.is_some()
364 }
365
366 fn has_instructing_party_in_any_seq_b(&self) -> bool {
368 self.transactions
369 .iter()
370 .any(|tx| tx.instructing_party_tx.is_some())
371 }
372
373 fn has_account_servicing_in_seq_a(&self) -> bool {
375 self.field_52a.is_some()
376 }
377
378 fn has_account_servicing_in_any_seq_b(&self) -> bool {
380 self.transactions.iter().any(|tx| tx.field_52.is_some())
381 }
382
383 fn validate_c1_fx_deal_reference(&self) -> Vec<SwiftValidationError> {
390 let mut errors = Vec::new();
391
392 for (idx, transaction) in self.transactions.iter().enumerate() {
393 if transaction.field_36.is_some() && transaction.field_21f.is_none() {
394 errors.push(SwiftValidationError::content_error(
395 "D54",
396 "21F",
397 "",
398 &format!(
399 "Transaction {}: Field 21F (F/X Deal Reference) is mandatory when field 36 (Exchange Rate) is present",
400 idx + 1
401 ),
402 "If an exchange rate is given in field 36, the corresponding forex deal must be referenced in field 21F",
403 ));
404 }
405 }
406
407 errors
408 }
409
410 fn validate_c2_amount_exchange(&self) -> Vec<SwiftValidationError> {
413 let mut errors = Vec::new();
414
415 for (idx, transaction) in self.transactions.iter().enumerate() {
416 if let Some(ref _field_33b) = transaction.field_33b {
417 let amount_is_zero = transaction.field_32b.amount.abs() < 0.01;
419
420 if amount_is_zero {
421 if transaction.field_36.is_some() {
423 errors.push(SwiftValidationError::content_error(
424 "D60",
425 "36",
426 "",
427 &format!(
428 "Transaction {}: Field 36 (Exchange Rate) is not allowed when field 33B is present and amount in field 32B is zero",
429 idx + 1
430 ),
431 "When field 33B is present and amount in field 32B equals zero, field 36 must not be present",
432 ));
433 }
434 } else {
435 if transaction.field_36.is_none() {
437 errors.push(SwiftValidationError::content_error(
438 "D60",
439 "36",
440 "",
441 &format!(
442 "Transaction {}: Field 36 (Exchange Rate) is mandatory when field 33B is present and amount in field 32B is not zero",
443 idx + 1
444 ),
445 "When field 33B is present and amount in field 32B is not equal to zero, field 36 must be present",
446 ));
447 }
448 }
449 } else {
450 if transaction.field_36.is_some() {
452 errors.push(SwiftValidationError::content_error(
453 "D60",
454 "36",
455 "",
456 &format!(
457 "Transaction {}: Field 36 (Exchange Rate) is not allowed when field 33B is not present",
458 idx + 1
459 ),
460 "Field 36 is only allowed when field 33B is present",
461 ));
462 }
463 }
464 }
465
466 errors
467 }
468
469 fn validate_c3_ordering_customer(&self) -> Option<SwiftValidationError> {
472 let in_seq_a = self.has_ordering_customer_in_seq_a();
473 let in_all_seq_b = self.has_ordering_customer_in_all_seq_b();
474 let in_any_seq_b = self.has_ordering_customer_in_any_seq_b();
475
476 if in_seq_a && in_any_seq_b {
477 return Some(SwiftValidationError::content_error(
479 "D61",
480 "50a",
481 "",
482 "Field 50a (Ordering Customer F/G/H) must not be present in both Sequence A and Sequence B",
483 "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",
484 ));
485 }
486
487 if !in_seq_a && !in_all_seq_b {
488 if in_any_seq_b {
490 return Some(SwiftValidationError::content_error(
492 "D61",
493 "50a",
494 "",
495 "Field 50a (Ordering Customer F/G/H) must be present in every Sequence B transaction when using multiple debit accounts",
496 "When field 50a (F/G/H) is not in Sequence A, it must be present in every occurrence of Sequence B",
497 ));
498 } else {
499 return Some(SwiftValidationError::content_error(
501 "D61",
502 "50a",
503 "",
504 "Field 50a (Ordering Customer F/G/H) must be present in either Sequence A or in every Sequence B transaction",
505 "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)",
506 ));
507 }
508 }
509
510 None
511 }
512
513 fn validate_c4_instructing_party(&self) -> Option<SwiftValidationError> {
516 let in_seq_a = self.has_instructing_party_in_seq_a();
517 let in_any_seq_b = self.has_instructing_party_in_any_seq_b();
518
519 if in_seq_a && in_any_seq_b {
520 return Some(SwiftValidationError::content_error(
521 "D62",
522 "50a",
523 "",
524 "Field 50a (Instructing Party C/L) must not be present in both Sequence A and Sequence B",
525 "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",
526 ));
527 }
528
529 None
530 }
531
532 fn validate_c5_currency_codes(&self) -> Vec<SwiftValidationError> {
535 let mut errors = Vec::new();
536
537 for (idx, transaction) in self.transactions.iter().enumerate() {
538 if let Some(ref field_33b) = transaction.field_33b {
539 let currency_32b = &transaction.field_32b.currency;
540 let currency_33b = &field_33b.currency;
541
542 if currency_32b == currency_33b {
543 errors.push(SwiftValidationError::content_error(
544 "D68",
545 "33B",
546 currency_33b,
547 &format!(
548 "Transaction {}: Currency code in field 33B ({}) must be different from currency code in field 32B ({})",
549 idx + 1, currency_33b, currency_32b
550 ),
551 "When field 33B is present, its currency code must differ from the currency code in field 32B within the same transaction",
552 ));
553 }
554 }
555 }
556
557 errors
558 }
559
560 fn validate_c6_account_servicing(&self) -> Option<SwiftValidationError> {
563 let in_seq_a = self.has_account_servicing_in_seq_a();
564 let in_any_seq_b = self.has_account_servicing_in_any_seq_b();
565
566 if in_seq_a && in_any_seq_b {
567 return Some(SwiftValidationError::content_error(
568 "D64",
569 "52a",
570 "",
571 "Field 52a (Account Servicing Institution) must not be present in both Sequence A and Sequence B",
572 "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",
573 ));
574 }
575
576 None
577 }
578
579 fn validate_c7_intermediary(&self) -> Vec<SwiftValidationError> {
582 let mut errors = Vec::new();
583
584 for (idx, transaction) in self.transactions.iter().enumerate() {
585 if transaction.field_56.is_some() && transaction.field_57.is_none() {
586 errors.push(SwiftValidationError::content_error(
587 "D65",
588 "57a",
589 "",
590 &format!(
591 "Transaction {}: Field 57a (Account With Institution) is mandatory when field 56a (Intermediary) is present",
592 idx + 1
593 ),
594 "If field 56a is present, field 57a must also be present",
595 ));
596 }
597 }
598
599 errors
600 }
601
602 fn validate_c8_currency_consistency(&self) -> Option<SwiftValidationError> {
605 self.field_21r.as_ref()?;
606
607 if self.transactions.is_empty() {
608 return None;
609 }
610
611 let first_currency = &self.transactions[0].field_32b.currency;
613
614 for (idx, transaction) in self.transactions.iter().enumerate().skip(1) {
616 if &transaction.field_32b.currency != first_currency {
617 return Some(SwiftValidationError::content_error(
618 "D98",
619 "32B",
620 &transaction.field_32b.currency,
621 &format!(
622 "Transaction {}: Currency code in field 32B ({}) must be the same as in other transactions ({}) when field 21R is present",
623 idx + 1,
624 transaction.field_32b.currency,
625 first_currency
626 ),
627 "When field 21R is present in Sequence A, the currency code in field 32B must be the same in all occurrences of Sequence B",
628 ));
629 }
630 }
631
632 None
633 }
634
635 fn validate_c9_zero_amount(&self) -> Vec<SwiftValidationError> {
638 let mut errors = Vec::new();
639
640 for (idx, transaction) in self.transactions.iter().enumerate() {
641 let amount_is_zero = transaction.field_32b.amount.abs() < 0.01;
643
644 if amount_is_zero {
645 let has_equi = transaction
647 .field_23e
648 .as_ref()
649 .is_some_and(|codes| codes.iter().any(|code| code.instruction_code == "EQUI"));
650
651 if has_equi {
652 if transaction.field_33b.is_none() {
654 errors.push(SwiftValidationError::relation_error(
655 "E54",
656 "33B",
657 vec!["32B".to_string(), "23E".to_string()],
658 &format!(
659 "Transaction {}: Field 33B is mandatory when amount in field 32B is zero and field 23E contains code EQUI",
660 idx + 1
661 ),
662 "When amount in field 32B equals zero and field 23E is present with code EQUI, field 33B is mandatory",
663 ));
664 }
665 } else {
666 if transaction.field_33b.is_some() {
668 errors.push(SwiftValidationError::relation_error(
669 "E54",
670 "33B",
671 vec!["32B".to_string(), "23E".to_string()],
672 &format!(
673 "Transaction {}: Field 33B is not allowed when amount in field 32B is zero and field 23E does not contain code EQUI",
674 idx + 1
675 ),
676 "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",
677 ));
678 }
679 if transaction.field_21f.is_some() {
680 errors.push(SwiftValidationError::relation_error(
681 "E54",
682 "21F",
683 vec!["32B".to_string(), "23E".to_string()],
684 &format!(
685 "Transaction {}: Field 21F is not allowed when amount in field 32B is zero and field 23E does not contain code EQUI",
686 idx + 1
687 ),
688 "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",
689 ));
690 }
691 }
692 }
693 }
694
695 errors
696 }
697
698 fn validate_field_23e(&self) -> Vec<SwiftValidationError> {
701 let mut errors = Vec::new();
702
703 for (idx, transaction) in self.transactions.iter().enumerate() {
704 if let Some(ref field_23e_vec) = transaction.field_23e {
705 let mut seen_codes = HashSet::new();
706
707 for field_23e in field_23e_vec {
708 let code = &field_23e.instruction_code;
709
710 if !Self::MT101_VALID_23E_CODES.contains(&code.as_str()) {
712 errors.push(SwiftValidationError::format_error(
713 "T47",
714 "23E",
715 code,
716 &format!("One of: {}", Self::MT101_VALID_23E_CODES.join(", ")),
717 &format!(
718 "Transaction {}: Instruction code '{}' is not valid for MT101. Valid codes: {}",
719 idx + 1,
720 code,
721 Self::MT101_VALID_23E_CODES.join(", ")
722 ),
723 ));
724 }
725
726 if field_23e.additional_info.is_some()
728 && !Self::CODES_WITH_ADDITIONAL_INFO.contains(&code.as_str())
729 {
730 errors.push(SwiftValidationError::content_error(
731 "D66",
732 "23E",
733 code,
734 &format!(
735 "Transaction {}: Additional information is only allowed for codes: {}. Code '{}' does not allow additional information",
736 idx + 1,
737 Self::CODES_WITH_ADDITIONAL_INFO.join(", "),
738 code
739 ),
740 "Additional information in field 23E is only allowed for codes: CMTO, PHON, OTHR, REPA",
741 ));
742 }
743
744 if code != "OTHR" {
746 if seen_codes.contains(code) {
747 errors.push(SwiftValidationError::relation_error(
748 "E46",
749 "23E",
750 vec![],
751 &format!(
752 "Transaction {}: Instruction code '{}' appears more than once. Same code must not be repeated except OTHR",
753 idx + 1, code
754 ),
755 "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",
756 ));
757 }
758 seen_codes.insert(code.clone());
759 }
760 }
761
762 for field_23e in field_23e_vec {
764 let code = &field_23e.instruction_code;
765
766 for &(base_code, forbidden_codes) in Self::INVALID_23E_COMBINATIONS {
767 if code == base_code {
768 for other_field in field_23e_vec {
770 let other_code = &other_field.instruction_code;
771 if forbidden_codes.contains(&other_code.as_str()) {
772 errors.push(SwiftValidationError::content_error(
773 "D67",
774 "23E",
775 code,
776 &format!(
777 "Transaction {}: Instruction code '{}' cannot be combined with code '{}'. Invalid combination",
778 idx + 1, code, other_code
779 ),
780 &format!(
781 "Code '{}' cannot be combined with: {}",
782 base_code,
783 forbidden_codes.join(", ")
784 ),
785 ));
786 }
787 }
788 }
789 }
790 }
791 }
792 }
793
794 errors
795 }
796
797 pub fn validate_network_rules(&self, stop_on_first_error: bool) -> Vec<SwiftValidationError> {
800 let mut all_errors = Vec::new();
801
802 let c1_errors = self.validate_c1_fx_deal_reference();
804 all_errors.extend(c1_errors);
805 if stop_on_first_error && !all_errors.is_empty() {
806 return all_errors;
807 }
808
809 let c2_errors = self.validate_c2_amount_exchange();
811 all_errors.extend(c2_errors);
812 if stop_on_first_error && !all_errors.is_empty() {
813 return all_errors;
814 }
815
816 if let Some(error) = self.validate_c3_ordering_customer() {
818 all_errors.push(error);
819 if stop_on_first_error {
820 return all_errors;
821 }
822 }
823
824 if let Some(error) = self.validate_c4_instructing_party() {
826 all_errors.push(error);
827 if stop_on_first_error {
828 return all_errors;
829 }
830 }
831
832 let c5_errors = self.validate_c5_currency_codes();
834 all_errors.extend(c5_errors);
835 if stop_on_first_error && !all_errors.is_empty() {
836 return all_errors;
837 }
838
839 if let Some(error) = self.validate_c6_account_servicing() {
841 all_errors.push(error);
842 if stop_on_first_error {
843 return all_errors;
844 }
845 }
846
847 let c7_errors = self.validate_c7_intermediary();
849 all_errors.extend(c7_errors);
850 if stop_on_first_error && !all_errors.is_empty() {
851 return all_errors;
852 }
853
854 if let Some(error) = self.validate_c8_currency_consistency() {
856 all_errors.push(error);
857 if stop_on_first_error {
858 return all_errors;
859 }
860 }
861
862 let c9_errors = self.validate_c9_zero_amount();
864 all_errors.extend(c9_errors);
865 if stop_on_first_error && !all_errors.is_empty() {
866 return all_errors;
867 }
868
869 let f23e_errors = self.validate_field_23e();
871 all_errors.extend(f23e_errors);
872
873 all_errors
874 }
875}
876
877impl crate::traits::SwiftMessageBody for MT101 {
878 fn message_type() -> &'static str {
879 "101"
880 }
881
882 fn parse_from_block4(block4: &str) -> Result<Self, crate::errors::ParseError> {
883 MT101::parse_from_block4(block4)
885 }
886
887 fn to_mt_string(&self) -> String {
888 MT101::to_mt_string(self)
890 }
891
892 fn validate_network_rules(&self, stop_on_first_error: bool) -> Vec<SwiftValidationError> {
893 MT101::validate_network_rules(self, stop_on_first_error)
895 }
896}