Beispiel #1
0
        protected override IEnumerable <int> GetValues(CartRuleContext context)
        {
            // Fast batch loading of product IDs.
            var productIds = new HashSet <int>();
            var take       = 4000;
            var query      = GetQuery(context);
            var maxId      = query.Max(x => (int?)x.Id) ?? 0;

            for (var lastId = 0; lastId < maxId;)
            {
                var batchQuery = query
                                 .OrderBy(x => x.Id)
                                 .Select(x => new { x.Id, x.ProductId });

                if (lastId > 0)
                {
                    batchQuery = batchQuery.Where(x => x.Id > lastId);
                }

                batchQuery = batchQuery.Take(() => take);
                var batch = batchQuery.ToList();

                productIds.AddRange(batch.Select(x => x.ProductId));
                lastId = batch.Last().Id;
            }

            return(productIds);
        }
Beispiel #2
0
        protected virtual IQueryable <OrderItem> GetQuery(CartRuleContext context)
        {
            var query = _orderService.GetOrders(context.Store.Id, context.Customer.Id, null, null, null, null, null, null, null, null, null)
                        .SelectMany(o => o.OrderItems);

            return(query);
        }
Beispiel #3
0
        public bool Match(CartRuleContext context, RuleExpression expression)
        {
            var query      = _orderService.GetOrders(context.Store.Id, context.Customer.Id, null, null, null, null, null, null, null, null);
            var orderCount = query.Count();

            return(expression.Operator.Match(orderCount, expression.Value));
        }
Beispiel #4
0
        public bool Match(CartRuleContext context, RuleExpression expression)
        {
            var sessionKey = context.SessionKey;
            var lockKey    = "rule:cart:carttotalrule:" + sessionKey.ToString();

            if (KeyedLock.IsLockHeld(lockKey))
            {
                return(false);
            }

            // We must prevent the rule from indirectly calling itself. It would cause a stack overflow on cart page.
            using (KeyedLock.Lock(lockKey))
            {
                var cart = _shoppingCartService.GetCartItems(context.Customer, ShoppingCartType.ShoppingCart, context.Store.Id);

                var cartTotal = ((decimal?)_orderTotalCalculationService.GetShoppingCartTotal(cart)) ?? decimal.Zero;

                // Currency values must be rounded, otherwise unexpected results may occur.
                var money = new Money(cartTotal, context.WorkContext.WorkingCurrency);
                cartTotal = money.RoundedAmount;

                var result = expression.Operator.Match(cartTotal, expression.Value);
                return(result);
            }
        }
Beispiel #5
0
        public bool Match(CartRuleContext context, RuleExpression expression)
        {
            // INFO/TODO: get cart total from somewhere
            var cartTotal = 1000d;

            return(expression.Operator.Match(cartTotal, expression.Value));
        }
        protected override IEnumerable <int> GetValues(CartRuleContext context)
        {
            var cartProductIds = _shoppingCartService.GetCartItems(context.Customer, ShoppingCartType.ShoppingCart, context.Store.Id)
                                 .Select(x => x.Item.ProductId);

            return(cartProductIds);
        }
Beispiel #7
0
        public bool Match(CartRuleContext context, RuleExpression expression)
        {
            var otherExpression = GetOtherExpression(expression);

            if (otherExpression == null)
            {
                // Skip\ignore expression.
                return(true);
            }

            var otherRule = _cartRuleProvider.GetProcessor(otherExpression);

            //var otherMatch = otherRule.Match(context, otherExpression);

            //return expression.Operator.Match(otherMatch, true);

            if (expression.Operator == RuleOperator.IsEqualTo)
            {
                return(otherRule.Match(context, otherExpression));
            }
            if (expression.Operator == RuleOperator.IsNotEqualTo)
            {
                return(!otherRule.Match(context, otherExpression));
            }

            throw new InvalidRuleOperatorException(expression);
        }
