using Antis.Pay.Core.Enum; using Antis.Pay.Core.Interface; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using System.Xml; using System.Web; using Antis.Pay.Core.Model; using NCC.Code; namespace Antis.Pay.Core { public class WePay : IWePay { /// /// 统一微信支付 /// /// /// /// /// /// /// public string BuildWePay(string openid, string orderNo, string productName, int totalFee, string customerIP, EnumWePayTradeType tradeType) { return this.UnifiedOrder(openid, orderNo, productName, totalFee, customerIP, tradeType); } public bool VerifyNotify(HttpRequestBase request, out WePayReturnModel model) { bool verifyResult = false; model = new WePayReturnModel(); string requestXml = GetRequestXmlData(request); var dic = FromXml(requestXml); Log4jHelper.LogInfo("dic" + dic); string returnCode = GetValueFromDic(dic, "return_code"); Log4jHelper.LogInfo("returnCode" + returnCode); //WePayNotifyValidation(dic); if (!string.IsNullOrEmpty(returnCode) && returnCode == "SUCCESS")//通讯成功 { bool result = WePayNotifyValidation(dic); if (result) { string transactionid = GetValueFromDic(dic, "transaction_id"); if (!string.IsNullOrEmpty(transactionid)) { string queryXml = BuildQueryRequest(transactionid, dic); string queryResult = HTTPHelper.Post(WepayConfig.WEPAY_ORDERQUERY_URL, queryXml); var queryReturnDic = FromXml(queryResult); if (ValidatonQueryResult(queryReturnDic))//查询成功 { Log4jHelper.LogInfo("queryReturnDic" + queryReturnDic); verifyResult = true; model.OutTradeNo = GetValueFromDic(dic, "out_trade_no"); model.TotalFee = GetValueFromDic(dic, "total_fee") / 100; model.TradeNo = transactionid; model.TradeStatus = GetValueFromDic(dic, "result_code"); model.ReturnXml = BuildReturnXml("OK", "成功"); } else model.ReturnXml = BuildReturnXml("FAIL", "订单查询失败"); } else model.ReturnXml = BuildReturnXml("FAIL", "支付结果中微信订单号不存在"); } else model.ReturnXml = BuildReturnXml("FAIL", "签名失败"); } else { string returnmsg; dic.TryGetValue("return_msg", out returnmsg); throw new Exception("异步通知错误:" + returnmsg); } Log4jHelper.LogInfo(" model.ReturnXml" + model.ReturnXml); return verifyResult; } #region private method /// /// 统一下单 /// /// private string UnifiedOrder(string openid, string orderNo, string productName, int totalFee, string customerIP, EnumWePayTradeType tradeType) { string requestXml = this.BuildRequest(openid, orderNo, productName, totalFee, customerIP, tradeType); Log4jHelper.LogInfo($" 第一个 resultXml = {requestXml}"); string resultXml = HTTPHelper.Post(WepayConfig.WEPAY_PAY_URL, requestXml); Log4jHelper.LogInfo($" UnifiedOrder resultXml = {resultXml}"); var dic = FromXml(resultXml); string returnCode = ""; dic.TryGetValue("return_code", out returnCode); if (returnCode == "SUCCESS") { if (tradeType == EnumWePayTradeType.APP) { var prepay_id = GetValueFromDic(dic, "prepay_id"); if (!string.IsNullOrEmpty(prepay_id)) return BuildAppPay(prepay_id); else throw new Exception("支付错误:" + GetValueFromDic(dic, "err_code_des")); } else if (tradeType == EnumWePayTradeType.NATIVE) { string codeUrl = ""; dic.TryGetValue("code_url", out codeUrl); if (!string.IsNullOrEmpty(codeUrl)) return codeUrl; else throw new Exception("未找到对应的二维码链接"); } else if (tradeType == EnumWePayTradeType.JSAPI) { var prepay_id = GetValueFromDic(dic, "prepay_id"); if (!string.IsNullOrEmpty(prepay_id)) return BuildJsApiPay(prepay_id); else throw new Exception("支付错误:" + GetValueFromDic(dic, "err_code_des")); } else throw new Exception(" WAP 未实现"); } else throw new Exception("后台统一下单失败"); } private string BuildRequest(string openid, string orderNo, string productName, int totalFee, string customerIP, EnumWePayTradeType tradeType) { SortedDictionary dicParam = CreateParam(openid, orderNo, productName, totalFee, customerIP, tradeType); string signString = CreateURLParamString(dicParam); string key = tradeType == EnumWePayTradeType.APP ? WepayConfig.WEPAY_APP_KEY : WepayConfig.WEPAY_WEB_KEY; string preString = signString + "&key=" + key; string sign = MD5Helper.Sign(preString, WepayConfig.WEPAY_CHARTSET).ToUpper(); dicParam.Add("sign", sign); //dicParam.Add("paySign", sign); return BuildForm(dicParam); } private static SortedDictionary CreateParam(string openid, string orderNo, string productName, decimal totalFee, string customerIP, EnumWePayTradeType tradeType) { SortedDictionary dic = new SortedDictionary(); dic.Add("appid", tradeType == EnumWePayTradeType.APP ? WepayConfig.WEPAY_APP_APPID : WepayConfig.WEPAY_WEB_APPID);//账号ID dic.Add("mch_id", tradeType == EnumWePayTradeType.APP ? WepayConfig.WEPAY_APP_MCH_ID : WepayConfig.WEPAY_WEB_MCH_ID);//商户号 dic.Add("nonce_str", Guid.NewGuid().ToString().Replace("-", ""));//随机字符串 dic.Add("body", productName);//商品描述 dic.Add("out_trade_no", orderNo);//商户订单号 dic.Add("total_fee", totalFee.ToString());//总金额 dic.Add("spbill_create_ip", customerIP);//终端IP dic.Add("notify_url", tradeType == EnumWePayTradeType.APP ? WepayConfig.WEPAY_APP_NOTIFY_URL : WepayConfig.WEPAY_WEB_NOTIFY_URL);//通知地址 dic.Add("trade_type", tradeType.ToString());//交易类型 //加入openid dic.Add("openid", openid);//交易类型 return dic; } private static string CreateURLParamString(SortedDictionary dicArray) { StringBuilder prestr = new StringBuilder(); foreach (KeyValuePair temp in dicArray.OrderBy(o => o.Key)) { prestr.Append(temp.Key + "=" + temp.Value + "&"); } int nLen = prestr.Length; prestr.Remove(nLen - 1, 1); return prestr.ToString(); } private static string BuildForm(SortedDictionary dicParam) { StringBuilder sbXML = new StringBuilder(); sbXML.Append(""); foreach (KeyValuePair temp in dicParam) { sbXML.Append("<" + temp.Key + ">" + temp.Value + ""); } sbXML.Append(""); return sbXML.ToString(); } private static SortedDictionary FromXml(string xml) { SortedDictionary sortDic = new SortedDictionary(); if (string.IsNullOrEmpty(xml)) { throw new Exception("将空的xml串转换为WxPayData不合法!"); } XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(xml); XmlNode xmlNode = xmlDoc.FirstChild;//获取到根节点 XmlNodeList nodes = xmlNode.ChildNodes; foreach (XmlNode xn in nodes) { XmlElement xe = (XmlElement)xn; if (!sortDic.ContainsKey(xe.Name)) sortDic.Add(xe.Name, xe.InnerText); } return sortDic; } private static T GetValueFromDic(SortedDictionary dic, string key) { string val; dic.TryGetValue(key, out val); T returnVal = default(T); if (val != null) returnVal = (T)Convert.ChangeType(val, typeof(T)); return returnVal; } /// /// app支付 /// /// /// private static string BuildAppPay(string prepayid) { var dicParam = CreateWapAndAppPayParam(prepayid); string signString = CreateURLParamString(dicParam); string preString = signString + "&key=" + WepayConfig.WEPAY_APP_KEY; string sign = MD5Helper.Sign(preString, WepayConfig.WEPAY_CHARTSET).ToUpper(); dicParam.Add("sign", sign); return JsonConvert.SerializeObject( new { appid = dicParam["appid"], partnerid = dicParam["partnerid"], prepayid = dicParam["prepayid"], package = dicParam["package"], noncestr = dicParam["noncestr"], timestamp = dicParam["timestamp"], sign = dicParam["sign"] }); } /// /// jsapi 公众号 /// /// /// private static string BuildJsApiPay(string prepayid) { var dicParam = CreatJsApiPayParam(prepayid); string signString = CreateURLParamString(dicParam); string preString = signString + "&key=" + WepayConfig.WEPAY_WEB_KEY; string sign = MD5Helper.Sign(preString, WepayConfig.WEPAY_CHARTSET).ToUpper(); dicParam.Add("paySign", sign); //修改的地方 return JsonConvert.SerializeObject( new { appId = dicParam["appId"], //partnerid = dicParam["partnerid"], //prepayid = dicParam["prepayid"], package = dicParam["package"], nonceStr = dicParam["nonceStr"], timeStamp = dicParam["timeStamp"], paySign = dicParam["paySign"] }); } /// /// 公众号支付json给前端获取 /// /// /// private static SortedDictionary CreatJsApiPayParam(string prepayId) { SortedDictionary dic = new SortedDictionary(); //修改的地方 dic.Add("appId", WepayConfig.WEPAY_WEB_APPID);//公众账号appID //dic.Add("partnerid", WepayConfig.WEPAY_WEB_MCH_ID);//商户号 //dic.Add("prepayid", prepayId);//预支付交易会话ID dic.Add("signType", "MD5");//预支付交易会话ID dic.Add("package", "prepay_id=" + prepayId);//扩展字段 dic.Add("nonceStr", Guid.NewGuid().ToString().Replace("-", ""));//随机字符串 dic.Add("timeStamp", (Convert.ToInt32((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds)).ToString());//时间戳 return dic; } private static SortedDictionary CreateWapAndAppPayParam(string prepayId) { SortedDictionary dic = new SortedDictionary(); dic.Add("appid", WepayConfig.WEPAY_APP_APPID);//公众账号ID dic.Add("partnerid", WepayConfig.WEPAY_APP_MCH_ID);//商户号 dic.Add("prepayid", prepayId);//预支付交易会话ID dic.Add("package", "Sign=WXPay");//扩展字段 dic.Add("noncestr", Guid.NewGuid().ToString().Replace("-", ""));//随机字符串 dic.Add("timestamp", (Convert.ToInt32((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds)).ToString());//时间戳 return dic; } private string GetRequestXmlData(HttpRequestBase request) { System.IO.Stream stream = request.InputStream; int count = 0; byte[] buffer = new byte[1024]; StringBuilder builder = new StringBuilder(); while ((count = stream.Read(buffer, 0, 1024)) > 0) { builder.Append(Encoding.UTF8.GetString(buffer, 0, count)); } stream.Flush(); stream.Close(); stream.Dispose(); return builder.ToString(); } public static bool WePayNotifyValidation(SortedDictionary dic) { string sign = GetValueFromDic(dic, "sign"); Log4jHelper.LogInfo("dic" + dic); if (dic.ContainsKey("sign")) { dic.Remove("sign"); } string tradeType = GetValueFromDic(dic, "trade_type"); string preString = CreateURLParamString(dic); Log4jHelper.LogInfo("preString字符串" + preString); //if (string.IsNullOrEmpty(tradeType)) //{ string key = tradeType == EnumWePayTradeType.APP.ToString() ? WepayConfig.WEPAY_APP_KEY : WepayConfig.WEPAY_WEB_KEY; string preSignString = preString + "&key=" + key; string signString = MD5Helper.Sign(preSignString, WepayConfig.WEPAY_CHARTSET).ToUpper(); Log4jHelper.LogInfo("最后的sign" + signString); return signString == sign; //} //else // return false; } //public static bool WePayNotifyValidation(SortedDictionary dic) //{ // string sign = GetValueFromDic(dic, "sign"); // Log4jHelper.LogInfo("dic" + dic); // if (dic.ContainsKey("sign")) // { // dic.Remove("sign"); // } // string tradeType = GetValueFromDic(dic, "trade_type"); // string preString = CreateURLParamString(dic); // Log4jHelper.LogInfo("preString字符串" + preString); // if (string.IsNullOrEmpty(tradeType)) // { // string key = tradeType == EnumWePayTradeType.APP.ToString() ? WepayConfig.WEPAY_APP_KEY : WepayConfig.WEPAY_WEB_KEY; // string preSignString = preString + "&key=" + key; // string signString = MD5Helper.Sign(preSignString, WepayConfig.WEPAY_CHARTSET).ToUpper(); // Log4jHelper.LogInfo("最后的sign" + signString); // return signString == sign; // } // else // return false; //} private static string BuildReturnXml(string code, string returnMsg) { return string.Format("", code, returnMsg); } public static string BuildQueryRequest(string transactionId, SortedDictionary dic) { string tradeType = GetValueFromDic(dic, "trade_type"); bool isApp = tradeType == EnumWePayTradeType.APP.ToString(); SortedDictionary dicParam = CreateQueryParam(transactionId, isApp); string signString = CreateURLParamString(dicParam); string key = isApp ? WepayConfig.WEPAY_APP_KEY : WepayConfig.WEPAY_WEB_KEY; string preString = signString + "&key=" + key; string sign = MD5Helper.Sign(preString, "utf-8").ToUpper(); dicParam.Add("sign", sign); return BuildForm(dicParam); } private static SortedDictionary CreateQueryParam(string transactionId, bool isApp) { SortedDictionary dic = new SortedDictionary(); dic.Add("appid", isApp ? WepayConfig.WEPAY_APP_APPID : WepayConfig.WEPAY_WEB_APPID);//公众账号ID dic.Add("mch_id", isApp ? WepayConfig.WEPAY_APP_MCH_ID : WepayConfig.WEPAY_WEB_MCH_ID);//商户号 dic.Add("nonce_str", Guid.NewGuid().ToString().Replace("-", ""));//随机字符串 dic.Add("transaction_id", transactionId);//随机字符串 return dic; } private static bool ValidatonQueryResult(SortedDictionary dic) { bool result = false; if (dic.ContainsKey("return_code") && dic.ContainsKey("return_code")) { if (dic["return_code"].ToString() == "SUCCESS" && dic["result_code"].ToString() == "SUCCESS") result = true; } if (!result) { StringBuilder sb = new StringBuilder(); foreach (var item in dic.Keys) { sb.Append(item + ":" + dic[item] + "|"); } } return result; } /// /// 微信退款 /// /// /// public SortedDictionary Refund(WePayReturnModel model) { Log4jHelper.LogInfo("refund in ok model = " + model.ToJson()); //参数 xml SortedDictionary dic = new SortedDictionary(); if (!model.OutTradeNo.IsNullOrEmpty())//微信订单号存在的条件下,则已微信订单号为准 { dic.Add("transaction_id", model.OutTradeNo); } else//微信订单号不存在,才根据商户订单号去退款 { dic.Add("out_trade_no", model.TradeNo); } dic.Add("out_refund_no", Guid.NewGuid().ToString("N"));//随机生成商户退款单号 int total_fee = model.TotalFee.ToInt(); int refund_fee = model.TotalFee.ToInt(); Log4jHelper.LogInfo("总金额" + total_fee); dic.Add("total_fee", total_fee.ToString());//订单总金额 dic.Add("refund_fee", refund_fee.ToString());//退款金额 dic.Add("op_user_id", WepayConfig.WEPAY_WEB_MCH_ID);//操作员,默认为商户号 dic.Add("appid", WepayConfig.WEPAY_WEB_APPID);//appid dic.Add("mch_id", WepayConfig.WEPAY_WEB_MCH_ID);//商户号 dic.Add("nonce_str", Guid.NewGuid().ToString().Replace("-", ""));////随机字符串 dic.Add("sign_type", "MD5");////签名类型 dic.Add("spbill_create_ip", Net.Ip);//终端IP //dic.Add("sign", WepayConfig.WEPAY_WEB_MCH_ID);////签名 Log4jHelper.LogInfo("商户号" + WepayConfig.WEPAY_WEB_MCH_ID); string signString = CreateURLParamString(dic); string key = WepayConfig.WEPAY_WEB_KEY; string preString = signString + "&key=" + key; string sign = MD5Helper.Sign(preString, WepayConfig.WEPAY_CHARTSET).ToUpper(); dic.Add("sign", sign); string requestXml = BuildForm(dic); Log4jHelper.LogInfo($"requestXml={requestXml}"); string resultXml = HTTPHelper.Post(WepayConfig.WECHAT_REFUND_URL, requestXml, true, model.timeout ?? 6); Log4jHelper.LogInfo($"最终resultxml={resultXml}"); //返回 var result = FromXml(resultXml); //post return result; } #endregion } }