use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; #[derive(Deserialize)] pub struct ActivityInput { pub sku_id: Uuid, pub name: serde_json::Value, #[serde(default)] pub description: Option, #[serde(default)] pub image: Option, pub group_price_minor: i64, pub currency: String, pub required_members: i32, pub starts_at: DateTime, pub ends_at: DateTime, pub group_lifetime_hours: i32, #[serde(default = "default_enabled")] pub enabled: bool, } fn default_enabled() -> bool { true } /// Checkout intent: one activity SKU at quantity 1, either joining an open /// group or asking to open a new one. #[derive(Deserialize, Clone, Copy)] pub struct GroupBuyIntent { pub activity_id: Uuid, pub sku_id: Uuid, #[serde(default)] pub group_id: Option, } #[derive(Debug, Serialize, sqlx::FromRow)] pub struct OpenGroupView { pub id: Uuid, pub paid_member_count: i32, pub required_members: i32, pub expires_at: DateTime, } /// Activity plus the SKU/catalog details both surfaces need, with its open /// groups for discovery. #[derive(Debug, Serialize, sqlx::FromRow)] pub struct ActivityView { pub id: Uuid, pub shop_id: Uuid, pub sku_id: Uuid, pub name: serde_json::Value, pub description: Option, pub image: Option, pub group_price_minor: i64, pub currency: String, pub required_members: i32, pub starts_at: DateTime, pub ends_at: DateTime, pub group_lifetime_hours: i32, pub enabled: bool, pub created_at: DateTime, pub updated_at: DateTime, pub sku_code: String, pub product_id: Uuid, pub product_slug: String, pub product_name: serde_json::Value, pub original_price_minor: i64, pub original_currency: String, #[sqlx(skip)] pub open_groups: Vec, } /// Outcome of validating a checkout intent. pub struct ResolvedIntent { pub activity_id: Uuid, pub group_id: Uuid, pub shop_id: Uuid, pub unit_price_minor: i64, /// True when checkout opened the group rather than joining one. pub opened: bool, }