Browse Source

add order status change

add  order status event
add order status event handler
pull/1940/head
cemaleddin 2 years ago
parent
commit
78a45cdad3
28 changed files with 470 additions and 47 deletions
  1. +6
    -2
      src/Services/Identity/Identity.API/Identity.API.csproj
  2. +1
    -0
      src/Services/Ordering/Ordering.API/Application/Commands/IdentifiedCommand.cs
  3. +13
    -0
      src/Services/Ordering/Ordering.API/Application/Commands/SetCompletedOrderStatusCommand.cs
  4. +51
    -0
      src/Services/Ordering/Ordering.API/Application/Commands/SetCompletedOrderStatusCommandHandler.cs
  5. +44
    -0
      src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderCompleted/OrderStatusChangedToCompletedDomainEventHandler.cs
  6. +35
    -0
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderCompletedFailedIntegrationEventHandler.cs
  7. +35
    -0
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderCompletedSucceededIntegrationEventHandler.cs
  8. +8
    -0
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderCompletedFailedIntegrationEvent.cs
  9. +8
    -0
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderCompletedSucceededIntegrationEvent.cs
  10. +21
    -0
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToCompletedIntegrationEvent.cs
  11. +25
    -0
      src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs
  12. +2
    -0
      src/Services/Ordering/Ordering.API/Startup.cs
  13. +10
    -0
      src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs
  14. +2
    -1
      src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/OrderStatus.cs
  15. +18
    -0
      src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToCompletedDomainEvent.cs
  16. +28
    -0
      src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToCompletedIntegrationEventHandler.cs
  17. +16
    -0
      src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToCompletedIntegrationEvent.cs
  18. +1
    -0
      src/Services/Ordering/Ordering.SignalrHub/Startup.cs
  19. +16
    -0
      src/Services/Ordering/Ordering.UnitTests/Application/OrdersWebApiTest.cs
  20. +7
    -0
      src/Web/WebMVC/Controllers/OrderController.cs
  21. +8
    -0
      src/Web/WebMVC/Infrastructure/API.cs
  22. +2
    -0
      src/Web/WebMVC/Services/IOrderingService.cs
  23. +20
    -0
      src/Web/WebMVC/Services/OrderingService.cs
  24. +52
    -31
      src/Web/WebMVC/Views/Order/Index.cshtml
  25. +27
    -7
      src/Web/WebMVC/Views/Shared/_Layout.cshtml
  26. +5
    -1
      src/Web/WebMVC/WebMVC.csproj
  27. +5
    -1
      src/Web/WebStatus/WebStatus.csproj
  28. +4
    -4
      src/eShopOnContainers-ServicesAndWebApps.sln

+ 6
- 2
src/Services/Identity/Identity.API/Identity.API.csproj View File

@ -39,8 +39,12 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.0" /> <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.18" /> <PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.18" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="6.0.0" />
<PackageReference Include="Microsoft.TypeScript.MSBuild" Version="4.7.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.11.1" /> <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.11.1" />
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.1.113" />
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.1.175" />
<PackageReference Include="Polly" Version="7.2.2" /> <PackageReference Include="Polly" Version="7.2.2" />
<PackageReference Include="Serilog.AspNetCore" Version="4.1.1-dev-00229" /> <PackageReference Include="Serilog.AspNetCore" Version="4.1.1-dev-00229" />
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.2.1-dev-00787" /> <PackageReference Include="Serilog.Enrichers.Environment" Version="2.2.1-dev-00787" />
@ -50,7 +54,7 @@
<PackageReference Include="Serilog.Sinks.Seq" Version="5.0.1" /> <PackageReference Include="Serilog.Sinks.Seq" Version="5.0.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.1" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.1" />
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.2.1" /> <PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.2.1" />
<PackageReference Include="System.Data.SqlClient" version="4.8.2"/>
<PackageReference Include="System.Data.SqlClient" version="4.8.2" />
<PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.2.1" /> <PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.2.1" />
<PackageReference Include="Azure.Identity" Version="1.4.0" /> <PackageReference Include="Azure.Identity" Version="1.4.0" />
</ItemGroup> </ItemGroup>


+ 1
- 0
src/Services/Ordering/Ordering.API/Application/Commands/IdentifiedCommand.cs View File

