Browse Source

Create checkout call in webmvc

Created Cancel call in webmvc
pull/809/head
Ramón Tomás 7 years ago
parent
commit
21fe9b7be4
24 changed files with 415 additions and 172 deletions
  1. +10
    -6
      src/Services/Basket/Basket.API/Controllers/BasketController.cs
  2. +0
    -21
      src/Services/Basket/Basket.API/IntegrationEvents/Events/UserCheckoutAccepted.cs
  3. +64
    -0
      src/Services/Basket/Basket.API/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs
  4. +35
    -0
      src/Services/Basket/Basket.API/Model/BasketCheckout.cs
  5. +0
    -14
      src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/SubmitOrderCommandMsg.cs
  6. +0
    -16
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/UserCheckoutAcceptedIntegrationEventHandler.cs
  7. +62
    -0
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs
  8. +18
    -0
      src/Services/Ordering/Ordering.API/Application/Models/BasketItem.cs
  9. +19
    -0
      src/Services/Ordering/Ordering.API/Application/Models/CustomerBasket.cs
  10. +5
    -4
      src/Services/Ordering/Ordering.API/Application/Sagas/OrderProcessSaga.cs
  11. +6
    -11
      src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs
  12. +1
    -0
      src/Services/Ordering/Ordering.API/Ordering.API.csproj
  13. +5
    -5
      src/Services/Ordering/Ordering.API/Startup.cs
  14. +19
    -2
      src/Web/WebMVC/Controllers/OrderController.cs
  15. +10
    -0
      src/Web/WebMVC/Infrastructure/API.cs
  16. +37
    -0
      src/Web/WebMVC/Models/BasketDTO.cs
  17. +11
    -0
      src/Web/WebMVC/Services/BasketService.cs
  18. +2
    -0
      src/Web/WebMVC/Services/IBasketService.cs
  19. +3
    -1
      src/Web/WebMVC/Services/IOrderingService.cs
  20. +26
    -11
      src/Web/WebMVC/Services/OrderingService.cs
  21. +1
    -1
      src/Web/WebMVC/Views/Order/Create.cshtml
  22. +6
    -5
      test/Services/UnitTest/Basket/Application/BasketWebApiTest.cs
  23. +45
    -45
      test/Services/UnitTest/Ordering/Application/OrderControllerTest.cs
  24. +30
    -30
      test/Services/UnitTest/Ordering/Application/OrdersWebApiTest.cs

+ 10
- 6
src/Services/Basket/Basket.API/Controllers/BasketController.cs View File

@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
using Basket.API.IntegrationEvents.Events; using Basket.API.IntegrationEvents.Events;
using Microsoft.eShopOnContainers.Services.Basket.API.Services; using Microsoft.eShopOnContainers.Services.Basket.API.Services;
using Basket.API.Model;
namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
{ {
@ -50,20 +51,23 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
return Ok(basket); return Ok(basket);
} }
[Route("checkouts")]
[HttpPost]
public async Task<IActionResult> Checkout()
[Route("checkout")]
[HttpPut]
public async Task<IActionResult> Checkout([FromBody]BasketCheckout value)
{ {
var userId = _identitySvc.GetUserIdentity(); var userId = _identitySvc.GetUserIdentity();
var basket = await _repository.GetBasketAsync(userId); var basket = await _repository.GetBasketAsync(userId);
_eventBus.Publish(new UserCheckoutAccepted(userId, basket));
var eventMessage = new UserCheckoutAcceptedIntegrationEvent(userId, value.City, value.Street,
value.State, value.Country, value.ZipCode, value.CardNumber, value.CardHolderName,
value.CardExpiration, value.CardSecurityNumber, value.CardTypeId, value.Buyer, value.RequestId, basket);
_eventBus.Publish(eventMessage);
if (basket == null) if (basket == null)
{ {
return BadRequest(); return BadRequest();
} }
return Accepted(); return Accepted();
} }


