Browse Source

MVC: Finish Orders integration (detail), validations, some refactor ...

Orders: Detail Query, new field in OrderDetail..
Identity: Validations in Register View, ensure all claims are returned in user end point..
pull/49/merge
Carlos Cañizares Estévez 8 years ago
parent
commit
31753fc057
59 changed files with 379 additions and 781 deletions
  1. +17
    -24
      docker-compose.override.yml
  2. +12
    -15
      docker-compose.yml
  3. +2
    -2
      src/Services/Basket/Basket.API/appsettings.json
  4. +1
    -1
      src/Services/Catalog/Catalog.API/settings.json
  5. +1
    -1
      src/Services/Identity/eShopOnContainers.Identity/Controllers/AccountController.cs
  6. +0
    -1
      src/Services/Identity/eShopOnContainers.Identity/Data/ApplicationContextSeed.cs
  7. +0
    -4
      src/Services/Identity/eShopOnContainers.Identity/Data/Migrations/20161019122215_Init_Scheme.cs
  8. +0
    -16
      src/Services/Identity/eShopOnContainers.Identity/Extensions/PrincipalExtensions.cs
  9. +12
    -4
      src/Services/Identity/eShopOnContainers.Identity/Models/ApplicationUser.cs
  10. +1
    -1
      src/Services/Identity/eShopOnContainers.Identity/Properties/launchSettings.json
  11. +3
    -0
      src/Services/Identity/eShopOnContainers.Identity/Services/ProfileService.cs
  12. +2
    -2
      src/Services/Identity/eShopOnContainers.Identity/appsettings.json
  13. +13
    -30
      src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs
  14. +1
    -0
      src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20161124133626_InitialModel.cs
  15. +2
    -0
      src/Services/Ordering/Ordering.API/Models/OrderItemViewModel.cs
  16. +2
    -2
      src/Services/Ordering/Ordering.API/Program.cs
  17. +1
    -1
      src/Services/Ordering/Ordering.API/Properties/launchSettings.json
  18. +0
    -10
      src/Services/Ordering/Ordering.API/appsettings.json
  19. +10
    -2
      src/Services/Ordering/Ordering.API/settings.json
  20. +49
    -2
      src/Services/Ordering/Ordering.Application/Queries/OrderQueries.cs
  21. +2
    -0
      src/Services/Ordering/Ordering.Domain/OrderItem.cs
  22. +7
    -16
      src/Web/WebMVC/Controllers/OrderController.cs
  23. +0
    -15
      src/Web/WebMVC/Models/AccountViewModels/ExternalLoginConfirmationViewModel.cs
  24. +0
    -15
      src/Web/WebMVC/Models/AccountViewModels/ForgotPasswordViewModel.cs
  25. +0
    -22
      src/Web/WebMVC/Models/AccountViewModels/LoginViewModel.cs
  26. +0
    -29
      src/Web/WebMVC/Models/AccountViewModels/RegisterViewModel.cs
  27. +0
    -27
      src/Web/WebMVC/Models/AccountViewModels/ResetPasswordViewModel.cs
  28. +0
    -19
      src/Web/WebMVC/Models/AccountViewModels/SendCodeViewModel.cs
  29. +0
    -25
      src/Web/WebMVC/Models/AccountViewModels/VerifyCodeViewModel.cs
  30. +0
    -21
      src/Web/WebMVC/Models/Address.cs
  31. +24
    -0
      src/Web/WebMVC/Models/Annotations/CardExpiration.cs
  32. +0
    -16
      src/Web/WebMVC/Models/ManageViewModels/AddPhoneNumberViewModel.cs
  33. +0
    -27
      src/Web/WebMVC/Models/ManageViewModels/ChangePasswordViewModel.cs
  34. +0
    -15
      src/Web/WebMVC/Models/ManageViewModels/ConfigureTwoFactorViewModel.cs
  35. +0
    -12
      src/Web/WebMVC/Models/ManageViewModels/FactorViewModel.cs
  36. +0
    -23
      src/Web/WebMVC/Models/ManageViewModels/IndexViewModel.cs
  37. +0
    -16
      src/Web/WebMVC/Models/ManageViewModels/ManageLoginsViewModel.cs
  38. +0
    -14
      src/Web/WebMVC/Models/ManageViewModels/RemoveLoginViewModel.cs
  39. +0
    -22
      src/Web/WebMVC/Models/ManageViewModels/SetPasswordViewModel.cs
  40. +0
    -19
      src/Web/WebMVC/Models/ManageViewModels/VerifyPhoneNumberViewModel.cs
  41. +52
    -30
      src/Web/WebMVC/Models/Order.cs
  42. +7
    -9
      src/Web/WebMVC/Models/OrderItem.cs
  43. +0
    -40
      src/Web/WebMVC/Models/OrderRequest.cs
  44. +0
    -20
      src/Web/WebMVC/Models/OrderRequestItem.cs
  45. +0
    -12
      src/Web/WebMVC/Models/OrderViewModels/CreateOrderViewModel.cs
  46. +0
    -25
      src/Web/WebMVC/Models/PaymentInfo.cs
  47. +1
    -1
      src/Web/WebMVC/Properties/launchSettings.json
  48. +7
    -10
      src/Web/WebMVC/Services/BasketService.cs
  49. +1
    -1
      src/Web/WebMVC/Services/IOrderingService.cs
  50. +22
    -90
      src/Web/WebMVC/Services/OrderingService.cs
  51. +27
    -26
      src/Web/WebMVC/Views/Order/Create.cshtml
  52. +10
    -19
      src/Web/WebMVC/Views/Order/Detail.cshtml
  53. +4
    -4
      src/Web/WebMVC/Views/Order/Index.cshtml
  54. +73
    -0
      src/Web/WebMVC/Views/Order/_OrderItems.cshtml
  55. +0
    -10
      src/Web/WebMVC/Views/Shared/Components/CartList/Default.cshtml
  56. +11
    -9
      src/Web/WebMVC/Views/Shared/Error.cshtml
  57. +0
    -2
      src/Web/WebMVC/Views/_ViewImports.cshtml
  58. +1
    -1
      src/Web/WebMVC/appsettings.json
  59. +1
    -1
      src/Web/WebMVC/wwwroot/css/site.css

+ 17
- 24
docker-compose.override.yml View File

