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..
This commit is contained in:
parent
0ac9526ffe
commit
31753fc057
@ -9,15 +9,15 @@ version: '2'
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
|
|
||||||
webmvc:
|
# webmvc:
|
||||||
environment:
|
# environment:
|
||||||
- CatalogUrl=http://catalog.api
|
# - CatalogUrl=http://catalog.api
|
||||||
- OrderingUrl=http://ordering.api:5102
|
# - OrderingUrl=http://ordering.api:5102
|
||||||
#- IdentityUrl=http://104.40.62.65:5105 #Remote: VM Needs to have public access at 5105.
|
#- 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.
|
# - 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
|
# - BasketUrl=http://basket.api:5103
|
||||||
ports:
|
# ports:
|
||||||
- "5100:5100"
|
# - "5100:5100"
|
||||||
|
|
||||||
webspa:
|
webspa:
|
||||||
environment:
|
environment:
|
||||||
@ -39,38 +39,31 @@ services:
|
|||||||
|
|
||||||
catalog.api:
|
catalog.api:
|
||||||
environment:
|
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:
|
ports:
|
||||||
- "5101:80"
|
- "5101:80"
|
||||||
|
|
||||||
ordering.api:
|
# ordering.api:
|
||||||
environment:
|
# environment:
|
||||||
- ConnectionString=Server=business.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word
|
# - ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word
|
||||||
- identityUrl=http://identity.service:5105 #local
|
# - identityUrl=http://identity.service:5105 #local
|
||||||
#- identityUrl=http://104.40.62.65:5105 #remote
|
#- identityUrl=http://104.40.62.65:5105 #remote
|
||||||
ports:
|
# ports:
|
||||||
- "5102:5102"
|
# - "5102:5102"
|
||||||
|
|
||||||
identity.service:
|
identity.service:
|
||||||
environment:
|
environment:
|
||||||
- SpaClient=http://localhost:5104
|
- 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://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.
|
- 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.
|
#10.0.75.1:5105 CCE/TODO: try to avoid host entry.
|
||||||
ports:
|
ports:
|
||||||
- "5105:5105"
|
- "5105:5105"
|
||||||
|
|
||||||
identity.data:
|
sql.data:
|
||||||
environment:
|
environment:
|
||||||
- SA_PASSWORD=Pass@word
|
- SA_PASSWORD=Pass@word
|
||||||
- ACCEPT_EULA=Y
|
- ACCEPT_EULA=Y
|
||||||
ports:
|
ports:
|
||||||
- "5433:1433"
|
- "5433:1433"
|
||||||
|
|
||||||
business.data:
|
|
||||||
environment:
|
|
||||||
- SA_PASSWORD=Pass@word
|
|
||||||
- ACCEPT_EULA=Y
|
|
||||||
ports:
|
|
||||||
- "5434:1433"
|
|
@ -7,11 +7,11 @@
|
|||||||
version: '2'
|
version: '2'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
webmvc:
|
# webmvc:
|
||||||
image: eshop/web
|
# image: eshop/web
|
||||||
depends_on:
|
# depends_on:
|
||||||
- identity.service
|
# - identity.service
|
||||||
- basket.api
|
# - basket.api
|
||||||
|
|
||||||
webspa:
|
webspa:
|
||||||
image: eshop/webspa
|
image: eshop/webspa
|
||||||
@ -28,22 +28,19 @@ services:
|
|||||||
catalog.api:
|
catalog.api:
|
||||||
image: eshop/catalog.api
|
image: eshop/catalog.api
|
||||||
depends_on:
|
depends_on:
|
||||||
- business.data
|
- sql.data
|
||||||
|
|
||||||
ordering.api:
|
# ordering.api:
|
||||||
image: eshop/ordering.api
|
# image: eshop/ordering.api
|
||||||
depends_on:
|
# depends_on:
|
||||||
- business.data
|
# - sql.data
|
||||||
|
|
||||||
identity.service:
|
identity.service:
|
||||||
image: eshop/identity
|
image: eshop/identity
|
||||||
depends_on:
|
depends_on:
|
||||||
- identity.data
|
- sql.data
|
||||||
|
|
||||||
identity.data:
|
sql.data:
|
||||||
image: microsoft/mssql-server-linux
|
|
||||||
|
|
||||||
business.data:
|
|
||||||
image: microsoft/mssql-server-linux
|
image: microsoft/mssql-server-linux
|
||||||
|
|
||||||
basket.data:
|
basket.data:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"IncludeScopes": false,
|
"IncludeScopes": false,
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
@ -7,6 +7,6 @@
|
|||||||
"Microsoft": "Information"
|
"Microsoft": "Information"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"IdentityUrl": "http://localhost:5000",
|
"IdentityUrl": "http://identity.service:5105",
|
||||||
"ConnectionString": "127.0.0.1"
|
"ConnectionString": "127.0.0.1"
|
||||||
}
|
}
|
||||||
|
@ -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": {
|
"Logging": {
|
||||||
"IncludeScopes": false,
|
"IncludeScopes": false,
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
|
@ -99,7 +99,7 @@ namespace IdentityServer4.Quickstart.UI.Controllers
|
|||||||
props = new AuthenticationProperties
|
props = new AuthenticationProperties
|
||||||
{
|
{
|
||||||
IsPersistent = true,
|
IsPersistent = true,
|
||||||
ExpiresUtc = DateTimeOffset.UtcNow.AddMonths(1)
|
ExpiresUtc = DateTimeOffset.UtcNow.AddYears(10)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -61,7 +61,6 @@
|
|||||||
CardType = 1,
|
CardType = 1,
|
||||||
City = "Redmond",
|
City = "Redmond",
|
||||||
Country = "U.S.",
|
Country = "U.S.",
|
||||||
CountryCode = "91",
|
|
||||||
Email = "demouser@microsoft.com",
|
Email = "demouser@microsoft.com",
|
||||||
Expiration = "12/20",
|
Expiration = "12/20",
|
||||||
Id = Guid.NewGuid().ToString(),
|
Id = Guid.NewGuid().ToString(),
|
||||||
|
@ -49,14 +49,11 @@ namespace WebMVC.Migrations
|
|||||||
City = table.Column<string>(nullable: true),
|
City = table.Column<string>(nullable: true),
|
||||||
ConcurrencyStamp = table.Column<string>(nullable: true),
|
ConcurrencyStamp = table.Column<string>(nullable: true),
|
||||||
Country = 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),
|
Email = table.Column<string>(maxLength: 256, nullable: true),
|
||||||
EmailConfirmed = table.Column<bool>(nullable: false),
|
EmailConfirmed = table.Column<bool>(nullable: false),
|
||||||
Expiration = table.Column<string>(nullable: true),
|
Expiration = table.Column<string>(nullable: true),
|
||||||
Latitude = table.Column<double>(nullable: false),
|
|
||||||
LockoutEnabled = table.Column<bool>(nullable: false),
|
LockoutEnabled = table.Column<bool>(nullable: false),
|
||||||
LockoutEnd = table.Column<DateTimeOffset>(nullable: true),
|
LockoutEnd = table.Column<DateTimeOffset>(nullable: true),
|
||||||
Longitude = table.Column<double>(nullable: false),
|
|
||||||
NormalizedEmail = table.Column<string>(maxLength: 256, nullable: true),
|
NormalizedEmail = table.Column<string>(maxLength: 256, nullable: true),
|
||||||
NormalizedUserName = table.Column<string>(maxLength: 256, nullable: true),
|
NormalizedUserName = table.Column<string>(maxLength: 256, nullable: true),
|
||||||
PasswordHash = table.Column<string>(nullable: true),
|
PasswordHash = table.Column<string>(nullable: true),
|
||||||
@ -65,7 +62,6 @@ namespace WebMVC.Migrations
|
|||||||
SecurityNumber = table.Column<string>(nullable: true),
|
SecurityNumber = table.Column<string>(nullable: true),
|
||||||
SecurityStamp = table.Column<string>(nullable: true),
|
SecurityStamp = table.Column<string>(nullable: true),
|
||||||
State = table.Column<string>(nullable: true),
|
State = table.Column<string>(nullable: true),
|
||||||
StateCode = table.Column<string>(nullable: true),
|
|
||||||
Street = table.Column<string>(nullable: true),
|
Street = table.Column<string>(nullable: true),
|
||||||
TwoFactorEnabled = table.Column<bool>(nullable: false),
|
TwoFactorEnabled = table.Column<bool>(nullable: false),
|
||||||
UserName = table.Column<string>(maxLength: 256, nullable: true),
|
UserName = table.Column<string>(maxLength: 256, nullable: true),
|
||||||
|
@ -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();
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
|
@ -10,21 +10,29 @@ namespace eShopOnContainers.Identity.Models
|
|||||||
// Add profile data for application users by adding properties to the ApplicationUser class
|
// Add profile data for application users by adding properties to the ApplicationUser class
|
||||||
public class ApplicationUser : IdentityUser
|
public class ApplicationUser : IdentityUser
|
||||||
{
|
{
|
||||||
|
[Required]
|
||||||
public string CardNumber { get; set; }
|
public string CardNumber { get; set; }
|
||||||
|
[Required]
|
||||||
public string SecurityNumber { get; set; }
|
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; }
|
public string Expiration { get; set; }
|
||||||
|
[Required]
|
||||||
public string CardHolderName { get; set; }
|
public string CardHolderName { get; set; }
|
||||||
public int CardType { get; set; }
|
public int CardType { get; set; }
|
||||||
|
[Required]
|
||||||
public string Street { get; set; }
|
public string Street { get; set; }
|
||||||
|
[Required]
|
||||||
public string City { get; set; }
|
public string City { get; set; }
|
||||||
|
[Required]
|
||||||
public string State { get; set; }
|
public string State { get; set; }
|
||||||
public string StateCode { get; set; }
|
[Required]
|
||||||
public string Country { get; set; }
|
public string Country { get; set; }
|
||||||
public string CountryCode { get; set; }
|
[Required]
|
||||||
public string ZipCode { get; set; }
|
public string ZipCode { get; set; }
|
||||||
public double Latitude { get; set; }
|
[Required]
|
||||||
public double Longitude { get; set; }
|
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
[Required]
|
||||||
public string LastName { get; set; }
|
public string LastName { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
"IIS Express": {
|
"IIS Express": {
|
||||||
"commandName": "IISExpress",
|
"commandName": "IISExpress",
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"launchUrl": "http://localhost:5000",
|
"launchUrl": "http://localhost:5105",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
}
|
}
|
||||||
|
@ -88,6 +88,9 @@ namespace eShopOnContainers.Identity.Services
|
|||||||
if (!string.IsNullOrWhiteSpace(user.SecurityNumber))
|
if (!string.IsNullOrWhiteSpace(user.SecurityNumber))
|
||||||
claims.Add(new Claim("card_security_number", 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))
|
if (!string.IsNullOrWhiteSpace(user.City))
|
||||||
claims.Add(new Claim("address_city", user.City));
|
claims.Add(new Claim("address_city", user.City));
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"DefaultConnection": "Server=127.0.0.1,5433;Database=aspnet-Microsoft.eShopOnContainers;User Id=sa;Password=Pass@word"
|
"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",
|
"SpaClient": "http://localhost:5104",
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"IncludeScopes": false,
|
"IncludeScopes": false,
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Models;
|
using Models;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
[Route("api/v1/[controller]")]
|
[Route("api/v1/[controller]")]
|
||||||
@ -34,38 +35,14 @@
|
|||||||
|
|
||||||
[Route("new")]
|
[Route("new")]
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<IActionResult> AddOrder([FromBody]NewOrderViewModel order)
|
public async Task<IActionResult> AddOrder([FromBody]NewOrderRequest order)
|
||||||
{
|
{
|
||||||
if (order.CardExpiration == DateTime.MinValue)
|
if (order.CardExpiration == DateTime.MinValue)
|
||||||
order.CardExpiration = DateTime.Now;
|
order.CardExpiration = DateTime.Now;
|
||||||
|
|
||||||
var newOrderRequest = new NewOrderRequest()
|
order.Buyer = GetUserName();
|
||||||
{
|
|
||||||
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);
|
|
||||||
|
|
||||||
|
var added = await _mediator.SendAsync(order);
|
||||||
if (added)
|
if (added)
|
||||||
{
|
{
|
||||||
return Ok();
|
return Ok();
|
||||||
@ -78,9 +55,15 @@
|
|||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<IActionResult> GetOrder(int orderId)
|
public async Task<IActionResult> GetOrder(int orderId)
|
||||||
{
|
{
|
||||||
var order = await _orderQueries.GetOrder(orderId);
|
try
|
||||||
|
{
|
||||||
return Ok(order);
|
var order = await _orderQueries.GetOrder(orderId);
|
||||||
|
return Ok(order);
|
||||||
|
}
|
||||||
|
catch (KeyNotFoundException)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("")]
|
[Route("")]
|
||||||
|
@ -172,6 +172,7 @@ namespace Ordering.API.Infrastructure.Migrations
|
|||||||
OrderId = table.Column<int>(nullable: false),
|
OrderId = table.Column<int>(nullable: false),
|
||||||
ProductId = table.Column<int>(nullable: false),
|
ProductId = table.Column<int>(nullable: false),
|
||||||
ProductName = table.Column<string>(nullable: false),
|
ProductName = table.Column<string>(nullable: false),
|
||||||
|
PictureUrl = table.Column<string>(nullable: false),
|
||||||
UnitPrice = table.Column<decimal>(nullable: false),
|
UnitPrice = table.Column<decimal>(nullable: false),
|
||||||
Units = table.Column<int>(nullable: false, defaultValue: 1)
|
Units = table.Column<int>(nullable: false, defaultValue: 1)
|
||||||
},
|
},
|
||||||
|
@ -11,5 +11,7 @@
|
|||||||
public decimal Discount { get; set; }
|
public decimal Discount { get; set; }
|
||||||
|
|
||||||
public int Units { get; set; }
|
public int Units { get; set; }
|
||||||
|
|
||||||
|
public string PictureUrl { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -15,9 +15,9 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API
|
|||||||
var host = new WebHostBuilder()
|
var host = new WebHostBuilder()
|
||||||
.UseKestrel()
|
.UseKestrel()
|
||||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||||
//.UseIISIntegration()
|
|
||||||
.UseStartup<Startup>()
|
|
||||||
.UseUrls("http://0.0.0.0:5102")
|
.UseUrls("http://0.0.0.0:5102")
|
||||||
|
.UseIISIntegration()
|
||||||
|
.UseStartup<Startup>()
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
host.Run();
|
host.Run();
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"windowsAuthentication": false,
|
"windowsAuthentication": false,
|
||||||
"anonymousAuthentication": true,
|
"anonymousAuthentication": true,
|
||||||
"iisExpress": {
|
"iisExpress": {
|
||||||
"applicationUrl": "http://localhost:5002/",
|
"applicationUrl": "http://localhost:5102/",
|
||||||
"sslPort": 0
|
"sslPort": 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"IncludeScopes": false,
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Debug",
|
|
||||||
"System": "Information",
|
|
||||||
"Microsoft": "Information"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
"ConnectionString": "Server=tcp:127.0.0.1,5434;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;",
|
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;",
|
||||||
"IdentityUrl": "http://localhost:5105"
|
"IdentityUrl": "http://identity.service:5105",
|
||||||
|
"Logging": {
|
||||||
|
"IncludeScopes": false,
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Debug",
|
||||||
|
"System": "Information",
|
||||||
|
"Microsoft": "Information"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
using System.Data.SqlClient;
|
using System.Data.SqlClient;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Dynamic;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
public class OrderQueries
|
public class OrderQueries
|
||||||
:IOrderQueries
|
:IOrderQueries
|
||||||
@ -16,14 +18,29 @@
|
|||||||
_connectionString = configuration["ConnectionString"];
|
_connectionString = configuration["ConnectionString"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task<dynamic> GetOrder(int id)
|
public async Task<dynamic> GetOrder(int id)
|
||||||
{
|
{
|
||||||
using (var connection = new SqlConnection(_connectionString))
|
using (var connection = new SqlConnection(_connectionString))
|
||||||
{
|
{
|
||||||
connection.Open();
|
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");
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
public string ProductName { get; set; }
|
public string ProductName { get; set; }
|
||||||
|
|
||||||
|
public string PictureUrl { get; set; }
|
||||||
|
|
||||||
public int OrderId { get; set; }
|
public int OrderId { get; set; }
|
||||||
|
|
||||||
public decimal UnitPrice { get; set; }
|
public decimal UnitPrice { get; set; }
|
||||||
|
@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using Microsoft.eShopOnContainers.WebMVC.Services;
|
using Microsoft.eShopOnContainers.WebMVC.Services;
|
||||||
using Microsoft.eShopOnContainers.WebMVC.Models;
|
using Microsoft.eShopOnContainers.WebMVC.Models;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.eShopOnContainers.WebMVC.Models.OrderViewModels;
|
using System.Net.Http;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
||||||
{
|
{
|
||||||
@ -25,31 +25,22 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
|||||||
|
|
||||||
public async Task<IActionResult> Create()
|
public async Task<IActionResult> Create()
|
||||||
{
|
{
|
||||||
var vm = new CreateOrderViewModel();
|
|
||||||
var user = _appUserParser.Parse(HttpContext.User);
|
var user = _appUserParser.Parse(HttpContext.User);
|
||||||
var basket = await _basketSvc.GetBasket(user);
|
var basket = await _basketSvc.GetBasket(user);
|
||||||
var order = _basketSvc.MapBasketToOrder(basket);
|
var order = _basketSvc.MapBasketToOrder(basket);
|
||||||
vm.Order = _orderSvc.MapUserInfoIntoOrder(user, order);
|
var vm = _orderSvc.MapUserInfoIntoOrder(user, order);
|
||||||
|
vm.CardExpirationShortFormat();
|
||||||
|
|
||||||
return View(vm);
|
return View(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[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 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 ]")
|
if (action == "[ Place Order ]")
|
||||||
{
|
{
|
||||||
|
await _orderSvc.CreateOrder(model);
|
||||||
await _orderSvc.CreateOrder(user, order);
|
|
||||||
|
|
||||||
//Empty basket for current user.
|
//Empty basket for current user.
|
||||||
await _basketSvc.CleanBasket(user);
|
await _basketSvc.CleanBasket(user);
|
||||||
@ -61,11 +52,11 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
|||||||
return View(model);
|
return View(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IActionResult Detail(string orderId)
|
public async Task<IActionResult> Detail(string orderId)
|
||||||
{
|
{
|
||||||
var user = _appUserParser.Parse(HttpContext.User);
|
var user = _appUserParser.Parse(HttpContext.User);
|
||||||
var order = _orderSvc.GetOrder(user, orderId);
|
|
||||||
|
|
||||||
|
var order = await _orderSvc.GetOrder(user, orderId);
|
||||||
return View(order);
|
return View(order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
src/Web/WebMVC/Models/Annotations/CardExpiration.cs
Normal file
24
src/Web/WebMVC/Models/Annotations/CardExpiration.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using Microsoft.eShopOnContainers.WebMVC.Models.Annotations;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -8,40 +9,61 @@ namespace Microsoft.eShopOnContainers.WebMVC.Models
|
|||||||
{
|
{
|
||||||
public class Order
|
public class Order
|
||||||
{
|
{
|
||||||
public Order()
|
public Order() {
|
||||||
{
|
|
||||||
OrderItems = new List<OrderItem>();
|
OrderItems = new List<OrderItem>();
|
||||||
ShippingAddress = new Address();
|
|
||||||
PaymentInfo = new PaymentInfo();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Id;
|
public string OrderNumber {get;set;}
|
||||||
public List<OrderItem> OrderItems { get; set; }
|
|
||||||
public string OrderNumber
|
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
|
CardExpirationShort = CardExpiration.ToString("MM/yy");
|
||||||
{
|
|
||||||
return string.Format("{0}/{1}-{2}", OrderDate.Year, OrderDate.Month, SequenceNumber);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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() {
|
public void CardExpirationApiFormat()
|
||||||
return OrderItems.Sum(x => x.Quantity * x.UnitPrice);
|
{
|
||||||
}
|
var month = CardExpirationShort.Split('/')[0];
|
||||||
|
var year = $"20{CardExpirationShort.Split('/')[1]}";
|
||||||
|
|
||||||
//(CCE) public virtual Address BillingAddress { get; set; }
|
CardExpiration = new DateTime(int.Parse(year), int.Parse(month), 1);
|
||||||
//(CDLTLL) public virtual OrderStatus Status { get; set; }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum OrderState:int
|
public enum CardType
|
||||||
{
|
{
|
||||||
InProcess = 0,
|
AMEX = 1
|
||||||
Delivered = 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,18 +7,16 @@ namespace Microsoft.eShopOnContainers.WebMVC.Models
|
|||||||
{
|
{
|
||||||
public class OrderItem
|
public class OrderItem
|
||||||
{
|
{
|
||||||
public string Id;
|
public int ProductId { get; set; }
|
||||||
public string ProductId { get; set; }
|
|
||||||
public string OrderId { get; set; }
|
|
||||||
public string ProductName { get; set; }
|
|
||||||
public decimal UnitPrice { get; set; }
|
|
||||||
public int Quantity { get; set; }
|
|
||||||
public decimal Discount { get; set; }
|
|
||||||
public string PictureUrl { get; set; }
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return String.Format("Product Id: {0}, Quantity: {1}", this.Id, this.Quantity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public string ProductName { get; set; }
|
||||||
|
|
||||||
|
public decimal UnitPrice { get; set; }
|
||||||
|
|
||||||
|
public decimal Discount { get; set; }
|
||||||
|
|
||||||
|
public int Units { get; set; }
|
||||||
|
|
||||||
|
public string PictureUrl { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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; }
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,7 +3,7 @@
|
|||||||
"windowsAuthentication": false,
|
"windowsAuthentication": false,
|
||||||
"anonymousAuthentication": true,
|
"anonymousAuthentication": true,
|
||||||
"iisExpress": {
|
"iisExpress": {
|
||||||
"applicationUrl": "http://localhost:5001",
|
"applicationUrl": "http://localhost:5100",
|
||||||
"sslPort": 0
|
"sslPort": 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -79,23 +79,21 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
|
|
||||||
public Order MapBasketToOrder(Basket basket)
|
public Order MapBasketToOrder(Basket basket)
|
||||||
{
|
{
|
||||||
var order = new Order()
|
var order = new Order();
|
||||||
{
|
order.Total = 0;
|
||||||
Id = Guid.NewGuid().ToString(),
|
|
||||||
BuyerId = basket.BuyerId
|
|
||||||
};
|
|
||||||
|
|
||||||
basket.Items.ForEach(x =>
|
basket.Items.ForEach(x =>
|
||||||
{
|
{
|
||||||
order.OrderItems.Add(new OrderItem()
|
order.OrderItems.Add(new OrderItem()
|
||||||
{
|
{
|
||||||
ProductId = x.ProductId,
|
ProductId = int.Parse(x.ProductId),
|
||||||
OrderId = order.Id,
|
|
||||||
PictureUrl = x.PictureUrl,
|
PictureUrl = x.PictureUrl,
|
||||||
ProductName = x.ProductName,
|
ProductName = x.ProductName,
|
||||||
Quantity = x.Quantity,
|
Units = x.Quantity,
|
||||||
UnitPrice = x.UnitPrice
|
UnitPrice = x.UnitPrice
|
||||||
});
|
});
|
||||||
|
order.Total += (x.Quantity * x.UnitPrice);
|
||||||
});
|
});
|
||||||
|
|
||||||
return order;
|
return order;
|
||||||
@ -109,8 +107,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
basket = new Basket()
|
basket = new Basket()
|
||||||
{
|
{
|
||||||
BuyerId = user.Id,
|
BuyerId = user.Id,
|
||||||
//Id = Guid.NewGuid().ToString(),
|
Items = new List<BasketItem>()
|
||||||
Items = new List<Models.BasketItem>()
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ 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 CreateOrder(ApplicationUser user, Order order);
|
Task CreateOrder(Order order);
|
||||||
Order MapUserInfoIntoOrder(ApplicationUser user, Order order);
|
Order MapUserInfoIntoOrder(ApplicationUser user, Order order);
|
||||||
void OverrideUserInfoIntoOrder(Order original, Order destination);
|
void OverrideUserInfoIntoOrder(Order original, Order destination);
|
||||||
}
|
}
|
||||||
|
@ -23,45 +23,6 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
_remoteServiceBaseUrl = $"{settings.Value.OrderingUrl}/api/v1/orders";
|
_remoteServiceBaseUrl = $"{settings.Value.OrderingUrl}/api/v1/orders";
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
_httpContextAccesor = httpContextAccesor;
|
_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)
|
async public Task<Order> GetOrder(ApplicationUser user, string Id)
|
||||||
@ -74,6 +35,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
|
|
||||||
var ordersUrl = $"{_remoteServiceBaseUrl}/{Id}";
|
var ordersUrl = $"{_remoteServiceBaseUrl}/{Id}";
|
||||||
var dataString = await _apiClient.GetStringAsync(ordersUrl);
|
var dataString = await _apiClient.GetStringAsync(ordersUrl);
|
||||||
|
|
||||||
var response = JsonConvert.DeserializeObject<Order>(dataString);
|
var response = JsonConvert.DeserializeObject<Order>(dataString);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
@ -96,50 +58,20 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
|
|
||||||
public Order MapUserInfoIntoOrder(ApplicationUser user, Order order)
|
public Order MapUserInfoIntoOrder(ApplicationUser user, Order order)
|
||||||
{
|
{
|
||||||
order.ShippingAddress.City = user.City;
|
order.City = user.City;
|
||||||
order.ShippingAddress.Street = user.Street;
|
order.Street = user.Street;
|
||||||
order.ShippingAddress.State = user.State;
|
order.State = user.State;
|
||||||
order.ShippingAddress.Country = user.Country;
|
order.Country = user.Country;
|
||||||
|
|
||||||
order.PaymentInfo.CardNumber = user.CardNumber;
|
order.CardNumber = user.CardNumber;
|
||||||
order.PaymentInfo.CardHolderName = user.CardHolderName;
|
order.CardHolderName = user.CardHolderName;
|
||||||
order.PaymentInfo.Expiration = user.Expiration;
|
//order.CardExpiration = user.Expiration;
|
||||||
order.PaymentInfo.SecurityNumber = user.SecurityNumber;
|
order.CardSecurityNumber = user.SecurityNumber;
|
||||||
|
|
||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OrderRequest MapOrderIntoOrderRequest(Order order)
|
async public Task CreateOrder(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)
|
|
||||||
{
|
{
|
||||||
var context = _httpContextAccesor.HttpContext;
|
var context = _httpContextAccesor.HttpContext;
|
||||||
var token = await context.Authentication.GetTokenAsync("access_token");
|
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);
|
_apiClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
|
||||||
|
|
||||||
var ordersUrl = $"{_remoteServiceBaseUrl}/new";
|
var ordersUrl = $"{_remoteServiceBaseUrl}/new";
|
||||||
order.PaymentInfo.CardType = CardType.AMEX;
|
order.CardTypeId = 1;
|
||||||
OrderRequest request = MapOrderIntoOrderRequest(order);
|
order.CardExpirationApiFormat();
|
||||||
StringContent content = new StringContent(JsonConvert.SerializeObject(request), System.Text.Encoding.UTF8, "application/json");
|
StringContent content = new StringContent(JsonConvert.SerializeObject(order), System.Text.Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
var response = await _apiClient.PostAsync(ordersUrl, content);
|
var response = await _apiClient.PostAsync(ordersUrl, content);
|
||||||
|
|
||||||
@ -160,15 +92,15 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
|
|
||||||
public void OverrideUserInfoIntoOrder(Order original, Order destination)
|
public void OverrideUserInfoIntoOrder(Order original, Order destination)
|
||||||
{
|
{
|
||||||
destination.ShippingAddress.City = original.ShippingAddress.City;
|
destination.City = original.City;
|
||||||
destination.ShippingAddress.Street = original.ShippingAddress.Street;
|
destination.Street = original.Street;
|
||||||
destination.ShippingAddress.State = original.ShippingAddress.State;
|
destination.State = original.State;
|
||||||
destination.ShippingAddress.Country = original.ShippingAddress.Country;
|
destination.Country = original.Country;
|
||||||
|
|
||||||
destination.PaymentInfo.CardNumber = original.PaymentInfo.CardNumber;
|
destination.CardNumber = original.CardNumber;
|
||||||
destination.PaymentInfo.CardHolderName = original.PaymentInfo.CardHolderName;
|
destination.CardHolderName = original.CardHolderName;
|
||||||
destination.PaymentInfo.Expiration = original.PaymentInfo.Expiration;
|
destination.CardExpiration = original.CardExpiration;
|
||||||
destination.PaymentInfo.SecurityNumber = original.PaymentInfo.SecurityNumber;
|
destination.CardSecurityNumber = original.CardSecurityNumber;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
@using Microsoft.eShopOnContainers.WebMVC.Services
|
@using Microsoft.eShopOnContainers.WebMVC.Services
|
||||||
@model Microsoft.eShopOnContainers.WebMVC.Models.OrderViewModels.CreateOrderViewModel
|
@model Microsoft.eShopOnContainers.WebMVC.Models.Order
|
||||||
@inject IIdentityParser<ApplicationUser> UserManager
|
@inject IIdentityParser<ApplicationUser> UserManager
|
||||||
|
|
||||||
@{
|
@{
|
||||||
@ -15,24 +15,24 @@
|
|||||||
<h4 class="order-create-section-title">SHIPPING ADDRESS</h4>
|
<h4 class="order-create-section-title">SHIPPING ADDRESS</h4>
|
||||||
<div class="form-horizontal row">
|
<div class="form-horizontal row">
|
||||||
<div class="form-group col-sm-6">
|
<div class="form-group col-sm-6">
|
||||||
<label asp-for="Order.ShippingAddress.Street" class="control-label form-label">Address</label>
|
<label asp-for="Street" class="control-label form-label">Address</label>
|
||||||
<input asp-for="Order.ShippingAddress.Street" class="form-control form-input" />
|
<input asp-for="Street" class="form-control form-input" />
|
||||||
<span asp-validation-for="Order.ShippingAddress.Street" class="text-danger" />
|
<span asp-validation-for="Street" class="text-danger" />
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group col-sm-6">
|
<div class="form-group col-sm-6">
|
||||||
<label asp-for="Order.ShippingAddress.City" class="control-label form-label">City</label>
|
<label asp-for="City" class="control-label form-label">City</label>
|
||||||
<input asp-for="Order.ShippingAddress.City" class="form-control form-input" />
|
<input asp-for="City" class="form-control form-input" />
|
||||||
<span asp-validation-for="Order.ShippingAddress.City" class="text-danger" />
|
<span asp-validation-for="City" class="text-danger" />
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group col-sm-6">
|
<div class="form-group col-sm-6">
|
||||||
<label asp-for="Order.ShippingAddress.State" class="control-label form-label">State</label>
|
<label asp-for="State" class="control-label form-label">State</label>
|
||||||
<input asp-for="Order.ShippingAddress.State" class="form-control form-input" />
|
<input asp-for="State" class="form-control form-input" />
|
||||||
<span asp-validation-for="Order.ShippingAddress.State" class="text-danger" />
|
<span asp-validation-for="State" class="text-danger" />
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group col-sm-6">
|
<div class="form-group col-sm-6">
|
||||||
<label asp-for="Order.ShippingAddress.Country" class="control-label form-label">Country</label>
|
<label asp-for="Country" class="control-label form-label">Country</label>
|
||||||
<input asp-for="Order.ShippingAddress.Country" class="form-control form-input" />
|
<input asp-for="Country" class="form-control form-input" />
|
||||||
<span asp-validation-for="Order.ShippingAddress.Country" class="text-danger" />
|
<span asp-validation-for="Country" class="text-danger" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br /><br />
|
<br /><br />
|
||||||
@ -40,33 +40,34 @@
|
|||||||
<h4 class="order-create-section-title">PAYMENT METHOD</h4>
|
<h4 class="order-create-section-title">PAYMENT METHOD</h4>
|
||||||
<div class="form-horizontal row">
|
<div class="form-horizontal row">
|
||||||
<div class="form-group col-sm-6">
|
<div class="form-group col-sm-6">
|
||||||
<label asp-for="Order.PaymentInfo.CardNumber" class="control-label form-label">Card Number</label>
|
<label asp-for="CardNumber" class="control-label form-label">Card Number</label>
|
||||||
<input asp-for="Order.PaymentInfo.CardNumber" class="form-control form-input" />
|
<input asp-for="CardNumber" class="form-control form-input" />
|
||||||
<span asp-validation-for="Order.PaymentInfo.CardNumber" class="text-danger" />
|
<span asp-validation-for="CardNumber" class="text-danger" />
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group col-sm-6">
|
<div class="form-group col-sm-6">
|
||||||
<label asp-for="Order.PaymentInfo.CardHolderName" class="control-label form-label">Cardholder Name</label>
|
<label asp-for="CardHolderName" class="control-label form-label">Cardholder Name</label>
|
||||||
<input asp-for="Order.PaymentInfo.CardHolderName" class="form-control form-input" />
|
<input asp-for="CardHolderName" class="form-control form-input" />
|
||||||
<span asp-validation-for="Order.PaymentInfo.CardHolderName" class="text-danger" />
|
<span asp-validation-for="CardHolderName" class="text-danger" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-horizontal row">
|
<div class="form-horizontal row">
|
||||||
<div class="form-group col-sm-3">
|
<div class="form-group col-sm-3">
|
||||||
<label asp-for="Order.PaymentInfo.Expiration" class="control-label form-label">Expiration Date</label>
|
<label asp-for="CardExpirationShort" class="control-label form-label">Expiration Date</label>
|
||||||
<input asp-for="Order.PaymentInfo.Expiration" placeholder="MM/YY" class="form-control form-select" />
|
<input asp-for="CardExpirationShort" placeholder="MM/YY" class="form-control form-select" />
|
||||||
<span asp-validation-for="Order.PaymentInfo.Expiration" class="text-danger" />
|
<span asp-validation-for="CardExpirationShort" class="text-danger" />
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group col-sm-3">
|
<div class="form-group col-sm-3">
|
||||||
<label asp-for="Order.PaymentInfo.SecurityNumber" class="control-label form-label">Security Code</label>
|
<label asp-for="CardSecurityNumber" class="control-label form-label">Security Code</label>
|
||||||
<input asp-for="Order.PaymentInfo.SecurityNumber" class="form-control form-input form-input-small" />
|
<input asp-for="CardSecurityNumber" class="form-control form-input form-input-small" />
|
||||||
<span asp-validation-for="Order.PaymentInfo.SecurityNumber" class="text-danger" />
|
<span asp-validation-for="CardSecurityNumber" class="text-danger" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br /><br />
|
<br /><br />
|
||||||
<div class="col-md-12 order-create-section-items">
|
<div class="col-md-12 order-create-section-items">
|
||||||
<section>
|
<section>
|
||||||
@await Component.InvokeAsync("CartList", new { user = UserManager.Parse(User) })
|
@*@await Component.InvokeAsync("CartList", new { user = UserManager.Parse(User) })*@
|
||||||
|
@await Html.PartialAsync("_OrderItems")
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
@model Microsoft.eShopOnContainers.WebMVC.Models.Order
|
@model Microsoft.eShopOnContainers.WebMVC.Models.Order
|
||||||
@inject UserManager<ApplicationUser> UserManager
|
|
||||||
|
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Order Detail";
|
ViewData["Title"] = "Order Detail";
|
||||||
@ -7,7 +6,7 @@
|
|||||||
|
|
||||||
<div class="brand-header-block">
|
<div class="brand-header-block">
|
||||||
<ul class="container">
|
<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>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -20,24 +19,24 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-3">
|
||||||
<span>DATE</span><br />
|
<span>DATE</span><br />
|
||||||
<span>@Model.OrderDate</span>
|
<span>@Model.Date</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-3">
|
||||||
<span>TOTAL</span><br />
|
<span>TOTAL</span><br />
|
||||||
<span>$ @Model.Total()</span>
|
<span>$ @Model.Total</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-3">
|
||||||
<span>STATUS</span><br />
|
<span>STATUS</span><br />
|
||||||
<span>@Model.State</span>
|
<span>@Model.Status</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row order-detail-section">
|
<div class="row order-detail-section">
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-3">
|
||||||
<span>SHIPING ADDRESS</span><br />
|
<span>SHIPING ADDRESS</span><br />
|
||||||
<span>@Model.ShippingAddress.Street</span><br />
|
<span>@Model.Street</span><br />
|
||||||
<span>@Model.ShippingAddress.City</span><br />
|
<span>@Model.City</span><br />
|
||||||
@*<span>@Model.ShippingAddress.ZipCode</span><br />*@
|
@*<span>@Model.ShippingAddress.ZipCode</span><br />*@
|
||||||
<span>@Model.ShippingAddress.Country</span><br />
|
<span>@Model.Country</span><br />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -54,8 +53,8 @@
|
|||||||
<td class="cart-product-column">@item.ProductName</td>
|
<td class="cart-product-column">@item.ProductName</td>
|
||||||
<td class="cart-product-column">ROSLYN</td>
|
<td class="cart-product-column">ROSLYN</td>
|
||||||
<td class="cart-product-column">$ @Math.Round(item.UnitPrice, 2)</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">@item.Units</td>
|
||||||
<td class="cart-product-column cart-total-value">$ @Math.Round(item.Quantity * item.UnitPrice,2)</td>
|
<td class="cart-product-column cart-total-value">$ @Math.Round(item.Units * item.UnitPrice,2)</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -68,17 +67,9 @@
|
|||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-offset-9 col-md-3">
|
<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="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-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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -34,16 +34,16 @@
|
|||||||
@Html.DisplayFor(modelItem => item.OrderNumber)
|
@Html.DisplayFor(modelItem => item.OrderNumber)
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@Html.DisplayFor(modelItem => item.OrderDate)
|
@Html.DisplayFor(modelItem => item.Date)
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
$ @item.Total()
|
$ @Html.DisplayFor(modelItem => item.Total)
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@Html.DisplayFor(modelItem => item.State)
|
@Html.DisplayFor(modelItem => item.Status)
|
||||||
</td>
|
</td>
|
||||||
<td class="order-detail-button">
|
<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>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
|
73
src/Web/WebMVC/Views/Order/_OrderItems.cshtml
Normal file
73
src/Web/WebMVC/Views/Order/_OrderItems.cshtml
Normal 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>
|
@ -68,15 +68,5 @@
|
|||||||
</table>
|
</table>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</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>*@
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,13 +2,15 @@
|
|||||||
ViewData["Title"] = "Error";
|
ViewData["Title"] = "Error";
|
||||||
}
|
}
|
||||||
|
|
||||||
<h1 class="text-danger">Error.</h1>
|
<div class="container">
|
||||||
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
<h1 class="text-danger">Error.</h1>
|
||||||
|
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
||||||
|
|
||||||
<h3>Development Mode</h3>
|
<h3>Development Mode</h3>
|
||||||
<p>
|
<p>
|
||||||
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
|
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
|
||||||
</p>
|
</p>
|
||||||
<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.
|
<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>
|
</p>
|
||||||
|
</div>
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
@using Microsoft.eShopOnContainers.WebMVC
|
@using Microsoft.eShopOnContainers.WebMVC
|
||||||
@using Microsoft.eShopOnContainers.WebMVC.Models
|
@using Microsoft.eShopOnContainers.WebMVC.Models
|
||||||
@using Microsoft.eShopOnContainers.WebMVC.Models.AccountViewModels
|
|
||||||
@using Microsoft.eShopOnContainers.WebMVC.Models.ManageViewModels
|
|
||||||
@using Microsoft.AspNetCore.Identity
|
@using Microsoft.AspNetCore.Identity
|
||||||
|
|
||||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"CatalogUrl": "http://localhost:5101",
|
"CatalogUrl": "http://localhost:5101",
|
||||||
"OrderingUrl": "http://localhost:5102",
|
"OrderingUrl": "http://localhost:5102",
|
||||||
"BasketUrl": "http://localhost:5103",
|
"BasketUrl": "http://localhost:5103",
|
||||||
"IdentityUrl": "http://localhost:5105",
|
"IdentityUrl": "http://identity.service:5105",
|
||||||
"CallBackUrl": "http://localhost:5100/",
|
"CallBackUrl": "http://localhost:5100/",
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"IncludeScopes": false,
|
"IncludeScopes": false,
|
||||||
|
@ -699,7 +699,7 @@ form .col-md-4 {
|
|||||||
|
|
||||||
.order-section-total {
|
.order-section-total {
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
margin-left: 40px;
|
margin-left: 20px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user