Beispiel #1
0
        /// <summary>
        /// Gets the discount amount for the specified value
        /// </summary>
        /// <param name="discount">Discount</param>
        /// <param name="amount">Amount</param>
        /// <returns>The discount amount</returns>
        public virtual decimal GetDiscountAmount(DiscountForCaching discount, decimal amount)
        {
            if (discount == null)
            {
                throw new ArgumentNullException(nameof(discount));
            }

            //calculate discount amount
            decimal result;

            if (discount.UsePercentage)
            {
                result = (decimal)((float)amount * (float)discount.DiscountPercentage / 100f);
            }
            else
            {
                result = discount.DiscountAmount;
            }

            //validate maximum discount amount
            if (discount.UsePercentage &&
                discount.MaximumDiscountAmount.HasValue &&
                result > discount.MaximumDiscountAmount.Value)
            {
                result = discount.MaximumDiscountAmount.Value;
            }

            if (result < decimal.Zero)
            {
                result = decimal.Zero;
            }

            return(result);
        }
Beispiel #2
0
        /// <summary>
        /// Validate discount
        /// </summary>
        /// <param name="discount">Discount</param>
        /// <param name="customer">Customer</param>
        /// <returns>Discount validation result</returns>
        public virtual DiscountValidationResult ValidateDiscount(DiscountForCaching discount, Customer customer)
        {
            if (discount == null)
            {
                throw new ArgumentNullException("discount");
            }

            if (customer == null)
            {
                throw new ArgumentNullException("customer");
            }

            string[] couponCodesToValidate = customer.ParseAppliedDiscountCouponCodes();
            return(ValidateDiscount(discount, customer, couponCodesToValidate));
        }
Beispiel #3
0
        /// <summary>
        /// Validate discount
        /// </summary>
        /// <param name="discount">Discount</param>
        /// <param name="customer">Customer</param>
        /// <returns>Discount validation result</returns>
        public virtual DiscountValidationResult ValidateDiscount(DiscountForCaching discount, Customer customer)
        {
            if (discount == null)
            {
                throw new ArgumentNullException(nameof(discount));
            }

            if (customer == null)
            {
                throw new ArgumentNullException(nameof(customer));
            }

            var couponCodesToValidate = _customerService.ParseAppliedDiscountCouponCodes(customer);

            return(ValidateDiscount(discount, customer, couponCodesToValidate));
        }
Beispiel #4
0
        /// <summary>
        /// Get category identifiers to which a discount is applied
        /// </summary>
        /// <param name="discount">Discount</param>
        /// <param name="customer">Customer</param>
        /// <returns>Category identifiers</returns>
        public virtual IList <int> GetAppliedCategoryIds(DiscountForCaching discount, Customer customer)
        {
            if (discount == null)
            {
                throw new ArgumentNullException(nameof(discount));
            }

            var discountId = discount.Id;
            var cacheKey   = string.Format(NopDiscountDefaults.DiscountCategoryIdsModelCacheKey,
                                           discountId,
                                           string.Join(",", customer.GetCustomerRoleIds()),
                                           _storeContext.CurrentStore.Id);
            var result = _cacheManager.Get(cacheKey, () =>
            {
                var ids             = new List <int>();
                var rootCategoryIds = _discountRepository.Table.Where(x => x.Id == discountId)
                                      .SelectMany(x => x.DiscountCategoryMappings.Select(mapping => mapping.CategoryId))
                                      .ToList();
                foreach (var categoryId in rootCategoryIds)
                {
                    if (!ids.Contains(categoryId))
                    {
                        ids.Add(categoryId);
                    }

                    if (!discount.AppliedToSubCategories)
                    {
                        continue;
                    }

                    //include subcategories
                    foreach (var childCategoryId in _categoryService.GetChildCategoryIds(categoryId, _storeContext.CurrentStore.Id))
                    {
                        if (!ids.Contains(childCategoryId))
                        {
                            ids.Add(childCategoryId);
                        }
                    }
                }

                return(ids);
            });

            return(result);
        }
