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