/// <summary>
 /// Gets discount amount
 /// </summary>
 /// <param name="productVariant">Product variant</param>
 /// <param name="customer">The customer</param>
 /// <param name="additionalCharge">Additional charge</param>
 /// <returns>Discount amount</returns>
 public virtual decimal GetDiscountAmount(ProductVariant productVariant, 
     Customer customer,
     decimal additionalCharge)
 {
     Discount appliedDiscount = null;
     return GetDiscountAmount(productVariant, customer, additionalCharge, out appliedDiscount);
 }
Esempio n. 2
0
 public void Can_check_taxExempt_productVariant()
 {
     var productVariant = new ProductVariant();
     productVariant.IsTaxExempt = true;
     _taxService.IsTaxExempt(productVariant, null).ShouldEqual(true);
     productVariant.IsTaxExempt = false;
     _taxService.IsTaxExempt(productVariant, null).ShouldEqual(false);
 }
Esempio n. 3
0
        public void Can_parse_required_productvariant_ids()
        {
            var productVariant = new ProductVariant
            {
                RequiredProductVariantIds = "1, 4,7 ,a,"
            };

            var ids = productVariant.ParseRequiredProductVariantIds();
            ids.Length.ShouldEqual(3);
            ids[0].ShouldEqual(1);
            ids[1].ShouldEqual(4);
            ids[2].ShouldEqual(7);
        }
        public void Can_parse_allowed_quantities()
        {
            var pv = new ProductVariant()
            {
                AllowedQuantities = "1, 5,4,10,sdf"
            };

            var result = pv.ParseAllowedQuatities();
            result.Length.ShouldEqual(4);
            result[0].ShouldEqual(1);
            result[1].ShouldEqual(5);
            result[2].ShouldEqual(4);
            result[3].ShouldEqual(10);
        }
        public void Can_get_final_product_price_with_additionalFee()
        {
            var productVariant = new ProductVariant
            {
                Id = 1,
                Name = "Product variant name 1",
                Price = 12.34M,
                CustomerEntersPrice = false,
                Published = true,
                Product = new Product()
                {
                    Id = 1,
                    Name = "Product name 1",
                    Published = true
                }
            };

            //customer
            Customer customer = null;

            _priceCalcService.GetFinalPrice(productVariant, customer, 5, false, 1).ShouldEqual(17.34M);
        }
        public void Can_get_shopping_cart_subTotal_discount_including_tax()
        {
            //customer
            Customer customer = new Customer();

            //shopping cart
            var productVariant1 = new ProductVariant
            {
                Id = 1,
                Name = "Product variant name 1",
                Price = 12.34M,
                CustomerEntersPrice = false,
                Published = true,
                Product = new Product()
                {
                    Id = 1,
                    Name = "Product name 1",
                    Published = true
                }
            };
            var sci1 = new ShoppingCartItem()
            {
                ProductVariant = productVariant1,
                ProductVariantId = productVariant1.Id,
                Quantity = 2,
            };
            var productVariant2 = new ProductVariant
            {
                Id = 2,
                Name = "Product variant name 2",
                Price = 21.57M,
                CustomerEntersPrice = false,
                Published = true,
                Product = new Product()
                {
                    Id = 2,
                    Name = "Product name 2",
                    Published = true
                }
            };
            var sci2 = new ShoppingCartItem()
            {
                ProductVariant = productVariant2,
                ProductVariantId = productVariant2.Id,
                Quantity = 3
            };

            var cart = new List<ShoppingCartItem>() { sci1, sci2 };
            cart.ForEach(sci => sci.Customer = customer);
            cart.ForEach(sci => sci.CustomerId = customer.Id);

            //discounts
            var discount1 = new Discount()
            {
                Id = 1,
                Name = "Discount 1",
                DiscountType = DiscountType.AssignedToOrderSubTotal,
                DiscountAmount = 3,
                DiscountLimitation = DiscountLimitationType.Unlimited,
            };
            _discountService.Expect(ds => ds.IsDiscountValid(discount1, customer)).Return(true);
            _discountService.Expect(ds => ds.GetAllDiscounts(DiscountType.AssignedToOrderSubTotal)).Return(new List<Discount>() { discount1 });
            _discountService.Expect(ds => ds.GetAllDiscounts(DiscountType.AssignedToCategories)).Return(new List<Discount>());

            decimal discountAmount;
            Discount appliedDiscount;
            decimal subTotalWithoutDiscount;
            decimal subTotalWithDiscount;
            SortedDictionary<decimal, decimal> taxRates;
            _orderTotalCalcService.GetShoppingCartSubTotal(cart, true,
                out discountAmount, out appliedDiscount,
                out subTotalWithoutDiscount, out subTotalWithDiscount, out taxRates);

            //TODO strange. Why does the commented test fail? discountAmount.ShouldEqual(3.3);
            //discountAmount.ShouldEqual(3.3);
            appliedDiscount.ShouldNotBeNull();
            appliedDiscount.Name.ShouldEqual("Discount 1");
            subTotalWithoutDiscount.ShouldEqual(98.329);
            subTotalWithDiscount.ShouldEqual(95.029);
            taxRates.Count.ShouldEqual(1);
            taxRates.ContainsKey(10).ShouldBeTrue();
            taxRates[10].ShouldEqual(8.639);
        }
        public void Can_get_tax_total()
        {
            //customer
            var customer = new Customer()
            {
                Id = 10,
            };

            //shopping cart
            var productVariant1 = new ProductVariant
            {
                Id = 1,
                Name = "Product variant name 1",
                Price = 10M,
                Published = true,
                IsShipEnabled = true,
                Product = new Product()
                {
                    Id = 1,
                    Name = "Product name 1",
                    Published = true
                }
            };
            var sci1 = new ShoppingCartItem()
            {
                ProductVariant = productVariant1,
                ProductVariantId = productVariant1.Id,
                Quantity = 2,
            };
            var productVariant2 = new ProductVariant
            {
                Id = 2,
                Name = "Product variant name 2",
                Price = 12M,
                Published = true,
                IsShipEnabled = true,
                Product = new Product()
                {
                    Id = 2,
                    Name = "Product name 2",
                    Published = true
                }
            };
            var sci2 = new ShoppingCartItem()
            {
                ProductVariant = productVariant2,
                ProductVariantId = productVariant2.Id,
                Quantity = 3
            };

            var cart = new List<ShoppingCartItem>() { sci1, sci2 };
            cart.ForEach(sci => sci.Customer = customer);
            cart.ForEach(sci => sci.CustomerId = customer.Id);

            _genericAttributeService.Expect(x => x.GetAttributesForEntity(customer.Id, "Customer"))
                .Return(new List<GenericAttribute>()
                            {
                                new GenericAttribute()
                                    {
                                        StoreId = _store.Id,
                                        EntityId = customer.Id,
                                        Key = SystemCustomerAttributeNames.SelectedPaymentMethod,
                                        KeyGroup = "Customer",
                                        Value = "test1"
                                    }
                            });
            _paymentService.Expect(ps => ps.GetAdditionalHandlingFee(cart, "test1")).Return(20);
            _discountService.Expect(ds => ds.GetAllDiscounts(DiscountType.AssignedToCategories)).Return(new List<Discount>());

            //56 - items, 10 - shipping (fixed), 20 - payment fee

            //1. shipping is taxable, payment fee is taxable
            _taxSettings.ShippingIsTaxable = true;
            _taxSettings.PaymentMethodAdditionalFeeIsTaxable = true;
            SortedDictionary<decimal, decimal> taxRates;
            _orderTotalCalcService.GetTaxTotal(cart, out taxRates).ShouldEqual(8.6);
            taxRates.ShouldNotBeNull();
            taxRates.Count.ShouldEqual(1);
            taxRates.ContainsKey(10).ShouldBeTrue();
            taxRates[10].ShouldEqual(8.6);

            //2. shipping is taxable, payment fee is not taxable
            _taxSettings.ShippingIsTaxable = true;
            _taxSettings.PaymentMethodAdditionalFeeIsTaxable = false;
            _orderTotalCalcService.GetTaxTotal(cart, out taxRates).ShouldEqual(6.6);
            taxRates.ShouldNotBeNull();
            taxRates.Count.ShouldEqual(1);
            taxRates.ContainsKey(10).ShouldBeTrue();
            taxRates[10].ShouldEqual(6.6);

            //3. shipping is not taxable, payment fee is taxable
            _taxSettings.ShippingIsTaxable = false;
            _taxSettings.PaymentMethodAdditionalFeeIsTaxable = true;
            _orderTotalCalcService.GetTaxTotal(cart, out taxRates).ShouldEqual(7.6);
            taxRates.ShouldNotBeNull();
            taxRates.Count.ShouldEqual(1);
            taxRates.ContainsKey(10).ShouldBeTrue();
            taxRates[10].ShouldEqual(7.6);

            //3. shipping is not taxable, payment fee is not taxable
            _taxSettings.ShippingIsTaxable = false;
            _taxSettings.PaymentMethodAdditionalFeeIsTaxable = false;
            _orderTotalCalcService.GetTaxTotal(cart, out taxRates).ShouldEqual(5.6);
            taxRates.ShouldNotBeNull();
            taxRates.Count.ShouldEqual(1);
            taxRates.ContainsKey(10).ShouldBeTrue();
            taxRates[10].ShouldEqual(5.6);
        }
        /// <summary>
        /// Sends a "quantity below" notification to a store owner
        /// </summary>
        /// <param name="productVariant">Product variant</param>
        /// <param name="languageId">Message language identifier</param>
        /// <returns>Queued email identifier</returns>
        public virtual int SendQuantityBelowStoreOwnerNotification(ProductVariant productVariant, int languageId)
        {
            if (productVariant == null)
                throw new ArgumentNullException("productVariant");

            languageId = EnsureLanguageIsActive(languageId);

            var messageTemplate = GetLocalizedActiveMessageTemplate("QuantityBelow.StoreOwnerNotification", languageId);
            if (messageTemplate == null)
                return 0;

            var productVariantTokens = GenerateTokens(productVariant);

            //event notification
            _eventPublisher.MessageTokensAdded(messageTemplate, productVariantTokens);

            var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId);
            var toEmail = emailAccount.Email;
            var toName = emailAccount.DisplayName;
            return SendNotification(messageTemplate, emailAccount,
                languageId, productVariantTokens,
                toEmail, toName);
        }
 /// <summary>
 /// Gets the final price
 /// </summary>
 /// <param name="productVariant">Product variant</param>
 /// <param name="includeDiscounts">A value indicating whether include discounts or not for final price computation</param>
 /// <returns>Final price</returns>
 public virtual decimal GetFinalPrice(ProductVariant productVariant, 
     bool includeDiscounts)
 {
     var customer = _workContext.CurrentCustomer;
     return GetFinalPrice(productVariant, customer, includeDiscounts);
 }
