微信商家转账到零钱 /v3/transfer/batches/out-batch-no/{out_batch_no}/details/out-detail-no/{out_detail_no}

官方文档
https://pay.weixin.qq.com/docs/merchant/apis/batch-transfer-to-balance/transfer-detail/get-transfer-detail-by-out-no.html

参考文章
https://blog.csdn.net/weixin_48337755/article/details/127449073
https://blog.csdn.net/u010481239/article/details/128028494

发起转账

// 转账到零钱
// $withdrawApply = [
//                'left_money'=>1,
//                'batch_no'=>'plfk2020042013',  //商户系统内部的商家批次单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一
//                'desc'=>'测试接口',
//                'openid'=>'dsadsadasd',
//                'sn'=>'plfk2023',
//                'real_name'=> '姓名'
//            ];


/**
 * @notes 商家转账到零钱
 */
public static function transfer($withdrawApply,$openid,$config)
{
    //请求URL
    $url = 'https://api.mch.weixin.qq.com/v3/transfer/batches';  //微信提现接口
    //请求方式
    $http_method = 'POST';
    //请求参数
    $data = [
        'appid' => config("weixin.app_id"),//申请商户号的appid或商户号绑定的appid(企业号corpid即为此appid)
        'out_batch_no' => $withdrawApply['batch_no'],//商户系统内部的商家批次单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一
        'batch_name' => '提现至微信零钱',//该笔批量转账的名称
        'batch_remark' => '提现至微信零钱',//转账说明,UTF8编码,最多允许32个字符
        'total_amount' => $withdrawApply['left_money'] * 100,//转账金额单位为“分”。转账总金额必须与批次内所有明细转账金额之和保持一致,否则无法发起转账操作
        'total_num' => 1,//一个转账批次单最多发起三千笔转账。转账总笔数必须与批次内所有明细之和保持一致,否则无法发起转账操作
        'transfer_detail_list' => [
            [//发起批量转账的明细列表,最多三千笔
                'out_detail_no' => $withdrawApply['sn'],//商户系统内部区分转账批次单下不同转账明细单的唯一标识,要求此参数只能由数字、大小写字母组成
                'transfer_amount' => $withdrawApply['left_money'] * 100,//转账金额单位为分
                'transfer_remark' => '提现至微信零钱',//单条转账备注(微信用户会收到该备注),UTF8编码,最多允许32个字符
                'openid' => $openid,//openid是微信用户在公众号appid下的唯一用户标识(appid不同,则获取到的openid就不同),可用于永久标记一个用户
            ]]
    ];
    if ($withdrawApply['left_money'] >= 2000) {
        if (empty($withdrawApply['real_name'])) {
            throw new \Exception('转账金额 >= 2000元,收款用户真实姓名必填');
        }
        $data['transfer_detail_list'][0]['user_name'] = self::getEncrypt($withdrawApply['real_name'],$config);
    }


    $xml_datas = json_encode($data);
    $token  = self::getToken($url,$xml_datas); //获取header Token认证

    $schema = config("weixin.schema");
    $res = requestPost($url,$xml_datas,[
        'Authorization:' . $schema . ' ' . $token,     // 注意这里
        'Accept: application/json',
        "Content-type: application/json;charset='utf-8'",
        'User-Agent: ' . $_SERVER['HTTP_USER_AGENT']
    ]);


    if(!isset($res['create_time'])) {  //批次受理失败 
        return reply($res,1);
    }else{        // 支付成功
        return reply();
    }


}

    /**
 * 获取签名
 * @param $url
 * @param $body
 * @param string $http_method
 * @return string
 */
public static function getToken($url,$body,$http_method = "POST")
{
    $timestamp = time();
    $nonce = uniqid();
    $merchant_id = config("weixin.mchid");
    $serial_no = config("weixin.serial_no");
    $mch_private_key = config("weixin.mch_private_key");

    $url_parts = parse_url($url);
    $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
    $message = $http_method."\n".
        $canonical_url."\n".
        $timestamp."\n".
        $nonce."\n".
        $body."\n";

    openssl_sign($message, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');
    $sign = base64_encode($raw_sign);

    return sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
        $merchant_id, $nonce, $timestamp, $serial_no, $sign);
}