Beispiel #5
0
        /// <summary>
        /// Get category identifiers to which a discount is applied
        /// </summary>
        /// <param name="discount">Discount</param>
        /// <param name="customer">Customer</param>
        /// <returns>Category identifiers</returns>
        public virtual IList <string> GetAppliedCategoryIds(DiscountForCaching discount, Customer customer)
        {
            if (discount == null)
            {
                throw new ArgumentNullException(nameof(discount));
            }

            var discountId = discount.Id;
            var cacheKey   = string.Format(DiscountEventConsumer.DISCOUNT_CATEGORY_IDS_MODEL_KEY,
                                           discountId,
                                           string.Join(",", customer.GetCustomerRoleIds()),
                                           0);
            var result = _cacheManager.Get(cacheKey, () =>
            {
                var ids             = new List <string>();
                var rootCategoryIds = _discountRepository.Table.Where(x => x.Id == discountId)
                                      .SelectMany(x => x.AppliedToCategories.Select(c => c.CategoryId))
                                      .ToList();
                foreach (var categoryId in rootCategoryIds)
                {
                    if (!ids.Contains(categoryId))
                    {
                        ids.Add(categoryId);
                    }
                    if (discount.AppliedToSubCategories)
                    {
                        //include subcategories
                        foreach (var childCategoryId in _categoryService
                                 .GetAllCategoriesByParentCategoryId(categoryId, false, true)
                                 .Select(x => x.CategoryId))
                        {
                            if (!ids.Contains(childCategoryId))
                            {
                                ids.Add(childCategoryId);
                            }
                        }
                    }
                }
                return(ids);
            });

            return(result);
        }
Beispiel #6
0
        /// <summary>
        /// Get manufacturer identifiers to which a discount is applied
        /// </summary>
        /// <param name="discount">Discount</param>
        /// <param name="customer">Customer</param>
        /// <returns>Manufacturer identifiers</returns>
        public virtual IList <int> GetAppliedManufacturerIds(DiscountForCaching discount, Customer customer)
        {
            if (discount == null)
            {
                throw new ArgumentNullException(nameof(discount));
            }

            var discountId = discount.Id;
            var cacheKey   = string.Format(NopDiscountDefaults.DiscountManufacturerIdsModelCacheKey,
                                           discountId,
                                           string.Join(",", customer.GetCustomerRoleIds()),
                                           _storeContext.CurrentStore.Id);
            var result = _cacheManager.Get(cacheKey, () =>
            {
                return(_discountRepository.Table.Where(x => x.Id == discountId)
                       .SelectMany(x => x.DiscountManufacturerMappings.Select(mapping => mapping.ManufacturerId))
                       .ToList());
            });

            return(result);
        }
Beispiel #7
0
        /// <summary>
        /// Get manufacturer identifiers to which a discount is applied
        /// </summary>
        /// <param name="discount">Discount</param>
        /// <param name="customer">Customer</param>
        /// <returns>Manufacturer identifiers</returns>
        public virtual IList <int> GetAppliedManufacturerIds(DiscountForCaching discount, Customer customer)
        {
            if (discount == null)
            {
                throw new ArgumentNullException(nameof(discount));
            }

            var discountId = discount.Id;
            var cacheKey   = string.Format(DiscountEventConsumer.DISCOUNT_MANUFACTURER_IDS_MODEL_KEY,
                                           discountId,
                                           string.Join(",", customer.GetCustomerRoleIds()),
                                           0);
            var result = _cacheManager.Get(cacheKey, () =>
            {
                return(_discountRepository.Table.Where(x => x.Id == discountId)
                       .SelectMany(x => x.AppliedToManufacturers.Select(c => c.Id))
                       .ToList());
            });

            return(result);
        }
