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

支付成功后再插入表单数据的Laravel实现问题咨询

问题概述

用户提交表单后会被重定向到PayTabs支付页面,但目前表单数据(Payment记录)和Transaction记录在支付前就被插入数据库,即使用户放弃支付或支付失败,数据依然存在。需求是仅在支付成功后才保存表单相关数据。

解决方案

核心思路是把表单数据暂存在Session中,等支付成功的回调触发时,再将数据写入数据库,同时调整交易记录的创建逻辑。

1. 修改index方法:暂存数据,延迟写入

把原来直接写入数据库的操作全部移除,只生成支付请求并把表单数据暂存到Session:

public function index(Request $request): RedirectResponse
{
    // 生成PayTabs支付请求
    $response = $this->request(
        url: 'https://secure-global.paytabs.com/payment/request',
        payload: $this->transactionPayload(
            amount: 0 // 注意:这里金额为0,需根据实际业务调整
        )
    );

    $tranRef = $response->json()['tran_ref'] ?? null;

    // 把表单数据和交易参考号暂存到Session
    session([
        'pending_payment' => [
            'tran_ref' => $tranRef,
            'user_id' => Auth::id(),
            'country_id' => $request->country_id,
            'delivery_id' => $request->delivery_id,
            'address' => $request->address,
            'street' => $request->street,
            'home' => $request->home,
            'email' => $request->email
        ]
    ]);

    // 可选:先创建未支付的交易记录,用于追踪未完成订单
    Transaction::create([
        'paytabs_transaction_reference' => $tranRef,
        'paid' => false
    ]);

    // 重定向到PayTabs支付页面
    return redirect()->away($response['redirect_url']);
}

2. 修改return方法:支付成功后写入数据

在支付成功的分支里,从Session取出暂存数据,完成数据库写入操作:

public function return(Request $request): \Illuminate\Contracts\View\View|string
{
    $category = Category::all();
    $products = Product::all();
    
    $validSignature = $this->validateSignature($request->all());

    if ($validSignature) {
        if ($request->respStatus == 'A') {
            // 取出Session中的暂存数据
            $pendingData = session('pending_payment');
            if (!$pendingData || $pendingData['tran_ref'] !== $request->tranRef) {
                return view('index', compact('category', 'products'))->with('error', '无效的支付数据');
            }

            // 更新交易记录为已支付
            $transaction = Transaction::where('paytabs_transaction_reference', $request->tranRef)->first();
            if ($transaction) {
                $transaction->paid = true;
                $transaction->save();
            }

            // 更新购物车状态和交易参考号
            $cart = Cart::where('user_id', $pendingData['user_id'])
                ->where('opened', 0)
                ->first();
            
            if ($cart) {
                $cart->update([
                    'paytabs_transaction_reference' => $request->tranRef,
                    'opened' => 1
                ]);

                // 创建Payment记录
                Payment::create([
                    'cart_id' => $cart->id,
                    'country_id' => $pendingData['country_id'],
                    'delivery_id' => $pendingData['delivery_id'],
                    'address' => $pendingData['address'],
                    'street' => $pendingData['street'],
                    'home' => $pendingData['home'],
                    'email' => $pendingData['email']
                ]);
            }

            // 清除Session中的暂存数据
            session()->forget('pending_payment');

            return view('index', compact('category', 'products'))->with('success', '支付成功!感谢您的购买。');
        } else {
            // 支付失败,清理暂存数据
            session()->forget('pending_payment');
            // 可选:删除未支付的交易记录
            Transaction::where('paytabs_transaction_reference', $request->tranRef)->delete();
            
            return view('index', compact('category', 'products'))->with('error', $request->respMessage);
        }
    } else {
        session()->forget('pending_payment');
        return '无效的交易签名';
    }
}

额外优化点

  • Session有效期:可以给暂存数据设置有效期,比如session(['pending_payment' => $data], now()->addMinutes(30)),避免无效数据长期占用Session。
  • 异常处理:在数据库操作部分添加try-catch块,防止因数据库错误导致流程中断。
  • 重复提交防护:可以给表单添加CSRF之外的防重复提交令牌,避免用户多次提交表单。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 20:09:25