Пример #1
0
        public virtual async Task <IActionResult> Category(int categoryId, CatalogProductsCommand command)
        {
            var category = await _categoryService.GetCategoryByIdAsync(categoryId);

            if (!await CheckCategoryAvailabilityAsync(category))
            {
                return(InvokeHttp404());
            }

            //'Continue shopping' URL
            await _genericAttributeService.SaveAttributeAsync(await _workContext.GetCurrentCustomerAsync(),
                                                              NopCustomerDefaults.LastContinueShoppingPageAttribute,
                                                              _webHelper.GetThisPageUrl(false),
                                                              (await _storeContext.GetCurrentStoreAsync()).Id);

            //display "edit" (manage) link
            if (await _permissionService.AuthorizeAsync(StandardPermissionProvider.AccessAdminPanel) && await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageCategories))
            {
                DisplayEditLink(Url.Action("Edit", "Category", new { id = category.Id, area = AreaNames.Admin }));
            }

            //activity log
            await _customerActivityService.InsertActivityAsync("PublicStore.ViewCategory",
                                                               string.Format(await _localizationService.GetResourceAsync("ActivityLog.PublicStore.ViewCategory"), category.Name), category);

            //model
            var model = await _catalogModelFactory.PrepareCategoryModelAsync(category, command);

            //template
            var templateViewPath = await _catalogModelFactory.PrepareCategoryTemplateViewPathAsync(category.CategoryTemplateId);

            return(View(templateViewPath, model));
        }
        /// <returns>A task that represents the asynchronous operation</returns>
        public async Task <IActionResult> TaxCategoryAdd(Models.Tax.TaxCategoryModel model)
        {
            //ensure that Avalara tax provider is active
            if (!await _taxPluginManager.IsPluginActiveAsync(AvalaraTaxDefaults.SystemName))
            {
                return(new NullJsonResult());
            }

            if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageTaxSettings))
            {
                return(AccessDeniedView());
            }

            if (!ModelState.IsValid)
            {
                return(ErrorJson(ModelState.SerializeErrors()));
            }

            var taxCategory = new TaxCategory();

            taxCategory = model.ToEntity(taxCategory);
            await _taxCategoryService.InsertTaxCategoryAsync(taxCategory);

            //save tax code type as generic attribute
            if (!string.IsNullOrEmpty(model.TypeId) && !model.TypeId.Equals(Guid.Empty.ToString()))
            {
                await _genericAttributeService.SaveAttributeAsync(taxCategory, AvalaraTaxDefaults.TaxCodeTypeAttribute, model.TypeId);
            }

            return(Json(new { Result = true }));
        }
        /// <summary>
        /// Handle event
        /// </summary>
        /// <param name="eventMessage">Event message</param>
        /// <returns>A task that represents the asynchronous operation</returns>
        public async Task HandleEventAsync(CustomerAutoRegisteredByExternalMethodEvent eventMessage)
        {
            if (eventMessage?.Customer == null || eventMessage.AuthenticationParameters == null)
            {
                return;
            }

            //handle event only for this authentication method
            if (!eventMessage.AuthenticationParameters.ProviderSystemName.Equals(FacebookAuthenticationDefaults.SystemName))
            {
                return;
            }

            //store some of the customer fields
            var firstName = eventMessage.AuthenticationParameters.Claims?.FirstOrDefault(claim => claim.Type == ClaimTypes.GivenName)?.Value;

            if (!string.IsNullOrEmpty(firstName))
            {
                await _genericAttributeService.SaveAttributeAsync(eventMessage.Customer, NopCustomerDefaults.FirstNameAttribute, firstName);
            }

            var lastName = eventMessage.AuthenticationParameters.Claims?.FirstOrDefault(claim => claim.Type == ClaimTypes.Surname)?.Value;

            if (!string.IsNullOrEmpty(lastName))
            {
                await _genericAttributeService.SaveAttributeAsync(eventMessage.Customer, NopCustomerDefaults.LastNameAttribute, lastName);
            }
        }
        public async Task TearDown()
        {
            await _genericAttributeService.SaveAttributeAsync(_customer, NopCustomerDefaults.TimeZoneIdAttribute, _defaultTimeZone);

            _dateTimeSettings.AllowCustomersToSetTimeZone = _defaultAllowCustomersToSetTimeZone;
            _dateTimeSettings.DefaultStoreTimeZoneId      = _defaultDefaultStoreTimeZoneId;

            await _settingService.SaveSettingAsync(_dateTimeSettings);
        }
Пример #5
0
        /// <summary>
        /// Handle entity deleted event
        /// </summary>
        /// <param name="eventMessage">Event message</param>
        /// <returns>A task that represents the asynchronous operation</returns>
        public async Task HandleEventAsync(EntityDeletedEvent <Address> eventMessage)
        {
            if (eventMessage.Entity is not Address address)
            {
                return;
            }

            await _genericAttributeService.SaveAttributeAsync <string>(address, What3wordsDefaults.AddressValueAttribute, null);
        }
Пример #6
0
        /// <summary>
        /// Sets current user working language
        /// </summary>
        /// <param name="language">Language</param>
        public virtual async Task SetWorkingLanguageAsync(Language language)
        {
            //save passed language identifier
            var customer = await GetCurrentCustomerAsync();

            var store = await _storeContext.GetCurrentStoreAsync();

            await _genericAttributeService.SaveAttributeAsync(customer, NopCustomerDefaults.LanguageIdAttribute, language?.Id ?? 0, store.Id);

            //then reset the cached value
            _cachedLanguage = null;
        }
Пример #7
0
        private async Task InsertFirstAndLastNameGenericAttributes(string firstName, string lastName, User newUser)
        {
            if (firstName != null)
            {
                await _genericAttributeService.SaveAttributeAsync(newUser, UserDefaults.FirstNameAttribute, firstName);
            }

            if (lastName != null)
            {
                await _genericAttributeService.SaveAttributeAsync(newUser, UserDefaults.LastNameAttribute, lastName);
            }
        }
