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("23B", optional)]
74    pub field_23b: Option<GenericTextField>,
75
76    #[field("32A", optional)]
77    pub field_32a: Option<Field32A>,
78
79    #[field("50", optional)]
80    pub field_50: Option<Field50>,
81
82    #[field("59", optional)]
83    pub field_59: Option<Field59>,
84
85    #[field("71A", optional)]
86    pub field_71a: Option<GenericTextField>,
87}
88
89/// Enhanced validation rules for MT192
90const MT192_VALIDATION_RULES: &str = r#"{
91  "rules": [
92    {
93      "id": "CONDITIONAL_C1",
94      "description": "Either field 79 or copy of original message fields must be present, or both",
95      "condition": {
96        "or": [
97          {"!!": {"var": "field_79"}},
98          {
99            "or": [
100              {"!!": {"var": "field_23b"}},
101              {"!!": {"var": "field_32a"}},
102              {"!!": {"var": "field_50"}},
103              {"!!": {"var": "field_59"}},
104              {"!!": {"var": "field_71a"}}
105            ]
106          }
107        ]
108      }
109    },
110    {
111      "id": "REFERENCE_FORMAT",
112      "description": "Reference fields must not have invalid slash patterns",
113      "condition": {
114        "and": [
115          {"!": {"startsWith": [{"var": "field_20.value"}, "/"]}},
116          {"!": {"endsWith": [{"var": "field_20.value"}, "/"]}},
117          {"!": {"includes": [{"var": "field_20.value"}, "//"]}},
118          {"!": {"startsWith": [{"var": "field_21.value"}, "/"]}},
119          {"!": {"endsWith": [{"var": "field_21.value"}, "/"]}},
120          {"!": {"includes": [{"var": "field_21.value"}, "//"]}}
121        ]
122      }
123    },
124    {
125      "id": "FIELD_11S_FORMAT",
126      "description": "Field 11S must have proper format for MT and date reference",
127      "condition": {
128        "and": [
129          {"==": [{"strlen": {"var": "field_11s.message_type"}}, 3]},
130          {"==": [{"strlen": {"var": "field_11s.date"}}, 6]},
131          {"==": [{"strlen": {"var": "field_11s.session_number"}}, 4]},
132          {"==": [{"strlen": {"var": "field_11s.input_sequence_number"}}, 4]}
133        ]
134      }
135    },
136    {
137      "id": "REQUIRED_FIELDS",
138      "description": "All mandatory fields must be present and non-empty",
139      "condition": {
140        "and": [
141          {"!=": [{"var": "field_20.value"}, ""]},
142          {"!=": [{"var": "field_21.value"}, ""]},
143          {"!=": [{"var": "field_11s.message_type"}, ""]},
144          {"!=": [{"var": "field_11s.date"}, ""]}
145        ]
146      }
147    },
148    {
149      "id": "REASON_CODE_VALIDATION",
150      "description": "If field 79 is present, it should contain valid cancellation reason codes",
151      "condition": {
152        "if": [
153          {"!!": {"var": "field_79"}},
154          {
155            "or": [
156              {"includes": [{"var": "field_79.lines.0"}, "AGNT"]},
157              {"includes": [{"var": "field_79.lines.0"}, "AM09"]},
158              {"includes": [{"var": "field_79.lines.0"}, "COVR"]},
159              {"includes": [{"var": "field_79.lines.0"}, "CURR"]},
160              {"includes": [{"var": "field_79.lines.0"}, "CUST"]},
161              {"includes": [{"var": "field_79.lines.0"}, "CUTA"]},
162              {"includes": [{"var": "field_79.lines.0"}, "DUPL"]},
163              {"includes": [{"var": "field_79.lines.0"}, "FRAD"]},
164              {"includes": [{"var": "field_79.lines.0"}, "TECH"]},
165              {"includes": [{"var": "field_79.lines.0"}, "UPAY"]}
166            ]
167          },
168          true
169        ]
170      }
171    }
172  ]
173}"#;