示例#1
0
        //EndDocSection:DisplayProduct

        //DocSection:DisplayVariant
        /// <summary>
        /// Displays product detail page of a product or a product variant specified by ID of the product's or variant's page.
        /// </summary>
        /// <param name="id">Node ID of the product's (variant's) page.</param>
        /// <param name="productAlias">Node alias of the product's (variant's) page.</param>
        public ActionResult Detail(int id, string productAlias)
        {
            // Gets the product from Kentico
            SKUTreeNode product = GetProduct(id);

            // If the product is not found or if it is not allowed for sale, redirects to error 404
            if ((product == null) || !product.SKU.SKUEnabled)
            {
                return(HttpNotFound());
            }

            // Redirects if the specified page alias does not match
            if (!string.IsNullOrEmpty(productAlias) && !product.NodeAlias.Equals(productAlias, StringComparison.InvariantCultureIgnoreCase))
            {
                return(RedirectToActionPermanent("Detail", new { id = product.NodeID, productAlias = product.NodeAlias }));
            }

            // Gets all product variants of the product
            List <Variant> variants = variantRepository.GetByProductId(product.NodeSKUID).OrderBy(v => v.VariantPrice).ToList();

            // Selects the first product variant
            Variant selectedVariant = variants.FirstOrDefault();

            // Calculates the price of the product or the variant
            ShoppingCart cart        = shoppingService.GetCurrentShoppingCart();
            ProductPrice priceDetail = selectedVariant != null?pricingService.CalculatePrice(selectedVariant, cart) : pricingService.CalculatePrice(product.SKU, cart);

            // Initializes the view model of the product or product variant
            ProductViewModel viewModel = new ProductViewModel(product, priceDetail, variants, selectedVariant?.VariantSKUID ?? 0);

            // Displays the product detail page
            return(View(viewModel));
        }
