swift_mt_message/fields/
field76.rs

1use super::swift_utils::parse_swift_chars;
2use crate::errors::ParseError;
3use crate::traits::SwiftField;
4use serde::{Deserialize, Serialize};
5
6/// **Field 76: Answers**
7///
8/// Answer information in MT n96 series messages providing responses to Field 75 queries,
9/// including status updates and clarifications.
10///
11/// **Format:** `6*35x` (max 6 lines, 35 chars each)
12/// **Used in:** MT 196, 296, 396, 496, 596, 696, 796, 896, 996 (answer messages)
13///
14/// **Example:**
15/// ```text
16/// :76:STATUS: COMPLETED
17/// SETTLEMENT DATE: 2023-12-25
18/// AMOUNT: USD 1000.00
19/// ```
20
21#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
22pub struct Field76 {
23    /// Answer information (max 6 lines, 35 chars each)
24    pub information: Vec<String>,
25}
26
27impl SwiftField for Field76 {
28    fn parse(input: &str) -> crate::Result<Self>
29    where
30        Self: Sized,
31    {
32        let mut lines = Vec::new();
33
34        // Parse up to 6 lines of 35 characters each
35        for line in input.lines().take(6) {
36            // Validate line length (max 35 characters)
37            if line.len() > 35 {
38                return Err(ParseError::InvalidFormat {
39                    message: format!("Field 76 line exceeds 35 characters: {}", line.len()),
40                });
41            }
42
43            // Validate SWIFT character set
44            parse_swift_chars(line, "Field 76 line")?;
45
46            lines.push(line.to_string());
47        }
48
49        if lines.is_empty() {
50            return Err(ParseError::InvalidFormat {
51                message: "Field 76 must contain at least one line".to_string(),
52            });
53        }
54
55        Ok(Field76 { information: lines })
56    }
57
58    fn to_swift_string(&self) -> String {
59        let content = self.information.join("\n");
60        format!(":76:{}", content)
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67
68    #[test]
69    fn test_field76_parse_single_line() {
70        let field = Field76::parse("STATUS: PROCESSED SUCCESSFULLY").unwrap();
71        assert_eq!(field.information.len(), 1);
72        assert_eq!(field.information[0], "STATUS: PROCESSED SUCCESSFULLY");
73    }
74
75    #[test]
76    fn test_field76_parse_multiple_lines() {
77        let input =
78            "TRANSACTION STATUS: COMPLETED\nSETTLEMENT DATE: 2023-12-25\nAMOUNT: USD 1000.00";
79        let field = Field76::parse(input).unwrap();
80        assert_eq!(field.information.len(), 3);
81        assert_eq!(field.information[0], "TRANSACTION STATUS: COMPLETED");
82        assert_eq!(field.information[1], "SETTLEMENT DATE: 2023-12-25");
83        assert_eq!(field.information[2], "AMOUNT: USD 1000.00");
84    }
85
86    #[test]
87    fn test_field76_line_too_long() {
88        let long_line = "THIS LINE IS MUCH TOO LONG TO BE ACCEPTED IN FIELD 76";
89        assert!(Field76::parse(long_line).is_err());
90    }
91
92    #[test]
93    fn test_field76_max_lines() {
94        let input = "LINE 1\nLINE 2\nLINE 3\nLINE 4\nLINE 5\nLINE 6";
95        let field = Field76::parse(input).unwrap();
96        assert_eq!(field.information.len(), 6);
97    }
98
99    #[test]
100    fn test_field76_empty_input() {
101        assert!(Field76::parse("").is_err());
102    }
103
104    #[test]
105    fn test_field76_to_swift_string() {
106        let field = Field76 {
107            information: vec![
108                "STATUS: COMPLETED".to_string(),
109                "DATE: 2023-12-25".to_string(),
110            ],
111        };
112        assert_eq!(
113            field.to_swift_string(),
114            ":76:STATUS: COMPLETED\nDATE: 2023-12-25"
115        );
116    }
117
118    #[test]
119    fn test_field76_single_line_to_swift_string() {
120        let field = Field76 {
121            information: vec!["ANSWER: CONFIRMED".to_string()],
122        };
123        assert_eq!(field.to_swift_string(), ":76:ANSWER: CONFIRMED");
124    }
125}