Пример #8
0
        public virtual async Task <IActionResult> Category(int categoryId, CatalogPagingFilteringModel command)
        {
            var category = await _categoryService.GetCategoryByIdAsync(categoryId);

            if (category == null || category.Deleted)
            {
                return(InvokeHttp404());
            }

            var notAvailable =
                //published?
                !category.Published ||
                //ACL (access control list)
                !await _aclService.AuthorizeAsync(category) ||
                //Store mapping
                !await _storeMappingService.AuthorizeAsync(category);

            //Check whether the current user has a "Manage categories" permission (usually a store owner)
            //We should allows him (her) to use "Preview" functionality
            var hasAdminAccess = await _permissionService.AuthorizeAsync(StandardPermissionProvider.AccessAdminPanel) && await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageCategories);

            if (notAvailable && !hasAdminAccess)
            {
                return(InvokeHttp404());
            }

            //'Continue shopping' URL
            await _genericAttributeService.SaveAttributeAsync(await _workContext.GetCurrentCustomerAsync(),
                                                              NopCustomerDefaults.LastContinueShoppingPageAttribute,
                                                              _webHelper.GetThisPageUrl(false),
                                                              (await _storeContext.GetCurrentStoreAsync()).Id);

            //display "edit" (manage) link
            if (await _permissionService.AuthorizeAsync(StandardPermissionProvider.AccessAdminPanel) && await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageCategories))
            {
                DisplayEditLink(Url.Action("Edit", "Category", new { id = category.Id, area = AreaNames.Admin }));
            }

            //activity log
            await _customerActivityService.InsertActivityAsync("PublicStore.ViewCategory",
                                                               string.Format(await _localizationService.GetResourceAsync("ActivityLog.PublicStore.ViewCategory"), category.Name), category);

            //model
            var model = await _catalogModelFactory.PrepareCategoryModelAsync(category, command);

            //template
            var templateViewPath = await _catalogModelFactory.PrepareCategoryTemplateViewPathAsync(category.CategoryTemplateId);

            return(View(templateViewPath, model));
        }
        /// <summary>
        /// Prepare shipping method model
        /// </summary>
        /// <param name="cart">Cart</param>
        /// <param name="shippingAddress">Shipping address</param>
        /// <returns>
        /// A task that represents the asynchronous operation
        /// The task result contains the shipping method model
        /// </returns>
        public virtual async Task <CheckoutShippingMethodModel> PrepareShippingMethodModelAsync(IList <ShoppingCartItem> cart, Address shippingAddress)
        {
            var model = new CheckoutShippingMethodModel
            {
                DisplayPickupInStore = _orderSettings.DisplayPickupInStoreOnShippingMethodPage
            };

            if (_orderSettings.DisplayPickupInStoreOnShippingMethodPage)
            {
                model.PickupPointsModel = await PrepareCheckoutPickupPointsModelAsync(cart);
            }

            var customer = await _workContext.GetCurrentCustomerAsync();

            var store = await _storeContext.GetCurrentStoreAsync();

            var getShippingOptionResponse = await _shippingService.GetShippingOptionsAsync(cart, shippingAddress, customer, storeId : store.Id);

            if (getShippingOptionResponse.Success)
            {
                //performance optimization. cache returned shipping options.
                //we'll use them later (after a customer has selected an option).
                await _genericAttributeService.SaveAttributeAsync(customer,
                                                                  NopCustomerDefaults.OfferedShippingOptionsAttribute,
                                                                  getShippingOptionResponse.ShippingOptions,
                                                                  store.Id);

                foreach (var shippingOption in getShippingOptionResponse.ShippingOptions)
                {
                    var soModel = new CheckoutShippingMethodModel.ShippingMethodModel
                    {
                        Name         = shippingOption.Name,
                        Description  = shippingOption.Description,
                        DisplayOrder = shippingOption.DisplayOrder ?? 0,
                        ShippingRateComputationMethodSystemName = shippingOption.ShippingRateComputationMethodSystemName,
                        ShippingOption = shippingOption,
                    };

                    //adjust rate
                    var(shippingTotal, _) = await _orderTotalCalculationService.AdjustShippingRateAsync(shippingOption.Rate, cart, shippingOption.IsPickupInStore);

                    var(rateBase, _) = await _taxService.GetShippingPriceAsync(shippingTotal, customer);

                    var rate = await _currencyService.ConvertFromPrimaryStoreCurrencyAsync(rateBase, await _workContext.GetWorkingCurrencyAsync());

                    soModel.Fee = await _priceFormatter.FormatShippingPriceAsync(rate, true);

                    soModel.Rate = rate;
                    model.ShippingMethods.Add(soModel);
                }

                //sort shipping methods
                if (model.ShippingMethods.Count > 1)
                {
                    model.ShippingMethods = (_shippingSettings.ShippingSorting switch
                    {
                        ShippingSortingEnum.ShippingCost => model.ShippingMethods.OrderBy(option => option.Rate),
                        _ => model.ShippingMethods.OrderBy(option => option.DisplayOrder)
                    }).ToList();
Пример #10
0
        /// <summary>
        /// Handle model received event
        /// </summary>
        /// <param name="eventMessage">Event message</param>
        /// <returns>A task that represents the asynchronous operation</returns>
        public async Task HandleEventAsync(ModelReceivedEvent <BaseNopModel> eventMessage)
        {
            if (eventMessage.Model is not ProductModel model)
            {
                return;
            }

            if (!await _shippingPluginManager.IsPluginActiveAsync(EasyPostDefaults.SystemName))
            {
                return;
            }

            if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageShippingSettings))
            {
                return;
            }

            var product = await _productService.GetProductByIdAsync(model.Id);

            if (product is null)
            {
                return;
            }

            //try to get additional form values for the product
            var form = _httpContextAccessor.HttpContext.Request.Form;

            if (form.TryGetValue(EasyPostDefaults.ProductPredefinedPackageFormKey, out var predefinedPackageValue))
            {
                var predefinedPackage = !StringValues.IsNullOrEmpty(predefinedPackageValue) ? predefinedPackageValue.ToString() : null;
                await _genericAttributeService.SaveAttributeAsync(product, EasyPostDefaults.ProductPredefinedPackageAttribute, predefinedPackage);
            }
            if (form.TryGetValue(EasyPostDefaults.ProductHtsNumberFormKey, out var htsNumberValue))
            {
                var htsNumber = !StringValues.IsNullOrEmpty(htsNumberValue) ? htsNumberValue.ToString() : null;
                await _genericAttributeService.SaveAttributeAsync(product, EasyPostDefaults.ProductHtsNumberAttribute, htsNumber);
            }
            if (form.TryGetValue(EasyPostDefaults.ProductOriginCountryFormKey, out var originCountryValue))
            {
                var originCountry = !StringValues.IsNullOrEmpty(originCountryValue) ? originCountryValue.ToString() : null;
                await _genericAttributeService.SaveAttributeAsync(product, EasyPostDefaults.ProductOriginCountryAttribute, originCountry);
            }
        }
Пример #11
0
        public async Task <JsonResult> SavePreference(string name, bool value)
        {
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException(nameof(name));
            }

            await _genericAttributeService.SaveAttributeAsync(_workContext.CurrentUser, name, value);

            return(Json(new { Result = true }));
        }
Пример #12
0
        public override async Task <IActionResult> Edit(ProductModel model, bool continueEditing)
        {
            // Saves PLP description
            var plpDescription = Request.Form["PLPDescription"].ToString();
            var product        = await _productService.GetProductByIdAsync(model.Id);

            await _genericAttributeService.SaveAttributeAsync <string>(
                product, "PLPDescription", plpDescription
                );

            return(await base.Edit(model, continueEditing));
        }
