swift_mt_message/messages/
mt192.rs

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