示例#2
0
        /// <summary>
        /// Creates a new product model with variants.
        /// </summary>
        /// <param name="productPage">Product's page.</param>
        /// <param name="priceDetail">Price of the selected variant.</param>
        /// <param name="variants">Collection of selectable variants.</param>
        /// <param name="selectedVariantID">ID of the selected variant.</param>
        public ProductViewModel(SKUTreeNode productPage, ProductPrice priceDetail, List <Variant> variants, int selectedVariantID)
            : this(productPage, priceDetail)
        {
            // Fills the selectable variants
            ProductVariants = variants;

            // Continues if the product has any variants
            if (variants.Any())
            {
                // Pre select variant
                var selectedVariant = variants.FirstOrDefault(v => v.VariantSKUID == selectedVariantID);

                if (selectedVariant != null)
                {
                    IsInStock         = !selectedVariant.InventoryTracked || selectedVariant.AvailableItems > 0;
                    SelectedVariantID = selectedVariantID;
                }

                // Creates a list of product variants
                VariantSelectList = new SelectList(variants.Select(v => new SelectListItem
                {
                    Text  = string.Join(", ", v.ProductAttributes.Select(a => a.SKUName)),
                    Value = v.VariantSKUID.ToString()
                }), "Value", "Text");
            }
        }
        /// <summary>
        /// Creates a new product model.
        /// </summary>
        /// <param name="productPage">Product's page.</param>
        /// <param name="priceDetail">Price of the product.</param>
        public ProductViewModel(SKUTreeNode productPage, ProductCatalogPrices priceDetail)
        {
            // Fills the page information
            Name             = productPage.DocumentName;
            Description      = productPage.DocumentSKUDescription;
            ShortDescription = productPage.DocumentSKUShortDescription;

            // Fills the SKU information
            SKUInfo sku = productPage.SKU;

            SKUID     = sku.SKUID;
            ImagePath = string.IsNullOrEmpty(sku.SKUImagePath) ? null : new FileUrl(sku.SKUImagePath, true)
                        .WithSizeConstraint(SizeConstraint.MaxWidthOrHeight(400))
                        .RelativePath;

            IsInStock = sku.SKUTrackInventory == TrackInventoryTypeEnum.Disabled ||
                        sku.SKUAvailableItems > 0;

            PriceDetail = new PriceDetailViewModel()
            {
                Price                = priceDetail.Price,
                ListPrice            = priceDetail.ListPrice,
                CurrencyFormatString = priceDetail.Currency.CurrencyFormatString
            };
        }
        private SKUTreeNode AppendProduct(TreeNode parent, CampaignProductDto product, SKUInfo sku, int siteId)
        {
            if (parent == null || product == null)
            {
                return(null);
            }

            TreeProvider    tree            = new TreeProvider(MembershipContext.AuthenticatedUser);
            SKUTreeNode     existingProduct = (SKUTreeNode)parent.Children.FirstOrDefault(c => c.NodeSKUID == sku.SKUID);
            SKUTreeNode     newProduct      = existingProduct ?? (SKUTreeNode)TreeNode.New(CampaignsProduct.CLASS_NAME, tree);
            Program         program         = GetProgram(product.Campaign, product.ProgramName);
            ProductCategory productCategory = GetProductCategory(product.ProductCategory);

            newProduct.DocumentName    = product.ProductName;
            newProduct.DocumentSKUName = product.ProductName;
            newProduct.NodeSKUID       = sku.SKUID;
            newProduct.NodeName        = product.ProductName;
            newProduct.DocumentCulture = _culture;
            newProduct.SetValue("ProductName", product.ProductName);
            newProduct.SetValue("BrandID", GetBrandID(product.Brand));
            SetProductItemSpecs(ref newProduct, product);
            if (program != null)
            {
                newProduct.SetValue("ProgramID", program.ProgramID);
            }
            if (!string.IsNullOrWhiteSpace(product.AllowedStates))
            {
                newProduct.SetValue("State", GetStatesGroupID(product.AllowedStates));
            }
            if (!string.IsNullOrWhiteSpace(product.EstimatedPrice))
            {
                newProduct.SetValue("EstimatedPrice", product.EstimatedPrice);
            }
            if (productCategory != null)
            {
                newProduct.SetValue("CategoryID", productCategory.ProductCategoryID);
            }
            if (!string.IsNullOrWhiteSpace(product.BundleQuantity))
            {
                newProduct.SetValue("QtyPerPack", product.BundleQuantity);
            }

            if (existingProduct == null)
            {
                newProduct.Insert(parent);
            }

            if (!string.IsNullOrEmpty(product.ImageURL) && !string.IsNullOrEmpty(product.ThumbnailURL))
            {
                GetAndSaveProductImages(newProduct, product.ImageURL, product.ThumbnailURL);
            }
            else
            {
                RemoveProductImages(newProduct);
            }

            newProduct.Update();

            return(newProduct);
        }
        /// <summary>
        /// Creates a new product model with variants.
        /// </summary>
        /// <param name="productPage">Product's page.</param>
        /// <param name="priceDetail">Price of the selected variant.</param>
        /// <param name="variants">Collection of selectable variants.</param>
        /// <param name="selectedVariantID">ID of the selected variant.</param>
        public ProductViewModel(SKUTreeNode productPage, ProductCatalogPrices priceDetail, List <ProductVariant> variants, int selectedVariantID)
            : this(productPage, priceDetail)
        {
            // Fills the selectable variants
            HasProductVariants = variants.Any();

            // Continues if the product has any variants
            if (HasProductVariants)
            {
                // Selects a default variant
                var selectedVariant = variants.FirstOrDefault(v => v.Variant.SKUID == selectedVariantID);

                if (selectedVariant != null)
                {
                    IsInStock         = (selectedVariant.Variant.SKUTrackInventory == TrackInventoryTypeEnum.Disabled) || (selectedVariant.Variant.SKUAvailableItems > 0);
                    SelectedVariantID = selectedVariantID;
                }

                // Creates a list of product variants
                VariantSelectList = new SelectList(variants.Select(v => new SelectListItem
                {
                    Text  = string.Join(", ", v.ProductAttributes.Select(a => a.SKUName)),
                    Value = v.Variant.SKUID.ToString()
                }), "Value", "Text");
            }
        }
示例#6
0
        private Variant GetCheapestVariant(SKUTreeNode product)
        {
            var variants        = mVariantRepository.GetByProductId(product.NodeSKUID).OrderBy(v => v.VariantPrice).ToList();
            var cheapestVariant = variants.FirstOrDefault();

            return(cheapestVariant);
        }
