diff --git a/src/Modules/Grand.Module.Installer/Extensions/PermissionExtensions.cs b/src/Modules/Grand.Module.Installer/Extensions/PermissionExtensions.cs index f998b7cb9..729f88c5b 100644 --- a/src/Modules/Grand.Module.Installer/Extensions/PermissionExtensions.cs +++ b/src/Modules/Grand.Module.Installer/Extensions/PermissionExtensions.cs @@ -211,6 +211,7 @@ public static IEnumerable DefaultPermissions() StandardPermission.ManagePaymentTransactions, StandardPermission.ManageShipments, StandardPermission.ManageMerchandiseReturns, + StandardPermission.ManageCheckoutAttribute, StandardPermission.ManageReports ] }, diff --git a/src/Web/Grand.Web.AdminShared/Interfaces/ICheckoutAttributeViewModelService.cs b/src/Web/Grand.Web.AdminShared/Interfaces/ICheckoutAttributeViewModelService.cs index fa71218a2..f79ea7052 100644 --- a/src/Web/Grand.Web.AdminShared/Interfaces/ICheckoutAttributeViewModelService.cs +++ b/src/Web/Grand.Web.AdminShared/Interfaces/ICheckoutAttributeViewModelService.cs @@ -5,7 +5,7 @@ namespace Grand.Web.AdminShared.Interfaces; public interface ICheckoutAttributeViewModelService { - Task> PrepareCheckoutAttributeListModel(); + Task> PrepareCheckoutAttributeListModel(string storeId = ""); Task> PrepareCheckoutAttributeValuesModel(string checkoutAttributeId); Task PrepareCheckoutAttributeModel(); Task PrepareCheckoutAttributeValueModel(string checkoutAttributeId); diff --git a/src/Web/Grand.Web.AdminShared/Services/CheckoutAttributeViewModelService.cs b/src/Web/Grand.Web.AdminShared/Services/CheckoutAttributeViewModelService.cs index 8871673e2..da4b224bb 100644 --- a/src/Web/Grand.Web.AdminShared/Services/CheckoutAttributeViewModelService.cs +++ b/src/Web/Grand.Web.AdminShared/Services/CheckoutAttributeViewModelService.cs @@ -27,9 +27,9 @@ public class CheckoutAttributeViewModelService( IEnumTranslationService enumTranslationService) : ICheckoutAttributeViewModelService { - public virtual async Task> PrepareCheckoutAttributeListModel() + public virtual async Task> PrepareCheckoutAttributeListModel(string storeId = "") { - var checkoutAttributes = await checkoutAttributeService.GetAllCheckoutAttributes(ignoreAcl: true); + var checkoutAttributes = await checkoutAttributeService.GetAllCheckoutAttributes(storeId: storeId, ignoreAcl: true); return checkoutAttributes.Select((Func)(x => { var attributeModel = x.ToModel(); diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/Create.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/Create.cshtml new file mode 100644 index 000000000..780ee3d3e --- /dev/null +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/Create.cshtml @@ -0,0 +1,37 @@ +@model CheckoutAttributeModel +@{ + //page title + ViewBag.Title = Loc["Admin.Orders.CheckoutAttributes.AddNew"]; +} +
+ +
+
+
+
+
+ + @Loc["Admin.Orders.CheckoutAttributes.AddNew"] + + @Html.ActionLink(Loc["Admin.Orders.CheckoutAttributes.BackToList"], "List") + +
+
+
+ + + +
+
+
+
+ +
+
+
+
+
\ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/Edit.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/Edit.cshtml new file mode 100644 index 000000000..34ab60b99 --- /dev/null +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/Edit.cshtml @@ -0,0 +1,42 @@ +@model CheckoutAttributeModel + +@{ + //page title + ViewBag.Title = Loc["Admin.Orders.CheckoutAttributes.EditAttributeDetails"]; +} +
+ +
+
+
+
+
+ + @Loc["Admin.Orders.CheckoutAttributes.EditAttributeDetails"] - @Model.Name + + @Html.ActionLink(Loc["Admin.Orders.CheckoutAttributes.BackToList"], "List") + +
+
+
+ + + + @Loc["Admin.Common.Delete"] + + +
+
+
+
+ +
+
+
+
+
+ \ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/List.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/List.cshtml new file mode 100644 index 000000000..da94020f9 --- /dev/null +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/List.cshtml @@ -0,0 +1,98 @@ +@{ + //page title + ViewBag.Title = Loc["Admin.Orders.CheckoutAttributes"]; +} + +
+
+
+
+
+ + @Loc["Admin.Orders.CheckoutAttributes"] +
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/Partials/CreateOrUpdate.TabCondition.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/Partials/CreateOrUpdate.TabCondition.cshtml new file mode 100644 index 000000000..3031f4945 --- /dev/null +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/Partials/CreateOrUpdate.TabCondition.cshtml @@ -0,0 +1,126 @@ +@model CheckoutAttributeModel + +@{ + if (!string.IsNullOrEmpty(Model.Id)) + { + + +
+
+
+ +
+ + +
+
+
+
+
+ @if (Model.ConditionModel.ConditionAttributes.Count > 0) + { +
+
+
+ +
+ + +
+
+
+ +
+ @for (var i = 0; i < Model.ConditionModel.ConditionAttributes.Count; i++) + { + +
+ @switch (Model.ConditionModel.ConditionAttributes[i].AttributeControlType) + { + case AttributeControlType.DropdownList: + + break; + case AttributeControlType.RadioList: + case AttributeControlType.ColorSquares: + case AttributeControlType.ImageSquares: + foreach (var value in Model.ConditionModel.ConditionAttributes[i].Values) + { +
+ + +
+ } + + break; + case AttributeControlType.Checkboxes: + for (var j = 0; j < Model.ConditionModel.ConditionAttributes[i].Values.Count; j++) + { +
+ +
+ } + + break; + case AttributeControlType.ReadonlyCheckboxes: + case AttributeControlType.TextBox: + case AttributeControlType.MultilineTextbox: + case AttributeControlType.Datepicker: + case AttributeControlType.FileUpload: + default: + //not supported as conditions + break; + } +
+ } +
+
+
+
+ } + else + { +
+ @Loc["Admin.Orders.CheckoutAttributes.Condition.NoAttributeExists"] +
+ } +
+ } + else + { +
+ @Loc["Admin.Orders.CheckoutAttributes.Condition.SaveBeforeEdit"] +
+ } +} + \ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/Partials/CreateOrUpdate.TabInfo.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/Partials/CreateOrUpdate.TabInfo.cshtml new file mode 100644 index 000000000..fd67f2a7f --- /dev/null +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/Partials/CreateOrUpdate.TabInfo.cshtml @@ -0,0 +1,201 @@ +@using Microsoft.AspNetCore.Mvc.Razor +@model CheckoutAttributeModel + + + + +@{ + Func + template = @
+
+ +
+ + +
+
+
+ +
+ + +
+
+ +
; +} + +
+ +
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ @{ + var attributeControlTypes = + EnumTranslationService.ToSelectList(((AttributeControlType)Model.AttributeControlTypeId), valuesToExclude: [(int)AttributeControlType.ImageSquares, (int)AttributeControlType.Hidden]); + } + + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+ \ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/Partials/CreateOrUpdate.TabValues.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/Partials/CreateOrUpdate.TabValues.cshtml new file mode 100644 index 000000000..183bbbbd8 --- /dev/null +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/Partials/CreateOrUpdate.TabValues.cshtml @@ -0,0 +1,146 @@ +@model CheckoutAttributeModel + +@{ + if (!string.IsNullOrEmpty(Model.Id)) + { + + + + + } + else + { +
+ @Loc["Admin.Orders.CheckoutAttributes.Values.SaveBeforeEdit"] +
+ } +} + \ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/Partials/CreateOrUpdate.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/Partials/CreateOrUpdate.cshtml new file mode 100644 index 000000000..29de17e25 --- /dev/null +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/Partials/CreateOrUpdate.cshtml @@ -0,0 +1,34 @@ +@model CheckoutAttributeModel + +
+ + + + + + +
+ +
+
+
+ + +
+ +
+
+
+ @if (Model.ConditionAllowed) + { + + +
+ +
+
+
+ } + +
+
\ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/Partials/CreateOrUpdateValue.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/Partials/CreateOrUpdateValue.cshtml new file mode 100644 index 000000000..e05bbca6f --- /dev/null +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/Partials/CreateOrUpdateValue.cshtml @@ -0,0 +1,95 @@ +@using Microsoft.AspNetCore.Mvc.Razor +@model CheckoutAttributeValueModel + +
+ + + + + + +@{ + Func + template = @
+
+ +
+ + +
+
+ +
; +} + +
+ +
+
+ +
+ + +
+
+
+
+
+ @if (Model.DisplayColorSquaresRgb) + { +
+ +
+ +
+ + +
+
+ } +
+ +
+ [@Model.PrimaryStoreCurrencyCode] + +
+
+
+ +
+ [@Model.BaseWeightIn] + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+ + +
+
+
+
+ \ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/ValueCreatePopup.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/ValueCreatePopup.cshtml new file mode 100644 index 000000000..816a1f3a9 --- /dev/null +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/ValueCreatePopup.cshtml @@ -0,0 +1,58 @@ +@{ + Layout = ""; +} + +@model CheckoutAttributeValueModel + +
+
+
+
+
+
+ + @Loc["Admin.Orders.CheckoutAttributes.Values.AddNew"] +
+
+ +
+
+
+ +
+
+
+
+ +
\ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/ValueEditPopup.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/ValueEditPopup.cshtml new file mode 100644 index 000000000..d5acf93a8 --- /dev/null +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/CheckoutAttribute/ValueEditPopup.cshtml @@ -0,0 +1,54 @@ +@model CheckoutAttributeValueModel +@{ + Layout = ""; +} +
+ +
+
+
+
+
+ + @Loc["Admin.Orders.CheckoutAttributes.Values.EditValueDetails"] +
+
+
+ +
+
+
+
+ +
\ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Controllers/CheckoutAttributeController.cs b/src/Web/Grand.Web.Store/Controllers/CheckoutAttributeController.cs new file mode 100644 index 000000000..d1510740d --- /dev/null +++ b/src/Web/Grand.Web.Store/Controllers/CheckoutAttributeController.cs @@ -0,0 +1,372 @@ +using Grand.Business.Core.Extensions; +using Grand.Business.Core.Interfaces.Catalog.Directory; +using Grand.Business.Core.Interfaces.Checkout.CheckoutAttributes; +using Grand.Business.Core.Interfaces.Common.Directory; +using Grand.Business.Core.Interfaces.Common.Localization; +using Grand.Domain.Catalog; +using Grand.Domain.Directory; +using Grand.Domain.Orders; +using Grand.Domain.Permissions; +using Grand.Infrastructure; +using Grand.Web.AdminShared.Extensions.Mapping; +using Grand.Web.AdminShared.Interfaces; +using Grand.Web.AdminShared.Models.Orders; +using Grand.Web.Common.DataSource; +using Grand.Web.Common.Filters; +using Grand.Web.Common.Security.Authorization; +using Microsoft.AspNetCore.Mvc; +using Grand.Web.AdminShared.Extensions; + +namespace Grand.Web.Store.Controllers; + +[PermissionAuthorize(PermissionSystemName.CheckoutAttributes)] +public class CheckoutAttributeController : BaseStoreController +{ + #region Constructors + + public CheckoutAttributeController(ICheckoutAttributeService checkoutAttributeService, + IContextAccessor contextAccessor, + ILanguageService languageService, + ITranslationService translationService, + ICurrencyService currencyService, + CurrencySettings currencySettings, + IMeasureService measureService, + MeasureSettings measureSettings, + ICheckoutAttributeViewModelService checkoutAttributeViewModelService) + { + _checkoutAttributeService = checkoutAttributeService; + _contextAccessor = contextAccessor; + _languageService = languageService; + _translationService = translationService; + _currencyService = currencyService; + _currencySettings = currencySettings; + _measureService = measureService; + _measureSettings = measureSettings; + _checkoutAttributeViewModelService = checkoutAttributeViewModelService; + } + + #endregion + + #region Fields + + private readonly ICheckoutAttributeService _checkoutAttributeService; + private readonly IContextAccessor _contextAccessor; + private readonly ILanguageService _languageService; + private readonly ITranslationService _translationService; + private readonly ICurrencyService _currencyService; + private readonly CurrencySettings _currencySettings; + private readonly IMeasureService _measureService; + private readonly MeasureSettings _measureSettings; + private readonly ICheckoutAttributeViewModelService _checkoutAttributeViewModelService; + + #endregion + + #region Helper Methods + + /// + /// Checks access permissions for a checkout attribute and handles warnings + /// + /// Checkout attribute to check + /// True if access is allowed, false if access should be denied + private bool CheckAccessPermission(CheckoutAttribute checkoutAttribute) + { + if (checkoutAttribute == null) + return false; + + if (!checkoutAttribute.LimitedToStores || (checkoutAttribute.LimitedToStores && + checkoutAttribute.Stores.Contains(_contextAccessor.WorkContext.CurrentCustomer.StaffStoreId) && + checkoutAttribute.Stores.Count > 1)) + { + Warning(_translationService.GetResource("admin.Catalog.attributes.checkoutAttributes.permissions")); + return true; + } + + return checkoutAttribute.AccessToEntityByStore(_contextAccessor.WorkContext.CurrentCustomer.StaffStoreId); + } + + #endregion + + #region Checkout attributes + + //list + public IActionResult Index() + { + return RedirectToAction("List"); + } + + public IActionResult List() + { + return View(); + } + + [HttpPost] + [PermissionAuthorizeAction(PermissionActionName.List)] + public async Task List(DataSourceRequest command) + { + var checkoutAttributes = await _checkoutAttributeViewModelService.PrepareCheckoutAttributeListModel(_contextAccessor.WorkContext.CurrentCustomer.StoreId); + var gridModel = new DataSourceResult { + Data = checkoutAttributes.ToList(), + Total = checkoutAttributes.Count() + }; + return Json(gridModel); + } + + //create + [PermissionAuthorizeAction(PermissionActionName.Create)] + public async Task Create() + { + var model = await _checkoutAttributeViewModelService.PrepareCheckoutAttributeModel(); + //locales + await AddLocales(_languageService, model.Locales); + + return View(model); + } + + [HttpPost] + [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] + [PermissionAuthorizeAction(PermissionActionName.Create)] + public async Task Create(CheckoutAttributeModel model, bool continueEditing) + { + if (ModelState.IsValid) + { + model.Stores = [_contextAccessor.WorkContext.CurrentCustomer.StaffStoreId]; + model.CustomerGroups = []; + var checkoutAttribute = await _checkoutAttributeViewModelService.InsertCheckoutAttributeModel(model); + Success(_translationService.GetResource("Admin.Orders.CheckoutAttributes.Added")); + return continueEditing + ? RedirectToAction("Edit", new { id = checkoutAttribute.Id }) + : RedirectToAction("List"); + } + + //If we got this far, something failed, redisplay form + //tax categories + await _checkoutAttributeViewModelService.PrepareTaxCategories(model, null, true); + + return View(model); + } + + //edit + [PermissionAuthorizeAction(PermissionActionName.Preview)] + public async Task Edit(string id) + { + var checkoutAttribute = await _checkoutAttributeService.GetCheckoutAttributeById(id); + if (checkoutAttribute == null) + //No checkout attribute found with the specified id + return RedirectToAction("List"); + + if (!CheckAccessPermission(checkoutAttribute)) + return RedirectToAction("List"); + + var model = checkoutAttribute.ToModel(); + //locales + await AddLocales(_languageService, model.Locales, (locale, languageId) => + { + locale.Name = checkoutAttribute.GetTranslation(x => x.Name, languageId, false); + locale.TextPrompt = checkoutAttribute.GetTranslation(x => x.TextPrompt, languageId, false); + }); + + //tax categories + await _checkoutAttributeViewModelService.PrepareTaxCategories(model, checkoutAttribute, false); + + //condition + await _checkoutAttributeViewModelService.PrepareConditionAttributes(model, checkoutAttribute); + + return View(model); + } + + [HttpPost] + [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] + [PermissionAuthorizeAction(PermissionActionName.Edit)] + public async Task Edit(CheckoutAttributeModel model, bool continueEditing) + { + var checkoutAttribute = await _checkoutAttributeService.GetCheckoutAttributeById(model.Id); + if (checkoutAttribute == null) + //No checkout attribute found with the specified id + return RedirectToAction("List"); + + if (!checkoutAttribute.AccessToEntityByStore(_contextAccessor.WorkContext.CurrentCustomer.StaffStoreId)) + return RedirectToAction("Edit", new { id = checkoutAttribute.Id }); + + if (ModelState.IsValid) + { + model.Stores = [_contextAccessor.WorkContext.CurrentCustomer.StaffStoreId]; + model.CustomerGroups = []; + + checkoutAttribute = await _checkoutAttributeViewModelService.UpdateCheckoutAttributeModel(checkoutAttribute, model); + Success(_translationService.GetResource("Admin.Orders.CheckoutAttributes.Updated")); + if (continueEditing) + { + //selected tab + await SaveSelectedTabIndex(); + + return RedirectToAction("Edit", new { id = checkoutAttribute.Id }); + } + + return RedirectToAction("List"); + } + + //If we got this far, something failed, redisplay form + //tax categories + await _checkoutAttributeViewModelService.PrepareTaxCategories(model, checkoutAttribute, true); + return View(model); + } + + //delete + [HttpPost] + [PermissionAuthorizeAction(PermissionActionName.Delete)] + public async Task Delete(string id) + { + var checkoutAttribute = await _checkoutAttributeService.GetCheckoutAttributeById(id); + + if (!checkoutAttribute.AccessToEntityByStore(_contextAccessor.WorkContext.CurrentCustomer.StaffStoreId)) + return RedirectToAction("List"); + + await _checkoutAttributeService.DeleteCheckoutAttribute(checkoutAttribute); + + Success(_translationService.GetResource("Admin.Orders.CheckoutAttributes.Deleted")); + return RedirectToAction("List"); + } + + #endregion + + #region Checkout attribute values + + //list + [HttpPost] + [PermissionAuthorizeAction(PermissionActionName.Preview)] + public async Task ValueList(string checkoutAttributeId, DataSourceRequest command) + { + var ca = await _checkoutAttributeService.GetCheckoutAttributeById(checkoutAttributeId); + if (!CheckAccessPermission(ca)) + return View("AccessDenied", _translationService.GetResource("admin.Catalog.attributes.checkoutAttributes.permissions")); + + var checkoutAttribute = await _checkoutAttributeViewModelService.PrepareCheckoutAttributeValuesModel(checkoutAttributeId); + + var gridModel = new DataSourceResult { + Data = checkoutAttribute.ToList(), + Total = checkoutAttribute.Count() + }; + return Json(gridModel); + } + + //create + [PermissionAuthorizeAction(PermissionActionName.Edit)] + public async Task ValueCreatePopup(string checkoutAttributeId) + { + var ca = await _checkoutAttributeService.GetCheckoutAttributeById(checkoutAttributeId); + if (ca == null) + throw new ArgumentException("No checkout attribute found with the specified id"); + + if (!ca.AccessToEntityByStore(_contextAccessor.WorkContext.CurrentCustomer.StaffStoreId)) + return View("AccessDenied", _translationService.GetResource("admin.Catalog.attributes.checkoutattributes.permissions")); + + var model = await _checkoutAttributeViewModelService.PrepareCheckoutAttributeValueModel(checkoutAttributeId); + //locales + await AddLocales(_languageService, model.Locales); + return View(model); + } + + [HttpPost] + [PermissionAuthorizeAction(PermissionActionName.Edit)] + public async Task ValueCreatePopup(CheckoutAttributeValueModel model) + { + var checkoutAttribute = await _checkoutAttributeService.GetCheckoutAttributeById(model.CheckoutAttributeId); + if (checkoutAttribute == null) + //No checkout attribute found with the specified id + return RedirectToAction("List"); + + if (!checkoutAttribute.AccessToEntityByStore(_contextAccessor.WorkContext.CurrentCustomer.StaffStoreId)) + return View("AccessDenied", _translationService.GetResource("admin.Catalog.attributes.checkoutattributes.permissions")); + + if (ModelState.IsValid) + { + await _checkoutAttributeViewModelService.InsertCheckoutAttributeValueModel(checkoutAttribute, model); + return Content(""); + } + + //If we got this far, something failed, redisplay form + model.PrimaryStoreCurrencyCode = + (await _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId)).CurrencyCode; + model.BaseWeightIn = (await _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId)).Name; + return View(model); + } + + //edit + [PermissionAuthorizeAction(PermissionActionName.Edit)] + public async Task ValueEditPopup(string id, string checkoutAttributeId) + { + var checkoutAttribute = await _checkoutAttributeService.GetCheckoutAttributeById(checkoutAttributeId); + + if (!CheckAccessPermission(checkoutAttribute)) + return View("AccessDenied", _translationService.GetResource("admin.Catalog.attributes.checkoutAttributes.permissions")); + + var cav = checkoutAttribute.CheckoutAttributeValues.FirstOrDefault(x => x.Id == id); + if (cav == null) + //No checkout attribute value found with the specified id + return RedirectToAction("List"); + + var model = await _checkoutAttributeViewModelService.PrepareCheckoutAttributeValueModel(checkoutAttribute, cav); + + //locales + await AddLocales(_languageService, model.Locales, (locale, languageId) => + { + locale.Name = cav.GetTranslation(x => x.Name, languageId, false); + }); + + return View(model); + } + + [HttpPost] + [PermissionAuthorizeAction(PermissionActionName.Edit)] + public async Task ValueEditPopup(CheckoutAttributeValueModel model) + { + var checkoutAttribute = await _checkoutAttributeService.GetCheckoutAttributeById(model.CheckoutAttributeId); + + if (!checkoutAttribute.AccessToEntityByStore(_contextAccessor.WorkContext.CurrentCustomer.StaffStoreId)) + return View("AccessDenied", _translationService.GetResource("admin.Catalog.attributes.checkoutAttributes.permissions")); + + var cav = checkoutAttribute.CheckoutAttributeValues.FirstOrDefault(x => x.Id == model.Id); + if (cav == null) + //No checkout attribute value found with the specified id + return RedirectToAction("List"); + + if (ModelState.IsValid) + { + await _checkoutAttributeViewModelService.UpdateCheckoutAttributeValueModel(checkoutAttribute, cav, model); + return Content(""); + } + + //If we got this far, something failed, redisplay form + model.PrimaryStoreCurrencyCode = + (await _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId)).CurrencyCode; + model.BaseWeightIn = (await _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId)).Name; + + return View(model); + } + + //delete + [HttpPost] + [PermissionAuthorizeAction(PermissionActionName.Edit)] + public async Task ValueDelete(string id, string checkoutAttributeId) + { + var checkoutAttribute = await _checkoutAttributeService.GetCheckoutAttributeById(checkoutAttributeId); + + if (!checkoutAttribute.AccessToEntityByStore(_contextAccessor.WorkContext.CurrentCustomer.StaffStoreId)) + return View("AccessDenied", _translationService.GetResource("admin.Catalog.attributes.checkoutAttributes.permissions")); + + var cav = checkoutAttribute.CheckoutAttributeValues.FirstOrDefault(x => x.Id == id); + if (cav == null) + throw new ArgumentException("No checkout attribute value found with the specified id"); + + if (ModelState.IsValid) + { + checkoutAttribute.CheckoutAttributeValues.Remove(cav); + await _checkoutAttributeService.UpdateCheckoutAttribute(checkoutAttribute); + return new JsonResult(""); + } + + return ErrorForKendoGridJson(ModelState); + } + + #endregion +} \ No newline at end of file diff --git a/src/Web/Grand.Web/App_Data/Resources/DefaultLanguage.xml b/src/Web/Grand.Web/App_Data/Resources/DefaultLanguage.xml index da1c65d7c..8b59be237 100644 Binary files a/src/Web/Grand.Web/App_Data/Resources/DefaultLanguage.xml and b/src/Web/Grand.Web/App_Data/Resources/DefaultLanguage.xml differ