Wechat payment enterprise payment to change function is widely used, such as wechat red packet reward, business settlement, etc. Through enterprise payment to individuals, payment funds will directly enter users' wechat change.
I. opening conditions
Payment fund
The enterprise pays the change fund with the balance fund of the merchant number.
According to the account opening situation of the merchant number, there are differences in the actual disbursement account:
◆ by default, the basic account (or balance account) balance of the merchant number is used when the enterprise pays the change. If the merchant number has opened an operation account, the enterprise will pay the change to use the funds in the operation account.
◆ the capital source of the basic account (or other above-mentioned disbursement account) may be the transaction settlement fund (only the basic account) or the capital charged to the account. When the balance of the disbursement account is insufficient, the payment will fail due to insufficient balance.
Payment rules
Payment method
Support API interface or web page operation, and pay to target users.
Identity assignment of payee
◆ specify the payee through APPID+OPENID.
◆ APPID needs to be the APPID when applying for the merchant number or has a binding relationship with the merchant number.
◆ for the access method of OPENID, please refer to: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140839
Payment limit
◆ payment for non real name users is not supported
◆ payment to the same real name user, single daily limit 2W/2W
◆ the total payment limit of one merchant on the same day is 100W
Note: the limit 2w and 100w in the above rules are not fully accurate due to the relationship between the calculation rules and risk control strategy, and the amount is only for reference. Please do not rely on this amount for system processing. The actual return and query results of the interface shall prevail, please be aware.
Identity verification of payee
◆ provide the function of verifying the real name for the target user of payment
Query payment status
◆ for the paid records, the enterprise can check the corresponding data through the enterprise payment query, or query the capital flow of the merchant number.
Frequency of payment
◆ by default, the payment to the same user can be made up to 10 times a day, which can be set in the merchant platform API security
Other precautions
◆ the payment amount must be less than or equal to the current available balance of the merchant;
II. Interface address
Interface link: https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers
Request parameters:
Please refer to the official enterprise payment development document for details
1. Basic configuration
1 //Public account number appid 2 $data["mch_appid"] = 'appid'; 3 //Merchant number 4 $data["mchid"] = ''; 5 //Random string 6 $data["nonce_str"] = 'suiji'.mt_rand(100,999); 7 //Merchant order number 8 $data["partner_trade_no"]=date('YmdHis').mt_rand(1000,9999); 9 //Amount the withdrawal amount entered by the user needs to be multiplied by 100 10 $data["amount"] = $money; 11 //Enterprise payment description 12 $data["desc"] = 'Enterprise pay to individual change'; 13 //user openid 14 $data["openid"] = $openid; 15 //Do not verify user name 16 $data["check_name"] = 'NO_CHECK'; 17 //Obtain IP 18 $data['spbill_create_ip']=$_SERVER['SERVER_ADDR']; 19 //Merchant key 20 $data['key']=''; 21 //Merchant certificate API Security certificate Download 22 $data['apiclient_cert.pem'] 23 $data['apiclient_key.pem']
2.PHP code
1 /** 2 **Start payment 3 / 4 public function userpay(){ 5 $money = 'User input withdrawal amount'; 6 $info['money'] = 'User balance'; 7 if ($this->openid && $money){ 8 if ($money>$info['money'] ){ 9 echo json_encode([ 10 'status' => 1, 11 'message' => 'The balance is not enough. Cash withdrawal is not allowed!', 12 'code'=>'The balance is not enough. Cash withdrawal is not allowed!' 13 ]); 14 }elseif ($money<1){ 15 echo json_encode([ 16 'status' => 2, 17 'message' => 'Withdrawal amount cannot be less than 1 yuan', 18 'code'=>'Withdrawal amount is too low' 19 ]); 20 }else{ 21 $openid = $this->openid; 22 $trade_no = date('YmdHis').mt_rand(1000,9999); 23 $res = $this->pay($openid,$trade_no,$money*100,'WeChat cash'); 24 25 //Result printing 26 if($res['result_code']=="SUCCESS"){ 27 28 echo json_encode([ 29 'status' => 3, 30 'message' => 'Withdrawal succeeded!', 31 ]); 32 }elseif ($res['err_code']=="SENDNUM_LIMIT"){ 33 echo json_encode([ 34 'status' => 4, 35 'message' => 'Withdrawal failed!', 36 'code'=>'Only one withdrawal per day', 37 ]); 38 }else{ 39 echo json_encode([ 40 'status' => 5, 41 'message' => 'Withdrawal failed!', 42 'code'=>$res['err_code'], 43 ]); 44 } 45 } 46 }else{ 47 echo json_encode([ 48 'status' => 5, 49 'message' => 'Your current wechat account is not detected~', 50 51 ]); 52 } 53 }
Payment method
1 /** 2 *Payment method 3 / 4 public function pay($openid,$trade_no,$money,$desc){ 5 $params["mch_appid"]=''; 6 $params["mchid"] = ''; 7 $params["nonce_str"]= 'suiji'.mt_rand(100,999); 8 $params["partner_trade_no"] = $trade_no; 9 $params["amount"]= $money; 10 $params["desc"]= $desc; 11 $params["openid"]= $openid; 12 $params["check_name"]= 'NO_CHECK'; 13 $params['spbill_create_ip'] = $_SERVER['SERVER_ADDR']; 14 15 //Generate signature 16 $str = 'amount='.$params["amount"].'&check_name='.$params["check_name"].'&desc='.$params["desc"].'&mch_appid='.$params["mch_appid"].'&mchid='.$params["mchid"].'&nonce_str='.$params["nonce_str"].'&openid='.$params["openid"].'&partner_trade_no='.$params["partner_trade_no"].'&spbill_create_ip='.$params['spbill_create_ip'].'&key=Merchant key'; 17 18 //md5 encryption to uppercase 19 $sign = strtoupper(md5($str)); 20 //Generate signature 21 $params['sign'] = $sign; 22 23 //Construct XML data 24 $xmldata = $this->array_to_xml($params); //Array to XML 25 $url='https://api.mch.weixin.qq.com/mmpaymkttransfers/prom otion/transfers'; 26 27 //Send post request 28 $res = $this->curl_post_ssl($url, $xmldata); //curl request 29 if(!$res){ 30 return array('status'=>1, 31 'msg'=>"Server connection failed" ); 32 } 33 34 //Payment result analysis 35 $content = $this->xml_to_array($res); //xml to array 36 return $content; 37 }
curl request
1 /** 2 * curl request 3 / 4 public function curl_post_ssl($url, $xmldata, $second=30,$aHeader=array()){ 5 $ch = curl_init(); 6 //Timeout time 7 curl_setopt($ch,CURLOPT_TIMEOUT,$second); 8 curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1); 9 //Set up a proxy here, if any 10 //curl_setopt($ch,CURLOPT_PROXY, '10.206.30.98'); 11 //curl_setopt($ch,CURLOPT_PROXYPORT, 8080); 12 curl_setopt($ch,CURLOPT_URL,$url); 13 curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false); 14 curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false); 15 16 //The default format is PEM, which can be annotated 17 curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM'); 18 //The absolute address can be printed with dirname ( dir ). If it is not the absolute address, 58 errors will be reported 19 curl_setopt($ch,CURLOPT_SSLCERT,' Absolute address/apiclient_cert.pem'); 20 curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM'); 21 curl_setopt($ch,CURLOPT_SSLKEY,'Absolute address/apiclient_key.pem'); 22 if( count($aHeader) >= 1 ){ 23 curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader); 24 } 25 curl_setopt($ch,CURLOPT_POST, 1); 26 curl_setopt($ch,CURLOPT_POSTFIELDS,$xmldata); 27 $data = curl_exec($ch); 28 if($data){ 29 curl_close($ch); 30 return $data; 31 } 32 else { 33 $error = curl_errno($ch); 34 echo "call faild, errorCode:$error\n"; 35 die(); 36 curl_close($ch); 37 return false; 38 } 39 }
Generate signature
1 /** 2 * array Turn xml 3 * Used to generate signatures 4 */ 5 public function array_to_xml($arr){ 6 $xml = "<xml>"; 7 foreach ($arr as $key => $val) { 8 if (is_numeric($val)) { 9 $xml .= "<" .$key.">".$val."</".$key.">"; 10 } else 11 $xml .= "<".$key."><![CDATA[".$val."]]></".$key.">"; 12 } 13 $xml .= "</xml>"; 14 return $xml; 15 } 16 17 /** 18 * xml Convert to array 19 */ 20 public function xml_to_array($xml){ 21 //Prohibit external references xml entity 22 libxml_disable_entity_loader(true); 23 $values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); 24 return $values; 25 }
The effect is as follows: