vcms微信支付流程

ThinkPhp 发表时间:2018-04-08 18:35:22 作者:梁子亮 浏览次数:930

前期准备工作,包括

1、公众号绑定到同一个开放平台(非必须,unionid机制才需要)

2、登陆公众号平台,修改如下

2.1 业务域名 : aaa.net.cn

2.2 JS接口安全域名 :aaa.net.cn

2.3 网页授权域名:aaa.net.cn

2.4 ip白名单都添加有 123.56.219.177

2.5 在商户平台添加支付授权链接为:http://aaa.net.cn/order/payment/sid/

3、更改config.php中的配置代码中的‘APPID’,‘APPSECRET’,‘MCHID’,‘KEY’(注意其中APPID和APPSECRET会影响到授权登录;APPID、MCHID和KEY会影响微信支付,即APPSECRET的值不会影响微信支付:前提是微信授权登录时openid获取的是正确的),至此前期准备工作完成

调用方法一:价格变量等都为后台php直接分配过去前台的

在config配置项配置好如下参数

php
'APPID' => 'xxxxxx', //公众平台可以查看
'APPSECRET' => 'xxxxxx',  //公众平台可以查看
'MCHID' => 'xxxxx',  //微信支付商户号,商户平台查看
'KEY' => 'xxxxx', //API秘钥,商户平台查看

在需要微信支付的地方引入微信支付类:

Vendor('Pay.WxPayData')

后台生成js参数分配到前台,在支付方法中加入,其中:

body为标题

attach为用户自定义数据

total_fee为总价钱

notify_url为通知函数(必须是完整地址,即要使用C('WEBSITE'))

trade_type包括'JSAPI'和'NATIVE'两种,其中'JSAPI'为公众号支付,'NATIVE'扫码支付

php
$pay = new \WxPay($openid, $body, $attach, $total_fee, $notify_url, $trade_type = 'JSAPI', $goods_tag = '');
$this->jsApiParameters = $pay->getJsParameters();

前台js调用如下,其中支付按钮就是onclick="callpay()"属性触发支付行为

javascript//调用微信JS api 支付
function jsApiCall() {
    WeixinJSBridge.invoke(
        'getBrandWCPayRequest',
        <?php echo $jsApiParameters; ?>,
        function(res){
            // WeixinJSBridge.log(res.err_msg);
            alert('err_code:' + res.err_code + ', err_desc:' +res.err_desc + ', err_msg:' + res.err_msg);
        }
    );
}

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();
    }
}

调用方法二:价格变量等都为前端ajax到后台获取的

在config配置项配置好如下参数

php
'APPID' => 'xxxxxx', //公众平台可以查看
'APPSECRET' => 'xxxxxx',  //公众平台可以查看
'MCHID' => 'xxxxx',  //微信支付商户号,商户平台查看
'KEY' => 'xxxxx', //API秘钥,商户平台查看

前端通过js去后端获取数据,其中支付按钮就是onclick="callpay()"属性触发支付行为,money为传入的参数

//调用微信JS api 支付
    function jsApiCall(money) {
        var values = {
            money : money,
            shop_id : shop_id
        };
        $.ajax({
            type : 'post',
            url : '/home/order/get_wechat_payment',
            data: values,
            success : function (ret) {
                if(ret.status == 200){
                    var order_id = ret.order_id;
                    var jsApiParameters = JSON.parse(ret.jsApiParameters);
                    WeixinJSBridge.invoke(
                        'getBrandWCPayRequest',
                        jsApiParameters,
                        function(res){
                            if(res.err_msg == "get_brand_wcpay_request:ok" ){
                                location.href = '/home/order/payment_result/order_id/'+order_id;
                            }
                            else if(res.err_msg == "get_brand_wcpay_request:cancel" ){
                                toast('支付取消');
                                closeLoading();
                            }
                            else{
                                toast('支付失败');
                                closeLoading();
                            }
                        }
                    );
                }
            }
        });
        
    }

    function callpay(money) {
        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(money);
        }
    }

后端在需要微信支付的地方引入微信支付类(此处为get_wechat_payment控制器内):

Vendor('Pay.WxPayData')

get_wechat_payment方法中创建一个新订单,状态为未支付且写入数据库;生成统一下单数据,并返回给前台

public function get_wechat_payment () {
        
        $user = $_SESSION['user'];
        $openid = $user['openid'];
        $money = I("money");
        $shop_id = I("shop_id");
        $save_data['uid'] = $user['id'];
        $save_data['shop_id'] = $shop_id;
        $attach = $save_data['out_trade_no'] = $save_data['order_number'] = create_order_number($user['id']);
        $save_data['must_pay'] = $money;
        $save_data['create_time'] = date('Y-m-d H:i:s');
        $save_data['order_type'] = 2; // 线下买单
        $save_data['pay_type'] = 1; // 微信支付
        $save_data['status'] = 0; // 待支付
        $res = M('GoodsOrder')->add($save_data);

        $body = '线下买单订单';
        $body = '线下买单';
        $total_fee = $money*100;
        $notify_url =  C('WEBSITE').'/home/index/test_notify_url';
        $pay = new \WxPay($openid, $body, $attach, $total_fee, $notify_url, $trade_type = 'JSAPI', $goods_tag = '');
        $jsApiParameters = $pay->getJsParameters();
        $data['status'] = 200;
        $data['jsApiParameters'] = $jsApiParameters;
        $data['order_id'] = $res;
        $this->ajaxReturn($data);die;

    }

前台接收后台返回的参数并处理,具体见上述jsApiCall方法。

支付结果异步通知处理

public function test_notify_url () {
    $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
    $post = json_decode(json_encode(simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA)), true); // 方法一
    $post = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA); // 方法二
    // 首先验证签名
    $bool = $this->checkSign($post);
    if($bool){
        $attach = $post['xml']['attach']['@cdata'];
        $attach_data = explode('|', $attach);
        $out_trade_no = $attach_data[0];
        $re = M("GoodsOrder")->where(array('out_trade_no'=>$out_trade_no))->find();
        if($re['status'] == 0){
            M("GoodsOrder")->where(array('id'=>$re['id']))->setField('status',1);
            D("Api/GoodsOrder")->paySuccess($re['id'],1,2);
        }
        echo '<xml><return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg></xml>';
    }
}

public function checkSign ($post) {
    if($post['xml']){
        $sign1 = $post['xml']['sign']['@cdata'];
        unset($post['xml']['sign']);
        $str1 = '';
        foreach ($post['xml'] as $k => $v) {
            if(is_array($v)){
                $str1 .= $k . '=' . $v['@cdata'] . '&';
            }
            else{
                $str1 .= $k . '=' . $v  . '&';
            }
        }
        // 拼接key
        $str2 =  $str1 . 'key=' . C('KEY');
        // md5编码并转成大写
        $sign2 = strtoupper(md5($str2));
        if($sign1 == $sign2){
            return true;
        }
        return false;
    }
}

支付完成!