swift_mt_message/messages/
mt290.rs

1use crate::errors::{ParseError, SwiftValidationError};
2use crate::fields::*;
3use crate::parser::MessageParser;
4use crate::parser::utils::*;
5use serde::{Deserialize, Serialize};
6
7/// **MT290: Advice of Charges, Interest and Other Adjustments**
8///
9/// Notification to beneficiary institution of charges and adjustments.
10///
11/// **Usage:** Interbank charge notifications, interest advice
12/// **Category:** Category 2 (Financial Institution Transfers)
13#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
14pub struct MT290 {
15    /// Transaction Reference Number (Field 20)
16    #[serde(rename = "20")]
17    pub field_20: Field20,
18
19    /// Related Reference (Field 21)
20    #[serde(rename = "21")]
21    pub field_21: Field21NoOption,
22
23    /// Account Identification (Field 25)
24    #[serde(rename = "25")]
25    pub field_25: Field25NoOption,
26
27    /// Value Date, Currency Code, Amount (Field 32)
28    #[serde(flatten)]
29    pub field_32: Field32AmountCD,
30
31    /// Ordering Institution (Field 52)
32    #[serde(flatten, skip_serializing_if = "Option::is_none")]
33    pub field_52: Option<Field52OrderingInstitution>,
34
35    /// Details of Charges (Field 71B)
36    #[serde(rename = "71B")]
37    pub field_71b: Field71B,
38
39    /// Sender to Receiver Information (Field 72)
40    #[serde(rename = "72", skip_serializing_if = "Option::is_none")]
41    pub field_72: Option<Field72>,
42}
43
44impl MT290 {
45    /// Parse MT290 from a raw SWIFT message string
46    pub fn parse_from_block4(block4: &str) -> Result<Self, ParseError> {
47        let mut parser = MessageParser::new(block4, "290");
48
49        // Parse mandatory fields
50        let field_20 = parser.parse_field::<Field20>("20")?;
51        let field_21 = parser.parse_field::<Field21NoOption>("21")?;
52
53        // Parse Field 25 - Account Identification
54        let field_25 = parser.parse_field::<Field25NoOption>("25")?;
55
56        // Parse Field 32 - variant field (32C or 32D only per spec)
57        let field_32 = parser.parse_variant_field::<Field32AmountCD>("32")?;
58
59        // Parse optional Field 52 - Ordering Institution
60        let field_52 = parser.parse_optional_variant_field::<Field52OrderingInstitution>("52")?;
61
62        // Parse mandatory Field 71B
63        let field_71b = parser.parse_field::<Field71B>("71B")?;
64
65        // Parse optional Field 72
66        let field_72 = parser.parse_optional_field::<Field72>("72")?;
67
68        Ok(MT290 {
69            field_20,
70            field_21,
71            field_25,
72            field_32,
73            field_52,
74            field_71b,
75            field_72,
76        })
77    }
78
79    /// Parse from generic SWIFT input (tries to detect blocks)
80    pub fn parse(input: &str) -> Result<Self, ParseError> {
81        let block4 = extract_block4(input)?;
82        Self::parse_from_block4(&block4)
83    }
84
85    /// Convert to SWIFT MT text format
86    pub fn to_mt_string(&self) -> String {
87        let mut result = String::new();
88
89        append_field(&mut result, &self.field_20);
90        append_field(&mut result, &self.field_21);
91        append_field(&mut result, &self.field_25);
92        append_field(&mut result, &self.field_32);
93        append_optional_field(&mut result, &self.field_52);
94        append_field(&mut result, &self.field_71b);
95        append_optional_field(&mut result, &self.field_72);
96
97        result.push('-');
98        result
99    }
100
101    // ========================================================================
102    // NETWORK VALIDATION RULES (SR 2025 MT290)
103    // ========================================================================
104
105    /// Main validation method - validates all network rules
106    ///
107    /// **Note**: MT290 has no network validated rules according to SR 2025 specification.
108    /// This method is provided for API consistency and always returns an empty vector.
109    ///
110    /// Returns array of validation errors, respects stop_on_first_error flag
111    pub fn validate_network_rules(&self, _stop_on_first_error: bool) -> Vec<SwiftValidationError> {
112        // MT290 has no network validated rules per SR 2025 specification
113        Vec::new()
114    }
115}
116
117impl crate::traits::SwiftMessageBody for MT290 {
118    fn message_type() -> &'static str {
119        "290"
120    }
121
122    fn parse_from_block4(block4: &str) -> Result<Self, crate::errors::ParseError> {
123        // Call the existing public method implementation
124        MT290::parse_from_block4(block4)
125    }
126
127    fn to_mt_string(&self) -> String {
128        // Call the existing public method implementation
129        MT290::to_mt_string(self)
130    }
131
132    fn validate_network_rules(&self, stop_on_first_error: bool) -> Vec<SwiftValidationError> {
133        // Call the existing public method implementation
134        MT290::validate_network_rules(self, stop_on_first_error)
135    }
136}