结果查询

/**
 * @notes 商家明细单号查询
 */
public static function detailsQuery($withdrawApply)
{
//         $withdrawApply['batch_no'] = 'C8yFKtxcY';
//         $withdrawApply['out_detail_no'] = 'plfk20231700099905';

    $url = 'https://api.mch.weixin.qq.com/v3/transfer/batches/out-batch-no/'.$withdrawApply['batch_no'].'/details/out-detail-no/'.$withdrawApply['out_detail_no'];
    // $url = 'https://api.mch.weixin.qq.com/v3/transfer/batches/out-batch-no/'.$withdrawApply['batch_no'].'?need_query_detail=true&detail_status=ALL';
    //请求方式
    $http_method = 'GET';
    //请求参数
    $data = [];
    
    $xml_datas = json_encode($data);

    $token  = self::token1($url,$http_method,'');//获取token

    $result =self::https_request1($url,'',$token);//发送请求

    $result_arr = json_decode($result,true);

    if($result_arr['detail_status']== 'SUCCESS'){
        //付款成功
        return reply($result_arr,1);
    }else{
        return reply($result_arr,0);
    }
}

public static function token1($url,$http_method,$data)
{
    $timestamp   = time();//请求时间戳
    $url_parts   = parse_url($url);//获取请求的绝对URL
    $nonce       = $timestamp.rand('10000','99999');//请求随机串
    $body        = empty($data) ? '' : json_encode((object)$data);//请求报文主体
    $stream_opts = [
        "ssl" => [
            "verify_peer"=>false,
            "verify_peer_name"=>false,
        ]
    ];

    $apiclient_cert_path = public_path("wx_pay_cert") . '/apiclient_cert.pem';   // 地址
    $apiclient_key_path  = public_path("wx_pay_cert") . '/apiclient_key.pem';



    $apiclient_cert_arr = openssl_x509_parse(file_get_contents($apiclient_cert_path,false, stream_context_create($stream_opts)));
//        $serial_no          = $apiclient_cert_arr['serialNumberHex'];//证书序列号

        $serialNo = '';
        if (\strtolower(\substr($apiclient_cert_arr['serialNumber'], 0, 2)) == '0x') { // HEX format
            $serialNo = \substr($apiclient_cert_arr['serialNumber'], 2);
        } else { // DEC format
            $value = $apiclient_cert_arr['serialNumber'];
            $hexvalues = ['0','1','2','3','4','5','6','7',
                '8','9','A','B','C','D','E','F'];
            while ($value != '0') {
                $serialNo = $hexvalues[\bcmod($value, '16')].$serialNo;
                $value = \bcdiv($value, '16', 0);
            }
        }
    $serial_no          = $serialNo;//证书序列号这里要serialNumberHex
    //   //sjc  serialNumber处理为serialNumberHex 2022年11月17日21:58:59

    $mch_private_key    = file_get_contents($apiclient_key_path,false, stream_context_create($stream_opts));//密钥
	// $merchant_id =  '*********';//商户id
	$merchant_id = config("weixin.mchid");
    $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
    $message = $http_method."\n".
        $canonical_url."\n".
        $timestamp."\n".
        $nonce."\n".
        $body."\n";
    openssl_sign($message, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');
    $sign = base64_encode($raw_sign);//签名
    $schema = 'WECHATPAY2-SHA256-RSA2048';
    $token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
        $merchant_id, $nonce, $timestamp, $serial_no, $sign);//微信返回token
    // return $schema.' '.$token;     // 注意这里,request 传参
    return $token;   // 注意这里,request 传参
}


public static function https_request1($url,$data,$token)
{
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, (string)$url);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
    if (!empty($data)){
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
    }
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

    $schema = config("weixin.schema");

    //添加请求头
    $headers = [
        // 'Authorization:'.$token,      // 注意这里,request 传参
        'Authorization:' . $schema . ' ' . $token,        // 注意这里,request 传参
        'Accept: application/json',
        'Content-Type: application/json; charset=utf-8',
        'User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',
    ];
    if(!empty($headers)){
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
    }
    $output = curl_exec($curl);
    curl_close($curl);
    return $output;

}

你可能感兴趣的:(微信,batch,windows)