From ce61b4d3db32229949dc21368230dd9668864029 Mon Sep 17 00:00:00 2001 From: Ho Ngoc Hai Date: Wed, 4 Mar 2026 10:37:55 +0700 Subject: [PATCH] feat(fnb-engine): add shopId and status filters to kitchen tickets Add shopId and status query params to GET /api/v1/kitchen/tickets. Joins through Session to resolve shopId since KitchenTicket only has SessionId. Backward-compatible: without shopId falls back to existing pending-by-station behavior. Co-Authored-By: Claude Opus 4.6 --- .../Queries/GetTicketsByShopQuery.cs | 11 +++++++ .../Queries/GetTicketsByShopQueryHandler.cs | 33 +++++++++++++++++++ .../Controllers/KitchenController.cs | 20 ++++++++--- .../IKitchenTicketRepository.cs | 6 ++++ .../Repositories/KitchenTicketRepository.cs | 19 +++++++++++ 5 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 services/fnb-engine-net/src/FnbEngine.API/Application/Queries/GetTicketsByShopQuery.cs create mode 100644 services/fnb-engine-net/src/FnbEngine.API/Application/Queries/GetTicketsByShopQueryHandler.cs diff --git a/services/fnb-engine-net/src/FnbEngine.API/Application/Queries/GetTicketsByShopQuery.cs b/services/fnb-engine-net/src/FnbEngine.API/Application/Queries/GetTicketsByShopQuery.cs new file mode 100644 index 00000000..b8ac3f14 --- /dev/null +++ b/services/fnb-engine-net/src/FnbEngine.API/Application/Queries/GetTicketsByShopQuery.cs @@ -0,0 +1,11 @@ +// EN: Query to get kitchen tickets by shop with optional status filter. +// VI: Query lấy phiếu bếp theo shop với bộ lọc trạng thái tùy chọn. + +using MediatR; + +namespace FnbEngine.API.Application.Queries; + +public record GetTicketsByShopQuery( + Guid ShopId, + string? Status = null +) : IRequest>; diff --git a/services/fnb-engine-net/src/FnbEngine.API/Application/Queries/GetTicketsByShopQueryHandler.cs b/services/fnb-engine-net/src/FnbEngine.API/Application/Queries/GetTicketsByShopQueryHandler.cs new file mode 100644 index 00000000..18aaec1c --- /dev/null +++ b/services/fnb-engine-net/src/FnbEngine.API/Application/Queries/GetTicketsByShopQueryHandler.cs @@ -0,0 +1,33 @@ +// EN: Handler for GetTicketsByShopQuery. +// VI: Handler cho GetTicketsByShopQuery. + +using MediatR; +using FnbEngine.Domain.AggregatesModel.KitchenAggregate; + +namespace FnbEngine.API.Application.Queries; + +public class GetTicketsByShopQueryHandler : IRequestHandler> +{ + private readonly IKitchenTicketRepository _repository; + + public GetTicketsByShopQueryHandler(IKitchenTicketRepository repository) + { + _repository = repository ?? throw new ArgumentNullException(nameof(repository)); + } + + public async Task> Handle(GetTicketsByShopQuery request, CancellationToken cancellationToken) + { + var tickets = await _repository.GetByShopAsync(request.ShopId, request.Status, cancellationToken); + + return tickets.Select(t => new KitchenTicketDto( + t.Id, + t.SessionId, + t.OrderItemId, + t.ItemName, + t.Station, + t.Priority, + t.Status, + t.CreatedAt + )); + } +} diff --git a/services/fnb-engine-net/src/FnbEngine.API/Controllers/KitchenController.cs b/services/fnb-engine-net/src/FnbEngine.API/Controllers/KitchenController.cs index d35f9129..9ee09bb9 100644 --- a/services/fnb-engine-net/src/FnbEngine.API/Controllers/KitchenController.cs +++ b/services/fnb-engine-net/src/FnbEngine.API/Controllers/KitchenController.cs @@ -22,16 +22,28 @@ public class KitchenController : ControllerBase } /// - /// EN: Get pending kitchen tickets. - /// VI: Lấy danh sách phiếu bếp chờ. + /// EN: Get kitchen tickets. Filter by shopId+status or by station (pending only). + /// VI: Lấy phiếu bếp. Lọc theo shopId+status hoặc theo station (chỉ pending). /// [HttpGet("tickets")] [ProducesResponseType(typeof(ApiResponse>), 200)] - public async Task>>> GetPendingTickets( + public async Task>>> GetTickets( + [FromQuery] Guid? shopId = null, + [FromQuery] string? status = null, [FromQuery] string? station = null, CancellationToken ct = default) { - var result = await _mediator.Send(new GetPendingTicketsQuery(station), ct); + IEnumerable result; + + if (shopId.HasValue && shopId.Value != Guid.Empty) + { + result = await _mediator.Send(new GetTicketsByShopQuery(shopId.Value, status), ct); + } + else + { + result = await _mediator.Send(new GetPendingTicketsQuery(station), ct); + } + return Ok(new ApiResponse> { Success = true, Data = result }); } diff --git a/services/fnb-engine-net/src/FnbEngine.Domain/AggregatesModel/KitchenAggregate/IKitchenTicketRepository.cs b/services/fnb-engine-net/src/FnbEngine.Domain/AggregatesModel/KitchenAggregate/IKitchenTicketRepository.cs index f6926b77..24b1eefb 100644 --- a/services/fnb-engine-net/src/FnbEngine.Domain/AggregatesModel/KitchenAggregate/IKitchenTicketRepository.cs +++ b/services/fnb-engine-net/src/FnbEngine.Domain/AggregatesModel/KitchenAggregate/IKitchenTicketRepository.cs @@ -40,4 +40,10 @@ public interface IKitchenTicketRepository : IRepository /// VI: Lấy danh sách phiếu theo session ID. /// Task> GetBySessionAsync(Guid sessionId, CancellationToken cancellationToken = default); + + /// + /// EN: Get tickets by shop ID with optional status filter. + /// VI: Lấy danh sách phiếu theo shop ID với bộ lọc trạng thái tùy chọn. + /// + Task> GetByShopAsync(Guid shopId, string? status = null, CancellationToken cancellationToken = default); } diff --git a/services/fnb-engine-net/src/FnbEngine.Infrastructure/Repositories/KitchenTicketRepository.cs b/services/fnb-engine-net/src/FnbEngine.Infrastructure/Repositories/KitchenTicketRepository.cs index cc3e0d89..ea4a6dfc 100644 --- a/services/fnb-engine-net/src/FnbEngine.Infrastructure/Repositories/KitchenTicketRepository.cs +++ b/services/fnb-engine-net/src/FnbEngine.Infrastructure/Repositories/KitchenTicketRepository.cs @@ -61,4 +61,23 @@ public class KitchenTicketRepository : IKitchenTicketRepository .OrderBy(kt => kt.CreatedAt) .ToListAsync(cancellationToken); } + + public async Task> GetByShopAsync(Guid shopId, string? status = null, CancellationToken cancellationToken = default) + { + var sessionIds = await _context.Sessions + .Where(s => s.ShopId == shopId) + .Select(s => s.Id) + .ToListAsync(cancellationToken); + + var query = _context.KitchenTickets + .Where(kt => sessionIds.Contains(kt.SessionId)); + + if (!string.IsNullOrWhiteSpace(status)) + query = query.Where(kt => kt.Status == status); + + return await query + .OrderByDescending(kt => kt.Priority) + .ThenBy(kt => kt.CreatedAt) + .ToListAsync(cancellationToken); + } }