@ -10,4 +10,5 @@ public class IdentifiedCommand<T, R> : IRequest<R>
Command = command; Command = command;
Id = id; Id = id;
} }
} }

+ 13
- 0
src/Services/Ordering/Ordering.API/Application/Commands/SetCompletedOrderStatusCommand.cs View File

@ -0,0 +1,13 @@
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
public class SetCompletedOrderStatusCommand : IRequest<bool>
{
[DataMember]
public int OrderNumber { get; private set; }
public SetCompletedOrderStatusCommand(int orderNumber)
{
OrderNumber = orderNumber;
}
}

+ 51
- 0
src/Services/Ordering/Ordering.API/Application/Commands/SetCompletedOrderStatusCommandHandler.cs View File

@ -0,0 +1,51 @@
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
// Regular CommandHandler
public class SetCompletedOrderStatusCommandHandler : IRequestHandler<SetCompletedOrderStatusCommand, bool>
{
private readonly IOrderRepository _orderRepository;
public SetCompletedOrderStatusCommandHandler(IOrderRepository orderRepository)
{
_orderRepository = orderRepository;
}
/// <summary>
/// Handler which processes the command when
/// Completed the order
/// </summary>
/// <param name="command"></param>
/// <returns></returns>
public async Task<bool> Handle(SetCompletedOrderStatusCommand command, CancellationToken cancellationToken)
{
// Simulate a work time for validating the completed
await Task.Delay(10000, cancellationToken);
var orderToUpdate = await _orderRepository.GetAsync(command.OrderNumber);
if (orderToUpdate == null)
{
return false;
}
orderToUpdate.SetCompletedStatus();
return await _orderRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);
}
}
// Use for Idempotency in Command process
public class SetCompletedIdentifiedOrderStatusCommandHandler : IdentifiedCommandHandler<SetCompletedOrderStatusCommand, bool>
{
public SetCompletedIdentifiedOrderStatusCommandHandler(
IMediator mediator,
IRequestManager requestManager,
ILogger<IdentifiedCommandHandler<SetCompletedOrderStatusCommand, bool>> logger)
: base(mediator, requestManager, logger)
{
}
protected override bool CreateResultForDuplicateRequest()
{
return true; // Ignore duplicate requests for processing order.
}
}

+ 44
- 0
src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderCompleted/OrderStatusChangedToCompletedDomainEventHandler.cs View File

@ -0,0 +1,44 @@
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.DomainEventHandlers.OrderCompleted;
public class OrderStatusChangedToCompletedDomainEventHandler
: INotificationHandler<OrderStatusChangedToCompletedDomainEvent>
{
private readonly IOrderRepository _orderRepository;
private readonly ILoggerFactory _logger;
private readonly IBuyerRepository _buyerRepository;
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
public OrderStatusChangedToCompletedDomainEventHandler(
IOrderRepository orderRepository, ILoggerFactory logger,
IBuyerRepository buyerRepository,
IOrderingIntegrationEventService orderingIntegrationEventService
)
{
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_buyerRepository = buyerRepository ?? throw new ArgumentNullException(nameof(buyerRepository));
_orderingIntegrationEventService = orderingIntegrationEventService ?? throw new ArgumentNullException(nameof(orderingIntegrationEventService));
}
public async Task Handle(OrderStatusChangedToCompletedDomainEvent orderStatusChangedToCompletedDomainEvent, CancellationToken cancellationToken)
{
_logger.CreateLogger<OrderStatusChangedToCompletedDomainEventHandler>()
.LogTrace("Order with Id: {OrderId} has been successfully updated to status {Status} ({Id})",
orderStatusChangedToCompletedDomainEvent.OrderId, nameof(OrderStatus.Complete), OrderStatus.Complete.Id);
var order = await _orderRepository.GetAsync(orderStatusChangedToCompletedDomainEvent.OrderId);
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
var orderStockList = orderStatusChangedToCompletedDomainEvent.OrderItems
.Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.GetUnits()));
var orderStatusChangedToCompletedIntegrationEvent = new OrderStatusChangedToCompletedIntegrationEvent(
orderStatusChangedToCompletedDomainEvent.OrderId,
order.OrderStatus.Name,
buyer.Name,
orderStockList);
await _orderingIntegrationEventService.AddAndSaveEventAsync(orderStatusChangedToCompletedIntegrationEvent);
}
}

