Beispiel #1
0
        public virtual Task <List <OrganizedShoppingCartItem> > GetCartItemsAsync(
            Customer customer         = null,
            ShoppingCartType cartType = ShoppingCartType.ShoppingCart,
            int storeId = 0)
        {
            customer ??= _workContext.CurrentCustomer;

            var cacheKey = CartItemsKey.FormatInvariant(customer.Id, (int)cartType, storeId);
            var result   = _requestCache.Get(cacheKey, async() =>
            {
                var cartItems = new List <ShoppingCartItem>();
                if (_db.IsCollectionLoaded(customer, x => x.ShoppingCartItems))
                {
                    var filteredCartItems = customer.ShoppingCartItems
                                            .Where(x => x.CustomerId == customer.Id && x.ShoppingCartTypeId == (int)cartType);

                    if (storeId > 0)
                    {
                        filteredCartItems = cartItems.Where(x => x.StoreId == storeId);
                    }

                    cartItems = filteredCartItems.ToList();
                }
                else
                {
                    cartItems = await _db.ShoppingCartItems
                                .Include(x => x.Product)
                                .ThenInclude(x => x.ProductVariantAttributes)
                                .ApplyStandardFilter(cartType, storeId, customer)
                                .ToListAsync();

                    customer.ShoppingCartItems = cartItems;
                }

                // Prefetch all product variant attributes
                var allAttributes    = new ProductVariantAttributeSelection(string.Empty);
                var allAttributeMaps = cartItems.SelectMany(x => x.AttributeSelection.AttributesMap);

                foreach (var attribute in allAttributeMaps)
                {
                    if (allAttributes.AttributesMap.Contains(attribute))
                    {
                        continue;
                    }

                    allAttributes.AddAttribute(attribute.Key, attribute.Value);
                }

                await _productAttributeMaterializer.MaterializeProductVariantAttributesAsync(allAttributes);

                return(await OrganizeCartItemsAsync(cartItems));
            });

            return(result);
        }
Beispiel #2
0
        public virtual async Task <TaskExecutionInfo> GetLastExecutionInfoByTaskAsync(TaskDescriptor task, bool?runningOnly = null)
        {
            Guard.NotNull(task, nameof(task));

            var query = _db.IsCollectionLoaded(task, x => x.ExecutionHistory)
                ? task.ExecutionHistory.AsQueryable()
                : GetExecutionInfoQuery().Include(x => x.Task).ApplyTaskFilter(task.Id);

            if (runningOnly.HasValue)
            {
                query = query.Where(x => x.IsRunning == runningOnly.Value);
            }

            query = query.ApplyCurrentMachineNameFilter();

            return(await ExecuteWithRetry(() => query.FirstOrDefaultAsync()));
        }
