diff --git a/docker-compose.vs.debug.yml b/docker-compose.vs.debug.yml index eaa0b6f35..f6187dee2 100644 --- a/docker-compose.vs.debug.yml +++ b/docker-compose.vs.debug.yml @@ -107,7 +107,7 @@ services: - "com.microsoft.visualstudio.targetoperatingsystem=linux" payment.api: - image: payment.api:dev + image: eshop/payment.api:dev build: args: source: ${DOCKER_BUILD_SOURCE} diff --git a/docker-compose.yml b/docker-compose.yml index cc134a005..75177c5db 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -86,7 +86,7 @@ services: dockerfile: Dockerfile payment.api: - image: payment.api + image: eshop/payment.api build: context: ./src/Services/Payment/Payment.API dockerfile: Dockerfile diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/ConfirmOrderStockIntegrationEventHandler.cs b/src/Services/Catalog/Catalog.API/IntegrationCommands/CommandHandlers/ConfirmOrderStockCommandMsgHandler.cs similarity index 77% rename from src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/ConfirmOrderStockIntegrationEventHandler.cs rename to src/Services/Catalog/Catalog.API/IntegrationCommands/CommandHandlers/ConfirmOrderStockCommandMsgHandler.cs index 21d12e1ee..beb23bbaf 100644 --- a/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/ConfirmOrderStockIntegrationEventHandler.cs +++ b/src/Services/Catalog/Catalog.API/IntegrationCommands/CommandHandlers/ConfirmOrderStockCommandMsgHandler.cs @@ -1,4 +1,4 @@ -namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.EventHandling +namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationCommands.CommandHandlers { using BuildingBlocks.EventBus.Abstractions; using System.Threading.Tasks; @@ -9,21 +9,22 @@ using global::Catalog.API.Infrastructure.Exceptions; using global::Catalog.API.IntegrationEvents; using Model; - using Events; + using Commands; + using IntegrationEvents.Events; - public class ConfirmOrderStockIntegrationEventHandler : IIntegrationEventHandler + public class ConfirmOrderStockCommandMsgHandler : IIntegrationEventHandler { private readonly CatalogContext _catalogContext; private readonly ICatalogIntegrationEventService _catalogIntegrationEventService; - public ConfirmOrderStockIntegrationEventHandler(CatalogContext catalogContext, + public ConfirmOrderStockCommandMsgHandler(CatalogContext catalogContext, ICatalogIntegrationEventService catalogIntegrationEventService) { _catalogContext = catalogContext; _catalogIntegrationEventService = catalogIntegrationEventService; } - public async Task Handle(ConfirmOrderStockIntegrationEvent @event) + public async Task Handle(ConfirmOrderStockCommandMsg @event) { var confirmedOrderStockItems = new List(); @@ -38,15 +39,11 @@ confirmedOrderStockItems.Add(confirmedOrderStockItem); } - //Create Integration Event to be published through the Event Bus 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(confirmedIntegrationEvent); } diff --git a/src/Services/Catalog/Catalog.API/IntegrationCommands/CommandHandlers/DecrementOrderStockCommandMsgHandler.cs b/src/Services/Catalog/Catalog.API/IntegrationCommands/CommandHandlers/DecrementOrderStockCommandMsgHandler.cs new file mode 100644 index 000000000..962f5222d --- /dev/null +++ b/src/Services/Catalog/Catalog.API/IntegrationCommands/CommandHandlers/DecrementOrderStockCommandMsgHandler.cs @@ -0,0 +1,42 @@ +namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationCommands.CommandHandlers +{ + using BuildingBlocks.EventBus.Abstractions; + using System.Threading.Tasks; + using Infrastructure; + using global::Catalog.API.Infrastructure.Exceptions; + using global::Catalog.API.IntegrationEvents; + using Model; + using Commands; + + public class DecrementOrderStockCommandMsgHandler : IIntegrationEventHandler + { + private readonly CatalogContext _catalogContext; + + public DecrementOrderStockCommandMsgHandler(CatalogContext catalogContext) + { + _catalogContext = catalogContext; + } + + public async Task Handle(DecrementOrderStockCommandMsg @event) + { + //we're not blocking stock/inventory + foreach (var orderStockItem in @event.OrderStockItems) + { + var catalogItem = _catalogContext.CatalogItems.Find(orderStockItem.ProductId); + CheckValidcatalogItemId(catalogItem); + + catalogItem.RemoveStock(orderStockItem.Units); + } + + await _catalogContext.SaveChangesAsync(); + } + + private void CheckValidcatalogItemId(CatalogItem catalogItem) + { + if (catalogItem is null) + { + throw new CatalogDomainException("Not able to process catalog event. Reason: no valid catalogItemId"); + } + } + } +} \ No newline at end of file diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ConfirmOrderStockIntegrationEvent.cs b/src/Services/Catalog/Catalog.API/IntegrationCommands/Commands/ConfirmOrderStockCommandMsg.cs similarity index 81% rename from src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ConfirmOrderStockIntegrationEvent.cs rename to src/Services/Catalog/Catalog.API/IntegrationCommands/Commands/ConfirmOrderStockCommandMsg.cs index 366c8f854..f5fc805b2 100644 --- a/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ConfirmOrderStockIntegrationEvent.cs +++ b/src/Services/Catalog/Catalog.API/IntegrationCommands/Commands/ConfirmOrderStockCommandMsg.cs @@ -1,14 +1,14 @@ -namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events +namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationCommands.Commands { using BuildingBlocks.EventBus.Events; using System.Collections.Generic; - public class ConfirmOrderStockIntegrationEvent : IntegrationEvent + public class ConfirmOrderStockCommandMsg : IntegrationEvent { public int OrderId { get; } public IEnumerable OrderStockItems { get; } - public ConfirmOrderStockIntegrationEvent(int orderId, + public ConfirmOrderStockCommandMsg(int orderId, IEnumerable orderStockItems) { OrderId = orderId; diff --git a/src/Services/Catalog/Catalog.API/IntegrationCommands/Commands/DecrementOrderStockCommandMsg.cs b/src/Services/Catalog/Catalog.API/IntegrationCommands/Commands/DecrementOrderStockCommandMsg.cs new file mode 100644 index 000000000..94bab1aa6 --- /dev/null +++ b/src/Services/Catalog/Catalog.API/IntegrationCommands/Commands/DecrementOrderStockCommandMsg.cs @@ -0,0 +1,18 @@ +namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationCommands.Commands +{ + using System.Collections.Generic; + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + + public class DecrementOrderStockCommandMsg : IntegrationEvent + { + public int OrderId { get; } + public IEnumerable OrderStockItems { get; } + + public DecrementOrderStockCommandMsg(int orderId, + IEnumerable orderStockItems) + { + OrderId = orderId; + OrderStockItems = orderStockItems; + } + } +} \ No newline at end of file diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/OrderStockConfirmedIntegrationEvent.cs b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/OrderStockConfirmedIntegrationEvent.cs index 1ce179c3a..b91eaae43 100644 --- a/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/OrderStockConfirmedIntegrationEvent.cs +++ b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/OrderStockConfirmedIntegrationEvent.cs @@ -1,6 +1,6 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events { - using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + using BuildingBlocks.EventBus.Events; public class OrderStockConfirmedIntegrationEvent : IntegrationEvent { diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductPriceChangedIntegrationEvent.cs b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductPriceChangedIntegrationEvent.cs index 10b8317da..7c14a07d1 100644 --- a/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductPriceChangedIntegrationEvent.cs +++ b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductPriceChangedIntegrationEvent.cs @@ -1,10 +1,7 @@ -using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; -using System; -using System.Collections.Generic; -using System.Text; - -namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events +namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events { + using BuildingBlocks.EventBus.Events; + // Integration Events notes: // An Event is “something that has happened in the past”, therefore its name has to be // An Integration Event is an event that can cause side effects to other microsrvices, Bounded-Contexts or external systems. @@ -23,4 +20,4 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Eve OldPrice = oldPrice; } } -} +} \ No newline at end of file diff --git a/src/Services/Catalog/Catalog.API/Startup.cs b/src/Services/Catalog/Catalog.API/Startup.cs index 509048d4c..22dd201d0 100644 --- a/src/Services/Catalog/Catalog.API/Startup.cs +++ b/src/Services/Catalog/Catalog.API/Startup.cs @@ -14,6 +14,9 @@ using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF; using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services; using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; + using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationCommands.Commands; + using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents; + using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationCommands.CommandHandlers; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.HealthChecks; @@ -24,7 +27,7 @@ using System.Data.Common; using System.Data.SqlClient; using System.Reflection; - + public class Startup { public IConfigurationRoot Configuration { get; } @@ -120,6 +123,8 @@ services.AddSingleton(); services.AddSingleton(); + services.AddTransient, ConfirmOrderStockCommandMsgHandler>(); + services.AddTransient, DecrementOrderStockCommandMsgHandler>(); var container = new ContainerBuilder(); container.Populate(services); @@ -149,6 +154,8 @@ CatalogContextSeed.SeedAsync(app, loggerFactory) .Wait(); + ConfigureEventBus(app); + var integrationEventLogContext = new IntegrationEventLogContext( new DbContextOptionsBuilder() .UseSqlServer(Configuration["ConnectionString"], b => b.MigrationsAssembly("Catalog.API")) @@ -180,5 +187,13 @@ ctx.Database.CloseConnection(); } } + + private void ConfigureEventBus(IApplicationBuilder app) + { + var eventBus = app.ApplicationServices.GetRequiredService(); + + eventBus.Subscribe>(); + eventBus.Subscribe>(); + } } } diff --git a/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs b/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs index c0d0a0d2b..3ef80a69a 100644 --- a/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs @@ -43,7 +43,7 @@ // make sure that consistency is preserved across the whole aggregate var address = new Address(message.Street, message.City, message.State, message.Country, message.ZipCode); var order = new Order(message.UserId, address, message.CardTypeId, message.CardNumber, message.CardSecurityNumber, message.CardHolderName, message.CardExpiration); - order.SetOrderStatusId(OrderStatus.Submited.Id); + order.SetSubmitedStatus(); foreach (var item in message.OrderItems) { order.AddOrderItem(item.ProductId, item.ProductName, item.UnitPrice, item.Discount, item.PictureUrl, item.Units); diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderGracePeriodConfirmed/OrderStatusChangedToAwaitingValidationDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderGracePeriodConfirmed/OrderStatusChangedToAwaitingValidationDomainEventHandler.cs new file mode 100644 index 000000000..d6906705f --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderGracePeriodConfirmed/OrderStatusChangedToAwaitingValidationDomainEventHandler.cs @@ -0,0 +1,46 @@ +namespace Ordering.API.Application.DomainEventHandlers.OrderGracePeriodConfirmed +{ + using MediatR; + using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; + using Microsoft.Extensions.Logging; + using Domain.Events; + using System; + using System.Threading.Tasks; + using Ordering.API.Application.IntegrationCommands.Commands; + using Ordering.API.Application.IntegrationEvents; + using System.Linq; + + public class OrderStatusChangedToAwaitingValidationDomainEventHandler + : IAsyncNotificationHandler + { + private readonly IOrderRepository _orderRepository; + private readonly ILoggerFactory _logger; + private readonly IOrderingIntegrationEventService _orderingIntegrationEventService; + + public OrderStatusChangedToAwaitingValidationDomainEventHandler( + IOrderRepository orderRepository, ILoggerFactory logger, + IOrderingIntegrationEventService orderingIntegrationEventService) + { + _orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _orderingIntegrationEventService = orderingIntegrationEventService; + } + + public async Task Handle(OrderStatusChangedToAwaitingValidationDomainEvent orderStatusChangedToAwaitingValidationDomainEvent) + { + await _orderRepository.UnitOfWork.SaveEntitiesAsync(); + + _logger.CreateLogger(nameof(OrderStatusChangedToAwaitingValidationDomainEvent)) + .LogTrace($"Order with Id: {orderStatusChangedToAwaitingValidationDomainEvent.OrderId} has been successfully updated with " + + $"a status order id: {OrderStatus.AwaitingValidation.Id}"); + + var orderStockList = orderStatusChangedToAwaitingValidationDomainEvent.OrderItems + .Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.GetUnits())); + + var confirmOrderStockEvent = new ConfirmOrderStockCommandMsg(orderStatusChangedToAwaitingValidationDomainEvent.OrderId, + orderStockList); + await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(confirmOrderStockEvent); + await _orderingIntegrationEventService.PublishThroughEventBusAsync(confirmOrderStockEvent); + } + } +} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderPaid/OrderStatusChangedToPaidDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderPaid/OrderStatusChangedToPaidDomainEventHandler.cs new file mode 100644 index 000000000..1eb4a8953 --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderPaid/OrderStatusChangedToPaidDomainEventHandler.cs @@ -0,0 +1,51 @@ +namespace Ordering.API.Application.DomainEventHandlers.OrderPaid +{ + using MediatR; + using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; + using Microsoft.Extensions.Logging; + using Domain.Events; + using System; + using System.Threading.Tasks; + using Ordering.API.Application.IntegrationCommands.Commands; + using Ordering.API.Application.IntegrationEvents; + using System.Linq; + + public class OrderStatusChangedToPaidDomainEventHandler + : IAsyncNotificationHandler + { + private readonly IOrderRepository _orderRepository; + private readonly ILoggerFactory _logger; + private readonly IOrderingIntegrationEventService _orderingIntegrationEventService; + + public OrderStatusChangedToPaidDomainEventHandler( + IOrderRepository orderRepository, ILoggerFactory logger, + IOrderingIntegrationEventService orderingIntegrationEventService) + { + _orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _orderingIntegrationEventService = orderingIntegrationEventService; + } + + public async Task Handle(OrderStatusChangedToPaidDomainEvent orderStatusChangedToPaidDomainEvent) + { + await _orderRepository.UnitOfWork.SaveEntitiesAsync(); + + _logger.CreateLogger(nameof(OrderStatusChangedToPaidDomainEventHandler)) + .LogTrace($"Order with Id: {orderStatusChangedToPaidDomainEvent.OrderId} has been successfully updated with " + + $"a status order id: {OrderStatus.Paid.Id}"); + + var orderStockList = orderStatusChangedToPaidDomainEvent.OrderItems + .Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.GetUnits())); + + var decrementOrderStockCommandMsg = new DecrementOrderStockCommandMsg(orderStatusChangedToPaidDomainEvent.OrderId, + orderStockList); + await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(decrementOrderStockCommandMsg); + await _orderingIntegrationEventService.PublishThroughEventBusAsync(decrementOrderStockCommandMsg); + + //is it necessary get a DecrementOrderStockSuccessIntegrationEvent/DecrementOrderStockFailedIntegrationEvent before to call ShipOrderCommandMsg??? + var shipOrderCommandMsg = new ShipOrderCommandMsg(orderStatusChangedToPaidDomainEvent.OrderId); + await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(shipOrderCommandMsg); + await _orderingIntegrationEventService.PublishThroughEventBusAsync(shipOrderCommandMsg); + } + } +} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmation/UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmed/OrderStatusChangedToStockConfirmedDomainEventHandler.cs similarity index 56% rename from src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmation/UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler.cs rename to src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmed/OrderStatusChangedToStockConfirmedDomainEventHandler.cs index 40b2fa865..2de4f5095 100644 --- a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmation/UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmed/OrderStatusChangedToStockConfirmedDomainEventHandler.cs @@ -1,4 +1,4 @@ -namespace Ordering.API.Application.DomainEventHandlers.OrderStartedEvent +namespace Ordering.API.Application.DomainEventHandlers.OrderStockConfirmed { using MediatR; using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; @@ -9,14 +9,14 @@ using Ordering.API.Application.IntegrationCommands.Commands; using Ordering.API.Application.IntegrationEvents; - public class UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler - : IAsyncNotificationHandler + public class OrderStatusChangedToStockConfirmedDomainEventHandler + : IAsyncNotificationHandler { private readonly IOrderRepository _orderRepository; private readonly ILoggerFactory _logger; private readonly IOrderingIntegrationEventService _orderingIntegrationEventService; - public UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler( + public OrderStatusChangedToStockConfirmedDomainEventHandler( IOrderRepository orderRepository, ILoggerFactory logger, IOrderingIntegrationEventService orderingIntegrationEventService) { @@ -25,21 +25,15 @@ _orderingIntegrationEventService = orderingIntegrationEventService; } - public async Task Handle(OrderStockMethodVerifiedDomainEvent orderStockMethodVerifiedDomainEvent) + public async Task Handle(OrderStatusChangedToStockConfirmedDomainEvent orderStatusChangedToStockConfirmedDomainEvent) { - var orderToUpdate = await _orderRepository.GetAsync(orderStockMethodVerifiedDomainEvent.OrderId); - orderToUpdate.SetOrderStatusId(orderStockMethodVerifiedDomainEvent.OrderStatus.Id); - - _orderRepository.Update(orderToUpdate); + await _orderRepository.UnitOfWork.SaveEntitiesAsync(); - await _orderRepository.UnitOfWork - .SaveEntitiesAsync(); + _logger.CreateLogger(nameof(OrderStatusChangedToStockConfirmedDomainEventHandler)) + .LogTrace($"Order with Id: {orderStatusChangedToStockConfirmedDomainEvent.OrderId} has been successfully updated with " + + $"a status order id: {OrderStatus.StockConfirmed.Id}"); - _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(orderToUpdate.Id); + var payOrderCommandMsg = new PayOrderCommandMsg(orderStatusChangedToStockConfirmedDomainEvent.OrderId); await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(payOrderCommandMsg); await _orderingIntegrationEventService.PublishThroughEventBusAsync(payOrderCommandMsg); } diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/ConfirmOrderStockCommandMsg.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/ConfirmOrderStockCommandMsg.cs index abf93d0ef..6e78598f1 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/ConfirmOrderStockCommandMsg.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/ConfirmOrderStockCommandMsg.cs @@ -6,13 +6,13 @@ public class ConfirmOrderStockCommandMsg : IntegrationEvent { public int OrderId { get; } - public IEnumerable OrderStockItem { get; } + public IEnumerable OrderStockItems { get; } public ConfirmOrderStockCommandMsg(int orderId, - IEnumerable orderStockItem) + IEnumerable orderStockItems) { OrderId = orderId; - OrderStockItem = orderStockItem; + OrderStockItems = orderStockItems; } } diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/DecrementOrderStockCommandMsg.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/DecrementOrderStockCommandMsg.cs new file mode 100644 index 000000000..e05a20c48 --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/DecrementOrderStockCommandMsg.cs @@ -0,0 +1,18 @@ +namespace Ordering.API.Application.IntegrationCommands.Commands +{ + using System.Collections.Generic; + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + + public class DecrementOrderStockCommandMsg : IntegrationEvent + { + public int OrderId { get; } + public IEnumerable OrderStockItems { get; } + + public DecrementOrderStockCommandMsg(int orderId, + IEnumerable orderStockItems) + { + OrderId = orderId; + OrderStockItems = orderStockItems; + } + } +} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/ShipOrderCommandMsg.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/ShipOrderCommandMsg.cs new file mode 100644 index 000000000..5a8695ae9 --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/ShipOrderCommandMsg.cs @@ -0,0 +1,14 @@ +namespace Ordering.API.Application.IntegrationCommands.Commands +{ + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + + public class ShipOrderCommandMsg : IntegrationEvent + { + public int OrderId { get; } + + public ShipOrderCommandMsg(int orderId) + { + OrderId = orderId; + } + } +} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentFailedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentFailedIntegrationEventHandler.cs index 485cf750f..074b2799b 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentFailedIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentFailedIntegrationEventHandler.cs @@ -1,14 +1,23 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling { using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; + using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; using Ordering.API.Application.IntegrationEvents.Events; using System.Threading.Tasks; public class OrderPaymentFailedIntegrationEventHandler : IIntegrationEventHandler { + private readonly IOrderRepository _orderRepository; + + public OrderPaymentFailedIntegrationEventHandler(IOrderRepository orderRepository) + { + _orderRepository = orderRepository; + } + public async Task Handle(OrderPaymentFailedIntegrationEvent @event) { + //TODO: Cancel Order } } } diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSuccededIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSuccededIntegrationEventHandler.cs index 86e3d5482..98ba54b08 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSuccededIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSuccededIntegrationEventHandler.cs @@ -1,14 +1,35 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling { using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; + using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; using Ordering.API.Application.IntegrationEvents.Events; + using Ordering.Domain.Exceptions; using System.Threading.Tasks; public class OrderPaymentSuccededIntegrationEventHandler : IIntegrationEventHandler { + private readonly IOrderRepository _orderRepository; + + public OrderPaymentSuccededIntegrationEventHandler(IOrderRepository orderRepository) + { + _orderRepository = orderRepository; + } + public async Task Handle(OrderPaymentSuccededIntegrationEvent @event) { + var order = await _orderRepository.GetAsync(@event.OrderId); + CheckValidSagaId(order); + + order.SetPaidStatus(); + } + + 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/OrderStockConfirmedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs index cfc2fdbe0..98d4fda08 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs @@ -10,32 +10,19 @@ public class OrderStockConfirmedIntegrationEventHandler : IIntegrationEventHandler { - private readonly IOrderingIntegrationEventService _orderingIntegrationEventService; private readonly IOrderRepository _orderRepository; - public OrderStockConfirmedIntegrationEventHandler(IOrderRepository orderRepository, - IOrderingIntegrationEventService orderingIntegrationEventService) + public OrderStockConfirmedIntegrationEventHandler(IOrderRepository orderRepository) { _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 var order = await _orderRepository.GetAsync(@event.OrderId); CheckValidSagaId(order); - order.SetOrderStockConfirmed(); - - //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); + order.SetStockConfirmedStatus(); } private void CheckValidSagaId(Order orderSaga) 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 dfcb1d480..d80a966f0 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs @@ -1,4 +1,5 @@ using System.Linq; +using Ordering.API.Application.IntegrationCommands.Commands; namespace Ordering.API.Application.IntegrationEvents.EventHandling { @@ -7,33 +8,27 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling 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; + using Domain.Exceptions; public class OrderStockNotConfirmedIntegrationEventHandler : IIntegrationEventHandler { - private readonly IOrderingIntegrationEventService _orderingIntegrationEventService; private readonly IOrderRepository _orderRepository; - public OrderStockNotConfirmedIntegrationEventHandler(IOrderRepository orderRepository, - IOrderingIntegrationEventService orderingIntegrationEventService) + public OrderStockNotConfirmedIntegrationEventHandler(IOrderRepository orderRepository) { _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 - var order = await _orderRepository.GetAsync(@event.OrderId); - CheckValidSagaId(order); + var orderToUpdate = await _orderRepository.GetAsync(@event.OrderId); + CheckValidSagaId(orderToUpdate); var orderStockNotConfirmedItems = @event.OrderStockItems .FindAll(c => !c.Confirmed) .Select(c => c.ProductId); - order.SetOrderStockConfirmed(orderStockNotConfirmedItems); + orderToUpdate.SetStockConfirmedStatus(orderStockNotConfirmedItems); } private void CheckValidSagaId(Order orderSaga) diff --git a/src/Services/Ordering/Ordering.API/Application/Sagas/OrderProcessSaga.cs b/src/Services/Ordering/Ordering.API/Application/Sagas/OrderProcessSaga.cs index 47dcbe6f5..3b5c8606b 100644 --- a/src/Services/Ordering/Ordering.API/Application/Sagas/OrderProcessSaga.cs +++ b/src/Services/Ordering/Ordering.API/Application/Sagas/OrderProcessSaga.cs @@ -8,8 +8,10 @@ using Ordering.API.Application.Commands; using Ordering.API.Application.IntegrationCommands.Commands; using Ordering.API.Application.IntegrationEvents; using Ordering.Domain.Exceptions; +using System; using System.Linq; using System.Threading.Tasks; +using Ordering.API.Application.IntegrationEvents; namespace Ordering.API.Application.Sagas { @@ -21,7 +23,7 @@ namespace Ordering.API.Application.Sagas /// the opportunity to cancel the order before proceeding /// with the validations. /// - public class OrderProcessSaga : Saga, + public class OrderProcessSaga : OrderSaga, IIntegrationEventHandler, IAsyncRequestHandler, IAsyncRequestHandler @@ -54,17 +56,9 @@ namespace Ordering.API.Application.Sagas if (orderSaga.OrderStatus != OrderStatus.Cancelled) { - orderSaga.SetOrderStatusId(OrderStatus.AwaitingValidation.Id); - await SaveChangesAsync(); - - var orderStockList = orderSaga.OrderItems - .Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.GetUnits())); + orderSaga.SetAwaitingValidationStatus(); - var confirmOrderStockEvent = new ConfirmOrderStockCommandMsg(orderSaga.Id, orderStockList); - - await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(confirmOrderStockEvent); - - await _orderingIntegrationEventService.PublishThroughEventBusAsync(confirmOrderStockEvent); + await SaveChangesAsync(); } } diff --git a/src/Services/Ordering/Ordering.API/Application/Sagas/OrderSaga.cs b/src/Services/Ordering/Ordering.API/Application/Sagas/OrderSaga.cs new file mode 100644 index 000000000..dd8e46ac7 --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Application/Sagas/OrderSaga.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; +using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; + +namespace Ordering.API.Application.Sagas +{ + public abstract class OrderSaga : Saga + { + private OrderingContext _orderingContext; + + public OrderSaga(OrderingContext orderingContext) : base(orderingContext) + { + _orderingContext = orderingContext; + } + + public override Order FindSagaById(int id) + { + var order = _orderingContext.Orders + .Single(c => c.Id == id); + + _orderingContext.Entry(order) + .Member("OrderStatus"); + + return order; + } + + public override async Task SaveChangesAsync() + { + return await _orderingContext.SaveEntitiesAsync(); + } + } +} diff --git a/src/Services/Ordering/Ordering.API/Application/Sagas/Saga.cs b/src/Services/Ordering/Ordering.API/Application/Sagas/Saga.cs index 14925f93f..b03fb18fa 100644 --- a/src/Services/Ordering/Ordering.API/Application/Sagas/Saga.cs +++ b/src/Services/Ordering/Ordering.API/Application/Sagas/Saga.cs @@ -14,17 +14,8 @@ namespace Ordering.API.Application.Sagas _dbContext = dbContext; } - protected TEntity FindSagaById(int id, DbContext context = null) - { - var ctx = context ?? _dbContext; - return ctx.Set().Where(x => x.Id == id).SingleOrDefault(); - } + public abstract TEntity FindSagaById(int id); - protected async Task SaveChangesAsync(DbContext context = null) - { - var ctx = context ?? _dbContext; - var result = await ctx.SaveChangesAsync(); - return result > 0; - } + public abstract Task SaveChangesAsync(); } } diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/OrderingContextSeed.cs b/src/Services/Ordering/Ordering.API/Infrastructure/OrderingContextSeed.cs index b41d019fb..68b1baf34 100644 --- a/src/Services/Ordering/Ordering.API/Infrastructure/OrderingContextSeed.cs +++ b/src/Services/Ordering/Ordering.API/Infrastructure/OrderingContextSeed.cs @@ -33,7 +33,7 @@ { context.OrderStatus.Add(OrderStatus.Submited); context.OrderStatus.Add(OrderStatus.AwaitingValidation); - context.OrderStatus.Add(OrderStatus.StockValidated); + context.OrderStatus.Add(OrderStatus.StockConfirmed); context.OrderStatus.Add(OrderStatus.Paid); context.OrderStatus.Add(OrderStatus.Shipped); context.OrderStatus.Add(OrderStatus.Cancelled); diff --git a/src/Services/Ordering/Ordering.API/Startup.cs b/src/Services/Ordering/Ordering.API/Startup.cs index 5d649f8a2..95014dd5b 100644 --- a/src/Services/Ordering/Ordering.API/Startup.cs +++ b/src/Services/Ordering/Ordering.API/Startup.cs @@ -8,6 +8,8 @@ using global::Ordering.API.Application.IntegrationEvents.Events; using global::Ordering.API.Application.Sagas; using global::Ordering.API.Infrastructure.Middlewares; + using global::Ordering.API.Application.IntegrationCommands.Commands; + using global::Ordering.API.Application.Sagas; using Infrastructure; using Infrastructure.Auth; using Infrastructure.AutofacModules; @@ -108,7 +110,7 @@ services.AddTransient(); services.AddTransient>( sp => (DbConnection c) => new IntegrationEventLogService(c)); - var serviceProvider = services.BuildServiceProvider(); + services.AddTransient(); services.AddSingleton(sp => diff --git a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs index d9468a342..e25f285f9 100644 --- a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs +++ b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs @@ -1,5 +1,6 @@ using Microsoft.eShopOnContainers.Services.Ordering.Domain.Seedwork; using Ordering.Domain.Events; +using Ordering.Domain.Exceptions; using System; using System.Collections.Generic; using System.Linq; @@ -93,33 +94,80 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O _buyerId = id; } - public void SetOrderStatusId(int id) + #region Status Changes + public void SetSubmitedStatus() { - _orderStatusId = id; + _orderStatusId = OrderStatus.Submited.Id; + } + + public void SetAwaitingValidationStatus() + { + if (_orderStatusId != OrderStatus.Submited.Id) + { + StatusChangeException(); + } + + _orderStatusId = OrderStatus.AwaitingValidation.Id; + + AddDomainEvent(new OrderStatusChangedToAwaitingValidationDomainEvent(Id, OrderItems)); } - public void SetOrderStockConfirmed(IEnumerable orderStockNotConfirmedItems = null) + public void SetStockConfirmedStatus(IEnumerable orderStockNotConfirmedItems = null) { - if(orderStockNotConfirmedItems is null) + if (_orderStatusId != OrderStatus.AwaitingValidation.Id) + { + StatusChangeException(); + } + + if (orderStockNotConfirmedItems is null) { - OrderStatus = OrderStatus.StockValidated; + OrderStatus = OrderStatus.StockConfirmed; + _description = "All the items were confirmed with available stock."; - //AddDomainEvent(new OrderStockMethodVerifiedDomainEvent(Id, OrderStatus.StockValidated)); + + AddDomainEvent(new OrderStatusChangedToStockConfirmedDomainEvent(Id)); } else { + OrderStatus = OrderStatus.Cancelled; + var itemsStockNotConfirmedProductNames = OrderItems .Where(c => orderStockNotConfirmedItems.Contains(c.ProductId)) .Select(c => c.GetOrderItemProductName()); var itemsStockNotConfirmedDescription = string.Join(", ", itemsStockNotConfirmedProductNames); + _description = $"The product items don't have stock: ({itemsStockNotConfirmedDescription})."; + } + } - OrderStatus = OrderStatus.Cancelled; - _description = $"The product items don't have stock: ({itemsStockNotConfirmedDescription})."; - //AddDomainEvent(new OrderStockMethodVerifiedDomainEvent(Id, OrderStatus.Cancelled)); + public void SetPaidStatus() + { + if (_orderStatusId != OrderStatus.StockConfirmed.Id) + { + StatusChangeException(); + } + + _orderStatusId = OrderStatus.Paid.Id; + _description = "The payment was performed at a simulated \"American Bank checking bank account endinf on XX35071\""; + + AddDomainEvent(new OrderStatusChangedToPaidDomainEvent(Id, OrderItems)); + } + + public void SetShippedStatus() + { + if (_orderStatusId != OrderStatus.Paid.Id) + { + StatusChangeException(); } + + _orderStatusId = OrderStatus.Shipped.Id; + _description = ""; + + //Call Domain Event } + #endregion + public int GetOrderStatusId() { return _orderStatusId; @@ -134,6 +182,11 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O this.AddDomainEvent(orderStartedDomainEvent); } + + private void StatusChangeException() + { + throw new OrderingDomainException("Not able to process order event. Reason: no valid order status change"); + } } } diff --git a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/OrderStatus.cs b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/OrderStatus.cs index 73178cbe5..02891fb58 100644 --- a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/OrderStatus.cs +++ b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/OrderStatus.cs @@ -12,7 +12,7 @@ { public static OrderStatus Submited = new OrderStatus(1, nameof(Submited).ToLowerInvariant()); public static OrderStatus AwaitingValidation = new OrderStatus(2, nameof(AwaitingValidation).ToLowerInvariant()); - public static OrderStatus StockValidated = new OrderStatus(3, nameof(StockValidated).ToLowerInvariant()); + public static OrderStatus StockConfirmed = new OrderStatus(3, nameof(StockConfirmed).ToLowerInvariant()); public static OrderStatus Paid = new OrderStatus(4, nameof(Paid).ToLowerInvariant()); public static OrderStatus Shipped = new OrderStatus(5, nameof(Shipped).ToLowerInvariant()); public static OrderStatus Cancelled = new OrderStatus(6, nameof(Cancelled).ToLowerInvariant()); @@ -27,7 +27,7 @@ } public static IEnumerable List() => - new[] { Submited, AwaitingValidation, StockValidated, Paid, Shipped, Cancelled }; + new[] { Submited, AwaitingValidation, StockConfirmed, Paid, Shipped, Cancelled }; public static OrderStatus FromName(string name) { diff --git a/src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToAwaitingValidationDomainEvent.cs b/src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToAwaitingValidationDomainEvent.cs new file mode 100644 index 000000000..e324ecfa0 --- /dev/null +++ b/src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToAwaitingValidationDomainEvent.cs @@ -0,0 +1,23 @@ +namespace Ordering.Domain.Events +{ + using MediatR; + using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; + using System.Collections.Generic; + + /// + /// Event used when the grace period order is confirmed + /// + public class OrderStatusChangedToAwaitingValidationDomainEvent + : IAsyncNotification + { + public int OrderId { get; } + public IEnumerable OrderItems { get; } + + public OrderStatusChangedToAwaitingValidationDomainEvent(int orderId, + IEnumerable orderItems) + { + OrderId = orderId; + OrderItems = orderItems; + } + } +} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToPaidDomainEvent.cs b/src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToPaidDomainEvent.cs new file mode 100644 index 000000000..743770507 --- /dev/null +++ b/src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToPaidDomainEvent.cs @@ -0,0 +1,23 @@ +namespace Ordering.Domain.Events +{ + using MediatR; + using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; + using System.Collections.Generic; + + /// + /// Event used when the order is paid + /// + public class OrderStatusChangedToPaidDomainEvent + : IAsyncNotification + { + public int OrderId { get; } + public IEnumerable OrderItems { get; } + + public OrderStatusChangedToPaidDomainEvent(int orderId, + IEnumerable orderItems) + { + OrderId = orderId; + OrderItems = orderItems; + } + } +} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToStockConfirmedDomainEvent.cs b/src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToStockConfirmedDomainEvent.cs new file mode 100644 index 000000000..2e9b2bab5 --- /dev/null +++ b/src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToStockConfirmedDomainEvent.cs @@ -0,0 +1,16 @@ +namespace Ordering.Domain.Events +{ + using MediatR; + + /// + /// Event used when the order stock items are confirmed + /// + public class OrderStatusChangedToStockConfirmedDomainEvent + : IAsyncNotification + { + public int OrderId { get; } + + public OrderStatusChangedToStockConfirmedDomainEvent(int orderId) + => OrderId = orderId; + } +} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.Domain/Events/OrderStockMethodVerifiedDomainEvent.cs b/src/Services/Ordering/Ordering.Domain/Events/OrderStockMethodVerifiedDomainEvent.cs deleted file mode 100644 index c5acd26dd..000000000 --- a/src/Services/Ordering/Ordering.Domain/Events/OrderStockMethodVerifiedDomainEvent.cs +++ /dev/null @@ -1,22 +0,0 @@ -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 diff --git a/src/Services/Payment/Payment.API/IntegrationCommands/CommandHandlers/PayOrderCommandMsgHandler.cs b/src/Services/Payment/Payment.API/IntegrationCommands/CommandHandlers/PayOrderCommandMsgHandler.cs new file mode 100644 index 000000000..0a41c133c --- /dev/null +++ b/src/Services/Payment/Payment.API/IntegrationCommands/CommandHandlers/PayOrderCommandMsgHandler.cs @@ -0,0 +1,19 @@ +namespace Payment.API.IntegrationCommands.CommandHandlers +{ + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; + using Payment.API.IntegrationCommands.Commands; + using System.Threading.Tasks; + using System; + + public class PayOrderCommandMsgHandler : IIntegrationEventHandler + { + public PayOrderCommandMsgHandler() + { + } + + public async Task Handle(PayOrderCommandMsg @event) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Services/Payment/Payment.API/IntegrationCommands/Commands/PayOrderCommandMsg.cs b/src/Services/Payment/Payment.API/IntegrationCommands/Commands/PayOrderCommandMsg.cs new file mode 100644 index 000000000..360f40606 --- /dev/null +++ b/src/Services/Payment/Payment.API/IntegrationCommands/Commands/PayOrderCommandMsg.cs @@ -0,0 +1,11 @@ +namespace Payment.API.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/Payment/Payment.API/IntegrationEvents/Events/OrderPaymentFailedIntegrationEvent.cs b/src/Services/Payment/Payment.API/IntegrationEvents/Events/OrderPaymentFailedIntegrationEvent.cs new file mode 100644 index 000000000..d51c518c4 --- /dev/null +++ b/src/Services/Payment/Payment.API/IntegrationEvents/Events/OrderPaymentFailedIntegrationEvent.cs @@ -0,0 +1,11 @@ +namespace Payment.API.IntegrationEvents.Events +{ + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + + public class OrderPaymentFailedIntegrationEvent : IntegrationEvent + { + public int OrderId { get; } + + public OrderPaymentFailedIntegrationEvent(int orderId) => OrderId = orderId; + } +} \ No newline at end of file diff --git a/src/Services/Payment/Payment.API/IntegrationEvents/Events/OrderPaymentSuccededIntegrationEvent.cs b/src/Services/Payment/Payment.API/IntegrationEvents/Events/OrderPaymentSuccededIntegrationEvent.cs new file mode 100644 index 000000000..d672ff9d4 --- /dev/null +++ b/src/Services/Payment/Payment.API/IntegrationEvents/Events/OrderPaymentSuccededIntegrationEvent.cs @@ -0,0 +1,11 @@ +namespace Payment.API.IntegrationEvents.Events +{ + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + + public class OrderPaymentSuccededIntegrationEvent : IntegrationEvent + { + public int OrderId { get; } + + public OrderPaymentSuccededIntegrationEvent(int orderId) => OrderId = orderId; + } +} \ No newline at end of file diff --git a/src/Services/Payment/Payment.API/Payment.API.csproj b/src/Services/Payment/Payment.API/Payment.API.csproj index 147cd2e3c..7f741fa53 100644 --- a/src/Services/Payment/Payment.API/Payment.API.csproj +++ b/src/Services/Payment/Payment.API/Payment.API.csproj @@ -25,5 +25,10 @@ + + + + + diff --git a/src/Services/Payment/Payment.API/Startup.cs b/src/Services/Payment/Payment.API/Startup.cs index c5160a81d..ac970d82d 100644 --- a/src/Services/Payment/Payment.API/Startup.cs +++ b/src/Services/Payment/Payment.API/Startup.cs @@ -6,6 +6,11 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; +using Payment.API.IntegrationCommands.Commands; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ; +using RabbitMQ.Client; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; namespace Payment.API { @@ -29,6 +34,21 @@ namespace Payment.API // Add framework services. services.AddMvc(); + services.AddSingleton(sp => + { + var logger = sp.GetRequiredService>(); + + var factory = new ConnectionFactory() + { + HostName = Configuration["EventBusConnection"] + }; + + return new DefaultRabbitMQPersistentConnection(factory, logger); + }); + + services.AddSingleton(); + services.AddSingleton(); + services.AddSwaggerGen(); services.ConfigureSwaggerGen(options => { @@ -47,6 +67,8 @@ namespace Payment.API return new AutofacServiceProvider(container.Build()); } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { @@ -57,6 +79,14 @@ namespace Payment.API app.UseSwagger() .UseSwaggerUi(); + + ConfigureEventBus(app); + } + + private void ConfigureEventBus(IApplicationBuilder app) + { + var eventBus = app.ApplicationServices.GetRequiredService(); + eventBus.Subscribe>(); } } } diff --git a/src/Services/SagaManager/SagaManager/Program.cs b/src/Services/SagaManager/SagaManager/Program.cs index 0e5e1dc5a..95105b23b 100644 --- a/src/Services/SagaManager/SagaManager/Program.cs +++ b/src/Services/SagaManager/SagaManager/Program.cs @@ -18,6 +18,7 @@ namespace SagaManager using Services; using Autofac.Extensions.DependencyInjection; using Autofac; + using System.Threading.Tasks; public class Program { @@ -25,7 +26,12 @@ namespace SagaManager public static void Main(string[] args) { - StartUp(); + MainAsync().Wait(); + } + + static async Task MainAsync() + { + StartUp(); IServiceCollection services = new ServiceCollection(); var serviceProvider = ConfigureServices(services); @@ -39,7 +45,7 @@ namespace SagaManager while (true) { sagaManagerService.CheckFinishedGracePeriodOrders(); - System.Threading.Thread.Sleep(30000); + await Task.Delay(30000); } } diff --git a/test/Services/UnitTest/Ordering/Domain/OrderAggregateTest.cs b/test/Services/UnitTest/Ordering/Domain/OrderAggregateTest.cs index 90bf412ef..dfa31eb62 100644 --- a/test/Services/UnitTest/Ordering/Domain/OrderAggregateTest.cs +++ b/test/Services/UnitTest/Ordering/Domain/OrderAggregateTest.cs @@ -96,7 +96,8 @@ public class OrderAggregateTest [Fact] public void Add_new_Order_raises_new_event() { - //Arrange + //Arrange + var userId = new Guid(); var street = "fakeStreet"; var city = "FakeCity"; var state = "fakeState"; @@ -119,7 +120,8 @@ public class OrderAggregateTest [Fact] public void Add_event_Order_explicitly_raises_new_event() { - //Arrange + //Arrange + var userId = new Guid(); var street = "fakeStreet"; var city = "FakeCity"; var state = "fakeState"; @@ -143,6 +145,7 @@ public class OrderAggregateTest public void Remove_event_Order_explicitly() { //Arrange + var userId = new Guid(); var street = "fakeStreet"; var city = "FakeCity"; var state = "fakeState";