swift_mt_message/messages/mt292.rs
1use crate::fields::*;
2use serde::{Deserialize, Serialize};
3use swift_mt_message_macros::{SwiftMessage, serde_swift_fields};
4
5/// # MT292: Request for Cancellation (Treasury)
6///
7/// This message is sent by a financial institution to request the cancellation
8/// of a previously sent treasury-related message. MT292 is used for cancellation
9/// requests related to treasury operations, interbank transfers, and institutional transactions.
10///
11/// ## Key Features
12/// - **Treasury cancellation**: Official request to cancel treasury/institutional messages
13/// - **Reference tracking**: Links to the original message through multiple reference fields
14/// - **Conditional structure**: Either narrative (field 79) or copy of original message fields
15/// - **Audit trail**: Maintains complete cancellation audit records for treasury operations
16/// - **Reason codes**: Standardized cancellation reason codes for institutional processing
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 must be present, or both.
21/// This structure is identical to MT192 but used for treasury/institutional contexts.
22///
23/// ## Cancellation Process
24/// Used when a treasury department or institutional sender needs to request cancellation
25/// of a previously sent message, typically MT2xx series messages for interbank transfers,
26/// due to errors, regulatory requirements, or operational changes.
27#[serde_swift_fields]
28#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, SwiftMessage)]
29#[validation_rules(MT292_VALIDATION_RULES)]
30pub struct MT292 {
31 /// **Transaction Reference Number** - Field 20
32 ///
33 /// Unique reference assigned by the sender for this treasury cancellation request.
34 /// This reference is used throughout the cancellation 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 to be cancelled.
42 /// This creates a direct link between the cancellation request and the original
43 /// treasury message, enabling the receiver to identify exactly which message to cancel.
44 #[field("21", mandatory)]
45 pub field_21: GenericReferenceField,
46
47 /// **MT and Date of the Original Message** - Field 11S
48 ///
49 /// Specifies the message type, date, session number, and Input Sequence Number (ISN)
50 /// of the original treasury message to be cancelled. Format: 3!n6!n4!n/4!n
51 /// Example: 202231215001/0123 (MT202 dated 2023-12-15, session 0001, ISN 0123)
52 #[field("11S", mandatory)]
53 pub field_11s: Field11S,
54
55 /// **Narrative Description of the Original Message** - Field 79 (Conditional)
56 ///
57 /// Contains cancellation reason codes and free-form text explaining the cancellation.
58 /// Must be present if copy of original message fields is not included, or both may be present.
59 /// Common reason codes: AGNT, AM09, COVR, CURR, CUST, CUTA, DUPL, FRAD, TECH, UPAY
60 #[field("79", optional)]
61 pub field_79: Option<GenericMultiLine6x35>,
62
63 /// **Copy of Mandatory Fields from Original Message** - Multiple Fields (Conditional)
64 ///
65 /// When present, contains a copy of at least the mandatory fields from the original treasury message.
66 /// This helps the receiver identify the exact treasury transaction to be cancelled.
67 /// The specific fields depend on the original message type referenced in field 11S.
68 ///
69 /// For MT202: Would include fields 32A, 53, 58
70 /// For MT205: Would include fields 32A, 53, 56, 57, 58
71 /// For MT210: Would include fields 32A, 53
72 ///
73 /// Note: This is represented as optional structured content that can contain
74 /// various field combinations depending on the original treasury message type.
75
76 #[field("32A", optional)]
77 pub field_32a: Option<Field32A>,
78
79 #[field("58A", optional)]
80 pub field_58a: Option<GenericBicField>,
81
82 #[field("52A", optional)]
83 pub field_52a: Option<GenericBicField>,
84
85 #[field("53A", optional)]
86 pub field_53a: Option<GenericBicField>,
87
88 #[field("56A", optional)]
89 pub field_56a: Option<GenericBicField>,
90
91 #[field("57A", optional)]
92 pub field_57a: Option<GenericBicField>,
93}
94
95/// Enhanced validation rules for MT292
96const MT292_VALIDATION_RULES: &str = r#"{
97 "rules": [
98 {
99 "id": "CONDITIONAL_C1",
100 "description": "Either field 79 or copy of original message fields must be present, or both",
101 "condition": {
102 "or": [
103 {"!!": {"var": "field_79"}},
104 {
105 "or": [
106 {"!!": {"var": "field_32a"}},
107 {"!!": {"var": "field_58a"}},
108 {"!!": {"var": "field_52a"}},
109 {"!!": {"var": "field_53a"}},
110 {"!!": {"var": "field_56a"}},
111 {"!!": {"var": "field_57a"}}
112 ]
113 }
114 ]
115 }
116 },
117 {
118 "id": "REFERENCE_FORMAT",
119 "description": "Reference fields must not have invalid slash patterns",
120 "condition": {
121 "and": [
122 {"!": {"startsWith": [{"var": "field_20.value"}, "/"]}},
123 {"!": {"endsWith": [{"var": "field_20.value"}, "/"]}},
124 {"!": {"includes": [{"var": "field_20.value"}, "//"]}},
125 {"!": {"startsWith": [{"var": "field_21.value"}, "/"]}},
126 {"!": {"endsWith": [{"var": "field_21.value"}, "/"]}},
127 {"!": {"includes": [{"var": "field_21.value"}, "//"]}}
128 ]
129 }
130 },
131 {
132 "id": "FIELD_11S_FORMAT",
133 "description": "Field 11S must have proper format for MT and date reference",
134 "condition": {
135 "and": [
136 {"==": [{"strlen": {"var": "field_11s.message_type"}}, 3]},
137 {"==": [{"strlen": {"var": "field_11s.date"}}, 6]},
138 {"==": [{"strlen": {"var": "field_11s.session_number"}}, 4]},
139 {"==": [{"strlen": {"var": "field_11s.input_sequence_number"}}, 4]}
140 ]
141 }
142 },
143 {
144 "id": "TREASURY_MESSAGE_TYPE",
145 "description": "Field 11S should reference valid treasury message types",
146 "condition": {
147 "in": [
148 {"var": "field_11s.message_type"},
149 ["200", "202", "205", "210", "256", "299"]
150 ]
151 }
152 },
153 {
154 "id": "REQUIRED_FIELDS",
155 "description": "All mandatory fields must be present and non-empty",
156 "condition": {
157 "and": [
158 {"!=": [{"var": "field_20.value"}, ""]},
159 {"!=": [{"var": "field_21.value"}, ""]},
160 {"!=": [{"var": "field_11s.message_type"}, ""]},
161 {"!=": [{"var": "field_11s.date"}, ""]}
162 ]
163 }
164 },
165 {
166 "id": "REASON_CODE_VALIDATION",
167 "description": "If field 79 is present, it should contain valid cancellation reason codes",
168 "condition": {
169 "if": [
170 {"!!": {"var": "field_79"}},
171 {
172 "or": [
173 {"includes": [{"var": "field_79.lines.0"}, "AGNT"]},
174 {"includes": [{"var": "field_79.lines.0"}, "AM09"]},
175 {"includes": [{"var": "field_79.lines.0"}, "COVR"]},
176 {"includes": [{"var": "field_79.lines.0"}, "CURR"]},
177 {"includes": [{"var": "field_79.lines.0"}, "CUST"]},
178 {"includes": [{"var": "field_79.lines.0"}, "CUTA"]},
179 {"includes": [{"var": "field_79.lines.0"}, "DUPL"]},
180 {"includes": [{"var": "field_79.lines.0"}, "FRAD"]},
181 {"includes": [{"var": "field_79.lines.0"}, "TECH"]},
182 {"includes": [{"var": "field_79.lines.0"}, "UPAY"]}
183 ]
184 },
185 true
186 ]
187 }
188 }
189 ]
190}"#;