Esempio n. 10
0
        /// <summary>
        /// Validates shopping cart item attributes
        /// </summary>
        /// <param name="shoppingCartType">Shopping cart type</param>
        /// <param name="productVariant">Product variant</param>
        /// <param name="selectedAttributes">Selected attributes</param>
        /// <returns>Warnings</returns>
        public virtual IList<string> GetShoppingCartItemAttributeWarnings(ShoppingCartType shoppingCartType,
            ProductVariant productVariant, string selectedAttributes)
        {
            if (productVariant == null)
                throw new ArgumentNullException("productVariant");

            var warnings = new List<string>();

            //selected attributes
            var pva1Collection = _productAttributeParser.ParseProductVariantAttributes(selectedAttributes);
            foreach (var pva1 in pva1Collection)
            {
                var pv1 = pva1.ProductVariant;
                if (pv1 != null)
                {
                    if (pv1.Id != productVariant.Id)
                    {
                        warnings.Add("Attribute error");
                    }
                }
                else
                {
                    warnings.Add("Attribute error");
                    return warnings;
                }
            }

            //existing product attributes
            var pva2Collection = productVariant.ProductVariantAttributes;
            foreach (var pva2 in pva2Collection)
            {
                if (pva2.IsRequired)
                {
                    bool found = false;
                    //selected product attributes
                    foreach (var pva1 in pva1Collection)
                    {
                        if (pva1.Id == pva2.Id)
                        {
                            var pvaValuesStr = _productAttributeParser.ParseValues(selectedAttributes, pva1.Id);
                            foreach (string str1 in pvaValuesStr)
                            {
                                if (!String.IsNullOrEmpty(str1.Trim()))
                                {
                                    found = true;
                                    break;
                                }
                            }
                        }
                    }

                    //if not found
                    if (!found)
                    {
                        if (!string.IsNullOrEmpty(pva2.TextPrompt))
                        {
                            warnings.Add(pva2.TextPrompt);
                        }
                        else
                        {
                            warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.SelectAttribute"), pva2.ProductAttribute.GetLocalized(a => a.Name)));
                        }
                    }
                }
            }

            return warnings;
        }
