Offers, redemption, preview subscriptions (#4121)

* Initial db migration/impl, guarded partner routes

* Add guard to /redeem

* Add `public` column to products prices, only expose public prices

* Query cache

* Add partner subscription type

* 5 days subscription interval, metadata

* Create server on redeem

* Query cache

* Fix race condition

* Unprovision Medal subscriptions

* Consider due expiring charge as unprovisionable

* Query cache

* Use a queue

* Promote to full subscription, fmt + clippy

* Patch expiring charge on promotion, comments

* Additional comments

* Add `tags` field to Archon /create request

* Address review comments

* Query cache

* Final fixes to edit_subscription

* Appease clippy

* fmt
This commit is contained in:
François-Xavier Talbot
2025-08-11 17:40:58 -04:00
committed by GitHub
parent c02b809601
commit 9497ba70a4
25 changed files with 1604 additions and 276 deletions

View File

@@ -24,6 +24,13 @@ pub enum ProductMetadata {
swap: u32,
storage: u32,
},
Medal {
cpu: u32,
ram: u32,
swap: u32,
storage: u32,
region: String,
},
}
#[derive(Serialize, Deserialize)]
@@ -48,6 +55,7 @@ pub enum Price {
#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Debug, Copy, Clone)]
#[serde(rename_all = "kebab-case")]
pub enum PriceDuration {
FiveDays,
Monthly,
Quarterly,
Yearly,
@@ -56,6 +64,7 @@ pub enum PriceDuration {
impl PriceDuration {
pub fn duration(&self) -> chrono::Duration {
match self {
PriceDuration::FiveDays => chrono::Duration::days(5),
PriceDuration::Monthly => chrono::Duration::days(30),
PriceDuration::Quarterly => chrono::Duration::days(90),
PriceDuration::Yearly => chrono::Duration::days(365),
@@ -64,6 +73,7 @@ impl PriceDuration {
pub fn from_string(string: &str) -> PriceDuration {
match string {
"five-days" => PriceDuration::FiveDays,
"monthly" => PriceDuration::Monthly,
"quarterly" => PriceDuration::Quarterly,
"yearly" => PriceDuration::Yearly,
@@ -76,6 +86,7 @@ impl PriceDuration {
PriceDuration::Monthly => "monthly",
PriceDuration::Quarterly => "quarterly",
PriceDuration::Yearly => "yearly",
PriceDuration::FiveDays => "five-days",
}
}
@@ -84,6 +95,7 @@ impl PriceDuration {
PriceDuration::Monthly,
PriceDuration::Quarterly,
PriceDuration::Yearly,
PriceDuration::FiveDays,
]
.into_iter()
}
@@ -146,6 +158,7 @@ impl SubscriptionStatus {
#[serde(tag = "type", rename_all = "kebab-case")]
pub enum SubscriptionMetadata {
Pyro { id: String, region: Option<String> },
Medal { id: String },
}
#[derive(Serialize, Deserialize)]
@@ -201,12 +214,16 @@ impl ChargeType {
#[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 charges are for the next billing interval
Open,
Processing,
Succeeded,
Failed,
Cancelled,
/// Expiring charges are charges that aren't expected to be processed
/// but can be promoted to a full charge, like for trials/freebies. When
/// due, the underlying subscription is unprovisioned.
Expiring,
}
impl ChargeStatus {
@@ -217,6 +234,7 @@ impl ChargeStatus {
"failed" => ChargeStatus::Failed,
"open" => ChargeStatus::Open,
"cancelled" => ChargeStatus::Cancelled,
"expiring" => ChargeStatus::Expiring,
_ => ChargeStatus::Failed,
}
}
@@ -228,6 +246,7 @@ impl ChargeStatus {
ChargeStatus::Failed => "failed",
ChargeStatus::Open => "open",
ChargeStatus::Cancelled => "cancelled",
ChargeStatus::Expiring => "expiring",
}
}
}
@@ -235,12 +254,14 @@ impl ChargeStatus {
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub enum PaymentPlatform {
Stripe,
None,
}
impl PaymentPlatform {
pub fn from_string(string: &str) -> PaymentPlatform {
match string {
"stripe" => PaymentPlatform::Stripe,
"none" => PaymentPlatform::None,
_ => PaymentPlatform::Stripe,
}
}
@@ -248,6 +269,7 @@ impl PaymentPlatform {
pub fn as_str(&self) -> &'static str {
match self {
PaymentPlatform::Stripe => "stripe",
PaymentPlatform::None => "none",
}
}
}