public void Can_Adding_An_Option_Changes_Product_Property_DefinesOptions_To_True()
        {
            //// Arrange
            var product = PreTestDataWorker.MakeExistingProduct();

            //// Act
            var option = new ProductOption("Color");
            product.ProductOptions.Add(option);
            product.ProductOptions.Add(new ProductOption("Size"));
            _productService.Save(product);

            //// Assert
            Assert.IsTrue(product.ProductOptions.Any());
            Assert.IsTrue(product.DefinesOptions);
        }
        public void Can_Map_ProductOption_To_ProductOptionDisplay()
        {
            //// Arrange
            var attributes = new ProductAttributeCollection
                {
                    new ProductAttribute("One", "One"),
                    new ProductAttribute("Two", "Two"),
                    new ProductAttribute("Three", "Three"),
                    new ProductAttribute("Four", "Four")
                };

            var productOption = new ProductOption("Numbers", true, attributes);

            //// Act
            var productOptionDisplay = AutoMapper.Mapper.Map<ProductOptionDisplay>(productOption);

            //// Assert
            Assert.NotNull(productOptionDisplay);
        }
        /// <summary>
        /// Maps a <see cref="ProductDisplay"/> to <see cref="IProduct"/>
        /// </summary>
        /// <param name="productDisplay">
        /// The product display.
        /// </param>
        /// <param name="destination">
        /// The destination.
        /// </param>
        /// <returns>
        /// The <see cref="IProduct"/>.
        /// </returns>
        internal static IProduct ToProduct(this ProductDisplay productDisplay, IProduct destination)
        {
            if (productDisplay.Key != Guid.Empty)
            {
                destination.Key = productDisplay.Key;
            }

            productDisplay.CatalogInventories = productDisplay.CatalogInventories ?? Enumerable.Empty<CatalogInventoryDisplay>();
            productDisplay.ProductOptions = productDisplay.ProductOptions ?? Enumerable.Empty<ProductOptionDisplay>();

            destination.Name = productDisplay.Name;
            destination.Sku = productDisplay.Sku;
            destination.Price = productDisplay.Price;
            destination.CostOfGoods = productDisplay.CostOfGoods;
            destination.SalePrice = productDisplay.SalePrice;
            destination.OnSale = productDisplay.OnSale;
            destination.Manufacturer = productDisplay.Manufacturer;
            destination.ManufacturerModelNumber = productDisplay.ManufacturerModelNumber;
            destination.Weight = productDisplay.Weight;
            destination.Length = productDisplay.Length;
            destination.Width = productDisplay.Width;
            destination.Height = productDisplay.Height;
            destination.Barcode = productDisplay.Barcode;
            destination.Available = productDisplay.Available;
            destination.TrackInventory = productDisplay.TrackInventory;
            destination.OutOfStockPurchase = productDisplay.OutOfStockPurchase;
            destination.Taxable = productDisplay.Taxable;
            destination.Shippable = productDisplay.Shippable;
            destination.Download = productDisplay.Download;
            destination.DownloadMediaId = productDisplay.DownloadMediaId;

            // We need to refactor the CatalogInventories to not be immutable if we are
            // going to need to do operations like this.  In the UI, the user "unchecks" a catalog that was
            // previously checked - so we need to remove it.
            var deletedCatalogKeys =
                destination.CatalogInventories.Where(
                    x => !productDisplay.CatalogInventories.Select(ci => ci.CatalogKey).Contains(x.CatalogKey)).Select(x => x.CatalogKey).ToArray();
            foreach (var deletedCatalogKey in deletedCatalogKeys)
            {
                ((Product)destination).MasterVariant.RemoveFromCatalogInventory(deletedCatalogKey);
            }

            foreach (var catalogInventory in productDisplay.CatalogInventories)
            {
                var catInv = destination.CatalogInventories.FirstOrDefault(x => x.CatalogKey == catalogInventory.CatalogKey);

                if (catInv != null)
                {
                    var destinationCatalogInventory = catInv;

                    destinationCatalogInventory = catalogInventory.ToCatalogInventory(destinationCatalogInventory);
                }
                else
                {
                    //// Add to a new catalog
                    ((Product)destination).MasterVariant.AddToCatalogInventory(new CatalogInventory(catalogInventory.CatalogKey, catalogInventory.ProductVariantKey)
                                                                                   {
                                                                                       Location = catalogInventory.Location,
                                                                                       Count = catalogInventory.Count,
                                                                                       LowCount = catalogInventory.LowCount
                                                                                   });
                }
            }

            // Fix option deletion here #M-161
            // remove any product options that exist in destination and do not exist in productDisplay
            var removers = destination.ProductOptions.Where(x => !productDisplay.ProductOptions.Select(pd => pd.Key).Contains(x.Key)).Select(x => x.Key).ToList();
            foreach (var remove in removers)
            {
                destination.ProductOptions.RemoveItem(remove);
            }

            foreach (var option in productDisplay.ProductOptions)
            {
                IProductOption destinationProductOption;

                if (destination.ProductOptions.Contains(option.Key))
                {
                    destinationProductOption = destination.ProductOptions[option.Key];

                    destinationProductOption = option.ToProductOption(destinationProductOption);
                }
                else
                {
                    destinationProductOption = new ProductOption(option.Name, option.Required);

                    destinationProductOption = option.ToProductOption(destinationProductOption);
                }

                destination.ProductOptions.Add(destinationProductOption);
            }

            destination.AddOrUpdateDetachedContent(productDisplay);

            return destination;
        }
        internal static IProduct ToProduct(this ProductDisplay productDisplay, IProduct destination)
        {
            if (productDisplay.Key != Guid.Empty)
            {
                destination.Key = productDisplay.Key;
            }

            productDisplay.CatalogInventories = productDisplay.CatalogInventories ?? Enumerable.Empty<CatalogInventoryDisplay>();
            productDisplay.ProductOptions = productDisplay.ProductOptions ?? Enumerable.Empty<ProductOptionDisplay>();

            destination.Name = productDisplay.Name;
            destination.Sku = productDisplay.Sku;
            destination.Price = productDisplay.Price;
            destination.CostOfGoods = productDisplay.CostOfGoods;
            destination.SalePrice = productDisplay.SalePrice;
            destination.OnSale = productDisplay.OnSale;
            destination.Manufacturer = productDisplay.Manufacturer;
            destination.ManufacturerModelNumber = productDisplay.ManufacturerModelNumber;
            destination.Weight = productDisplay.Weight;
            destination.Length = productDisplay.Length;
            destination.Width = productDisplay.Width;
            destination.Height = productDisplay.Height;
            destination.Barcode = productDisplay.Barcode;
            destination.Available = productDisplay.Available;
            destination.TrackInventory = productDisplay.TrackInventory;
            destination.OutOfStockPurchase = productDisplay.OutOfStockPurchase;
            destination.Taxable = productDisplay.Taxable;
            destination.Shippable = productDisplay.Shippable;
            destination.Download = productDisplay.Download;
            destination.DownloadMediaId = productDisplay.DownloadMediaId;

            foreach (var catalogInventory in productDisplay.CatalogInventories)
            {
                var catInv = destination.CatalogInventories.FirstOrDefault(x => x.CatalogKey == catalogInventory.CatalogKey);

                if (catInv != null)
                {
                    var destinationCatalogInventory = catInv;

                    destinationCatalogInventory = catalogInventory.ToCatalogInventory(destinationCatalogInventory);
                }
                else if (!Guid.Empty.Equals(catalogInventory.CatalogKey) && destination.HasIdentity)
                {
                    //// Add to a new catalog
                    ((Product)destination).MasterVariant.AddToCatalogInventory(catalogInventory.CatalogKey);
                }
            }

            // Fix option deletion here #M-161
            // remove any product options that exist in destination and do not exist in productDisplay
            var removers = destination.ProductOptions.Where(x => !productDisplay.ProductOptions.Select(pd => pd.Key).Contains(x.Key)).Select(x => x.Key).ToList();
            foreach (var remove in removers)
            {
                destination.ProductOptions.RemoveItem(remove);
            }


            foreach (var option in productDisplay.ProductOptions)
            {
                IProductOption destinationProductOption;
                

                if (destination.ProductOptions.Contains(option.Key))
                {
                    destinationProductOption = destination.ProductOptions[option.Key];

                    destinationProductOption = option.ToProductOption(destinationProductOption);
                }
                else
                {
                    destinationProductOption = new ProductOption(option.Name, option.Required);

                    destinationProductOption = option.ToProductOption(destinationProductOption);
                }

                destination.ProductOptions.Add(destinationProductOption);
            }

            return destination;
        }
        public override void FixtureSetup()
        {
            base.FixtureSetup();

            _product = DbPreTestDataWorker.MakeExistingProduct(weight: 10, price: 15);
            var option = new ProductOption("Color");
            _product.ProductOptions.Add(option);
            _product.ProductOptions.Add(new ProductOption("Size"));
            MerchelloContext.Current.Services.ProductService.Save(_product);
        }
        public void Can_Remove_An_Option_By_The_Option()
        {
            //// Arrange
            var product = PreTestDataWorker.MakeExistingProduct();
            product.ProductOptions.Add(new ProductOption("Option1"));
            product.ProductOptions.Add(new ProductOption("Option2"));

            var removeItem = new ProductOption("Option3");
            product.ProductOptions.Add(removeItem);

            product.ProductOptions.Add(new ProductOption("Option4"));
            _productService.Save(product);
            Assert.IsTrue(product.ProductOptions.Count == 4);

            //// Act
            product.ProductOptions.Remove(removeItem);

            //// Assert
            Assert.IsTrue(product.ProductOptions.Count == 3);
        }
        /// <summary>
        /// Creates a <see cref="IProductOption"/> without saving it to the database.
        /// </summary>
        /// <param name="name">
        /// The option name.
        /// </param>
        /// <param name="shared">
        /// A value indicating whether or not this is a shared option (usable by multiple products).
        /// </param>
        /// <param name="required">
        /// The required.
        /// </param>
        /// <param name="raiseEvents">
        ///  Optional boolean indicating whether or not to raise events.
        /// </param>
        /// <returns>
        /// The <see cref="IProductOption"/>.
        /// </returns>
        public IProductOption CreateProductOption(string name, bool shared = false, bool required = true, bool raiseEvents = true)
        {
            var option = new ProductOption(name)
                        {
                            UseName = name,
                            Shared = shared,
                            Required = required
                        };

            if (raiseEvents)
            if (Creating.IsRaisedEventCancelled(new Events.NewEventArgs<IProductOption>(option), this))
            {
                option.WasCancelled = true;
                return option;
            }

            if (raiseEvents) Created.RaiseEvent(new Events.NewEventArgs<IProductOption>(option), this);

            return option;
        }
        public void Can_Remove_An_Option_By_The_Option()
        {
            //// Arrange
            var product = PreTestDataWorker.MakeExistingProduct();
            product.ProductOptions.Add(new ProductOption("Option1"));
            product.ProductOptions.Add(new ProductOption("Option2"));

            var removeItem = new ProductOption("Option3");
            product.ProductOptions.Add(removeItem);

            product.ProductOptions.Add(new ProductOption("Option4"));
            _productService.Save(product);
            Assert.AreEqual(4, product.ProductOptions.Count, "There should be 4 options");

            //// Act
            product.ProductOptions.Remove(removeItem);

            //// Assert
            Assert.AreEqual(3, product.ProductOptions.Count, "There should be 3 options");
        }
        /// <summary>
        /// Creates shared options.
        /// </summary>
        private void CreateSharedOptions()
        {
            var productOptionService = MerchelloContext.Current.Services.ProductOptionService;

            var size = new ProductOption("Size") { Shared = true, UiOption = "select" };
            size.Choices.Add(new ProductAttribute("Small", "sm") { SortOrder = 1, IsDefaultChoice = false });
            size.Choices.Add(new ProductAttribute("Medium", "md") { SortOrder = 2, IsDefaultChoice = false });
            size.Choices.Add(new ProductAttribute("Large", "lg") { SortOrder = 3, IsDefaultChoice = true });
            size.Choices.Add(new ProductAttribute("X-Large", "xl") { SortOrder = 4, IsDefaultChoice = false });

            var colour = new ProductOption("Colour") { Shared = true, UiOption = "select" };
            colour.Choices.Add(new ProductAttribute("White", "white") { SortOrder = 1, IsDefaultChoice = false });
            colour.Choices.Add(new ProductAttribute("Black", "black") { SortOrder = 2, IsDefaultChoice = false });
            colour.Choices.Add(new ProductAttribute("Grey", "grey") { SortOrder = 3, IsDefaultChoice = true });
            colour.Choices.Add(new ProductAttribute("Blue", "blue") { SortOrder = 4, IsDefaultChoice = false });

            productOptionService.Save(size);
            productOptionService.Save(colour);

            _sharedOptions.Add("size", size);
            _sharedOptions.Add("colour", colour);
        }