228 lines
8.2 KiB
C#

using System.Text;
using YD_Event.Application.Order.Dtos;
using YD_Event.Core.Entities;
using YD_Event.Core.Enum;
namespace YD_Event.Application.Order;
/// <summary>
/// 订单管理服务
/// </summary>
public class OrderService : BaseService<EventRegistration>, ITransient
{
private readonly ISqlSugarRepository<EventRegistration> _repository;
private readonly ISqlSugarRepository<EventRegistrationItem> _itemRepository;
private readonly ISqlSugarRepository<EventRegistrationPerson> _personRepository;
private readonly ISqlSugarRepository<EventRegistrationPayment> _paymentRepository;
private readonly IIdGenerator _idGenerator;
public OrderService(ISqlSugarRepository<EventRegistration> repository,
ISqlSugarRepository<EventRegistrationItem> itemRepository,
ISqlSugarRepository<EventRegistrationPerson> personRepository,
ISqlSugarRepository<EventRegistrationPayment> paymentRepository,
IIdGenerator idGenerator) : base(repository)
{
_repository = repository;
_itemRepository = itemRepository;
_personRepository = personRepository;
_paymentRepository = paymentRepository;
_idGenerator = idGenerator;
}
/// <summary>
/// 创建订单
/// </summary>
[DisplayName("创建订单")]
[HttpPost("create")]
[UnitOfWork]
public async Task<string> Create(CreateOrderInput input)
{
// 1. Create Registration
var entity = input.Adapt<EventRegistration>();
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<List<EventRegistrationItem>>();
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<List<EventRegistrationPerson>>();
persons.ForEach(x =>
{
x.Id = _idGenerator.NextId();
x.RegistrationId = entity.Id;
});
await _personRepository.InsertRangeAsync(persons);
}
return entity.OrderNo;
}
/// <summary>
/// 订单分页查询
/// </summary>
[DisplayName("订单分页查询")]
[HttpGet]
public async Task<PageResult<EventRegistration>> 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);
}
/// <summary>
/// 获取订单详情
/// </summary>
[DisplayName("获取订单详情")]
[HttpGet("detail")]
public async Task<EventRegistration> 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;
}
/// <summary>
/// 更新订单状态
/// </summary>
[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);
}
/// <summary>
/// 订单退款
/// </summary>
[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);
}
}
/// <summary>
/// 删除订单
/// </summary>
[DisplayName("删除订单")]
[HttpPost("delete")]
public async Task Delete([FromBody] List<long> ids)
{
await _repository.DeleteAsync(x => ids.Contains(x.Id));
}
/// <summary>
/// 导出订单
/// </summary>
[DisplayName("导出订单")]
[HttpGet("export")]
public async Task<IActionResult> 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"
};
}
}