using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Microsoft.EntityFrameworkCore; using SharedKernel.Results; using CouponEntity = Domain.Entities.Store.Coupon; namespace Application.Features.Admin.Store.Coupon.Create; public sealed class Handler(IAppDbContext db) : ICommandHandler> { public async Task> Handle(Command request, CancellationToken ct) { // Product 존재 + GameID 일치 검증 (사용자 정책: 게임 필수, 상품 필수) var product = await db.Product.AsNoTracking() .Where(p => p.ID == request.ProductID) .Select(p => new { p.ID, p.GameID }) .FirstOrDefaultAsync(ct); if (product is null) { return Result.Failure(Error.NotFound("Coupon.ProductNotFound", "선택한 상품이 없습니다.")); } // GameID 가 Product 의 GameID 와 일치하지 않으면 경고 (UI 에서 자동 맞춰주지만 안전망) if (product.GameID != request.GameID) { return Result.Failure(Error.Problem("Coupon.GameMismatch", "선택한 게임이 상품의 게임과 일치하지 않습니다.")); } var coupon = CouponEntity.Create( productID: request.ProductID, gameID: request.GameID, name: request.Name, usagePolicy: request.UsagePolicy, expiresAt: request.ExpiresAt, lowStockThreshold: request.LowStockThreshold ); db.Coupon.Add(coupon); await db.SaveChangesAsync(ct); return Result.Success(coupon.ID); } }