關於微信支付,退款操作,原路返回
阿新 • • 發佈:2018-11-02
有這樣的場景,使用者購買商品。但是退款的時候要去除運費。
或者,使用者購買多個商家的商品,統一支付。但是使用者只退其中一個商家的商品。
又或者,使用者一個訂單購買多個商品。只退其中一個商品。
微信退款介面可以滿足這些需求,前提是總的退款金額不能超過總的支付金額。
支付的時候,不需要證書。
但是退款的時候,需要提供證書。
下面看看實際的情況。
從上圖可以看出,我支付2分錢,可以一次性退。
也可以,一次退1分,分兩次退還。
而且,用銀行卡就退到銀行卡,用信用卡就退到信用卡。
這些支付,退款相關的資訊,可以在管理後臺中統一管理。或者寫到配置檔案中。
退款需要證書,需要到微信商戶平臺進行下載。(開放平臺【app】,公眾平臺【微信,pc,小程式】)分別有一個商戶號。
退款的時候,需要提供支付的訂單號或者微信提供的transaction_id。每一個退款都有自己的退款號(確保不要相同)。
一筆退款失敗後重新提交,請不要更換退款單號,請使用原商戶退款單號。
private function refundWx($data) { Clog::setLog($data); vendor('Wxpay.WxPay'); $input = new WxPayRefund(); $input->SetOut_trade_no($data['out_trade_no']); $input->SetAppid($data['app_id']); $input->SetMch_id($data['mch_id']); $input->SetOut_refund_no($data['out_trade_no'] . 'R'); $input->SetTotal_fee($data['price']); $input->SetRefund_fee($data['price']); $input->SetOp_user_id($data['mch_id']); $input->key = $data['key']; $path = C('WX_KEY_PATH'); switch ($data['type']) { case 1: $path = $path . 'open/'; break; case 2: $path = $path . 'public/'; break; } $response = WxPayApi::refund($input, $path); if ($response['return_code'] == 'SUCCESS' && $response['result_code'] == 'SUCCESS') { return true; } else { return false; } }
/** * * 申請退款,WxPayRefund中out_trade_no、transaction_id至少填一個且 * out_refund_no、total_fee、refund_fee、op_user_id為必填引數 * appid、mchid、spbill_create_ip、nonce_str不需要填入 * @param WxPayRefund $inputObj * @param int $timeOut * @throws WxPayException * @return 成功時返回,其他拋異常 */ public static function refund($inputObj, $path, $timeOut = 6) { $url = "https://api.mch.weixin.qq.com/secapi/pay/refund"; //檢測必填引數 if(!$inputObj->IsOut_trade_noSet() && !$inputObj->IsTransaction_idSet()) { throw new WxPayException("退款申請介面中,out_trade_no、transaction_id至少填一個!"); }else if(!$inputObj->IsOut_refund_noSet()){ throw new WxPayException("退款申請介面中,缺少必填引數out_refund_no!"); }else if(!$inputObj->IsTotal_feeSet()){ throw new WxPayException("退款申請介面中,缺少必填引數total_fee!"); }else if(!$inputObj->IsRefund_feeSet()){ throw new WxPayException("退款申請介面中,缺少必填引數refund_fee!"); }else if(!$inputObj->IsOp_user_idSet()){ throw new WxPayException("退款申請介面中,缺少必填引數op_user_id!"); } $inputObj->SetNonce_str(self::getNonceStr());//隨機字串 $inputObj->SetSign();//簽名 $xml = $inputObj->ToXml(); $startTimeStamp = self::getMillisecond();//請求開始時間 $response = self::postXmlCurl($xml, $url, true, $timeOut, $path); $result = WxPayResults::Init($response); self::reportCostTime($url, $startTimeStamp, $result);//上報請求花費時間 return $result; }
/**
* 以post方式提交xml到對應的介面url
*
* @param string $xml 需要post的xml資料
* @param string $url url
* @param bool $useCert 是否需要證書,預設不需要
* @param int $second url執行超時時間,預設30s
* @throws WxPayException
*/
private static function postXmlCurl($xml, $url, $useCert = false, $second = 30, $certPath = '')
{
$ch = curl_init();
//設定超時
curl_setopt($ch, CURLOPT_TIMEOUT, $second);
//如果有配置代理這裡就設定代理
if(WxPayConfig::CURL_PROXY_HOST != "0.0.0.0"
&& WxPayConfig::CURL_PROXY_PORT != 0){
curl_setopt($ch,CURLOPT_PROXY, WxPayConfig::CURL_PROXY_HOST);
curl_setopt($ch,CURLOPT_PROXYPORT, WxPayConfig::CURL_PROXY_PORT);
}
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//嚴格校驗
//設定header
curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求結果為字串且輸出到螢幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
if($useCert == true){
//設定證書
//使用證書:cert 與 key 分別屬於兩個.pem檔案
curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLCERT, $certPath . 'apiclient_cert.pem');
curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLKEY, $certPath . 'apiclient_key.pem');
}
//post提交方式
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
//執行curl
$data = curl_exec($ch);
//返回結果
if($data){
curl_close($ch);
return $data;
} else {
$error = curl_errno($ch);
curl_close($ch);
throw new WxPayException("curl出錯,錯誤碼:$error");
}
}
具體的參考:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4