Browse Source

Merge branch 'order-processflow-redesign' of https://github.com/dotnet-architecture/eShopOnContainers into order-processflow-redesign

# Conflicts:
#	src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs
pull/223/head
Christian Arenas 7 years ago
parent
commit
94ee95f32b
53 changed files with 748 additions and 241 deletions
  1. +8
    -2
      src/Services/Basket/Basket.API/Controllers/BasketController.cs
  2. +0
    -9
      src/Services/Catalog/Catalog.API/IntegrationCommands/CommandHandlers/DecrementOrderStockCommandMsgHandler.cs
  3. +21
    -0
      src/Services/Ordering/Ordering.API/Application/Commands/ShipOrderCommand.cs
  4. +0
    -2
      src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStartedEvent/ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler.cs
  5. +0
    -1
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentFailedIntegrationEventHandler.cs
  6. +0
    -1
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSuccededIntegrationEventHandler.cs
  7. +0
    -2
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs
  8. +0
    -2
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs
  9. +48
    -16
      src/Services/Ordering/Ordering.API/Application/Sagas/OrderProcessSaga.cs
  10. +16
    -1
      src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs
  11. +2
    -0
      src/Services/Ordering/Ordering.API/Startup.cs
  12. +32
    -15
      src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs
  13. +1
    -2
      src/Services/Ordering/Ordering.Infrastructure/Repositories/OrderRepository.cs
  14. +13
    -4
      src/Services/Payment/Payment.API/IntegrationCommands/CommandHandlers/PayOrderCommandMsgHandler.cs
  15. +9
    -0
      src/Services/Payment/Payment.API/IntegrationEvents/IPaymentIntegrationEventService.cs
  16. +21
    -0
      src/Services/Payment/Payment.API/IntegrationEvents/PaymentIntegrationEventService.cs
  17. +0
    -2
      src/Services/Payment/Payment.API/Startup.cs
  18. +4
    -10
      src/Web/WebMVC/Controllers/OrderController.cs
  19. +43
    -0
      src/Web/WebMVC/Controllers/OrderManagementController.cs
  20. +5
    -0
      src/Web/WebMVC/Infrastructure/API.cs
  21. +11
    -0
      src/Web/WebMVC/Models/OrderDTO.cs
  22. +25
    -0
      src/Web/WebMVC/Models/OrderProcessAction.cs
  23. +1
    -1
      src/Web/WebMVC/Services/BasketService.cs
  24. +2
    -1
      src/Web/WebMVC/Services/IOrderingService.cs
  25. +27
    -3
      src/Web/WebMVC/Services/OrderingService.cs
  26. +25
    -1
      src/Web/WebMVC/ViewModels/Order.cs
  27. +2
    -1
      src/Web/WebMVC/Views/Cart/Index.cshtml
  28. +2
    -2
      src/Web/WebMVC/Views/Order/Create.cshtml
  29. +2
    -1
      src/Web/WebMVC/Views/Order/Detail.cshtml
  30. +10
    -2
      src/Web/WebMVC/Views/Order/Index.cshtml
  31. +43
    -0
      src/Web/WebMVC/Views/OrderManagement/Index.cshtml
  32. +6
    -2
      src/Web/WebMVC/Views/Shared/_Header.cshtml
  33. +14
    -0
      src/Web/WebMVC/wwwroot/css/shared/components/header/header.css
  34. +28
    -1
      src/Web/WebSPA/Client/modules/basket/basket.service.ts
  35. +7
    -6
      src/Web/WebSPA/Client/modules/orders/orders-new/orders-new.component.ts
  36. +3
    -2
      src/Web/WebSPA/Client/modules/orders/orders.module.ts
  37. +1
    -7
      src/Web/WebSPA/Client/modules/orders/orders.service.ts
  38. +16
    -0
      src/Web/WebSPA/Client/modules/shared/models/basketCheckout.model.ts
  39. +22
    -0
      src/Web/WebSPA/Client/modules/shared/services/data.service.ts
  40. +2
    -2
      src/Web/WebSPA/WebSPA.csproj
  41. +3
    -6
      test/Services/FunctionalTests/Services/Basket/BasketTestsStartup.cs
  42. +4
    -0
      test/Services/IntegrationTests/IntegrationTests.csproj
  43. +36
    -0
      test/Services/IntegrationTests/Services/Basket/BasketScenarioBase.cs
  44. +80
    -0
      test/Services/IntegrationTests/Services/Basket/BasketScenarios.cs
  45. +26
    -0
      test/Services/IntegrationTests/Services/Basket/BasketTestsStartup.cs
  46. +8
    -0
      test/Services/IntegrationTests/Services/Basket/appsettings.json
  47. +3
    -2
      test/Services/IntegrationTests/Services/Ordering/OrderingScenarioBase.cs
  48. +47
    -98
      test/Services/IntegrationTests/Services/Ordering/OrderingScenarios.cs
  49. +3
    -2
      test/Services/UnitTest/Basket/Application/BasketWebApiTest.cs
  50. +2
    -1
      test/Services/UnitTest/Ordering/Application/IdentifierCommandHandlerTest.cs
  51. +3
    -2
      test/Services/UnitTest/Ordering/Application/NewOrderCommandHandlerTest.cs
  52. +56
    -24
      test/Services/UnitTest/Ordering/Application/OrdersWebApiTest.cs
  53. +5
    -5
      test/Services/UnitTest/Ordering/Domain/OrderAggregateTest.cs

+ 8
- 2
src/Services/Basket/Basket.API/Controllers/BasketController.cs View File

@ -52,15 +52,21 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
} }
[Route("checkout")] [Route("checkout")]
[HttpPut]
public async Task<IActionResult> Checkout([FromBody]BasketCheckout value)
[HttpPost]
public async Task<IActionResult> Checkout([FromBody]BasketCheckout value, [FromHeader(Name = "x-requestid")] string requestId)
{ {
var userId = _identitySvc.GetUserIdentity(); var userId = _identitySvc.GetUserIdentity();
value.RequestId = (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty) ?
guid : value.RequestId;
var basket = await _repository.GetBasketAsync(userId); var basket = await _repository.GetBasketAsync(userId);
var eventMessage = new UserCheckoutAcceptedIntegrationEvent(userId, value.City, value.Street, var eventMessage = new UserCheckoutAcceptedIntegrationEvent(userId, value.City, value.Street,
value.State, value.Country, value.ZipCode, value.CardNumber, value.CardHolderName, value.State, value.Country, value.ZipCode, value.CardNumber, value.CardHolderName,
value.CardExpiration, value.CardSecurityNumber, value.CardTypeId, value.Buyer, value.RequestId, basket); value.CardExpiration, value.CardSecurityNumber, value.CardTypeId, value.Buyer, value.RequestId, basket);
// Once basket is checkout, sends an integration event to
// ordering.api to convert basket to order and proceeds with
// order creation process
_eventBus.Publish(eventMessage); _eventBus.Publish(eventMessage);
if (basket == null) if (basket == null)


+ 0
- 9
src/Services/Catalog/Catalog.API/IntegrationCommands/CommandHandlers/DecrementOrderStockCommandMsgHandler.cs View File

@ -23,20 +23,11 @@
foreach (var orderStockItem in @event.OrderStockItems) foreach (var orderStockItem in @event.OrderStockItems)
{ {
var catalogItem = _catalogContext.CatalogItems.Find(orderStockItem.ProductId); var catalogItem = _catalogContext.CatalogItems.Find(orderStockItem.ProductId);
CheckValidcatalogItemId(catalogItem);
catalogItem.RemoveStock(orderStockItem.Units); catalogItem.RemoveStock(orderStockItem.Units);
} }
await _catalogContext.SaveChangesAsync(); await _catalogContext.SaveChangesAsync();
} }
private void CheckValidcatalogItemId(CatalogItem catalogItem)
{
if (catalogItem is null)
{
throw new CatalogDomainException("Not able to process catalog event. Reason: no valid catalogItemId");
}
}
} }
} }

+ 21
- 0
src/Services/Ordering/Ordering.API/Application/Commands/ShipOrderCommand.cs View File

@ -0,0 +1,21 @@
using MediatR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading.Tasks;
namespace Ordering.API.Application.Commands
{
public class ShipOrderCommand : IAsyncRequest<bool>
{
[DataMember]
public int OrderNumber { get; private set; }
public ShipOrderCommand(int orderNumber)
{
OrderNumber = orderNumber;
}
}
}

