PHP微信商户支付 - 企业付款到零钱功能(即提现)技术资料汇总

PHP实现微信开发中提现功能(企业付款到用户零钱)

一.实现该功能目的

    这几天在小程序里要实现用户从系统中提现到零钱的功能,查了一下文档可以使用 企业付款到用户零钱 来实现;

 官方文档:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_1;

 注意事项:商户打款时是从商户可用余额中减钱,所以确保商户可用余额充足,同时注意官方文档中的付款规则;

二.PHP实现

复制代码
 //封装提现方法
  function tixian($money){
        $appid = "################";//商户账号appid
        $secret = "##########";//api密码
        $mch_id = "#######";//商户号
        $mch_no = "#######";
        $openid="123456789";//授权用户openid
             
        $arr = array();
        $arr['mch_appid'] = $appid;
        $arr['mchid'] = $mch_id;
        $arr['nonce_str'] = ugv::randomid(20);//随机字符串,不长于32位
        $arr['partner_trade_no'] = '1298016501' . date("Ymd") . rand(10000, 90000) . rand(10000, 90000);//商户订单号
        $arr['openid'] = $openid;
        $arr['check_name'] = 'NO_CHECK';//是否验证用户真实姓名,这里不验证
        $arr['amount'] = $money;//付款金额,单位为分
        $desc = "###提现";
        $arr['desc'] = $desc;//描述信息
        $arr['spbill_create_ip'] = '192.168.0.1';//获取服务器的ip
        //封装的关于签名的算法
        $notify = new Notify_pub();
        $notify->weixin_app_config = array();
        $notify->weixin_app_config['KEY'] = $mch_no;

        $arr['sign'] = $notify->getSign($arr);//签名

        $var = $notify->arrayToXml($arr);
        $xml = $this->curl_post_ssl('https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers', $var, 30, array(), 1);
        $rdata = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
        $return_code = (string)$rdata->return_code;
        $result_code = (string)$rdata->result_code;
        $return_code = trim(strtoupper($return_code));
        $result_code = trim(strtoupper($result_code));

        if ($return_code == 'SUCCESS' && $result_code == 'SUCCESS') {
            $isrr = array(
                'con'=>'ok',
                'error' => 0,
            );
        } else {
            $returnmsg = (string)$rdata->return_msg;
            $isrr = array(
                'error' => 1,
                'errmsg' => $returnmsg,
            );

        }
        return json_encode($isrr);
    }    
复制代码
复制代码
//上个方法中用到的curl_post_ssl()
function curl_post_ssl($url, $vars, $second = 30, $aHeader = array())
    {
        $isdir = "/cert/";//证书位置

        $ch = curl_init();//初始化curl

        curl_setopt($ch, CURLOPT_TIMEOUT, $second);//设置执行最长秒数
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);//要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_URL, $url);//抓取指定网页
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);// 终止从服务端进行验证
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);//
        curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');//证书类型
        curl_setopt($ch, CURLOPT_SSLCERT, $isdir . 'apiclient_cert.pem');//证书位置
        curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');//CURLOPT_SSLKEY中规定的私钥的加密类型
        curl_setopt($ch, CURLOPT_SSLKEY, $isdir . 'apiclient_key.pem');//证书位置
        curl_setopt($ch, CURLOPT_CAINFO, 'PEM');
        curl_setopt($ch, CURLOPT_CAINFO, $isdir . 'rootca.pem');
        if (count($aHeader) >= 1) {
            curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader);//设置头部
        }
        curl_setopt($ch, CURLOPT_POST, 1);//post提交方式
        curl_setopt($ch, CURLOPT_POSTFIELDS, $vars);//全部数据使用HTTP协议中的"POST"操作来发送

        $data = curl_exec($ch);//执行回话
        if ($data) {
            curl_close($ch);
            return $data;
        } else {
            $error = curl_errno($ch);
            echo "call faild, errorCode:$error\n";
            curl_close($ch);
            return false;
        }
    }
复制代码

三.补充

关于具体签名算法,可参考微信官方文档;

简单示范签名算法:

复制代码
//将要发送的数据整理为$data

ksort($data);//排序
//使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串
$str='';
foreach($data as $k=>$v) {
    $str.=$k.'='.$v.'&';
}
//拼接API密钥
$str.='key='.$secrect;
$data['sign']=md5($str);//加密
复制代码

将数组转换成xml格式(简单方法):

复制代码
//遍历数组方法
function arraytoxml($data){
    $str='<xml>';
    foreach($data as $k=>$v) {
        $str.='<'.$k.'>'.$v.'</'.$k.'>';
    }
    $str.='</xml>';
    return $str;
}
复制代码

