发布:2023/3/28 20:25:55作者:管理员 来源:本站 浏览次数:679
支付链接获取
//隐藏代码:获取一个订单model实体,并判断此订单是否发起过支付链接吊起,如发起过且链接没过期,则直接返回支付链接(仅限微信)
if (//隐藏代码:判断是否为待付款)
{
switch (dto.PayType)
{
case //阿里:
return new DtoView.PostCreatePayOrder() { Url = _aliPay_H5.GetPayForm(model.TotalPrice, model.OrderNumber, "商城订单"), HandlerUrl = "" };
case //微信:
if (string.IsNullOrEmpty(model.WXPayUrl) || (model.WXPayUrlCreateTime!=null && DateTime.Now.Subtract(model.WXPayUrlCreateTime.Value).TotalMinutes>=5)) {
List<string> urlList = _wxPay_H5.UnifiedorderH5Async(model.TotalPrice, model.OrderNumber,ip, "商城订单").Result;
if (urlList == null || urlList.Count != 2) {
throw new Ex.ParameterException("微信支付链接生成错误");
}
//隐藏代码:更新订单实体中的支付状态和支付链接,下一次吊起支付可以用这次的支付链接,不必重复获取
}
return new DtoView.PostCreatePayOrder() { Url = model.WXPayUrl,HandlerUrl= model.WXPayHandlerUrl };
default:
throw new Ex.ParameterException("支付平台类型参数错误");
}
}
throw new Ex.ParameterException("订单信息错误或已支付");
支付宝支付退款公共方法
using Alipay.AopSdk.Core;
using Alipay.AopSdk.Core.Domain;
using Alipay.AopSdk.Core.Request;
using Alipay.AopSdk.Core.Response;
using Alipay.AopSdk.Core.Util;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Text;
namespace Test.Application.Common.AliPay
{
public class AliPay_H5
{
private readonly AliPay.AliOption _aliOption;
public AliPay_H5(IOptions<AliPay.AliOption> aliOption)
{
_aliOption = aliOption.Value;
}
/// <summary>
/// 获取支付宝H5支付表单
/// </summary>
/// <param name="totalfee"></param>
/// <param name="orderNo"></param>
/// <param name="description"></param>
/// <returns></returns>
public string GetPayForm(decimal totalfee, string orderNo, string description) {
DefaultAopClient client = new DefaultAopClient(_aliOption.Ali_GatewayUrl, _aliOption.Ali_AppID, _aliOption.Ali_PrivateKey, "json", "1.0", "RSA2", _aliOption.Ali_PublicKey, "UTF-8", false);
// 组装业务参数model
AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
model.Body = description;
model.Subject = "收款方";
model.TotalAmount = totalfee.ToString();
model.OutTradeNo = orderNo;
model.ProductCode = "QUICK_WAP_WAY";
model.QuitUrl = _aliOption.Ali_QuitUrl;
AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
// 设置支付完成同步回调地址
request.SetReturnUrl(_aliOption.Ali_ReturnUrl);
// 设置支付完成异步通知接收地址
request.SetNotifyUrl(_aliOption.Ali_NOTIFY_URL);
// 将业务model载入到request
request.SetBizModel(model);
AlipayTradeWapPayResponse response = null;
response = client.PageExecute(request, null, "post");
LogHelper.Info("支付宝获取支付订单返回:" + response.Body);
return response.Body;
}
/// <summary>
/// 验证回调数据
/// </summary>
/// <param name="sArray"></param>
/// <returns></returns>
public bool ValidationPayNotify(Dictionary<string, string> sArray) {
bool checkR= AlipaySignature.RSACheckV1(sArray, _aliOption.Ali_PublicKey, "UTF-8", "RSA2", false);
return checkR;
}
/// <summary>
/// 支付宝退款
/// </summary>
/// <param name="orderNo"></param>
/// <param name="refundNo"></param>
/// <param name="refund"></param>
/// <param name="total"></param>
/// <param name="reason"></param>
/// <returns></returns>
public string Refund(string orderNo, string refundNo, decimal refund, decimal total, string reason) {
DefaultAopClient client = new DefaultAopClient(_aliOption.Ali_GatewayUrl, _aliOption.Ali_AppID, _aliOption.Ali_PrivateKey, "json", "1.0", "RSA2", _aliOption.Ali_PublicKey, "UTF-8", false);
AlipayTradeRefundModel model = new AlipayTradeRefundModel();
model.OutTradeNo = orderNo;
model.TradeNo = "";
model.RefundAmount = refund.ToString();
model.RefundReason = reason;
model.OutRequestNo = refundNo;
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
request.SetBizModel(model);
AlipayTradeRefundResponse response = null;
response = client.Execute(request);
LogHelper.Info("支付宝订单退款返回:" + response.Body);
return response.Body;
}
public void CloseOrder(string orderNo) {
DefaultAopClient client = new DefaultAopClient(_aliOption.Ali_GatewayUrl, _aliOption.Ali_AppID, _aliOption.Ali_PrivateKey, "json", "1.0", "RSA2", _aliOption.Ali_PublicKey, "UTF-8", false);
AlipayTradeCloseModel model = new AlipayTradeCloseModel();
model.OutTradeNo = orderNo;
model.TradeNo = "";
AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
request.SetBizModel(model);
AlipayTradeCloseResponse response = null;
response = client.Execute(request);
LogHelper.Info("支付宝关闭订单返回:" + response.Body);
}
}
}
public class AliOption : IOptions<AliOption>
{
AliOption IOptions<AliOption>.Value => this;
public string Ali_AppID { get; set; }
public string Ali_GatewayUrl { get; set; }
public string Ali_PrivateKey { get; set; }
public string Ali_PublicKey { get; set; }
public string Ali_NOTIFY_URL { get; set; }
public string Ali_REFUNDNOTIFY_URL { get; set; }
public string Ali_QuitUrl { get; set; }
public string Ali_ReturnUrl { get; set; }
}
微信支付退款公共方法
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Options;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace Test.Application.Common.WxPay
{
public class WxPay_H5
{
private HttpClient _client { get; }
private readonly WxPay.WeiXinOption _weiXinOption;
private readonly IWebHostEnvironment _webHostEnvironment;
private readonly string BaseAddress = "https://api.mch.weixin.qq.com";
public WxPay_H5(HttpClient client, IOptions<WxPay.WeiXinOption> weChatOptions, IWebHostEnvironment webHostEnvironment)
{
// GitHub API versioning
client.DefaultRequestHeaders.Add("Accept",
"application/json");
// GitHub requires a user-agent
client.DefaultRequestHeaders.Add("User-Agent",
"HttpClientFactory-Sample");
_client = client;
_weiXinOption = weChatOptions.Value;
_webHostEnvironment = webHostEnvironment;
}
/// <summary>
/// H5下单
/// </summary>
/// <param name="totalfee">支付金额,单位:分</param>
/// <param name="orderNo">订单号</param>
/// <param name="description">商品描述</param>
/// <returns></returns>
public async Task<List<string>> UnifiedorderH5Async(decimal totalfee, string orderNo, string description, string ip)
{
H5Pay h5Pay = new H5Pay() { appid = _weiXinOption.WX_AppID, mchid = _weiXinOption.WX_mch_ID, description = description, out_trade_no = orderNo, notify_url = _weiXinOption.WX_NOTIFY_URL, amount = new Amount { total = (int)(totalfee * 100) }, scene_info = new Scene_Info { payer_client_ip = ip, h5_info = new H5_Info { type = "Wap" } } };
var param = Newtonsoft.Json.JsonConvert.SerializeObject(h5Pay);
var json = await Post(param, "/v3/pay/transactions/h5");
LogHelper.Info("微信支付创建订单微信返回:" + json);
if (json.Contains("h5_url"))
json = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(json)["h5_url"];
return await GetHandleUrl(json);
}
/// <summary>
/// H5查询订单
/// </summary>
/// <param name="out_trade_no"></param>
/// <returns></returns>
public async Task<string> GetOrderH5Async(string out_trade_no)
{
var json = await Get($"/v3/pay/transactions/out-trade-no/{out_trade_no}?mchid=" + _weiXinOption.WX_mch_ID);
return json;
}
/// <summary>
/// H5关闭订单
/// </summary>
/// <returns></returns>
public async Task CloseOrderH5Async(string orderNo)
{
H5PayClose h5PayClose = new H5PayClose() { mchid = _weiXinOption.WX_mch_ID };
var param = Newtonsoft.Json.JsonConvert.SerializeObject(h5PayClose);
await Post(param, $"/v3/pay/transactions/out-trade-no/{orderNo}/close");
}
/// <summary>
/// H5订单退款
/// </summary>
/// <param name="orderNo"></param>
/// <param name="refundNo"></param>
/// <param name="refund"></param>
/// <param name="total"></param>
/// <param name="reason"></param>
/// <returns></returns>
public async Task<string> RefundH5Async(string orderNo, string refundNo, decimal refund, decimal total, string reason)
{
H5PayRefund h5PayRefund = new H5PayRefund() { out_trade_no = orderNo, out_refund_no = refundNo, notify_url = _weiXinOption.WX_REFUNDNOTIFY_URL, amount = new RefundAmount { total = (int)(total * 100), refund = (int)(refund * 100), currency = "CNY" } };
var param = Newtonsoft.Json.JsonConvert.SerializeObject(h5PayRefund);
LogHelper.Info("微信订单退款参数:" + param);
var json = await Post(param, "/v3/refund/domestic/refunds");
LogHelper.Info("微信订单退款返回:" + json);
if (json.Contains("status"))
json = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(json)["status"];
return json;
}
public class H5Pay
{
public string mchid { get; set; }
public string out_trade_no { get; set; }
public string appid { get; set; }
public string description { get; set; }
public string notify_url { get; set; }
public Amount amount { get; set; }
public Scene_Info scene_info { get; set; }
}
public class H5PayClose
{
public string mchid { get; set; }
}
#region 退款
public class H5PayRefund
{
/// <summary>
/// 商户订单号
/// </summary>
public string out_trade_no { get; set; }
/// <summary>
/// 商户退款单号
/// </summary>
public string out_refund_no { get; set; }
/// <summary>
/// 退款原因(非必填)
/// </summary>
//public string reason { get; set; }
/// <summary>
/// 退款结果回调url (非必填)
/// </summary>
public string notify_url { get; set; }
/// <summary>
/// 退款金额
/// </summary>
public RefundAmount amount { get; set; }
}
/// <summary>
/// 退款金额
/// </summary>
public class RefundAmount
{
/// <summary>
/// refund
/// </summary>
public int refund { get; set; }
/// <summary>
/// 原订单金额
/// </summary>
public int total { get; set; }
/// <summary>
/// 退款币种(CNY)
/// </summary>
public string currency { get; set; }
}
/// <summary>
/// 指定商品
/// </summary>
public class GoodsDetailListObj
{
/// <summary>
/// 商户侧商品编码
/// </summary>
public string merchant_goods_id { get; set; }
/// <summary>
/// 微信侧商品编码(非必填)
/// </summary>
public string wechatpay_goods_id { get; set; }
/// <summary>
/// 商品名称(非必填)
/// </summary>
public string goods_name { get; set; }
/// <summary>
/// 商品单价
/// </summary>
public int unit_price { get; set; }
/// <summary>
/// 商品退款金额
/// </summary>
public int refund_amount { get; set; }
/// <summary>
/// 商品退货数量
/// </summary>
public int refund_quantity { get; set; }
}
#endregion
public class Amount
{
public int total { get; set; }
public string currency { get; set; } = "CNY";
}
public class Scene_Info
{
public string payer_client_ip { get; set; }
public H5_Info h5_info { get; set; }
}
public class H5_Info
{
public string type { get; set; }
}
public async Task<string> Post(string jsonData, string url)
{
CreateSign("POST", url, jsonData);
var postData = new StringContent(jsonData, Encoding.UTF8, "application/json");
var response = await _client.PostAsync(BaseAddress + url, postData);
LogHelper.Info("微信请求结果:" + response);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
public async Task<string> Get(string url)
{
CreateSign("GET", url, "");
var response = await _client.GetAsync(BaseAddress + url);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
/// <summary>
/// 创建签名
/// </summary>
/// <param name="method"></param>
/// <param name="uri"></param>
/// <param name="body"></param>
private void CreateSign(string method, string uri, string body)
{
string nonce_str = Guid.NewGuid().ToString();
string timestamp = (Tools.UnicodeConvert.ConvertDateTimeInt(DateTime.Now) + "").Substring(0, 10);
string message = $"{method}\n{uri}\n{timestamp}\n{nonce_str}\n{body}\n";
string signature = Tools.CertificateHelper.Sign(message, _webHostEnvironment.ContentRootPath + "\\" + _weiXinOption.WX_Certificate, _weiXinOption.WX_mch_ID);
_client.DefaultRequestHeaders.Add("Authorization", $"WECHATPAY2-SHA256-RSA2048 mchid=\"{_weiXinOption.WX_mch_ID}\",serial_no=\"{_weiXinOption.WX_Serial_No}\",nonce_str=\"{nonce_str}\",timestamp=\"{timestamp}\",signature=\"{signature}\"");
}
/// <summary>
/// 获取解密后的数据
/// </summary>
/// <param name="associatedData"></param>
/// <param name="nonce"></param>
/// <param name="ciphertext"></param>
/// <returns></returns>
public string AesGcmDecrypt(string associatedData, string nonce, string ciphertext)
{
GcmBlockCipher gcmBlockCipher = new GcmBlockCipher(new AesEngine());
AeadParameters aeadParameters = new AeadParameters(
new KeyParameter(Encoding.UTF8.GetBytes(_weiXinOption.WX_AppSecret)),
128,
Encoding.UTF8.GetBytes(nonce),
Encoding.UTF8.GetBytes(associatedData));
gcmBlockCipher.Init(false, aeadParameters);
byte[] data = Convert.FromBase64String(ciphertext);
byte[] plaintext = new byte[gcmBlockCipher.GetOutputSize(data.Length)];
int length = gcmBlockCipher.ProcessBytes(data, 0, data.Length, plaintext, 0);
gcmBlockCipher.DoFinal(plaintext, length);
return Encoding.UTF8.GetString(plaintext);
}
/// <summary>
/// 获取处理后的支付链接(不获取安卓程序内置浏览器吊起错误)
/// </summary>
/// <param name="oldUrl"></param>
/// <returns></returns>
public async Task<List<string>> GetHandleUrl(string oldUrl) {
List<string> urlList = new List<string>();
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("Host", "wx.tenpay.com");
httpClient.DefaultRequestHeaders.Add("Accept-Language", "en, zh-CN; q=0.8,zh; q=0.6,en-US; q=0.4");
httpClient.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml");
httpClient.DefaultRequestHeaders.Add("Upgrade-Insecure-Requests", "1");
string[] urls = _weiXinOption.WX_NOTIFY_URL.Split('/');
httpClient.DefaultRequestHeaders.Add("Referer", "http://" + urls[2] + "/");
var response = await httpClient.GetAsync(oldUrl);
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
string pattern = "\"weixin(.*?)\"";
Regex regex = new Regex(pattern);
Match matcher = regex.Match(json);
if (matcher.Success) {
if (matcher.Groups.Count > 0) {
urlList.Add(oldUrl);
urlList.Add(matcher.Groups[0].Value.Substring(1, matcher.Groups[0].Value.Length - 2));
}
}
return urlList;
}
}
}
public class WeiXinOption: IOptions<WeiXinOption>
{
WeiXinOption IOptions<WeiXinOption>.Value => this;
public string WX_AppID { get; set; }
public string WX_AppSecret { get; set; }
public string WX_mch_ID { get; set; }
public string WX_IP { get; set; }
public string WX_NOTIFY_URL { get; set; }
public string WX_REFUNDNOTIFY_URL { get; set; }
public string WX_Certificate { get; set; }
public string WX_Serial_No { get; set; }
}
支付宝支付回调
/// <summary>
/// 支付宝支付完成回调(后台用)
/// </summary>
public dynamic CallBack()
{
var coll = Request.Form;
List<string> requestItem = coll.Keys.ToList();
Dictionary<string, string> sArray = new Dictionary<string, string>();
foreach (var item in requestItem)
{
sArray.Add(item, Request.Form[item]);
}
string strr = "";
foreach (var item in sArray)
{
strr +="Key="+ item.Key + ";Value=" + item.Value + ";";
}
if (_aliPay_H5.ValidationPayNotify(sArray)){
string RechargeTime = sArray.GetValueOrDefault("gmt_payment");
string RechargeMoney = sArray.GetValueOrDefault("total_amount");
string RechargeNo = sArray.GetValueOrDefault("out_trade_no");
decimal price = decimal.Zero;
if (!decimal.TryParse(RechargeMoney, out price))
{
//支付宝支付回调失败
return new
{
code = "ERROR",
message = Common.Enums.StateEnum.ShopPayNoticeState.PriceChangeError.GetDescription()
};
}
int payType = (int)Common.Enums.TypeEnum.ShopOrderPayType.Ali;
DateTime payTime = DateTime.Now;
if (RechargeTime.Contains("T"))
{
RechargeTime = RechargeTime.Replace('T', ' ');
if (!DateTime.TryParse(RechargeTime, out payTime))
{
//支付宝支付回调失败
return new
{
code = "ERROR",
message = Common.Enums.StateEnum.ShopPayNoticeState.TimeChangeError.GetDescription()
};
}
}
return TestCB(RechargeNo, "", price, payType, payTime);
}
return "验证失败";
}
///<summary>
///支付宝微信支付完成回调通用业务处理方法
///</summary>
private dynamic TestCB(string orderNumber, string TransactionId, decimal price, int payType,DateTime payTime) {
//隐藏代码:用orderNumber获取订单实体并判断price数据是否正确
if (payType == (int)Common.Enums.TypeEnum.ShopOrderPayType.Ali)
{
return "success";
}
else {
return new
{
code = "SUCCESS",
message = ""
};
}
}
微信支付退款回调
/// <summary>
/// 微信支付完成回调(后台用)
/// </summary>
public dynamic PayCB()
{
#region
var syncIOFeature = HttpContext.Features.Get<IHttpBodyControlFeature>();
if (syncIOFeature != null)
{
syncIOFeature.AllowSynchronousIO = true;
}
#endregion
System.IO.Stream s = HttpContext.Request.Body;
int count = 0;
byte[] buffer = new byte[1024];
StringBuilder builder = new StringBuilder();
while ((count = s.Read(buffer, 0, 1024)) > 0)
{
builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
}
s.Flush();
s.Close();
s.Dispose();
string notDeStr = builder;
JObject notDeObj = JObject.Parse(notDeStr);
string ciphertext = notDeObj["resource"]["ciphertext"].ToString();
string associatedData = notDeObj["resource"]["associated_data"].ToString();
string nonce = notDeObj["resource"]["nonce"].ToString();
string deData = _wxPay_H5.AesGcmDecrypt(associatedData,nonce, ciphertext);
JObject deObj = JObject.Parse(deData);
string RechargeMoney = deObj["amount"]["payer_total"].ToString();
string RechargeTime = deObj["success_time"].ToString();
string RechargeNo = deObj["out_trade_no"].ToString();
string TransactionId = deObj["transaction_id"].ToString();
decimal price = decimal.Zero;
if (decimal.TryParse(RechargeMoney, out price))
{
price = price / 100;
}
else
{
//微信支付回调失败转换金额失败
return new
{
code = "ERROR",
message = Common.Enums.StateEnum.ShopPayNoticeState.PriceChangeError.GetDescription()
};
}
int payType = (int)Common.Enums.TypeEnum.ShopOrderPayType.WX;
DateTime payTime = DateTime.Now;
if (RechargeTime.Contains("T"))
{
RechargeTime = RechargeTime.Replace('T', ' ');
if (!DateTime.TryParse(RechargeTime, out payTime))
{
//微信支付回调失败-转换时间失败
return new
{
code = "ERROR",
message = Common.Enums.StateEnum.ShopPayNoticeState.TimeChangeError.GetDescription()
};
}
}
return TestCB(RechargeNo, TransactionId, price, payType, payTime);
}
/// <summary>
/// 微信退款回调(后台用)
/// </summary>
public dynamic TKCB()
{
//获取回调POST过来的xml数据的代码
#region
//.net core 3.0以后需加下边这段,否则Stream会报错
var syncIOFeature = HttpContext.Features.Get<IHttpBodyControlFeature>();
if (syncIOFeature != null)
{
syncIOFeature.AllowSynchronousIO = true;
}
#endregion
//接收从微信后台POST过来的数据
System.IO.Stream s = HttpContext.Request.Body;
int count = 0;
byte[] buffer = new byte[1024];
StringBuilder builder = new StringBuilder();
while ((count = s.Read(buffer, 0, 1024)) > 0)
{
builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
}
s.Flush();
s.Close();
s.Dispose();
string notDeStr = builder;
JObject notDeObj = JObject.Parse(notDeStr);
string ciphertext = notDeObj["resource"]["ciphertext"].ToString();
string associatedData = notDeObj["resource"]["associated_data"].ToString();
string nonce = notDeObj["resource"]["nonce"].ToString();
string deData = _wxPay_H5.AesGcmDecrypt(associatedData, nonce, ciphertext);
JObject deObj = JObject.Parse(deData);
string RefundTime = deObj["success_time"].ToString();
string OrderNumber = deObj["out_trade_no"].ToString();
string RefundNo = deObj["out_refund_no"].ToString();
int payType = (int)Common.Enums.TypeEnum.ShopOrderPayType.WX;
DateTime refundTime = DateTime.Now;
if (RefundTime.Contains("T"))
{
RefundTime = RefundTime.Replace('T', ' ');
if (!DateTime.TryParse(RefundTime, out refundTime))
{
//微信支付回调失败-订单号:" + OrderNumber + ",错误类型:转换时间失败" + RefundTime
return new
{
code = "ERROR",
message = Common.Enums.StateEnum.ShopRefundNoticeState.TimeChangeError.GetDescription()
};
}
}
//隐藏业务代码,判断参数是否正确,订单是否正确
return new
{
code = "SUCCESS",
message = ""
};
}
© Copyright 2014 - 2024 柏港建站平台 ejk5.com. 渝ICP备16000791号-4