Parcourir la source

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	vendor/services.php
zhangdehua il y a 1 an
Parent
commit
858059afc3

+ 29 - 2
app/api/controller/Order.php

@@ -12,7 +12,9 @@ declare (strict_types=1);
 
 namespace app\api\controller;
 
+use app\api\service\recharge\PayPal;
 use think\App;
+use think\facade\Cache;
 use think\response\Json;
 use app\api\model\Order as OrderModel;
 use app\api\model\Setting as SettingModel;
@@ -123,8 +125,33 @@ class Order extends Controller
 
     public function createOrderPaypal()
     {
-        $url = 'http://www.baidu.com';
-        $a = curl_request($url,'get');
+        $clientId = 'AS0FH780ZGtSAdpT1NTjwkFzryCPf69rZb_FR9Rt_rZdasB80cmjqTQ6CQELWiFVh_MU9e31CSnyz7Ai';
+        $clientSecret = 'EDqRQhgLNHCb5bxld98T8-JJJZKvMIeqxudO7lMwDFOxBfy138PjM5A21FnDNyb3q4yYUh8r7Qr2BnVi';
+        $pappalService = new PayPal($clientId,$clientSecret);
+        //$b = $pappalService->captureOrder('8LJ66491SN1477024');
+        $b = $pappalService->createOrderV2();
+        return $this->renderSuccess(compact('b'));
+
+        $a = $pappalService->getAccessToken();
+        dd($a);
+
+        $url = 'https://api-m.sandbox.paypal.com/v2/checkout/orders';
+
+        $headers = [
+            'Content-Type' => 'application/json',
+            //'PayPal-Request-Id' => $PayPalRequestId,
+            //'Authorization' => $PayPalRequestId,
+        ];
+        $a = curl_request($url, 'get');
         dd($a);
     }
+
+    public function captureOrderPaypal()
+    {
+        $clientId = 'AS0FH780ZGtSAdpT1NTjwkFzryCPf69rZb_FR9Rt_rZdasB80cmjqTQ6CQELWiFVh_MU9e31CSnyz7Ai';
+        $clientSecret = 'EDqRQhgLNHCb5bxld98T8-JJJZKvMIeqxudO7lMwDFOxBfy138PjM5A21FnDNyb3q4yYUh8r7Qr2BnVi';
+        $pappalService = new PayPal($clientId,$clientSecret);
+        $b = $pappalService->captureOrder('8LJ66491SN1477024');
+        return $this->renderSuccess(compact('b'));
+    }
 }

+ 7 - 0
app/api/service/passport/MailCaptcha.php

