예제 #1
0
        private async Task ValidateItemsAsync(ShoppingCart cart)
        {
            var workContext = _workContextFactory();
            var productIds  = cart.Items.Select(i => i.ProductId).ToArray();
            var cacheKey    = "CartValidator.ValidateItemsAsync-" + workContext.CurrentCurrency.Code + ":" + workContext.CurrentLanguage + ":" + string.Join(":", productIds);
            var products    = await _cacheManager.GetAsync(cacheKey, "ApiRegion", async() => { return(await _catalogService.GetProductsAsync(productIds, ItemResponseGroup.ItemLarge)); });

            var productsToReevaluate = GetProductsToReevaluate(cart, products);

            // Reevaluate products promotions for getting new product prices to compare with
            if (productsToReevaluate.Any())
            {
                var promotionContext = workContext.ToPromotionEvaluationContext(productsToReevaluate);
                await _promotionEvaluator.EvaluateDiscountsAsync(promotionContext, productsToReevaluate);
            }

            foreach (var lineItem in cart.Items.ToList())
            {
                lineItem.ValidationErrors.Clear();

                var product = products.FirstOrDefault(p => p.Id == lineItem.ProductId);
                if (product == null || (product != null && (!product.IsActive || !product.IsBuyable)))
                {
                    lineItem.ValidationErrors.Add(new ProductUnavailableError());
                }
                else if (product != null)
                {
                    if (product.TrackInventory && product.Inventory != null &&
                        (lineItem.ValidationType == ValidationType.PriceAndQuantity || lineItem.ValidationType == ValidationType.Quantity))
                    {
                        var availableQuantity = product.Inventory.InStockQuantity;
                        if (product.Inventory.ReservedQuantity.HasValue)
                        {
                            availableQuantity -= product.Inventory.ReservedQuantity.Value;
                        }
                        if (availableQuantity.HasValue && lineItem.Quantity > availableQuantity.Value)
                        {
                            lineItem.ValidationErrors.Add(new ProductQuantityError(availableQuantity.Value));
                        }
                    }

                    if (lineItem.PlacedPrice != product.Price.ActualPrice &&
                        (lineItem.ValidationType == ValidationType.PriceAndQuantity || lineItem.ValidationType == ValidationType.Price))
                    {
                        var newLineItem = product.ToLineItem(workContext.CurrentLanguage, lineItem.Quantity);
                        newLineItem.ValidationWarnings.Add(new ProductPriceError(lineItem.PlacedPrice));

                        cart.Items.Remove(lineItem);
                        cart.Items.Add(newLineItem);
                    }
                }
            }

            // Reevaluate shopping cart for applying promotions for changed product prices
            if (productsToReevaluate.Any())
            {
                var promotionContext = workContext.ToPromotionEvaluationContext();
                await _promotionEvaluator.EvaluateDiscountsAsync(promotionContext, new[] { cart });
            }
        }
예제 #2
0
        public virtual async Task <ICollection <ShippingMethod> > GetAvailableShippingMethodsAsync()
        {
            var availableShippingMethods = new List <ShippingMethod>();

            // TODO: Remake with shipmentId
            var serviceModels = await _cartApi.CartModuleGetShipmentMethodsAsync(_cart.Id);

            foreach (var serviceModel in serviceModels)
            {
                availableShippingMethods.Add(serviceModel.ToWebModel(_cart.Currency));
            }
            //Evaluate tax for shipping methods
            var taxEvalContext = _cart.ToTaxEvalContext();

            taxEvalContext.Lines.Clear();
            taxEvalContext.Lines.AddRange(availableShippingMethods.Select(x => x.ToTaxLine()));
            var taxResult = await _commerceApi.CommerceEvaluateTaxesAsync(_cart.StoreId, taxEvalContext);

            if (taxResult != null)
            {
                var taxRates = taxResult.Select(x => x.ToWebModel(_cart.Currency)).ToList();
                foreach (var shippingMethod in availableShippingMethods)
                {
                    shippingMethod.ApplyTaxRates(taxRates);
                }
            }
            //Evaluate promotions for shipping methods
            var promoEvalContext = _cart.ToPromotionEvaluationContext();
            await _promotionEvaluator.EvaluateDiscountsAsync(promoEvalContext, availableShippingMethods);

            return(availableShippingMethods);
        }