@ -9,15 +9,15 @@ version: '2'
services:
webmvc:
environment:
- CatalogUrl=http://catalog.api
- OrderingUrl=http://ordering.api:5102
# webmvc:
# environment:
# - CatalogUrl=http://catalog.api
# - OrderingUrl=http://ordering.api:5102
#- IdentityUrl=http://104.40.62.65:5105 #Remote: VM Needs to have public access at 5105.
- IdentityUrl=http://identity.service:5105 #Local: You need a entry in windows host file to run identity in local docker.
- BasketUrl=http://basket.api:5103
ports:
- "5100:5100"
# - IdentityUrl=http://identity.service:5105 #Local: You need a entry in windows host file to run identity in local docker.
# - BasketUrl=http://basket.api:5103
# ports:
# - "5100:5100"
webspa:
environment:
@ -39,38 +39,31 @@ services:
catalog.api:
environment:
- ConnectionString=Server=business.data;Database=CatalogDB;User Id=sa;Password=Pass@word
- ConnectionString=Server=sql.data;Database=CatalogDB;User Id=sa;Password=Pass@word
ports:
- "5101:80"
ordering.api:
environment:
- ConnectionString=Server=business.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word
- identityUrl=http://identity.service:5105 #local
# ordering.api:
# environment:
# - ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word
# - identityUrl=http://identity.service:5105 #local
#- identityUrl=http://104.40.62.65:5105 #remote
ports:
- "5102:5102"
# ports:
# - "5102:5102"
identity.service:
environment:
- SpaClient=http://localhost:5104
- ConnectionStrings__DefaultConnection=Server=identity.data;Database=aspnet-Microsoft.eShopOnContainers;User Id=sa;Password=Pass@word
- ConnectionStrings__DefaultConnection=Server=sql.data;Database=aspnet-Microsoft.eShopOnContainers;User Id=sa;Password=Pass@word
#- MvcClient=http://104.40.62.65:5100 #Remote: VM Needs to have public access at 5105.
- MvcClient=http://localhost:5100 #Local: You need a entry in windows host file to run identity in local docker.
#10.0.75.1:5105 CCE/TODO: try to avoid host entry.
ports:
- "5105:5105"
identity.data:
sql.data:
environment:
- SA_PASSWORD=Pass@word
- ACCEPT_EULA=Y
ports:
- "5433:1433"
business.data:
environment:
- SA_PASSWORD=Pass@word
- ACCEPT_EULA=Y
ports:
- "5434:1433"

+ 12
- 15
docker-compose.yml View File

@ -7,11 +7,11 @@
version: '2'
services:
webmvc:
image: eshop/web
depends_on:
- identity.service
- basket.api
# webmvc:
# image: eshop/web
# depends_on:
# - identity.service
# - basket.api
webspa:
image: eshop/webspa
@ -28,22 +28,19 @@ services:
catalog.api:
image: eshop/catalog.api
depends_on:
- business.data
- sql.data
ordering.api:
image: eshop/ordering.api
depends_on:
- business.data
# ordering.api:
# image: eshop/ordering.api
# depends_on:
# - sql.data
identity.service:
image: eshop/identity
depends_on:
- identity.data
identity.data:
image: microsoft/mssql-server-linux
- sql.data
business.data:
sql.data:
image: microsoft/mssql-server-linux
basket.data:


+ 2
- 2
src/Services/Basket/Basket.API/appsettings.json View File

@ -1,4 +1,4 @@
{
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
@ -7,6 +7,6 @@
"Microsoft": "Information"
}
},
"IdentityUrl": "http://localhost:5000",
"IdentityUrl": "http://identity.service:5105",
"ConnectionString": "127.0.0.1"
}

+ 1
- 1
src/Services/Catalog/Catalog.API/settings.json View File