Пример #13
0
        public virtual async Task <IActionResult> EuCookieLawAccept()
        {
            if (!_storeInformationSettings.DisplayEuCookieLawWarning)
            {
                //disabled
                return(Json(new { stored = false }));
            }

            //save setting
            await _genericAttributeService.SaveAttributeAsync(await _workContext.GetCurrentCustomerAsync(), NopCustomerDefaults.EuCookieLawAcceptedAttribute, true, (await _storeContext.GetCurrentStoreAsync()).Id);

            return(Json(new { stored = true }));
        }
Пример #14
0
        /// <summary>
        /// Prepare the header links model
        /// </summary>
        /// <returns>
        /// A task that represents the asynchronous operation
        /// The task result contains the header links model
        /// </returns>
        public virtual async Task <HeaderLinksModel> PrepareHeaderLinksModelAsync()
        {
            var customer = await _workContext.GetCurrentCustomerAsync();

            var store = await _storeContext.GetCurrentStoreAsync();

            var unreadMessageCount = await GetUnreadPrivateMessagesAsync();

            var unreadMessage = string.Empty;
            var alertMessage  = string.Empty;

            if (unreadMessageCount > 0)
            {
                unreadMessage = string.Format(await _localizationService.GetResourceAsync("PrivateMessages.TotalUnread"), unreadMessageCount);

                //notifications here
                if (_forumSettings.ShowAlertForPM &&
                    !await _genericAttributeService.GetAttributeAsync <bool>(customer, NopCustomerDefaults.NotifiedAboutNewPrivateMessagesAttribute, store.Id))
                {
                    await _genericAttributeService.SaveAttributeAsync(customer, NopCustomerDefaults.NotifiedAboutNewPrivateMessagesAttribute, true, store.Id);

                    alertMessage = string.Format(await _localizationService.GetResourceAsync("PrivateMessages.YouHaveUnreadPM"), unreadMessageCount);
                }
            }

            var model = new HeaderLinksModel
            {
                RegistrationType      = _customerSettings.UserRegistrationType,
                IsAuthenticated       = await _customerService.IsRegisteredAsync(customer),
                CustomerName          = await _customerService.IsRegisteredAsync(customer) ? await _customerService.FormatUsernameAsync(customer) : string.Empty,
                ShoppingCartEnabled   = await _permissionService.AuthorizeAsync(StandardPermissionProvider.EnableShoppingCart),
                WishlistEnabled       = await _permissionService.AuthorizeAsync(StandardPermissionProvider.EnableWishlist),
                AllowPrivateMessages  = await _customerService.IsRegisteredAsync(customer) && _forumSettings.AllowPrivateMessages,
                UnreadPrivateMessages = unreadMessage,
                AlertMessage          = alertMessage,
            };

            //performance optimization (use "HasShoppingCartItems" property)
            if (customer.HasShoppingCartItems)
            {
                model.ShoppingCartItems = (await _shoppingCartService.GetShoppingCartAsync(customer, ShoppingCartType.ShoppingCart, store.Id))
                                          .Sum(item => item.Quantity);

                model.WishlistItems = (await _shoppingCartService.GetShoppingCartAsync(customer, ShoppingCartType.Wishlist, store.Id))
                                      .Sum(item => item.Quantity);
            }

            return(model);
        }
        /// <returns>A task that represents the asynchronous operation</returns>
        public virtual async Task <IActionResult> SavePreference(string name, bool value)
        {
            //permission validation is not required here
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException(nameof(name));
            }

            await _genericAttributeService.SaveAttributeAsync(await _workContext.GetCurrentCustomerAsync(), name, value);

            return(Json(new
            {
                Result = true
            }));
        }
Пример #16
0
        /// <summary>
        /// Uninstall the plugin
        /// </summary>
        /// <returns>A task that represents the asynchronous operation</returns>
        public override async Task UninstallAsync()
        {
            //smtp accounts
            foreach (var store in await _storeService.GetAllStoresAsync())
            {
                var key            = $"{nameof(SendinblueSettings)}.{nameof(SendinblueSettings.EmailAccountId)}";
                var emailAccountId = await _settingService.GetSettingByKeyAsync <int>(key, storeId : store.Id, loadSharedValueIfNotFound : true);

                var emailAccount = await _emailAccountService.GetEmailAccountByIdAsync(emailAccountId);

                if (emailAccount != null)
                {
                    await _emailAccountService.DeleteEmailAccountAsync(emailAccount);
                }
            }

            //settings
            if (_widgetSettings.ActiveWidgetSystemNames.Contains(SendinblueDefaults.SystemName))
            {
                _widgetSettings.ActiveWidgetSystemNames.Remove(SendinblueDefaults.SystemName);
                await _settingService.SaveSettingAsync(_widgetSettings);
            }
            await _settingService.DeleteSettingAsync <SendinblueSettings>();

            //generic attributes
            foreach (var store in await _storeService.GetAllStoresAsync())
            {
                var messageTemplates = await _messageTemplateService.GetAllMessageTemplatesAsync(store.Id);

                foreach (var messageTemplate in messageTemplates)
                {
                    await _genericAttributeService.SaveAttributeAsync <int?>(messageTemplate, SendinblueDefaults.TemplateIdAttribute, null);
                }
            }

            //schedule task
            var task = await _scheduleTaskService.GetTaskByTypeAsync(SendinblueDefaults.SynchronizationTask);

            if (task != null)
            {
                await _scheduleTaskService.DeleteTaskAsync(task);
            }

            //locales
            await _localizationService.DeleteLocaleResourcesAsync("Plugins.Misc.Sendinblue");

            await base.UninstallAsync();
        }
Пример #17
0
        public async Task <IActionResult> MessageUpdate(SendinblueMessageTemplateModel model)
        {
            if (!ModelState.IsValid)
            {
                return(ErrorJson(ModelState.SerializeErrors().ToString()));
            }

            var message = await _messageTemplateService.GetMessageTemplateByIdAsync(model.Id);

            //Sendinblue message template
            if (model.UseSendinblueTemplate)
            {
                var storeId = await _storeContext.GetActiveStoreScopeConfigurationAsync();

                var sendinblueSettings = await _settingService.LoadSettingAsync <SendinblueSettings>(storeId);

                //get template or create new one
                var currentTemplateId = await _genericAttributeService.GetAttributeAsync <int?>(message, SendinblueDefaults.TemplateIdAttribute);

                var templateId = await _sendinblueEmailManager.GetTemplateIdAsync(currentTemplateId, message,
                                                                                  await _emailAccountService.GetEmailAccountByIdAsync(sendinblueSettings.EmailAccountId));

                await _genericAttributeService.SaveAttributeAsync(message, SendinblueDefaults.TemplateIdAttribute, templateId);

                model.EditLink = $"{string.Format(SendinblueDefaults.EditMessageTemplateUrl, templateId)}";
            }
            else
            {
                //standard message template
                await _genericAttributeService.SaveAttributeAsync <int?>(message, SendinblueDefaults.TemplateIdAttribute, null);

                model.EditLink = Url.Action("Edit", "MessageTemplate", new { id = model.Id, area = AreaNames.Admin });
            }

            //update message template
            if (model.IsActive == message.IsActive)
            {
                return(new NullJsonResult());
            }

            message.IsActive = model.IsActive;
            await _messageTemplateService.UpdateMessageTemplateAsync(message);

            return(new NullJsonResult());
        }
