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

Laravel集成Stripe时如何关联Invoice与Payment支付记录

问题根因

你当前的实现从创建环节就存在逻辑偏差:你手动创建了和Invoice完全独立的PaymentIntent,两个资源在Stripe侧是完全孤立的,根本不需要在支付成功回调里做关联绑定。正确流程是创建Invoice后由Stripe自动生成已绑定的PaymentIntent,不需要手动新建独立的支付对象。

现有代码的两个核心问题

  • 创建完草稿Invoice后没有执行最终化(finalize)操作,Invoice会一直停留在草稿状态,本身不会生成关联的待支付对象
  • 手动单独创建的PaymentIntent没有传入Invoice关联参数,哪怕支付成功,Stripe也只会标记该PaymentIntent为成功状态,不会把这笔款项算到对应Invoice的支付记录里,Invoice会一直显示未支付

正确实现逻辑

1. 后端创建支付环节修正

不需要手动创建PaymentIntent,流程调整如下:

  • 匹配/创建Stripe客户的逻辑可保持不变
  • 创建InvoiceItem的逻辑可保持不变,注意InvoiceItem会自动挂载到客户下的待处理草稿Invoice上
  • 创建草稿Invoice后,调用finalizeInvoice接口将草稿发票最终化,Stripe会自动为该Invoice生成绑定好的PaymentIntent,存在Invoice对象的payment_intent字段中
  • 前端直接使用这个自动生成的PaymentIntent的client_secret初始化Elements组件即可,无需手动新建PaymentIntent

修正后的后端创建部分参考代码:

// 匹配/创建Stripe客户
$stripeCustomer = $this->stripe->customers->search([
    'query' => "email:'$user->email'",
]);
if (isset($stripeCustomer['data']) && !count($stripeCustomer['data']) ) {
    $stripeCustomer = $this->stripe->customers->create([
        'email' => $user->email,
        'name'  => $user->name
    ]);
    $stripeCustomerId = $stripeCustomer->id;
} else {
    $stripeCustomerId = $stripeCustomer['data'][0]->id;
}

// 创建InvoiceItem
$invoiceItems = $this->stripe->invoiceItems->create([
    'customer' => $stripeCustomerId,
    'price' => $product ? $product->stripe_price_id : null,
]);

// 创建草稿发票并最终化,由Stripe自动生成绑定的PaymentIntent
$invoice = $this->stripe->invoices->create([
    'customer' => $stripeCustomerId,
    'auto_advance' => true, // 支付成功后自动更新发票状态
]);
// 将发票从draft状态转为open(待支付)状态
$finalizedInvoice = $this->stripe->invoices->finalizeInvoice($invoice->id);

// 直接取发票关联的PaymentIntent客户端密钥给前端,无需手动创建PaymentIntent
$clientSecret = $finalizedInvoice->payment_intent->client_secret;
// 建议此处将$invoice->id存入本地系统订单记录,方便后续回调校验

2. 前端支付逻辑说明

现有前端confirmPayment逻辑无需修改。使用Invoice自动生成的PaymentIntent完成支付时,Stripe会自动完成两个操作:

  • 标记对应PaymentIntent为succeeded状态
  • 自动标记对应Invoice为paid状态,自动完成支付记录与Invoice的绑定,无需手动处理关联关系

3. 支付成功回调逻辑修正

不需要在回调中手动绑定Invoice和支付记录,回调中只需要做状态校验即可:

  • 不建议用自定义编码的token传递paymentId,更稳妥的方式是直接从Stripe回跳参数中获取payment_intentID,查询对应的PaymentIntent详情
  • 校验PaymentIntent状态是否为succeeded
  • 从PaymentIntent对象的invoice字段即可获取已自动关联的Invoice信息,校验Invoice金额、客户信息与本地订单匹配后,更新本地订单状态为已支付即可

回调部分参考代码:

public function paymentSuccess(Request $request)
{
    // 从Stripe回跳参数中获取PaymentIntent ID
    $paymentIntentId = $request->get('payment_intent');
    // 查询时扩展返回关联的Invoice信息
    $paymentIntent = $this->stripe->paymentIntents->retrieve($paymentIntentId, ['expand' => ['invoice']]);
    
    // 校验支付状态
    if ($paymentIntent->status !== 'succeeded') {
        abort(400, '支付未完成');
    }
    
    // 直接获取Stripe自动绑定的关联发票信息
    $relatedInvoice = $paymentIntent->invoice;
    // 校验发票对应的客户、金额与本地订单匹配后,更新本地订单状态为已支付即可
}

特殊场景说明:如果必须使用手动创建的PaymentIntent支付Invoice,需要在创建PaymentIntent时传入invoice参数指定对应Invoice ID。这种方式不推荐,容易触发金额不匹配、发票状态异常等问题,优先使用Stripe自动生成PaymentIntent的标准流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 12:39:14