Stripe订阅变更未支付场景下的业务逻辑处理疑问
Stripe订阅变更后遗留未支付发票的问题解决
你遇到的核心问题是每次订阅变更都会生成独立发票,且未支付的旧发票不会自动关联或失效,这是当前参数设置的必然结果:
payment_behavior: 'default_incomplete'会让订阅变更时立即生成待支付发票,订阅状态变为past_due但不阻止后续变更proration_behavior: 'always_invoice'会把变更产生的 prorations 单独开票,进一步增加独立发票数量
针对你提到的两个场景,以下是具体解决方案:
一、调整订阅更新逻辑,从根源避免遗留发票
方案1:限制未结清欠款时的订阅变更
将payment_behavior从default_incomplete改为pending_if_incomplete,这样当用户存在未支付发票时,后续的订阅变更请求会被暂停,直到旧发票被支付或取消,从根源上防止多次变更产生多张未付发票。
修改updateCustomerSubscription方法:
async updateCustomerSubscription(subscriptionId: string, subscriptionInfo: SubscriptionInfoT) { const subscription = await this.stripe.subscriptions.retrieve(subscriptionId); return this.stripe.subscriptions.update(subscriptionId, { payment_behavior: 'pending_if_incomplete', // 替换原参数 proration_behavior: 'always_invoice', description: Object.values(subscriptionInfo.numbers) .filter(n => n) .join(', '), items: [ { id: subscription.items.data[0].id, price: subscriptionInfo.priceId, quantity: subscriptionInfo.quantity, }, ], metadata: subscriptionInfo.numbers, expand: ['latest_invoice.payment_intent'], }); }
方案2:更新订阅时自动作废未支付旧发票
如果需要允许用户在未支付时继续调整订阅,可以在执行更新前,先查询该订阅关联的所有未支付发票并标记为作废,旧发票作废后不会再显示给用户,也不会影响订阅状态。
修改后的updateCustomerSubscription方法:
async updateCustomerSubscription(subscriptionId: string, subscriptionInfo: SubscriptionInfoT) { // 先处理未支付的旧发票 const openInvoices = await this.stripe.invoices.list({ subscription: subscriptionId, status: 'open', limit: 10 }); for (const invoice of openInvoices.data) { await this.stripe.invoices.voidInvoice(invoice.id); } // 再执行订阅更新 const subscription = await this.stripe.subscriptions.retrieve(subscriptionId); return this.stripe.subscriptions.update(subscriptionId, { payment_behavior: 'default_incomplete', proration_behavior: 'always_invoice', description: Object.values(subscriptionInfo.numbers) .filter(n => n) .join(', '), items: [ { id: subscription.items.data[0].id, price: subscriptionInfo.priceId, quantity: subscriptionInfo.quantity, }, ], metadata: subscriptionInfo.numbers, expand: ['latest_invoice.payment_intent'], }); }
二、处理已存在的遗留未支付发票
对于已经产生的未支付发票,可以通过以下代码批量作废指定客户的未结清订阅发票:
async voidUnpaidSubscriptionInvoices(customerId: string) { const invoices = await this.stripe.invoices.list({ customer: customerId, status: 'open', limit: 100 }); for (const invoice of invoices.data) { if (invoice.subscription) { await this.stripe.invoices.voidInvoice(invoice.id); } } }
内容的提问来源于stack exchange,提问作者Oleksandr Dimov
相关产品推荐
相关产品推荐