Esempio n. 11
0
        /// <summary>
        /// Finds a shopping cart item in the cart
        /// </summary>
        /// <param name="shoppingCart">Shopping cart</param>
        /// <param name="shoppingCartType">Shopping cart type</param>
        /// <param name="productVariant">Product variant</param>
        /// <param name="selectedAttributes">Selected attributes</param>
        /// <param name="customerEnteredPrice">Price entered by a customer</param>
        /// <returns>Found shopping cart item</returns>
        public virtual ShoppingCartItem FindShoppingCartItemInTheCart(IList<ShoppingCartItem> shoppingCart,
            ShoppingCartType shoppingCartType,
            ProductVariant productVariant,
            string selectedAttributes = "",
            decimal customerEnteredPrice = decimal.Zero)
        {
            if (shoppingCart == null)
                throw new ArgumentNullException("shoppingCart");

            if (productVariant == null)
                throw new ArgumentNullException("productVariant");

            foreach (var sci in shoppingCart.Where(a => a.ShoppingCartType == shoppingCartType))
            {
                if (sci.ProductVariantId == productVariant.Id)
                {
                    //attributes
                    bool attributesEqual = _productAttributeParser.AreProductAttributesEqual(sci.AttributesXml, selectedAttributes);

                    //gift cards
                    bool giftCardInfoSame = true;
                    if (sci.ProductVariant.IsGiftCard)
                    {
                        string giftCardRecipientName1 = string.Empty;
                        string giftCardRecipientEmail1 = string.Empty;
                        string giftCardSenderName1 = string.Empty;
                        string giftCardSenderEmail1 = string.Empty;
                        string giftCardMessage1 = string.Empty;
                        _productAttributeParser.GetGiftCardAttribute(selectedAttributes,
                            out giftCardRecipientName1, out giftCardRecipientEmail1,
                            out giftCardSenderName1, out giftCardSenderEmail1, out giftCardMessage1);

                        string giftCardRecipientName2 = string.Empty;
                        string giftCardRecipientEmail2 = string.Empty;
                        string giftCardSenderName2 = string.Empty;
                        string giftCardSenderEmail2 = string.Empty;
                        string giftCardMessage2 = string.Empty;
                        _productAttributeParser.GetGiftCardAttribute(sci.AttributesXml,
                            out giftCardRecipientName2, out giftCardRecipientEmail2,
                            out giftCardSenderName2, out giftCardSenderEmail2, out giftCardMessage2);

                        if (giftCardRecipientName1.ToLowerInvariant() != giftCardRecipientName2.ToLowerInvariant() ||
                            giftCardSenderName1.ToLowerInvariant() != giftCardSenderName2.ToLowerInvariant())
                            giftCardInfoSame = false;
                    }

                    //price is the same (for products which require customers to enter a price)
                    bool customerEnteredPricesEqual = true;
                    if (sci.ProductVariant.CustomerEntersPrice)
                        customerEnteredPricesEqual = Math.Round(sci.CustomerEnteredPrice, 2) == Math.Round(customerEnteredPrice, 2);

                    //found?
                    if (attributesEqual && giftCardInfoSame && customerEnteredPricesEqual)
                        return sci;
                }
            }

            return null;
        }
        public void Can_get_shopping_cart_total_with_applied_reward_points()
        {
            //customer
            var customer = new Customer()
            {
                Id = 10,
            };

            //shopping cart
            var productVariant1 = new ProductVariant
            {
                Id = 1,
                Name = "Product variant name 1",
                Price = 10M,
                Published = true,
                IsShipEnabled = true,
                Product = new Product()
                {
                    Id = 1,
                    Name = "Product name 1",
                    Published = true
                }
            };
            var sci1 = new ShoppingCartItem()
            {
                ProductVariant = productVariant1,
                ProductVariantId = productVariant1.Id,
                Quantity = 2,
            };
            var productVariant2 = new ProductVariant
            {
                Id = 2,
                Name = "Product variant name 2",
                Price = 12M,
                Published = true,
                IsShipEnabled = true,
                Product = new Product()
                {
                    Id = 2,
                    Name = "Product name 2",
                    Published = true
                }
            };
            var sci2 = new ShoppingCartItem()
            {
                ProductVariant = productVariant2,
                ProductVariantId = productVariant2.Id,
                Quantity = 3
            };

            var cart = new List<ShoppingCartItem>() { sci1, sci2 };
            cart.ForEach(sci => sci.Customer = customer);
            cart.ForEach(sci => sci.CustomerId = customer.Id);

            _genericAttributeService.Expect(x => x.GetAttributesForEntity(customer.Id, "Customer"))
                .Return(new List<GenericAttribute>()
                            {
                                new GenericAttribute()
                                    {
                                        StoreId = _store.Id,
                                        EntityId = customer.Id,
                                        Key = SystemCustomerAttributeNames.SelectedPaymentMethod,
                                        KeyGroup = "Customer",
                                        Value = "test1"
                                    },
                                new GenericAttribute()
                                        {
                                        StoreId = 1,
                                        EntityId = customer.Id,
                                        Key = SystemCustomerAttributeNames.UseRewardPointsDuringCheckout,
                                        KeyGroup = "Customer",
                                        Value = true.ToString()
                                        }
                            });
            _paymentService.Expect(ps => ps.GetAdditionalHandlingFee(cart, "test1")).Return(20);

            _discountService.Expect(ds => ds.GetAllDiscounts(DiscountType.AssignedToCategories)).Return(new List<Discount>());

            decimal discountAmount;
            Discount appliedDiscount;
            List<AppliedGiftCard> appliedGiftCards;
            int redeemedRewardPoints;
            decimal redeemedRewardPointsAmount;

            //shipping is taxable, payment fee is taxable
            _taxSettings.ShippingIsTaxable = true;
            _taxSettings.PaymentMethodAdditionalFeeIsTaxable = true;

            //reward points
            _rewardPointsSettings.Enabled = true;
            _rewardPointsSettings.ExchangeRate = 2; //1 reward point = 2
            customer.AddRewardPointsHistoryEntry(15); //15*2=30

            //56 - items, 10 - shipping (fixed), 20 - payment fee, 8.6 - tax, -30 (reward points)
            _orderTotalCalcService.GetShoppingCartTotal(cart, out discountAmount, out appliedDiscount,
                out appliedGiftCards, out redeemedRewardPoints, out redeemedRewardPointsAmount)
                .ShouldEqual(64.6M);
        }
        /// <summary>
        /// Gets a preferred discount
        /// </summary>
        /// <param name="productVariant">Product variant</param>
        /// <param name="customer">Customer</param>
        /// <param name="additionalCharge">Additional charge</param>
        /// <param name="quantity">Product quantity</param>
        /// <returns>Preferred discount</returns>
        protected virtual Discount GetPreferredDiscount(ProductVariant productVariant,
            Customer customer, decimal additionalCharge = decimal.Zero, int quantity = 1)
        {
            if (_catalogSettings.IgnoreDiscounts)
                return null;

            var allowedDiscounts = GetAllowedDiscounts(productVariant, customer);
            decimal finalPriceWithoutDiscount = GetFinalPrice(productVariant, customer, additionalCharge, false, quantity);
            var preferredDiscount = allowedDiscounts.GetPreferredDiscount(finalPriceWithoutDiscount);
            return preferredDiscount;
        }
        /// <summary>
        /// Gets a tier price
        /// </summary>
        /// <param name="productVariant">Product variant</param>
        /// <param name="customer">Customer</param>
        /// <param name="quantity">Quantity</param>
        /// <returns>Price</returns>
        protected virtual decimal? GetMinimumTierPrice(ProductVariant productVariant, Customer customer, int quantity)
        {
            if (!productVariant.HasTierPrices)
                return decimal.Zero;

            var tierPrices = productVariant.TierPrices
                .OrderBy(tp => tp.Quantity)
                .ToList()
                .FilterForCustomer(customer)
                .RemoveDuplicatedQuantities();

            int previousQty = 1;
            decimal? previousPrice = null;
            foreach (var tierPrice in tierPrices)
            {
                //check quantity
                if (quantity < tierPrice.Quantity)
                    continue;
                if (tierPrice.Quantity < previousQty)
                    continue;

                //save new price
                previousPrice = tierPrice.Price;
                previousQty = tierPrice.Quantity;
            }

            return previousPrice;
        }
        /// <summary>
        /// Gets allowed discounts
        /// </summary>
        /// <param name="productVariant">Product variant</param>
        /// <param name="customer">Customer</param>
        /// <returns>Discounts</returns>
        protected virtual IList<Discount> GetAllowedDiscounts(ProductVariant productVariant, 
            Customer customer)
        {
            var allowedDiscounts = new List<Discount>();
            if (_catalogSettings.IgnoreDiscounts)
                return allowedDiscounts;

            if (productVariant.HasDiscountsApplied)
            {
                //we use this property ("HasDiscountsApplied") for performance optimziation to avoid unnecessary database calls
                foreach (var discount in productVariant.AppliedDiscounts)
                {
                    if (_discountService.IsDiscountValid(discount, customer) &&
                        discount.DiscountType == DiscountType.AssignedToSkus &&
                        !allowedDiscounts.ContainsDiscount(discount))
                        allowedDiscounts.Add(discount);
                }
            }

            var productCategories = _categoryService.GetProductCategoriesByProductId(productVariant.ProductId);
            if (productCategories != null)
            {
                foreach (var productCategory in productCategories)
                {
                    var category = productCategory.Category;

                    if (category.HasDiscountsApplied)
                    {
                        //we use this property ("HasDiscountsApplied") for performance optimziation to avoid unnecessary database calls
                        var categoryDiscounts = category.AppliedDiscounts;
                        foreach (var discount in categoryDiscounts)
                        {
                            if (_discountService.IsDiscountValid(discount, customer) &&
                                discount.DiscountType == DiscountType.AssignedToCategories &&
                                !allowedDiscounts.ContainsDiscount(discount))
                                allowedDiscounts.Add(discount);
                        }
                    }
                }
            }
            return allowedDiscounts;
        }
        /// <summary>
        /// Get product variant special price (is valid)
        /// </summary>
        /// <param name="productVariant">Product variant</param>
        /// <returns>Product variant special price</returns>
        public virtual decimal? GetSpecialPrice(ProductVariant productVariant)
        {
            if (productVariant == null)
                throw new ArgumentNullException("productVariant");

            if (!productVariant.SpecialPrice.HasValue)
                return null;

            //check date range
            DateTime now = DateTime.UtcNow;
            if (productVariant.SpecialPriceStartDateTimeUtc.HasValue)
            {
                DateTime startDate = DateTime.SpecifyKind(productVariant.SpecialPriceStartDateTimeUtc.Value, DateTimeKind.Utc);
                if (startDate.CompareTo(now) > 0)
                    return null;
            }
            if (productVariant.SpecialPriceEndDateTimeUtc.HasValue)
            {
                DateTime endDate = DateTime.SpecifyKind(productVariant.SpecialPriceEndDateTimeUtc.Value, DateTimeKind.Utc);
                if (endDate.CompareTo(now) < 0)
                    return null;
            }

            return productVariant.SpecialPrice.Value;
        }
        /// <summary>
        /// Gets the final price
        /// </summary>
        /// <param name="productVariant">Product variant</param>
        /// <param name="customer">The customer</param>
        /// <param name="additionalCharge">Additional charge</param>
        /// <param name="includeDiscounts">A value indicating whether include discounts or not for final price computation</param>
        /// <param name="quantity">Shopping cart item quantity</param>
        /// <returns>Final price</returns>
        public virtual decimal GetFinalPrice(ProductVariant productVariant, 
            Customer customer,
            decimal additionalCharge,
            bool includeDiscounts,
            int quantity)
        {
            //initial price
            decimal result = productVariant.Price;

            //special price
            var specialPrice = GetSpecialPrice(productVariant);
            if (specialPrice.HasValue)
                result = specialPrice.Value;

            //tier prices
            if (productVariant.HasTierPrices)
            {
                decimal? tierPrice = GetMinimumTierPrice(productVariant, customer, quantity);
                if (tierPrice.HasValue)
                    result = Math.Min(result, tierPrice.Value);
            }

            //discount + additional charge
            if (includeDiscounts)
            {
                Discount appliedDiscount = null;
                decimal discountAmount = GetDiscountAmount(productVariant, customer, additionalCharge, quantity, out appliedDiscount);
                result = result + additionalCharge - discountAmount;
            }
            else
            {
                result = result + additionalCharge;
            }
            if (result < decimal.Zero)
                result = decimal.Zero;
            return result;
        }
 /// <summary>
 /// Gets the final price
 /// </summary>
 /// <param name="productVariant">Product variant</param>
 /// <param name="customer">The customer</param>
 /// <param name="additionalCharge">Additional charge</param>
 /// <param name="includeDiscounts">A value indicating whether include discounts or not for final price computation</param>
 /// <returns>Final price</returns>
 public virtual decimal GetFinalPrice(ProductVariant productVariant, 
     Customer customer,
     decimal additionalCharge,
     bool includeDiscounts)
 {
     return GetFinalPrice(productVariant, customer, additionalCharge,
         includeDiscounts, 1);
 }
 /// <summary>
 /// Gets the final price
 /// </summary>
 /// <param name="productVariant">Product variant</param>
 /// <param name="customer">The customer</param>
 /// <param name="includeDiscounts">A value indicating whether include discounts or not for final price computation</param>
 /// <returns>Final price</returns>
 public virtual decimal GetFinalPrice(ProductVariant productVariant, 
     Customer customer,
     bool includeDiscounts)
 {
     return GetFinalPrice(productVariant, customer, decimal.Zero, includeDiscounts);
 }
        public void Can_get_shopping_cart_subTotal_including_tax()
        {
            //customer
            Customer customer = new Customer();

            //shopping cart
            var productVariant1 = new ProductVariant
            {
                Id = 1,
                Name = "Product variant name 1",
                Price = 12.34M,
                CustomerEntersPrice = false,
                Published = true,
                Product = new Product()
                {
                    Id = 1,
                    Name = "Product name 1",
                    Published = true
                }
            };
            var sci1 = new ShoppingCartItem()
            {
                ProductVariant = productVariant1,
                ProductVariantId = productVariant1.Id,
                Quantity = 2,
            };
            var productVariant2 = new ProductVariant
            {
                Id = 2,
                Name = "Product variant name 2",
                Price = 21.57M,
                CustomerEntersPrice = false,
                Published = true,
                Product = new Product()
                {
                    Id = 2,
                    Name = "Product name 2",
                    Published = true
                }
            };
            var sci2 = new ShoppingCartItem()
            {
                ProductVariant = productVariant2,
                ProductVariantId = productVariant2.Id,
                Quantity = 3
            };

            var cart = new List<ShoppingCartItem>() { sci1, sci2 };
            cart.ForEach(sci => sci.Customer = customer);
            cart.ForEach(sci => sci.CustomerId = customer.Id);

            _discountService.Expect(ds => ds.GetAllDiscounts(DiscountType.AssignedToCategories)).Return(new List<Discount>());

            decimal discountAmount;
            Discount appliedDiscount;
            decimal subTotalWithoutDiscount;
            decimal subTotalWithDiscount;
            SortedDictionary<decimal, decimal> taxRates;

            _orderTotalCalcService.GetShoppingCartSubTotal(cart, true,
                out discountAmount, out appliedDiscount,
                out subTotalWithoutDiscount, out subTotalWithDiscount, out taxRates);
            discountAmount.ShouldEqual(0);
            appliedDiscount.ShouldBeNull();
            subTotalWithoutDiscount.ShouldEqual(98.329);
            subTotalWithDiscount.ShouldEqual(98.329);
            taxRates.Count.ShouldEqual(1);
            taxRates.ContainsKey(10).ShouldBeTrue();
            taxRates[10].ShouldEqual(8.939);
        }
        public void Can_get_shopping_cart_total_discount()
        {
            //customer
            var customer = new Customer()
            {
                Id = 10,
            };

            //shopping cart
            var productVariant1 = new ProductVariant
            {
                Id = 1,
                Name = "Product variant name 1",
                Price = 10M,
                Published = true,
                IsShipEnabled = true,
                Product = new Product()
                {
                    Id = 1,
                    Name = "Product name 1",
                    Published = true
                }
            };
            var sci1 = new ShoppingCartItem()
            {
                ProductVariant = productVariant1,
                ProductVariantId = productVariant1.Id,
                Quantity = 2,
            };
            var productVariant2 = new ProductVariant
            {
                Id = 2,
                Name = "Product variant name 2",
                Price = 12M,
                Published = true,
                IsShipEnabled = true,
                Product = new Product()
                {
                    Id = 2,
                    Name = "Product name 2",
                    Published = true
                }
            };
            var sci2 = new ShoppingCartItem()
            {
                ProductVariant = productVariant2,
                ProductVariantId = productVariant2.Id,
                Quantity = 3
            };

            var cart = new List<ShoppingCartItem>() { sci1, sci2 };
            cart.ForEach(sci => sci.Customer = customer);
            cart.ForEach(sci => sci.CustomerId = customer.Id);

            //discounts
            var discount1 = new Discount()
            {
                Id = 1,
                Name = "Discount 1",
                DiscountType = DiscountType.AssignedToOrderTotal,
                DiscountAmount = 3,
                DiscountLimitation = DiscountLimitationType.Unlimited,
            };
            _discountService.Expect(ds => ds.IsDiscountValid(discount1, customer)).Return(true);
            _discountService.Expect(ds => ds.GetAllDiscounts(DiscountType.AssignedToOrderTotal)).Return(new List<Discount>() { discount1 });
            _discountService.Expect(ds => ds.GetAllDiscounts(DiscountType.AssignedToCategories)).Return(new List<Discount>());

            _genericAttributeService.Expect(x => x.GetAttributesForEntity(customer.Id, "Customer"))
                .Return(new List<GenericAttribute>()
                            {
                                new GenericAttribute()
                                    {
                                        StoreId = _store.Id,
                                        EntityId = customer.Id,
                                        Key = SystemCustomerAttributeNames.SelectedPaymentMethod,
                                        KeyGroup = "Customer",
                                        Value = "test1"
                                    }
                            });
            _paymentService.Expect(ps => ps.GetAdditionalHandlingFee(cart, "test1")).Return(20);

            decimal discountAmount;
            Discount appliedDiscount;
            List<AppliedGiftCard> appliedGiftCards;
            int redeemedRewardPoints;
            decimal redeemedRewardPointsAmount;

            //shipping is taxable, payment fee is taxable
            _taxSettings.ShippingIsTaxable = true;
            _taxSettings.PaymentMethodAdditionalFeeIsTaxable = true;

            //56 - items, 10 - shipping (fixed), 20 - payment fee, 8.6 - tax, [-3] - discount
            _orderTotalCalcService.GetShoppingCartTotal(cart, out discountAmount, out appliedDiscount,
                out appliedGiftCards, out redeemedRewardPoints, out redeemedRewardPointsAmount)
                .ShouldEqual(91.6M);
            discountAmount.ShouldEqual(3);
            appliedDiscount.ShouldNotBeNull();
            appliedDiscount.Name.ShouldEqual("Discount 1");
        }
 /// <summary>
 /// Gets discount amount
 /// </summary>
 /// <param name="productVariant">Product variant</param>
 /// <returns>Discount amount</returns>
 public virtual decimal GetDiscountAmount(ProductVariant productVariant)
 {
     var customer = _workContext.CurrentCustomer;
     return GetDiscountAmount(productVariant, customer, decimal.Zero);
 }
