Created Ship order process in WebMVC app
Create Ship order command and handler in Ordering.api Create Order management page in WebMVC app
This commit is contained in:
parent
8045d6302b
commit
e104da9f85
@ -61,6 +61,9 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
|
|||||||
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)
|
||||||
|
@ -88,7 +88,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
|
|||||||
var result = new List<OrderItemDTO>();
|
var result = new List<OrderItemDTO>();
|
||||||
basketItems.ForEach((item) => {
|
basketItems.ForEach((item) => {
|
||||||
result.Add(new OrderItemDTO() {
|
result.Add(new OrderItemDTO() {
|
||||||
ProductId = int.TryParse(item.Id, out int id) ? id : -1,
|
ProductId = int.TryParse(item.ProductId, out int id) ? id : -1,
|
||||||
ProductName = item.ProductName,
|
ProductName = item.ProductName,
|
||||||
PictureUrl = item.PictureUrl,
|
PictureUrl = item.PictureUrl,
|
||||||
UnitPrice = item.UnitPrice,
|
UnitPrice = item.UnitPrice,
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
|
||||||
|
@ -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,15 +6,10 @@ 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 System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Ordering.API.Application.IntegrationEvents;
|
using Ordering.API.Application.IntegrationEvents;
|
||||||
using Ordering.API.Application.IntegrationEvents.Events;
|
using Ordering.Domain.Exceptions;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Ordering.API.Application.Sagas
|
namespace Ordering.API.Application.Sagas
|
||||||
{
|
{
|
||||||
@ -29,19 +23,16 @@ namespace Ordering.API.Application.Sagas
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class OrderProcessSaga : Saga<Order>,
|
public class OrderProcessSaga : Saga<Order>,
|
||||||
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;
|
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
|
||||||
|
|
||||||
public OrderProcessSaga(
|
public OrderProcessSaga(
|
||||||
Func<Owned<OrderingContext>> dbContextFactory, OrderingContext orderingContext,
|
OrderingContext orderingContext,
|
||||||
IMediator mediator, IOrderingIntegrationEventService orderingIntegrationEventService)
|
IOrderingIntegrationEventService orderingIntegrationEventService)
|
||||||
: base(orderingContext)
|
: base(orderingContext)
|
||||||
{
|
{
|
||||||
_dbContextFactory = dbContextFactory;
|
|
||||||
_mediator = mediator;
|
|
||||||
_orderingIntegrationEventService = orderingIntegrationEventService;
|
_orderingIntegrationEventService = orderingIntegrationEventService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,12 +76,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.SetOrderStatusId(OrderStatus.Cancelled.Id);
|
||||||
|
result = await SaveChangesAsync();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
/// <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);
|
||||||
|
|
||||||
|
// Only ship order when
|
||||||
|
// its status is paid
|
||||||
|
if (orderSaga.GetOrderStatusId() == OrderStatus.Paid.Id)
|
||||||
|
{
|
||||||
|
orderSaga.SetOrderStatusId(OrderStatus.Shipped.Id);
|
||||||
|
result = await SaveChangesAsync();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CheckValidSagaId(Order orderSaga)
|
private void CheckValidSagaId(Order orderSaga)
|
||||||
@ -115,6 +135,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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -120,6 +120,11 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
|
@ -59,18 +59,12 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
|||||||
return View(model);
|
return View(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPut]
|
public async Task<IActionResult> Cancel(string orderId)
|
||||||
public async Task<IActionResult> Cancel(Order model)
|
|
||||||
{
|
{
|
||||||
if (ModelState.IsValid)
|
await _orderSvc.CancelOrder(orderId);
|
||||||
{
|
|
||||||
var user = _appUserParser.Parse(HttpContext.User);
|
|
||||||
await _orderSvc.CancelOrder(model);
|
|
||||||
|
|
||||||
//Redirect to historic list.
|
//Redirect to historic list.
|
||||||
return RedirectToAction("Index");
|
return RedirectToAction("Index");
|
||||||
}
|
|
||||||
return View(model);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IActionResult> Detail(string orderId)
|
public async Task<IActionResult> Detail(string orderId)
|
||||||
|
43
src/Web/WebMVC/Controllers/OrderManagementController.cs
Normal file
43
src/Web/WebMVC/Controllers/OrderManagementController.cs
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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
src/Web/WebMVC/Models/OrderDTO.cs
Normal file
11
src/Web/WebMVC/Models/OrderDTO.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace WebMVC.Models
|
||||||
|
{
|
||||||
|
public class OrderDTO
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string OrderNumber { get; set; }
|
||||||
|
}
|
||||||
|
}
|
25
src/Web/WebMVC/Models/OrderProcessAction.cs
Normal file
25
src/Web/WebMVC/Models/OrderProcessAction.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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>
|
||||||
|
@ -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">
|
||||||
|
@ -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">
|
||||||
|
@ -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
src/Web/WebMVC/Views/OrderManagement/Index.cshtml
Normal file
43
src/Web/WebMVC/Views/OrderManagement/Index.cshtml
Normal 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=""> 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>
|
||||||
|
@ -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;
|
||||||
|
@ -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,8 @@ 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,
|
||||||
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,
|
||||||
state: args != null && args.ContainsKey("state") ? (string)args["state"] : null,
|
state: args != null && args.ContainsKey("state") ? (string)args["state"] : null,
|
||||||
|
@ -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,14 @@ namespace UnitTest.Ordering.Application
|
|||||||
|
|
||||||
private Order FakeOrder()
|
private Order FakeOrder()
|
||||||
{
|
{
|
||||||
return new Order(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,
|
||||||
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,
|
||||||
state: args != null && args.ContainsKey("state") ? (string)args["state"] : null,
|
state: args != null && args.ContainsKey("state") ? (string)args["state"] : null,
|
||||||
|
@ -110,7 +110,7 @@ public class OrderAggregateTest
|
|||||||
var expectedResult = 1;
|
var expectedResult = 1;
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var fakeOrder = new Order(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);
|
||||||
@ -133,8 +133,8 @@ public class OrderAggregateTest
|
|||||||
var expectedResult = 2;
|
var expectedResult = 2;
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var fakeOrder = new Order(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);
|
||||||
fakeOrder.AddDomainEvent(new OrderStartedDomainEvent(fakeOrder,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);
|
||||||
}
|
}
|
||||||
@ -153,8 +153,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(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);
|
||||||
var @fakeEvent = new OrderStartedDomainEvent(fakeOrder, 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…
x
Reference in New Issue
Block a user