.net 微信V3版 商家转账到零钱

 自从2022.5.18号开始,微信就关闭了企业付款到零钱,改为了商家转账到零钱,这个是用微信V3版的接口,之前开通的企业付款到零钱  V2接口还是可以使用的。

 微信如果返回的批次创建时间字段不为空,则认为批次受理成功,但不代表支付成功,需要主动查询批次的受理状态;

 其中开通商家转账到零钱时有个免密支付,默认最高免密金额是100元,如果开通后且支付超过100元 需要商户号上手动点确认支付才可以完成转账,如果商家不确认 会被默认关闭,所以就需要服务器主动向微信查询受理的状态

 下发有根据批次单号 查询状态的示例。

 

微信官网文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter4_3_1.shtml

 

        /// <summary>
        /// 商家转账到零钱
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public WithDrawsV3Back WithDrawsToWx(WithDrawsToWxDto dto)
        {
            var config = CommonCode.AppSettings("WeiXinMinAppid", "MchId", "SerialNo", "PrivateKey");

            var totalFee = Convert.ToInt32(dto.Amount * 100);
            var desc = "提现收益";
            var lis = new List<object>();
            lis.Add(new
            {
                out_detail_no = dto.PartnerTradeNo,
                transfer_amount = totalFee,
                transfer_remark = desc,
                openid = dto.OpenId
            });
            var body = new
            {
                appid = config[0],
                out_batch_no = dto.PartnerTradeNo,
                batch_name = desc,
                batch_remark = desc,
                total_amount = totalFee,
                total_num = 1,
                transfer_detail_list = lis

            };
            var url = "https://api.mch.weixin.qq.com/v3/transfer/batches";
            string transactionsResponse = WxV3PostJson(url, Newtonsoft.Json.JsonConvert.SerializeObject(body), config[3], config[1], config[2], "POST");
            //_log.LogInformation("商户转账到零钱返回:" + transactionsResponse);
            var result = Newtonsoft.Json.JsonConvert.DeserializeObject<WithDrawsV3Back>(transactionsResponse);
            return result;
        }

        /// <summary>
        /// 根据微信批次单号 查询转账状态
        /// </summary>
        /// <param name="batch_id"></param>
        /// <returns></returns>
        public WithDrawsStateRet QryWithDrawsState(string batch_id)
        {
            var config = CommonCode.AppSettings("WeiXinMinAppid", "MchId", "SerialNo", "PrivateKey");
            var url = "https://api.mch.weixin.qq.com/v3/transfer/batches/batch-id/" + batch_id + "?need_query_detail=false&offset=1";
            string response = WxV3PostJson(url, string.Empty, config[3], config[1], config[2], "GET");
            _log.LogInformation("根据微信批次单号 查询转账状态返回:" + response);
            var result = Newtonsoft.Json.JsonConvert.DeserializeObject<WithDrawsStateRet>(response);
            return result;
        }

        /// <summary>
        /// V3版本请求接口
        /// </summary>
        /// <param name="url">微信的接口地址</param>
        /// <param name="postData">post请求的数据,json格式 </param>
        /// <param name="privateKey">apiclient_key.pem中的内容,不要-----BEGIN PRIVATE KEY-----  -----END PRIVATE KEY-----</param>
        /// <param name="merchantId">发起请求的商户(包括直连商户、服务商或渠道商)的商户号 mchid</param>
        /// <param name="serialNo">商户证书号</param>
        /// <param name="method"></param>
        /// <returns></returns>
        public string WxV3PostJson(string url, string postData, string privateKey, string merchantId, string serialNo, string method)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = method;
            request.ContentType = "application/json;charset=UTF-8";
            request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3100.0 Safari/537.36";
            request.Accept = "application/json";

            string Authorization = GetAuthorization(url, method, postData, privateKey, merchantId, serialNo);
            string value = $"WECHATPAY2-SHA256-RSA2048 {Authorization}";
            request.Headers.Add("Authorization", value);
            if (!string.IsNullOrEmpty(postData))
            {
                byte[] paramJsonBytes;
                paramJsonBytes = System.Text.Encoding.UTF8.GetBytes(postData);
                request.ContentLength = paramJsonBytes.Length;
                Stream writer;
                try
                {
                    writer = request.GetRequestStream();
                }
                catch (Exception e)
                {
                    writer = null;
                    _log.LogInformation("请求接口失败:" + e.Message);
                }
                writer.Write(paramJsonBytes, 0, paramJsonBytes.Length);
                writer.Close();
            }

            HttpWebResponse response;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (WebException ex)
            {
                response = ex.Response as HttpWebResponse;
            }
            Stream resStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(resStream);
            string text = reader.ReadToEnd();
            return text;
       }

        /// <summary>
        /// 获取authorzation 值
        /// </summary>
        /// <param name="url">微信的接口地址</param>
        /// <param name="method">请求的方式GET,POST,PUT</param>
        /// <param name="jsonParame">post请求的数据,json格式  ,get时传空</param>
        /// <param name="privateKey">apiclient_key.pem中的内容,不要-----BEGIN PRIVATE KEY-----  -----END PRIVATE KEY-----</param>
        /// <param name="merchantId">发起请求的商户(包括直连商户、服务商或渠道商)的商户号 mchid</param>
        /// <param name="serialNo">商户证书号</param>
        /// <returns></returns>
        protected string GetAuthorization(string url, string method, string jsonParame, string privateKey, string merchantId, string serialNo)
        {
            var uri = new Uri(url);
            string urlPath = uri.PathAndQuery;
            string nonce = Guid.NewGuid().ToString();
            var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
            //数据签名     HTTP请求方法n接口地址的urln请求时间戳n请求随机串n请求报文主体n
            method = string.IsNullOrEmpty(method) ? "" : method;
            string message = $"{method}\n{urlPath}\n{timestamp}\n{nonce}\n{jsonParame}\n";
            string signTxt = Sign(message, privateKey);
            //Authorization和格式
            string authorzationTxt = $"mchid=\"{merchantId}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{serialNo}\",signature=\"{signTxt}\""; ;
            return authorzationTxt;
        }

        /// <summary>
        /// 获取签名
        /// </summary>
        protected string Sign(string message, string privateKey)
        {
            byte[] keyData = Convert.FromBase64String(privateKey);
            var rsa = RSA.Create();
            rsa.ImportPkcs8PrivateKey(keyData, out _);
            byte[] data = Encoding.UTF8.GetBytes(message);
            return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
        }

 public class WithDrawsV3Back
    {
        /// <summary>
        /// 微信批次单号
        /// </summary>
        public string batch_id { get; set; }
        /// <summary>
        /// 商家批次单号
        /// </summary>
        public string out_batch_no { get; set; }
        public string create_time { get; set; }
        public string code { get; set; }
        public string message { get; set; }
    }
    /// <summary>
    /// 根据微信批次单号 查询转账状态返回
    /// </summary>
    public class WithDrawsStateRet
    {
        /// <summary>
        /// 转账批次单
        /// </summary>
        public transfer_batch transfer_batch { get; set; }
        /// <summary>
        /// 转账明细单列表
        /// </summary>
        public object transfer_detail_list { get; set; }
    }

    public class transfer_batch
    {
        public string mchid { get; set; }
        public string out_batch_no { get; set; }
        public string batch_id { get; set; }
        public string appid { get; set; }
        public string batch_status { get; set; }
        public string batch_type { get; set; }
        public string batch_name { get; set; }

        public string close_reason { get; set; }

        public int total_amount { get; set; }
        public int total_num { get; set; }
        public string create_time { get; set; }

        public string update_time { get; set; }
        public int success_amount { get; set; }
        public int success_num { get; set; }
        public int fail_amount { get; set; }
        public int fail_num { get; set; }
    }

 

posted @ 2022-07-30 14:39  YuanY  阅读(2428)  评论(1编辑  收藏  举报