Handler.cs 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. using Application.Abstractions.Data;
  2. using Application.Abstractions.Messaging;
  3. using SharedKernel.Results;
  4. using Domain.Entities.Donations;
  5. using Domain.Entities.Donations.ValueObject;
  6. using Microsoft.EntityFrameworkCore;
  7. namespace Application.Features.Api.DonationGoal.SaveConfig;
  8. internal sealed class Handler(IAppDbContext db) : ICommandHandler<Command, Result>
  9. {
  10. public async Task<Result> Handle(Command r, CancellationToken ct)
  11. {
  12. var period = (RankPeriodType)r.Period;
  13. // Custom 시 StartAt/EndAt 필수
  14. if (period == RankPeriodType.Custom && (!r.StartAt.HasValue || !r.EndAt.HasValue))
  15. {
  16. return Result.Failure(Error.Problem("DonationGoal.CustomPeriodRequired", "사용자 지정 기간은 시작일/종료일이 필요합니다."));
  17. }
  18. // 기간 중복 검증: 활성 + Custom 끼리만
  19. if (r.IsActive && period == RankPeriodType.Custom && r.StartAt.HasValue && r.EndAt.HasValue)
  20. {
  21. var overlap = await db.DonationGoalConfig
  22. .AnyAsync(c => c.ChannelID == r.ChannelID
  23. && c.IsActive
  24. && c.Period == RankPeriodType.Custom
  25. && c.ID != (r.ID ?? 0)
  26. && c.StartAt != null && c.EndAt != null
  27. && c.StartAt < r.EndAt && c.EndAt > r.StartAt, ct
  28. );
  29. if (overlap)
  30. {
  31. return Result.Failure(Error.Conflict("DonationGoal.PeriodOverlap", "해당 기간에 이미 활성화된 목표가 존재합니다."));
  32. }
  33. }
  34. if (r.ID.HasValue)
  35. {
  36. var config = await db.DonationGoalConfig.FirstOrDefaultAsync(c => c.ID == r.ID.Value && c.ChannelID == r.ChannelID, ct);
  37. if (config is null)
  38. {
  39. return Result.Failure(Error.NotFound("DonationGoal.NotFound", "설정을 찾을 수 없습니다."));
  40. }
  41. config.Update(
  42. r.Title, (GoalWidgetStyle)r.Style, r.StartAmount, r.TargetAmount,
  43. r.StartAt, r.EndAt, r.IsShowPercent,
  44. r.BarColor, r.BarBackgroundColor, r.BarHeightPx,
  45. r.TitleFontSizePx, r.TitleFontColor,
  46. r.AmountFontSizePx, r.AmountFontColor,
  47. r.TitleFontFamily, r.AmountFontFamily,
  48. period,
  49. r.IsActive
  50. );
  51. }
  52. else
  53. {
  54. var config = DonationGoalConfig.Create(r.ChannelID, r.MemberID, r.Title, r.TargetAmount);
  55. config.Update(
  56. r.Title, (GoalWidgetStyle)r.Style, r.StartAmount, r.TargetAmount,
  57. r.StartAt, r.EndAt, r.IsShowPercent,
  58. r.BarColor, r.BarBackgroundColor, r.BarHeightPx,
  59. r.TitleFontSizePx, r.TitleFontColor,
  60. r.AmountFontSizePx, r.AmountFontColor,
  61. r.TitleFontFamily, r.AmountFontFamily,
  62. period,
  63. r.IsActive
  64. );
  65. db.DonationGoalConfig.Add(config);
  66. }
  67. await db.SaveChangesAsync(ct);
  68. return Result.Success();
  69. }
  70. }