forked from coracle/caravel
Track payment method
This commit is contained in:
@@ -6,6 +6,7 @@ CREATE TABLE IF NOT EXISTS tenant (
|
|||||||
created_at INTEGER NOT NULL,
|
created_at INTEGER NOT NULL,
|
||||||
billing_anchor INTEGER,
|
billing_anchor INTEGER,
|
||||||
stripe_customer_id TEXT NOT NULL,
|
stripe_customer_id TEXT NOT NULL,
|
||||||
|
stripe_payment_method_id TEXT,
|
||||||
renewed_at INTEGER,
|
renewed_at INTEGER,
|
||||||
churned_at INTEGER
|
churned_at INTEGER
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -233,7 +233,7 @@ impl Billing {
|
|||||||
/// a relay created/activated *within* the period isn't active before the
|
/// a relay created/activated *within* the period isn't active before the
|
||||||
/// boundary, so it's covered by its own prorated charge instead.
|
/// boundary, so it's covered by its own prorated charge instead.
|
||||||
async fn reconcile_renewal(&self, tenant: &Tenant, period: &BillingPeriod) -> Result<()> {
|
async fn reconcile_renewal(&self, tenant: &Tenant, period: &BillingPeriod) -> Result<()> {
|
||||||
let relays = query::list_relays(&tenant.pubkey).await?;
|
let relays = query::list_relays_for_tenant(&tenant.pubkey).await?;
|
||||||
|
|
||||||
let mut line_items = Vec::new();
|
let mut line_items = Vec::new();
|
||||||
for relay in relays {
|
for relay in relays {
|
||||||
@@ -419,7 +419,7 @@ impl Billing {
|
|||||||
async fn churn_tenant(&self, tenant: &Tenant, now: i64) -> Result<()> {
|
async fn churn_tenant(&self, tenant: &Tenant, now: i64) -> Result<()> {
|
||||||
command::set_tenant_churned_at(&tenant.pubkey, Some(now)).await?;
|
command::set_tenant_churned_at(&tenant.pubkey, Some(now)).await?;
|
||||||
|
|
||||||
for relay in query::list_relays(&tenant.pubkey).await? {
|
for relay in query::list_relays_for_tenant(&tenant.pubkey).await? {
|
||||||
if relay.status == RELAY_STATUS_ACTIVE {
|
if relay.status == RELAY_STATUS_ACTIVE {
|
||||||
command::mark_relay_delinquent(&relay).await?;
|
command::mark_relay_delinquent(&relay).await?;
|
||||||
}
|
}
|
||||||
@@ -434,7 +434,7 @@ impl Billing {
|
|||||||
async fn reactivate_tenant(&self, tenant: &Tenant) -> Result<()> {
|
async fn reactivate_tenant(&self, tenant: &Tenant) -> Result<()> {
|
||||||
command::set_tenant_churned_at(&tenant.pubkey, None).await?;
|
command::set_tenant_churned_at(&tenant.pubkey, None).await?;
|
||||||
|
|
||||||
for relay in query::list_relays(&tenant.pubkey).await? {
|
for relay in query::list_relays_for_tenant(&tenant.pubkey).await? {
|
||||||
if relay.status == RELAY_STATUS_DELINQUENT {
|
if relay.status == RELAY_STATUS_DELINQUENT {
|
||||||
command::unmark_relay_delinquent(&relay).await?;
|
command::unmark_relay_delinquent(&relay).await?;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ pub struct Tenant {
|
|||||||
pub created_at: i64,
|
pub created_at: i64,
|
||||||
pub billing_anchor: Option<i64>,
|
pub billing_anchor: Option<i64>,
|
||||||
pub stripe_customer_id: String,
|
pub stripe_customer_id: String,
|
||||||
|
/// The tenant's saved Stripe payment method, or `None` if they have not set
|
||||||
|
/// up a card yet. Set when the tenant adds a card via the Stripe portal.
|
||||||
|
pub stripe_payment_method_id: Option<String>,
|
||||||
/// `period_start` of the most recent period this tenant was renewed for, or
|
/// `period_start` of the most recent period this tenant was renewed for, or
|
||||||
/// `None` if never renewed. The per-period renewal idempotency marker.
|
/// `None` if never renewed. The per-period renewal idempotency marker.
|
||||||
pub renewed_at: Option<i64>,
|
pub renewed_at: Option<i64>,
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ pub async fn list_relays_pending_sync() -> Result<Vec<Relay>> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_relays(tenant_pubkey: &str) -> Result<Vec<Relay>> {
|
pub async fn list_relays_for_tenant(tenant_pubkey: &str) -> Result<Vec<Relay>> {
|
||||||
Ok(sqlx::query_as::<_, Relay>(&select_relay("WHERE tenant_pubkey = ?"))
|
Ok(sqlx::query_as::<_, Relay>(&select_relay("WHERE tenant_pubkey = ?"))
|
||||||
.bind(tenant_pubkey)
|
.bind(tenant_pubkey)
|
||||||
.fetch_all(pool())
|
.fetch_all(pool())
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ pub struct TenantResponse {
|
|||||||
pub created_at: i64,
|
pub created_at: i64,
|
||||||
pub billing_anchor: Option<i64>,
|
pub billing_anchor: Option<i64>,
|
||||||
pub stripe_customer_id: String,
|
pub stripe_customer_id: String,
|
||||||
|
pub stripe_payment_method_id: Option<String>,
|
||||||
/// Set when billing has churned the tenant; the UI uses it to warn that the
|
/// Set when billing has churned the tenant; the UI uses it to warn that the
|
||||||
/// account is delinquent until billing is re-activated.
|
/// account is delinquent until billing is re-activated.
|
||||||
pub churned_at: Option<i64>,
|
pub churned_at: Option<i64>,
|
||||||
@@ -37,6 +38,7 @@ impl From<Tenant> for TenantResponse {
|
|||||||
created_at: t.created_at,
|
created_at: t.created_at,
|
||||||
billing_anchor: t.billing_anchor,
|
billing_anchor: t.billing_anchor,
|
||||||
stripe_customer_id: t.stripe_customer_id,
|
stripe_customer_id: t.stripe_customer_id,
|
||||||
|
stripe_payment_method_id: t.stripe_payment_method_id,
|
||||||
churned_at: t.churned_at,
|
churned_at: t.churned_at,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,7 +144,7 @@ pub async fn list_tenant_relays(
|
|||||||
) -> ApiResult {
|
) -> ApiResult {
|
||||||
api.require_admin_or_tenant(&auth, &pubkey)?;
|
api.require_admin_or_tenant(&auth, &pubkey)?;
|
||||||
|
|
||||||
let relays = query::list_relays(&pubkey)
|
let relays = query::list_relays_for_tenant(&pubkey)
|
||||||
.await
|
.await
|
||||||
.map_err(internal)?;
|
.map_err(internal)?;
|
||||||
ok(relays)
|
ok(relays)
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ export type Tenant = {
|
|||||||
nwc_is_set: boolean
|
nwc_is_set: boolean
|
||||||
created_at: number
|
created_at: number
|
||||||
stripe_customer_id: string
|
stripe_customer_id: string
|
||||||
|
stripe_payment_method_id: string | null
|
||||||
nwc_error: string | null
|
nwc_error: string | null
|
||||||
stripe_error: string | null
|
stripe_error: string | null
|
||||||
churned_at: number | null
|
churned_at: number | null
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ export const reactivateRelayById = (id: string) => reactivateRelay(id)
|
|||||||
|
|
||||||
export async function tenantNeedsPaymentSetup(): Promise<boolean> {
|
export async function tenantNeedsPaymentSetup(): Promise<boolean> {
|
||||||
const tenant = await getTenant(account()!.pubkey)
|
const tenant = await getTenant(account()!.pubkey)
|
||||||
return !tenant.nwc_is_set
|
return !tenant.nwc_is_set && !tenant.stripe_payment_method_id
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getLatestOpenInvoice(): Promise<Invoice | null> {
|
export async function getLatestOpenInvoice(): Promise<Invoice | null> {
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export default function RelayDetail() {
|
|||||||
if (!isPaidRelay()) return false
|
if (!isPaidRelay()) return false
|
||||||
const t = tenant()
|
const t = tenant()
|
||||||
if (!t) return false
|
if (!t) return false
|
||||||
return !t.nwc_is_set
|
return !t.nwc_is_set && !t.stripe_payment_method_id
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user