add order status event add order status event handlerpull/1940/head
@ -0,0 +1,13 @@ | |||
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; | |||
public class SetCompletedOrderStatusCommand : IRequest<bool> | |||
{ | |||
[DataMember] | |||
public int OrderNumber { get; private set; } | |||
public SetCompletedOrderStatusCommand(int orderNumber) | |||
{ | |||
OrderNumber = orderNumber; | |||
} | |||
} |
@ -0,0 +1,51 @@ | |||
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; | |||
// Regular CommandHandler | |||
public class SetCompletedOrderStatusCommandHandler : IRequestHandler<SetCompletedOrderStatusCommand, bool> | |||
{ | |||
private readonly IOrderRepository _orderRepository; | |||
public SetCompletedOrderStatusCommandHandler(IOrderRepository orderRepository) | |||
{ | |||
_orderRepository = orderRepository; | |||
} | |||
/// <summary> | |||
/// Handler which processes the command when | |||
/// Completed the order | |||
/// </summary> | |||
/// <param name="command"></param> | |||
/// <returns></returns> | |||
public async Task<bool> Handle(SetCompletedOrderStatusCommand command, CancellationToken cancellationToken) | |||
{ | |||
// Simulate a work time for validating the completed | |||
await Task.Delay(10000, 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 SetCompletedIdentifiedOrderStatusCommandHandler : IdentifiedCommandHandler<SetCompletedOrderStatusCommand, bool> | |||
{ | |||
public SetCompletedIdentifiedOrderStatusCommandHandler( | |||
IMediator mediator, | |||
IRequestManager requestManager, | |||
ILogger<IdentifiedCommandHandler<SetCompletedOrderStatusCommand, bool>> logger) | |||
: base(mediator, requestManager, logger) | |||
{ | |||
} | |||
protected override bool CreateResultForDuplicateRequest() | |||
{ | |||
return true; // Ignore duplicate requests for processing order. | |||
} | |||
} |
@ -0,0 +1,44 @@ | |||
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.DomainEventHandlers.OrderCompleted; | |||
public class OrderStatusChangedToCompletedDomainEventHandler | |||
: INotificationHandler<OrderStatusChangedToCompletedDomainEvent> | |||
{ | |||
private readonly IOrderRepository _orderRepository; | |||
private readonly ILoggerFactory _logger; | |||
private readonly IBuyerRepository _buyerRepository; | |||
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService; | |||
public OrderStatusChangedToCompletedDomainEventHandler( | |||
IOrderRepository orderRepository, ILoggerFactory 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 ?? throw new ArgumentNullException(nameof(orderingIntegrationEventService)); | |||
} | |||
public async Task Handle(OrderStatusChangedToCompletedDomainEvent orderStatusChangedToCompletedDomainEvent, CancellationToken cancellationToken) | |||
{ | |||
_logger.CreateLogger<OrderStatusChangedToCompletedDomainEventHandler>() | |||
.LogTrace("Order with Id: {OrderId} has been successfully updated to status {Status} ({Id})", | |||
orderStatusChangedToCompletedDomainEvent.OrderId, nameof(OrderStatus.Complete), OrderStatus.Complete.Id); | |||
var order = await _orderRepository.GetAsync(orderStatusChangedToCompletedDomainEvent.OrderId); | |||
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString()); | |||
var orderStockList = orderStatusChangedToCompletedDomainEvent.OrderItems | |||
.Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.GetUnits())); | |||
var orderStatusChangedToCompletedIntegrationEvent = new OrderStatusChangedToCompletedIntegrationEvent( | |||
orderStatusChangedToCompletedDomainEvent.OrderId, | |||
order.OrderStatus.Name, | |||
buyer.Name, | |||
orderStockList); | |||
await _orderingIntegrationEventService.AddAndSaveEventAsync(orderStatusChangedToCompletedIntegrationEvent); | |||
} | |||
} |
@ -0,0 +1,35 @@ | |||
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.IntegrationEvents.EventHandling; | |||
public class OrderCompletedFailedIntegrationEventHandler : | |||
IIntegrationEventHandler<OrderCompletedFailedIntegrationEvent> | |||
{ | |||
private readonly IMediator _mediator; | |||
private readonly ILogger<OrderCompletedFailedIntegrationEventHandler> _logger; | |||
public OrderCompletedFailedIntegrationEventHandler( | |||
IMediator mediator, | |||
ILogger<OrderCompletedFailedIntegrationEventHandler> logger) | |||
{ | |||
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator)); | |||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); | |||
} | |||
public async Task Handle(OrderCompletedFailedIntegrationEvent @event) | |||
{ | |||
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}")) | |||
{ | |||
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event); | |||
var command = new CancelOrderCommand(@event.OrderId); | |||
_logger.LogInformation( | |||
"----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})", | |||
command.GetGenericTypeName(), | |||
nameof(command.OrderNumber), | |||
command.OrderNumber, | |||
command); | |||
await _mediator.Send(command); | |||
} | |||
} | |||
} |
@ -0,0 +1,35 @@ | |||
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.IntegrationEvents.EventHandling; | |||
public class OrderCompletedSucceededIntegrationEventHandler : | |||
IIntegrationEventHandler<OrderCompletedSucceededIntegrationEvent> | |||
{ | |||
private readonly IMediator _mediator; | |||
private readonly ILogger<OrderCompletedSucceededIntegrationEventHandler> _logger; | |||
public OrderCompletedSucceededIntegrationEventHandler( | |||
IMediator mediator, | |||
ILogger<OrderCompletedSucceededIntegrationEventHandler> logger) | |||
{ | |||
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator)); | |||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); | |||
} | |||
public async Task Handle(OrderCompletedSucceededIntegrationEvent @event) | |||
{ | |||
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}")) | |||
{ | |||
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event); | |||
var command = new SetCompletedOrderStatusCommand(@event.OrderId); | |||
_logger.LogInformation( | |||
"----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})", | |||
command.GetGenericTypeName(), | |||
nameof(command.OrderNumber), | |||
command.OrderNumber, | |||
command); | |||
await _mediator.Send(command); | |||
} | |||
} | |||
} |
@ -0,0 +1,8 @@ | |||
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.IntegrationEvents.Events; | |||
public record OrderCompletedFailedIntegrationEvent : IntegrationEvent | |||
{ | |||
public int OrderId { get; } | |||
public OrderCompletedFailedIntegrationEvent(int orderId) => OrderId = orderId; | |||
} |
@ -0,0 +1,8 @@ | |||
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.IntegrationEvents.Events; | |||
public record OrderCompletedSucceededIntegrationEvent : IntegrationEvent | |||
{ | |||
public int OrderId { get; } | |||
public OrderCompletedSucceededIntegrationEvent(int orderId) => OrderId = orderId; | |||
} |
@ -0,0 +1,21 @@ | |||
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 IEnumerable<OrderStockItem> OrderStockItems { get; } | |||
public OrderStatusChangedToCompletedIntegrationEvent(int orderId, | |||
string orderStatus, | |||
string buyerName, | |||
IEnumerable<OrderStockItem> orderStockItems) | |||
{ | |||
OrderId = orderId; | |||
OrderStockItems = orderStockItems; | |||
OrderStatus = orderStatus; | |||
BuyerName = buyerName; | |||
} | |||
} | |||
@ -0,0 +1,18 @@ | |||
namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.Events; | |||
/// <summary> | |||
/// Event used when the order is completed | |||
/// </summary> | |||
public class OrderStatusChangedToCompletedDomainEvent | |||
: INotification | |||
{ | |||
public int OrderId { get; } | |||
public IEnumerable<OrderItem> OrderItems { get; } | |||
public OrderStatusChangedToCompletedDomainEvent(int orderId, | |||
IEnumerable<OrderItem> orderItems) | |||
{ | |||
OrderId = orderId; | |||
OrderItems = orderItems; | |||
} | |||
} |
@ -0,0 +1,28 @@ | |||
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 (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}")) | |||
{ | |||
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @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; | |||
} | |||
} |