Beispiel #8
0
        /// <summary>
        /// Get destination identifiers to which a discount is applied
        /// </summary>
        /// <param name="discount">Discount</param>
        /// <param name="customer">Customer</param>
        /// <returns>Destination identifiers</returns>
        public virtual IList <int> GetAppliedDestinationIds(DiscountForCaching discount, Customer customer)
        {
            if (discount == null)
            {
                throw new ArgumentNullException("discount");
            }

            var discountId = discount.Id;
            var cacheKey   = string.Format(DiscountEventConsumer.DISCOUNT_DESTINATION_IDS_MODEL_KEY,
                                           discountId,
                                           string.Join(",", customer.GetCustomerRoleIds()),
                                           _storeContext.CurrentStore.Id);
            var result = _cacheManager.Get(cacheKey, () =>
            {
                return(_discountRepository.Table.Where(x => x.Id == discountId)
                       .SelectMany(x => x.AppliedToDestinations.Select(c => c.Id))
                       .ToList());
            });

            return(result);
        }
Beispiel #9
0
        /// <summary>
        /// Check whether a list of discounts already contains a certain discount instance
        /// </summary>
        /// <param name="discounts">A list of discounts</param>
        /// <param name="discount">Discount to check</param>
        /// <returns>Result</returns>
        public virtual bool ContainsDiscount(IList <DiscountForCaching> discounts, DiscountForCaching discount)
        {
            if (discounts == null)
            {
                throw new ArgumentNullException(nameof(discounts));
            }

            if (discount == null)
            {
                throw new ArgumentNullException(nameof(discount));
            }

            foreach (var dis1 in discounts)
            {
                if (discount.Id == dis1.Id)
                {
                    return(true);
                }
            }

            return(false);
        }
        /// <summary>
        /// Check whether a list of discounts already contains a certain discount intance
        /// </summary>
        /// <param name="discounts">A list of discounts</param>
        /// <param name="discount">Discount to check</param>
        /// <returns>Result</returns>
        public static bool ContainsDiscount(this IList <DiscountForCaching> discounts,
                                            DiscountForCaching discount)
        {
            if (discounts == null)
            {
                throw new ArgumentNullException("discounts");
            }

            if (discount == null)
            {
                throw new ArgumentNullException("discount");
            }

            foreach (var dis1 in discounts)
            {
                if (discount.Id == dis1.Id)
                {
                    return(true);
                }
            }

            return(false);
        }
