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