@ -1,5 +1,5 @@
{
"ConnectionString": "Server=tcp:127.0.0.1,5434;Initial Catalog=CatalogDB;User Id=sa;Password=Pass@word",
"ConnectionString": "Server=tcp:127.0.0.1,5433;Initial Catalog=CatalogDB;User Id=sa;Password=Pass@word",
"Logging": {
"IncludeScopes": false,
"LogLevel": {


+ 1
- 1
src/Services/Identity/eShopOnContainers.Identity/Controllers/AccountController.cs View File

@ -99,7 +99,7 @@ namespace IdentityServer4.Quickstart.UI.Controllers
props = new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTimeOffset.UtcNow.AddMonths(1)
ExpiresUtc = DateTimeOffset.UtcNow.AddYears(10)
};
};


+ 0
- 1
src/Services/Identity/eShopOnContainers.Identity/Data/ApplicationContextSeed.cs View File

@ -61,7 +61,6 @@
CardType = 1,
City = "Redmond",
Country = "U.S.",
CountryCode = "91",
Email = "demouser@microsoft.com",
Expiration = "12/20",
Id = Guid.NewGuid().ToString(),


+ 0
- 4
src/Services/Identity/eShopOnContainers.Identity/Data/Migrations/20161019122215_Init_Scheme.cs View File

@ -49,14 +49,11 @@ namespace WebMVC.Migrations
City = table.Column<string>(nullable: true),
ConcurrencyStamp = table.Column<string>(nullable: true),
Country = table.Column<string>(nullable: true),
CountryCode = table.Column<string>(nullable: true),
Email = table.Column<string>(maxLength: 256, nullable: true),
EmailConfirmed = table.Column<bool>(nullable: false),
Expiration = table.Column<string>(nullable: true),
Latitude = table.Column<double>(nullable: false),
LockoutEnabled = table.Column<bool>(nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(nullable: true),
Longitude = table.Column<double>(nullable: false),
NormalizedEmail = table.Column<string>(maxLength: 256, nullable: true),
NormalizedUserName = table.Column<string>(maxLength: 256, nullable: true),
PasswordHash = table.Column<string>(nullable: true),
@ -65,7 +62,6 @@ namespace WebMVC.Migrations
SecurityNumber = table.Column<string>(nullable: true),
SecurityStamp = table.Column<string>(nullable: true),
State = table.Column<string>(nullable: true),
StateCode = table.Column<string>(nullable: true),
Street = table.Column<string>(nullable: true),
TwoFactorEnabled = table.Column<bool>(nullable: false),
UserName = table.Column<string>(maxLength: 256, nullable: true),


+ 0
- 16
src/Services/Identity/eShopOnContainers.Identity/Extensions/PrincipalExtensions.cs View File

@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.Threading.Tasks;
namespace eShopOnContainers.Identity.Extensions
{
//public static class PrincipalExtensions
//{
// public static string GetSubjectId(this IPrincipal principal)
// {
// return principal.Identity.GetSubjectId();
// }
//}
}

+ 12
- 4
src/Services/Identity/eShopOnContainers.Identity/Models/ApplicationUser.cs View File

@ -10,21 +10,29 @@ namespace eShopOnContainers.Identity.Models
// Add profile data for application users by adding properties to the ApplicationUser class
public class ApplicationUser : IdentityUser
{
[Required]
public string CardNumber { get; set; }
[Required]
public string SecurityNumber { get; set; }
[Required]
[RegularExpression(@"(0[1-9]|1[0-2])\/[0-9]{2}", ErrorMessage = "Expiration should match a valid MM/YY value")]
public string Expiration { get; set; }
[Required]
public string CardHolderName { get; set; }
public int CardType { get; set; }
[Required]
public string Street { get; set; }
[Required]
public string City { get; set; }
[Required]
public string State { get; set; }
public string StateCode { get; set; }
[Required]
public string Country { get; set; }
public string CountryCode { get; set; }
[Required]
public string ZipCode { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string LastName { get; set; }
}
}

+ 1
- 1
src/Services/Identity/eShopOnContainers.Identity/Properties/launchSettings.json View File

@ -11,7 +11,7 @@
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "http://localhost:5000",
"launchUrl": "http://localhost:5105",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}


+ 3
- 0
src/Services/Identity/eShopOnContainers.Identity/Services/ProfileService.cs View File

@ -88,6 +88,9 @@ namespace eShopOnContainers.Identity.Services
if (!string.IsNullOrWhiteSpace(user.SecurityNumber))
claims.Add(new Claim("card_security_number", user.SecurityNumber));
if (!string.IsNullOrWhiteSpace(user.Expiration))
claims.Add(new Claim("card_expiration", user.Expiration));
if (!string.IsNullOrWhiteSpace(user.City))
claims.Add(new Claim("address_city", user.City));


+ 2
- 2
src/Services/Identity/eShopOnContainers.Identity/appsettings.json View File

@ -1,8 +1,8 @@
{
{
"ConnectionStrings": {
"DefaultConnection": "Server=127.0.0.1,5433;Database=aspnet-Microsoft.eShopOnContainers;User Id=sa;Password=Pass@word"
},
"MvcClient": "http://localhost:5001",
"MvcClient": "http://localhost:5100",
"SpaClient": "http://localhost:5104",
"Logging": {
"IncludeScopes": false,


+ 13
- 30
src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs View File

@ -7,6 +7,7 @@
using Microsoft.AspNetCore.Mvc;
using Models;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
[Route("api/v1/[controller]")]
@ -34,38 +35,14 @@
[Route("new")]
[HttpPost]
public async Task<IActionResult> AddOrder([FromBody]NewOrderViewModel order)
public async Task<IActionResult> AddOrder([FromBody]NewOrderRequest order)
{
if (order.CardExpiration == DateTime.MinValue)
order.CardExpiration = DateTime.Now;
var newOrderRequest = new NewOrderRequest()
{
Buyer = GetUserName(),
CardTypeId = 1, //TODO
CardHolderName = order.CardHolderName,
CardNumber = order.CardNumber,
CardExpiration = order.CardExpiration,
CardSecurityNumber = order.CardSecurityNumber,
State = order.ShippingState,
City = order.ShippingCity,
Country = order.ShippingCountry,
Street = order.ShippingStreet
};
foreach (var orderItem in order.Items)
{
newOrderRequest.AddOrderItem(new Domain.OrderItem() {
Discount = orderItem.Discount,
ProductId = orderItem.ProductId,
UnitPrice = orderItem.UnitPrice,
ProductName = orderItem.ProductName,
Units = orderItem.Units
});
}
var added = await _mediator.SendAsync(newOrderRequest);
order.Buyer = GetUserName();
var added = await _mediator.SendAsync(order);
if (added)
{
return Ok();
@ -78,9 +55,15 @@
[HttpGet]
public async Task<IActionResult> GetOrder(int orderId)
{
var order = await _orderQueries.GetOrder(orderId);
return Ok(order);
try
{
var order = await _orderQueries.GetOrder(orderId);
return Ok(order);
}
catch (KeyNotFoundException)
{
return NotFound();
}
}
[Route("")]


+ 1
- 0
src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20161124133626_InitialModel.cs View File

@ -172,6 +172,7 @@ namespace Ordering.API.Infrastructure.Migrations
OrderId = table.Column<int>(nullable: false),
ProductId = table.Column<int>(nullable: false),
ProductName = table.Column<string>(nullable: false),
PictureUrl = table.Column<string>(nullable: false),
UnitPrice = table.Column<decimal>(nullable: false),
Units = table.Column<int>(nullable: false, defaultValue: 1)
},


+ 2
- 0
src/Services/Ordering/Ordering.API/Models/OrderItemViewModel.cs View File

@ -11,5 +11,7 @@
public decimal Discount { get; set; }
public int Units { get; set; }
public string PictureUrl { get; set; }
}
}

+ 2
- 2
src/Services/Ordering/Ordering.API/Program.cs View File

@ -15,9 +15,9 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
//.UseIISIntegration()
.UseStartup<Startup>()
.UseUrls("http://0.0.0.0:5102")
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();


+ 1
- 1
src/Services/Ordering/Ordering.API/Properties/launchSettings.json View File

@ -3,7 +3,7 @@
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:5002/",
"applicationUrl": "http://localhost:5102/",
"sslPort": 0
}
},


+ 0
- 10
src/Services/Ordering/Ordering.API/appsettings.json View File

@ -1,10 +0,0 @@
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}

+ 10
- 2
src/Services/Ordering/Ordering.API/settings.json View File

@ -1,4 +1,12 @@
{
"ConnectionString": "Server=tcp:127.0.0.1,5434;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;",
"IdentityUrl": "http://localhost:5105"
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;",
"IdentityUrl": "http://identity.service:5105",
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}

+ 49
- 2
src/Services/Ordering/Ordering.Application/Queries/OrderQueries.cs View File

@ -5,6 +5,8 @@
using System.Data.SqlClient;
using System.Threading.Tasks;
using System;
using System.Dynamic;
using System.Collections.Generic;
public class OrderQueries
:IOrderQueries
@ -16,14 +18,29 @@
_connectionString = configuration["ConnectionString"];
}
public async Task<dynamic> GetOrder(int id)
{
using (var connection = new SqlConnection(_connectionString))
{
connection.Open();
return await connection.QueryAsync<dynamic>("SELECT * FROM ordering.Orders where Id=@id",new { id });
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);
}
}
@ -50,5 +67,35 @@
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;
}
}
}

+ 2
- 0
src/Services/Ordering/Ordering.Domain/OrderItem.cs View File

@ -10,6 +10,8 @@
public string ProductName { get; set; }
public string PictureUrl { get; set; }
public int OrderId { get; set; }
public decimal UnitPrice { get; set; }


+ 7
- 16
src/Web/WebMVC/Controllers/OrderController.cs View File

