Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

Commit

Permalink
Fix new charge date, pyro suspend reason
Browse files Browse the repository at this point in the history
  • Loading branch information
Geometrically committed Oct 14, 2024
1 parent 9846435 commit 0c17663
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 96 deletions.

This file was deleted.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions src/database/models/charge_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,22 @@ impl ChargeItem {
.collect::<Result<Vec<_>, serde_json::Error>>()?)
}

pub async fn get_unprovision(
exec: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
) -> Result<Vec<ChargeItem>, DatabaseError> {
let now = Utc::now();

let res =
select_charges_with_predicate!("WHERE (status = 'cancelled' AND due < $1) OR (status = 'failed' AND last_attempt < $1 - INTERVAL '2 days')", now)
.fetch_all(exec)
.await?;

Ok(res
.into_iter()
.map(|r| r.try_into())
.collect::<Result<Vec<_>, serde_json::Error>>()?)
}

pub async fn remove(
id: ChargeId,
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
Expand Down
24 changes: 0 additions & 24 deletions src/database/models/user_subscription_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,30 +95,6 @@ impl UserSubscriptionItem {
.collect::<Result<Vec<_>, serde_json::Error>>()?)
}

pub async fn get_all_unprovision(
exec: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
) -> Result<Vec<UserSubscriptionItem>, DatabaseError> {
let now = Utc::now();
let results = select_user_subscriptions_with_predicate!(
"
INNER JOIN charges c
ON c.subscription_id = us.id
AND (
(c.status = 'cancelled' AND c.due < $1) OR
(c.status = 'failed' AND c.last_attempt < $1 - INTERVAL '2 days')
)
",
now
)
.fetch_all(exec)
.await?;

Ok(results
.into_iter()
.map(|r| r.try_into())
.collect::<Result<Vec<_>, serde_json::Error>>()?)
}

pub async fn upsert(
&self,
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
Expand Down
60 changes: 46 additions & 14 deletions src/routes/internal/billing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1178,11 +1178,7 @@ pub async fn stripe_webhook(
price_id,
interval,
created: Utc::now(),
status: if charge_status == ChargeStatus::Succeeded {
SubscriptionStatus::Provisioned
} else {
SubscriptionStatus::Unprovisioned
},
status: SubscriptionStatus::Unprovisioned,
metadata: None,
};

Expand Down Expand Up @@ -1342,16 +1338,18 @@ pub async fn stripe_webhook(
.json::<PyroServerResponse>()
.await?;

if let Some(ref mut subscription) = metadata.user_subscription_item {
subscription.metadata = Some(SubscriptionMetadata::Pyro { id: res.uuid });
subscription.upsert(&mut transaction).await?;
if let Some(ref mut subscription) =
metadata.user_subscription_item
{
subscription.metadata =
Some(SubscriptionMetadata::Pyro { id: res.uuid });
}
}
}
}
}

if let Some(subscription) = metadata.user_subscription_item {
if let Some(mut subscription) = metadata.user_subscription_item {
let open_charge =
ChargeItem::get_open_subscription(subscription.id, &mut *transaction)
.await?;
Expand Down Expand Up @@ -1382,7 +1380,11 @@ pub async fn stripe_webhook(
amount: new_price as i64,
currency_code: metadata.product_price_item.currency_code,
status: ChargeStatus::Open,
due: Utc::now() + subscription.interval.duration(),
due: if subscription.status == SubscriptionStatus::Unprovisioned {
Utc::now() + subscription.interval.duration()
} else {
metadata.charge_item.due + subscription.interval.duration()
},
last_attempt: None,
type_: ChargeType::Subscription,
subscription_id: Some(subscription.id),
Expand All @@ -1391,6 +1393,9 @@ pub async fn stripe_webhook(
.upsert(&mut transaction)
.await?;
};

subscription.status = SubscriptionStatus::Provisioned;
subscription.upsert(&mut transaction).await?;
}

transaction.commit().await?;
Expand Down Expand Up @@ -1538,8 +1543,18 @@ pub async fn subscription_task(pool: PgPool, redis: RedisPool) {
let mut clear_cache_users = Vec::new();

// If an active subscription has a canceled charge OR a failed charge more than two days ago, it should be cancelled
let all_subscriptions =
user_subscription_item::UserSubscriptionItem::get_all_unprovision(&pool).await?;
let all_charges = ChargeItem::get_unprovision(&pool).await?;

let mut all_subscriptions = user_subscription_item::UserSubscriptionItem::get_many(
&all_charges
.iter()
.filter_map(|x| x.subscription_id)
.collect::<HashSet<_>>()
.into_iter()
.collect::<Vec<_>>(),
&pool,
)
.await?;
let subscription_prices = product_item::ProductPriceItem::get_many(
&all_subscriptions
.iter()
Expand Down Expand Up @@ -1572,7 +1587,20 @@ pub async fn subscription_task(pool: PgPool, redis: RedisPool) {
)
.await?;

for mut subscription in all_subscriptions {
for charge in all_charges {
let subscription = if let Some(subscription) = all_subscriptions
.iter_mut()
.find(|x| Some(x.id) == charge.subscription_id)
{
subscription
} else {
continue;
};

if subscription.status == SubscriptionStatus::Unprovisioned {
continue;
}

let product_price = if let Some(product_price) = subscription_prices
.iter()
.find(|x| x.id == subscription.price_id)
Expand Down Expand Up @@ -1624,7 +1652,11 @@ pub async fn subscription_task(pool: PgPool, redis: RedisPool) {
))
.header("X-Master-Key", dotenvy::var("PYRO_API_KEY")?)
.json(&serde_json::json!({
"reason": "cancelled"
"reason": if charge.status == ChargeStatus::Cancelled {
"cancelled"
} else {
"paymentfailed"
}
}))
.send()
.await;
Expand Down

0 comments on commit 0c17663

Please sign in to comment.