ThinkCMF微信JSAPI支付,扫码支付,h5支付 , 支付宝支付

前言

支付是基于ThinkCMF的电商版里面的支付插件 pay 做的。
电商版地址:https://github.com/thinkcmf/mall
插件可以在里面的 public/plugins/pay

安装配置

微信支付基本配置

1.注册微信公众号,获取里面的APPID,APPSECRET
2.配置授权域名,白名单等
3.微信商户号申请Native支付,JSAPI支付,h5支付(有的默认是就有的)
4.获取商户号(10位的数字)配置商户秘钥(KEY)
5.配置支付授权目录
JSAPI的授权目录 http://www.xxxxx.com/order/payment/
Native回调地址 http://www.xxxxx.com/plugin/pay/wechat/notify.html
【以上地址是根据ThinkCMF电商版的商城模块来的】

支付宝支付基本配置

1.注册支付宝商户平台
2.注册支付宝开发者平台
3.获取支付宝的公钥私钥,这个支付宝提供了一个生成的工具,下载下来生成一下就可以
https://opendocs.alipay.com/open/291/106097/
ThinkCMF微信JSAPI支付,扫码支付,h5支付 , 支付宝支付_第1张图片
4.获取支付宝APPID,应用私钥,支付宝公钥(注意这里会有一个应用公钥,就是生成的公钥,不是那个)
ThinkCMF微信JSAPI支付,扫码支付,h5支付 , 支付宝支付_第2张图片

后台配置填写

ThinkCMF微信JSAPI支付,扫码支付,h5支付 , 支付宝支付_第3张图片
这套操作下来,电商版的支付就可以成功了。但是我在使用的时候发现了一些BUG。
BUG 1:
插件里面的pay/lib/Config.php 微信回调地址错误

public static function get($key = false)
    {
        $data   = [];
        $config = cmf_get_plugin_config('Pay');
        $dev    = isset($config['dev']) ? $config['dev'] : false;

        $config = [
            // 微信支付参数
            'wechat' => [
                'debug'      => $dev, // 沙箱模式
                'app_id'     => isset($config['wx_app_id']) ? $config['wx_app_id'] : '', // 应用ID
                'mch_id'     => isset($config['wx_mch_id']) ? $config['wx_mch_id'] : '', // 微信支付商户号
                'mch_key'    => isset($config['wx_mch_key']) ? $config['wx_mch_key'] : '', // 微信支付密钥
                'ssl_cer'    => '', // 微信证书 cert 文件
                'ssl_key'    => '', // 微信证书 key 文件
                'notify_url' => cmf_plugin_url('Pay://Wechat/notify', [], true), // 支付通知URL
                'cache_path' => Env::get('runtime_path'),// 缓存目录配置(沙箱模式需要用到)
            ],
            // 支付宝支付参数
            'alipay' => [
                'debug'       => $dev, // 沙箱模式
                'app_id'      => isset($config['ali_app_id']) ? $config['ali_app_id'] : '', // 应用ID
                'public_key'  => isset($config['ali_public_key']) ? $config['ali_public_key'] : '',
                'private_key' => isset($config['ali_private_key']) ? $config['ali_private_key'] : '',
                'notify_url'  => cmf_plugin_url('Pay://Alipay/notify', [], true), // 支付通知URL
                'return_url'  => cmf_url('order/order/index',[],true,true),
            ]
        ];
        if($key && isset($config[$key])){
            return $config[$key];
        }
        return $config;
    }

BUG 2:
pay/controller/WechatController 里面初始化配置获取错误

public function initialize()
{
    $this->config = \plugins\pay\lib\Config::get();
}

BUG3:
pay/PayPlugin.php 里面的安装文字不对,统一下单里面公众号支付缺少openid



namespace plugins\pay;

use cmf\lib\Plugin;
use think\Db;
use think\exception\HttpResponseException;


class PayPlugin extends Plugin
{
    const CMF_WECHAT_QRCODE = 'cmf-wechat-qrcode';
    const CMF_WECHAT_H5     = 'cmf-wechat-h5';
    const CMF_WECHAT_MP     = 'cmf-wechat-mp';
    const CMF_WECHAT_MINI   = 'cmf-wechat-miniapp'; //增加微信小程序支付
    const CMF_ALIPAY_WEB    = 'cmf-alipay-web';
    const CMF_ALIPAY_H5     = 'cmf-alipay-h5';

