tap_msg/message/
cancel.rs

1//! Cancel message type for the Transaction Authorization Protocol.
2//!
3//! This module defines the Cancel message type, which is used
4//! for canceling transactions in the TAP protocol.
5
6use crate::error::{Error, Result};
7use crate::TapMessage;
8use serde::{Deserialize, Serialize};
9
10/// Cancel message body (TAIP-4).
11#[derive(Debug, Clone, Serialize, Deserialize, TapMessage)]
12#[tap(message_type = "https://tap.rsvp/schema/1.0#Cancel")]
13pub struct Cancel {
14    /// ID of the transfer being cancelled.
15    #[tap(thread_id)]
16    pub transaction_id: String,
17
18    /// The party of the transaction wishing to cancel it.
19    /// (In case of a Transfer [TAIP3] `originator` or `beneficiary`)
20    pub by: String,
21
22    /// Optional reason for cancellation.
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub reason: Option<String>,
25}
26
27impl Cancel {
28    /// Create a new Cancel message
29    pub fn new(transaction_id: &str, by: &str) -> Self {
30        Self {
31            transaction_id: transaction_id.to_string(),
32            by: by.to_string(),
33            reason: None,
34        }
35    }
36
37    /// Create a new Cancel message with a reason
38    pub fn with_reason(transaction_id: &str, by: &str, reason: &str) -> Self {
39        Self {
40            transaction_id: transaction_id.to_string(),
41            by: by.to_string(),
42            reason: Some(reason.to_string()),
43        }
44    }
45}
46
47impl Cancel {
48    /// Custom validation for Cancel messages
49    pub fn validate_cancel(&self) -> Result<()> {
50        if self.transaction_id.is_empty() {
51            return Err(Error::Validation(
52                "Cancel message must have a transaction_id".into(),
53            ));
54        }
55        if self.by.is_empty() {
56            return Err(Error::Validation(
57                "Cancel message must specify 'by' field".into(),
58            ));
59        }
60        Ok(())
61    }
62}