+ 35
- 0
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderCompletedFailedIntegrationEventHandler.cs View File

@ -0,0 +1,35 @@
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.IntegrationEvents.EventHandling;
public class OrderCompletedFailedIntegrationEventHandler :
IIntegrationEventHandler<OrderCompletedFailedIntegrationEvent>
{
private readonly IMediator _mediator;
private readonly ILogger<OrderCompletedFailedIntegrationEventHandler> _logger;
public OrderCompletedFailedIntegrationEventHandler(
IMediator mediator,
ILogger<OrderCompletedFailedIntegrationEventHandler> logger)
{
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task Handle(OrderCompletedFailedIntegrationEvent @event)
{
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
{
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
var command = new CancelOrderCommand(@event.OrderId);
_logger.LogInformation(
"----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
command.GetGenericTypeName(),
nameof(command.OrderNumber),
command.OrderNumber,
command);
await _mediator.Send(command);
}
}
}

+ 35
- 0
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderCompletedSucceededIntegrationEventHandler.cs View File

@ -0,0 +1,35 @@
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.IntegrationEvents.EventHandling;
public class OrderCompletedSucceededIntegrationEventHandler :
IIntegrationEventHandler<OrderCompletedSucceededIntegrationEvent>
{
private readonly IMediator _mediator;
private readonly ILogger<OrderCompletedSucceededIntegrationEventHandler> _logger;
public OrderCompletedSucceededIntegrationEventHandler(
IMediator mediator,
ILogger<OrderCompletedSucceededIntegrationEventHandler> logger)
{
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task Handle(OrderCompletedSucceededIntegrationEvent @event)
{
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
{
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
var command = new SetCompletedOrderStatusCommand(@event.OrderId);
_logger.LogInformation(
"----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
command.GetGenericTypeName(),
nameof(command.OrderNumber),
command.OrderNumber,
command);
await _mediator.Send(command);
}
}
}

+ 8
- 0
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderCompletedFailedIntegrationEvent.cs View File

@ -0,0 +1,8 @@
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.IntegrationEvents.Events;
public record OrderCompletedFailedIntegrationEvent : IntegrationEvent
{
public int OrderId { get; }
public OrderCompletedFailedIntegrationEvent(int orderId) => OrderId = orderId;
}

+ 8
- 0
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderCompletedSucceededIntegrationEvent.cs View File

@ -0,0 +1,8 @@
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.IntegrationEvents.Events;
public record OrderCompletedSucceededIntegrationEvent : IntegrationEvent
{
public int OrderId { get; }
public OrderCompletedSucceededIntegrationEvent(int orderId) => OrderId = orderId;
}

+ 21
- 0
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStatusChangedToCompletedIntegrationEvent.cs View File

@ -0,0 +1,21 @@
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.IntegrationEvents.Events;
public record OrderStatusChangedToCompletedIntegrationEvent : IntegrationEvent
{
public int OrderId { get; }
public string OrderStatus { get; }
public string BuyerName { get; }
public IEnumerable<OrderStockItem> OrderStockItems { get; }
public OrderStatusChangedToCompletedIntegrationEvent(int orderId,
string orderStatus,
string buyerName,
IEnumerable<OrderStockItem> orderStockItems)
{
OrderId = orderId;
OrderStockItems = orderStockItems;
OrderStatus = orderStatus;
BuyerName = buyerName;
}
}

+ 25
- 0
src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs View File

@ -140,4 +140,29 @@ public class OrdersController : ControllerBase
return await _mediator.Send(createOrderDraftCommand); return await _mediator.Send(createOrderDraftCommand);
} }
[Route("completed")]
[HttpPut]
[ProducesResponseType((int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
public async Task<IActionResult> CompletedOrderAsync([FromBody] SetCompletedOrderStatusCommand setCompletedOrderStatusCommand, [FromHeader(Name = "x-requestid")] string requestId)
{
bool commandResult = false;
_logger.LogInformation(
"----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
setCompletedOrderStatusCommand.GetGenericTypeName(),
nameof(setCompletedOrderStatusCommand.OrderNumber),
setCompletedOrderStatusCommand.OrderNumber,
setCompletedOrderStatusCommand);
commandResult = await _mediator.Send(setCompletedOrderStatusCommand);
if (!commandResult)
{
return BadRequest();
}
return Ok();
}
} }

+ 2
- 0
src/Services/Ordering/Ordering.API/Startup.cs View File

@ -105,7 +105,9 @@ public class Startup
eventBus.Subscribe<OrderStockConfirmedIntegrationEvent, IIntegrationEventHandler<OrderStockConfirmedIntegrationEvent>>(); eventBus.Subscribe<OrderStockConfirmedIntegrationEvent, IIntegrationEventHandler<OrderStockConfirmedIntegrationEvent>>();
eventBus.Subscribe<OrderStockRejectedIntegrationEvent, IIntegrationEventHandler<OrderStockRejectedIntegrationEvent>>(); eventBus.Subscribe<OrderStockRejectedIntegrationEvent, IIntegrationEventHandler<OrderStockRejectedIntegrationEvent>>();
eventBus.Subscribe<OrderPaymentFailedIntegrationEvent, IIntegrationEventHandler<OrderPaymentFailedIntegrationEvent>>(); eventBus.Subscribe<OrderPaymentFailedIntegrationEvent, IIntegrationEventHandler<OrderPaymentFailedIntegrationEvent>>();
eventBus.Subscribe<OrderCompletedFailedIntegrationEvent, IIntegrationEventHandler<OrderCompletedFailedIntegrationEvent>>();
eventBus.Subscribe<OrderPaymentSucceededIntegrationEvent, IIntegrationEventHandler<OrderPaymentSucceededIntegrationEvent>>(); eventBus.Subscribe<OrderPaymentSucceededIntegrationEvent, IIntegrationEventHandler<OrderPaymentSucceededIntegrationEvent>>();
eventBus.Subscribe<OrderCompletedSucceededIntegrationEvent, IIntegrationEventHandler<OrderCompletedSucceededIntegrationEvent>>();
} }
protected virtual void ConfigureAuth(IApplicationBuilder app) protected virtual void ConfigureAuth(IApplicationBuilder app)


