微信服务商支付如何在小程序中调用

2019-01-11 20:28:08
137
Wecha App PHP Javascript ThinkPHP

成功申请为微信支付服务商后,可以为没有开发能力的商户提供对接系统的生产、安装和维护服务,自行与商家进行业务洽谈,服务商信息会在我司备案,消除了商家质疑心理,使它更具备官方性、真实性、正规性。这是官方的语句,微信支付服务商目前在网上的文献还很少 特别是对接小程序的时候 


微信服务商对接小程序支付会比传统的支付多几个参数


1:我们需要去微信支付开通微信支付服务商


image.png


2:登录微信服务商平台,设置微信支付 key

image.png

image.png


3:绑定子商户信息

image.png


4:php后台实现 我用的是tp5 下面是统一下单实现方法

public function unifiedorder($orders_sn,$total_fee,$openid,$body = '微信支付测试')
    {

        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        
        $post['appid'] = $this->config['appid'];  //微信分配的公众账号ID
        $post['sub_appid'] = $this->config['sub_appid'];    //小程序ID
        $post['sub_mch_id'] = $this->config['sub_mch_id'];//子商户id
        $post['body'] = $body;
        $post['mch_id'] = $this->config['mch_id'];
        $post['nonce_str'] = $this->createNoncestr();//随机字符串
        $post['notify_url'] = $this->config['notify_url'];
        $post['sub_openid'] = $openid;
        $post['out_trade_no'] = $orders_sn;
        $post['spbill_create_ip'] = request()->ip();//服务器终端的ip
        $post['total_fee'] = $total_fee*100; //总金额 最低为一分钱 必须是整数
        $post['trade_type'] = 'JSAPI';
        $sign = $this->makeSign($post);

        $post['sign']   =   $sign;

        $result = $this->request($url,$post);

        if ($result['return_code'] === "SUCCESS" && $result['return_msg'] === 'OK'){
            $return = [
                'appId'     => $this->config['sub_appid'],
                'timeStamp' => time().'',
                'nonceStr'  => $post['nonce_str'],
                'package'   => 'prepay_id='.$result['prepay_id'],
                'signType'  => 'MD5'
            ];
            //二次验签
            $return['paySign'] = $this->twoSign($return);

            return $return;
        }
        return $result;
    }


因为微信服务商需要转账到子商户下面去 所以我们需要传入sub_appid和sub_mchid


这儿的 sub_openid,此参数必传,用户在子商户appid下的唯一标识。openid和sub_openid可以选传其中之一,如果选择传sub_openid,则必须传sub_appid。下单前需要调用【网页授权获取用户信息】接口获取到用户的Openid。


在小程序上面调用服务商支付 必须使用sub_openid


5:小程序调用跟传统的调用方法一致即可

wx.requestPayment({
timeStamp: info.timeStamp,
nonceStr: info.nonceStr,
package: info.package,
signType: info.signType,
paySign: info.paySign,
complete(res){
console.log(res)
}
})
})


服务商支付跟普通商户支付的方法大致一样 只是多了几个参数而已


下面是完整实例

<?php
/**
 * 微信支付类 小程序 服务商支付
 */
namespace lib;
class Payhyh{

    private $config;//微信配置

    public function __construct($config)
    {
        $this->config = $config;
    }

    /**
     * 统一下单接口
     * @param $orders_sn 订单号
     * @param $total_fee 支付金额
     * @param $openid 用户openid
     * @return mixed
     */

    public function unifiedorder($orders_sn,$total_fee,$openid,$body = '微信支付测试')
    {

        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $post['appid'] = $this->config['appid'];  //服务商ID
        $post['sub_appid'] = $this->config['sub_appid'];    //小程序ID
        $post['sub_mch_id'] = $this->config['sub_mch_id'];
        $post['body'] = $body;
        $post['mch_id'] = $this->config['mch_id'];
        $post['nonce_str'] = $this->createNoncestr();//随机字符串
        $post['notify_url'] = $this->config['notify_url'];
        $post['sub_openid'] = $openid;
        $post['out_trade_no'] = $orders_sn;
        $post['spbill_create_ip'] = request()->ip();//服务器终端的ip
        $post['total_fee'] = $total_fee*100; //总金额 最低为一分钱 必须是整数
        $post['trade_type'] = 'JSAPI';
        $sign = $this->makeSign($post);

        $post['sign']   =   $sign;

        $result = $this->request($url,$post);

        if ($result['return_code'] === "SUCCESS" && $result['return_msg'] === 'OK'){
            $return = [
                'appId'     => $this->config['sub_appid'],
                'timeStamp' => time().'',
                'nonceStr'  => $post['nonce_str'],
                'package'   => 'prepay_id='.$result['prepay_id'],
                'signType'  => 'MD5'
            ];
            //二次验签
            $return['paySign'] = $this->twoSign($return);

            return $return;
        }
        return $result;
    }