Esempio n. 23
0
        /// <summary>
        /// Add a product variant to shopping cart
        /// </summary>
        /// <param name="customer">Customer</param>
        /// <param name="productVariant">Product variant</param>
        /// <param name="shoppingCartType">Shopping cart type</param>
        /// <param name="selectedAttributes">Selected attributes</param>
        /// <param name="customerEnteredPrice">The price enter by a customer</param>
        /// <param name="quantity">Quantity</param>
        /// <param name="automaticallyAddRequiredProductVariantsIfEnabled">Automatically add required product variants if enabled</param>
        /// <returns>Warnings</returns>
        public virtual IList<string> AddToCart(Customer customer, ProductVariant productVariant, 
            ShoppingCartType shoppingCartType, string selectedAttributes,
            decimal customerEnteredPrice, int quantity, bool automaticallyAddRequiredProductVariantsIfEnabled)
        {
            if (customer == null)
                throw new ArgumentNullException("customer");

            if (productVariant == null)
                throw new ArgumentNullException("productVariant");

            var warnings = new List<string>();
            if (shoppingCartType == ShoppingCartType.ShoppingCart && !_permissionService.Authorize(StandardPermissionProvider.EnableShoppingCart, customer))
            {
                warnings.Add("Shopping cart is disabled");
                return warnings;
            }
            if (shoppingCartType == ShoppingCartType.Wishlist && !_permissionService.Authorize(StandardPermissionProvider.EnableWishlist, customer))
            {
                warnings.Add("Wishlist is disabled");
                return warnings;
            }

            if (quantity <= 0)
            {
                warnings.Add(_localizationService.GetResource("ShoppingCart.QuantityShouldPositive"));
                return warnings;
            }

            //reset checkout info
            _customerService.ResetCheckoutData(customer);

            var cart = customer.ShoppingCartItems.Where(sci=>sci.ShoppingCartType == shoppingCartType).ToList();

            var shoppingCartItem = FindShoppingCartItemInTheCart(cart,
                shoppingCartType, productVariant, selectedAttributes, customerEnteredPrice);

            if (shoppingCartItem != null)
            {
                //update existing shopping cart item
                int newQuantity = shoppingCartItem.Quantity + quantity;
                warnings.AddRange(GetShoppingCartItemWarnings(customer, shoppingCartType, productVariant,
                    selectedAttributes, customerEnteredPrice, newQuantity, automaticallyAddRequiredProductVariantsIfEnabled));

                if (warnings.Count == 0)
                {
                    shoppingCartItem.AttributesXml = selectedAttributes;
                    shoppingCartItem.Quantity = newQuantity;
                    shoppingCartItem.UpdatedOnUtc = DateTime.UtcNow;
                    _customerService.UpdateCustomer(customer);

                    //event notification
                    _eventPublisher.EntityUpdated(shoppingCartItem);
                }
            }
            else
            {
                //new shopping cart item
                warnings.AddRange(GetShoppingCartItemWarnings(customer, shoppingCartType, productVariant,
                    selectedAttributes, customerEnteredPrice, quantity, automaticallyAddRequiredProductVariantsIfEnabled));
                if (warnings.Count == 0)
                {
                    //maximum items validation
                    switch (shoppingCartType)
                    {
                        case ShoppingCartType.ShoppingCart:
                            {
                                if (cart.Count >= _shoppingCartSettings.MaximumShoppingCartItems)
                                    return warnings;
                            }
                            break;
                        case ShoppingCartType.Wishlist:
                            {
                                if (cart.Count >= _shoppingCartSettings.MaximumWishlistItems)
                                    return warnings;
                            }
                            break;
                        default:
                            break;
                    }

                    DateTime now = DateTime.UtcNow;
                    shoppingCartItem = new ShoppingCartItem()
                    {
                        ShoppingCartType = shoppingCartType,
                        ProductVariant = productVariant,
                        AttributesXml = selectedAttributes,
                        CustomerEnteredPrice = customerEnteredPrice,
                        Quantity = quantity,
                        CreatedOnUtc = now,
                        UpdatedOnUtc = now
                    };
                    customer.ShoppingCartItems.Add(shoppingCartItem);
                    _customerService.UpdateCustomer(customer);

                    //event notification
                    _eventPublisher.EntityInserted(shoppingCartItem);
                }
            }

            return warnings;
        }
 /// <summary>
 /// Gets discount amount
 /// </summary>
 /// <param name="productVariant">Product variant</param>
 /// <param name="customer">The customer</param>
 /// <returns>Discount amount</returns>
 public virtual decimal GetDiscountAmount(ProductVariant productVariant, 
     Customer customer)
 {
     return GetDiscountAmount(productVariant, customer, decimal.Zero);
 }
