You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

241 lines
11 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using Aop.Api;
using Aop.Api.Request;
using Aop.Api.Response;
using NLog;
using POSV.ShoppingCart;
using POSV.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace POSV.PayApi
{
public class WeixinApi
{
private static Logger logger = NLog.LogManager.GetCurrentClassLogger();
private static Dictionary<AccountTypeEnum, Tuple<string, string, string, string, string>> clientDic = new Dictionary<AccountTypeEnum, Tuple<string, string, string, string, string>>();
/// <summary>
/// 获取微信账户信息
/// </summary>
/// <param name="accountType"></param>
/// <returns></returns>
public static Tuple<string, string, string, string, string> GetWeixinInfo(AccountTypeEnum accountType)
{
Tuple<string, string, string, string, string> result = null;
switch (accountType)
{
case AccountTypeEnum.:
{
if (!clientDic.ContainsKey(AccountTypeEnum.))
{
var payMode = OrderUtils.GetPayMode("05");
var parameter = payMode.Body;
string appId = parameter.ContainsKey("appid") ? parameter["appid"].ToString() : "";
string mchId = parameter.ContainsKey("mchid") ? parameter["mchid"].ToString() : "";
string subMchId = parameter.ContainsKey("submchid") ? parameter["submchid"].ToString() : "";
string key = parameter.ContainsKey("appsecret") ? parameter["appsecret"].ToString() : "";
string certText = payMode.CertText;
clientDic.Add(AccountTypeEnum., new Tuple<string, string, string, string, string>(appId, mchId, subMchId, key, certText));
}
return clientDic[AccountTypeEnum.];
}
break;
}
return result;
}
/// <summary>
/// 微信退款申请
/// </summary>
/// <param name="accountType"></param>
/// <param name="tradeNo"></param>
/// <param name="totalAmount"></param>
/// <param name="refundNo"></param>
/// <param name="reason"></param>
/// <returns></returns>
public static Tuple<bool, string, OrderRefundResult> RefundByWeixin(AccountTypeEnum accountType, string tradeNo, decimal totalAmount, decimal refundAmount, string refundNo, string reason)
{
lock (Global.Instance.SyncLock)
{
try
{
logger.Info("订单[{0}]开始发起微信退款......", tradeNo);
string nonceStr = "x86" + ObjectId.GenerateNewStringId();
string totalAmountStr = Convert.ToInt32(totalAmount * 100) + "";
string RefundAmountStr = Convert.ToInt32(refundAmount * 100) + "";
var accountInfo = GetWeixinInfo(accountType);
if(accountInfo != null)
{
if (!string.IsNullOrEmpty(accountInfo.Item5))
{
string appId = accountInfo.Item1;
string mchId = accountInfo.Item2;
string subMchId = accountInfo.Item3;
string appSecret = accountInfo.Item4;
string certText = accountInfo.Item5;
WxPayV3OrderRefundRequestData request = new WxPayV3OrderRefundRequestData(appId, mchId, subMchId, appSecret, nonceStr, null, tradeNo, refundNo, totalAmountStr, RefundAmountStr, "SNY", reason);
byte[] certDataArray = Convert.FromBase64String(certText);
X509Certificate2 cert = new X509Certificate2(certDataArray, mchId);
var refundResult = WxPayV3.OrderRefund(request, cert);
logger.Info("订单[{0}]微信退款请求结果:{1}", tradeNo, JsonUtils.Serialize(refundResult));
if ("SUCCESS".Equals(refundResult.return_code))
{
if ("SUCCESS".Equals(refundResult.result_code))
{
return new Tuple<bool, string, OrderRefundResult>(true, null, refundResult);
}
else
{
return new Tuple<bool, string, OrderRefundResult>(false, refundResult.err_code + refundResult.err_code_des, null);
}
}
else
{
return new Tuple<bool, string, OrderRefundResult>(false, refundResult.return_msg, null);
}
}
else
{
return new Tuple<bool, string, OrderRefundResult>(false, "未配置微信支付证书(退款必须)", null);
}
}
else
{
return new Tuple<bool, string, OrderRefundResult>(false, "未配置微信支付参数", null);
}
}
catch (Exception ex)
{
logger.Error(ex, "订单[{0}]调用微信退款接口异常", tradeNo);
return new Tuple<bool, string, OrderRefundResult>(false, "调用微信退款接口异常", null);
}
}
}
/// <summary>
/// 微信退款结果查询
/// </summary>
/// <param name="tradeNo"></param>
/// <returns></returns>
public static Tuple<bool, string, RefundQueryResult> QueryWeixinRefundResult(AccountTypeEnum accountType, string tradeNo, string refundNo)
{
lock (Global.Instance.SyncLock)
{
try
{
logger.Info("订单[{0}]开始发起微信退款查询请求......", tradeNo);
string nonceStr = "x86" + ObjectId.GenerateNewStringId();
var accountInfo = GetWeixinInfo(accountType);
if (accountInfo != null)
{
string appId = accountInfo.Item1;
string mchId = accountInfo.Item2;
string subMchId = accountInfo.Item3;
string appSecret = accountInfo.Item4;
WxPayV3RefundQueryRequestData request = new WxPayV3RefundQueryRequestData(appId, mchId, subMchId, appSecret, nonceStr, null, tradeNo, refundNo, null);
var queryResult = WxPayV3.RefundQuery(request);
logger.Info("订单[{0}]微信退款查询结果:{1}", tradeNo, JsonUtils.Serialize(queryResult));
if ("SUCCESS".Equals(queryResult.return_code))
{
if ("SUCCESS".Equals(queryResult.result_code))
{
return new Tuple<bool, string, RefundQueryResult>(true, null, queryResult);
}
else
{
return new Tuple<bool, string, RefundQueryResult>(false, queryResult.err_code + queryResult.err_code_des, null);
}
}
else
{
return new Tuple<bool, string, RefundQueryResult>(false, queryResult.return_msg, null);
}
}
else
{
return new Tuple<bool, string, RefundQueryResult>(false, "未配置微信支付参数", null);
}
}
catch (Exception ex)
{
logger.Error(ex, "订单[{0}]调用微信退款查询接口异常", tradeNo);
return new Tuple<bool, string, RefundQueryResult>(false, "调用微信退款查询接口异常", null);
}
}
}
/// <summary>
/// 微信退款+查询结果
/// </summary>
/// <param name="reMoney"></param>
/// <param name="tradeNo"></param>
/// <param name="reTradeNo"></param>
/// <returns></returns>
public static Tuple<bool, string> RefundAndQuery(AccountTypeEnum accountType, string tradeNo, decimal totalAmount, decimal refundAmount, string reTradeNo, string reason, int timeout = 60)
{
try
{
var refundResponse = RefundByWeixin(accountType, tradeNo, totalAmount, refundAmount, reTradeNo, reason);
if (refundResponse.Item1)//请求成功
{
//int queryCount = 0;
//int sleepTime = 3000;
//if(timeout < 60)
//{//微信退款较慢显示最小60秒查询
// timeout = 60;
//}
//queryCount = (timeout * 1000 / sleepTime);
//int i = 0; //60秒超时
//while (i < queryCount)
//{
// var queryRefundResponse = QueryWeixinRefundResult(accountType, tradeNo, reTradeNo);
// if (queryRefundResponse.Item1 && queryRefundResponse.Item3.refund_status_list.Count > 0 && queryRefundResponse.Item3.refund_status_list[0] == "SUCCESS")
// {
// return new Tuple<bool, string>(true, "退款成功!");
// }
// i++;
// System.Threading.Thread.Sleep(3000);//睡眠3秒
//}
//if (i == queryCount)
//{
// return new Tuple<bool, string>(false, "查询退款结果超时,退单失败!");
//}
return new Tuple<bool, string>(true, "退款成功!");
}
else if ("ERROR订单已全额退款".Equals(refundResponse.Item2))
{
return new Tuple<bool, string>(true, "退款成功!");
}
else
{
//请求失败
return new Tuple<bool, string>(false, refundResponse.Item2);
}
}
catch (Exception ex)
{
logger.Error(ex, "微信退款发生异常");
return new Tuple<bool, string>(false, "退款发生异常!");
}
return new Tuple<bool, string>(false, "退款失败!");
}
}
}