From 349bd553df9b20e51172cc133243a50d8f66e065 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E6=A2=93=E5=BD=AD?= Date: Fri, 17 Apr 2026 12:47:13 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=80=E6=AC=BE=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Event/Dtos/EventRecordDtos.cs | 36 +++++++++ YD_Event.Application/Event/Dtos/ScoreDtos.cs | 14 +++- .../Event/EventScoreService.cs | 6 +- .../Event/UnifiedRegistrationService.cs | 69 ++++++++++++++++- YD_Event.Application/YD_Event.Application.xml | 76 ++++++++++++------- 5 files changed, 166 insertions(+), 35 deletions(-) diff --git a/YD_Event.Application/Event/Dtos/EventRecordDtos.cs b/YD_Event.Application/Event/Dtos/EventRecordDtos.cs index 155ce7a..6e1a04f 100644 --- a/YD_Event.Application/Event/Dtos/EventRecordDtos.cs +++ b/YD_Event.Application/Event/Dtos/EventRecordDtos.cs @@ -174,6 +174,16 @@ public class CancelPreviewOutput /// public decimal RefundableAmount { get; set; } + /// + /// 退款规则列表 + /// + public List RefundRules { get; set; } = new(); + + /// + /// 当前适用的退款规则描述 + /// + public string? ApplicableRefundRule { get; set; } + /// /// 项目列表 /// @@ -185,6 +195,32 @@ public class CancelPreviewOutput public List Members { get; set; } = new(); } +/// +/// 退款规则DTO +/// +public class RefundRuleDto +{ + /// + /// 距离比赛开始天数(起) + /// + public int DayStart { get; set; } + + /// + /// 距离比赛开始天数(止) + /// + public int DayEnd { get; set; } + + /// + /// 扣除比例(%) + /// + public decimal DeductPercentage { get; set; } + + /// + /// 退款备注 + /// + public string? Remark { get; set; } +} + /// /// 取消报名项目DTO /// diff --git a/YD_Event.Application/Event/Dtos/ScoreDtos.cs b/YD_Event.Application/Event/Dtos/ScoreDtos.cs index 3b74be2..6cf7595 100644 --- a/YD_Event.Application/Event/Dtos/ScoreDtos.cs +++ b/YD_Event.Application/Event/Dtos/ScoreDtos.cs @@ -150,7 +150,7 @@ public class CoachLeaderListOutput /// /// 性别 /// - public string Gender { get; set; } + public int Gender { get; set; } /// /// 出生日期 @@ -160,7 +160,17 @@ public class CoachLeaderListOutput /// /// 身份证号 /// - public string IdCardNumber { get; set; } + public string? IdCardNumber { get; set; } + + /// + /// 身份证正面图片URL + /// + public string? IdCardImageUrl { get; set; } + + /// + /// 身份证背面图片URL + /// + public string? IdCardBackImageUrl { get; set; } /// /// 电话 diff --git a/YD_Event.Application/Event/EventScoreService.cs b/YD_Event.Application/Event/EventScoreService.cs index 56221f2..f18264d 100644 --- a/YD_Event.Application/Event/EventScoreService.cs +++ b/YD_Event.Application/Event/EventScoreService.cs @@ -221,7 +221,11 @@ public class EventScoreService : BaseService, ITransient Id = p.Id, Name = p.Name, Age = p.Age, - IdCardNumber = p.IdCardImageUrl, + Gender = (int)p.Gender, + BirthDate = p.BirthDate, + IdCardNumber = p.IdCardNumber, + IdCardImageUrl = p.IdCardImageUrl, + IdCardBackImageUrl = p.IdCardBackImageUrl, Mobile = p.Mobile, CertificateId = 0 // 需要单独查询,此处先设为0 }) diff --git a/YD_Event.Application/Event/UnifiedRegistrationService.cs b/YD_Event.Application/Event/UnifiedRegistrationService.cs index 04f5435..ff86ce3 100644 --- a/YD_Event.Application/Event/UnifiedRegistrationService.cs +++ b/YD_Event.Application/Event/UnifiedRegistrationService.cs @@ -2445,6 +2445,38 @@ public class UnifiedRegistrationService : ITransient }); } + var refundConfigs = await _refundConfigService.GetList(); + refundConfigs = refundConfigs.Where(x => x.Status == Core.Enum.AvailabilityStatus.Enable).OrderBy(x => x.DayStart).ToList(); + + foreach (var config in refundConfigs) + { + output.RefundRules.Add(new RefundRuleDto + { + DayStart = config.DayStart, + DayEnd = config.DayEnd, + DeductPercentage = config.DeductPercentage, + Remark = config.Remark + }); + } + + var daysRemaining = (eventInfo.MatchStartTime - DateTime.Now).TotalDays; + if (daysRemaining < 0) daysRemaining = 0; + + var matchConfig = refundConfigs.FirstOrDefault(c => + daysRemaining >= c.DayStart && + (c.DayEnd == int.MaxValue ? true : daysRemaining < c.DayEnd) + ); + + if (matchConfig != null) + { + var refundPercentage = 100 - matchConfig.DeductPercentage; + output.ApplicableRefundRule = $"距离比赛开始还有 {Math.Round(daysRemaining, 1)} 天,退款比例为 {refundPercentage}%,扣除 {matchConfig.DeductPercentage}%。"; + } + else + { + output.ApplicableRefundRule = "距离比赛开始还有 " + Math.Round(daysRemaining, 1) + " 天,全额退款。"; + } + return output; } @@ -2544,6 +2576,36 @@ public class UnifiedRegistrationService : ITransient if (registration.TotalAmount > 0 && !string.IsNullOrEmpty(registration.OrderNo) && actualRefundAmount > 0) { + var originalOrder = await _orderRepository.GetFirstAsync(o => o.OrderNo == registration.OrderNo); + if (originalOrder != null) + { + var refundOrder = new YD_Event.Core.Entities.Order + { + Id = _idGenerator.NewLong(), + OrderNo = await _orderNoGeneratorService.GenerateRefundOrderNoAsync(), + OrderType = 2, + MerchantId = originalOrder.MerchantId, + MerchantCertificationId = originalOrder.MerchantCertificationId, + EventId = originalOrder.EventId, + RegistrationId = originalOrder.RegistrationId, + RelatedOrderId = originalOrder.Id, + OriginalAmount = originalOrder.ActualAmount, + ActualAmount = actualRefundAmount, + DiscountAmount = 0, + OrderStatus = OrderStatus.Refunded, + PaymentTime = now, + Remark = input.CancelReason, + CreatedTime = now, + CreatedUserId = operatorUserId, + Status = AvailabilityStatus.Enable + }; + await _orderRepository.InsertAsync(refundOrder); + output.RefundNo = refundOrder.OrderNo; + + _logger.LogInformation("退款订单创建成功:报名ID={RegistrationId}, 原订单号={OriginalOrderNo}, 退款订单号={RefundOrderNo}, 退款金额={Amount}", + registration.Id, originalOrder.OrderNo, refundOrder.OrderNo, actualRefundAmount); + } + var merchant = await _merchantRepository.GetFirstAsync(x => x.Id == eventInfo.MerchantId); if (merchant != null) @@ -2553,7 +2615,10 @@ public class UnifiedRegistrationService : ITransient if (wechatConfig != null) { var outRefundNo = await _orderNoGeneratorService.GenerateRefundOrderNoAsync(); - output.RefundNo = outRefundNo; + if (string.IsNullOrEmpty(output.RefundNo)) + { + output.RefundNo = outRefundNo; + } var refundRequest = new Core.Infrastructure.WeChat.Dto.CreateRefundRequest { @@ -2574,8 +2639,6 @@ public class UnifiedRegistrationService : ITransient registration.Id, refundResult.Message); output.Success = false; output.Message = refundResult.Message; - output.RefundAmount = 0; - output.RefundNo = null; return output; } diff --git a/YD_Event.Application/YD_Event.Application.xml b/YD_Event.Application/YD_Event.Application.xml index 85282d1..03432e2 100644 --- a/YD_Event.Application/YD_Event.Application.xml +++ b/YD_Event.Application/YD_Event.Application.xml @@ -4920,6 +4920,16 @@ 可退款金额 + + + 退款规则列表 + + + + + 当前适用的退款规则描述 + + 项目列表 @@ -4930,6 +4940,31 @@ 队员列表 + + + 退款规则DTO + + + + + 距离比赛开始天数(起) + + + + + 距离比赛开始天数(止) + + + + + 扣除比例(%) + + + + + 退款备注 + + 取消报名项目DTO @@ -5865,6 +5900,16 @@ 身份证号 + + + 身份证正面图片URL + + + + + 身份证背面图片URL + + 电话 @@ -5897,7 +5942,7 @@ - 页面类型:0-未指定,1-运动员页面,2-教练页面,3-领队页面 + 页面类型:1-运动员页面,2-教练页面,3-领队页面 用于明确区分不同角色页面的证书生成逻辑 @@ -6758,27 +6803,7 @@ - 成员ID列表(单个团队报名时使用,向后兼容) - - - - - 团队列表(支持多个团队报名同一项目组别) - - - - - 用户团队输入DTO - - - - - 团队序号(用于显示,如"团队一"、"团队二") - - - - - 该团队的成员ID列表 + 成员ID列表 @@ -7775,13 +7800,6 @@ 发放证书(支持模板选择和批量发放) - - - 验证 PageType 参数是否有效 - - 页面类型值 - 是否有效 - 根据页面类型获取允许的人员类型列表