using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Application.Features.Api.Studio.Helpers; using Microsoft.EntityFrameworkCore; using SharedKernel.Results; namespace Application.Features.Api.Studio.Wallet.GetWithdraw; internal sealed class Handler(IAppDbContext db) : IQueryHandler> { public async Task> Handle(Query request, CancellationToken ct) { // Wallet Donation 잔액 var wallet = await db.Wallet.AsNoTracking() .Include(w => w.Balances) .FirstOrDefaultAsync(w => w.MemberID == request.MemberID, ct); var withdrawableBalance = 0; if (wallet is not null) { var donationBal = wallet.Balances.FirstOrDefault(b => b.Type == Domain.Entities.Wallets.ValueObject.WalletBalanceType.Donation); if (donationBal is not null) { withdrawableBalance = (int)donationBal.Amount.Value; } } // 정산 계좌 목록 var accounts = await db.SettlementAccount.AsNoTracking() .Where(a => a.MemberID == request.MemberID) .OrderBy(a => a.CreatedAt) .Select(a => new AccountInfo( a.ID, a.BankName, a.AccountNumber.Length > 4 ? "****" + a.AccountNumber.Substring(a.AccountNumber.Length - 4) : a.AccountNumber, a.AccountHolder )) .ToListAsync(ct); // 출금 내역 var (start, end) = PeriodHelper.GetRange(request.Period); var baseQuery = db.WithdrawalRequest.AsNoTracking() .Where(w => w.MemberID == request.MemberID && w.RequestedAt >= start && w.RequestedAt <= end); var total = await baseQuery.CountAsync(ct); var list = await baseQuery .OrderByDescending(w => w.RequestedAt) .Skip((request.Page - 1) * request.PerPage) .Take(request.PerPage) .Select(w => new WithdrawItem( w.ID, w.RequestedAmount, w.WithholdingTax, w.NetAmount, w.Status.ToString(), w.BankName, w.AccountNumber.Length > 4 ? "****" + w.AccountNumber.Substring(w.AccountNumber.Length - 4) : w.AccountNumber, w.RequestedAt, w.ProcessedAt, w.RejectedReason )) .ToListAsync(ct); return Result.Success(new Response(total, withdrawableBalance, accounts, list)); } }