tap_msg/message/
complete.rs

1//! Complete message type for the Transaction Authorization Protocol.
2//!
3//! This module defines the Complete message type, which is used
4//! for completing payment transactions in the TAP protocol.
5
6use serde::{Deserialize, Serialize};
7
8use crate::error::{Error, Result};
9use crate::TapMessage;
10
11/// Complete message body (TAIP-14).
12///
13/// Used to indicate completion of a payment transaction.
14#[derive(Debug, Clone, Serialize, Deserialize, TapMessage)]
15#[tap(message_type = "https://tap.rsvp/schema/1.0#Complete")]
16pub struct Complete {
17    /// ID of the payment being completed.
18    #[tap(thread_id)]
19    pub transaction_id: String,
20
21    /// Settlement address (CAIP-10 format) where payment was sent.
22    #[serde(rename = "settlementAddress")]
23    pub settlement_address: String,
24
25    /// Optional amount completed. If specified, must be less than or equal to the original amount.
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub amount: Option<String>,
28}
29
30impl Complete {
31    /// Create a new Complete message
32    pub fn new(transaction_id: &str, settlement_address: &str) -> Self {
33        Self {
34            transaction_id: transaction_id.to_string(),
35            settlement_address: settlement_address.to_string(),
36            amount: None,
37        }
38    }
39
40    /// Create a new Complete message with an amount
41    pub fn with_amount(transaction_id: &str, settlement_address: &str, amount: &str) -> Self {
42        Self {
43            transaction_id: transaction_id.to_string(),
44            settlement_address: settlement_address.to_string(),
45            amount: Some(amount.to_string()),
46        }
47    }
48}
49
50impl Complete {
51    /// Custom validation for Complete messages
52    pub fn validate_complete(&self) -> Result<()> {
53        if self.transaction_id.is_empty() {
54            return Err(Error::Validation(
55                "Transaction ID is required in Complete".to_string(),
56            ));
57        }
58
59        if self.settlement_address.is_empty() {
60            return Err(Error::Validation(
61                "Settlement address is required in Complete".to_string(),
62            ));
63        }
64
65        // Validate settlement address format (basic CAIP-10 check)
66        if !self.settlement_address.contains(':') {
67            return Err(Error::Validation(
68                "Settlement address must be in CAIP-10 format".to_string(),
69            ));
70        }
71
72        if let Some(amount) = &self.amount {
73            if amount.is_empty() {
74                return Err(Error::Validation(
75                    "Amount cannot be empty when provided".to_string(),
76                ));
77            }
78        }
79
80        Ok(())
81    }
82
83    /// Validation method that will be called by TapMessageBody trait
84    pub fn validate(&self) -> Result<()> {
85        self.validate_complete()
86    }
87}