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}"#;