using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Domain.Entities.Developers.ValueObject; using Microsoft.EntityFrameworkCore; using SharedKernel.Results; namespace Application.Features.Api.V1.Purchases.Get; internal sealed class Handler(IAppDbContext db) : IQueryHandler> { public async Task> Handle(Query request, CancellationToken ct) { if (string.IsNullOrWhiteSpace(request.OrderID)) { return Result.Failure(Error.Problem("Purchase.OrderIDRequired", "orderID 는 필수입니다.")); } if (request.Marketplace.HasValue && !Enum.IsDefined(typeof(ApiPurchaseMarketplace), request.Marketplace.Value)) { return Result.Failure(Error.Problem("Purchase.MarketplaceInvalid", "marketplace 는 1(구글)~6(기타) 값이어야 합니다.")); } var orderID = request.OrderID.Trim(); var query = db.ApiPurchase.AsNoTracking().Where(c => c.OrderID == orderID); // 호출 주체 범위 제한 — OAuth2: 해당 앱 / PAT: 본인 소유 앱 전체 if (request.ApplicationID.HasValue) { query = query.Where(c => c.ApplicationID == request.ApplicationID.Value); } else if (request.OwnerMemberID.HasValue) { query = query.Where(c => c.Application!.OwnerMemberID == request.OwnerMemberID.Value); } else { return Result.Failure(Error.Unauthorized("Purchase.CallerUnknown", "호출 주체를 식별할 수 없습니다.")); } if (request.Marketplace.HasValue) { var marketplace = (ApiPurchaseMarketplace)request.Marketplace.Value; query = query.Where(c => c.Marketplace == marketplace); } var rows = await query .Select(c => new Response( c.ID, c.OrderID, (int)c.Marketplace, c.Channel!.DonationCode, c.Channel!.SID, c.Game!.Code ?? string.Empty, c.ProductID, c.SubID, c.OrderPrice, c.CommissionRate, c.CommissionAmount, c.Status.ToString(), c.ConfirmDueAt, c.ConfirmedAt, c.CanceledAt, c.CreatedAt )) .ToListAsync(ct); if (rows.Count == 0) { return Result.Failure(Error.NotFound("Purchase.NotFound", "등록된 주문을 찾을 수 없습니다.")); } if (rows.Count > 1) { return Result.Failure(Error.Problem("Purchase.AmbiguousOrderID", "여러 건이 조회되었습니다. marketplace 를 지정하세요.")); } return Result.Success(rows[0]); } }