Beispiel #3
0
        // TODO: (ms) (core) AddToCartContext needs to have bundleItem and childItems already included correctly, they get just added...
        public virtual async Task <IList <string> > AddToCartAsync(AddToCartContext ctx)
        {
            Guard.NotNull(ctx, nameof(ctx));

            // This is called when customer adds a product to cart
            var warnings = new List <string>();

            ctx.Customer ??= _workContext.CurrentCustomer;
            ctx.StoreId ??= _storeContext.CurrentStore.Id;


            // TODO: (ms) (core) customerService.ResetCheckoutData() is missing
            //_customerService.ResetCheckoutData(customer, storeId);

            // Checks whether attributes have been selected
            // TODO: (ms) (core) VariantQuery is missing. Tries to get attributes of product.
            //if (ctx.VariantQuery != null)
            //{
            //    // Create attribute selection from  product attributes
            //    var attributes = _productAttributeMaterializer.MaterializeProductVariantAttributesAsync(ctx.AttributeSelection);
            //    //ctx.RawAttributes = ctx.VariantQuery.CreateSelectedAttributesXml(ctx.Product.Id, ctx.BundleItemId, attributes, _productAttributeParser,
            //    //_localizationService, _downloadService, _catalogSettings, null, ctx.Warnings);

            //    // Check context for bundle item errors
            //    if (ctx.Product.ProductType == ProductType.BundledProduct && ctx.RawAttributes.HasValue())
            //    {
            //        ctx.Warnings.Add(T("ShoppingCart.Bundle.NoAttributes"));

            //        if (ctx.BundleItem != null)
            //            return ctx.Warnings;
            //    }
            //}

            warnings.AddRange(await _cartValidator.ValidateAccessPermissionsAsync(ctx));
            if (warnings.Count > 0)
            {
                return(warnings);
            }


            // TODO: (ms) (core) Call ValidateRequiredProductsAsync and check product for required products, that are not included in cart
            // add them if neccessary and wanted
            //ctx.AutomaticallyAddRequiredProductsIfEnabled

            var shoppingCart = await GetCartItemsAsync(ctx.Customer, ctx.CartType, ctx.StoreId.Value);

            warnings.AddRange(await _cartValidator.ValidateRequiredProductsAsync(ctx, shoppingCart));
            //if(ctx.AutomaticallyAddRequiredProductsIfEnabled)
            // Add missing products.....

            OrganizedShoppingCartItem existingCartItem = null;

            if (ctx.BundleItem == null)
            {
                existingCartItem = shoppingCart.FindItemInCart(ctx.CartType, ctx.Product, ctx.AttributeSelection, ctx.CustomerEnteredPrice);
            }

            // Add item to cart (if no warnings accured)
            if (existingCartItem != null)
            {
                // Product is already in cart, find existing item
                ctx.Quantity += existingCartItem.Item.Quantity;

                warnings.AddRange(await _cartValidator.ValidateCartItemAsync(ctx, shoppingCart));
                if (warnings.Count > 0)
                {
                    return(warnings);
                }

                // Update cart item
                existingCartItem.Item.Quantity      = ctx.Quantity;
                existingCartItem.Item.UpdatedOnUtc  = DateTime.UtcNow;
                existingCartItem.Item.RawAttributes = ctx.RawAttributes;
                _db.TryUpdate(ctx.Customer);
                await _db.SaveChangesAsync();
            }
            else
            {
                warnings.AddRange(await _cartValidator.ValidateCartItemAsync(ctx, shoppingCart));
                if (warnings.Count > 0)
                {
                    return(warnings);
                }

                var warning = _cartValidator.ValidateCartItemsMaximum(ctx.CartType, shoppingCart.Count);
                if (warning.Count > 0)
                {
                    ctx.Warnings.AddRange(warning);
                    warnings.AddRange(warning);
                    return(warnings);
                }

                // Product is not in cart yet, create new item
                var cartItem = new ShoppingCartItem
                {
                    CustomerEnteredPrice = ctx.CustomerEnteredPrice,
                    RawAttributes        = ctx.RawAttributes,
                    ShoppingCartType     = ctx.CartType,
                    StoreId      = ctx.StoreId.Value,
                    Quantity     = ctx.Quantity,
                    Customer     = ctx.Customer,
                    Product      = ctx.Product,
                    ParentItemId = null,
                    BundleItemId = ctx.BundleItem?.Id
                };

                // If product is no bundle, add it as cartItem
                if (ctx.BundleItem == null)
                {
                    Debug.Assert(ctx.Item == null, "Add to cart item already specified");
                    ctx.Item = cartItem;
                }
                else
                {
                    ctx.ChildItems.Add(cartItem);
                }
            }

            _requestCache.RemoveByPattern(CartItemsPatternKey);

            // If ctx.Product is a bundle product, try adding all corresponding bundleItems
            if (ctx.Product.ProductType == ProductType.BundledProduct && ctx.BundleItem == null && warnings.Count == 0)
            {
                var bundleItems = new List <ProductBundleItem>();

                // Get all bundle items and add each to the cart
                if (_db.IsCollectionLoaded(ctx.Product, x => x.ProductBundleItems))
                {
                    bundleItems = ctx.Product.ProductBundleItems.ToList();
                }
                else
                {
                    bundleItems = await _db.ProductBundleItem
                                  .ApplyBundledProductsFilter(new[] { ctx.Product.Id })
                                  .ToListAsync();
                }

                foreach (var bundleItem in bundleItems)
                {
                    // Try add each bundleItem to the cart
                    warnings.AddRange(
                        await AddToCartAsync(
                            new AddToCartContext
                    {
                        Item       = ctx.Item,
                        Customer   = ctx.Customer,
                        BundleItem = bundleItem,
                        Warnings   = ctx.Warnings,
                        CartType   = ctx.CartType,
                        StoreId    = ctx.StoreId.Value,
                        ChildItems = ctx.ChildItems,
                        Product    = bundleItem.Product,
                        Quantity   = bundleItem.Quantity,
                        //VariantQuery = ctx.VariantQuery,
                        AutomaticallyAddRequiredProductsIfEnabled = ctx.AutomaticallyAddRequiredProductsIfEnabled
                    })
                        );

                    // If bundleItem could not be added to the shopping cart, remove child items as they
                    if (warnings.Count > 0)
                    {
                        ctx.ChildItems.Clear();
                        break;
                    }
                }
            }

            // If context is no bundleItem, add item (parent) and its children (grouped product)
            if (ctx.BundleItem == null && warnings.Count == 0)
            {
                await AddItemToCartAsync(ctx);
            }

            return(warnings);
        }