将xml格式转换为数组:

复制代码
function xmltoarray($xml) { 
     //禁止引用外部xml实体 
    libxml_disable_entity_loader(true); 
    $xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA); 
    $val = json_decode(json_encode($xmlstring),true); 
    return $val;
}

 


PHP微信商户支付企业付款到零钱功能

这几天在给客户做一个微信现金红包功能,需要用到微信支付的企业付款到零钱功能。

微信支付企业付款到零钱功能应用广泛,比如微信红包奖励,业务结算等。通过企业向个人付款,付款资金将直接进入用户微信零钱。

一 开通条件

 

付款资金
企业付款到零钱资金使用商户号余额资金。

根据商户号的账户开通情况,实际出款账户有做区别:

◆ 默认情况下,企业付款到零钱使用商户号基本户(或余额账户)余额。如商户号已开通运营账户,则企业付款到零钱使用运营账户内的资金。
◆ 基本户(或上述其他出款账户)的资金来源,可能是交易结算款项(仅基本户),或给账户充值的资金。当出款账户余额不足时,付款将因余额不足而付款失败。
付款规则
付款方式
◆ 支持API接口或网页操作,付款至目标用户。

收款用户身份指定
◆ 通过APPID+OPENID指定收款用户。

◆ APPID需要为申请商户号时的APPID,或者与商户号有绑定关系。

◆ OPENID的获取方式,可参照:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140839

付款额度
◆ 不支持给非实名用户打款

◆ 给同一个实名用户付款,单笔单日限额2W/2W

◆ 一个商户同一日付款总额限额100W

注意:以上规则中的限额2w、100w由于计算规则与风控策略的关系,不是完全精确值,金额仅做参考,请不要依赖此金额做系统处理,应以接口实际返回和查询结果为准,请知晓。

收款用户身份校验
◆ 针对付款的目标用户,提供可校验真实姓名的功能

查询付款情况
◆ 已付款的记录,企业可通过企业付款查询查看相应数据,或者查询商户号资金流水。

付款频次
◆ 默认每天最多可向同一个用户付款10次,可以在商户平台--API安全进行设置

其他注意事项
◆ 付款金额必须小于或等于商户当前可用余额的金额;

二  接口地址
接口链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers

请求参数:

具体参看官方企业付款开发文档说明

 

PHP代码示例调用

<?php
//企业付款到微信零钱,PHP接口调用方法
define("APPID", "wxde3234454354"); // 商户账号appid
define("MCHID", "1900000109"); // 商户号
define("SECRECT_KEY", "145535866885"); //支付密钥签名
define("IP", "120.178.12.52"); //IP

function createNoncestr($length =32)
{

$chars = "abcdefghijklmnopqrstuvwxyz0123456789";

$str ="";

for ( $i = 0; $i < $length; $i++ ) {

$str.= substr($chars, mt_rand(0, strlen($chars)-1), 1);

}
return $str;
}


function unicode() {
$str = uniqid(mt_rand(),1);
$str=sha1($str);
return md5($str);
}
function arraytoxml($data){
$str='<xml>';
foreach($data as $k=>$v) {
$str.='<'.$k.'>'.$v.'</'.$k.'>';
}
$str.='</xml>';
return $str;
}
function xmltoarray($xml) {
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
$val = json_decode(json_encode($xmlstring),true);
return $val;
}

function curl($param="",$url) {

$postUrl = $url;
$curlPost = $param;
$ch = curl_init(); //初始化curl
curl_setopt($ch, CURLOPT_URL,$postUrl); //抓取指定网页
curl_setopt($ch, CURLOPT_HEADER, 0); //设置header
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_POST, 1); //post提交方式
curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost); // 增加 HTTP Header(头)里的字段
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // 终止从服务端进行验证
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch,CURLOPT_SSLCERT,ROOT_PATH .'/wxpay/cacert/apiclient_cert.pem'); //这个是证书的位置绝对路径
curl_setopt($ch,CURLOPT_SSLKEY,ROOT_PATH .'/wxpay/cacert/apiclient_key.pem'); //这个也是证书的位置绝对路径
$data = curl_exec($ch); //运行curl
curl_close($ch);
return $data;
}

