From 9a6ad2cc8568223073fe4d2f884a6fdcd0357c4e Mon Sep 17 00:00:00 2001 From: Christian Arenas Date: Wed, 10 May 2017 19:48:36 +0200 Subject: [PATCH] Continue implementing OrderStockConfirmed events --- ...onfirmOrderStockIntegrationEventHandler.cs | 23 +++++---- ...erStockMethodVerifiedDomainEventHandler.cs | 50 +++++++++++++++++++ .../Commands/PayOrderCommandMsg.cs | 14 ++++++ ...erStockConfirmedIntegrationEventHandler.cs | 36 +++++++++++-- ...tockNotConfirmedIntegrationEventHandler.cs | 34 ++++++++++++- .../OrderStockNotConfirmedIntegrationEvent.cs | 6 +-- .../Application/Sagas/OrderProcessSaga.cs | 16 +++--- .../Ordering/Ordering.API/Ordering.API.csproj | 1 - src/Services/Ordering/Ordering.API/Startup.cs | 2 +- .../AggregatesModel/OrderAggregate/Order.cs | 14 ++++++ .../OrderStockMethodVerifiedDomainEvent.cs | 22 ++++++++ 11 files changed, 189 insertions(+), 29 deletions(-) create mode 100644 src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmation/UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler.cs create mode 100644 src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/PayOrderCommandMsg.cs create mode 100644 src/Services/Ordering/Ordering.Domain/Events/OrderStockMethodVerifiedDomainEvent.cs diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/ConfirmOrderStockIntegrationEventHandler.cs b/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/ConfirmOrderStockIntegrationEventHandler.cs index 062263a33..21d12e1ee 100644 --- a/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/ConfirmOrderStockIntegrationEventHandler.cs +++ b/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/ConfirmOrderStockIntegrationEventHandler.cs @@ -1,16 +1,14 @@ -using System.Collections.Generic; -using System.Linq; -using Catalog.API.Infrastructure.Exceptions; -using Catalog.API.IntegrationEvents; -using Microsoft.eShopOnContainers.Services.Catalog.API.Model; - -namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.EventHandling +namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.EventHandling { using BuildingBlocks.EventBus.Abstractions; using System.Threading.Tasks; using BuildingBlocks.EventBus.Events; using Infrastructure; - + using System.Collections.Generic; + using System.Linq; + using global::Catalog.API.Infrastructure.Exceptions; + using global::Catalog.API.IntegrationEvents; + using Model; using Events; public class ConfirmOrderStockIntegrationEventHandler : IIntegrationEventHandler @@ -41,12 +39,15 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Eve } //Create Integration Event to be published through the Event Bus - var integrationEvent = confirmedOrderStockItems.Any(c => !c.Confirmed) + var confirmedIntegrationEvent = confirmedOrderStockItems.Any(c => !c.Confirmed) ? (IntegrationEvent) new OrderStockNotConfirmedIntegrationEvent(@event.OrderId, confirmedOrderStockItems) : new OrderStockConfirmedIntegrationEvent(@event.OrderId); - + + // Achieving atomicity between original Catalog database operation and the IntegrationEventLog thanks to a local transaction + await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(confirmedIntegrationEvent); + // Publish through the Event Bus and mark the saved event as published - await _catalogIntegrationEventService.PublishThroughEventBusAsync(integrationEvent); + await _catalogIntegrationEventService.PublishThroughEventBusAsync(confirmedIntegrationEvent); } private void CheckValidcatalogItemId(CatalogItem catalogItem) diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmation/UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmation/UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler.cs new file mode 100644 index 000000000..abea5e0da --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmation/UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler.cs @@ -0,0 +1,50 @@ +namespace Ordering.API.Application.DomainEventHandlers.OrderStartedEvent +{ + using MediatR; + using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; + using Microsoft.Extensions.Logging; + using Domain.Events; + using System; + using System.Threading.Tasks; + + public class UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler + : IAsyncNotificationHandler + { + private readonly IOrderRepository _orderRepository; + private readonly ILoggerFactory _logger; + + public UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler( + IOrderRepository orderRepository, ILoggerFactory logger) + { + _orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } + + // Domain Logic comment: + // When the Order Stock items method have been validate and confirmed, + // then we can update the original Order with the new order status + public async Task Handle(OrderStockMethodVerifiedDomainEvent orderStockMethodVerifiedDomainEvent) + { + var orderToUpdate = await _orderRepository.GetAsync(orderStockMethodVerifiedDomainEvent.OrderId); + orderToUpdate.SetOrderStatusId(orderStockMethodVerifiedDomainEvent.OrderStatus.Id); + + _orderRepository.Update(orderToUpdate); + + await _orderRepository.UnitOfWork + .SaveEntitiesAsync(); + + _logger.CreateLogger(nameof(UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler)) + .LogTrace($"Order with Id: {orderStockMethodVerifiedDomainEvent.OrderId} has been successfully updated with " + + $"a status order id: { orderStockMethodVerifiedDomainEvent.OrderStatus.Id }"); + + + //var payOrderCommandMsg = new PayOrderCommandMsg(order.Id); + + //// Achieving atomicity between original Catalog database operation and the IntegrationEventLog thanks to a local transaction + //await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(payOrderCommandMsg); + + //// Publish through the Event Bus and mark the saved event as published + //await _orderingIntegrationEventService.PublishThroughEventBusAsync(payOrderCommandMsg); + } + } +} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/PayOrderCommandMsg.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/PayOrderCommandMsg.cs new file mode 100644 index 000000000..749ec882e --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/PayOrderCommandMsg.cs @@ -0,0 +1,14 @@ +namespace Ordering.API.Application.IntegrationCommands.Commands +{ + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + + public class PayOrderCommandMsg : IntegrationEvent + { + public int OrderId { get; } + + public PayOrderCommandMsg(int orderId) + { + OrderId = orderId; + } + } +} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs index 819755e00..34dec2351 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs @@ -1,18 +1,48 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling { using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; - using System; using System.Threading.Tasks; using Events; + using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; + using Ordering.API.Application.IntegrationCommands.Commands; + using Ordering.Domain.Exceptions; public class OrderStockConfirmedIntegrationEventHandler : IIntegrationEventHandler { + private readonly IOrderingIntegrationEventService _orderingIntegrationEventService; + private readonly IOrderRepository _orderRepository; + + public OrderStockConfirmedIntegrationEventHandler(IOrderRepository orderRepository, + IOrderingIntegrationEventService orderingIntegrationEventService) + { + _orderRepository = orderRepository; + _orderingIntegrationEventService = orderingIntegrationEventService; + } + public async Task Handle(OrderStockConfirmedIntegrationEvent @event) { //TODO: 1) Updates the state to "StockValidated" and any meaningful OrderContextDescription message saying that all the items were confirmed with available stock, etc - //TODO: 2) Sends a Command-message (PayOrderCommand msg/bus) to the Payment svc. from Ordering micro (thru Command Bus, as a message, NOT http) + var order = await _orderRepository.GetAsync(@event.OrderId); + CheckValidSagaId(order); + + order.SetOrderStockConfirmed(true); - throw new NotImplementedException(); + //Create Integration Event to be published through the Event Bus + var payOrderCommandMsg = new PayOrderCommandMsg(order.Id); + + // Achieving atomicity between original Catalog database operation and the IntegrationEventLog thanks to a local transaction + await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(payOrderCommandMsg); + + // Publish through the Event Bus and mark the saved event as published + await _orderingIntegrationEventService.PublishThroughEventBusAsync(payOrderCommandMsg); + } + + private void CheckValidSagaId(Order orderSaga) + { + if (orderSaga is null) + { + throw new OrderingDomainException("Not able to process order saga event. Reason: no valid orderId"); + } } } } \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs index c82cdd6eb..c5b7e6b01 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs @@ -4,15 +4,45 @@ using System; using System.Threading.Tasks; using Events; + using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; + using Ordering.API.Application.Sagas; + using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; + using Ordering.Domain.Exceptions; public class OrderStockNotConfirmedIntegrationEventHandler : IIntegrationEventHandler { + private readonly IOrderingIntegrationEventService _orderingIntegrationEventService; + private readonly IOrderRepository _orderRepository; + + public OrderStockNotConfirmedIntegrationEventHandler(IOrderRepository orderRepository, + IOrderingIntegrationEventService orderingIntegrationEventService) + { + _orderRepository = orderRepository; + _orderingIntegrationEventService = orderingIntegrationEventService; + } + public async Task Handle(OrderStockNotConfirmedIntegrationEvent @event) { //TODO: must update the order state to cancelled and the CurrentOrderStateContextDescription with the reasons of no-stock confirm - //TODO: for this/that articles which is info coming in that integration event. --> ORDER PROCESS + var order = await _orderRepository.GetAsync(@event.OrderId); + CheckValidSagaId(order); + + order.SetOrderStockConfirmed(false); - throw new NotImplementedException(); + var orderStockNotConfirmedItems = @event.OrderStockItems.FindAll(c => !c.Confirmed); + + foreach (var orderStockNotConfirmedItem in orderStockNotConfirmedItems) + { + //TODO: Add messages + } + } + + private void CheckValidSagaId(Order orderSaga) + { + if (orderSaga is null) + { + throw new OrderingDomainException("Not able to process order saga event. Reason: no valid orderId"); + } } } } \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStockNotConfirmedIntegrationEvent.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStockNotConfirmedIntegrationEvent.cs index 13e3279bc..5337c5eae 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStockNotConfirmedIntegrationEvent.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStockNotConfirmedIntegrationEvent.cs @@ -8,13 +8,13 @@ namespace Ordering.API.Application.IntegrationEvents.Events { public int OrderId { get; } - public IEnumerable OrderStockItem { get; } + public List OrderStockItems { get; } public OrderStockNotConfirmedIntegrationEvent(int orderId, - IEnumerable orderStockItem) + List orderStockItems) { OrderId = orderId; - OrderStockItem = orderStockItem; + OrderStockItems = orderStockItems; } } diff --git a/src/Services/Ordering/Ordering.API/Application/Sagas/OrderProcessSaga.cs b/src/Services/Ordering/Ordering.API/Application/Sagas/OrderProcessSaga.cs index 28de7b10f..d071d0ea8 100644 --- a/src/Services/Ordering/Ordering.API/Application/Sagas/OrderProcessSaga.cs +++ b/src/Services/Ordering/Ordering.API/Application/Sagas/OrderProcessSaga.cs @@ -78,9 +78,9 @@ namespace Ordering.API.Application.Sagas /// period has completed. /// /// - public async Task Handle(ConfirmGracePeriodCommandMsg command) + public async Task Handle(ConfirmGracePeriodCommandMsg @event) { - var orderSaga = FindSagaById(command.OrderId); + var orderSaga = FindSagaById(@event.OrderId); CheckValidSagaId(orderSaga); if (orderSaga.OrderStatus != OrderStatus.Cancelled) @@ -88,14 +88,14 @@ namespace Ordering.API.Application.Sagas orderSaga.SetOrderStatusId(OrderStatus.AwaitingValidation.Id); await SaveChangesAsync(); - var orderStockList = orderSaga.OrderItems - .Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.GetUnits())); + var orderStockList = orderSaga.OrderItems + .Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.GetUnits())); - //Create Integration Event to be published through the Event Bus - var confirmOrderStockEvent = new ConfirmOrderStockCommandMsg(orderSaga.Id, orderStockList); + //Create Integration Event to be published through the Event Bus + var confirmOrderStockEvent = new ConfirmOrderStockCommandMsg(orderSaga.Id, orderStockList); - // Publish through the Event Bus and mark the saved event as published - await _orderingIntegrationEventService.PublishThroughEventBusAsync(confirmOrderStockEvent); + // Publish through the Event Bus and mark the saved event as published + await _orderingIntegrationEventService.PublishThroughEventBusAsync(confirmOrderStockEvent); } } diff --git a/src/Services/Ordering/Ordering.API/Ordering.API.csproj b/src/Services/Ordering/Ordering.API/Ordering.API.csproj index 117551584..d5ef524bb 100644 --- a/src/Services/Ordering/Ordering.API/Ordering.API.csproj +++ b/src/Services/Ordering/Ordering.API/Ordering.API.csproj @@ -79,7 +79,6 @@ - diff --git a/src/Services/Ordering/Ordering.API/Startup.cs b/src/Services/Ordering/Ordering.API/Startup.cs index fb32d3a08..2319c72b9 100644 --- a/src/Services/Ordering/Ordering.API/Startup.cs +++ b/src/Services/Ordering/Ordering.API/Startup.cs @@ -127,9 +127,9 @@ services.AddSingleton(); services.AddSingleton(); + services.AddTransient(); services.AddTransient, OrderProcessSaga>(); - services.AddTransient, OrderProcessSaga>(); services.AddTransient(); services.AddTransient(); services.AddOptions(); diff --git a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs index 9539c5184..7519a7de3 100644 --- a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs +++ b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs @@ -99,6 +99,20 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O _orderStatusId = id; } + public void SetOrderStockConfirmed(bool confirmed) + { + if(confirmed) + { + OrderStatus = OrderStatus.StockValidated; + AddDomainEvent(new OrderStockMethodVerifiedDomainEvent(Id, OrderStatus.StockValidated)); + } + else + { + OrderStatus = OrderStatus.Cancelled; + AddDomainEvent(new OrderStockMethodVerifiedDomainEvent(Id, OrderStatus.Cancelled)); + } + } + private void AddOrderStartedDomainEvent(int cardTypeId, string cardNumber, string cardSecurityNumber, string cardHolderName, DateTime cardExpiration) { diff --git a/src/Services/Ordering/Ordering.Domain/Events/OrderStockMethodVerifiedDomainEvent.cs b/src/Services/Ordering/Ordering.Domain/Events/OrderStockMethodVerifiedDomainEvent.cs new file mode 100644 index 000000000..c5acd26dd --- /dev/null +++ b/src/Services/Ordering/Ordering.Domain/Events/OrderStockMethodVerifiedDomainEvent.cs @@ -0,0 +1,22 @@ +namespace Ordering.Domain.Events +{ + using MediatR; + using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; + + /// + /// Event used when the order stock items are verified + /// + public class OrderStockMethodVerifiedDomainEvent + : IAsyncNotification + { + public int OrderId { get; } + public OrderStatus OrderStatus { get; } + + public OrderStockMethodVerifiedDomainEvent(int orderId, + OrderStatus orderStatus) + { + OrderId = orderId; + OrderStatus = orderStatus; + } + } +} \ No newline at end of file