499 lines
19 KiB
C#
Raw Normal View History

2025-04-24 18:31:27 +08:00
using MyCode.Project.Infrastructure.Common;
using MyCode.Project.Infrastructure.Utils;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Xml;
using Wolf.ExternalService.CMBPay.Common;
using Wolf.ExternalService.CMBPay.Core;
using Wolf.ExternalService.CMBPay.Core.Events;
using Wolf.ExternalService.CMBPay.Core.Utils;
using static MyCode.Project.Infrastructure.Constant.LxmConst;
namespace MyCode.Project.Infrastructure.PayModels
{
/// <summary>
/// 招行支付的底层类扩展,
/// 方法1 增加查询订单实际支付情况的接口
/// </summary>
public class ExtendedGateway : Gateway
{
#region
/// <summary>
/// 统一下单 接口类型
/// </summary>
private const string UnifiedOrderApiType = "unified.trade.micropay";
/// <summary>
/// 查询订单 接口类型
/// </summary>
private const string QueryApiType = "unified.trade.query";
/// <summary>
/// 关闭订单 接口类型
/// </summary>
private const string CloseOrderApiType = "unified.micropay.reverse";
#endregion
#region
/// <summary>
/// 通知
/// </summary>
public new Notify Notify => (Notify)base.Notify;
#endregion
#region
/// <summary>
/// 初始化一个<see cref="ExtendedGateway"/>类型的实例
/// </summary>
public ExtendedGateway() : this(new Merchant())
{
}
/// <summary>
/// 初始化一个<see cref="ExtendedGateway"/>类型的实例
/// </summary>
/// <param name="merchant">商家数据</param>
public ExtendedGateway(Merchant merchant) : base(merchant)
{
}
#endregion
#region
/// <summary>
/// 每隔5秒轮询判断用户各种支付的真实支付情况总共轮询5次
/// </summary>
/// <param name="auxiliary">辅助接口</param>
private void PollQueryTradeState(IAuxiliary auxiliary)
{
for (int i = 0; i < 5; i++)
{
Thread.Sleep(5000);
BuildQuery(auxiliary);
string dsds = Notify.TradeState.ToLower();
if (IsSuccessPay && Notify.TradeState.ToLower() == SUCCESS)
{
OnPaymentSucceed(new PaymentSucceedEventArgs(this));
return;
}
}
}
/// <summary>
/// 异步每隔5秒轮询判断用户是否支付总共轮询5次
/// </summary>
/// <param name="auxiliary">辅助接口</param>
/// <returns></returns>
private async Task PollQueryTradeStateAsync(IAuxiliary auxiliary)
{
await Task.Run(() => PollQueryTradeState(auxiliary));
}
/// <summary>
/// 查询订单的相关平台参数
/// </summary>
/// <param name="query"></param>
public void QueryOrderPay(Auxiliary query)
{
Task.Run(async () =>
{
await PollQueryTradeStateAsync(new Auxiliary()
{
TransactionId = query.TransactionId,
OutTradeNo = query.OutTradeNo
});
})
.GetAwaiter()
.GetResult();
}
/// <summary>
/// 生成查询订单参数
/// </summary>
/// <param name="auxiliary">辅助参数</param>
/// <returns></returns>
private INotify BuildQuery(IAuxiliary auxiliary)
{
InitQuery(auxiliary);
Commit();
return Notify;
}
/// <summary>
/// 初始化查询订单参数
/// </summary>
/// <param name="auxiliary">辅助参数</param>
private void InitQuery(IAuxiliary auxiliary)
{
Merchant.Service = QueryApiType;
InitAuxiliaryParameter(GatewayAuxiliaryType.Query, auxiliary);
}
#endregion
/// <summary>
/// 初始化订单参数
/// </summary>
/// <param name="action">操作</param>
private void InitOrderParameter(Action action = null)
{
GatewayData.Clear();
Merchant.NonceStr = Util.GenerateNonceStr();
Merchant.DeviceInfo = Wolf.ExternalService.CMBPay.Common.Constant.WEB;
action?.Invoke();
GatewayData.Add(Merchant, StringCase.Snake);
GatewayData.Add(Order, StringCase.Snake);
AddSign();
}
/// <summary>
/// 初始化辅助参数
/// </summary>
/// <param name="gatewayAuxiliaryType">辅助类型</param>
/// <param name="auxiliary">辅助参数</param>
private void InitAuxiliaryParameter(GatewayAuxiliaryType gatewayAuxiliaryType, IAuxiliary auxiliary)
{
auxiliary.Validate(gatewayAuxiliaryType);
Merchant.NonceStr = Util.GenerateNonceStr();
//Merchant.NotifyUrl = "";
GatewayData.Add(Merchant, StringCase.Snake);
GatewayData.Add(auxiliary, StringCase.Snake);
AddSign();
}
/// <summary>
/// 转换通知对象
/// </summary>
/// <returns></returns>
protected override INotify ToObject()
{
return GatewayData.ToObject<Notify>(StringCase.Snake);
}
/// <summary>
/// 转换通知对象
/// </summary>
/// <returns></returns>
protected override async Task<INotify> ToObjectAsync()
{
return await GatewayData.ToObjectAsync<Notify>(StringCase.Snake);
}
#region testfuyoupay()
/// <summary>
/// 富友扫客户支付码支付
/// </summary>
/// <param name="order"></param>
/// <param name="order_type">支付类型 ALIPAY , WECHAT, QQ(QQ 钱包), UNIONPAY(银联二维码) , BESTPAY(翼支付)</param>
/// <returns></returns>
public string FuiouScanpPay(Wolf.ExternalService.CMBPay.Barcodepay.Order order, string order_type)
{
Dictionary<string, string> map = new Dictionary<string, string>();
map.Add("version", "1.0");
map.Add("ins_cd", FuiouPayConst.ins_cd);
map.Add("mchnt_cd", order.OpUserId);
map.Add("term_id", FuiouPayConst.term_id);
map.Add("random_str", Guid.NewGuid().ToString("N"));
map.Add("sign", "");
map.Add("order_type", order_type);
map.Add("goods_des", order.Body);
map.Add("goods_detail", "");
map.Add("reserved_expire_minute", "1440");
map.Add("addn_inf", order.Attach);
map.Add("auth_code", order.AuthCode);
map.Add("mchnt_order_no", order.OutTradeNo);
map.Add("curr_type", "");
map.Add("order_amt", order.Amount.ToString());
map.Add("term_ip", FuiouPayConst.term_ip);
map.Add("txn_begin_ts", DateTime.Now.ToString("yyyyMMddhhmmss"));
map.Add("goods_tag", "");
map.Add("sence", "1");
map.Add("reserved_sub_appid", "");
map.Add("reserved_limit_pay", "");
string result = run(map, FuiouPayConst.fuiouScanpPayUrl);
return result;
}
#endregion
private static string run(Dictionary<string, string> map, string url)
{
Dictionary<string, string> reqs = new Dictionary<string, string>();
Dictionary<string, string> nvs = new Dictionary<string, string>();
foreach (KeyValuePair<string, string> kvp in map)
{
reqs.Add(kvp.Key, kvp.Value);
}
string sign = FuYouPayUtils.getSign(reqs);
reqs.Remove("sign");
reqs.Add("sign", sign);
XmlDocument doc = new XmlDocument();
XmlElement elem = doc.CreateElement("xml");
doc.AppendChild(elem);
foreach (KeyValuePair<string, string> kvp in reqs)
{
XmlElement elem2 = doc.CreateElement(kvp.Key);
elem2.InnerText = kvp.Value;
elem.AppendChild(elem2);
}
string reqBody = "<?xml version=\"1.0\" encoding=\"GBK\" standalone=\"yes\"?>" + doc.OuterXml;
LogHelper.Info("请求报文:" + reqBody);
reqBody = FuYouPayUtils.UrlEncode(reqBody, Encoding.GetEncoding(FuiouPayConst.charset));
nvs.Add("req", reqBody);
StringBuilder result = new StringBuilder("");
Infrastructure.Utils.HttpUtils httpUtils = new HttpUtils();
httpUtils.post(url, nvs, result);
string data = HttpUtility.UrlDecode(result.ToString(), Encoding.GetEncoding(FuiouPayConst.charset));
LogHelper.Info("在线支付返回报文:" + data);
return data;
}
#region FuyouOnlinePay()
/// <summary>
/// 富友客户扫商家的二维码支付
/// </summary>
/// <param name="order"></param>
/// <param name="order_type">支付类型 ALIPAY , WECHAT, QQ(QQ 钱包), UNIONPAY(银联二维码) , BESTPAY(翼支付)</param>
/// <returns></returns>
public string FuiouOnlinePay(FuiouOrder order, string order_type)
{
Dictionary<string, string> map = new Dictionary<string, string>();
map.Add("order_type", order_type);
map.Add("goods_des", order.Body);
map.Add("reserved_expire_minute", "1440");
map.Add("addn_inf", order.Attach);
map.Add("mchnt_order_no", order.OutTradeNo);
map.Add("order_amt", order.Amount.ToString());
map.Add("version", "1.0");
map.Add("ins_cd", FuiouPayConst.ins_cd);
map.Add("mchnt_cd", order.OpUserId);
//map.Add("mchnt_cd", FuiouPayConst.mchnt_cd);
map.Add("term_id", FuiouPayConst.term_id);
map.Add("random_str", Guid.NewGuid().ToString("N"));
map.Add("sign", "");
map.Add("goods_detail", "");
map.Add("curr_type", "");
map.Add("term_ip", order.SpbillCreateIp);//FuiouPayConst.term_ip);
map.Add("txn_begin_ts", DateTime.Now.ToString("yyyyMMddhhmmss"));
map.Add("goods_tag", "");
map.Add("notify_url", FuiouPayConst.notify_url);
map.Add("reserved_sub_appid", "");
map.Add("reserved_limit_pay", "");
map.Add("reserved_terminal_info", order.DeviceInfo);
string result = run(map, FuiouPayConst.fuiouOnlinePayUrl);
XmlDocument doc = new XmlDocument();
doc.LoadXml(result);
string ifok = doc.SelectSingleNode("/xml/result_code").InnerText;
if (ifok == "000000")
result = doc.SelectSingleNode("/xml/qr_code").InnerText;
else
result = doc.SelectSingleNode("/xml/result_msg").InnerText;
return result;
}
#endregion
/// <summary>
/// 解析富友的XML字符串为可读文本
/// </summary>
/// <param name="res"></param>
/// <returns></returns>
public string GetXMLString(string res)
{
res = HttpUtility.UrlDecode(res, Encoding.GetEncoding(FuiouPayConst.charset));
return res;
}
#region FuyouWXOnlinePay( /)
/// <summary>
/// 富友 公众号/服务窗统一下单
/// </summary>
/// <param name="order"></param>
/// <param name="order_type">支付类型 ALIPAY , JSAPI, QQ(QQ 钱包), UNIONPAY(银联二维码) , BESTPAY(翼支付) LETPAY-小程序</param>
/// <param name="openid"></param>
/// <param name="appid"></param>
/// <returns></returns>
public string FuyouWXOnlinePay(Wolf.ExternalService.CMBPay.Barcodepay.Order order, string order_type, string openid, string appid)
{
Dictionary<string, string> map = new Dictionary<string, string>();
map.Add("version", "1.0");
map.Add("ins_cd", FuiouPayConst.ins_cd);
map.Add("mchnt_cd", order.OpUserId);
map.Add("term_id", FuiouPayConst.term_id);
map.Add("random_str", Guid.NewGuid().ToString("N"));
map.Add("sign", "");
map.Add("goods_des", order.Body);
map.Add("goods_detail", "");
map.Add("goods_tag", "");
map.Add("txn_begin_ts", DateTime.Now.ToString("yyyyMMddhhmmss"));
map.Add("notify_url", FuiouPayConst.notify_url);
map.Add("limit_pay", "");
if (order_type == "WECHAT")
order_type = "JSAPI";
else if (order_type == "ALIPAY")
order_type = "FWC";
else if (order_type == "LETPAY")
order_type = "LETPAY";
map.Add("trade_type", order_type);
map.Add("addn_inf", order.Attach);
map.Add("openid", "");
map.Add("product_id", "");
map.Add("sub_openid", openid);
map.Add("sub_appid", appid);
map.Add("reserved_expire_minute", "1440");
map.Add("mchnt_order_no", order.OutTradeNo);
map.Add("curr_type", "CNY");
map.Add("order_amt", order.Amount.ToString());
map.Add("term_ip", FuiouPayConst.term_ip);
string result = run(map, FuiouPayConst.fuiouOnlineWxPayUrl);
LogHelper.Info(result);
XmlDocument doc = new XmlDocument();
doc.LoadXml(result);
string ifok = doc.SelectSingleNode("/xml/result_code").InnerText;
if (ifok == "000000")
result = doc.SelectSingleNode("/xml/reserved_pay_info").InnerText;
else
result = doc.SelectSingleNode("/xml/result_msg").InnerText;
return result;
}
#endregion
#region FuyouOnlinePay()
/// <summary>
/// 富友主动查询订单支付状态
/// </summary>
/// <param name="mchnt_order_no">商户订单交易号</param>
/// <param name="order_type">支付类型 ALIPAY , WECHAT, QQ(QQ 钱包), UNIONPAY(银联二维码) , BESTPAY(翼支付)</param>
/// <returns></returns>
public string FuyouQueryPay(string mchnt_order_no, string order_type, string mchnt_cd = "0002900F0370588")
{
Dictionary<string, string> map = new Dictionary<string, string>();
map.Add("order_type", order_type);
map.Add("mchnt_order_no", mchnt_order_no);
map.Add("version", "1.0");
map.Add("ins_cd", FuiouPayConst.ins_cd);
map.Add("mchnt_cd", mchnt_cd);
map.Add("term_id", FuiouPayConst.term_id);
map.Add("random_str", Guid.NewGuid().ToString("N"));
map.Add("sign", "");
string result = run(map, FuiouPayConst.fuiou_23_url);
//XmlDocument doc = new XmlDocument();
//doc.LoadXml(result);
//string ifok = doc.SelectSingleNode("/xml/result_code").InnerText;
//if (ifok == "000000")
// result = doc.SelectSingleNode("/xml/trans_stat").InnerText;
//else
// result = doc.SelectSingleNode("/xml/result_msg").InnerText;
return result;
}
#endregion
#region FuYouReturnMoney(退)
/// <summary>
/// 富友退款申请
/// </summary>
public string FuYouReturnMoney(string OutTradeNo, string order_type, string refund_order_no
, decimal total_amt, decimal refund_amt, string mchnt_cd = "")
{
string total = (total_amt * 100).ToString("0");
string refund = (refund_amt * 100).ToString("0");
Dictionary<string, string> map = new Dictionary<string, string>();
map.Add("version", "1.0");
map.Add("ins_cd", FuiouPayConst.ins_cd);
map.Add("mchnt_cd", mchnt_cd);
map.Add("term_id", FuiouPayConst.term_id);
map.Add("random_str", Guid.NewGuid().ToString("N"));
map.Add("sign", "");
map.Add("order_type", order_type);
map.Add("mchnt_order_no", OutTradeNo);
map.Add("total_amt", total);
map.Add("operator_id", "");
map.Add("reserved_fy_term_id", "");
map.Add("refund_amt", refund);
map.Add("refund_order_no", refund_order_no);
string result = run(map, FuiouPayConst.fuiou_24_url);
result = GetXMLString(result);
//XmlDocument doc = new XmlDocument();
//doc.LoadXml(result);
//string ifok = doc.SelectSingleNode("/xml/result_code").InnerText;
//if (ifok == "000000")
// result = doc.SelectSingleNode("/xml/reserved_refund_amt").InnerText;
//else
// result = doc.SelectSingleNode("/xml/result_msg").InnerText;
return result;
}
#endregion
#region FuYouRefundQuery(退)
/// <summary>
/// 富友退款申请进度查询
/// </summary>
/// <param name="refund_order_no">商户退款单号</param>
/// <param name="mchnt_cd">商户号, 富友分配的商户号</param>
/// <returns></returns>
public string FuYouRefundQuery(string refund_order_no
, string mchnt_cd = "")
{
Dictionary<string, string> map = new Dictionary<string, string>();
map.Add("version", "1.0");
map.Add("ins_cd", FuiouPayConst.ins_cd);
map.Add("mchnt_cd", mchnt_cd);
map.Add("term_id", FuiouPayConst.term_id);
map.Add("refund_order_no", refund_order_no);
map.Add("random_str", Guid.NewGuid().ToString("N"));
map.Add("sign", "");
string result = run(map, FuiouPayConst.fuiou_30_url);
result = GetXMLString(result);
//XmlDocument doc = new XmlDocument();
//doc.LoadXml(result);
//string ifok = doc.SelectSingleNode("/xml/result_code").InnerText;
//if (ifok == "000000")
// result = doc.SelectSingleNode("/xml/reserved_refund_amt").InnerText;
//else
// result = doc.SelectSingleNode("/xml/result_msg").InnerText;
return result;
}
#endregion
}
}