From 9a4c2c37649409b06afa510eb73739be893b35a3 Mon Sep 17 00:00:00 2001 From: KrzysztofPajak Date: Tue, 28 Apr 2020 11:51:14 +0200 Subject: [PATCH] Add new field - ShowOnCatalogPage on ProductAttributeMapping --- .../Domain/Catalog/ProductAttributeMapping.cs | 5 + .../Catalog/ProductAttributeService.cs | 1 + Grand.Services/Catalog/ProductExtensions.cs | 80 +------------ .../Upgrade/EN_460_470.nopres.xml | 6 + .../defaultResources.grandres.xml | 6 + .../ProductAttributeCombinationModel.cs | 5 - .../Admin/Models/Catalog/ProductModel.cs | 4 +- .../Admin/Services/ProductViewModelService.cs | 1 + .../ProductAttributeMappingPopup.cshtml | 12 +- ...roductAttributeValidationRulesPopup.cshtml | 4 +- ...ate.ProductAttributes.TabAttributes.cshtml | 72 +---------- .../Catalog/GetFormatBasePriceHandler.cs | 68 +++++++++++ .../Catalog/GetProductAttributeHandler.cs | 28 +++++ .../Products/GetProductDetailsPageHandler.cs | 6 +- .../Products/GetProductOverviewHandler.cs | 113 ++++++++++++------ .../Models/Catalog/GetFormatBasePrice.cs | 12 ++ .../Models/Catalog/GetProductAttribute.cs | 10 ++ .../Models/Catalog/ProductOverviewModel.cs | 32 +++++ Grand.Web/Views/Shared/_ProductBox.cshtml | 53 ++++++++ 19 files changed, 325 insertions(+), 193 deletions(-) create mode 100644 Grand.Web/Features/Handlers/Catalog/GetFormatBasePriceHandler.cs create mode 100644 Grand.Web/Features/Handlers/Catalog/GetProductAttributeHandler.cs create mode 100644 Grand.Web/Features/Models/Catalog/GetFormatBasePrice.cs create mode 100644 Grand.Web/Features/Models/Catalog/GetProductAttribute.cs diff --git a/Grand.Core/Domain/Catalog/ProductAttributeMapping.cs b/Grand.Core/Domain/Catalog/ProductAttributeMapping.cs index 489a2cc96c..ef0e03be65 100644 --- a/Grand.Core/Domain/Catalog/ProductAttributeMapping.cs +++ b/Grand.Core/Domain/Catalog/ProductAttributeMapping.cs @@ -34,6 +34,11 @@ public ProductAttributeMapping() /// public bool IsRequired { get; set; } + /// + /// Gets or sets whether the attribute will be shown on the catalog page + /// + public bool ShowOnCatalogPage { get; set; } + /// /// Gets or sets the attribute control type identifier /// diff --git a/Grand.Services/Catalog/ProductAttributeService.cs b/Grand.Services/Catalog/ProductAttributeService.cs index 111d204723..a914c1a275 100644 --- a/Grand.Services/Catalog/ProductAttributeService.cs +++ b/Grand.Services/Catalog/ProductAttributeService.cs @@ -260,6 +260,7 @@ public virtual async Task UpdateProductAttributeMapping(ProductAttributeMapping .Set(x => x.ProductAttributeMappings.ElementAt(-1).ProductAttributeId, productAttributeMapping.ProductAttributeId) .Set(x => x.ProductAttributeMappings.ElementAt(-1).TextPrompt, productAttributeMapping.TextPrompt) .Set(x => x.ProductAttributeMappings.ElementAt(-1).IsRequired, productAttributeMapping.IsRequired) + .Set(x => x.ProductAttributeMappings.ElementAt(-1).ShowOnCatalogPage, productAttributeMapping.ShowOnCatalogPage) .Set(x => x.ProductAttributeMappings.ElementAt(-1).AttributeControlTypeId, productAttributeMapping.AttributeControlTypeId) .Set(x => x.ProductAttributeMappings.ElementAt(-1).DisplayOrder, productAttributeMapping.DisplayOrder) .Set(x => x.ProductAttributeMappings.ElementAt(-1).ValidationMinLength, productAttributeMapping.ValidationMinLength) diff --git a/Grand.Services/Catalog/ProductExtensions.cs b/Grand.Services/Catalog/ProductExtensions.cs index 6824c26a87..7c44275582 100644 --- a/Grand.Services/Catalog/ProductExtensions.cs +++ b/Grand.Services/Catalog/ProductExtensions.cs @@ -1,12 +1,9 @@ -using Grand.Core; using Grand.Core.Domain.Catalog; using Grand.Core.Domain.Customers; -using Grand.Services.Directory; using Grand.Services.Localization; using System; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; namespace Grand.Services.Catalog { @@ -39,7 +36,7 @@ public static TierPrice GetPreferredTierPrice(this Product product, Customer cus var tierPrice = actualTierPrices.LastOrDefault(price => quantity >= price.Quantity); return tierPrice; - } + } /// /// Formats the stock availability/quantity message @@ -140,7 +137,7 @@ public static string FormatStockMessage(this Product product, string warehouseId default: break; } - if(!combination.AllowOutOfStockOrders) + if (!combination.AllowOutOfStockOrders) stockMessage = localizationService.GetResource("Products.Availability.Attributes.OutOfStock"); } } @@ -199,7 +196,7 @@ public static int[] ParseAllowedQuantities(this Product product) if (!String.IsNullOrWhiteSpace(product.AllowedQuantities)) { product.AllowedQuantities - .Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries) + .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .ToList() .ForEach(qtyStr => { @@ -227,7 +224,7 @@ public static int[] ParseAllowedQuantities(this Product product) /// Used only with "multiple warehouses" enabled. /// /// Result - public static int GetTotalStockQuantity(this Product product, + public static int GetTotalStockQuantity(this Product product, bool useReservedQuantity = true, string warehouseId = "") { if (product == null) @@ -320,7 +317,7 @@ public static int GetTotalStockQuantityForCombination(this Product product, Prod } - + /// /// Gets SKU, Manufacturer part number and GTIN @@ -341,7 +338,7 @@ private static void GetSkuMpnGtin(this Product product, string attributesXml, IP manufacturerPartNumber = null; gtin = null; - if (!String.IsNullOrEmpty(attributesXml) && + if (!String.IsNullOrEmpty(attributesXml) && product.ManageInventoryMethod == ManageInventoryMethod.ManageStockByAttributes) { //manage stock by attribute combinations @@ -431,70 +428,5 @@ public static string FormatGtin(this Product product, string attributesXml = nul return gtin; } - - - /// - /// Format base price (PAngV) - /// - /// Product - /// Product price (in primary currency). Pass null if you want to use a default produce price - /// Localization service - /// Measure service - /// Currency service - /// Work context - /// Price formatter - /// Base price - public static async Task FormatBasePrice(this Product product, decimal? productPrice, ILocalizationService localizationService, - IMeasureService measureService, ICurrencyService currencyService, - IWorkContext workContext, IPriceFormatter priceFormatter) - { - if (product == null) - throw new ArgumentNullException("product"); - - if (localizationService == null) - throw new ArgumentNullException("localizationService"); - - if (measureService == null) - throw new ArgumentNullException("measureService"); - - if (currencyService == null) - throw new ArgumentNullException("currencyService"); - - if (workContext == null) - throw new ArgumentNullException("workContext"); - - if (priceFormatter == null) - throw new ArgumentNullException("priceFormatter"); - - if (!product.BasepriceEnabled) - return null; - - var productAmount = product.BasepriceAmount; - //Amount in product cannot be 0 - if (productAmount == 0) - return null; - var referenceAmount = product.BasepriceBaseAmount; - var productUnit = await measureService.GetMeasureWeightById(product.BasepriceUnitId); - //measure weight cannot be loaded - if (productUnit == null) - return null; - var referenceUnit = await measureService.GetMeasureWeightById(product.BasepriceBaseUnitId); - //measure weight cannot be loaded - if (referenceUnit == null) - return null; - - productPrice = productPrice.HasValue ? productPrice.Value : product.Price; - - decimal basePrice = productPrice.Value / - //do not round. otherwise, it can cause issues - await measureService.ConvertWeight(productAmount, productUnit, referenceUnit, false) * - referenceAmount; - decimal basePriceInCurrentCurrency = await currencyService.ConvertFromPrimaryStoreCurrency(basePrice, workContext.WorkingCurrency); - string basePriceStr = priceFormatter.FormatPrice(basePriceInCurrentCurrency, true, false); - - var result = string.Format(localizationService.GetResource("Products.BasePrice"), - basePriceStr, referenceAmount.ToString("G29"), referenceUnit.Name); - return result; - } } } diff --git a/Grand.Web/App_Data/Localization/Upgrade/EN_460_470.nopres.xml b/Grand.Web/App_Data/Localization/Upgrade/EN_460_470.nopres.xml index 26a959e2c1..3e433c8fcd 100644 --- a/Grand.Web/App_Data/Localization/Upgrade/EN_460_470.nopres.xml +++ b/Grand.Web/App_Data/Localization/Upgrade/EN_460_470.nopres.xml @@ -363,5 +363,11 @@ Set a search engine friendly name. Leave empty to generate it automatically based on the name of the attribute. + + Show attribute on product catalog pages + + + Check to show in public store on catalog pages. + diff --git a/Grand.Web/App_Data/Localization/defaultResources.grandres.xml b/Grand.Web/App_Data/Localization/defaultResources.grandres.xml index 8ea5524898..429b1f7fcd 100644 --- a/Grand.Web/App_Data/Localization/defaultResources.grandres.xml +++ b/Grand.Web/App_Data/Localization/defaultResources.grandres.xml @@ -4315,6 +4315,12 @@ Text prompt + + Show attribute on product catalog pages + + + Check to show in public store on catalog pages. + Validation rules diff --git a/Grand.Web/Areas/Admin/Models/Catalog/ProductAttributeCombinationModel.cs b/Grand.Web/Areas/Admin/Models/Catalog/ProductAttributeCombinationModel.cs index 2042514a32..daab5cded3 100644 --- a/Grand.Web/Areas/Admin/Models/Catalog/ProductAttributeCombinationModel.cs +++ b/Grand.Web/Areas/Admin/Models/Catalog/ProductAttributeCombinationModel.cs @@ -70,15 +70,10 @@ public ProductAttributeModel() } public string ProductAttributeId { get; set; } - public string Name { get; set; } - public string TextPrompt { get; set; } - public bool IsRequired { get; set; } - public AttributeControlType AttributeControlType { get; set; } - public IList Values { get; set; } } diff --git a/Grand.Web/Areas/Admin/Models/Catalog/ProductModel.cs b/Grand.Web/Areas/Admin/Models/Catalog/ProductModel.cs index c68cdc3743..789b2a5cbc 100644 --- a/Grand.Web/Areas/Admin/Models/Catalog/ProductModel.cs +++ b/Grand.Web/Areas/Admin/Models/Catalog/ProductModel.cs @@ -965,12 +965,12 @@ public ProductAttributeMappingModel() public IList AvailableProductAttribute { get; set; } [GrandResourceDisplayName("Admin.Catalog.Products.ProductAttributes.Attributes.Fields.TextPrompt")] - public string TextPrompt { get; set; } [GrandResourceDisplayName("Admin.Catalog.Products.ProductAttributes.Attributes.Fields.IsRequired")] public bool IsRequired { get; set; } - + [GrandResourceDisplayName("Admin.Catalog.Products.ProductAttributes.Attributes.Fields.ShowOnCatalogPage")] + public bool ShowOnCatalogPage { get; set; } public int AttributeControlTypeId { get; set; } [GrandResourceDisplayName("Admin.Catalog.Products.ProductAttributes.Attributes.Fields.AttributeControlType")] public string AttributeControlType { get; set; } diff --git a/Grand.Web/Areas/Admin/Services/ProductViewModelService.cs b/Grand.Web/Areas/Admin/Services/ProductViewModelService.cs index 0a5fb69732..ea2f55c98d 100644 --- a/Grand.Web/Areas/Admin/Services/ProductViewModelService.cs +++ b/Grand.Web/Areas/Admin/Services/ProductViewModelService.cs @@ -2139,6 +2139,7 @@ public virtual async Task DeleteBulkEdit(IList products) ProductAttributeId = x.ProductAttributeId, TextPrompt = x.TextPrompt, IsRequired = x.IsRequired, + ShowOnCatalogPage = x.ShowOnCatalogPage, AttributeControlType = x.AttributeControlType.GetLocalizedEnum(_localizationService, _workContext), AttributeControlTypeId = x.AttributeControlTypeId, DisplayOrder = x.DisplayOrder diff --git a/Grand.Web/Areas/Admin/Views/Product/ProductAttributeMappingPopup.cshtml b/Grand.Web/Areas/Admin/Views/Product/ProductAttributeMappingPopup.cshtml index ccc75949e4..ae674c3647 100644 --- a/Grand.Web/Areas/Admin/Views/Product/ProductAttributeMappingPopup.cshtml +++ b/Grand.Web/Areas/Admin/Views/Product/ProductAttributeMappingPopup.cshtml @@ -54,11 +54,21 @@
+
+ +
+ + +
+
diff --git a/Grand.Web/Areas/Admin/Views/Product/ProductAttributeValidationRulesPopup.cshtml b/Grand.Web/Areas/Admin/Views/Product/ProductAttributeValidationRulesPopup.cshtml index 5b82acdfcb..08c1df6087 100644 --- a/Grand.Web/Areas/Admin/Views/Product/ProductAttributeValidationRulesPopup.cshtml +++ b/Grand.Web/Areas/Admin/Views/Product/ProductAttributeValidationRulesPopup.cshtml @@ -39,14 +39,14 @@
- ) +
- ) +
diff --git a/Grand.Web/Areas/Admin/Views/Product/_CreateOrUpdate.ProductAttributes.TabAttributes.cshtml b/Grand.Web/Areas/Admin/Views/Product/_CreateOrUpdate.ProductAttributes.TabAttributes.cshtml index 2faa028d13..ebdba69e49 100644 --- a/Grand.Web/Areas/Admin/Views/Product/_CreateOrUpdate.ProductAttributes.TabAttributes.cshtml +++ b/Grand.Web/Areas/Admin/Views/Product/_CreateOrUpdate.ProductAttributes.TabAttributes.cshtml @@ -1,5 +1,4 @@ @model ProductModel -@using Grand.Core.Domain.Catalog
@@ -111,28 +110,14 @@ field: "AttributeControlTypeId", title: "@T("Admin.Catalog.Products.ProductAttributes.Attributes.Fields.AttributeControlType")", width: 140, - editor: attributeControlTypeDropDownEditor, - template: "#:AttributeControlType#" + template: "#:AttributeControlType#
# if(ValidationRulesAllowed) {# @T("Admin.Catalog.Products.ProductAttributes.Attributes.ValidationRules.ViewLink")
#=ValidationRulesString# #} #" }, { - field: "DisplayOrder", - title: "@T("Admin.Catalog.Products.ProductAttributes.Attributes.Fields.DisplayOrder")", - width: 70, - headerAttributes: { style: "text-align:center" }, - attributes: { style: "text-align:center" }, - //integer format - format: "{0:0}" - }, { field: "ShouldHaveValues", title: "@T("Admin.Catalog.Products.ProductAttributes.Attributes.Values")", width: 60, template: '# if(ShouldHaveValues) {# @T("Admin.Catalog.Products.ProductAttributes.Attributes.Values.ViewLink")
@T("Admin.Catalog.Products.ProductAttributes.Attributes.Values.TotalValues") #=TotalValues# #} #' }, - { - field: "ValidationRulesAllowed", - title: "@T("Admin.Catalog.Products.ProductAttributes.Attributes.ValidationRules")", - width: 80, - template: "# if(ValidationRulesAllowed) {# @T("Admin.Catalog.Products.ProductAttributes.Attributes.ValidationRules.ViewLink")
#=ValidationRulesString# #} #"}, { field: "ConditionAllowed", title: "@T("Admin.Catalog.Products.ProductAttributes.Attributes.Condition")", @@ -152,62 +137,7 @@ }); }); - //local datasource - var allProductAttributes = [ - @for (int i = 0; i < Model.AvailableProductAttributes.Count; i++) - { - var productAttributeItem = Model.AvailableProductAttributes[i]; - - { - Id: '@(productAttributeItem.Value)', - Name: "@(Html.Raw(System.Text.Encodings.Web.JavaScriptEncoder.Default.Encode(productAttributeItem.Text)))" - } - - if (i != Model.AvailableProductAttributes.Count - 1) - { - , - } - } - ]; - - var allAttributeControlTypes = [ - @{ - var allAttributeControlTypes = (from act in AttributeControlType.DropdownList.ToSelectList(Context) - select new {Id = act.Value, Name = act.Text}).ToList(); - } - @for (int i = 0; i < allAttributeControlTypes.Count; i++) - { - var attributeControlType = allAttributeControlTypes[i]; - - { - Id: '@(attributeControlType.Id)', - Name: "@(Html.Raw(System.Text.Encodings.Web.JavaScriptEncoder.Default.Encode(attributeControlType.Name)))" - } - - if (i != allAttributeControlTypes.Count - 1) - { - , - } - } - ]; - - function productAttributeDropDownEditor(container, options) { - $('') - .appendTo(container) - .kendoDropDownList({ - autoBind: true, - dataSource: allProductAttributes - }); - } - function attributeControlTypeDropDownEditor(container, options) { - $('') - .appendTo(container) - .kendoDropDownList({ - autoBind: true, - dataSource: allAttributeControlTypes - }); - }