@ -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; | |||
} | |||
} | |||
} |