+ 0
- 2
src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStartedEvent/ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler.cs View File

@ -26,8 +26,6 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderStartedEvent
{ {
var cardTypeId = (orderStartedEvent.CardTypeId != 0) ? orderStartedEvent.CardTypeId : 1; var cardTypeId = (orderStartedEvent.CardTypeId != 0) ? orderStartedEvent.CardTypeId : 1;
//var userGuid = _identityService.GetUserIdentity();
var buyer = await _buyerRepository.FindAsync(orderStartedEvent.UserId); var buyer = await _buyerRepository.FindAsync(orderStartedEvent.UserId);
bool buyerOriginallyExisted = (buyer == null) ? false : true; bool buyerOriginallyExisted = (buyer == null) ? false : true;


+ 0
- 1
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentFailedIntegrationEventHandler.cs View File

@ -3,7 +3,6 @@
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using Ordering.API.Application.IntegrationEvents.Events; using Ordering.API.Application.IntegrationEvents.Events;
using Ordering.Domain.Exceptions;
using System.Threading.Tasks; using System.Threading.Tasks;
public class OrderPaymentFailedIntegrationEventHandler : public class OrderPaymentFailedIntegrationEventHandler :


+ 0
- 1
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSuccededIntegrationEventHandler.cs View File

@ -3,7 +3,6 @@
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using Ordering.API.Application.IntegrationEvents.Events; using Ordering.API.Application.IntegrationEvents.Events;
using Ordering.Domain.Exceptions;
using System.Threading.Tasks; using System.Threading.Tasks;
public class OrderPaymentSuccededIntegrationEventHandler : public class OrderPaymentSuccededIntegrationEventHandler :


+ 0
- 2
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs View File

@ -4,8 +4,6 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Events; using Events;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using Ordering.API.Application.IntegrationCommands.Commands;
using Ordering.Domain.Exceptions;
public class OrderStockConfirmedIntegrationEventHandler : public class OrderStockConfirmedIntegrationEventHandler :
IIntegrationEventHandler<OrderStockConfirmedIntegrationEvent> IIntegrationEventHandler<OrderStockConfirmedIntegrationEvent>


+ 0
- 2
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs View File

@ -4,11 +4,9 @@ using Ordering.API.Application.IntegrationCommands.Commands;
namespace Ordering.API.Application.IntegrationEvents.EventHandling namespace Ordering.API.Application.IntegrationEvents.EventHandling
{ {
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Events; using Events;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using Domain.Exceptions;
public class OrderStockNotConfirmedIntegrationEventHandler : IIntegrationEventHandler<OrderStockNotConfirmedIntegrationEvent> public class OrderStockNotConfirmedIntegrationEventHandler : IIntegrationEventHandler<OrderStockNotConfirmedIntegrationEvent>
{ {


+ 48
- 16
src/Services/Ordering/Ordering.API/Application/Sagas/OrderProcessSaga.cs View File

@ -1,5 +1,4 @@
using Autofac.Features.OwnedInstances;
using MediatR;
using MediatR;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
@ -7,11 +6,9 @@ using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency; using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
using Ordering.API.Application.Commands; using Ordering.API.Application.Commands;
using Ordering.API.Application.IntegrationCommands.Commands; using Ordering.API.Application.IntegrationCommands.Commands;
using Ordering.API.Application.IntegrationEvents;
using Ordering.Domain.Exceptions; using Ordering.Domain.Exceptions;
using System;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ordering.API.Application.IntegrationEvents;
namespace Ordering.API.Application.Sagas namespace Ordering.API.Application.Sagas
{ {
@ -25,20 +22,14 @@ namespace Ordering.API.Application.Sagas
/// </summary> /// </summary>
public class OrderProcessSaga : OrderSaga, public class OrderProcessSaga : OrderSaga,
IIntegrationEventHandler<ConfirmGracePeriodCommandMsg>, IIntegrationEventHandler<ConfirmGracePeriodCommandMsg>,
IAsyncRequestHandler<CancelOrderCommand, bool>
IAsyncRequestHandler<CancelOrderCommand, bool>,
IAsyncRequestHandler<ShipOrderCommand, bool>
{ {
private readonly IMediator _mediator;
private readonly Func<Owned<OrderingContext>> _dbContextFactory;
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
public OrderProcessSaga( public OrderProcessSaga(
Func<Owned<OrderingContext>> dbContextFactory, OrderingContext orderingContext,
IMediator mediator, IOrderingIntegrationEventService orderingIntegrationEventService)
OrderingContext orderingContext)
: base(orderingContext) : base(orderingContext)
{ {
_dbContextFactory = dbContextFactory;
_mediator = mediator;
_orderingIntegrationEventService = orderingIntegrationEventService;
} }
/// <summary> /// <summary>
@ -73,12 +64,41 @@ namespace Ordering.API.Application.Sagas
/// <returns></returns> /// <returns></returns>
public async Task<bool> Handle(CancelOrderCommand command) public async Task<bool> Handle(CancelOrderCommand command)
{ {
var result = false;
var orderSaga = FindSagaById(command.OrderNumber); var orderSaga = FindSagaById(command.OrderNumber);
CheckValidSagaId(orderSaga); CheckValidSagaId(orderSaga);
// Set order status tu cancelled
// Not possible to cancel order when
// it has already been shipped
if (orderSaga.GetOrderStatusId() != OrderStatus.Cancelled.Id
|| orderSaga.GetOrderStatusId() != OrderStatus.Shipped.Id)
{
orderSaga.SetCancelStatus();
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);
return true;
// Only ship order when
// its status is paid
if (orderSaga.GetOrderStatusId() == OrderStatus.Paid.Id)
{
orderSaga.SetShippedStatus();
result = await SaveChangesAsync();
}
return result;
} }
private void CheckValidSagaId(Order orderSaga) private void CheckValidSagaId(Order orderSaga)
@ -103,6 +123,18 @@ namespace Ordering.API.Application.Sagas
} }
} }
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.
}
}
#endregion #endregion
} }
} }

+ 16
- 1
src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs View File

@ -28,7 +28,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
} }
[Route("cancel")] [Route("cancel")]
[HttpPost]
[HttpPut]
public async Task<IActionResult> CancelOrder([FromBody]CancelOrderCommand command, [FromHeader(Name = "x-requestid")] string requestId) public async Task<IActionResult> CancelOrder([FromBody]CancelOrderCommand command, [FromHeader(Name = "x-requestid")] string requestId)
{ {
bool commandResult = false; bool commandResult = false;
@ -42,6 +42,21 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
} }
[Route("ship")]
[HttpPut]
public async Task<IActionResult> ShipOrder([FromBody]ShipOrderCommand command, [FromHeader(Name = "x-requestid")] string requestId)
{
bool commandResult = false;
if (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty)
{
var requestShipOrder = new IdentifiedCommand<ShipOrderCommand, bool>(command, guid);
commandResult = await _mediator.SendAsync(requestShipOrder);
}
return commandResult ? (IActionResult)Ok() : (IActionResult)BadRequest();
}
[Route("{orderId:int}")] [Route("{orderId:int}")]
[HttpGet] [HttpGet]
public async Task<IActionResult> GetOrder(int orderId) public async Task<IActionResult> GetOrder(int orderId)


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

@ -3,8 +3,10 @@
using AspNetCore.Http; using AspNetCore.Http;
using Autofac; using Autofac;
using Autofac.Extensions.DependencyInjection; using Autofac.Extensions.DependencyInjection;
using global::Ordering.API.Application.IntegrationCommands.Commands;
using global::Ordering.API.Application.IntegrationEvents; using global::Ordering.API.Application.IntegrationEvents;
using global::Ordering.API.Application.IntegrationEvents.Events; using global::Ordering.API.Application.IntegrationEvents.Events;
using global::Ordering.API.Application.Sagas;
using global::Ordering.API.Infrastructure.Middlewares; using global::Ordering.API.Infrastructure.Middlewares;
using global::Ordering.API.Application.IntegrationCommands.Commands; using global::Ordering.API.Application.IntegrationCommands.Commands;
using global::Ordering.API.Application.Sagas; using global::Ordering.API.Application.Sagas;


