feat(order-processing): execute order item strategies during order creation and add kitchen ticket API with session management.
This commit is contained in:
@@ -6,6 +6,7 @@ using MediatR;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using FnbEngine.API.Application.Commands;
|
||||
using FnbEngine.API.Application.Queries;
|
||||
using FnbEngine.Domain.AggregatesModel.SessionAggregate;
|
||||
|
||||
namespace FnbEngine.API.Controllers;
|
||||
|
||||
@@ -15,10 +16,12 @@ namespace FnbEngine.API.Controllers;
|
||||
public class KitchenController : ControllerBase
|
||||
{
|
||||
private readonly IMediator _mediator;
|
||||
private readonly ISessionRepository _sessionRepository;
|
||||
|
||||
public KitchenController(IMediator mediator)
|
||||
public KitchenController(IMediator mediator, ISessionRepository sessionRepository)
|
||||
{
|
||||
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
||||
_sessionRepository = sessionRepository ?? throw new ArgumentNullException(nameof(sessionRepository));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -62,6 +65,42 @@ public class KitchenController : ControllerBase
|
||||
var result = await _mediator.Send(new UpdateTicketStatusCommand(id, request.Status), ct);
|
||||
return Ok(new ApiResponse<bool> { Success = true, Data = result });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EN: Create a kitchen ticket from order-service.
|
||||
/// VI: Tạo phiếu bếp từ order-service.
|
||||
/// </summary>
|
||||
[HttpPost("tickets")]
|
||||
[ProducesResponseType(typeof(CreateTicketResponse), 200)]
|
||||
public async Task<ActionResult<CreateTicketResponse>> CreateTicket(
|
||||
[FromBody] CreateTicketRequest request,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
// EN: Find or create an active session for this shop
|
||||
// VI: Tìm hoặc tạo session hoạt động cho shop này
|
||||
var sessions = await _sessionRepository.GetByShopAsync(request.ShopId, ct);
|
||||
var activeSession = sessions.FirstOrDefault(s => s.Status == "Active");
|
||||
|
||||
if (activeSession == null)
|
||||
{
|
||||
activeSession = new Session(request.ShopId, request.ShopId, 1);
|
||||
await _sessionRepository.AddAsync(activeSession, ct);
|
||||
await _sessionRepository.UnitOfWork.SaveEntitiesAsync(ct);
|
||||
}
|
||||
|
||||
// EN: Create kitchen ticket via MediatR
|
||||
// VI: Tạo phiếu bếp qua MediatR
|
||||
var ticketId = await _mediator.Send(new CreateKitchenTicketCommand(
|
||||
activeSession.Id,
|
||||
request.ProductId,
|
||||
request.ProductName,
|
||||
null,
|
||||
0
|
||||
), ct);
|
||||
|
||||
return Ok(new CreateTicketResponse(ticketId));
|
||||
}
|
||||
|
||||
// ═══ RECIPE ENDPOINTS ═══
|
||||
|
||||
[HttpGet("recipes")]
|
||||
@@ -102,3 +141,12 @@ public class KitchenController : ControllerBase
|
||||
}
|
||||
|
||||
public record UpdateStatusRequest(string Status);
|
||||
|
||||
public record CreateTicketRequest(
|
||||
Guid ProductId,
|
||||
string ProductName,
|
||||
Guid ShopId,
|
||||
int Quantity,
|
||||
string? Notes);
|
||||
|
||||
public record CreateTicketResponse(Guid TicketId);
|
||||
|
||||
@@ -67,6 +67,14 @@ public class CreateOrderCommandHandler : IRequestHandler<CreateOrderCommand, Cre
|
||||
}
|
||||
}
|
||||
|
||||
// EN: Execute all items via their strategies (e.g., create kitchen tickets for PreparedFood)
|
||||
// VI: Thực thi tất cả items qua strategies (vd: tạo phiếu bếp cho PreparedFood)
|
||||
foreach (var item in order.Items)
|
||||
{
|
||||
var strategy = GetStrategy(item.ProductType);
|
||||
await strategy.ExecuteAsync(item, request.ShopId, cancellationToken);
|
||||
}
|
||||
|
||||
// EN: Apply discount if provided
|
||||
// VI: Áp dụng giảm giá nếu có
|
||||
if (request.DiscountAmount is > 0)
|
||||
|
||||
@@ -4,27 +4,23 @@
|
||||
using MediatR;
|
||||
using OrderService.Domain.AggregatesModel.OrderAggregate;
|
||||
using OrderService.Domain.Exceptions;
|
||||
using OrderService.Domain.Strategies;
|
||||
|
||||
namespace OrderService.API.Application.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Handler for processing payment and executing order items via strategies.
|
||||
/// VI: Handler xử lý thanh toán và thực thi order items qua strategies.
|
||||
/// EN: Handler for processing payment.
|
||||
/// VI: Handler xử lý thanh toán.
|
||||
/// </summary>
|
||||
public class PayOrderCommandHandler : IRequestHandler<PayOrderCommand, PayOrderResult>
|
||||
{
|
||||
private readonly IOrderRepository _orderRepository;
|
||||
private readonly IEnumerable<ILineItemStrategy> _strategies;
|
||||
private readonly ILogger<PayOrderCommandHandler> _logger;
|
||||
|
||||
public PayOrderCommandHandler(
|
||||
IOrderRepository orderRepository,
|
||||
IEnumerable<ILineItemStrategy> strategies,
|
||||
ILogger<PayOrderCommandHandler> logger)
|
||||
{
|
||||
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
|
||||
_strategies = strategies ?? throw new ArgumentNullException(nameof(strategies));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
@@ -55,21 +51,8 @@ public class PayOrderCommandHandler : IRequestHandler<PayOrderCommand, PayOrderR
|
||||
// VI: Đánh dấu order là đã thanh toán (sẽ validate status bên trong)
|
||||
order.MarkAsPaid();
|
||||
|
||||
// EN: Execute all items via their strategies
|
||||
// VI: Thực thi tất cả items qua strategies của chúng
|
||||
foreach (var item in order.Items)
|
||||
{
|
||||
var strategy = GetStrategy(item.ProductType);
|
||||
await strategy.ExecuteAsync(item, request.ShopId, cancellationToken);
|
||||
|
||||
_logger.LogInformation(
|
||||
"EN: Executed item {ProductName} via {StrategyType} / VI: Đã thực thi item {ProductName} qua {StrategyType}",
|
||||
item.ProductName,
|
||||
strategy.GetType().Name);
|
||||
}
|
||||
|
||||
// EN: Mark order as processing
|
||||
// VI: Đánh dấu order là đang xử lý
|
||||
// EN: Mark order as processing (strategies already executed at order creation)
|
||||
// VI: Đánh dấu order là đang xử lý (strategies đã được thực thi khi tạo order)
|
||||
order.MarkAsProcessing();
|
||||
|
||||
// EN: Save changes
|
||||
@@ -82,15 +65,4 @@ public class PayOrderCommandHandler : IRequestHandler<PayOrderCommand, PayOrderR
|
||||
|
||||
return new PayOrderResult(true, order.Status.Name);
|
||||
}
|
||||
|
||||
private ILineItemStrategy GetStrategy(string productType)
|
||||
{
|
||||
var strategy = _strategies.FirstOrDefault(s => s.SupportedType == productType);
|
||||
if (strategy == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"EN: No strategy found for product type / VI: Không tìm thấy strategy cho loại sản phẩm: {productType}");
|
||||
}
|
||||
return strategy;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public class FnbEngineClient
|
||||
notes);
|
||||
|
||||
var response = await _httpClient.PostAsJsonAsync(
|
||||
"/api/v1/fnb/kitchen-tickets",
|
||||
"/api/v1/kitchen/tickets",
|
||||
request,
|
||||
cancellationToken);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user