浏览代码

调整支付配置

Anyon 4 年之前
父节点
当前提交
cd3d540c2b

+ 9 - 4
app/data/controller/Payment.php

@@ -74,15 +74,20 @@ class Payment extends Controller
     protected function _form_filter(array &$data)
     {
         if ($this->request->isGet()) {
-            foreach ($this->types as &$vo) {
-                $binds = [];
+            $this->payments = [];
+            foreach ($this->types as $k => $vo) {
+                [$allow, $group] = [[], ucfirst(strstr($k, '_', true))];
                 foreach ($vo['bind'] as $api) if (isset(UserService::TYPES[$api])) {
-                    $binds[$api] = UserService::TYPES[$api]['name'];
+                    $allow[$api] = UserService::TYPES[$api]['name'];
                 }
-                $vo['allow'] = join('、', $binds);
+                $vo['allow'] = join('、', $allow);
+                $this->payments[$group][$k] = $vo;
             }
             $data['content'] = json_decode($data['content'] ?? '[]', true) ?: [];
         } else {
+            if (empty($data['type'])) {
+                $this->error('请选择支付通道并配置支付参数!');
+            }
             $data['content'] = json_encode($this->request->post() ?: [], JSON_UNESCAPED_UNICODE);
         }
     }

+ 12 - 1
app/data/controller/api/Login.php

@@ -17,7 +17,7 @@ class Login extends Controller
      * 接口认证类型
      * @var string
      */
-    private $type = UserService::APITYPE_WAP;
+    private $type;
 
     /**
      * 绑定数据表
@@ -26,6 +26,17 @@ class Login extends Controller
     protected $table = 'DataUser';
 
     /**
+     * 控制器初始化
+     */
+    protected function initialize()
+    {
+        $this->type = input('api', UserService::APITYPE_WAP);
+        if (empty(UserService::TYPES[$this->type])) {
+            $this->error("接口通道[{$this->type}]未定义规则!");
+        }
+    }
+
+    /**
      * 用户登录接口
      * @throws \think\Exception
      * @throws \think\db\exception\DataNotFoundException

+ 16 - 0
app/data/controller/api/Notify.php

@@ -2,6 +2,7 @@
 
 namespace app\data\controller\api;
 
+use app\data\service\payment\AliPaymentService;
 use app\data\service\payment\JoinPaymentService;
 use app\data\service\payment\WechatPaymentService;
 use think\admin\Controller;
@@ -33,6 +34,21 @@ class Notify extends Controller
     }
 
     /**
+     * 支付宝支付通知
+     * @param string $scene 支付场景
+     * @param string $param 支付通道
+     * @return string
+     */
+    public function alipay(string $scene = 'order', string $param = ''): string
+    {
+        if (strtolower($scene) === 'order') {
+            return AliPaymentService::instance()->notify($param);
+        } else {
+            return 'success';
+        }
+    }
+
+    /**
      * 汇聚支付通知
      * @param string $scene 支付场景
      * @param string $param 支付通道

+ 31 - 5
app/data/service/PaymentService.php

@@ -19,35 +19,61 @@ abstract class PaymentService extends Service
     const PAYMENT_JOINPAY_XCX = 'joinpay_xcx';
 
     // 微信支付通道
+    const PAYMENT_WECHAT_APP = 'wechat_app';
     const PAYMENT_WECHAT_MWEB = 'wechat_mweb';
     const PAYMENT_WECHAT_JSAPI = 'wechat_jsapi';
     const PAYMENT_WECHAT_NATIVE = 'wechat_native';
 
+    // 支付宝支付通道
+    const PAYMENT_ALIAPY_APP = 'alipay_app';
+    const PAYMENT_ALIPAY_WAP = 'alipay_wap';
+    const PAYMENT_ALIPAY_WEB = 'alipay_web';
+
     // 支付通道配置
     const TYPES = [
+        PaymentService::PAYMENT_WECHAT_APP    => [
+            'type' => 'APP',
+            'name' => '微信商户 APP 支付',
+            'bind' => [UserService::APITYPE_IOSAPP, UserService::APITYPE_ANDROID],
+        ],
         PaymentService::PAYMENT_WECHAT_MWEB   => [
             'type' => 'MWEB',
-            'name' => '微信商户H5支付',
+            'name' => '微信商户 H5 支付',
             'bind' => [UserService::APITYPE_WAP],
         ],
         PaymentService::PAYMENT_WECHAT_NATIVE => [
             'type' => 'NATIVE',
-            'name' => '微信商户NATIVE支付',
+            'name' => '微信商户 NATIVE 支付',
             'bind' => [UserService::APITYPE_WEB],
         ],
         PaymentService::PAYMENT_WECHAT_JSAPI  => [
             'type' => 'JSAPI',
-            'name' => '微信商户JSAPI支付',
+            'name' => '微信商户 JSAPI 支付',
             'bind' => [UserService::APITYPE_WXAPP, UserService::APITYPE_WECHAT],
         ],
+        PaymentService::PAYMENT_ALIAPY_APP    => [
+            'type' => '',
+            'name' => '支付宝 APP 支付',
+            'bind' => [UserService::APITYPE_ANDROID, UserService::APITYPE_IOSAPP],
+        ],
+        PaymentService::PAYMENT_ALIPAY_WAP    => [
+            'type' => '',
+            'name' => '支付宝 WAP 支付',
+            'bind' => [UserService::APITYPE_WAP],
+        ],
+        PaymentService::PAYMENT_ALIPAY_WEB    => [
+            'type' => '',
+            'name' => '支付宝 WEB 支付',
+            'bind' => [UserService::APITYPE_WEB],
+        ],
         PaymentService::PAYMENT_JOINPAY_XCX   => [
             'type' => 'WEIXIN_XCX',
-            'name' => '汇聚小程序JSAPI支付',
+            'name' => '汇聚小程序 JSAPI 支付',
             'bind' => [UserService::APITYPE_WXAPP],
         ],
         PaymentService::PAYMENT_JOINPAY_GZH   => [
             'type' => 'WEIXIN_GZH',
-            'name' => '汇聚服务号JSAPI支付',
+            'name' => '汇聚服务号 JSAPI 支付',
             'bind' => [UserService::APITYPE_WECHAT],
         ],
     ];

+ 18 - 8
app/data/service/UserService.php

@@ -15,24 +15,34 @@ class UserService extends Service
     const APITYPE_WEB = 'web';
     const APITYPE_WXAPP = 'wxapp';
     const APITYPE_WECHAT = 'wechat';
+    const APITYPE_IOSAPP = 'ios';
+    const APITYPE_ANDROID = 'android';
 
     const TYPES = [
-        UserService::APITYPE_WAP    => [
-            'name' => '手机浏览器终端',
+        UserService::APITYPE_WAP     => [
+            'name' => '手机浏览器',
             'auth' => '',
         ],
-        UserService::APITYPE_WEB    => [
-            'name' => '电脑浏览器终端',
+        UserService::APITYPE_WEB     => [
+            'name' => '电脑浏览器',
             'auth' => '',
         ],
-        UserService::APITYPE_WXAPP  => [
-            'name' => '微信小程序终端',
+        UserService::APITYPE_WXAPP   => [
+            'name' => '微信小程序',
             'auth' => 'openid1',
         ],
-        UserService::APITYPE_WECHAT => [
-            'name' => '微信服务号终端',
+        UserService::APITYPE_WECHAT  => [
+            'name' => '微信服务号',
             'auth' => 'openid2',
         ],
+        UserService::APITYPE_ANDROID => [
+            'name' => '安卓应用',
+            'auth' => '',
+        ],
+        UserService::APITYPE_IOSAPP  => [
+            'name' => '苹果应用',
+            'auth' => '',
+        ],
     ];
 
     /**

+ 141 - 0
app/data/service/payment/AliPaymentService.php

@@ -0,0 +1,141 @@
+<?php
+
+namespace app\data\service\payment;
+
+use app\data\service\PaymentService;
+
+/**
+ * 支付宝支付基础服务
+ * Class JoinPaymentService
+ * @package app\store\service\payment
+ */
+class AliPaymentService extends PaymentService
+{
+
+    /**
+     * 支付参数配置
+     * @var array
+     */
+    protected $params = [];
+
+    /**
+     * 支付服务初始化
+     * @return $this
+     */
+    protected function initialize(): AliPaymentService
+    {
+        $this->params = [
+            // 沙箱模式
+            'debug'       => false,
+            // 签名类型(RSA|RSA2)
+            'sign_type'   => "RSA2",
+            // 应用ID
+            'appid'       => static::$config['alipay_appid'],
+            // 支付宝公钥 (1行填写,特别注意,这里是支付宝公钥,不是应用公钥,最好从开发者中心的网页上去复制)
+            'public_key'  => static::$config['alipay_public_key'],
+            // 支付宝私钥 (1行填写)
+            'private_key' => static::$config['alipay_private_key'],
+            // 应用公钥证书(新版资金类接口转 app_cert_sn)
+            'app_cert'    => '',
+            // 支付宝根证书(新版资金类接口转 alipay_root_cert_sn)
+            'root_cert'   => '',
+            // 支付成功通知地址
+            'notify_url'  => '',
+            // 网页支付回跳地址
+            'return_url'  => '',
+        ];
+        return $this;
+    }
+
+    /**
+     * 支付结果处理
+     * @param string $type 支付通道
+     * @return string
+     * @throws \WeChat\Exceptions\InvalidResponseException
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function notify(string $type = ''): string
+    {
+        if (is_numeric(stripos($type, '-'))) {
+            [$payType, $payId] = explode('-', $type);
+        } else {
+            [$payType, $payId] = [$type ?: static::$type, static::$id];
+        }
+        $notify = \AliPay\App::instance($this->params)->notify();
+        if (in_array($notify['trade_status'], ['TRADE_SUCCESS', 'TRADE_FINISHED'])) {
+            // 更新支付记录
+            data_save('DataPaymentItem', [
+                'order_no'         => $notify['out_trade_no'],
+                'payment_id'       => $payId,
+                'payment_type'     => $payType,
+                'payment_code'     => $notify['trade_no'],
+                'payment_amount'   => $notify['total_amount'],
+                'payment_status'   => 1,
+                'payment_datatime' => date('Y-m-d H:i:s'),
+            ], 'order_no', ['payment_type' => $payType, 'payment_status' => 0]);
+            // 更新记录状态
+            if ($this->updateOrder($notify['out_trade_no'], $notify['trade_no'], $notify['total_amount'], $payType)) {
+                return 'success';
+            }
+        } else {
+            return 'error';
+        }
+    }
+
+    /**
+     * 查询订单数据
+     * @param string $orderNo
+     * @return array
+     * @throws \WeChat\Exceptions\InvalidResponseException
+     * @throws \WeChat\Exceptions\LocalCacheException
+     */
+    public function query(string $orderNo): array
+    {
+        return \AliPay\App::instance($this->params)->query($orderNo);
+    }
+
+    /**
+     * 创建订单支付参数
+     * @param string $openid 会员OPENID
+     * @param string $orderNo 交易订单单号
+     * @param string $payAmount 交易订单金额(元)
+     * @param string $payTitle 交易订单名称
+     * @param string $payRemark 订单订单描述
+     * @return array
+     * @throws \think\Exception
+     */
+    public function create(string $openid, string $orderNo, string $payAmount, string $payTitle, string $payRemark): array
+    {
+        try {
+            if (isset(static::TYPES[static::$type])) {
+                $tradeType = static::TYPES[static::$type]['type'];
+                $tradeParam = static::$type . '-' . static::$id;
+            } else {
+                throw new \think\Exception('支付类型[' . static::$type . ']未配置定义!');
+            }
+            $this->params['notify_url'] = sysuri("@data/api.notify/alipay/scene/order/param/{$tradeParam}", [], false, true);
+            if ($tradeType === static::PAYMENT_WECHAT_APP) {
+                $payment = \AliPay\App::instance($this->params);
+            } elseif ($tradeType === static::PAYMENT_ALIPAY_WAP) {
+                $payment = \AliPay\Wap::instance($this->params);
+            } elseif ($tradeType === static::PAYMENT_ALIPAY_WEB) {
+                $payment = \AliPay\Web::instance($this->params);
+            } else {
+                throw new \think\Exception("支付类型[{$tradeType}]暂时不支持!");
+            }
+            $result = $payment->apply(['out_trade_no' => $orderNo, 'total_amount' => $payAmount, 'subject' => $payTitle, 'body' => $payRemark]);
+            // 创建支付记录
+            $this->app->db->name('DataPaymentItem')->insert([
+                'order_no'   => $orderNo, 'order_name' => $payTitle, 'order_amount' => $payAmount,
+                'payment_id' => static::$id, 'payment_type' => static::$type,
+            ]);
+            return ['result' => $result];
+        } catch (\think\Exception $exception) {
+            throw $exception;
+        } catch (\Exception $exception) {
+            throw new \think\Exception($exception->getMessage(), $exception->getCode());
+        }
+    }
+}

+ 3 - 3
app/data/service/payment/JoinPaymentService.php

@@ -70,7 +70,7 @@ class JoinPaymentService extends PaymentService
         try {
             if (isset(static::TYPES[static::$type])) {
                 $tradeType = static::TYPES[static::$type]['type'];
-                $tradeParam = static::$type . '_' . static::$id;
+                $tradeParam = static::$type . '-' . static::$id;
             } else {
                 throw new \think\Exception('支付类型[' . static::$type . ']未配置定义!');
             }
@@ -132,8 +132,8 @@ class JoinPaymentService extends PaymentService
      */
     public function notify(string $type = ''): string
     {
-        if (is_numeric(stripos($type, '_'))) {
-            [$payType, $payId] = explode('_', $type);
+        if (is_numeric(stripos($type, '-'))) {
+            [$payType, $payId] = explode('-', $type);
         } else {
             [$payType, $payId] = [$type ?: static::$type, static::$id];
         }

+ 3 - 3
app/data/service/payment/WechatPaymentService.php

@@ -60,7 +60,7 @@ class WechatPaymentService extends PaymentService
         try {
             if (isset(static::TYPES[static::$type])) {
                 $tradeType = static::TYPES[static::$type]['type'];
-                $tradeParam = static::$type . '_' . static::$id;
+                $tradeParam = static::$type . '-' . static::$id;
             } else {
                 throw new \think\Exception('支付类型[' . static::$type . ']未配置定义!');
             }
@@ -108,8 +108,8 @@ class WechatPaymentService extends PaymentService
      */
     public function notify(string $type = ''): string
     {
-        if (is_numeric(stripos($type, '_'))) {
-            [$payType, $payId] = explode('_', $type);
+        if (is_numeric(stripos($type, '-'))) {
+            [$payType, $payId] = explode('-', $type);
         } else {
             [$payType, $payId] = [$type ?: static::$type, static::$id];
         }

+ 31 - 22
app/data/view/payment/form.html

@@ -14,22 +14,25 @@
         <div class="layui-form-item">
             <span class="color-green font-w7 label-required-prev">支付通道</span>
             <span class="color-desc margin-left-5">Payment Channel</span>
-            <div class="layui-input">
+            <label class="block full-width">
                 {empty name='vo.type'}{php}$vo['type'] = 'wechat_jsapi';{/php}{/empty}
-                {foreach $types as $k => $v}
-                <label class="think-radio notselect">
-                    {if $vo.type eq $k}
-                    <input data-payment-type data-allow="{$v.allow}" checked type="radio" name="type" value="{$k}"> {$v.name}
-                    {else}
-                    <input data-payment-type data-allow="{$v.allow}" type="radio" name="type" value="{$k}"> {$v.name}
-                    {/if}
-                </label>
-                {/foreach}
-            </div>
-            <div class="help-block">此支付通道支持 <span class="color-blue" data-payment-info></span> 的终端用户通过 API 发起支付</div>
+                <select name="type" class="layui-select" lay-search lay-filter="payment-type">
+                    <option value="">-- 请选择 --</option>
+                    {foreach $payments as $kk => $vv}
+                    <optgroup label="{$kk}">
+                        {foreach $vv as $k => $v}{if $vo.type eq $k}
+                        <option selected value="{$kk}">{$v.name} ( {$v.allow} )</option>
+                        {else}
+                        <option value="{$k}">{$v.name} ( {$v.allow} )</option>
+                        {/if}{/foreach}
+                    </optgroup>
+                    {/foreach}
+                </select>
+            </label>
         </div>
 
         <div data-payment-type="wechat">{include file='payment/form_wechat'}</div>
+        <div data-payment-type="alipay" class="layui-hide">{include file='payment/form_alipay'}</div>
         <div data-payment-type="joinpay" class="layui-hide">{include file='payment/form_joinpay'}</div>
 
         <div class="layui-form-item relative block">
@@ -55,16 +58,22 @@
 
 {block name='script'}
 <script>
-    $('input[data-payment-type]').on('change', function () {
-        var $radio = $('input[data-payment-type]:checked');
-        if ($radio.val().indexOf('wechat') > -1) {
-            $('[data-payment-type="wechat"]').removeClass('layui-hide')
-            $('[data-payment-type="joinpay"]').addClass('layui-hide');
-        } else {
-            $('[data-payment-type="wechat"]').addClass('layui-hide')
-            $('[data-payment-type="joinpay"]').removeClass('layui-hide');
+    (function () {
+        layui.form.render();
+        apply({value: '{$vo.type}'});
+        layui.form.on('select(payment-type)', apply);
+
+        function apply(data) {
+            if (data.value.indexOf('wechat') > -1) {
+                $('[data-payment-type]').not($('[data-payment-type="wechat"]').removeClass('layui-hide')).addClass('layui-hide');
+            } else if (data.value.indexOf('alipay') > -1) {
+                $('[data-payment-type]').not($('[data-payment-type="alipay"]').removeClass('layui-hide')).addClass('layui-hide');
+            } else if (data.value.indexOf('joinpay') > -1) {
+                $('[data-payment-type]').not($('[data-payment-type="joinpay"]').removeClass('layui-hide')).addClass('layui-hide');
+            } else {
+                $('[data-payment-type]').addClass('layui-hide');
+            }
         }
-        $('[data-payment-info]').html($radio.data('allow'));
-    }).trigger('change');
+    })();
 </script>
 {/block}

+ 17 - 0
app/data/view/payment/form_alipay.html

@@ -0,0 +1,17 @@
+<label class="layui-form-item margin-bottom-20 block relative">
+    <span class="color-green font-s14 font-w7 margin-right-10">绑定商户编号</span>
+    <input name="alipay_appid" required placeholder="请输入绑定公众号(必填)" value="{$vo.content.alipay_appid|default=''}" class="layui-input">
+    <span class="help-block">商户绑定的公众号,授权给汇聚支付平台的公众号APPID</span>
+</label>
+
+<label class="layui-form-item margin-bottom-20 block relative">
+    <span class="color-green font-s14 font-w7">支付宝私钥文件内容</span><span class="nowrap color-desc">( 需要填写文件的全部内容 )</span>
+    <textarea name="alipay_public_key" placeholder="请输入支付宝私钥文件内容" class="layui-textarea">{$vo.content.alipay_public_key|default=''}</textarea>
+    <span class="help-block">从商户平台上下载支付证书,解压并取得其中的支付宝私钥文件用记事本打开并复制文件内容填至此处</span>
+</label>
+
+<label class="layui-form-item margin-bottom-20 block relative">
+    <span class="color-green font-s14 font-w7">支付宝公钥证书文件内容</span><span class="nowrap color-desc">( 需要填写文件的全部内容 )</span>
+    <textarea name="alipay_private_key" placeholder="请输入支付宝公钥证书文件内容" class="layui-textarea">{$vo.content.alipay_private_key|default=''}</textarea>
+    <span class="help-block">从商户平台上下载支付证书,解压并取得其中的支付宝公钥证书文件用记事本打开并复制文件内容填至此处</span>
+</label>