Пример #18
0
        private async Task <bool> SetShippingOptionAsync(
            string shippingRateComputationMethodSystemName, string shippingOptionName, int storeId, Customer customer, List <ShoppingCartItem> shoppingCartItems)
        {
            var isValid = true;

            if (string.IsNullOrEmpty(shippingRateComputationMethodSystemName))
            {
                isValid = false;

                ModelState.AddModelError("shipping_rate_computation_method_system_name",
                                         "Please provide shipping_rate_computation_method_system_name");
            }
            else if (string.IsNullOrEmpty(shippingOptionName))
            {
                isValid = false;

                ModelState.AddModelError("shipping_option_name", "Please provide shipping_option_name");
            }
            else
            {
                var shippingOptionResponse = await _shippingService.GetShippingOptionsAsync(shoppingCartItems, await CustomerService.GetCustomerShippingAddressAsync(customer), customer,
                                                                                            shippingRateComputationMethodSystemName, storeId);

                if (shippingOptionResponse.Success)
                {
                    var shippingOptions = shippingOptionResponse.ShippingOptions.ToList();

                    var shippingOption = shippingOptions
                                         .Find(so => !string.IsNullOrEmpty(so.Name) && so.Name.Equals(shippingOptionName, StringComparison.InvariantCultureIgnoreCase));

                    await _genericAttributeService.SaveAttributeAsync(customer,
                                                                      NopCustomerDefaults.SelectedShippingOptionAttribute,
                                                                      shippingOption, storeId);
                }
                else
                {
                    isValid = false;

                    foreach (var errorMessage in shippingOptionResponse.Errors)
                    {
                        ModelState.AddModelError("shipping_option", errorMessage);
                    }
                }
            }

            return(isValid);
        }
Пример #19
0
        /// <summary>
        /// Set current theme system name
        /// </summary>
        public virtual async Task SetWorkingThemeNameAsync(string workingThemeName)
        {
            //whether customers are allowed to select a theme
            if (!_storeInformationSettings.AllowCustomerToSelectTheme ||
                await _workContext.GetCurrentCustomerAsync() == null)
            {
                return;
            }

            //save selected by customer theme system name
            await _genericAttributeService.SaveAttributeAsync(await _workContext.GetCurrentCustomerAsync(),
                                                              NopCustomerDefaults.WorkingThemeNameAttribute, workingThemeName,
                                                              (await _storeContext.GetCurrentStoreAsync()).Id);

            //clear cache
            _cachedThemeName = null;
        }
        public async Task <IActionResult> ChangeLanguage(int id, string returnUrl)
        {
            var language = await _languageService.GetLanguageByIdAsync(id);

            if (language == null || !language.Published)
            {
                language = _workContext.WorkingLanguage;
            }

            if (language != null && HttpContext.User.IsAuthenticated())
            {
                await _genericAttributeService.SaveAttributeAsync(KeyGroupDefaults.UserKeyGroup, UserDefaults.LanguageIdAttribute, language.Id.ToString());
            }

            _workContext.WorkingLanguage = language;

            return(LocalRedirect(returnUrl));
        }
Пример #21
0
        public virtual async Task <IActionResult> Index()
        {
            //display a warning to a store owner if there are some error
            var customer = await _workContext.GetCurrentCustomerAsync();

            var hideCard = await _genericAttributeService.GetAttributeAsync <bool>(customer, NopCustomerDefaults.HideConfigurationStepsAttribute);

            var closeCard = await _genericAttributeService.GetAttributeAsync <bool>(customer, NopCustomerDefaults.CloseConfigurationStepsAttribute);

            if ((hideCard || closeCard) && await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageMaintenance))
            {
                var warnings = await _commonModelFactory.PrepareSystemWarningModelsAsync();

                if (warnings.Any(warning => warning.Level == SystemWarningLevel.Fail ||
                                 warning.Level == SystemWarningLevel.CopyrightRemovalKey ||
                                 warning.Level == SystemWarningLevel.Warning))
                {
                    _notificationService.WarningNotification(
                        string.Format(await _localizationService.GetResourceAsync("Admin.System.Warnings.Errors"),
                                      Url.Action("Warnings", "Common")),
                        //do not encode URLs
                        false);
                }
            }

            //progress of localozation
            var currentLanguage = await _workContext.GetWorkingLanguageAsync();

            var progress = await _genericAttributeService.GetAttributeAsync <string>(currentLanguage, NopCommonDefaults.LanguagePackProgressAttribute);

            if (!string.IsNullOrEmpty(progress))
            {
                var locale = await _localizationService.GetResourceAsync("Admin.Configuration.LanguagePackProgressMessage");

                _notificationService.SuccessNotification(string.Format(locale, progress, NopLinksDefaults.OfficialSite.Translations), false);
                await _genericAttributeService.SaveAttributeAsync(currentLanguage, NopCommonDefaults.LanguagePackProgressAttribute, string.Empty);
            }

            //prepare model
            var model = await _homeModelFactory.PrepareDashboardModelAsync(new DashboardModel());

            return(View(model));
        }
Пример #22
0
        /// <summary>
        /// Handle model received event
        /// </summary>
        /// <param name="eventMessage">Event message</param>
        /// <returns>A task that represents the asynchronous operation</returns>
        public async Task HandleEventAsync(ModelReceivedEvent <BaseNopModel> eventMessage)
        {
            //get entity by received model
            var entity = eventMessage.Model switch
            {
                CustomerModel customerModel => (BaseEntity)await _customerService.GetCustomerByIdAsync(customerModel.Id),
                CustomerRoleModel customerRoleModel => await _customerService.GetCustomerRoleByIdAsync(customerRoleModel.Id),
                ProductModel productModel => await _productService.GetProductByIdAsync(productModel.Id),
                CheckoutAttributeModel checkoutAttributeModel => await _checkoutAttributeService.GetCheckoutAttributeByIdAsync(checkoutAttributeModel.Id),
                _ => null
            };

            if (entity == null)
            {
                return;
            }

            //ensure that Avalara tax provider is active
            if (!await _taxPluginManager.IsPluginActiveAsync(AvalaraTaxDefaults.SystemName))
            {
                return;
            }

            if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageTaxSettings))
            {
                return;
            }

            //whether there is a form value for the entity use code
            if (_httpContextAccessor.HttpContext.Request.Form.TryGetValue(AvalaraTaxDefaults.EntityUseCodeAttribute, out var entityUseCodeValue) &&
                !StringValues.IsNullOrEmpty(entityUseCodeValue))
            {
                //save attribute
                var entityUseCode = !entityUseCodeValue.ToString().Equals(Guid.Empty.ToString()) ? entityUseCodeValue.ToString() : null;
                await _genericAttributeService.SaveAttributeAsync(entity, AvalaraTaxDefaults.EntityUseCodeAttribute, entityUseCode);
            }
        }