Beispiel #4
0
        protected virtual async Task <ICollection <Discount> > GetApplicableDiscounts(Product product, CalculatorContext context)
        {
            var result       = new HashSet <Discount>();
            var batchContext = context.Options.BatchContext;
            var customer     = context.Options.Customer;

            // Check discounts assigned to the product.
            // We use the property "HasDiscountsApplied" for performance optimization to avoid unnecessary database calls.
            if (product.HasDiscountsApplied)
            {
                var collectionLoaded = _db.IsCollectionLoaded(product, x => x.AppliedDiscounts);
                var appliedDiscounts = collectionLoaded ? product.AppliedDiscounts : await batchContext.AppliedDiscounts.GetOrLoadAsync(product.Id);

                if (appliedDiscounts != null)
                {
                    await TryAddDiscounts(appliedDiscounts, result, DiscountType.AssignedToSkus, context.Options);
                }
            }

            // Check discounts assigned to categories.
            var categoryDiscounts = await _discountService.GetAllDiscountsAsync(DiscountType.AssignedToCategories);

            if (categoryDiscounts.Any())
            {
                var productCategories = await batchContext.ProductCategories.GetOrLoadAsync(product.Id);

                foreach (var productCategory in productCategories)
                {
                    var category = productCategory.Category;

                    if (category?.HasDiscountsApplied ?? false)
                    {
                        // INFO: AppliedDiscounts are eager loaded already.
                        //await _db.LoadCollectionAsync(category, x => x.AppliedDiscounts);

                        await TryAddDiscounts(category.AppliedDiscounts, result, DiscountType.AssignedToCategories, context.Options);
                    }
                }
            }

            // Check discounts assigned to manufacturers.
            var manufacturerDiscounts = await _discountService.GetAllDiscountsAsync(DiscountType.AssignedToManufacturers);

            if (manufacturerDiscounts.Any())
            {
                var productManufacturers = await batchContext.ProductManufacturers.GetOrLoadAsync(product.Id);

                foreach (var productManufacturer in productManufacturers)
                {
                    var manu = productManufacturer.Manufacturer;

                    if (manu?.HasDiscountsApplied ?? false)
                    {
                        // INFO: AppliedDiscounts are eager loaded already.
                        //await _db.LoadCollectionAsync(manu, x => x.AppliedDiscounts);

                        await TryAddDiscounts(manu.AppliedDiscounts, result, DiscountType.AssignedToManufacturers, context.Options);
                    }
                }
            }

            return(result);
        }
        // TODO: (ms) (core) AddToCartContext needs to have bundleItem and childItems already included correctly, they get just added...TEST THIS EXTENSIVELY
        public virtual async Task <bool> AddToCartAsync(AddToCartContext ctx)
        {
            Guard.NotNull(ctx, nameof(ctx));

            // This is called when customer adds a product to cart
            ctx.Customer ??= _workContext.CurrentCustomer;
            ctx.StoreId ??= _storeContext.CurrentStore.Id;

            ctx.Customer.ResetCheckoutData(ctx.StoreId.Value);

            // Checks whether attributes have been selected
            if (ctx.VariantQuery != null)
            {
                // Create attribute selection from product attributes
                var attributes = await _productAttributeMaterializer.MaterializeProductVariantAttributesAsync(ctx.Item.AttributeSelection);

                ctx.RawAttributes = ctx.Item.AttributeSelection.AsJson();

                // Check context for bundle item errors
                if (ctx.Product.ProductType == ProductType.BundledProduct && ctx.RawAttributes.HasValue())
                {
                    ctx.Warnings.Add(T("ShoppingCart.Bundle.NoAttributes"));

                    if (ctx.BundleItem != null)
                    {
                        return(false);
                    }
                }
            }

            if (!await _cartValidator.ValidateAccessPermissionsAsync(ctx.Customer, ctx.CartType, ctx.Warnings))
            {
                return(false);
            }

            var cartItems = await GetCartItemsAsync(ctx.Customer, ctx.CartType, ctx.StoreId.Value);

            // Adds required products automatically if it is enabled
            if (ctx.AutomaticallyAddRequiredProductsIfEnabled)
            {
                var requiredProductIds = ctx.Product.ParseRequiredProductIds();
                if (requiredProductIds.Any())
                {
                    var cartProductIds            = cartItems.Select(x => x.Item.ProductId);
                    var missingRequiredProductIds = requiredProductIds.Except(cartProductIds);
                    var missingRequiredProducts   = await _db.Products.GetManyAsync(missingRequiredProductIds);

                    foreach (var product in missingRequiredProducts)
                    {
                        var item = new ShoppingCartItem
                        {
                            CustomerEnteredPrice = ctx.CustomerEnteredPrice.Amount,
                            RawAttributes        = ctx.AttributeSelection.AsJson(),
                            ShoppingCartType     = ctx.CartType,
                            StoreId      = ctx.StoreId.Value,
                            Quantity     = ctx.Quantity,
                            Customer     = ctx.Customer,
                            Product      = product,
                            ParentItemId = product.ParentGroupedProductId,
                            BundleItemId = ctx.BundleItem?.Id
                        };

                        await AddItemToCartAsync(new AddToCartContext
                        {
                            Item       = item,
                            ChildItems = ctx.ChildItems,
                            Customer   = ctx.Customer
                        });
                    }
                }
            }

            // Checks whether required products are still missing
            await _cartValidator.ValidateRequiredProductsAsync(ctx.Product, cartItems, ctx.Warnings);

            OrganizedShoppingCartItem existingCartItem = null;

            if (ctx.BundleItem == null)
            {
                existingCartItem = cartItems.FindItemInCart(ctx.CartType, ctx.Product, ctx.AttributeSelection, ctx.CustomerEnteredPrice);
            }

            // Add item to cart (if no warnings accured)
            if (existingCartItem != null)
            {
                // Product is already in cart, find existing item
                ctx.Quantity += existingCartItem.Item.Quantity;

                if (!await _cartValidator.ValidateAddToCartItemAsync(ctx, cartItems))
                {
                    return(false);
                }

                // Update cart item
                existingCartItem.Item.Quantity      = ctx.Quantity;
                existingCartItem.Item.UpdatedOnUtc  = DateTime.UtcNow;
                existingCartItem.Item.RawAttributes = ctx.AttributeSelection.AsJson();
                _db.TryUpdate(ctx.Customer);
                await _db.SaveChangesAsync();
            }
            else
            {
                if (!await _cartValidator.ValidateAddToCartItemAsync(ctx, cartItems))
                {
                    return(false);
                }

                if (!_cartValidator.ValidateItemsMaximumCartQuantity(ctx.CartType, cartItems.Count, ctx.Warnings))
                {
                    return(false);
                }

                // Product is not in cart yet, create new item
                var cartItem = new ShoppingCartItem
                {
                    CustomerEnteredPrice = ctx.CustomerEnteredPrice.Amount,
                    RawAttributes        = ctx.AttributeSelection.AsJson(),
                    ShoppingCartType     = ctx.CartType,
                    StoreId      = ctx.StoreId.Value,
                    Quantity     = ctx.Quantity,
                    Customer     = ctx.Customer,
                    Product      = ctx.Product,
                    ParentItemId = null,
                    BundleItemId = ctx.BundleItem?.Id
                };

                // If product is no bundle, add it as cartItem
                if (ctx.BundleItem == null)
                {
                    Debug.Assert(ctx.Item == null, "Add to cart item already specified");
                    ctx.Item = cartItem;
                }
                else
                {
                    ctx.ChildItems.Add(cartItem);
                }
            }

            _requestCache.RemoveByPattern(CartItemsPatternKey);

            // If ctx.Product is a bundle product, try adding all corresponding bundleItems
            if (ctx.Product.ProductType == ProductType.BundledProduct && ctx.BundleItem == null && ctx.Warnings.Count == 0)
            {
                // Get all bundle items and add each to the cart
                var bundleItems = _db.IsCollectionLoaded(ctx.Product, x => x.ProductBundleItems)
                    ? ctx.Product.ProductBundleItems
                    : await _db.ProductBundleItem
                                  .ApplyBundledProductsFilter(new[] { ctx.Product.Id })
                                  .ToListAsync();

                foreach (var bundleItem in bundleItems)
                {
                    var tempCtx = new AddToCartContext
                    {
                        Warnings             = new(),
                        Item                 = ctx.Item,
                        StoreId              = ctx.StoreId,
                        Customer             = ctx.Customer,
                        CartType             = ctx.CartType,
                        BundleItem           = bundleItem,
                        ChildItems           = ctx.ChildItems,
                        Product              = bundleItem.Product,
                        Quantity             = bundleItem.Quantity,
                        VariantQuery         = ctx.VariantQuery,
                        RawAttributes        = ctx.AttributeSelection.AsJson(),
                        CustomerEnteredPrice = ctx.CustomerEnteredPrice,
                        AutomaticallyAddRequiredProductsIfEnabled = ctx.AutomaticallyAddRequiredProductsIfEnabled,
                    };

                    // If bundleItem could not be added to the shopping cart, remove child items
                    if (!await AddToCartAsync(tempCtx))
                    {
                        ctx.ChildItems.Clear();
                        break;
                    }
                }
            }

            // If context is no bundleItem, add item (parent) and its children (grouped product)
            if (ctx.BundleItem == null && ctx.Warnings.Count == 0)
            {
                await AddItemToCartAsync(ctx);
            }

            return(true);
        }