| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- 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.GetRevenue;
- internal sealed class Handler(IAppDbContext db) : IQueryHandler<Query, Result<Response>>
- {
- public async Task<Result<Response>> Handle(Query request, CancellationToken ct)
- {
- var (start, end) = PeriodHelper.GetRange(request.Period);
- var baseQuery = db.Donation.AsNoTracking()
- .Where(d => d.ReceiverMemberID == request.MemberID && !d.IsTest && d.CreatedAt >= start && d.CreatedAt <= end);
- // Summary
- var total = await baseQuery.CountAsync(ct);
- var grossSum = total > 0 ? await baseQuery.SumAsync(d => d.Amount, ct) : 0;
- var feeSum = total > 0 ? await baseQuery.SumAsync(d => d.FeeAmount, ct) : 0;
- var netSum = total > 0 ? await baseQuery.SumAsync(d => d.NetAmount, ct) : 0;
- // 누적 판매 수수료 (같은 기간 — 채널 보상 입금)
- var totalStoreCommission = await db.WalletTransaction.AsNoTracking()
- .Where(t => t.Wallet!.MemberID == request.MemberID
- && t.BalanceType == Domain.Entities.Wallets.ValueObject.WalletBalanceType.StoreRevenue
- && t.TxType == Domain.Entities.Wallets.ValueObject.WalletTransactionType.OrderChannelReward
- && t.CreatedAt >= start && t.CreatedAt <= end)
- .SumAsync(t => (int)t.Amount.Value, ct);
- // API 결제 보고 수수료 — 기간 내 확정 입금분
- var totalApiCommission = await db.WalletTransaction.AsNoTracking()
- .Where(t => t.Wallet!.MemberID == request.MemberID
- && t.BalanceType == Domain.Entities.Wallets.ValueObject.WalletBalanceType.StoreRevenue
- && t.TxType == Domain.Entities.Wallets.ValueObject.WalletTransactionType.ApiCommissionEarned
- && t.CreatedAt >= start && t.CreatedAt <= end)
- .SumAsync(t => (int?)t.Amount.Value, ct) ?? 0;
- // 보류 중(미확정) 수수료 — 기간 무관 실시간 잔여 전체. 확정 시 지갑 입금, 14일 내 취소 시 소멸
- var pendingQuery = db.ApiPurchase.AsNoTracking()
- .Where(c => c.CreditedMemberID == request.MemberID && c.Status == Domain.Entities.Developers.ValueObject.ApiPurchaseStatus.Pending);
- var pendingApiCommission = await pendingQuery.SumAsync(c => (int?)c.CommissionAmount, ct) ?? 0;
- var pendingList = await pendingQuery
- .OrderBy(c => c.ConfirmDueAt)
- .Take(50)
- .Select(c => new PendingCommissionItem(
- c.ID,
- c.Game!.KorName,
- c.CommissionAmount,
- c.ConfirmDueAt,
- c.CreatedAt
- ))
- .ToListAsync(ct);
- var summary = new RevenueSummary(grossSum, feeSum, netSum, totalStoreCommission, totalApiCommission, pendingApiCommission);
- // Paged list
- var list = await baseQuery
- .OrderByDescending(d => d.CreatedAt)
- .Skip((request.Page - 1) * request.PerPage)
- .Take(request.PerPage)
- .Select(d => new RevenueItem(
- d.ID,
- d.SendName,
- d.Sponsor != null ? d.Sponsor.SID : null,
- d.Amount,
- d.FeeAmount,
- d.NetAmount,
- d.CrewSessionID != null ? "crew_donation" : "donation",
- d.CrewMember != null ? d.CrewMember.Nickname : null,
- d.CreatedAt
- ))
- .ToListAsync(ct);
- // Chart data — daily grouping
- var chartRaw = await baseQuery
- .GroupBy(d => d.CreatedAt.Date)
- .Select(g => new
- {
- Date = g.Key,
- GrossAmount = g.Sum(d => d.Amount),
- PlatformFee = g.Sum(d => d.FeeAmount),
- NetAmount = g.Sum(d => d.NetAmount)
- })
- .OrderBy(x => x.Date)
- .ToListAsync(ct);
- var chartData = chartRaw.Select(c => new ChartItem(c.Date.ToString("MM/dd"), c.GrossAmount, c.PlatformFee, c.NetAmount)).ToList();
- return Result.Success(new Response(total, summary, list, chartData, pendingList));
- }
- }
|