示例#7
0
        //EndDocSection:Constructor


        //DocSection:DisplayProduct
        /// <summary>
        /// Displays a product detail page of a product specified by the GUID of the product's page.
        /// </summary>
        /// <param name="guid">Node GUID of the product's page.</param>
        /// <param name="productAlias">Node alias of the product's page.</param>
        public ActionResult BasicDetail(Guid guid, string productAlias)
        {
            // Gets the product from the connected Kentico database
            SKUTreeNode product = GetProduct(guid);

            // If the product is not found or if it is not allowed for sale, redirects to error 404
            if ((product == null) || (product.SKU == null) || !product.SKU.SKUEnabled)
            {
                return(HttpNotFound());
            }

            // Redirects if the specified page alias does not match
            if (!string.IsNullOrEmpty(productAlias) && !product.NodeAlias.Equals(productAlias, StringComparison.InvariantCultureIgnoreCase))
            {
                return(RedirectToActionPermanent("Detail", new { guid = product.NodeGUID, productAlias = product.NodeAlias }));
            }

            // Initializes the view model of the product with a calculated price
            ShoppingCartInfo cart = shoppingService.GetCurrentShoppingCart();

            ProductCatalogPrices price = calculatorFactory
                                         .GetCalculator(cart.ShoppingCartSiteID)
                                         .GetPrices(product.SKU, Enumerable.Empty <SKUInfo>(), cart);

            // Fills the product model with retrieved data
            ProductViewModel viewModel = new ProductViewModel(product, price);

            // Displays the product details page
            return(View(viewModel));
        }
示例#8
0
 public SearchResultProductItemModel(SearchResultItem resultItem, SKUTreeNode page, ProductCatalogPrices priceDetail, IPageUrlRetriever pageUrlRetriever)
     : base(resultItem, page, pageUrlRetriever)
 {
     Description      = page.DocumentSKUDescription;
     ShortDescription = HTMLHelper.StripTags(page.DocumentSKUShortDescription, false);
     PriceDetail      = priceDetail;
 }
        /// <summary>
        /// Process added product in Recombee.
        /// </summary>
        /// <param name="productPage">Product page.</param>
        public void AddProduct(SKUTreeNode productPage)
        {
            if (productPage is null)
            {
                throw new ArgumentNullException(nameof(productPage));
            }

            UpdateProduct(productPage);
        }
        /// <summary>
        /// Updates given product from recombee database.
        /// </summary>
        /// <param name="user">Product to update.</param>
        public void UpdateProduct(SKUTreeNode productPage)
        {
            if (productPage is null)
            {
                throw new ArgumentNullException(nameof(productPage));
            }

            recombeeClientService.UpdateProduct(productPage);
        }
        private static void AttachThumbnail(SKUTreeNode product, string fromUrl)
        {
            var newAttachment = DownloadAttachmentThumbnail(product, fromUrl);

            if (newAttachment != null)
            {
                product.SetValue("ProductThumbnail", newAttachment.AttachmentGUID);
            }
        }
        private static AttachmentInfo DownloadAttachmentThumbnail(SKUTreeNode product, string fromUrl)
        {
            if (product.SKU == null)
            {
                throw new ArgumentNullException(nameof(product.SKU));
            }

            using (var client = new HttpClient())
            {
                using (var request = new HttpRequestMessage(HttpMethod.Get, fromUrl))
                {
                    using (var response = client.SendAsync(request).Result)
                    {
                        if (response.StatusCode == System.Net.HttpStatusCode.OK)
                        {
                            var mimetype = response.Content?.Headers?.ContentType?.MediaType ?? string.Empty;

                            if (!mimetype.StartsWith("image/"))
                            {
                                throw new Exception("Thumbnail is not of image MIME type");
                            }

                            var stream = response.Content.ReadAsStreamAsync().Result;

                            var extension = Path.GetExtension(fromUrl);

                            if (string.IsNullOrEmpty(extension) && mimetype.StartsWith("image/"))
                            {
                                extension = mimetype.Split('/')[1];
                            }

                            // attach file as page attachment and set it's GUID as ProductThumbnail (of type guid) property of  Product
                            var newAttachment = new AttachmentInfo()
                            {
                                InputStream            = stream,
                                AttachmentSiteID       = product.NodeSiteID,
                                AttachmentDocumentID   = product.DocumentID,
                                AttachmentExtension    = extension,
                                AttachmentName         = $"Thumbnail{product.SKU.GetStringValue("SKUProductCustomerReferenceNumber", product.SKU.SKUNumber)}.{extension}",
                                AttachmentLastModified = DateTime.Now,
                                AttachmentMimeType     = mimetype,
                                AttachmentSize         = (int)stream.Length
                            };

                            AttachmentInfoProvider.SetAttachmentInfo(newAttachment);

                            return(newAttachment);
                        }
                        else
                        {
                            throw new Exception("Failed to download thumbnail image");
                        }
                    }
                }
            }
        }
 /// <summary>
 /// Gets ViewModel for <paramref name="product"/>.
 /// </summary>
 /// <param name="product">Product.</param>
 /// <returns>Hydrated ViewModel.</returns>
 public static ProductCardViewModel GetViewModel(SKUTreeNode product)
 {
     return(product == null
         ? new ProductCardViewModel()
         : new ProductCardViewModel
     {
         Heading = product.DocumentSKUName,
         Image = product.SKU.SKUImagePath,
         Text = product.DocumentSKUShortDescription
     });
 }
