Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,20 @@ where c.AppliedDiscounts.Any(x => x == discountId)
return await _productRepository.PagedAsync(query, pageIndex, pageSize);
}

/// <summary>
/// Counts products visible in the given store that are also visible in at least one other store
/// </summary>
/// <param name="storeId">Store identifier</param>
/// <returns>Number of shared products</returns>
public virtual async Task<int> CountSharedProducts(string storeId)
{
var query = from p in _productRepository.Table
where !p.LimitedToStores || (p.Stores.Contains(storeId) && p.Stores.Count > 1)
select p;

return await _productRepository.CountAsync(query);
}


/// <summary>
/// Inserts a product
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Grand.Business.Core.Interfaces.Common.Security;
using Grand.Data;
using Grand.Domain.Directory;
using Grand.Infrastructure;
using Grand.Infrastructure.Caching;
using Grand.Infrastructure.Caching.Constants;
using Grand.Infrastructure.Extensions;
Expand Down Expand Up @@ -29,13 +30,15 @@ public CurrencyService(ICacheBase cacheBase,
IRepository<Currency> currencyRepository,
IAclService aclService,
CurrencySettings currencySettings,
IMediator mediator)
IMediator mediator,
IContextAccessor contextAccessor)
{
_cacheBase = cacheBase;
_currencyRepository = currencyRepository;
_aclService = aclService;
_currencySettings = currencySettings;
_mediator = mediator;
_contextAccessor = contextAccessor;
}

#endregion
Expand All @@ -47,6 +50,7 @@ public CurrencyService(ICacheBase cacheBase,
private readonly ICacheBase _cacheBase;
private readonly IMediator _mediator;
private readonly CurrencySettings _currencySettings;
private readonly IContextAccessor _contextAccessor;
private Currency _primaryCurrency;
private Currency _primaryExchangeRateCurrency;

Expand All @@ -66,11 +70,18 @@ public virtual Task<Currency> GetCurrencyById(string currencyId)
}

/// <summary>
/// Gets primary store currency
/// Gets primary store currency - the currency prices are stored in. A store may override it via
/// Store.PrimaryCurrencyId; otherwise the global setting applies.
/// </summary>
/// <returns>Currency</returns>
public async Task<Currency> GetPrimaryStoreCurrency()
{
if (_primaryCurrency != null) return _primaryCurrency;

var storeCurrencyId = _contextAccessor?.StoreContext?.CurrentStore?.PrimaryCurrencyId;
if (!string.IsNullOrEmpty(storeCurrencyId))
_primaryCurrency = await GetCurrencyById(storeCurrencyId);

return _primaryCurrency ??= await GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ public interface IProductService
/// <returns>Products</returns>
Task<IPagedList<Product>> GetProductsByDiscount(string discountId, int pageIndex = 0, int pageSize = int.MaxValue);

/// <summary>
/// Counts products visible in the given store that are also visible in at least one other store,
/// either because they are not limited to stores at all or because they are mapped to more stores.
/// </summary>
/// <param name="storeId">Store identifier</param>
/// <returns>Number of shared products</returns>
Task<int> CountSharedProducts(string storeId);

/// <summary>
/// Inserts a product
/// </summary>
Expand Down
6 changes: 6 additions & 0 deletions src/Core/Grand.Domain/Stores/Store.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ public class Store : BaseEntity, ITranslationEntity
/// </summary>
public string DefaultCurrencyId { get; set; }

/// <summary>
/// Gets or sets the identifier of the primary currency for this store - the currency prices are
/// stored in. Empty means the store follows the global CurrencySettings.PrimaryStoreCurrencyId.
/// </summary>
public string PrimaryCurrencyId { get; set; }

/// <summary>
/// Gets or sets the display order
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ public void TestInitialize()
_currencyRepo,
_aclService,
_currencySettings,
null);
null,
new Mock<IContextAccessor>().Object);

