当前位置: 首页 > article >正文

ThinkPHP接入PayPal支付

ThinkPHP 5接入PayPal 支付,PayPal的流程是服务器请求Paypal的接口下单(需要传订单id/支付成功的重定向地址/支付失败的重定向地址),接会返回一个支付地址,项目服务器把地址返给用户,用户打开链接登录Paypal完成付款,然后Paypal给重定向到指定地址。

在paypal官网开通商户号,设置通知地址。

开通沙箱模式用于测试,后台会给沙箱模式生成商户账号和用户账号,请注意区分。

申请和开通网上有教程不在赘述。

具体实现步骤如下

1.安装包

composer require paypal/rest-api-sdk-php:*

2.具体实现代码

<?php

namespace app\api\controller;

use app\common\controller\Api;
use app\common\model\ShopOrder;
use PayPal\Api\Amount;
use PayPal\Api\Payer;
use PayPal\Api\Payment;
use PayPal\Api\Transaction;
use PayPal\Api\PaymentExecution;
use PayPal\Auth\OAuthTokenCredential;
use PayPal\Rest\ApiContext;
use PayPal\Api\RedirectUrls;
use think\Log;
class Paypal extends Api
{
    protected $noNeedLogin = ['*'];
    protected $noNeedRight = ['*'];

    private $apiContext;

    public function __construct()
    {
        parent::__construct();

        // 初始化PayPal API上下文
        $this->apiContext = new ApiContext(
            new OAuthTokenCredential(
                'AV8d**************************N-jbpRvV-K0_dLuEA5d8uodUowab6jdWtM',     // 客户端ID
                'EByrRAncAi*****************************RSqIRA'         // 客户端密钥
            )
        );
        $this->apiContext->setConfig([
            'mode' => 'sandbox',      // 或者 'live'
            // 其他配置...
        ]);
    }

    /**
     * 下单接口
     * @return \think\response\Json|void
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function createPaypalPaymentUrl()
    {
        // 获取前端传递的order_Id
        $orderId = input('post.order_id');

        // 查询订单信息(这里你需要根据自己的数据库结构进行查询)
        // 假设我们得到了一个包含订单详情的数组$orderInfo
        $orderInfo = ShopOrder::where('id', $orderId)->where('status', '1')->find();

        if (empty($orderInfo)) {
            $this->error('订单不存在或不是待支付状态');
        }

        // 设置Payer信息,表明付款人是通过PayPal付款
        $payer = new Payer();
        $payer->setPaymentMethod("paypal");

        // 设置交易金额
        $amount = new Amount();
        $amount->setCurrency("AUD")
            ->setTotal(number_format($orderInfo['actual_money'], 2, '.', ''));

        // 创建Transaction对象,并使用订单ID作为发票号
        $transaction = new Transaction();
        $transaction->setAmount($amount)
            ->setDescription("Slem order pay")  // 描述可选
            ->setInvoiceNumber($orderInfo->order_num);  // 使用订单order_num作为发票号

        // 创建RedirectUrls对象
        $redirectUrls = new RedirectUrls();
        $redirectUrls->setReturnUrl("https://slem.a.hlidc.cn/api/paypal/paymentSuccess")  // 支付成功后的回调地址
        ->setCancelUrl("https://slem.a.hlidc.cn/api/paypal/paymentCancel");  // 用户取消支付后的回调地址

        // 创建Payment对象
        $payment = new Payment();
        $payment->setIntent("sale")
            ->setPayer($payer)
            ->setRedirectUrls($redirectUrls)
            ->setTransactions([$transaction]);

        try {
            // 创建支付请求
            $payment->create($this->apiContext);

            // 获取approval_url,这是用户需要访问来完成支付的URL
            foreach ($payment->getLinks() as $link) {
                if ($link->getRel() == 'approval_url') {
                    // 返回支付链接给客户端
                    return json(['code' => 1, 'data' => $link->getHref()]);
//                    $data = ['status' => 'success', 'approval_url' => $link->getHref()];
//                    $this->success(__('SUccess'),$data);
                }
            }
        } catch (\Exception $ex) {
            // 输出详细的错误信息
            return json([
                'status' => 'error',
                'message' => 'Error creating PayPal payment: ' . $ex->getMessage(),
                'details' => $ex->getTraceAsString(),
                'response' => $payment->toArray()
            ]);
        }
    }

    /**
     * 支付成功跳转的页面
     * 建议前端出个html后台做渲染,本方法只为展示流程
     * @return \think\response\Json
     */
    public function paymentSuccess()
    {
        // 获取PayPal传递过来的参数
        $paymentId = input('get.paymentId');
        $payerId = input('get.PayerID');

        if (empty($paymentId) || empty($payerId)) {
            return json(['status' => 'error', 'message' => 'Missing payment ID or payer ID']);
        }

        try {
            // 获取支付信息
            $payment = Payment::get($paymentId, $this->apiContext);

            // 创建PaymentExecution对象并设置payer_id
            $execution = new PaymentExecution();
            $execution->setPayerId($payerId);

            // 执行支付请求
            $result = $payment->execute($execution, $this->apiContext);

            // 检查支付状态
            if ($result->getState() === 'approved') {
                // 使用发票号(即订单ID)来查找订单
                $invoiceNumber = $payment->getTransactions()[0]->getInvoiceNumber();
                $order = ShopOrder::where('order_num', $invoiceNumber)->find();

                if (!empty($order)) {
                    // 更新订单状态为已支付
                    $order->payment = 'paypal';
                    $order->status = '2';
                    $order->save();

                    // 你可以在这里添加更多的业务逻辑,比如发送确认邮件等

                    // 返回成功信息给前端
                    return json(['status' => 'success', 'message' => 'Payment successful']);
                } else {
                    return json(['status' => 'error', 'message' => 'Order not found']);
                }
            } else {
                return json(['status' => 'error', 'message' => 'Payment not approved']);
            }
        } catch (\Exception $ex) {
            // 错误处理
            Log::error('PayPal Error: ' . $ex->getMessage());
            return json([
                'status' => 'error',
                'message' => 'Error executing payment: ' . $ex->getMessage(),
                'details' => $ex->getTraceAsString()
            ]);
        }
    }

