using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Domain.Entities.Store.ValueObject; using Microsoft.EntityFrameworkCore; using SharedKernel.Helpers; using SharedKernel.Results; namespace Application.Features.Admin.Store.Coupon.ExportCodes; /// /// CSV 양식 (DB 컬럼명 기준): /// ID, Code, Status, IssuedToMemberID, IssuedToMemberName, IssuedToMemberEmail, IssuedAt, UsedAt, CreatedAt /// /// Status 인코딩 (사용자 결정 — Option A): /// 0 = Available (미배포) /// 1 = Reserved/Issued/Used (배포된 상태로 묶음) /// /// 일시는 KST 로 출력 (UTC → Local 변환). /// public sealed class Handler(IAppDbContext db) : IQueryHandler> { private static readonly string[] Header = [ "ID", "Code", "Status", "IssuedToMemberID", "IssuedToMemberName", "IssuedToMemberEmail", "IssuedAt", "UsedAt", "CreatedAt" ]; public async Task> Handle(Query request, CancellationToken ct) { var coupon = await db.Coupon.AsNoTracking() .Where(c => c.ID == request.CouponID) .Select(c => new { c.ID, c.Name }) .FirstOrDefaultAsync(ct); if (coupon is null) { return Result.Failure(Error.NotFound("Coupon.NotFound", "쿠폰을 찾을 수 없습니다.")); } var rows = await db.CouponCode.AsNoTracking() .Include(c => c.IssuedToMember) .Where(c => c.CouponID == request.CouponID) .OrderBy(c => c.ID) .Select(c => new { c.ID, c.Code, c.Status, c.IssuedToMemberID, Name = c.IssuedToMember != null ? c.IssuedToMember.Name : null, Email = c.IssuedToMember != null ? c.IssuedToMember.Email : null, c.IssuedAt, c.UsedAt, c.CreatedAt }) .ToListAsync(ct); var csvRows = new List { Header }; foreach (var r in rows) { var status = r.Status == CouponCodeStatus.Available ? "0" : "1"; var memberID = r.IssuedToMemberID?.ToString() ?? ""; var name = r.Name ?? ""; var email = r.Email ?? ""; var issuedAt = r.IssuedAt.HasValue ? DateTime.SpecifyKind(r.IssuedAt.Value, DateTimeKind.Utc).ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss") : ""; var usedAt = r.UsedAt.HasValue ? DateTime.SpecifyKind(r.UsedAt.Value, DateTimeKind.Utc).ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss") : ""; var createdAt = DateTime.SpecifyKind(r.CreatedAt, DateTimeKind.Utc).ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"); csvRows.Add([ r.ID.ToString(), r.Code, status, memberID, name, email, issuedAt, usedAt, createdAt ]); } var bytes = CsvHelper.WriteUtf8Bom(csvRows); var fileName = $"coupon-codes-{request.CouponID}-{DateTime.Now:yyyyMMdd-HHmmss}.csv"; return Result.Success(new Response(bytes, fileName)); } }