提示:以下示例为CRMEB PRO V2 开发示例,TP版本可以跳过 三、四.1、四.2


文章目录

  • 一、注册申请PayPal账号
  • 二、安装paypal SDK
  • 三、增加配置分类 (非CMEB 可跳过)
  • 四、增加paypal代码
  • 1.增加后台paypal 配置代码 (非CMEB 可跳过)
  • 2.增加启用状态返回值 (非CMEB 可跳过)
  • 3.增加支付类型和paypal支付链接返回
  • 五.遇到的问题和解决方法
  • 1、调用sdk 提示 swoole_curl_setopt 10083不支持



提示:以下是本篇文章正文内容,下面案例可供参考

一、注册申请PayPal账号

首先去官网注册一个paypal账号,注册完登录后,进入开发者中心

二、安装paypal SDK

composer 怎么安装应该就不用说了吧 不会安装的可以百度一下 很多教程
composer require paypal/rest-api-sdk-php

三、增加配置分类 (非CMEB 可跳过)

1、需要在后台 “设置”->“系统维护”->“开发配置”->“配置分类”->"支付配置"中增加paypal支付配置

2、在paypal支付配置 的 配置列表中增加配置项(配置名称无所谓,变量字段需要认真设置)

paypal支付接口开发 java paypal支付接口配置_paypal支付接口开发 java


paypal支付接口开发 java paypal支付接口配置_php_02

四、增加paypal代码

1.增加后台paypal 配置代码 (非CMEB 可跳过)

在app/services/system/config/SteamConfigServices.php : 2082 行增加paypal支付配置代码,需要注意的是Build::input 第一个参数需要与 步骤1-2 的变量字段一致
代码如下(示例):

->option('paypal支付', [
	Build::alert('paypal支付(地址:https://developer.paypal.com,需要配置Webhook)', Alert::WARNING)->showIcon(true),
	Build::switch('paypal_status', $data['paypal_status']['info'], (int)$data['paypal_status']['value'])->control(1, [
		Build::input('paypal_client_id', $data['paypal_client_id']['info'], $data['paypal_client_id']['value'])->info($data['paypal_client_id']['desc']),
		Build::input('paypal_client_secret', $data['paypal_client_secret']['info'], $data['paypal_client_secret']['value'])->rows(5)->type('textarea')->info($data['paypal_client_secret']['desc']),
		Build::input('paypal_currency', $data['paypal_currency']['info'], $data['paypal_currency']['value'])->rows(5)->type('textarea')->info($data['paypal_currency']['desc']),
	])->trueValue('开启', 1)->falseValue('关闭', 0)->info($data['paypal_status']['desc']),
])

2.增加启用状态返回值 (非CMEB 可跳过)

订单详情接口 app/controller/api/v1/order/StoreOrderController.php detail方法 增加paypal支付状态返回值,
代码如下(示例):

$order['paypal_status'] = sys_config('paypal_status') ? 1 : 0;//paypal支付 1 开启 0 关闭

3.增加支付类型和paypal支付链接返回

订单详情接口 app/controller/api/v1/order/StoreOrderController.php pay方法
代码如下(示例):

public function pay(Request $request, StorePinkServices $services, OrderPayServices $payServices, YuePayServices $yuePayServices,PaypaylPayService $paypaylPayService)
 {
 	//******** CREMB 代码就不贴了
 	 $order['pay_type'] = $paytype; //重新支付选择支付方式
        switch ($order['pay_type']) {
            //CREMB 代码就不贴了
            case PayServices::PAYPAL://增加 paypal支付类型 并请求paypalPayService 获取支付链接
                //TODO 请求PAYPAL支付返回支付参数
                $pay = $paypaylPayService->pay($order->toArray());
                
                if (is_array($pay))
                    return app('json')->status($pay['status'], $pay['msg']);
                else
                    return app('json')->status('paypal', ['order_id'=>$order['order_id'],'jsConfig' => $pay]);
                break;

        }
 }

app/services/pay增加 PaypaylPayService.php 文件,具体代码如下

