@ -0,0 +1,19 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | |||||
using Microsoft.AspNetCore.Mvc; | |||||
// For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860 | |||||
namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers | |||||
{ | |||||
public class HomeController : Controller | |||||
{ | |||||
// GET: /<controller>/ | |||||
public IActionResult Index() | |||||
{ | |||||
return new RedirectResult("~/swagger/ui"); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,12 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | |||||
namespace eShopOnContainers.Identity | |||||
{ | |||||
public class AppSettings | |||||
{ | |||||
public string MvcClient { get; set; } | |||||
} | |||||
} |
@ -0,0 +1,48 @@ | |||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Api.Application.Commands | |||||
{ | |||||
using System; | |||||
using MediatR; | |||||
using Domain; | |||||
using System.Collections; | |||||
using System.Collections.Generic; | |||||
public class NewOrderRequest | |||||
:IAsyncRequest<bool> | |||||
{ | |||||
private readonly List<OrderItem> _orderItems; | |||||
public string City { get; set; } | |||||
public string Street { get; set; } | |||||
public string State { get; set; } | |||||
public string Country { get; set; } | |||||
public string ZipCode { get; set; } | |||||
public string CardNumber { get; set; } | |||||
public string CardHolderName { get; set; } | |||||
public DateTime CardExpiration { get; set; } | |||||
public string CardSecurityNumber { get; set; } | |||||
public int CardTypeId { get; set; } | |||||
public string Buyer { get; set; } | |||||
public IEnumerable<OrderItem> OrderItems => _orderItems; | |||||
public void AddOrderItem(OrderItem item) | |||||
{ | |||||
_orderItems.Add(item); | |||||
} | |||||
public NewOrderRequest() | |||||
{ | |||||
_orderItems = new List<OrderItem>(); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,118 @@ | |||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Api.Application.Commands | |||||
{ | |||||
using Domain.Repositories; | |||||
using MediatR; | |||||
using System.Linq; | |||||
using System; | |||||
using System.Threading.Tasks; | |||||
using Domain; | |||||
public class NewOrderRequestHandler | |||||
: IAsyncRequestHandler<NewOrderRequest, bool> | |||||
{ | |||||
private readonly IBuyerRepository _buyerRepository; | |||||
private readonly IOrderRepository _orderRepository; | |||||
public NewOrderRequestHandler(IBuyerRepository buyerRepository,IOrderRepository orderRepository) | |||||
{ | |||||
if (buyerRepository == null) | |||||
{ | |||||
throw new ArgumentNullException(nameof(buyerRepository)); | |||||
} | |||||
if (orderRepository == null) | |||||
{ | |||||
throw new ArgumentNullException(nameof(orderRepository)); | |||||
} | |||||
_buyerRepository = buyerRepository; | |||||
_orderRepository = orderRepository; | |||||
} | |||||
public async Task<bool> Handle(NewOrderRequest message) | |||||
{ | |||||
//find buyer/payment or add a new one buyer/payment | |||||
var buyer = await _buyerRepository.FindAsync(message.Buyer); | |||||
if (buyer == null) | |||||
{ | |||||
buyer = CreateBuyer(message); | |||||
} | |||||
var payment = GetExistingPaymentOrAddANewOne(buyer, message); | |||||
await _buyerRepository.UnitOfWork | |||||
.SaveChangesAsync(); | |||||
//create order for buyer and payment method | |||||
var order = CreateOrder(buyer.Id, payment.Id, 0); | |||||
order.SetAddress( new Address() | |||||
{ | |||||
City = message.City, | |||||
State = message.State, | |||||
Street = message.Street, | |||||
ZipCode = message.ZipCode | |||||
}); | |||||
foreach (var item in message.OrderItems) | |||||
{ | |||||
order.AddOrderItem(item); | |||||
} | |||||
_orderRepository.Add(order); | |||||
var result = await _orderRepository.UnitOfWork | |||||
.SaveChangesAsync(); | |||||
return result > 0; | |||||
} | |||||
Payment GetExistingPaymentOrAddANewOne(Buyer buyer, NewOrderRequest message) | |||||
{ | |||||
Payment payment = PaymentAlreadyExist(buyer, message); | |||||
if (payment == null) | |||||
{ | |||||
payment = CreatePayment(message); | |||||
buyer.Payments.Add(payment); | |||||
} | |||||
return payment; | |||||
} | |||||
Payment PaymentAlreadyExist(Domain.Buyer buyer, NewOrderRequest message) | |||||
{ | |||||
return buyer.Payments | |||||
.SingleOrDefault(p => | |||||
{ | |||||
return p.CardHolderName == message.CardHolderName | |||||
&& | |||||
p.CardNumber == message.CardNumber | |||||
&& | |||||
p.Expiration == message.CardExpiration | |||||
&& | |||||
p.SecurityNumber == message.CardSecurityNumber; | |||||
}); | |||||
} | |||||
Buyer CreateBuyer(NewOrderRequest message) | |||||
{ | |||||
return _buyerRepository.Add( | |||||
new Buyer(message.Buyer)); | |||||
} | |||||
Order CreateOrder(int buyerId, int paymentId, int addressId) | |||||
{ | |||||
return new Order(buyerId, paymentId); | |||||
} | |||||
Payment CreatePayment(NewOrderRequest message) | |||||
{ | |||||
return new Payment(message.CardNumber, message.CardSecurityNumber, message.CardHolderName, message.CardExpiration, message.CardTypeId); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,34 @@ | |||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Api.Application.Decorators | |||||
{ | |||||
using Extensions.Logging; | |||||
using MediatR; | |||||
using System.Threading.Tasks; | |||||
public class LogDecorator<TRequest, TResponse> | |||||
: IAsyncRequestHandler<TRequest, TResponse> | |||||
where TRequest : IAsyncRequest<TResponse> | |||||
{ | |||||
private readonly IAsyncRequestHandler<TRequest, TResponse> _inner; | |||||
private readonly ILogger<LogDecorator<TRequest, TResponse>> _logger; | |||||
public LogDecorator( | |||||
IAsyncRequestHandler<TRequest, TResponse> inner, | |||||
ILogger<LogDecorator<TRequest, TResponse>> logger) | |||||
{ | |||||
_inner = inner; | |||||
_logger = logger; | |||||
} | |||||
public async Task<TResponse> Handle(TRequest message) | |||||
{ | |||||
_logger.LogInformation($"Executing command {_inner.GetType().FullName}"); | |||||
var response = await _inner.Handle(message); | |||||
_logger.LogInformation($"Succedded executed command {_inner.GetType().FullName}"); | |||||
return response; | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,13 @@ | |||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Api.Application.Queries | |||||
{ | |||||
using System.Threading.Tasks; | |||||
public interface IOrderQueries | |||||
{ | |||||
Task<dynamic> GetOrder(int id); | |||||
Task<dynamic> GetOrders(); | |||||
Task<dynamic> GetCardTypes(); | |||||
} | |||||
} |
@ -0,0 +1,101 @@ | |||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Api.Application.Queries | |||||
{ | |||||
using Dapper; | |||||
using Microsoft.Extensions.Configuration; | |||||
using System.Data.SqlClient; | |||||
using System.Threading.Tasks; | |||||
using System; | |||||
using System.Dynamic; | |||||
using System.Collections.Generic; | |||||
public class OrderQueries | |||||
:IOrderQueries | |||||
{ | |||||
private string _connectionString = string.Empty; | |||||
public OrderQueries(IConfiguration configuration) | |||||
{ | |||||
_connectionString = configuration["ConnectionString"]; | |||||
} | |||||
public async Task<dynamic> GetOrder(int id) | |||||
{ | |||||
using (var connection = new SqlConnection(_connectionString)) | |||||
{ | |||||
connection.Open(); | |||||
var result = await connection.QueryAsync<dynamic>( | |||||
@"select o.[Id] as ordernumber,o.OrderDate as date, os.Name as status, | |||||
oi.ProductName as productname, oi.Units as units, oi.UnitPrice as unitprice, oi.PictureUrl as pictureurl, | |||||
oa.Street as street, oa.City as city, oa.Country as country, oa.State as state, oa.ZipCode as zipcode | |||||
FROM ordering.Orders o | |||||
LEFT JOIN ordering.Orderitems oi ON o.Id = oi.orderid | |||||
LEFT JOIN ordering.orderstatus os on o.StatusId = os.Id | |||||
LEFT JOIN ordering.address oa on o.ShippingAddressId = oa.Id | |||||
WHERE o.Id=@id" | |||||
, new { id } | |||||
); | |||||
if (result.AsList().Count == 0) | |||||
throw new KeyNotFoundException(); | |||||
return MapOrderItems(result); | |||||
} | |||||
} | |||||
public async Task<dynamic> GetOrders() | |||||
{ | |||||
using (var connection = new SqlConnection(_connectionString)) | |||||
{ | |||||
connection.Open(); | |||||
return await connection.QueryAsync<dynamic>(@"SELECT o.[Id] as ordernumber,o.[OrderDate] as [date],os.[Name] as [status],SUM(oi.units*oi.unitprice) as total | |||||
FROM [ordering].[Orders] o | |||||
LEFT JOIN[ordering].[orderitems] oi ON o.Id = oi.orderid | |||||
LEFT JOIN[ordering].[orderstatus] os on o.StatusId = os.Id | |||||
GROUP BY o.[Id], o.[OrderDate], os.[Name]"); | |||||
} | |||||
} | |||||
public async Task<dynamic> GetCardTypes() | |||||
{ | |||||
using (var connection = new SqlConnection(_connectionString)) | |||||
{ | |||||
connection.Open(); | |||||
return await connection.QueryAsync<dynamic>("SELECT * FROM ordering.cardtypes"); | |||||
} | |||||
} | |||||
private dynamic MapOrderItems(dynamic result) | |||||
{ | |||||
dynamic order = new ExpandoObject(); | |||||
order.ordernumber = result[0].ordernumber; | |||||
order.date = result[0].date; | |||||
order.status = result[0].status; | |||||
order.street = result[0].street; | |||||
order.city = result[0].city; | |||||
order.zipcode = result[0].zipcode; | |||||
order.country = result[0].country; | |||||
order.orderitems = new List<dynamic>(); | |||||
order.total = 0; | |||||
foreach (dynamic item in result) | |||||
{ | |||||
dynamic orderitem = new ExpandoObject(); | |||||
orderitem.productname = item.productname; | |||||
orderitem.units = item.units; | |||||
orderitem.unitprice = item.unitprice; | |||||
orderitem.pictureurl = item.pictureurl; | |||||
order.total += item.units * item.unitprice; | |||||
order.orderitems.Add(orderitem); | |||||
} | |||||
return order; | |||||
} | |||||
} | |||||
} |