Esempio n. 25
0
        /// <summary>
        /// Validates required product variants (product variants which require other variant to be added to the cart)
        /// </summary>
        /// <param name="customer">Customer</param>
        /// <param name="shoppingCartType">Shopping cart type</param>
        /// <param name="productVariant">Product variant</param>
        /// <param name="automaticallyAddRequiredProductVariantsIfEnabled">Automatically add required product variants if enabled</param>
        /// <returns>Warnings</returns>
        public virtual IList<string> GetRequiredProductVariantWarnings(Customer customer, ShoppingCartType shoppingCartType,
            ProductVariant productVariant, bool automaticallyAddRequiredProductVariantsIfEnabled)
        {
            if (customer == null)
                throw new ArgumentNullException("customer");

            if (productVariant == null)
                throw new ArgumentNullException("productVariant");

            var cart = customer.ShoppingCartItems.Where(sci => sci.ShoppingCartType == shoppingCartType).ToList();

            var warnings = new List<string>();

            if (productVariant.RequireOtherProducts)
            {
                var requiredProductVariants = new List<ProductVariant>();
                foreach (var id in productVariant.ParseRequiredProductVariantIds())
                {
                    var rpv = _productService.GetProductVariantById(id);
                    if (rpv != null)
                        requiredProductVariants.Add(rpv);
                }

                foreach (var rpv in requiredProductVariants)
                {
                    //ensure that product is in the cart
                    bool alreadyInTheCart = false;
                    foreach (var sci in cart)
                    {
                        if (sci.ProductVariantId == rpv.Id)
                        {
                            alreadyInTheCart = true;
                            break;
                        }
                    }
                    //not in the cart
                    if (!alreadyInTheCart)
                    {

                        string fullProductName = "";
                        if (!String.IsNullOrEmpty(rpv.GetLocalized(x => x.Name)))
                            fullProductName = string.Format("{0} ({1})", rpv.Product.GetLocalized(x => x.Name), rpv.GetLocalized(x => x.Name));
                        else
                            fullProductName = rpv.Product.GetLocalized(x => x.Name);

                        if (productVariant.AutomaticallyAddRequiredProductVariants)
                        {
                            //add to cart (if possible)
                            if (automaticallyAddRequiredProductVariantsIfEnabled)
                            {
                                //pass 'false' for 'automaticallyAddRequiredProductVariantsIfEnabled' to prevent circular references
                                var addToCartWarnings = AddToCart(customer, rpv, shoppingCartType, "", decimal.Zero, 1, false);
                                if (addToCartWarnings.Count > 0)
                                {
                                    //a product wasn't atomatically added for some reasons

                                    //don't display specific errors from 'addToCartWarnings' variable
                                    //display only generic error
                                    warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.RequiredProductWarning"), fullProductName));
                                }
                            }
                            else
                            {
                                warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.RequiredProductWarning"), fullProductName));
                            }
                        }
                        else
                        {
                            warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.RequiredProductWarning"), fullProductName));
                        }
                    }
                }
            }

            return warnings;
        }
