using System.Text; using YD_Event.Application.Order.Dtos; using YD_Event.Core.Entities; using YD_Event.Core.Enum; using YD_Event.Application.Refund; namespace YD_Event.Application.Order; /// /// 订单管理服务 /// public class OrderService : BaseService, ITransient { private readonly ISqlSugarRepository _repository; private readonly ISqlSugarRepository _itemRepository; private readonly ISqlSugarRepository _personRepository; private readonly ISqlSugarRepository _paymentRepository; private readonly ISqlSugarRepository _eventRepository; private readonly RefundConfigService _refundConfigService; private readonly IIdGenerator _idGenerator; public OrderService(ISqlSugarRepository repository, ISqlSugarRepository itemRepository, ISqlSugarRepository personRepository, ISqlSugarRepository paymentRepository, ISqlSugarRepository eventRepository, RefundConfigService refundConfigService, IIdGenerator idGenerator) : base(repository) { _repository = repository; _itemRepository = itemRepository; _personRepository = personRepository; _paymentRepository = paymentRepository; _eventRepository = eventRepository; _refundConfigService = refundConfigService; _idGenerator = idGenerator; } /// /// 创建订单 /// [DisplayName("创建订单")] [HttpPost("create")] [UnitOfWork] public async Task Create(CreateOrderInput input) { // 1. Create Registration var entity = input.Adapt(); entity.Id = _idGenerator.NextId(); entity.OrderNo = DateTime.Now.ToString("yyyyMMdd") + new Random().Next(1000, 9999); // Simple generation entity.RegistrationStatus = 0; // Pending entity.PaymentStatus = 0; // Unpaid entity.RegistrationTime = DateTime.Now; // Calculate Total decimal totalAmount = 0; int totalPerson = 0; if (input.Items != null) { foreach (var item in input.Items) { totalAmount += item.UnitPrice * item.PersonCount; totalPerson += item.PersonCount; } } entity.TotalAmount = totalAmount; entity.TotalPersonCount = totalPerson; await _repository.InsertAsync(entity); // 2. Create Items if (input.Items != null && input.Items.Any()) { var items = input.Items.Adapt>(); items.ForEach(x => { x.Id = _idGenerator.NextId(); x.RegistrationId = entity.Id; x.TotalPrice = x.UnitPrice * x.PersonCount; }); await _itemRepository.InsertRangeAsync(items); } // 3. Create Persons if (input.Persons != null && input.Persons.Any()) { var persons = input.Persons.Adapt>(); persons.ForEach(x => { x.Id = _idGenerator.NextId(); x.RegistrationId = entity.Id; }); await _personRepository.InsertRangeAsync(persons); } return entity.OrderNo; } /// /// 订单分页查询 /// [DisplayName("订单分页查询")] [HttpGet] public async Task> Page([FromQuery] OrderQueryInput input) { return await _repository.AsQueryable() .WhereIF(!string.IsNullOrWhiteSpace(input.OrderNo), x => x.OrderNo.Contains(input.OrderNo)) .WhereIF(input.EventId.HasValue, x => x.EventId == input.EventId) .WhereIF(input.PaymentStatus.HasValue, x => x.PaymentStatus == input.PaymentStatus) .WhereIF(!string.IsNullOrWhiteSpace(input.ContactPhone), x => x.ContactPhone.Contains(input.ContactPhone)) .WhereIF(input.StartTime.HasValue, x => x.CreatedTime >= input.StartTime) .WhereIF(input.EndTime.HasValue, x => x.CreatedTime <= input.EndTime) .OrderByDescending(x => x.CreatedTime) .ToPagedListAsync(input); } /// /// 获取订单详情 /// [DisplayName("获取订单详情")] [HttpGet("detail")] public async Task Detail([FromQuery] long id) { var entity = await _repository.GetByIdAsync(id); if (entity == null) throw Oops.Bah("订单不存在"); entity.Items = await _itemRepository.AsQueryable().Where(x => x.RegistrationId == id).ToListAsync(); entity.Persons = await _personRepository.AsQueryable().Where(x => x.RegistrationId == id).ToListAsync(); entity.Payment = await _paymentRepository.AsQueryable().Where(x => x.RegistrationId == id).FirstAsync(); return entity; } /// /// 更新订单状态 /// [DisplayName("更新订单状态")] [HttpPut("status")] public async Task UpdateStatus(UpdateOrderStatusInput input) { var entity = await _repository.GetByIdAsync(input.Id); if (entity == null) throw Oops.Bah("订单不存在"); entity.PaymentStatus = input.PaymentStatus; if (input.PaymentStatus == 1) // Paid { entity.PaymentTime = DateTime.Now; } await _repository.UpdateAsync(entity); } /// /// 获取建议退款金额 /// [DisplayName("获取建议退款金额")] [HttpGet("refund-amount")] public async Task GetRefundAmount([FromQuery] long orderId) { var order = await _repository.GetByIdAsync(orderId); if (order == null) throw Oops.Bah("订单不存在"); var eventInfo = await _eventRepository.GetByIdAsync(order.EventId); if (eventInfo == null) return order.TotalAmount; // 无法获取赛事时间,默认全额 return await _refundConfigService.CalculateRefundAmount(order.TotalAmount, eventInfo.MatchStartTime); } /// /// 订单退款 /// [DisplayName("订单退款")] [HttpPost("refund")] [UnitOfWork] public async Task Refund(RefundOrderInput input) { var entity = await _repository.GetByIdAsync(input.Id); if (entity == null) throw Oops.Bah("订单不存在"); if (entity.PaymentStatus != 1) throw Oops.Bah("订单未支付,无法退款"); // Update Registration Status entity.PaymentStatus = 3; // Refunded await _repository.UpdateAsync(entity); // Update Payment Record var payment = await _paymentRepository.AsQueryable().Where(x => x.RegistrationId == entity.Id).FirstAsync(); if (payment != null) { payment.RefundStatus = 2; // Refunded payment.RefundAmount = input.RefundAmount; payment.RefundReason = input.Reason; payment.RefundTime = DateTime.Now; await _paymentRepository.UpdateAsync(payment); } else { // Create a payment record if missing (should not happen in real scenario if flow is correct) payment = new EventRegistrationPayment { Id = _idGenerator.NextId(), RegistrationId = entity.Id, RefundStatus = 2, RefundAmount = input.RefundAmount, RefundReason = input.Reason, RefundTime = DateTime.Now, TransactionNo = "REF" + DateTime.Now.ToString("yyyyMMddHHmmss") }; await _paymentRepository.InsertAsync(payment); } } /// /// 删除订单 /// [DisplayName("删除订单")] [HttpPost("delete")] public async Task Delete([FromBody] List ids) { await _repository.DeleteAsync(x => ids.Contains(x.Id)); } /// /// 导出订单 /// [DisplayName("导出订单")] [HttpGet("export")] public async Task Export([FromQuery] OrderQueryInput input) { var list = await _repository.AsQueryable() .WhereIF(!string.IsNullOrWhiteSpace(input.OrderNo), x => x.OrderNo.Contains(input.OrderNo)) .WhereIF(input.EventId.HasValue, x => x.EventId == input.EventId) .OrderByDescending(x => x.CreatedTime) .ToListAsync(); // Since we cannot use external libraries easily without knowing what's installed, // we return a CSV string as a file. var sb = new StringBuilder(); sb.AppendLine("订单编号,赛事ID,报名人,联系电话,总金额,状态,创建时间"); foreach (var item in list) { sb.AppendLine($"{item.OrderNo},{item.EventId},{item.ContactName},{item.ContactPhone},{item.TotalAmount},{item.PaymentStatus},{item.CreatedTime}"); } var bytes = Encoding.UTF8.GetBytes(sb.ToString()); return new FileContentResult(bytes, "text/csv") { FileDownloadName = $"Orders_{DateTime.Now:yyyyMMddHHmmss}.csv" }; } }