+ 10
- 0
src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs View File

@ -132,6 +132,16 @@ public class Order
_description = "The payment was performed at a simulated \"American Bank checking bank account ending on XX35071\""; _description = "The payment was performed at a simulated \"American Bank checking bank account ending on XX35071\"";
} }
} }
public void SetCompletedStatus()
{
if (_orderStatusId == OrderStatus.Paid.Id)
{
AddDomainEvent(new OrderStatusChangedToCompletedDomainEvent(Id, OrderItems));
_orderStatusId = OrderStatus.Complete.Id;
_description = "completed \"Yurt içi cargo ending on XX35071\"";
}
}
public void SetShippedStatus() public void SetShippedStatus()
{ {


+ 2
- 1
src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/OrderStatus.cs View File

@ -11,6 +11,7 @@ public class OrderStatus
public static OrderStatus Paid = new OrderStatus(4, nameof(Paid).ToLowerInvariant()); public static OrderStatus Paid = new OrderStatus(4, nameof(Paid).ToLowerInvariant());
public static OrderStatus Shipped = new OrderStatus(5, nameof(Shipped).ToLowerInvariant()); public static OrderStatus Shipped = new OrderStatus(5, nameof(Shipped).ToLowerInvariant());
public static OrderStatus Cancelled = new OrderStatus(6, nameof(Cancelled).ToLowerInvariant()); public static OrderStatus Cancelled = new OrderStatus(6, nameof(Cancelled).ToLowerInvariant());
public static OrderStatus Complete = new OrderStatus(7, nameof(Complete).ToLowerInvariant());
public OrderStatus(int id, string name) public OrderStatus(int id, string name)
: base(id, name) : base(id, name)
@ -18,7 +19,7 @@ public class OrderStatus
} }
public static IEnumerable<OrderStatus> List() => public static IEnumerable<OrderStatus> List() =>
new[] { Submitted, AwaitingValidation, StockConfirmed, Paid, Shipped, Cancelled };
new[] { Submitted, AwaitingValidation, StockConfirmed, Paid, Shipped, Cancelled, Complete };
public static OrderStatus FromName(string name) public static OrderStatus FromName(string name)
{ {


+ 18
- 0
src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToCompletedDomainEvent.cs View File

@ -0,0 +1,18 @@
namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.Events;
/// <summary>
/// Event used when the order is completed
/// </summary>
public class OrderStatusChangedToCompletedDomainEvent
: INotification
{
public int OrderId { get; }
public IEnumerable<OrderItem> OrderItems { get; }
public OrderStatusChangedToCompletedDomainEvent(int orderId,
IEnumerable<OrderItem> orderItems)
{
OrderId = orderId;
OrderItems = orderItems;
}
}

+ 28
- 0
src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/EventHandling/OrderStatusChangedToCompletedIntegrationEventHandler.cs View File

@ -0,0 +1,28 @@
namespace Microsoft.eShopOnContainers.Services.Ordering.SignalrHub.IntegrationEvents.EventHandling;
public class OrderStatusChangedToCompletedIntegrationEventHandler : IIntegrationEventHandler<OrderStatusChangedToCompletedIntegrationEvent>
{
private readonly IHubContext<NotificationsHub> _hubContext;
private readonly ILogger<OrderStatusChangedToCompletedIntegrationEventHandler> _logger;
public OrderStatusChangedToCompletedIntegrationEventHandler(
IHubContext<NotificationsHub> hubContext,
ILogger<OrderStatusChangedToCompletedIntegrationEventHandler> logger)
{
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task Handle(OrderStatusChangedToCompletedIntegrationEvent @event)
{
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}"))
{
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
await _hubContext.Clients
.Group(@event.BuyerName)
.SendAsync("UpdatedOrderState", new { OrderId = @event.OrderId, Status = @event.OrderStatus });
}
}
}

+ 16
- 0
src/Services/Ordering/Ordering.SignalrHub/IntegrationEvents/Events/OrderStatusChangedToCompletedIntegrationEvent.cs View File

@ -0,0 +1,16 @@
namespace Microsoft.eShopOnContainers.Services.Ordering.SignalrHub.IntegrationEvents.Events;
public record OrderStatusChangedToCompletedIntegrationEvent : IntegrationEvent
{
public int OrderId { get; }
public string OrderStatus { get; }
public string BuyerName { get; }
public OrderStatusChangedToCompletedIntegrationEvent(int orderId,
string orderStatus, string buyerName)
{
OrderId = orderId;
OrderStatus = orderStatus;
BuyerName = buyerName;
}
}

+ 1
- 0
src/Services/Ordering/Ordering.SignalrHub/Startup.cs View File

@ -138,6 +138,7 @@ public class Startup
eventBus.Subscribe<OrderStatusChangedToAwaitingValidationIntegrationEvent, OrderStatusChangedToAwaitingValidationIntegrationEventHandler>(); eventBus.Subscribe<OrderStatusChangedToAwaitingValidationIntegrationEvent, OrderStatusChangedToAwaitingValidationIntegrationEventHandler>();
eventBus.Subscribe<OrderStatusChangedToPaidIntegrationEvent, OrderStatusChangedToPaidIntegrationEventHandler>(); eventBus.Subscribe<OrderStatusChangedToPaidIntegrationEvent, OrderStatusChangedToPaidIntegrationEventHandler>();
eventBus.Subscribe<OrderStatusChangedToCompletedIntegrationEvent, OrderStatusChangedToCompletedIntegrationEventHandler>();
eventBus.Subscribe<OrderStatusChangedToStockConfirmedIntegrationEvent, OrderStatusChangedToStockConfirmedIntegrationEventHandler>(); eventBus.Subscribe<OrderStatusChangedToStockConfirmedIntegrationEvent, OrderStatusChangedToStockConfirmedIntegrationEventHandler>();
eventBus.Subscribe<OrderStatusChangedToShippedIntegrationEvent, OrderStatusChangedToShippedIntegrationEventHandler>(); eventBus.Subscribe<OrderStatusChangedToShippedIntegrationEvent, OrderStatusChangedToShippedIntegrationEventHandler>();
eventBus.Subscribe<OrderStatusChangedToCancelledIntegrationEvent, OrderStatusChangedToCancelledIntegrationEventHandler>(); eventBus.Subscribe<OrderStatusChangedToCancelledIntegrationEvent, OrderStatusChangedToCancelledIntegrationEventHandler>();


+ 16
- 0
src/Services/Ordering/Ordering.UnitTests/Application/OrdersWebApiTest.cs View File

@ -131,4 +131,20 @@ public class OrdersWebApiTest
//Assert //Assert
Assert.Equal((actionResult.Result as OkObjectResult).StatusCode, (int)System.Net.HttpStatusCode.OK); Assert.Equal((actionResult.Result as OkObjectResult).StatusCode, (int)System.Net.HttpStatusCode.OK);
} }
[Fact]
public async Task Completed_order_status_requestId_change()
{
//Arrange
_mediatorMock.Setup(x => x.Send(It.IsAny<SetCompletedOrderStatusCommand>(), default(CancellationToken)))
.Returns(Task.FromResult(true));
//Act
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object, _loggerMock.Object);
var actionResult = await orderController.CompletedOrderAsync(new SetCompletedOrderStatusCommand(22),Guid.NewGuid().ToString()) as OkResult;
//Assert
Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.OK);
}
} }