+ 32
- 15
src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs View File

@ -168,28 +168,45 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
public void SetCancelledStatus() public void SetCancelledStatus()
{ {
switch(OrderStatus.From(_orderStatusId))
if (_orderStatusId == OrderStatus.Submited.Id)
{ {
//case OrderStatus.Submited:
// _description = "";
// break;
//case OrderStatus.StockConfirmed:
// _description = "";
// break;
//case OrderStatus.Paid:
// _description = "";
// break;
//case OrderStatus.Shipped:
// _description = "";
// break;
_description = "";
}
else if (_orderStatusId == OrderStatus.AwaitingValidation.Id)
{
_description = "";
}
else if (_orderStatusId == OrderStatus.StockConfirmed.Id)
{
_description = "";
}
else if (_orderStatusId == OrderStatus.Paid.Id)
{
_description = "";
}
else if(_orderStatusId == OrderStatus.Shipped.Id)
{
throw new OrderingDomainException("Not possible to change order status. Reason: cannot cancel order it is already shipped");
} }
_orderStatusId = OrderStatus.Cancelled.Id; _orderStatusId = OrderStatus.Cancelled.Id;
} }
public void SetCancelStatus()
{
if (_orderStatusId == OrderStatus.Shipped.Id)
{
throw new OrderingDomainException("Not possible to change order status. Reason: cannot cancel order it is already shipped");
}
_orderStatusId = OrderStatus.Cancelled.Id;
}
#endregion #endregion
public int GetOrderStatusId()
{
return _orderStatusId;
}
private void AddOrderStartedDomainEvent(string userId, int cardTypeId, string cardNumber, private void AddOrderStartedDomainEvent(string userId, int cardTypeId, string cardNumber,
string cardSecurityNumber, string cardHolderName, DateTime cardExpiration) string cardSecurityNumber, string cardHolderName, DateTime cardExpiration)
{ {


+ 1
- 2
src/Services/Ordering/Ordering.Infrastructure/Repositories/OrderRepository.cs View File

@ -33,8 +33,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositor
public async Task<Order> GetAsync(int orderId) public async Task<Order> GetAsync(int orderId)
{ {
return await _context.Orders.FindAsync(orderId)
?? throw new OrderingDomainException($"Not able to get the order. Reason: no valid orderId: {orderId}");
return await _context.Orders.FindAsync(orderId);
} }
public void Update(Order order) public void Update(Order order)


+ 13
- 4
src/Services/Payment/Payment.API/IntegrationCommands/CommandHandlers/PayOrderCommandMsgHandler.cs View File

@ -4,16 +4,25 @@
using Payment.API.IntegrationCommands.Commands; using Payment.API.IntegrationCommands.Commands;
using System.Threading.Tasks; using System.Threading.Tasks;
using System; using System;
using Payment.API.IntegrationEvents;
using Payment.API.IntegrationEvents.Events;
public class PayOrderCommandMsgHandler : IIntegrationEventHandler<PayOrderCommandMsg> public class PayOrderCommandMsgHandler : IIntegrationEventHandler<PayOrderCommandMsg>
{ {
public PayOrderCommandMsgHandler()
{
}
private readonly IPaymentIntegrationEventService _paymentIntegrationEventService;
public PayOrderCommandMsgHandler(IPaymentIntegrationEventService paymentIntegrationEventService)
=> _paymentIntegrationEventService = paymentIntegrationEventService;
public async Task Handle(PayOrderCommandMsg @event) public async Task Handle(PayOrderCommandMsg @event)
{ {
throw new NotImplementedException();
//PAYMENT SUCCESSED
var orderPaymentSuccededIntegrationEvent = new OrderPaymentSuccededIntegrationEvent(@event.OrderId);
_paymentIntegrationEventService.PublishThroughEventBus(orderPaymentSuccededIntegrationEvent);
//PAYMENT FAILED
//var orderPaymentFailedIntegrationEvent = new OrderPaymentFailedIntegrationEvent(@event.OrderId);
//_paymentIntegrationEventService.PublishThroughEventBus(orderPaymentFailedIntegrationEvent);
} }
} }
} }

+ 9
- 0
src/Services/Payment/Payment.API/IntegrationEvents/IPaymentIntegrationEventService.cs View File

@ -0,0 +1,9 @@
namespace Payment.API.IntegrationEvents
{
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
public interface IPaymentIntegrationEventService
{
void PublishThroughEventBus(IntegrationEvent evt);
}
}

+ 21
- 0
src/Services/Payment/Payment.API/IntegrationEvents/PaymentIntegrationEventService.cs View File

@ -0,0 +1,21 @@
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); ;
}
}
}

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

@ -67,8 +67,6 @@ namespace Payment.API
return new AutofacServiceProvider(container.Build()); return new AutofacServiceProvider(container.Build());
} }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{ {


+ 4
- 10
src/Web/WebMVC/Controllers/OrderController.cs View File

@ -59,18 +59,12 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
return View(model); return View(model);
} }
[HttpPut]
public async Task<IActionResult> Cancel(Order model)
public async Task<IActionResult> Cancel(string orderId)
{ {
if (ModelState.IsValid)
{
var user = _appUserParser.Parse(HttpContext.User);
await _orderSvc.CancelOrder(model);
await _orderSvc.CancelOrder(orderId);
//Redirect to historic list.
return RedirectToAction("Index");
}
return View(model);
//Redirect to historic list.
return RedirectToAction("Index");
} }
public async Task<IActionResult> Detail(string orderId) public async Task<IActionResult> Detail(string orderId)


+ 43
- 0
src/Web/WebMVC/Controllers/OrderManagementController.cs View File

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using WebMVC.Models;
using Microsoft.eShopOnContainers.WebMVC.Services;
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
using Microsoft.AspNetCore.Authorization;
namespace WebMVC.Controllers
{
[Authorize]
public class OrderManagementController : Controller
{
private IOrderingService _orderSvc;
private readonly IIdentityParser<ApplicationUser> _appUserParser;
public OrderManagementController(IOrderingService orderSvc, IIdentityParser<ApplicationUser> appUserParser)
{
_appUserParser = appUserParser;
_orderSvc = orderSvc;
}
public async Task<IActionResult> Index()
{
var user = _appUserParser.Parse(HttpContext.User);
var vm = await _orderSvc.GetMyOrders(user);
return View(vm);
}
[HttpPost]
public async Task<IActionResult> OrderProcess(string orderId, string actionCode)
{
if (OrderProcessAction.Ship.Code == actionCode)
{
await _orderSvc.ShipOrder(orderId);
}
return RedirectToAction("Index");
}
}
}

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

@ -46,6 +46,11 @@
{ {
return $"{baseUri}/cancel"; return $"{baseUri}/cancel";
} }
public static string ShipOrder(string baseUri)
{
return $"{baseUri}/ship";
}
} }
public static class Catalog public static class Catalog


+ 11
- 0
src/Web/WebMVC/Models/OrderDTO.cs View File

@ -0,0 +1,11 @@
using System;
using System.ComponentModel.DataAnnotations;
namespace WebMVC.Models
{
public class OrderDTO
{
[Required]
public string OrderNumber { get; set; }
}
}

+ 25
- 0
src/Web/WebMVC/Models/OrderProcessAction.cs View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace WebMVC.Models
{
public class OrderProcessAction
{
public string Code { get; private set; }
public string Name { get; private set; }
public static OrderProcessAction Ship = new OrderProcessAction(nameof(Ship).ToLowerInvariant(), "Ship");
protected OrderProcessAction()
{
}
public OrderProcessAction(string code, string name)
{
Code = code;
Name = name;
}
}
}

+ 1
- 1
src/Web/WebMVC/Services/BasketService.cs View File

@ -60,7 +60,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
var token = await GetUserTokenAsync(); var token = await GetUserTokenAsync();
var updateBasketUri = API.Basket.CheckoutBasket(_remoteServiceBaseUrl); var updateBasketUri = API.Basket.CheckoutBasket(_remoteServiceBaseUrl);
var response = await _apiClient.PutAsync(updateBasketUri, basket, token);
var response = await _apiClient.PostAsync(updateBasketUri, basket, token);
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
} }


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

