1use chrono::{DateTime, Utc};
7use rust_decimal::Decimal;
8use serde::{Deserialize, Serialize};
9use stateset_primitives::CurrencyCode;
10use strum::{Display, EnumString};
11use uuid::Uuid;
12
13use super::agent_card::TrustLevel;
14use super::cart::CartAddress;
15use super::x402::{X402Asset, X402Network};
16
17#[derive(Debug, Clone, Default, Serialize, Deserialize)]
23pub struct DiscoverSellersInput {
24 pub categories: Option<Vec<String>>,
26 pub query: Option<String>,
28 pub payment_networks: Option<Vec<X402Network>>,
30 pub payment_assets: Option<Vec<X402Asset>>,
32 pub min_trust_level: Option<TrustLevel>,
34 pub region: Option<String>,
36 pub limit: Option<u32>,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct DiscoverSellersOutput {
43 pub sellers: Vec<SellerInfo>,
45 pub total_count: u32,
47 pub has_more: bool,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct SellerInfo {
54 pub agent_id: Uuid,
56 pub name: String,
58 pub description: Option<String>,
60 pub payment_networks: Vec<X402Network>,
62 pub payment_assets: Vec<X402Asset>,
64 pub trust_level: TrustLevel,
66 pub category: Option<String>,
68 pub endpoint_url: Option<String>,
70 pub rating: Option<f32>,
72 pub transaction_count: Option<u32>,
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct RequestQuoteInput {
83 pub seller_agent_id: Uuid,
85 pub items: Vec<QuoteItem>,
87 pub shipping_address: Option<CartAddress>,
89 pub payment_network: Option<X402Network>,
91 pub payment_asset: Option<X402Asset>,
93 pub notes: Option<String>,
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct QuoteItem {
100 pub sku: Option<String>,
102 pub name: String,
104 pub quantity: i32,
106 pub max_unit_price: Option<Decimal>,
108 pub specifications: Option<String>,
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct RequestQuoteOutput {
115 pub quote_id: Uuid,
117 pub quote_number: String,
119 pub status: QuoteStatus,
121 pub seller_agent_id: Uuid,
123 pub items: Vec<QuotedItem>,
125 pub subtotal: Decimal,
127 pub tax_amount: Decimal,
129 pub shipping_amount: Decimal,
131 pub discount_amount: Decimal,
133 pub total: Decimal,
135 pub currency: CurrencyCode,
137 pub payment_network: X402Network,
139 pub payment_asset: X402Asset,
141 pub valid_until: DateTime<Utc>,
143 pub estimated_delivery: Option<DateTime<Utc>>,
145 pub seller_notes: Option<String>,
147}
148
149#[derive(Debug, Clone, Serialize, Deserialize)]
151pub struct QuotedItem {
152 pub line_number: u32,
154 pub sku: Option<String>,
156 pub name: String,
158 pub quantity: i32,
160 pub unit_price: Decimal,
162 pub total: Decimal,
164 pub availability: ItemAvailability,
166 pub lead_time_days: Option<i32>,
168}
169
170#[derive(
172 Debug, Clone, Copy, PartialEq, Eq, Display, EnumString, Serialize, Deserialize, Default,
173)]
174#[strum(serialize_all = "snake_case", ascii_case_insensitive)]
175#[serde(rename_all = "snake_case")]
176#[non_exhaustive]
177pub enum QuoteStatus {
178 #[default]
180 Pending,
181 Quoted,
183 Accepted,
185 Rejected,
187 Expired,
189 Purchased,
191}
192
193#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
195#[serde(rename_all = "snake_case")]
196#[non_exhaustive]
197pub enum ItemAvailability {
198 #[default]
200 InStock,
201 LimitedStock,
203 Backorder,
205 OutOfStock,
207 Discontinued,
209 PreOrder,
211}
212
213#[derive(Debug, Clone, Serialize, Deserialize)]
219pub struct InitiatePurchaseInput {
220 pub quote_id: Uuid,
222 pub payer_address: String,
224 pub network: X402Network,
226 pub asset: X402Asset,
228 pub shipping_address: Option<CartAddress>,
230 pub billing_address: Option<CartAddress>,
232 pub notes: Option<String>,
234}
235
236#[derive(Debug, Clone, Serialize, Deserialize)]
238pub struct InitiatePurchaseOutput {
239 pub purchase_id: Uuid,
241 pub purchase_number: String,
243 pub status: PurchaseStatus,
245 pub payment_intent_id: Uuid,
247 pub signing_hash: String,
249 pub amount: u64,
251 pub amount_display: String,
253 pub asset: X402Asset,
255 pub network: X402Network,
257 pub payee_address: String,
259 pub valid_until: DateTime<Utc>,
261 pub cart_id: Option<Uuid>,
263}
264
265#[derive(Debug, Clone, Copy, PartialEq, Eq, strum::Display, Serialize, Deserialize, Default)]
267#[strum(serialize_all = "snake_case")]
268#[serde(rename_all = "snake_case")]
269#[non_exhaustive]
270pub enum PurchaseStatus {
271 #[default]
273 Initiated,
274 PaymentPending,
276 Paid,
278 Fulfilling,
280 Shipped,
282 Delivered,
284 Completed,
286 Cancelled,
288 Disputed,
290}
291
292#[derive(Debug, Clone, Serialize, Deserialize)]
298pub struct ConfirmDeliveryInput {
299 pub purchase_id: Uuid,
301 pub confirmation_signature: String,
303 pub rating: Option<u8>,
305 pub feedback: Option<String>,
307}
308
309#[derive(Debug, Clone, Serialize, Deserialize)]
311pub struct ConfirmDeliveryOutput {
312 pub purchase_id: Uuid,
314 pub status: PurchaseStatus,
316 pub order_id: Option<Uuid>,
318 pub confirmed_at: DateTime<Utc>,
320 pub release_tx_hash: Option<String>,
322}
323
324#[derive(Debug, Clone, Serialize, Deserialize)]
330pub struct A2AQuote {
331 pub id: Uuid,
332 pub quote_number: String,
333 pub status: QuoteStatus,
334 pub buyer_agent_id: Uuid,
335 pub seller_agent_id: Uuid,
336 pub items: Vec<QuotedItem>,
337 pub subtotal: Decimal,
338 pub tax_amount: Decimal,
339 pub shipping_amount: Decimal,
340 pub discount_amount: Decimal,
341 pub total: Decimal,
342 pub currency: CurrencyCode,
343 pub payment_network: Option<X402Network>,
344 pub payment_asset: Option<X402Asset>,
345 pub shipping_address: Option<CartAddress>,
346 pub valid_until: DateTime<Utc>,
347 pub purchase_id: Option<Uuid>,
348 pub payment_intent_id: Option<Uuid>,
349 pub notes: Option<String>,
350 pub metadata: Option<String>,
351 pub created_at: DateTime<Utc>,
352 pub updated_at: DateTime<Utc>,
353}
354
355#[derive(Debug, Clone, Serialize, Deserialize)]
361pub struct A2APurchase {
362 pub id: Uuid,
363 pub purchase_number: String,
364 pub status: PurchaseStatus,
365 pub buyer_agent_id: Uuid,
366 pub seller_agent_id: Uuid,
367 pub quote_id: Option<Uuid>,
368 pub cart_id: Option<Uuid>,
369 pub order_id: Option<Uuid>,
370 pub payment_intent_id: Option<Uuid>,
371 pub items: Vec<QuotedItem>,
372 pub total: Decimal,
373 pub currency: CurrencyCode,
374 pub fulfillment_type: Option<String>,
375 pub tracking_info: Option<String>,
376 pub delivered_at: Option<DateTime<Utc>>,
377 pub delivery_confirmed_at: Option<DateTime<Utc>>,
378 pub delivery_confirmation_signature: Option<String>,
379 pub buyer_rating: Option<u8>,
380 pub buyer_feedback: Option<String>,
381 pub seller_rating: Option<u8>,
382 pub seller_feedback: Option<String>,
383 pub notes: Option<String>,
384 pub metadata: Option<String>,
385 pub created_at: DateTime<Utc>,
386 pub updated_at: DateTime<Utc>,
387}
388
389#[derive(Debug, Clone, Default, Serialize, Deserialize)]
395pub struct CreateA2AQuote {
396 pub buyer_agent_id: Uuid,
397 pub seller_agent_id: Uuid,
398 pub items: Vec<QuotedItem>,
399 pub subtotal: Decimal,
400 pub tax_amount: Option<Decimal>,
401 pub shipping_amount: Option<Decimal>,
402 pub discount_amount: Option<Decimal>,
403 pub total: Decimal,
404 pub currency: Option<CurrencyCode>,
405 pub payment_network: Option<X402Network>,
406 pub payment_asset: Option<X402Asset>,
407 pub shipping_address: Option<CartAddress>,
408 pub valid_until: DateTime<Utc>,
409 pub notes: Option<String>,
410 pub metadata: Option<String>,
411}
412
413#[derive(Debug, Clone, Default, Serialize, Deserialize)]
415pub struct CreateA2APurchase {
416 pub buyer_agent_id: Uuid,
417 pub seller_agent_id: Uuid,
418 pub quote_id: Option<Uuid>,
419 pub payment_intent_id: Option<Uuid>,
420 pub items: Vec<QuotedItem>,
421 pub total: Decimal,
422 pub currency: Option<CurrencyCode>,
423 pub fulfillment_type: Option<String>,
424 pub notes: Option<String>,
425 pub metadata: Option<String>,
426}
427
428#[derive(Debug, Clone, Default, Serialize, Deserialize)]
430pub struct A2AQuoteFilter {
431 pub buyer_agent_id: Option<Uuid>,
432 pub seller_agent_id: Option<Uuid>,
433 pub status: Option<QuoteStatus>,
434 pub from_date: Option<DateTime<Utc>>,
435 pub to_date: Option<DateTime<Utc>>,
436 pub limit: Option<u32>,
437 pub offset: Option<u32>,
438}
439
440#[derive(Debug, Clone, Default, Serialize, Deserialize)]
442pub struct A2APurchaseFilter {
443 pub buyer_agent_id: Option<Uuid>,
444 pub seller_agent_id: Option<Uuid>,
445 pub status: Option<PurchaseStatus>,
446 pub order_id: Option<Uuid>,
447 pub from_date: Option<DateTime<Utc>>,
448 pub to_date: Option<DateTime<Utc>>,
449 pub limit: Option<u32>,
450 pub offset: Option<u32>,
451}
452
453#[cfg(test)]
454mod tests {
455 use super::*;
456 use rust_decimal_macros::dec;
457
458 #[test]
459 fn test_quote_item_creation() {
460 let item = QuoteItem {
461 sku: Some("WIDGET-001".to_string()),
462 name: "Premium Widget".to_string(),
463 quantity: 5,
464 max_unit_price: Some(dec!(29.99)),
465 specifications: None,
466 };
467
468 assert_eq!(item.quantity, 5);
469 assert_eq!(item.max_unit_price, Some(dec!(29.99)));
470 }
471
472 #[test]
473 fn test_quote_status_display() {
474 assert_eq!(QuoteStatus::Pending.to_string(), "pending");
475 assert_eq!(QuoteStatus::Purchased.to_string(), "purchased");
476 }
477
478 #[test]
479 fn test_purchase_status_display() {
480 assert_eq!(PurchaseStatus::Initiated.to_string(), "initiated");
481 assert_eq!(PurchaseStatus::Completed.to_string(), "completed");
482 }
483}