Пример #23
0
        public async Task <IActionResult> ChangeTenantScopeConfiguration(int tenantId, string returnUrl = "")
        {
            var tenant = _tenantService.GetTenantByIdAsync(tenantId);

            if (tenant != null || tenantId == 0)
            {
                await _genericAttributeService.SaveAttributeAsync(_workContext.CurrentUser,
                                                                  UserDefaults.TenantScopeConfigurationAttribute, tenantId);
            }

            //home page
            if (string.IsNullOrEmpty(returnUrl))
            {
                returnUrl = Url.Action("Index", "Home");
            }

            //prevent open redirection attack
            if (!Url.IsLocalUrl(returnUrl))
            {
                return(RedirectToAction("Index", "Home"));
            }

            return(Redirect(returnUrl));
        }
Пример #24
0
        /// <returns>A task that represents the asynchronous operation</returns>
        public async Task <IActionResult> GoogleAuthenticatorDelete(GoogleAuthenticatorModel model)
        {
            if (!ModelState.IsValid)
            {
                return(ErrorJson(ModelState.SerializeErrors()));
            }

            //delete configuration
            var configuration = await _googleAuthenticatorService.GetConfigurationByIdAsync(model.Id);

            if (configuration != null)
            {
                await _googleAuthenticatorService.DeleteConfigurationAsync(configuration);
            }
            var customer = await _customerService.GetCustomerByEmailAsync(configuration.Customer) ??
                           await _customerService.GetCustomerByUsernameAsync(configuration.Customer);

            if (customer != null)
            {
                await _genericAttributeService.SaveAttributeAsync(customer, NopCustomerDefaults.SelectedMultiFactorAuthenticationProviderAttribute, string.Empty);
            }

            return(new NullJsonResult());
        }
Пример #25
0
        /// <returns>A task that represents the asynchronous operation</returns>
        public virtual async Task <IActionResult> Create(VendorModel model, bool continueEditing, IFormCollection form)
        {
            if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageVendors))
            {
                return(AccessDeniedView());
            }

            //parse vendor attributes
            var vendorAttributesXml = await ParseVendorAttributesAsync(form);

            (await _vendorAttributeParser.GetAttributeWarningsAsync(vendorAttributesXml)).ToList()
            .ForEach(warning => ModelState.AddModelError(string.Empty, warning));

            if (ModelState.IsValid)
            {
                var vendor = model.ToEntity <Vendor>();
                await _vendorService.InsertVendorAsync(vendor);

                //activity log
                await _customerActivityService.InsertActivityAsync("AddNewVendor",
                                                                   string.Format(await _localizationService.GetResourceAsync("ActivityLog.AddNewVendor"), vendor.Id), vendor);

                //search engine name
                model.SeName = await _urlRecordService.ValidateSeNameAsync(vendor, model.SeName, vendor.Name, true);

                await _urlRecordService.SaveSlugAsync(vendor, model.SeName, 0);

                //address
                var address = model.Address.ToEntity <Address>();
                address.CreatedOnUtc = DateTime.UtcNow;

                //some validation
                if (address.CountryId == 0)
                {
                    address.CountryId = null;
                }
                if (address.StateProvinceId == 0)
                {
                    address.StateProvinceId = null;
                }
                await _addressService.InsertAddressAsync(address);

                vendor.AddressId = address.Id;
                await _vendorService.UpdateVendorAsync(vendor);

                //vendor attributes
                await _genericAttributeService.SaveAttributeAsync(vendor, NopVendorDefaults.VendorAttributes, vendorAttributesXml);

                //locales
                await UpdateLocalesAsync(vendor, model);

                //update picture seo file name
                await UpdatePictureSeoNamesAsync(vendor);

                _notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Vendors.Added"));

                if (!continueEditing)
                {
                    return(RedirectToAction("List"));
                }

                return(RedirectToAction("Edit", new { id = vendor.Id }));
            }

            //prepare model
            model = await _vendorModelFactory.PrepareVendorModelAsync(model, null, true);

            //if we got this far, something failed, redisplay form
            return(View(model));
        }
        /// <summary>
        /// Handle shopping cart changed event
        /// </summary>
        /// <param name="cartItem">Shopping cart item</param>
        /// <returns>A task that represents the asynchronous operation</returns>
        public async Task HandleShoppingCartChangedEventAsync(ShoppingCartItem cartItem)
        {
            //whether marketing automation is enabled
            if (!_sendinblueSettings.UseMarketingAutomation)
            {
                return;
            }

            var customer = await _customerService.GetCustomerByIdAsync(cartItem.CustomerId);

            try
            {
                //create API client
                var client = CreateMarketingAutomationClient();

                //first, try to identify current customer
                await client.IdentifyAsync(new Identify(customer.Email));

                //get shopping cart GUID
                var shoppingCartGuid = await _genericAttributeService
                                       .GetAttributeAsync <Guid?>(customer, SendinblueDefaults.ShoppingCartGuidAttribute);

                //create track event object
                var trackEvent = new TrackEvent(customer.Email, string.Empty);

                //get current customer's shopping cart
                var store = await _storeContext.GetCurrentStoreAsync();

                var cart = await _shoppingCartService
                           .GetShoppingCartAsync(customer, ShoppingCartType.ShoppingCart, store.Id);

                if (cart.Any())
                {
                    //get URL helper
                    var urlHelper = _urlHelperFactory.GetUrlHelper(_actionContextAccessor.ActionContext);

                    //get shopping cart amounts
                    var(_, cartDiscount, _, cartSubtotal, _) = await _orderTotalCalculationService.GetShoppingCartSubTotalAsync(cart,
                                                                                                                                await _workContext.GetTaxDisplayTypeAsync() == TaxDisplayType.IncludingTax);

                    var cartTax = await _orderTotalCalculationService.GetTaxTotalAsync(cart, false);

                    var cartShipping = await _orderTotalCalculationService.GetShoppingCartShippingTotalAsync(cart);

                    var(cartTotal, _, _, _, _, _) = await _orderTotalCalculationService.GetShoppingCartTotalAsync(cart, false, false);

                    //get products data by shopping cart items
                    var itemsData = await cart.Where(item => item.ProductId != 0).SelectAwait(async item =>
                    {
                        var product = await _productService.GetProductByIdAsync(item.ProductId);

                        //try to get product attribute combination
                        var combination = await _productAttributeParser.FindProductAttributeCombinationAsync(product, item.AttributesXml);

                        //get default product picture
                        var picture = await _pictureService.GetProductPictureAsync(product, item.AttributesXml);

                        //get product SEO slug name
                        var seName = await _urlRecordService.GetSeNameAsync(product);

                        //create product data
                        return(new
                        {
                            id = product.Id,
                            name = product.Name,
                            variant_id = combination?.Id ?? product.Id,
                            variant_name = combination?.Sku ?? product.Name,
                            sku = combination?.Sku ?? product.Sku,
                            category = await(await _categoryService.GetProductCategoriesByProductIdAsync(item.ProductId)).AggregateAwaitAsync(",", async(all, pc) =>
                            {
                                var res = (await _categoryService.GetCategoryByIdAsync(pc.CategoryId)).Name;
                                res = all == "," ? res : all + ", " + res;
                                return res;
                            }),
                            url = urlHelper.RouteUrl("Product", new { SeName = seName }, _webHelper.GetCurrentRequestProtocol()),
                            image = (await _pictureService.GetPictureUrlAsync(picture)).Url,
                            quantity = item.Quantity,
                            price = (await _shoppingCartService.GetSubTotalAsync(item, true)).subTotal
                        });
                    }).ToArrayAsync();

                    //prepare cart data
                    var cartData = new
                    {
                        affiliation      = store.Name,
                        subtotal         = cartSubtotal,
                        shipping         = cartShipping ?? decimal.Zero,
                        total_before_tax = cartSubtotal + cartShipping ?? decimal.Zero,
                        tax      = cartTax,
                        discount = cartDiscount,
                        revenue  = cartTotal ?? decimal.Zero,
                        url      = urlHelper.RouteUrl("ShoppingCart", null, _webHelper.GetCurrentRequestProtocol()),
                        currency = (await _currencyService.GetCurrencyByIdAsync(_currencySettings.PrimaryStoreCurrencyId))?.CurrencyCode,
                        //gift_wrapping = string.Empty, //currently we can't get this value
                        items = itemsData
                    };

                    //if there is a single item in the cart, so the cart is just created
                    if (cart.Count == 1)
                    {
                        shoppingCartGuid = Guid.NewGuid();
                    }
                    else
                    {
                        //otherwise cart is updated
                        shoppingCartGuid ??= Guid.NewGuid();
                    }
                    trackEvent.EventName = SendinblueDefaults.CartUpdatedEventName;
                    trackEvent.EventData = new { id = $"cart:{shoppingCartGuid}", data = cartData };
                }
                else
                {
                    //there are no items in the cart, so the cart is deleted
                    shoppingCartGuid ??= Guid.NewGuid();
                    trackEvent.EventName = SendinblueDefaults.CartDeletedEventName;
                    trackEvent.EventData = new { id = $"cart:{shoppingCartGuid}" };
                }

                //track event
                await client.TrackEventAsync(trackEvent);

                //update GUID for the current customer's shopping cart
                await _genericAttributeService.SaveAttributeAsync(customer, SendinblueDefaults.ShoppingCartGuidAttribute, shoppingCartGuid);
            }
            catch (Exception exception)
            {
                //log full error
                await _logger.ErrorAsync($"Sendinblue Marketing Automation error: {exception.Message}.", exception, customer);
            }
        }
