public virtual async Task SaveChangesAsync(TaxProvider[] taxProviders)
        {
            var pkMap = new PrimaryKeyResolvingMap();

            using (var repository = _repositoryFactory())
            {
                var dataExistEntities = await repository.GetStoreTaxProviderByIdsAsync(taxProviders.Where(x => !x.IsTransient()).Select(x => x.Id).ToArray());

                foreach (var taxProvider in taxProviders)
                {
                    var originalEntity = dataExistEntities.FirstOrDefault(x => x.Id == taxProvider.Id);
                    var modifiedEntity = AbstractTypeFactory <StoreTaxProviderEntity> .TryCreateInstance().FromModel(taxProvider, pkMap);

                    if (originalEntity != null)
                    {
                        modifiedEntity.Patch(originalEntity);
                    }
                    else
                    {
                        repository.Add(modifiedEntity);
                    }
                }
                //Raise domain events
                await repository.UnitOfWork.CommitAsync();

                pkMap.ResolvePrimaryKeys();
                //Save settings
                await _settingManager.DeepSaveSettingsAsync(taxProviders);
            }

            TaxCacheRegion.ExpireRegion();
        }
        public virtual async Task <TaxProvider[]> GetByIdsAsync(string[] ids, string responseGroup)
        {
            var cacheKey = CacheKey.With(GetType(), "GetByIdsAsync", string.Join("-", ids));

            return(await _memCache.GetOrCreateExclusiveAsync(cacheKey, async (cacheEntry) =>
            {
                var result = new List <TaxProvider>();

                using (var repository = _repositoryFactory())
                {
                    repository.DisableChangesTracking();
                    var existEntities = await repository.GetStoreTaxProviderByIdsAsync(ids, responseGroup);
                    foreach (var existEntity in existEntities)
                    {
                        var taxProvider = AbstractTypeFactory <TaxProvider> .TryCreateInstance(string.IsNullOrEmpty(existEntity.TypeName) ? $"{existEntity.Code}TaxProvider" : existEntity.TypeName);
                        if (taxProvider != null)
                        {
                            existEntity.ToModel(taxProvider);

                            await _settingManager.DeepLoadSettingsAsync(taxProvider);
                            result.Add(taxProvider);
                        }
                    }
                    cacheEntry.AddExpirationToken(TaxCacheRegion.CreateChangeToken());
                    return result.ToArray();
                }
            }));
        }
        public virtual async Task <TaxProviderSearchResult> SearchTaxProvidersAsync(TaxProviderSearchCriteria criteria)
        {
            var cacheKey = CacheKey.With(GetType(), "SearchTaxProvidersAsync", criteria.GetCacheKey());

            return(await _memCache.GetOrCreateExclusiveAsync(cacheKey, async (cacheEntry) =>
            {
                cacheEntry.AddExpirationToken(TaxCacheRegion.CreateChangeToken());
                var result = AbstractTypeFactory <TaxProviderSearchResult> .TryCreateInstance();

                var tmpSkip = 0;
                var tmpTake = 0;

                var sortInfos = BuildSortExpression(criteria);
                using (var repository = _repositoryFactory())
                {
                    var query = BuildQuery(repository, criteria);

                    result.TotalCount = await query.CountAsync();
                    if (criteria.Take > 0)
                    {
                        var providerIds = await query.OrderBySortInfos(sortInfos).ThenBy(x => x.Id)
                                          .Select(x => x.Id).Skip(criteria.Skip)
                                          .Take(criteria.Take).ToArrayAsync();

                        result.Results = (await _taxProviderService.GetByIdsAsync(providerIds, criteria.ResponseGroup)).AsQueryable().OrderBySortInfos(sortInfos).ToList();
                    }
                }
                tmpSkip = Math.Min(result.TotalCount, criteria.Skip);
                tmpTake = Math.Min(criteria.Take, Math.Max(0, result.TotalCount - criteria.Skip));

                criteria.Skip = criteria.Skip - tmpSkip;
                criteria.Take = criteria.Take - tmpTake;
                if (criteria.Take > 0 && !criteria.WithoutTransient)
                {
                    var transientProvidersQuery = AbstractTypeFactory <TaxProvider> .AllTypeInfos.Select(x => AbstractTypeFactory <TaxProvider> .TryCreateInstance(x.Type.Name))
                                                  .OfType <TaxProvider>().AsQueryable();
                    if (!string.IsNullOrEmpty(criteria.Keyword))
                    {
                        transientProvidersQuery = transientProvidersQuery.Where(x => x.Code.Contains(criteria.Keyword));
                    }
                    var allPersistentProvidersTypes = result.Results.Select(x => x.GetType()).Distinct();
                    transientProvidersQuery = transientProvidersQuery.Where(x => !allPersistentProvidersTypes.Contains(x.GetType()));

                    result.TotalCount += transientProvidersQuery.Count();
                    var transientProviders = transientProvidersQuery.Skip(criteria.Skip)
                                             .Take(criteria.Take)
                                             .ToList();

                    foreach (var transientProvider in transientProviders)
                    {
                        await _settingManager.DeepLoadSettingsAsync(transientProvider);
                    }

                    result.Results = result.Results.Concat(transientProviders).AsQueryable()
                                     .OrderBySortInfos(sortInfos).ThenBy(x => x.Id).ToList();
                }
                return result;
            }));
        }
        public virtual async Task EvaluateTaxesAsync(TaxEvaluationContext context, IEnumerable <ITaxable> owners)
        {
            IList <coreService.TaxRate> taxRates = new List <coreService.TaxRate>();

            if (context.StoreTaxCalculationEnabled)
            {
                var cacheKey = CacheKey.With(GetType(), context.GetCacheKey());

                taxRates = await _memoryCache.GetOrCreateExclusiveAsync(cacheKey, (cacheEntry) =>
                {
                    cacheEntry.AddExpirationToken(TaxCacheRegion.CreateChangeToken());
                    return(_commerceApi.EvaluateTaxesAsync(context.StoreId, context.ToTaxEvaluationContextDto()));
                });
            }
            ApplyTaxRates(taxRates, owners);
        }
        public ActionResult ResetCache()
        {
            //TODO: Replace to some other (maybe with using reflection)
            ThemeEngineCacheRegion.ExpireRegion();
            CartCacheRegion.ExpireRegion();
            CatalogCacheRegion.ExpireRegion();
            ContentBlobCacheRegion.ExpireRegion();
            CustomerCacheRegion.ExpireRegion();
            MarketingCacheRegion.ExpireRegion();
            PricingCacheRegion.ExpireRegion();
            QuoteCacheRegion.ExpireRegion();
            RecommendationsCacheRegion.ExpireRegion();
            StaticContentCacheRegion.ExpireRegion();
            StoreCacheRegion.ExpireRegion();
            TaxCacheRegion.ExpireRegion();
            SubscriptionCacheRegion.ExpireRegion();
            SecurityCacheRegion.ExpireRegion();

            return(StoreFrontRedirect("~/"));
        }
        public virtual async Task EvaluateTaxesAsync(TaxEvaluationContext context, IEnumerable <ITaxable> owners)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            if (owners == null)
            {
                throw new ArgumentNullException(nameof(owners));
            }
            IList <coreService.TaxRate> taxRates = new List <coreService.TaxRate>();

            if (context.StoreTaxCalculationEnabled)
            {
                //Do not execute platform API for tax evaluation if fixed tax rate is used
                if (context.FixedTaxRate != 0)
                {
                    foreach (var line in context.Lines ?? Enumerable.Empty <TaxLine>())
                    {
                        var rate = new coreService.TaxRate()
                        {
                            Rate     = (double)(line.Amount * context.FixedTaxRate * 0.01m).Amount,
                            Currency = context.Currency.Code,
                            Line     = line.ToTaxLineDto()
                        };
                        taxRates.Add(rate);
                    }
                }
                else
                {
                    var cacheKey = CacheKey.With(GetType(), context.GetCacheKey());
                    taxRates = await _memoryCache.GetOrCreateExclusiveAsync(cacheKey, (cacheEntry) =>
                    {
                        cacheEntry.AddExpirationToken(TaxCacheRegion.CreateChangeToken());
                        return(_commerceApi.EvaluateTaxesAsync(context.StoreId, context.ToTaxEvaluationContextDto()));
                    });
                }
            }
            ApplyTaxRates(taxRates, owners);
        }