@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopOnContainers.WebMVC.Services;
using Microsoft.eShopOnContainers.WebMVC.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.eShopOnContainers.WebMVC.Models.OrderViewModels;
using System.Net.Http;
namespace Microsoft.eShopOnContainers.WebMVC.Controllers
{
@ -25,31 +25,22 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
public async Task<IActionResult> Create()
{
var vm = new CreateOrderViewModel();
var user = _appUserParser.Parse(HttpContext.User);
var basket = await _basketSvc.GetBasket(user);
var order = _basketSvc.MapBasketToOrder(basket);
vm.Order = _orderSvc.MapUserInfoIntoOrder(user, order);
var vm = _orderSvc.MapUserInfoIntoOrder(user, order);
vm.CardExpirationShortFormat();
return View(vm);
}
[HttpPost]
public async Task<IActionResult> Create(CreateOrderViewModel model, Dictionary<string, int> quantities, string action)
public async Task<IActionResult> Create(Order model, string action)
{
var user = _appUserParser.Parse(HttpContext.User);
var basket = await _basketSvc.SetQuantities(user, quantities);
basket = await _basketSvc.UpdateBasket(basket);
var order = _basketSvc.MapBasketToOrder(basket);
// override if user has changed some shipping address or payment info data.
_orderSvc.OverrideUserInfoIntoOrder(model.Order, order);
if (action == "[ Place Order ]")
{
await _orderSvc.CreateOrder(user, order);
await _orderSvc.CreateOrder(model);
//Empty basket for current user.
await _basketSvc.CleanBasket(user);
@ -61,11 +52,11 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
return View(model);
}
public IActionResult Detail(string orderId)
public async Task<IActionResult> Detail(string orderId)
{
var user = _appUserParser.Parse(HttpContext.User);
var order = _orderSvc.GetOrder(user, orderId);
var order = await _orderSvc.GetOrder(user, orderId);
return View(order);
}


+ 0
- 15
src/Web/WebMVC/Models/AccountViewModels/ExternalLoginConfirmationViewModel.cs View File

@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Models.AccountViewModels
{
public class ExternalLoginConfirmationViewModel
{
[Required]
[EmailAddress]
public string Email { get; set; }
}
}

+ 0
- 15
src/Web/WebMVC/Models/AccountViewModels/ForgotPasswordViewModel.cs View File

@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Models.AccountViewModels
{
public class ForgotPasswordViewModel
{
[Required]
[EmailAddress]
public string Email { get; set; }
}
}

+ 0
- 22
src/Web/WebMVC/Models/AccountViewModels/LoginViewModel.cs View File

@ -1,22 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Models.AccountViewModels
{
public class LoginViewModel
{
[Required]
[EmailAddress]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
}
}

+ 0
- 29
src/Web/WebMVC/Models/AccountViewModels/RegisterViewModel.cs View File

@ -1,29 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Models.AccountViewModels
{
public class RegisterViewModel
{
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
public ApplicationUser User { get; set; }
}
}

+ 0
- 27
src/Web/WebMVC/Models/AccountViewModels/ResetPasswordViewModel.cs View File

@ -1,27 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Models.AccountViewModels
{
public class ResetPasswordViewModel
{
[Required]
[EmailAddress]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
public string Code { get; set; }
}
}

+ 0
- 19
src/Web/WebMVC/Models/AccountViewModels/SendCodeViewModel.cs View File

@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace Microsoft.eShopOnContainers.WebMVC.Models.AccountViewModels
{
public class SendCodeViewModel
{
public string SelectedProvider { get; set; }
public ICollection<SelectListItem> Providers { get; set; }
public string ReturnUrl { get; set; }
public bool RememberMe { get; set; }
}
}

+ 0
- 25
src/Web/WebMVC/Models/AccountViewModels/VerifyCodeViewModel.cs View File

@ -1,25 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Models.AccountViewModels
{
public class VerifyCodeViewModel
{
[Required]
public string Provider { get; set; }
[Required]
public string Code { get; set; }
public string ReturnUrl { get; set; }
[Display(Name = "Remember this browser?")]
public bool RememberBrowser { get; set; }
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
}
}

+ 0
- 21
src/Web/WebMVC/Models/Address.cs View File

@ -1,21 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Models
{
public class Address
{
public Guid Id { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string StateCode { get; set; }
public string Country { get; set; }
public string CountryCode { get; set; }
public string ZipCode { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
}
}

+ 24
- 0
src/Web/WebMVC/Models/Annotations/CardExpiration.cs View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Models.Annotations
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
public class CardExpirationAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
if (value == null)
return false;
var month = value.ToString().Split('/')[0];
var year = $"20{value.ToString().Split('/')[1]}";
DateTime d = new DateTime(int.Parse(year), int.Parse(month), 1);
return d > DateTime.UtcNow;
}
}
}

+ 0
- 16
src/Web/WebMVC/Models/ManageViewModels/AddPhoneNumberViewModel.cs View File

@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Models.ManageViewModels
{
public class AddPhoneNumberViewModel
{
[Required]
[Phone]
[Display(Name = "Phone number")]
public string PhoneNumber { get; set; }
}
}

+ 0
- 27
src/Web/WebMVC/Models/ManageViewModels/ChangePasswordViewModel.cs View File

@ -1,27 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Models.ManageViewModels
{
public class ChangePasswordViewModel
{
[Required]
[DataType(DataType.Password)]
[Display(Name = "Current password")]
public string OldPassword { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "New password")]
public string NewPassword { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm new password")]
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
}

+ 0
- 15
src/Web/WebMVC/Models/ManageViewModels/ConfigureTwoFactorViewModel.cs View File

@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace Microsoft.eShopOnContainers.WebMVC.Models.ManageViewModels
{
public class ConfigureTwoFactorViewModel
{
public string SelectedProvider { get; set; }
public ICollection<SelectListItem> Providers { get; set; }
}
}

+ 0
- 12
src/Web/WebMVC/Models/ManageViewModels/FactorViewModel.cs View File

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Models.ManageViewModels
{
public class FactorViewModel
{
public string Purpose { get; set; }
}
}

+ 0
- 23
src/Web/WebMVC/Models/ManageViewModels/IndexViewModel.cs View File

@ -1,23 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
namespace Microsoft.eShopOnContainers.WebMVC.Models.ManageViewModels
{
public class IndexViewModel
{
public bool HasPassword { get; set; }
public IList<UserLoginInfo> Logins { get; set; }
public string PhoneNumber { get; set; }
public bool TwoFactor { get; set; }
public bool BrowserRemembered { get; set; }
public ApplicationUser User { get; set; }
}
}

+ 0
- 16
src/Web/WebMVC/Models/ManageViewModels/ManageLoginsViewModel.cs View File

@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.AspNetCore.Identity;
namespace Microsoft.eShopOnContainers.WebMVC.Models.ManageViewModels
{
public class ManageLoginsViewModel
{
public IList<UserLoginInfo> CurrentLogins { get; set; }
public IList<AuthenticationDescription> OtherLogins { get; set; }
}
}

+ 0
- 14
src/Web/WebMVC/Models/ManageViewModels/RemoveLoginViewModel.cs View File

@ -1,14 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Models.ManageViewModels
{
public class RemoveLoginViewModel
{
public string LoginProvider { get; set; }
public string ProviderKey { get; set; }
}
}

+ 0
- 22
src/Web/WebMVC/Models/ManageViewModels/SetPasswordViewModel.cs View File

@ -1,22 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Models.ManageViewModels
{
public class SetPasswordViewModel
{
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "New password")]
public string NewPassword { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm new password")]
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
}

+ 0
- 19
src/Web/WebMVC/Models/ManageViewModels/VerifyPhoneNumberViewModel.cs View File

@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Models.ManageViewModels
{
public class VerifyPhoneNumberViewModel
{
[Required]
public string Code { get; set; }
[Required]
[Phone]
[Display(Name = "Phone number")]
public string PhoneNumber { get; set; }
}
}

+ 52
- 30
src/Web/WebMVC/Models/Order.cs View File

@ -1,6 +1,7 @@
using System;
using Microsoft.eShopOnContainers.WebMVC.Models.Annotations;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
@ -8,40 +9,61 @@ namespace Microsoft.eShopOnContainers.WebMVC.Models
{
public class Order
{
public Order()
{
public Order() {
OrderItems = new List<OrderItem>();
ShippingAddress = new Address();
PaymentInfo = new PaymentInfo();
}
public string Id;
public List<OrderItem> OrderItems { get; set; }
public string OrderNumber
public string OrderNumber {get;set;}
public DateTime Date {get;set;}
public string Status { get; set; }
public decimal Total {get;set;}
[Required]
public string City { get; set; }
[Required]
public string Street { get; set; }
[Required]
public string State { get; set; }
[Required]
public string Country { get; set; }
public string ZipCode { get; set; }
[Required]
public string CardNumber { get; set; }
[Required]
public string CardHolderName { get; set; }
public DateTime CardExpiration { get; set; }
[RegularExpression(@"(0[1-9]|1[0-2])\/[0-9]{2}", ErrorMessage = "Expiration should match a valid MM/YY value")]
[CardExpiration(ErrorMessage = "Should't be expired"), Required]
public string CardExpirationShort { get; set; }
[Required]
public string CardSecurityNumber { get; set; }
public int CardTypeId { get; set; }
public string Buyer { get; set; }
public List<OrderItem> OrderItems { get; }
public void CardExpirationShortFormat()
{
get
{
return string.Format("{0}/{1}-{2}", OrderDate.Year, OrderDate.Month, SequenceNumber);
}
CardExpirationShort = CardExpiration.ToString("MM/yy");
}
public void CardExpirationApiFormat()
{
var month = CardExpirationShort.Split('/')[0];
var year = $"20{CardExpirationShort.Split('/')[1]}";
CardExpiration = new DateTime(int.Parse(year), int.Parse(month), 1);
}
public int SequenceNumber { get; set; }
public virtual string BuyerId { get; set; }
public virtual Address ShippingAddress { get; set; }
public virtual PaymentInfo PaymentInfo { get; set; }
public virtual DateTime OrderDate { get; set; }
public OrderState State { get; set; }
public decimal Total() {
return OrderItems.Sum(x => x.Quantity * x.UnitPrice);
}
//(CCE) public virtual Address BillingAddress { get; set; }
//(CDLTLL) public virtual OrderStatus Status { get; set; }
}
public enum OrderState:int
public enum CardType
{
InProcess = 0,
Delivered = 1
AMEX = 1
}
}

+ 7
- 9
src/Web/WebMVC/Models/OrderItem.cs View File

@ -7,18 +7,16 @@ namespace Microsoft.eShopOnContainers.WebMVC.Models
{
public class OrderItem
{
public string Id;
public string ProductId { get; set; }
public string OrderId { get; set; }
public int ProductId { get; set; }
public string ProductName { get; set; }
public decimal UnitPrice { get; set; }
public int Quantity { get; set; }
public decimal Discount { get; set; }
public int Units { get; set; }
public string PictureUrl { get; set; }
public override string ToString()
{
return String.Format("Product Id: {0}, Quantity: {1}", this.Id, this.Quantity);
}
}
}

+ 0
- 40
src/Web/WebMVC/Models/OrderRequest.cs View File

@ -1,40 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Models
{
public class OrderRequest
{
public OrderRequest() {
Items = new List<OrderRequestItem>();
}
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 List<OrderRequestItem> Items { get; }
}
}

+ 0
- 20
src/Web/WebMVC/Models/OrderRequestItem.cs View File

@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Models
{
public class OrderRequestItem
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public decimal UnitPrice { get; set; }
public decimal Discount { get; set; }
public int Units { get; set; }
}
}

+ 0
- 12
src/Web/WebMVC/Models/OrderViewModels/CreateOrderViewModel.cs View File

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Models.OrderViewModels
{
public class CreateOrderViewModel
{
public Order Order { get; set; }
}
}

+ 0
- 25
src/Web/WebMVC/Models/PaymentInfo.cs View File

@ -1,25 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Models
{
public class PaymentInfo
{
public Guid Id { get; set; }
public string CardNumber {get;set;}
public string SecurityNumber { get; set; }
public int ExpirationMonth { get; set; } //CCE: I would simplify with a string Expiration field so I guess we are not going to validate with real data. It's a demo..
public int ExpirationYear { get; set; } //CCE: Idem.
public string CardHolderName { get; set; }
public CardType CardType { get; set; } //CCE: Discuss with team if this is needed for a demo.
public string Expiration { get; set; } //CCE: Added to simplify..
}
public enum CardType:int
{
AMEX,
VISA
}
}

+ 1
- 1
src/Web/WebMVC/Properties/launchSettings.json View File

@ -3,7 +3,7 @@
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:5001",
"applicationUrl": "http://localhost:5100",
"sslPort": 0
}
},