Beispiel #8
0
        public async Task <bool> MatchAsync(CartRuleContext context, RuleExpression expression)
        {
            var sessionKey = context.SessionKey;
            var lockKey    = "rule:cart:cartsubtotalrule:" + sessionKey.ToString();

            if (AsyncLock.IsLockHeld(lockKey))
            {
                //$"locked expression {expression.Id}: {lockKey}".Dump();
                return(false);
            }

            // We must prevent the rule from indirectly calling itself. It would cause a stack overflow on cart page.
            using (await AsyncLock.KeyedAsync(lockKey))
            {
                var cart = await _shoppingCartService.GetCartItemsAsync(context.Customer, ShoppingCartType.ShoppingCart, context.Store.Id);

                // TODO: (mg) (core) Complete CartSubtotalRule (IOrderTotalCalculationService required).
                //await _orderTotalCalculationService.GetShoppingCartSubTotalAsync(cart, out _, out _, out var cartSubtotal, out _);
                var cartSubtotal = decimal.Zero;

                // Currency values must be rounded, otherwise unexpected results may occur.
                var money = new Money(cartSubtotal, context.WorkContext.WorkingCurrency);
                cartSubtotal = money.RoundedAmount;

                var result = expression.Operator.Match(cartSubtotal, expression.Value);
                //$"unlocked expression {expression.Id}: {lockKey}".Dump();
                return(result);
            }
        }
Beispiel #9
0
        public Task <bool> MatchAsync(CartRuleContext context, RuleExpression expression)
        {
            var paymentMethod = context.Customer.GenericAttributes.Get <string>(SystemCustomerAttributeNames.SelectedPaymentMethod, context.Store.Id);
            var match         = expression.HasListMatch(paymentMethod.NullEmpty(), StringComparer.InvariantCultureIgnoreCase);

            return(Task.FromResult(match));
        }
Beispiel #10
0
        public bool Match(CartRuleContext context, RuleExpression expression)
        {
            var result = true;

            // We must prevent the rule from indirectly calling itself. It would cause a stack overflow on cart page
            // and wrong discount calculation (due to MergeWithCombination, if the cart contains a product several times).
            if (Interlocked.CompareExchange(ref _reentrancyNum, 1, 0) == 0)
            {
                try
                {
                    var cart = _shoppingCartService.GetCartItems(context.Customer, ShoppingCartType.ShoppingCart, context.Store.Id);

                    var cartTotal = ((decimal?)_orderTotalCalculationService.GetShoppingCartTotal(cart)) ?? decimal.Zero;

                    // Currency values must be rounded, otherwise unexpected results may occur.
                    var money = new Money(cartTotal, context.WorkContext.WorkingCurrency);
                    cartTotal = money.RoundedAmount;

                    result = expression.Operator.Match(cartTotal, expression.Value);
                }
                finally
                {
                    _reentrancyNum = 0;
                }
            }

            return(result);
        }
        public bool Match(CartRuleContext context, RuleExpression expression)
        {
            var query        = _customerContentService.GetAllCustomerContent <ProductReview>(context.Customer.Id, true).SourceQuery;
            var reviewsCount = query.Count();

            return(expression.Operator.Match(reviewsCount, expression.Value));
        }
Beispiel #12
0
        public Task <bool> MatchAsync(CartRuleContext context, RuleExpression expression)
        {
            var country = _countryLookup.LookupCountry(_webHelper.GetClientIpAddress());
            var match   = expression.HasListMatch(country?.IsoCode ?? string.Empty, StringComparer.InvariantCultureIgnoreCase);

            return(Task.FromResult(match));
        }
        public Task <bool> MatchAsync(CartRuleContext context, RuleExpression expression)
        {
            var roleIds = context.Customer.GetRoleIds();
            var match   = expression.HasListsMatch(roleIds);

            return(Task.FromResult(match));
        }
        public bool Match(CartRuleContext context, RuleExpression expression)
        {
            var cart         = _shoppingCartService.GetCartItems(context.Customer, ShoppingCartType.ShoppingCart, context.Store.Id);
            var productCount = cart.GetTotalProducts();

            return(expression.Operator.Match(productCount, expression.Value));
        }
Beispiel #15
0
        protected override IEnumerable <string> GetValues(CartRuleContext context)
        {
            // Fast batch loading of payment methods.
            var paymentMethods = new HashSet <string>(StringComparer.InvariantCultureIgnoreCase);
            var take           = 4000;
            var query          = GetQuery(context);
            var maxId          = query.Max(x => (int?)x.Id) ?? 0;

            for (var lastId = 0; lastId < maxId;)
            {
                var batchQuery = query
                                 .OrderBy(x => x.Id)
                                 .Select(x => new { x.Id, x.PaymentMethodSystemName });

                if (lastId > 0)
                {
                    batchQuery = batchQuery.Where(x => x.Id > lastId);
                }

                batchQuery = batchQuery.Take(() => take);
                var batch = batchQuery.ToList();

                paymentMethods.AddRange(batch.Select(x => x.PaymentMethodSystemName));
                lastId = batch.Last().Id;
            }

            return(paymentMethods);
        }
