Update to add a the ability to apply a coupon code for demo purposes
This commit is contained in:
parent
395e18f2e1
commit
288a90566b
@ -66,8 +66,9 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers
|
||||
ProductId = catalogItem.Id,
|
||||
ProductName = catalogItem.Name,
|
||||
PictureUrl = catalogItem.PictureUri,
|
||||
UnitPrice = catalogItem.Price,
|
||||
Quantity = bitem.Quantity
|
||||
UnitPrice = itemInBasket.UnitPrice,
|
||||
Quantity = bitem.Quantity,
|
||||
isDiscounted = false
|
||||
});
|
||||
}
|
||||
else
|
||||
|
@ -16,6 +16,7 @@
|
||||
public int Quantity { get; set; }
|
||||
|
||||
public string PictureUrl { get; set; }
|
||||
public bool isDiscounted { get; internal set; }
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,5 +7,7 @@
|
||||
public int ProductId { get; set; } // Catalog item id
|
||||
|
||||
public int Quantity { get; set; } // Quantity
|
||||
|
||||
public bool isDiscounted { get; set; } // Discount applied
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,8 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
|
||||
ProductId = item.Productid,
|
||||
ProductName = item.Productname,
|
||||
Quantity = item.Quantity,
|
||||
UnitPrice = (decimal)item.Unitprice
|
||||
UnitPrice = (decimal)item.Unitprice,
|
||||
isDiscounted = item.Isdiscounted
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -92,7 +93,8 @@ namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services
|
||||
Productid = item.ProductId,
|
||||
Productname = item.ProductName,
|
||||
Quantity = item.Quantity,
|
||||
Unitprice = (double)item.UnitPrice
|
||||
Unitprice = (double)item.UnitPrice,
|
||||
Isdiscounted = item.isDiscounted
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -72,7 +72,8 @@ namespace GrpcBasket
|
||||
Productid = item.ProductId,
|
||||
Productname = item.ProductName,
|
||||
Quantity = item.Quantity,
|
||||
Unitprice = (double)item.UnitPrice
|
||||
Unitprice = (double)item.UnitPrice,
|
||||
Isdiscounted = item.isDiscounted
|
||||
}));
|
||||
|
||||
return response;
|
||||
@ -93,7 +94,8 @@ namespace GrpcBasket
|
||||
ProductId = item.Productid,
|
||||
ProductName = item.Productname,
|
||||
Quantity = item.Quantity,
|
||||
UnitPrice = (decimal)item.Unitprice
|
||||
UnitPrice = (decimal)item.Unitprice,
|
||||
isDiscounted = item.Isdiscounted
|
||||
}));
|
||||
|
||||
return response;
|
||||
|
@ -12,6 +12,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
|
||||
public decimal OldUnitPrice { get; set; }
|
||||
public int Quantity { get; set; }
|
||||
public string PictureUrl { get; set; }
|
||||
public bool isDiscounted { get; set; }
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
var results = new List<ValidationResult>();
|
||||
|
@ -31,4 +31,5 @@ message BasketItemResponse {
|
||||
double oldunitprice = 5;
|
||||
int32 quantity = 6;
|
||||
string pictureurl = 7;
|
||||
bool isdiscounted = 8;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ namespace UnitTest.Basket.Application
|
||||
private readonly Mock<ICatalogService> _catalogServiceMock;
|
||||
private readonly Mock<IBasketService> _basketServiceMock;
|
||||
private readonly Mock<IIdentityParser<ApplicationUser>> _identityParserMock;
|
||||
private readonly Mock<ICouponService> _couponServiceMock;
|
||||
private readonly Mock<HttpContext> _contextMock;
|
||||
|
||||
public CartControllerTest()
|
||||
@ -24,6 +25,7 @@ namespace UnitTest.Basket.Application
|
||||
_catalogServiceMock = new Mock<ICatalogService>();
|
||||
_basketServiceMock = new Mock<IBasketService>();
|
||||
_identityParserMock = new Mock<IIdentityParser<ApplicationUser>>();
|
||||
_couponServiceMock = new Mock<ICouponService>;
|
||||
_contextMock = new Mock<HttpContext>();
|
||||
}
|
||||
|
||||
@ -33,6 +35,7 @@ namespace UnitTest.Basket.Application
|
||||
//Arrange
|
||||
var fakeBuyerId = "1";
|
||||
var action = string.Empty;
|
||||
var couponCode = string.Empty;
|
||||
var fakeBasket = GetFakeBasket(fakeBuyerId);
|
||||
var fakeQuantities = new Dictionary<string, int>()
|
||||
{
|
||||
@ -47,9 +50,9 @@ namespace UnitTest.Basket.Application
|
||||
.Returns(Task.FromResult(fakeBasket));
|
||||
|
||||
//Act
|
||||
var cartController = new CartController(_basketServiceMock.Object, _catalogServiceMock.Object, _identityParserMock.Object);
|
||||
var cartController = new CartController(_basketServiceMock.Object, _catalogServiceMock.Object, _identityParserMock.Object, _couponServiceMock.Object);
|
||||
cartController.ControllerContext.HttpContext = _contextMock.Object;
|
||||
var actionResult = await cartController.Index(fakeQuantities, action);
|
||||
var actionResult = await cartController.Index(fakeQuantities, couponCode, action);
|
||||
|
||||
//Assert
|
||||
var viewResult = Assert.IsType<ViewResult>(actionResult);
|
||||
@ -61,6 +64,7 @@ namespace UnitTest.Basket.Application
|
||||
//Arrange
|
||||
var fakeBuyerId = "1";
|
||||
var action = "[ Checkout ]";
|
||||
var couponCode = string.Empty;
|
||||
var fakeBasket = GetFakeBasket(fakeBuyerId);
|
||||
var fakeQuantities = new Dictionary<string, int>()
|
||||
{
|
||||
@ -75,9 +79,9 @@ namespace UnitTest.Basket.Application
|
||||
.Returns(Task.FromResult(fakeBasket));
|
||||
|
||||
//Act
|
||||
var orderController = new CartController(_basketServiceMock.Object, _catalogServiceMock.Object, _identityParserMock.Object);
|
||||
var orderController = new CartController(_basketServiceMock.Object, _catalogServiceMock.Object, _identityParserMock.Object, _couponServiceMock.Object);
|
||||
orderController.ControllerContext.HttpContext = _contextMock.Object;
|
||||
var actionResult = await orderController.Index(fakeQuantities, action);
|
||||
var actionResult = await orderController.Index(fakeQuantities, couponCode, action);
|
||||
|
||||
//Assert
|
||||
var redirectToActionResult = Assert.IsType<RedirectToActionResult>(actionResult);
|
||||
@ -95,7 +99,7 @@ namespace UnitTest.Basket.Application
|
||||
.Returns(Task.FromResult(1));
|
||||
|
||||
//Act
|
||||
var orderController = new CartController(_basketServiceMock.Object, _catalogServiceMock.Object, _identityParserMock.Object);
|
||||
var orderController = new CartController(_basketServiceMock.Object, _catalogServiceMock.Object, _identityParserMock.Object, _couponServiceMock.Object);
|
||||
orderController.ControllerContext.HttpContext = _contextMock.Object;
|
||||
var actionResult = await orderController.AddToCart(fakeCatalogItem);
|
||||
|
||||
|
@ -14,13 +14,15 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
||||
{
|
||||
private readonly IBasketService _basketSvc;
|
||||
private readonly ICatalogService _catalogSvc;
|
||||
private readonly ICouponService _couponSvc;
|
||||
private readonly IIdentityParser<ApplicationUser> _appUserParser;
|
||||
|
||||
public CartController(IBasketService basketSvc, ICatalogService catalogSvc, IIdentityParser<ApplicationUser> appUserParser)
|
||||
public CartController(IBasketService basketSvc, ICatalogService catalogSvc, IIdentityParser<ApplicationUser> appUserParser, ICouponService couponService)
|
||||
{
|
||||
_basketSvc = basketSvc;
|
||||
_catalogSvc = catalogSvc;
|
||||
_appUserParser = appUserParser;
|
||||
_couponSvc = couponService;
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Index()
|
||||
@ -40,14 +42,24 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
||||
return View();
|
||||
}
|
||||
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Index(Dictionary<string, int> quantities, string action)
|
||||
public async Task<IActionResult> Index(Dictionary<string, int> quantities, string couponCode, string action)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = _appUserParser.Parse(HttpContext.User);
|
||||
var basket = await _basketSvc.SetQuantities(user, quantities);
|
||||
|
||||
var vm = await _basketSvc.GetBasket(user);
|
||||
if (action == "[ Submit Coupon ]")
|
||||
{
|
||||
var updatedBasket = await _couponSvc.Apply(vm, couponCode);
|
||||
await _basketSvc.ApplyCoupon(updatedBasket);
|
||||
}
|
||||
if (action == "[ Update ]")
|
||||
{
|
||||
var basket = await _basketSvc.SetQuantities(user, quantities);
|
||||
}
|
||||
|
||||
if (action == "[ Checkout ]")
|
||||
{
|
||||
return RedirectToAction("Create", "Order");
|
||||
@ -60,7 +72,6 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
||||
|
||||
return View();
|
||||
}
|
||||
|
||||
public async Task<IActionResult> AddToCart(CatalogItem productDetails)
|
||||
{
|
||||
try
|
||||
|
@ -57,22 +57,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
||||
{
|
||||
var uri = API.Basket.UpdateBasket(_basketByPassUrl);
|
||||
|
||||
var basketUpdate = new
|
||||
{
|
||||
BuyerId = basket.BuyerId,
|
||||
Items = basket.Items.Select(item => new
|
||||
{
|
||||
Id = item.Id,
|
||||
ProductId = item.ProductId,
|
||||
ProductName = item.ProductName,
|
||||
UnitPrice = item.UnitPrice * (decimal)0.10,
|
||||
OldUnitPrice = item.UnitPrice,
|
||||
Quantity = item.Quantity,
|
||||
PictureUrl = item.PictureUrl
|
||||
}).ToArray()
|
||||
};
|
||||
|
||||
var basketContent = new StringContent(JsonConvert.SerializeObject(basketUpdate), System.Text.Encoding.UTF8, "application/json");
|
||||
var basketContent = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json");
|
||||
|
||||
var response = await _apiClient.PostAsync(uri, basketContent);
|
||||
|
||||
@ -137,7 +122,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
||||
{
|
||||
CatalogItemId = productId,
|
||||
BasketId = user.Id,
|
||||
Quantity = 1
|
||||
Quantity = 1,
|
||||
isDiscounted = false
|
||||
};
|
||||
|
||||
var basketContent = new StringContent(JsonConvert.SerializeObject(newItem), System.Text.Encoding.UTF8, "application/json");
|
||||
|
@ -5,6 +5,7 @@ using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using WebMVC.Infrastructure;
|
||||
@ -14,23 +15,69 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
||||
{
|
||||
public class CouponService : ICouponService
|
||||
{
|
||||
public Basket Apply(Basket basket)
|
||||
private readonly IOptions<AppSettings> _settings;
|
||||
private readonly HttpClient _apiClient;
|
||||
private readonly ILogger<CouponService> _logger;
|
||||
|
||||
public CouponService(HttpClient httpClient, IOptions<AppSettings> settings, ILogger<CouponService> logger)
|
||||
{
|
||||
//Basket updatedBasket = new Basket();
|
||||
//updatedBasket.BuyerId = basket.BuyerId;
|
||||
//// Todo: Stub for now, should reach out to a coupon microservice
|
||||
//if (basket.CouponCode == "SM360")
|
||||
//{
|
||||
// foreach (BasketItem item in basket.Items)
|
||||
// {
|
||||
// item.UnitPrice = item.UnitPrice - (item.UnitPrice * (decimal)0.1);
|
||||
// }
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
throw new System.NotImplementedException();
|
||||
//}
|
||||
//return basket;
|
||||
_apiClient = httpClient;
|
||||
_settings = settings;
|
||||
_logger = logger;
|
||||
}
|
||||
public async Task<Basket> Apply(Basket basket, string couponCode)
|
||||
{
|
||||
decimal discount = 0;
|
||||
|
||||
List<BasketItem> Items = new List<BasketItem>();
|
||||
// Todo: Stub for now, should reach out to a coupon microservice
|
||||
// Coupon for smart hotel 360 provides a 10% discount
|
||||
if (couponCode == "SH360")
|
||||
{
|
||||
foreach (BasketItem Item in basket.Items.Select(item => item).ToList())
|
||||
{
|
||||
if (Item.isDiscounted == false)
|
||||
{
|
||||
Items.Add(
|
||||
new BasketItem
|
||||
{
|
||||
Id = Item.Id,
|
||||
ProductId = Item.ProductId,
|
||||
ProductName = Item.ProductName,
|
||||
UnitPrice = Item.UnitPrice * (decimal)(1 - 0.1),
|
||||
OldUnitPrice = Item.UnitPrice,
|
||||
Quantity = Item.Quantity,
|
||||
PictureUrl = Item.PictureUrl,
|
||||
isDiscounted = true
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (BasketItem Item in basket.Items.Select(item => item).ToList())
|
||||
{
|
||||
Items.Add(
|
||||
new BasketItem
|
||||
{
|
||||
Id = Item.Id,
|
||||
ProductId = Item.ProductId,
|
||||
ProductName = Item.ProductName,
|
||||
UnitPrice = Item.UnitPrice,
|
||||
OldUnitPrice = Item.OldUnitPrice,
|
||||
Quantity = Item.Quantity,
|
||||
PictureUrl = Item.PictureUrl,
|
||||
isDiscounted = Item.isDiscounted
|
||||
});
|
||||
}
|
||||
}
|
||||
Basket basketUpdate = new Basket
|
||||
{
|
||||
BuyerId = basket.BuyerId,
|
||||
Items = Items
|
||||
};
|
||||
return basketUpdate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,6 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
||||
{
|
||||
public interface ICouponService
|
||||
{
|
||||
Basket Apply(Basket basket);
|
||||
Task<Basket> Apply(Basket basket, string couponCode);
|
||||
}
|
||||
}
|
||||
|
@ -160,6 +160,9 @@ namespace Microsoft.eShopOnContainers.WebMVC
|
||||
services.AddHttpClient<ICatalogService, CatalogService>()
|
||||
.AddDevspacesSupport();
|
||||
|
||||
services.AddHttpClient<ICouponService, CouponService>()
|
||||
.AddDevspacesSupport();
|
||||
|
||||
services.AddHttpClient<IOrderingService, OrderingService>()
|
||||
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
|
||||
.AddHttpMessageHandler<HttpClientRequestIdDelegatingHandler>()
|
||||
|
@ -7,6 +7,7 @@
|
||||
public string ProductName { get; init; }
|
||||
public decimal UnitPrice { get; init; }
|
||||
public decimal OldUnitPrice { get; init; }
|
||||
public bool isDiscounted { get; set; }
|
||||
public int Quantity { get; init; }
|
||||
public string PictureUrl { get; init; }
|
||||
}
|
||||
|
@ -34,23 +34,27 @@
|
||||
{
|
||||
var item = Model.Items[i];
|
||||
|
||||
<article class="esh-basket-items row">
|
||||
<section class="esh-basket-item esh-basket-item--middle col-lg-3 hidden-lg-down">
|
||||
<img class="esh-basket-image" src="@item.PictureUrl" />
|
||||
</section>
|
||||
<section class="esh-basket-item esh-basket-item--middle col-3">@item.ProductName</section>
|
||||
<section class="esh-basket-item esh-basket-item--middle col-2">$ @item.UnitPrice.ToString("N2")</section>
|
||||
<section class="esh-basket-item esh-basket-item--middle col-2">
|
||||
<input type="hidden" name="@("quantities[" + i +"].Key")" value="@item.Id" />
|
||||
<input type="number" class="esh-basket-input" min="1" name="@("quantities[" + i +"].Value")" value="@item.Quantity" />
|
||||
</section>
|
||||
<section class="esh-basket-item esh-basket-item--middle esh-basket-item--mark col-2">$ @Math.Round(item.Quantity * item.UnitPrice, 2).ToString("N2")</section>
|
||||
</article>
|
||||
<article class="esh-basket-items row">
|
||||
<section class="esh-basket-item esh-basket-item--middle col-lg-3 hidden-lg-down">
|
||||
<img class="esh-basket-image" src="@item.PictureUrl" />
|
||||
</section>
|
||||
<section class="esh-basket-item esh-basket-item--middle col-3">@item.ProductName</section>
|
||||
<section class="esh-basket-item esh-basket-item--middle col-2">$ @item.UnitPrice.ToString("N2")</section>
|
||||
<section class="esh-basket-item esh-basket-item--middle col-2">
|
||||
<input type="hidden" name="@("quantities[" + i +"].Key")" value="@item.Id" />
|
||||
<input type="number" class="esh-basket-input" min="1" name="@("quantities[" + i +"].Value")" value="@item.Quantity" />
|
||||
</section>
|
||||
<section class="esh-basket-item esh-basket-item--middle esh-basket-item--mark col-2">$ @Math.Round(item.Quantity * item.UnitPrice, 2).ToString("N2")</section>
|
||||
</article>
|
||||
|
||||
<div class="esh-basket-items--border row">
|
||||
@if (item.OldUnitPrice != 0)
|
||||
@if (item.OldUnitPrice != 0 && item.isDiscounted == false)
|
||||
{
|
||||
<div class="alert alert-warning esh-basket-margin12" role="alert"> Note that the price of this article changed in our Catalog. The old price when you originally added it to the basket was $ @item.OldUnitPrice </div>
|
||||
<div class="alert alert-warning esh-basket-margin12" role="alert"> Coupon code was not valid.</div>
|
||||
}
|
||||
@if (item.OldUnitPrice != 0 && item.isDiscounted == true)
|
||||
{
|
||||
<div class="alert alert-warning esh-basket-margin12" role="alert"> Coupon Applied Original Price $ @item.OldUnitPrice; New Price @item.UnitPrice </div>
|
||||
}
|
||||
</div>
|
||||
<br />
|
||||
@ -68,9 +72,20 @@
|
||||
</article>
|
||||
|
||||
<article class="esh-basket-items row">
|
||||
<section class="esh-basket-item col-7"></section>
|
||||
<section class="esh-basket-item col-7">
|
||||
<section class="esh-basket-item col-1">
|
||||
<input type="text"
|
||||
class="form-input form-input-medium"
|
||||
value="Coupon Code" name="couponCode" />
|
||||
<input type="submit"
|
||||
class="btn esh-basket-checkout"
|
||||
value="[ Submit Coupon ]" name="action" />
|
||||
</section>
|
||||
</section>
|
||||
<section class="esh-basket-item col-2">
|
||||
<button class="btn esh-basket-checkout" name="name" value="" type="submit">[ Update ]</button>
|
||||
<input type="submit"
|
||||
class="btn esh-basket-checkout"
|
||||
value="[ Update ]" name="action" />
|
||||
</section>
|
||||
<section class="esh-basket-item col-3">
|
||||
<input type="submit"
|
||||
@ -80,7 +95,7 @@
|
||||
</article>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
@ -36,7 +36,9 @@
|
||||
</article>
|
||||
<br/>
|
||||
<div class="esh-basket-items-margin-left1 row">
|
||||
<div class="alert alert-warning" role="alert" *ngIf="item.oldUnitPrice > 0"> Note that the price of this article changed in our Catalog. The old price when you originally added it to the basket was $ {{item.oldUnitPrice}} </div>
|
||||
<div class="alert alert-warning" role="alert" *ngIf="item.oldUnitPrice > 0 && item.isDiscounted == false"> Note that the application is jacked... added it to the basket was $ {{item.oldUnitPrice}} </div>
|
||||
<div class="alert alert-warning" role="alert" *ngIf="item.oldUnitPrice > 0 && item.isDiscounted == true"> Coupon was applied. New price: $ {{item.UnitPrice}} Old Price: $ {{item.oldUnitPrice}} </div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user