+ 7
- 10
src/Web/WebMVC/Services/BasketService.cs View File

@ -79,23 +79,21 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
public Order MapBasketToOrder(Basket basket)
{
var order = new Order()
{
Id = Guid.NewGuid().ToString(),
BuyerId = basket.BuyerId
};
var order = new Order();
order.Total = 0;
basket.Items.ForEach(x =>
{
order.OrderItems.Add(new OrderItem()
{
ProductId = x.ProductId,
OrderId = order.Id,
ProductId = int.Parse(x.ProductId),
PictureUrl = x.PictureUrl,
ProductName = x.ProductName,
Quantity = x.Quantity,
Units = x.Quantity,
UnitPrice = x.UnitPrice
});
order.Total += (x.Quantity * x.UnitPrice);
});
return order;
@ -109,8 +107,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
basket = new Basket()
{
BuyerId = user.Id,
//Id = Guid.NewGuid().ToString(),
Items = new List<Models.BasketItem>()
Items = new List<BasketItem>()
};
}


+ 1
- 1
src/Web/WebMVC/Services/IOrderingService.cs View File

@ -10,7 +10,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
{
Task<List<Order>> GetMyOrders(ApplicationUser user);
Task<Order> GetOrder(ApplicationUser user, string orderId);
Task CreateOrder(ApplicationUser user, Order order);
Task CreateOrder(Order order);
Order MapUserInfoIntoOrder(ApplicationUser user, Order order);
void OverrideUserInfoIntoOrder(Order original, Order destination);
}