    public $info = [
        'name'        => 'Pay',
        'title'       => '支付插件',
        'description' => '支付插件',
        'status'      => 1,
        'author'      => '五五',
        'version'     => '1.0',
        'demo_url'    => 'http://www.thinkcmf.com',
        'author_url'  => 'http://www.thinkcmf.com'
    ];

    public $hasAdmin = 0;

    // 插件安装
    public function install()
    {
        Db::name('OrderPayment')->delete(true);
        Db::name('OrderPayment')->insertAll([
            [
                'code'        => self::CMF_WECHAT_QRCODE,
                'name'        => '微信扫码支付',
                'description' => '微信扫码支付',
                'tips'        => '微信扫码',
            ],
            [
                'code'        => self::CMF_WECHAT_H5,
                'name'        => '微信H5支付',
                'description' => '微信H5支付',
                'tips'        => '微信H5',
            ],
            [
                'code'        => self::CMF_WECHAT_MP,
                'name'        => '微信支付',
                'description' => '微信支付',
                'tips'        => '微信',
            ],
            [
                'code'        => self::CMF_WECHAT_MINI,
                'name'        => '微信小程序支付',
                'description' => '微信小程序支付',
                'tips'        => '微信小程序',
            ],
            [
                'code'        => self::CMF_ALIPAY_WEB,
                'name'        => '支付宝web支付',
                'description' => '支付宝web支付',
                'tips'        => '支付宝跳转',
            ],
            [
                'code'        => self::CMF_ALIPAY_H5,
                'name'        => '支付宝H5支付',
                'description' => '支付宝H5支付',
                'tips'        => '支付宝跳转',
            ]
        ]);
        return true;//安装成功返回true,失败false
    }

    // 插件卸载
    public function uninstall()
    {
        return true;//卸载成功返回true,失败false
    }

    /**
     * 统一下单
     *
     * @param array $params
     * @return bool|mixed|\think\Response
     */
    public function orderPaymentUnifiedorder($params = [])
    {
        try {
            switch ($params['code']) {
                case self::CMF_WECHAT_QRCODE:
                    $payType   = 'wechat';
                    $payMethod = 'scan';
                    $order     = [
                        'out_trade_no' => $params['sn'],
                        'body'         => $params['sn'],
                        'total_fee'    => (string)bcmul($params['amount'], 100),
                    ];
                    break;
                case self::CMF_WECHAT_MP:
                    $payType   = 'wechat';
                    $payMethod = 'mp';
                    $order     = [
                        'out_trade_no' => $params['sn'],
                        'body'         => $params['sn'],
                        'openid'       => $params['openid'],
                        'total_fee'    => (string)bcmul($params['amount'], 100),
                    ];
                    break;
                case self::CMF_WECHAT_H5:
                    $payType   = 'wechat';
                    $payMethod = 'wap';
                    $order     = [
                        'out_trade_no' => $params['sn'],
                        'body'         => $params['sn'],
                        'total_fee'    => (string)bcmul($params['amount'], 100),
                    ];
                    break;
                case self::CMF_WECHAT_MINI:
                    $payType   = 'wechat';
                    $payMethod = 'miniapp';
                    $order     = [
                        'out_trade_no' => $params['sn'],
                        'body'         => $params['body'],
                        'attach'       => $params['attach'],
                        'openid'         => $params['openid'],
                        'total_fee'    => (string)bcmul($params['amount'], 100),
                    ];
                    break;
                case self::CMF_ALIPAY_WEB:
                    $payType   = 'alipay';
                    $payMethod = 'web';
                    $order     = [
                        'out_trade_no' => $params['sn'],
                        'subject'      => $params['sn'],
                        'total_amount' => $params['amount'],
                    ];
                    break;
                case self::CMF_ALIPAY_H5:
                    $payType   = 'alipay';
                    $payMethod = 'wap';
                    $order     = [
                        'out_trade_no' => $params['sn'],
                        'subject'      => $params['sn'],
                        'total_amount' => $params['amount'],
                    ];
                    break;
                default:
                    return false;
            }
            $config  = \plugins\pay\lib\Config::get();
            $pay     = new \Pay\Pay($config);
            $options = $pay->driver($payType)->gateway($payMethod)->apply($order);
            switch ($params['code']) {
                case self::CMF_WECHAT_QRCODE:
                    return $options;
                    break;
                case self::CMF_WECHAT_MP:
                    return $options;
                    break;
                case self::CMF_WECHAT_H5:
                    throw new HttpResponseException(\redirect($options));
                    break;
                case self::CMF_WECHAT_MINI:
                    return $options;
                    break;
                case self::CMF_ALIPAY_WEB:
                    throw new HttpResponseException(\response($options));
                    break;
                case self::CMF_ALIPAY_H5:
                    throw new HttpResponseException(\response($options));
                    break;
                default:
                    return $options;
            }

        } catch (Exception $e) {
            return false;
        }

    }