示例#14
0
 /// <summary>
 /// Gets ViewModel for <paramref name="product"/>.
 /// </summary>
 /// <param name="product">Product.</param>
 /// <returns>Hydrated ViewModel.</returns>
 public static ProductCardViewModel GetViewModel(SKUTreeNode product)
 {
     return(product == null
         ? new ProductCardViewModel()
         : new ProductCardViewModel
     {
         Heading = product.DocumentSKUName,
         ImagePath = string.IsNullOrEmpty(product.SKU.SKUImagePath) ? null : new FileUrl(product.SKU.SKUImagePath, true).WithSizeConstraint(SizeConstraint.MaxWidthOrHeight(300)).RelativePath,
         Text = product.DocumentSKUShortDescription
     });
 }
示例#15
0
        public SearchResultProductItemModel(SearchResultItem resultItem, SKUTreeNode skuTreeNode, ProductCatalogPrices priceDetail)
            : base(resultItem, skuTreeNode)
        {
            Description      = skuTreeNode.DocumentSKUDescription;
            ShortDescription = HTMLHelper.StripTags(skuTreeNode.DocumentSKUShortDescription, false);
            PriceDetail      = priceDetail;

            var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);

            Url = urlHelper.Action("Detail", "Product",
                                   new { guid = skuTreeNode.NodeGUID, productAlias = skuTreeNode.NodeAlias });
        }
示例#16
0
        /// <summary>
        /// Deletes given product from recombee database.
        /// </summary>
        /// <param name="user">Product to delete.</param>
        public void Delete(SKUTreeNode productPage)
        {
            var deleteRequest = new DeleteItem(productPage.DocumentGUID.ToString());

            try
            {
                client.Send(deleteRequest);
            }
            catch (Exception ex)
            {
                Service.Resolve <IEventLogService>().LogException("RecombeeAdminModule", "ON_PRODUCT_DELETE", ex);
            }
        }
示例#17
0
        private string GetProductStatus(SKUTreeNode accessory)
        {
            if (accessory is FilterPack filterPack)
            {
                return(filterPack.Product.PublicStatus?.PublicStatusDisplayName);
            }

            if (accessory is Tableware tableware)
            {
                return(tableware.Product.PublicStatus?.PublicStatusDisplayName);
            }

            return(string.Empty);
        }
        private static void RemoveTumbnail(SKUTreeNode product)
        {
            var oldAttachmentGuid = product.GetGuidValue("ProductThumbnail", Guid.Empty);
            var siteName          = (product.Site ?? SiteInfoProvider.GetSiteInfo(product.NodeSiteID)).SiteName;

            if (oldAttachmentGuid != Guid.Empty)
            {
                var oldAttachment = AttachmentInfoProvider.GetAttachmentInfo(oldAttachmentGuid, siteName);
                if (oldAttachment != null)
                {
                    AttachmentInfoProvider.DeleteAttachmentInfo(oldAttachment);
                }
            }
        }