/*
$amount 发送的金额(分)目前发送金额不能少于1元
$re_openid, 发送人的 openid
$desc // 企业付款描述信息 (必填)
$check_name 收款用户姓名 (选填)
*/
function sendMoney($amount,$re_openid,$desc='测试',$check_name=''){

$total_amount = (100) * $amount;

$data=array(
'mch_appid'=>APPID,//商户账号appid
'mchid'=> MCHID,//商户号
'nonce_str'=>createNoncestr(),//随机字符串
'partner_trade_no'=> date('YmdHis').rand(1000, 9999),//商户订单号
'openid'=> $re_openid,//用户openid
'check_name'=>'NO_CHECK',//校验用户姓名选项,
're_user_name'=> $check_name,//收款用户姓名
'amount'=>$total_amount,//金额
'desc'=> $desc,//企业付款描述信息
'spbill_create_ip'=> IP,//Ip地址
);
$secrect_key=SECRECT_KEY;///这个就是个API密码。MD5 32位。
$data=array_filter($data);
ksort($data);
$str='';
foreach($data as $k=>$v) {
$str.=$k.'='.$v.'&';
}
$str.='key='.$secrect_key;
$data['sign']=md5($str);
$xml=arraytoxml($data);

$url='https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers'; //调用接口
$res=curl($xml,$url);
$return=xmltoarray($res);


print_r($return);
//返回来的结果
// [return_code] => SUCCESS [return_msg] => Array ( ) [mch_appid] => wxd44b890e61f72c63 [mchid] => 1493475512 [nonce_str] => 616615516 [result_code] => SUCCESS [partner_trade_no] => 20186505080216815
// [payment_no] => 1000018361251805057502564679 [payment_time] => 2018-05-15 15:29:50


$responseObj = simplexml_load_string($res, 'SimpleXMLElement', LIBXML_NOCDATA);
echo $res= $responseObj->return_code; //SUCCESS 如果返回来SUCCESS,则发生成功,处理自己的逻辑

return $res;
}



?>
三 调用方法  :
sendMoney(1,'ewrwexe32423423423423423','xxxx测试');
      注释 :调用的话,稍微在修改下,加上自己的业务逻辑就行了。
调用效果:


注释 :调用的话,稍微在修改下,加上自己的业务逻辑就行了。
---------------------
作者:Json2008
来源:CSDN
原文:https://blog.csdn.net/fengqingtao2008/article/details/80244182
版权声明:本文为博主原创文章,转载请附上博文链接!


浅析微信支付:(余额提现)企业付款到微信用户零钱或银行卡账户

浅析微信支付系列已经更新十二篇了哟~,没有看过的朋友们可以看一下哦。

浅析微信支付:支付验收示例和验收指引

浅析微信支付:如何使用沙箱环境测试

浅析微信支付:下载对账单和资金账单

浅析微信支付:申请退款、退款回调接口、查询退款

如果你是做电商或者某些有福利返利的系统,基本上会遇到诸如 余额提现 这类需求,主要就是平台向用户返利现金,积累到某一个门槛,可以领取到自己的余额账号、银行卡;或者是使用为用户发送现金红包的方式。

接下来的两篇文章,会为大家描述在微信支付中,像用户付款的以上三种方式。

以下为三种付款方式的必要条件:

  1. 商户号(或同主体其他非服务商商户号)已入驻90日
  2. 商户号(或同主体其他非服务商商户号)有30天连续正常交易
  3. 登录微信支付商户平台-产品中心,开通企业付款。

企业付款到微信用户零钱

企业付款提供由商户直接付钱至用户微信零钱的能力,支持平台操作及接口调用两种方式,资金到账速度快,使用及查询方便。主要用来解决合理的商户对用户付款需求,比如:保险理赔、彩票兑换等等。

如何开通?

  1. 入驻成为商户:在线提交营业执照、身份证、银行账户等基本信息,快速提交申请;
  2. 超级管理员开通:前往商户平台-产品中心-企业付款到零钱-申请开通;
  3. 特殊要求:交易资金是即时入账到商户号基本户的商户,需要满足以下要求:需入驻满90天,连续交易30天。

所需资料:开通企业付款到零钱功能无需提供额外的材料。
费用:试用期间免费使用。

应用场景

企业付款为企业提供付款至用户零钱的能力,支持通过API接口付款,或通过微信支付商户平台(pay.weixin.qq.com)网页操作付款。

以下为官方的解释:

https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_1

抓重点,首先需要知道的是,开通了运营账户的商户,付款时会从运营账户余额中扣除,这个一定要注意,以免金额不足时付款失败(可以使用主账户为运营账户充值,参考[交易中心]-[充值/转入])。

以下为特别需要注意的地方,为大家标记出来,设计系统时一定要参考一下,以免入坑。

企业付款到余额-1

接口链接

https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers

是否需要证书

请求需要双向证书。

调用接口

