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 + "" + temp.Key + ">");
}
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
}
}