diff --git a/Admin.NET/Admin.NET.Core/Job/EnumToDictJob.cs b/Admin.NET/Admin.NET.Core/Job/EnumToDictJob.cs
index 475cb738..8aaa5b69 100644
--- a/Admin.NET/Admin.NET.Core/Job/EnumToDictJob.cs
+++ b/Admin.NET/Admin.NET.Core/Job/EnumToDictJob.cs
@@ -1,215 +1,215 @@
-// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
-//
-// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
-//
-// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
-
-namespace Admin.NET.Core;
-
-///
-/// 枚举转字典
-///
-[JobDetail("job_EnumToDictJob", Description = "枚举转字典", GroupName = "default", Concurrent = false)]
-[PeriodSeconds(1, TriggerId = "trigger_EnumToDictJob", Description = "枚举转字典", MaxNumberOfRuns = 1, RunOnStart = true)]
-public class EnumToDictJob : IJob
-{
- private readonly IServiceScopeFactory _scopeFactory;
- private const int OrderOffset = 10;
- private const string DefaultTagType = "info";
-
- public EnumToDictJob(IServiceScopeFactory scopeFactory)
- {
- _scopeFactory = scopeFactory;
- }
-
- public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
- {
- using var serviceScope = _scopeFactory.CreateScope();
- var sysEnumService = serviceScope.ServiceProvider.GetRequiredService();
- // 获取数据库连接
- var db = serviceScope.ServiceProvider.GetRequiredService().CopyNew();
-
- // 获取枚举类型列表
- var enumTypeList = sysEnumService.GetEnumTypeList();
- var enumCodeList = enumTypeList.Select(u => u.TypeName);
- // 查询数据库中已存在的枚举类型代码
- //var exp = Expressionable.Create>().And((t1, t2) => t1.Code == t2.ColumnName).ToExpression();
- //var sysDictTypeList = await db.Queryable().Includes(t1 => t1.Children).BulkListQuery(exp, enumCodeList, stoppingToken);
- var sysDictTypeList = await db.Queryable().Includes(u => u.Children)
- .Where(u => enumCodeList.Contains(u.Code)).ToListAsync(stoppingToken);
- // 更新的枚举转换字典
- var updatedEnumCodes = sysDictTypeList.Select(u => u.Code);
- var updatedEnumType = enumTypeList.Where(u => updatedEnumCodes.Contains(u.TypeName)).ToList();
- var sysDictTypeDict = sysDictTypeList.ToDictionary(u => u.Code, u => u);
- var (updatedDictTypes, updatedDictDatas, newSysDictDatas) = GetUpdatedDicts(updatedEnumType, sysDictTypeDict);
-
- // 新增的枚举转换字典
- var newEnumType = enumTypeList.Where(u => !updatedEnumCodes.Contains(u.TypeName)).ToList();
- var (newDictTypes, newDictDatas) = GetNewSysDicts(newEnumType);
-
- // 执行数据库操作
- try
- {
- await db.BeginTranAsync();
-
- if (updatedDictTypes.Count > 0)
- await db.Updateable(updatedDictTypes).ExecuteCommandAsync(stoppingToken);
-
- if (updatedDictDatas.Count > 0)
- await db.Updateable(updatedDictDatas).ExecuteCommandAsync(stoppingToken);
-
- if (newSysDictDatas.Count > 0)
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 枚举转字典
+///
+[JobDetail("job_EnumToDictJob", Description = "枚举转字典", GroupName = "default", Concurrent = false)]
+[PeriodSeconds(1, TriggerId = "trigger_EnumToDictJob", Description = "枚举转字典", MaxNumberOfRuns = 1, RunOnStart = true)]
+public class EnumToDictJob : IJob
+{
+ private readonly IServiceScopeFactory _scopeFactory;
+ private const int OrderOffset = 10;
+ private const string DefaultTagType = "info";
+
+ public EnumToDictJob(IServiceScopeFactory scopeFactory)
+ {
+ _scopeFactory = scopeFactory;
+ }
+
+ public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
+ {
+ using var serviceScope = _scopeFactory.CreateScope();
+ var sysEnumService = serviceScope.ServiceProvider.GetRequiredService();
+ // 获取数据库连接
+ var db = serviceScope.ServiceProvider.GetRequiredService().CopyNew();
+
+ // 获取枚举类型列表
+ var enumTypeList = sysEnumService.GetEnumTypeList();
+ var enumCodeList = enumTypeList.Select(u => u.TypeName);
+ // 查询数据库中已存在的枚举类型代码
+ //var exp = Expressionable.Create>().And((t1, t2) => t1.Code == t2.ColumnName).ToExpression();
+ //var sysDictTypeList = await db.Queryable().Includes(t1 => t1.Children).BulkListQuery(exp, enumCodeList, stoppingToken);
+ var sysDictTypeList = await db.Queryable().Includes(u => u.Children)
+ .Where(u => enumCodeList.Contains(u.Code)).ToListAsync(stoppingToken);
+ // 更新的枚举转换字典
+ var updatedEnumCodes = sysDictTypeList.Select(u => u.Code);
+ var updatedEnumType = enumTypeList.Where(u => updatedEnumCodes.Contains(u.TypeName)).ToList();
+ var sysDictTypeDict = sysDictTypeList.ToDictionary(u => u.Code, u => u);
+ var (updatedDictTypes, updatedDictDatas, newSysDictDatas) = GetUpdatedDicts(updatedEnumType, sysDictTypeDict);
+
+ // 新增的枚举转换字典
+ var newEnumType = enumTypeList.Where(u => !updatedEnumCodes.Contains(u.TypeName)).ToList();
+ var (newDictTypes, newDictDatas) = GetNewSysDicts(newEnumType);
+
+ // 执行数据库操作
+ try
+ {
+ await db.BeginTranAsync();
+
+ if (updatedDictTypes.Count > 0)
+ await db.Updateable(updatedDictTypes).ExecuteCommandAsync(stoppingToken);
+
+ if (updatedDictDatas.Count > 0)
+ await db.Updateable(updatedDictDatas).ExecuteCommandAsync(stoppingToken);
+
+ if (newSysDictDatas.Count > 0)
{
- //达梦 下用db.Insertable(newDictTypes).ExecuteCommandAsync(stoppingToken);插入400条以上会内容溢出错误,所以改用逐条插入
- //达梦 下不支持storageable2.BulkUpdateAsync 功能,注意使用
- foreach (var dd in newSysDictDatas)
- await db.Insertable(dd).ExecuteCommandAsync(stoppingToken);
- }
-
- if (newDictTypes.Count > 0)
- await db.Insertable(newDictTypes).ExecuteCommandAsync(stoppingToken);
-
- if (newDictDatas.Count > 0)
+ // 达梦:用db.Insertable(newDictTypes).ExecuteCommandAsync(stoppingToken);插入400条以上会内容溢出错误,所以改用逐条插入
+ // 达梦:不支持storageable2.BulkUpdateAsync 功能
+ foreach (var dd in newSysDictDatas)
+ await db.Insertable(dd).ExecuteCommandAsync(stoppingToken);
+ }
+
+ if (newDictTypes.Count > 0)
+ await db.Insertable(newDictTypes).ExecuteCommandAsync(stoppingToken);
+
+ if (newDictDatas.Count > 0)
{
- //达梦 下用db.Insertable(newDictTypes).ExecuteCommandAsync(stoppingToken);插入400条以上会内容溢出错误,所以改用逐条插入
- //达梦 下不支持storageable2.BulkUpdateAsync 功能,注意使用
- foreach (var dd in newDictDatas)
- await db.Insertable(dd).ExecuteCommandAsync(stoppingToken);
- }
-
- await db.CommitTranAsync();
- }
- catch (Exception error)
- {
- await db.RollbackTranAsync();
- Log.Error($"系统枚举转换字典操作错误:{error.Message}\n堆栈跟踪:{error.StackTrace}", error);
- throw;
- }
- var originColor = Console.ForegroundColor;
- Console.ForegroundColor = ConsoleColor.Green;
- Console.WriteLine($"【{DateTime.Now}】系统枚举转换字典");
- Console.ForegroundColor = originColor;
- }
-
- ///
- /// 获取需要新增的字典列表
- ///
- ///
- ///
- /// 一个元组,包含以下元素:
- ///
- /// - SysDictTypes字典类型列表
- /// - SysDictDatas字典数据列表
- ///
- ///
- private (List, List) GetNewSysDicts(List addEnumType)
- {
- var newDictType = new List();
- var newDictData = new List();
- if (addEnumType.Count <= 0)
- return (newDictType, newDictData);
-
- // 新增字典类型
- newDictType = addEnumType.Select(u => new SysDictType
- {
- Id = YitIdHelper.NextId(),
- Code = u.TypeName,
- Name = u.TypeDescribe,
- Remark = u.TypeRemark,
- Status = StatusEnum.Enable
- }).ToList();
-
- // 新增字典数据
- newDictData = addEnumType.Join(newDictType, t1 => t1.TypeName, t2 => t2.Code, (t1, t2) => new
- {
- Data = t1.EnumEntities.Select(u => new SysDictData
- {
- Id = YitIdHelper.NextId(),
- DictTypeId = t2.Id,
- Name = u.Describe,
- Value = u.Value.ToString(),
- Code = u.Name,
- Remark = t2.Remark,
- OrderNo = u.Value + OrderOffset,
- TagType = u.Theme != "" ? u.Theme : DefaultTagType,
- }).ToList()
- }).SelectMany(x => x.Data).ToList();
-
- return (newDictType, newDictData);
- }
-
- ///
- /// 获取需要更新的字典列表
- ///
- ///
- ///
- ///
- /// 一个元组,包含以下元素:
- ///
- /// - SysDictTypes更新字典类型列表
- ///
- /// - SysDictDatas更新字典数据列表
- ///
- /// - SysDictDatas新增字典数据列表
- ///
- ///
- ///
- private (List, List, List) GetUpdatedDicts(List updatedEnumType, Dictionary sysDictTypeDict)
- {
- var updatedSysDictTypes = new List();
- var updatedSysDictData = new List();
- var newSysDictData = new List();
- foreach (var e in updatedEnumType)
- {
- if (!sysDictTypeDict.TryGetValue(e.TypeName, out var value))
- continue;
-
- var updatedDictType = value;
- updatedDictType.Name = e.TypeDescribe;
- updatedDictType.Remark = e.TypeRemark;
- updatedSysDictTypes.Add(updatedDictType);
- var updatedDictData = updatedDictType.Children.Where(u => u.DictTypeId == updatedDictType.Id).ToList();
-
- // 遍历需要更新的字典数据
- foreach (var dictData in updatedDictData)
- {
- var enumData = e.EnumEntities.FirstOrDefault(u => dictData.Code == u.Name);
- if (enumData != null)
- {
- dictData.Value = enumData.Value.ToString();
- dictData.OrderNo = enumData.Value + OrderOffset;
- dictData.Name = enumData.Describe;
- dictData.TagType = enumData.Theme != "" ? enumData.Theme : dictData.TagType != "" ? dictData.TagType : DefaultTagType;
- updatedSysDictData.Add(dictData);
- }
- }
-
- // 新增的枚举值名称列表
- var newEnumDataNameList = e.EnumEntities.Select(u => u.Name).Except(updatedDictData.Select(u => u.Code));
- foreach (var newEnumDataName in newEnumDataNameList)
- {
- var enumData = e.EnumEntities.FirstOrDefault(u => newEnumDataName == u.Name);
- if (enumData != null)
- {
- var dictData = new SysDictData
- {
- Id = YitIdHelper.NextId(),
- DictTypeId = updatedDictType.Id,
- Name = enumData.Describe,
- Value = enumData.Value.ToString(),
- Code = enumData.Name,
- Remark = updatedDictType.Remark,
- OrderNo = enumData.Value + OrderOffset,
- TagType = enumData.Theme != "" ? enumData.Theme : DefaultTagType,
- };
- dictData.TagType = enumData.Theme != "" ? enumData.Theme : dictData.TagType != "" ? dictData.TagType : DefaultTagType;
- newSysDictData.Add(dictData);
- }
- }
-
- // 删除的情况暂不处理
- }
-
- return (updatedSysDictTypes, updatedSysDictData, newSysDictData);
- }
+ // 达梦:用db.Insertable(newDictTypes).ExecuteCommandAsync(stoppingToken);插入400条以上会内容溢出错误,所以改用逐条插入
+ // 达梦:不支持storageable2.BulkUpdateAsync 功能
+ foreach (var dd in newDictDatas)
+ await db.Insertable(dd).ExecuteCommandAsync(stoppingToken);
+ }
+
+ await db.CommitTranAsync();
+ }
+ catch (Exception error)
+ {
+ await db.RollbackTranAsync();
+ Log.Error($"系统枚举转换字典操作错误:{error.Message}\n堆栈跟踪:{error.StackTrace}", error);
+ throw;
+ }
+ var originColor = Console.ForegroundColor;
+ Console.ForegroundColor = ConsoleColor.Green;
+ Console.WriteLine($"【{DateTime.Now}】系统枚举转换字典");
+ Console.ForegroundColor = originColor;
+ }
+
+ ///
+ /// 获取需要新增的字典列表
+ ///
+ ///
+ ///
+ /// 一个元组,包含以下元素:
+ ///
+ /// - SysDictTypes字典类型列表
+ /// - SysDictDatas字典数据列表
+ ///
+ ///
+ private (List, List) GetNewSysDicts(List addEnumType)
+ {
+ var newDictType = new List();
+ var newDictData = new List();
+ if (addEnumType.Count <= 0)
+ return (newDictType, newDictData);
+
+ // 新增字典类型
+ newDictType = addEnumType.Select(u => new SysDictType
+ {
+ Id = YitIdHelper.NextId(),
+ Code = u.TypeName,
+ Name = u.TypeDescribe,
+ Remark = u.TypeRemark,
+ Status = StatusEnum.Enable
+ }).ToList();
+
+ // 新增字典数据
+ newDictData = addEnumType.Join(newDictType, t1 => t1.TypeName, t2 => t2.Code, (t1, t2) => new
+ {
+ Data = t1.EnumEntities.Select(u => new SysDictData
+ {
+ Id = YitIdHelper.NextId(),
+ DictTypeId = t2.Id,
+ Name = u.Describe,
+ Value = u.Value.ToString(),
+ Code = u.Name,
+ Remark = t2.Remark,
+ OrderNo = u.Value + OrderOffset,
+ TagType = u.Theme != "" ? u.Theme : DefaultTagType,
+ }).ToList()
+ }).SelectMany(x => x.Data).ToList();
+
+ return (newDictType, newDictData);
+ }
+
+ ///
+ /// 获取需要更新的字典列表
+ ///
+ ///
+ ///
+ ///
+ /// 一个元组,包含以下元素:
+ ///
+ /// - SysDictTypes更新字典类型列表
+ ///
+ /// - SysDictDatas更新字典数据列表
+ ///
+ /// - SysDictDatas新增字典数据列表
+ ///
+ ///
+ ///
+ private (List, List, List) GetUpdatedDicts(List updatedEnumType, Dictionary sysDictTypeDict)
+ {
+ var updatedSysDictTypes = new List();
+ var updatedSysDictData = new List();
+ var newSysDictData = new List();
+ foreach (var e in updatedEnumType)
+ {
+ if (!sysDictTypeDict.TryGetValue(e.TypeName, out var value))
+ continue;
+
+ var updatedDictType = value;
+ updatedDictType.Name = e.TypeDescribe;
+ updatedDictType.Remark = e.TypeRemark;
+ updatedSysDictTypes.Add(updatedDictType);
+ var updatedDictData = updatedDictType.Children.Where(u => u.DictTypeId == updatedDictType.Id).ToList();
+
+ // 遍历需要更新的字典数据
+ foreach (var dictData in updatedDictData)
+ {
+ var enumData = e.EnumEntities.FirstOrDefault(u => dictData.Code == u.Name);
+ if (enumData != null)
+ {
+ dictData.Value = enumData.Value.ToString();
+ dictData.OrderNo = enumData.Value + OrderOffset;
+ dictData.Name = enumData.Describe;
+ dictData.TagType = enumData.Theme != "" ? enumData.Theme : dictData.TagType != "" ? dictData.TagType : DefaultTagType;
+ updatedSysDictData.Add(dictData);
+ }
+ }
+
+ // 新增的枚举值名称列表
+ var newEnumDataNameList = e.EnumEntities.Select(u => u.Name).Except(updatedDictData.Select(u => u.Code));
+ foreach (var newEnumDataName in newEnumDataNameList)
+ {
+ var enumData = e.EnumEntities.FirstOrDefault(u => newEnumDataName == u.Name);
+ if (enumData != null)
+ {
+ var dictData = new SysDictData
+ {
+ Id = YitIdHelper.NextId(),
+ DictTypeId = updatedDictType.Id,
+ Name = enumData.Describe,
+ Value = enumData.Value.ToString(),
+ Code = enumData.Name,
+ Remark = updatedDictType.Remark,
+ OrderNo = enumData.Value + OrderOffset,
+ TagType = enumData.Theme != "" ? enumData.Theme : DefaultTagType,
+ };
+ dictData.TagType = enumData.Theme != "" ? enumData.Theme : dictData.TagType != "" ? dictData.TagType : DefaultTagType;
+ newSysDictData.Add(dictData);
+ }
+ }
+
+ // 删除的情况暂不处理
+ }
+
+ return (updatedSysDictTypes, updatedSysDictData, newSysDictData);
+ }
}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Service/Auth/Dto/LoginInput.cs b/Admin.NET/Admin.NET.Core/Service/Auth/Dto/LoginInput.cs
index 98771558..39f83e66 100644
--- a/Admin.NET/Admin.NET.Core/Service/Auth/Dto/LoginInput.cs
+++ b/Admin.NET/Admin.NET.Core/Service/Auth/Dto/LoginInput.cs
@@ -28,7 +28,7 @@ public class LoginInput
///
/// 租户域名
///
- [Required(ErrorMessage = "租户域名不能为空")]
+ //[Required(ErrorMessage = "租户域名不能为空")]
public string Host { get; set; }
///
@@ -67,8 +67,8 @@ public class LoginPhoneInput
///
/// 租户域名
///
- [Required(ErrorMessage = "租户域名不能为空")]
- public string? Host { get; set; }
+ //[Required(ErrorMessage = "租户域名不能为空")]
+ public string Host { get; set; }
///
/// 登录模式
diff --git a/Admin.NET/Admin.NET.Core/Service/Auth/SysAuthService.cs b/Admin.NET/Admin.NET.Core/Service/Auth/SysAuthService.cs
index 6ccd67f3..dc53bd0d 100644
--- a/Admin.NET/Admin.NET.Core/Service/Auth/SysAuthService.cs
+++ b/Admin.NET/Admin.NET.Core/Service/Auth/SysAuthService.cs
@@ -153,26 +153,24 @@ public class SysAuthService : IDynamicApiController, ITransient
///
private void VerifyPassword(string password, string keyPasswordErrorTimes, int passwordErrorTimes, SysUser user)
{
- if (CryptogramUtil.CryptoType == CryptogramEnum.MD5.ToString())
+ // 国密SM2解密(前端密码传输SM2加密后的)
+ try
{
- // 国密SM2解密(前端密码传输SM2加密后的)
- try
- {
- password = CryptogramUtil.SM2Decrypt(password);
- }
- catch
- {
- throw Oops.Oh(ErrorCodeEnum.D0010);
- }
- if (user.Password.Equals(MD5Encryption.Encrypt(password))) return;
-
- _sysCacheService.Set(keyPasswordErrorTimes, ++passwordErrorTimes, TimeSpan.FromMinutes(30));
- throw Oops.Oh(ErrorCodeEnum.D1000);
+ password = CryptogramUtil.SM2Decrypt(password);
+ }
+ catch
+ {
+ throw Oops.Oh(ErrorCodeEnum.D0010);
}
- // 国密SM2解密(前端密码传输SM2加密后的)
- password = CryptogramUtil.SM2Decrypt(password);
- if (CryptogramUtil.Decrypt(user.Password).Equals(password)) return;
+ if (CryptogramUtil.CryptoType == CryptogramEnum.MD5.ToString())
+ {
+ if (user.Password.Equals(MD5Encryption.Encrypt(password))) return;
+ }
+ else
+ {
+ if (CryptogramUtil.Decrypt(user.Password).Equals(password)) return;
+ }
_sysCacheService.Set(keyPasswordErrorTimes, ++passwordErrorTimes, TimeSpan.FromMinutes(30));
throw Oops.Oh(ErrorCodeEnum.D1000);
diff --git a/Admin.NET/Admin.NET.Core/Service/Wechat/SysWechatPayService.cs b/Admin.NET/Admin.NET.Core/Service/Wechat/SysWechatPayService.cs
index 821aa94a..5d0271aa 100644
--- a/Admin.NET/Admin.NET.Core/Service/Wechat/SysWechatPayService.cs
+++ b/Admin.NET/Admin.NET.Core/Service/Wechat/SysWechatPayService.cs
@@ -1,538 +1,538 @@
-// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
-//
-// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
-//
-// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
-
-using Furion.Logging.Extensions;
-using Newtonsoft.Json;
-
-namespace Admin.NET.Core.Service;
-
-///
-/// 微信支付服务 🧩
-///
-[ApiDescriptionSettings(Order = 210, Description = "微信支付")]
-public class SysWechatPayService : IDynamicApiController, ITransient
-{
- private readonly SqlSugarRepository _sysWechatPayRep;
- private readonly SqlSugarRepository _sysWechatRefundRep;
- private readonly WechatPayOptions _wechatPayOptions;
- private readonly PayCallBackOptions _payCallBackOptions;
-
- private readonly WechatTenpayClient _wechatTenpayClient;
-
- public SysWechatPayService(SqlSugarRepository sysWechatPayRep,
- SqlSugarRepository sysWechatRefundRep,
- IOptions wechatPayOptions,
- IOptions payCallBackOptions)
- {
- _sysWechatPayRep = sysWechatPayRep;
- this._sysWechatRefundRep = sysWechatRefundRep;
- _wechatPayOptions = wechatPayOptions.Value;
- _payCallBackOptions = payCallBackOptions.Value;
-
- _wechatTenpayClient = CreateTenpayClient();
- }
-
- ///
- /// 初始化微信支付客户端
- ///
- ///
- private WechatTenpayClient CreateTenpayClient()
- {
- var cerFilePath = App.WebHostEnvironment.ContentRootPath + _wechatPayOptions.MerchantCertificatePrivateKey;
-
- if (!File.Exists(cerFilePath))
- Log.Warning("商户证书文件不存在:" + cerFilePath);
-
- var tenpayClientOptions = new WechatTenpayClientOptions()
- {
- MerchantId = _wechatPayOptions.MerchantId,
- MerchantV3Secret = _wechatPayOptions.MerchantV3Secret,
- MerchantCertificateSerialNumber = _wechatPayOptions.MerchantCertificateSerialNumber,
- MerchantCertificatePrivateKey = File.Exists(cerFilePath) ? File.ReadAllText(cerFilePath) : "",
- PlatformCertificateManager = new InMemoryCertificateManager()
- };
- return new WechatTenpayClient(tenpayClientOptions);
- }
-
- ///
- /// 生成JSAPI调起支付所需参数 🔖
- ///
- ///
- ///
- [DisplayName("生成JSAPI调起支付所需参数")]
- public dynamic GenerateParametersForJsapiPay(WechatPayParaInput input)
- {
- return _wechatTenpayClient.GenerateParametersForJsapiPayRequest(_wechatPayOptions.AppId, input.PrepayId);
- }
-
- ///
- /// 微信支付统一下单获取Id(商户直连) 🔖
- ///
- [DisplayName("微信支付统一下单获取Id(商户直连)")]
- public async Task 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 = outTradeNumber,
- AppId = _wechatPayOptions.AppId,
- Description = input.Description,
- Attachment = input.Attachment,
- GoodsTag = input.GoodsTag,
- ExpireTime = DateTimeOffset.Now.AddMinutes(10),
- NotifyUrl = _payCallBackOptions.WechatPayUrl,
- Amount = new CreatePayTransactionJsapiRequest.Types.Amount() { Total = input.Total },
- Payer = new CreatePayTransactionJsapiRequest.Types.Payer() { OpenId = input.OpenId }
- };
- var response = await _wechatTenpayClient.ExecuteCreatePayTransactionJsapiAsync(request);
- if (!response.IsSuccessful())
- throw Oops.Oh(response.ErrorMessage);
-
- if (wechatPay == null)
- {
- // 保存订单信息
- 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,
- Tags = input.Tags,
- BusinessId = input.BusinessId,
- };
- await _sysWechatPayRep.InsertAsync(wechatPay);
- }
-
- //var singInfo = GenerateParametersForJsapiPay(new WechatPayParaInput() { PrepayId = response.PrepayId });
- return new CreatePayTransactionOutput
- {
- PrepayId = response.PrepayId,
- OutTradeNumber = request.OutTradeNumber,
- //SingInfo = singInfo
- };
- }
-
- ///
- /// 微信支付统一下单(商户直连)Native
- ///
- [DisplayName("微信支付统一下单(商户直连)Native")]
- public async Task CreatePayTransactionNative([FromBody] WechatPayTransactionInput input)
- {
- var request = new CreatePayTransactionNativeRequest()
- {
- OutTradeNumber = DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next(100, 1000), // 微信需要的订单号(唯一)
- AppId = _wechatPayOptions.AppId,
- Description = input.Description,
- Attachment = input.Attachment,
- GoodsTag = input.GoodsTag,
- ExpireTime = DateTimeOffset.Now.AddMinutes(10),
- NotifyUrl = _payCallBackOptions.WechatPayUrl,
- Amount = new CreatePayTransactionNativeRequest.Types.Amount() { Total = input.Total },
- //Payer = new CreatePayTransactionNativeRequest.Types.Payer() { OpenId = input.OpenId }
- Scene = new CreatePayTransactionNativeRequest.Types.Scene() { ClientIp = "127.0.0.1" }
- };
- var response = await _wechatTenpayClient.ExecuteCreatePayTransactionNativeAsync(request);
- if (!response.IsSuccessful())
- {
- JsonConvert.SerializeObject(response).LogInformation();
- throw Oops.Oh(response.ErrorMessage);
- }
- // 保存订单信息
- var 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 = "",
- QrcodeContent = response.QrcodeUrl,
- Tags = input.Tags,
- BusinessId = input.BusinessId,
- };
- await _sysWechatPayRep.InsertAsync(wechatPay);
- return new CreatePayTransactionNativeOutput
- {
- OutTradeNumber = request.OutTradeNumber,
- QrcodeUrl = response.QrcodeUrl
- };
- }
-
- ///
- /// 微信支付统一下单获取Id(服务商模式) 🔖
- ///
- [DisplayName("微信支付统一下单获取Id(服务商模式)")]
- public async Task 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 = outTradeNumber,
- AppId = _wechatPayOptions.AppId,
- MerchantId = _wechatPayOptions.MerchantId,
- SubAppId = _wechatPayOptions.AppId,
- SubMerchantId = _wechatPayOptions.MerchantId,
- Description = input.Description,
- Attachment = input.Attachment,
- GoodsTag = input.GoodsTag,
- ExpireTime = DateTimeOffset.Now.AddMinutes(10),
- NotifyUrl = _payCallBackOptions.WechatPayUrl,
- Amount = new CreatePayPartnerTransactionJsapiRequest.Types.Amount() { Total = input.Total },
- Payer = new CreatePayPartnerTransactionJsapiRequest.Types.Payer() { OpenId = input.OpenId }
- };
- var response = await _wechatTenpayClient.ExecuteCreatePayPartnerTransactionJsapiAsync(request);
- if (!response.IsSuccessful())
- throw Oops.Oh($"JSAPI 下单失败(状态码:{response.GetRawStatus()},错误代码:{response.ErrorCode},错误描述:{response.ErrorMessage})");
- if (wechatPay == null)
- {
- // 保存订单信息
- 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 CreatePayTransactionOutput
- {
- PrepayId = response.PrepayId,
- OutTradeNumber = request.OutTradeNumber
- };
- }
-
- ///
- /// 获取支付订单详情 🔖
- ///
- ///
- ///
- [DisplayName("获取支付订单详情")]
- public async Task GetPayInfo(string tradeId)
- {
- return await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == tradeId);
- }
-
- ///
- /// 微信支付成功回调(商户直连) 🔖
- ///
- ///
- [AllowAnonymous]
- [DisplayName("微信支付成功回调(商户直连)")]
- public async Task PayCallBack()
- {
- using var ms = new MemoryStream();
- await App.HttpContext.Request.Body.CopyToAsync(ms);
- var b = ms.ToArray();
- var callbackJson = Encoding.UTF8.GetString(b);
-
- var callbackModel = _wechatTenpayClient.DeserializeEvent(callbackJson);
- if ("TRANSACTION.SUCCESS".Equals(callbackModel.EventType))
- {
- var callbackResource = _wechatTenpayClient.DecryptEventResource(callbackModel);
-
- // 修改订单支付状态
- var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == callbackResource.OutTradeNumber
- && u.MerchantId == callbackResource.MerchantId);
- if (wechatPay == null) return null;
- //wechatPay.OpenId = callbackResource.Payer.OpenId; // 支付者标识
- //wechatPay.MerchantId = callbackResource.MerchantId; // 微信商户号
- //wechatPay.OutTradeNumber = callbackResource.OutTradeNumber; // 商户订单号
- wechatPay.TransactionId = callbackResource.TransactionId; // 支付订单号
- wechatPay.TradeType = callbackResource.TradeType; // 交易类型
- wechatPay.TradeState = callbackResource.TradeState; // 交易状态
- wechatPay.TradeStateDescription = callbackResource.TradeStateDescription; // 交易状态描述
- wechatPay.BankType = callbackResource.BankType; // 付款银行类型
- wechatPay.Total = callbackResource.Amount.Total; // 订单总金额
- wechatPay.PayerTotal = callbackResource.Amount.PayerTotal; // 用户支付金额
- wechatPay.SuccessTime = callbackResource.SuccessTime; // 支付完成时间
-
- await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
-
- return new WechatPayOutput()
- {
- Total = wechatPay.Total,
- Attachment = wechatPay.Attachment,
- GoodsTag = wechatPay.GoodsTag
- };
- }
-
- return null;
- }
-
- ///
- /// 微信支付成功回调(服务商模式) 🔖
- ///
- ///
- [AllowAnonymous]
- [DisplayName("微信支付成功回调(服务商模式)")]
- public async Task PayPartnerCallBack()
- {
- using var ms = new MemoryStream();
- await App.HttpContext.Request.Body.CopyToAsync(ms);
- var b = ms.ToArray();
- var callbackJson = Encoding.UTF8.GetString(b);
-
- var callbackModel = _wechatTenpayClient.DeserializeEvent(callbackJson);
- if ("TRANSACTION.SUCCESS".Equals(callbackModel.EventType))
- {
- var callbackResource = _wechatTenpayClient.DecryptEventResource(callbackModel);
-
- // 修改订单支付状态
- var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == callbackResource.OutTradeNumber
- && u.MerchantId == callbackResource.MerchantId);
- if (wechatPay == null) return;
- //wechatPay.OpenId = callbackResource.Payer.OpenId; // 支付者标识
- //wechatPay.MerchantId = callbackResource.MerchantId; // 微信商户号
- //wechatPay.OutTradeNumber = callbackResource.OutTradeNumber; // 商户订单号
- wechatPay.TransactionId = callbackResource.TransactionId; // 支付订单号
- wechatPay.TradeType = callbackResource.TradeType; // 交易类型
- wechatPay.TradeState = callbackResource.TradeState; // 交易状态
- wechatPay.TradeStateDescription = callbackResource.TradeStateDescription; // 交易状态描述
- wechatPay.BankType = callbackResource.BankType; // 付款银行类型
- wechatPay.Total = callbackResource.Amount.Total; // 订单总金额
- wechatPay.PayerTotal = callbackResource.Amount.PayerTotal; // 用户支付金额
- wechatPay.SuccessTime = callbackResource.SuccessTime; // 支付完成时间
-
- await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
- }
- }
-
- ///
- /// 退款申请 🔖
- /// https://pay.weixin.qq.com/docs/merchant/apis/mini-program-payment/create.html
- ///
- ///
- ///
- [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($"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);
- }
- }
-
- ///
- /// 查询单笔退款(通过商户退款单号) 🔖
- /// https://pay.weixin.qq.com/docs/merchant/apis/mini-program-payment/query-by-out-refund-no.html
- ///
- ///
- ///
- [DisplayName("微信查询单笔退款)")]
- public async Task GetRefundByOutRefundNumber(string outRefundNumber)
- {
- var request = new GetRefundDomesticRefundByOutRefundNumberRequest()
- {
- OutRefundNumber = outRefundNumber
- };
- return await _wechatTenpayClient.ExecuteGetRefundDomesticRefundByOutRefundNumberAsync(request);
- }
-
- ///
- /// 微信支付订单号查询(校正) 🔖
- /// https://api.mch.weixin.qq.com/v3/pay/transactions/id/{transaction_id}
- ///
- ///
- ///
- [DisplayName("微信支付订单号查询(校正)")]
- public async Task GetPayTransactionByIdAsync(string transactionId)
- {
- if (string.IsNullOrEmpty(transactionId))
- throw Oops.Oh("TransactionId 不能为空");
-
- if (string.IsNullOrEmpty(_wechatPayOptions.MerchantId) || string.IsNullOrEmpty(_wechatPayOptions.MerchantCertificateSerialNumber))
- throw Oops.Oh("商户号或证书序列号不能为空,请检查支付配置");
-
- var request = new GetPayTransactionByIdRequest()
- {
- MerchantId = _wechatPayOptions.MerchantId,
- TransactionId = transactionId,
- WechatpaySerialNumber = _wechatPayOptions.MerchantCertificateSerialNumber
- };
- var response = await _wechatTenpayClient.ExecuteGetPayTransactionByIdAsync(request);
- if (response.TradeState == "SUCCESS" || response.TradeState == "CLOSED" || response.TradeState == "NOTPAY")
- {
- // 修正订单支付状态
- var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.TransactionId == request.TransactionId && u.MerchantId == request.MerchantId);
- if (wechatPay != null && string.IsNullOrEmpty(wechatPay.TradeState))
- {
- wechatPay.TradeType = response.TradeType; // 交易类型
- wechatPay.TradeState = response.TradeState; // 交易状态
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+using Furion.Logging.Extensions;
+using Newtonsoft.Json;
+
+namespace Admin.NET.Core.Service;
+
+///
+/// 微信支付服务 🧩
+///
+[ApiDescriptionSettings(Order = 210, Description = "微信支付")]
+public class SysWechatPayService : IDynamicApiController, ITransient
+{
+ private readonly SqlSugarRepository _sysWechatPayRep;
+ private readonly SqlSugarRepository _sysWechatRefundRep;
+ private readonly WechatPayOptions _wechatPayOptions;
+ private readonly PayCallBackOptions _payCallBackOptions;
+
+ private readonly WechatTenpayClient _wechatTenpayClient;
+
+ public SysWechatPayService(SqlSugarRepository sysWechatPayRep,
+ SqlSugarRepository sysWechatRefundRep,
+ IOptions wechatPayOptions,
+ IOptions payCallBackOptions)
+ {
+ _sysWechatPayRep = sysWechatPayRep;
+ this._sysWechatRefundRep = sysWechatRefundRep;
+ _wechatPayOptions = wechatPayOptions.Value;
+ _payCallBackOptions = payCallBackOptions.Value;
+
+ _wechatTenpayClient = CreateTenpayClient();
+ }
+
+ ///
+ /// 初始化微信支付客户端
+ ///
+ ///
+ private WechatTenpayClient CreateTenpayClient()
+ {
+ var cerFilePath = App.WebHostEnvironment.ContentRootPath + _wechatPayOptions.MerchantCertificatePrivateKey;
+
+ if (!File.Exists(cerFilePath))
+ Log.Warning("商户证书文件不存在:" + cerFilePath);
+
+ var tenpayClientOptions = new WechatTenpayClientOptions()
+ {
+ MerchantId = _wechatPayOptions.MerchantId,
+ MerchantV3Secret = _wechatPayOptions.MerchantV3Secret,
+ MerchantCertificateSerialNumber = _wechatPayOptions.MerchantCertificateSerialNumber,
+ MerchantCertificatePrivateKey = File.Exists(cerFilePath) ? File.ReadAllText(cerFilePath) : "",
+ PlatformCertificateManager = new InMemoryCertificateManager()
+ };
+ return new WechatTenpayClient(tenpayClientOptions);
+ }
+
+ ///
+ /// 生成JSAPI调起支付所需参数 🔖
+ ///
+ ///
+ ///
+ [DisplayName("生成JSAPI调起支付所需参数")]
+ public dynamic GenerateParametersForJsapiPay(WechatPayParaInput input)
+ {
+ return _wechatTenpayClient.GenerateParametersForJsapiPayRequest(_wechatPayOptions.AppId, input.PrepayId);
+ }
+
+ ///
+ /// 微信支付统一下单获取Id(商户直连) 🔖
+ ///
+ [DisplayName("微信支付统一下单获取Id(商户直连)")]
+ public async Task 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 = outTradeNumber,
+ AppId = _wechatPayOptions.AppId,
+ Description = input.Description,
+ Attachment = input.Attachment,
+ GoodsTag = input.GoodsTag,
+ ExpireTime = DateTimeOffset.Now.AddMinutes(10),
+ NotifyUrl = _payCallBackOptions.WechatPayUrl,
+ Amount = new CreatePayTransactionJsapiRequest.Types.Amount() { Total = input.Total },
+ Payer = new CreatePayTransactionJsapiRequest.Types.Payer() { OpenId = input.OpenId }
+ };
+ var response = await _wechatTenpayClient.ExecuteCreatePayTransactionJsapiAsync(request);
+ if (!response.IsSuccessful())
+ throw Oops.Oh(response.ErrorMessage);
+
+ if (wechatPay == null)
+ {
+ // 保存订单信息
+ 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,
+ Tags = input.Tags,
+ BusinessId = input.BusinessId,
+ };
+ await _sysWechatPayRep.InsertAsync(wechatPay);
+ }
+
+ //var singInfo = GenerateParametersForJsapiPay(new WechatPayParaInput() { PrepayId = response.PrepayId });
+ return new CreatePayTransactionOutput
+ {
+ PrepayId = response.PrepayId,
+ OutTradeNumber = request.OutTradeNumber,
+ //SingInfo = singInfo
+ };
+ }
+
+ ///
+ /// 微信支付统一下单(商户直连)Native
+ ///
+ [DisplayName("微信支付统一下单(商户直连)Native")]
+ public async Task CreatePayTransactionNative([FromBody] WechatPayTransactionInput input)
+ {
+ var request = new CreatePayTransactionNativeRequest()
+ {
+ OutTradeNumber = DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next(100, 1000), // 微信需要的订单号(唯一)
+ AppId = _wechatPayOptions.AppId,
+ Description = input.Description,
+ Attachment = input.Attachment,
+ GoodsTag = input.GoodsTag,
+ ExpireTime = DateTimeOffset.Now.AddMinutes(10),
+ NotifyUrl = _payCallBackOptions.WechatPayUrl,
+ Amount = new CreatePayTransactionNativeRequest.Types.Amount() { Total = input.Total },
+ //Payer = new CreatePayTransactionNativeRequest.Types.Payer() { OpenId = input.OpenId }
+ Scene = new CreatePayTransactionNativeRequest.Types.Scene() { ClientIp = "127.0.0.1" }
+ };
+ var response = await _wechatTenpayClient.ExecuteCreatePayTransactionNativeAsync(request);
+ if (!response.IsSuccessful())
+ {
+ JsonConvert.SerializeObject(response).LogInformation();
+ throw Oops.Oh(response.ErrorMessage);
+ }
+ // 保存订单信息
+ var 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 = "",
+ QrcodeContent = response.QrcodeUrl,
+ Tags = input.Tags,
+ BusinessId = input.BusinessId,
+ };
+ await _sysWechatPayRep.InsertAsync(wechatPay);
+ return new CreatePayTransactionNativeOutput
+ {
+ OutTradeNumber = request.OutTradeNumber,
+ QrcodeUrl = response.QrcodeUrl
+ };
+ }
+
+ ///
+ /// 微信支付统一下单获取Id(服务商模式) 🔖
+ ///
+ [DisplayName("微信支付统一下单获取Id(服务商模式)")]
+ public async Task 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 = outTradeNumber,
+ AppId = _wechatPayOptions.AppId,
+ MerchantId = _wechatPayOptions.MerchantId,
+ SubAppId = _wechatPayOptions.AppId,
+ SubMerchantId = _wechatPayOptions.MerchantId,
+ Description = input.Description,
+ Attachment = input.Attachment,
+ GoodsTag = input.GoodsTag,
+ ExpireTime = DateTimeOffset.Now.AddMinutes(10),
+ NotifyUrl = _payCallBackOptions.WechatPayUrl,
+ Amount = new CreatePayPartnerTransactionJsapiRequest.Types.Amount() { Total = input.Total },
+ Payer = new CreatePayPartnerTransactionJsapiRequest.Types.Payer() { OpenId = input.OpenId }
+ };
+ var response = await _wechatTenpayClient.ExecuteCreatePayPartnerTransactionJsapiAsync(request);
+ if (!response.IsSuccessful())
+ throw Oops.Oh($"JSAPI 下单失败(状态码:{response.GetRawStatus()},错误代码:{response.ErrorCode},错误描述:{response.ErrorMessage})");
+ if (wechatPay == null)
+ {
+ // 保存订单信息
+ 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 CreatePayTransactionOutput
+ {
+ PrepayId = response.PrepayId,
+ OutTradeNumber = request.OutTradeNumber
+ };
+ }
+
+ ///
+ /// 获取支付订单详情 🔖
+ ///
+ ///
+ ///
+ [DisplayName("获取支付订单详情")]
+ public async Task GetPayInfo(string tradeId)
+ {
+ return await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == tradeId);
+ }
+
+ ///
+ /// 微信支付成功回调(商户直连) 🔖
+ ///
+ ///
+ [AllowAnonymous]
+ [DisplayName("微信支付成功回调(商户直连)")]
+ public async Task PayCallBack()
+ {
+ using var ms = new MemoryStream();
+ await App.HttpContext.Request.Body.CopyToAsync(ms);
+ var b = ms.ToArray();
+ var callbackJson = Encoding.UTF8.GetString(b);
+
+ var callbackModel = _wechatTenpayClient.DeserializeEvent(callbackJson);
+ if ("TRANSACTION.SUCCESS".Equals(callbackModel.EventType))
+ {
+ var callbackResource = _wechatTenpayClient.DecryptEventResource(callbackModel);
+
+ // 修改订单支付状态
+ var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == callbackResource.OutTradeNumber
+ && u.MerchantId == callbackResource.MerchantId);
+ if (wechatPay == null) return null;
+ //wechatPay.OpenId = callbackResource.Payer.OpenId; // 支付者标识
+ //wechatPay.MerchantId = callbackResource.MerchantId; // 微信商户号
+ //wechatPay.OutTradeNumber = callbackResource.OutTradeNumber; // 商户订单号
+ wechatPay.TransactionId = callbackResource.TransactionId; // 支付订单号
+ wechatPay.TradeType = callbackResource.TradeType; // 交易类型
+ wechatPay.TradeState = callbackResource.TradeState; // 交易状态
+ wechatPay.TradeStateDescription = callbackResource.TradeStateDescription; // 交易状态描述
+ wechatPay.BankType = callbackResource.BankType; // 付款银行类型
+ wechatPay.Total = callbackResource.Amount.Total; // 订单总金额
+ wechatPay.PayerTotal = callbackResource.Amount.PayerTotal; // 用户支付金额
+ wechatPay.SuccessTime = callbackResource.SuccessTime; // 支付完成时间
+
+ await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
+
+ return new WechatPayOutput()
+ {
+ Total = wechatPay.Total,
+ Attachment = wechatPay.Attachment,
+ GoodsTag = wechatPay.GoodsTag
+ };
+ }
+
+ return null;
+ }
+
+ ///
+ /// 微信支付成功回调(服务商模式) 🔖
+ ///
+ ///
+ [AllowAnonymous]
+ [DisplayName("微信支付成功回调(服务商模式)")]
+ public async Task PayPartnerCallBack()
+ {
+ using var ms = new MemoryStream();
+ await App.HttpContext.Request.Body.CopyToAsync(ms);
+ var b = ms.ToArray();
+ var callbackJson = Encoding.UTF8.GetString(b);
+
+ var callbackModel = _wechatTenpayClient.DeserializeEvent(callbackJson);
+ if ("TRANSACTION.SUCCESS".Equals(callbackModel.EventType))
+ {
+ var callbackResource = _wechatTenpayClient.DecryptEventResource(callbackModel);
+
+ // 修改订单支付状态
+ var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == callbackResource.OutTradeNumber
+ && u.MerchantId == callbackResource.MerchantId);
+ if (wechatPay == null) return;
+ //wechatPay.OpenId = callbackResource.Payer.OpenId; // 支付者标识
+ //wechatPay.MerchantId = callbackResource.MerchantId; // 微信商户号
+ //wechatPay.OutTradeNumber = callbackResource.OutTradeNumber; // 商户订单号
+ wechatPay.TransactionId = callbackResource.TransactionId; // 支付订单号
+ wechatPay.TradeType = callbackResource.TradeType; // 交易类型
+ wechatPay.TradeState = callbackResource.TradeState; // 交易状态
+ wechatPay.TradeStateDescription = callbackResource.TradeStateDescription; // 交易状态描述
+ wechatPay.BankType = callbackResource.BankType; // 付款银行类型
+ wechatPay.Total = callbackResource.Amount.Total; // 订单总金额
+ wechatPay.PayerTotal = callbackResource.Amount.PayerTotal; // 用户支付金额
+ wechatPay.SuccessTime = callbackResource.SuccessTime; // 支付完成时间
+
+ await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
+ }
+ }
+
+ ///
+ /// 退款申请 🔖
+ /// https://pay.weixin.qq.com/docs/merchant/apis/mini-program-payment/create.html
+ ///
+ ///
+ ///
+ [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($"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);
+ }
+ }
+
+ ///
+ /// 查询单笔退款(通过商户退款单号) 🔖
+ /// https://pay.weixin.qq.com/docs/merchant/apis/mini-program-payment/query-by-out-refund-no.html
+ ///
+ ///
+ ///
+ [DisplayName("微信查询单笔退款)")]
+ public async Task GetRefundByOutRefundNumber(string outRefundNumber)
+ {
+ var request = new GetRefundDomesticRefundByOutRefundNumberRequest()
+ {
+ OutRefundNumber = outRefundNumber
+ };
+ return await _wechatTenpayClient.ExecuteGetRefundDomesticRefundByOutRefundNumberAsync(request);
+ }
+
+ ///
+ /// 微信支付订单号查询(校正) 🔖
+ /// https://api.mch.weixin.qq.com/v3/pay/transactions/id/{transaction_id}
+ ///
+ ///
+ ///
+ [DisplayName("微信支付订单号查询(校正)")]
+ public async Task GetPayTransactionByIdAsync(string transactionId)
+ {
+ if (string.IsNullOrEmpty(transactionId))
+ throw Oops.Oh("TransactionId 不能为空");
+
+ if (string.IsNullOrEmpty(_wechatPayOptions.MerchantId) || string.IsNullOrEmpty(_wechatPayOptions.MerchantCertificateSerialNumber))
+ throw Oops.Oh("商户号或证书序列号不能为空,请检查支付配置");
+
+ var request = new GetPayTransactionByIdRequest()
+ {
+ MerchantId = _wechatPayOptions.MerchantId,
+ TransactionId = transactionId,
+ WechatpaySerialNumber = _wechatPayOptions.MerchantCertificateSerialNumber
+ };
+ var response = await _wechatTenpayClient.ExecuteGetPayTransactionByIdAsync(request);
+ if (response.TradeState == "SUCCESS" || response.TradeState == "CLOSED" || response.TradeState == "NOTPAY")
+ {
+ // 修正订单支付状态
+ var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.TransactionId == request.TransactionId && u.MerchantId == request.MerchantId);
+ if (wechatPay != null && string.IsNullOrEmpty(wechatPay.TradeState))
+ {
+ wechatPay.TradeType = response.TradeType; // 交易类型
+ wechatPay.TradeState = response.TradeState; // 交易状态
wechatPay.TradeStateDescription = response.TradeStateDescription; // 交易状态描述
- wechatPay.OpenId = response.Payer?.OpenId;// 付款用户OpenId
- wechatPay.BankType = response.BankType; // 付款银行类型
- wechatPay.PayerTotal = response.Amount?.PayerTotal; // 用户支付金额
- wechatPay.SuccessTime = response.SuccessTime; // 支付完成时间
- await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
- return wechatPay.Adapt();
- }
- }
- return response.Adapt();
- }
-
- ///
- /// 商户订单号查询(校正) 🔖
- /// https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}
- ///
- ///
- ///
- [DisplayName("微信商户订单号查询(校正)")]
- public async Task GetPayTransactionByOutTradeNumberAsync(string outTradeNumber)
- {
- if (string.IsNullOrEmpty(outTradeNumber))
- throw Oops.Oh("商户订单号(OutTradeNumber)不能为空");
-
- if (string.IsNullOrEmpty(_wechatPayOptions.MerchantId) || string.IsNullOrEmpty(_wechatPayOptions.MerchantCertificateSerialNumber))
- throw Oops.Oh("商户号或证书序列号不能为空,请检查支付配置");
-
- var request = new GetPayTransactionByOutTradeNumberRequest()
- {
- MerchantId = _wechatPayOptions.MerchantId,
- OutTradeNumber = outTradeNumber,
- WechatpaySerialNumber = _wechatPayOptions.MerchantCertificateSerialNumber,
- };
- var response = await _wechatTenpayClient.ExecuteGetPayTransactionByOutTradeNumberAsync(request);
- if (response.TradeState == "SUCCESS" || response.TradeState == "CLOSED" || response.TradeState == "NOTPAY")
- {
- // 修正订单支付状态
- 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.OpenId = response.Payer?.OpenId;// 付款用户OpenId
+ wechatPay.BankType = response.BankType; // 付款银行类型
+ wechatPay.PayerTotal = response.Amount?.PayerTotal; // 用户支付金额
+ wechatPay.SuccessTime = response.SuccessTime; // 支付完成时间
+ await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
+ return wechatPay.Adapt();
+ }
+ }
+ return response.Adapt();
+ }
+
+ ///
+ /// 商户订单号查询(校正) 🔖
+ /// https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}
+ ///
+ ///
+ ///
+ [DisplayName("微信商户订单号查询(校正)")]
+ public async Task GetPayTransactionByOutTradeNumberAsync(string outTradeNumber)
+ {
+ if (string.IsNullOrEmpty(outTradeNumber))
+ throw Oops.Oh("商户订单号(OutTradeNumber)不能为空");
+
+ if (string.IsNullOrEmpty(_wechatPayOptions.MerchantId) || string.IsNullOrEmpty(_wechatPayOptions.MerchantCertificateSerialNumber))
+ throw Oops.Oh("商户号或证书序列号不能为空,请检查支付配置");
+
+ var request = new GetPayTransactionByOutTradeNumberRequest()
+ {
+ MerchantId = _wechatPayOptions.MerchantId,
+ OutTradeNumber = outTradeNumber,
+ WechatpaySerialNumber = _wechatPayOptions.MerchantCertificateSerialNumber,
+ };
+ var response = await _wechatTenpayClient.ExecuteGetPayTransactionByOutTradeNumberAsync(request);
+ if (response.TradeState == "SUCCESS" || response.TradeState == "CLOSED" || response.TradeState == "NOTPAY")
+ {
+ // 修正订单支付状态
+ 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.OpenId = response.Payer?.OpenId;// 付款用户OpenId
- wechatPay.BankType = response.BankType; // 付款银行类型
- wechatPay.PayerTotal = response.Amount?.PayerTotal; // 用户支付金额
- wechatPay.SuccessTime = response.SuccessTime; // 支付完成时间
- await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
- return wechatPay.Adapt();
- }
- }
- return response.Adapt();
- }
-
- ///
- /// 获取支付记录分页列表 🔖
- ///
- /// PageSysWechatPayInput
- ///
- [DisplayName("获取支付记录分页列表")]
- public async Task> PageAsync(PageSysWechatPayInput input)
- {
- var query = _sysWechatPayRep.AsQueryable()
- .WhereIF(!string.IsNullOrWhiteSpace(input.OrderId), u => u.OrderId == input.OrderId)
- .WhereIF(!string.IsNullOrWhiteSpace(input.OrderStatus), 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.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.Where(u => u.SuccessTime < end);
- }
- }
- if (input.ExpireTimeRange != null && input.ExpireTimeRange.Count > 0)
- {
- DateTime? start = input.ExpireTimeRange[0];
- 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.Where(u => u.ExpireTime < end);
- }
- }
- query.OrderByDescending(u => u.CreateTime);
- return await query.ToPagedListAsync(input.Page, input.PageSize);
- }
-
- ///
- /// 根据支付Id获取退款信息列表
- ///
- ///
- ///
- [DisplayName("根据支付Id获取退款信息列表")]
- public async Task> GetRefundList([FromQuery] string transactionId)
- {
- return await _sysWechatRefundRep.AsQueryable().Where(u => u.TransactionId == transactionId).ToListAsync();
- }
+ wechatPay.OpenId = response.Payer?.OpenId;// 付款用户OpenId
+ wechatPay.BankType = response.BankType; // 付款银行类型
+ wechatPay.PayerTotal = response.Amount?.PayerTotal; // 用户支付金额
+ wechatPay.SuccessTime = response.SuccessTime; // 支付完成时间
+ await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
+ return wechatPay.Adapt();
+ }
+ }
+ return response.Adapt();
+ }
+
+ ///
+ /// 获取支付记录分页列表 🔖
+ ///
+ /// PageSysWechatPayInput
+ ///
+ [DisplayName("获取支付记录分页列表")]
+ public async Task> PageAsync(PageSysWechatPayInput input)
+ {
+ var query = _sysWechatPayRep.AsQueryable()
+ .WhereIF(!string.IsNullOrWhiteSpace(input.OrderId), u => u.OrderId == input.OrderId)
+ .WhereIF(!string.IsNullOrWhiteSpace(input.OrderStatus), 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.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.Where(u => u.SuccessTime < end);
+ }
+ }
+ if (input.ExpireTimeRange != null && input.ExpireTimeRange.Count > 0)
+ {
+ DateTime? start = input.ExpireTimeRange[0];
+ 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.Where(u => u.ExpireTime < end);
+ }
+ }
+ query.OrderByDescending(u => u.CreateTime);
+ return await query.ToPagedListAsync(input.Page, input.PageSize);
+ }
+
+ ///
+ /// 根据支付Id获取退款信息列表
+ ///
+ ///
+ ///
+ [DisplayName("根据支付Id获取退款信息列表")]
+ public async Task> GetRefundList([FromQuery] string transactionId)
+ {
+ return await _sysWechatRefundRep.AsQueryable().Where(u => u.TransactionId == transactionId).ToListAsync();
+ }
}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Utils/CodeGenUtil.cs b/Admin.NET/Admin.NET.Core/Utils/CodeGenUtil.cs
index 44cb8f7c..5b2fc195 100644
--- a/Admin.NET/Admin.NET.Core/Utils/CodeGenUtil.cs
+++ b/Admin.NET/Admin.NET.Core/Utils/CodeGenUtil.cs
@@ -68,6 +68,7 @@ public static class CodeGenUtil
{
return ConvertDataType_OracleSQL(dataType, length, scale); //达梦兼容Oracle,目前先这样实现
}
+
// OracleSQL数据类型对应的字段类型
public static string ConvertDataType_OracleSQL(string dataType, int? length, int? scale)
{