swift_mt_message/fields/
field72.rs

1use super::field_utils::parse_multiline_text;
2use crate::errors::ParseError;
3use crate::traits::SwiftField;
4use serde::{Deserialize, Serialize};
5
6/// **Field 72: Sender to Receiver Information**
7///
8/// Additional information for receiver or other parties in financial messages,
9/// enabling institutional coordination and processing instructions.
10///
11/// **Format:** `6*35x` (max 6 lines, 35 chars each)
12/// **Common codes:** `/ACC/` (account), `/BNF/` (beneficiary), `/INST/` (instruction), `/INS/` (instructing institution)
13///
14/// **Example:**
15/// ```text
16/// :72:/BNF/BENEFICIARY DETAILS
17/// /INST/CREDIT ACCOUNT IMMEDIATELY
18/// ```
19#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
20pub struct Field72 {
21    /// Sender to receiver information (max 6 lines, 35 chars each)
22    pub information: Vec<String>,
23}
24
25impl SwiftField for Field72 {
26    fn parse(input: &str) -> crate::Result<Self>
27    where
28        Self: Sized,
29    {
30        // Parse as multiline text (up to 6 lines, 35 chars each)
31        let information = parse_multiline_text(input, 6, 35)?;
32
33        if information.is_empty() {
34            return Err(ParseError::InvalidFormat {
35                message: "Field 72 must have at least one line of information".to_string(),
36            });
37        }
38
39        Ok(Field72 { information })
40    }
41
42    fn to_swift_string(&self) -> String {
43        format!(":72:{}", self.information.join("\n"))
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50
51    #[test]
52    fn test_field72_single_line() {
53        let field = Field72::parse("/BNF/BENEFICIARY DETAILS").unwrap();
54        assert_eq!(field.information.len(), 1);
55        assert_eq!(field.information[0], "/BNF/BENEFICIARY DETAILS");
56    }
57
58    #[test]
59    fn test_field72_multiline() {
60        let input = "/BNF/BENEFICIARY DETAILS\n/ACC/ACCOUNT INFO\n/REC/RECEIVER INFO";
61        let field = Field72::parse(input).unwrap();
62        assert_eq!(field.information.len(), 3);
63        assert_eq!(field.information[0], "/BNF/BENEFICIARY DETAILS");
64        assert_eq!(field.information[1], "/ACC/ACCOUNT INFO");
65        assert_eq!(field.information[2], "/REC/RECEIVER INFO");
66    }
67
68    #[test]
69    fn test_field72_continuation() {
70        let input = "/INST/LONG INSTRUCTION THAT\n//CONTINUES ON NEXT LINE\n//AND ANOTHER LINE";
71        let field = Field72::parse(input).unwrap();
72        assert_eq!(field.information.len(), 3);
73        assert!(field.information[1].starts_with("//"));
74        assert!(field.information[2].starts_with("//"));
75    }
76
77    #[test]
78    fn test_field72_to_swift_string() {
79        let field = Field72 {
80            information: vec!["/CODE1/INFO1".to_string(), "/CODE2/INFO2".to_string()],
81        };
82        assert_eq!(field.to_swift_string(), ":72:/CODE1/INFO1\n/CODE2/INFO2");
83    }
84
85    #[test]
86    fn test_field72_max_lines() {
87        let input = "LINE1\nLINE2\nLINE3\nLINE4\nLINE5\nLINE6";
88        let field = Field72::parse(input).unwrap();
89        assert_eq!(field.information.len(), 6);
90
91        // Test that 7 lines would fail
92        let too_many = "LINE1\nLINE2\nLINE3\nLINE4\nLINE5\nLINE6\nLINE7";
93        assert!(Field72::parse(too_many).is_err());
94    }
95
96    #[test]
97    fn test_field72_line_length() {
98        // Test max length line (35 chars)
99        let max_line = format!("/ACC/{}", "A".repeat(30));
100        assert_eq!(max_line.len(), 35);
101        let field = Field72::parse(&max_line).unwrap();
102        assert_eq!(field.information[0].len(), 35);
103
104        // Test too long line (36 chars)
105        let too_long = "A".repeat(36);
106        assert!(Field72::parse(&too_long).is_err());
107    }
108}