예제 #1
0
        // TODO: (ms) (core) TESTING! Make sure it works in any case - Works for ReOrder().
        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.RawAttributes;

                // 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);

            ShoppingCartItem existingCartItem = null;

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

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

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

                // Update cart item
                existingCartItem.Quantity      = newQuantity;
                existingCartItem.UpdatedOnUtc  = DateTime.UtcNow;
                existingCartItem.RawAttributes = ctx.AttributeSelection.AsJson();
                _db.TryUpdate(ctx.Customer);
                await _db.SaveChangesAsync();
            }
            else
            {
                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.RawAttributes,
                    ShoppingCartType     = ctx.CartType,
                    StoreId      = ctx.StoreId.Value,
                    Quantity     = ctx.Quantity,
                    Customer     = ctx.Customer,
                    Product      = ctx.Product,
                    ProductId    = ctx.Product.Id,
                    ParentItemId = null,
                    BundleItemId = ctx.BundleItem?.Id
                };

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

                // Check whether the product is part of a bundle, the bundle item or just any item.
                // If product is no child of bundle or no bundle at all
                if (ctx.BundleItem == null)
                {
                    // Set cart item as item for simple & bundle products, only if its not set by the caller
                    ctx.Item ??= cartItem;
                }
                else
                {
                    ctx.ChildItems.Add(cartItem);
                }
            }

            _requestCache.RemoveByPattern(CartItemsPatternKey);

            // If ctx.Product is a bundle product and the setting to automatically add bundle products is true, try to add all corresponding BundleItems.

            if (ctx.AutomaticallyAddBundleProductsIfEnabled &&
                ctx.Product.ProductType == ProductType.BundledProduct &&
                ctx.BundleItem == null &&
                ctx.Warnings.Count == 0)
            {
                var bundleItems = await _db.ProductBundleItem
                                  .Include(x => x.Product)
                                  .Include(x => x.BundleProduct)
                                  .ApplyBundledProductsFilter(new[] { ctx.Product.Id }, true)
                                  .ToListAsync();

                foreach (var bundleItem in bundleItems)
                {
                    var bundleItemContext = 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.RawAttributes,
                        CustomerEnteredPrice = ctx.CustomerEnteredPrice,
                        AutomaticallyAddRequiredProductsIfEnabled = ctx.AutomaticallyAddRequiredProductsIfEnabled,
                    };

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

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

            return(true);
        }
예제 #2
0
        public async Task <IActionResult> Index()
        {
            var storeId  = Services.StoreContext.CurrentStore.Id;
            var customer = Services.WorkContext.CurrentCustomer;
            var cart     = await _shoppingCartService.GetCartItemsAsync(storeId : storeId);

            if (!cart.Any())
            {
                return(RedirectToRoute("ShoppingCart"));
            }

            if (customer.IsGuest() && !_orderSettings.AnonymousCheckoutAllowed)
            {
                return(new UnauthorizedResult());
            }

            customer.ResetCheckoutData(storeId);

            // Validate checkout attributes.
            var checkoutAttributes = customer.GenericAttributes.CheckoutAttributes;

            var warnings = new List <string>();
            var isValid  = await _shoppingCartValidator.ValidateCartItemsAsync(cart, warnings, true, checkoutAttributes);

            if (!isValid)
            {
                NotifyWarning(string.Join(Environment.NewLine, warnings.Take(3)));
                return(RedirectToRoute("ShoppingCart"));
            }

            var validatingCartEvent = new ValidatingCartEvent(cart, warnings, customer);
            await Services.EventPublisher.PublishAsync(validatingCartEvent);

            if (validatingCartEvent.Result != null)
            {
                return(validatingCartEvent.Result);
            }

            if (warnings.Any())
            {
                NotifyWarning(string.Join(Environment.NewLine, warnings.Take(3)));
                return(RedirectToRoute("ShoppingCart"));
            }

            // Validate each shopping cart item.
            foreach (var cartItem in cart)
            {
                var ctx = new AddToCartContext
                {
                    StoreId    = storeId,
                    Product    = cartItem.Item.Product,
                    BundleItem = cartItem.Item.BundleItem,
                    ChildItems = cartItem.ChildItems.Select(x => x.Item).ToList()
                };

                isValid = await _shoppingCartValidator.ValidateAddToCartItemAsync(ctx, cartItem.Item, cart);

                if (!isValid)
                {
                    warnings.AddRange(ctx.Warnings);
                    NotifyWarning(string.Join(Environment.NewLine, warnings.Take(3)));
                    return(RedirectToRoute("ShoppingCart"));
                }
            }

            await _db.SaveChangesAsync();

            return(RedirectToAction(nameof(BillingAddress)));
        }