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); }
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); }
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)); }
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); } }
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); }
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); }
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); } }
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)); }
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)); }
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)); }
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); }
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); } }
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); } }
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)); }
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); }
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)); }
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); }
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)); }
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); }
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)); }
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>()); }