Merge branch 'main' of http://101.43.53.74:3000/Admin.NET/Admin.NET.Pro
This commit is contained in:
commit
46d81dd0a7
@ -11,8 +11,21 @@ namespace Admin.NET.Core;
|
||||
/// </summary>
|
||||
[SugarTable(null, "系统微信支付表")]
|
||||
[SysTable]
|
||||
[SugarIndex("sys_wechat_pay_order_id", nameof(OrderId), OrderByType.Desc)]
|
||||
public partial class SysWechatPay : EntityBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 关联的商户订单号
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "OrderId")]
|
||||
public virtual long OrderId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关联的商户订单状态(或者为第几次支付,有些订单涉及多次支付,比如先付预付款,后补尾款)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "OrderStatus")]
|
||||
public virtual int OrderStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 微信商户号
|
||||
/// </summary>
|
||||
@ -154,7 +167,7 @@ public partial class SysWechatPay : EntityBase
|
||||
/// <summary>
|
||||
/// 子商户AppId
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "回调通知地址")]
|
||||
[SugarColumn(ColumnDescription = "子商户AppId")]
|
||||
public string? SubAppId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
121
Admin.NET/Admin.NET.Core/Entity/SysWechatRefund.cs
Normal file
121
Admin.NET/Admin.NET.Core/Entity/SysWechatRefund.cs
Normal file
@ -0,0 +1,121 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 微信退款表
|
||||
/// </summary>
|
||||
[SugarTable(null, "系统微信退款表")]
|
||||
[SysTable]
|
||||
[SugarIndex("sys_wechat_refund_order_id", nameof(OrderId), OrderByType.Desc)]
|
||||
public class SysWechatRefund : EntityBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 微信支付订单号(原支付交易对应的微信订单号)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "微信支付订单号", Length = 32)]
|
||||
[Required]
|
||||
public string TransactionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商户订单号(原交易对应的商户付款单号)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "商户付款单号", Length = 32)]
|
||||
[Required]
|
||||
public string OutTradeNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商户系统内部的退款单号,商户系统内部唯一,只能是数字、大小写字母_-|*@ ,同一退款单号多次请求只退一笔。
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "商户退款单号", Length = 64)]
|
||||
[Required]
|
||||
public string OutRefundNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 退款原因,示例:商品已售完
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "退款原因", Length = 80)]
|
||||
public string Reason { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 退款金额
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "退款金额")]
|
||||
public int Refund { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 原订单总金额
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "订单总金额")]
|
||||
public int Total { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 退款结果回调url
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "退款结果回调url", Length = 256)]
|
||||
public string? NotifyUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 退款资金来源, 可不传,默认使用未结算资金退款(仅对老资金流商户适用)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "退款资金来源", Length = 32)]
|
||||
public string FundsAccount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关联的商户订单号
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "关联的用户订单号")]
|
||||
public long OrderId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关联的商户订单状态(或者为第几次支付,有些订单涉及多次支付,比如先付预付款,后补尾款)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "关联的商户订单状态")]
|
||||
public int OrderStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关联的商户商品编码
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "关联的商户商品编码", Length = 32)]
|
||||
public string MerchantGoodsId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关联的商户商品名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "关联的商户商品名称", Length = 256)]
|
||||
public string GoodsName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关联的商户商品单价
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "关联的商户商品单价")]
|
||||
public int UnitPrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关联的商户商品退款金额
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "关联的商户商品退款金额")]
|
||||
public int RefundAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关联的商户商品退货数量
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "关联的商户商品退货数量")]
|
||||
public int RefundQuantity { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 附加数据
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "附加数据")]
|
||||
public string? Attachment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "备注")]
|
||||
public string? Remark { get; set; }
|
||||
}
|
||||
@ -32,6 +32,16 @@ public class WechatPayTransactionInput
|
||||
/// 优惠标记
|
||||
/// </summary>
|
||||
public string GoodsTag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关联的商户订单号
|
||||
/// </summary>
|
||||
public long OrderId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关联的商户订单付款状态(或者为第几次支付,有些订单涉及多次支付,比如先付预付款,后补尾款)
|
||||
/// </summary>
|
||||
public int OrderStatus { get; set; } = 0;
|
||||
}
|
||||
|
||||
public class WechatPayParaInput
|
||||
@ -40,4 +50,95 @@ public class WechatPayParaInput
|
||||
/// 订单Id
|
||||
/// </summary>
|
||||
public string PrepayId { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class RefundRequestInput // : WechatTenpayRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// 商户订单号(原支付交易对应的付款单号)
|
||||
/// </summary>
|
||||
public string OutTradeNumber { get; set; }
|
||||
///// <summary>
|
||||
///// 退款单号
|
||||
///// </summary>
|
||||
//public string OutRefundNumber { get; set; }
|
||||
/// <summary>
|
||||
/// 原订单金额(分)
|
||||
/// </summary>
|
||||
public int Total { get; set; }
|
||||
/// <summary>
|
||||
/// 退款金额(分)
|
||||
/// </summary>
|
||||
public int Refund { get; set; }
|
||||
/// <summary>
|
||||
/// 退款原因
|
||||
/// </summary>
|
||||
public string Reason { get; set; }
|
||||
/// <summary>
|
||||
/// 关联的商户订单号
|
||||
/// </summary>
|
||||
public long OrderId { get; set; }
|
||||
/// <summary>
|
||||
/// 关联的商户订单状态(或者为第几次支付,有些订单涉及多次支付,比如先付预付款,后补尾款)
|
||||
/// </summary>
|
||||
public int OrderStatus { get; set; }
|
||||
/// <summary>
|
||||
/// 关联的商户商品编码
|
||||
/// </summary>
|
||||
public string MerchantGoodsId { get; set; }
|
||||
/// <summary>
|
||||
/// 关联的商户商品名称
|
||||
/// </summary>
|
||||
public string GoodsName { get; set; }
|
||||
/// <summary>
|
||||
/// 关联的商户商品单价
|
||||
/// </summary>
|
||||
public int UnitPrice { get; set; } = 0;
|
||||
/// <summary>
|
||||
/// 关联的商户商品退款金额
|
||||
/// </summary>
|
||||
public int RefundAmount { get; set; } = 0;
|
||||
/// <summary>
|
||||
/// 关联的商户商品退货数量
|
||||
/// </summary>
|
||||
public int RefundQuantity { get; set; } = 1;
|
||||
/// <summary>
|
||||
/// 附加数据
|
||||
/// </summary>
|
||||
public string Attachment { get; set; }
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string Remark { get; set; }
|
||||
}
|
||||
|
||||
public class PageSysWechatPayInput : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// order_id
|
||||
/// </summary>
|
||||
/// <example></example>
|
||||
public long? OrderId { get; set; } = -1;
|
||||
/// <summary>
|
||||
/// order_status
|
||||
/// </summary>
|
||||
/// <example></example>
|
||||
public long? OrderStatus { get; set; } = -1;
|
||||
|
||||
/// <summary>
|
||||
/// out_trade_number
|
||||
/// </summary>
|
||||
/// <example></example>
|
||||
public string OutTradeNumber { get; set; }
|
||||
/// <summary>
|
||||
/// success_time范围
|
||||
/// </summary>
|
||||
/// <example></example>
|
||||
public List<DateTime?> SuccessTimeRange { get; set; }
|
||||
/// <summary>
|
||||
/// expire_time范围
|
||||
/// </summary>
|
||||
/// <example></example>
|
||||
public List<DateTime?> ExpireTimeRange { get; set; }
|
||||
}
|
||||
@ -12,19 +12,51 @@ public class WechatPayOutput
|
||||
/// OpenId
|
||||
/// </summary>
|
||||
public string OpenId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商户(支付交易)单号,微信唯一
|
||||
/// </summary>
|
||||
public string OutTradeNumber { get; set; }
|
||||
/// <summary>
|
||||
/// 关联的商户(商品交易)订单号
|
||||
/// </summary>
|
||||
public long OrderId { get; set; }
|
||||
/// <summary>
|
||||
/// 关联的商户订单状态(或者为第几次支付,有些订单涉及多次支付,比如先付预付款,后补尾款)
|
||||
/// </summary>
|
||||
public int OrderStatus { get; set; }
|
||||
/// <summary>
|
||||
/// 订单金额
|
||||
/// </summary>
|
||||
public int Total { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 附加数据
|
||||
/// </summary>
|
||||
public string Attachment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 优惠标记
|
||||
/// </summary>
|
||||
public string GoodsTag { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 支付发起时间
|
||||
/// </summary>
|
||||
public DateTimeOffset CreateTime { get; set; }
|
||||
/// <summary>
|
||||
/// 支付完成时间
|
||||
/// </summary>
|
||||
public DateTimeOffset SuccessTime { get; set; }
|
||||
/// <summary>
|
||||
/// 交易状态(支付成功后,微信返回)
|
||||
/// </summary>
|
||||
public string? TradeState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易状态描述(支付成功后,微信返回)
|
||||
/// </summary>
|
||||
public string? TradeStateDescription { get; set; }
|
||||
}
|
||||
|
||||
public class CreatePayTransactionOutput
|
||||
{
|
||||
public string PrepayId { get; set; }
|
||||
public string OutTradeNumber { get; set; }
|
||||
}
|
||||
|
||||
@ -12,18 +12,20 @@ namespace Admin.NET.Core.Service;
|
||||
[ApiDescriptionSettings(Order = 210)]
|
||||
public class SysWechatPayService : IDynamicApiController, ITransient
|
||||
{
|
||||
private readonly SqlSugarRepository<SysWechatPay> _sysWechatPayUserRep;
|
||||
|
||||
private readonly SqlSugarRepository<SysWechatPay> _sysWechatPayRep;
|
||||
private readonly SqlSugarRepository<SysWechatRefund> _sysWechatRefundRep;
|
||||
private readonly WechatPayOptions _wechatPayOptions;
|
||||
private readonly PayCallBackOptions _payCallBackOptions;
|
||||
|
||||
private readonly WechatTenpayClient _wechatTenpayClient;
|
||||
|
||||
public SysWechatPayService(SqlSugarRepository<SysWechatPay> sysWechatPayUserRep,
|
||||
IOptions<WechatPayOptions> wechatPayOptions,
|
||||
IOptions<PayCallBackOptions> payCallBackOptions)
|
||||
public SysWechatPayService(SqlSugarRepository<SysWechatPay> sysWechatPayRep
|
||||
, SqlSugarRepository<SysWechatRefund> sysWechatRefundRep
|
||||
, IOptions<WechatPayOptions> wechatPayOptions
|
||||
, IOptions<PayCallBackOptions> payCallBackOptions)
|
||||
{
|
||||
_sysWechatPayUserRep = sysWechatPayUserRep;
|
||||
_sysWechatPayRep = sysWechatPayRep;
|
||||
this._sysWechatRefundRep = sysWechatRefundRep;
|
||||
_wechatPayOptions = wechatPayOptions.Value;
|
||||
_payCallBackOptions = payCallBackOptions.Value;
|
||||
|
||||
@ -64,11 +66,20 @@ public class SysWechatPayService : IDynamicApiController, ITransient
|
||||
/// 微信支付统一下单获取Id(商户直连) 🔖
|
||||
/// </summary>
|
||||
[DisplayName("微信支付统一下单获取Id(商户直连)")]
|
||||
public async Task<dynamic> CreatePayTransaction([FromBody] WechatPayTransactionInput input)
|
||||
public async Task<CreatePayTransactionOutput> CreatePayTransaction([FromBody] WechatPayTransactionInput input)
|
||||
{
|
||||
string outTradeNumber = DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next(100, 1000); // 微信需要的订单号(唯一)
|
||||
|
||||
//检查订单信息是否已存在(使用“商户交易单号+状态”唯一性判断)
|
||||
var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OrderId == input.OrderId && u.OrderStatus == input.OrderStatus);
|
||||
if (wechatPay != null)
|
||||
{
|
||||
outTradeNumber = wechatPay.OutTradeNumber;
|
||||
}
|
||||
|
||||
var request = new CreatePayTransactionJsapiRequest()
|
||||
{
|
||||
OutTradeNumber = DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next(100, 1000), // 订单号
|
||||
OutTradeNumber = outTradeNumber,
|
||||
AppId = _wechatPayOptions.AppId,
|
||||
Description = input.Description,
|
||||
Attachment = input.Attachment,
|
||||
@ -80,27 +91,32 @@ public class SysWechatPayService : IDynamicApiController, ITransient
|
||||
};
|
||||
var response = await _wechatTenpayClient.ExecuteCreatePayTransactionJsapiAsync(request);
|
||||
if (!response.IsSuccessful())
|
||||
throw Oops.Oh(response.ErrorMessage);
|
||||
throw Oops.Oh<Exception>(response.ErrorMessage);
|
||||
|
||||
// 保存订单信息
|
||||
var wechatPay = new SysWechatPay()
|
||||
if (wechatPay == null)
|
||||
{
|
||||
AppId = _wechatPayOptions.AppId,
|
||||
MerchantId = _wechatPayOptions.MerchantId,
|
||||
OutTradeNumber = request.OutTradeNumber,
|
||||
Description = input.Description,
|
||||
Attachment = input.Attachment,
|
||||
GoodsTag = input.GoodsTag,
|
||||
Total = input.Total,
|
||||
OpenId = input.OpenId,
|
||||
TransactionId = ""
|
||||
};
|
||||
await _sysWechatPayUserRep.InsertAsync(wechatPay);
|
||||
// 保存订单信息
|
||||
wechatPay = new SysWechatPay()
|
||||
{
|
||||
AppId = _wechatPayOptions.AppId,
|
||||
MerchantId = _wechatPayOptions.MerchantId,
|
||||
OutTradeNumber = request.OutTradeNumber,
|
||||
Description = input.Description,
|
||||
Attachment = input.Attachment,
|
||||
GoodsTag = input.GoodsTag,
|
||||
Total = input.Total,
|
||||
OpenId = input.OpenId,
|
||||
TransactionId = "",
|
||||
OrderId = input.OrderId,
|
||||
OrderStatus = input.OrderStatus
|
||||
};
|
||||
await _sysWechatPayRep.InsertAsync(wechatPay);
|
||||
}
|
||||
|
||||
return new
|
||||
return new CreatePayTransactionOutput
|
||||
{
|
||||
response.PrepayId,
|
||||
request.OutTradeNumber
|
||||
PrepayId = response.PrepayId,
|
||||
OutTradeNumber = request.OutTradeNumber
|
||||
};
|
||||
}
|
||||
|
||||
@ -108,11 +124,20 @@ public class SysWechatPayService : IDynamicApiController, ITransient
|
||||
/// 微信支付统一下单获取Id(服务商模式) 🔖
|
||||
/// </summary>
|
||||
[DisplayName("微信支付统一下单获取Id(服务商模式)")]
|
||||
public async Task<dynamic> CreatePayPartnerTransaction([FromBody] WechatPayTransactionInput input)
|
||||
public async Task<CreatePayTransactionOutput> CreatePayPartnerTransaction([FromBody] WechatPayTransactionInput input)
|
||||
{
|
||||
string outTradeNumber = DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next(100, 1000); // 微信需要的订单号(唯一)
|
||||
|
||||
//检查订单信息是否已存在(使用“商户交易单号+状态”唯一性判断)
|
||||
var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OrderId == input.OrderId && u.OrderStatus == input.OrderStatus);
|
||||
if (wechatPay != null)
|
||||
{
|
||||
outTradeNumber = wechatPay.OutTradeNumber;
|
||||
}
|
||||
|
||||
var request = new CreatePayPartnerTransactionJsapiRequest()
|
||||
{
|
||||
OutTradeNumber = DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next(100, 1000), // 订单号
|
||||
OutTradeNumber = outTradeNumber,
|
||||
AppId = _wechatPayOptions.AppId,
|
||||
MerchantId = _wechatPayOptions.MerchantId,
|
||||
SubAppId = _wechatPayOptions.AppId,
|
||||
@ -127,29 +152,31 @@ public class SysWechatPayService : IDynamicApiController, ITransient
|
||||
};
|
||||
var response = await _wechatTenpayClient.ExecuteCreatePayPartnerTransactionJsapiAsync(request);
|
||||
if (!response.IsSuccessful())
|
||||
throw Oops.Oh(response.ErrorMessage);
|
||||
|
||||
// 保存订单信息
|
||||
var wechatPay = new SysWechatPay()
|
||||
throw Oops.Oh<Exception>($"JSAPI 下单失败(状态码:{response.GetRawStatus()},错误代码:{response.ErrorCode},错误描述:{response.ErrorMessage})");
|
||||
if (wechatPay == null)
|
||||
{
|
||||
AppId = _wechatPayOptions.AppId,
|
||||
MerchantId = _wechatPayOptions.MerchantId,
|
||||
SubAppId = _wechatPayOptions.AppId,
|
||||
SubMerchantId = _wechatPayOptions.MerchantId,
|
||||
OutTradeNumber = request.OutTradeNumber,
|
||||
Description = input.Description,
|
||||
Attachment = input.Attachment,
|
||||
GoodsTag = input.GoodsTag,
|
||||
Total = input.Total,
|
||||
OpenId = input.OpenId,
|
||||
TransactionId = ""
|
||||
};
|
||||
await _sysWechatPayUserRep.InsertAsync(wechatPay);
|
||||
// 保存订单信息
|
||||
wechatPay = new SysWechatPay()
|
||||
{
|
||||
AppId = _wechatPayOptions.AppId,
|
||||
MerchantId = _wechatPayOptions.MerchantId,
|
||||
SubAppId = _wechatPayOptions.AppId,
|
||||
SubMerchantId = _wechatPayOptions.MerchantId,
|
||||
OutTradeNumber = request.OutTradeNumber,
|
||||
Description = input.Description,
|
||||
Attachment = input.Attachment,
|
||||
GoodsTag = input.GoodsTag,
|
||||
Total = input.Total,
|
||||
OpenId = input.OpenId,
|
||||
TransactionId = ""
|
||||
};
|
||||
await _sysWechatPayRep.InsertAsync(wechatPay);
|
||||
}
|
||||
|
||||
return new
|
||||
return new CreatePayTransactionOutput
|
||||
{
|
||||
response.PrepayId,
|
||||
request.OutTradeNumber
|
||||
PrepayId = response.PrepayId,
|
||||
OutTradeNumber = request.OutTradeNumber
|
||||
};
|
||||
}
|
||||
|
||||
@ -161,7 +188,7 @@ public class SysWechatPayService : IDynamicApiController, ITransient
|
||||
[DisplayName("获取支付订单详情")]
|
||||
public async Task<SysWechatPay> GetPayInfo(string tradeId)
|
||||
{
|
||||
return await _sysWechatPayUserRep.GetFirstAsync(u => u.OutTradeNumber == tradeId);
|
||||
return await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == tradeId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -183,7 +210,7 @@ public class SysWechatPayService : IDynamicApiController, ITransient
|
||||
var callbackResource = _wechatTenpayClient.DecryptEventResource<TransactionResource>(callbackModel);
|
||||
|
||||
// 修改订单支付状态
|
||||
var wechatPay = await _sysWechatPayUserRep.GetFirstAsync(u => u.OutTradeNumber == callbackResource.OutTradeNumber
|
||||
var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == callbackResource.OutTradeNumber
|
||||
&& u.MerchantId == callbackResource.MerchantId);
|
||||
if (wechatPay == null) return null;
|
||||
//wechatPay.OpenId = callbackResource.Payer.OpenId; // 支付者标识
|
||||
@ -198,7 +225,7 @@ public class SysWechatPayService : IDynamicApiController, ITransient
|
||||
wechatPay.PayerTotal = callbackResource.Amount.PayerTotal; // 用户支付金额
|
||||
wechatPay.SuccessTime = callbackResource.SuccessTime; // 支付完成时间
|
||||
|
||||
await _sysWechatPayUserRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
|
||||
await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
|
||||
|
||||
return new WechatPayOutput()
|
||||
{
|
||||
@ -230,7 +257,7 @@ public class SysWechatPayService : IDynamicApiController, ITransient
|
||||
var callbackResource = _wechatTenpayClient.DecryptEventResource<PartnerTransactionResource>(callbackModel);
|
||||
|
||||
// 修改订单支付状态
|
||||
var wechatPay = await _sysWechatPayUserRep.GetFirstAsync(u => u.OutTradeNumber == callbackResource.OutTradeNumber
|
||||
var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == callbackResource.OutTradeNumber
|
||||
&& u.MerchantId == callbackResource.MerchantId);
|
||||
if (wechatPay == null) return;
|
||||
//wechatPay.OpenId = callbackResource.Payer.OpenId; // 支付者标识
|
||||
@ -245,7 +272,187 @@ public class SysWechatPayService : IDynamicApiController, ITransient
|
||||
wechatPay.PayerTotal = callbackResource.Amount.PayerTotal; // 用户支付金额
|
||||
wechatPay.SuccessTime = callbackResource.SuccessTime; // 支付完成时间
|
||||
|
||||
await _sysWechatPayUserRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
|
||||
await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 退款申请
|
||||
/// https://pay.weixin.qq.com/docs/merchant/apis/mini-program-payment/create.html
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("微信退款申请)")]
|
||||
public async Task Refund(RefundRequestInput input)
|
||||
{
|
||||
var request = new CreateRefundDomesticRefundRequest()
|
||||
{
|
||||
OutTradeNumber = input.OutTradeNumber,
|
||||
OutRefundNumber = "REFUND_" + DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff"),
|
||||
Amount = new CreateRefundDomesticRefundRequest.Types.Amount()
|
||||
{
|
||||
Total = input.Total,
|
||||
Refund = input.Refund
|
||||
},
|
||||
Reason = input.Reason,
|
||||
};
|
||||
var response = await _wechatTenpayClient.ExecuteCreateRefundDomesticRefundAsync(request);
|
||||
|
||||
if (!response.IsSuccessful())
|
||||
throw Oops.Oh<Exception>($"JSAPI 退款申请失败(状态码:{response.GetRawStatus()},错误代码:{response.ErrorCode},错误描述:{response.ErrorMessage})");
|
||||
|
||||
var wechatRefund = await _sysWechatRefundRep.GetFirstAsync(u => u.OutTradeNumber == input.OutTradeNumber);
|
||||
if (wechatRefund == null)
|
||||
{
|
||||
// 保存退款申请信息
|
||||
wechatRefund = new SysWechatRefund()
|
||||
{
|
||||
TransactionId = input.OutTradeNumber,
|
||||
OutTradeNumber = request.OutTradeNumber,
|
||||
OutRefundNo = request.OutTradeNumber, //每笔付款只退一次,所以这里直接用付款单号
|
||||
Reason = request.Reason,
|
||||
Refund = input.Refund,
|
||||
Total = input.Total,
|
||||
//NotifyUrl = "",
|
||||
OrderId = input.OrderId,
|
||||
OrderStatus = input.OrderStatus,
|
||||
MerchantGoodsId = input.MerchantGoodsId,
|
||||
GoodsName = input.GoodsName,
|
||||
UnitPrice = input.UnitPrice,
|
||||
RefundAmount = input.RefundAmount,
|
||||
RefundQuantity = input.RefundQuantity,
|
||||
Attachment = input.Attachment,
|
||||
Remark = input.Remark
|
||||
};
|
||||
await _sysWechatRefundRep.InsertAsync(wechatRefund);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询单笔退款(通过商户退款单号)
|
||||
/// https://pay.weixin.qq.com/docs/merchant/apis/mini-program-payment/query-by-out-refund-no.html
|
||||
/// </summary>
|
||||
/// <param name="outRefundNumber"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("微信查询单笔退款)")]
|
||||
public async Task<GetRefundDomesticRefundByOutRefundNumberResponse> GetRefundByOutRefundNumber(string outRefundNumber)
|
||||
{
|
||||
var request = new GetRefundDomesticRefundByOutRefundNumberRequest()
|
||||
{
|
||||
OutRefundNumber = outRefundNumber
|
||||
};
|
||||
return await _wechatTenpayClient.ExecuteGetRefundDomesticRefundByOutRefundNumberAsync(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 微信支付订单号查询(校正)
|
||||
/// https://api.mch.weixin.qq.com/v3/pay/transactions/id/{transaction_id}
|
||||
/// </summary>
|
||||
/// <param name="transactionId"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("微信支付订单号查询(校正)")]
|
||||
public async Task<WechatPayOutput> GetPayTransactionByIdAsync(string transactionId)
|
||||
{
|
||||
var request = new GetPayTransactionByIdRequest()
|
||||
{
|
||||
MerchantId = _wechatPayOptions.MerchantId,
|
||||
TransactionId = transactionId,
|
||||
WechatpayCertificateSerialNumber = _wechatPayOptions.MerchantCertificateSerialNumber
|
||||
};
|
||||
var response = await _wechatTenpayClient.ExecuteGetPayTransactionByIdAsync(request);
|
||||
if (response.TradeState == "SUCCESS")
|
||||
{
|
||||
// 修正订单支付状态
|
||||
var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.TransactionId == transactionId && u.MerchantId == request.MerchantId);
|
||||
if (wechatPay != null && string.IsNullOrEmpty(wechatPay.TradeState))
|
||||
{
|
||||
wechatPay.TransactionId = response.TransactionId; // 支付订单号
|
||||
wechatPay.TradeType = response.TradeType; // 交易类型
|
||||
wechatPay.TradeState = response.TradeState; // 交易状态
|
||||
wechatPay.TradeStateDescription = response.TradeStateDescription; // 交易状态描述
|
||||
wechatPay.BankType = response.BankType; // 付款银行类型
|
||||
wechatPay.Total = response.Amount.Total; // 订单总金额
|
||||
wechatPay.PayerTotal = response.Amount.PayerTotal; // 用户支付金额
|
||||
wechatPay.SuccessTime = response.SuccessTime; // 支付完成时间
|
||||
|
||||
await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
|
||||
return wechatPay.Adapt<WechatPayOutput>();
|
||||
}
|
||||
}
|
||||
return response.Adapt<WechatPayOutput>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 商户订单号查询(校正)
|
||||
/// https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}
|
||||
/// </summary>
|
||||
/// <param name="outTradeNumber"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("微信商户订单号查询(校正)")]
|
||||
public async Task<WechatPayOutput> GetPayTransactionByOutTradeNumberAsync(string outTradeNumber)
|
||||
{
|
||||
var request = new GetPayTransactionByOutTradeNumberRequest()
|
||||
{
|
||||
MerchantId = _wechatPayOptions.MerchantId,
|
||||
OutTradeNumber = outTradeNumber,
|
||||
WechatpayCertificateSerialNumber = _wechatPayOptions.MerchantCertificateSerialNumber
|
||||
};
|
||||
var response = await _wechatTenpayClient.ExecuteGetPayTransactionByOutTradeNumberAsync(request);
|
||||
if (response.TradeState == "SUCCESS")
|
||||
{
|
||||
// 修正订单支付状态
|
||||
var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == outTradeNumber && u.MerchantId == request.MerchantId);
|
||||
if (wechatPay != null && string.IsNullOrEmpty(wechatPay.TradeState))
|
||||
{
|
||||
wechatPay.TransactionId = response.TransactionId; // 支付订单号
|
||||
wechatPay.TradeType = response.TradeType; // 交易类型
|
||||
wechatPay.TradeState = response.TradeState; // 交易状态
|
||||
wechatPay.TradeStateDescription = response.TradeStateDescription; // 交易状态描述
|
||||
wechatPay.BankType = response.BankType; // 付款银行类型
|
||||
wechatPay.Total = response.Amount.Total; // 订单总金额
|
||||
wechatPay.PayerTotal = response.Amount.PayerTotal; // 用户支付金额
|
||||
wechatPay.SuccessTime = response.SuccessTime; // 支付完成时间
|
||||
await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
|
||||
return wechatPay.Adapt<WechatPayOutput>();
|
||||
}
|
||||
}
|
||||
return response.Adapt<WechatPayOutput>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取支付记录列表(分页)
|
||||
/// </summary>
|
||||
/// <param name="input">PageSysWechatPayInput</param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取支付记录列表(分页)")]
|
||||
public async Task<SqlSugarPagedList<SysWechatPay>> PageAsync(PageSysWechatPayInput input)
|
||||
{
|
||||
var query = _sysWechatPayRep.AsQueryable()
|
||||
.WhereIF(input.OrderId > 0, u => u.OrderId == input.OrderId)
|
||||
.WhereIF(input.OrderStatus > 0, u => u.OrderStatus == input.OrderStatus)
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.OutTradeNumber), u => u.OutTradeNumber.Contains(input.OutTradeNumber.Trim()));
|
||||
|
||||
if (input.SuccessTimeRange != null && input.SuccessTimeRange.Count > 0)
|
||||
{
|
||||
DateTime? start = input.SuccessTimeRange[0];
|
||||
query = query.WhereIF(start.HasValue, u => u.SuccessTime > start);
|
||||
if (input.SuccessTimeRange.Count > 1 && input.SuccessTimeRange[1].HasValue)
|
||||
{
|
||||
var end = input.SuccessTimeRange[1].Value.AddDays(1);
|
||||
query = query.Where(u => u.SuccessTime < end);
|
||||
}
|
||||
}
|
||||
if (input.ExpireTimeRange != null && input.ExpireTimeRange.Count > 0)
|
||||
{
|
||||
DateTime? start = input.ExpireTimeRange[0];
|
||||
query = query.WhereIF(start.HasValue, u => u.ExpireTime > start);
|
||||
if (input.ExpireTimeRange.Count > 1 && input.ExpireTimeRange[1].HasValue)
|
||||
{
|
||||
var end = input.ExpireTimeRange[1].Value.AddDays(1);
|
||||
query = query.Where(u => u.ExpireTime < end);
|
||||
}
|
||||
}
|
||||
query = query.OrderByDescending(u => u.CreateTime);
|
||||
return await query.ToPagedListAsync(input.Page, input.PageSize);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user