Laravel集成PayPal SDK:沙箱账户金额未更新问题求助
问题分析与解决方案
你遇到的核心问题是:PayPal REST API的支付流程没有走完最后一步——捕获已授权的支付金额。当用户在PayPal页面完成授权后,你只是跳转到了成功页,但没有告诉PayPal完成资金转账操作,所以沙箱账户里的金额不会发生变化。
接下来一步步帮你修正代码:
1. 完善success方法,添加支付捕获逻辑
在用户授权支付后,PayPal会把paymentId和PayerID作为查询参数返回给你的成功回调地址。你需要用这两个参数来完成支付的捕获:
use Illuminate\Http\Request; public function success(Request $request){ $apiContext = new \PayPal\Rest\ApiContext( new \PayPal\Auth\OAuthTokenCredential( 'Ac.................asd', // 你的ClientID 'Ac.................sdf' // 你的ClientSecret ) ); // 显式设置沙箱环境(如果你的ClientID是沙箱的,这一步可省略,但加上更稳妥) $apiContext->setConfig([ 'mode' => 'sandbox', // sandbox 或 live 'log.LogEnabled' => true, 'log.FileName' => storage_path('logs/paypal.log'), 'log.LogLevel' => 'DEBUG' // 方便排查问题 ]); try { // 获取PayPal返回的支付ID和PayerID $paymentId = $request->input('paymentId'); $payerId = $request->input('PayerID'); // 根据支付ID获取支付对象 $payment = \PayPal\Api\Payment::get($paymentId, $apiContext); // 创建捕获请求 $execution = new \PayPal\Api\PaymentExecution(); $execution->setPayerId($payerId); // 执行捕获,完成资金转账 $result = $payment->execute($execution, $apiContext); // 这里可以处理支付成功后的业务逻辑,比如更新订单状态、发送通知等 return response()->json([ 'status' => 'success', 'message' => '支付完成', 'transaction_details' => $result ]); } catch (\Exception $ex) { // 捕获错误,处理失败逻辑 \Log::error('PayPal支付捕获失败: ' . $ex->getMessage()); return response()->json([ 'status' => 'error', 'message' => '支付确认失败,请稍后重试', 'error_info' => $ex->getMessage() ], 500); } }
2. 优化createpayment方法的返回逻辑
你原来的createpayment方法最后用echo输出内容,这不符合Laravel的响应规范,应该改为跳转至PayPal授权页面:
public function createpayment(){ $apiContext = new \PayPal\Rest\ApiContext( new \PayPal\Auth\OAuthTokenCredential( 'Ac.................asd', // ClientID 'Ac.................sdf' // ClientSecret ) ); // 添加沙箱配置,统一环境 $apiContext->setConfig([ 'mode' => 'sandbox', 'log.LogEnabled' => true, 'log.FileName' => storage_path('logs/paypal.log'), 'log.LogLevel' => 'DEBUG' ]); $payer = new \PayPal\Api\Payer(); $payer->setPaymentMethod("paypal"); $item1 = new \PayPal\Api\Item(); $item1->setName('Ground Coffee 40 oz') ->setCurrency('USD') ->setQuantity(1) ->setSku("123123") ->setPrice(7.5); $item2 = new \PayPal\Api\Item(); $item2->setName('Granola bars') ->setCurrency('USD') ->setQuantity(5) ->setSku("321321") ->setPrice(2); $itemList = new \PayPal\Api\ItemList(); $itemList->setItems([$item1, $item2]); $details = new \PayPal\Api\Details(); $details->setShipping(1.2) ->setTax(1.3) ->setSubtotal(17.50); $amount = new \PayPal\Api\Amount(); $amount->setCurrency("USD") ->setTotal(20) ->setDetails($details); $transaction = new \PayPal\Api\Transaction(); $transaction->setAmount($amount) ->setItemList($itemList) ->setDescription("Payment description") ->setInvoiceNumber(uniqid()); $redirectUrls = new \PayPal\Api\RedirectUrls(); $redirectUrls->setReturnUrl(route('success')) ->setCancelUrl(route('cancel')); $payment = new \PayPal\Api\Payment(); $payment->setIntent("sale") ->setPayer($payer) ->setRedirectUrls($redirectUrls) ->setTransactions([$transaction]); try { $payment->create($apiContext); } catch (\Exception $ex) { // 用Laravel日志记录错误,方便排查 \Log::error('PayPal支付链接生成失败: ' . $ex->getMessage()); return redirect()->back()->with('error', '支付链接生成失败,请稍后重试'); } $approvalUrl = $payment->getApprovalLink(); // 跳转到PayPal授权页面 return redirect($approvalUrl); }
3. 沙箱测试的关键注意事项
- 确保你使用的商家账户(关联ClientID的账户)和买家账户都是PayPal沙箱账户,不能用真实账户测试。
- 检查沙箱账户余额:买家账户需要有足够的余额完成支付,商家账户需要是已验证的沙箱商家账户。
- 查看
storage/logs/paypal.log日志文件,如果捕获过程中出现错误,日志会帮你快速定位问题。
这样修改后,当用户完成PayPal授权跳转回成功页时,代码会自动执行支付捕获操作,沙箱里的商家账户会收到款项,买家账户余额也会相应扣除,同时成功页会返回结构化的支付响应。
内容的提问来源于stack exchange,提问作者Imran Abbas
相关产品推荐
相关产品推荐

