支付宝微信提现

一.支付宝

支付宝提现官方名称为  单笔转账到支付宝账户  主要分为2个接口 :

1.alipay.fund.trans.toaccount.transfer(单笔转账到支付宝账户接口)  官方文档:https://docs.open.alipay.com/api_28/alipay.fund.trans.toaccount.transfer

2.alipay.fund.trans.order.query(查询转账订单接口)  官方文档https://docs.open.alipay.com/api_28/alipay.fund.trans.order.query/

ps:其中查询转账接口主要是为了防止漏单 在错误码为20000,40004,或者编码为SYSTEM_ERROR 时需要使用该接口查询是否已经转账过 根据接口返回值判断是否已经打款 如果未打款需要重新发起打款 如果重试后失败需要加入出错列表或其他处理 随业务需要而定

主要接口 alipay.fund.trans.toaccount.transfer

调用时准备步骤:

1. 创建应用并获取APPID

2.添加功能

测试时可使用沙盒内数据

3.配置应用环境

生成秘钥

4.下载sdk

5.调用

其中调用时 要注意在调用中放的公钥为支付宝公钥 而不是应用公钥 如果传错会造成转账成功但是报sign check fail: check Sign and Data Fail!错误

转账金额 小数点最多只能2位 文本类型 和微信提现有差别 微信单位为分

附代码例子:

 1  //沙箱数据
 2 string serverUrl = "https://openapi.alipaydev.com/gateway.do"; 
 3  string appId = "test appid";
 4 //私钥
 5 string privateKeyPem ="";
 6  //支付宝公钥
 7  string alipay_public_key = "";
 8 try
 9             {
10                 IAopClient client = new DefaultAopClient(serverUrl, appId, privateKeyPem, "json", "1.0", "RSA2", alipay_public_key, "GBK", false);
11                 AlipayFundTransToaccountTransferRequest request = new AlipayFundTransToaccountTransferRequest();
12                 request.BizContent = "{" +
13     "    "out_biz_no":"" + sn + ""," +//商户转账唯一订单号
14     "    "payee_type":"ALIPAY_LOGONID"," +//ALIPAY_LOGONID:支付宝登录号
15     "    "payee_account":"" + payee + ""," +//收款方账户
16     "    "amount":"" + Math.Round(amount, 2).ToString() + ""," +//转账金额
17     "    "payee_real_name":"" + userName + ""," +//收款方真实姓名
18     "    "remark":"用户提现打款"," +
19     "  }";
20                 var response = client.Execute(request);
21                 if (response.Code == "10000")
22                 {
23                     return true;
24                 }
25                 else
26                 {
27                     LogInfo(string.Format("单号:{1} 支付宝支付失败 原因:{0}", response.SubMsg, sn));
28                     if (response.Code == "20000" || response.Code == "40004" || response.SubCode == "SYSTEM_ERROR")
29                     {
30                         //掉单
31                         //查询转账结果
32                         AlipayFundTransOrderQueryRequest _request = new AlipayFundTransOrderQueryRequest();
33                         request.BizContent = "{" +
34                         ""out_biz_no":"" + sn + ""," +
35                         ""order_id":"" + response.OrderId + """ +
36                         "  }";
37                         var _response = client.Execute(_request);
38                         if (_response.Code == "10000" && _response.Status == "SUCCESS" && !string.IsNullOrEmpty(_response.PayDate) && string.IsNullOrEmpty(_response.ErrorCode))
39                         {
40                             return true;//掉单 网络问题实际转账成功
41                         }
42                         else
43                         {
44                             if (errorTimes <= 3)
45                             {
46                                 //增加错误数
47                                 using (MongoDbProviderFactory factory = base.NewWashcarFactory())
48                                 {
49                                     WithdrawalsApplyRecordAccess access = new WithdrawalsApplyRecordAccess(factory.Context);
50                                     var rec = access.Single(recordId);
51                                     if (rec != null)
52                                     {
53                                         rec.ErrorTimes = rec.ErrorTimes + 1;
54                                         access.Update(rec);
55                                     }
56                                 }
57                                 //重新打款一次
58                                 response = client.Execute(request);
59                                 if (response.Code == "10000")
60                                 {
61                                     return true;
62                                 }
63                                 else
64                                 {
65                                     LogInfo(string.Format("单号:{1} 支付宝支付失败 原因:{0}", response.SubMsg, sn));
66                                     return false;
67                                 }
68                             }
69                         }
70                     }
71                     return false;
72                 }
73             }
74             catch (Exception ex)
75             {
76                 LogInfo(string.Format("单号:{1} 支付宝支付失败 ex:{0}", ex.Message, sn));
77                 return false;
78             }
提现关键代码片段

 二.微信

