You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Stripe Upcoming Invoice预览订阅变更时无修改返回金额异常问题

Stripe Upcoming Invoices接口无订阅变更时返回非预期金额问题

我希望使用Stripe Upcoming Invoices向用户展示修改订阅配置后将被扣除的账单金额,但实际调用过程中出现了不符合预期的返回结果。

问题现象

基础套餐信息:

  • basic_monthly套餐价格:29.0
  • premium_monthly套餐价格:49.0

测试流程与结果:

  1. 创建测试客户,绑定Visa测试支付方式
  2. 为客户创建basic_monthly套餐的月度订阅
  3. 调用upcoming接口时传入和当前订阅完全一致的price_id、quantity,预期返回变更扣款0,实际返回29
  4. 调用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;
}

问题原因

  1. 参数配置错误
    你在所有upcoming调用中都传入了subscription_items参数,同时设置subscription_proration_behavior = 'always_invoice'。Stripe的接口逻辑是:只要传入subscription_items,无论参数和当前订阅配置是否完全一致,都会判定为要触发订阅更新;而always_invoice规则会在无实际差价时,直接将下一个计费周期的全额套餐费计入本次预览发票,这就是无变更时返回29的直接原因。
  2. 取值逻辑错误
    amount_due字段返回的是预览发票的总应付金额,包含下一个完整计费周期的全额订阅费,不是你需要的「本次订阅变更产生的即时扣款差额」。升级场景返回20只是刚好和差价数值一致,属于巧合,不代表逻辑正确。

修复方案

  1. 调整接口调用逻辑:仅在需要预览订阅变更时才传入subscription_items、subscription_proration_behavior参数,普通查询下一期账单只传订阅ID即可;同时将subscription_proration_behavior改为默认值create_prorations,仅在存在实际差价时生成摊销行项。
  2. 调整金额取值逻辑:不要直接取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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 06:57:14