From aa3da35e8ec8e166a0453ce09650addf660e5c03 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Tue, 4 Feb 2025 18:12:35 -0500 Subject: [PATCH] collab: Add `has_overdue_invoices` to `billing_customers` (#24239) This PR adds a new `has_overdue_invoices` field to the `billing_customers` table. This will be used to statefully track whether a customer has overdue invoices, and also to reset it when the invoices are paid. We will set this field to `true` when a subscription is canceled with the reason `payment_failed`. Release Notes: - N/A --- .../20221109000000_test_schema.sql | 1 + ..._overdue_invoices_to_billing_customers.sql | 2 ++ crates/collab/src/api/billing.rs | 21 +++++++++++++++++++ .../src/db/queries/billing_customers.rs | 2 ++ .../collab/src/db/tables/billing_customer.rs | 1 + 5 files changed, 27 insertions(+) create mode 100644 crates/collab/migrations/20250204224004_add_has_overdue_invoices_to_billing_customers.sql diff --git a/crates/collab/migrations.sqlite/20221109000000_test_schema.sql b/crates/collab/migrations.sqlite/20221109000000_test_schema.sql index fb2de18b6356d5..185bd45cd3235d 100644 --- a/crates/collab/migrations.sqlite/20221109000000_test_schema.sql +++ b/crates/collab/migrations.sqlite/20221109000000_test_schema.sql @@ -430,6 +430,7 @@ CREATE TABLE IF NOT EXISTS billing_customers ( id INTEGER PRIMARY KEY AUTOINCREMENT, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, user_id INTEGER NOT NULL REFERENCES users(id), + has_overdue_invoices BOOLEAN NOT NULL DEFAULT FALSE, stripe_customer_id TEXT NOT NULL ); diff --git a/crates/collab/migrations/20250204224004_add_has_overdue_invoices_to_billing_customers.sql b/crates/collab/migrations/20250204224004_add_has_overdue_invoices_to_billing_customers.sql new file mode 100644 index 00000000000000..07c40303994395 --- /dev/null +++ b/crates/collab/migrations/20250204224004_add_has_overdue_invoices_to_billing_customers.sql @@ -0,0 +1,2 @@ +alter table billing_customers +add column has_overdue_invoices bool not null default false; diff --git a/crates/collab/src/api/billing.rs b/crates/collab/src/api/billing.rs index eceb01ee231b4f..2e5a4a925b3980 100644 --- a/crates/collab/src/api/billing.rs +++ b/crates/collab/src/api/billing.rs @@ -666,6 +666,27 @@ async fn handle_customer_subscription_event( .await? .ok_or_else(|| anyhow!("billing customer not found"))?; + let was_canceled_due_to_payment_failure = subscription.status == SubscriptionStatus::Canceled + && subscription + .cancellation_details + .as_ref() + .and_then(|details| details.reason) + .map_or(false, |reason| { + reason == CancellationDetailsReason::PaymentFailed + }); + + if was_canceled_due_to_payment_failure { + app.db + .update_billing_customer( + billing_customer.id, + &UpdateBillingCustomerParams { + has_overdue_invoices: ActiveValue::set(true), + ..Default::default() + }, + ) + .await?; + } + if let Some(existing_subscription) = app .db .get_billing_subscription_by_stripe_subscription_id(&subscription.id) diff --git a/crates/collab/src/db/queries/billing_customers.rs b/crates/collab/src/db/queries/billing_customers.rs index 188bb39e1cd5d1..efbc31c7c7a169 100644 --- a/crates/collab/src/db/queries/billing_customers.rs +++ b/crates/collab/src/db/queries/billing_customers.rs @@ -10,6 +10,7 @@ pub struct CreateBillingCustomerParams { pub struct UpdateBillingCustomerParams { pub user_id: ActiveValue, pub stripe_customer_id: ActiveValue, + pub has_overdue_invoices: ActiveValue, } impl Database { @@ -43,6 +44,7 @@ impl Database { id: ActiveValue::set(id), user_id: params.user_id.clone(), stripe_customer_id: params.stripe_customer_id.clone(), + has_overdue_invoices: params.has_overdue_invoices.clone(), ..Default::default() }) .exec(&*tx) diff --git a/crates/collab/src/db/tables/billing_customer.rs b/crates/collab/src/db/tables/billing_customer.rs index 258a7e0c0ccab0..914d73061f51bb 100644 --- a/crates/collab/src/db/tables/billing_customer.rs +++ b/crates/collab/src/db/tables/billing_customer.rs @@ -9,6 +9,7 @@ pub struct Model { pub id: BillingCustomerId, pub user_id: UserId, pub stripe_customer_id: String, + pub has_overdue_invoices: bool, pub created_at: DateTime, }