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

Laravel集成Stripe:无法通过Checkout Session支付指定已有发票

解决Stripe指定未结发票支付问题(Laravel环境)

问题背景

  • 技术栈:Laravel + Stripe PHP SDK
  • 场景:存在一张订阅生成的未结Stripe发票,ID为in_1PVBjnSE4D7cjIupbEfXsQ4w
  • 需求:
    1. 生成客户支付该指定发票的URL
    2. 客户完成支付后跳转至指定页面
  • 问题:跳转功能正常,但原有未结发票未被支付,反而生成了等额新发票
  • 尝试方案:用Stripe Checkout Session实现跳转,但无法引导支付指定发票

原错误代码:

public function createCheckoutSession(Request $request, $invoiceId)
{
    $firmId = session('firmdatas.id');
    $firmData = Firmregistration::findOrFail($firmId);

    $invoice = FirmInvoices::findOrFail($invoiceId);
    $stripeObj = new \Stripe\StripeClient(config('services.stripe.secret'));
    $subscription = $stripeObj->subscriptions->retrieve($invoice->stripe_subscription_id);
    try {
        $session = $stripeObj->checkout->sessions->create([
            'payment_method_types' => ['card'],
            'line_items' => [[
                'price_data' => [
                    'currency' => 'usd',
                    'product_data' => [
                        'name' => 'Invoice Payment',
                    ],
                    'unit_amount' => $invoice->amount_due,
                ],
                'quantity' => 1,
            ]],
            'subscription_data' => [
                'items' => [
                    ['plan' => $subscription->items->data[0]->id], // Assuming only one item in the subscription
                ],
            ],
            'mode' => 'payment',
            'customer' => $firmData->stripe_id,
            'payment_intent_data' => [
                'description' => "Payment for Invoice #{$invoice->number}",
                'metadata' => [
                    'invoice_id' => $invoice->invoice_id,
                ],
            ],
            'success_url' => route('admin.subscription.invoice.paymentsuccess', [
                'invoiceid' => $invoice->invoice_id,
                'amount_paid' => $invoice->amount_due, // Stripe will update the actual amount paid after payment
                'receipt_url' => '', // Placeholder, will be updated below
            ]),
            'cancel_url' => route('admin.subscription.view'),
        ]);

        // Redirect to the Checkout Session URL
        return redirect()->away($session->url);

    } catch (\Exception $e) {
        Log::error('Error creating Stripe Checkout Session: ' . $e->getMessage());
        return view('errors.500');
    }
}

错误原因

原代码核心问题:

  1. 使用mode: 'payment'结合subscription_data,会触发Stripe创建新的订阅周期并生成新发票,而非支付已有未结发票
  2. 通过line_items手动构建金额,完全脱离了目标发票的关联逻辑

解决方案

要支付指定的未结发票,需直接基于该发票创建Checkout Session,无需手动构建商品或订阅数据。修改后的代码如下:

public function createCheckoutSession(Request $request, $invoiceId)
{
    $firmId = session('firmdatas.id');
    $firmData = Firmregistration::findOrFail($firmId);

    $invoice = FirmInvoices::findOrFail($invoiceId);
    $stripeObj = new \Stripe\StripeClient(config('services.stripe.secret'));

    try {
        // 验证目标Stripe发票状态为未结(open)
        $stripeInvoice = $stripeObj->invoices->retrieve($invoice->stripe_invoice_id);
        if ($stripeInvoice->status !== 'open') {
            abort(400, '该发票无法支付');
        }

        $session = $stripeObj->checkout->sessions->create([
            'payment_method_types' => ['card'],
            // 直接关联目标Stripe发票ID
            'invoice' => $stripeInvoice->id,
            'mode' => 'payment',
            'customer' => $firmData->stripe_id,
            'success_url' => route('admin.subscription.invoice.paymentsuccess', [
                'invoiceid' => $invoice->invoice_id,
                'stripe_invoice_id' => $stripeInvoice->id,
            ]),
            'cancel_url' => route('admin.subscription.view'),
        ]);

        return redirect()->away($session->url);

    } catch (\Exception $e) {
        Log::error('Error creating Stripe Checkout Session for invoice payment: ' . $e->getMessage());
        return view('errors.500');
    }
}

关键说明

  1. 发票状态验证:必须确保Stripe发票处于open状态,已支付/已过期的发票无法创建支付会话
  2. 关联发票参数:通过invoice字段直接指定目标Stripe发票ID,Stripe会自动加载发票金额、明细等信息,避免手动构建的误差
  3. Webhook处理:支付完成后,务必监听Stripe的invoice.paid webhook事件,更新本地FirmInvoices的支付状态(如标记为已支付、记录支付时间等)
  4. 客户匹配:确保customer参数与发票所属客户一致,否则会报错

内容的提问来源于stack exchange,提问作者surya kumar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 22:42:10