use crate::models::ids::Base62Id; use crate::models::ids::UserId; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; #[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)] #[serde(from = "Base62Id")] #[serde(into = "Base62Id")] pub struct ProductId(pub u64); #[derive(Serialize, Deserialize)] pub struct Product { pub id: ProductId, pub metadata: ProductMetadata, pub prices: Vec, pub unitary: bool, } #[derive(Serialize, Deserialize)] #[serde(tag = "type", rename_all = "kebab-case")] pub enum ProductMetadata { Midas, Pyro { cpu: u32, ram: u32, swap: u32, storage: u32, }, } #[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)] #[serde(from = "Base62Id")] #[serde(into = "Base62Id")] pub struct ProductPriceId(pub u64); #[derive(Serialize, Deserialize)] pub struct ProductPrice { pub id: ProductPriceId, pub product_id: ProductId, pub prices: Price, pub currency_code: String, } #[derive(Serialize, Deserialize)] #[serde(tag = "type", rename_all = "kebab-case")] pub enum Price { OneTime { price: i32, }, Recurring { intervals: HashMap, }, } #[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Debug, Copy, Clone)] #[serde(rename_all = "kebab-case")] pub enum PriceDuration { Monthly, Yearly, } impl PriceDuration { pub fn duration(&self) -> chrono::Duration { match self { PriceDuration::Monthly => chrono::Duration::days(30), PriceDuration::Yearly => chrono::Duration::days(365), } } pub fn from_string(string: &str) -> PriceDuration { match string { "monthly" => PriceDuration::Monthly, "yearly" => PriceDuration::Yearly, _ => PriceDuration::Monthly, } } pub fn as_str(&self) -> &'static str { match self { PriceDuration::Monthly => "monthly", PriceDuration::Yearly => "yearly", } } pub fn iterator() -> impl Iterator { vec![PriceDuration::Monthly, PriceDuration::Yearly].into_iter() } } #[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)] #[serde(from = "Base62Id")] #[serde(into = "Base62Id")] pub struct UserSubscriptionId(pub u64); #[derive(Serialize, Deserialize)] pub struct UserSubscription { pub id: UserSubscriptionId, pub user_id: UserId, pub price_id: ProductPriceId, pub interval: PriceDuration, pub status: SubscriptionStatus, pub created: DateTime, pub metadata: Option, } impl From for UserSubscription { fn from( x: crate::database::models::user_subscription_item::UserSubscriptionItem, ) -> Self { Self { id: x.id.into(), user_id: x.user_id.into(), price_id: x.price_id.into(), interval: x.interval, status: x.status, created: x.created, metadata: x.metadata, } } } #[derive(Serialize, Deserialize, Eq, PartialEq, Copy, Clone)] #[serde(rename_all = "kebab-case")] pub enum SubscriptionStatus { Provisioned, Unprovisioned, } impl SubscriptionStatus { pub fn from_string(string: &str) -> SubscriptionStatus { match string { "provisioned" => SubscriptionStatus::Provisioned, "unprovisioned" => SubscriptionStatus::Unprovisioned, _ => SubscriptionStatus::Provisioned, } } pub fn as_str(&self) -> &'static str { match self { SubscriptionStatus::Provisioned => "provisioned", SubscriptionStatus::Unprovisioned => "unprovisioned", } } } #[derive(Serialize, Deserialize)] #[serde(tag = "type", rename_all = "kebab-case")] pub enum SubscriptionMetadata { Pyro { id: String }, } #[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)] #[serde(from = "Base62Id")] #[serde(into = "Base62Id")] pub struct ChargeId(pub u64); #[derive(Serialize, Deserialize)] pub struct Charge { pub id: ChargeId, pub user_id: UserId, pub price_id: ProductPriceId, pub amount: i64, pub currency_code: String, pub status: ChargeStatus, pub due: DateTime, pub last_attempt: Option>, #[serde(flatten)] pub type_: ChargeType, pub subscription_id: Option, pub subscription_interval: Option, pub platform: PaymentPlatform, pub parent_charge_id: Option, pub net: Option, } #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)] #[serde(tag = "type", rename_all = "kebab-case")] pub enum ChargeType { OneTime, Subscription, Proration, Refund, } impl ChargeType { pub fn as_str(&self) -> &'static str { match self { ChargeType::OneTime => "one-time", ChargeType::Subscription => "subscription", ChargeType::Proration => "proration", ChargeType::Refund => "refund", } } pub fn from_string(string: &str) -> ChargeType { match string { "one-time" => ChargeType::OneTime, "subscription" => ChargeType::Subscription, "proration" => ChargeType::Proration, "refund" => ChargeType::Refund, _ => ChargeType::OneTime, } } } #[derive(Serialize, Deserialize, Eq, PartialEq, Copy, Clone, Debug)] #[serde(rename_all = "kebab-case")] pub enum ChargeStatus { // Open charges are for the next billing interval Open, Processing, Succeeded, Failed, Cancelled, } impl ChargeStatus { pub fn from_string(string: &str) -> ChargeStatus { match string { "processing" => ChargeStatus::Processing, "succeeded" => ChargeStatus::Succeeded, "failed" => ChargeStatus::Failed, "open" => ChargeStatus::Open, "cancelled" => ChargeStatus::Cancelled, _ => ChargeStatus::Failed, } } pub fn as_str(&self) -> &'static str { match self { ChargeStatus::Processing => "processing", ChargeStatus::Succeeded => "succeeded", ChargeStatus::Failed => "failed", ChargeStatus::Open => "open", ChargeStatus::Cancelled => "cancelled", } } } #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)] pub enum PaymentPlatform { Stripe, } impl PaymentPlatform { pub fn from_string(string: &str) -> PaymentPlatform { match string { "stripe" => PaymentPlatform::Stripe, _ => PaymentPlatform::Stripe, } } pub fn as_str(&self) -> &'static str { match self { PaymentPlatform::Stripe => "stripe", } } }