@ -11,7 +11,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
{ {
Task<List<Order>> GetMyOrders(ApplicationUser user); Task<List<Order>> GetMyOrders(ApplicationUser user);
Task<Order> GetOrder(ApplicationUser user, string orderId); Task<Order> GetOrder(ApplicationUser user, string orderId);
Task CancelOrder(Order order);
Task CancelOrder(string orderId);
Task ShipOrder(string orderId);
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);


+ 27
- 3
src/Web/WebMVC/Services/OrderingService.cs View File

@ -66,13 +66,17 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
return order; return order;
} }
async public Task CancelOrder(Order order)
async public Task CancelOrder(string orderId)
{ {
var token = await GetUserTokenAsync(); var token = await GetUserTokenAsync();
var requestId = order.RequestId.ToString();
var order = new OrderDTO()
{
OrderNumber = orderId
};
var cancelOrderUri = API.Order.CancelOrder(_remoteServiceBaseUrl); var cancelOrderUri = API.Order.CancelOrder(_remoteServiceBaseUrl);
var response = await _apiClient.PutAsync(cancelOrderUri, order, token, requestId);
var response = await _apiClient.PutAsync(cancelOrderUri, order, token, Guid.NewGuid().ToString());
if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError) if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
{ {
@ -82,6 +86,26 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
} }
async public Task ShipOrder(string orderId)
{
var token = await GetUserTokenAsync();
var order = new OrderDTO()
{
OrderNumber = orderId
};
var shipOrderUri = API.Order.ShipOrder(_remoteServiceBaseUrl);
var response = await _apiClient.PutAsync(shipOrderUri, order, token, Guid.NewGuid().ToString());
if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
{
throw new Exception("Error in ship order process, try later.");
}
response.EnsureSuccessStatusCode();
}
public void OverrideUserInfoIntoOrder(Order original, Order destination) public void OverrideUserInfoIntoOrder(Order original, Order destination)
{ {
destination.City = original.City; destination.City = original.City;


+ 25
- 1
src/Web/WebMVC/ViewModels/Order.cs View File

@ -1,4 +1,5 @@
using Microsoft.eShopOnContainers.WebMVC.ViewModels.Annotations;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.eShopOnContainers.WebMVC.ViewModels.Annotations;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -6,6 +7,7 @@ using System.ComponentModel;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using WebMVC.Models;
namespace Microsoft.eShopOnContainers.WebMVC.ViewModels namespace Microsoft.eShopOnContainers.WebMVC.ViewModels
{ {
@ -51,6 +53,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewModels
public string Buyer { get; set; } public string Buyer { get; set; }
public List<SelectListItem> ActionCodeSelectList =>
GetActionCodesByCurrentState();
// See the property initializer syntax below. This // See the property initializer syntax below. This
// initializes the compiler generated field for this // initializes the compiler generated field for this
// auto-implemented property. // auto-implemented property.
@ -72,6 +77,25 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewModels
CardExpiration = new DateTime(int.Parse(year), int.Parse(month), 1); CardExpiration = new DateTime(int.Parse(year), int.Parse(month), 1);
} }
private List<SelectListItem> GetActionCodesByCurrentState()
{
var actions = new List<OrderProcessAction>();
switch (Status?.ToLower())
{
case "paid":
actions.Add(OrderProcessAction.Ship);
break;
}
var result = new List<SelectListItem>();
actions.ForEach(action =>
{
result.Add(new SelectListItem { Text = action.Name, Value = action.Code });
});
return result;
}
} }
public enum CardType public enum CardType


+ 2
- 1
src/Web/WebMVC/Views/Cart/Index.cshtml View File

@ -10,7 +10,8 @@
<form method="post" id="cartForm"> <form method="post" id="cartForm">
<div class="esh-basket"> <div class="esh-basket">
@Html.Partial("_Header", new Header(){ Controller = "Catalog", Text = "Back to catalog" })
@Html.Partial("_Header", new List<Header>() {
new Header() { Controller = "Catalog", Text = "Back to catalog" } })
@await Component.InvokeAsync("CartList", new { user = UserManager.Parse(User) }) @await Component.InvokeAsync("CartList", new { user = UserManager.Parse(User) })
</div> </div>


+ 2
- 2
src/Web/WebMVC/Views/Order/Create.cshtml View File

@ -6,8 +6,8 @@
ViewData["Title"] = "New Order"; ViewData["Title"] = "New Order";
} }
@Html.Partial("_Header", new Header() { Controller = "Cart", Text = "Back to cart" })
@Html.Partial("_Header", new List<Header>() {
new Header() { Controller = "Cart", Text = "Back to cart" } })
<div class="container"> <div class="container">
<form method="post" asp-controller="Order" asp-action="Checkout"> <form method="post" asp-controller="Order" asp-action="Checkout">
<section class="esh-orders_new-section"> <section class="esh-orders_new-section">


+ 2
- 1
src/Web/WebMVC/Views/Order/Detail.cshtml View File

@ -7,7 +7,8 @@
} }
<div class="esh-orders_detail"> <div class="esh-orders_detail">
@Html.Partial("_Header", new Header() { Controller = "Order", Text = "Back to list" })
@Html.Partial("_Header", new List<Header>() {
new Header() { Controller = "Catalog", Text = "Back to catalog" } })
<div class="container"> <div class="container">
<section class="esh-orders_detail-section"> <section class="esh-orders_detail-section">


+ 10
- 2
src/Web/WebMVC/Views/Order/Index.cshtml View File

@ -7,7 +7,9 @@
} }
<div class="esh-orders"> <div class="esh-orders">
@Html.Partial("_Header", new Header() { Controller = "Catalog", Text = "Back to catalog" })
@Html.Partial("_Header", new List<Header>() {
new Header() { Controller = "Catalog", Text = "Back to catalog" },
new Header() { Controller = "OrderManagement", Text = "Orders Management" } })
<div class="container"> <div class="container">
<article class="esh-orders-titles row"> <article class="esh-orders-titles row">
@ -25,9 +27,15 @@
<section class="esh-orders-item col-xs-4">@Html.DisplayFor(modelItem => item.Date)</section> <section class="esh-orders-item col-xs-4">@Html.DisplayFor(modelItem => item.Date)</section>
<section class="esh-orders-item col-xs-2">$ @Html.DisplayFor(modelItem => item.Total)</section> <section class="esh-orders-item col-xs-2">$ @Html.DisplayFor(modelItem => item.Total)</section>
<section class="esh-orders-item col-xs-2">@Html.DisplayFor(modelItem => item.Status)</section> <section class="esh-orders-item col-xs-2">@Html.DisplayFor(modelItem => item.Status)</section>
<section class="esh-orders-item col-xs-2">
<section class="esh-orders-item col-xs-1">
<a class="esh-orders-link" asp-controller="Order" asp-action="Detail" asp-route-orderId="@item.OrderNumber">Detail</a> <a class="esh-orders-link" asp-controller="Order" asp-action="Detail" asp-route-orderId="@item.OrderNumber">Detail</a>
</section> </section>
<section class="esh-orders-item col-xs-1">
@if ((item.Status.ToLower() != "shipped") && (item.Status.ToLower() != "cancelled"))
{
<a class="esh-orders-link" asp-controller="Order" asp-action="Cancel" asp-route-orderId="@item.OrderNumber">Cancel</a>
}
</section>
</article> </article>
} }
</div> </div>


+ 43
- 0
src/Web/WebMVC/Views/OrderManagement/Index.cshtml View File

@ -0,0 +1,43 @@
@using Microsoft.eShopOnContainers.WebMVC.ViewModels
@model IEnumerable<Microsoft.eShopOnContainers.WebMVC.ViewModels.Order>
@{
ViewData["Title"] = "My Orders";
}
<div class="esh-orders">
@Html.Partial("_Header", new List<Header>() {
new Header() { Controller = "Catalog", Text = "Back to catalog" } })
<div class="container">
<article class="esh-orders-titles row">
<section class="esh-orders-title col-xs-2">Order number</section>
<section class="esh-orders-title col-xs-4">Date</section>
<section class="esh-orders-title col-xs-2">Total</section>
<section class="esh-orders-title col-xs-2">Status</section>
<section class="esh-orders-title col-xs-2"></section>
</article>
@foreach (var item in Model)
{
<article class="esh-orders-items row">
<section class="esh-orders-item col-xs-2">@Html.DisplayFor(modelItem => item.OrderNumber)</section>
<section class="esh-orders-item col-xs-4">@Html.DisplayFor(modelItem => item.Date)</section>
<section class="esh-orders-item col-xs-2">$ @Html.DisplayFor(modelItem => item.Total)</section>
<section class="esh-orders-item col-xs-2">@Html.DisplayFor(modelItem => item.Status)</section>
<section class="esh-orders-item col-xs-2">
<form asp-action="OrderProcess" id="orderForm+@item.OrderNumber" method="post">
<input type="hidden" name="orderId" value="@item.OrderNumber" />
<select name="actionCode" asp-items="@item.ActionCodeSelectList"
disabled=@(item.Status != "paid")
onchange="document.getElementById('orderForm+@item.OrderNumber').submit()">
<option value="">&nbsp;&nbsp;Select Action</option>
<option value="">------------------</option>
</select>
</form>
</section>
</article>
}
</div>
</div>