+ 7
- 0
src/Web/WebMVC/Controllers/OrderController.cs View File

@ -65,6 +65,13 @@ public class OrderController : Controller
var order = await _orderSvc.GetOrder(user, orderId); var order = await _orderSvc.GetOrder(user, orderId);
return View(order); return View(order);
} }
[HttpPost]
public async Task Completed(string orderId)
{
await _orderSvc.CompleteOrder(orderId);
}
public async Task<IActionResult> Index(Order item) public async Task<IActionResult> Index(Order item)
{ {


+ 8
- 0
src/Web/WebMVC/Infrastructure/API.cs View File

@ -45,6 +45,14 @@ public static class API
{ {
return $"{baseUri}/ship"; return $"{baseUri}/ship";
} }
public static string CompleteOrder(string baseUri)
{
return $"{baseUri}/completed";
///o/api/v1/orders/complated
}
} }
public static class Catalog public static class Catalog


+ 2
- 0
src/Web/WebMVC/Services/IOrderingService.cs View File

@ -10,4 +10,6 @@ public interface IOrderingService
Order MapUserInfoIntoOrder(ApplicationUser user, Order order); Order MapUserInfoIntoOrder(ApplicationUser user, Order order);
BasketDTO MapOrderToBasket(Order order); BasketDTO MapOrderToBasket(Order order);
void OverrideUserInfoIntoOrder(Order original, Order destination); void OverrideUserInfoIntoOrder(Order original, Order destination);
Task CompleteOrder(string orderId);
} }

