赛事积分
This commit is contained in:
parent
f7eed7e479
commit
5a86989ec5
@ -187,6 +187,8 @@ public class MyController : IDynamicApiController
|
||||
user.IdCardImageUrl = input.IdCardImageUrl;
|
||||
user.IdCardBackImageUrl = input.IdCardBackImageUrl;
|
||||
user.PassportPhotoUrl = null; // 清空护照图片
|
||||
user.Gender = (Gender)input.Gender.Value;
|
||||
user.BirthDate = input.BirthDate.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -66,10 +66,15 @@ public class ScoreListOutput
|
||||
public string UnitName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 名次
|
||||
/// 名次(数字)
|
||||
/// </summary>
|
||||
public int Rank { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 名次(汉字)
|
||||
/// </summary>
|
||||
public string RankText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 性别
|
||||
/// </summary>
|
||||
@ -250,13 +255,13 @@ public class ScoreImportDto
|
||||
/// <summary>
|
||||
/// 名次(数字)
|
||||
/// </summary>
|
||||
[ExcelColumnName("名次")]
|
||||
[ExcelColumnName("名次(数字)")]
|
||||
public int Rank { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 名次说明(文字描述,如"冠军"、"亚军"等)
|
||||
/// 名次(汉字)
|
||||
/// </summary>
|
||||
[ExcelColumnName("名次说明")]
|
||||
[ExcelColumnName("名次(汉字)")]
|
||||
public string RankText { get; set; }
|
||||
}
|
||||
|
||||
|
||||
@ -4,8 +4,12 @@ using Microsoft.Extensions.Logging;
|
||||
using YD_Event.Application.Event.Dtos;
|
||||
using YD_Event.Core.Entities;
|
||||
using YD_Event.Core.Enum;
|
||||
using YD_Event.Core.Domain.Export;
|
||||
using MiniExcelLibs;
|
||||
using SqlSugar;
|
||||
using OfficeOpenXml;
|
||||
using OfficeOpenXml.Style;
|
||||
using System.Drawing;
|
||||
|
||||
namespace YD_Event.Application.Event;
|
||||
|
||||
@ -14,11 +18,40 @@ namespace YD_Event.Application.Event;
|
||||
/// </summary>
|
||||
public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
{
|
||||
private static readonly string[] ChineseNumbers = { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十" };
|
||||
|
||||
/// <summary>
|
||||
/// 将数字名次转换为汉字形式
|
||||
/// </summary>
|
||||
private static string ConvertRankToChinese(int rank)
|
||||
{
|
||||
if (rank <= 0)
|
||||
return string.Empty;
|
||||
|
||||
if (rank <= 10)
|
||||
return $"第{ChineseNumbers[rank]}名";
|
||||
|
||||
if (rank < 20)
|
||||
return $"第十{ChineseNumbers[rank % 10]}名";
|
||||
|
||||
if (rank % 10 == 0)
|
||||
return $"第{ChineseNumbers[rank / 10]}十名";
|
||||
|
||||
return $"第{ChineseNumbers[rank / 10]}十{ChineseNumbers[rank % 10]}名";
|
||||
}
|
||||
|
||||
private readonly ISqlSugarRepository<EventRegistrationPerson> _personRepository;
|
||||
private readonly ISqlSugarRepository<EventResult> _resultRepository;
|
||||
private readonly ISqlSugarRepository<EventCertificate> _certificateRepository;
|
||||
private readonly ISqlSugarRepository<EventRegistration> _registrationRepository;
|
||||
private readonly ISqlSugarRepository<CertificateTemplate> _templateRepository;
|
||||
private readonly ISqlSugarRepository<YD_Event.Core.Entities.Project> _projectRepository;
|
||||
private readonly ISqlSugarRepository<TeamMember> _teamMemberRepository;
|
||||
private readonly ISqlSugarRepository<EventInfo> _eventRepository;
|
||||
private readonly ISqlSugarRepository<PointsRule> _pointsRuleRepository;
|
||||
private readonly ISqlSugarRepository<PointsRuleDetail> _pointsRuleDetailRepository;
|
||||
private readonly ISqlSugarRepository<PointsRecord> _pointsRecordRepository;
|
||||
private readonly ISqlSugarRepository<YD_Event.Core.Entities.AppUser> _appUserRepository;
|
||||
private readonly IIdGenerator _idGenerator;
|
||||
private readonly ILogger<EventScoreService> _logger;
|
||||
|
||||
@ -28,6 +61,13 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
ISqlSugarRepository<EventCertificate> certificateRepository,
|
||||
ISqlSugarRepository<EventRegistration> registrationRepository,
|
||||
ISqlSugarRepository<CertificateTemplate> templateRepository,
|
||||
ISqlSugarRepository<YD_Event.Core.Entities.Project> projectRepository,
|
||||
ISqlSugarRepository<TeamMember> teamMemberRepository,
|
||||
ISqlSugarRepository<EventInfo> eventRepository,
|
||||
ISqlSugarRepository<PointsRule> pointsRuleRepository,
|
||||
ISqlSugarRepository<PointsRuleDetail> pointsRuleDetailRepository,
|
||||
ISqlSugarRepository<PointsRecord> pointsRecordRepository,
|
||||
ISqlSugarRepository<YD_Event.Core.Entities.AppUser> appUserRepository,
|
||||
IIdGenerator idGenerator,
|
||||
ILogger<EventScoreService> logger) : base(resultRepository)
|
||||
{
|
||||
@ -36,6 +76,13 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
_certificateRepository = certificateRepository;
|
||||
_registrationRepository = registrationRepository;
|
||||
_templateRepository = templateRepository;
|
||||
_projectRepository = projectRepository;
|
||||
_teamMemberRepository = teamMemberRepository;
|
||||
_eventRepository = eventRepository;
|
||||
_pointsRuleRepository = pointsRuleRepository;
|
||||
_pointsRuleDetailRepository = pointsRuleDetailRepository;
|
||||
_pointsRecordRepository = pointsRecordRepository;
|
||||
_appUserRepository = appUserRepository;
|
||||
_idGenerator = idGenerator;
|
||||
_logger = logger;
|
||||
}
|
||||
@ -46,7 +93,7 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
[DisplayName("运动员成绩列表")]
|
||||
public async Task<PageResult<ScoreListOutput>> PageAthlete(ScoreQueryInput input)
|
||||
{
|
||||
return await _personRepository.AsQueryable()
|
||||
var pageResult = await _personRepository.AsQueryable()
|
||||
.LeftJoin<EventRegistration>((p, r) => p.RegistrationId == r.Id)
|
||||
.LeftJoin<EventResult>((p, r, res) => p.Id == res.RegistrationPersonId)
|
||||
.LeftJoin<EventCertificate>((p, r, res, c) => res.Id == c.ResultId)
|
||||
@ -68,32 +115,79 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
CertificateId = c.Id
|
||||
})
|
||||
.ToPagedListAsync(input);
|
||||
|
||||
foreach (var item in pageResult.Rows)
|
||||
{
|
||||
item.RankText = ConvertRankToChinese(item.Rank);
|
||||
}
|
||||
|
||||
return pageResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 教练/领队列表
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 通过运动员所在的团队关联获取教练和领队人员信息
|
||||
/// </remarks>
|
||||
[DisplayName("教练领队列表")]
|
||||
public async Task<PageResult<CoachLeaderListOutput>> PageCoachLeader(CoachLeaderQueryInput input)
|
||||
{
|
||||
return await _personRepository.AsQueryable()
|
||||
.LeftJoin<EventCertificate>((p, c) => p.Id == c.ParticipationRecordId)
|
||||
.InnerJoin<EventRegistration>((p, c, r) => p.RegistrationId == r.Id)
|
||||
.Where((p, c, r) => r.EventId == input.EventId && p.PersonType == input.PersonType)
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.Name), p => p.Name.Contains(input.Name))
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.Mobile), p => p.Phone.Contains(input.Mobile))
|
||||
.WhereIF(input.Gender.HasValue, p => p.Gender == input.Gender.Value)
|
||||
.Select((p, c) => new CoachLeaderListOutput
|
||||
// 步骤1:获取该赛事的所有运动员的 UserId
|
||||
var athleteUserIds = await _personRepository.AsQueryable()
|
||||
.InnerJoin<EventRegistration>((p, r) => p.RegistrationId == r.Id)
|
||||
.Where((p, r) => r.EventId == input.EventId && p.PersonType == PersonType.Athlete)
|
||||
.Select(p => p.UserId)
|
||||
.ToListAsync();
|
||||
|
||||
if (!athleteUserIds.Any())
|
||||
{
|
||||
return new PageResult<CoachLeaderListOutput>();
|
||||
}
|
||||
|
||||
// 步骤2:通过运动员的 UserId 找到对应的 TeamId
|
||||
var teamIds = await _teamMemberRepository.AsQueryable()
|
||||
.Where(tm => athleteUserIds.Contains(tm.UserId) && !tm.DeleteMark)
|
||||
.Select(tm => tm.TeamId)
|
||||
.Distinct()
|
||||
.ToListAsync();
|
||||
|
||||
if (!teamIds.Any())
|
||||
{
|
||||
return new PageResult<CoachLeaderListOutput>();
|
||||
}
|
||||
|
||||
// 步骤3:通过 TeamId 获取同团队的教练/领队的 UserId
|
||||
var coachLeaderUserIds = await _teamMemberRepository.AsQueryable()
|
||||
.Where(tm => teamIds.Contains(tm.TeamId) && tm.PersonType == input.PersonType && !tm.DeleteMark)
|
||||
.Select(tm => tm.UserId)
|
||||
.Distinct()
|
||||
.ToListAsync();
|
||||
|
||||
if (!coachLeaderUserIds.Any())
|
||||
{
|
||||
return new PageResult<CoachLeaderListOutput>();
|
||||
}
|
||||
|
||||
// 步骤4:从 AppUser 表获取教练/领队的详细信息(需要关联查询)
|
||||
var userQuery = _appUserRepository.AsQueryable()
|
||||
.Where(p => coachLeaderUserIds.Contains(p.Id))
|
||||
.Where(p=> p.PersonType == input.PersonType);
|
||||
|
||||
var pageResult = await userQuery
|
||||
.Select(p => new CoachLeaderListOutput
|
||||
{
|
||||
Id = p.Id,
|
||||
Name = p.Name,
|
||||
Age = p.Age,
|
||||
Gender = p.Gender.ToString(),
|
||||
Gender = p.Gender.Description(),
|
||||
IdCardNumber = p.IdCard,
|
||||
Mobile = p.Phone,
|
||||
CertificateId = c.Id
|
||||
CertificateId = 0 // 需要单独查询,此处先设为0
|
||||
})
|
||||
.ToPagedListAsync(input);
|
||||
|
||||
return pageResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -142,7 +236,7 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
p.ProjectName,
|
||||
p.GroupName,
|
||||
p.RegistrationId,
|
||||
p.ProjectId
|
||||
p.ProjectId
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
@ -152,6 +246,11 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
var personDict = allPersons
|
||||
.GroupBy(p => $"{p.Name}_{p.ProjectName}_{p.GroupName}")
|
||||
.ToDictionary(g => g.Key, g => g.First());
|
||||
|
||||
// 预加载项目信息,用于获取项目类型名称
|
||||
var projectIds = allPersons.Select(p => p.ProjectId).Distinct().ToList();
|
||||
var projects = await _projectRepository.GetListAsync(x => projectIds.Contains(x.Id));
|
||||
var projectDict = projects.ToDictionary(p => p.Id, p => p.ProjectType.Description());
|
||||
|
||||
// 步骤3:预加载该赛事的所有成绩记录
|
||||
var personIds = allPersons.Select(p => p.Id).ToList();
|
||||
@ -182,6 +281,7 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
existingResult.Score = row.Score;
|
||||
existingResult.Rank = row.Rank;
|
||||
existingResult.Remark = row.RankText;
|
||||
existingResult.ProjectTypeName = projectDict.TryGetValue(person.ProjectId, out var projectTypeName) ? projectTypeName : string.Empty;
|
||||
existingResult.UpdatedTime = now;
|
||||
resultsToUpdate.Add(existingResult);
|
||||
}
|
||||
@ -197,6 +297,7 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
ProjectId = person.ProjectId,
|
||||
ParticipantName = person.Name,
|
||||
GroupName = person.GroupName,
|
||||
ProjectTypeName = projectDict.TryGetValue(person.ProjectId, out var projectTypeName) ? projectTypeName : string.Empty,
|
||||
Score = row.Score,
|
||||
Rank = row.Rank,
|
||||
Remark = row.RankText,
|
||||
@ -370,35 +471,29 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
/// <summary>
|
||||
/// 查看证书接口
|
||||
/// </summary>
|
||||
/// <param name="id">报名人员ID (EventRegistrationPerson的Id)</param>
|
||||
/// <param name="input">输入参数</param>
|
||||
/// <returns>证书详情</returns>
|
||||
[DisplayName("查看证书")]
|
||||
[HttpGet("/api/EventScore/GetCertificateDetail/{id}")]
|
||||
public async Task<IActionResult> GetCertificateDetail([FromRoute] long id)
|
||||
public async Task<object> GetCertificateDetail(YD_Event.Application.Certificate.Dtos.IdInput input)
|
||||
{
|
||||
if (id <= 0)
|
||||
if (input.Id <= 0)
|
||||
{
|
||||
return new BadRequestObjectResult(new { message = "无效的 ID" });
|
||||
throw Oops.Bah("无效的 ID");
|
||||
}
|
||||
|
||||
var personExists = await _personRepository.IsAnyAsync(x => x.Id == id);
|
||||
var personExists = await _personRepository.IsAnyAsync(x => x.Id == input.Id);
|
||||
if (!personExists)
|
||||
{
|
||||
return new NotFoundObjectResult(new { message = "人员记录不存在" });
|
||||
throw Oops.Bah("人员记录不存在");
|
||||
}
|
||||
|
||||
var cert = await _certificateRepository.GetFirstAsync(x => x.ParticipationRecordId == id);
|
||||
var cert = await _certificateRepository.GetFirstAsync(x => x.ParticipationRecordId == input.Id);
|
||||
if (cert == null)
|
||||
{
|
||||
return new NotFoundObjectResult(new { message = "未找到对应的证书信息" });
|
||||
throw Oops.Bah("未找到对应的证书信息");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cert.CertificateUrl))
|
||||
{
|
||||
return new NoContentResult();
|
||||
}
|
||||
|
||||
return new JsonResult(new { url = cert.CertificateUrl });
|
||||
return new { Url = cert.CertificateUrl };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -442,31 +537,47 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
[HttpGet]
|
||||
public IActionResult DownloadTemplate()
|
||||
{
|
||||
var headers = new string[] {
|
||||
"赛事地址",
|
||||
"项目",
|
||||
"组别",
|
||||
"姓名",
|
||||
"联系方式",
|
||||
"单位",
|
||||
"成绩",
|
||||
"名次",
|
||||
"名次说明"
|
||||
};
|
||||
|
||||
var value = new List<Dictionary<string, object>>
|
||||
{
|
||||
headers.ToDictionary(h => h, h => (object)null)
|
||||
};
|
||||
|
||||
using var memoryStream = new MemoryStream();
|
||||
memoryStream.SaveAs(value);
|
||||
|
||||
return new FileContentResult(memoryStream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||
var exporter = new ScoreTemplateExporter();
|
||||
var bytes = exporter.ExportAsync().GetAwaiter().GetResult();
|
||||
|
||||
return new FileContentResult(bytes, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||
{
|
||||
FileDownloadName = "成绩导入模板.xlsx"
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 成绩模板导出器
|
||||
/// </summary>
|
||||
private class ScoreTemplateExporter : ExcelExportBase
|
||||
{
|
||||
public override async Task<byte[]> ExportAsync()
|
||||
{
|
||||
CreateWorksheet("成绩导入模板");
|
||||
|
||||
var headers = new string[] {
|
||||
"赛事地址",
|
||||
"项目",
|
||||
"组别",
|
||||
"姓名",
|
||||
"联系方式",
|
||||
"单位",
|
||||
"成绩",
|
||||
"名次(汉字)",
|
||||
"名次(数字)"
|
||||
};
|
||||
|
||||
var headerColor = Color.FromArgb(204, 255, 204);
|
||||
SetHeaders(headers, 1, headerColor, 11);
|
||||
|
||||
var widths = new double[] { 15, 15, 15, 12, 15, 20, 15, 15, 15 };
|
||||
SetColumnWidths(widths);
|
||||
|
||||
SetRowHeight(1, 25);
|
||||
|
||||
return await GetAsByteArrayAsync();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导出证书
|
||||
@ -565,4 +676,144 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发放积分输入模型
|
||||
/// </summary>
|
||||
public class IssuePointsInput
|
||||
{
|
||||
public long EventId { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发放积分
|
||||
/// </summary>
|
||||
[DisplayName("发放积分")]
|
||||
[HttpPost("issuePoints")]
|
||||
[UnitOfWork]
|
||||
public async Task<object> IssuePoints([FromBody] IssuePointsInput input)
|
||||
{
|
||||
_logger.LogInformation("开始发放积分,赛事ID={EventId}", input.EventId);
|
||||
|
||||
var eventInfo = await _eventRepository.GetByIdAsync(input.EventId);
|
||||
if (eventInfo == null)
|
||||
{
|
||||
throw Oops.Bah("赛事不存在");
|
||||
}
|
||||
|
||||
if (!eventInfo.PointsRuleId.HasValue)
|
||||
{
|
||||
throw Oops.Bah("该赛事未配置积分规则");
|
||||
}
|
||||
|
||||
var pointsRule = await _pointsRuleRepository.GetByIdAsync(eventInfo.PointsRuleId.Value);
|
||||
if (pointsRule == null)
|
||||
{
|
||||
throw Oops.Bah("积分规则不存在");
|
||||
}
|
||||
|
||||
if (pointsRule.Status != AvailabilityStatus.Enable)
|
||||
{
|
||||
throw Oops.Bah("积分规则未启用");
|
||||
}
|
||||
|
||||
var ruleDetails = await _pointsRuleDetailRepository.AsQueryable()
|
||||
.Where(x => x.PointsRuleId == pointsRule.Id)
|
||||
.OrderBy(x => x.StartRank)
|
||||
.ToListAsync();
|
||||
|
||||
var results = await _resultRepository.AsQueryable()
|
||||
.InnerJoin<EventRegistrationPerson>((r, p) => r.RegistrationPersonId == p.Id)
|
||||
.Where((r, p) => r.EventId == input.EventId && r.Rank > 0)
|
||||
.Select((r, p) => new
|
||||
{
|
||||
ResultId = r.Id,
|
||||
UserId = p.UserId,
|
||||
ProjectId = r.ProjectId,
|
||||
GroupName = r.GroupName,
|
||||
Rank = r.Rank,
|
||||
ParticipantName = r.ParticipantName,
|
||||
ProjectIdForRecord = r.ProjectId
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
if (!results.Any())
|
||||
{
|
||||
throw Oops.Bah("没有可发放积分的成绩记录");
|
||||
}
|
||||
|
||||
var existingRecords = await _pointsRecordRepository.AsQueryable()
|
||||
.Where(x => x.EventId == input.EventId)
|
||||
.Select(x => x.Remark)
|
||||
.ToListAsync();
|
||||
|
||||
var processedResultIds = existingRecords
|
||||
.Where(x => !string.IsNullOrEmpty(x) && x.StartsWith("ResultId:"))
|
||||
.Select(x =>
|
||||
{
|
||||
var parts = x.Split('|');
|
||||
var resultIdPart = parts.FirstOrDefault(p => p.StartsWith("ResultId:"));
|
||||
return resultIdPart != null && long.TryParse(resultIdPart.Replace("ResultId:", ""), out var id) ? id : 0;
|
||||
})
|
||||
.Where(x => x > 0)
|
||||
.ToHashSet();
|
||||
|
||||
int successCount = 0;
|
||||
int skipCount = 0;
|
||||
var pointsRecords = new List<PointsRecord>();
|
||||
|
||||
foreach (var result in results)
|
||||
{
|
||||
if (processedResultIds.Contains(result.ResultId))
|
||||
{
|
||||
skipCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
int pointsToAward = 0;
|
||||
|
||||
if (pointsRule.ParticipationPoints.HasValue && pointsRule.ParticipationPoints.Value > 0)
|
||||
{
|
||||
pointsToAward += pointsRule.ParticipationPoints.Value;
|
||||
}
|
||||
|
||||
var matchingDetail = ruleDetails.FirstOrDefault(d => result.Rank >= d.StartRank && result.Rank <= d.EndRank);
|
||||
if (matchingDetail != null)
|
||||
{
|
||||
pointsToAward += matchingDetail.Points;
|
||||
}
|
||||
|
||||
if (pointsToAward > 0)
|
||||
{
|
||||
var record = new PointsRecord
|
||||
{
|
||||
Id = _idGenerator.NextId(),
|
||||
UserId = result.UserId,
|
||||
Type = PointsOperationType.Acquire,
|
||||
EventId = input.EventId,
|
||||
ProjectId = result.ProjectIdForRecord,
|
||||
Points = pointsToAward,
|
||||
Remark = $"ResultId:{result.ResultId}|Rank:{result.Rank}",
|
||||
Status = AvailabilityStatus.Enable,
|
||||
CreatedTime = DateTime.Now
|
||||
};
|
||||
pointsRecords.Add(record);
|
||||
successCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (pointsRecords.Any())
|
||||
{
|
||||
await _pointsRecordRepository.InsertRangeAsync(pointsRecords);
|
||||
}
|
||||
|
||||
_logger.LogInformation("积分发放完成:赛事ID={EventId},成功发放={SuccessCount},跳过={SkipCount}",
|
||||
input.EventId, successCount, skipCount);
|
||||
|
||||
return new
|
||||
{
|
||||
Success = true,
|
||||
Message = $"积分发放成功!已发放 {successCount} 条积分记录,跳过 {skipCount} 条已发放记录"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using YD_Event.Core.Entities;
|
||||
using YD_Event.Core.Enum;
|
||||
using YD_Event.Core.Infrastructure.WeChat;
|
||||
using YD_Event.Core.Infrastructure.WeChat.Dto;
|
||||
|
||||
namespace YD_Event.Application.Event;
|
||||
|
||||
@ -31,6 +35,8 @@ public class PaymentExpirationBackgroundService : BackgroundService
|
||||
while (await _timer.WaitForNextTickAsync(stoppingToken))
|
||||
{
|
||||
await ProcessExpiredPaymentsAsync(stoppingToken);
|
||||
await ProcessUnpaidWeChatOrdersAsync(stoppingToken);
|
||||
await ProcessRefundingWeChatOrdersAsync(stoppingToken);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
@ -90,6 +96,383 @@ public class PaymentExpirationBackgroundService : BackgroundService
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理微信未支付订单:定期检查并更新订单状态
|
||||
/// </summary>
|
||||
private async Task ProcessUnpaidWeChatOrdersAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("开始检查微信未支付订单");
|
||||
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var registrationRepository = scope.ServiceProvider.GetRequiredService<ISqlSugarRepository<EventRegistration>>();
|
||||
var orderRepository = scope.ServiceProvider.GetRequiredService<ISqlSugarRepository<YD_Event.Core.Entities.Order>>();
|
||||
var weChatPayConfigRepository = scope.ServiceProvider.GetRequiredService<ISqlSugarRepository<WeChatPayConfig>>();
|
||||
var weChatPayService = scope.ServiceProvider.GetRequiredService<WeChatPayService>();
|
||||
var paymentRepository = scope.ServiceProvider.GetRequiredService<ISqlSugarRepository<EventRegistrationPayment>>();
|
||||
|
||||
var now = DateTime.Now;
|
||||
|
||||
var unpaidRegistrations = await registrationRepository.AsQueryable()
|
||||
.Where(x => x.PaymentMethod == 2
|
||||
&& x.PaymentMethodType == PaymentMethodType.WeChatPay
|
||||
&& x.PaymentStatus == 0
|
||||
&& !x.DeleteMark)
|
||||
.OrderBy(x => x.CreatedTime)
|
||||
.Take(50)
|
||||
.ToListAsync(stoppingToken);
|
||||
|
||||
if (!unpaidRegistrations.Any())
|
||||
{
|
||||
_logger.LogInformation("没有发现需要检查的微信未支付订单");
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.LogInformation("发现 {Count} 个微信未支付订单需要检查", unpaidRegistrations.Count);
|
||||
|
||||
foreach (var registration in unpaidRegistrations)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(registration.OrderNo))
|
||||
{
|
||||
_logger.LogWarning("报名记录 {RegistrationId} 没有订单编号", registration.Id);
|
||||
continue;
|
||||
}
|
||||
|
||||
var order = await orderRepository.GetFirstAsync(o => o.OrderNo == registration.OrderNo, stoppingToken);
|
||||
if (order == null)
|
||||
{
|
||||
_logger.LogWarning("找不到订单编号 {OrderNo} 对应的订单记录", registration.OrderNo);
|
||||
continue;
|
||||
}
|
||||
|
||||
var weChatPayConfig = await weChatPayConfigRepository.GetFirstAsync(
|
||||
c => c.MerchantId == order.MerchantId && c.Status == AvailabilityStatus.Enable && !c.DeleteMark,
|
||||
stoppingToken);
|
||||
|
||||
if (weChatPayConfig == null)
|
||||
{
|
||||
_logger.LogWarning("商户 {MerchantId} 没有找到可用的微信支付配置", order.MerchantId);
|
||||
continue;
|
||||
}
|
||||
|
||||
var queryResult = await weChatPayService.QueryOrderAsync(weChatPayConfig, registration.OrderNo);
|
||||
|
||||
if (!queryResult.Success)
|
||||
{
|
||||
_logger.LogWarning("查询订单 {OrderNo} 状态失败: {Message}", registration.OrderNo, queryResult.Message);
|
||||
continue;
|
||||
}
|
||||
|
||||
_logger.LogInformation("订单 {OrderNo} 微信支付状态: {TradeState}", registration.OrderNo, queryResult.TradeState);
|
||||
|
||||
if (queryResult.TradeState == "SUCCESS")
|
||||
{
|
||||
await ProcessWeChatPaymentSuccessAsync(
|
||||
registration,
|
||||
order,
|
||||
queryResult,
|
||||
now,
|
||||
registrationRepository,
|
||||
orderRepository,
|
||||
paymentRepository,
|
||||
stoppingToken);
|
||||
}
|
||||
else if (queryResult.TradeState == "CLOSED" || queryResult.TradeState == "REVOKED")
|
||||
{
|
||||
await ProcessWeChatPaymentClosedAsync(
|
||||
registration,
|
||||
order,
|
||||
now,
|
||||
registrationRepository,
|
||||
orderRepository,
|
||||
stoppingToken);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "处理报名记录 {RegistrationId} 时发生错误", registration.Id);
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogInformation("微信未支付订单检查完成");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "检查微信未支付订单时发生错误");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理微信支付成功的订单
|
||||
/// </summary>
|
||||
private async Task ProcessWeChatPaymentSuccessAsync(
|
||||
EventRegistration registration,
|
||||
YD_Event.Core.Entities.Order order,
|
||||
WeChatPayQueryResult queryResult,
|
||||
DateTime now,
|
||||
ISqlSugarRepository<EventRegistration> registrationRepository,
|
||||
ISqlSugarRepository<YD_Event.Core.Entities.Order> orderRepository,
|
||||
ISqlSugarRepository<EventRegistrationPayment> paymentRepository,
|
||||
CancellationToken stoppingToken)
|
||||
{
|
||||
_logger.LogInformation("订单 {OrderNo} 支付成功,更新订单状态", registration.OrderNo);
|
||||
|
||||
var paymentTime = queryResult.SuccessTime.HasValue ? queryResult.SuccessTime.Value.LocalDateTime : now;
|
||||
|
||||
registration.PaymentStatus = 1;
|
||||
registration.PaymentTime = paymentTime;
|
||||
registration.UpdatedTime = now;
|
||||
await registrationRepository.UpdateAsync(registration);
|
||||
|
||||
order.OrderStatus = OrderStatus.Paid;
|
||||
order.PaymentTime = paymentTime;
|
||||
order.UpdatedTime = now;
|
||||
await orderRepository.UpdateAsync(order);
|
||||
|
||||
var existingPayment = await paymentRepository.GetFirstAsync(p => p.RegistrationId == registration.Id, stoppingToken);
|
||||
if (existingPayment != null)
|
||||
{
|
||||
existingPayment.PaymentStatus = 1;
|
||||
existingPayment.PaymentTime = paymentTime;
|
||||
existingPayment.UpdatedTime = now;
|
||||
if (!string.IsNullOrEmpty(queryResult.TransactionId))
|
||||
{
|
||||
existingPayment.TransactionNo = queryResult.TransactionId;
|
||||
}
|
||||
await paymentRepository.UpdateAsync(existingPayment);
|
||||
}
|
||||
else
|
||||
{
|
||||
var idGenerator = _serviceProvider.GetRequiredService<IIdGenerator>();
|
||||
var newPayment = new EventRegistrationPayment
|
||||
{
|
||||
Id = idGenerator.NextId(),
|
||||
RegistrationId = registration.Id,
|
||||
TransactionNo = queryResult.TransactionId ?? string.Empty,
|
||||
PaymentChannel = 1,
|
||||
PaymentAmount = order.ActualAmount,
|
||||
PaymentTime = paymentTime,
|
||||
PaymentStatus = 1,
|
||||
RefundStatus = 0,
|
||||
RefundAmount = 0,
|
||||
PayeeAccount = string.Empty,
|
||||
CreatedTime = now,
|
||||
CreatedUserId = registration.CreatedUserId
|
||||
};
|
||||
await paymentRepository.InsertAsync(newPayment);
|
||||
}
|
||||
|
||||
_logger.LogInformation("订单 {OrderNo} 支付状态更新成功", registration.OrderNo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理微信支付关闭的订单
|
||||
/// </summary>
|
||||
private async Task ProcessWeChatPaymentClosedAsync(
|
||||
EventRegistration registration,
|
||||
YD_Event.Core.Entities.Order order,
|
||||
DateTime now,
|
||||
ISqlSugarRepository<EventRegistration> registrationRepository,
|
||||
ISqlSugarRepository<YD_Event.Core.Entities.Order> orderRepository,
|
||||
CancellationToken stoppingToken)
|
||||
{
|
||||
_logger.LogInformation("订单 {OrderNo} 支付已关闭,更新订单状态为已取消", registration.OrderNo);
|
||||
|
||||
registration.PaymentStatus = 4;
|
||||
registration.UpdatedTime = now;
|
||||
await registrationRepository.UpdateAsync(registration);
|
||||
|
||||
order.OrderStatus = OrderStatus.Cancelled;
|
||||
order.UpdatedTime = now;
|
||||
await orderRepository.UpdateAsync(order);
|
||||
|
||||
_logger.LogInformation("订单 {OrderNo} 状态更新为已取消成功", registration.OrderNo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理微信退款中的订单
|
||||
/// </summary>
|
||||
private async Task ProcessRefundingWeChatOrdersAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("开始检查微信退款中的订单");
|
||||
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var refundRecordRepository = scope.ServiceProvider.GetRequiredService<ISqlSugarRepository<RefundRecord>>();
|
||||
var registrationRepository = scope.ServiceProvider.GetRequiredService<ISqlSugarRepository<EventRegistration>>();
|
||||
var orderRepository = scope.ServiceProvider.GetRequiredService<ISqlSugarRepository<YD_Event.Core.Entities.Order>>();
|
||||
var weChatPayConfigRepository = scope.ServiceProvider.GetRequiredService<ISqlSugarRepository<WeChatPayConfig>>();
|
||||
var weChatPayService = scope.ServiceProvider.GetRequiredService<WeChatPayService>();
|
||||
var paymentRepository = scope.ServiceProvider.GetRequiredService<ISqlSugarRepository<EventRegistrationPayment>>();
|
||||
|
||||
var now = DateTime.Now;
|
||||
|
||||
var refundingRecords = await refundRecordRepository.AsQueryable()
|
||||
.Where(x => x.RefundStatus == 0 && !x.DeleteMark)
|
||||
.OrderBy(x => x.ApplyTime)
|
||||
.Take(50)
|
||||
.ToListAsync(stoppingToken);
|
||||
|
||||
if (!refundingRecords.Any())
|
||||
{
|
||||
_logger.LogInformation("没有发现需要检查的微信退款订单");
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.LogInformation("发现 {Count} 个微信退款订单需要检查", refundingRecords.Count);
|
||||
|
||||
foreach (var refundRecord in refundingRecords)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(refundRecord.OutRefundNo))
|
||||
{
|
||||
_logger.LogWarning("退款记录 {RefundRecordId} 没有退款单号", refundRecord.Id);
|
||||
continue;
|
||||
}
|
||||
|
||||
WeChatPayConfig? weChatPayConfig = null;
|
||||
if (refundRecord.WeChatPayConfigId.HasValue)
|
||||
{
|
||||
weChatPayConfig = await weChatPayConfigRepository.GetByIdAsync(refundRecord.WeChatPayConfigId.Value, stoppingToken);
|
||||
}
|
||||
else if (refundRecord.MerchantId.HasValue)
|
||||
{
|
||||
weChatPayConfig = await weChatPayConfigRepository.GetFirstAsync(
|
||||
c => c.MerchantId == refundRecord.MerchantId && c.Status == AvailabilityStatus.Enable && !c.DeleteMark,
|
||||
stoppingToken);
|
||||
}
|
||||
|
||||
if (weChatPayConfig == null)
|
||||
{
|
||||
_logger.LogWarning("退款记录 {RefundRecordId} 没有找到可用的微信支付配置", refundRecord.Id);
|
||||
continue;
|
||||
}
|
||||
|
||||
var queryResult = await weChatPayService.QueryRefundAsync(weChatPayConfig, refundRecord.OutRefundNo);
|
||||
|
||||
if (!queryResult.Success)
|
||||
{
|
||||
_logger.LogWarning("查询退款 {OutRefundNo} 状态失败: {Message}", refundRecord.OutRefundNo, queryResult.Message);
|
||||
continue;
|
||||
}
|
||||
|
||||
_logger.LogInformation("退款 {OutRefundNo} 微信退款状态: {RefundStatus}", refundRecord.OutRefundNo, queryResult.RefundStatus);
|
||||
|
||||
if (queryResult.RefundStatus == "SUCCESS")
|
||||
{
|
||||
await ProcessWeChatRefundSuccessAsync(
|
||||
refundRecord,
|
||||
queryResult,
|
||||
now,
|
||||
refundRecordRepository,
|
||||
registrationRepository,
|
||||
orderRepository,
|
||||
paymentRepository,
|
||||
stoppingToken);
|
||||
}
|
||||
else if (queryResult.RefundStatus == "CLOSED" || queryResult.RefundStatus == "ABNORMAL")
|
||||
{
|
||||
await ProcessWeChatRefundFailedAsync(
|
||||
refundRecord,
|
||||
queryResult,
|
||||
now,
|
||||
refundRecordRepository,
|
||||
stoppingToken);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "处理退款记录 {RefundRecordId} 时发生错误", refundRecord.Id);
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogInformation("微信退款订单检查完成");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "检查微信退款订单时发生错误");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理微信退款成功的订单
|
||||
/// </summary>
|
||||
private async Task ProcessWeChatRefundSuccessAsync(
|
||||
RefundRecord refundRecord,
|
||||
WeChatRefundQueryResult queryResult,
|
||||
DateTime now,
|
||||
ISqlSugarRepository<RefundRecord> refundRecordRepository,
|
||||
ISqlSugarRepository<EventRegistration> registrationRepository,
|
||||
ISqlSugarRepository<YD_Event.Core.Entities.Order> orderRepository,
|
||||
ISqlSugarRepository<EventRegistrationPayment> paymentRepository,
|
||||
CancellationToken stoppingToken)
|
||||
{
|
||||
_logger.LogInformation("退款 {OutRefundNo} 成功,更新退款状态", refundRecord.OutRefundNo);
|
||||
|
||||
var successTime = queryResult.SuccessTime.HasValue ? queryResult.SuccessTime.Value.LocalDateTime : now;
|
||||
|
||||
refundRecord.RefundStatus = 1;
|
||||
refundRecord.SuccessTime = successTime;
|
||||
refundRecord.RefundId = queryResult.RefundId ?? refundRecord.RefundId;
|
||||
refundRecord.WeChatResponse = queryResult.WeChatResponse ?? refundRecord.WeChatResponse;
|
||||
refundRecord.UpdatedTime = now;
|
||||
await refundRecordRepository.UpdateAsync(refundRecord);
|
||||
|
||||
var registration = await registrationRepository.GetByIdAsync(refundRecord.RegistrationId, stoppingToken);
|
||||
if (registration != null)
|
||||
{
|
||||
registration.PaymentStatus = 3;
|
||||
registration.UpdatedTime = now;
|
||||
await registrationRepository.UpdateAsync(registration);
|
||||
}
|
||||
|
||||
var order = await orderRepository.GetFirstAsync(o => o.OrderNo == refundRecord.OutTradeNo, stoppingToken);
|
||||
if (order != null)
|
||||
{
|
||||
order.OrderStatus = OrderStatus.Refunded;
|
||||
order.UpdatedTime = now;
|
||||
await orderRepository.UpdateAsync(order);
|
||||
}
|
||||
|
||||
var payment = await paymentRepository.GetFirstAsync(p => p.RegistrationId == refundRecord.RegistrationId, stoppingToken);
|
||||
if (payment != null)
|
||||
{
|
||||
payment.RefundStatus = 2;
|
||||
payment.RefundAmount = refundRecord.RefundAmount;
|
||||
payment.RefundTime = successTime;
|
||||
payment.UpdatedTime = now;
|
||||
await paymentRepository.UpdateAsync(payment);
|
||||
}
|
||||
|
||||
_logger.LogInformation("退款 {OutRefundNo} 状态更新成功", refundRecord.OutRefundNo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理微信退款失败的订单
|
||||
/// </summary>
|
||||
private async Task ProcessWeChatRefundFailedAsync(
|
||||
RefundRecord refundRecord,
|
||||
WeChatRefundQueryResult queryResult,
|
||||
DateTime now,
|
||||
ISqlSugarRepository<RefundRecord> refundRecordRepository,
|
||||
CancellationToken stoppingToken)
|
||||
{
|
||||
_logger.LogInformation("退款 {OutRefundNo} 失败,更新退款状态", refundRecord.OutRefundNo);
|
||||
|
||||
refundRecord.RefundStatus = queryResult.RefundStatus == "CLOSED" ? 3 : 2;
|
||||
refundRecord.ErrorMessage = queryResult.Message ?? "退款失败";
|
||||
refundRecord.WeChatResponse = queryResult.WeChatResponse ?? refundRecord.WeChatResponse;
|
||||
refundRecord.UpdatedTime = now;
|
||||
await refundRecordRepository.UpdateAsync(refundRecord);
|
||||
|
||||
_logger.LogInformation("退款 {OutRefundNo} 状态更新为失败成功", refundRecord.OutRefundNo);
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
_timer.Dispose();
|
||||
|
||||
@ -5674,7 +5674,12 @@
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.ScoreListOutput.Rank">
|
||||
<summary>
|
||||
名次
|
||||
名次(数字)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.ScoreListOutput.RankText">
|
||||
<summary>
|
||||
名次(汉字)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.ScoreListOutput.Gender">
|
||||
@ -5849,7 +5854,7 @@
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.ScoreImportDto.RankText">
|
||||
<summary>
|
||||
名次说明(文字描述,如"冠军"、"亚军"等)
|
||||
名次(汉字)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Event.Dtos.CertificateExportDto">
|
||||
@ -7502,6 +7507,11 @@
|
||||
成绩与证书管理
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.EventScoreService.ConvertRankToChinese(System.Int32)">
|
||||
<summary>
|
||||
将数字名次转换为汉字形式
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.EventScoreService.PageAthlete(YD_Event.Application.Event.Dtos.ScoreQueryInput)">
|
||||
<summary>
|
||||
运动员成绩列表
|
||||
@ -7511,6 +7521,9 @@
|
||||
<summary>
|
||||
教练/领队列表
|
||||
</summary>
|
||||
<remarks>
|
||||
通过运动员所在的团队关联获取教练和领队人员信息
|
||||
</remarks>
|
||||
</member>
|
||||
<!-- Badly formed XML comment ignored for member "M:YD_Event.Application.Event.EventScoreService.ImportScore(System.Int64,Microsoft.AspNetCore.Http.IFormFile)" -->
|
||||
<member name="M:YD_Event.Application.Event.EventScoreService.IssueCertificate(YD_Event.Application.Event.Dtos.IssueCertificateInput)">
|
||||
@ -7518,11 +7531,11 @@
|
||||
发放证书(支持模板选择和批量发放)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.EventScoreService.GetCertificateDetail(System.Int64)">
|
||||
<member name="M:YD_Event.Application.Event.EventScoreService.GetCertificateDetail(YD_Event.Application.Certificate.Dtos.IdInput)">
|
||||
<summary>
|
||||
查看证书接口
|
||||
</summary>
|
||||
<param name="id">报名人员ID (EventRegistrationPerson的Id)</param>
|
||||
<param name="input">输入参数</param>
|
||||
<returns>证书详情</returns>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.EventScoreService.VerifyCertificate(System.String)">
|
||||
@ -7535,6 +7548,11 @@
|
||||
下载模板
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Event.EventScoreService.ScoreTemplateExporter">
|
||||
<summary>
|
||||
成绩模板导出器
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.EventScoreService.ExportCertificate(YD_Event.Application.Event.Dtos.ScoreQueryInput)">
|
||||
<summary>
|
||||
导出证书
|
||||
@ -7550,6 +7568,16 @@
|
||||
验证导入数据
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Event.EventScoreService.IssuePointsInput">
|
||||
<summary>
|
||||
发放积分输入模型
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.EventScoreService.IssuePoints(YD_Event.Application.Event.EventScoreService.IssuePointsInput)">
|
||||
<summary>
|
||||
发放积分
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Event.EventService">
|
||||
<summary>
|
||||
赛事管理服务
|
||||
@ -7659,6 +7687,36 @@
|
||||
支付超时处理后台服务
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.PaymentExpirationBackgroundService.ProcessUnpaidWeChatOrdersAsync(System.Threading.CancellationToken)">
|
||||
<summary>
|
||||
处理微信未支付订单:定期检查并更新订单状态
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.PaymentExpirationBackgroundService.ProcessWeChatPaymentSuccessAsync(YD_Event.Core.Entities.EventRegistration,YD_Event.Core.Entities.Order,YD_Event.Core.Infrastructure.WeChat.Dto.WeChatPayQueryResult,System.DateTime,SqlSugar.ISqlSugarRepository{YD_Event.Core.Entities.EventRegistration},SqlSugar.ISqlSugarRepository{YD_Event.Core.Entities.Order},SqlSugar.ISqlSugarRepository{YD_Event.Core.Entities.EventRegistrationPayment},System.Threading.CancellationToken)">
|
||||
<summary>
|
||||
处理微信支付成功的订单
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.PaymentExpirationBackgroundService.ProcessWeChatPaymentClosedAsync(YD_Event.Core.Entities.EventRegistration,YD_Event.Core.Entities.Order,System.DateTime,SqlSugar.ISqlSugarRepository{YD_Event.Core.Entities.EventRegistration},SqlSugar.ISqlSugarRepository{YD_Event.Core.Entities.Order},System.Threading.CancellationToken)">
|
||||
<summary>
|
||||
处理微信支付关闭的订单
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.PaymentExpirationBackgroundService.ProcessRefundingWeChatOrdersAsync(System.Threading.CancellationToken)">
|
||||
<summary>
|
||||
处理微信退款中的订单
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.PaymentExpirationBackgroundService.ProcessWeChatRefundSuccessAsync(YD_Event.Core.Entities.RefundRecord,YD_Event.Core.Infrastructure.WeChat.Dto.WeChatRefundQueryResult,System.DateTime,SqlSugar.ISqlSugarRepository{YD_Event.Core.Entities.RefundRecord},SqlSugar.ISqlSugarRepository{YD_Event.Core.Entities.EventRegistration},SqlSugar.ISqlSugarRepository{YD_Event.Core.Entities.Order},SqlSugar.ISqlSugarRepository{YD_Event.Core.Entities.EventRegistrationPayment},System.Threading.CancellationToken)">
|
||||
<summary>
|
||||
处理微信退款成功的订单
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.PaymentExpirationBackgroundService.ProcessWeChatRefundFailedAsync(YD_Event.Core.Entities.RefundRecord,YD_Event.Core.Infrastructure.WeChat.Dto.WeChatRefundQueryResult,System.DateTime,SqlSugar.ISqlSugarRepository{YD_Event.Core.Entities.RefundRecord},System.Threading.CancellationToken)">
|
||||
<summary>
|
||||
处理微信退款失败的订单
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Event.UnifiedRegistrationService">
|
||||
<summary>
|
||||
统一报名处理服务
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user