_taxSettings = new TaxSettings();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public void TestInitialize()

_currencyService = new CurrencyService(
cacheManager, _currencyRepository, _aclService,
_currencySettings, _eventPublisher);
_currencySettings, _eventPublisher, new Mock<IContextAccessor>().Object);

tempDiscountApplicationService = new Mock<IDiscountHandlerService>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -862,4 +862,59 @@ public async Task InsertDiscountTest()
Assert.IsNotNull(result);
Assert.HasCount(1, result.AppliedDiscounts);
}

[TestMethod]
public async Task CountSharedProducts_ProductAvailableInEveryStore_IsCountedAsShared()
{
//Arrange
await _productRepository.InsertAsync(new Product { LimitedToStores = false });

//Act
var result = await _productService.CountSharedProducts("store-1");

//Assert
Assert.AreEqual(1, result);
}

[TestMethod]
public async Task CountSharedProducts_ProductLimitedToThisStoreOnly_IsNotCountedAsShared()
{
//Arrange
await _productRepository.InsertAsync(new Product
{ LimitedToStores = true, Stores = new List<string> { "store-1" } });

//Act
var result = await _productService.CountSharedProducts("store-1");

//Assert
Assert.AreEqual(0, result);
}

[TestMethod]
public async Task CountSharedProducts_ProductLimitedToThisStoreAndAnother_IsCountedAsShared()
{
//Arrange
await _productRepository.InsertAsync(new Product
{ LimitedToStores = true, Stores = new List<string> { "store-1", "store-2" } });

//Act
var result = await _productService.CountSharedProducts("store-1");

//Assert
Assert.AreEqual(1, result);
}

