Laravel 接入微信服务商分账接口
记录一个用户微信支付后立即分账的功能
开发步骤
一.添加分账接收方
// 添加分账接收方
public function add_sub(User $user)
{
header("Content-Type:text/html;charset=utf8");
$open_id = $user->open_id;
$request_para = array();
$request_para['mch_id'] = env('MCH_ID');// 商户号
$request_para['appid'] = env('APP_ID');// 公众账号ID
$request_para['nonce_str'] = $this->createNoncestr();// 随机字符串
$request_para['sign_type'] = "HMAC-SHA256";// 签名类型
$receiver = array(
// MERCHANT_ID:商户ID
// PERSONAL_WECHATID:个人微信号
// PERSONAL_OPENID:个人openid
'type' => 'PERSONAL_OPENID',
'account' => $open_id,
'relation_type' => 'STAFF'
);
$request_para["receiver"] = json_encode($receiver);
// 签名
$request_para["sign"] = $this->appgetSign($request_para, env('MCH_KEY'), false);
//把数组转化成xml格式
$xmlData = $this->arrayToXml($request_para, true);
$url = 'https://api.mch.weixin.qq.com/pay/profitsharingaddreceiver';
//发送请求
$get_data = $this->sendPrePayCurl($xmlData, $url);
\Log::alert('添加分账接收方返回结果:');
\Log::alert($get_data);
}
//随机字符串
public 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;
}
//格式化参数格式化成url参数 生成签名sign
public function appgetSign($Obj, $appwxpay_key, $bool = true)
{
foreach ($Obj as $k => $v) {
$Parameters[$k] = $v;
}
//签名步骤一:按字典序排序参数
ksort($Parameters); // ksort — 对数组按照键名排序
$String = $this->formatBizQueryParaMap($Parameters, false);
//签名步骤二:在string后加入KEY
if ($appwxpay_key) {
$String = $String . "&key=" . $appwxpay_key;
}
if ($bool) {
//签名步骤三:MD5加密
$String = md5($String);
} else {
//HMAC-SHA256签名方式
$String = hash_hmac("sha256", $String, $appwxpay_key);
}
//签名步骤四:所有字符转为大写
$result_ = strtoupper($String);
return $result_;
}
//按字典序排序参数
public function formatBizQueryParaMap($paraMap, $urlencode)
{
$buff = "";
ksort($paraMap);
foreach ($paraMap as $k => $v) {
if ($urlencode) {
$v = urlencode($v); //urlencode — 编码 URL 字符串
}
//$buff .= strtolower($k) . "=" . $v . "&";
$buff .= $k . "=" . $v . "&";
}
$reqPar = '';
if (strlen($buff) > 0) {
$reqPar = substr($buff, 0, strlen($buff) - 1);
}
return $reqPar;
}
//将数组转换为xml格式
public function arrayToXml($arr, $bool)
{
$xml = "<xml>";
foreach ($arr as $key => $val) {
if ($bool) {
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
} else{
$xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
}
}
$xml .= "</xml>";
return $xml;
}
//发送请求
public function sendPrePayCurl($xml, $url = '', $options = array())
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
if (!empty($options)) {
curl_setopt_array($ch, $options);
}
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$data = curl_exec($ch);
curl_close($ch);
$data_xml_arr = $this->XMLDataParse($data);
if ($data_xml_arr) {
return $data_xml_arr;
} else {
return false;
}
}
//xml格式数据解析函数
public function XMLDataParse($data)
{
$xml = simplexml_load_string($data, NULL, LIBXML_NOCDATA);
$array = json_decode(json_encode($xml), true);
return $array;
}
二.在统一下单API新增profit_sharing参数
$result = $app->order->unify([
'body' => '支付人民币' . $money . '元',
'out_trade_no' => $order_no,
'total_fee' => $total_fee,
'notify_url' => env('BACKURL'),
'trade_type' => 'JSAPI',
'openid' => $open_id,
'attach' => $attach,
'profit_sharing' => 'Y',
// Y-是,需要分账 N-否,不分账 字母要求大写,不传默认不分账
]);
三.队列处理请求分账接口
将请求分账接口加入队列,异步处理支付逻辑和分账功能
public function sub_account($transaction_id,$order,$type)
{
header("Content-Type:text/html;charset=utf8");
$newPara = array();
// 公众账号ID
$newPara["appid"] = env('APP_ID');
// 商户号
$newPara["mch_id"] = env('MCH_ID');
// 随机字符串
$newPara["nonce_str"] = $this->createNoncestr();
// 商户分账单号
$out_order_no = mt_rand(100000,999999).time().mt_rand(100,999);
$newPara["out_order_no"] = $out_order_no;
// 微信订单号
$newPara["transaction_id"] = $transaction_id;
//签名类型 HMAC-SHA256
$newPara["sign_type"] = "HMAC-SHA256";
$user = User::where('is_sub',1)->select(['id','open_id','proportion'])->get();
// 分账接收方列表
$receivers = [];
foreach ($user as $k => $val) {
if($order->money >= 1){
// 扣除0.6%微信手续费
$money = floor($order->money * 0.994 * $val->proportion); // 舍去法取整
}else{
$money = floor($order->money * $val->proportion); // 舍去法取整
}
$receivers[$k]['type'] = 'PERSONAL_OPENID';
$receivers[$k]['account'] = $val->open_id;
$receivers[$k]['amount'] = $money;
$receivers[$k]['description'] = '';
}
$newPara["receivers"] = json_encode($receivers);
// 签名
$newPara["sign"] = $this->appgetSign($newPara, env('MCH_KEY'), false);
//把数组转化成xml格式
$xmlData = $this->arrayToXml($newPara, true);
$options = array(
CURLOPT_SSLCERT => '/www/wwwroot/supliao/cert/apiclient_cert.pem',// 客户端证书,用于双向认证
CURLOPT_SSLCERTTYPE => 'PEM',// 证书的类型。支持的格式有"PEM" (默认值), "DER"和"ENG"。
CURLOPT_SSLKEY => '/www/wwwroot/supliao/cert/apiclient_key.pem',// 客户端私钥的文件路径
CURLOPT_SSLKEYTYPE => 'PEM',// 客户端私钥类型,支持的私钥类型为"PEM"(默认值)、"DER"和"ENG"。
CURLOPT_KEYPASSWD => env('MCH_ID'),//客户端私钥密码,私钥在创建时可以选择加密。
//API证书调用或安装需要使用到密码,该密码的值为微信商户号(mch_id)
);
$url = "https://api.mch.weixin.qq.com/secapi/pay/profitsharing";
$get_data = $this->sendPrePayCurl($xmlData, $url, $options);
\Log::alert('分账返回结果:');
\Log::alert($get_data);
//更新订单数据
return true;
}
结语
微信分账文档地址
pay.weixin.qq.com/wiki/doc/api/all...
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: