tap_msg/message/
settle.rs1use crate::didcomm::PlainMessage;
7use crate::error::{Error, Result};
8use crate::impl_tap_message;
9use crate::message::tap_message_trait::TapMessageBody;
10use chrono::Utc;
11use serde::{Deserialize, Serialize};
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct Settle {
16 pub transaction_id: String,
18
19 pub settlement_id: String,
21
22 #[serde(skip_serializing_if = "Option::is_none")]
24 pub amount: Option<String>,
25}
26
27impl Settle {
28 pub fn new(transaction_id: &str, settlement_id: &str) -> Self {
30 Self {
31 transaction_id: transaction_id.to_string(),
32 settlement_id: settlement_id.to_string(),
33 amount: None,
34 }
35 }
36
37 pub fn with_amount(transaction_id: &str, settlement_id: &str, amount: &str) -> Self {
39 Self {
40 transaction_id: transaction_id.to_string(),
41 settlement_id: settlement_id.to_string(),
42 amount: Some(amount.to_string()),
43 }
44 }
45}
46
47impl TapMessageBody for Settle {
48 fn message_type() -> &'static str {
49 "https://tap.rsvp/schema/1.0#settle"
50 }
51
52 fn validate(&self) -> Result<()> {
53 if self.transaction_id.is_empty() {
54 return Err(Error::Validation(
55 "Transaction ID is required in Settle".to_string(),
56 ));
57 }
58
59 if self.settlement_id.is_empty() {
60 return Err(Error::Validation(
61 "Settlement ID is required in Settle".to_string(),
62 ));
63 }
64
65 if let Some(amount) = &self.amount {
66 if amount.is_empty() {
67 return Err(Error::Validation(
68 "Amount must be a valid number".to_string(),
69 ));
70 }
71
72 match amount.parse::<f64>() {
74 Ok(amount) if amount <= 0.0 => {
75 return Err(Error::Validation("Amount must be positive".to_string()));
76 }
77 Err(_) => {
78 return Err(Error::Validation(
79 "Amount must be a valid number".to_string(),
80 ));
81 }
82 _ => {}
83 }
84 }
85
86 Ok(())
87 }
88
89 fn to_didcomm(&self, from_did: &str) -> Result<PlainMessage> {
90 let mut body_json =
92 serde_json::to_value(self).map_err(|e| Error::SerializationError(e.to_string()))?;
93
94 if let Some(body_obj) = body_json.as_object_mut() {
96 body_obj.insert(
98 "@type".to_string(),
99 serde_json::Value::String(Self::message_type().to_string()),
100 );
101 }
102
103 let id = uuid::Uuid::new_v4().to_string();
105 let created_time = Utc::now().timestamp() as u64;
106
107 let message = PlainMessage {
109 id,
110 typ: "application/didcomm-plain+json".to_string(),
111 type_: Self::message_type().to_string(),
112 from: from_did.to_string(),
113 to: Vec::new(), thid: Some(self.transaction_id.clone()),
115 pthid: None,
116 created_time: Some(created_time),
117 expires_time: None,
118 extra_headers: std::collections::HashMap::new(),
119 from_prior: None,
120 body: body_json,
121 attachments: None,
122 };
123
124 Ok(message)
125 }
126}
127
128impl_tap_message!(Settle);