diff --git a/src/ApplicationCore/Entities/BasketAggregate/Basket.cs b/src/ApplicationCore/Entities/BasketAggregate/Basket.cs index 3ac0867..71ab4ee 100644 --- a/src/ApplicationCore/Entities/BasketAggregate/Basket.cs +++ b/src/ApplicationCore/Entities/BasketAggregate/Basket.cs @@ -10,6 +10,9 @@ public class Basket : BaseEntity, IAggregateRoot private readonly List _items = new List(); public IReadOnlyCollection Items => _items.AsReadOnly(); + public int TotalItems => _items.Sum(i => i.Quantity); + + public Basket(string buyerId) { BuyerId = buyerId; diff --git a/src/ApplicationCore/Interfaces/IBasketQueryService.cs b/src/ApplicationCore/Interfaces/IBasketQueryService.cs deleted file mode 100644 index 1d1babb..0000000 --- a/src/ApplicationCore/Interfaces/IBasketQueryService.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.Threading.Tasks; - -namespace Microsoft.eShopWeb.ApplicationCore.Interfaces; - -public interface IBasketQueryService -{ - Task CountTotalBasketItems(string username); -} diff --git a/src/Infrastructure/Data/BasketQueryService.cs b/src/Infrastructure/Data/BasketQueryService.cs deleted file mode 100644 index 4d392fe..0000000 --- a/src/Infrastructure/Data/BasketQueryService.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Linq; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; -using Microsoft.eShopWeb.ApplicationCore.Interfaces; - -namespace Microsoft.eShopWeb.Infrastructure.Data; - -public class BasketQueryService : IBasketQueryService -{ - private readonly CatalogContext _dbContext; - - public BasketQueryService(CatalogContext dbContext) - { - _dbContext = dbContext; - } - - public async Task CountTotalBasketItems(string username) - { - var totalItems = await _dbContext.Baskets - .Where(basket => basket.BuyerId == username) - .SelectMany(item => item.Items) - .SumAsync(sum => sum.Quantity); - - return totalItems; - } -} diff --git a/src/Web/Configuration/ConfigureCoreServices.cs b/src/Web/Configuration/ConfigureCoreServices.cs index 33e85ea..b9b843f 100644 --- a/src/Web/Configuration/ConfigureCoreServices.cs +++ b/src/Web/Configuration/ConfigureCoreServices.cs @@ -18,7 +18,6 @@ public static class ConfigureCoreServices services.AddScoped(); services.AddScoped(); - services.AddScoped(); services.AddSingleton(new UriComposer(configuration.Get())); services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>)); services.AddTransient(); diff --git a/src/Web/Interfaces/IBasketViewModelService.cs b/src/Web/Interfaces/IBasketViewModelService.cs index 0c18a25..a5cb8b4 100644 --- a/src/Web/Interfaces/IBasketViewModelService.cs +++ b/src/Web/Interfaces/IBasketViewModelService.cs @@ -7,8 +7,5 @@ namespace Microsoft.eShopWeb.Web.Interfaces; public interface IBasketViewModelService { Task GetOrCreateBasketForUser(string userName); - - Task CountTotalBasketItems(string username); - Task Map(Basket basket); } diff --git a/src/Web/Pages/Basket/Checkout.cshtml b/src/Web/Pages/Basket/Checkout.cshtml index aa483ab..b52a931 100644 --- a/src/Web/Pages/Basket/Checkout.cshtml +++ b/src/Web/Pages/Basket/Checkout.cshtml @@ -80,7 +80,7 @@
- [ Continue Shopping..] + [ Continue Shopping ]
} \ No newline at end of file diff --git a/src/Web/Pages/Basket/Index.cshtml b/src/Web/Pages/Basket/Index.cshtml index cf05540..4c8ea44 100644 --- a/src/Web/Pages/Basket/Index.cshtml +++ b/src/Web/Pages/Basket/Index.cshtml @@ -63,7 +63,7 @@ diff --git a/src/Web/Pages/Shared/Components/BasketComponent/Basket.cs b/src/Web/Pages/Shared/Components/BasketComponent/Basket.cs index 519a335..4b6c6c6 100644 --- a/src/Web/Pages/Shared/Components/BasketComponent/Basket.cs +++ b/src/Web/Pages/Shared/Components/BasketComponent/Basket.cs @@ -2,21 +2,27 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; +using Microsoft.eShopWeb.ApplicationCore.Interfaces; +using Microsoft.eShopWeb.ApplicationCore.Specifications; using Microsoft.eShopWeb.Infrastructure.Identity; using Microsoft.eShopWeb.Web.Interfaces; using Microsoft.eShopWeb.Web.ViewModels; +using BasketEntity = Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate.Basket; namespace Microsoft.eShopWeb.Web.Pages.Shared.Components.BasketComponent; public class Basket : ViewComponent { - private readonly IBasketViewModelService _basketService; + private readonly IBasketViewModelService _basketViewModelService; + private readonly IReadRepository _basketRepository; private readonly SignInManager _signInManager; - public Basket(IBasketViewModelService basketService, - SignInManager signInManager) + public Basket(IBasketViewModelService basketViewModelService, + IReadRepository basketRepository, + SignInManager signInManager) { - _basketService = basketService; + _basketViewModelService = basketViewModelService; + _basketRepository = basketRepository; _signInManager = signInManager; } @@ -33,18 +39,26 @@ public class Basket : ViewComponent { if (_signInManager.IsSignedIn(HttpContext.User)) { - return await _basketService.CountTotalBasketItems(User.Identity.Name); + var userNameSpec = new BasketWithItemsSpecification(User.Identity.Name); + + var userBasket = await _basketRepository.GetBySpecAsync(userNameSpec); + if (userBasket == null) return 0; + return userBasket.TotalItems; } string anonymousId = GetAnnonymousIdFromCookie(); if (anonymousId == null) return 0; - return await _basketService.CountTotalBasketItems(anonymousId); + var anonymousSpec = new BasketWithItemsSpecification(anonymousId); + var anonymousBasket = await _basketRepository.GetBySpecAsync(anonymousSpec); + if (anonymousBasket == null) return 0; + return anonymousBasket.TotalItems; } private string GetAnnonymousIdFromCookie() { + // TODO: Add a prefix to anonymous cookie values so they cannot collide with user names if (Request.Cookies.ContainsKey(Constants.BASKET_COOKIENAME)) { var id = Request.Cookies[Constants.BASKET_COOKIENAME]; diff --git a/src/Web/Services/BasketViewModelService.cs b/src/Web/Services/BasketViewModelService.cs index 06cfdf4..ab12285 100644 --- a/src/Web/Services/BasketViewModelService.cs +++ b/src/Web/Services/BasketViewModelService.cs @@ -14,17 +14,14 @@ public class BasketViewModelService : IBasketViewModelService { private readonly IRepository _basketRepository; private readonly IUriComposer _uriComposer; - private readonly IBasketQueryService _basketQueryService; - private readonly IRepository _itemRepository; + private readonly IReadRepository _itemRepository; public BasketViewModelService(IRepository basketRepository, - IRepository itemRepository, - IUriComposer uriComposer, - IBasketQueryService basketQueryService) + IReadRepository itemRepository, + IUriComposer uriComposer) { _basketRepository = basketRepository; _uriComposer = uriComposer; - _basketQueryService = basketQueryService; _itemRepository = itemRepository; } @@ -86,11 +83,4 @@ public class BasketViewModelService : IBasketViewModelService Items = await GetBasketItems(basket.Items) }; } - - public async Task CountTotalBasketItems(string username) - { - var counter = await _basketQueryService.CountTotalBasketItems(username); - - return counter; - } } diff --git a/tests/UnitTests/ApplicationCore/Entities/BasketTests/BasketAddItem.cs b/tests/UnitTests/ApplicationCore/Entities/BasketTests/BasketAddItem.cs index 18a47cd..6f3ad2d 100644 --- a/tests/UnitTests/ApplicationCore/Entities/BasketTests/BasketAddItem.cs +++ b/tests/UnitTests/ApplicationCore/Entities/BasketTests/BasketAddItem.cs @@ -1,8 +1,8 @@ using System; -using System.Linq; -using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate; -using Xunit; - +using System.Linq; +using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate; +using Xunit; + namespace Microsoft.eShopWeb.UnitTests.ApplicationCore.Entities.BasketTests; public class BasketAddItem @@ -72,4 +72,4 @@ public class BasketAddItem Assert.Throws(() => basket.AddItem(_testCatalogItemId, _testUnitPrice, -2)); } -} +} diff --git a/tests/UnitTests/ApplicationCore/Entities/BasketTests/BasketTotalItems.cs b/tests/UnitTests/ApplicationCore/Entities/BasketTests/BasketTotalItems.cs new file mode 100644 index 0000000..cedffae --- /dev/null +++ b/tests/UnitTests/ApplicationCore/Entities/BasketTests/BasketTotalItems.cs @@ -0,0 +1,35 @@ +using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate; +using Xunit; + +namespace Microsoft.eShopWeb.UnitTests.ApplicationCore.Entities.BasketTests; + +public class BasketTotalItems +{ + private readonly int _testCatalogItemId = 123; + private readonly decimal _testUnitPrice = 1.23m; + private readonly int _testQuantity = 2; + private readonly string _buyerId = "Test buyerId"; + + [Fact] + public void ReturnsTotalQuantityWithOneItem() + { + var basket = new Basket(_buyerId); + basket.AddItem(_testCatalogItemId, _testUnitPrice, _testQuantity); + + var result = basket.TotalItems; + + Assert.Equal(_testQuantity, result); + } + + [Fact] + public void ReturnsTotalQuantityWithMultipleItems() + { + var basket = new Basket(_buyerId); + basket.AddItem(_testCatalogItemId, _testUnitPrice, _testQuantity); + basket.AddItem(_testCatalogItemId, _testUnitPrice, _testQuantity*2); + + var result = basket.TotalItems; + + Assert.Equal(_testQuantity*3, result); + } +}