示例#19
0
        /// <summary>
        /// Creates an instance of the <see cref="RecommendedProductViewModel"/> view model-
        /// </summary>
        /// <param name="productPage">Product page.</param>
        /// <param name="priceDetail">Price.</param>
        public RecommendedProductViewModel(SKUTreeNode productPage, ProductCatalogPrices priceDetail)
        {
            // Set page information
            Name             = productPage.DocumentName;
            ProductPageGUID  = productPage.NodeGUID;
            ProductPageAlias = productPage.NodeAlias;

            // Set SKU information
            ImagePath = productPage.SKU.SKUImagePath;
            Available = !productPage.SKU.SKUSellOnlyAvailable || productPage.SKU.SKUAvailableItems > 0;

            // Set additional info
            PriceDetail = priceDetail;
        }
示例#20
0
        private string GetProductStatus(SKUTreeNode grinder)
        {
            if (grinder is ManualGrinder manualGrinder)
            {
                return(manualGrinder.Product.PublicStatus?.PublicStatusDisplayName);
            }

            if (grinder is ElectricGrinder electricGrinder)
            {
                return(electricGrinder.Product.PublicStatus?.PublicStatusDisplayName);
            }

            return(string.Empty);
        }
        public ProductListItemViewModel(SKUTreeNode productPage, ProductCatalogPrices priceDetail, string publicStatusName, IPageUrlRetriever pageUrlRetriever)
        {
            // Set page information
            Name = productPage.DocumentName;
            Url  = pageUrlRetriever.Retrieve(productPage).RelativePath;

            // Set SKU information
            ImagePath        = string.IsNullOrEmpty(productPage.SKU.SKUImagePath) ? null : new FileUrl(productPage.SKU.SKUImagePath, true).WithSizeConstraint(SizeConstraint.Size(452, 452)).RelativePath;
            Available        = !productPage.SKU.SKUSellOnlyAvailable || productPage.SKU.SKUAvailableItems > 0;
            PublicStatusName = publicStatusName;

            // Set additional info
            PriceDetail = priceDetail;
        }
 private void SetProductItemSpecs(ref SKUTreeNode newProduct, CampaignProductDto product)
 {
     if (!string.IsNullOrWhiteSpace(product.ItemSpecs))
     {
         ProductItemSpecsItem itemSpecs = CustomTableItemProvider.GetItems <ProductItemSpecsItem>().WhereEquals("ItemSpec", product.ItemSpecs);
         if (itemSpecs != null)
         {
             newProduct.SetValue("ItemSpecs", itemSpecs.ItemID);
         }
     }
     if (!string.IsNullOrWhiteSpace(product.CustomItemSpecs))
     {
         newProduct.SetValue("CustomItemSpecs", product.CustomItemSpecs);
     }
 }
        public ProductListItemViewModel(SKUTreeNode productPage, ProductCatalogPrices priceDetail, string publicStatusName)
        {
            // Set page information
            Name             = productPage.DocumentName;
            ProductPageGUID  = productPage.NodeGUID;
            ProductPageAlias = productPage.NodeAlias;

            // Set SKU information
            ImagePath        = productPage.SKU.SKUImagePath;
            Available        = !productPage.SKU.SKUSellOnlyAvailable || productPage.SKU.SKUAvailableItems > 0;
            PublicStatusName = publicStatusName;

            // Set additional info
            PriceDetail = priceDetail;
        }
示例#24
0
        /// <summary>
        /// Updates given product <paramref name="productPage"/> in Recombee database.
        /// </summary>
        /// <param name="productPage">Product to update.</param>
        public void UpdateProduct(SKUTreeNode productPage)
        {
            var updateRequest = new SetItemValues(
                productPage.DocumentGUID.ToString(),
                ProductMapper.Map(productPage),
                true);

            try
            {
                client.Send(updateRequest);
            }
            catch (Exception ex)
            {
                Service.Resolve <IEventLogService>().LogException("RecombeeAdminModule", "ON_PRODUCT_CREATED", ex);
            }
        }
        // ready for potential use in Product upload
        private static void GetAndSaveProductImages(SKUTreeNode product, string imageUrl, string thumbnailUrl)
        {
            var library = new MediaLibrary
            {
                SiteId             = product.NodeSiteID,
                LibraryName        = "ProductImages",
                LibraryFolder      = "Products",
                LibraryDescription = "Media library for storing product images"
            };
            var libraryImageUrl = library.DownloadImageToMedialibrary(imageUrl, $"Image{product.SKU.SKUNumber}", $"Product image for SKU {product.SKU.SKUNumber}");

            product.RemoveImage();
            product.SetImage(libraryImageUrl);
            RemoveTumbnail(product);
            AttachThumbnail(product, thumbnailUrl);
        }