+ 0
- 21
src/Services/Basket/Basket.API/IntegrationEvents/Events/UserCheckoutAccepted.cs View File

@ -1,21 +0,0 @@
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
using Microsoft.eShopOnContainers.Services.Basket.API.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Basket.API.IntegrationEvents.Events
{
public class UserCheckoutAccepted : IntegrationEvent
{
public string UserId {get; }
CustomerBasket Basket { get; }
public UserCheckoutAccepted(string userId, CustomerBasket basket)
{
UserId = userId;
Basket = basket;
}
}
}

+ 64
- 0
src/Services/Basket/Basket.API/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs View File

@ -0,0 +1,64 @@
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
using Microsoft.eShopOnContainers.Services.Basket.API.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Basket.API.IntegrationEvents.Events
{
public class UserCheckoutAcceptedIntegrationEvent : IntegrationEvent
{
public string UserId { get; }
public int OrderNumber { get; set; }
public string City { get; set; }
public string Street { get; set; }
public string State { get; set; }
public string Country { get; set; }
public string ZipCode { get; set; }
public string CardNumber { get; set; }
public string CardHolderName { get; set; }
public DateTime CardExpiration { get; set; }
public string CardSecurityNumber { get; set; }
public int CardTypeId { get; set; }
public string Buyer { get; set; }
public Guid RequestId { get; set; }
public CustomerBasket Basket { get; }
public UserCheckoutAcceptedIntegrationEvent(string userId, string city, string street,
string state, string country, string zipCode, string cardNumber, string cardHolderName,
DateTime cardExpiration, string cardSecurityNumber, int cardTypeId, string buyer, Guid requestId,
CustomerBasket basket)
{
UserId = userId;
City = city;
Street = street;
State = state;
Country = country;
ZipCode = zipCode;
CardNumber = cardNumber;
CardHolderName = cardHolderName;
CardExpiration = cardExpiration;
CardSecurityNumber = cardSecurityNumber;
CardTypeId = cardTypeId;
Buyer = buyer;
Basket = basket;
RequestId = requestId;
}
}
}

+ 35
- 0
src/Services/Basket/Basket.API/Model/BasketCheckout.cs View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Basket.API.Model
{
public class BasketCheckout
{
public string City { get; set; }
public string Street { get; set; }
public string State { get; set; }
public string Country { get; set; }
public string ZipCode { get; set; }
public string CardNumber { get; set; }
public string CardHolderName { get; set; }
public DateTime CardExpiration { get; set; }
public string CardSecurityNumber { get; set; }
public int CardTypeId { get; set; }
public string Buyer { get; set; }
public Guid RequestId { get; set; }
}
}

+ 0
- 14
src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/SubmitOrderCommandMsg.cs View File

@ -1,14 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
namespace Ordering.API.Application.IntegrationCommands.Commands
{
public class SubmitOrderCommandMsg : IntegrationEvent
{
public int OrderNumber { get; private set; }
//TODO: message should change to Integration command type once command bus is implemented
}
}

+ 0
- 16
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/UserCheckoutAcceptedIntegrationEventHandler.cs View File

@ -1,16 +0,0 @@
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ordering.API.Application.IntegrationEvents.EventHandling
{
public class UserCheckoutAcceptedIntegrationEventHandler : IDynamicIntegrationEventHandler
{
public async Task Handle(dynamic eventData)
{
int i = 0;
}
}
}

+ 62
- 0
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs View File