微信功能官方名称 企业付款 文档地址:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2  文档很全面  

开发步骤:

1.注册服务号

2.注册微信商户号

3.在商户号后台对AppID授权 开通企业付款到零钱功能

4.下载证书

5.调用接口

注意事项:

1.打款 是预付款形式 必须先在商户平台充值

2.签名需要根据ASCII码排序 并加密 详见文档

3.证书需要放在服务器非虚拟路径处 防止被非法下载盗用 代码中必须调用 否则证书安装了没效果

4.必须通过微信的openId 获取被转账人 所以需要在调用之前根据业务绑定微信和用户账号

代码部分:

  1   /// <summary>
  2         /// 微信提现
  3         /// </summary>
  4         /// <param name="sn">单号</param>
  5         /// <param name="wxOpenId">微信用户openid</param>
  6         /// <param name="userName">用户真实姓名</param>
  7         /// <param name="amount">金额 单位分</param>
  8         private bool WechatPay(string sn, string wxOpenId, string userName, int amount)
  9         {
 10             if (string.IsNullOrEmpty(sn)) { LogAndSetMsg(string.Format("单号为空 转账失败")); return false; }
 11             if (string.IsNullOrEmpty(wxOpenId)) { LogAndSetMsg(string.Format("单号{0} 微信用户openId为空 转账失败", sn)); return false; }
 12             if (string.IsNullOrEmpty(userName)) { LogAndSetMsg(string.Format("单号{0} 用户真实姓名为空 转账失败", sn)); return false; }
 13             #region 微信支付配置区
 14             string mch_appid = "";//商户账号appid
 15             string mchid = "";//商户号
 16             string key = "";//秘钥
 17             string cert = @"E:certificatewechartapiclient_cert.p12";//证书路径
 18             #endregion
 19             string nonce_str = Guid.NewGuid().ToString().Replace("-", "");//随机字符串
 20             string sign = "";//签名
 21             string partner_trade_no = sn;//商户订单号
 22             string openid = wxOpenId;//用户openid
 23             string check_name = "FORCE_CHECK";//强校验真实姓名
 24             string re_user_name = userName;//收款用户姓名
 25             string desc = "用户提现打款";//企业付款描述信息
 26             string spbill_create_ip = GetLocalIP();//Ip地址
 27             Dictionary<string, string> parm = new Dictionary<string, string>();
 28             parm.Add("mch_appid", mch_appid);
 29             parm.Add("mchid", mchid);
 30             parm.Add("nonce_str", nonce_str);
 31             parm.Add("partner_trade_no", partner_trade_no);
 32             parm.Add("openid", openid);
 33             parm.Add("check_name", check_name);
 34             parm.Add("re_user_name", re_user_name);
 35             parm.Add("amount", amount.ToString());
 36             parm.Add("desc", desc);
 37             parm.Add("spbill_create_ip", spbill_create_ip);
 38             //设置签名
 39             var stringSignTemp = getParamSrc(parm);//签名处理中间变量
 40             stringSignTemp = stringSignTemp + "&key=" + key;
 41             sign = GetMD5(stringSignTemp).ToUpper();
 42             parm.Add("sign", sign);
 43             XDocument xml;
 44             try
 45             {//发送带证书的请求
 46                 ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
 47                 X509Certificate cer = new X509Certificate(cert, mchid);
 48                 HttpWebRequest webrequest = (HttpWebRequest)HttpWebRequest.Create("https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers");
 49                 webrequest.ClientCertificates.Add(cer);
 50                 webrequest.ContentType = "application/x-www-form-urlencoded";
 51                 webrequest.Method = "post";
 52                 //拼接post请求
 53                 string parmStr = "<xml>";
 54                 parmStr += "<amount>" + amount + "</amount>";
 55                 parmStr += "<check_name>"+check_name+"</check_name>";
 56                 parmStr += "<desc>"+desc+"</desc>";
 57                 parmStr += "<mch_appid>"+ mch_appid + "</mch_appid>";
 58                 parmStr += "<mchid>"+ mchid + "</mchid>";
 59                 parmStr += "<nonce_str>"+ nonce_str + "</nonce_str>";
 60                 parmStr += "<openid>"+ openid + "</openid>";
 61                 parmStr += "<partner_trade_no>"+ partner_trade_no + "</partner_trade_no>";
 62                 parmStr += "<re_user_name>"+ re_user_name + "</re_user_name>";
 63                 parmStr += "<spbill_create_ip>"+ spbill_create_ip + "</spbill_create_ip>";
 64                 parmStr += "<sign>"+ sign + "</sign>";
 65                 parmStr += "</xml>";
 66                 byte[] byteArray = Encoding.UTF8.GetBytes(parmStr); //转化
 67                 webrequest.ContentLength = byteArray.Length;
 68                 using (Stream newStream = webrequest.GetRequestStream())
 69                 {
 70                     newStream.Write(byteArray, 0, byteArray.Length);//写入参数
 71                 }
 72                 HttpWebResponse webreponse = (HttpWebResponse)webrequest.GetResponse();
 73                 Stream stream = webreponse.GetResponseStream();
 74                 StreamReader sr = new StreamReader(webreponse.GetResponseStream(), Encoding.UTF8);
 75                 string str = sr.ReadToEnd();
 76                 xml = XDocument.Load(stream);
 77             }
 78             catch (Exception ex)
 79             {
 80                 LogAndSetMsg(string.Format("单号:{1} 发送带证书的请求失败 ex:{0}", ex.Message, sn));
 81                 return false;
 82             }
 83             //解析返回结果
 84             if (xml == null) { LogAndSetMsg(string.Format("解析微信返回值出错 单号:{0}", sn)); return false; }
 85             //获取根节点
 86             var root = xml.Root;
 87             var node = root.Element("result_code");
 88             if (node != null && node.Value == "SUCCESS")
 89             {
 90                 return true;
 91             }
 92             else
 93             {
 94                 var err = root.Element("return_msg");
 95                 if (err != null)
 96                 {
 97                     LogAndSetMsg(string.Format("支付失败:{0} 单号:{1}", err.Value, sn));
 98                 }
 99                 else
100                 {
101                     LogAndSetMsg(string.Format("支付失败:原因未知 单号:{0}", sn));
102                 }
103                 return false;
104             }
105         }
关键方法
 1   //加密
 2         public static string GetMD5(string pwd)
 3         {
 4             MD5 md5Hasher = MD5.Create();
 5 
 6             byte[] data = md5Hasher.ComputeHash(Encoding.UTF8.GetBytes(pwd));
 7 
 8             StringBuilder sBuilder = new StringBuilder();
 9             for (int i = 0; i < data.Length; i++)
10             {
11                 sBuilder.Append(data[i].ToString("x2"));
12             }
13 
14             return sBuilder.ToString();
15         }
MD5
 1    /// <summary>
 2         /// 参数按照ASCII码从小到大排序
 3         /// </summary>
 4         /// <param name="paramsMap"></param>
 5         /// <returns></returns>
 6         private string getParamSrc(Dictionary<string, string> paramsMap)
 7         {
 8             var vDic = (from objDic in paramsMap orderby objDic.Key ascending select objDic);
 9             StringBuilder str = new StringBuilder();
10             foreach (KeyValuePair<string, string> kv in vDic)
11             {
12                 string pkey = kv.Key;
13                 string pvalue = kv.Value;
14                 str.Append(pkey + "=" + pvalue + "&");
15             }
16 
17             string result = str.ToString().Substring(0, str.ToString().Length - 1);
18             return result;
19         }
根据AscII码排序参数为文本
 1  /// <summary>
 2         /// 获取本机ip
 3         /// </summary>
 4         /// <returns></returns>
 5         private string GetLocalIP()
 6         {
 7             try
 8             {
 9                 string HostName = Dns.GetHostName(); //得到主机名
10                 IPHostEntry IpEntry = Dns.GetHostEntry(HostName);
11                 for (int i = 0; i < IpEntry.AddressList.Length; i++)
12                 {
13                     //从IP地址列表中筛选出IPv4类型的IP地址
14                     //AddressFamily.InterNetwork表示此IP为IPv4,
15                     //AddressFamily.InterNetworkV6表示此地址为IPv6类型
16                     if (IpEntry.AddressList[i].AddressFamily == AddressFamily.InterNetwork)
17                     {
18                         return IpEntry.AddressList[i].ToString();
19                     }
20                 }
21                 LogInfo("未能获取到本机IP");
22                 return "";
23             }
24             catch (Exception ex)
25             {
26                 LogInfo("获取本机IP出错:" + ex.Message);
27                 return "";
28             }
29         }
获取本机IP
1  private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
2         {
3             if (errors == SslPolicyErrors.None)
4                 return true;
5             return false;
6         }
证书请求回调

注:

1. post请求参数为xml格式 

2.SYSTEMERROR 错误时 需要原单号重试 否则会多次支付 代码中未展示

3.证书出错  官方解决方案:https://pay.weixin.qq.com/wiki/doc/api/download/cert.zip 里面有一个word文档

还有个简洁的做法就是 服务的情况下 在属性--->登录--->选择此账户 选择管理员账户

原文地址:https://www.cnblogs.com/nontracey/p/8309492.html