agentic_payments/acp/
models.rs

1//! ACP (Agentic Commerce Protocol) Data Models
2//!
3//! Core types for checkout sessions and payment delegation
4
5use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7
8/// Checkout Session Status
9#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
10#[serde(rename_all = "snake_case")]
11pub enum CheckoutStatus {
12    Created,
13    Active,
14    Completed,
15    Cancelled,
16    Expired,
17}
18
19/// Checkout Session - represents an active shopping session
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct CheckoutSession {
22    pub id: String,
23    pub status: CheckoutStatus,
24    pub amount: i64, // Amount in minor units (cents)
25    pub currency: String,
26    pub merchant_id: String,
27    pub items: Vec<CheckoutItem>,
28    pub created_at: i64, // Unix timestamp
29    pub expires_at: Option<i64>, // Unix timestamp
30}
31
32/// Checkout Item
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct CheckoutItem {
35    pub id: String,
36    pub name: String,
37    pub quantity: u32,
38    pub unit_price: i64,
39}
40
41impl CheckoutSession {
42    pub fn new(merchant_id: String, amount: i64, currency: String) -> Self {
43        Self {
44            id: format!("cs_{}", uuid::Uuid::new_v4()),
45            status: CheckoutStatus::Created,
46            amount,
47            currency,
48            merchant_id,
49            items: Vec::new(),
50            created_at: Utc::now().timestamp(),
51            expires_at: None,
52        }
53    }
54
55    pub fn add_item(&mut self, item: CheckoutItem) {
56        self.items.push(item);
57    }
58
59    pub fn is_valid(&self) -> bool {
60        match self.status {
61            CheckoutStatus::Created | CheckoutStatus::Active => {
62                if let Some(expires_at) = self.expires_at {
63                    Utc::now().timestamp() < expires_at
64                } else {
65                    true
66                }
67            }
68            _ => false,
69        }
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76
77    #[test]
78    fn test_checkout_session_creation() {
79        let session = CheckoutSession::new(
80            "merchant_123".to_string(),
81            5000,
82            "USD".to_string(),
83        );
84
85        assert_eq!(session.status, CheckoutStatus::Created);
86        assert_eq!(session.amount, 5000);
87        assert_eq!(session.currency, "USD");
88        assert!(session.is_valid());
89    }
90
91    #[test]
92    fn test_add_item() {
93        let mut session = CheckoutSession::new(
94            "merchant_123".to_string(),
95            5000,
96            "USD".to_string(),
97        );
98
99        let item = CheckoutItem {
100            id: "item_1".to_string(),
101            name: "Test Product".to_string(),
102            quantity: 2,
103            unit_price: 2500,
104        };
105
106        session.add_item(item);
107        assert_eq!(session.items.len(), 1);
108    }
109}