swift_mt_message/messages/
mt296.rs

1use crate::fields::*;
2use serde::{Deserialize, Serialize};
3use swift_mt_message_macros::{SwiftMessage, serde_swift_fields};
4
5/// # MT296: Answers (Treasury Messages)
6///
7/// This message is sent by a financial institution to provide answers, confirmations,
8/// or status information in response to queries or requests related to treasury messages.
9/// MT296 is used for answering treasury transfer queries and other institutional inquiries.
10///
11/// ## Key Features
12/// - **Treasury answer provision**: Official responses to treasury message queries
13/// - **Reference tracking**: Links to the original message through reference fields
14/// - **Conditional structure**: Either narrative (field 79) or copy of original message fields
15/// - **Answer codes**: Standardized answer codes with supplementary data
16/// - **Narrative support**: Additional narrative description capability
17///
18/// ## Field Structure
19/// The message follows a conditional structure where either field 79 (narrative description)
20/// or a copy of the mandatory fields from the original message may be present, but not both.
21/// This structure is identical to MT196 but used for treasury/institutional contexts.
22///
23/// ## Answer Process
24/// Used when a treasury department or institutional receiver needs to provide answers,
25/// confirmations, or status updates regarding previously received treasury messages,
26/// including confirmations of institutional transfers, cover payments, or responses to treasury queries.
27#[serde_swift_fields]
28#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, SwiftMessage)]
29#[validation_rules(MT296_VALIDATION_RULES)]
30pub struct MT296 {
31    /// **Transaction Reference Number** - Field 20
32    ///
33    /// Unique reference assigned by the sender for this treasury answer message.
34    /// This reference is used throughout the answer lifecycle for tracking,
35    /// acknowledgment, and audit purposes. Must be unique within sender's system per business day.
36    #[field("20", mandatory)]
37    pub field_20: GenericReferenceField,
38
39    /// **Related Reference** - Field 21
40    ///
41    /// Contains the reference from field 20 of the treasury message being answered.
42    /// This creates a direct link between the answer and the original
43    /// treasury message, enabling complete audit trails and transaction tracking.
44    #[field("21", mandatory)]
45    pub field_21: GenericReferenceField,
46
47    /// **Answers** - Field 76
48    ///
49    /// Contains response codes, narratives, and supplementary data.
50    /// Includes confirmation codes (1-33), cancellation codes (CNCL, PDCR, RJCR),
51    /// and reason codes with optional supplementary details in parentheses.
52    #[field("76", mandatory)]
53    pub field_76: GenericMultiLine6x35,
54
55    /// **Narrative** - Field 77A (Optional)
56    ///
57    /// Free-form narrative description that supplements the answer codes in field 76.
58    /// Used for providing additional context, explanations, or details about the treasury answers.
59    #[field("77A", optional)]
60    pub field_77a: Option<GenericMultiLine20x35>,
61
62    /// **MT and Date of the Original Message** - Field 11a (Optional)
63    ///
64    /// Specifies the message type and date of the original treasury message being answered.
65    /// Can be in Option R format (with session/ISN) or Option S format (date only).
66    #[field("11a", optional)]
67    pub field_11a: Option<GenericTextField>,
68
69    /// **Narrative Description of Original Message** - Field 79 (Conditional)
70    ///
71    /// Contains narrative description of the original treasury message being answered.
72    /// Must be present if copy of original message fields is not included.
73    /// Cannot be used together with copy of original message fields.
74    #[field("79", optional)]
75    pub field_79: Option<GenericMultiLine6x35>,
76
77    /// **Copy of Mandatory Fields from Original Message** - Multiple Fields (Conditional)
78    ///
79    /// When present, contains a copy of at least the mandatory fields from the original treasury message.
80    /// This helps identify the exact treasury transaction being answered.
81    /// Cannot be used together with field 79 according to conditional rule C1.
82    ///
83    /// For treasury messages:
84    /// - MT202: Would include fields 32A, 53, 58
85    /// - MT205: Would include fields 32A, 53, 56, 57, 58
86    /// - MT210: Would include fields 32A, 53
87    #[field("32A", optional)]
88    pub field_32a: Option<Field32A>,
89
90    #[field("58A", optional)]
91    pub field_58a: Option<GenericBicField>,
92
93    #[field("52A", optional)]
94    pub field_52a: Option<GenericBicField>,
95
96    #[field("53A", optional)]
97    pub field_53a: Option<GenericBicField>,
98
99    #[field("56A", optional)]
100    pub field_56a: Option<GenericBicField>,
101
102    #[field("57A", optional)]
103    pub field_57a: Option<GenericBicField>,
104}
105
106/// Enhanced validation rules for MT296
107const MT296_VALIDATION_RULES: &str = r#"{
108  "rules": [
109    {
110      "id": "CONDITIONAL_C1",
111      "description": "Field 79 or copy of original message fields may be present, but not both",
112      "condition": {
113        "!": {
114          "and": [
115            {"!!": {"var": "field_79"}},
116            {
117              "or": [
118                {"!!": {"var": "field_32a"}},
119                {"!!": {"var": "field_58a"}},
120                {"!!": {"var": "field_52a"}},
121                {"!!": {"var": "field_53a"}},
122                {"!!": {"var": "field_56a"}},
123                {"!!": {"var": "field_57a"}}
124              ]
125            }
126          ]
127        }
128      }
129    },
130    {
131      "id": "REFERENCE_FORMAT",
132      "description": "Reference fields must not have invalid slash patterns",
133      "condition": {
134        "and": [
135          {"!": {"startsWith": [{"var": "field_20.value"}, "/"]}},
136          {"!": {"endsWith": [{"var": "field_20.value"}, "/"]}},
137          {"!": {"includes": [{"var": "field_20.value"}, "//"]}},
138          {"!": {"startsWith": [{"var": "field_21.value"}, "/"]}},
139          {"!": {"endsWith": [{"var": "field_21.value"}, "/"]}},
140          {"!": {"includes": [{"var": "field_21.value"}, "//"]}}
141        ]
142      }
143    },
144    {
145      "id": "FIELD_11A_FORMAT",
146      "description": "Field 11a must have proper format when present",
147      "condition": {
148        "if": [
149          {"!!": {"var": "field_11a"}},
150          {">": [{"strlen": {"var": "field_11a.reference"}}, 8]},
151          true
152        ]
153      }
154    },
155    {
156      "id": "REQUIRED_FIELDS",
157      "description": "All mandatory fields must be present and non-empty",
158      "condition": {
159        "and": [
160          {"!=": [{"var": "field_20.value"}, ""]},
161          {"!=": [{"var": "field_21.value"}, ""]},
162          {"!!": {"var": "field_76"}},
163          {">": [{"count": {"var": "field_76.answer_lines"}}, 0]}
164        ]
165      }
166    },
167    {
168      "id": "ANSWER_CODE_VALIDATION",
169      "description": "Field 76 must contain valid answer codes",
170      "condition": {
171        "all": [
172          {"var": "field_76.answer_lines"},
173          {"!=": [{"var": ""}, ""]}
174        ]
175      }
176    }
177  ]
178}"#;