| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- using Application.Abstractions.Data;
- using Application.Abstractions.Messaging;
- using Domain.Entities.Store.ValueObject;
- using Microsoft.EntityFrameworkCore;
- namespace Application.Features.Api.Store.Orders.List;
- internal sealed class Handler(IAppDbContext db) : IQueryHandler<Query, Response>
- {
- public async Task<Response> Handle(Query request, CancellationToken ct)
- {
- var query = db.Order.AsNoTracking()
- .Include(o => o.Channel)
- .Include(o => o.Items)
- .ThenInclude(i => i.Product)
- .Where(o => o.MemberID == request.MemberID);
- if (request.Status.HasValue)
- {
- query = query.Where(o => o.Status == request.Status.Value);
- }
- else
- {
- // Pending(미결제) 은 사용자 뷰에서 제외
- query = query.Where(o => o.Status != OrderStatus.Pending);
- }
- // 기간 필터: Year 명시 → 해당 연도 / 미명시 → 최근 6개월 (CreatedAt UTC 기준)
- if (request.Year.HasValue)
- {
- var start = new DateTime(request.Year.Value, 1, 1, 0, 0, 0, DateTimeKind.Utc);
- var end = start.AddYears(1);
- query = query.Where(o => o.CreatedAt >= start && o.CreatedAt < end);
- }
- else
- {
- var sixMonthsAgo = DateTime.UtcNow.AddMonths(-6);
- query = query.Where(o => o.CreatedAt >= sixMonthsAgo);
- }
- // 상품명 검색 — 주문 라인 중 1개라도 매칭되면 주문 노출
- if (!string.IsNullOrWhiteSpace(request.Keyword))
- {
- var kw = request.Keyword.Trim();
- query = query.Where(o => o.Items.Any(i => i.Product!.Name.Contains(kw)));
- }
- var total = await query.CountAsync(ct);
- var list = await query
- .OrderByDescending(o => o.ID)
- .Skip((request.Page - 1) * request.PerPage)
- .Take(request.PerPage)
- .Select(o => new
- {
- o.ID,
- o.OrderNumber,
- o.TotalAmount,
- o.Status,
- o.ChannelID,
- ChannelName = o.Channel != null ? o.Channel.Name : null,
- HasPhysical = o.Items.Any(i => i.Product!.Type == ProductType.Physical),
- HasDigital = o.Items.Any(i => i.Product!.Type == ProductType.Digital),
- o.CreatedAt,
- o.PaidAt,
- ItemCount = o.Items.Count,
- FirstItemName = o.Items.OrderBy(i => i.ID).Select(i => i.Product!.Name).FirstOrDefault() ?? "",
- FirstItemThumbnail = o.Items.OrderBy(i => i.ID).Select(i => i.Product!.Thumbnail).FirstOrDefault(),
- ShipmentStatus = db.Shipment.Where(s => s.OrderID == o.ID).Select(s => (ShipmentStatus?)s.Status).FirstOrDefault(),
- HasActiveRefundRequest = db.OrderRefund.Any(r => r.OrderID == o.ID && r.Status == RefundStatus.Requested)
- })
- .ToListAsync(ct);
- return new Response(
- total,
- [.. list.Select(c => new Response.Row(
- c.ID,
- c.OrderNumber,
- c.TotalAmount,
- c.Status,
- c.ChannelID,
- c.ChannelName,
- c.HasPhysical,
- c.HasDigital,
- c.CreatedAt,
- c.PaidAt,
- c.ItemCount,
- c.FirstItemName,
- c.FirstItemThumbnail,
- c.ShipmentStatus,
- c.HasActiveRefundRequest
- ))]
- );
- }
- }
|