using Application.Abstractions.Messaging; using Application.Abstractions.Data; using Domain.Entities.Wallets.ValueObject; using Microsoft.EntityFrameworkCore; namespace Application.Features.Admin.Member.Wallet.Transactions.Search; public sealed class Handler(IAppDbContext db) : IQueryHandler { public async Task Handle(Query request, CancellationToken ct) { var query = db.WalletTransaction.AsNoTracking().Include(x => x.Wallet).ThenInclude(w => w.Member).AsQueryable(); // 거래 유형 필터 if (request.Type.HasValue) { query = query.Where(x => x.TxType == request.Type.Value); } // 키워드 검색 if (!string.IsNullOrWhiteSpace(request.Keyword)) { query = request.Search switch { 1 => query.Where(x => x.Wallet.Member.Email.Contains(request.Keyword)), 2 => query.Where(x => x.ID.ToString().Contains(request.Keyword)), 3 => query.Where(x => x.Wallet.ID.ToString().Contains(request.Keyword)), 4 => query.Where(x => x.Wallet.MemberID.ToString().Contains(request.Keyword)), 5 => query.Where(x => x.Wallet.Member.Name != null && x.Wallet.Member.Name.Contains(request.Keyword)), _ => query }; } // 날짜 필터 if (!string.IsNullOrWhiteSpace(request.StartAt) && DateTime.TryParse(request.StartAt, out var startAt)) { query = query.Where(x => x.CreatedAt >= startAt); } if (!string.IsNullOrWhiteSpace(request.EndAt) && DateTime.TryParse(request.EndAt, out var endAt)) { query = query.Where(x => x.CreatedAt <= endAt); } var total = await query.CountAsync(ct); // 유형별 카운트 (GroupBy 1회 쿼리) var typeCounts = await db.WalletTransaction.AsNoTracking().GroupBy(x => x.TxType).Select(g => new { Type = g.Key, Count = g.Count() }).ToListAsync(ct); int CountOf(WalletTransactionType t) => typeCounts.FirstOrDefault(x => x.Type == t)?.Count ?? 0; var skip = (request.PageNum - 1) * request.PerPage; var list = await query.OrderByDescending(x => x.ID).Skip(skip).Take(request.PerPage).Select(x => new { x.ID, x.WalletKey, MemberID = x.Wallet.MemberID, MemberEmail = x.Wallet.Member.Email, MemberName = x.Wallet.Member.Name, x.TxType, x.BalanceType, Amount = x.Amount.Value, BalanceAfter = x.BalanceAfter.Value, x.Reason, x.RefID, x.Memo, x.CreatedAt }).ToListAsync(ct); var rows = list.Select((x, idx) => new Response.Row { Num = total - skip - idx, ID = x.ID, WalletKey = x.WalletKey, MemberID = x.MemberID, MemberEmail = x.MemberEmail, MemberName = x.MemberName, TxType = x.TxType, BalanceType = x.BalanceType, Amount = (long)x.Amount, BalanceAfter = (long)x.BalanceAfter, Reason = x.Reason, RefID = x.RefID, Memo = x.Memo, CreatedAt = x.CreatedAt }).ToList(); return new Response { Total = total, TotalCharge = CountOf(WalletTransactionType.Charge), TotalDonationIn = CountOf(WalletTransactionType.DonationIn), TotalDonationOut = CountOf(WalletTransactionType.DonationOut), TotalRewardEarned = CountOf(WalletTransactionType.RewardEarned), TotalSpend = CountOf(WalletTransactionType.Spend), TotalRefund = CountOf(WalletTransactionType.Refund), TotalLock = CountOf(WalletTransactionType.Lock), TotalUnlock = CountOf(WalletTransactionType.Unlock), TotalAdjusted = CountOf(WalletTransactionType.Adjusted), List = rows }; } }