예제 #3
0
        public virtual async Task EvaluateProductPricesAsync(IEnumerable <Product> products, WorkContext workContext)
        {
            if (products == null)
            {
                throw new ArgumentNullException(nameof(products));
            }
            if (workContext == null)
            {
                throw new ArgumentNullException(nameof(workContext));
            }

            //Evaluate products prices
            var evalContext    = workContext.ToPriceEvaluationContext(products);
            var cacheKey       = CacheKey.With(GetType(), "EvaluateProductPricesAsync", evalContext.GetCacheKey());
            var pricesResponse = await _memoryCache.GetOrCreateExclusiveAsync(cacheKey, async (cacheEntry) =>
            {
                cacheEntry.AddExpirationToken(PricingCacheRegion.CreateChangeToken());
                cacheEntry.AddExpirationToken(_apiChangesWatcher.CreateChangeToken());

                return(await _pricingApi.EvaluatePricesAsync(evalContext.ToPriceEvaluationContextDto()));
            });

            ApplyProductPrices(products, pricesResponse, workContext);

            //Evaluate product discounts
            //Fill product inventories for getting InStockQuantity data for promotion evaluation
            await _inventoryService.EvaluateProductInventoriesAsync(products.ToList(), workContext);

            var promoEvalContext = workContext.ToPromotionEvaluationContext(products);
            await _promotionEvaluator.EvaluateDiscountsAsync(promoEvalContext, products);

            //Evaluate product taxes
            var taxEvalContext = workContext.ToTaxEvaluationContext(products);
            await _taxEvaluator.EvaluateTaxesAsync(taxEvalContext, products);
        }
        private async Task LoadProductsDiscountsAsync(Product[] products)
        {
            var promotionContext = _workContext.ToPromotionEvaluationContext();

            promotionContext.PromoEntries = products.Select(x => x.ToPromotionItem()).ToList();
            await _promotionEvaluator.EvaluateDiscountsAsync(promotionContext, products);
        }
예제 #5
0
        private async Task LoadProductsDiscountsAsync(IEnumerable <Product> products)
        {
            var workContext      = _workContextFactory();
            var promotionContext = workContext.ToPromotionEvaluationContext(products);

            promotionContext.PromoEntries = products.Select(x => x.ToPromotionItem()).ToList();
            await _promotionEvaluator.EvaluateDiscountsAsync(promotionContext, products);
        }
예제 #6
0
        public virtual async Task<IEnumerable<ShippingMethod>> GetAvailableShippingMethodsAsync()
        {
            var workContext = _workContextAccessor.WorkContext;

            //Request available shipping rates 
            var retVal = await _cartService.GetAvailableShippingMethodsAsync(Cart);
            
            //Evaluate promotions cart and apply rewards for available shipping methods
            var promoEvalContext = Cart.ToPromotionEvaluationContext();
            await _promotionEvaluator.EvaluateDiscountsAsync(promoEvalContext, retVal);

            //Evaluate taxes for available shipping rates
            var taxEvalContext = Cart.ToTaxEvalContext(workContext.CurrentStore);
            taxEvalContext.Lines.Clear();
            taxEvalContext.Lines.AddRange(retVal.SelectMany(x => x.ToTaxLines()));
            await _taxEvaluator.EvaluateTaxesAsync(taxEvalContext, retVal);

            return retVal;
        }
