Try your search with a different keyword or use * as a wildcard.
using System.Globalization;
using System.Text;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Nop.Core;
using Nop.Core.Domain.Catalog;
using Nop.Core.Domain.Common;
using Nop.Core.Domain.Customers;
using Nop.Core.Domain.Forums;
using Nop.Core.Domain.Gdpr;
using Nop.Core.Domain.Messages;
using Nop.Core.Domain.Tax;
using Nop.Core.Events;
using Nop.Services.Attributes;
using Nop.Services.Common;
using Nop.Services.Customers;
using Nop.Services.ExportImport;
using Nop.Services.Forums;
using Nop.Services.Gdpr;
using Nop.Services.Helpers;
using Nop.Services.Localization;
using Nop.Services.Logging;
using Nop.Services.Messages;
using Nop.Services.Orders;
using Nop.Services.Security;
using Nop.Services.Tax;
using Nop.Web.Areas.Admin.Factories;
using Nop.Web.Areas.Admin.Infrastructure.Mapper.Extensions;
using Nop.Web.Areas.Admin.Models.Customers;
using Nop.Web.Framework.Controllers;
using Nop.Web.Framework.Mvc;
using Nop.Web.Framework.Mvc.Filters;
namespace Nop.Web.Areas.Admin.Controllers;
public partial class CustomerController : BaseAdminController
{
#region Fields
protected readonly CustomerSettings _customerSettings;
protected readonly DateTimeSettings _dateTimeSettings;
protected readonly EmailAccountSettings _emailAccountSettings;
protected readonly ForumSettings _forumSettings;
protected readonly GdprSettings _gdprSettings;
protected readonly IAddressService _addressService;
protected readonly IAttributeParser<AddressAttribute, AddressAttributeValue> _addressAttributeParser;
protected readonly IAttributeParser<CustomerAttribute, CustomerAttributeValue> _customerAttributeParser;
protected readonly IAttributeService<CustomerAttribute, CustomerAttributeValue> _customerAttributeService;
protected readonly ICustomerActivityService _customerActivityService;
protected readonly ICustomerModelFactory _customerModelFactory;
protected readonly ICustomerRegistrationService _customerRegistrationService;
protected readonly ICustomerService _customerService;
protected readonly IDateTimeHelper _dateTimeHelper;
protected readonly IEmailAccountService _emailAccountService;
protected readonly IEventPublisher _eventPublisher;
protected readonly IExportManager _exportManager;
protected readonly IForumService _forumService;
protected readonly IGdprService _gdprService;
protected readonly IGenericAttributeService _genericAttributeService;
protected readonly IImportManager _importManager;
protected readonly ILocalizationService _localizationService;
protected readonly INewsLetterSubscriptionService _newsLetterSubscriptionService;
protected readonly INotificationService _notificationService;
protected readonly IPermissionService _permissionService;
protected readonly IQueuedEmailService _queuedEmailService;
protected readonly IRewardPointService _rewardPointService;
protected readonly IStoreContext _storeContext;
protected readonly ITaxService _taxService;
protected readonly IWorkContext _workContext;
protected readonly IWorkflowMessageService _workflowMessageService;
protected readonly TaxSettings _taxSettings;
private static readonly char[] _separator = [','];
#endregion
#region Ctor
public CustomerController(CustomerSettings customerSettings,
DateTimeSettings dateTimeSettings,
EmailAccountSettings emailAccountSettings,
ForumSettings forumSettings,
GdprSettings gdprSettings,
IAddressService addressService,
IAttributeParser<AddressAttribute, AddressAttributeValue> addressAttributeParser,
IAttributeParser<CustomerAttribute, CustomerAttributeValue> customerAttributeParser,
IAttributeService<CustomerAttribute, CustomerAttributeValue> customerAttributeService,
ICustomerActivityService customerActivityService,
ICustomerModelFactory customerModelFactory,
ICustomerRegistrationService customerRegistrationService,
ICustomerService customerService,
IDateTimeHelper dateTimeHelper,
IEmailAccountService emailAccountService,
IEventPublisher eventPublisher,
IExportManager exportManager,
IForumService forumService,
IGdprService gdprService,
IGenericAttributeService genericAttributeService,
IImportManager importManager,
ILocalizationService localizationService,
INewsLetterSubscriptionService newsLetterSubscriptionService,
INotificationService notificationService,
IPermissionService permissionService,
IQueuedEmailService queuedEmailService,
IRewardPointService rewardPointService,
IStoreContext storeContext,
ITaxService taxService,
IWorkContext workContext,
IWorkflowMessageService workflowMessageService,
TaxSettings taxSettings)
{
_customerSettings = customerSettings;
_dateTimeSettings = dateTimeSettings;
_emailAccountSettings = emailAccountSettings;
_forumSettings = forumSettings;
_gdprSettings = gdprSettings;
_addressService = addressService;
_addressAttributeParser = addressAttributeParser;
_customerAttributeParser = customerAttributeParser;
_customerAttributeService = customerAttributeService;
_customerActivityService = customerActivityService;
_customerModelFactory = customerModelFactory;
_customerRegistrationService = customerRegistrationService;
_customerService = customerService;
_dateTimeHelper = dateTimeHelper;
_emailAccountService = emailAccountService;
_eventPublisher = eventPublisher;
_exportManager = exportManager;
_forumService = forumService;
_gdprService = gdprService;
_genericAttributeService = genericAttributeService;
_importManager = importManager;
_localizationService = localizationService;
_newsLetterSubscriptionService = newsLetterSubscriptionService;
_notificationService = notificationService;
_permissionService = permissionService;
_queuedEmailService = queuedEmailService;
_rewardPointService = rewardPointService;
_storeContext = storeContext;
_taxService = taxService;
_workContext = workContext;
_workflowMessageService = workflowMessageService;
_taxSettings = taxSettings;
}
#endregion
#region Utilities
protected virtual async Task<string> ValidateCustomerRolesAsync(IList<CustomerRole> customerRoles, IList<CustomerRole> existingCustomerRoles)
{
ArgumentNullException.ThrowIfNull(customerRoles);
ArgumentNullException.ThrowIfNull(existingCustomerRoles);
//check ACL permission to manage customer roles
var rolesToAdd = customerRoles.Except(existingCustomerRoles, new CustomerRoleComparerByName());
var rolesToDelete = existingCustomerRoles.Except(customerRoles, new CustomerRoleComparerByName());
if (rolesToAdd.Any(role => role.SystemName != NopCustomerDefaults.RegisteredRoleName) || rolesToDelete.Any())
{
if (!await _permissionService.AuthorizeAsync(StandardPermission.Configuration.MANAGE_ACL))
return await _localizationService.GetResourceAsync("Admin.Customers.Customers.CustomerRolesManagingError");
}
//ensure a customer is not added to both 'Guests' and 'Registered' customer roles
//ensure that a customer is in at least one required role ('Guests' and 'Registered')
var isInGuestsRole = customerRoles.FirstOrDefault(cr => cr.SystemName == NopCustomerDefaults.GuestsRoleName) != null;
var isInRegisteredRole = customerRoles.FirstOrDefault(cr => cr.SystemName == NopCustomerDefaults.RegisteredRoleName) != null;
if (isInGuestsRole && isInRegisteredRole)
return await _localizationService.GetResourceAsync("Admin.Customers.Customers.GuestsAndRegisteredRolesError");
if (!isInGuestsRole && !isInRegisteredRole)
return await _localizationService.GetResourceAsync("Admin.Customers.Customers.AddCustomerToGuestsOrRegisteredRoleError");
//no errors
return string.Empty;
}
protected virtual async Task<string> ParseCustomCustomerAttributesAsync(IFormCollection form)
{
ArgumentNullException.ThrowIfNull(form);
var attributesXml = string.Empty;
var customerAttributes = await _customerAttributeService.GetAllAttributesAsync();
foreach (var attribute in customerAttributes)
{
var controlId = $"{NopCustomerServicesDefaults.CustomerAttributePrefix}{attribute.Id}";
StringValues ctrlAttributes;
switch (attribute.AttributeControlType)
{
case AttributeControlType.DropdownList:
case AttributeControlType.RadioList:
ctrlAttributes = form[controlId];
if (!StringValues.IsNullOrEmpty(ctrlAttributes))
{
var selectedAttributeId = int.Parse(ctrlAttributes);
if (selectedAttributeId > 0)
attributesXml = _customerAttributeParser.AddAttribute(attributesXml,
attribute, selectedAttributeId.ToString());
}
break;
case AttributeControlType.Checkboxes:
var cblAttributes = form[controlId];
if (!StringValues.IsNullOrEmpty(cblAttributes))
{
foreach (var item in cblAttributes.ToString()
.Split(_separator, StringSplitOptions.RemoveEmptyEntries))
{
var selectedAttributeId = int.Parse(item);
if (selectedAttributeId > 0)
attributesXml = _customerAttributeParser.AddAttribute(attributesXml,
attribute, selectedAttributeId.ToString());
}
}
break;
case AttributeControlType.ReadonlyCheckboxes:
//load read-only (already server-side selected) values
var attributeValues = await _customerAttributeService.GetAttributeValuesAsync(attribute.Id);
foreach (var selectedAttributeId in attributeValues
.Where(v => v.IsPreSelected)
.Select(v => v.Id)
.ToList())
{
attributesXml = _customerAttributeParser.AddAttribute(attributesXml,
attribute, selectedAttributeId.ToString());
}
break;
case AttributeControlType.TextBox:
case AttributeControlType.MultilineTextbox:
ctrlAttributes = form[controlId];
if (!StringValues.IsNullOrEmpty(ctrlAttributes))
{
var enteredText = ctrlAttributes.ToString().Trim();
attributesXml = _customerAttributeParser.AddAttribute(attributesXml,
attribute, enteredText);
}
break;
case AttributeControlType.Datepicker:
case AttributeControlType.ColorSquares:
case AttributeControlType.ImageSquares:
case AttributeControlType.FileUpload:
//not supported customer attributes
default:
break;
}
}
return attributesXml;
}
protected virtual async Task<bool> SecondAdminAccountExistsAsync(Customer customer)
{
var customers = await _customerService.GetAllCustomersAsync(customerRoleIds: [(await _customerService.GetCustomerRoleBySystemNameAsync(NopCustomerDefaults.AdministratorsRoleName)).Id]);
return customers.Any(c => c.Active && c.Id != customer.Id);
}
#endregion
#region Customers
public virtual IActionResult Index()
{
return RedirectToAction("List");
}
[CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)]
public virtual async Task<IActionResult> List()
{
//prepare model
var model = await _customerModelFactory.PrepareCustomerSearchModelAsync(new CustomerSearchModel());
return View(model);
}
[HttpPost]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)]
public virtual async Task<IActionResult> CustomerList(CustomerSearchModel searchModel)
{
//prepare model
var model = await _customerModelFactory.PrepareCustomerListModelAsync(searchModel);
return Json(model);
}
[CheckPermission(StandardPermission.Customers.CUSTOMERS_CREATE_EDIT_DELETE)]
public virtual async Task<IActionResult> Create()
{
//prepare model
var model = await _customerModelFactory.PrepareCustomerModelAsync(new CustomerModel(), null);
return View(model);
}
[HttpPost, ParameterBasedOnFormName("save-continue", "continueEditing")]
[FormValueRequired("save", "save-continue")]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_CREATE_EDIT_DELETE)]
public virtual async Task<IActionResult> Create(CustomerModel model, bool continueEditing, IFormCollection form)
{
if (!string.IsNullOrWhiteSpace(model.Email) && await _customerService.GetCustomerByEmailAsync(model.Email) != null)
ModelState.AddModelError(string.Empty, "Email is already registered");
if (!string.IsNullOrWhiteSpace(model.Username) && _customerSettings.UsernamesEnabled &&
await _customerService.GetCustomerByUsernameAsync(model.Username) != null)
{
ModelState.AddModelError(string.Empty, "Username is already registered");
}
//validate customer roles
var allCustomerRoles = await _customerService.GetAllCustomerRolesAsync(true);
var newCustomerRoles = new List<CustomerRole>();
foreach (var customerRole in allCustomerRoles)
if (model.SelectedCustomerRoleIds.Contains(customerRole.Id))
newCustomerRoles.Add(customerRole);
var customerRolesError = await ValidateCustomerRolesAsync(newCustomerRoles, new List<CustomerRole>());
if (!string.IsNullOrEmpty(customerRolesError))
{
ModelState.AddModelError(string.Empty, customerRolesError);
_notificationService.ErrorNotification(customerRolesError);
}
// Ensure that valid email address is entered if Registered role is checked to avoid registered customers with empty email address
if (newCustomerRoles.Any() && newCustomerRoles.FirstOrDefault(c => c.SystemName == NopCustomerDefaults.RegisteredRoleName) != null &&
!CommonHelper.IsValidEmail(model.Email))
{
ModelState.AddModelError(string.Empty, await _localizationService.GetResourceAsync("Admin.Customers.Customers.ValidEmailRequiredRegisteredRole"));
_notificationService.ErrorNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.ValidEmailRequiredRegisteredRole"));
}
//custom customer attributes
var customerAttributesXml = await ParseCustomCustomerAttributesAsync(form);
if (newCustomerRoles.Any() && newCustomerRoles.FirstOrDefault(c => c.SystemName == NopCustomerDefaults.RegisteredRoleName) != null)
{
var customerAttributeWarnings = await _customerAttributeParser.GetAttributeWarningsAsync(customerAttributesXml);
foreach (var error in customerAttributeWarnings)
{
ModelState.AddModelError(string.Empty, error);
}
}
if (ModelState.IsValid)
{
//fill entity from model
var customer = model.ToEntity<Customer>();
var currentStore = await _storeContext.GetCurrentStoreAsync();
customer.CustomerGuid = Guid.NewGuid();
customer.CreatedOnUtc = DateTime.UtcNow;
customer.LastActivityDateUtc = DateTime.UtcNow;
customer.RegisteredInStoreId = currentStore.Id;
//form fields
if (_dateTimeSettings.AllowCustomersToSetTimeZone)
customer.TimeZoneId = model.TimeZoneId;
if (_customerSettings.GenderEnabled)
customer.Gender = model.Gender;
if (_customerSettings.FirstNameEnabled)
customer.FirstName = model.FirstName;
if (_customerSettings.LastNameEnabled)
customer.LastName = model.LastName;
if (_customerSettings.DateOfBirthEnabled)
customer.DateOfBirth = model.DateOfBirth;
if (_customerSettings.CompanyEnabled)
customer.Company = model.Company;
if (_customerSettings.StreetAddressEnabled)
customer.StreetAddress = model.StreetAddress;
if (_customerSettings.StreetAddress2Enabled)
customer.StreetAddress2 = model.StreetAddress2;
if (_customerSettings.ZipPostalCodeEnabled)
customer.ZipPostalCode = model.ZipPostalCode;
if (_customerSettings.CityEnabled)
customer.City = model.City;
if (_customerSettings.CountyEnabled)
customer.County = model.County;
if (_customerSettings.CountryEnabled)
customer.CountryId = model.CountryId;
if (_customerSettings.CountryEnabled && _customerSettings.StateProvinceEnabled)
customer.StateProvinceId = model.StateProvinceId;
if (_customerSettings.PhoneEnabled)
customer.Phone = model.Phone;
if (_customerSettings.FaxEnabled)
customer.Fax = model.Fax;
customer.CustomCustomerAttributesXML = customerAttributesXml;
await _customerService.InsertCustomerAsync(customer);
//password
if (!string.IsNullOrWhiteSpace(model.Password))
{
var changePassRequest = new ChangePasswordRequest(model.Email, false, _customerSettings.DefaultPasswordFormat, model.Password);
var changePassResult = await _customerRegistrationService.ChangePasswordAsync(changePassRequest);
if (!changePassResult.Success)
{
foreach (var changePassError in changePassResult.Errors)
_notificationService.ErrorNotification(changePassError);
}
}
//customer roles
foreach (var customerRole in newCustomerRoles)
{
//ensure that the current customer cannot add to "Administrators" system role if he's not an admin himself
if (customerRole.SystemName == NopCustomerDefaults.AdministratorsRoleName && !await _customerService.IsAdminAsync(await _workContext.GetCurrentCustomerAsync()))
continue;
await _customerService.AddCustomerRoleMappingAsync(new CustomerCustomerRoleMapping { CustomerId = customer.Id, CustomerRoleId = customerRole.Id });
}
await _customerService.UpdateCustomerAsync(customer);
//ensure that a customer with a vendor associated is not in "Administrators" role
//otherwise, he won't have access to other functionality in admin area
if (await _customerService.IsAdminAsync(customer) && customer.VendorId > 0)
{
customer.VendorId = 0;
await _customerService.UpdateCustomerAsync(customer);
_notificationService.ErrorNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.AdminCouldNotbeVendor"));
}
//ensure that a customer in the Vendors role has a vendor account associated.
//otherwise, he will have access to ALL products
if (await _customerService.IsVendorAsync(customer) && customer.VendorId == 0)
{
var vendorRole = await _customerService.GetCustomerRoleBySystemNameAsync(NopCustomerDefaults.VendorsRoleName);
await _customerService.RemoveCustomerRoleMappingAsync(customer, vendorRole);
_notificationService.ErrorNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.CannotBeInVendoRoleWithoutVendorAssociated"));
}
//activity log
await _customerActivityService.InsertActivityAsync("AddNewCustomer",
string.Format(await _localizationService.GetResourceAsync("ActivityLog.AddNewCustomer"), customer.Id), customer);
_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.Added"));
if (!continueEditing)
return RedirectToAction("List");
return RedirectToAction("Edit", new { id = customer.Id });
}
//prepare model
model = await _customerModelFactory.PrepareCustomerModelAsync(model, null, true);
//if we got this far, something failed, redisplay form
return View(model);
}
[CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)]
public virtual async Task<IActionResult> Edit(int id)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(id);
if (customer == null || customer.Deleted)
return RedirectToAction("List");
//prepare model
var model = await _customerModelFactory.PrepareCustomerModelAsync(null, customer);
return View(model);
}
[HttpPost, ParameterBasedOnFormName("save-continue", "continueEditing")]
[FormValueRequired("save", "save-continue")]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_CREATE_EDIT_DELETE)]
public virtual async Task<IActionResult> Edit(CustomerModel model, bool continueEditing, IFormCollection form)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(model.Id);
if (customer == null || customer.Deleted)
return RedirectToAction("List");
//validate customer roles
var allCustomerRoles = await _customerService.GetAllCustomerRolesAsync(true);
var newCustomerRoles = new List<CustomerRole>();
foreach (var customerRole in allCustomerRoles)
if (model.SelectedCustomerRoleIds.Contains(customerRole.Id))
newCustomerRoles.Add(customerRole);
var customerRolesError = await ValidateCustomerRolesAsync(newCustomerRoles, await _customerService.GetCustomerRolesAsync(customer));
if (!string.IsNullOrEmpty(customerRolesError))
{
ModelState.AddModelError(string.Empty, customerRolesError);
_notificationService.ErrorNotification(customerRolesError);
}
// Ensure that valid email address is entered if Registered role is checked to avoid registered customers with empty email address
if (newCustomerRoles.Any() && newCustomerRoles.FirstOrDefault(c => c.SystemName == NopCustomerDefaults.RegisteredRoleName) != null &&
!CommonHelper.IsValidEmail(model.Email))
{
ModelState.AddModelError(string.Empty, await _localizationService.GetResourceAsync("Admin.Customers.Customers.ValidEmailRequiredRegisteredRole"));
_notificationService.ErrorNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.ValidEmailRequiredRegisteredRole"));
}
//custom customer attributes
var customerAttributesXml = await ParseCustomCustomerAttributesAsync(form);
if (newCustomerRoles.Any() && newCustomerRoles.FirstOrDefault(c => c.SystemName == NopCustomerDefaults.RegisteredRoleName) != null)
{
var customerAttributeWarnings = await _customerAttributeParser.GetAttributeWarningsAsync(customerAttributesXml);
foreach (var error in customerAttributeWarnings)
{
ModelState.AddModelError(string.Empty, error);
}
}
if (ModelState.IsValid)
{
try
{
customer.AdminComment = model.AdminComment;
customer.IsTaxExempt = model.IsTaxExempt;
customer.MustChangePassword = model.MustChangePassword;
//prevent deactivation of the last active administrator
if (!await _customerService.IsAdminAsync(customer) || model.Active || await SecondAdminAccountExistsAsync(customer))
customer.Active = model.Active;
else
_notificationService.ErrorNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.AdminAccountShouldExists.Deactivate"));
//email
if (!string.IsNullOrWhiteSpace(model.Email))
await _customerRegistrationService.SetEmailAsync(customer, model.Email, false);
else
customer.Email = model.Email;
//username
if (_customerSettings.UsernamesEnabled)
{
if (!string.IsNullOrWhiteSpace(model.Username))
await _customerRegistrationService.SetUsernameAsync(customer, model.Username);
else
customer.Username = model.Username;
}
//VAT number
if (_taxSettings.EuVatEnabled)
{
var prevVatNumber = customer.VatNumber;
customer.VatNumber = model.VatNumber;
//set VAT number status
if (!string.IsNullOrEmpty(model.VatNumber))
{
if (!model.VatNumber.Equals(prevVatNumber, StringComparison.InvariantCultureIgnoreCase))
{
customer.VatNumberStatusId = (int)(await _taxService.GetVatNumberStatusAsync(model.VatNumber)).vatNumberStatus;
}
}
else
customer.VatNumberStatusId = (int)VatNumberStatus.Empty;
}
//vendor
customer.VendorId = model.VendorId;
//form fields
if (_dateTimeSettings.AllowCustomersToSetTimeZone)
customer.TimeZoneId = model.TimeZoneId;
if (_customerSettings.GenderEnabled)
customer.Gender = model.Gender;
if (_customerSettings.FirstNameEnabled)
customer.FirstName = model.FirstName;
if (_customerSettings.LastNameEnabled)
customer.LastName = model.LastName;
if (_customerSettings.DateOfBirthEnabled)
customer.DateOfBirth = model.DateOfBirth;
if (_customerSettings.CompanyEnabled)
customer.Company = model.Company;
if (_customerSettings.StreetAddressEnabled)
customer.StreetAddress = model.StreetAddress;
if (_customerSettings.StreetAddress2Enabled)
customer.StreetAddress2 = model.StreetAddress2;
if (_customerSettings.ZipPostalCodeEnabled)
customer.ZipPostalCode = model.ZipPostalCode;
if (_customerSettings.CityEnabled)
customer.City = model.City;
if (_customerSettings.CountyEnabled)
customer.County = model.County;
if (_customerSettings.CountryEnabled)
customer.CountryId = model.CountryId;
if (_customerSettings.CountryEnabled && _customerSettings.StateProvinceEnabled)
customer.StateProvinceId = model.StateProvinceId;
if (_customerSettings.PhoneEnabled)
customer.Phone = model.Phone;
if (_customerSettings.FaxEnabled)
customer.Fax = model.Fax;
//custom customer attributes
customer.CustomCustomerAttributesXML = customerAttributesXml;
var currentCustomerRoleIds = await _customerService.GetCustomerRoleIdsAsync(customer, true);
//customer roles
foreach (var customerRole in allCustomerRoles)
{
//ensure that the current customer cannot add/remove to/from "Administrators" system role
//if he's not an admin himself
if (customerRole.SystemName == NopCustomerDefaults.AdministratorsRoleName &&
!await _customerService.IsAdminAsync(await _workContext.GetCurrentCustomerAsync()))
continue;
if (model.SelectedCustomerRoleIds.Contains(customerRole.Id))
{
//new role
if (currentCustomerRoleIds.All(roleId => roleId != customerRole.Id))
await _customerService.AddCustomerRoleMappingAsync(new CustomerCustomerRoleMapping { CustomerId = customer.Id, CustomerRoleId = customerRole.Id });
}
else
{
//prevent attempts to delete the administrator role from the user, if the user is the last active administrator
if (customerRole.SystemName == NopCustomerDefaults.AdministratorsRoleName && !await SecondAdminAccountExistsAsync(customer))
{
_notificationService.ErrorNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.AdminAccountShouldExists.DeleteRole"));
continue;
}
//remove role
if (currentCustomerRoleIds.Any(roleId => roleId == customerRole.Id))
await _customerService.RemoveCustomerRoleMappingAsync(customer, customerRole);
}
}
await _customerService.UpdateCustomerAsync(customer);
//ensure that a customer with a vendor associated is not in "Administrators" role
//otherwise, he won't have access to the other functionality in admin area
if (await _customerService.IsAdminAsync(customer) && customer.VendorId > 0)
{
customer.VendorId = 0;
await _customerService.UpdateCustomerAsync(customer);
_notificationService.ErrorNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.AdminCouldNotbeVendor"));
}
//ensure that a customer in the Vendors role has a vendor account associated.
//otherwise, he will have access to ALL products
if (await _customerService.IsVendorAsync(customer) && customer.VendorId == 0)
{
var vendorRole = await _customerService.GetCustomerRoleBySystemNameAsync(NopCustomerDefaults.VendorsRoleName);
await _customerService.RemoveCustomerRoleMappingAsync(customer, vendorRole);
_notificationService.ErrorNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.CannotBeInVendoRoleWithoutVendorAssociated"));
}
//activity log
await _customerActivityService.InsertActivityAsync("EditCustomer",
string.Format(await _localizationService.GetResourceAsync("ActivityLog.EditCustomer"), customer.Id), customer);
_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.Updated"));
if (!continueEditing)
return RedirectToAction("List");
return RedirectToAction("Edit", new { id = customer.Id });
}
catch (Exception exc)
{
_notificationService.ErrorNotification(exc.Message);
}
}
//prepare model
model = await _customerModelFactory.PrepareCustomerModelAsync(model, customer, true);
//if we got this far, something failed, redisplay form
return View(model);
}
[HttpPost, ActionName("Edit")]
[FormValueRequired("changepassword")]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_CREATE_EDIT_DELETE)]
public virtual async Task<IActionResult> ChangePassword(CustomerModel model)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(model.Id);
if (customer == null)
return RedirectToAction("List");
//ensure that the current customer cannot change passwords of "Administrators" if he's not an admin himself
if (await _customerService.IsAdminAsync(customer) && !await _customerService.IsAdminAsync(await _workContext.GetCurrentCustomerAsync()))
{
_notificationService.ErrorNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.OnlyAdminCanChangePassword"));
return RedirectToAction("Edit", new { id = customer.Id });
}
var changePassRequest = new ChangePasswordRequest(customer.Email,
false, _customerSettings.DefaultPasswordFormat, model.Password);
var changePassResult = await _customerRegistrationService.ChangePasswordAsync(changePassRequest);
if (changePassResult.Success)
_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.PasswordChanged"));
else
foreach (var error in changePassResult.Errors)
_notificationService.ErrorNotification(error);
return RedirectToAction("Edit", new { id = customer.Id });
}
[HttpPost, ActionName("Edit")]
[FormValueRequired("markVatNumberAsValid")]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_CREATE_EDIT_DELETE)]
public virtual async Task<IActionResult> MarkVatNumberAsValid(CustomerModel model)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(model.Id);
if (customer == null)
return RedirectToAction("List");
customer.VatNumberStatusId = (int)VatNumberStatus.Valid;
await _customerService.UpdateCustomerAsync(customer);
return RedirectToAction("Edit", new { id = customer.Id });
}
[HttpPost, ActionName("Edit")]
[FormValueRequired("markVatNumberAsInvalid")]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_CREATE_EDIT_DELETE)]
public virtual async Task<IActionResult> MarkVatNumberAsInvalid(CustomerModel model)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(model.Id);
if (customer == null)
return RedirectToAction("List");
customer.VatNumberStatusId = (int)VatNumberStatus.Invalid;
await _customerService.UpdateCustomerAsync(customer);
return RedirectToAction("Edit", new { id = customer.Id });
}
[HttpPost, ActionName("Edit")]
[FormValueRequired("remove-affiliate")]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_CREATE_EDIT_DELETE)]
public virtual async Task<IActionResult> RemoveAffiliate(CustomerModel model)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(model.Id);
if (customer == null)
return RedirectToAction("List");
customer.AffiliateId = 0;
await _customerService.UpdateCustomerAsync(customer);
return RedirectToAction("Edit", new { id = customer.Id });
}
[HttpPost]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_CREATE_EDIT_DELETE)]
public virtual async Task<IActionResult> RemoveBindMFA(int id)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(id);
if (customer == null)
return RedirectToAction("List");
await _genericAttributeService.SaveAttributeAsync(customer, NopCustomerDefaults.SelectedMultiFactorAuthenticationProviderAttribute, string.Empty);
//raise event
await _eventPublisher.PublishAsync(new CustomerChangeMultiFactorAuthenticationProviderEvent(customer));
_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.UnbindMFAProvider"));
return RedirectToAction("Edit", new { id = customer.Id });
}
[HttpPost]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_CREATE_EDIT_DELETE)]
public virtual async Task<IActionResult> Delete(int id)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(id);
if (customer == null)
return RedirectToAction("List");
try
{
//prevent attempts to delete the user, if it is the last active administrator
if (await _customerService.IsAdminAsync(customer) && !await SecondAdminAccountExistsAsync(customer))
{
_notificationService.ErrorNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.AdminAccountShouldExists.DeleteAdministrator"));
return RedirectToAction("Edit", new { id = customer.Id });
}
//ensure that the current customer cannot delete "Administrators" if he's not an admin himself
if (await _customerService.IsAdminAsync(customer) && !await _customerService.IsAdminAsync(await _workContext.GetCurrentCustomerAsync()))
{
_notificationService.ErrorNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.OnlyAdminCanDeleteAdmin"));
return RedirectToAction("Edit", new { id = customer.Id });
}
//get customer email before deleting customer entity to avoid problems with the changed email after deleting see CustomerSettings.SuffixDeletedCustomers settings
var customerEmail = customer.Email;
//delete
await _customerService.DeleteCustomerAsync(customer);
//remove newsletter subscriptions (if exist)
var subscriptions = await _newsLetterSubscriptionService.GetNewsLetterSubscriptionsByEmailAsync(customerEmail);
foreach (var subscription in subscriptions)
await _newsLetterSubscriptionService.DeleteNewsLetterSubscriptionAsync(subscription);
//activity log
await _customerActivityService.InsertActivityAsync("DeleteCustomer",
string.Format(await _localizationService.GetResourceAsync("ActivityLog.DeleteCustomer"), customer.Id), customer);
_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.Deleted"));
return RedirectToAction("List");
}
catch (Exception exc)
{
_notificationService.ErrorNotification(exc.Message);
return RedirectToAction("Edit", new { id = customer.Id });
}
}
[HttpPost, ActionName("Edit")]
[FormValueRequired("impersonate")]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_IMPERSONATION)]
public virtual async Task<IActionResult> Impersonate(int id)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(id);
if (customer == null)
return RedirectToAction("List");
if (!customer.Active)
{
_notificationService.WarningNotification(
await _localizationService.GetResourceAsync("Admin.Customers.Customers.Impersonate.Inactive"));
return RedirectToAction("Edit", customer.Id);
}
//ensure that a non-admin user cannot impersonate as an administrator
//otherwise, that user can simply impersonate as an administrator and gain additional administrative privileges
var currentCustomer = await _workContext.GetCurrentCustomerAsync();
if (!await _customerService.IsAdminAsync(currentCustomer) && await _customerService.IsAdminAsync(customer))
{
_notificationService.ErrorNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.NonAdminNotImpersonateAsAdminError"));
return RedirectToAction("Edit", customer.Id);
}
//activity log
await _customerActivityService.InsertActivityAsync("Impersonation.Started",
string.Format(await _localizationService.GetResourceAsync("ActivityLog.Impersonation.Started.StoreOwner"), customer.Email, customer.Id), customer);
await _customerActivityService.InsertActivityAsync(customer, "Impersonation.Started",
string.Format(await _localizationService.GetResourceAsync("ActivityLog.Impersonation.Started.Customer"), currentCustomer.Email, currentCustomer.Id), currentCustomer);
//ensure login is not required
customer.RequireReLogin = false;
await _customerService.UpdateCustomerAsync(customer);
await _genericAttributeService.SaveAttributeAsync<int?>(currentCustomer, NopCustomerDefaults.ImpersonatedCustomerIdAttribute, customer.Id);
return RedirectToAction("Index", "Home", new { area = string.Empty });
}
[HttpPost, ActionName("Edit")]
[FormValueRequired("send-welcome-message")]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_CREATE_EDIT_DELETE)]
public virtual async Task<IActionResult> SendWelcomeMessage(CustomerModel model)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(model.Id);
if (customer == null)
return RedirectToAction("List");
await _workflowMessageService.SendCustomerWelcomeMessageAsync(customer, (await _workContext.GetWorkingLanguageAsync()).Id);
_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.SendWelcomeMessage.Success"));
return RedirectToAction("Edit", new { id = customer.Id });
}
[HttpPost, ActionName("Edit")]
[FormValueRequired("resend-activation-message")]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_CREATE_EDIT_DELETE)]
public virtual async Task<IActionResult> ReSendActivationMessage(CustomerModel model)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(model.Id);
if (customer == null)
return RedirectToAction("List");
//email validation message
await _genericAttributeService.SaveAttributeAsync(customer, NopCustomerDefaults.AccountActivationTokenAttribute, Guid.NewGuid().ToString());
await _workflowMessageService.SendCustomerEmailValidationMessageAsync(customer, (await _workContext.GetWorkingLanguageAsync()).Id);
_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.ReSendActivationMessage.Success"));
return RedirectToAction("Edit", new { id = customer.Id });
}
[CheckPermission(StandardPermission.Customers.CUSTOMERS_CREATE_EDIT_DELETE)]
public virtual async Task<IActionResult> SendEmail(CustomerModel model)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(model.Id);
if (customer == null)
return RedirectToAction("List");
try
{
if (string.IsNullOrWhiteSpace(customer.Email))
throw new NopException("Customer email is empty");
if (!CommonHelper.IsValidEmail(customer.Email))
throw new NopException("Customer email is not valid");
if (string.IsNullOrWhiteSpace(model.SendEmail.Subject))
throw new NopException("Email subject is empty");
if (string.IsNullOrWhiteSpace(model.SendEmail.Body))
throw new NopException("Email body is empty");
var emailAccount = (await _emailAccountService.GetEmailAccountByIdAsync(_emailAccountSettings.DefaultEmailAccountId)
?? (await _emailAccountService.GetAllEmailAccountsAsync()).FirstOrDefault())
?? throw new NopException("Email account can't be loaded");
var email = new QueuedEmail
{
Priority = QueuedEmailPriority.High,
EmailAccountId = emailAccount.Id,
FromName = emailAccount.DisplayName,
From = emailAccount.Email,
ToName = await _customerService.GetCustomerFullNameAsync(customer),
To = customer.Email,
Subject = model.SendEmail.Subject,
Body = model.SendEmail.Body,
CreatedOnUtc = DateTime.UtcNow,
DontSendBeforeDateUtc = model.SendEmail.SendImmediately || !model.SendEmail.DontSendBeforeDate.HasValue ?
null : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.SendEmail.DontSendBeforeDate.Value)
};
await _queuedEmailService.InsertQueuedEmailAsync(email);
_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.SendEmail.Queued"));
}
catch (Exception exc)
{
_notificationService.ErrorNotification(exc.Message);
}
return RedirectToAction("Edit", new { id = customer.Id });
}
[CheckPermission(StandardPermission.Customers.CUSTOMERS_CREATE_EDIT_DELETE)]
public virtual async Task<IActionResult> SendPm(CustomerModel model)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(model.Id);
if (customer == null)
return RedirectToAction("List");
try
{
if (!_forumSettings.AllowPrivateMessages)
throw new NopException("Private messages are disabled");
if (await _customerService.IsGuestAsync(customer))
throw new NopException("Customer should be registered");
if (string.IsNullOrWhiteSpace(model.SendPm.Subject))
throw new NopException(await _localizationService.GetResourceAsync("PrivateMessages.SubjectCannotBeEmpty"));
if (string.IsNullOrWhiteSpace(model.SendPm.Message))
throw new NopException(await _localizationService.GetResourceAsync("PrivateMessages.MessageCannotBeEmpty"));
var store = await _storeContext.GetCurrentStoreAsync();
var currentCustomer = await _workContext.GetCurrentCustomerAsync();
var privateMessage = new PrivateMessage
{
StoreId = store.Id,
ToCustomerId = customer.Id,
FromCustomerId = currentCustomer.Id,
Subject = model.SendPm.Subject,
Text = model.SendPm.Message,
IsDeletedByAuthor = false,
IsDeletedByRecipient = false,
IsRead = false,
CreatedOnUtc = DateTime.UtcNow
};
await _forumService.InsertPrivateMessageAsync(privateMessage);
_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.SendPM.Sent"));
}
catch (Exception exc)
{
_notificationService.ErrorNotification(exc.Message);
}
return RedirectToAction("Edit", new { id = customer.Id });
}
#endregion
#region Reward points history
[HttpPost]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)]
public virtual async Task<IActionResult> RewardPointsHistorySelect(CustomerRewardPointsSearchModel searchModel)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(searchModel.CustomerId)
?? throw new ArgumentException("No customer found with the specified id");
//prepare model
var model = await _customerModelFactory.PrepareRewardPointsListModelAsync(searchModel, customer);
return Json(model);
}
[CheckPermission(StandardPermission.Customers.CUSTOMERS_CREATE_EDIT_DELETE)]
public virtual async Task<IActionResult> RewardPointsHistoryAdd(AddRewardPointsToCustomerModel model)
{
//prevent adding a new row with zero value
if (model.Points == 0)
return ErrorJson(await _localizationService.GetResourceAsync("Admin.Customers.Customers.RewardPoints.AddingZeroValueNotAllowed"));
//prevent adding negative point validity for point reduction
if (model.Points < 0 && model.PointsValidity.HasValue)
return ErrorJson(await _localizationService.GetResourceAsync("Admin.Customers.Customers.RewardPoints.Fields.AddNegativePointsValidity"));
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(model.CustomerId);
if (customer == null)
return ErrorJson("Customer cannot be loaded");
//check whether delay is set
DateTime? activatingDate = null;
if (!model.ActivatePointsImmediately && model.ActivationDelay > 0)
{
var delayPeriod = (RewardPointsActivatingDelayPeriod)model.ActivationDelayPeriodId;
var delayInHours = delayPeriod.ToHours(model.ActivationDelay);
activatingDate = DateTime.UtcNow.AddHours(delayInHours);
}
//whether points validity is set
DateTime? endDate = null;
if (model.PointsValidity > 0)
endDate = (activatingDate ?? DateTime.UtcNow).AddDays(model.PointsValidity.Value);
//add reward points
await _rewardPointService.AddRewardPointsHistoryEntryAsync(customer, model.Points, model.StoreId, model.Message,
activatingDate: activatingDate, endDate: endDate);
return Json(new { Result = true });
}
#endregion
#region Addresses
[HttpPost]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)]
public virtual async Task<IActionResult> AddressesSelect(CustomerAddressSearchModel searchModel)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(searchModel.CustomerId)
?? throw new ArgumentException("No customer found with the specified id");
//prepare model
var model = await _customerModelFactory.PrepareCustomerAddressListModelAsync(searchModel, customer);
return Json(model);
}
[HttpPost]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_CREATE_EDIT_DELETE)]
public virtual async Task<IActionResult> AddressDelete(int id, int customerId)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(customerId)
?? throw new ArgumentException("No customer found with the specified id", nameof(customerId));
//try to get an address with the specified id
var address = await _customerService.GetCustomerAddressAsync(customer.Id, id);
if (address == null)
return Content("No address found with the specified id");
await _customerService.RemoveCustomerAddressAsync(customer, address);
await _customerService.UpdateCustomerAsync(customer);
//now delete the address record
await _addressService.DeleteAddressAsync(address);
return new NullJsonResult();
}
[CheckPermission(StandardPermission.Customers.CUSTOMERS_CREATE_EDIT_DELETE)]
public virtual async Task<IActionResult> AddressCreate(int customerId)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(customerId);
if (customer == null)
return RedirectToAction("List");
//prepare model
var model = await _customerModelFactory.PrepareCustomerAddressModelAsync(new CustomerAddressModel(), customer, null);
return View(model);
}
[HttpPost]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_CREATE_EDIT_DELETE)]
public virtual async Task<IActionResult> AddressCreate(CustomerAddressModel model, IFormCollection form)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(model.CustomerId);
if (customer == null)
return RedirectToAction("List");
//custom address attributes
var customAttributes = await _addressAttributeParser.ParseCustomAttributesAsync(form, NopCommonDefaults.AddressAttributeControlName);
var customAttributeWarnings = await _addressAttributeParser.GetAttributeWarningsAsync(customAttributes);
foreach (var error in customAttributeWarnings)
{
ModelState.AddModelError(string.Empty, error);
}
if (ModelState.IsValid)
{
var address = model.Address.ToEntity<Address>();
address.CustomAttributes = customAttributes;
address.CreatedOnUtc = DateTime.UtcNow;
//some validation
if (address.CountryId == 0)
address.CountryId = null;
if (address.StateProvinceId == 0)
address.StateProvinceId = null;
await _addressService.InsertAddressAsync(address);
await _customerService.InsertCustomerAddressAsync(customer, address);
_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.Addresses.Added"));
return RedirectToAction("AddressEdit", new { addressId = address.Id, customerId = model.CustomerId });
}
//prepare model
model = await _customerModelFactory.PrepareCustomerAddressModelAsync(model, customer, null, true);
//if we got this far, something failed, redisplay form
return View(model);
}
[CheckPermission(StandardPermission.Customers.CUSTOMERS_CREATE_EDIT_DELETE)]
public virtual async Task<IActionResult> AddressEdit(int addressId, int customerId)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(customerId);
if (customer == null)
return RedirectToAction("List");
//try to get an address with the specified id
var address = await _addressService.GetAddressByIdAsync(addressId);
if (address == null)
return RedirectToAction("Edit", new { id = customer.Id });
//prepare model
var model = await _customerModelFactory.PrepareCustomerAddressModelAsync(null, customer, address);
return View(model);
}
[HttpPost]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_CREATE_EDIT_DELETE)]
public virtual async Task<IActionResult> AddressEdit(CustomerAddressModel model, IFormCollection form)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(model.CustomerId);
if (customer == null)
return RedirectToAction("List");
//try to get an address with the specified id
var address = await _addressService.GetAddressByIdAsync(model.Address.Id);
if (address == null)
return RedirectToAction("Edit", new { id = customer.Id });
//custom address attributes
var customAttributes = await _addressAttributeParser.ParseCustomAttributesAsync(form, NopCommonDefaults.AddressAttributeControlName);
var customAttributeWarnings = await _addressAttributeParser.GetAttributeWarningsAsync(customAttributes);
foreach (var error in customAttributeWarnings)
{
ModelState.AddModelError(string.Empty, error);
}
if (ModelState.IsValid)
{
address = model.Address.ToEntity(address);
address.CustomAttributes = customAttributes;
await _addressService.UpdateAddressAsync(address);
_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.Addresses.Updated"));
return RedirectToAction("AddressEdit", new { addressId = model.Address.Id, customerId = model.CustomerId });
}
//prepare model
model = await _customerModelFactory.PrepareCustomerAddressModelAsync(model, customer, address, true);
//if we got this far, something failed, redisplay form
return View(model);
}
#endregion
#region Orders
[HttpPost]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)]
public virtual async Task<IActionResult> OrderList(CustomerOrderSearchModel searchModel)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(searchModel.CustomerId)
?? throw new ArgumentException("No customer found with the specified id");
//prepare model
var model = await _customerModelFactory.PrepareCustomerOrderListModelAsync(searchModel, customer);
return Json(model);
}
#endregion
#region Customer
[CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)]
public virtual async Task<IActionResult> LoadCustomerStatistics(string period)
{
var result = new List<object>();
var nowDt = await _dateTimeHelper.ConvertToUserTimeAsync(DateTime.Now);
var timeZone = await _dateTimeHelper.GetCurrentTimeZoneAsync();
var searchCustomerRoleIds = new[] { (await _customerService.GetCustomerRoleBySystemNameAsync(NopCustomerDefaults.RegisteredRoleName)).Id };
var culture = new CultureInfo((await _workContext.GetWorkingLanguageAsync()).LanguageCulture);
switch (period)
{
case "year":
//year statistics
var yearAgoDt = nowDt.AddYears(-1).AddMonths(1);
var searchYearDateUser = new DateTime(yearAgoDt.Year, yearAgoDt.Month, 1);
for (var i = 0; i <= 12; i++)
{
result.Add(new
{
date = searchYearDateUser.Date.ToString("Y", culture),
value = (await _customerService.GetAllCustomersAsync(
createdFromUtc: _dateTimeHelper.ConvertToUtcTime(searchYearDateUser, timeZone),
createdToUtc: _dateTimeHelper.ConvertToUtcTime(searchYearDateUser.AddMonths(1), timeZone),
customerRoleIds: searchCustomerRoleIds,
pageIndex: 0,
pageSize: 1, getOnlyTotalCount: true)).TotalCount.ToString()
});
searchYearDateUser = searchYearDateUser.AddMonths(1);
}
break;
case "month":
//month statistics
var monthAgoDt = nowDt.AddDays(-30);
var searchMonthDateUser = new DateTime(monthAgoDt.Year, monthAgoDt.Month, monthAgoDt.Day);
for (var i = 0; i <= 30; i++)
{
result.Add(new
{
date = searchMonthDateUser.Date.ToString("M", culture),
value = (await _customerService.GetAllCustomersAsync(
createdFromUtc: _dateTimeHelper.ConvertToUtcTime(searchMonthDateUser, timeZone),
createdToUtc: _dateTimeHelper.ConvertToUtcTime(searchMonthDateUser.AddDays(1), timeZone),
customerRoleIds: searchCustomerRoleIds,
pageIndex: 0,
pageSize: 1, getOnlyTotalCount: true)).TotalCount.ToString()
});
searchMonthDateUser = searchMonthDateUser.AddDays(1);
}
break;
case "week":
default:
//week statistics
var weekAgoDt = nowDt.AddDays(-7);
var searchWeekDateUser = new DateTime(weekAgoDt.Year, weekAgoDt.Month, weekAgoDt.Day);
for (var i = 0; i <= 7; i++)
{
result.Add(new
{
date = searchWeekDateUser.Date.ToString("d dddd", culture),
value = (await _customerService.GetAllCustomersAsync(
createdFromUtc: _dateTimeHelper.ConvertToUtcTime(searchWeekDateUser, timeZone),
createdToUtc: _dateTimeHelper.ConvertToUtcTime(searchWeekDateUser.AddDays(1), timeZone),
customerRoleIds: searchCustomerRoleIds,
pageIndex: 0,
pageSize: 1, getOnlyTotalCount: true)).TotalCount.ToString()
});
searchWeekDateUser = searchWeekDateUser.AddDays(1);
}
break;
}
return Json(result);
}
#endregion
#region Current shopping cart/ wishlist
[HttpPost]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)]
public virtual async Task<IActionResult> GetCartList(CustomerShoppingCartSearchModel searchModel)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(searchModel.CustomerId)
?? throw new ArgumentException("No customer found with the specified id");
//prepare model
var model = await _customerModelFactory.PrepareCustomerShoppingCartListModelAsync(searchModel, customer);
return Json(model);
}
#endregion
#region Activity log
[HttpPost]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)]
[CheckPermission(StandardPermission.Customers.ACTIVITY_LOG_VIEW)]
public virtual async Task<IActionResult> ListActivityLog(CustomerActivityLogSearchModel searchModel)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(searchModel.CustomerId)
?? throw new ArgumentException("No customer found with the specified id");
//prepare model
var model = await _customerModelFactory.PrepareCustomerActivityLogListModelAsync(searchModel, customer);
return Json(model);
}
#endregion
#region Back in stock subscriptions
[HttpPost]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)]
public virtual async Task<IActionResult> BackInStockSubscriptionList(CustomerBackInStockSubscriptionSearchModel searchModel)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(searchModel.CustomerId)
?? throw new ArgumentException("No customer found with the specified id");
//prepare model
var model = await _customerModelFactory.PrepareCustomerBackInStockSubscriptionListModelAsync(searchModel, customer);
return Json(model);
}
#endregion
#region GDPR
[CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)]
[CheckPermission(StandardPermission.Customers.GDPR_MANAGE)]
public virtual async Task<IActionResult> GdprLog()
{
//prepare model
var model = await _customerModelFactory.PrepareGdprLogSearchModelAsync(new GdprLogSearchModel());
return View(model);
}
[HttpPost]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)]
[CheckPermission(StandardPermission.Customers.GDPR_MANAGE)]
public virtual async Task<IActionResult> GdprLogList(GdprLogSearchModel searchModel)
{
//prepare model
var model = await _customerModelFactory.PrepareGdprLogListModelAsync(searchModel);
return Json(model);
}
[HttpPost]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_CREATE_EDIT_DELETE)]
[CheckPermission(StandardPermission.Customers.GDPR_MANAGE)]
public virtual async Task<IActionResult> GdprDelete(int id)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(id);
if (customer == null)
return RedirectToAction("List");
if (!_gdprSettings.GdprEnabled)
return RedirectToAction("List");
try
{
//prevent attempts to delete the user, if it is the last active administrator
if (await _customerService.IsAdminAsync(customer) && !await SecondAdminAccountExistsAsync(customer))
{
_notificationService.ErrorNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.AdminAccountShouldExists.DeleteAdministrator"));
return RedirectToAction("Edit", new { id = customer.Id });
}
//ensure that the current customer cannot delete "Administrators" if he's not an admin himself
if (await _customerService.IsAdminAsync(customer) && !await _customerService.IsAdminAsync(await _workContext.GetCurrentCustomerAsync()))
{
_notificationService.ErrorNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.OnlyAdminCanDeleteAdmin"));
return RedirectToAction("Edit", new { id = customer.Id });
}
//delete
await _gdprService.PermanentDeleteCustomerAsync(customer);
//activity log
await _customerActivityService.InsertActivityAsync("DeleteCustomer",
string.Format(await _localizationService.GetResourceAsync("ActivityLog.DeleteCustomer"), customer.Id), customer);
_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.Deleted"));
return RedirectToAction("List");
}
catch (Exception exc)
{
_notificationService.ErrorNotification(exc.Message);
return RedirectToAction("Edit", new { id = customer.Id });
}
}
[CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)]
[CheckPermission(StandardPermission.Customers.GDPR_MANAGE)]
public virtual async Task<IActionResult> GdprExport(int id)
{
//try to get a customer with the specified id
var customer = await _customerService.GetCustomerByIdAsync(id);
if (customer == null)
return RedirectToAction("List");
try
{
//log
//_gdprService.InsertLog(customer, 0, GdprRequestType.ExportData, await _localizationService.GetResource("Gdpr.Exported"));
//export
var store = await _storeContext.GetCurrentStoreAsync();
var bytes = await _exportManager.ExportCustomerGdprInfoToXlsxAsync(customer, store.Id);
return File(bytes, MimeTypes.TextXlsx, $"customerdata-{customer.Id}.xlsx");
}
catch (Exception exc)
{
await _notificationService.ErrorNotificationAsync(exc);
return RedirectToAction("Edit", new { id = customer.Id });
}
}
#endregion
#region Export / Import
[HttpPost, ActionName("ExportExcel")]
[FormValueRequired("exportexcel-all")]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_IMPORT_EXPORT)]
public virtual async Task<IActionResult> ExportExcelAll(CustomerSearchModel model)
{
var customers = await _customerService.GetAllCustomersAsync(customerRoleIds: model.SelectedCustomerRoleIds.ToArray(),
email: model.SearchEmail,
username: model.SearchUsername,
firstName: model.SearchFirstName,
lastName: model.SearchLastName,
dayOfBirth: int.TryParse(model.SearchDayOfBirth, out var dayOfBirth) ? dayOfBirth : 0,
monthOfBirth: int.TryParse(model.SearchMonthOfBirth, out var monthOfBirth) ? monthOfBirth : 0,
company: model.SearchCompany,
isActive: model.SearchIsActive,
phone: model.SearchPhone,
zipPostalCode: model.SearchZipPostalCode);
try
{
var bytes = await _exportManager.ExportCustomersToXlsxAsync(customers);
return File(bytes, MimeTypes.TextXlsx, "customers.xlsx");
}
catch (Exception exc)
{
await _notificationService.ErrorNotificationAsync(exc);
return RedirectToAction("List");
}
}
[HttpPost]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_IMPORT_EXPORT)]
public virtual async Task<IActionResult> ExportExcelSelected(string selectedIds)
{
var customers = new List<Customer>();
if (selectedIds != null)
{
var ids = selectedIds
.Split(_separator, StringSplitOptions.RemoveEmptyEntries)
.Select(x => Convert.ToInt32(x))
.ToArray();
customers.AddRange(await _customerService.GetCustomersByIdsAsync(ids));
}
try
{
var bytes = await _exportManager.ExportCustomersToXlsxAsync(customers);
return File(bytes, MimeTypes.TextXlsx, "customers.xlsx");
}
catch (Exception exc)
{
await _notificationService.ErrorNotificationAsync(exc);
return RedirectToAction("List");
}
}
[HttpPost, ActionName("ExportXML")]
[FormValueRequired("exportxml-all")]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_IMPORT_EXPORT)]
public virtual async Task<IActionResult> ExportXmlAll(CustomerSearchModel model)
{
var customers = await _customerService.GetAllCustomersAsync(customerRoleIds: model.SelectedCustomerRoleIds.ToArray(),
email: model.SearchEmail,
username: model.SearchUsername,
firstName: model.SearchFirstName,
lastName: model.SearchLastName,
dayOfBirth: int.TryParse(model.SearchDayOfBirth, out var dayOfBirth) ? dayOfBirth : 0,
monthOfBirth: int.TryParse(model.SearchMonthOfBirth, out var monthOfBirth) ? monthOfBirth : 0,
company: model.SearchCompany,
isActive: model.SearchIsActive,
phone: model.SearchPhone,
zipPostalCode: model.SearchZipPostalCode);
try
{
var xml = await _exportManager.ExportCustomersToXmlAsync(customers);
return File(Encoding.UTF8.GetBytes(xml), "application/xml", "customers.xml");
}
catch (Exception exc)
{
await _notificationService.ErrorNotificationAsync(exc);
return RedirectToAction("List");
}
}
[HttpPost]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_IMPORT_EXPORT)]
public virtual async Task<IActionResult> ExportXmlSelected(string selectedIds)
{
var customers = new List<Customer>();
if (selectedIds != null)
{
var ids = selectedIds
.Split(_separator, StringSplitOptions.RemoveEmptyEntries)
.Select(x => Convert.ToInt32(x))
.ToArray();
customers.AddRange(await _customerService.GetCustomersByIdsAsync(ids));
}
try
{
var xml = await _exportManager.ExportCustomersToXmlAsync(customers);
return File(Encoding.UTF8.GetBytes(xml), "application/xml", "customers.xml");
}
catch (Exception exc)
{
await _notificationService.ErrorNotificationAsync(exc);
return RedirectToAction("List");
}
}
[HttpPost]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_CREATE_EDIT_DELETE)]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_IMPORT_EXPORT)]
public virtual async Task<IActionResult> ImportExcel(IFormFile importexcelfile)
{
if (await _workContext.GetCurrentVendorAsync() != null)
//a vendor can not import customer
return AccessDeniedView();
try
{
if ((importexcelfile?.Length ?? 0) > 0)
await _importManager.ImportCustomersFromXlsxAsync(importexcelfile.OpenReadStream());
else
{
_notificationService.ErrorNotification(await _localizationService.GetResourceAsync("Admin.Common.UploadFile"));
return RedirectToAction("List");
}
_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Customers.Customers.Imported"));
return RedirectToAction("List");
}
catch (Exception exc)
{
await _notificationService.ErrorNotificationAsync(exc);
return RedirectToAction("List");
}
}
#endregion
}