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
This commit is contained in:
commit
94ee95f32b
@ -52,15 +52,21 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Route("checkout")]
|
[Route("checkout")]
|
||||||
[HttpPut]
|
[HttpPost]
|
||||||
public async Task<IActionResult> Checkout([FromBody]BasketCheckout value)
|
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)
|
||||||
|
@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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;
|
||||||
|
|
||||||
|
@ -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 :
|
||||||
|
@ -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 :
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
{
|
{
|
||||||
|
@ -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.Domain.Exceptions;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Ordering.API.Application.IntegrationEvents;
|
using Ordering.API.Application.IntegrationEvents;
|
||||||
|
using Ordering.Domain.Exceptions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
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,
|
OrderingContext orderingContext)
|
||||||
IMediator mediator, IOrderingIntegrationEventService orderingIntegrationEventService)
|
|
||||||
: 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;
|
||||||
|
}
|
||||||
|
|
||||||
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.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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
@ -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 = "";
|
||||||
// _description = "";
|
|
||||||
// break;
|
|
||||||
//case OrderStatus.StockConfirmed:
|
|
||||||
// _description = "";
|
|
||||||
// break;
|
|
||||||
//case OrderStatus.Paid:
|
|
||||||
// _description = "";
|
|
||||||
// break;
|
|
||||||
//case OrderStatus.Shipped:
|
|
||||||
// _description = "";
|
|
||||||
// break;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
_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)
|
||||||
{
|
{
|
||||||
|
@ -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)
|
return await _context.Orders.FindAsync(orderId);
|
||||||
?? throw new OrderingDomainException($"Not able to get the order. Reason: no valid orderId: {orderId}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(Order order)
|
public void Update(Order order)
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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); ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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,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)
|
||||||
|
@ -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],
|
||||||
@ -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;
|
||||||
|
let basketCheckout = this.basketService.mapBasketInfoCheckout(this.order);
|
||||||
this.service.postOrder(this.order)
|
this.basketService.setBasketCheckout(basketCheckout)
|
||||||
.catch((errMessage) => {
|
.catch((errMessage) => {
|
||||||
this.errorReceived = true;
|
this.errorReceived = true;
|
||||||
this.isOrderProcessing = false;
|
this.isOrderProcessing = false;
|
||||||
|
@ -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 { }
|
||||||
|
@ -44,13 +44,7 @@ export class OrdersService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
postOrder(item): Observable<boolean> {
|
mapOrderAndIdentityInfoNewOrder(): IOrder {
|
||||||
return this.service.postWithId(this.ordersUrl + '/api/v1/orders/new', item).map((response: Response) => {
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
mapBasketAndIdentityInfoNewOrder(): 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;
|
||||||
|
@ -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;
|
||||||
|
}
|
@ -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 = {};
|
||||||
|
|
||||||
|
@ -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" />
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
using Microsoft.eShopOnContainers.Services.Basket.API;
|
using FunctionalTests.Middleware;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
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
|
||||||
{
|
{
|
||||||
|
@ -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>
|
||||||
|
@ -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"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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]
|
[Fact]
|
||||||
// public async Task Get_get_all_stored_orders_and_response_ok_status_code()
|
public async Task Get_get_all_stored_orders_and_response_ok_status_code()
|
||||||
// {
|
{
|
||||||
// using (var server = CreateServer())
|
using (var server = CreateServer())
|
||||||
// {
|
{
|
||||||
// var response = await server.CreateClient()
|
var response = await server.CreateClient()
|
||||||
// .GetAsync(Get.Orders);
|
.GetAsync(Get.Orders);
|
||||||
|
|
||||||
// response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// [Fact]
|
[Fact]
|
||||||
// public async Task AddNewOrder_add_new_order_and_response_ok_status_code()
|
public async Task Cancel_order_and_response_ok_status_code()
|
||||||
// {
|
{
|
||||||
// using (var server = CreateServer())
|
using (var server = CreateServer())
|
||||||
// {
|
{
|
||||||
// var content = new StringContent(BuildOrder(), UTF8Encoding.UTF8, "application/json");
|
var content = new StringContent(BuildOrder(), UTF8Encoding.UTF8, "application/json");
|
||||||
// var response = await server.CreateIdempotentClient()
|
var response = await server.CreateIdempotentClient()
|
||||||
// .PostAsync(Post.AddNewOrder, content);
|
.PutAsync(Put.CancelOrder, content);
|
||||||
|
|
||||||
// response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// [Fact]
|
[Fact]
|
||||||
// public async Task AddNewOrder_response_bad_request_if_card_expiration_is_invalid()
|
public async Task Ship_order_and_response_bad_status_code()
|
||||||
// {
|
{
|
||||||
// using (var server = CreateServer())
|
using (var server = CreateServer())
|
||||||
// {
|
{
|
||||||
// var content = new StringContent(BuildOrderWithInvalidExperationTime(), UTF8Encoding.UTF8, "application/json");
|
var content = new StringContent(BuildOrder(), UTF8Encoding.UTF8, "application/json");
|
||||||
|
var response = await server.CreateIdempotentClient()
|
||||||
|
.PutAsync(Put.ShipOrder, content);
|
||||||
|
|
||||||
// var response = await server.CreateIdempotentClient()
|
response.EnsureSuccessStatusCode();
|
||||||
// .PostAsync(Post.AddNewOrder, content);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Assert.True(response.StatusCode == System.Net.HttpStatusCode.BadRequest);
|
string BuildOrder()
|
||||||
// }
|
{
|
||||||
// }
|
var order = new OrderDTO()
|
||||||
|
{
|
||||||
// //public CreateOrderCommand(string city, string street, string state, string country, string zipcode,
|
OrderNumber = "1"
|
||||||
// // string cardNumber, string cardHolderName, DateTime cardExpiration,
|
};
|
||||||
// // string cardSecurityNumber, int cardTypeId, int paymentId, int buyerId) : this()
|
return JsonConvert.SerializeObject(order);
|
||||||
|
}
|
||||||
// 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);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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]
|
[Fact]
|
||||||
//public async Task Create_order_with_requestId_success()
|
public async Task Create_order_with_requestId_success()
|
||||||
//{
|
{
|
||||||
// //Arrange
|
//Arrange
|
||||||
// _mediatorMock.Setup(x => x.SendAsync(It.IsAny<IdentifiedCommand<CreateOrderCommand, bool>>()))
|
_mediatorMock.Setup(x => x.SendAsync(It.IsAny<IdentifiedCommand<CancelOrderCommand, bool>>()))
|
||||||
// .Returns(Task.FromResult(true));
|
.Returns(Task.FromResult(true));
|
||||||
|
|
||||||
// //Act
|
//Act
|
||||||
// var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
|
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
|
||||||
// var actionResult = await orderController.CreateOrder(new CreateOrderCommand(), Guid.NewGuid().ToString()) as OkResult;
|
var actionResult = await orderController.CancelOrder(new CancelOrderCommand(1), Guid.NewGuid().ToString()) as OkResult;
|
||||||
|
|
||||||
// //Assert
|
//Assert
|
||||||
// Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.OK);
|
Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.OK);
|
||||||
|
|
||||||
//}
|
}
|
||||||
|
|
||||||
//[Fact]
|
[Fact]
|
||||||
//public async Task Create_order_bad_request()
|
public async Task Cancel_order_bad_request()
|
||||||
//{
|
{
|
||||||
// //Arrange
|
//Arrange
|
||||||
// _mediatorMock.Setup(x => x.SendAsync(It.IsAny<IdentifiedCommand<CreateOrderCommand, bool>>()))
|
_mediatorMock.Setup(x => x.SendAsync(It.IsAny<IdentifiedCommand<CancelOrderCommand, bool>>()))
|
||||||
// .Returns(Task.FromResult(true));
|
.Returns(Task.FromResult(true));
|
||||||
|
|
||||||
// //Act
|
//Act
|
||||||
// var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
|
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
|
||||||
// var actionResult = await orderController.CreateOrder(new CreateOrderCommand(), String.Empty) as BadRequestResult;
|
var actionResult = await orderController.CancelOrder(new CancelOrderCommand(1), String.Empty) as BadRequestResult;
|
||||||
|
|
||||||
// //Assert
|
//Assert
|
||||||
// Assert.Equal(actionResult.StatusCode, (int)System.Net.HttpStatusCode.BadRequest);
|
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()
|
||||||
|
@ -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);
|
var fakeOrder = new Order("1", new Address(street, city, state, country, zipcode), cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration);
|
||||||
fakeOrder.AddDomainEvent(new OrderStartedDomainEvent(fakeOrder, userId.ToString(), 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 fakeOrder = new Order("1", 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 @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