+ 22
- 90
src/Web/WebMVC/Services/OrderingService.cs View File

@ -23,45 +23,6 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
_remoteServiceBaseUrl = $"{settings.Value.OrderingUrl}/api/v1/orders";
_settings = settings;
_httpContextAccesor = httpContextAccesor;
#region fake items
//_orders = new List<Order>()
//{
// new Order()
// {
// Id = Guid.NewGuid().ToString(),
// BuyerId = new Guid("ebcbcb4c-b032-4baa-834b-7fd66d37bc95").ToString(),
// OrderDate = DateTime.Now,
// State = OrderState.InProcess,
// OrderItems = new List<OrderItem>()
// {
// new OrderItem() { UnitPrice = 12.40m, PictureUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt", Quantity = 1, ProductName="Roslyn Red T-Shirt" }
// }
// },
// new Order()
// {
// Id = Guid.NewGuid().ToString(),
// BuyerId = new Guid("ebcbcb4c-b032-4baa-834b-7fd66d37bc95").ToString(),
// OrderDate = DateTime.Now,
// State = OrderState.InProcess,
// OrderItems = new List<OrderItem>()
// {
// new OrderItem() { UnitPrice = 12.00m, PictureUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt", Quantity = 1, ProductName="Roslyn Red T-Shirt" }
// }
// },
// new Order()
// {
// Id = Guid.NewGuid().ToString(),
// BuyerId = new Guid("ebcbcb4c-b032-4baa-834b-7fd66d37bc95").ToString(),
// OrderDate = DateTime.Now,
// State = OrderState.Delivered,
// OrderItems = new List<OrderItem>()
// {
// new OrderItem() { UnitPrice = 12.05m, PictureUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt", Quantity = 1, ProductName="Roslyn Red T-Shirt" }
// }
// }
//};
#endregion
}
async public Task<Order> GetOrder(ApplicationUser user, string Id)
@ -74,6 +35,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
var ordersUrl = $"{_remoteServiceBaseUrl}/{Id}";
var dataString = await _apiClient.GetStringAsync(ordersUrl);
var response = JsonConvert.DeserializeObject<Order>(dataString);
return response;
@ -96,50 +58,20 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
public Order MapUserInfoIntoOrder(ApplicationUser user, Order order)
{
order.ShippingAddress.City = user.City;
order.ShippingAddress.Street = user.Street;
order.ShippingAddress.State = user.State;
order.ShippingAddress.Country = user.Country;
order.City = user.City;
order.Street = user.Street;
order.State = user.State;
order.Country = user.Country;
order.PaymentInfo.CardNumber = user.CardNumber;
order.PaymentInfo.CardHolderName = user.CardHolderName;
order.PaymentInfo.Expiration = user.Expiration;
order.PaymentInfo.SecurityNumber = user.SecurityNumber;
order.CardNumber = user.CardNumber;
order.CardHolderName = user.CardHolderName;
//order.CardExpiration = user.Expiration;
order.CardSecurityNumber = user.SecurityNumber;
return order;
}
public OrderRequest MapOrderIntoOrderRequest(Order order)
{
var od = new OrderRequest()
{
CardHolderName = order.PaymentInfo.CardHolderName,
CardNumber = order.PaymentInfo.CardNumber,
CardSecurityNumber = order.PaymentInfo.SecurityNumber,
CardTypeId = (int)order.PaymentInfo.CardType,
City = order.ShippingAddress.City,
Country = order.ShippingAddress.Country,
State = order.ShippingAddress.State,
Street = order.ShippingAddress.Street,
ZipCode = order.ShippingAddress.ZipCode,
};
foreach (var item in order.OrderItems)
{
od.Items.Add(new OrderRequestItem()
{
Discount = item.Discount,
ProductId = int.Parse(item.ProductId),
ProductName = item.ProductName,
UnitPrice = item.UnitPrice,
Units = item.Quantity
});
}
return od;
}
async public Task CreateOrder(ApplicationUser user, Order order)
async public Task CreateOrder(Order order)
{
var context = _httpContextAccesor.HttpContext;
var token = await context.Authentication.GetTokenAsync("access_token");
@ -148,9 +80,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
_apiClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
var ordersUrl = $"{_remoteServiceBaseUrl}/new";
order.PaymentInfo.CardType = CardType.AMEX;
OrderRequest request = MapOrderIntoOrderRequest(order);
StringContent content = new StringContent(JsonConvert.SerializeObject(request), System.Text.Encoding.UTF8, "application/json");
order.CardTypeId = 1;
order.CardExpirationApiFormat();
StringContent content = new StringContent(JsonConvert.SerializeObject(order), System.Text.Encoding.UTF8, "application/json");
var response = await _apiClient.PostAsync(ordersUrl, content);
@ -160,15 +92,15 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
public void OverrideUserInfoIntoOrder(Order original, Order destination)
{
destination.ShippingAddress.City = original.ShippingAddress.City;
destination.ShippingAddress.Street = original.ShippingAddress.Street;
destination.ShippingAddress.State = original.ShippingAddress.State;
destination.ShippingAddress.Country = original.ShippingAddress.Country;
destination.PaymentInfo.CardNumber = original.PaymentInfo.CardNumber;
destination.PaymentInfo.CardHolderName = original.PaymentInfo.CardHolderName;
destination.PaymentInfo.Expiration = original.PaymentInfo.Expiration;
destination.PaymentInfo.SecurityNumber = original.PaymentInfo.SecurityNumber;
destination.City = original.City;
destination.Street = original.Street;
destination.State = original.State;
destination.Country = original.Country;
destination.CardNumber = original.CardNumber;
destination.CardHolderName = original.CardHolderName;
destination.CardExpiration = original.CardExpiration;
destination.CardSecurityNumber = original.CardSecurityNumber;
}
}
}