+ 20
- 0
src/Web/WebMVC/Services/OrderingService.cs View File

@ -137,4 +137,24 @@ public class OrderingService : IOrderingService
RequestId = order.RequestId RequestId = order.RequestId
}; };
} }
async public Task CompleteOrder(string orderId)
{
var order = new OrderDTO()
{
OrderNumber = orderId
};
var uri = API.Order.CompleteOrder(_remoteServiceBaseUrl);
var orderContent = new StringContent(JsonSerializer.Serialize(order), System.Text.Encoding.UTF8, "application/json");
var response = await _httpClient.PutAsync(uri, orderContent);
if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
{
throw new Exception("Error completeng order, try later.");
}
response.EnsureSuccessStatusCode();
}
} }

+ 52
- 31
src/Web/WebMVC/Views/Order/Index.cshtml View File

@ -3,45 +3,66 @@
@model IEnumerable<Microsoft.eShopOnContainers.WebMVC.ViewModels.Order> @model IEnumerable<Microsoft.eShopOnContainers.WebMVC.ViewModels.Order>
@{ @{
ViewData["Title"] = "My Orders";
var headerList= new List<Header>() {
ViewData["Title"] = "My Orders";
var headerList = new List<Header>() {
new Header() { Controller = "Catalog", Text = "Back to catalog" }, new Header() { Controller = "Catalog", Text = "Back to catalog" },
new Header() { Text = " / " }, new Header() { Text = " / " },
new Header() { Controller = "OrderManagement", Text = "Orders Management" } }; new Header() { Controller = "OrderManagement", Text = "Orders Management" } };
} }
<div class="esh-orders"> <div class="esh-orders">
<partial name="_Header" model="headerList"/>
<partial name="_Header" model="headerList" />
<div class="container"> <div class="container">
<article class="esh-orders-titles row">
<section class="esh-orders-title col-2">Order number</section>
<section class="esh-orders-title col-4">Date</section>
<section class="esh-orders-title col-2">Total</section>
<section class="esh-orders-title col-2">Status</section>
<section class="esh-orders-title col-2"></section>
</article>
@if (Model != null && Model.Any())
{
foreach (var item in Model)
{
<article class="esh-orders-items row">
<section class="esh-orders-item col-2">@Html.DisplayFor(modelItem => item.OrderNumber)</section>
<section class="esh-orders-item col-4">@Html.DisplayFor(modelItem => item.Date)</section>
<section class="esh-orders-item col-2">$ @Html.DisplayFor(modelItem => item.Total)</section>
<section class="esh-orders-item col-2">@Html.DisplayFor(modelItem => item.Status)</section>
<section class="esh-orders-item col-1">
<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-1">
@if (item.Status.ToLower() == "submitted")
{
<a class="esh-orders-link" asp-controller="Order" asp-action="cancel" asp-route-orderId="@item.OrderNumber">Cancel</a>
}
</section>
</article>
}
}
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Order number</th>
<th scope="col">Date</th>
<th scope="col">Total</th>
<th scope="col">Status</th>
<th scope="col"></th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
@if (Model != null && Model.Any())
{
foreach (var item in Model)
{
<tr>
<th scope="row">1</th>
<td>@Html.DisplayFor(modelItem => item.OrderNumber)</td>
<td>$ @Html.DisplayFor(modelItem => item.Total)</td>
<td>@Html.DisplayFor(modelItem => item.Status)</td>
<td> <a class="esh-orders-link" asp-controller="Order" asp-action="Detail" asp-route-orderId="@item.OrderNumber">Detail</a></td>
<td>
@if (item.Status.ToLower() == "submitted")
{
<a class="esh-orders-link" asp-controller="Order" asp-action="cancel" asp-route-orderId="@item.OrderNumber">Cancel</a>
}
</td>
<td>
@if (item.Status.ToLower() == "paid")
{
<button id="completed" class="btn btn-primary" data-order-id="@item.OrderNumber"> Completed Event</button>
@*<a class="esh-orders-link" asp-controller="Order" asp-action="completed" asp-route-orderId="@item.OrderNumber">Completed</a>*@
}
</td>
</tr>
}
}
</tbody>
</table>
</div> </div>
</div> </div>