    /**
     * 支付渠道
     *
     * @param array $params
     * @return array|\PDOStatement|string|\think\Collection
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function orderPayment($params = [])
    {
        $data = [];
        if (cmf_is_mobile()) {
            $data = Db::name('OrderPayment')
                ->where('status', 1)
                ->where('code',self::CMF_ALIPAY_H5)
                ->whereOr(
                    'code',self::CMF_WECHAT_H5
                )
                ->field(true)
                ->select();
        } else {
            $data = Db::name('OrderPayment')
                ->where('status', 1)
                ->where('code',self::CMF_ALIPAY_WEB)
                ->whereOr(
                    'code',self::CMF_WECHAT_QRCODE
                )
                ->field(true)
                ->select();
        }
        if (cmf_is_wechat()) {
            $data = Db::name('OrderPayment')
                ->where('status', 1)
                ->where('code',self::CMF_WECHAT_MP)
                ->field(true)
                ->select();
        }
        if (strpos($_SERVER['HTTP_USER_AGENT'], 'AlipayClient') !== false) {
            $data = Db::name('OrderPayment')
                ->where('status', 1)
                ->where('code',self::CMF_ALIPAY_H5)
                ->field(true)
                ->select();
        }
        return $data;
    }
}

PaymentController 里面修改,加上获取openid,加上扫码支付时,判断支付状态


// +----------------------------------------------------------------------
// | ThinkCMF [ WE CAN DO IT MORE SIMPLE ]
// +----------------------------------------------------------------------
// | Copyright (c) 2013-2019 http://www.thinkcmf.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 老猫 
// +----------------------------------------------------------------------
namespace app\order\Controller;

use app\order\model\OrderModel;
use cmf\controller\UserBaseController;
use think\Db;

class PaymentController extends UserBaseController
{

    public function getCode()
    {
        $paymentId   = $this->request->param('payment_id', 0, 'intval');
        $paymentCode = $this->request->param('payment_code', '');
        $orderId    = $this->request->param('order_id');

        if (empty($orderId)) {
            $this->error('订单不能为空');
        }

        $userId = cmf_get_current_user_id();

        if (empty($paymentId)) {
            $payment = Db::name("OrderPayment")->where('code', $paymentCode)->find();
        } else {
            $payment = Db::name("OrderPayment")->where('id', $paymentId)->find();
        }

        $findOrder = Db::name('Order')->where(['user_id' => $userId, 'id' => $orderId])->find();

        if (empty($findOrder)) {
            $this->error('订单不存在!');
        } else if ($findOrder['pay_status'] == 1) {
            $this->error('订单已支付!');
        }

        $userPayments = session('user_payments');

        $userPayments = empty($userPayments) ? [] : $userPayments;

        if (!in_array($payment['code'], $userPayments) && $findOrder['payment_code'] != $payment['code']) {
            $this->error('非法支付方式!');
        }

        $data = ['payment_code' => $payment['code'], 'payment_name' => $payment['name']];

        if (empty($payment['is_prepay']) && $findOrder['pay_status'] != 10) {
            $data['pay_status'] = 10;//10:等待支付
        }

        //修改订单支付方式
        Db::name('Order')->where(['user_id' => $userId, 'id' => $orderId, 'pay_status' => 0])->update($data);

        $order   = Db::name('Order')->where(['user_id' => $userId, 'id' => $orderId])->find();
        $params  = [
            'code'   => $payment['code'],
            'amount' => $order['order_amount'],
            'sn'     => $order['order_sn']
        ];
        
        //修改的,这里是微信JSAPI支付要带上openid
        $openid = session('openid');
        if($payment['code'] == 'cmf-wechat-mp'){
            $params['openid'] = $openid;
        }
        $info = hook_one('order_payment_unifiedorder', $params);
        if(cmf_is_wechat()){
            $info = json_encode($info);
        }
        $this->assign([
            'order_sn' => $order['order_sn'],
            'payment'=>$payment,
            'info'=>$info
        ]);
        
        return $this->fetch('payment');
    }

    /**
     * 判断订单状态
     */
    public function check(){
        $order_sn = $this->request->param('sn');
        $order = OrderModel::where('order_sn',$order_sn)->find();
        if($order['pay_status'] == 1){
            $this->success('success');
        }else{
            $this->error('error');
        }
    }
}

