use chrono::{DateTime, Utc};
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
use stateset_primitives::CurrencyCode;
use strum::{Display, EnumString};
use uuid::Uuid;
use super::agent_card::TrustLevel;
use super::cart::CartAddress;
use super::x402::{X402Asset, X402Network};
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct DiscoverSellersInput {
pub categories: Option<Vec<String>>,
pub query: Option<String>,
pub payment_networks: Option<Vec<X402Network>>,
pub payment_assets: Option<Vec<X402Asset>>,
pub min_trust_level: Option<TrustLevel>,
pub region: Option<String>,
pub limit: Option<u32>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DiscoverSellersOutput {
pub sellers: Vec<SellerInfo>,
pub total_count: u32,
pub has_more: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SellerInfo {
pub agent_id: Uuid,
pub name: String,
pub description: Option<String>,
pub payment_networks: Vec<X402Network>,
pub payment_assets: Vec<X402Asset>,
pub trust_level: TrustLevel,
pub category: Option<String>,
pub endpoint_url: Option<String>,
pub rating: Option<f32>,
pub transaction_count: Option<u32>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RequestQuoteInput {
pub seller_agent_id: Uuid,
pub items: Vec<QuoteItem>,
pub shipping_address: Option<CartAddress>,
pub payment_network: Option<X402Network>,
pub payment_asset: Option<X402Asset>,
pub notes: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QuoteItem {
pub sku: Option<String>,
pub name: String,
pub quantity: i32,
pub max_unit_price: Option<Decimal>,
pub specifications: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RequestQuoteOutput {
pub quote_id: Uuid,
pub quote_number: String,
pub status: QuoteStatus,
pub seller_agent_id: Uuid,
pub items: Vec<QuotedItem>,
pub subtotal: Decimal,
pub tax_amount: Decimal,
pub shipping_amount: Decimal,
pub discount_amount: Decimal,
pub total: Decimal,
pub currency: CurrencyCode,
pub payment_network: X402Network,
pub payment_asset: X402Asset,
pub valid_until: DateTime<Utc>,
pub estimated_delivery: Option<DateTime<Utc>>,
pub seller_notes: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QuotedItem {
pub line_number: u32,
pub sku: Option<String>,
pub name: String,
pub quantity: i32,
pub unit_price: Decimal,
pub total: Decimal,
pub availability: ItemAvailability,
pub lead_time_days: Option<i32>,
}
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Display, EnumString, Serialize, Deserialize, Default,
)]
#[strum(serialize_all = "snake_case", ascii_case_insensitive)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum QuoteStatus {
#[default]
Pending,
Quoted,
Accepted,
Rejected,
Expired,
Purchased,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum ItemAvailability {
#[default]
InStock,
LimitedStock,
Backorder,
OutOfStock,
Discontinued,
PreOrder,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InitiatePurchaseInput {
pub quote_id: Uuid,
pub payer_address: String,
pub network: X402Network,
pub asset: X402Asset,
pub shipping_address: Option<CartAddress>,
pub billing_address: Option<CartAddress>,
pub notes: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InitiatePurchaseOutput {
pub purchase_id: Uuid,
pub purchase_number: String,
pub status: PurchaseStatus,
pub payment_intent_id: Uuid,
pub signing_hash: String,
pub amount: u64,
pub amount_display: String,
pub asset: X402Asset,
pub network: X402Network,
pub payee_address: String,
pub valid_until: DateTime<Utc>,
pub cart_id: Option<Uuid>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, strum::Display, Serialize, Deserialize, Default)]
#[strum(serialize_all = "snake_case")]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum PurchaseStatus {
#[default]
Initiated,
PaymentPending,
Paid,
Fulfilling,
Shipped,
Delivered,
Completed,
Cancelled,
Disputed,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConfirmDeliveryInput {
pub purchase_id: Uuid,
pub confirmation_signature: String,
pub rating: Option<u8>,
pub feedback: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConfirmDeliveryOutput {
pub purchase_id: Uuid,
pub status: PurchaseStatus,
pub order_id: Option<Uuid>,
pub confirmed_at: DateTime<Utc>,
pub release_tx_hash: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct A2AQuote {
pub id: Uuid,
pub quote_number: String,
pub status: QuoteStatus,
pub buyer_agent_id: Uuid,
pub seller_agent_id: Uuid,
pub items: Vec<QuotedItem>,
pub subtotal: Decimal,
pub tax_amount: Decimal,
pub shipping_amount: Decimal,
pub discount_amount: Decimal,
pub total: Decimal,
pub currency: CurrencyCode,
pub payment_network: Option<X402Network>,
pub payment_asset: Option<X402Asset>,
pub shipping_address: Option<CartAddress>,
pub valid_until: DateTime<Utc>,
pub purchase_id: Option<Uuid>,
pub payment_intent_id: Option<Uuid>,
pub notes: Option<String>,
pub metadata: Option<String>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct A2APurchase {
pub id: Uuid,
pub purchase_number: String,
pub status: PurchaseStatus,
pub buyer_agent_id: Uuid,
pub seller_agent_id: Uuid,
pub quote_id: Option<Uuid>,
pub cart_id: Option<Uuid>,
pub order_id: Option<Uuid>,
pub payment_intent_id: Option<Uuid>,
pub items: Vec<QuotedItem>,
pub total: Decimal,
pub currency: CurrencyCode,
pub fulfillment_type: Option<String>,
pub tracking_info: Option<String>,
pub delivered_at: Option<DateTime<Utc>>,
pub delivery_confirmed_at: Option<DateTime<Utc>>,
pub delivery_confirmation_signature: Option<String>,
pub buyer_rating: Option<u8>,
pub buyer_feedback: Option<String>,
pub seller_rating: Option<u8>,
pub seller_feedback: Option<String>,
pub notes: Option<String>,
pub metadata: Option<String>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CreateA2AQuote {
pub buyer_agent_id: Uuid,
pub seller_agent_id: Uuid,
pub items: Vec<QuotedItem>,
pub subtotal: Decimal,
pub tax_amount: Option<Decimal>,
pub shipping_amount: Option<Decimal>,
pub discount_amount: Option<Decimal>,
pub total: Decimal,
pub currency: Option<CurrencyCode>,
pub payment_network: Option<X402Network>,
pub payment_asset: Option<X402Asset>,
pub shipping_address: Option<CartAddress>,
pub valid_until: DateTime<Utc>,
pub notes: Option<String>,
pub metadata: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CreateA2APurchase {
pub buyer_agent_id: Uuid,
pub seller_agent_id: Uuid,
pub quote_id: Option<Uuid>,
pub payment_intent_id: Option<Uuid>,
pub items: Vec<QuotedItem>,
pub total: Decimal,
pub currency: Option<CurrencyCode>,
pub fulfillment_type: Option<String>,
pub notes: Option<String>,
pub metadata: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct A2AQuoteFilter {
pub buyer_agent_id: Option<Uuid>,
pub seller_agent_id: Option<Uuid>,
pub status: Option<QuoteStatus>,
pub from_date: Option<DateTime<Utc>>,
pub to_date: Option<DateTime<Utc>>,
pub limit: Option<u32>,
pub offset: Option<u32>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct A2APurchaseFilter {
pub buyer_agent_id: Option<Uuid>,
pub seller_agent_id: Option<Uuid>,
pub status: Option<PurchaseStatus>,
pub order_id: Option<Uuid>,
pub from_date: Option<DateTime<Utc>>,
pub to_date: Option<DateTime<Utc>>,
pub limit: Option<u32>,
pub offset: Option<u32>,
}
#[cfg(test)]
mod tests {
use super::*;
use rust_decimal_macros::dec;
#[test]
fn test_quote_item_creation() {
let item = QuoteItem {
sku: Some("WIDGET-001".to_string()),
name: "Premium Widget".to_string(),
quantity: 5,
max_unit_price: Some(dec!(29.99)),
specifications: None,
};
assert_eq!(item.quantity, 5);
assert_eq!(item.max_unit_price, Some(dec!(29.99)));
}
#[test]
fn test_quote_status_display() {
assert_eq!(QuoteStatus::Pending.to_string(), "pending");
assert_eq!(QuoteStatus::Purchased.to_string(), "purchased");
}
#[test]
fn test_purchase_status_display() {
assert_eq!(PurchaseStatus::Initiated.to_string(), "initiated");
assert_eq!(PurchaseStatus::Completed.to_string(), "completed");
}
}