Beispiel #16
0
        public async Task <bool> MatchAsync(CartRuleContext context, RuleExpression expression)
        {
            var sessionKey = context.SessionKey;
            var lockKey    = "rule:cart:cartsubtotalrule:" + sessionKey.ToString();

            if (AsyncLock.IsLockHeld(lockKey))
            {
                //$"locked expression {expression.Id}: {lockKey}".Dump();
                return(false);
            }

            // We must prevent the rule from indirectly calling itself. It would cause a stack overflow on cart page.
            using (await AsyncLock.KeyedAsync(lockKey))
            {
                var cart = await _shoppingCartService.GetCartItemsAsync(context.Customer, ShoppingCartType.ShoppingCart, context.Store.Id);

                var subtotal = await _orderCalculationService.GetShoppingCartSubtotalAsync(cart);

                // Subtotal is always calculated for working currency. No new money struct required here.
                // Currency values must be rounded here because otherwise unexpected results may occur.
                var cartSubtotal = subtotal.SubtotalWithoutDiscount.RoundedAmount;

                var result = expression.Operator.Match(cartSubtotal, expression.Value);
                //$"unlocked expression {expression.Id}: {lockKey}".Dump();
                return(result);
            }
        }
Beispiel #17
0
        public bool Match(CartRuleContext context, RuleExpression expression)
        {
            var lockKey = $"rule:cart:cartsubtotalrule:{Thread.CurrentThread.ManagedThreadId}-{expression.Id}";

            if (KeyedLock.IsLockHeld(lockKey))
            {
                //$"locked: {lockKey}".Dump();
                return(false);
            }

            // We must prevent the rule from indirectly calling itself. It would cause a stack overflow on cart page.
            using (KeyedLock.Lock(lockKey))
            {
                var cart = _shoppingCartService.GetCartItems(context.Customer, ShoppingCartType.ShoppingCart, context.Store.Id);

                _orderTotalCalculationService.GetShoppingCartSubTotal(cart, out _, out _, out var cartSubtotal, out _);

                // Currency values must be rounded, otherwise unexpected results may occur.
                var money = new Money(cartSubtotal, context.WorkContext.WorkingCurrency);
                cartSubtotal = money.RoundedAmount;

                var result = expression.Operator.Match(cartSubtotal, expression.Value);
                //$"unlocked {result}: {lockKey}".Dump();
                return(result);
            }
        }
Beispiel #18
0
        public Task <bool> MatchAsync(CartRuleContext context, RuleExpression expression)
        {
            var shippingMethod = context.Customer.GenericAttributes.Get <ShippingOption>(SystemCustomerAttributeNames.SelectedShippingOption, context.Store.Id);
            var match          = expression.HasListMatch(shippingMethod?.ShippingMethodId ?? 0);

            return(Task.FromResult(match));
        }
        public async Task <bool> MatchAsync(CartRuleContext context, RuleExpression expression)
        {
            var cart = await _shoppingCartService.GetCartItemsAsync(context.Customer, ShoppingCartType.ShoppingCart, context.Store.Id);

            var productCount = cart.GetTotalQuantity();

            return(expression.Operator.Match(productCount, expression.Value));
        }
Beispiel #20
0
        public async Task <bool> MatchAsync(CartRuleContext context, RuleExpression expression)
        {
            var count = await _db.Orders
                        .ApplyStandardFilter(context.Customer.Id, context.Store.Id)
                        .CountAsync();

            return(expression.Operator.Match(count, expression.Value));
        }
        protected override IEnumerable <int> GetValues(CartRuleContext context)
        {
            var roleIds = context.Customer.CustomerRoles
                          .Where(x => x.Active)
                          .Select(x => x.Id);

            return(roleIds);
        }
Beispiel #22
0
        public async Task <bool> MatchAsync(CartRuleContext context, RuleExpression expression)
        {
            var reviewsCount = await _db.CustomerContent
                               .ApplyCustomerFilter(context.Customer.Id, true)
                               .OfType <ProductReview>()
                               .CountAsync();

            return(expression.Operator.Match(reviewsCount, expression.Value));
        }
