場景:小程式開發一個拆紅包的功能,背景thinkphp3.2,小程式和微信商戶平台不是同一個賬号,但是已經關聯
官方接口文檔:微信支付-企業付款到零錢
使用條件
1、商戶号(或同主體其他商戶号)已入駐90日
2、商戶号(或同主體其他商戶号)有30天連續正常交易
3、登入微信支付商戶平台-産品中心,開通企業付款。
4、紅包金額目前最新規定為 0.30元 到 200元(傳參的時候微信以分為機關,是以amount最小值30,最大值20000)
企業付款到零錢 接口連結:https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers
目前項目的小程式
各種坑不一一列舉,隻寫注意事項及容易出錯的地方:
注意事項:
1. 參數名嚴格按照官方文檔輸入(文後有代碼範例作為參考)
2. 小程式登入網址 https://mp.weixin.qq.com
3. CA憑證要用商戶号裡下載下傳的證書。商戶号登入網址:https://pay.weixin.qq.com(商戶登入賬号類似:[email protected],密碼在騰訊發的郵件裡有六位數字的)
4. mchid:商戶平台下的mchid
5. mch_appid: 小程式的appid
6. openid: 小程式的使用者openid
7. key: 微信商戶平台的密鑰key(sign簽名使用的密鑰)
另外:如果你用微信線上簽名生成的簽名跟你自己生成的簽名是一樣的,但是傳回還是報簽名錯誤,很有可能是以上4-7的參數用錯了,仔細檢查吧(小程式支付也一樣)
小程式拆紅包代碼:
//紅包js代碼
onHongbao: function () {
var that = this;
if (that.hongbaoOpened){
wx.showModal({
title: '紅包已拆過',
content: '紅包已拆過',
showCancel: false,
})
}else{
//拆紅包按鈕顯示控制
that.setData({
hongbaoOpened: true
})
//openid傳給背景,擷取紅包
app.post('https://zhipur.com/api/pay/wxpay_hongbao',{
openid: openid,
}).then( (res)=>{
console.log(res);//微信接口傳回資訊
if(res.wxmsg.return_code=="SUCCESS"&&res.wxmsg.result_code=="SUCCESS"){
//使用者界面顯示紅包資訊
wx.showModal({
title: res.from + '發放的紅包',
content: res.amount + '元已轉入微信錢包',
showCancel: false,
})
}else{
//使用者界面顯示紅包資訊
wx.showModal({
title: '紅包出錯了',
content: '紅包出錯了',
showCancel: false,
})
}
}).catch( (err)=>{
console.log(err);//微信接口傳回資訊
});
}
},
背景PHP代碼:
/**
* 微信小程式紅包 企業付款
* @param {String} $cid 訂單編号
* @param {String} $name 訂單名
* @param {Datetime} $subdate 送出日期
*/
public function wxpay_hongbao(){
$post = I('post.');
// 是否已開啟過紅包
// $this->hongbaoOpened($post['openid'], $post['itemId']);
//讀取配置
$cfg = C('WXPAY_CONFIG');
$nonce_str = abs_rand();//生成16位随機字元串
$api = $cfg['hongbao_api'];//微信企業付款到零錢接口
//擷取IP 或者直接擷取$_SERVER['REMOTE_ADDR']
$spbill_create_ip = $_SERVER['REMOTE_ADDR'] == '::1' ? '192.127.1.1' : $_SERVER['REMOTE_ADDR'];
//微信随機金額紅包 範圍:30 - 2000分,預設:30 - 50分
$min=;
$max=;
$amount = $this->make_wxhb_rand_money($min,$max);
/** 微信接口 */
$mchid = $cfg['mch_id'];//微信商戶平台 商戶号
$appid = $cfg['mini_appid'];//小程式 appid
$trade_key = $cfg['trade_key'];//微信商戶平台 密鑰
$openid = $post['openid'] ? $post['openid'] : 'oVyb00JwH1J8tKdlUuZ4FZOsteVw';//預設openid回收錯誤openid的紅包資金
$desc = '紅包';
$partner_trade_no = date('Ymd').mt_rand(,) ;//生成訂單号 比如'2018032812345'
$signArr = array(
'amount'=>$amount,
'check_name'=>'NO_CHECK',
'desc'=>$desc,
'mch_appid'=>$appid,
'mchid'=>$mchid,
'nonce_str'=>$nonce_str,
'openid'=>$openid,
'partner_trade_no'=>$partner_trade_no,
'spbill_create_ip'=>$spbill_create_ip,
);
//企業付款到零錢 簽名
$sign = $this->make_wxhb_sign($signArr,$trade_key);
$postXml = $this->array2xml($signArr, $sign);
//curl 微信支付接口擷取 prepay_id
$xmlRes = curl_post_xml_with_wxCA($api, $postXml);//微信傳回資料
$postObj = xml2obj($xmlRes);//轉對象
//如果成功,寫入資料庫hongbao表
if($postObj->result_code=='SUCCESS'&&$postObj->return_code=='SUCCESS'){
$this->doHongbao($amount, $openid, $post['cityName']);
$this->ajaxReturn( array('wxmsg'=>$postObj, 'amount'=>($amount/), 'from'=>'貨驗金睛') );
}else{
$this->ajaxReturn( array('wxmsg'=>$postObj) );
}
}
/**
* 紅包成功後的業務邏輯
* @param {Array} $arr 源數組
* @param {String} $sign 簽名字元串
* @return {String} $xml xml字元串
*/
protected function doHongbao($amount, $openid, $city='北京市朝陽區', $time){
//未完成
}
/**
* 改紅包是否已經被拆過
* @param {String} $openid 小程式對應openid
* @param {String} $itemid 物品id/紅包id
* @return {String} $xml xml字元串
*/
protected function hongbaoOpened($openid, $itemid){
//未完成
}
/**
* 數組生成微信api适配的xml字元串
* @param {Array} $arr 源數組
* @param {String} $sign 簽名字元串
* @return {String} $xml xml字元串
*/
protected function array2xml($arr,$sign){
if(! is_array($arr) ) return false;
$xml = '<xml>';
foreach ($arr as $k => $v) {
$xml .= '<'.$k.'>'.$v.'</'.$k.'>';
}
$xml .= '<sign>'.$sign.'</sign></xml>';
return $xml;
}
/**
* 生成随機紅包金額 - 小程式企業付款到零錢
* @param {Float} $min 下限
* @param {Float} $max 上限
* @param {Float} $rnd 随機金額
*/
protected function make_wxhb_rand_money($min=,$max=){
return mt_rand($min,$max);
}
/**
* 生成簽名 - 小程式企業付款到零錢
* @param {Array} $arr 要傳遞的參數數組
* @param {Boolean} $is_call_back 是否二次簽名
* @return {String} $sign 簽名字元串
*/
protected function make_wxhb_sign($arr,$trade_key,$is_call_back=false) {
ksort($arr); //将參數數組按照參數名ASCII碼從小到大排序
reset($arr);
foreach ($arr as $key => $value) {
if($key!='sign' && $key!='sign_type'){
$newArr[] = $key.'='.$value; // 整合新的參數數組
}
}
$stringA = implode("&", $newArr); //使用 & 符号連接配接參數
$stringSignTemp = $stringA."&key=".$trade_key; //拼接key
$sign = strtoupper( MD5($stringSignTemp) );//将字元串進行MD5加密 并轉換為大寫
return $sign;
}