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

Stripe支付成功后,如何更新Checkout表记录支付状态及用户详情?

问题描述

已基于Stripe实现支付网关,Stripe端支付已成功,但无法在自身系统的Checkout表中标记支付成功并记录完整支付相关信息。当前Checkout表未设置支付相关字段,且对Stripe具体工作机制不了解。

现有Stripe初始化代码:

$userId = Auth::id();
// code of online payment starts
// Enter Your Stripe Secret
\Stripe\Stripe::setApiKey('sk_test_51NUj9NSCBDBzYpgwK1lDUIy49i02R3KB8tWaU78XYXluNB4LaBwToHdcPp2kqZraydfqRxvtaMJ1Gm3pgOYO5KaN00FiJHCWJU');
$result = Order_user::where('userid', $userId)
    ->select(DB::raw('SUM(price) as total_price'))
    ->first();
$totalPrice = $result->total_price;
$shipping_charge = Shipping_charge::select('s_charge')->where('id', 1)->first()->s_charge;
$shipping_charge = intval($shipping_charge);

// Calculate the payment amount including the shipping charge
$amount = ($totalPrice + $shipping_charge) * 100;
$payment_intent = \Stripe\PaymentIntent::create([
    'description' => 'Stripe Test Payment',
    'amount' => $amount,
    'currency' => 'INR',
    'payment_method_types' => ['card'],
]);
$intent = $payment_intent->client_secret;

// code of online payment ends

$order_data = Order_user::join('product', 'order_user.pid', '=', 'product.id')
    ->where('order_user.userid', $userId)
    ->select('order_user.*', 'product.product_name')
    ->get();
$shipping_charge = Shipping_charge::where('id', 1)->value('s_charge');
return view("checkout", ['order_data' => $order_data, 'shipping_charge' => $shipping_charge, 'intent' => $intent]);

提交Checkout数据的代码:

$shipping_charge = Shipping_charge::select('s_charge')->where('id', 1)->first()->s_charge;
$userId = Auth::id();
$first_name = $request->input('firstName');
$last_name = $request->input('lastName');
$email = $request->input('email');
$mobile_no = $request->input('mobileno');
$b_address = $request->input('baddress');
$s_address = $request->input('saddress');
$checkout = Checkout::insertGetId([
    'userid' => $userId,
    'first_name' => $first_name,
    'last_name' => $last_name,
    'email' => $email,
    'mobile_no' => $mobile_no,
    'b_address' => $b_address,
    's_address' => $s_address,
    's_charge' => $shipping_charge,
    'created_at' => now(),
    'updated_at' => now()
]);
解决方案

1. 扩展Checkout表结构

先给Checkout表添加支付相关字段,用来关联Stripe支付信息并标记状态。创建Laravel迁移文件:

php artisan make:migration add_payment_fields_to_checkouts_table

在生成的迁移文件中写入字段定义:

public function up()
{
    Schema::table('checkouts', function (Blueprint $table) {
        $table->string('payment_intent_id')->nullable(); // 关联Stripe的Payment Intent ID
        $table->enum('payment_status', ['unpaid', 'paid', 'failed'])->default('unpaid'); // 支付状态枚举
        $table->decimal('total_amount', 10, 2)->nullable(); // 实际支付总金额(含运费)
        $table->timestamp('paid_at')->nullable(); // 支付完成时间
    });
}

public function down()
{
    Schema::table('checkouts', function (Blueprint $table) {
        $table->dropColumn(['payment_intent_id', 'payment_status', 'total_amount', 'paid_at']);
    });
}

执行迁移生效:

php artisan migrate

2. 明确Stripe核心工作逻辑

Stripe支付的核心是Payment Intent:

  • 后端创建Payment Intent后,将client_secret传给前端,前端用该密钥调用Stripe.js完成支付操作
  • 重点:前端支付成功的回调不可信(存在篡改可能),必须依赖Stripe主动发送的Webhook通知确认支付状态。当支付成功时,Stripe会向你配置的后端URL发送payment_intent.succeeded事件,这才是可靠的支付成功信号。