+ 27
- 26
src/Web/WebMVC/Views/Order/Create.cshtml View File

@ -1,5 +1,5 @@
@using Microsoft.eShopOnContainers.WebMVC.Services
@model Microsoft.eShopOnContainers.WebMVC.Models.OrderViewModels.CreateOrderViewModel
@model Microsoft.eShopOnContainers.WebMVC.Models.Order
@inject IIdentityParser<ApplicationUser> UserManager
@{
@ -15,24 +15,24 @@
<h4 class="order-create-section-title">SHIPPING ADDRESS</h4>
<div class="form-horizontal row">
<div class="form-group col-sm-6">
<label asp-for="Order.ShippingAddress.Street" class="control-label form-label">Address</label>
<input asp-for="Order.ShippingAddress.Street" class="form-control form-input" />
<span asp-validation-for="Order.ShippingAddress.Street" class="text-danger" />
<label asp-for="Street" class="control-label form-label">Address</label>
<input asp-for="Street" class="form-control form-input" />
<span asp-validation-for="Street" class="text-danger" />
</div>
<div class="form-group col-sm-6">
<label asp-for="Order.ShippingAddress.City" class="control-label form-label">City</label>
<input asp-for="Order.ShippingAddress.City" class="form-control form-input" />
<span asp-validation-for="Order.ShippingAddress.City" class="text-danger" />
<label asp-for="City" class="control-label form-label">City</label>
<input asp-for="City" class="form-control form-input" />
<span asp-validation-for="City" class="text-danger" />
</div>
<div class="form-group col-sm-6">
<label asp-for="Order.ShippingAddress.State" class="control-label form-label">State</label>
<input asp-for="Order.ShippingAddress.State" class="form-control form-input" />
<span asp-validation-for="Order.ShippingAddress.State" class="text-danger" />
<label asp-for="State" class="control-label form-label">State</label>
<input asp-for="State" class="form-control form-input" />
<span asp-validation-for="State" class="text-danger" />
</div>
<div class="form-group col-sm-6">
<label asp-for="Order.ShippingAddress.Country" class="control-label form-label">Country</label>
<input asp-for="Order.ShippingAddress.Country" class="form-control form-input" />
<span asp-validation-for="Order.ShippingAddress.Country" class="text-danger" />
<label asp-for="Country" class="control-label form-label">Country</label>
<input asp-for="Country" class="form-control form-input" />
<span asp-validation-for="Country" class="text-danger" />
</div>
</div>
<br /><br />
@ -40,33 +40,34 @@
<h4 class="order-create-section-title">PAYMENT METHOD</h4>
<div class="form-horizontal row">
<div class="form-group col-sm-6">
<label asp-for="Order.PaymentInfo.CardNumber" class="control-label form-label">Card Number</label>
<input asp-for="Order.PaymentInfo.CardNumber" class="form-control form-input" />
<span asp-validation-for="Order.PaymentInfo.CardNumber" class="text-danger" />
<label asp-for="CardNumber" class="control-label form-label">Card Number</label>
<input asp-for="CardNumber" class="form-control form-input" />
<span asp-validation-for="CardNumber" class="text-danger" />
</div>
<div class="form-group col-sm-6">
<label asp-for="Order.PaymentInfo.CardHolderName" class="control-label form-label">Cardholder Name</label>
<input asp-for="Order.PaymentInfo.CardHolderName" class="form-control form-input" />
<span asp-validation-for="Order.PaymentInfo.CardHolderName" class="text-danger" />
<label asp-for="CardHolderName" class="control-label form-label">Cardholder Name</label>
<input asp-for="CardHolderName" class="form-control form-input" />
<span asp-validation-for="CardHolderName" class="text-danger" />
</div>
</div>
<div class="form-horizontal row">
<div class="form-group col-sm-3">
<label asp-for="Order.PaymentInfo.Expiration" class="control-label form-label">Expiration Date</label>
<input asp-for="Order.PaymentInfo.Expiration" placeholder="MM/YY" class="form-control form-select" />
<span asp-validation-for="Order.PaymentInfo.Expiration" class="text-danger" />
<label asp-for="CardExpirationShort" class="control-label form-label">Expiration Date</label>
<input asp-for="CardExpirationShort" placeholder="MM/YY" class="form-control form-select" />
<span asp-validation-for="CardExpirationShort" class="text-danger" />
</div>
<div class="form-group col-sm-3">
<label asp-for="Order.PaymentInfo.SecurityNumber" class="control-label form-label">Security Code</label>
<input asp-for="Order.PaymentInfo.SecurityNumber" class="form-control form-input form-input-small" />
<span asp-validation-for="Order.PaymentInfo.SecurityNumber" class="text-danger" />
<label asp-for="CardSecurityNumber" class="control-label form-label">Security Code</label>
<input asp-for="CardSecurityNumber" class="form-control form-input form-input-small" />
<span asp-validation-for="CardSecurityNumber" class="text-danger" />
</div>
</div>
</div>
<br /><br />
<div class="col-md-12 order-create-section-items">
<section>
@await Component.InvokeAsync("CartList", new { user = UserManager.Parse(User) })
@*@await Component.InvokeAsync("CartList", new { user = UserManager.Parse(User) })*@
@await Html.PartialAsync("_OrderItems")
</section>
</div>
<div class="form-group">


+ 10
- 19
src/Web/WebMVC/Views/Order/Detail.cshtml View File

@ -1,5 +1,4 @@
@model Microsoft.eShopOnContainers.WebMVC.Models.Order
@inject UserManager<ApplicationUser> UserManager
@{
ViewData["Title"] = "Order Detail";
@ -7,7 +6,7 @@
<div class="brand-header-block">
<ul class="container">
<li class="brand-header-back"><a asp-area="" asp-controller="Catalog" asp-action="Index">Back to list</a></li>
<li class="brand-header-back"><a asp-area="" asp-controller="Order" asp-action="Index">Back to list</a></li>
</ul>
</div>
@ -20,24 +19,24 @@
</div>
<div class="col-sm-3">
<span>DATE</span><br />
<span>@Model.OrderDate</span>
<span>@Model.Date</span>
</div>
<div class="col-sm-3">
<span>TOTAL</span><br />
<span>$ @Model.Total()</span>
<span>$ @Model.Total</span>
</div>
<div class="col-sm-3">
<span>STATUS</span><br />
<span>@Model.State</span>
<span>@Model.Status</span>
</div>
</div>
<div class="row order-detail-section">
<div class="col-sm-3">
<span>SHIPING ADDRESS</span><br />
<span>@Model.ShippingAddress.Street</span><br />
<span>@Model.ShippingAddress.City</span><br />
<span>@Model.Street</span><br />
<span>@Model.City</span><br />
@*<span>@Model.ShippingAddress.ZipCode</span><br />*@
<span>@Model.ShippingAddress.Country</span><br />
<span>@Model.Country</span><br />
</div>
</div>
<div>
@ -54,8 +53,8 @@
<td class="cart-product-column">@item.ProductName</td>
<td class="cart-product-column">ROSLYN</td>
<td class="cart-product-column">$ @Math.Round(item.UnitPrice, 2)</td>
<td class="cart-product-column">@item.Quantity</td>
<td class="cart-product-column cart-total-value">$ @Math.Round(item.Quantity * item.UnitPrice,2)</td>
<td class="cart-product-column">@item.Units</td>
<td class="cart-product-column cart-total-value">$ @Math.Round(item.Units * item.UnitPrice,2)</td>
</tr>
}
</tbody>
@ -68,17 +67,9 @@
</section>
</div>
<div class="col-md-offset-9 col-md-3">
@*<input type="submit"
class="btn btn-default cart-refresh-button"
value=""
name="action" />*@
<div class="order-section-total">
@*<div class="cart-subtotal-label"><span>SUBTOTAL</span></div>
<div class="cart-subtotal-value"><span>$ @Model.Total()</span></div>
<div class="cart-subtotal-label"><span>TAX</span></div>
<div class="cart-subtotal-value"><span>$ 4.20</span></div>*@
<div class="cart-total-label"><span>TOTAL</span></div>
<div class="cart-total-value"><span>$ @Model.Total()</span></div>
<div class="cart-total-value"><span>$ @Model.Total</span></div>
</div>
</div>
</div>

+ 4
- 4
src/Web/WebMVC/Views/Order/Index.cshtml View File

@ -34,16 +34,16 @@
@Html.DisplayFor(modelItem => item.OrderNumber)
</td>
<td>
@Html.DisplayFor(modelItem => item.OrderDate)
@Html.DisplayFor(modelItem => item.Date)
</td>
<td>
$ @item.Total()
$ @Html.DisplayFor(modelItem => item.Total)
</td>
<td>
@Html.DisplayFor(modelItem => item.State)
@Html.DisplayFor(modelItem => item.Status)
</td>
<td class="order-detail-button">
<a asp-controller="Order" asp-action="Detail" asp-route-orderId="@item.Id">Detail</a>
<a asp-controller="Order" asp-action="Detail" asp-route-orderId="@item.OrderNumber">Detail</a>
</td>
</tr>
}


