示例#1
0
        /// <summary>
        /// Validate discount
        /// </summary>
        /// <param name="discount">Discount</param>
        /// <param name="customer">Customer</param>
        /// <param name="couponCodeToValidate">Coupon code to validate</param>
        /// <returns>Discount validation result</returns>
        public virtual DiscountValidationResult ValidateDiscount(Discount discount, Customer customer, string couponCodeToValidate)
        {
            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 (!discount.CouponCode.Equals(couponCodeToValidate, 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.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
            //UNDONE we should inject static cache manager into constructor. we we already have "per request" cache manager injected. better way to do it?
            //we cache meta info of rdiscount requirements. this way we should not load them for each HTTP request
            var    staticCacheManager = EngineContext.Current.ContainerManager.Resolve <ICacheManager>();
            string key = string.Format(DiscountRequirementEventConsumer.DISCOUNT_REQUIREMENT_MODEL_KEY, discount.Id);
            //var requirements = discount.DiscountRequirements;
            var requirements = staticCacheManager.Get(key, () =>
            {
                var cachedRequirements = new List <DiscountRequirementForCaching>();
                foreach (var dr in discount.DiscountRequirements)
                {
                    cachedRequirements.Add(new DiscountRequirementForCaching
                    {
                        Id         = dr.Id,
                        DiscountId = dr.DiscountId,
                        SystemName = dr.DiscountRequirementRuleSystemName
                    });
                }
                return(cachedRequirements);
            });

            foreach (var req in requirements)
            {
                //load a plugin
                var requirementRulePlugin = LoadDiscountRequirementRuleBySystemName(req.SystemName);
                if (requirementRulePlugin == null)
                {
                    continue;
                }
                if (!_pluginFinder.AuthenticateStore(requirementRulePlugin.PluginDescriptor, _storeContext.CurrentStore.Id))
                {
                    continue;
                }

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

            result.IsValid = true;
            return(result);
        }
        /// <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 async Task <DiscountValidationResult> ValidateDiscount(Discount discount, Customer customer, string[] couponCodesToValidate)
        {
            if (discount == null)
            {
                throw new ArgumentNullException("discount");
            }

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

            var result = new DiscountValidationResult();

            //check is enabled
            if (!discount.IsEnabled)
            {
                return(result);
            }

            //do not allow use discount in the current store
            if (discount.LimitedToStores && !discount.Stores.Any(x => _storeContext.CurrentStore.Id == x))
            {
                result.UserError = _localizationService.GetResource("ShoppingCart.Discount.CannotBeUsedInStore");
                return(result);
            }

            //check coupon code
            if (discount.RequiresCouponCode)
            {
                if (couponCodesToValidate == null || !couponCodesToValidate.Any())
                {
                    return(result);
                }
                var exists = false;
                foreach (var item in couponCodesToValidate)
                {
                    if (discount.Reused)
                    {
                        if (await ExistsCodeInDiscount(item, discount.Id, null))
                        {
                            result.CouponCode = item;
                            exists            = true;
                        }
                    }
                    else
                    {
                        if (await ExistsCodeInDiscount(item, discount.Id, false))
                        {
                            result.CouponCode = item;
                            exists            = true;
                        }
                    }
                }
                if (!exists)
                {
                    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(_shoppingCartSettings.CartsSharedBetweenStores, _storeContext.CurrentStore.Id)
                           .ToList();

                var hasGiftCards = cart.Any(x => x.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 = await GetAllDiscountUsageHistory(discount.Id, null, null, false, 0, 1);

                if (usedTimes.TotalCount >= discount.LimitationTimes)
                {
                    return(result);
                }
            }
            break;

            case DiscountLimitationType.NTimesPerCustomer:
            {
                if (customer.IsRegistered())
                {
                    var usedTimes = await GetAllDiscountUsageHistory(discount.Id, customer.Id, null, false, 0, 1);

                    if (usedTimes.TotalCount >= discount.LimitationTimes)
                    {
                        result.UserError = _localizationService.GetResource("ShoppingCart.Discount.CannotBeUsedAnymore");
                        return(result);
                    }
                }
            }
            break;

            case DiscountLimitationType.Unlimited:
            default:
                break;
            }

            //discount requirements
            string keyReq       = string.Format(DiscountRequirementEventConsumer.DISCOUNT_REQUIREMENT_MODEL_KEY, discount.Id);
            var    requirements = await _cacheBase.GetAsync(keyReq, async() =>
            {
                return(await Task.FromResult(discount.DiscountRequirements.ToList()));
            });

            foreach (var req in requirements)
            {
                //load a plugin
                var discountRequirementPlugin = LoadDiscountPluginBySystemName(req.DiscountRequirementRuleSystemName);

                if (discountRequirementPlugin == null)
                {
                    continue;
                }

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

                var ruleRequest = new DiscountRequirementValidationRequest {
                    DiscountRequirementId = req.Id,
                    DiscountId            = req.DiscountId,
                    Customer = customer,
                    Store    = _storeContext.CurrentStore
                };

                var singleRequirementRule = discountRequirementPlugin.GetRequirementRules().Single(x => x.SystemName == req.DiscountRequirementRuleSystemName);
                var ruleResult            = await singleRequirementRule.CheckRequirement(ruleRequest);

                if (!ruleResult.IsValid)
                {
                    result.UserError = ruleResult.UserError;
                    return(result);
                }
            }

            result.IsValid = true;
            return(result);

            // });

            //return validationResult;
        }