my-code-codex

CreateOrderUseCase

Caso de uso que orquestra a criação de um pedido. Coordena domínio, repositório, Unit of Work e publicação de eventos.

namespace Application.UseCases;

public record CreateOrderInput(string CustomerId, List<OrderItemInput> Items);
public record OrderItemInput(string ProductId, decimal Price, int Quantity);
public record CreateOrderOutput(Guid OrderId, decimal Total);

public class CreateOrderUseCase
{
    private readonly IOrderRepository _orderRepository;
    private readonly IUnitOfWork _unitOfWork;
    private readonly OrderDomainService _domainService;
    private readonly OrderFactory _factory;
    private readonly IEventPublisher _eventPublisher;

    public CreateOrderUseCase(
        IOrderRepository orderRepository,
        IUnitOfWork unitOfWork,
        OrderDomainService domainService,
        OrderFactory factory,
        IEventPublisher eventPublisher)
    {
        _orderRepository = orderRepository;
        _unitOfWork = unitOfWork;
        _domainService = domainService;
        _factory = factory;
        _eventPublisher = eventPublisher;
    }

    public async Task<Result<CreateOrderOutput>> ExecuteAsync(CreateOrderInput input, CancellationToken ct = default)
    {
        var existingOrders = await _orderRepository.GetByCustomerIdAsync(input.CustomerId, ct);

        if (!_domainService.CustomerCanPlaceOrder(existingOrders))
            return Result.Fail("Cliente atingiu o limite de pedidos pendentes.");

        var order = _factory.Create(
            input.CustomerId,
            input.Items.Select(i => (i.ProductId, i.Price, i.Quantity))
        );

        await _orderRepository.AddAsync(order, ct);

        // Um único commit: tudo persiste junto ou nada persiste
        await _unitOfWork.CommitAsync(ct);

        foreach (var domainEvent in order.DomainEvents)
        {
            var integrationEvent = new OrderCreatedIntegrationEvent(order.Id, order.CustomerId);
            await _eventPublisher.PublishAsync(integrationEvent, ct);
        }

        order.ClearDomainEvents();

        return Result.Ok(new CreateOrderOutput(order.Id, order.Total));
    }
}