use chrono::{DateTime, Utc, Duration}; use serde::{Deserialize, Serialize}; use crate::db::core::{SledModel, Storable}; // Import Sled traits from new location /// Currency represents a monetary value with amount and currency code #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Currency { pub amount: f64, pub currency_code: String, } impl Currency { /// Create a new currency with amount and code pub fn new(amount: f64, currency_code: String) -> Self { Self { amount, currency_code, } } } /// ProductType represents the type of a product #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum ProductType { Product, Service, } /// ProductStatus represents the status of a product #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum ProductStatus { Available, Unavailable, } /// ProductComponent represents a component of a product #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ProductComponent { pub id: u32, pub name: String, pub description: String, pub quantity: i32, pub created_at: DateTime, pub updated_at: DateTime, } impl ProductComponent { /// Create a new product component with default timestamps pub fn new(id: u32, name: String, description: String, quantity: i32) -> Self { let now = Utc::now(); Self { id, name, description, quantity, created_at: now, updated_at: now, } } } /// Product represents a product or service offered by the Freezone #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Product { pub id: u32, pub name: String, pub description: String, pub price: Currency, pub type_: ProductType, pub category: String, pub status: ProductStatus, pub created_at: DateTime, pub updated_at: DateTime, pub max_amount: u16, // means allows us to define how many max of this there are pub purchase_till: DateTime, pub active_till: DateTime, // after this product no longer active if e.g. a service pub components: Vec, } // Removed old Model trait implementation impl Product { /// Create a new product with default timestamps pub fn new( id: u32, name: String, description: String, price: Currency, type_: ProductType, category: String, status: ProductStatus, max_amount: u16, validity_days: i64, // How many days the product is valid after purchase ) -> Self { let now = Utc::now(); // Default: purchasable for 1 year, active for specified validity days after purchase Self { id, name, description, price, type_, category, status, created_at: now, updated_at: now, max_amount, purchase_till: now + Duration::days(365), active_till: now + Duration::days(validity_days), components: Vec::new(), } } /// Add a component to this product pub fn add_component(&mut self, component: ProductComponent) { self.components.push(component); self.updated_at = Utc::now(); } /// Update the purchase availability timeframe pub fn set_purchase_period(&mut self, purchase_till: DateTime) { self.purchase_till = purchase_till; self.updated_at = Utc::now(); } /// Update the active timeframe pub fn set_active_period(&mut self, active_till: DateTime) { self.active_till = active_till; self.updated_at = Utc::now(); } /// Check if the product is available for purchase pub fn is_purchasable(&self) -> bool { self.status == ProductStatus::Available && Utc::now() <= self.purchase_till } /// Check if the product is still active (for services) pub fn is_active(&self) -> bool { Utc::now() <= self.active_till } } // Implement Storable trait (provides default dump/load) impl Storable for Product {} // Implement SledModel trait impl SledModel for Product { fn get_id(&self) -> String { self.id.to_string() } fn db_prefix() -> &'static str { "product" } }