예제 #7
0
        public async Task <ActionResult> GetActualProductPricesJson(Product[] products)
        {
            var prices = new List <ProductPrice>();

            if (products == null)
            {
                return(Json(prices, JsonRequestBehavior.AllowGet));
            }

            var pricesResponse = await _pricingApi.PricingModuleEvaluatePricesAsync(
                evalContextProductIds : products.Select(p => p.Id).ToList(),
                evalContextCatalogId : WorkContext.CurrentStore.Catalog,
                evalContextCurrency : WorkContext.CurrentCurrency.Code,
                evalContextCustomerId : WorkContext.CurrentCustomer.Id,
                evalContextLanguage : WorkContext.CurrentLanguage.CultureName,
                evalContextStoreId : WorkContext.CurrentStore.Id);

            if (pricesResponse == null)
            {
                return(Json(prices, JsonRequestBehavior.AllowGet));
            }

            prices = pricesResponse.Select(p => p.ToWebModel()).ToList();
            var promotionContext = new PromotionEvaluationContext
            {
                CartPromoEntries = GetCartPromoEntries(WorkContext.CurrentCart),
                Currency         = WorkContext.CurrentCurrency,
                CustomerId       = WorkContext.CurrentCustomer.Id,
                IsRegisteredUser = WorkContext.CurrentCustomer.HasAccount,
                Language         = WorkContext.CurrentLanguage,
                PromoEntries     = GetPromoEntries(products, prices),
                StoreId          = WorkContext.CurrentStore.Id
            };

            foreach (var product in products)
            {
                product.Currency = WorkContext.CurrentCurrency;
                product.Price    = prices.FirstOrDefault(p => p.ProductId == product.Id);
            }

            await _promotionEvaluator.EvaluateDiscountsAsync(promotionContext, products);

            prices = products.Select(p => p.Price).ToList();

            foreach (var price in prices)
            {
                if (price.ActiveDiscount != null)
                {
                    price.AbsoluteBenefit += price.ActiveDiscount.Amount;
                    price.ActualPrice      = price.SalePrice - price.AbsoluteBenefit;
                }
            }

            return(Json(prices, JsonRequestBehavior.AllowGet));
        }
예제 #8
0
        public virtual async Task <ICollection <ShippingMethod> > GetAvailableShippingMethodsAsync()
        {
            var workContext = _workContextFactory();

            //Request available shipping rates
            var shippingRates = await _cartApi.CartModule.GetAvailableShippingRatesAsync(Cart.Id);

            var retVal = shippingRates.Select(x => x.ToShippingMethod(Cart.Currency, workContext.AllCurrencies)).OrderBy(x => x.Priority).ToList();

            //Evaluate promotions cart and apply rewards for available shipping methods
            var promoEvalContext = Cart.ToPromotionEvaluationContext();
            await _promotionEvaluator.EvaluateDiscountsAsync(promoEvalContext, retVal);

            //Evaluate taxes for available shipping rates
            var taxEvalContext = Cart.ToTaxEvalContext();

            taxEvalContext.Lines.Clear();
            taxEvalContext.Lines.AddRange(retVal.SelectMany(x => x.ToTaxLines()));
            await _taxEvaluator.EvaluateTaxesAsync(taxEvalContext, retVal);

            return(retVal);
        }
예제 #9
0
        public virtual async Task EvaluateProductPricesAsync(ICollection <Product> products, WorkContext workContext)
        {
            //Evaluate products prices
            var evalContext = workContext.ToPriceEvaluationContextDto(products);

            var pricesResponse = await _pricingApi.PricingModule.EvaluatePricesAsync(evalContext);

            ApplyProductPricesInternal(products, pricesResponse, workContext);
            //Evaluate product discounts
            var promoEvalContext = workContext.ToPromotionEvaluationContext(products);
            await _promotionEvaluator.EvaluateDiscountsAsync(promoEvalContext, products);

            //Evaluate product taxes
            var taxEvalContext = workContext.ToTaxEvaluationContext(products);
            await _taxEvaluator.EvaluateTaxesAsync(taxEvalContext, products);
        }
예제 #10
0
        public async Task <ActionResult> GetActualProductPricesJson(Product[] products)
        {
            if (products == null)
            {
                throw new ArgumentNullException("products");
            }
            //Evaluate products prices
            await _pricingService.EvaluateProductPricesAsync(products);

            //Evaluate discounts
            var promotionContext = WorkContext.ToPromotionEvaluationContext();

            promotionContext.PromoEntries = products.Select(x => x.ToPromotionItem()).ToList();
            await _promotionEvaluator.EvaluateDiscountsAsync(promotionContext, products);

            var retVal = products.Select(x => x.Price).ToArray();

            return(Json(retVal, JsonRequestBehavior.AllowGet));
        }
예제 #11
0
        public async Task <ActionResult> GetActualProductPrices(Product[] products)
        {
            if (products != null)
            {
                //Evaluate products prices
                await _pricingService.EvaluateProductPricesAsync(products);

                //Evaluate discounts
                var promotionContext = WorkContext.ToPromotionEvaluationContext(products);
                promotionContext.PromoEntries = products.Select(x => x.ToPromotionItem()).ToList();

                await _promotionEvaluator.EvaluateDiscountsAsync(promotionContext, products);

                var retVal = products.Select(x => x.Price).ToArray();

                return(Json(retVal));
            }
            return(new HttpStatusCodeResult(HttpStatusCode.OK));
        }
