Handler.cs 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344
  1. using Application.Abstractions.Data;
  2. using Application.Abstractions.Messaging;
  3. using Domain.Entities.Donations.ValueObject;
  4. using SharedKernel.Results;
  5. using Microsoft.EntityFrameworkCore;
  6. namespace Application.Features.Api.DonationGoal.GetProgress;
  7. internal sealed class Handler(IAppDbContext db) : IQueryHandler<Query, Result<Response>>
  8. {
  9. public async Task<Result<Response>> Handle(Query request, CancellationToken ct)
  10. {
  11. var goal = await db.DonationGoalConfig.AsNoTracking().FirstOrDefaultAsync(g => g.ID == request.GoalConfigID && g.ChannelID == request.ChannelID && g.IsActive, ct);
  12. if (goal is null)
  13. {
  14. return Result.Failure<Response>(Error.NotFound("DonationGoal.NotFound", "목표 설정을 찾을 수 없습니다."));
  15. }
  16. // Period 기반 시간 범위 계산
  17. var now = DateTime.UtcNow;
  18. DateTime? rangeStart = goal.Period switch
  19. {
  20. RankPeriodType.Daily => now.Date,
  21. RankPeriodType.Weekly => now.Date.AddDays(-(int)now.DayOfWeek),
  22. RankPeriodType.Monthly => new DateTime(now.Year, now.Month, 1, 0, 0, 0, DateTimeKind.Utc),
  23. RankPeriodType.Yearly => new DateTime(now.Year, 1, 1, 0, 0, 0, DateTimeKind.Utc),
  24. RankPeriodType.Custom => goal.StartAt,
  25. _ => null // AllTime
  26. };
  27. DateTime? rangeEnd = goal.Period == RankPeriodType.Custom ? goal.EndAt : null;
  28. var currentAmount = await db.Donation.AsNoTracking()
  29. .Where(d => d.ChannelID == request.ChannelID
  30. && !d.IsTest
  31. && (rangeStart == null || d.CreatedAt >= rangeStart)
  32. && (rangeEnd == null || d.CreatedAt <= rangeEnd))
  33. .SumAsync(d => d.Amount, ct);
  34. var adjusted = currentAmount + goal.StartAmount;
  35. var percent = goal.TargetAmount > 0 ? Math.Min((decimal)adjusted / goal.TargetAmount * 100, 100) : 0;
  36. return Result.Success(new Response(goal.ID, goal.Title, goal.StartAmount, goal.TargetAmount, adjusted, Math.Round(percent, 1)));
  37. }
  38. }