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

Commit 0c17663

Browse files
committed
Fix new charge date, pyro suspend reason
1 parent 9846435 commit 0c17663

5 files changed

+144
-96
lines changed

.sqlx/query-3cbc34bc326595fc9d070494613fca57628eed279f720565fab55c8d10decd88.json

-58
This file was deleted.

.sqlx/query-a87c913916adf9177f8f38369975d5fc644d989293ccb42c1e06ec54dc2571f8.json

+82
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/database/models/charge_item.rs

+16
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,22 @@ impl ChargeItem {
162162
.collect::<Result<Vec<_>, serde_json::Error>>()?)
163163
}
164164

165+
pub async fn get_unprovision(
166+
exec: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
167+
) -> Result<Vec<ChargeItem>, DatabaseError> {
168+
let now = Utc::now();
169+
170+
let res =
171+
select_charges_with_predicate!("WHERE (status = 'cancelled' AND due < $1) OR (status = 'failed' AND last_attempt < $1 - INTERVAL '2 days')", now)
172+
.fetch_all(exec)
173+
.await?;
174+
175+
Ok(res
176+
.into_iter()
177+
.map(|r| r.try_into())
178+
.collect::<Result<Vec<_>, serde_json::Error>>()?)
179+
}
180+
165181
pub async fn remove(
166182
id: ChargeId,
167183
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,

src/database/models/user_subscription_item.rs

-24
Original file line numberDiff line numberDiff line change
@@ -95,30 +95,6 @@ impl UserSubscriptionItem {
9595
.collect::<Result<Vec<_>, serde_json::Error>>()?)
9696
}
9797

98-
pub async fn get_all_unprovision(
99-
exec: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
100-
) -> Result<Vec<UserSubscriptionItem>, DatabaseError> {
101-
let now = Utc::now();
102-
let results = select_user_subscriptions_with_predicate!(
103-
"
104-
INNER JOIN charges c
105-
ON c.subscription_id = us.id
106-
AND (
107-
(c.status = 'cancelled' AND c.due < $1) OR
108-
(c.status = 'failed' AND c.last_attempt < $1 - INTERVAL '2 days')
109-
)
110-
",
111-
now
112-
)
113-
.fetch_all(exec)
114-
.await?;
115-
116-
Ok(results
117-
.into_iter()
118-
.map(|r| r.try_into())
119-
.collect::<Result<Vec<_>, serde_json::Error>>()?)
120-
}
121-
12298
pub async fn upsert(
12399
&self,
124100
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,

src/routes/internal/billing.rs

+46-14
Original file line numberDiff line numberDiff line change
@@ -1178,11 +1178,7 @@ pub async fn stripe_webhook(
11781178
price_id,
11791179
interval,
11801180
created: Utc::now(),
1181-
status: if charge_status == ChargeStatus::Succeeded {
1182-
SubscriptionStatus::Provisioned
1183-
} else {
1184-
SubscriptionStatus::Unprovisioned
1185-
},
1181+
status: SubscriptionStatus::Unprovisioned,
11861182
metadata: None,
11871183
};
11881184

@@ -1342,16 +1338,18 @@ pub async fn stripe_webhook(
13421338
.json::<PyroServerResponse>()
13431339
.await?;
13441340

1345-
if let Some(ref mut subscription) = metadata.user_subscription_item {
1346-
subscription.metadata = Some(SubscriptionMetadata::Pyro { id: res.uuid });
1347-
subscription.upsert(&mut transaction).await?;
1341+
if let Some(ref mut subscription) =
1342+
metadata.user_subscription_item
1343+
{
1344+
subscription.metadata =
1345+
Some(SubscriptionMetadata::Pyro { id: res.uuid });
13481346
}
13491347
}
13501348
}
13511349
}
13521350
}
13531351

1354-
if let Some(subscription) = metadata.user_subscription_item {
1352+
if let Some(mut subscription) = metadata.user_subscription_item {
13551353
let open_charge =
13561354
ChargeItem::get_open_subscription(subscription.id, &mut *transaction)
13571355
.await?;
@@ -1382,7 +1380,11 @@ pub async fn stripe_webhook(
13821380
amount: new_price as i64,
13831381
currency_code: metadata.product_price_item.currency_code,
13841382
status: ChargeStatus::Open,
1385-
due: Utc::now() + subscription.interval.duration(),
1383+
due: if subscription.status == SubscriptionStatus::Unprovisioned {
1384+
Utc::now() + subscription.interval.duration()
1385+
} else {
1386+
metadata.charge_item.due + subscription.interval.duration()
1387+
},
13861388
last_attempt: None,
13871389
type_: ChargeType::Subscription,
13881390
subscription_id: Some(subscription.id),
@@ -1391,6 +1393,9 @@ pub async fn stripe_webhook(
13911393
.upsert(&mut transaction)
13921394
.await?;
13931395
};
1396+
1397+
subscription.status = SubscriptionStatus::Provisioned;
1398+
subscription.upsert(&mut transaction).await?;
13941399
}
13951400

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

15401545
// If an active subscription has a canceled charge OR a failed charge more than two days ago, it should be cancelled
1541-
let all_subscriptions =
1542-
user_subscription_item::UserSubscriptionItem::get_all_unprovision(&pool).await?;
1546+
let all_charges = ChargeItem::get_unprovision(&pool).await?;
1547+
1548+
let mut all_subscriptions = user_subscription_item::UserSubscriptionItem::get_many(
1549+
&all_charges
1550+
.iter()
1551+
.filter_map(|x| x.subscription_id)
1552+
.collect::<HashSet<_>>()
1553+
.into_iter()
1554+
.collect::<Vec<_>>(),
1555+
&pool,
1556+
)
1557+
.await?;
15431558
let subscription_prices = product_item::ProductPriceItem::get_many(
15441559
&all_subscriptions
15451560
.iter()
@@ -1572,7 +1587,20 @@ pub async fn subscription_task(pool: PgPool, redis: RedisPool) {
15721587
)
15731588
.await?;
15741589

1575-
for mut subscription in all_subscriptions {
1590+
for charge in all_charges {
1591+
let subscription = if let Some(subscription) = all_subscriptions
1592+
.iter_mut()
1593+
.find(|x| Some(x.id) == charge.subscription_id)
1594+
{
1595+
subscription
1596+
} else {
1597+
continue;
1598+
};
1599+
1600+
if subscription.status == SubscriptionStatus::Unprovisioned {
1601+
continue;
1602+
}
1603+
15761604
let product_price = if let Some(product_price) = subscription_prices
15771605
.iter()
15781606
.find(|x| x.id == subscription.price_id)
@@ -1624,7 +1652,11 @@ pub async fn subscription_task(pool: PgPool, redis: RedisPool) {
16241652
))
16251653
.header("X-Master-Key", dotenvy::var("PYRO_API_KEY")?)
16261654
.json(&serde_json::json!({
1627-
"reason": "cancelled"
1655+
"reason": if charge.status == ChargeStatus::Cancelled {
1656+
"cancelled"
1657+
} else {
1658+
"paymentfailed"
1659+
}
16281660
}))
16291661
.send()
16301662
.await;

0 commit comments

Comments
 (0)