@ -0,0 +1,62 @@
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
using Ordering.API.Application.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ordering.API.Application.IntegrationEvents.Events
{
public class UserCheckoutAcceptedIntegrationEvent : IntegrationEvent
{
public string UserId { get; }
public string City { get; set; }
public string Street { get; set; }
public string State { get; set; }
public string Country { get; set; }
public string ZipCode { get; set; }
public string CardNumber { get; set; }
public string CardHolderName { get; set; }
public DateTime CardExpiration { get; set; }
public string CardSecurityNumber { get; set; }
public int CardTypeId { get; set; }
public string Buyer { get; set; }
public Guid RequestId { get; set; }
public CustomerBasket Basket { get; }
public UserCheckoutAcceptedIntegrationEvent(string userId, string city, string street,
string state, string country, string zipCode, string cardNumber, string cardHolderName,
DateTime cardExpiration, string cardSecurityNumber, int cardTypeId, string buyer, Guid requestId,
CustomerBasket basket)
{
UserId = userId;
City = city;
Street = street;
State = state;
Country = country;
ZipCode = zipCode;
CardNumber = cardNumber;
CardHolderName = cardHolderName;
CardExpiration = cardExpiration;
CardSecurityNumber = cardSecurityNumber;
CardTypeId = cardTypeId;
Buyer = buyer;
Basket = basket;
RequestId = requestId;
}
}
}

+ 18
- 0
src/Services/Ordering/Ordering.API/Application/Models/BasketItem.cs View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ordering.API.Application.Models
{
public class BasketItem
{
public string Id { get; set; }
public string ProductId { get; set; }
public string ProductName { get; set; }
public decimal UnitPrice { get; set; }
public decimal OldUnitPrice { get; set; }
public int Quantity { get; set; }
public string PictureUrl { get; set; }
}
}

+ 19
- 0
src/Services/Ordering/Ordering.API/Application/Models/CustomerBasket.cs View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ordering.API.Application.Models
{
public class CustomerBasket
{
public string BuyerId { get; set; }
public List<BasketItem> Items { get; set; }
public CustomerBasket(string customerId)
{
BuyerId = customerId;
Items = new List<BasketItem>();
}
}
}

+ 5
- 4
src/Services/Ordering/Ordering.API/Application/Sagas/OrderProcessSaga.cs View File