+ 27
- 7
src/Web/WebMVC/Views/Shared/_Layout.cshtml View File

@ -94,11 +94,12 @@
<script type="text/javascript"> <script type="text/javascript">
if ('@User.Identity.IsAuthenticated' === 'True') { if ('@User.Identity.IsAuthenticated' === 'True') {
var timerId; var timerId;
stablishConnection((conn) => registerNotificationHandlers(conn));
console.log("registerNotificationHandlers geldim.");
stablishConnection((conn) => registerNotificationHandlers(conn));
} }
function stablishConnection(cb) { function stablishConnection(cb) {
console.log("stablishConnection geldim.");
let connection = new signalR.HubConnectionBuilder() let connection = new signalR.HubConnectionBuilder()
.withUrl('@settings.Value.SignalrHubUrl/hub/notificationhub', { .withUrl('@settings.Value.SignalrHubUrl/hub/notificationhub', {
accessTokenFactory: () => { accessTokenFactory: () => {
@ -106,16 +107,20 @@
} }
}) })
.withAutomaticReconnect() .withAutomaticReconnect()
.build();
connection.start().then(function () {
.build();
connection.start().then(function() {
console.log('User Registered to Signalr Hub'); console.log('User Registered to Signalr Hub');
cb(connection); cb(connection);
});
});
} }
function registerNotificationHandlers(connection) { function registerNotificationHandlers(connection) {
console.log("UpdatedOrderState geldim.");
connection.on("UpdatedOrderState", (message) => { connection.on("UpdatedOrderState", (message) => {
console.log(message);
toastr.success('Updated to status: ' + message.status, 'Order Id: ' + message.orderId); toastr.success('Updated to status: ' + message.status, 'Order Id: ' + message.orderId);
if (window.location.pathname.split("/").pop() === 'Order') { if (window.location.pathname.split("/").pop() === 'Order') {
refreshOrderList(); refreshOrderList();
@ -129,10 +134,25 @@
function refreshOrderList() { function refreshOrderList() {
clearTimeout(timerId); clearTimeout(timerId);
timerId = setTimeout(function () {
timerId = setTimeout(function() {
window.location.reload(); window.location.reload();
}, 1000); }, 1000);
} }
$("#completed").click(function() {
var orderId = $(this).data("order-id");
var url = "@Url.Action("Completed","Order")";
console.log(url);
$.post(url,
{
orderId
}
//function(data, status) {
// console.log("Data: " + data + "\nStatus: " + status);
//});
});
</script> </script>
</body> </body>
</html> </html>

+ 5
- 1
src/Web/WebMVC/WebMVC.csproj View File

@ -34,7 +34,11 @@
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" /> <PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="16.8.0" /> <PackageReference Include="Microsoft.Build.Utilities.Core" Version="16.8.0" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="6.0.0" />
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.1.113" />
<PackageReference Include="Microsoft.TypeScript.MSBuild" Version="4.7.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.1.175" />
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" /> <PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.1.3" /> <PackageReference Include="Serilog.Enrichers.Environment" Version="2.1.3" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.1.1-dev-00216" /> <PackageReference Include="Serilog.Settings.Configuration" Version="3.1.1-dev-00216" />


+ 5
- 1
src/Web/WebStatus/WebStatus.csproj View File

@ -18,7 +18,11 @@
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="2.0.2-beta2" /> <PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="2.0.2-beta2" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="6.0.0" />
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.1.113" />
<PackageReference Include="Microsoft.TypeScript.MSBuild" Version="4.7.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.1.175" />
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" /> <PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.1.3" /> <PackageReference Include="Serilog.Enrichers.Environment" Version="2.1.3" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.1.1-dev-00216" /> <PackageReference Include="Serilog.Settings.Configuration" Version="3.1.1-dev-00216" />


+ 4
- 4
src/eShopOnContainers-ServicesAndWebApps.sln View File

@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29020.237
# Visual Studio Version 17
VisualStudioVersion = 17.2.32630.192
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{FEA0C318-FFED-4D39-8781-265718CA43DD}" Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{FEA0C318-FFED-4D39-8781-265718CA43DD}"
EndProject EndProject
@ -450,8 +450,8 @@ Global
{F16E3C6A-1C94-4EAB-BE91-099618060B68}.AppStore|x64.Build.0 = Release|Any CPU {F16E3C6A-1C94-4EAB-BE91-099618060B68}.AppStore|x64.Build.0 = Release|Any CPU
{F16E3C6A-1C94-4EAB-BE91-099618060B68}.AppStore|x86.ActiveCfg = Release|Any CPU {F16E3C6A-1C94-4EAB-BE91-099618060B68}.AppStore|x86.ActiveCfg = Release|Any CPU
{F16E3C6A-1C94-4EAB-BE91-099618060B68}.AppStore|x86.Build.0 = Release|Any CPU {F16E3C6A-1C94-4EAB-BE91-099618060B68}.AppStore|x86.Build.0 = Release|Any CPU
{F16E3C6A-1C94-4EAB-BE91-099618060B68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F16E3C6A-1C94-4EAB-BE91-099618060B68}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F16E3C6A-1C94-4EAB-BE91-099618060B68}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{F16E3C6A-1C94-4EAB-BE91-099618060B68}.Debug|Any CPU.Build.0 = Release|Any CPU
{F16E3C6A-1C94-4EAB-BE91-099618060B68}.Debug|ARM.ActiveCfg = Debug|Any CPU {F16E3C6A-1C94-4EAB-BE91-099618060B68}.Debug|ARM.ActiveCfg = Debug|Any CPU
{F16E3C6A-1C94-4EAB-BE91-099618060B68}.Debug|ARM.Build.0 = Debug|Any CPU {F16E3C6A-1C94-4EAB-BE91-099618060B68}.Debug|ARM.Build.0 = Debug|Any CPU
{F16E3C6A-1C94-4EAB-BE91-099618060B68}.Debug|iPhone.ActiveCfg = Debug|Any CPU {F16E3C6A-1C94-4EAB-BE91-099618060B68}.Debug|iPhone.ActiveCfg = Debug|Any CPU


Loading…
Cancel
Save