    /**
     * 二次验签
     * @return [type] [description]
     */
    private function twoSign($result)
    {
        return strtoupper(md5('appId='.$result['appId'].'&nonceStr='.$result['nonceStr'].'&package='.$result['package'].'&signType=MD5&timeStamp='.$result['timeStamp'].'&key='.$this->config['key']));
    }

    /**
     * 发起一个post请求
     * @param $url 请求 url
     * @param $array 请求参数
     * @param $setCert 是否是要证书 证书需要绝对路径
     * @return mixed
     */
    private function request($url,$array,$setCert = false)
    {
        $curl = curl_init(); // 启动一个CURL会话
        curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
        //设置header
        curl_setopt($curl, CURLOPT_HEADER, FALSE);
        if ($setCert == true) {
            //网站根目录
            $getRootPath = str_replace('\\','/',app()->getRootPath());
            // 设置证书
            curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'pem');
            curl_setopt($curl, CURLOPT_SSLCERT, $getRootPath . 'vendor/wechatPay/cert/apiclient_cert.pem');
            curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'pem');
            curl_setopt($curl, CURLOPT_SSLKEY, $getRootPath . 'vendor/wechatPay/cert/apiclient_key.pem');
            curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'pem');
            curl_setopt($curl, CURLOPT_CAINFO, $getRootPath . 'vendor/wechatPay/cert/rootca.pem');
        }
        //要求结果为字符串且输出到屏幕上
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($curl, CURLOPT_POST, TRUE);       //发送一个常规的Post请求
        curl_setopt($curl, CURLOPT_POSTFIELDS, $this->ToXml($array)); // Post提交的数据包
        curl_setopt($curl, CURLOPT_TIMEOUT, 30);      // 设置超时限制防止死循环
        $tmpInfo = curl_exec($curl); // 执行操作
        curl_close($curl); //关闭CURL会话
        return $this->FromXml($tmpInfo);
    }
    /**
     * 生成随机数
     * @param int $len 随机数长度
     * @return string
     */
    private function createNoncestr($length = 32)
    {
        $str = null;
        $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
        $max = strlen($strPol)-1;

        for($i=0;$i<$length;$i++){
            $str.=$strPol[rand(0,$max)];//rand($min,$max)生成介于min和max两个数之间的一个随机整数
        }

        return $str;
    }

    /**
     * 将 xml 转为数组
     * @param $xml
     * @return mixed
     */
    private function FromXml($xml)
    {
        //将XML转为array
        return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)),true);
    }

    /**
     * 将 数组 转为 xml
     * @param $arr
     * @return string
     */
    private function ToXml($arr)
    {
        $xml = "<xml>";
        foreach ($arr as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }

    /**
     * 生成支付签名
     * @param $data
     * @return string
     */
    private function makeSign($paramArray,$isencode = false){

        $paramStr = '';

        ksort($paramArray);

        $i = 0;

        foreach ($paramArray as $key => $value)

        {

            if ($key == 'Signature'){

                continue;

            }

            if ($i == 0){

                $paramStr .= '';

            }else{

                $paramStr .= '&';

            }

            $paramStr .= $key . '=' . ($isencode?urlencode($value):$value);

            ++$i;

        }

        $stringSignTemp=$paramStr."&key=".$this->config['key'];

        $sign=strtoupper(md5($stringSignTemp));

        return $sign;
    }
}


thank

最新评论
总共 1 条评论
用户659604
可以啊,大佬
2019-01-16 19:17:57