maxwen

写这篇文章的目的主要是由于在微信公众平台提供的SDK中并没有提供此功能的SDK实现,

其实最后实现还是借助 微信公众平台开发文档 和 SDK

企业付款的应用场景: 公众号向已关注用户付款,比如处理退款、财务结算等

 

先说一下实现思路:

在SDK中自带类库的基础上扩展WxMchPay组件, 实现企业付款功能的扩展。

话不多说,上代码, 下面是继承SDK,实现企业付款的组件:

$parameters参数参考: 企业付款API的文档

<?php
// 引入SDK
import(\'Common.Util.WxPay\');

/**
 * 微信企业付款操作类
 * Author  :  Max.wen
 * DateTime: <15/9/16 11:00>
 */
class WxMchPay extends Wxpay_client_pub
{
    /**
     * API 参数
     * @var array
     * \'mch_appid\'         # 公众号APPID
     * \'mchid\'             # 商户号
     * \'device_info\'       # 设备号
     * \'nonce_str\'         # 随机字符串
     * \'partner_trade_no\'  # 商户订单号
     * \'openid\'            # 收款用户openid
     * \'check_name\'        # 校验用户姓名选项 针对实名认证的用户
     * \'re_user_name\'      # 收款用户姓名
     * \'amount\'            # 付款金额
     * \'desc\'              # 企业付款描述信息
     * \'spbill_create_ip\'  # Ip地址
     * \'sign\'              # 签名
     */
    public $parameters = [];

    public function __construct()
    {
        $this->url = \'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers\';
        $this->curl_timeout = WxPayConf_pub::CURL_TIMEOUT;
    }

    /**
     * 生成请求xml数据
     * @return string
     */
    public function createXml()
    {
        $this->parameters[\'mch_appid\'] = WxPayConf_pub::APPID;
        $this->parameters[\'mchid\']     = WxPayConf_pub::MCHID;
        $this->parameters[\'nonce_str\'] = $this->createNoncestr();
        $this->parameters[\'sign\']      = $this->getSign($this->parameters);
        return $this->arrayToXml($this->parameters);
    }


    /**
     *     作用:使用证书,以post方式提交xml到对应的接口url
     */
    function postXmlSSLCurl($xml,$url,$second=30)
    {
        $ch = curl_init();
        //超时时间
        curl_setopt($ch,CURLOPT_TIMEOUT,$second);
        //这里设置代理,如果有的话
        //curl_setopt($ch,CURLOPT_PROXY, \'8.8.8.8\');
        //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
        curl_setopt($ch,CURLOPT_URL, $url);
        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
        //设置header
        curl_setopt($ch,CURLOPT_HEADER,FALSE);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE);
        //设置证书
        curl_setopt($ch,CURLOPT_CAINFO, WxPayConf_pub::SSLROOTCA_PATH);
        //使用证书:cert 与 key 分别属于两个.pem文件
        //默认格式为PEM,可以注释
        curl_setopt($ch,CURLOPT_SSLCERTTYPE,\'PEM\');
        curl_setopt($ch,CURLOPT_SSLCERT, WxPayConf_pub::SSLCERT_PATH);
        //默认格式为PEM,可以注释
        curl_setopt($ch,CURLOPT_SSLKEYTYPE,\'PEM\');
        curl_setopt($ch,CURLOPT_SSLKEY, WxPayConf_pub::SSLKEY_PATH);

        //post提交方式
        curl_setopt($ch,CURLOPT_POST, true);
        curl_setopt($ch,CURLOPT_POSTFIELDS,$xml);
        $data = curl_exec($ch);
        //返回结果
        if($data){
            curl_close($ch);
            return $data;
        }
        else {
            $error = curl_errno($ch);
            echo "curl出错,错误码:$error"."<br>";
            echo "<a href=\'http://curl.haxx.se/libcurl/c/libcurl-errors.html\'>错误原因查询</a></br>";
            curl_close($ch);
            return false;
        }
    }


}

 

Controller层功能实现:

<?php
/**
 * Author  :  Max.wen
 * DateTime: <15/9/20 16:47>
 */

namespace Home\Controller;


class TestController extends CommonController
{

    /**
     * 企业付款测试
     */
    public function rebate()
    {
        import(\'Common.Util.WxMchPay\');
        $mchPay = new \WxMchPay();
        // 用户openid
        $mchPay->setParameter(\'openid\', \'oy2lbszXkgvlEKThrzqEziKEBzqU\');
        // 商户订单号
        $mchPay->setParameter(\'partner_trade_no\', \'test-\'.time());
        // 校验用户姓名选项
        $mchPay->setParameter(\'check_name\', \'NO_CHECK\');
        // 企业付款金额  单位为分
        $mchPay->setParameter(\'amount\', 100);
        // 企业付款描述信息
        $mchPay->setParameter(\'desc\', \'开发测试\');
        // 调用接口的机器IP地址  自定义
        $mchPay->setParameter(\'spbill_create_ip\', \'127.0.0.1\'); # getClientIp()
        // 收款用户姓名
        // $mchPay->setParameter(\'re_user_name\', \'Max wen\');
        // 设备信息
        // $mchPay->setParameter(\'device_info\', \'dev_server\');

        $response = $mchPay->postXmlSSL();
        if( !empty($response) ) {
            $data = simplexml_load_string($response, null, LIBXML_NOCDATA);
            echo json_encode($data);
        }else{
            echo json_encode( array(\'return_code\' => \'FAIL\', \'return_msg\' => \'transfers_接口出错\', \'return_ext\' => array()) );
        }
    }
}

 

完成上述两部分代码,基本就可以成功调用企业付款API了。

返回结果的数据结构示例:

{
	"return_code": "SUCCESS",
	"return_msg": { },
	"mch_appid": "wx519cae424099ed6b",
	"mchid": "1228636402",
	"device_info": { },
	"nonce_str": "qjupk84q4iqxkb578hb5h2qiatgcwxwg",
	"result_code": "SUCCESS",
	"partner_trade_no": "test-1442801966",
	"payment_no": "1000018301201509210739170397",
	"payment_time": "2015-09-21 10:19:26"
}

  

可能遇到的问题:

1、CA证书错误

  在WxMchPay中大家可以看到,我重写了SDK中 Wxpay_client_pub 的 postXmlSSLCurl()方法

  因为默认在SDK中的这个方法在CURL POST请求的时候没有附带CA证书。

  相比之下就多了 

  curl_setopt($ch,CURLOPT_CAINFO, WxPayConf_pub::SSLROOTCA_PATH);  这么一行代码。  

  作用就是请求时附带CA证书。

 

 

2、对同一用户转账操作过于频繁,请稍候重试.

  这个错误属于微信服务端的限制,具体限制频率也没有找到那里有说明,不过经过实际测试大概在1分钟左右。

  所以在开发的时候还需要多注意。


有任何疑问欢迎共同探讨。



P.S. 搬家至博客园的第一篇随笔, 送给组织的见面礼。希望再次广交猿友。

 

分类:

技术点:

相关文章: