# Conflicts: # src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cspull/223/head
@ -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,0 +1,9 @@ | |||||
namespace Payment.API.IntegrationEvents | |||||
{ | |||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | |||||
public interface IPaymentIntegrationEventService | |||||
{ | |||||
void PublishThroughEventBus(IntegrationEvent evt); | |||||
} | |||||
} |
@ -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,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"); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,11 @@ | |||||
using System; | |||||
using System.ComponentModel.DataAnnotations; | |||||
namespace WebMVC.Models | |||||
{ | |||||
public class OrderDTO | |||||
{ | |||||
[Required] | |||||
public string OrderNumber { get; set; } | |||||
} | |||||
} |
@ -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; | |||||
} | |||||
} | |||||
} |
@ -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=""> Select Action</option> | |||||
<option value="">------------------</option> | |||||
</select> | |||||
</form> | |||||
</section> | |||||
</article> | |||||
} | |||||
</div> | |||||
</div> |
@ -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> |
@ -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; | |||||
} |
@ -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"; | |||||
} | |||||
} | |||||
} |
@ -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); | |||||
} | |||||
} | |||||
} |
@ -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); | |||||
} | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,8 @@ | |||||
{ | |||||
"ConnectionString": "127.0.0.1", | |||||
"IdentityUrl": "http://localhost:5105", | |||||
"isTest": "true", | |||||
"EventBusConnection": "localhost" | |||||
} | |||||
@ -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); | |||||
} | |||||
} | } | ||||
} | } |