@ -7,6 +7,7 @@ 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.Events;
using Ordering.Domain.Exceptions; using Ordering.Domain.Exceptions;
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -22,7 +23,7 @@ namespace Ordering.API.Application.Sagas
/// with the validations. /// with the validations.
/// </summary> /// </summary>
public class OrderProcessSaga : Saga<Order>, public class OrderProcessSaga : Saga<Order>,
IIntegrationEventHandler<SubmitOrderCommandMsg>,
IIntegrationEventHandler<UserCheckoutAcceptedIntegrationEvent>,
IIntegrationEventHandler<ConfirmGracePeriodCommandMsg>, IIntegrationEventHandler<ConfirmGracePeriodCommandMsg>,
IAsyncRequestHandler<CancelOrderCommand, bool> IAsyncRequestHandler<CancelOrderCommand, bool>
{ {
@ -48,10 +49,10 @@ namespace Ordering.API.Application.Sagas
/// order items. /// order items.
/// </param> /// </param>
/// <returns></returns> /// <returns></returns>
public async Task Handle(SubmitOrderCommandMsg command)
public async Task Handle(UserCheckoutAcceptedIntegrationEvent command)
{ {
var orderSaga = FindSagaById(command.OrderNumber);
CheckValidSagaId(orderSaga);
var commanda = command;
// TODO: This handler should change to Integration command handler type once command bus is implemented // TODO: This handler should change to Integration command handler type once command bus is implemented


+ 6
- 11
src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs View File

@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries; using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries;
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services; using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
using Ordering.API.Application.Commands;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -26,23 +27,17 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
_identityService = identityService ?? throw new ArgumentNullException(nameof(identityService)); _identityService = identityService ?? throw new ArgumentNullException(nameof(identityService));
} }
[Route("new")]
[Route("cancel")]
[HttpPost] [HttpPost]
public async Task<IActionResult> CreateOrder([FromBody]CreateOrderCommand 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;
if (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty) if (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty)
{ {
var requestCreateOrder = new IdentifiedCommand<CreateOrderCommand, bool>(command, guid);
commandResult = await _mediator.SendAsync(requestCreateOrder);
var requestCancelOrder = new IdentifiedCommand<CancelOrderCommand, bool>(command, guid);
commandResult = await _mediator.SendAsync(requestCancelOrder);
} }
else
{
// If no x-requestid header is found we process the order anyway. This is just temporary to not break existing clients
// that aren't still updated. When all clients were updated this could be removed.
commandResult = await _mediator.SendAsync(command);
}
return commandResult ? (IActionResult)Ok() : (IActionResult)BadRequest(); return commandResult ? (IActionResult)Ok() : (IActionResult)BadRequest();
} }


+ 1
- 0
src/Services/Ordering/Ordering.API/Ordering.API.csproj View File

@ -80,6 +80,7 @@
<ItemGroup> <ItemGroup>
<Folder Include="Application\IntegrationCommands\CommandHandlers\" /> <Folder Include="Application\IntegrationCommands\CommandHandlers\" />
<Folder Include="Application\IntegrationEvents\EventHandling\" />
<Folder Include="Infrastructure\IntegrationEventMigrations\" /> <Folder Include="Infrastructure\IntegrationEventMigrations\" />
</ItemGroup> </ItemGroup>


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

@ -4,7 +4,7 @@
using Autofac; using Autofac;
using Autofac.Extensions.DependencyInjection; using Autofac.Extensions.DependencyInjection;
using global::Ordering.API.Application.IntegrationEvents; using global::Ordering.API.Application.IntegrationEvents;
using global::Ordering.API.Application.IntegrationEvents.EventHandling;
using global::Ordering.API.Application.IntegrationEvents.Events;
using global::Ordering.API.Infrastructure.Middlewares; using global::Ordering.API.Infrastructure.Middlewares;
using Infrastructure; using Infrastructure;
using Infrastructure.Auth; using Infrastructure.Auth;
@ -124,7 +124,7 @@
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>(); services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();
services.AddSingleton<IEventBus, EventBusRabbitMQ>(); services.AddSingleton<IEventBus, EventBusRabbitMQ>();
services.AddTransient<UserCheckoutAcceptedIntegrationEventHandler>();
//services.AddTransient<UserCheckoutAcceptedIntegrationEventHandler>();
services.AddOptions(); services.AddOptions();
//configure autofac //configure autofac
@ -168,9 +168,9 @@
private void ConfigureEventBus(IApplicationBuilder app) private void ConfigureEventBus(IApplicationBuilder app)
{ {
var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>(); var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();
eventBus.SubscribeDynamic(
"UserCheckoutAccepted",
() => app.ApplicationServices.GetRequiredService<UserCheckoutAcceptedIntegrationEventHandler>());
eventBus.Subscribe<UserCheckoutAcceptedIntegrationEvent,IIntegrationEventHandler<UserCheckoutAcceptedIntegrationEvent>>(
() => app.ApplicationServices.GetRequiredService<IIntegrationEventHandler<UserCheckoutAcceptedIntegrationEvent>>());
} }


+ 19
- 2
src/Web/WebMVC/Controllers/OrderController.cs View File

@ -8,6 +8,7 @@ using Microsoft.eShopOnContainers.WebMVC.ViewModels;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using System.Net.Http; using System.Net.Http;
using Polly.CircuitBreaker; using Polly.CircuitBreaker;
using WebMVC.Models;
namespace Microsoft.eShopOnContainers.WebMVC.Controllers namespace Microsoft.eShopOnContainers.WebMVC.Controllers
{ {
@ -36,14 +37,16 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
} }
[HttpPost] [HttpPost]
public async Task<IActionResult> Create(Order model, string action)
public async Task<IActionResult> Checkout(Order model)
{ {
try try
{ {
if (ModelState.IsValid) if (ModelState.IsValid)
{ {
var user = _appUserParser.Parse(HttpContext.User); var user = _appUserParser.Parse(HttpContext.User);
await _orderSvc.CreateOrder(model);
var basket = _orderSvc.MapOrderToBasket(model);
await _basketSvc.Checkout(basket);
//Redirect to historic list. //Redirect to historic list.
return RedirectToAction("Index"); return RedirectToAction("Index");
@ -56,6 +59,20 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
return View(model); return View(model);
} }
[HttpPut]
public async Task<IActionResult> Cancel(Order model)
{
if (ModelState.IsValid)
{
var user = _appUserParser.Parse(HttpContext.User);
await _orderSvc.CancelOrder(model);
//Redirect to historic list.
return RedirectToAction("Index");
}
return View(model);
}
public async Task<IActionResult> Detail(string orderId) public async Task<IActionResult> Detail(string orderId)
{ {
var user = _appUserParser.Parse(HttpContext.User); var user = _appUserParser.Parse(HttpContext.User);


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

@ -14,6 +14,11 @@
return baseUri; return baseUri;
} }
public static string CheckoutBasket(string baseUri)
{
return $"{baseUri}/checkout";
}
public static string CleanBasket(string baseUri, string basketId) public static string CleanBasket(string baseUri, string basketId)
{ {
return $"{baseUri}/{basketId}"; return $"{baseUri}/{basketId}";
@ -36,6 +41,11 @@
{ {
return $"{baseUri}/new"; return $"{baseUri}/new";
} }
public static string CancelOrder(string baseUri)
{
return $"{baseUri}/cancel";
}
} }
public static class Catalog public static class Catalog


+ 37
- 0
src/Web/WebMVC/Models/BasketDTO.cs View File

@ -0,0 +1,37 @@
using System;
using System.ComponentModel.DataAnnotations;
namespace WebMVC.Models
{
public class BasketDTO
{
[Required]
public string City { get; set; }
[Required]
public string Street { get; set; }
[Required]
public string State { get; set; }
[Required]
public string Country { get; set; }
public string ZipCode { get; set; }
[Required]
public string CardNumber { get; set; }
[Required]
public string CardHolderName { get; set; }
[Required]
public DateTime CardExpiration { get; set; }
[Required]
public string CardSecurityNumber { get; set; }
public int CardTypeId { get; set; }
public string Buyer { get; set; }
[Required]
public Guid RequestId { get; set; }
}
}

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

@ -7,6 +7,7 @@ using Newtonsoft.Json;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using WebMVC.Infrastructure; using WebMVC.Infrastructure;
using WebMVC.Models;
namespace Microsoft.eShopOnContainers.WebMVC.Services namespace Microsoft.eShopOnContainers.WebMVC.Services
{ {
@ -54,6 +55,16 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
return basket; return basket;
} }
public async Task Checkout(BasketDTO basket)
{
var token = await GetUserTokenAsync();
var updateBasketUri = API.Basket.CheckoutBasket(_remoteServiceBaseUrl);
var response = await _apiClient.PutAsync(updateBasketUri, basket, token);
response.EnsureSuccessStatusCode();
}
public async Task<Basket> SetQuantities(ApplicationUser user, Dictionary<string, int> quantities) public async Task<Basket> SetQuantities(ApplicationUser user, Dictionary<string, int> quantities)
{ {
var basket = await GetBasket(user); var basket = await GetBasket(user);


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

@ -3,6 +3,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using WebMVC.Models;
namespace Microsoft.eShopOnContainers.WebMVC.Services namespace Microsoft.eShopOnContainers.WebMVC.Services
{ {
@ -11,6 +12,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
Task<Basket> GetBasket(ApplicationUser user); Task<Basket> GetBasket(ApplicationUser user);
Task AddItemToBasket(ApplicationUser user, BasketItem product); Task AddItemToBasket(ApplicationUser user, BasketItem product);
Task<Basket> UpdateBasket(Basket basket); Task<Basket> UpdateBasket(Basket basket);
Task Checkout(BasketDTO basket);
Task<Basket> SetQuantities(ApplicationUser user, Dictionary<string, int> quantities); Task<Basket> SetQuantities(ApplicationUser user, Dictionary<string, int> quantities);
Order MapBasketToOrder(Basket basket); Order MapBasketToOrder(Basket basket);
Task CleanBasket(ApplicationUser user); Task CleanBasket(ApplicationUser user);


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

@ -3,6 +3,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using WebMVC.Models;
namespace Microsoft.eShopOnContainers.WebMVC.Services namespace Microsoft.eShopOnContainers.WebMVC.Services
{ {
@ -10,8 +11,9 @@ 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 CreateOrder(Order order);
Task CancelOrder(Order order);
Order MapUserInfoIntoOrder(ApplicationUser user, Order order); Order MapUserInfoIntoOrder(ApplicationUser user, Order order);
BasketDTO MapOrderToBasket(Order order);
void OverrideUserInfoIntoOrder(Order original, Order destination); void OverrideUserInfoIntoOrder(Order original, Order destination);
} }
} }

+ 26
- 11
src/Web/WebMVC/Services/OrderingService.cs View File

@ -8,6 +8,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using WebMVC.Infrastructure; using WebMVC.Infrastructure;
using WebMVC.Models;
namespace Microsoft.eShopOnContainers.WebMVC.Services namespace Microsoft.eShopOnContainers.WebMVC.Services
{ {
@ -65,22 +66,17 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
return order; return order;
} }
async public Task CreateOrder(Order order)
async public Task CancelOrder(Order order)
{ {
var token = await GetUserTokenAsync(); var token = await GetUserTokenAsync();
var requestId = order.RequestId.ToString(); var requestId = order.RequestId.ToString();
var addNewOrderUri = API.Order.AddNewOrder(_remoteServiceBaseUrl);
order.CardTypeId = 1;
order.CardExpirationApiFormat();
SetFakeIdToProducts(order);
var response = await _apiClient.PostAsync(addNewOrderUri, order, token, requestId);
var cancelOrderUri = API.Order.CancelOrder(_remoteServiceBaseUrl);
var response = await _apiClient.PutAsync(cancelOrderUri, order, token, requestId);
if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError) if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
{ {
throw new Exception("Error creating order, try later.");
throw new Exception("Error cancelling order, try later.");
} }
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
@ -100,6 +96,25 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
destination.CardSecurityNumber = original.CardSecurityNumber; destination.CardSecurityNumber = original.CardSecurityNumber;
} }
public BasketDTO MapOrderToBasket(Order order)
{
return new BasketDTO()
{
City = order.City,
Street = order.Street,
State = order.State,
Country = order.Country,
ZipCode = order.ZipCode,
CardNumber = order.CardNumber,
CardHolderName = order.CardHolderName,
CardExpiration = order.CardExpiration,
CardSecurityNumber = order.CardSecurityNumber,
CardTypeId = order.CardTypeId,
Buyer = order.Buyer,
RequestId = order.RequestId
};
}
void SetFakeIdToProducts(Order order) void SetFakeIdToProducts(Order order)
{ {
var id = 1; var id = 1;
@ -111,6 +126,6 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
var context = _httpContextAccesor.HttpContext; var context = _httpContextAccesor.HttpContext;
return await context.Authentication.GetTokenAsync("access_token"); return await context.Authentication.GetTokenAsync("access_token");
}
}
} }
} }

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

@ -9,7 +9,7 @@
@Html.Partial("_Header", new Header() { Controller = "Cart", Text = "Back to cart" }) @Html.Partial("_Header", new Header() { Controller = "Cart", Text = "Back to cart" })
<div class="container"> <div class="container">
<form method="post" asp-controller="Order" asp-action="Create">
<form method="post" asp-controller="Order" asp-action="Checkout">
<section class="esh-orders_new-section"> <section class="esh-orders_new-section">
<div class="row"> <div class="row">
@foreach (var error in ViewData.ModelState.Values.SelectMany(err => err.Errors)) { @foreach (var error in ViewData.ModelState.Values.SelectMany(err => err.Errors)) {


+ 6
- 5
test/Services/UnitTest/Basket/Application/BasketWebApiTest.cs View File

@ -1,4 +1,5 @@
using Basket.API.IntegrationEvents.Events; using Basket.API.IntegrationEvents.Events;
using Basket.API.Model;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
using Microsoft.eShopOnContainers.Services.Basket.API.Controllers; using Microsoft.eShopOnContainers.Services.Basket.API.Controllers;
@ -35,7 +36,7 @@ namespace UnitTest.Basket.Application
.Returns(Task.FromResult(fakeCustomerBasket)); .Returns(Task.FromResult(fakeCustomerBasket));
_identityServiceMock.Setup(x => x.GetUserIdentity()).Returns(fakeCustomerId); _identityServiceMock.Setup(x => x.GetUserIdentity()).Returns(fakeCustomerId);
_serviceBusMock.Setup(x => x.Publish(It.IsAny<UserCheckoutAccepted>()));
_serviceBusMock.Setup(x => x.Publish(It.IsAny<UserCheckoutAcceptedIntegrationEvent>()));
//Act //Act
var basketController = new BasketController( var basketController = new BasketController(
_basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object); _basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object);
@ -56,7 +57,7 @@ namespace UnitTest.Basket.Application
_basketRepositoryMock.Setup(x => x.UpdateBasketAsync(It.IsAny<CustomerBasket>())) _basketRepositoryMock.Setup(x => x.UpdateBasketAsync(It.IsAny<CustomerBasket>()))
.Returns(Task.FromResult(fakeCustomerBasket)); .Returns(Task.FromResult(fakeCustomerBasket));
_identityServiceMock.Setup(x => x.GetUserIdentity()).Returns(fakeCustomerId); _identityServiceMock.Setup(x => x.GetUserIdentity()).Returns(fakeCustomerId);
_serviceBusMock.Setup(x => x.Publish(It.IsAny<UserCheckoutAccepted>()));
_serviceBusMock.Setup(x => x.Publish(It.IsAny<UserCheckoutAcceptedIntegrationEvent>()));
//Act //Act
var basketController = new BasketController( var basketController = new BasketController(
_basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object); _basketRepositoryMock.Object, _identityServiceMock.Object, _serviceBusMock.Object);
@ -79,7 +80,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() as BadRequestResult;
var result = await basketController.Checkout(new BasketCheckout()) as BadRequestResult;
Assert.NotNull(result); Assert.NotNull(result);
} }
@ -95,8 +96,8 @@ 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() as AcceptedResult;
_serviceBusMock.Verify(mock => mock.Publish(It.IsAny<UserCheckoutAccepted>()), Times.Once);
var result = await basketController.Checkout(new BasketCheckout()) as AcceptedResult;
_serviceBusMock.Verify(mock => mock.Publish(It.IsAny<UserCheckoutAcceptedIntegrationEvent>()), Times.Once);
Assert.NotNull(result); Assert.NotNull(result);
} }