Beispiel #11
0
        /// <summary>
        /// Validate discount
        /// </summary>
        /// <param name="discount">Discount</param>
        /// <param name="customer">Customer</param>
        /// <param name="couponCodesToValidate">Coupon codes to validate</param>
        /// <returns>Discount validation result</returns>
        public virtual DiscountValidationResult ValidateDiscount(DiscountForCaching discount, Customer customer, string[] couponCodesToValidate)
        {
            if (discount == null)
            {
                throw new ArgumentNullException(nameof(discount));
            }

            if (customer == null)
            {
                throw new ArgumentNullException(nameof(customer));
            }

            //invalid by default
            var result = new DiscountValidationResult();

            //check coupon code
            if (discount.RequiresCouponCode)
            {
                if (string.IsNullOrEmpty(discount.CouponCode))
                {
                    return(result);
                }

                if (couponCodesToValidate == null)
                {
                    return(result);
                }

                if (!couponCodesToValidate.Any(x => x.Equals(discount.CouponCode, StringComparison.InvariantCultureIgnoreCase)))
                {
                    return(result);
                }
            }

            //Do not allow discounts applied to order subtotal or total when a customer has gift cards in the cart.
            //Otherwise, this customer can purchase gift cards with discount and get more than paid ("free money").
            if (discount.DiscountType == DiscountType.AssignedToOrderSubTotal ||
                discount.DiscountType == DiscountType.AssignedToOrderTotal)
            {
                var cart = customer.ShoppingCartItems
                           .Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart)
                           .LimitPerStore(_storeContext.CurrentStore.Id)
                           .ToList();

                var hasGiftCards = cart.Any(x => x.Product.IsGiftCard);
                if (hasGiftCards)
                {
                    result.Errors = new List <string> {
                        _localizationService.GetResource("ShoppingCart.Discount.CannotBeUsedWithGiftCards")
                    };
                    return(result);
                }
            }

            //check date range
            var now = DateTime.UtcNow;

            if (discount.StartDateUtc.HasValue)
            {
                var startDate = DateTime.SpecifyKind(discount.StartDateUtc.Value, DateTimeKind.Utc);
                if (startDate.CompareTo(now) > 0)
                {
                    result.Errors = new List <string> {
                        _localizationService.GetResource("ShoppingCart.Discount.NotStartedYet")
                    };
                    return(result);
                }
            }

            if (discount.EndDateUtc.HasValue)
            {
                var endDate = DateTime.SpecifyKind(discount.EndDateUtc.Value, DateTimeKind.Utc);
                if (endDate.CompareTo(now) < 0)
                {
                    result.Errors = new List <string> {
                        _localizationService.GetResource("ShoppingCart.Discount.Expired")
                    };
                    return(result);
                }
            }

            //discount limitation
            switch (discount.DiscountLimitation)
            {
            case DiscountLimitationType.NTimesOnly:
            {
                var usedTimes = GetAllDiscountUsageHistory(discount.Id, null, null, 0, 1).TotalCount;
                if (usedTimes >= discount.LimitationTimes)
                {
                    return(result);
                }
            }

            break;

            case DiscountLimitationType.NTimesPerCustomer:
            {
                if (customer.IsRegistered())
                {
                    var usedTimes = GetAllDiscountUsageHistory(discount.Id, customer.Id, null, 0, 1).TotalCount;
                    if (usedTimes >= discount.LimitationTimes)
                    {
                        result.Errors = new List <string> {
                            _localizationService.GetResource("ShoppingCart.Discount.CannotBeUsedAnymore")
                        };
                        return(result);
                    }
                }
            }

            break;

            case DiscountLimitationType.Unlimited:
            default:
                break;
            }

            //discount requirements
            var key = string.Format(NopDiscountDefaults.DiscountRequirementModelCacheKey, discount.Id);
            var requirementsForCaching = _cacheManager.Get(key, () =>
            {
                var requirements = GetAllDiscountRequirements(discount.Id, true);
                return(GetReqirementsForCaching(requirements));
            });

            //get top-level group
            var topLevelGroup = requirementsForCaching.FirstOrDefault();

            if (topLevelGroup == null || (topLevelGroup.IsGroup && !topLevelGroup.ChildRequirements.Any()) || !topLevelGroup.InteractionType.HasValue)
            {
                //there are no requirements, so discount is valid
                result.IsValid = true;
                return(result);
            }

            //requirements exist, let's check them
            var errors = new List <string>();

            result.IsValid = GetValidationResult(requirementsForCaching, topLevelGroup.InteractionType.Value, customer, errors);

            //set errors if result is not valid
            if (!result.IsValid)
            {
                result.Errors = errors;
            }

            return(result);
        }