示例#26
0
        public ProductViewModel(SKUTreeNode productPage, ProductPrice price,
                                ITypedProductViewModel typedProductViewModel, Variant defaultVariant,
                                IEnumerable <ProductOptionCategoryViewModel> categories)
            : this(productPage, price, typedProductViewModel)
        {
            if (defaultVariant == null)
            {
                throw new ArgumentNullException(nameof(defaultVariant));
            }

            IsInStock         = !defaultVariant.InventoryTracked || defaultVariant.AvailableItems > 0;
            SelectedVariantID = defaultVariant.VariantSKUID;

            // Variant categories which will be rendered
            ProductOptionCategories = categories;
        }
            public void SetUp()
            {
                Fake <SKUInfo, SKUInfoProvider>().WithData(sku = new SKUInfo
                {
                    SKUID = SKU_ID
                }, variant = new SKUInfo
                {
                    SKUID = VARIANT_ID
                });
                Fake <VariantOptionInfo, VariantOptionInfoProvider>().WithData();

                page = Substitute.For <SKUTreeNode>();

                retiever          = Substitute.For <IPageDataContextRetriever>();
                variantRepository = Substitute.For <IVariantRepository>();
                controller        = new ProductController(retiever, null, variantRepository, null, null, SKUInfo.Provider);
            }
示例#28
0
        public ProductViewModel(SKUTreeNode productPage, ProductCatalogPrices price,
                                ITypedProductViewModel typedProductViewModel, ProductVariant defaultVariant,
                                IEnumerable <ProductOptionCategoryViewModel> categories)
            : this(productPage, price, typedProductViewModel)
        {
            if (defaultVariant == null)
            {
                throw new ArgumentNullException(nameof(defaultVariant));
            }

            var variant = defaultVariant.Variant;

            IsInStock         = ((variant.SKUTrackInventory == TrackInventoryTypeEnum.Disabled) || (variant.SKUAvailableItems > 0));
            SelectedVariantID = variant.SKUID;

            // Variant categories which will be rendered
            ProductOptionCategories = categories;
        }
        /// <summary>
        /// Maps <paramref name="productPage"/> to Recombee structure.
        /// </summary>
        /// <param name="productPage">Product page.</param>
        public static Dictionary <string, object> Map(SKUTreeNode productPage)
        {
            if (productPage is null)
            {
                throw new ArgumentNullException(nameof(productPage));
            }

            return(new Dictionary <string, object>
            {
                { "Name", productPage.DocumentSKUName },
                { "Description", productPage.DocumentSKUShortDescription },
                { "Content", productPage.DocumentSKUDescription },
                { "Culture", productPage.DocumentCulture },
                { "ClassName", productPage.ClassName },
                { "Price", productPage.SKU.SKUPrice },
                { "Type", "Product" },
            });
        }
示例#30
0
        /// <summary>
        /// Creates a new product model.
        /// </summary>
        /// <param name="productPage">Product's page.</param>
        /// <param name="priceDetail">Price of the product.</param>
        public ProductViewModel(SKUTreeNode productPage, ProductPrice priceDetail)
        {
            // Fills the page information
            Name             = productPage.DocumentName;
            Description      = productPage.DocumentSKUDescription;
            ShortDescription = productPage.DocumentSKUShortDescription;
            ProductPageID    = productPage.NodeID;
            ProductPageAlias = productPage.NodeAlias;

            // Fills the SKU information
            SKUInfo sku = productPage.SKU;

            SKUID     = sku.SKUID;
            ImagePath = sku.SKUImagePath;
            IsInStock = sku.SKUTrackInventory == TrackInventoryTypeEnum.Disabled ||
                        sku.SKUAvailableItems > 0;

            PriceDetail = priceDetail;
        }