    /**
     * 支付取消跳转的页面
     * @return \think\response\Json
     */
    public function paymentCancel()
    {
        // 获取订单ID或其他相关信息(如果需要)
        $orderId = input('get.order_id'); // 如果PayPal回调包含order_id

        if (!empty($orderId)) {
            try {
                // 根据订单ID查找订单信息
                $order = ShopOrder::where('id', $orderId)->find();

                if (!empty($order)) {
                    // 你可以在这里添加更多的业务逻辑,比如记录取消原因、发送通知等

                    // 更新订单状态为已取消或保持不变,视业务需求而定
                    // 这里假设我们不改变订单状态,仅记录取消事件
                    Log::info("Payment cancelled for order ID: " . $orderId);

                    // 返回取消信息给前端
                    return json(['status' => 'info', 'message' => 'Payment cancelled.']);
                } else {
                    return json(['status' => 'error', 'message' => 'Order not found.']);
                }
            } catch (\Exception $ex) {
                // 错误处理
                Log::error('Error handling payment cancellation: ' . $ex->getMessage());
                return json([
                    'status' => 'error',
                    'message' => 'An error occurred while processing your request.',
                    'details' => $ex->getTraceAsString()
                ]);
            }
        } else {
            // 如果没有提供订单ID,则简单地告知用户支付已被取消
            return json(['status' => 'info', 'message' => 'Payment cancelled.']);
        }
    }
}


http://www.kler.cn/a/450450.html

相关文章:

  • 信创源代码加密的答案:信创沙箱
  • Datawhale AI 冬令营学习笔记-零编程基础制作井字棋小游戏
  • 解决 Docker 中 DataLoader 多进程错误:共享内存不足
  • Java爬虫:速卖通(AliExpress)商品评论获取指南
  • 对javascript语言标准函数与箭头函数中this的理解(补充)
  • SRE 与 DevOps记录
  • 一个比RTK或redux更轻量级更易使用的 React 第三方状态管理工具库的配置与使用
  • 云手机方案总结
  • 代码随想录day25 回溯4
  • C++ 23版的最新特性
  • WebService简介
  • 建筑工地AI安全检测系统:YOLO11数据标注训练与PyQt5界面设计应用开发
  • 契约锁数智化合同大会全国巡展启动,助力合同管理全程数字化转型
  • 【FAQ】HarmonyOS SDK 闭源开放能力 — Vision Kit(2)
  • 如何打造用户友好的维护页面:6个创意提升WordPress网站体验
  • 一键打断线(根据相交点打断)——CAD c# 二次开发
  • 查询Elasticsearch索引刷新间隔
  • [Unity Shader] 【游戏开发】【图形渲染】Shader数学基础3:矢量与标量的乘法与除法详解
  • IntelliJ IDEA 基本使用教程及Spring Boot项目搭建实战
  • 比亚迪“天神之眼”重磅升级,无图城市领航功能全国开通
  • I.MX6U 启动方式详解
  • mac 使用 launchctl 实现每次登录系统时 frpc 就会自动启动
  • js原型和原型链
  • 实验17 优化算法的比较分析
  • 解决POM依赖与maven仓库关联的问题
  • JAVA HTTP压缩数据