<?php
	// +----------------------------------------------------------------------
	// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
	// +----------------------------------------------------------------------
	// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
	// +----------------------------------------------------------------------
	// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
	// +----------------------------------------------------------------------
	// | Author: CRMEB Team <admin@crmeb.com>
	// +----------------------------------------------------------------------

	namespace app\services\pay;


	use App\Models\PaymentRecord;
	use App\Vendor\BLog;
	use Illuminate\Http\Request;
	use PayPal\Api\Amount;
	use PayPal\Api\Details;
	use PayPal\Api\Item;
	use PayPal\Api\ItemList;
	use PayPal\Api\Payer;
	use PayPal\Api\Payment;
	use PayPal\Api\RedirectUrls;
	use PayPal\Api\Refund;
	use PayPal\Api\Transaction;
	use PayPal\Api\ExecutePayment;
	use PayPal\Api\PaymentExecution;
	use PayPal\Exception\PayPalConnectionException;
	use PayPal\Api\Sale;
	use PayPal\Rest\ApiContext;
	use PayPal\Auth\OAuthTokenCredential;
	use think\exception\ValidateException;


	/**
	 * paypal 支付
	 * Class PaypaylPayService
	 * @package app\services\pay
	 */
	class PaypaylPayService
	{
		protected $clientId;
		protected $clientSecret;
		protected $currency;
		protected $accept_url;

		protected $PayPal;

		public function __construct()
		{
			$this->clientId     = sys_config('paypal_client_id');//'AYTs9IoyjC8F2_D8xWZdmLiNetToAPJqT_S1w6FP_FLrXGGW8nMG7HnQgaFbGXP0Tz6KcY0V-VV2tL1x';
			$this->clientSecret = sys_config('paypal_client_secret');//'EAx1mFZghicg5La3-yBZcpgNXgxApgPhfPzOgu6gW24o5nAnYsGPJVHtWNBCLYc9vjkYJthYRvkEor9D';
			$this->currency     = sys_config('paypal_currency');//'USD';//币种
			$this->accept_url   = '支付返回地址';//返回地址

			//初始化
			$this->PayPal = new ApiContext(
				new OAuthTokenCredential(
					$this->clientId,
					$this->clientSecret
				)
			);

			//线上使用请打开下面代码
//			$this->PayPal->setConfig([
//				'mode' => 'live',
//			]);
		}

		/**
		 * @param
		 * $product 商品
		 * $price 价钱
		 * $shipping 运费
		 * $description 描述内容
		 */
		public function pay(array $orderInfo)
		{
			if(!$orderInfo) {
				throw new ValidateException('订单不存在');
			}

			if($orderInfo['paid']) {
				throw new ValidateException('该订单已支付!');
			}

			//组件订单支付数据
			$product     = "商品订单";
			$description = "支付订单:{$orderInfo['order_id']}";
			$paypal      = $this->PayPal;
			$shipping    = $orderInfo['pay_postage'];//运费
			$price       = $orderInfo['pay_price'] - $shipping;//商品价格
			$total       = $orderInfo['pay_price'];//总价

			$payer = new Payer();
			$payer->setPaymentMethod('paypal');

			//设置产品数据
			$item = new Item();
			$item->setName($product)->setCurrency($this->currency)->setQuantity(1)->setPrice($price);

			$itemList = new ItemList();
			$itemList->setItems([$item]);

			//设置订单数据
			$details = new Details();
			$details->setShipping($shipping)->setSubtotal($price);

			$amount = new Amount();
			$amount->setCurrency($this->currency)->setTotal($total)->setDetails($details);

			$transaction = new Transaction();
			$transaction->setAmount($amount)->setItemList($itemList)->setDescription($description)->setInvoiceNumber($orderInfo['order_id']);

			$redirectUrls = new RedirectUrls();
			$redirectUrls->setReturnUrl($this->accept_url . "?success=true&orderId={$orderInfo['order_id']}")
				->setCancelUrl($this->accept_url. "/?success=false&orderId={$orderInfo['order_id']}");

			$payment = new Payment();
			$payment->setIntent('sale')->setPayer($payer)->setRedirectUrls($redirectUrls)->setTransactions([$transaction]);

			try {
				$payment->create($paypal);
			} catch (PayPalConnectionException $e) {
				throw new ValidateException($e->getMessage());
			}

			$approvalUrl = $payment->getApprovalLink();

			return $approvalUrl;
		}


		/**
		 * 回调
		 * @param Request $request
		 * @return void
		 */
		public function paypal_recharge() {

			//所有log 都是记录 回调数据  失败啊 成功啊   写接口调用此方法就行 但是要把get传参改掉  从接口获取get 然后传给此方法
			\think\facade\Log::info('paypal支付回调,数据:'.json_encode($_GET) );

			$tPaymentRecordId = trim($_GET['paymemtRecordID']);
			$appOrderNO       = trim($_GET['orderId']);

			//业务逻辑,查询订单表
			$success = trim($_GET['success']);
			if ($success == 'false' && !isset($_GET['paymentId']) && !isset($_GET['PayerID'])) {
				\think\facade\Log::info('paypal支付取消付款,数据:'.json_encode($_GET) );
				return false;
			}
			$paymentId = trim($_GET['paymentId']);
			$PayerID   = trim($_GET['PayerID']);
			if (!isset($success, $paymentId, $PayerID)) {
				\think\facade\Log::info('paypal支付失败,数据:'.json_encode($_GET) );
				return false;
			}
			if ((bool)$_GET['success'] === 'false') {
				\think\facade\Log::info('paypal支付失败,数据:'.json_encode($_GET) );
				return false;
			}
			$payment = Payment::get($paymentId, $this->PayPal);
			$execute = new PaymentExecution();
			$execute->setPayerId($PayerID);
			try {
				$payment->execute($execute, $this->PayPal);
			} catch (\Exception $e) {
				$log = '支付失败,支付ID【' . $paymentId . '】,支付人ID【' . $PayerID . '】';
				\think\facade\Log::info('paypal支付核验失败,数据:'.json_encode($_GET) );
				return false;
			}

			\think\facade\Log::info('paypal支付成功,数据:'.json_encode($_GET) );

			//支付成功的后续操作
			$pay_log = $this->Pay_log_model->get_info($tPaymentRecordId);
			if(!empty($pay_log))
			{
				if($pay_log['pay_status'] == 0)
				{
					//修改支付状态
					$log_data = array(
						'pay_status'=>1,
						'trade_no'=>$appOrderNO,
						'pay_trans_id'=>$paymentId,
						'pay_code'=>$success
					);
					$this->Pay_log_model->save($log_data, $tPaymentRecordId);
				}
			}

			return true;
		}


	

	}

五.遇到的问题和解决方法

1、调用sdk 提示 swoole_curl_setopt 10083不支持

订单详情接口 app/controller/api/v1/order/StoreOrderController.php detail方法 增加paypal支付状态返回值,
提示:swoole_curl_setopt():option[10083] is not supported
解决方法:

  1. 命令行切换php 7.4,进入终端 运行php --ri swoole 查看 swoole 未开启 curl-native。(默认宝塔安装的都是没有开启的)
  2. 进入软件商店 卸载 swoole 扩展
  3. 重新手动安装扩展
  4. 修改配置文件时别忘了加上 extension = swoole_loader74.so 这句
  5. 重启CRMEB swoole 进程