+ 73
- 0
src/Web/WebMVC/Views/Order/_OrderItems.cshtml View File

@ -0,0 +1,73 @@
@model Microsoft.eShopOnContainers.WebMVC.Models.Order
<div class="col-md-12">
<section>
<table class="table">
<thead>
<tr>
<th class="cart-product-column">
PRODUCT
</th>
<th>
</th>
<th>
BRAND
</th>
<th>
PRICE
</th>
<th>
QUANTITY
</th>
<th>
COST
</th>
</tr>
</thead>
<tbody>
@for (int i = 0; i < Model.OrderItems.Count; i++)
{
var item = Model.OrderItems[i];
<tr>
<td class="cart-product-column">
<img class="cart-product-image" src="@item.PictureUrl" />
<input type="hidden" value="@item.PictureUrl" name=@("orderitems[" + i + "].PictureUrl") />
</td>
<td class="cart-product-column">
<span class="cart-product-column-name">@item.ProductName</span>
<input type="hidden" value="@item.ProductName" name=@("orderitems[" + i + "].ProductName") />
</td>
<td class="cart-product-column">ROSLYN</td>
<td class="cart-product-column">$ @item.UnitPrice
<input type="hidden" value="@item.UnitPrice" name=@("orderitems[" + i + "].UnitPrice") />
</td>
<td class="cart-product-column">@item.Units
<input type="hidden" value="@item.Units" name=@("orderitems[" + i + "].Units") />
</td>
<td class="cart-product-column cart-total-value">$ @Math.Round(item.Units * item.UnitPrice, 2)</td>
</tr>
}
<tr class="cart-totals">
<td></td>
<td></td>
<td></td>
<td></td>
<td>
<input type="submit"
class="btn btn-default cart-refresh-button"
value=""
name="action" />
</td>
<td>
<div class="cart-total-value">
<div class="cart-total-label"><span>TOTAL</span></div>
<span>$ @Model.Total</span>
</div>
</td>
</tr>
</tbody>
</table>
</section>
</div>

+ 0
- 10
src/Web/WebMVC/Views/Shared/Components/CartList/Default.cshtml View File

@ -68,15 +68,5 @@
</table>
</section>
</div>
@*<div class="col-md-offset-8 col-md-4">
<div class="cart-section-total">
<div class="cart-subtotal-label"><span>SUBTOTAL</span></div>
<div class="cart-subtotal-value"><span>$ @Model.Total()</span></div>
<div class="cart-subtotal-label"><span>TAX</span></div>
<div class="cart-subtotal-value"><span>$ 4.20</span></div>
<div class="cart-total-label"><span>TOTAL</span></div>
<div class="cart-total-value"><span>$ @Model.Total()</span></div>
</div>
</div>*@

+ 11
- 9
src/Web/WebMVC/Views/Shared/Error.cshtml View File

@ -2,13 +2,15 @@
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
<div class="container">
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>Development environment should not be enabled in deployed applications</strong>, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>, and restarting the application.
</p>
<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>Development environment should not be enabled in deployed applications</strong>, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>, and restarting the application.
</p>
</div>

+ 0
- 2
src/Web/WebMVC/Views/_ViewImports.cshtml View File

@ -1,7 +1,5 @@
@using Microsoft.eShopOnContainers.WebMVC
@using Microsoft.eShopOnContainers.WebMVC.Models
@using Microsoft.eShopOnContainers.WebMVC.Models.AccountViewModels
@using Microsoft.eShopOnContainers.WebMVC.Models.ManageViewModels
@using Microsoft.AspNetCore.Identity
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

+ 1
- 1
src/Web/WebMVC/appsettings.json View File

@ -2,7 +2,7 @@
"CatalogUrl": "http://localhost:5101",
"OrderingUrl": "http://localhost:5102",
"BasketUrl": "http://localhost:5103",
"IdentityUrl": "http://localhost:5105",
"IdentityUrl": "http://identity.service:5105",
"CallBackUrl": "http://localhost:5100/",
"Logging": {
"IncludeScopes": false,


+ 1
- 1
src/Web/WebMVC/wwwroot/css/site.css View File

@ -699,7 +699,7 @@ form .col-md-4 {
.order-section-total {
margin-bottom: 5px;
margin-left: 40px;
margin-left: 20px;
text-align: left;
}


Loading…
Cancel
Save