注意事项:
◆ 当返回错误码为“SYSTEMERROR”时,请不要更换商户订单号,一定要使用原商户订单号重试,否则可能造成重复支付等资金风险。
◆ XML具有可扩展性,因此返回参数可能会有新增,而且顺序可能不完全遵循此文档规范,如果在解析回包的时候发生错误,请商户务必不要换单重试,请商户联系客服确认付款情况。如果有新回包字段,会更新到此API文档中。
◆ 因为错误代码字段err_code的值后续可能会增加,所以商户如果遇到回包返回新的错误码,请商户务必不要换单重试,请商户联系客服确认付款情况。如果有新的错误码,会更新到此API文档中。
◆ 错误代码描述字段err_code_des只供人工定位问题时做参考,系统实现时请不要依赖这个字段来做自动化处理。

PS:目前支持向指定微信用户的openid付款。

官方文档如下:

https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2

具体的传入参数,这里就不一一列举了,请大家参考一下官方文档,下面贴上具体的实现源码:

/**
 * [微信支付提现接口] - 保存调用的相关记录
 * @param payment 支付对象
 * @param wxPayConfig 微信支付单例对象
 * @return map
 *
 * @author yclimb
 * @date 2018/7/30
 */
public Map<String, String> saveWxPayTransfers(Payment payment, WXPayConfig wxPayConfig) throws Exception {
    // 支付前验证

    // 微信支付对象
    // WXPay wxPay = new WXPay(WXPayConfigImpl.getInstance());
    WXPay wxPay = new WXPay(wxPayConfig);

    // 微信退款接口
    Map<String, String> resultMap = wxPay.transfers(...);
    logger.info("saveWxPayTransfers:resultMap:" + resultMap.toString());

    // 下单失败,进行处理
    if (WXPayConstants.FAIL.equals(resultMap.get(WXPayConstants.RETURN_CODE)) || WXPayConstants.FAIL.equals(resultMap.get(WXPayConstants.RESULT_CODE))) {

        // 处理结果返回,无需继续执行

        // 余额不足提醒
        if (WXPayCodeEnum.ERR_CODE_NOTENOUGH.getCode().equals(resultMap.get(WXPayConstants.ERR_CODE))) {
            // 发送余额不足的消息提醒
            
        }
    }

    // 付款记录修改 & 记录付款日志
    
    return resultMap;
}

以上为调用的应用方法,下面为大家贴出微信接口调用代码 imall.weixin.sdk.WXPay

/**
 * 作用:企业向微信用户个人付款<br>
 * 场景:企业付款为企业提供付款至用户零钱的能力,支持通过API接口付款,或通过微信支付商户平台(pay.weixin.qq.com)网页操作付款。
 * 接口文档地址:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
 *
 * @param partner_trade_no 商户订单号
 * @param openid           用户openid
 * @param amount           企业付款金额
 * @param desc             企业付款描述信息
 * @param spbill_create_ip 该IP可传用户端或者服务端的IP
 * @return API返回数据
 * @throws Exception e
 */
public Map<String, String> transfers(String partner_trade_no, String openid, String amount, String desc, String spbill_create_ip) throws Exception {

    /** 构造请求参数数据 **/
    Map<String, String> data = new HashMap<>();

    // 商户订单号    partner_trade_no    是   10000098201411111234567890  String  商户订单号,需保持唯一性(只能是字母或者数字,不能包含有符号)
    data.put("partner_trade_no", partner_trade_no);
    // 用户openid openid  是   oxTWIuGaIt6gTKsQRLau2M0yL16E    String  商户appid下,某用户的openid
    data.put("openid", openid);
    // 校验用户姓名选项 check_name  是   FORCE_CHECK String  NO_CHECK:不校验真实姓名,FORCE_CHECK:强校验真实姓名
    data.put("check_name", "NO_CHECK");
    // 金额   amount  是   10099   int 企业付款金额,单位为分
    data.put("amount", String.valueOf(new BigDecimal(amount).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).intValue()));
    // 企业付款描述信息 desc    是   理赔  String  企业付款操作说明信息。必填。
    data.put("desc", desc);
    // Ip地址 spbill_create_ip    是   192.168.0.1 String(32)  该IP同在商户平台设置的IP白名单中的IP没有关联,该IP可传用户端或者服务端的IP。
    data.put("spbill_create_ip", spbill_create_ip);

    /** 以下参数为非必填参数 **/

    /*// 设备号    device_info 否   013467007045764 String(32)  微信支付分配的终端设备号
    data.put("device_info", "xxx");
    // 收款用户姓名   re_user_name    可选  王小王 String  收款用户真实姓名。(如果check_name设置为FORCE_CHECK,则必填用户真实姓名)
    data.put("re_user_name", "xxx");*/

    // 微信调用接口
    Map<String, String> resultMap = this.transfers(data);

    WXPayUtil.getLogger().info("wxPay.transfers:" + resultMap);

    return resultMap;
}