Esempio n. 26
0
        /// <summary>
        /// Validates shopping cart item
        /// </summary>
        /// <param name="customer">Customer</param>
        /// <param name="shoppingCartType">Shopping cart type</param>
        /// <param name="productVariant">Product variant</param>
        /// <param name="selectedAttributes">Selected attributes</param>
        /// <param name="customerEnteredPrice">Customer entered price</param>
        /// <param name="quantity">Quantity</param>
        /// <param name="automaticallyAddRequiredProductVariantsIfEnabled">Automatically add required product variants if enabled</param>
        /// <param name="getStandardWarnings">A value indicating whether we should validate a product variant for standard properties</param>
        /// <param name="getAttributesWarnings">A value indicating whether we should validate product attributes</param>
        /// <param name="getGiftCardWarnings">A value indicating whether we should validate gift card properties</param>
        /// <param name="getRequiredProductVariantWarnings">A value indicating whether we should validate required product variants (product variants which require other variant to be added to the cart)</param>
        /// <returns>Warnings</returns>
        public virtual IList<string> GetShoppingCartItemWarnings(Customer customer, ShoppingCartType shoppingCartType,
            ProductVariant productVariant, string selectedAttributes, decimal customerEnteredPrice,
            int quantity, bool automaticallyAddRequiredProductVariantsIfEnabled,
            bool getStandardWarnings = true, bool getAttributesWarnings = true, 
            bool getGiftCardWarnings = true, bool getRequiredProductVariantWarnings = true)
        {
            if (productVariant == null)
                throw new ArgumentNullException("productVariant");

            var warnings = new List<string>();

            //standard properties
            if (getStandardWarnings)
                warnings.AddRange(GetStandardWarnings(customer, shoppingCartType, productVariant, selectedAttributes, customerEnteredPrice, quantity));

            //selected attributes
            if (getAttributesWarnings)
                warnings.AddRange(GetShoppingCartItemAttributeWarnings(shoppingCartType, productVariant, selectedAttributes));

            //gift cards
            if (getGiftCardWarnings)
                warnings.AddRange(GetShoppingCartItemGiftCardWarnings(shoppingCartType, productVariant, selectedAttributes));

            //required product variants
            if (getRequiredProductVariantWarnings)
                warnings.AddRange(GetRequiredProductVariantWarnings(customer, shoppingCartType, productVariant, automaticallyAddRequiredProductVariantsIfEnabled));

            return warnings;
        }