@@ -70,6 +70,13 @@ class MailCaptcha extends BaseService
         try {
             //Server settings
             $mail->SMTPDebug = SMTP::DEBUG_SERVER;//DEBUG_OFF                   //Enable verbose debug output
+            $mail->SMTPOptions = array(
+                'ssl' => array(
+                    'verify_peer' => false,
+                    'verify_peer_name' => false,
+                    'allow_self_signed' => true
+                )
+            );
             $mail->isSMTP();                                            //Send using SMTP
             $mail->Host = 'smtp.163.com';                     //Set the SMTP server to send through
             $mail->SMTPAuth = true;                                   //Enable SMTP authentication

+ 440 - 0
app/api/service/recharge/PayPal.php

@@ -0,0 +1,440 @@
+<?php
+// +----------------------------------------------------------------------
+// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2017~2024 https://www.yiovo.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
+// +----------------------------------------------------------------------
+// | Author: 萤火科技 <admin@yiovo.com>
+// +----------------------------------------------------------------------
+declare (strict_types=1);
+
+namespace app\api\service\recharge;
+
+use app\api\model\Payment as PaymentModel;
+use app\api\model\recharge\Order as OrderModel;
+use app\api\model\PaymentTrade as PaymentTradeModel;
+use app\api\service\User as UserService;
+use app\api\service\Order as OrderService;
+use app\api\service\recharge\PaySuccess as RechargePaySuccesService;
+use app\common\service\BaseService;
+use app\common\enum\Client as ClientEnum;
+use app\common\enum\OrderType as OrderTypeEnum;
+use app\common\enum\payment\Method as PaymentMethodEnum;
+use app\common\library\payment\Facade as PaymentFacade;
+use cores\exception\BaseException;
+use think\facade\Cache;
+
+/**
+ * 余额充值订单付款服务类
+ * Class Payment
+ * @package app\api\controller
+ */
+class PayPal extends BaseService
+{
+    // 提示信息
+    private string $message = '';
+
+    // 订单信息
+    private OrderModel $orderInfo;
+
+    // 支付方式 (微信支付、支付宝)
+    private string $method = '';
+
+    // 下单的客户端
+    private string $client = '';
+
+
+    /**
+     * 设置当前支付方式
+     * @param string $method 支付方式
+     * @return $this
+     */
+    public function setMethod(string $method): PayPal
+    {
+        $this->method = $method;
+        return $this;
+    }
+
+    /**
+     * 设置下单的客户端
+     * @param string $client 客户端
+     * @return $this
+     */
+    public function setClient(string $client): PayPal
+    {
+        $this->client = $client;
+        return $this;
+    }
+
+    /**
+     * 确认订单支付事件
+     * @param int|null $planId 方案ID
+     * @param string|null $customMoney 自定义金额
+     * @param array $extra 附加数据
+     * @return array[]
+     * @throws BaseException
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function orderPay(?int $planId = null, string $customMoney = null, array $extra = []): array
+    {
+        // 创建余额订单信息
+        $this->orderInfo = $this->createOrder($planId, $customMoney);
+        // 构建第三方支付请求的参数
+        $payment = $this->unifiedorder($extra);
+        // 记录第三方交易信息
+        $this->recordPaymentTrade($payment);
+        // 返回结果
+        return compact('payment');
+    }
+
+    /**
+     * 创建充值订单
+     * @param int|null $planId 方案ID
+     * @param string|null $customMoney 自定义金额
+     * @return OrderModel
+     * @throws BaseException
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    private function createOrder(?int $planId = null, string $customMoney = null): OrderModel
+    {
+        $model = new OrderModel;
+        if (!$model->createOrder($planId, $customMoney)) {
+            throwError($model->getError() ?: '创建充值订单失败');
+        }
+        $model['order_id'] = (int)$model['order_id'];
+        return $model;
+    }
+
+    /**
+     * 查询订单是否支付成功 (仅限第三方支付订单)
+     * @param string $outTradeNo 商户订单号
+     * @return bool
+     * @throws BaseException
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function tradeQuery(string $outTradeNo): bool
+    {
+        // 判断支付方式是否合法
+        if (!in_array($this->method, [PaymentMethodEnum::WECHAT, PaymentMethodEnum::ALIPAY])) {
+            return false;
+        }
+        // 获取支付方式的配置信息
+        $options = $this->getPaymentConfig();
+        // 构建支付模块
+        $Payment = PaymentFacade::store($this->method)->setOptions($options, $this->client);
+        // 执行第三方支付查询API
+        $result = $Payment->tradeQuery($outTradeNo);
+        // 订单支付成功事件
+        if (!empty($result) && $result['paySuccess']) {
+            // 获取第三方交易记录信息
+            $tradeInfo = PaymentTradeModel::detailByOutTradeNo($outTradeNo);
+            // 订单支付成功事件
+            $this->orderPaySucces($tradeInfo['order_no'], $tradeInfo['trade_id'], $result);
+        }
+        // 返回订单状态
+        return $result ? $result['paySuccess'] : false;
+    }
+
+    /**
+     * 记录第三方交易信息
+     * @param array $payment 第三方支付数据
+     * @throws BaseException
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    private function recordPaymentTrade(array $payment): void
+    {
+        if ($this->method != PaymentMethodEnum::BALANCE) {
+            PaymentTradeModel::record(
+                $this->orderInfo,
+                $this->method,
+                $this->client,
+                OrderTypeEnum::RECHARGE,
+                $payment
+            );
+        }
+    }
+
+    /**
+     * 返回消息提示
+     * @return string
+     */
+    public function getMessage(): string
+    {
+        return $this->message;
+    }
+
+    /**
+     * 构建第三方支付请求的参数
+     * @param array $extra 附加数据
+     * @return array
+     * @throws BaseException
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    private function unifiedorder(array $extra = []): array
+    {
+        // 判断支付方式是否合法
+        if (!in_array($this->method, [PaymentMethodEnum::WECHAT, PaymentMethodEnum::ALIPAY])) {
+            return [];
+        }
+        // 生成第三方交易订单号 (并非主订单号)
+        $outTradeNo = OrderService::createOrderNo();
+        // 获取支付方式的配置信息
+        $options = $this->getPaymentConfig();
+        // 整理下单接口所需的附加数据
+        $extra = $this->extraAsUnify($extra);
+        // 构建支付模块
+        $Payment = PaymentFacade::store($this->method)->setOptions($options, $this->client);
+        // 执行第三方支付下单API
+        if (!$Payment->unify($outTradeNo, (string)$this->orderInfo['pay_price'], $extra)) {
+            throwError('第三方支付下单API调用失败');
+        }
+        // 返回客户端需要的支付参数
+        return $Payment->getUnifyResult();
+    }
+
+    /**
+     * 获取支付方式的配置信息
+     * @return mixed
+     * @throws BaseException
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    private function getPaymentConfig()
+    {
+        $PaymentModel = new PaymentModel;
+        $templateInfo = $PaymentModel->getPaymentInfo($this->method, $this->client, $this->getStoreId());
+        return $templateInfo['template']['config'][$this->method];
+    }
+
+    /**
+     * 整理下单接口所需的附加数据
+     * @param array $extra
+     * @return array
+     * @throws BaseException
+     */
+    private function extraAsUnify(array $extra = []): array
+    {
+        // 微信支付时需要的附加数据
+        if ($this->method === PaymentMethodEnum::WECHAT) {
+            // 微信小程序端需要openid
+            if (in_array($this->client, [ClientEnum::MP_WEIXIN])) {
+                $extra['openid'] = $this->getWechatOpenid();
+            }
+        }
+        // 支付宝支付时需要的附加数据
+        if ($this->method === PaymentMethodEnum::ALIPAY) {
+
+        }
+        return $extra;
+    }
+
+
+    /**
+     * 订单支付成功事件
+     * @param string $orderNo 当前订单号
+     * @param int|null $tradeId 第三方交易记录ID
+     * @param array $paymentData 第三方支付成功返回的数据
+     * @return void
+     * @throws BaseException
+     */
+    private function orderPaySucces(string $orderNo, ?int $tradeId = null, array $paymentData = []): void
+    {
+        // 获取订单详情
+        $service = new RechargePaySuccesService;
+        // 订单支付成功业务处理
+        $service->setOrderNo($orderNo)->setMethod($this->method)->setTradeId($tradeId)->setPaymentData($paymentData);
+        if (!$service->handle()) {
+            throwError($service->getError() ?: '订单支付失败');
+        }
+        $this->message = '恭喜您,余额充值成功';
+    }
+
+    protected $appId;
+    protected $appSecret;
+    protected $baseUrl = 'https://api.sandbox.paypal.com';
+    //protected $baseUrl = 'https://api-m.paypal.com';
+
+    /*构造函数,把实例化Paypal类时传进来的appId和appSecret保存起来
+     *
+     *
+     * */
+    public function __construct($appId, $appSecret)
+    {
+        $this->appId = $appId;
+        $this->appSecret = $appSecret;
+    }
+
+    /*curl post
+     *param
+     * $extreUrl string  接口地址
+     * $data     array   提交的数据 为空时为get请求
+     * $header   array   请求头信息
+     * $Oauth    bool    是否使用Oauth验证
+     * return    array   响应信息
+     * */
+    protected function httpRequest($extreUrl, $data, $header, $Oauth = false)
+    {
+        $url = $this->baseUrl . $extreUrl;
+        $curl = curl_init();
+        curl_setopt($curl, CURLOPT_URL, $url);
+        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
+        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
+        if ($Oauth) {
+            curl_setopt($curl, CURLOPT_USERPWD, $this->appId . ":" . $this->appSecret);
+        }
+        //获取请求头信息
+        //curl_setopt($curl, CURLINFO_HEADER_OUT, TRUE);
+        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
+
+        if ($data) {
+            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
+            curl_setopt($curl, CURLOPT_POST, 1);
+        }
+        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
+        $output = curl_exec($curl);
+        //获取请求头信息
+        //var_dump(curl_getinfo($curl)["request_header"]);
+        curl_close($curl);
+        return json_decode($output, true);
+    }
+
+    /*请求头部加上Authorization
+     *param
+     * $extreUrl string  接口地址
+     * $data     array   请求的参数
+     * return    array   返回信息
+     * */
+    protected function httpRequestWithAuth($extreUrl, $data = [])
+    {
+        $header[] = 'Content-Type:application/json';
+        $header[] = 'Authorization:Bearer ' . $this->getAccessToken();
+        return $this->httpRequest($extreUrl, $data, $header);
+    }
+
+    /*转化数组为键值对形式
+     *param
+     * $array    array   需要转化的数组
+     * return    string  转化后的字符串:参数1=值1&参数2=值2
+     * */
+    protected function array2keyvalue($array)
+    {
+        $res = [];
+        foreach ($array as $k => $v) {
+            $res[] = $k . '=' . $v;
+        }
+        return implode('&', $res);
+    }
+
+    /*获取accesstoken
+     * 判断存储的accesstoken是否过期,过期则调用接口获取新的accesstoken否则直接返回。
+     * 可以把文件读取改成缓存读取 数据库读取。
+     * return    string  accesstoken值
+     * */
+    public function getAccessToken()
+    {
+        //        $clientId = 'AS0FH780ZGtSAdpT1NTjwkFzryCPf69rZb_FR9Rt_rZdasB80cmjqTQ6CQELWiFVh_MU9e31CSnyz7Ai';
+        //        $clientSecret = 'EDqRQhgLNHCb5bxld98T8-JJJZKvMIeqxudO7lMwDFOxBfy138PjM5A21FnDNyb3q4yYUh8r7Qr2BnVi';
+        //从paypal_access_token.json文件中读取accesstoken和过期时间
+        $access_token = Cache::get('paypal_access_token', null);
+        //$data = json_decode(file_get_contents("paypal_access_token.json"),true);
+        if (empty($access_token)) {
+            $extreUrl = '/v1/oauth2/token';
+            $postdata['grant_type'] = 'client_credentials';
+            $postdata = $this->array2keyvalue($postdata);
+            $header[] = "Content-type: application/x-www-form-urlencoded";
+            $res = $this->httpRequest($extreUrl, $postdata, $header, true);
+            \think\facade\Log::info('pay::' . json_encode($res));
+            $access_token = $res['access_token'];
+            if ($access_token) {
+                Cache::set('paypal_access_token', $access_token, $res['expires_in'] - 20);
+            }
+        }
+        return $access_token;
+    }
+
+    public function createOrderV2()
+    {
+        $extreUrl = '/v2/checkout/orders';
+        $body = [
+            "intent" => "CAPTURE",
+            "purchase_units" => [
+                [
+                    "amount" => [
+                        "currency_code" => "USD",//USD
+                        "value" => "100.00"
+                    ]
+                ]
+            ],
+            "application_context" => [
+                "return_url" => "https://lar.lmm.gold/store/index.html",//todo 自己的结算详情,通过接口获取然后转到location
+                "cancel_url" => "https://lar.lmm.gold/store/index.html"
+            ]
+        ];
+        return $this->httpRequestWithAuth($extreUrl, json_encode($body));
+
+    }
+
+    public function captureOrder($id)
+    {
+        $extreUrl = '/v2/checkout/orders/' . $id . '/capture';
+        return $this->httpRequestWithAuth($extreUrl);
+
+    }
+
+    /*创建payment
+    *
+	*/
+    public function CreatePayment($array)
+    {
+        $extreUrl = '/v1/payments/payment';
+        $data['intent'] = 'sale';
+        $data['payer'] = ['payment_method' => 'paypal'];
+        $transactions['amount'] = $array['amount'];
+        $transactions['description'] = $array['description'];
+        $transactions['custom'] = $array['orderid'];
+        $transactions['invoice_number'] = $array['orderid'];
+        $transactions['item_list']['items'] = $array['items'];
+        $transactions['payment_options']['allowed_payment_method'] = 'INSTANT_FUNDING_SOURCE';
+        $transactions['item_list']['shipping_address'] = $array['shipping_address'];
+        $data['transactions'][] = $transactions;
+        $data['note_to_payer'] = $array['note_to_payer'];
+        $data['redirect_urls'] = $array['redirect_urls'];
+        return $this->httpRequestWithAuth($extreUrl, json_encode($data));
+    }
+
+    /* 获取 完成payment
+   *param
+   * paymentId 创建payment后返回的ID
+   * PayerID     用户id 用户完成授权后跳转的excute页面中url带的参数
+   **/
+    public function ExcutePayment($array)
+    {
+        $extreUrl = '/v1/payments/payment/' . $array['paymentId'] . '/execute';
+        $data['payer_id'] = $array['PayerID'];
+        return $this->httpRequestWithAuth($extreUrl, json_encode($data));
+    }
+
+    /* 获取payment详情
+    *param
+    * paymentId 创建payment后返回的ID
+    **/
+    public function PaymentInfo($array)
+    {
+        $extreUrl = '/v1/payments/payment/' . $array['paymentId'];
+        return $this->httpRequestWithAuth($extreUrl);
+    }
+
+}

+ 1 - 1
vendor/services.php

@@ -1,5 +1,5 @@
 <?php 
-// This file is automatically generated at:2024-03-04 11:49:38
+// This file is automatically generated at:2024-02-27 18:20:50
 declare (strict_types = 1);
 return array (
   0 => 'think\\app\\Service',