提示:以下示例为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代码
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
解决方法:
- 命令行切换php 7.4,进入终端 运行
php --ri swoole
查看 swoole 未开启 curl-native。(默认宝塔安装的都是没有开启的) - 进入软件商店 卸载 swoole 扩展
- 重新手动安装扩展
- 修改配置文件时别忘了加上 extension = swoole_loader74.so 这句
- 重启CRMEB swoole 进程