Esempio n. 27
0
        /// <summary>
        /// Validates shopping cart item (gift card)
        /// </summary>
        /// <param name="shoppingCartType">Shopping cart type</param>
        /// <param name="productVariant">Product variant</param>
        /// <param name="selectedAttributes">Selected attributes</param>
        /// <returns>Warnings</returns>
        public virtual IList<string> GetShoppingCartItemGiftCardWarnings(ShoppingCartType shoppingCartType,
            ProductVariant productVariant, string selectedAttributes)
        {
            if (productVariant == null)
                throw new ArgumentNullException("productVariant");

            var warnings = new List<string>();

            //gift cards
            if (productVariant.IsGiftCard)
            {
                string giftCardRecipientName = string.Empty;
                string giftCardRecipientEmail = string.Empty;
                string giftCardSenderName = string.Empty;
                string giftCardSenderEmail = string.Empty;
                string giftCardMessage = string.Empty;
                _productAttributeParser.GetGiftCardAttribute(selectedAttributes,
                    out giftCardRecipientName, out giftCardRecipientEmail,
                    out giftCardSenderName, out giftCardSenderEmail, out giftCardMessage);

                if (String.IsNullOrEmpty(giftCardRecipientName))
                    warnings.Add(_localizationService.GetResource("ShoppingCart.RecipientNameError"));

                if (productVariant.GiftCardType == GiftCardType.Virtual)
                {
                    //validate for virtual gift cards only
                    if (String.IsNullOrEmpty(giftCardRecipientEmail) || !CommonHelper.IsValidEmail(giftCardRecipientEmail))
                        warnings.Add(_localizationService.GetResource("ShoppingCart.RecipientEmailError"));
                }

                if (String.IsNullOrEmpty(giftCardSenderName))
                    warnings.Add(_localizationService.GetResource("ShoppingCart.SenderNameError"));

                if (productVariant.GiftCardType == GiftCardType.Virtual)
                {
                    //validate for virtual gift cards only
                    if (String.IsNullOrEmpty(giftCardSenderEmail) || !CommonHelper.IsValidEmail(giftCardSenderEmail))
                        warnings.Add(_localizationService.GetResource("ShoppingCart.SenderEmailError"));
                }
            }

            return warnings;
        }
        /// <summary>
        /// Gets discount amount
        /// </summary>
        /// <param name="productVariant">Product variant</param>
        /// <param name="customer">The customer</param>
        /// <param name="additionalCharge">Additional charge</param>
        /// <param name="quantity">Product quantity</param>
        /// <param name="appliedDiscount">Applied discount</param>
        /// <returns>Discount amount</returns>
        public virtual decimal GetDiscountAmount(ProductVariant productVariant,
            Customer customer,
            decimal additionalCharge,
            int quantity,
            out Discount appliedDiscount)
        {
            appliedDiscount = null;
            decimal appliedDiscountAmount = decimal.Zero;

            //we don't apply discounts to products with price entered by a customer
            if (productVariant.CustomerEntersPrice)
                return appliedDiscountAmount;

            appliedDiscount = GetPreferredDiscount(productVariant, customer, additionalCharge, quantity);
            if (appliedDiscount != null)
            {
                decimal finalPriceWithoutDiscount = GetFinalPrice(productVariant, customer, additionalCharge, false, quantity);
                appliedDiscountAmount = appliedDiscount.GetDiscountAmount(finalPriceWithoutDiscount);
            }

            return appliedDiscountAmount;
        }
