使用Stripe Upcoming Invoice预览订阅变更时无修改返回金额异常问题
Stripe Upcoming Invoices接口无订阅变更时返回非预期金额问题
我希望使用Stripe Upcoming Invoices向用户展示修改订阅配置后将被扣除的账单金额,但实际调用过程中出现了不符合预期的返回结果。
问题现象
基础套餐信息:
- basic_monthly套餐价格:29.0
- premium_monthly套餐价格:49.0
测试流程与结果:
- 创建测试客户,绑定Visa测试支付方式
- 为客户创建basic_monthly套餐的月度订阅
- 调用upcoming接口时传入和当前订阅完全一致的price_id、quantity,预期返回变更扣款0,实际返回29
- 调用upcoming接口传入premium_monthly的price_id模拟升级,预期返回差价20,实际返回20(该场景结果符合预期)
核心测试代码如下:
// 创建客户 function step1_create_customer() { $stripe = new \Stripe\StripeClient(env('STRIPE_SECRET_KEY')); $test_clock = $stripe->testHelpers->testClocks->create([ 'frozen_time' => time(), 'name' => sprintf('Testing Upcoming Invoices'), ]); $stripe_customer = $stripe->customers->create([ 'test_clock' => $test_clock->id, 'payment_method' => 'pm_card_visa', 'invoice_settings' => ['default_payment_method' => 'pm_card_visa'], 'metadata' => [ 'testing_upcoming_invoices' => 1, ], 'expand' => [ 'test_clock', 'invoice_settings.default_payment_method', ], ]); return $stripe_customer; } // 创建订阅 function step2_create_subscription($stripe_customer, $stripe_price_id) { $stripe = new \Stripe\StripeClient(env('STRIPE_SECRET_KEY')); $stripe_subscription = $stripe->subscriptions->create([ 'customer' => $stripe_customer->id, 'items' => [ [ 'price' => $stripe_price_id, 'quantity' => 1, ], ], 'metadata' => [ 'testing_upcoming_invoices' => 1, ], ]); return $stripe_subscription; } // 原upcoming调用逻辑 function upcoming($stripe_subscription, $stripe_price_id) { $stripe = new \Stripe\StripeClient(env('STRIPE_SECRET_KEY')); $stripe_invoice = $stripe->invoices->upcoming([ 'subscription' => $stripe_subscription->id, 'subscription_items' => [ [ 'id' => $stripe_subscription->items->data[0]->id, 'price' => $stripe_price_id, 'quantity' => 1, ], ], 'subscription_cancel_at_period_end' => false, 'subscription_proration_behavior' => 'always_invoice', //'subscription_proration_date' => $now, ]); return $stripe_invoice; }
问题原因
- 参数配置错误
你在所有upcoming调用中都传入了subscription_items参数,同时设置subscription_proration_behavior = 'always_invoice'。Stripe的接口逻辑是:只要传入subscription_items,无论参数和当前订阅配置是否完全一致,都会判定为要触发订阅更新;而always_invoice规则会在无实际差价时,直接将下一个计费周期的全额套餐费计入本次预览发票,这就是无变更时返回29的直接原因。 - 取值逻辑错误
amount_due字段返回的是预览发票的总应付金额,包含下一个完整计费周期的全额订阅费,不是你需要的「本次订阅变更产生的即时扣款差额」。升级场景返回20只是刚好和差价数值一致,属于巧合,不代表逻辑正确。
修复方案
- 调整接口调用逻辑:仅在需要预览订阅变更时才传入
subscription_items、subscription_proration_behavior参数,普通查询下一期账单只传订阅ID即可;同时将subscription_proration_behavior改为默认值create_prorations,仅在存在实际差价时生成摊销行项。 - 调整金额取值逻辑:不要直接取
amount_due作为变更扣款额,遍历返回发票的行项列表,累加所有proration = true的行项金额,得到的才是本次变更会即时扣除的差价,无变更时该值自然为0。
修正后的upcoming函数参考:
function upcoming($stripe_subscription, $stripe_price_id = null) { $stripe = new \Stripe\StripeClient(env('STRIPE_SECRET_KEY')); $params = [ 'subscription' => $stripe_subscription->id, ]; // 仅当传入新价格ID时,才附加订阅变更参数 if (!is_null($stripe_price_id)) { $params['subscription_items'] = [ [ 'id' => $stripe_subscription->items->data[0]->id, 'price' => $stripe_price_id, 'quantity' => 1, ] ]; $params['subscription_proration_behavior'] = 'create_prorations'; } $invoice = $stripe->invoices->upcoming($params); // 计算即时摊销扣款 $immediateCharge = 0; foreach ($invoice->lines->data as $line) { if ($line->proration) { $immediateCharge += $line->amount; } } return [ 'next_cycle_total' => $invoice->amount_due / 100, // 下一期账单总金额 'immediate_proration_charge' => $immediateCharge / 100 // 本次变更即时扣款 ]; }
修正后调用结果:
- 无变更调用
upcoming($stripe_subscription),immediate_proration_charge返回0,符合预期 - 升级调用
upcoming($stripe_subscription, $plans['premium_monthly']->stripe_price_id),immediate_proration_charge返回20,符合预期
内容的提问来源于stack exchange,提问作者vbarbarosh
相关产品推荐
相关产品推荐

