Handler.cs 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344
  1. using Application.Abstractions.Data;
  2. using Application.Abstractions.Messaging;
  3. using Microsoft.EntityFrameworkCore;
  4. using SharedKernel.Results;
  5. using CouponEntity = Domain.Entities.Store.Coupon;
  6. namespace Application.Features.Admin.Store.Coupon.Create;
  7. public sealed class Handler(IAppDbContext db) : ICommandHandler<Command, Result<int>>
  8. {
  9. public async Task<Result<int>> Handle(Command request, CancellationToken ct)
  10. {
  11. // Product 존재 + GameID 일치 검증 (사용자 정책: 게임 필수, 상품 필수)
  12. var product = await db.Product.AsNoTracking()
  13. .Where(p => p.ID == request.ProductID)
  14. .Select(p => new { p.ID, p.GameID })
  15. .FirstOrDefaultAsync(ct);
  16. if (product is null)
  17. {
  18. return Result.Failure<int>(Error.NotFound("Coupon.ProductNotFound", "선택한 상품이 없습니다."));
  19. }
  20. // GameID 가 Product 의 GameID 와 일치하지 않으면 경고 (UI 에서 자동 맞춰주지만 안전망)
  21. if (product.GameID != request.GameID)
  22. {
  23. return Result.Failure<int>(Error.Problem("Coupon.GameMismatch", "선택한 게임이 상품의 게임과 일치하지 않습니다."));
  24. }
  25. var coupon = CouponEntity.Create(
  26. productID: request.ProductID,
  27. gameID: request.GameID,
  28. name: request.Name,
  29. usagePolicy: request.UsagePolicy,
  30. expiresAt: request.ExpiresAt,
  31. lowStockThreshold: request.LowStockThreshold
  32. );
  33. db.Coupon.Add(coupon);
  34. await db.SaveChangesAsync(ct);
  35. return Result.Success(coupon.ID);
  36. }
  37. }