@ -0,0 +1,46 @@ | |||||
using MediatR; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | |||||
namespace Ordering.API.Application.Commands | |||||
{ | |||||
public class CancelOrderCommandIdentifiedHandler : IdentifierCommandHandler<CancelOrderCommand, bool> | |||||
{ | |||||
public CancelOrderCommandIdentifiedHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager) | |||||
{ | |||||
} | |||||
protected override bool CreateResultForDuplicateRequest() | |||||
{ | |||||
return true; // Ignore duplicate requests for processing order. | |||||
} | |||||
} | |||||
public class CancelOrderCommandHandler : IAsyncRequestHandler<CancelOrderCommand, bool> | |||||
{ | |||||
private readonly IOrderRepository _orderRepository; | |||||
public CancelOrderCommandHandler(IOrderRepository orderRepository) | |||||
{ | |||||
_orderRepository = orderRepository; | |||||
} | |||||
/// <summary> | |||||
/// Handler which processes the command when | |||||
/// customer executes cancel order from app | |||||
/// </summary> | |||||
/// <param name="command"></param> | |||||
/// <returns></returns> | |||||
public async Task<bool> Handle(CancelOrderCommand command) | |||||
{ | |||||
var orderToUpdate = await _orderRepository.GetAsync(command.OrderNumber); | |||||
orderToUpdate.SetCancelledStatus(); | |||||
return await _orderRepository.UnitOfWork.SaveEntitiesAsync(); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,43 @@ | |||||
using MediatR; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency; | |||||
using System.Threading.Tasks; | |||||
namespace Ordering.API.Application.Commands | |||||
{ | |||||
public class ShipOrderCommandIdentifiedHandler : IdentifierCommandHandler<ShipOrderCommand, bool> | |||||
{ | |||||
public ShipOrderCommandIdentifiedHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager) | |||||
{ | |||||
} | |||||
protected override bool CreateResultForDuplicateRequest() | |||||
{ | |||||
return true; // Ignore duplicate requests for processing order. | |||||
} | |||||
} | |||||
public class ShipOrderCommandHandler : IAsyncRequestHandler<ShipOrderCommand, bool> | |||||
{ | |||||
private readonly IOrderRepository _orderRepository; | |||||
public ShipOrderCommandHandler(IOrderRepository orderRepository) | |||||
{ | |||||
_orderRepository = orderRepository; | |||||
} | |||||
/// <summary> | |||||
/// Handler which processes the command when | |||||
/// administrator executes ship order from app | |||||
/// </summary> | |||||
/// <param name="command"></param> | |||||
/// <returns></returns> | |||||
public async Task<bool> Handle(ShipOrderCommand command) | |||||
{ | |||||
var orderToUpdate = await _orderRepository.GetAsync(command.OrderNumber); | |||||
orderToUpdate.SetShippedStatus(); | |||||
return await _orderRepository.UnitOfWork.SaveEntitiesAsync(); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,32 @@ | |||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; | |||||
using Ordering.API.Application.IntegrationEvents.Events; | |||||
using System.Threading.Tasks; | |||||
namespace Ordering.API.Application.IntegrationEvents.EventHandling | |||||
{ | |||||
public class GracePeriodConfirmedIntegrationEventHandler : IIntegrationEventHandler<GracePeriodConfirmedIntegrationEvent> | |||||
{ | |||||
private readonly IOrderRepository _orderRepository; | |||||
public GracePeriodConfirmedIntegrationEventHandler(IOrderRepository orderRepository) | |||||
{ | |||||
_orderRepository = orderRepository; | |||||
} | |||||
/// <summary> | |||||
/// Event handler which confirms that the grace period | |||||
/// has been completed and order will not initially be cancelled. | |||||
/// Therefore, the order process continues for validation. | |||||
/// </summary> | |||||
/// <param name="event"> | |||||
/// </param> | |||||
/// <returns></returns> | |||||
public async Task Handle(GracePeriodConfirmedIntegrationEvent @event) | |||||
{ | |||||
var orderToUpdate = await _orderRepository.GetAsync(@event.OrderId); | |||||
orderToUpdate.SetAwaitingValidationStatus(); | |||||
await _orderRepository.UnitOfWork.SaveEntitiesAsync(); | |||||
} | |||||
} | |||||
} |
@ -1,121 +0,0 @@ | |||||
using MediatR; | |||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency; | |||||
using Ordering.API.Application.Commands; | |||||
using Ordering.API.Application.IntegrationEvents.Events; | |||||
using Ordering.Domain.Exceptions; | |||||
using System.Threading.Tasks; | |||||
namespace Ordering.API.Application.Sagas | |||||
{ | |||||
/// <summary> | |||||
/// Saga for handling the place order process | |||||
/// and which is started once the basket.api has | |||||
/// successfully processed the items ordered. | |||||
/// Saga provides a period of grace to give the customer | |||||
/// the opportunity to cancel the order before proceeding | |||||
/// with the validations. | |||||
/// </summary> | |||||
public class OrderProcessSaga : OrderSaga, | |||||
IIntegrationEventHandler<GracePeriodConfirmedIntegrationEvent>, | |||||
IAsyncRequestHandler<CancelOrderCommand, bool>, | |||||
IAsyncRequestHandler<ShipOrderCommand, bool> | |||||
{ | |||||
public OrderProcessSaga( | |||||
OrderingContext orderingContext) | |||||
: base(orderingContext) | |||||
{ | |||||
} | |||||
/// <summary> | |||||
/// Event handler which confirms that the grace period | |||||
/// has been completed and order will not initially be cancelled. | |||||
/// Therefore, the order process continues for validation. | |||||
/// </summary> | |||||
/// <param name="event"> | |||||
/// Integration event message which is sent by a saga scheduler | |||||
/// telling us that the saga's grace period has completed. | |||||
/// </param> | |||||
/// <returns></returns> | |||||
public async Task Handle(GracePeriodConfirmedIntegrationEvent @event) | |||||
{ | |||||
var orderSaga = FindSagaById(@event.OrderId); | |||||
CheckValidSagaId(orderSaga); | |||||
orderSaga.SetAwaitingValidationStatus(); | |||||
await SaveChangesAsync(); | |||||
} | |||||
/// <summary> | |||||
/// Handler which processes the command when | |||||
/// customer executes cancel order from app | |||||
/// </summary> | |||||
/// <param name="command"></param> | |||||
/// <returns></returns> | |||||
public async Task<bool> Handle(CancelOrderCommand command) | |||||
{ | |||||
var result = false; | |||||
var orderSaga = FindSagaById(command.OrderNumber); | |||||
CheckValidSagaId(orderSaga); | |||||
orderSaga.SetCancelledStatus(); | |||||
result = await SaveChangesAsync(); | |||||
return result; | |||||
} | |||||
/// <summary> | |||||
/// Handler which processes the command when | |||||
/// administrator executes ship order from app | |||||
/// </summary> | |||||
/// <param name="command"></param> | |||||
/// <returns></returns> | |||||
public async Task<bool> Handle(ShipOrderCommand command) | |||||
{ | |||||
var result = false; | |||||
var orderSaga = FindSagaById(command.OrderNumber); | |||||
CheckValidSagaId(orderSaga); | |||||
orderSaga.SetShippedStatus(); | |||||
result = await SaveChangesAsync(); | |||||
return result; | |||||
} | |||||
private void CheckValidSagaId(Order orderSaga) | |||||
{ | |||||
if (orderSaga is null) | |||||
{ | |||||
throw new OrderingDomainException("Not able to process order saga event. Reason: no valid orderId"); | |||||
} | |||||
} | |||||
public class CancelOrderCommandIdentifiedHandler : IdentifierCommandHandler<CancelOrderCommand, bool> | |||||
{ | |||||
public CancelOrderCommandIdentifiedHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager) | |||||
{ | |||||
} | |||||
protected override bool CreateResultForDuplicateRequest() | |||||
{ | |||||
return true; // Ignore duplicate requests for processing order. | |||||
} | |||||
} | |||||
public class ShipOrderCommandIdentifiedHandler : IdentifierCommandHandler<ShipOrderCommand, bool> | |||||
{ | |||||
public ShipOrderCommandIdentifiedHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager) | |||||
{ | |||||
} | |||||
protected override bool CreateResultForDuplicateRequest() | |||||
{ | |||||
return true; // Ignore duplicate requests for processing order. | |||||
} | |||||
} | |||||
} | |||||
} |
@ -1,32 +0,0 @@ | |||||
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<Order> | |||||
{ | |||||
private OrderingContext _orderingContext; | |||||
public OrderSaga(OrderingContext orderingContext) : base(orderingContext) | |||||
{ | |||||
_orderingContext = orderingContext; | |||||
} | |||||
public override Order FindSagaById(int id) | |||||
{ | |||||
return _orderingContext.Orders | |||||
.Include(c => c.OrderStatus) | |||||
.Include(c => c.OrderItems) | |||||
.Include(c => c.Address) | |||||
.Single(c => c.Id == id); | |||||
} | |||||
public override async Task<bool> SaveChangesAsync() | |||||
{ | |||||
return await _orderingContext.SaveEntitiesAsync(); | |||||
} | |||||
} | |||||
} |
@ -1,21 +0,0 @@ | |||||
using Microsoft.EntityFrameworkCore; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.Seedwork; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | |||||
namespace Ordering.API.Application.Sagas | |||||
{ | |||||
public abstract class Saga<TEntity> where TEntity : Entity | |||||
{ | |||||
private readonly DbContext _dbContext; | |||||
public Saga(DbContext dbContext) | |||||
{ | |||||
_dbContext = dbContext; | |||||
} | |||||
public abstract TEntity FindSagaById(int id); | |||||
public abstract Task<bool> SaveChangesAsync(); | |||||
} | |||||
} |