@ -0,0 +1,16 @@ | |||||
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; | |||||
public class CompleteOrderCommand : IRequest<bool> | |||||
{ | |||||
[DataMember] | |||||
public int OrderNumber { get; set; } | |||||
public CompleteOrderCommand() | |||||
{ | |||||
} | |||||
public CompleteOrderCommand(int orderNumber) | |||||
{ | |||||
OrderNumber = orderNumber; | |||||
} | |||||
} |
@ -0,0 +1,48 @@ | |||||
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; | |||||
// Regular CommandHandler | |||||
public class CompleteOrderCommandHandler : IRequestHandler<CompleteOrderCommand, bool> | |||||
{ | |||||
private readonly IOrderRepository _orderRepository; | |||||
public CompleteOrderCommandHandler(IOrderRepository orderRepository) | |||||
{ | |||||
_orderRepository = orderRepository; | |||||
} | |||||
/// <summary> | |||||
/// Handler which processes the command when | |||||
/// customer executes complete order from app | |||||
/// </summary> | |||||
/// <param name="command"></param> | |||||
/// <returns></returns> | |||||
public async Task<bool> Handle(CompleteOrderCommand command, CancellationToken cancellationToken) | |||||
{ | |||||
var orderToUpdate = await _orderRepository.GetAsync(command.OrderNumber); | |||||
if (orderToUpdate == null) | |||||
{ | |||||
return false; | |||||
} | |||||
orderToUpdate.SetCompletedStatus(); | |||||
return await _orderRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken); | |||||
} | |||||
} | |||||
// Use for Idempotency in Command process | |||||
public class CompleteOrderIdentifiedCommandHandler : IdentifiedCommandHandler<CompleteOrderCommand, bool> | |||||
{ | |||||
public CompleteOrderIdentifiedCommandHandler( | |||||
IMediator mediator, | |||||
IRequestManager requestManager, | |||||
ILogger<IdentifiedCommandHandler<CompleteOrderCommand, bool>> logger) | |||||
: base(mediator, requestManager, logger) | |||||
{ | |||||
} | |||||
protected override bool CreateResultForDuplicateRequest() | |||||
{ | |||||
return true; // Ignore duplicate requests for processing order. | |||||
} | |||||
} |
@ -0,0 +1,33 @@ | |||||
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.DomainEventHandlers; | |||||
public partial class OrderCompletedDomainEventHandler | |||||
: INotificationHandler<OrderCompletedDomainEvent> | |||||
{ | |||||
private readonly IOrderRepository _orderRepository; | |||||
private readonly IBuyerRepository _buyerRepository; | |||||
private readonly ILogger _logger; | |||||
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService; | |||||
public OrderCompletedDomainEventHandler( | |||||
IOrderRepository orderRepository, | |||||
ILogger<OrderCompletedDomainEventHandler> logger, | |||||
IBuyerRepository buyerRepository, | |||||
IOrderingIntegrationEventService orderingIntegrationEventService) | |||||
{ | |||||
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository)); | |||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); | |||||
_buyerRepository = buyerRepository ?? throw new ArgumentNullException(nameof(buyerRepository)); | |||||
_orderingIntegrationEventService = orderingIntegrationEventService; | |||||
} | |||||
public async Task Handle(OrderCompletedDomainEvent domainEvent, CancellationToken cancellationToken) | |||||
{ | |||||
OrderingApiTrace.LogOrderStatusUpdated(_logger, domainEvent.Order.Id, nameof(OrderStatus.Cancelled), OrderStatus.Cancelled.Id); | |||||
var order = await _orderRepository.GetAsync(domainEvent.Order.Id); | |||||
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString()); | |||||
var integrationEvent = new OrderStatusChangedToCompletedIntegrationEvent(order.Id, order.OrderStatus.Name, buyer.Name); | |||||
await _orderingIntegrationEventService.AddAndSaveEventAsync(integrationEvent); | |||||
} | |||||
} |
@ -0,0 +1,15 @@ | |||||
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.IntegrationEvents.Events; | |||||
public record OrderStatusChangedToCompletedIntegrationEvent : IntegrationEvent | |||||
{ | |||||
public int OrderId { get; } | |||||
public string OrderStatus { get; } | |||||
public string BuyerName { get; } | |||||
public OrderStatusChangedToCompletedIntegrationEvent(int orderId, string orderStatus, string buyerName) | |||||
{ | |||||
OrderId = orderId; | |||||
OrderStatus = orderStatus; | |||||
BuyerName = buyerName; | |||||
} | |||||
} |
@ -0,0 +1,11 @@ | |||||
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Validations; | |||||
public class CompleteOrderCommandValidator : AbstractValidator<CompleteOrderCommand> | |||||
{ | |||||
public CompleteOrderCommandValidator(ILogger<CompleteOrderCommandValidator> logger) | |||||
{ | |||||
RuleFor(order => order.OrderNumber).NotEmpty().WithMessage("No orderId found"); | |||||
logger.LogTrace("INSTANCE CREATED - {ClassName}", GetType().Name); | |||||
} | |||||
} |
@ -0,0 +1,12 @@ | |||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.Events; | |||||
public class OrderCompletedDomainEvent : INotification | |||||
{ | |||||
public Order Order { get; } | |||||
public OrderCompletedDomainEvent(Order order) | |||||
{ | |||||
Order = order; | |||||
} | |||||
} | |||||
@ -0,0 +1,30 @@ | |||||
using System.Collections.Generic; | |||||
namespace Microsoft.eShopOnContainers.Services.Ordering.SignalrHub.IntegrationEvents.EventHandling; | |||||
public class OrderStatusChangedToCompletedIntegrationEventHandler : IIntegrationEventHandler<OrderStatusChangedToCompletedIntegrationEvent> | |||||
{ | |||||
private readonly IHubContext<NotificationsHub> _hubContext; | |||||
private readonly ILogger<OrderStatusChangedToCompletedIntegrationEventHandler> _logger; | |||||
public OrderStatusChangedToCompletedIntegrationEventHandler( | |||||
IHubContext<NotificationsHub> hubContext, | |||||
ILogger<OrderStatusChangedToCompletedIntegrationEventHandler> logger) | |||||
{ | |||||
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext)); | |||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); | |||||
} | |||||
public async Task Handle(OrderStatusChangedToCompletedIntegrationEvent @event) | |||||
{ | |||||
using (_logger.BeginScope(new List<KeyValuePair<string, object>> { new ("IntegrationEventContext", @event.Id) })) | |||||
{ | |||||
_logger.LogInformation("Handling integration event: {IntegrationEventId} - ({@IntegrationEvent})", @event.Id, @event); | |||||
await _hubContext.Clients | |||||
.Group(@event.BuyerName) | |||||
.SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus }); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,16 @@ | |||||
namespace Microsoft.eShopOnContainers.Services.Ordering.SignalrHub.IntegrationEvents.Events; | |||||
public record OrderStatusChangedToCompletedIntegrationEvent : IntegrationEvent | |||||
{ | |||||
public int OrderId { get; } | |||||
public string OrderStatus { get; } | |||||
public string BuyerName { get; } | |||||
public OrderStatusChangedToCompletedIntegrationEvent(int orderId, string orderStatus, string buyerName) | |||||
{ | |||||
OrderId = orderId; | |||||
OrderStatus = orderStatus; | |||||
BuyerName = buyerName; | |||||
} | |||||
} | |||||