[TestMethod]
public async Task CountSharedProducts_ProductLimitedToAnotherStoreOnly_IsNotCountedAsShared()
{
//Arrange
await _productRepository.InsertAsync(new Product
{ LimitedToStores = true, Stores = new List<string> { "store-2", "store-3" } });

//Act
var result = await _productService.CountSharedProducts("store-1");

//Assert
Assert.AreEqual(0, result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using Grand.Data;
using Grand.Data.Mongo;
using Grand.Domain.Directory;
using Grand.Domain.Stores;
using Grand.Infrastructure;
using Grand.Infrastructure.Caching;
using Grand.Infrastructure.Events;
using Grand.SharedKernel;
Expand All @@ -19,6 +21,7 @@ public class CurrencyServiceTests
{
private Mock<IAclService> _aclService;
private Mock<ICacheBase> _cacheManager;
private Mock<IContextAccessor> _contextAccessor;
private IRepository<Currency> _currencyRepository;
private ICurrencyService _currencyService;
private CurrencySettings _currencySettings;
Expand Down Expand Up @@ -74,6 +77,7 @@ public void TestInitialize()
IMongoCollection.Insert(currencyRUR);

tempCurrencyRepository.Setup(x => x.Table).Returns(IMongoCollection.Table);
tempCurrencyRepository.Setup(x => x.GetByIdAsync(It.IsAny<string>())).ReturnsAsync((Currency)null);
tempCurrencyRepository.Setup(x => x.GetByIdAsync(currencyUSD.Id)).ReturnsAsync(currencyUSD);
tempCurrencyRepository.Setup(x => x.GetByIdAsync(currencyEUR.Id)).ReturnsAsync(currencyEUR);
tempCurrencyRepository.Setup(x => x.GetByIdAsync(currencyRUR.Id)).ReturnsAsync(currencyRUR);
Expand All @@ -87,6 +91,7 @@ public void TestInitialize()

_cacheManager = new Mock<ICacheBase>();
_aclService = new Mock<IAclService>();
_contextAccessor = new Mock<IContextAccessor>();
_serviceProvider = new Mock<IServiceProvider>().Object;

_currencySettings = new CurrencySettings {
Expand All @@ -97,7 +102,7 @@ public void TestInitialize()

_currencyService = new CurrencyService(
_cacheManager.Object, _currencyRepository, _aclService.Object,
_currencySettings, _eventPublisher);
_currencySettings, _eventPublisher, _contextAccessor.Object);

//tempDiscountServiceMock.Setup(x => x.GetAllDiscounts(DiscountType.AssignedToCategories, "", "", false)).ReturnsAsync(new List<Discount>());
}
Expand Down Expand Up @@ -167,6 +172,79 @@ public async Task GetPrimaryStoreCurrency_ReturnExpectedValue()
Assert.AreEqual(result.Id, currencyUSD.Id);
}

[TestMethod]
public async Task GetPrimaryStoreCurrency_StoreDefinesPrimaryCurrency_ReturnsStoreCurrency()
{
_currencySettings.PrimaryStoreCurrencyId = currencyUSD.Id;
ResolveCurrencyByIdFromRepository();
SetCurrentStore(new Store { Id = "store-1", PrimaryCurrencyId = currencyRUR.Id });

var result = await _currencyService.GetPrimaryStoreCurrency();

Assert.AreEqual(currencyRUR.Id, result.Id);
}

[TestMethod]
public async Task GetPrimaryStoreCurrency_StoreDefinesNoPrimaryCurrency_FallsBackToGlobalSetting()
{
_currencySettings.PrimaryStoreCurrencyId = currencyUSD.Id;
ResolveCurrencyByIdFromRepository();
SetCurrentStore(new Store { Id = "store-1", PrimaryCurrencyId = "" });

var result = await _currencyService.GetPrimaryStoreCurrency();

Assert.AreEqual(currencyUSD.Id, result.Id);
}

[TestMethod]
public async Task GetPrimaryStoreCurrency_NoStoreContext_FallsBackToGlobalSetting()
{
_currencySettings.PrimaryStoreCurrencyId = currencyUSD.Id;
ResolveCurrencyByIdFromRepository();
_contextAccessor.Setup(x => x.StoreContext).Returns((IStoreContext)null);

var result = await _currencyService.GetPrimaryStoreCurrency();

Assert.AreEqual(currencyUSD.Id, result.Id);
}

[TestMethod]
public async Task GetPrimaryStoreCurrency_StorePrimaryCurrencyNoLongerExists_FallsBackToGlobalSetting()
{
_currencySettings.PrimaryStoreCurrencyId = currencyUSD.Id;
ResolveCurrencyByIdFromRepository();
SetCurrentStore(new Store { Id = "store-1", PrimaryCurrencyId = "deleted-currency" });

var result = await _currencyService.GetPrimaryStoreCurrency();

Assert.AreEqual(currencyUSD.Id, result.Id);
}

[TestMethod]
public async Task GetPrimaryExchangeRateCurrency_StoreDefinesPrimaryCurrency_StaysGlobal()
{
_currencySettings.PrimaryExchangeRateCurrencyId = currencyEUR.Id;
ResolveCurrencyByIdFromRepository();
SetCurrentStore(new Store { Id = "store-1", PrimaryCurrencyId = currencyRUR.Id });

var result = await _currencyService.GetPrimaryExchangeRateCurrency();

Assert.AreEqual(currencyEUR.Id, result.Id);
}

private void ResolveCurrencyByIdFromRepository()
{
_cacheManager.Setup(c => c.GetAsync(It.IsAny<string>(), It.IsAny<Func<Task<Currency>>>()))
.Returns((string _, Func<Task<Currency>> acquire) => acquire());
}

private void SetCurrentStore(Store store)
{
var storeContext = new Mock<IStoreContext>();
storeContext.Setup(x => x.CurrentStore).Returns(store);
_contextAccessor.Setup(x => x.StoreContext).Returns(storeContext.Object);
}

[TestMethod]
public async Task InsertCurrency_ValidArgument()
{
Expand Down
Loading