Пример #27
0
        /// <returns>A task that represents the asynchronous operation</returns>
        public virtual async Task <IActionResult> ApplyVendorSubmit(ApplyVendorModel model, bool captchaValid, IFormFile uploadedFile, IFormCollection form)
        {
            if (!_vendorSettings.AllowCustomersToApplyForVendorAccount)
            {
                return(RedirectToRoute("Homepage"));
            }

            if (!await _customerService.IsRegisteredAsync(await _workContext.GetCurrentCustomerAsync()))
            {
                return(Challenge());
            }

            if (await _customerService.IsAdminAsync(await _workContext.GetCurrentCustomerAsync()))
            {
                ModelState.AddModelError("", await _localizationService.GetResourceAsync("Vendors.ApplyAccount.IsAdmin"));
            }

            //validate CAPTCHA
            if (_captchaSettings.Enabled && _captchaSettings.ShowOnApplyVendorPage && !captchaValid)
            {
                ModelState.AddModelError("", await _localizationService.GetResourceAsync("Common.WrongCaptchaMessage"));
            }

            var pictureId = 0;

            if (uploadedFile != null && !string.IsNullOrEmpty(uploadedFile.FileName))
            {
                try
                {
                    var contentType         = uploadedFile.ContentType;
                    var vendorPictureBinary = await _downloadService.GetDownloadBitsAsync(uploadedFile);

                    var picture = await _pictureService.InsertPictureAsync(vendorPictureBinary, contentType, null);

                    if (picture != null)
                    {
                        pictureId = picture.Id;
                    }
                }
                catch (Exception)
                {
                    ModelState.AddModelError("", await _localizationService.GetResourceAsync("Vendors.ApplyAccount.Picture.ErrorMessage"));
                }
            }

            //vendor attributes
            var vendorAttributesXml = await ParseVendorAttributesAsync(form);

            (await _vendorAttributeParser.GetAttributeWarningsAsync(vendorAttributesXml)).ToList()
            .ForEach(warning => ModelState.AddModelError(string.Empty, warning));

            if (ModelState.IsValid)
            {
                var description = Core.Html.HtmlHelper.FormatText(model.Description, false, false, true, false, false, false);
                //disabled by default
                var vendor = new Vendor
                {
                    Name  = model.Name,
                    Email = model.Email,
                    //some default settings
                    PageSize = 6,
                    AllowCustomersToSelectPageSize = true,
                    PageSizeOptions = _vendorSettings.DefaultVendorPageSizeOptions,
                    PictureId       = pictureId,
                    Description     = description
                };
                await _vendorService.InsertVendorAsync(vendor);

                //search engine name (the same as vendor name)
                var seName = await _urlRecordService.ValidateSeNameAsync(vendor, vendor.Name, vendor.Name, true);

                await _urlRecordService.SaveSlugAsync(vendor, seName, 0);

                //associate to the current customer
                //but a store owner will have to manually add this customer role to "Vendors" role
                //if he wants to grant access to admin area
                (await _workContext.GetCurrentCustomerAsync()).VendorId = vendor.Id;
                await _customerService.UpdateCustomerAsync(await _workContext.GetCurrentCustomerAsync());

                //update picture seo file name
                await UpdatePictureSeoNamesAsync(vendor);

                //save vendor attributes
                await _genericAttributeService.SaveAttributeAsync(vendor, NopVendorDefaults.VendorAttributes, vendorAttributesXml);

                //notify store owner here (email)
                await _workflowMessageService.SendNewVendorAccountApplyStoreOwnerNotificationAsync(await _workContext.GetCurrentCustomerAsync(),
                                                                                                   vendor, _localizationSettings.DefaultAdminLanguageId);

                model.DisableFormInput = true;
                model.Result           = await _localizationService.GetResourceAsync("Vendors.ApplyAccount.Submitted");

                return(View(model));
            }

            //If we got this far, something failed, redisplay form
            model = await _vendorModelFactory.PrepareApplyVendorModelAsync(model, false, true, vendorAttributesXml);

            return(View(model));
        }