예제 #12
0
        private async Task EvaluatePromotionsAsync()
        {
            var promotionItems = _cart.Items.Select(i => i.ToPromotionItem()).ToList();

            var promotionContext = new PromotionEvaluationContext();

            promotionContext.CartPromoEntries = promotionItems;
            promotionContext.CartTotal        = _cart.Total;
            promotionContext.Coupon           = _cart.Coupon != null ? _cart.Coupon.Code : null;
            promotionContext.Currency         = _cart.Currency;
            promotionContext.CustomerId       = _customer.Id;
            promotionContext.IsRegisteredUser = _customer.HasAccount;
            promotionContext.Language         = _language;
            promotionContext.PromoEntries     = promotionItems;
            promotionContext.StoreId          = _store.Id;

            await _promotionEvaluator.EvaluateDiscountsAsync(promotionContext, new IDiscountable[] { _cart });

            CalculateTotals();
        }
예제 #13
0
        public virtual async Task <ICartBuilder> EvaluatePromotionsAsync()
        {
            var promotionItems = _cart.Items.Select(i => i.ToPromotionItem()).ToList();

            var promotionContext = new PromotionEvaluationContext();

            promotionContext.CartPromoEntries = promotionItems;
            promotionContext.CartTotal        = _cart.Total;
            promotionContext.Coupon           = _cart.Coupon != null ? _cart.Coupon.Code : null;
            promotionContext.Currency         = _cart.Currency;
            promotionContext.CustomerId       = _cart.Customer.Id;
            promotionContext.IsRegisteredUser = _cart.Customer.IsRegisteredUser;
            promotionContext.Language         = _cart.Language;
            promotionContext.PromoEntries     = promotionItems;
            promotionContext.StoreId          = _cart.StoreId;

            await _promotionEvaluator.EvaluateDiscountsAsync(promotionContext, new IDiscountable[] { _cart });

            return(this);
        }
예제 #14
0
        public virtual async Task EvaluateProductPricesAsync(ICollection <Product> products, WorkContext workContext)
        {
            //Evaluate products prices
            var evalContext = workContext.ToPriceEvaluationContextDto(products);

            var pricesResponse = await _pricingApi.PricingModule.EvaluatePricesAsync(evalContext);

            ApplyProductPricesInternal(products, pricesResponse, workContext);

            //Evaluate product discounts
            //Fill product inventories for getting InStockQuantity data for promotion evaluation
            await _inventoryService.EvaluateProductInventoriesAsync(products, workContext);

            var promoEvalContext = workContext.ToPromotionEvaluationContext(products);
            await _promotionEvaluator.EvaluateDiscountsAsync(promoEvalContext, products);

            //Evaluate product taxes
            var taxEvalContext = workContext.ToTaxEvaluationContext(products);
            await _taxEvaluator.EvaluateTaxesAsync(taxEvalContext, products);
        }
예제 #15
0
        public async Task <ActionResult> GetActualProductPricesJson(Product[] products)
        {
            var prices = new List <ProductPrice>();

            if (products == null)
            {
                return(Json(prices, JsonRequestBehavior.AllowGet));
            }

            var pricesResponse = await _pricingApi.PricingModuleEvaluatePricesAsync(
                evalContextProductIds : products.Select(p => p.Id).ToList(),
                evalContextCatalogId : WorkContext.CurrentStore.Catalog,
                evalContextCurrency : WorkContext.CurrentCurrency.Code,
                evalContextCustomerId : WorkContext.CurrentCustomer.Id,
                evalContextLanguage : WorkContext.CurrentLanguage.CultureName,
                evalContextStoreId : WorkContext.CurrentStore.Id);

            if (pricesResponse == null)
            {
                return(Json(prices, JsonRequestBehavior.AllowGet));
            }

            prices = pricesResponse.Select(p => p.ToWebModel()).ToList();
            var promotionContext = WorkContext.ToPromotionEvaluationContext();

            promotionContext.PromoEntries = GetPromoEntries(products, prices);

            foreach (var product in products)
            {
                product.Currency = WorkContext.CurrentCurrency;
                product.Price    = prices.FirstOrDefault(p => p.ProductId == product.Id);
            }
            await _promotionEvaluator.EvaluateDiscountsAsync(promotionContext, products);

            return(Json(prices, JsonRequestBehavior.AllowGet));
        }