Beispiel #23
0
        public bool Match(CartRuleContext context, RuleExpression expression)
        {
            if (_userAgent.UserAgent.Minor.HasValue() && int.TryParse(_userAgent.UserAgent.Minor, out var minorVersion))
            {
                return(expression.Operator.Match(minorVersion, expression.Value));
            }

            return(false);
        }
Beispiel #24
0
        public Task <bool> MatchAsync(CartRuleContext context, RuleExpression expression)
        {
            var match = false;

            if (_userAgent.UserAgent.Minor.HasValue() && int.TryParse(_userAgent.UserAgent.Minor, out var minorVersion))
            {
                match = expression.Operator.Match(minorVersion, expression.Value);
            }

            return(Task.FromResult(match));
        }
Beispiel #25
0
        public bool Match(CartRuleContext context, RuleExpression expression)
        {
            var query       = _orderService.GetOrders(context.Store.Id, context.Customer.Id, null, null, new int[] { (int)OrderStatus.Complete }, null, null, null, null, null);
            var spentAmount = query.Sum(x => (decimal?)x.OrderTotal) ?? decimal.Zero;

            var money = new Money(spentAmount, context.WorkContext.WorkingCurrency);

            spentAmount = money.RoundedAmount;

            return(expression.Operator.Match(spentAmount, expression.Value));
        }
        public bool Match(CartRuleContext context, RuleExpression expression)
        {
            var list = expression.Value as List <int>;

            if (list == null || list.Count == 0)
            {
                return(true);
            }

            var currentRoleIds = context.Customer.CustomerRoles.Select(x => x.Id);

            return(currentRoleIds.All(x => expression.Operator.Match(x, list)));
        }
        public async Task <bool> MatchAsync(CartRuleContext context, RuleExpression expression)
        {
            var cart = await _shoppingCartService.GetCartItemsAsync(context.Customer, ShoppingCartType.ShoppingCart, context.Store.Id);

            var productIds = cart
                             .Select(x => x.Item.ProductId)
                             .Distinct()
                             .ToArray();

            var match = expression.HasListsMatch(productIds);

            return(match);
        }
Beispiel #28
0
        public bool Match(CartRuleContext context, RuleExpression expression)
        {
            var cart = _shoppingCartService.GetCartItems(context.Customer, ShoppingCartType.ShoppingCart, context.Store.Id);

            var cartTotal = ((decimal?)_orderTotalCalculationService.GetShoppingCartTotal(cart)) ?? decimal.Zero;

            // Currency values must be rounded, otherwise unexpected results may occur.
            var money = new Money(cartTotal, context.WorkContext.WorkingCurrency);

            cartTotal = money.RoundedAmount;

            return(expression.Operator.Match(cartTotal, expression.Value));
        }
Beispiel #29
0
        public async Task <bool> MatchAsync(CartRuleContext context, RuleExpression expression)
        {
            var query = _db.Orders
                        .AsNoTracking()
                        .ApplyStandardFilter(context.Customer.Id, context.Store.Id)
                        .ApplyStatusFilter(new[] { (int)OrderStatus.Complete });

            var spentAmount = await query.SumAsync(x => (decimal?)x.OrderTotal);

            var money = new Money(spentAmount ?? decimal.Zero, context.WorkContext.WorkingCurrency);

            return(expression.Operator.Match(money.RoundedAmount, expression.Value));
        }
        protected override IEnumerable <int> GetValues(CartRuleContext context)
        {
            var cart       = _shoppingCartService.GetCartItems(context.Customer, ShoppingCartType.ShoppingCart, context.Store.Id);
            var productIds = cart.Select(x => x.Item.ProductId).ToArray();

            if (productIds.Any())
            {
                // It's unnecessary to check things like ACL, limited-to-stores, published, deleted etc. here
                // because the products are from shopping cart and it cannot contain hidden products.
                var categoryIds = _productCategoryRepository.TableUntracked
                                  .Where(x => productIds.Contains(x.ProductId))
                                  .Select(x => x.CategoryId)
                                  .ToList();

                return(categoryIds.Distinct());
            }

            return(Enumerable.Empty <int>());
        }