3. 调整现有代码逻辑

3.1 创建Checkout记录时关联Payment Intent

在提交Checkout数据的代码中,需要关联之前创建的Stripe Payment Intent ID,并记录总金额:

// 从前端接收Payment Intent ID(前端需将该ID随表单一起提交)
$paymentIntentId = $request->input('payment_intent_id');
// 计算实际支付总金额(无需乘以100,数据库存元单位金额)
$totalAmount = ($totalPrice + $shipping_charge);

$shipping_charge = Shipping_charge::select('s_charge')->where('id', 1)->first()->s_charge;
$userId = Auth::id();
$first_name = $request->input('firstName');
$last_name = $request->input('lastName');
$email = $request->input('email');
$mobile_no = $request->input('mobileno');
$b_address = $request->input('baddress');
$s_address = $request->input('saddress');

$checkout = Checkout::insertGetId([
    'userid' => $userId,
    'first_name' => $first_name,
    'last_name' => $last_name,
    'email' => $email,
    'mobile_no' => $mobile_no,
    'b_address' => $b_address,
    's_address' => $s_address,
    's_charge' => $shipping_charge,
    'payment_intent_id' => $paymentIntentId,
    'total_amount' => $totalAmount,
    'payment_status' => 'unpaid', // 初始状态设为未支付
    'created_at' => now(),
    'updated_at' => now()
]);

3.2 实现Stripe Webhook处理

创建处理Webhook的控制器:

php artisan make:controller StripeWebhookController

在控制器中编写事件处理逻辑:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Stripe\Webhook;
use Stripe\Stripe;
use App\Models\Checkout;

class StripeWebhookController extends Controller
{
    public function handle(Request $request)
    {
        Stripe::setApiKey(env('STRIPE_SECRET_KEY'));
        
        $payload = $request->getContent();
        $sigHeader = $request->header('Stripe-Signature');
        $webhookSecret = env('STRIPE_WEBHOOK_SECRET'); // 从Stripe后台获取的Webhook密钥

        try {
            $event = Webhook::constructEvent(
                $payload, $sigHeader, $webhookSecret
            );
        } catch(\UnexpectedValueException $e) {
            // 无效请求体
            return response()->json(['error' => 'Invalid payload'], 400);
        } catch(\Stripe\Exception\SignatureVerificationException $e) {
            // 无效签名
            return response()->json(['error' => 'Invalid signature'], 400);
        }

        // 处理支付成功事件
        if ($event->type === 'payment_intent.succeeded') {
            $paymentIntent = $event->data->object;
            $paymentIntentId = $paymentIntent->id;

            // 找到对应Checkout记录并更新支付状态
            $checkout = Checkout::where('payment_intent_id', $paymentIntentId)->first();
            if ($checkout) {
                $checkout->update([
                    'payment_status' => 'paid',
                    'paid_at' => now()
                ]);

                // 可在此添加其他业务逻辑:比如标记订单为已支付、发送支付成功通知等
            }
        }

        return response()->json(['status' => 'success']);
    }
}

在routes/web.php中添加Webhook路由:

Route::post('/stripe/webhook', [StripeWebhookController::class, 'handle'])->name('stripe.webhook');

最后,在Stripe后台(Dashboard -> Developers -> Webhooks)配置你的Webhook URL(如https://你的域名/stripe/webhook),启用payment_intent.succeeded事件,并将获取到的Webhook密钥配置到.env文件:

STRIPE_SECRET_KEY=sk_test_xxx
STRIPE_WEBHOOK_SECRET=whsec_xxx

4. 前端补充说明

前端完成支付后,需将Stripe返回的payment_intent_id随Checkout表单一起提交到后端,确保Checkout记录与Stripe支付信息关联。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 04:02:04