using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Domain.Entities.Store.ValueObject; using Microsoft.EntityFrameworkCore; namespace Application.Features.Admin.Store.Order.Search; public sealed class Handler(IAppDbContext db) : IQueryHandler { public async Task Handle(Query request, CancellationToken ct) { // 전체 navtab 카운트 (필터 무관) var counts = await db.Order.AsNoTracking() .GroupBy(c => c.Status) .Select(g => new { Status = g.Key, Count = g.Count() }) .ToListAsync(ct); int CountOf(OrderStatus s) => counts.FirstOrDefault(x => x.Status == s)?.Count ?? 0; var statusCounts = new Response.StatusCounts( All: counts.Sum(x => x.Count), Paid: CountOf(OrderStatus.Paid), Preparing: CountOf(OrderStatus.Preparing), Shipped: CountOf(OrderStatus.Shipped), Delivered: CountOf(OrderStatus.Delivered), Cancelled: CountOf(OrderStatus.Cancelled), Refunded: CountOf(OrderStatus.Refunded), Exchanged: CountOf(OrderStatus.Exchanged) ); // 필터 적용 var query = db.Order.AsNoTracking().AsQueryable(); if (request.Status.HasValue) { query = query.Where(c => c.Status == request.Status.Value); } if (!string.IsNullOrWhiteSpace(request.Keyword)) { var kw = request.Keyword.Trim(); query = request.Search switch { 1 => query.Where(c => c.OrderNumber.Contains(kw)), 2 => query.Where(c => c.Member!.Email.Contains(kw)), _ => query.Where(c => c.OrderNumber.Contains(kw) || c.Member!.Email.Contains(kw)) }; } if (DateTime.TryParse(request.StartAt, out var startAt)) { query = query.Where(c => c.CreatedAt >= startAt); } if (DateTime.TryParse(request.EndAt, out var endAt)) { query = query.Where(c => c.CreatedAt <= endAt); } var total = await query.CountAsync(ct); var list = await query .OrderByDescending(c => c.ID) .Skip((request.Page - 1) * request.PerPage) .Take(request.PerPage) .Select(c => new { c.ID, c.OrderNumber, c.MemberID, MemberEmail = c.Member!.Email, c.ChannelID, ChannelName = c.Channel != null ? c.Channel.Name : null, c.TotalAmount, c.PlatformFeeAmount, c.GameRevenueAmount, c.ChannelRewardAmount, c.Status, c.CreatedAt, c.PaidAt }) .ToListAsync(ct); var startNum = total - ((request.Page - 1) * request.PerPage); return new Response( Total: total, List: [.. list.Select((c, i) => new Response.Row( Num: startNum - i, c.ID, c.OrderNumber, c.MemberID, c.MemberEmail, c.ChannelID, c.ChannelName, c.TotalAmount, c.PlatformFeeAmount, c.GameRevenueAmount, c.ChannelRewardAmount, c.Status, c.CreatedAt, c.PaidAt ))], Counts: statusCounts ); } }