Immutable commands - wip
This commit is contained in:
parent
b4162035f9
commit
67ab1159df
@ -11,27 +11,25 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
|
|||||||
{
|
{
|
||||||
private readonly List<OrderItemDTO> _orderItems;
|
private readonly List<OrderItemDTO> _orderItems;
|
||||||
|
|
||||||
public string City { get; set; }
|
public string City { get; private set; }
|
||||||
|
|
||||||
public string Street { get; set; }
|
public string Street { get; private set; }
|
||||||
|
|
||||||
public string State { get; set; }
|
public string State { get; private set; }
|
||||||
|
|
||||||
public string Country { get; set; }
|
public string Country { get; private set; }
|
||||||
|
|
||||||
public string ZipCode { get; set; }
|
public string ZipCode { get; private set; }
|
||||||
|
|
||||||
public string CardNumber { get; set; }
|
public string CardNumber { get; private set; }
|
||||||
|
|
||||||
public string CardHolderName { get; set; }
|
public string CardHolderName { get; private set; }
|
||||||
|
|
||||||
public DateTime CardExpiration { get; set; }
|
public DateTime CardExpiration { get; private set; }
|
||||||
|
|
||||||
public string CardSecurityNumber { get; set; }
|
public string CardSecurityNumber { get; private set; }
|
||||||
|
|
||||||
public int CardTypeId { get; set; }
|
public int CardTypeId { get; private set; }
|
||||||
|
|
||||||
public string BuyerIdentityGuid { get; set; }
|
|
||||||
|
|
||||||
public IEnumerable<OrderItemDTO> OrderItems => _orderItems;
|
public IEnumerable<OrderItemDTO> OrderItems => _orderItems;
|
||||||
|
|
||||||
@ -45,6 +43,21 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
|
|||||||
_orderItems = new List<OrderItemDTO>();
|
_orderItems = new List<OrderItemDTO>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CreateOrderCommand(string city, string street, string state, string country, string zipcode,
|
||||||
|
string cardNumber, string cardHolderName, DateTime cardExpiration,
|
||||||
|
string cardSecurityNumber, int cardTypeId) : this()
|
||||||
|
{
|
||||||
|
City = city;
|
||||||
|
Street = street;
|
||||||
|
State = state;
|
||||||
|
Country = country;
|
||||||
|
ZipCode = zipcode;
|
||||||
|
CardNumber = cardNumber;
|
||||||
|
CardHolderName = cardHolderName;
|
||||||
|
CardSecurityNumber = cardSecurityNumber;
|
||||||
|
CardTypeId = cardTypeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public class OrderItemDTO
|
public class OrderItemDTO
|
||||||
{
|
{
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
using Domain.AggregatesModel.BuyerAggregate;
|
using Domain.AggregatesModel.BuyerAggregate;
|
||||||
using Domain.AggregatesModel.OrderAggregate;
|
using Domain.AggregatesModel.OrderAggregate;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -11,12 +12,14 @@
|
|||||||
{
|
{
|
||||||
private readonly IBuyerRepository<Buyer> _buyerRepository;
|
private readonly IBuyerRepository<Buyer> _buyerRepository;
|
||||||
private readonly IOrderRepository<Order> _orderRepository;
|
private readonly IOrderRepository<Order> _orderRepository;
|
||||||
|
private readonly IIdentityService _identityService;
|
||||||
|
|
||||||
// Using DI to inject infrastructure persistence Repositories
|
// Using DI to inject infrastructure persistence Repositories
|
||||||
public CreateOrderCommandHandler(IBuyerRepository<Buyer> buyerRepository, IOrderRepository<Order> orderRepository)
|
public CreateOrderCommandHandler(IBuyerRepository<Buyer> buyerRepository, IOrderRepository<Order> orderRepository, IIdentityService identityService)
|
||||||
{
|
{
|
||||||
_buyerRepository = buyerRepository ?? throw new ArgumentNullException(nameof(buyerRepository));
|
_buyerRepository = buyerRepository ?? throw new ArgumentNullException(nameof(buyerRepository));
|
||||||
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
|
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
|
||||||
|
_identityService = identityService ?? throw new ArgumentNullException(nameof(identityService));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> Handle(CreateOrderCommand message)
|
public async Task<bool> Handle(CreateOrderCommand message)
|
||||||
@ -26,14 +29,17 @@
|
|||||||
// methods and constructor so validations, invariants and business logic
|
// methods and constructor so validations, invariants and business logic
|
||||||
// make sure that consistency is preserved across the whole aggregate
|
// make sure that consistency is preserved across the whole aggregate
|
||||||
|
|
||||||
var buyer = await _buyerRepository.FindAsync(message.BuyerIdentityGuid);
|
var cardTypeId = message.CardTypeId != 0 ? message.CardTypeId : 1;
|
||||||
|
|
||||||
|
var buyerGuid = _identityService.GetUserIdentity();
|
||||||
|
var buyer = await _buyerRepository.FindAsync(buyerGuid);
|
||||||
|
|
||||||
if (buyer == null)
|
if (buyer == null)
|
||||||
{
|
{
|
||||||
buyer = new Buyer(message.BuyerIdentityGuid);
|
buyer = new Buyer(buyerGuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
var payment = buyer.AddPaymentMethod(message.CardTypeId,
|
var payment = buyer.AddPaymentMethod(cardTypeId,
|
||||||
$"Payment Method on {DateTime.UtcNow}",
|
$"Payment Method on {DateTime.UtcNow}",
|
||||||
message.CardNumber,
|
message.CardNumber,
|
||||||
message.CardSecurityNumber,
|
message.CardSecurityNumber,
|
||||||
|
@ -30,13 +30,6 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
|
|||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<IActionResult> CreateOrder([FromBody]CreateOrderCommand createOrderCommand)
|
public async Task<IActionResult> CreateOrder([FromBody]CreateOrderCommand createOrderCommand)
|
||||||
{
|
{
|
||||||
if (createOrderCommand.CardTypeId == 0)
|
|
||||||
{
|
|
||||||
createOrderCommand.CardTypeId = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
createOrderCommand.BuyerIdentityGuid = _identityService.GetUserIdentity();
|
|
||||||
|
|
||||||
var result = await _mediator.SendAsync(createOrderCommand);
|
var result = await _mediator.SendAsync(createOrderCommand);
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
|
@ -65,19 +65,18 @@
|
|||||||
|
|
||||||
string BuildOrder()
|
string BuildOrder()
|
||||||
{
|
{
|
||||||
var order = new CreateOrderCommand()
|
var order = new CreateOrderCommand(
|
||||||
{
|
cardExpiration: DateTime.UtcNow.AddYears(1),
|
||||||
CardExpiration = DateTime.UtcNow.AddYears(1),
|
cardNumber: "5145-555-5555",
|
||||||
CardNumber = "5145-555-5555",
|
cardHolderName: "Jhon Senna",
|
||||||
CardHolderName = "Jhon Senna",
|
cardSecurityNumber: "232",
|
||||||
CardSecurityNumber = "232",
|
cardTypeId: 1,
|
||||||
CardTypeId = 1,
|
city: "Redmon",
|
||||||
City = "Redmon",
|
country: "USA",
|
||||||
Country = "USA",
|
state: "WA",
|
||||||
State = "WA",
|
street: "One way",
|
||||||
Street = "One way",
|
zipcode: "zipcode"
|
||||||
ZipCode = "zipcode",
|
);
|
||||||
};
|
|
||||||
|
|
||||||
order.AddOrderItem(new OrderItemDTO()
|
order.AddOrderItem(new OrderItemDTO()
|
||||||
{
|
{
|
||||||
@ -92,19 +91,18 @@
|
|||||||
}
|
}
|
||||||
string BuildOrderWithInvalidExperationTime()
|
string BuildOrderWithInvalidExperationTime()
|
||||||
{
|
{
|
||||||
var order = new CreateOrderCommand()
|
var order = new CreateOrderCommand(
|
||||||
{
|
cardExpiration: DateTime.UtcNow.AddYears(-1),
|
||||||
CardExpiration = DateTime.UtcNow.AddYears(-1),
|
cardNumber: "5145-555-5555",
|
||||||
CardNumber = "5145-555-5555",
|
cardHolderName: "Jhon Senna",
|
||||||
CardHolderName = "Jhon Senna",
|
cardSecurityNumber: "232",
|
||||||
CardSecurityNumber = "232",
|
cardTypeId: 1,
|
||||||
CardTypeId = 1,
|
city: "Redmon",
|
||||||
City = "Redmon",
|
country: "USA",
|
||||||
Country = "USA",
|
state: "WA",
|
||||||
State = "WA",
|
street: "One way",
|
||||||
Street = "One way",
|
zipcode: "zipcode"
|
||||||
ZipCode = "zipcode"
|
);
|
||||||
};
|
|
||||||
|
|
||||||
return JsonConvert.SerializeObject(order);
|
return JsonConvert.SerializeObject(order);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
|
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
||||||
using Moq;
|
using Moq;
|
||||||
@ -13,19 +14,23 @@ namespace UnitTest.Ordering.Application
|
|||||||
{
|
{
|
||||||
private readonly Mock<IBuyerRepository<Buyer>> _buyerRepositoryMock;
|
private readonly Mock<IBuyerRepository<Buyer>> _buyerRepositoryMock;
|
||||||
private readonly Mock<IOrderRepository<Order>> _orderRepositoryMock;
|
private readonly Mock<IOrderRepository<Order>> _orderRepositoryMock;
|
||||||
|
private readonly Mock<IIdentityService> _identityServiceMock;
|
||||||
|
|
||||||
public NewOrderRequestHandlerTest()
|
public NewOrderRequestHandlerTest()
|
||||||
{
|
{
|
||||||
|
|
||||||
_buyerRepositoryMock = new Mock<IBuyerRepository<Buyer>>();
|
_buyerRepositoryMock = new Mock<IBuyerRepository<Buyer>>();
|
||||||
_orderRepositoryMock = new Mock<IOrderRepository<Order>>();
|
_orderRepositoryMock = new Mock<IOrderRepository<Order>>();
|
||||||
|
_identityServiceMock = new Mock<IIdentityService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Handle_returns_true_when_order_is_persisted_succesfully()
|
public async Task Handle_returns_true_when_order_is_persisted_succesfully()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
var buyerId = "1234";
|
||||||
// Arrange
|
// Arrange
|
||||||
_buyerRepositoryMock.Setup(buyerRepo => buyerRepo.FindAsync(FakeOrderRequestWithBuyer().BuyerIdentityGuid))
|
_buyerRepositoryMock.Setup(buyerRepo => buyerRepo.FindAsync(buyerId))
|
||||||
.Returns(Task.FromResult<Buyer>(FakeBuyer()));
|
.Returns(Task.FromResult<Buyer>(FakeBuyer()));
|
||||||
|
|
||||||
_buyerRepositoryMock.Setup(buyerRepo => buyerRepo.UnitOfWork.SaveChangesAsync(default(CancellationToken)))
|
_buyerRepositoryMock.Setup(buyerRepo => buyerRepo.UnitOfWork.SaveChangesAsync(default(CancellationToken)))
|
||||||
@ -37,8 +42,9 @@ namespace UnitTest.Ordering.Application
|
|||||||
_orderRepositoryMock.Setup(or => or.UnitOfWork.SaveChangesAsync(default(CancellationToken)))
|
_orderRepositoryMock.Setup(or => or.UnitOfWork.SaveChangesAsync(default(CancellationToken)))
|
||||||
.Returns(Task.FromResult(1));
|
.Returns(Task.FromResult(1));
|
||||||
|
|
||||||
|
_identityServiceMock.Setup(svc => svc.GetUserIdentity()).Returns(buyerId);
|
||||||
//Act
|
//Act
|
||||||
var handler = new CreateOrderCommandHandler(_buyerRepositoryMock.Object, _orderRepositoryMock.Object);
|
var handler = new CreateOrderCommandHandler(_buyerRepositoryMock.Object, _orderRepositoryMock.Object, _identityServiceMock.Object);
|
||||||
var result = await handler.Handle(FakeOrderRequestWithBuyer());
|
var result = await handler.Handle(FakeOrderRequestWithBuyer());
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
@ -48,7 +54,8 @@ namespace UnitTest.Ordering.Application
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task Handle_return_false_if_order_is_not_persisted()
|
public async Task Handle_return_false_if_order_is_not_persisted()
|
||||||
{
|
{
|
||||||
_buyerRepositoryMock.Setup(buyerRepo => buyerRepo.FindAsync(FakeOrderRequestWithBuyer().BuyerIdentityGuid))
|
var buyerId = "1234";
|
||||||
|
_buyerRepositoryMock.Setup(buyerRepo => buyerRepo.FindAsync(buyerId))
|
||||||
.Returns(Task.FromResult<Buyer>(FakeBuyer()));
|
.Returns(Task.FromResult<Buyer>(FakeBuyer()));
|
||||||
|
|
||||||
_buyerRepositoryMock.Setup(buyerRepo => buyerRepo.UnitOfWork.SaveChangesAsync(default(CancellationToken)))
|
_buyerRepositoryMock.Setup(buyerRepo => buyerRepo.UnitOfWork.SaveChangesAsync(default(CancellationToken)))
|
||||||
@ -57,9 +64,10 @@ namespace UnitTest.Ordering.Application
|
|||||||
_orderRepositoryMock.Setup(or => or.Add(FakeOrder())).Returns(FakeOrder());
|
_orderRepositoryMock.Setup(or => or.Add(FakeOrder())).Returns(FakeOrder());
|
||||||
_orderRepositoryMock.Setup(or => or.UnitOfWork.SaveChangesAsync(default(CancellationToken)))
|
_orderRepositoryMock.Setup(or => or.UnitOfWork.SaveChangesAsync(default(CancellationToken)))
|
||||||
.Returns(Task.FromResult(0));
|
.Returns(Task.FromResult(0));
|
||||||
|
_identityServiceMock.Setup(svc => svc.GetUserIdentity()).Returns(buyerId);
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var handler = new CreateOrderCommandHandler(_buyerRepositoryMock.Object, _orderRepositoryMock.Object);
|
var handler = new CreateOrderCommandHandler(_buyerRepositoryMock.Object, _orderRepositoryMock.Object, _identityServiceMock.Object);
|
||||||
var result = await handler.Handle(FakeOrderRequestWithBuyer());
|
var result = await handler.Handle(FakeOrderRequestWithBuyer());
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
@ -78,14 +86,17 @@ namespace UnitTest.Ordering.Application
|
|||||||
|
|
||||||
private CreateOrderCommand FakeOrderRequestWithBuyer()
|
private CreateOrderCommand FakeOrderRequestWithBuyer()
|
||||||
{
|
{
|
||||||
return new CreateOrderCommand
|
return new CreateOrderCommand(
|
||||||
{
|
city: null,
|
||||||
BuyerIdentityGuid = "1234",
|
street: null,
|
||||||
CardNumber = "1234",
|
state: null,
|
||||||
CardExpiration = DateTime.Now.AddYears(1),
|
country: null,
|
||||||
CardSecurityNumber = "123",
|
zipcode: null,
|
||||||
CardHolderName = "XXX"
|
cardNumber: "1234",
|
||||||
};
|
cardExpiration: DateTime.Now.AddYears(1),
|
||||||
|
cardSecurityNumber: "123",
|
||||||
|
cardHolderName: "XXX",
|
||||||
|
cardTypeId: 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user