Merge branch 'order-processflow-redesign' of https://github.com/dotnet-architecture/eShopOnContainers into order-processflow-redesign
This commit is contained in:
		
						commit
						87201a3f35
					
				| @ -11,7 +11,6 @@ services: | ||||
|     environment: | ||||
|       - ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word | ||||
|       - EventBusConnection=rabbitmq | ||||
|       - GracePeriod=15 #In minutes | ||||
|        | ||||
|   basket.api: | ||||
|     environment: | ||||
|  | ||||
| @ -53,16 +53,16 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers | ||||
| 
 | ||||
|         [Route("checkout")] | ||||
|         [HttpPost] | ||||
|         public async Task<IActionResult> Checkout([FromBody]BasketCheckout value, [FromHeader(Name = "x-requestid")] string requestId) | ||||
|         public async Task<IActionResult> Checkout([FromBody]BasketCheckout basketCheckout, [FromHeader(Name = "x-requestid")] string requestId) | ||||
|         { | ||||
|             var userId = _identitySvc.GetUserIdentity(); | ||||
|             value.RequestId = (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty) ? | ||||
|                 guid : value.RequestId; | ||||
|             basketCheckout.RequestId = (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty) ? | ||||
|                 guid : basketCheckout.RequestId; | ||||
| 
 | ||||
|             var basket = await _repository.GetBasketAsync(userId); | ||||
|             var eventMessage = new UserCheckoutAcceptedIntegrationEvent(userId, value.City, value.Street, | ||||
|                 value.State, value.Country, value.ZipCode, value.CardNumber, value.CardHolderName, | ||||
|                 value.CardExpiration, value.CardSecurityNumber, value.CardTypeId, value.Buyer, value.RequestId, basket); | ||||
|             var eventMessage = new UserCheckoutAcceptedIntegrationEvent(userId, basketCheckout.City, basketCheckout.Street, | ||||
|                 basketCheckout.State, basketCheckout.Country, basketCheckout.ZipCode, basketCheckout.CardNumber, basketCheckout.CardHolderName, | ||||
|                 basketCheckout.CardExpiration, basketCheckout.CardSecurityNumber, basketCheckout.CardTypeId, basketCheckout.Buyer, basketCheckout.RequestId, basket); | ||||
| 
 | ||||
|             // Once basket is checkout, sends an integration event to | ||||
|             // ordering.api to convert basket to order and proceeds with | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationCommands.CommandHandlers | ||||
| namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.EventHandling | ||||
| { | ||||
|     using BuildingBlocks.EventBus.Abstractions; | ||||
|     using System.Threading.Tasks; | ||||
| @ -6,53 +6,41 @@ | ||||
|     using Infrastructure; | ||||
|     using System.Collections.Generic; | ||||
|     using System.Linq; | ||||
|     using global::Catalog.API.Infrastructure.Exceptions; | ||||
|     using global::Catalog.API.IntegrationEvents; | ||||
|     using Model; | ||||
|     using Commands; | ||||
|     using IntegrationEvents.Events; | ||||
| 
 | ||||
|     public class ConfirmOrderStockCommandHandler : IIntegrationEventHandler<ConfirmOrderStockCommand> | ||||
|     public class OrderStatusChangedToAwaitingValidationIntegrationEventHandler :  | ||||
|         IIntegrationEventHandler<OrderStatusChangedToAwaitingValidationIntegrationEvent> | ||||
|     { | ||||
|         private readonly CatalogContext _catalogContext; | ||||
|         private readonly ICatalogIntegrationEventService _catalogIntegrationEventService; | ||||
| 
 | ||||
|         public ConfirmOrderStockCommandHandler(CatalogContext catalogContext, | ||||
|         public OrderStatusChangedToAwaitingValidationIntegrationEventHandler(CatalogContext catalogContext, | ||||
|             ICatalogIntegrationEventService catalogIntegrationEventService) | ||||
|         { | ||||
|             _catalogContext = catalogContext; | ||||
|             _catalogIntegrationEventService = catalogIntegrationEventService; | ||||
|         } | ||||
| 
 | ||||
|         public async Task Handle(ConfirmOrderStockCommand command) | ||||
|         public async Task Handle(OrderStatusChangedToAwaitingValidationIntegrationEvent command) | ||||
|         { | ||||
|             var confirmedOrderStockItems = new List<ConfirmedOrderStockItem>(); | ||||
| 
 | ||||
|             foreach (var orderStockItem in command.OrderStockItems) | ||||
|             { | ||||
|                 var catalogItem = _catalogContext.CatalogItems.Find(orderStockItem.ProductId); | ||||
|                 CheckValidcatalogItemId(catalogItem); | ||||
| 
 | ||||
|                 var confirmedOrderStockItem = new ConfirmedOrderStockItem(catalogItem.Id,  | ||||
|                     catalogItem.AvailableStock >= orderStockItem.Units); | ||||
|                 var hasStock = catalogItem.AvailableStock >= orderStockItem.Units; | ||||
|                 var confirmedOrderStockItem = new ConfirmedOrderStockItem(catalogItem.Id, hasStock); | ||||
| 
 | ||||
|                 confirmedOrderStockItems.Add(confirmedOrderStockItem); | ||||
|             } | ||||
| 
 | ||||
|             var confirmedIntegrationEvent = confirmedOrderStockItems.Any(c => !c.HasStock) | ||||
|                 ? (IntegrationEvent) new OrderStockNotConfirmedIntegrationEvent(command.OrderId, confirmedOrderStockItems) | ||||
|                 ? (IntegrationEvent) new OrderStockRejectedIntegrationEvent(command.OrderId, confirmedOrderStockItems) | ||||
|                 : new OrderStockConfirmedIntegrationEvent(command.OrderId); | ||||
| 
 | ||||
|             await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(confirmedIntegrationEvent); | ||||
|             await _catalogIntegrationEventService.PublishThroughEventBusAsync(confirmedIntegrationEvent); | ||||
|         } | ||||
| 
 | ||||
|         private void CheckValidcatalogItemId(CatalogItem catalogItem) | ||||
|         { | ||||
|             if (catalogItem is null) | ||||
|             { | ||||
|                 throw new CatalogDomainException("Not able to process catalog event. Reason: no valid catalogItemId"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -1,20 +1,21 @@ | ||||
| namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationCommands.CommandHandlers | ||||
| namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.EventHandling | ||||
| { | ||||
|     using BuildingBlocks.EventBus.Abstractions; | ||||
|     using System.Threading.Tasks; | ||||
|     using Infrastructure; | ||||
|     using Commands; | ||||
|     using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events; | ||||
| 
 | ||||
|     public class DecrementOrderStockCommandHandler : IIntegrationEventHandler<DecrementOrderStockCommand> | ||||
|     public class OrderStatusChangedToPaidIntegrationEventHandler :  | ||||
|         IIntegrationEventHandler<OrderStatusChangedToPaidIntegrationEvent> | ||||
|     { | ||||
|         private readonly CatalogContext _catalogContext; | ||||
| 
 | ||||
|         public DecrementOrderStockCommandHandler(CatalogContext catalogContext) | ||||
|         public OrderStatusChangedToPaidIntegrationEventHandler(CatalogContext catalogContext) | ||||
|         { | ||||
|             _catalogContext = catalogContext; | ||||
|         } | ||||
| 
 | ||||
|         public async Task Handle(DecrementOrderStockCommand command) | ||||
|         public async Task Handle(OrderStatusChangedToPaidIntegrationEvent command) | ||||
|         { | ||||
|             //we're not blocking stock/inventory | ||||
|             foreach (var orderStockItem in command.OrderStockItems) | ||||
| @ -1,14 +1,14 @@ | ||||
| namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationCommands.Commands | ||||
| namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events | ||||
| { | ||||
|     using BuildingBlocks.EventBus.Events; | ||||
|     using System.Collections.Generic; | ||||
| 
 | ||||
|     public class ConfirmOrderStockCommand : IntegrationEvent | ||||
|     public class OrderStatusChangedToAwaitingValidationIntegrationEvent : IntegrationEvent | ||||
|     { | ||||
|         public int OrderId { get; } | ||||
|         public IEnumerable<OrderStockItem> OrderStockItems { get; } | ||||
| 
 | ||||
|         public ConfirmOrderStockCommand(int orderId, | ||||
|         public OrderStatusChangedToAwaitingValidationIntegrationEvent(int orderId, | ||||
|             IEnumerable<OrderStockItem> orderStockItems) | ||||
|         { | ||||
|             OrderId = orderId; | ||||
| @ -1,14 +1,14 @@ | ||||
| namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationCommands.Commands | ||||
| namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events | ||||
| { | ||||
|     using System.Collections.Generic; | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||
| 
 | ||||
|     public class DecrementOrderStockCommand : IntegrationEvent | ||||
|     public class OrderStatusChangedToPaidIntegrationEvent : IntegrationEvent | ||||
|     { | ||||
|         public int OrderId { get; } | ||||
|         public IEnumerable<OrderStockItem> OrderStockItems { get; } | ||||
| 
 | ||||
|         public DecrementOrderStockCommand(int orderId, | ||||
|         public OrderStatusChangedToPaidIntegrationEvent(int orderId, | ||||
|             IEnumerable<OrderStockItem> orderStockItems) | ||||
|         { | ||||
|             OrderId = orderId; | ||||
| @ -3,13 +3,13 @@ | ||||
|     using BuildingBlocks.EventBus.Events; | ||||
|     using System.Collections.Generic; | ||||
| 
 | ||||
|     public class OrderStockNotConfirmedIntegrationEvent : IntegrationEvent | ||||
|     public class OrderStockRejectedIntegrationEvent : IntegrationEvent | ||||
|     { | ||||
|         public int OrderId { get; } | ||||
| 
 | ||||
|         public List<ConfirmedOrderStockItem> OrderStockItems { get; } | ||||
| 
 | ||||
|         public OrderStockNotConfirmedIntegrationEvent(int orderId, | ||||
|         public OrderStockRejectedIntegrationEvent(int orderId, | ||||
|             List<ConfirmedOrderStockItem> orderStockItems) | ||||
|         { | ||||
|             OrderId = orderId; | ||||
| @ -14,9 +14,8 @@ | ||||
|     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.eShopOnContainers.Services.Catalog.API.IntegrationEvents.EventHandling; | ||||
|     using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events; | ||||
|     using Microsoft.Extensions.Configuration; | ||||
|     using Microsoft.Extensions.DependencyInjection; | ||||
|     using Microsoft.Extensions.HealthChecks; | ||||
| @ -190,19 +189,20 @@ | ||||
|             services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>(); | ||||
|             services.AddSingleton<IEventBus, EventBusRabbitMQ>(); | ||||
| 
 | ||||
|             services.AddTransient<IIntegrationEventHandler<ConfirmOrderStockCommand>, | ||||
|                 ConfirmOrderStockCommandHandler>(); | ||||
|             services.AddTransient<IIntegrationEventHandler<DecrementOrderStockCommand>, | ||||
|                 DecrementOrderStockCommandHandler>(); | ||||
| 
 | ||||
|             services.AddTransient<IIntegrationEventHandler<OrderStatusChangedToAwaitingValidationIntegrationEvent>, | ||||
|                 OrderStatusChangedToAwaitingValidationIntegrationEventHandler>(); | ||||
|             services.AddTransient<IIntegrationEventHandler<OrderStatusChangedToPaidIntegrationEvent>, | ||||
|                 OrderStatusChangedToPaidIntegrationEventHandler>(); | ||||
|         } | ||||
| 
 | ||||
|         private void ConfigureEventBus(IApplicationBuilder app) | ||||
|         { | ||||
|             var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>(); | ||||
| 
 | ||||
|             eventBus.Subscribe<ConfirmOrderStockCommand, IIntegrationEventHandler<ConfirmOrderStockCommand>>(); | ||||
|             eventBus.Subscribe<DecrementOrderStockCommand, IIntegrationEventHandler<DecrementOrderStockCommand>>(); | ||||
|             eventBus.Subscribe<OrderStatusChangedToAwaitingValidationIntegrationEvent,  | ||||
|                 IIntegrationEventHandler<OrderStatusChangedToAwaitingValidationIntegrationEvent>>(); | ||||
|             eventBus.Subscribe<OrderStatusChangedToPaidIntegrationEvent,  | ||||
|                 IIntegrationEventHandler<OrderStatusChangedToPaidIntegrationEvent>>(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -36,11 +36,7 @@ namespace Ordering.API.Application.DomainEventHandlers.BuyerAndPaymentMethodVeri | ||||
|                                      | ||||
|             var orderStartedIntegrationEvent = new OrderStartedIntegrationEvent(buyerPaymentMethodVerifiedEvent.Buyer.IdentityGuid); | ||||
| 
 | ||||
|             await _orderingIntegrationEventService | ||||
|                 .SaveEventAndOrderingContextChangesAsync(orderStartedIntegrationEvent); | ||||
| 
 | ||||
|             await _orderingIntegrationEventService | ||||
|                 .PublishThroughEventBusAsync(orderStartedIntegrationEvent); | ||||
|             await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStartedIntegrationEvent); | ||||
| 
 | ||||
|             _logger.CreateLogger(nameof(UpdateOrderWhenBuyerAndPaymentMethodVerifiedDomainEventHandler)) | ||||
|                 .LogTrace($"Order with Id: {buyerPaymentMethodVerifiedEvent.OrderId} has been successfully updated with a payment method id: { buyerPaymentMethodVerifiedEvent.Payment.Id }");                         | ||||
|  | ||||
| @ -6,9 +6,9 @@ | ||||
|     using Domain.Events; | ||||
|     using System; | ||||
|     using System.Threading.Tasks; | ||||
|     using Ordering.API.Application.IntegrationCommands.Commands; | ||||
|     using Ordering.API.Application.IntegrationEvents; | ||||
|     using System.Linq; | ||||
|     using Ordering.API.Application.IntegrationEvents.Events; | ||||
| 
 | ||||
|     public class OrderStatusChangedToAwaitingValidationDomainEventHandler | ||||
|                    : IAsyncNotificationHandler<OrderStatusChangedToAwaitingValidationDomainEvent> | ||||
| @ -35,10 +35,9 @@ | ||||
|             var orderStockList = orderStatusChangedToAwaitingValidationDomainEvent.OrderItems | ||||
|                 .Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.GetUnits())); | ||||
| 
 | ||||
|             var confirmOrderStockCommand = new ConfirmOrderStockCommand(orderStatusChangedToAwaitingValidationDomainEvent.OrderId,  | ||||
|                 orderStockList); | ||||
|             await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(confirmOrderStockCommand); | ||||
|             await _orderingIntegrationEventService.PublishThroughEventBusAsync(confirmOrderStockCommand); | ||||
|             var orderStatusChangedToAwaitingValidationIntegrationEvent = new OrderStatusChangedToAwaitingValidationIntegrationEvent( | ||||
|                 orderStatusChangedToAwaitingValidationDomainEvent.OrderId, orderStockList); | ||||
|             await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedToAwaitingValidationIntegrationEvent); | ||||
|         } | ||||
|     }   | ||||
| } | ||||
| @ -6,9 +6,9 @@ | ||||
|     using Domain.Events; | ||||
|     using System; | ||||
|     using System.Threading.Tasks; | ||||
|     using Ordering.API.Application.IntegrationCommands.Commands; | ||||
|     using Ordering.API.Application.IntegrationEvents; | ||||
|     using System.Linq; | ||||
|     using Ordering.API.Application.IntegrationEvents.Events; | ||||
| 
 | ||||
|     public class OrderStatusChangedToPaidDomainEventHandler | ||||
|                    : IAsyncNotificationHandler<OrderStatusChangedToPaidDomainEvent> | ||||
| @ -35,10 +35,9 @@ | ||||
|             var orderStockList = orderStatusChangedToPaidDomainEvent.OrderItems | ||||
|                 .Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.GetUnits())); | ||||
| 
 | ||||
|             var decrementOrderStockCommand = new DecrementOrderStockCommand(orderStatusChangedToPaidDomainEvent.OrderId, | ||||
|             var orderStatusChangedToPaidIntegrationEvent = new OrderStatusChangedToPaidIntegrationEvent(orderStatusChangedToPaidDomainEvent.OrderId, | ||||
|                 orderStockList); | ||||
|             await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(decrementOrderStockCommand); | ||||
|             await _orderingIntegrationEventService.PublishThroughEventBusAsync(decrementOrderStockCommand); | ||||
|             await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedToPaidIntegrationEvent); | ||||
|         } | ||||
|     }   | ||||
| } | ||||
| @ -6,8 +6,8 @@ | ||||
|     using Domain.Events; | ||||
|     using System; | ||||
|     using System.Threading.Tasks; | ||||
|     using Ordering.API.Application.IntegrationCommands.Commands; | ||||
|     using Ordering.API.Application.IntegrationEvents; | ||||
|     using Ordering.API.Application.IntegrationEvents.Events; | ||||
| 
 | ||||
|     public class OrderStatusChangedToStockConfirmedDomainEventHandler | ||||
|                    : IAsyncNotificationHandler<OrderStatusChangedToStockConfirmedDomainEvent> | ||||
| @ -31,9 +31,8 @@ | ||||
|                 .LogTrace($"Order with Id: {orderStatusChangedToStockConfirmedDomainEvent.OrderId} has been successfully updated with " + | ||||
|                           $"a status order id: {OrderStatus.StockConfirmed.Id}"); | ||||
| 
 | ||||
|             var payOrderCommand = new PayOrderCommand(orderStatusChangedToStockConfirmedDomainEvent.OrderId); | ||||
|             await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(payOrderCommand); | ||||
|             await _orderingIntegrationEventService.PublishThroughEventBusAsync(payOrderCommand); | ||||
|             var orderStatusChangedToStockConfirmedIntegrationEvent = new OrderStatusChangedToStockConfirmedIntegrationEvent(orderStatusChangedToStockConfirmedDomainEvent.OrderId); | ||||
|             await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedToStockConfirmedIntegrationEvent); | ||||
|         } | ||||
|     }   | ||||
| } | ||||
| @ -1,12 +0,0 @@ | ||||
| using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||
| 
 | ||||
| namespace Ordering.API.Application.IntegrationCommands.Commands | ||||
| { | ||||
|     public class ConfirmGracePeriodCommand : IntegrationEvent | ||||
|     { | ||||
|         public int OrderId { get; } | ||||
| 
 | ||||
|         public ConfirmGracePeriodCommand(int orderId) => | ||||
|             OrderId = orderId; | ||||
|     } | ||||
| } | ||||
| @ -1,14 +0,0 @@ | ||||
| namespace Ordering.API.Application.IntegrationCommands.Commands | ||||
| { | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||
| 
 | ||||
|     public class PayOrderCommand : IntegrationEvent | ||||
|     { | ||||
|         public int OrderId { get; } | ||||
| 
 | ||||
|         public PayOrderCommand(int orderId) | ||||
|         { | ||||
|             OrderId = orderId; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -17,7 +17,7 @@ | ||||
| 
 | ||||
|         public async Task Handle(OrderPaymentFailedIntegrationEvent @event) | ||||
|         { | ||||
|             var orderToUpdate = await _orderRepository.GetWithDependenciesAsync(@event.OrderId); | ||||
|             var orderToUpdate = await _orderRepository.GetAsync(@event.OrderId); | ||||
| 
 | ||||
|             orderToUpdate.SetCancelledStatus(); | ||||
| 
 | ||||
|  | ||||
| @ -17,7 +17,7 @@ | ||||
| 
 | ||||
|         public async Task Handle(OrderPaymentSuccededIntegrationEvent @event) | ||||
|         { | ||||
|             var orderToUpdate = await _orderRepository.GetWithDependenciesAsync(@event.OrderId); | ||||
|             var orderToUpdate = await _orderRepository.GetAsync(@event.OrderId); | ||||
| 
 | ||||
|             orderToUpdate.SetPaidStatus(); | ||||
| 
 | ||||
|  | ||||
| @ -17,7 +17,7 @@ | ||||
| 
 | ||||
|         public async Task Handle(OrderStockConfirmedIntegrationEvent @event) | ||||
|         { | ||||
|             var orderToUpdate = await _orderRepository.GetWithDependenciesAsync(@event.OrderId); | ||||
|             var orderToUpdate = await _orderRepository.GetAsync(@event.OrderId); | ||||
| 
 | ||||
|             orderToUpdate.SetStockConfirmedStatus(); | ||||
| 
 | ||||
|  | ||||
| @ -1,33 +0,0 @@ | ||||
| using System.Linq; | ||||
| using Ordering.API.Application.IntegrationCommands.Commands; | ||||
| 
 | ||||
| namespace Ordering.API.Application.IntegrationEvents.EventHandling | ||||
| { | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | ||||
|     using System.Threading.Tasks; | ||||
|     using Events; | ||||
|     using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; | ||||
| 
 | ||||
|     public class OrderStockNotConfirmedIntegrationEventHandler : IIntegrationEventHandler<OrderStockNotConfirmedIntegrationEvent> | ||||
|     { | ||||
|         private readonly IOrderRepository _orderRepository; | ||||
| 
 | ||||
|         public OrderStockNotConfirmedIntegrationEventHandler(IOrderRepository orderRepository) | ||||
|         { | ||||
|             _orderRepository = orderRepository; | ||||
|         } | ||||
| 
 | ||||
|         public async Task Handle(OrderStockNotConfirmedIntegrationEvent @event) | ||||
|         { | ||||
|             var orderToUpdate = await _orderRepository.GetWithDependenciesAsync(@event.OrderId); | ||||
| 
 | ||||
|             var orderStockNotConfirmedItems = @event.OrderStockItems | ||||
|                 .FindAll(c => !c.HasStock) | ||||
|                 .Select(c => c.ProductId); | ||||
| 
 | ||||
|             orderToUpdate.SetStockConfirmedStatus(orderStockNotConfirmedItems); | ||||
| 
 | ||||
|             await _orderRepository.UnitOfWork.SaveEntitiesAsync(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,31 @@ | ||||
| namespace Ordering.API.Application.IntegrationEvents.EventHandling | ||||
| { | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | ||||
|     using System.Threading.Tasks; | ||||
|     using Events; | ||||
|     using System.Linq; | ||||
|     using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; | ||||
| 
 | ||||
|     public class OrderStockRejectedIntegrationEventHandler : IIntegrationEventHandler<OrderStockRejectedIntegrationEvent> | ||||
|     { | ||||
|         private readonly IOrderRepository _orderRepository; | ||||
| 
 | ||||
|         public OrderStockRejectedIntegrationEventHandler(IOrderRepository orderRepository) | ||||
|         { | ||||
|             _orderRepository = orderRepository; | ||||
|         } | ||||
| 
 | ||||
|         public async Task Handle(OrderStockRejectedIntegrationEvent @event) | ||||
|         { | ||||
|             var orderToUpdate = await _orderRepository.GetAsync(@event.OrderId); | ||||
| 
 | ||||
|             var orderStockRejectedItems = @event.OrderStockItems | ||||
|                 .FindAll(c => !c.HasStock) | ||||
|                 .Select(c => c.ProductId); | ||||
| 
 | ||||
|             orderToUpdate.SetCancelledStatusWhenStockIsRejected(orderStockRejectedItems); | ||||
| 
 | ||||
|             await _orderRepository.UnitOfWork.SaveEntitiesAsync(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,12 @@ | ||||
| namespace Ordering.API.Application.IntegrationEvents.Events | ||||
| { | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||
| 
 | ||||
|     public class GracePeriodConfirmedIntegrationEvent : IntegrationEvent | ||||
|     { | ||||
|         public int OrderId { get; } | ||||
| 
 | ||||
|         public GracePeriodConfirmedIntegrationEvent(int orderId) => | ||||
|             OrderId = orderId; | ||||
|     } | ||||
| } | ||||
| @ -1,7 +1,7 @@ | ||||
| using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||
| 
 | ||||
| namespace Ordering.API.Application.IntegrationEvents.Events | ||||
| namespace Ordering.API.Application.IntegrationEvents.Events | ||||
| { | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||
| 
 | ||||
|     public class OrderPaymentFailedIntegrationEvent : IntegrationEvent | ||||
|     { | ||||
|         public int OrderId { get; } | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||
| 
 | ||||
| namespace Ordering.API.Application.IntegrationEvents.Events | ||||
| namespace Ordering.API.Application.IntegrationEvents.Events | ||||
| { | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||
| 
 | ||||
|     public class OrderPaymentSuccededIntegrationEvent : IntegrationEvent | ||||
|     { | ||||
|         public int OrderId { get; } | ||||
|  | ||||
| @ -1,14 +1,14 @@ | ||||
| namespace Ordering.API.Application.IntegrationCommands.Commands | ||||
| namespace Ordering.API.Application.IntegrationEvents.Events | ||||
| { | ||||
|     using System.Collections.Generic; | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||
| 
 | ||||
|     public class ConfirmOrderStockCommand : IntegrationEvent | ||||
|     public class OrderStatusChangedToAwaitingValidationIntegrationEvent : IntegrationEvent | ||||
|     { | ||||
|         public int OrderId { get; } | ||||
|         public IEnumerable<OrderStockItem> OrderStockItems { get; } | ||||
| 
 | ||||
|         public ConfirmOrderStockCommand(int orderId, | ||||
|         public OrderStatusChangedToAwaitingValidationIntegrationEvent(int orderId, | ||||
|             IEnumerable<OrderStockItem> orderStockItems) | ||||
|         { | ||||
|             OrderId = orderId; | ||||
| @ -1,14 +1,14 @@ | ||||
| namespace Ordering.API.Application.IntegrationCommands.Commands | ||||
| namespace Ordering.API.Application.IntegrationEvents.Events | ||||
| { | ||||
|     using System.Collections.Generic; | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||
| 
 | ||||
|     public class DecrementOrderStockCommand : IntegrationEvent | ||||
|     public class OrderStatusChangedToPaidIntegrationEvent : IntegrationEvent | ||||
|     { | ||||
|         public int OrderId { get; } | ||||
|         public IEnumerable<OrderStockItem> OrderStockItems { get; } | ||||
| 
 | ||||
|         public DecrementOrderStockCommand(int orderId, | ||||
|         public OrderStatusChangedToPaidIntegrationEvent(int orderId, | ||||
|             IEnumerable<OrderStockItem> orderStockItems) | ||||
|         { | ||||
|             OrderId = orderId; | ||||
| @ -0,0 +1,12 @@ | ||||
| namespace Ordering.API.Application.IntegrationEvents.Events | ||||
| { | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||
| 
 | ||||
|     public class OrderStatusChangedToStockConfirmedIntegrationEvent : IntegrationEvent | ||||
|     { | ||||
|         public int OrderId { get; } | ||||
| 
 | ||||
|         public OrderStatusChangedToStockConfirmedIntegrationEvent(int orderId) | ||||
|             => OrderId = orderId; | ||||
|     } | ||||
| } | ||||
| @ -1,16 +1,15 @@ | ||||
| using System.Collections.Generic; | ||||
| 
 | ||||
| namespace Ordering.API.Application.IntegrationEvents.Events | ||||
| namespace Ordering.API.Application.IntegrationEvents.Events | ||||
| { | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||
|     using System.Collections.Generic; | ||||
| 
 | ||||
|     public class OrderStockNotConfirmedIntegrationEvent : IntegrationEvent | ||||
|     public class OrderStockRejectedIntegrationEvent : IntegrationEvent | ||||
|     { | ||||
|         public int OrderId { get; } | ||||
| 
 | ||||
|         public List<ConfirmedOrderStockItem> OrderStockItems { get; } | ||||
| 
 | ||||
|         public OrderStockNotConfirmedIntegrationEvent(int orderId, | ||||
|         public OrderStockRejectedIntegrationEvent(int orderId, | ||||
|             List<ConfirmedOrderStockItem> orderStockItems) | ||||
|         { | ||||
|             OrderId = orderId; | ||||
| @ -5,7 +5,6 @@ namespace Ordering.API.Application.IntegrationEvents | ||||
| { | ||||
|     public interface IOrderingIntegrationEventService | ||||
|     { | ||||
|         Task SaveEventAndOrderingContextChangesAsync(IntegrationEvent evt); | ||||
|         Task PublishThroughEventBusAsync(IntegrationEvent evt); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -30,11 +30,12 @@ namespace Ordering.API.Application.IntegrationEvents | ||||
| 
 | ||||
|         public async Task PublishThroughEventBusAsync(IntegrationEvent evt) | ||||
|         { | ||||
|             await SaveEventAndOrderingContextChangesAsync(evt); | ||||
|             _eventBus.Publish(evt); | ||||
|             await _eventLogService.MarkEventAsPublishedAsync(evt); | ||||
|         } | ||||
| 
 | ||||
|         public async Task SaveEventAndOrderingContextChangesAsync(IntegrationEvent evt) | ||||
|         private async Task SaveEventAndOrderingContextChangesAsync(IntegrationEvent evt) | ||||
|         { | ||||
|             //Use of an EF Core resiliency strategy when using multiple DbContexts within an explicit BeginTransaction(): | ||||
|             //See: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency             | ||||
|  | ||||
| @ -5,8 +5,7 @@ using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.Order | ||||
| using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; | ||||
| using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency; | ||||
| using Ordering.API.Application.Commands; | ||||
| using Ordering.API.Application.IntegrationCommands.Commands; | ||||
| using Ordering.API.Application.IntegrationEvents; | ||||
| using Ordering.API.Application.IntegrationEvents.Events; | ||||
| using Ordering.Domain.Exceptions; | ||||
| using System.Threading.Tasks; | ||||
| 
 | ||||
| @ -21,7 +20,7 @@ namespace Ordering.API.Application.Sagas | ||||
|     /// with the validations. | ||||
|     /// </summary> | ||||
|     public class OrderProcessSaga : OrderSaga, | ||||
|         IIntegrationEventHandler<ConfirmGracePeriodCommand>, | ||||
|         IIntegrationEventHandler<GracePeriodConfirmedIntegrationEvent>, | ||||
|         IAsyncRequestHandler<CancelOrderCommand, bool>, | ||||
|         IAsyncRequestHandler<ShipOrderCommand, bool> | ||||
|     { | ||||
| @ -43,9 +42,9 @@ namespace Ordering.API.Application.Sagas | ||||
|         /// period has completed. | ||||
|         /// </param> | ||||
|         /// <returns></returns> | ||||
|         public async Task Handle(ConfirmGracePeriodCommand command) | ||||
|         public async Task Handle(GracePeriodConfirmedIntegrationEvent @event) | ||||
|         { | ||||
|             var orderSaga = FindSagaById(command.OrderId); | ||||
|             var orderSaga = FindSagaById(@event.OrderId); | ||||
|             CheckValidSagaId(orderSaga); | ||||
| 
 | ||||
|             orderSaga.SetAwaitingValidationStatus(); | ||||
| @ -96,8 +95,6 @@ namespace Ordering.API.Application.Sagas | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #region CommandHandlerIdentifiers | ||||
| 
 | ||||
|         public class CancelOrderCommandIdentifiedHandler : IdentifierCommandHandler<CancelOrderCommand, bool> | ||||
|         { | ||||
|             public CancelOrderCommandIdentifiedHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager) | ||||
| @ -121,7 +118,5 @@ namespace Ordering.API.Application.Sagas | ||||
|                 return true;                // Ignore duplicate requests for processing order. | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -17,12 +17,11 @@ namespace Ordering.API.Application.Sagas | ||||
| 
 | ||||
|         public override Order FindSagaById(int id) | ||||
|         { | ||||
|             var order = _orderingContext.Orders | ||||
|             return _orderingContext.Orders | ||||
|                 .Include(c => c.OrderStatus) | ||||
|                 .Include(c => c.OrderItems) | ||||
|                 .Include(c => c.Address) | ||||
|                 .Single(c => c.Id == id); | ||||
| 
 | ||||
|             return order; | ||||
|         } | ||||
| 
 | ||||
|         public override async Task<bool> SaveChangesAsync() | ||||
|  | ||||
| @ -79,7 +79,6 @@ | ||||
|   </ItemGroup> | ||||
| 
 | ||||
|   <ItemGroup> | ||||
|     <Folder Include="Application\IntegrationCommands\CommandHandlers\" /> | ||||
|     <Folder Include="Infrastructure\IntegrationEventMigrations\" /> | ||||
|   </ItemGroup> | ||||
| 
 | ||||
|  | ||||
| @ -3,11 +3,9 @@ | ||||
|     using AspNetCore.Http; | ||||
|     using Autofac; | ||||
|     using Autofac.Extensions.DependencyInjection; | ||||
|     using global::Ordering.API.Application.IntegrationCommands.Commands; | ||||
|     using global::Ordering.API.Application.IntegrationEvents; | ||||
|     using global::Ordering.API.Application.IntegrationEvents.EventHandling; | ||||
|     using global::Ordering.API.Application.IntegrationEvents.Events; | ||||
|     using global::Ordering.API.Application.Sagas; | ||||
|     using global::Ordering.API.Infrastructure.Middlewares; | ||||
|     using Infrastructure; | ||||
|     using Infrastructure.Auth; | ||||
| @ -169,24 +167,18 @@ | ||||
|         { | ||||
|             services.AddSingleton<IEventBus, EventBusRabbitMQ>(); | ||||
|             services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>(); | ||||
|             services.AddTransient<IIntegrationEventHandler<ConfirmGracePeriodCommand>, OrderProcessSaga>(); | ||||
|             services.AddTransient<UserCheckoutAcceptedIntegrationEventHandler>();             | ||||
|             services.AddTransient<OrderStockConfirmedIntegrationEventHandler>(); | ||||
|             services.AddTransient<OrderStockNotConfirmedIntegrationEventHandler>(); | ||||
|             services.AddTransient<OrderPaymentFailedIntegrationEventHandler>(); | ||||
|             services.AddTransient<OrderPaymentSuccededIntegrationEventHandler>(); | ||||
|         } | ||||
| 
 | ||||
|         private void ConfigureEventBus(IApplicationBuilder app) | ||||
|         { | ||||
|             var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>(); | ||||
| 
 | ||||
|             eventBus.Subscribe<ConfirmGracePeriodCommand, IIntegrationEventHandler<ConfirmGracePeriodCommand>>(); | ||||
|             eventBus.Subscribe<UserCheckoutAcceptedIntegrationEvent, UserCheckoutAcceptedIntegrationEventHandler>();             | ||||
|             eventBus.Subscribe<OrderStockConfirmedIntegrationEvent, OrderStockConfirmedIntegrationEventHandler>(); | ||||
|             eventBus.Subscribe<OrderStockNotConfirmedIntegrationEvent, OrderStockNotConfirmedIntegrationEventHandler>(); | ||||
|             eventBus.Subscribe<OrderPaymentFailedIntegrationEvent, OrderPaymentFailedIntegrationEventHandler>(); | ||||
|             eventBus.Subscribe<OrderPaymentSuccededIntegrationEvent, OrderPaymentSuccededIntegrationEventHandler>(); | ||||
|             eventBus.Subscribe<UserCheckoutAcceptedIntegrationEvent, IIntegrationEventHandler<UserCheckoutAcceptedIntegrationEvent>>(); | ||||
|             eventBus.Subscribe<GracePeriodConfirmedIntegrationEvent, IIntegrationEventHandler<GracePeriodConfirmedIntegrationEvent>>(); | ||||
|             eventBus.Subscribe<OrderStockConfirmedIntegrationEvent, IIntegrationEventHandler<OrderStockConfirmedIntegrationEvent>>(); | ||||
|             eventBus.Subscribe<OrderStockRejectedIntegrationEvent, IIntegrationEventHandler<OrderStockRejectedIntegrationEvent>>(); | ||||
|             eventBus.Subscribe<OrderPaymentFailedIntegrationEvent, IIntegrationEventHandler<OrderPaymentFailedIntegrationEvent>>(); | ||||
|             eventBus.Subscribe<OrderPaymentSuccededIntegrationEvent, IIntegrationEventHandler<OrderPaymentSuccededIntegrationEvent>>(); | ||||
|         } | ||||
| 
 | ||||
|         protected virtual void ConfigureAuth(IApplicationBuilder app) | ||||
|  | ||||
| @ -17,6 +17,8 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O | ||||
| 
 | ||||
|         public String ZipCode { get; private set; } | ||||
| 
 | ||||
|         private Address() { } | ||||
| 
 | ||||
|         public Address(string street, string city, string state, string country, string zipcode) | ||||
|         { | ||||
|             Street = street; | ||||
|  | ||||
| @ -13,7 +13,5 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O | ||||
|         void Update(Order order); | ||||
| 
 | ||||
|         Task<Order> GetAsync(int orderId); | ||||
| 
 | ||||
|         Task<Order> GetWithDependenciesAsync(int orderId); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -94,14 +94,12 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O | ||||
|             _buyerId = id; | ||||
|         } | ||||
| 
 | ||||
|         #region Status Changes | ||||
| 
 | ||||
|         public void SetAwaitingValidationStatus() | ||||
|         { | ||||
|             if (_orderStatusId != OrderStatus.Submited.Id && | ||||
|                 _orderStatusId != OrderStatus.Cancelled.Id) | ||||
|             if (_orderStatusId == OrderStatus.Cancelled.Id || | ||||
|                 _orderStatusId != OrderStatus.Submited.Id) | ||||
|             { | ||||
|                 StatusChangeException(); | ||||
|                 StatusChangeException(OrderStatus.AwaitingValidation); | ||||
|             }   | ||||
| 
 | ||||
|             AddDomainEvent(new OrderStatusChangedToAwaitingValidationDomainEvent(Id, _orderItems)); | ||||
| @ -109,38 +107,24 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O | ||||
|             _orderStatusId = OrderStatus.AwaitingValidation.Id; | ||||
|         } | ||||
| 
 | ||||
|         public void SetStockConfirmedStatus(IEnumerable<int> orderStockNotConfirmedItems = null) | ||||
|         public void SetStockConfirmedStatus() | ||||
|         { | ||||
|             if (_orderStatusId != OrderStatus.AwaitingValidation.Id) | ||||
|             { | ||||
|                 StatusChangeException(); | ||||
|                 StatusChangeException(OrderStatus.StockConfirmed); | ||||
|             } | ||||
| 
 | ||||
|             if (orderStockNotConfirmedItems is null) | ||||
|             { | ||||
|                 AddDomainEvent(new OrderStatusChangedToStockConfirmedDomainEvent(Id)); | ||||
|             AddDomainEvent(new OrderStatusChangedToStockConfirmedDomainEvent(Id)); | ||||
| 
 | ||||
|                 _orderStatusId = OrderStatus.StockConfirmed.Id; | ||||
|                 _description = "All the items were confirmed with available stock."; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 _orderStatusId = OrderStatus.Cancelled.Id; | ||||
| 
 | ||||
|                 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}).";    | ||||
|             } | ||||
|             _orderStatusId = OrderStatus.StockConfirmed.Id; | ||||
|             _description = "All the items were confirmed with available stock."; | ||||
|         } | ||||
| 
 | ||||
|         public void SetPaidStatus() | ||||
|         { | ||||
|             if (_orderStatusId != OrderStatus.StockConfirmed.Id) | ||||
|             { | ||||
|                 StatusChangeException(); | ||||
|                 StatusChangeException(OrderStatus.Paid); | ||||
|             } | ||||
| 
 | ||||
|             AddDomainEvent(new OrderStatusChangedToPaidDomainEvent(Id, OrderItems)); | ||||
| @ -153,40 +137,41 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O | ||||
|         { | ||||
|             if (_orderStatusId != OrderStatus.Paid.Id) | ||||
|             { | ||||
|                 StatusChangeException(); | ||||
|                 StatusChangeException(OrderStatus.Shipped); | ||||
|             } | ||||
| 
 | ||||
|             _orderStatusId = OrderStatus.Shipped.Id; | ||||
|             _description = ""; | ||||
|             _description = "The order was shipped."; | ||||
|         } | ||||
| 
 | ||||
|         public void SetCancelledStatus() | ||||
|         { | ||||
|             if (_orderStatusId == OrderStatus.Submited.Id) | ||||
|             if (_orderStatusId == OrderStatus.Paid.Id || | ||||
|                 _orderStatusId == OrderStatus.Shipped.Id) | ||||
|             { | ||||
|                 _description = "The order was cancelled before the grace period was confirmed."; | ||||
|             } | ||||
|             else if (_orderStatusId == OrderStatus.AwaitingValidation.Id) | ||||
|             { | ||||
|                 _description = "The order was cancelled before to check the order stock items."; | ||||
|             } | ||||
|             else if (_orderStatusId == OrderStatus.StockConfirmed.Id) | ||||
|             { | ||||
|                 _description = "The order was cancelled before to pay the order."; | ||||
|             } | ||||
|             else if (_orderStatusId == OrderStatus.Paid.Id) | ||||
|             { | ||||
|                 _description = "The order was cancelled before to ship the order."; | ||||
|             } | ||||
|             else if(_orderStatusId == OrderStatus.Shipped.Id) | ||||
|             { | ||||
|                 throw new OrderingDomainException("Not possible to change order status. Reason: cannot cancel order it is already shipped."); | ||||
|                 StatusChangeException(OrderStatus.Cancelled); | ||||
|             } | ||||
| 
 | ||||
|             _orderStatusId = OrderStatus.Cancelled.Id; | ||||
|             _description = $"The order was cancelled."; | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
|         public void SetCancelledStatusWhenStockIsRejected(IEnumerable<int> orderStockRejectedItems) | ||||
|         { | ||||
|             if (_orderStatusId != OrderStatus.AwaitingValidation.Id) | ||||
|             { | ||||
|                 StatusChangeException(OrderStatus.Cancelled); | ||||
|             } | ||||
| 
 | ||||
|             _orderStatusId = OrderStatus.Cancelled.Id; | ||||
| 
 | ||||
|             var itemsStockRejectedProductNames = OrderItems | ||||
|                 .Where(c => orderStockRejectedItems.Contains(c.ProductId)) | ||||
|                 .Select(c => c.GetOrderItemProductName()); | ||||
| 
 | ||||
|             var itemsStockRejectedDescription = string.Join(", ", itemsStockRejectedProductNames); | ||||
|             _description = $"The product items don't have stock: ({itemsStockRejectedDescription})."; | ||||
|         } | ||||
| 
 | ||||
|         private void AddOrderStartedDomainEvent(string userId, int cardTypeId, string cardNumber, | ||||
|                 string cardSecurityNumber, string cardHolderName, DateTime cardExpiration) | ||||
| @ -198,9 +183,9 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O | ||||
|             this.AddDomainEvent(orderStartedDomainEvent); | ||||
|         } | ||||
| 
 | ||||
|         private void StatusChangeException() | ||||
|         private void StatusChangeException(OrderStatus orderStatusToChange) | ||||
|         { | ||||
|             throw new OrderingDomainException("Not able to process order event. Reason: no valid order status change"); | ||||
|             throw new OrderingDomainException($"Not possible to change order status from {OrderStatus.Name} to {orderStatusToChange.Name}."); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -33,15 +33,18 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositor | ||||
| 
 | ||||
|         public async Task<Order> GetAsync(int orderId) | ||||
|         { | ||||
|             return await _context.Orders.FindAsync(orderId); | ||||
|         } | ||||
|             var order = await _context.Orders.FindAsync(orderId); | ||||
|             if (order != null) | ||||
|             { | ||||
|                 await _context.Entry(order) | ||||
|                     .Collection(i => i.OrderItems).LoadAsync(); | ||||
|                 await _context.Entry(order) | ||||
|                     .Reference(i => i.OrderStatus).LoadAsync(); | ||||
|                 await _context.Entry(order) | ||||
|                     .Reference(i => i.Address).LoadAsync(); | ||||
|             } | ||||
| 
 | ||||
|         public async Task<Order> GetWithDependenciesAsync(int orderId) | ||||
|         { | ||||
|             return await _context.Orders | ||||
|                 .Include(c => c.OrderStatus) | ||||
|                 .Include(c => c.OrderItems) | ||||
|                 .SingleAsync(c => c.Id == orderId); | ||||
|             return order; | ||||
|         } | ||||
| 
 | ||||
|         public void Update(Order order) | ||||
|  | ||||
| @ -1,27 +0,0 @@ | ||||
| namespace Payment.API.IntegrationCommands.CommandHandlers | ||||
| { | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | ||||
|     using Payment.API.IntegrationCommands.Commands; | ||||
|     using System.Threading.Tasks; | ||||
|     using Payment.API.IntegrationEvents; | ||||
|     using Payment.API.IntegrationEvents.Events; | ||||
| 
 | ||||
|     public class PayOrderCommandHandler : IIntegrationEventHandler<PayOrderCommand> | ||||
|     { | ||||
|         private readonly IPaymentIntegrationEventService _paymentIntegrationEventService; | ||||
| 
 | ||||
|         public PayOrderCommandHandler(IPaymentIntegrationEventService paymentIntegrationEventService) | ||||
|             => _paymentIntegrationEventService = paymentIntegrationEventService; | ||||
| 
 | ||||
|         public async Task Handle(PayOrderCommand @event) | ||||
|         { | ||||
|             //PAYMENT SUCCESSED | ||||
|             var orderPaymentSuccededIntegrationEvent = new OrderPaymentSuccededIntegrationEvent(@event.OrderId); | ||||
|             _paymentIntegrationEventService.PublishThroughEventBus(orderPaymentSuccededIntegrationEvent); | ||||
| 
 | ||||
|             //PAYMENT FAILED | ||||
|             //var orderPaymentFailedIntegrationEvent = new OrderPaymentFailedIntegrationEvent(@event.OrderId); | ||||
|             //_paymentIntegrationEventService.PublishThroughEventBus(orderPaymentFailedIntegrationEvent); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -1,11 +0,0 @@ | ||||
| namespace Payment.API.IntegrationCommands.Commands | ||||
| { | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||
| 
 | ||||
|     public class PayOrderCommand : IntegrationEvent | ||||
|     { | ||||
|         public int OrderId { get; } | ||||
| 
 | ||||
|         public PayOrderCommand(int orderId) => OrderId = orderId; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,37 @@ | ||||
| namespace Payment.API.IntegrationEvents.EventHandling | ||||
| { | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | ||||
|     using System.Threading.Tasks; | ||||
|     using Payment.API.IntegrationEvents.Events; | ||||
|     using Microsoft.Extensions.Options; | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||
| 
 | ||||
|     public class OrderStatusChangedToStockConfirmedIntegrationEventHandler :  | ||||
|         IIntegrationEventHandler<OrderStatusChangedToStockConfirmedIntegrationEvent> | ||||
|     { | ||||
|         private readonly IEventBus _eventBus; | ||||
|         private readonly PaymentSettings _settings; | ||||
| 
 | ||||
|         public OrderStatusChangedToStockConfirmedIntegrationEventHandler(IEventBus eventBus,  | ||||
|             IOptionsSnapshot<PaymentSettings> settings) | ||||
|         { | ||||
|             _eventBus = eventBus; | ||||
|             _settings = settings.Value; | ||||
|         }          | ||||
| 
 | ||||
|         public async Task Handle(OrderStatusChangedToStockConfirmedIntegrationEvent @event) | ||||
|         { | ||||
|             IntegrationEvent orderPaymentIntegrationEvent; | ||||
|             if(_settings.SuccessPayment) | ||||
|             { | ||||
|                 orderPaymentIntegrationEvent = new OrderPaymentSuccededIntegrationEvent(@event.OrderId); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 orderPaymentIntegrationEvent = new OrderPaymentFailedIntegrationEvent(@event.OrderId); | ||||
|             } | ||||
| 
 | ||||
|             _eventBus.Publish(orderPaymentIntegrationEvent); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,12 @@ | ||||
| namespace Payment.API.IntegrationEvents.Events | ||||
| { | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||
| 
 | ||||
|     public class OrderStatusChangedToStockConfirmedIntegrationEvent : IntegrationEvent | ||||
|     { | ||||
|         public int OrderId { get; } | ||||
| 
 | ||||
|         public OrderStatusChangedToStockConfirmedIntegrationEvent(int orderId) | ||||
|             => OrderId = orderId; | ||||
|     } | ||||
| } | ||||
| @ -1,9 +0,0 @@ | ||||
| namespace Payment.API.IntegrationEvents | ||||
| { | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||
| 
 | ||||
|     public interface IPaymentIntegrationEventService | ||||
|     { | ||||
|         void PublishThroughEventBus(IntegrationEvent evt); | ||||
|     } | ||||
| } | ||||
| @ -1,21 +0,0 @@ | ||||
| namespace Payment.API.IntegrationEvents | ||||
| {  | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||
|     using System; | ||||
| 
 | ||||
|     public class PaymentIntegrationEventService : IPaymentIntegrationEventService | ||||
|     { | ||||
|         private readonly IEventBus _eventBus; | ||||
| 
 | ||||
|         public PaymentIntegrationEventService(IEventBus eventBus) | ||||
|         { | ||||
|             _eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus)); | ||||
|         } | ||||
| 
 | ||||
|         public void PublishThroughEventBus(IntegrationEvent evt) | ||||
|         { | ||||
|             _eventBus.Publish(evt); ; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										8
									
								
								src/Services/Payment/Payment.API/PaymentSettings.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/Services/Payment/Payment.API/PaymentSettings.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| namespace Payment.API | ||||
| { | ||||
|     public class PaymentSettings | ||||
|     { | ||||
|         public bool SuccessPayment { get; set; } | ||||
|         public string EventBusConnection { get; set; } | ||||
|     } | ||||
| } | ||||
| @ -7,12 +7,11 @@ 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; | ||||
| using Payment.API.IntegrationEvents; | ||||
| using Payment.API.IntegrationCommands.CommandHandlers; | ||||
| using Payment.API.IntegrationEvents.Events; | ||||
| using Payment.API.IntegrationEvents.EventHandling; | ||||
| 
 | ||||
| namespace Payment.API | ||||
| { | ||||
| @ -35,8 +34,7 @@ namespace Payment.API | ||||
|         { | ||||
|             // Add framework services. | ||||
|             services.AddMvc(); | ||||
| 
 | ||||
|             services.AddTransient<IPaymentIntegrationEventService, PaymentIntegrationEventService>(); | ||||
|             services.Configure<PaymentSettings>(Configuration); | ||||
|             services.AddSingleton<IRabbitMQPersistentConnection>(sp => | ||||
|             { | ||||
|                 var logger = sp.GetRequiredService<ILogger<DefaultRabbitMQPersistentConnection>>(); | ||||
| @ -88,13 +86,15 @@ namespace Payment.API | ||||
|             services.AddSingleton<IEventBus, EventBusRabbitMQ>(); | ||||
|             services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>(); | ||||
| 
 | ||||
|             services.AddTransient<IIntegrationEventHandler<PayOrderCommand>, PayOrderCommandHandler>(); | ||||
|             services.AddTransient<IIntegrationEventHandler<OrderStatusChangedToStockConfirmedIntegrationEvent>,  | ||||
|                 OrderStatusChangedToStockConfirmedIntegrationEventHandler>(); | ||||
|         } | ||||
| 
 | ||||
|         private void ConfigureEventBus(IApplicationBuilder app) | ||||
|         { | ||||
|             var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>(); | ||||
|             eventBus.Subscribe<PayOrderCommand, IIntegrationEventHandler<PayOrderCommand>>(); | ||||
|             eventBus.Subscribe<OrderStatusChangedToStockConfirmedIntegrationEvent,  | ||||
|                 IIntegrationEventHandler<OrderStatusChangedToStockConfirmedIntegrationEvent>>(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -4,5 +4,6 @@ | ||||
|     "LogLevel": { | ||||
|       "Default": "Warning" | ||||
|     } | ||||
|   } | ||||
|   }, | ||||
|   "SuccessPayment": "true" | ||||
| } | ||||
|  | ||||
| @ -2,10 +2,10 @@ | ||||
| { | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||
| 
 | ||||
|     public class ConfirmGracePeriodCommand : IntegrationEvent | ||||
|     public class GracePeriodConfirmedIntegrationEvent : IntegrationEvent | ||||
|     { | ||||
|         public int OrderId { get;} | ||||
| 
 | ||||
|         public ConfirmGracePeriodCommand(int orderId) => OrderId = orderId; | ||||
|         public GracePeriodConfirmedIntegrationEvent(int orderId) => OrderId = orderId; | ||||
|     } | ||||
| } | ||||
| @ -1,9 +0,0 @@ | ||||
| namespace SagaManager.IntegrationEvents | ||||
| { | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||
| 
 | ||||
|     public interface ISagaManagerIntegrationEventService | ||||
|     { | ||||
|         void PublishThroughEventBus(IntegrationEvent evt); | ||||
|     } | ||||
| } | ||||
| @ -1,17 +0,0 @@ | ||||
| namespace SagaManager.IntegrationEvents | ||||
| { | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||
|     using System; | ||||
| 
 | ||||
|     public class SagaManagerIntegrationEventService : ISagaManagerIntegrationEventService | ||||
|     { | ||||
|         private readonly IEventBus _eventBus; | ||||
| 
 | ||||
|         public SagaManagerIntegrationEventService(IEventBus eventBus) | ||||
|             => _eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus)); | ||||
| 
 | ||||
| 
 | ||||
|         public void PublishThroughEventBus(IntegrationEvent evt) => _eventBus.Publish(evt); | ||||
|     } | ||||
| } | ||||
| @ -14,7 +14,6 @@ | ||||
|     using Microsoft.Extensions.Options; | ||||
|     using RabbitMQ.Client; | ||||
|     using Services; | ||||
|     using IntegrationEvents; | ||||
| 
 | ||||
|     public class Program | ||||
|     { | ||||
| @ -34,11 +33,13 @@ | ||||
| 
 | ||||
|             var sagaManagerService = serviceProvider | ||||
|                 .GetRequiredService<ISagaManagerService>(); | ||||
|             var checkUpdateTime = serviceProvider | ||||
|                 .GetRequiredService<IOptions<SagaManagerSettings>>().Value.CheckUpdateTime; | ||||
| 
 | ||||
|             while (true) | ||||
|             { | ||||
|                 sagaManagerService.CheckConfirmedGracePeriodOrders(); | ||||
|                 await Task.Delay(90000); | ||||
|                 await Task.Delay(checkUpdateTime); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| @ -58,8 +59,6 @@ | ||||
|                 .AddOptions() | ||||
|                 .Configure<SagaManagerSettings>(Configuration) | ||||
|                 .AddSingleton<ISagaManagerService, SagaManagerService>() | ||||
|                 .AddSingleton<ISagaManagerIntegrationEventService, SagaManagerIntegrationEventService>() | ||||
| 
 | ||||
|                 .AddSingleton<IRabbitMQPersistentConnection>(sp => | ||||
|                 { | ||||
|                     var settings = sp.GetRequiredService<IOptions<SagaManagerSettings>>().Value; | ||||
|  | ||||
| @ -6,6 +6,8 @@ | ||||
| 
 | ||||
|         public string EventBusConnection { get; set; } | ||||
| 
 | ||||
|         public int GracePeriod { get; set; } | ||||
|         public int GracePeriodTime { get; set; } | ||||
| 
 | ||||
|         public int CheckUpdateTime { get; set; } | ||||
|     } | ||||
| } | ||||
| @ -5,21 +5,21 @@ | ||||
|     using Microsoft.Extensions.Options; | ||||
|     using Microsoft.Extensions.Logging; | ||||
|     using Dapper; | ||||
|     using IntegrationEvents; | ||||
|     using IntegrationEvents.Events; | ||||
|     using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | ||||
| 
 | ||||
|     public class SagaManagerService : ISagaManagerService | ||||
|     { | ||||
|         private readonly SagaManagerSettings _settings; | ||||
|         private readonly ISagaManagerIntegrationEventService _sagaManagerIntegrationEventService; | ||||
|         private readonly IEventBus _eventBus; | ||||
|         private readonly ILogger<SagaManagerService> _logger; | ||||
| 
 | ||||
|         public SagaManagerService(IOptions<SagaManagerSettings> settings, | ||||
|             ISagaManagerIntegrationEventService sagaManagerIntegrationEventService, | ||||
|             IEventBus eventBus, | ||||
|             ILogger<SagaManagerService> logger) | ||||
|         { | ||||
|             _settings = settings.Value; | ||||
|             _sagaManagerIntegrationEventService = sagaManagerIntegrationEventService; | ||||
|             _eventBus = eventBus; | ||||
|             _logger = logger; | ||||
|         } | ||||
| 
 | ||||
| @ -29,8 +29,8 @@ | ||||
| 
 | ||||
|             foreach (var orderId in orderIds) | ||||
|             { | ||||
|                 var confirmGracePeriodEvent = new ConfirmGracePeriodCommand(orderId); | ||||
|                 _sagaManagerIntegrationEventService.PublishThroughEventBus(confirmGracePeriodEvent); | ||||
|                 var confirmGracePeriodEvent = new GracePeriodConfirmedIntegrationEvent(orderId); | ||||
|                 _eventBus.Publish(confirmGracePeriodEvent); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| @ -45,9 +45,9 @@ | ||||
|                     conn.Open(); | ||||
|                     orderIds = conn.Query<int>( | ||||
|                         @"SELECT Id FROM [Microsoft.eShopOnContainers.Services.OrderingDb].[ordering].[orders] 
 | ||||
|                             WHERE DATEDIFF(hour, [OrderDate], GETDATE()) >= @GracePeriod | ||||
|                             WHERE DATEDIFF(hour, [OrderDate], GETDATE()) >= @GracePeriodTime | ||||
|                             AND [OrderStatusId] = 1",
 | ||||
|                         new { GracePeriod = _settings.GracePeriod });   | ||||
|                         new { GracePeriodTime = _settings.GracePeriodTime });   | ||||
|                 } | ||||
|                 catch (SqlException exception) | ||||
|                 { | ||||
|  | ||||
| @ -7,5 +7,7 @@ | ||||
|       "Microsoft": "Information" | ||||
|     } | ||||
|   }, | ||||
|   "ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;" | ||||
|   "ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;", | ||||
|   "GracePeriodTime": "15", | ||||
|   "CheckUpdateTime": "30000" | ||||
| } | ||||
|  | ||||
| @ -31,9 +31,9 @@ | ||||
|                     <a class="esh-orders-link" asp-controller="Order" asp-action="Detail" asp-route-orderId="@item.OrderNumber">Detail</a> | ||||
|                 </section> | ||||
|                 <section class="esh-orders-item col-xs-1"> | ||||
|                     @if ((item.Status.ToLower() != "shipped") && (item.Status.ToLower() != "cancelled")) | ||||
|                     @if (item.Status.ToLower() == "submited") | ||||
|                     { | ||||
|                         <a class="esh-orders-link" asp-controller="Order" asp-action="Cancel" asp-route-orderId="@item.OrderNumber">Cancel</a> | ||||
|                         <a class="esh-orders-link" asp-controller="Order" asp-action="cancel" asp-route-orderId="@item.OrderNumber">Cancel</a> | ||||
|                     }                     | ||||
|                 </section> | ||||
|             </article> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user