PS:推荐数据库中对于金额存储为数值单位,以分为单位来存储,1.1元可以储存为101,这样和微信对应,会方便很多。

对于企业付款查询的接口,这里就不详细描述了,以下为具体的官方文档链接:

https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_3

需要的朋友,根据文档进行接口查询即可,非高频接口。

企业付款到银行卡

企业付款到银行卡提供由商户直接付钱至指定银行卡账户的能力,支持平台操作及接口调用两种方式,资金到账速度快,使用及查询方便。主要用来解决合理的商户对用户付款需求,比如:保险理赔、彩票兑换等等。

开通流程:

  1. 入驻成为商户:在线提交营业执照、身份证、银行账户等基本信息,快速提交申请;
  2. 超级管理员开通:前往商户平台-产品中心-企业付款到银行卡-申请开通;
  3. 特殊要求:交易资金是即时入账到商户号基本户的商户,需要满足以下要求:需入驻满90天,连续交易30天。

所需资料:开通企业付款到银行卡功能无需提供额外的材料。
费用:此功能需收取手续费,按照单笔金额收取,每笔收取0.1%,最低1元,最高25元。

应用场景

微信支付已上线企业付款至银行卡功能。商户可以将商户号余额付款至指定的收款银行账户。通过指定收款银行账户户名、卡号,以及收款银行信息即可实现付款。

官方文档地址:

https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_1&index=1

功能说明:

  1. 企业付款至银行卡只支持新资金流类型账户
  2. 目前企业付款到银行卡支持17家银行,更多银行逐步开放中
  3. 付款到账实效为1-3日,最快次日到账
  4. 每笔按付款金额收取手续费,按金额0.1%收取,最低1元,最高25元,如果商户开通了运营账户,手续费和付款的金额都从运营账户出。如果没有开通,则都从基本户出。
  5. 每个商户号每天可以出款100万,单商户给同一银行卡付款每天限额5万
  6. 发票:在账户中心-发票信息页面申请开票的商户会按月收到发票(已申请的无需重复申请)。
    企业付款到银行卡发票与交易手续费发票为拆分单独开具。

需要注意的是,微信支持的银行有限,具体的支持银行见如下链接:

https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_4&index=5

所以肯定会出现不支持的银行,小伙伴们在开发的时候,可以在前后端控制用户选择提现银行来解决。

平台上手动付款流程:

  1. 在产品中心,开通企业付款到个人银行卡功能
  2. 进入交易中心-企业付款到银行卡页面进行付款
  3. 指定收款银行账号、户名、收款方开户行,及付款金额信息,即可实现付款

接口链接

https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank

是否需要证书

请求需要双向证书。

调用接口

接口介绍:
用于企业向微信用户银行卡付款
目前支持接口API的方式向指定微信用户的银行卡付款。

接口调用规则:
◆ 单商户日限额——单日100w
◆ 单次限额——单次5w
◆ 单商户给同一银行卡单日限额——单日5w

注意:重点来了,首先,收款方银行卡号enc_bank_no、收款方用户名enc_true_name 这两个入参是需要 采用标准RSA算法,公钥由微信侧提供 得到的,所以还需要先拿到这个密钥,下面是官方文档地址:

https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_7&index=4

以上文档详细介绍了如何得到具体的密钥方式,如果有看不明白的小伙伴,可以直接百度 获取RSA加密公钥API,可以得到很多示例,这里我就不讲了。

除入参和企业付款到微信用户零钱有所不一致之外,其他方面都差不多,小伙伴们可以参考上面付款到零钱的接口来实现付款到银行卡接口。

结语

以上为微信余额提现相关的解释和源码,小伙伴们一定要注意看看官方文档哦,具体的源码可以看作者的github,里面对每个方法有详细的注释。

如果小伙伴有遇到解决不了的问题,可以关注作者微信公众号,加入讨论群中发出疑问,和小伙伴们一起解决哦~

预告:下一篇文章会讲发放奖励的另一种方式 商户平台-现金红包,敬请期待!!!

​如果想要提前一览源码的小伙伴,可以先看看我的 github,地址如下:

​https://github.com/YClimb/wxpay-sdk/blob/master/README.md ​

 

posted @ 2019-04-15 10:17  谦信君  阅读(2319)  评论(0编辑  收藏  举报