JSAPI支付页面

<extend name="public@base"/>
<block name="seo">
	<title>填写核对订单</title>
	<meta name="keywords" content=""/>
	<meta name="description" content=""/>
</block>

<block name="main">

</block>

<block name="footer"></block>
<block name="script">
	<script type="text/javascript">
		var url = "{:url('order/Order/index')}";
		//调用微信JS api 支付
		function jsApiCall()
		{
			WeixinJSBridge.invoke(
					'getBrandWCPayRequest',{$info},
					function(res){
						WeixinJSBridge.log(res.err_msg);

						if(res.err_msg == "get_brand_wcpay_request:ok"){
							window.location.href= url;
						}else if(res.err_msg == "get_brand_wcpay_request:cancel"){
							alert('取消支付');
							window.location.href = document.referrer;
						}else if(res.err_msg == "get_brand_wcpay_request:fail"){
							alert('支付失败');
						}
					}
			);
		}
		function callpay()
		{
			if (typeof WeixinJSBridge == "undefined"){
				if( document.addEventListener ){
					document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
				}else if (document.attachEvent){
					document.attachEvent('WeixinJSBridgeReady', jsApiCall);
					document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
				}
			}else{
				jsApiCall();
			}
		}
		callpay();
	</script>
</block>

微信扫码支付页面

<extend name="public@base"/>
<block name="seo">
	<title>填写核对订单</title>
	<meta name="keywords" content=""/>
	<meta name="description" content=""/>
</block>
<block name="css">
	<style>
		.table-with-head thead {
			background: #eee;
		}

		.table-with-head {
			border: 1px solid #ddd;
		}
		blockquote {
			margin-bottom: 0;
		}
	</style>
</block>
<block name="main">
	<div class="container">
		<div class="row">
			<div class="row"></div>
			<div class="row">
				<div class="col-md-12 col-xs-12 col-sm-12">

				</div>
				<div class="col-md-4 col-xs-4 col-sm-4">
					<h1 style="text-align: center">微信支付</h1>
					<div id="qrcode" data-url="{$info}"></div>
				</div>
				<div class="col-md-4 col-xs-4 col-sm-4"></div>
			</div>

		</div>


	</div>
</block>

<block name="footer"></block>
<block name="script">
	<style>
		#qrcode > img {
			width: 100%;
		}
	</style>
	<script>
		Wind.use('__TMPL__/public/assets/js/qrcode.min.js', function () {
			var url = $('#qrcode').data('url');
			new QRCode(document.getElementById("qrcode"),url);
		});
		var order_sn = {$order_sn};
		setInterval(function(){
			$.get("{:url('order/payment/check')}",{sn:order_sn},function(res){
				console.log(res);
			})
		},2000);
	</script>
</block>

openid获取方式,没做微信登陆
在HomeBaseController 里面增加判断

protected function initialize()
    {
        // 监听home_init
        hook('home_init');
        parent::initialize();
        if(cmf_is_wechat() && !session('openid')){
            $this->getOpenid();
        }
        $siteInfo = cmf_get_site_info();
        View::share('site_info', $siteInfo);
    }
    
protected function getOpenid(){
        $appid = 'appid';
        $appkey = 'appkey';
        $redirect_uri = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
        if (!isset($_GET['code'])) {
            $state = md5(uniqid(rand(), true));
            $callback = urlencode($redirect_uri);
            $wxurl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=$appid&redirect_uri=$callback&response_type=code&scope=snsapi_base&state=$state#wechat_redirect";
            $this->redirect($wxurl);
        }else{
            $url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=' . $appid .'&secret=' . $appkey . '&code=' . $_GET['code'] .'&grant_type=authorization_code';
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_URL, $url);
            $json = curl_exec($ch);
            curl_close($ch);
            $arr = json_decode($json, 1);
            session('openid',$arr['openid']);
        }
    }

支付宝支付没有做其它的修改,直接可用

你可能感兴趣的:(ThinkCMF)