+ 45
- 45
test/Services/UnitTest/Ordering/Application/OrderControllerTest.cs View File

@ -95,51 +95,51 @@ namespace UnitTest.Ordering.Application
Assert.IsAssignableFrom<Order>(viewResult.ViewData.Model); Assert.IsAssignableFrom<Order>(viewResult.ViewData.Model);
} }
[Fact]
public async Task Post_create_order_success()
{
//Arrange
var fakeOrder = GetFakeOrder();
_basketServiceMock.Setup(x => x.CleanBasket(It.IsAny<ApplicationUser>()))
.Returns(Task.FromResult(1));
_orderServiceMock.Setup(x => x.CreateOrder(It.IsAny<Order>()))
.Returns(Task.FromResult(1));
//Act
var orderController = new OrderController(_orderServiceMock.Object, _basketServiceMock.Object, _identityParserMock.Object);
orderController.ControllerContext.HttpContext = _contextMock.Object;
var actionResult = await orderController.Create(fakeOrder, "fakeAction");
//Assert
var redirectToActionResult = Assert.IsType<RedirectToActionResult>(actionResult);
Assert.Null(redirectToActionResult.ControllerName);
Assert.Equal("Index", redirectToActionResult.ActionName);
}
[Fact]
public async Task Post_create_order_fail()
{
//Arrange
var fakeOrder = GetFakeOrder();
_basketServiceMock.Setup(x => x.CleanBasket(It.IsAny<ApplicationUser>()))
.Returns(Task.FromResult(1));
_orderServiceMock.Setup(x => x.CreateOrder(It.IsAny<Order>()))
.Returns(Task.FromResult(1));
//Act
var orderController = new OrderController(_orderServiceMock.Object, _basketServiceMock.Object, _identityParserMock.Object);
orderController.ControllerContext.HttpContext = _contextMock.Object;
orderController.ModelState.AddModelError("fakeError", "fakeError");
var actionResult = await orderController.Create(fakeOrder, "action");
//Assert
var viewResult = Assert.IsType<ViewResult>(actionResult);
Assert.IsAssignableFrom<Order>(viewResult.ViewData.Model);
}
//[Fact]
//public async Task Post_create_order_success()
//{
// //Arrange
// var fakeOrder = GetFakeOrder();
// _basketServiceMock.Setup(x => x.CleanBasket(It.IsAny<ApplicationUser>()))
// .Returns(Task.FromResult(1));
// _orderServiceMock.Setup(x => x.CreateOrder(It.IsAny<Order>()))
// .Returns(Task.FromResult(1));
// //Act
// var orderController = new OrderController(_orderServiceMock.Object, _basketServiceMock.Object, _identityParserMock.Object);
// orderController.ControllerContext.HttpContext = _contextMock.Object;
// var actionResult = await orderController.Create(fakeOrder, "fakeAction");
// //Assert
// var redirectToActionResult = Assert.IsType<RedirectToActionResult>(actionResult);
// Assert.Null(redirectToActionResult.ControllerName);
// Assert.Equal("Index", redirectToActionResult.ActionName);
//}
//[Fact]
//public async Task Post_create_order_fail()
//{
// //Arrange
// var fakeOrder = GetFakeOrder();
// _basketServiceMock.Setup(x => x.CleanBasket(It.IsAny<ApplicationUser>()))
// .Returns(Task.FromResult(1));
// _orderServiceMock.Setup(x => x.CreateOrder(It.IsAny<Order>()))
// .Returns(Task.FromResult(1));
// //Act
// var orderController = new OrderController(_orderServiceMock.Object, _basketServiceMock.Object, _identityParserMock.Object);
// orderController.ControllerContext.HttpContext = _contextMock.Object;
// orderController.ModelState.AddModelError("fakeError", "fakeError");
// var actionResult = await orderController.Create(fakeOrder, "action");
// //Assert
// var viewResult = Assert.IsType<ViewResult>(actionResult);
// Assert.IsAssignableFrom<Order>(viewResult.ViewData.Model);
//}
private BasketModel GetFakeBasket(string buyerId) private BasketModel GetFakeBasket(string buyerId)
{ {


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

@ -25,36 +25,36 @@ 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));
//Act
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
var actionResult = await orderController.CreateOrder(new CreateOrderCommand(), Guid.NewGuid().ToString()) as OkResult;
//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));
//Act
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
var actionResult = await orderController.CreateOrder(new CreateOrderCommand(), String.Empty) as BadRequestResult;
//Assert
Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.BadRequest);
}
//[Fact]
//public async Task Create_order_with_requestId_success()
//{
// //Arrange
// _mediatorMock.Setup(x => x.SendAsync(It.IsAny<IdentifiedCommand<CreateOrderCommand, 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;
// //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));
// //Act
// var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
// var actionResult = await orderController.CreateOrder(new CreateOrderCommand(), 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()


Loading…
Cancel
Save