feat(billing): provision Stripe customer + subscription on tenant create
Wire the Stripe lifecycle into TenantsService (best-effort, gated on stripe.enabled): on create open a Stripe customer and, for a priced plan with seats >= 1, lazily create a Stripe Product+Price (persisted to Price.stripePriceIds[currency]) and a send_invoice subscription; mirror seat changes to the subscription quantity; pause/resume on suspend/resume; cancel on delete. A Stripe failure never blocks the tenant — the local Subscription stays the source of truth for derived MRR.
This commit is contained in:
@@ -30,6 +30,19 @@ export class PricesService {
|
||||
return price.amounts[currency]
|
||||
}
|
||||
|
||||
// Persist the Stripe Price id we created for (this row, currency) so the
|
||||
// next tenant on the same plan/cycle/currency reuses it instead of creating
|
||||
// a duplicate Stripe Price. Keyed write — never clobbers other currencies.
|
||||
async setStripePriceId(
|
||||
priceId: PriceDocument['_id'],
|
||||
currency: PriceCurrency,
|
||||
stripePriceId: string,
|
||||
): Promise<void> {
|
||||
await this.priceModel
|
||||
.updateOne({ _id: priceId }, { $set: { [`stripePriceIds.${currency}`]: stripePriceId } })
|
||||
.exec()
|
||||
}
|
||||
|
||||
async create(dto: CreatePriceDto): Promise<PriceDocument> {
|
||||
try {
|
||||
return await this.priceModel.create({ ...dto, active: dto.active ?? true })
|
||||
|
||||
Reference in New Issue
Block a user