Esempio n. 29
0
        /// <summary>
        /// Validates a product variant for standard properties
        /// </summary>
        /// <param name="customer">Customer</param>
        /// <param name="shoppingCartType">Shopping cart type</param>
        /// <param name="productVariant">Product variant</param>
        /// <param name="selectedAttributes">Selected attributes</param>
        /// <param name="customerEnteredPrice">Customer entered price</param>
        /// <param name="quantity">Quantity</param>
        /// <returns>Warnings</returns>
        public virtual IList<string> GetStandardWarnings(Customer customer, ShoppingCartType shoppingCartType,
            ProductVariant productVariant, string selectedAttributes, decimal customerEnteredPrice,
            int quantity)
        {
            if (customer == null)
                throw new ArgumentNullException("customer");

            if (productVariant == null)
                throw new ArgumentNullException("productVariant");

            var warnings = new List<string>();

            var product = productVariant.Product;
            if (product == null)
            {
                warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.CannotLoadProduct"), productVariant.ProductId));
                return warnings;
            }

            //deleted?
            if (product.Deleted || productVariant.Deleted)
            {
                warnings.Add(_localizationService.GetResource("ShoppingCart.ProductDeleted"));
                return warnings;
            }

            //published?
            if (!product.Published || !productVariant.Published)
            {
                warnings.Add(_localizationService.GetResource("ShoppingCart.ProductUnpublished"));
            }

            //ACL
            if (!_aclService.Authorize(product, customer))
            {
                warnings.Add(_localizationService.GetResource("ShoppingCart.ProductUnpublished"));
            }

            //disabled "add to cart" button
            if (shoppingCartType == ShoppingCartType.ShoppingCart && productVariant.DisableBuyButton)
            {
                warnings.Add(_localizationService.GetResource("ShoppingCart.BuyingDisabled"));
            }

            //disabled "add to wishlist" button
            if (shoppingCartType == ShoppingCartType.Wishlist && productVariant.DisableWishlistButton)
            {
                warnings.Add(_localizationService.GetResource("ShoppingCart.WishlistDisabled"));
            }

            //call for price
            if (shoppingCartType == ShoppingCartType.ShoppingCart && productVariant.CallForPrice)
            {
                warnings.Add(_localizationService.GetResource("Products.CallForPrice"));
            }

            //customer entered price
            if (productVariant.CustomerEntersPrice)
            {
                if (customerEnteredPrice < productVariant.MinimumCustomerEnteredPrice ||
                    customerEnteredPrice > productVariant.MaximumCustomerEnteredPrice)
                {
                    decimal minimumCustomerEnteredPrice = _currencyService.ConvertFromPrimaryStoreCurrency(productVariant.MinimumCustomerEnteredPrice, _workContext.WorkingCurrency);
                    decimal maximumCustomerEnteredPrice = _currencyService.ConvertFromPrimaryStoreCurrency(productVariant.MaximumCustomerEnteredPrice, _workContext.WorkingCurrency);
                    warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.CustomerEnteredPrice.RangeError"),
                        _priceFormatter.FormatPrice(minimumCustomerEnteredPrice, false, false),
                        _priceFormatter.FormatPrice(maximumCustomerEnteredPrice, false, false)));
                }
            }

            //quantity validation
            var hasQtyWarnings = false;
            if (quantity < productVariant.OrderMinimumQuantity)
            {
                warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.MinimumQuantity"), productVariant.OrderMinimumQuantity));
                hasQtyWarnings = true;
            }
            if (quantity > productVariant.OrderMaximumQuantity)
            {
                warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.MaximumQuantity"), productVariant.OrderMaximumQuantity));
                hasQtyWarnings = true;
            }
            var allowedQuantities = productVariant.ParseAllowedQuatities();
            if (allowedQuantities.Length > 0 && !allowedQuantities.Contains(quantity))
            {
                warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.AllowedQuantities"), string.Join(", ", allowedQuantities)));
            }

            var validateOutOfStock = shoppingCartType == ShoppingCartType.ShoppingCart || !_shoppingCartSettings.AllowOutOfStockItemsToBeAddedToWishlist;
            if (validateOutOfStock && !hasQtyWarnings)
            {
                switch (productVariant.ManageInventoryMethod)
                {
                    case ManageInventoryMethod.DontManageStock:
                        {
                        }
                        break;
                    case ManageInventoryMethod.ManageStock:
                        {
                            if ((BackorderMode)productVariant.BackorderMode == BackorderMode.NoBackorders)
                            {
                                if (productVariant.StockQuantity < quantity)
                                {
                                    int maximumQuantityCanBeAdded = productVariant.StockQuantity;
                                    if (maximumQuantityCanBeAdded <= 0)
                                        warnings.Add(_localizationService.GetResource("ShoppingCart.OutOfStock"));
                                    else
                                        warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.QuantityExceedsStock"), maximumQuantityCanBeAdded));
                                }
                            }
                        }
                        break;
                    case ManageInventoryMethod.ManageStockByAttributes:
                        {
                            var combination = productVariant
                                .ProductVariantAttributeCombinations
                                .FirstOrDefault(x => _productAttributeParser.AreProductAttributesEqual(x.AttributesXml, selectedAttributes));
                            if (combination != null &&
                                !combination.AllowOutOfStockOrders &&
                                combination.StockQuantity < quantity)
                            {
                                int maximumQuantityCanBeAdded = combination.StockQuantity;
                                if (maximumQuantityCanBeAdded <= 0)
                                    warnings.Add(_localizationService.GetResource("ShoppingCart.OutOfStock"));
                                else
                                    warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.QuantityExceedsStock"), maximumQuantityCanBeAdded));
                            }
                        }
                        break;
                    default:
                        break;
                }
            }

            //availability dates
            bool availableStartDateError = false;
            if (productVariant.AvailableStartDateTimeUtc.HasValue)
            {
                DateTime now = DateTime.UtcNow;
                DateTime availableStartDateTime = DateTime.SpecifyKind(productVariant.AvailableStartDateTimeUtc.Value, DateTimeKind.Utc);
                if (availableStartDateTime.CompareTo(now) > 0)
                {
                    warnings.Add(_localizationService.GetResource("ShoppingCart.NotAvailable"));
                    availableStartDateError = true;
                }
            }
            if (productVariant.AvailableEndDateTimeUtc.HasValue && !availableStartDateError)
            {
                DateTime now = DateTime.UtcNow;
                DateTime availableEndDateTime = DateTime.SpecifyKind(productVariant.AvailableEndDateTimeUtc.Value, DateTimeKind.Utc);
                if (availableEndDateTime.CompareTo(now) < 0)
                {
                    warnings.Add(_localizationService.GetResource("ShoppingCart.NotAvailable"));
                }
            }
            return warnings;
        }
 private IList<Token> GenerateTokens(ProductVariant productVariant)
 {
     var tokens = new List<Token>();
     _messageTokenProvider.AddStoreTokens(tokens);
     _messageTokenProvider.AddProductVariantTokens(tokens, productVariant);
     return tokens;
 }