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
相关产品推荐
相关产品推荐