Beispiel #12
0
        /// <summary>
        /// Validate discount
        /// </summary>
        /// <param name="discount">Discount</param>
        /// <param name="customer">Customer</param>
        /// <param name="couponCodesToValidate">Coupon codes to validate</param>
        /// <returns>Discount validation result</returns>
        public virtual DiscountValidationResult ValidateDiscount(DiscountForCaching discount, Customer customer, string[] couponCodesToValidate)
        {
            if (discount == null)
            {
                throw new ArgumentNullException("discount");
            }

            if (customer == null)
            {
                throw new ArgumentNullException("customer");
            }

            //invalid by default
            var result = new DiscountValidationResult();

            //check coupon code
            if (discount.RequiresCouponCode)
            {
                if (String.IsNullOrEmpty(discount.CouponCode))
                {
                    return(result);
                }

                if (couponCodesToValidate == null)
                {
                    return(result);
                }

                if (!couponCodesToValidate.Any(x => x.Equals(discount.CouponCode, StringComparison.InvariantCultureIgnoreCase)))
                {
                    return(result);
                }
            }

            //Do not allow discounts applied to order subtotal or total when a customer has gift cards in the cart.
            //Otherwise, this customer can purchase gift cards with discount and get more than paid ("free money").
            if (discount.DiscountType == DiscountType.AssignedToOrderSubTotal ||
                discount.DiscountType == DiscountType.AssignedToOrderTotal)
            {
                var cart = customer.ShoppingCartItems
                           .Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart)
                           .LimitPerStore(_storeContext.CurrentStore.Id)
                           .ToList();

                var hasGiftCards = cart.Any(x => x.Product.IsGiftCard);
                if (hasGiftCards)
                {
                    result.UserError = _localizationService.GetResource("ShoppingCart.Discount.CannotBeUsedWithGiftCards");
                    return(result);
                }
            }

            //check date range
            DateTime now = DateTime.UtcNow;

            if (discount.StartDateUtc.HasValue)
            {
                DateTime startDate = DateTime.SpecifyKind(discount.StartDateUtc.Value, DateTimeKind.Utc);
                if (startDate.CompareTo(now) > 0)
                {
                    result.UserError = _localizationService.GetResource("ShoppingCart.Discount.NotStartedYet");
                    return(result);
                }
            }
            if (discount.EndDateUtc.HasValue)
            {
                DateTime endDate = DateTime.SpecifyKind(discount.EndDateUtc.Value, DateTimeKind.Utc);
                if (endDate.CompareTo(now) < 0)
                {
                    result.UserError = _localizationService.GetResource("ShoppingCart.Discount.Expired");
                    return(result);
                }
            }

            //discount limitation
            switch (discount.DiscountLimitation)
            {
            case DiscountLimitationType.NTimesOnly:
            {
                var usedTimes = GetAllDiscountUsageHistory(discount.Id, null, null, 0, 1).TotalCount;
                if (usedTimes >= discount.LimitationTimes)
                {
                    return(result);
                }
            }
            break;

            case DiscountLimitationType.NTimesPerCustomer:
            {
                if (customer.IsRegistered())
                {
                    var usedTimes = GetAllDiscountUsageHistory(discount.Id, customer.Id, null, 0, 1).TotalCount;
                    if (usedTimes >= discount.LimitationTimes)
                    {
                        result.UserError = _localizationService.GetResource("ShoppingCart.Discount.CannotBeUsedAnymore");
                        return(result);
                    }
                }
            }
            break;

            case DiscountLimitationType.Unlimited:
            default:
                break;
            }

            //discount requirements
            string key          = string.Format(DiscountEventConsumer.DISCOUNT_REQUIREMENT_MODEL_KEY, discount.Id);
            var    requirements = _cacheManager.Get(key, () =>
            {
                var cachedRequirements = new List <DiscountRequirementForCaching>();
                foreach (var dr in GetAllDiscountRequirements(discount.Id))
                {
                    cachedRequirements.Add(new DiscountRequirementForCaching
                    {
                        Id         = dr.Id,
                        SystemName = dr.DiscountRequirementRuleSystemName
                    });
                }
                return(cachedRequirements);
            });

            foreach (var req in requirements)
            {
                //load a plugin
                var requirementRulePlugin = LoadDiscountRequirementRuleBySystemName(req.SystemName);
                if (requirementRulePlugin == null)
                {
                    continue;
                }

                if (!_pluginFinder.AuthorizedForUser(requirementRulePlugin.PluginDescriptor, customer))
                {
                    continue;
                }

                if (!_pluginFinder.AuthenticateStore(requirementRulePlugin.PluginDescriptor, _storeContext.CurrentStore.Id))
                {
                    continue;
                }

                var ruleRequest = new DiscountRequirementValidationRequest
                {
                    DiscountRequirementId = req.Id,
                    Customer = customer,
                    Store    = _storeContext.CurrentStore
                };
                var ruleResult = requirementRulePlugin.CheckRequirement(ruleRequest);
                if (!ruleResult.IsValid)
                {
                    result.UserError = ruleResult.UserError;
                    return(result);
                }
            }

            result.IsValid = true;
            return(result);
        }