Пример #28
0
        public async Task <IActionResult> Register(RegisterViewModel model, string returnUrl)
        {
            if (_workContext.CurrentUser.IsRegistered())
            {
                //Already registered user.
                await _authenticationService.SignOutAsync();

                //Save a new record
                _workContext.CurrentUser = await _userService.InsertGuestUserAsync();
            }
            var user = _workContext.CurrentUser;

            user.RegisteredInTenantId = _tenantContext.CurrentTenant.Id;

            if (ModelState.IsValid)
            {
                if (_userSettings.UsernamesEnabled && model.Username != null)
                {
                    model.Username = model.Username.Trim();
                }

                var registrationRequest = new UserRegistrationRequest(
                    user,
                    model.Email,
                    _userSettings.UsernamesEnabled ? model.Username : model.Email,
                    model.Password,
                    _userSettings.DefaultPasswordFormat,
                    _tenantContext.CurrentTenant.Id);
                var registrationResult = await _userRegistrationService.RegisterUserAsync(registrationRequest);

                if (registrationResult.Success)
                {
                    //properties
                    if (_dateTimeSettings.AllowUsersToSetTimeZone)
                    {
                        await _genericAttributeService.SaveAttributeAsync(user, UserDefaults.TimeZoneIdAttribute, model.TimeZoneId);
                    }

                    //form fields
                    if (_userSettings.GenderEnabled)
                    {
                        await _genericAttributeService.SaveAttributeAsync(user, UserDefaults.GenderAttribute, model.Gender);
                    }
                    await _genericAttributeService.SaveAttributeAsync(user, UserDefaults.FirstNameAttribute, model.FirstName);

                    await _genericAttributeService.SaveAttributeAsync(user, UserDefaults.LastNameAttribute, model.LastName);

                    if (_userSettings.DateOfBirthEnabled)
                    {
                        var dateOfBirth = model.ParseDateOfBirth();
                        await _genericAttributeService.SaveAttributeAsync(user, UserDefaults.DateOfBirthAttribute, dateOfBirth);
                    }
                    if (_userSettings.PhoneEnabled)
                    {
                        await _genericAttributeService.SaveAttributeAsync(user, UserDefaults.PhoneAttribute, model.Phone);
                    }

                    //login
                    await _authenticationService.SignInAsync(user, true);

                    if (string.IsNullOrEmpty(returnUrl) || !Url.IsLocalUrl(returnUrl))
                    {
                        return(RedirectToRoute("HomePage"));
                    }

                    return(Redirect(returnUrl));
                }

                //errors
                foreach (var error in registrationResult.Errors)
                {
                    ModelState.AddModelError("", error);
                }
            }

            //If we got this far, something failed, redisplay form
            model = await _userAccountModelFactory.PrepareRegisterModel(model, true);

            return(View(model));
        }
        private async Task <string> GetEcommerceScriptAsync(Order order)
        {
            var analyticsTrackingScript = _googleAnalyticsSettings.TrackingScript + "\n";

            analyticsTrackingScript = analyticsTrackingScript.Replace("{GOOGLEID}", _googleAnalyticsSettings.GoogleId);
            //remove {ECOMMERCE} (used in previous versions of the plugin)
            analyticsTrackingScript = analyticsTrackingScript.Replace("{ECOMMERCE}", "");
            //remove {CustomerID} (used in previous versions of the plugin)
            analyticsTrackingScript = analyticsTrackingScript.Replace("{CustomerID}", "");

            //whether to include customer identifier
            var customerIdCode = string.Empty;

            if (_googleAnalyticsSettings.IncludeCustomerId && !await _customerService.IsGuestAsync(await _workContext.GetCurrentCustomerAsync()))
            {
                customerIdCode = $"gtag('set', {{'user_id': '{(await _workContext.GetCurrentCustomerAsync()).Id}'}});{Environment.NewLine}";
            }
            analyticsTrackingScript = analyticsTrackingScript.Replace("{CUSTOMER_TRACKING}", customerIdCode);

            //ecommerce info
            var googleAnalyticsSettings = await _settingService.LoadSettingAsync <GoogleAnalyticsSettings>((await _storeContext.GetCurrentStoreAsync()).Id);

            //ensure that ecommerce tracking code is renderred only once (avoid duplicated data in Google Analytics)
            if (order != null && !await _genericAttributeService.GetAttributeAsync <bool>(order, ORDER_ALREADY_PROCESSED_ATTRIBUTE_NAME))
            {
                var usCulture = new CultureInfo("en-US");

                var analyticsEcommerceScript = @"gtag('event', 'purchase', {
                    'transaction_id': '{ORDERID}',
                    'affiliation': '{SITE}',
                    'value': {TOTAL},
                    'currency': '{CURRENCY}',
                    'tax': {TAX},
                    'shipping': {SHIP},
                    'items': [
                    {DETAILS}
                    ]
                });";
                analyticsEcommerceScript = analyticsEcommerceScript.Replace("{ORDERID}", FixIllegalJavaScriptChars(order.CustomOrderNumber));
                analyticsEcommerceScript = analyticsEcommerceScript.Replace("{SITE}", FixIllegalJavaScriptChars((await _storeContext.GetCurrentStoreAsync()).Name));
                analyticsEcommerceScript = analyticsEcommerceScript.Replace("{TOTAL}", order.OrderTotal.ToString("0.00", usCulture));
                var currencyCode = (await _currencyService.GetCurrencyByIdAsync(_currencySettings.PrimaryStoreCurrencyId)).CurrencyCode;
                analyticsEcommerceScript = analyticsEcommerceScript.Replace("{CURRENCY}", currencyCode);
                analyticsEcommerceScript = analyticsEcommerceScript.Replace("{TAX}", order.OrderTax.ToString("0.00", usCulture));
                var orderShipping = googleAnalyticsSettings.IncludingTax ? order.OrderShippingInclTax : order.OrderShippingExclTax;
                analyticsEcommerceScript = analyticsEcommerceScript.Replace("{SHIP}", orderShipping.ToString("0.00", usCulture));

                var sb = new StringBuilder();
                var listingPosition = 1;
                foreach (var item in await _orderService.GetOrderItemsAsync(order.Id))
                {
                    if (!string.IsNullOrEmpty(sb.ToString()))
                    {
                        sb.AppendLine(",");
                    }

                    var analyticsEcommerceDetailScript = @"{
                    'id': '{PRODUCTSKU}',
                    'name': '{PRODUCTNAME}',
                    'category': '{CATEGORYNAME}',
                    'list_position': {LISTPOSITION},
                    'quantity': {QUANTITY},
                    'price': '{UNITPRICE}'
                    }
                    ";

                    var product = await _productService.GetProductByIdAsync(item.ProductId);

                    var sku = await _productService.FormatSkuAsync(product, item.AttributesXml);

                    if (string.IsNullOrEmpty(sku))
                    {
                        sku = product.Id.ToString();
                    }

                    analyticsEcommerceDetailScript = analyticsEcommerceDetailScript.Replace("{PRODUCTSKU}", FixIllegalJavaScriptChars(sku));
                    analyticsEcommerceDetailScript = analyticsEcommerceDetailScript.Replace("{PRODUCTNAME}", FixIllegalJavaScriptChars(product.Name));
                    var category = (await _categoryService.GetCategoryByIdAsync((await _categoryService.GetProductCategoriesByProductIdAsync(item.ProductId)).FirstOrDefault()?.CategoryId ?? 0))?.Name;
                    analyticsEcommerceDetailScript = analyticsEcommerceDetailScript.Replace("{CATEGORYNAME}", FixIllegalJavaScriptChars(category));
                    analyticsEcommerceDetailScript = analyticsEcommerceDetailScript.Replace("{LISTPOSITION}", listingPosition.ToString());
                    var unitPrice = googleAnalyticsSettings.IncludingTax ? item.UnitPriceInclTax : item.UnitPriceExclTax;
                    analyticsEcommerceDetailScript = analyticsEcommerceDetailScript.Replace("{QUANTITY}", item.Quantity.ToString());
                    analyticsEcommerceDetailScript = analyticsEcommerceDetailScript.Replace("{UNITPRICE}", unitPrice.ToString("0.00", usCulture));
                    sb.AppendLine(analyticsEcommerceDetailScript);

                    listingPosition++;
                }

                analyticsEcommerceScript = analyticsEcommerceScript.Replace("{DETAILS}", sb.ToString());

                analyticsTrackingScript = analyticsTrackingScript.Replace("{ECOMMERCE_TRACKING}", analyticsEcommerceScript);

                await _genericAttributeService.SaveAttributeAsync(order, ORDER_ALREADY_PROCESSED_ATTRIBUTE_NAME, true);
            }
            else
            {
                analyticsTrackingScript = analyticsTrackingScript.Replace("{ECOMMERCE_TRACKING}", "");
            }

            return(analyticsTrackingScript);
        }
        /// <summary>
        /// Add order items to the request query parameters
        /// </summary>
        /// <param name="parameters">Query parameters</param>
        /// <param name="postProcessPaymentRequest">Payment info required for an order processing</param>
        private async Task AddItemsParametersAsync(IDictionary <string, string> parameters, PostProcessPaymentRequest postProcessPaymentRequest)
        {
            //upload order items
            parameters.Add("cmd", "_cart");
            parameters.Add("upload", "1");

            var cartTotal        = decimal.Zero;
            var roundedCartTotal = decimal.Zero;
            var itemCount        = 1;

            //add shopping cart items
            foreach (var item in await _orderService.GetOrderItemsAsync(postProcessPaymentRequest.Order.Id))
            {
                var roundedItemPrice = Math.Round(item.UnitPriceExclTax, 2);

                var product = await _productService.GetProductByIdAsync(item.ProductId);

                //add query parameters
                parameters.Add($"item_name_{itemCount}", product.Name);
                parameters.Add($"amount_{itemCount}", roundedItemPrice.ToString("0.00", CultureInfo.InvariantCulture));
                parameters.Add($"quantity_{itemCount}", item.Quantity.ToString());

                cartTotal        += item.PriceExclTax;
                roundedCartTotal += roundedItemPrice * item.Quantity;
                itemCount++;
            }

            //add checkout attributes as order items
            var checkoutAttributeValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(postProcessPaymentRequest.Order.CheckoutAttributesXml);
            var customer = await _customerService.GetCustomerByIdAsync(postProcessPaymentRequest.Order.CustomerId);

            await foreach (var(attribute, values) in checkoutAttributeValues)
            {
                await foreach (var attributeValue in values)
                {
                    var(attributePrice, _) = await _taxService.GetCheckoutAttributePriceAsync(attribute, attributeValue, false, customer);

                    var roundedAttributePrice = Math.Round(attributePrice, 2);

                    //add query parameters
                    if (attribute == null)
                    {
                        continue;
                    }

                    parameters.Add($"item_name_{itemCount}", attribute.Name);
                    parameters.Add($"amount_{itemCount}", roundedAttributePrice.ToString("0.00", CultureInfo.InvariantCulture));
                    parameters.Add($"quantity_{itemCount}", "1");

                    cartTotal        += attributePrice;
                    roundedCartTotal += roundedAttributePrice;
                    itemCount++;
                }
            }

            //add shipping fee as a separate order item, if it has price
            var roundedShippingPrice = Math.Round(postProcessPaymentRequest.Order.OrderShippingExclTax, 2);

            if (roundedShippingPrice > decimal.Zero)
            {
                parameters.Add($"item_name_{itemCount}", "Shipping fee");
                parameters.Add($"amount_{itemCount}", roundedShippingPrice.ToString("0.00", CultureInfo.InvariantCulture));
                parameters.Add($"quantity_{itemCount}", "1");

                cartTotal        += postProcessPaymentRequest.Order.OrderShippingExclTax;
                roundedCartTotal += roundedShippingPrice;
                itemCount++;
            }

            //add payment method additional fee as a separate order item, if it has price
            var roundedPaymentMethodPrice = Math.Round(postProcessPaymentRequest.Order.PaymentMethodAdditionalFeeExclTax, 2);

            if (roundedPaymentMethodPrice > decimal.Zero)
            {
                parameters.Add($"item_name_{itemCount}", "Payment method fee");
                parameters.Add($"amount_{itemCount}", roundedPaymentMethodPrice.ToString("0.00", CultureInfo.InvariantCulture));
                parameters.Add($"quantity_{itemCount}", "1");

                cartTotal        += postProcessPaymentRequest.Order.PaymentMethodAdditionalFeeExclTax;
                roundedCartTotal += roundedPaymentMethodPrice;
                itemCount++;
            }

            //add tax as a separate order item, if it has positive amount
            var roundedTaxAmount = Math.Round(postProcessPaymentRequest.Order.OrderTax, 2);

            if (roundedTaxAmount > decimal.Zero)
            {
                parameters.Add($"item_name_{itemCount}", "Tax amount");
                parameters.Add($"amount_{itemCount}", roundedTaxAmount.ToString("0.00", CultureInfo.InvariantCulture));
                parameters.Add($"quantity_{itemCount}", "1");

                cartTotal        += postProcessPaymentRequest.Order.OrderTax;
                roundedCartTotal += roundedTaxAmount;
            }

            if (cartTotal > postProcessPaymentRequest.Order.OrderTotal)
            {
                //get the difference between what the order total is and what it should be and use that as the "discount"
                var discountTotal = Math.Round(cartTotal - postProcessPaymentRequest.Order.OrderTotal, 2);
                roundedCartTotal -= discountTotal;

                //gift card or rewarded point amount applied to cart in nopCommerce - shows in PayPal as "discount"
                parameters.Add("discount_amount_cart", discountTotal.ToString("0.00", CultureInfo.InvariantCulture));
            }

            //save order total that actually sent to PayPal (used for PDT order total validation)
            await _genericAttributeService.SaveAttributeAsync(postProcessPaymentRequest.Order, PayPalHelper.OrderTotalSentToPayPal, roundedCartTotal);
        }