You've already forked AstralRinth
Move charges to DB + fix subscription recurring payments (#971)
* Move charges to DB + fix subscription recurring payments * Finish most + pyro integration * Finish billing * Run prepare * Fix intervals * Fix clippy * Remove unused test
This commit is contained in:
@@ -21,6 +21,7 @@ pub struct Product {
|
||||
#[serde(tag = "type", rename_all = "kebab-case")]
|
||||
pub enum ProductMetadata {
|
||||
Midas,
|
||||
Pyro { ram: u32 },
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
@@ -55,6 +56,13 @@ pub enum PriceDuration {
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -84,8 +92,7 @@ pub struct UserSubscription {
|
||||
pub interval: PriceDuration,
|
||||
pub status: SubscriptionStatus,
|
||||
pub created: DateTime<Utc>,
|
||||
pub expires: DateTime<Utc>,
|
||||
pub last_charge: Option<DateTime<Utc>>,
|
||||
pub metadata: Option<SubscriptionMetadata>,
|
||||
}
|
||||
|
||||
impl From<crate::database::models::user_subscription_item::UserSubscriptionItem>
|
||||
@@ -99,38 +106,119 @@ impl From<crate::database::models::user_subscription_item::UserSubscriptionItem>
|
||||
interval: x.interval,
|
||||
status: x.status,
|
||||
created: x.created,
|
||||
expires: x.expires,
|
||||
last_charge: x.last_charge,
|
||||
metadata: x.metadata,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Eq, PartialEq)]
|
||||
#[derive(Serialize, Deserialize, Eq, PartialEq, Copy, Clone)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum SubscriptionStatus {
|
||||
Active,
|
||||
PaymentProcessing,
|
||||
PaymentFailed,
|
||||
Cancelled,
|
||||
Provisioned,
|
||||
Unprovisioned,
|
||||
}
|
||||
|
||||
impl SubscriptionStatus {
|
||||
pub fn from_string(string: &str) -> SubscriptionStatus {
|
||||
match string {
|
||||
"active" => SubscriptionStatus::Active,
|
||||
"payment-processing" => SubscriptionStatus::PaymentProcessing,
|
||||
"payment-failed" => SubscriptionStatus::PaymentFailed,
|
||||
"cancelled" => SubscriptionStatus::Cancelled,
|
||||
_ => SubscriptionStatus::Cancelled,
|
||||
"provisioned" => SubscriptionStatus::Provisioned,
|
||||
"unprovisioned" => SubscriptionStatus::Unprovisioned,
|
||||
_ => SubscriptionStatus::Provisioned,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
SubscriptionStatus::Active => "active",
|
||||
SubscriptionStatus::PaymentProcessing => "payment-processing",
|
||||
SubscriptionStatus::PaymentFailed => "payment-failed",
|
||||
SubscriptionStatus::Cancelled => "cancelled",
|
||||
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<Utc>,
|
||||
pub last_attempt: Option<DateTime<Utc>>,
|
||||
#[serde(flatten)]
|
||||
pub type_: ChargeType,
|
||||
pub subscription_id: Option<UserSubscriptionId>,
|
||||
pub subscription_interval: Option<PriceDuration>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(tag = "type", rename_all = "kebab-case")]
|
||||
pub enum ChargeType {
|
||||
OneTime,
|
||||
Subscription,
|
||||
Proration,
|
||||
}
|
||||
|
||||
impl ChargeType {
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
ChargeType::OneTime => "one-time",
|
||||
ChargeType::Subscription { .. } => "subscription",
|
||||
ChargeType::Proration { .. } => "proration",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_string(string: &str) -> ChargeType {
|
||||
match string {
|
||||
"one-time" => ChargeType::OneTime,
|
||||
"subscription" => ChargeType::Subscription,
|
||||
"proration" => ChargeType::Proration,
|
||||
_ => ChargeType::OneTime,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Eq, PartialEq, Copy, Clone)]
|
||||
#[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",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,7 @@ pub use super::teams::TeamId;
|
||||
pub use super::threads::ThreadId;
|
||||
pub use super::threads::ThreadMessageId;
|
||||
pub use super::users::UserId;
|
||||
pub use crate::models::billing::UserSubscriptionId;
|
||||
pub use crate::models::v3::billing::{ProductId, ProductPriceId};
|
||||
pub use crate::models::billing::{ChargeId, ProductId, ProductPriceId, UserSubscriptionId};
|
||||
use thiserror::Error;
|
||||
|
||||
/// Generates a random 64 bit integer that is exactly `n` characters
|
||||
@@ -137,6 +136,7 @@ base62_id_impl!(PayoutId, PayoutId);
|
||||
base62_id_impl!(ProductId, ProductId);
|
||||
base62_id_impl!(ProductPriceId, ProductPriceId);
|
||||
base62_id_impl!(UserSubscriptionId, UserSubscriptionId);
|
||||
base62_id_impl!(ChargeId, ChargeId);
|
||||
|
||||
pub mod base62_impl {
|
||||
use serde::de::{self, Deserializer, Visitor};
|
||||
|
||||
Reference in New Issue
Block a user