+ 6
- 2
src/Web/WebMVC/Views/Shared/_Header.cshtml View File

@ -1,7 +1,11 @@
@model Microsoft.eShopOnContainers.WebMVC.ViewModels.Header
@model IEnumerable<Microsoft.eShopOnContainers.WebMVC.ViewModels.Header>
<div class="esh-header"> <div class="esh-header">
<div class="container"> <div class="container">
<a class="esh-header-back" asp-area="" asp-controller="@Model.Controller" asp-action="Index">@Model.Text</a>
@foreach (var header in @Model)
{
<a class="esh-header-title" asp-area="" asp-controller="@header.Controller" asp-action="Index">@header.Text</a>
}
</div> </div>
</div> </div>

+ 14
- 0
src/Web/WebMVC/wwwroot/css/shared/components/header/header.css View File

@ -3,6 +3,20 @@
height: 4rem; height: 4rem;
} }
.esh-header-title {
color: rgba(255, 255, 255, 0.5) !important;
line-height: 4rem;
text-transform: uppercase;
text-decoration: none;
transition: color 0.35s;
margin-right: 15px;
}
.esh-header-title:hover {
color: #FFFFFF !important;
transition: color 0.35s;
}
.esh-header-back { .esh-header-back {
color: rgba(255, 255, 255, 0.5) !important; color: rgba(255, 255, 255, 0.5) !important;
line-height: 4rem; line-height: 4rem;


+ 28
- 1
src/Web/WebSPA/Client/modules/basket/basket.service.ts View File

@ -4,7 +4,9 @@ import { Router } from '@angular/router';
import { DataService } from '../shared/services/data.service'; import { DataService } from '../shared/services/data.service';
import { SecurityService } from '../shared/services/security.service'; import { SecurityService } from '../shared/services/security.service';
import { IBasket } from '../shared/models/basket.model';
import { IBasket } from '../shared/models/basket.model';
import { IOrder } from '../shared/models/order.model';
import { IBasketCheckout } from '../shared/models/basketCheckout.model';
import { IBasketItem } from '../shared/models/basketItem.model'; import { IBasketItem } from '../shared/models/basketItem.model';
import { BasketWrapperService } from '../shared/services/basket.wrapper.service'; import { BasketWrapperService } from '../shared/services/basket.wrapper.service';
import { ConfigurationService } from '../shared/services/configuration.service'; import { ConfigurationService } from '../shared/services/configuration.service';
@ -67,6 +69,12 @@ export class BasketService {
}); });
} }
setBasketCheckout(basketCheckout): Observable<boolean> {
return this.service.postWithId(this.basketUrl + '/checkout', basketCheckout).map((response: Response) => {
return true;
});
}
getBasket(): Observable<IBasket> { getBasket(): Observable<IBasket> {
return this.service.get(this.basketUrl + '/' + this.basket.buyerId).map((response: Response) => { return this.service.get(this.basketUrl + '/' + this.basket.buyerId).map((response: Response) => {
if (response.status === 204) { if (response.status === 204) {
@ -83,6 +91,25 @@ export class BasketService {
this.basketDropedSource.next(); this.basketDropedSource.next();
} }
mapBasketInfoCheckout(order: IOrder): IBasketCheckout {
let basketCheckout = <IBasketCheckout>{};
basketCheckout.street = order.street
basketCheckout.city = order.city;
basketCheckout.country = order.country;
basketCheckout.state = order.state;
basketCheckout.zipcode = order.zipcode;
basketCheckout.cardexpiration = order.cardexpiration;
basketCheckout.cardnumber = order.cardnumber;
basketCheckout.cardsecuritynumber = order.cardsecuritynumber;
basketCheckout.cardtypeid = order.cardtypeid;
basketCheckout.cardholdername = order.cardholdername;
basketCheckout.total = 0;
basketCheckout.expiration = order.expiration;
return basketCheckout;
}
private loadData() { private loadData() {
this.getBasket().subscribe(basket => { this.getBasket().subscribe(basket => {
if (basket != null) if (basket != null)


+ 7
- 6
src/Web/WebSPA/Client/modules/orders/orders-new/orders-new.component.ts View File

@ -1,6 +1,7 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { OrdersService } from '../orders.service';
import { OrdersService } from '../orders.service';
import { BasketService } from '../../basket/basket.service';
import { IOrder } from '../../shared/models/order.model'; import { IOrder } from '../../shared/models/order.model';
import { BasketWrapperService } from '../../shared/services/basket.wrapper.service'; import { BasketWrapperService } from '../../shared/services/basket.wrapper.service';
@ -18,9 +19,9 @@ export class OrdersNewComponent implements OnInit {
errorReceived: boolean; errorReceived: boolean;
order: IOrder; order: IOrder;
constructor(private service: OrdersService, fb: FormBuilder, private router: Router) {
constructor(private orderService: OrdersService, private basketService: BasketService, fb: FormBuilder, private router: Router) {
// Obtain user profile information // Obtain user profile information
this.order = service.mapBasketAndIdentityInfoNewOrder();
this.order = orderService.mapOrderAndIdentityInfoNewOrder();
this.newOrderForm = fb.group({ this.newOrderForm = fb.group({
'street': [this.order.street, Validators.required], 'street': [this.order.street, Validators.required],
'city': [this.order.city, Validators.required], 'city': [this.order.city, Validators.required],
@ -36,7 +37,7 @@ export class OrdersNewComponent implements OnInit {
ngOnInit() { ngOnInit() {
} }
submitForm(value: any) {
submitForm(value: any) {
this.order.street = this.newOrderForm.controls['street'].value; this.order.street = this.newOrderForm.controls['street'].value;
this.order.city = this.newOrderForm.controls['city'].value; this.order.city = this.newOrderForm.controls['city'].value;
this.order.state = this.newOrderForm.controls['state'].value; this.order.state = this.newOrderForm.controls['state'].value;
@ -46,8 +47,8 @@ export class OrdersNewComponent implements OnInit {
this.order.cardholdername = this.newOrderForm.controls['cardholdername'].value; this.order.cardholdername = this.newOrderForm.controls['cardholdername'].value;
this.order.cardexpiration = new Date(20 + this.newOrderForm.controls['expirationdate'].value.split('/')[1], this.newOrderForm.controls['expirationdate'].value.split('/')[0]); this.order.cardexpiration = new Date(20 + this.newOrderForm.controls['expirationdate'].value.split('/')[1], this.newOrderForm.controls['expirationdate'].value.split('/')[0]);
this.order.cardsecuritynumber = this.newOrderForm.controls['securitycode'].value; this.order.cardsecuritynumber = this.newOrderForm.controls['securitycode'].value;
this.service.postOrder(this.order)
let basketCheckout = this.basketService.mapBasketInfoCheckout(this.order);
this.basketService.setBasketCheckout(basketCheckout)
.catch((errMessage) => { .catch((errMessage) => {
this.errorReceived = true; this.errorReceived = true;
this.isOrderProcessing = false; this.isOrderProcessing = false;


+ 3
- 2
src/Web/WebSPA/Client/modules/orders/orders.module.ts View File

@ -5,12 +5,13 @@ import { SharedModule } from '../shared/shared.module';
import { OrdersComponent } from './orders.component'; import { OrdersComponent } from './orders.component';
import { OrdersDetailComponent } from './orders-detail/orders-detail.component'; import { OrdersDetailComponent } from './orders-detail/orders-detail.component';
import { OrdersNewComponent } from './orders-new/orders-new.component'; import { OrdersNewComponent } from './orders-new/orders-new.component';
import { OrdersService } from './orders.service';
import { OrdersService } from './orders.service';
import { BasketService } from '../basket/basket.service';
import { Header } from '../shared/components/header/header'; import { Header } from '../shared/components/header/header';
@NgModule({ @NgModule({
imports: [BrowserModule, SharedModule], imports: [BrowserModule, SharedModule],
declarations: [OrdersComponent, OrdersDetailComponent, OrdersNewComponent], declarations: [OrdersComponent, OrdersDetailComponent, OrdersNewComponent],
providers: [OrdersService]
providers: [OrdersService, BasketService]
}) })
export class OrdersModule { } export class OrdersModule { }

+ 1
- 7
src/Web/WebSPA/Client/modules/orders/orders.service.ts View File

@ -44,13 +44,7 @@ export class OrdersService {
}); });
} }
postOrder(item): Observable<boolean> {
return this.service.postWithId(this.ordersUrl + '/api/v1/orders/new', item).map((response: Response) => {
return true;
});
}
mapBasketAndIdentityInfoNewOrder(): IOrder {
mapOrderAndIdentityInfoNewOrder(): IOrder {
let order = <IOrder>{}; let order = <IOrder>{};
let basket = this.basketService.basket; let basket = this.basketService.basket;
let identityInfo = this.identityService.UserData; let identityInfo = this.identityService.UserData;


+ 16
- 0
src/Web/WebSPA/Client/modules/shared/models/basketCheckout.model.ts View File

@ -0,0 +1,16 @@
export interface IBasketCheckout {
city: number;
street: string;
state: string;
country: number;
zipcode: string;
cardnumber: string;
cardexpiration: Date;
expiration: string;
cardsecuritynumber: string;
cardholdername: string;
cardtypeid: number;
buyer: string;
ordernumber: string;
total: number;
}

+ 22
- 0
src/Web/WebSPA/Client/modules/shared/services/data.service.ts View File

@ -39,6 +39,10 @@ export class DataService {
return this.doPost(url, data, false, params); return this.doPost(url, data, false, params);
} }
putWithId(url: string, data: any, params?: any): Observable<Response> {
return this.doPut(url, data, true, params);
}
private doPost(url: string, data: any, needId: boolean, params?: any): Observable<Response> { private doPost(url: string, data: any, needId: boolean, params?: any): Observable<Response> {
let options: RequestOptionsArgs = {}; let options: RequestOptionsArgs = {};
@ -57,6 +61,24 @@ export class DataService {
}).catch(this.handleError); }).catch(this.handleError);
} }
private doPut(url: string, data: any, needId: boolean, params?: any): Observable<Response> {
let options: RequestOptionsArgs = {};
options.headers = new Headers();
if (this.securityService) {
options.headers.append('Authorization', 'Bearer ' + this.securityService.GetToken());
}
if (needId) {
let guid = Guid.newGuid();
options.headers.append('x-requestid', guid);
}
return this.http.put(url, data, options).map(
(res: Response) => {
return res;
}).catch(this.handleError);
}
delete(url: string, params?: any) { delete(url: string, params?: any) {
let options: RequestOptionsArgs = {}; let options: RequestOptionsArgs = {};


+ 2
- 2
src/Web/WebSPA/WebSPA.csproj View File

@ -72,12 +72,12 @@
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="1.0.0-msbuild3-final" /> <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="1.0.0-msbuild3-final" />
</ItemGroup> </ItemGroup>
<!-- workaround for https://github.com/aspnet/websdk/issues/114 -->
<!-- workaround for https://github.com/aspnet/websdk/issues/114 --><!--
<Target Name="AddGeneratedContentItems" BeforeTargets="AssignTargetPaths" DependsOnTargets="PrepareForPublish"> <Target Name="AddGeneratedContentItems" BeforeTargets="AssignTargetPaths" DependsOnTargets="PrepareForPublish">
<ItemGroup> <ItemGroup>
<Content Include="wwwroot/**" CopyToPublishDirectory="PreserveNewest" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder);@(Content)" /> <Content Include="wwwroot/**" CopyToPublishDirectory="PreserveNewest" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder);@(Content)" />
</ItemGroup> </ItemGroup>
</Target>
</Target>-->
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" /> <ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />


+ 3
- 6
test/Services/FunctionalTests/Services/Basket/BasketTestsStartup.cs View File

@ -1,10 +1,7 @@
using Microsoft.eShopOnContainers.Services.Basket.API;
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Hosting;
using FunctionalTests.Middleware;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using FunctionalTests.Middleware;
using Microsoft.AspNetCore.Hosting;
using Microsoft.eShopOnContainers.Services.Basket.API;
namespace FunctionalTests.Services.Basket namespace FunctionalTests.Services.Basket
{ {


+ 4
- 0
test/Services/IntegrationTests/IntegrationTests.csproj View File

@ -18,6 +18,9 @@
<ItemGroup> <ItemGroup>
<!--<Content Include="settings.json;web.config">--> <!--<Content Include="settings.json;web.config">-->
<Content Include="Services\Basket\appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Services\Catalog\settings.json"> <Content Include="Services\Catalog\settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
@ -30,6 +33,7 @@
<ProjectReference Include="..\..\..\src\Services\Basket\Basket.API\Basket.API.csproj" /> <ProjectReference Include="..\..\..\src\Services\Basket\Basket.API\Basket.API.csproj" />
<ProjectReference Include="..\..\..\src\Services\Catalog\Catalog.API\Catalog.API.csproj" /> <ProjectReference Include="..\..\..\src\Services\Catalog\Catalog.API\Catalog.API.csproj" />
<ProjectReference Include="..\..\..\src\Services\Ordering\Ordering.API\Ordering.API.csproj" /> <ProjectReference Include="..\..\..\src\Services\Ordering\Ordering.API\Ordering.API.csproj" />
<ProjectReference Include="..\..\..\src\Web\WebMVC\WebMVC.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>


+ 36
- 0
test/Services/IntegrationTests/Services/Basket/BasketScenarioBase.cs View File

@ -0,0 +1,36 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using Microsoft.eShopOnContainers.Services.Basket.API;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace IntegrationTests.Services.Basket
{
public class BasketScenarioBase
{
public TestServer CreateServer()
{
var webHostBuilder = new WebHostBuilder();
webHostBuilder.UseContentRoot(Directory.GetCurrentDirectory() + "\\Services\\basket");
webHostBuilder.UseStartup<BasketTestsStartup>();
return new TestServer(webHostBuilder);
}
public static class Get
{
public static string GetBasket(int id)
{
return $"api/v1/basket/{id}";
}
}
public static class Post
{
public static string Basket = "api/v1/basket";
public static string CheckoutOrder = "api/v1/basket/checkout";
}
}
}

+ 80
- 0
test/Services/IntegrationTests/Services/Basket/BasketScenarios.cs View File

@ -0,0 +1,80 @@
using Microsoft.eShopOnContainers.Services.Basket.API.Model;
using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using WebMVC.Models;
using Xunit;
namespace IntegrationTests.Services.Basket
{
public class BasketScenarios
: BasketScenarioBase
{
[Fact]
public async Task Post_basket_and_response_ok_status_code()
{
using (var server = CreateServer())
{
var content = new StringContent(BuildBasket(), UTF8Encoding.UTF8, "application/json");
var response = await server.CreateClient()
.PostAsync(Post.Basket, content);
response.EnsureSuccessStatusCode();
}
}
[Fact]
public async Task Get_basket_and_response_ok_status_code()
{
using (var server = CreateServer())
{
var response = await server.CreateClient()
.GetAsync(Get.GetBasket(1));
response.EnsureSuccessStatusCode();
}
}
[Fact]
public async Task Send_Checkout_basket_and_response_ok_status_code()
{
using (var server = CreateServer())
{
var content = new StringContent(BuildCheckout(), UTF8Encoding.UTF8, "application/json");
var response = await server.CreateClient()
.PostAsync(Post.CheckoutOrder, content);
response.EnsureSuccessStatusCode();
}
}
string BuildBasket()
{
var order = new CustomerBasket("1");
return JsonConvert.SerializeObject(order);
}
string BuildCheckout()
{
var checkoutBasket = new BasketDTO()
{
City = "city",
Street = "street",
State = "state",
Country = "coutry",
ZipCode = "zipcode",
CardNumber = "CardNumber",
CardHolderName = "CardHolderName",
CardExpiration = DateTime.UtcNow,
CardSecurityNumber = "1234",
CardTypeId = 1,
Buyer = "Buyer",
RequestId = Guid.NewGuid()
};
return JsonConvert.SerializeObject(checkoutBasket);
}
}
}

+ 26
- 0
test/Services/IntegrationTests/Services/Basket/BasketTestsStartup.cs View File

@ -0,0 +1,26 @@
using IntegrationTests.Middleware;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.eShopOnContainers.Services.Basket.API;
namespace IntegrationTests.Services.Basket
{
public class BasketTestsStartup : Startup
{
public BasketTestsStartup(IHostingEnvironment env) : base(env)
{
}
protected override void ConfigureAuth(IApplicationBuilder app)
{
if (Configuration["isTest"] == bool.TrueString.ToLowerInvariant())
{
app.UseMiddleware<AutoAuthorizeMiddleware>();
}
else
{
base.ConfigureAuth(app);
}
}
}
}

+ 8
- 0
test/Services/IntegrationTests/Services/Basket/appsettings.json View File

@ -0,0 +1,8 @@
{
"ConnectionString": "127.0.0.1",
"IdentityUrl": "http://localhost:5105",
"isTest": "true",
"EventBusConnection": "localhost"
}

+ 3
- 2
test/Services/IntegrationTests/Services/Ordering/OrderingScenarioBase.cs View File

@ -26,9 +26,10 @@
} }
} }
public static class Post
public static class Put
{ {
public static string AddNewOrder = "api/v1/orders/new";
public static string CancelOrder = "api/v1/orders/cancel";
public static string ShipOrder = "api/v1/orders/ship";
} }
} }
} }

+ 47
- 98
test/Services/IntegrationTests/Services/Ordering/OrderingScenarios.cs View File

@ -1,112 +1,61 @@
namespace IntegrationTests.Services.Ordering namespace IntegrationTests.Services.Ordering
{ {
using IntegrationTests.Services.Extensions; using IntegrationTests.Services.Extensions;
using Microsoft.AspNetCore.TestHost;
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
using Newtonsoft.Json; using Newtonsoft.Json;
using System;
using System.Net.Http; using System.Net.Http;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using WebMVC.Models;
using Xunit; using Xunit;
using System.Collections;
using static Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands.CreateOrderCommand;
using System.Collections.Generic;
public class OrderingScenarios public class OrderingScenarios
: OrderingScenarioBase : OrderingScenarioBase
{ {
// [Fact]
// public async Task Get_get_all_stored_orders_and_response_ok_status_code()
// {
// using (var server = CreateServer())
// {
// var response = await server.CreateClient()
// .GetAsync(Get.Orders);
// response.EnsureSuccessStatusCode();
// }
// }
// [Fact]
// public async Task AddNewOrder_add_new_order_and_response_ok_status_code()
// {
// using (var server = CreateServer())
// {
// var content = new StringContent(BuildOrder(), UTF8Encoding.UTF8, "application/json");
// var response = await server.CreateIdempotentClient()
// .PostAsync(Post.AddNewOrder, content);
// response.EnsureSuccessStatusCode();
// }
// }
// [Fact]
// public async Task AddNewOrder_response_bad_request_if_card_expiration_is_invalid()
// {
// using (var server = CreateServer())
// {
// var content = new StringContent(BuildOrderWithInvalidExperationTime(), UTF8Encoding.UTF8, "application/json");
// var response = await server.CreateIdempotentClient()
// .PostAsync(Post.AddNewOrder, content);
// Assert.True(response.StatusCode == System.Net.HttpStatusCode.BadRequest);
// }
// }
// //public CreateOrderCommand(string city, string street, string state, string country, string zipcode,
// // string cardNumber, string cardHolderName, DateTime cardExpiration,
// // string cardSecurityNumber, int cardTypeId, int paymentId, int buyerId) : this()
// string BuildOrder()
// {
// List<OrderItemDTO> orderItemsList = new List<OrderItemDTO>();
// orderItemsList.Add(new OrderItemDTO()
// {
// ProductId = 1,
// Discount = 10M,
// UnitPrice = 10,
// Units = 1,
// ProductName = "Some name"
// }
// );
// var order = new CreateOrderCommand(
// orderItemsList,
// cardExpiration: DateTime.UtcNow.AddYears(1),
// cardNumber: "5145-555-5555",
// cardHolderName: "Jhon Senna",
// cardSecurityNumber: "232",
// cardTypeId: 1,
// city: "Redmon",
// country: "USA",
// state: "WA",
// street: "One way",
// zipcode: "zipcode"
// );
// return JsonConvert.SerializeObject(order);
// }
// string BuildOrderWithInvalidExperationTime()
// {
// var order = new CreateOrderCommand(
// null,
// cardExpiration: DateTime.UtcNow.AddYears(-1),
// cardNumber: "5145-555-5555",
// cardHolderName: "Jhon Senna",
// cardSecurityNumber: "232",
// cardTypeId: 1,
// city: "Redmon",
// country: "USA",
// state: "WA",
// street: "One way",
// zipcode: "zipcode",
// buyerId: 1,
// paymentId:1
// );
// return JsonConvert.SerializeObject(order);
// }
[Fact]
public async Task Get_get_all_stored_orders_and_response_ok_status_code()
{
using (var server = CreateServer())
{
var response = await server.CreateClient()
.GetAsync(Get.Orders);
response.EnsureSuccessStatusCode();
}
}
[Fact]
public async Task Cancel_order_and_response_ok_status_code()
{
using (var server = CreateServer())
{
var content = new StringContent(BuildOrder(), UTF8Encoding.UTF8, "application/json");
var response = await server.CreateIdempotentClient()
.PutAsync(Put.CancelOrder, content);
response.EnsureSuccessStatusCode();
}
}
[Fact]
public async Task Ship_order_and_response_bad_status_code()
{
using (var server = CreateServer())
{
var content = new StringContent(BuildOrder(), UTF8Encoding.UTF8, "application/json");
var response = await server.CreateIdempotentClient()
.PutAsync(Put.ShipOrder, content);
response.EnsureSuccessStatusCode();
}
}
string BuildOrder()
{
var order = new OrderDTO()
{
OrderNumber = "1"
};
return JsonConvert.SerializeObject(order);
}
} }
} }

+ 3
- 2
test/Services/UnitTest/Basket/Application/BasketWebApiTest.cs View File

@ -5,6 +5,7 @@ using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
using Microsoft.eShopOnContainers.Services.Basket.API.Controllers; using Microsoft.eShopOnContainers.Services.Basket.API.Controllers;
using Microsoft.eShopOnContainers.Services.Basket.API.Model; using Microsoft.eShopOnContainers.Services.Basket.API.Model;
using Moq; using Moq;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Xunit; using Xunit;
@ -80,7 +81,7 @@ namespace UnitTest.Basket.Application
var basketController = new BasketController( var basketController = new BasketController(
_basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object); _basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object);
var result = await basketController.Checkout(new BasketCheckout()) as BadRequestResult;
var result = await basketController.Checkout(new BasketCheckout(), Guid.NewGuid().ToString()) as BadRequestResult;
Assert.NotNull(result); Assert.NotNull(result);
} }
@ -96,7 +97,7 @@ namespace UnitTest.Basket.Application
var basketController = new BasketController( var basketController = new BasketController(
_basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object); _basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object);
var result = await basketController.Checkout(new BasketCheckout()) as AcceptedResult;
var result = await basketController.Checkout(new BasketCheckout(), Guid.NewGuid().ToString()) as AcceptedResult;
_serviceBusMock.Verify(mock => mock.Publish(It.IsAny<UserCheckoutAcceptedIntegrationEvent>()), Times.Once); _serviceBusMock.Verify(mock => mock.Publish(It.IsAny<UserCheckoutAcceptedIntegrationEvent>()), Times.Once);
Assert.NotNull(result); Assert.NotNull(result);
} }


+ 2
- 1
test/Services/UnitTest/Ordering/Application/IdentifierCommandHandlerTest.cs View File

@ -4,6 +4,7 @@ using System.Text;
namespace UnitTest.Ordering.Application namespace UnitTest.Ordering.Application
{ {
using global::Ordering.API.Application.Models;
using MediatR; using MediatR;
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency; using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
@ -70,7 +71,7 @@ namespace UnitTest.Ordering.Application
private CreateOrderCommand FakeOrderRequest(Dictionary<string, object> args = null) private CreateOrderCommand FakeOrderRequest(Dictionary<string, object> args = null)
{ {
return new CreateOrderCommand( return new CreateOrderCommand(
null,
new List<BasketItem>(),
userId: args != null && args.ContainsKey("userId") ? (string)args["userId"] : null, userId: args != null && args.ContainsKey("userId") ? (string)args["userId"] : null,
city: args != null && args.ContainsKey("city") ? (string)args["city"] : null, city: args != null && args.ContainsKey("city") ? (string)args["city"] : null,
street: args != null && args.ContainsKey("street") ? (string)args["street"] : null, street: args != null && args.ContainsKey("street") ? (string)args["street"] : null,


+ 3
- 2
test/Services/UnitTest/Ordering/Application/NewOrderCommandHandlerTest.cs View File

@ -10,6 +10,7 @@ using System.Threading.Tasks;
namespace UnitTest.Ordering.Application namespace UnitTest.Ordering.Application
{ {
using global::Ordering.API.Application.Models;
using MediatR; using MediatR;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
@ -66,13 +67,13 @@ namespace UnitTest.Ordering.Application
private Order FakeOrder() private Order FakeOrder()
{ {
return new Order(new Guid().ToString(), new Address("street", "city", "state", "country", "zipcode"), 1, "12", "111", "fakeName", DateTime.Now.AddYears(1));
return new Order("1", new Address("street", "city", "state", "country", "zipcode"), 1, "12", "111", "fakeName", DateTime.Now.AddYears(1));
} }
private CreateOrderCommand FakeOrderRequestWithBuyer(Dictionary<string, object> args = null) private CreateOrderCommand FakeOrderRequestWithBuyer(Dictionary<string, object> args = null)
{ {
return new CreateOrderCommand( return new CreateOrderCommand(
null,
new List<BasketItem>(),
userId: args != null && args.ContainsKey("userId") ? (string)args["userId"] : null, userId: args != null && args.ContainsKey("userId") ? (string)args["userId"] : null,
city: args != null && args.ContainsKey("city") ? (string)args["city"] : null, city: args != null && args.ContainsKey("city") ? (string)args["city"] : null,
street: args != null && args.ContainsKey("street") ? (string)args["street"] : null, street: args != null && args.ContainsKey("street") ? (string)args["street"] : null,


+ 56
- 24
test/Services/UnitTest/Ordering/Application/OrdersWebApiTest.cs View File

@ -5,6 +5,7 @@ using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries;
using Microsoft.eShopOnContainers.Services.Ordering.API.Controllers; using Microsoft.eShopOnContainers.Services.Ordering.API.Controllers;
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services; using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
using Moq; using Moq;
using Ordering.API.Application.Commands;
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -25,36 +26,67 @@ namespace UnitTest.Ordering.Application
_identityServiceMock = new Mock<IIdentityService>(); _identityServiceMock = new Mock<IIdentityService>();
} }
//[Fact]
//public async Task Create_order_with_requestId_success()
//{
// //Arrange
// _mediatorMock.Setup(x => x.SendAsync(It.IsAny<IdentifiedCommand<CreateOrderCommand, bool>>()))
// .Returns(Task.FromResult(true));
[Fact]
public async Task Create_order_with_requestId_success()
{
//Arrange
_mediatorMock.Setup(x => x.SendAsync(It.IsAny<IdentifiedCommand<CancelOrderCommand, bool>>()))
.Returns(Task.FromResult(true));
// //Act
// var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
// var actionResult = await orderController.CreateOrder(new CreateOrderCommand(), Guid.NewGuid().ToString()) as OkResult;
//Act
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
var actionResult = await orderController.CancelOrder(new CancelOrderCommand(1), Guid.NewGuid().ToString()) as OkResult;
// //Assert
// Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.OK);
//Assert
Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.OK);
//}
}
//[Fact]
//public async Task Create_order_bad_request()
//{
// //Arrange
// _mediatorMock.Setup(x => x.SendAsync(It.IsAny<IdentifiedCommand<CreateOrderCommand, bool>>()))
// .Returns(Task.FromResult(true));
[Fact]
public async Task Cancel_order_bad_request()
{
//Arrange
_mediatorMock.Setup(x => x.SendAsync(It.IsAny<IdentifiedCommand<CancelOrderCommand, bool>>()))
.Returns(Task.FromResult(true));
// //Act
// var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
// var actionResult = await orderController.CreateOrder(new CreateOrderCommand(), String.Empty) as BadRequestResult;
//Act
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
var actionResult = await orderController.CancelOrder(new CancelOrderCommand(1), String.Empty) as BadRequestResult;
// //Assert
// Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.BadRequest);
//}
//Assert
Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.BadRequest);
}
[Fact]
public async Task Ship_order_with_requestId_success()
{
//Arrange
_mediatorMock.Setup(x => x.SendAsync(It.IsAny<IdentifiedCommand<ShipOrderCommand, bool>>()))
.Returns(Task.FromResult(true));
//Act
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
var actionResult = await orderController.ShipOrder(new ShipOrderCommand(1), Guid.NewGuid().ToString()) as OkResult;
//Assert
Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.OK);
}
[Fact]
public async Task Ship_order_bad_request()
{
//Arrange
_mediatorMock.Setup(x => x.SendAsync(It.IsAny<IdentifiedCommand<ShipOrderCommand, bool>>()))
.Returns(Task.FromResult(true));
//Act
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
var actionResult = await orderController.ShipOrder(new ShipOrderCommand(1), String.Empty) as BadRequestResult;
//Assert
Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.BadRequest);
}
[Fact] [Fact]
public async Task Get_orders_success() public async Task Get_orders_success()


+ 5
- 5
test/Services/UnitTest/Ordering/Domain/OrderAggregateTest.cs View File

@ -111,7 +111,7 @@ public class OrderAggregateTest
var expectedResult = 1; var expectedResult = 1;
//Act //Act
var fakeOrder = new Order(userId.ToString(), new Address(street, city, state, country, zipcode), cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration);
var fakeOrder = new Order("1", new Address(street, city, state, country, zipcode), cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration);
//Assert //Assert
Assert.Equal(fakeOrder.DomainEvents.Count, expectedResult); Assert.Equal(fakeOrder.DomainEvents.Count, expectedResult);
@ -135,8 +135,8 @@ public class OrderAggregateTest
var expectedResult = 2; var expectedResult = 2;
//Act //Act
var fakeOrder = new Order(userId.ToString(), new Address(street, city, state, country, zipcode), cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration);
fakeOrder.AddDomainEvent(new OrderStartedDomainEvent(fakeOrder, userId.ToString(), cardTypeId,cardNumber,cardSecurityNumber,cardHolderName,cardExpiration));
var fakeOrder = new Order("1", new Address(street, city, state, country, zipcode), cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration);
fakeOrder.AddDomainEvent(new OrderStartedDomainEvent(fakeOrder, "1", cardTypeId,cardNumber,cardSecurityNumber,cardHolderName,cardExpiration));
//Assert //Assert
Assert.Equal(fakeOrder.DomainEvents.Count, expectedResult); Assert.Equal(fakeOrder.DomainEvents.Count, expectedResult);
} }
@ -156,8 +156,8 @@ public class OrderAggregateTest
var cardSecurityNumber = "123"; var cardSecurityNumber = "123";
var cardHolderName = "FakeName"; var cardHolderName = "FakeName";
var cardExpiration = DateTime.Now.AddYears(1); var cardExpiration = DateTime.Now.AddYears(1);
var fakeOrder = new Order(userId.ToString(), new Address(street, city, state, country, zipcode), cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration);
var @fakeEvent = new OrderStartedDomainEvent(fakeOrder, userId.ToString(), cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration);
var fakeOrder = new Order("1", new Address(street, city, state, country, zipcode), cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration);
var @fakeEvent = new OrderStartedDomainEvent(fakeOrder, "1", cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration);
var expectedResult = 1; var expectedResult = 1;
//Act //Act


Loading…
Cancel
Save