1680 lines
68 KiB
C#
1680 lines
68 KiB
C#
using System.Xml;
|
|
using Nop.Core;
|
|
using Nop.Core.Caching;
|
|
using Nop.Core.Domain.Blogs;
|
|
using Nop.Core.Domain.Catalog;
|
|
using Nop.Core.Domain.Common;
|
|
using Nop.Core.Domain.Customers;
|
|
using Nop.Core.Domain.Forums;
|
|
using Nop.Core.Domain.News;
|
|
using Nop.Core.Domain.Orders;
|
|
using Nop.Core.Domain.Polls;
|
|
using Nop.Core.Domain.Shipping;
|
|
using Nop.Core.Domain.Tax;
|
|
using Nop.Core.Events;
|
|
using Nop.Core.Infrastructure;
|
|
using Nop.Data;
|
|
using Nop.Services.Common;
|
|
using Nop.Services.Localization;
|
|
|
|
namespace Nop.Services.Customers;
|
|
|
|
/// <summary>
|
|
/// Customer service
|
|
/// </summary>
|
|
public partial class CustomerService : ICustomerService
|
|
{
|
|
#region Fields
|
|
|
|
protected readonly CustomerSettings _customerSettings;
|
|
protected readonly IEventPublisher _eventPublisher;
|
|
protected readonly IGenericAttributeService _genericAttributeService;
|
|
protected readonly INopDataProvider _dataProvider;
|
|
protected readonly IRepository<Address> _customerAddressRepository;
|
|
protected readonly IRepository<BlogComment> _blogCommentRepository;
|
|
protected readonly IRepository<Customer> _customerRepository;
|
|
protected readonly IRepository<CustomerAddressMapping> _customerAddressMappingRepository;
|
|
protected readonly IRepository<CustomerCustomerRoleMapping> _customerCustomerRoleMappingRepository;
|
|
protected readonly IRepository<CustomerPassword> _customerPasswordRepository;
|
|
protected readonly IRepository<CustomerRole> _customerRoleRepository;
|
|
protected readonly IRepository<ForumPost> _forumPostRepository;
|
|
protected readonly IRepository<ForumTopic> _forumTopicRepository;
|
|
protected readonly IRepository<GenericAttribute> _gaRepository;
|
|
protected readonly IRepository<NewsComment> _newsCommentRepository;
|
|
protected readonly IRepository<Order> _orderRepository;
|
|
protected readonly IRepository<ProductReview> _productReviewRepository;
|
|
protected readonly IRepository<ProductReviewHelpfulness> _productReviewHelpfulnessRepository;
|
|
protected readonly IRepository<PollVotingRecord> _pollVotingRecordRepository;
|
|
protected readonly IRepository<ShoppingCartItem> _shoppingCartRepository;
|
|
protected readonly IShortTermCacheManager _shortTermCacheManager;
|
|
protected readonly IStaticCacheManager _staticCacheManager;
|
|
protected readonly IStoreContext _storeContext;
|
|
protected readonly ShoppingCartSettings _shoppingCartSettings;
|
|
protected readonly TaxSettings _taxSettings;
|
|
|
|
#endregion
|
|
|
|
#region Ctor
|
|
|
|
public CustomerService(CustomerSettings customerSettings,
|
|
IEventPublisher eventPublisher,
|
|
IGenericAttributeService genericAttributeService,
|
|
INopDataProvider dataProvider,
|
|
IRepository<Address> customerAddressRepository,
|
|
IRepository<BlogComment> blogCommentRepository,
|
|
IRepository<Customer> customerRepository,
|
|
IRepository<CustomerAddressMapping> customerAddressMappingRepository,
|
|
IRepository<CustomerCustomerRoleMapping> customerCustomerRoleMappingRepository,
|
|
IRepository<CustomerPassword> customerPasswordRepository,
|
|
IRepository<CustomerRole> customerRoleRepository,
|
|
IRepository<ForumPost> forumPostRepository,
|
|
IRepository<ForumTopic> forumTopicRepository,
|
|
IRepository<GenericAttribute> gaRepository,
|
|
IRepository<NewsComment> newsCommentRepository,
|
|
IRepository<Order> orderRepository,
|
|
IRepository<ProductReview> productReviewRepository,
|
|
IRepository<ProductReviewHelpfulness> productReviewHelpfulnessRepository,
|
|
IRepository<PollVotingRecord> pollVotingRecordRepository,
|
|
IRepository<ShoppingCartItem> shoppingCartRepository,
|
|
IShortTermCacheManager shortTermCacheManager,
|
|
IStaticCacheManager staticCacheManager,
|
|
IStoreContext storeContext,
|
|
ShoppingCartSettings shoppingCartSettings,
|
|
TaxSettings taxSettings)
|
|
{
|
|
_customerSettings = customerSettings;
|
|
_eventPublisher = eventPublisher;
|
|
_genericAttributeService = genericAttributeService;
|
|
_dataProvider = dataProvider;
|
|
_customerAddressRepository = customerAddressRepository;
|
|
_blogCommentRepository = blogCommentRepository;
|
|
_customerRepository = customerRepository;
|
|
_customerAddressMappingRepository = customerAddressMappingRepository;
|
|
_customerCustomerRoleMappingRepository = customerCustomerRoleMappingRepository;
|
|
_customerPasswordRepository = customerPasswordRepository;
|
|
_customerRoleRepository = customerRoleRepository;
|
|
_forumPostRepository = forumPostRepository;
|
|
_forumTopicRepository = forumTopicRepository;
|
|
_gaRepository = gaRepository;
|
|
_newsCommentRepository = newsCommentRepository;
|
|
_orderRepository = orderRepository;
|
|
_productReviewRepository = productReviewRepository;
|
|
_productReviewHelpfulnessRepository = productReviewHelpfulnessRepository;
|
|
_pollVotingRecordRepository = pollVotingRecordRepository;
|
|
_shoppingCartRepository = shoppingCartRepository;
|
|
_shortTermCacheManager = shortTermCacheManager;
|
|
_staticCacheManager = staticCacheManager;
|
|
_storeContext = storeContext;
|
|
_shoppingCartSettings = shoppingCartSettings;
|
|
_taxSettings = taxSettings;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Utilities
|
|
|
|
/// <summary>
|
|
/// Gets a dictionary of all customer roles mapped by ID.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation and contains a dictionary of all customer roles mapped by ID.
|
|
/// </returns>
|
|
protected virtual async Task<IDictionary<int, CustomerRole>> GetAllCustomerRolesDictionaryAsync()
|
|
{
|
|
return await _staticCacheManager.GetAsync(
|
|
_staticCacheManager.PrepareKeyForDefaultCache(NopEntityCacheDefaults<CustomerRole>.AllCacheKey),
|
|
async () => await _customerRoleRepository.Table.ToDictionaryAsync(cr => cr.Id));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
#region Customers
|
|
|
|
/// <summary>
|
|
/// Gets all customers
|
|
/// </summary>
|
|
/// <param name="createdFromUtc">Created date from (UTC); null to load all records</param>
|
|
/// <param name="createdToUtc">Created date to (UTC); null to load all records</param>
|
|
/// <param name="lastActivityFromUtc">Last activity date from (UTC); null to load all records</param>
|
|
/// <param name="lastActivityToUtc">Last activity date to (UTC); null to load all records</param>
|
|
/// <param name="affiliateId">Affiliate identifier</param>
|
|
/// <param name="vendorId">Vendor identifier</param>
|
|
/// <param name="customerRoleIds">A list of customer role identifiers to filter by (at least one match); pass null or empty list in order to load all customers; </param>
|
|
/// <param name="email">Email; null to load all customers</param>
|
|
/// <param name="username">Username; null to load all customers</param>
|
|
/// <param name="firstName">First name; null to load all customers</param>
|
|
/// <param name="lastName">Last name; null to load all customers</param>
|
|
/// <param name="dayOfBirth">Day of birth; 0 to load all customers</param>
|
|
/// <param name="monthOfBirth">Month of birth; 0 to load all customers</param>
|
|
/// <param name="company">Company; null to load all customers</param>
|
|
/// <param name="phone">Phone; null to load all customers</param>
|
|
/// <param name="zipPostalCode">Phone; null to load all customers</param>
|
|
/// <param name="ipAddress">IP address; null to load all customers</param>
|
|
/// <param name="isActive">Customer is active; null to load all customers</param>
|
|
/// <param name="pageIndex">Page index</param>
|
|
/// <param name="pageSize">Page size</param>
|
|
/// <param name="getOnlyTotalCount">A value in indicating whether you want to load only total number of records. Set to "true" if you don't want to load data from database</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the customers
|
|
/// </returns>
|
|
public virtual async Task<IPagedList<Customer>> GetAllCustomersAsync(DateTime? createdFromUtc = null, DateTime? createdToUtc = null,
|
|
DateTime? lastActivityFromUtc = null, DateTime? lastActivityToUtc = null,
|
|
int affiliateId = 0, int vendorId = 0, int[] customerRoleIds = null,
|
|
string email = null, string username = null, string firstName = null, string lastName = null,
|
|
int dayOfBirth = 0, int monthOfBirth = 0,
|
|
string company = null, string phone = null, string zipPostalCode = null, string ipAddress = null,
|
|
bool? isActive = null, int pageIndex = 0, int pageSize = int.MaxValue, bool getOnlyTotalCount = false)
|
|
{
|
|
var customers = await _customerRepository.GetAllPagedAsync(query =>
|
|
{
|
|
if (createdFromUtc.HasValue)
|
|
query = query.Where(c => createdFromUtc.Value <= c.CreatedOnUtc);
|
|
if (createdToUtc.HasValue)
|
|
query = query.Where(c => createdToUtc.Value >= c.CreatedOnUtc);
|
|
if (lastActivityFromUtc.HasValue)
|
|
query = query.Where(c => lastActivityFromUtc.Value <= c.LastActivityDateUtc);
|
|
if (lastActivityToUtc.HasValue)
|
|
query = query.Where(c => lastActivityToUtc.Value >= c.LastActivityDateUtc);
|
|
if (affiliateId > 0)
|
|
query = query.Where(c => affiliateId == c.AffiliateId);
|
|
if (vendorId > 0)
|
|
query = query.Where(c => vendorId == c.VendorId);
|
|
if (isActive.HasValue)
|
|
query = query.Where(c => c.Active == isActive.Value);
|
|
|
|
query = query.Where(c => !c.Deleted);
|
|
|
|
if (customerRoleIds != null && customerRoleIds.Length > 0)
|
|
{
|
|
query = query.Join(_customerCustomerRoleMappingRepository.Table, x => x.Id, y => y.CustomerId,
|
|
(x, y) => new { Customer = x, Mapping = y })
|
|
.Where(z => customerRoleIds.Contains(z.Mapping.CustomerRoleId))
|
|
.Select(z => z.Customer)
|
|
.Distinct();
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(email))
|
|
query = query.Where(c => c.Email.Contains(email));
|
|
if (!string.IsNullOrWhiteSpace(username))
|
|
query = query.Where(c => c.Username.Contains(username));
|
|
if (!string.IsNullOrWhiteSpace(firstName))
|
|
query = query.Where(c => c.FirstName.Contains(firstName));
|
|
if (!string.IsNullOrWhiteSpace(lastName))
|
|
query = query.Where(c => c.LastName.Contains(lastName));
|
|
if (!string.IsNullOrWhiteSpace(company))
|
|
query = query.Where(c => c.Company.Contains(company));
|
|
if (!string.IsNullOrWhiteSpace(phone))
|
|
query = query.Where(c => c.Phone.Contains(phone));
|
|
if (!string.IsNullOrWhiteSpace(zipPostalCode))
|
|
query = query.Where(c => c.ZipPostalCode.Contains(zipPostalCode));
|
|
|
|
if (dayOfBirth > 0 && monthOfBirth > 0)
|
|
query = query.Where(c => c.DateOfBirth.HasValue && c.DateOfBirth.Value.Day == dayOfBirth &&
|
|
c.DateOfBirth.Value.Month == monthOfBirth);
|
|
else if (dayOfBirth > 0)
|
|
query = query.Where(c => c.DateOfBirth.HasValue && c.DateOfBirth.Value.Day == dayOfBirth);
|
|
else if (monthOfBirth > 0)
|
|
query = query.Where(c => c.DateOfBirth.HasValue && c.DateOfBirth.Value.Month == monthOfBirth);
|
|
|
|
//search by IpAddress
|
|
if (!string.IsNullOrWhiteSpace(ipAddress) && CommonHelper.IsValidIpAddress(ipAddress))
|
|
{
|
|
query = query.Where(w => w.LastIpAddress == ipAddress);
|
|
}
|
|
|
|
query = query.OrderByDescending(c => c.CreatedOnUtc);
|
|
|
|
return query;
|
|
}, pageIndex, pageSize, getOnlyTotalCount);
|
|
|
|
return customers;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets online customers
|
|
/// </summary>
|
|
/// <param name="lastActivityFromUtc">Customer last activity date (from)</param>
|
|
/// <param name="customerRoleIds">A list of customer role identifiers to filter by (at least one match); pass null or empty list in order to load all customers; </param>
|
|
/// <param name="pageIndex">Page index</param>
|
|
/// <param name="pageSize">Page size</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the customers
|
|
/// </returns>
|
|
public virtual async Task<IPagedList<Customer>> GetOnlineCustomersAsync(DateTime lastActivityFromUtc,
|
|
int[] customerRoleIds, int pageIndex = 0, int pageSize = int.MaxValue)
|
|
{
|
|
var query = _customerRepository.Table;
|
|
query = query.Where(c => lastActivityFromUtc <= c.LastActivityDateUtc);
|
|
query = query.Where(c => !c.Deleted);
|
|
|
|
if (customerRoleIds != null && customerRoleIds.Length > 0)
|
|
query = query.Where(c => _customerCustomerRoleMappingRepository.Table.Any(ccrm => ccrm.CustomerId == c.Id && customerRoleIds.Contains(ccrm.CustomerRoleId)));
|
|
|
|
query = query.OrderByDescending(c => c.LastActivityDateUtc);
|
|
var customers = await query.ToPagedListAsync(pageIndex, pageSize);
|
|
|
|
return customers;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets customers with shopping carts
|
|
/// </summary>
|
|
/// <param name="shoppingCartType">Shopping cart type; pass null to load all records</param>
|
|
/// <param name="storeId">Store identifier; pass 0 to load all records</param>
|
|
/// <param name="productId">Product identifier; pass null to load all records</param>
|
|
/// <param name="createdFromUtc">Created date from (UTC); pass null to load all records</param>
|
|
/// <param name="createdToUtc">Created date to (UTC); pass null to load all records</param>
|
|
/// <param name="countryId">Billing country identifier; pass null to load all records</param>
|
|
/// <param name="pageIndex">Page index</param>
|
|
/// <param name="pageSize">Page size</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the customers
|
|
/// </returns>
|
|
public virtual async Task<IPagedList<Customer>> GetCustomersWithShoppingCartsAsync(ShoppingCartType? shoppingCartType = null,
|
|
int storeId = 0, int? productId = null,
|
|
DateTime? createdFromUtc = null, DateTime? createdToUtc = null, int? countryId = null,
|
|
int pageIndex = 0, int pageSize = int.MaxValue)
|
|
{
|
|
//get all shopping cart items
|
|
var items = _shoppingCartRepository.Table;
|
|
|
|
//filter by type
|
|
if (shoppingCartType.HasValue)
|
|
items = items.Where(item => item.ShoppingCartTypeId == (int)shoppingCartType.Value);
|
|
|
|
//filter shopping cart items by store
|
|
if (storeId > 0 && !_shoppingCartSettings.CartsSharedBetweenStores)
|
|
items = items.Where(item => item.StoreId == storeId);
|
|
|
|
//filter shopping cart items by product
|
|
if (productId > 0)
|
|
items = items.Where(item => item.ProductId == productId);
|
|
|
|
//filter shopping cart items by date
|
|
if (createdFromUtc.HasValue)
|
|
items = items.Where(item => createdFromUtc.Value <= item.CreatedOnUtc);
|
|
if (createdToUtc.HasValue)
|
|
items = items.Where(item => createdToUtc.Value >= item.CreatedOnUtc);
|
|
|
|
//get all active customers
|
|
var customers = _customerRepository.Table.Where(customer => customer.Active && !customer.Deleted);
|
|
|
|
//filter customers by billing country
|
|
if (countryId > 0)
|
|
customers = from c in customers
|
|
join a in _customerAddressRepository.Table on c.BillingAddressId equals a.Id
|
|
where a.CountryId == countryId
|
|
select c;
|
|
|
|
var customersWithCarts = from c in customers
|
|
join item in items on c.Id equals item.CustomerId
|
|
//we change ordering for the MySQL engine to avoid problems with the ONLY_FULL_GROUP_BY server property that is set by default since the 5.7.5 version
|
|
orderby _dataProvider.ConfigurationName == "MySql" ? c.CreatedOnUtc : item.CreatedOnUtc descending
|
|
select c;
|
|
|
|
return await customersWithCarts.Distinct().ToPagedListAsync(pageIndex, pageSize);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets customer for shopping cart
|
|
/// </summary>
|
|
/// <param name="shoppingCart">Shopping cart</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the result
|
|
/// </returns>
|
|
public virtual async Task<Customer> GetShoppingCartCustomerAsync(IList<ShoppingCartItem> shoppingCart)
|
|
{
|
|
var customerId = shoppingCart.FirstOrDefault()?.CustomerId;
|
|
|
|
return customerId.HasValue && customerId != 0 ? await GetCustomerByIdAsync(customerId.Value) : null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delete a customer
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <returns>A task that represents the asynchronous operation</returns>
|
|
public virtual async Task DeleteCustomerAsync(Customer customer)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customer);
|
|
|
|
if (customer.IsSystemAccount)
|
|
throw new NopException($"System customer account ({customer.SystemName}) could not be deleted");
|
|
|
|
customer.Deleted = true;
|
|
|
|
if (_customerSettings.SuffixDeletedCustomers)
|
|
{
|
|
if (!string.IsNullOrEmpty(customer.Email))
|
|
customer.Email += NopCustomerServicesDefaults.CustomerDeletedSuffix;
|
|
if (!string.IsNullOrEmpty(customer.Username))
|
|
customer.Username += NopCustomerServicesDefaults.CustomerDeletedSuffix;
|
|
}
|
|
|
|
await _customerRepository.UpdateAsync(customer, false);
|
|
await _customerRepository.DeleteAsync(customer);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a customer
|
|
/// </summary>
|
|
/// <param name="customerId">Customer identifier</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains a customer
|
|
/// </returns>
|
|
public virtual async Task<Customer> GetCustomerByIdAsync(int customerId)
|
|
{
|
|
return await _customerRepository.GetByIdAsync(customerId, cache => default, useShortTermCache: true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get customers by identifiers
|
|
/// </summary>
|
|
/// <param name="customerIds">Customer identifiers</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the customers
|
|
/// </returns>
|
|
public virtual async Task<IList<Customer>> GetCustomersByIdsAsync(int[] customerIds)
|
|
{
|
|
return await _customerRepository.GetByIdsAsync(customerIds, includeDeleted: false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get customers by guids
|
|
/// </summary>
|
|
/// <param name="customerGuids">Customer guids</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the customers
|
|
/// </returns>
|
|
public virtual async Task<IList<Customer>> GetCustomersByGuidsAsync(Guid[] customerGuids)
|
|
{
|
|
if (customerGuids == null)
|
|
return null;
|
|
|
|
var query = from c in _customerRepository.Table
|
|
where customerGuids.Contains(c.CustomerGuid)
|
|
select c;
|
|
var customers = await query.ToListAsync();
|
|
|
|
return customers;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a customer by GUID
|
|
/// </summary>
|
|
/// <param name="customerGuid">Customer GUID</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains a customer
|
|
/// </returns>
|
|
public virtual async Task<Customer> GetCustomerByGuidAsync(Guid customerGuid)
|
|
{
|
|
if (customerGuid == Guid.Empty)
|
|
return null;
|
|
|
|
var query = from c in _customerRepository.Table
|
|
where c.CustomerGuid == customerGuid
|
|
orderby c.Id
|
|
select c;
|
|
|
|
return await _shortTermCacheManager.GetAsync(async () => await query.FirstOrDefaultAsync(), NopCustomerServicesDefaults.CustomerByGuidCacheKey, customerGuid);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get customer by email
|
|
/// </summary>
|
|
/// <param name="email">Email</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the customer
|
|
/// </returns>
|
|
public virtual async Task<Customer> GetCustomerByEmailAsync(string email)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(email))
|
|
return null;
|
|
|
|
var query = from c in _customerRepository.Table
|
|
orderby c.Id
|
|
where c.Email == email
|
|
select c;
|
|
var customer = await query.FirstOrDefaultAsync();
|
|
|
|
return customer;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get customer by system name
|
|
/// </summary>
|
|
/// <param name="systemName">System name</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the customer
|
|
/// </returns>
|
|
public virtual async Task<Customer> GetCustomerBySystemNameAsync(string systemName)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(systemName))
|
|
return null;
|
|
|
|
var query = from c in _customerRepository.Table
|
|
orderby c.Id
|
|
where c.SystemName == systemName
|
|
select c;
|
|
|
|
var customer = await _shortTermCacheManager.GetAsync(async () => await query.FirstOrDefaultAsync(), NopCustomerServicesDefaults.CustomerBySystemNameCacheKey, systemName);
|
|
|
|
return customer;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets built-in system record used for background tasks
|
|
/// </summary>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains a customer object
|
|
/// </returns>
|
|
public virtual async Task<Customer> GetOrCreateBackgroundTaskUserAsync()
|
|
{
|
|
var backgroundTaskUser = await GetCustomerBySystemNameAsync(NopCustomerDefaults.BackgroundTaskCustomerName);
|
|
|
|
if (backgroundTaskUser is null)
|
|
{
|
|
var store = await _storeContext.GetCurrentStoreAsync();
|
|
//If for any reason the system user isn't in the database, then we add it
|
|
backgroundTaskUser = new Customer
|
|
{
|
|
Email = "builtin@background-task-record.com",
|
|
CustomerGuid = Guid.NewGuid(),
|
|
AdminComment = "Built-in system record used for background tasks.",
|
|
Active = true,
|
|
IsSystemAccount = true,
|
|
SystemName = NopCustomerDefaults.BackgroundTaskCustomerName,
|
|
CreatedOnUtc = DateTime.UtcNow,
|
|
LastActivityDateUtc = DateTime.UtcNow,
|
|
RegisteredInStoreId = store.Id
|
|
};
|
|
|
|
await InsertCustomerAsync(backgroundTaskUser);
|
|
|
|
var guestRole = await GetCustomerRoleBySystemNameAsync(NopCustomerDefaults.GuestsRoleName) ?? throw new NopException("'Guests' role could not be loaded");
|
|
|
|
await AddCustomerRoleMappingAsync(new CustomerCustomerRoleMapping { CustomerRoleId = guestRole.Id, CustomerId = backgroundTaskUser.Id });
|
|
}
|
|
|
|
return backgroundTaskUser;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets built-in system guest record used for requests from search engines
|
|
/// </summary>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains a customer object
|
|
/// </returns>
|
|
public virtual async Task<Customer> GetOrCreateSearchEngineUserAsync()
|
|
{
|
|
var searchEngineUser = await GetCustomerBySystemNameAsync(NopCustomerDefaults.SearchEngineCustomerName);
|
|
|
|
if (searchEngineUser is null)
|
|
{
|
|
var store = await _storeContext.GetCurrentStoreAsync();
|
|
//If for any reason the system user isn't in the database, then we add it
|
|
searchEngineUser = new Customer
|
|
{
|
|
Email = "builtin@search_engine_record.com",
|
|
CustomerGuid = Guid.NewGuid(),
|
|
AdminComment = "Built-in system guest record used for requests from search engines.",
|
|
Active = true,
|
|
IsSystemAccount = true,
|
|
SystemName = NopCustomerDefaults.SearchEngineCustomerName,
|
|
CreatedOnUtc = DateTime.UtcNow,
|
|
LastActivityDateUtc = DateTime.UtcNow,
|
|
RegisteredInStoreId = store.Id
|
|
};
|
|
|
|
await InsertCustomerAsync(searchEngineUser);
|
|
|
|
var guestRole = await GetCustomerRoleBySystemNameAsync(NopCustomerDefaults.GuestsRoleName) ?? throw new NopException("'Guests' role could not be loaded");
|
|
|
|
await AddCustomerRoleMappingAsync(new CustomerCustomerRoleMapping { CustomerRoleId = guestRole.Id, CustomerId = searchEngineUser.Id });
|
|
}
|
|
|
|
return searchEngineUser;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get customer by username
|
|
/// </summary>
|
|
/// <param name="username">Username</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the customer
|
|
/// </returns>
|
|
public virtual async Task<Customer> GetCustomerByUsernameAsync(string username)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(username))
|
|
return null;
|
|
|
|
var query = from c in _customerRepository.Table
|
|
orderby c.Id
|
|
where c.Username == username
|
|
select c;
|
|
var customer = await query.FirstOrDefaultAsync();
|
|
|
|
return customer;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Insert a guest customer
|
|
/// </summary>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the customer
|
|
/// </returns>
|
|
public virtual async Task<Customer> InsertGuestCustomerAsync()
|
|
{
|
|
var customer = new Customer
|
|
{
|
|
CustomerGuid = Guid.NewGuid(),
|
|
Active = true,
|
|
CreatedOnUtc = DateTime.UtcNow,
|
|
LastActivityDateUtc = DateTime.UtcNow
|
|
};
|
|
|
|
//add to 'Guests' role
|
|
var guestRole = await GetCustomerRoleBySystemNameAsync(NopCustomerDefaults.GuestsRoleName) ?? throw new NopException("'Guests' role could not be loaded");
|
|
|
|
await _customerRepository.InsertAsync(customer);
|
|
|
|
await AddCustomerRoleMappingAsync(new CustomerCustomerRoleMapping { CustomerId = customer.Id, CustomerRoleId = guestRole.Id });
|
|
|
|
return customer;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Insert a customer
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <returns>A task that represents the asynchronous operation</returns>
|
|
public virtual async Task InsertCustomerAsync(Customer customer)
|
|
{
|
|
await _customerRepository.InsertAsync(customer);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the customer
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <returns>A task that represents the asynchronous operation</returns>
|
|
public virtual async Task UpdateCustomerAsync(Customer customer)
|
|
{
|
|
await _customerRepository.UpdateAsync(customer);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reset data required for checkout
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <param name="storeId">Store identifier</param>
|
|
/// <param name="clearCouponCodes">A value indicating whether to clear coupon code</param>
|
|
/// <param name="clearCheckoutAttributes">A value indicating whether to clear selected checkout attributes</param>
|
|
/// <param name="clearRewardPoints">A value indicating whether to clear "Use reward points" flag</param>
|
|
/// <param name="clearShippingMethod">A value indicating whether to clear selected shipping method</param>
|
|
/// <param name="clearPaymentMethod">A value indicating whether to clear selected payment method</param>
|
|
/// <returns>A task that represents the asynchronous operation</returns>
|
|
public virtual async Task ResetCheckoutDataAsync(Customer customer, int storeId,
|
|
bool clearCouponCodes = false, bool clearCheckoutAttributes = false,
|
|
bool clearRewardPoints = true, bool clearShippingMethod = true,
|
|
bool clearPaymentMethod = true)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customer);
|
|
|
|
//clear entered coupon codes
|
|
if (clearCouponCodes)
|
|
{
|
|
await _genericAttributeService.SaveAttributeAsync<string>(customer, NopCustomerDefaults.DiscountCouponCodeAttribute, null);
|
|
await _genericAttributeService.SaveAttributeAsync<string>(customer, NopCustomerDefaults.GiftCardCouponCodesAttribute, null);
|
|
}
|
|
|
|
//clear checkout attributes
|
|
if (clearCheckoutAttributes)
|
|
await _genericAttributeService.SaveAttributeAsync<string>(customer, NopCustomerDefaults.CheckoutAttributes, null, storeId);
|
|
|
|
//clear reward points flag
|
|
if (clearRewardPoints)
|
|
await _genericAttributeService.SaveAttributeAsync(customer, NopCustomerDefaults.UseRewardPointsDuringCheckoutAttribute, false, storeId);
|
|
|
|
//clear selected shipping method
|
|
if (clearShippingMethod)
|
|
{
|
|
await _genericAttributeService.SaveAttributeAsync<ShippingOption>(customer, NopCustomerDefaults.SelectedShippingOptionAttribute, null, storeId);
|
|
await _genericAttributeService.SaveAttributeAsync<ShippingOption>(customer, NopCustomerDefaults.OfferedShippingOptionsAttribute, null, storeId);
|
|
await _genericAttributeService.SaveAttributeAsync<PickupPoint>(customer, NopCustomerDefaults.SelectedPickupPointAttribute, null, storeId);
|
|
}
|
|
|
|
//clear selected payment method
|
|
if (clearPaymentMethod)
|
|
await _genericAttributeService.SaveAttributeAsync<string>(customer, NopCustomerDefaults.SelectedPaymentMethodAttribute, null, storeId);
|
|
|
|
await _eventPublisher.PublishAsync(new ResetCheckoutDataEvent(customer, storeId));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delete guest customer records
|
|
/// </summary>
|
|
/// <param name="createdFromUtc">Created date from (UTC); null to load all records</param>
|
|
/// <param name="createdToUtc">Created date to (UTC); null to load all records</param>
|
|
/// <param name="onlyWithoutShoppingCart">A value indicating whether to delete customers only without shopping cart</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the number of deleted customers
|
|
/// </returns>
|
|
public virtual async Task<int> DeleteGuestCustomersAsync(DateTime? createdFromUtc, DateTime? createdToUtc, bool onlyWithoutShoppingCart)
|
|
{
|
|
var guestRole = await GetCustomerRoleBySystemNameAsync(NopCustomerDefaults.GuestsRoleName);
|
|
|
|
var allGuestCustomers = from guest in _customerRepository.Table
|
|
join ccm in _customerCustomerRoleMappingRepository.Table on guest.Id equals ccm.CustomerId
|
|
where ccm.CustomerRoleId == guestRole.Id
|
|
select guest;
|
|
|
|
var guestsToDelete = from guest in _customerRepository.Table
|
|
join g in allGuestCustomers on guest.Id equals g.Id
|
|
from sCart in _shoppingCartRepository.Table.Where(sci => sci.CustomerId == guest.Id).DefaultIfEmpty()
|
|
from order in _orderRepository.Table.Where(o => o.CustomerId == guest.Id).DefaultIfEmpty()
|
|
from blogComment in _blogCommentRepository.Table.Where(o => o.CustomerId == guest.Id).DefaultIfEmpty()
|
|
from newsComment in _newsCommentRepository.Table.Where(o => o.CustomerId == guest.Id).DefaultIfEmpty()
|
|
from productReview in _productReviewRepository.Table.Where(o => o.CustomerId == guest.Id).DefaultIfEmpty()
|
|
from productReviewHelpfulness in _productReviewHelpfulnessRepository.Table.Where(o => o.CustomerId == guest.Id).DefaultIfEmpty()
|
|
from pollVotingRecord in _pollVotingRecordRepository.Table.Where(o => o.CustomerId == guest.Id).DefaultIfEmpty()
|
|
from forumTopic in _forumTopicRepository.Table.Where(o => o.CustomerId == guest.Id).DefaultIfEmpty()
|
|
from forumPost in _forumPostRepository.Table.Where(o => o.CustomerId == guest.Id).DefaultIfEmpty()
|
|
where (!onlyWithoutShoppingCart || sCart == null) &&
|
|
order == null && blogComment == null && newsComment == null && productReview == null && productReviewHelpfulness == null &&
|
|
pollVotingRecord == null && forumTopic == null && forumPost == null &&
|
|
!guest.IsSystemAccount &&
|
|
(createdFromUtc == null || guest.CreatedOnUtc > createdFromUtc) &&
|
|
(createdToUtc == null || guest.CreatedOnUtc < createdToUtc)
|
|
select new { CustomerId = guest.Id };
|
|
|
|
await using var tmpGuests = await _dataProvider.CreateTempDataStorageAsync("tmp_guestsToDelete", guestsToDelete);
|
|
await using var tmpAddresses = await _dataProvider.CreateTempDataStorageAsync("tmp_guestsAddressesToDelete",
|
|
_customerAddressMappingRepository.Table
|
|
.Where(ca => tmpGuests.Any(c => c.CustomerId == ca.CustomerId))
|
|
.Select(ca => new { AddressId = ca.AddressId }));
|
|
|
|
//delete guests
|
|
var totalRecordsDeleted = await _customerRepository.DeleteAsync(c => tmpGuests.Any(tmp => tmp.CustomerId == c.Id));
|
|
|
|
//delete attributes
|
|
await _gaRepository.DeleteAsync(ga => tmpGuests.Any(c => c.CustomerId == ga.EntityId) && ga.KeyGroup == nameof(Customer));
|
|
|
|
//delete m -> m addresses
|
|
await _customerAddressRepository.DeleteAsync(a => tmpAddresses.Any(tmp => tmp.AddressId == a.Id));
|
|
|
|
return totalRecordsDeleted;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a tax display type for the customer
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the tax display type
|
|
/// </returns>
|
|
public virtual async Task<TaxDisplayType> GetCustomerTaxDisplayTypeAsync(Customer customer)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customer);
|
|
|
|
//default tax display type
|
|
var taxDisplayType = _taxSettings.TaxDisplayType;
|
|
|
|
//whether customers are allowed to select tax display type and the customer has previously saved one
|
|
if (_taxSettings.AllowCustomersToSelectTaxDisplayType && customer.TaxDisplayTypeId.HasValue)
|
|
taxDisplayType = (TaxDisplayType)customer.TaxDisplayTypeId.Value;
|
|
else
|
|
{
|
|
//default tax type by customer roles
|
|
var defaultRoleTaxDisplayType = await GetCustomerDefaultTaxDisplayTypeAsync(customer);
|
|
if (defaultRoleTaxDisplayType.HasValue)
|
|
taxDisplayType = defaultRoleTaxDisplayType.Value;
|
|
}
|
|
|
|
return taxDisplayType;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a default tax display type (if configured)
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the result
|
|
/// </returns>
|
|
public virtual async Task<TaxDisplayType?> GetCustomerDefaultTaxDisplayTypeAsync(Customer customer)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customer);
|
|
|
|
var roleWithOverriddenTaxType = (await GetCustomerRolesAsync(customer)).FirstOrDefault(cr => cr.Active && cr.OverrideTaxDisplayType);
|
|
if (roleWithOverriddenTaxType == null)
|
|
return null;
|
|
|
|
return (TaxDisplayType)roleWithOverriddenTaxType.DefaultTaxDisplayTypeId;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get full name
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the customer full name
|
|
/// </returns>
|
|
public virtual async Task<string> GetCustomerFullNameAsync(Customer customer)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customer);
|
|
|
|
var firstName = customer.FirstName;
|
|
var lastName = customer.LastName;
|
|
|
|
var fullName = string.Empty;
|
|
if (!string.IsNullOrWhiteSpace(firstName) && !string.IsNullOrWhiteSpace(lastName))
|
|
{
|
|
//do not inject ILocalizationService via constructor because it'll cause circular references
|
|
var format = await EngineContext.Current.Resolve<ILocalizationService>().GetResourceAsync("Customer.FullNameFormat");
|
|
|
|
fullName = string.Format(format, firstName, lastName);
|
|
}
|
|
else
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(firstName))
|
|
fullName = firstName;
|
|
|
|
if (!string.IsNullOrWhiteSpace(lastName))
|
|
fullName = lastName;
|
|
}
|
|
|
|
return fullName;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Formats the customer name
|
|
/// </summary>
|
|
/// <param name="customer">Source</param>
|
|
/// <param name="stripTooLong">Strip too long customer name</param>
|
|
/// <param name="maxLength">Maximum customer name length</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the formatted text
|
|
/// </returns>
|
|
public virtual async Task<string> FormatUsernameAsync(Customer customer, bool stripTooLong = false, int maxLength = 0)
|
|
{
|
|
if (customer == null)
|
|
return string.Empty;
|
|
|
|
if (await IsGuestAsync(customer))
|
|
//do not inject ILocalizationService via constructor because it'll cause circular references
|
|
return await EngineContext.Current.Resolve<ILocalizationService>().GetResourceAsync("Customer.Guest");
|
|
|
|
var result = string.Empty;
|
|
switch (_customerSettings.CustomerNameFormat)
|
|
{
|
|
case CustomerNameFormat.ShowEmails:
|
|
result = customer.Email;
|
|
break;
|
|
case CustomerNameFormat.ShowUsernames:
|
|
result = customer.Username;
|
|
break;
|
|
case CustomerNameFormat.ShowFullNames:
|
|
result = await GetCustomerFullNameAsync(customer);
|
|
break;
|
|
case CustomerNameFormat.ShowFirstName:
|
|
result = customer.FirstName;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (stripTooLong && maxLength > 0)
|
|
result = CommonHelper.EnsureMaximumLength(result, maxLength);
|
|
|
|
return result ?? string.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets coupon codes
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the coupon codes
|
|
/// </returns>
|
|
public virtual async Task<string[]> ParseAppliedDiscountCouponCodesAsync(Customer customer)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customer);
|
|
|
|
var existingCouponCodes = await _genericAttributeService.GetAttributeAsync<string>(customer, NopCustomerDefaults.DiscountCouponCodeAttribute);
|
|
|
|
var couponCodes = new List<string>();
|
|
if (string.IsNullOrEmpty(existingCouponCodes))
|
|
return couponCodes.ToArray();
|
|
|
|
try
|
|
{
|
|
var xmlDoc = new XmlDocument();
|
|
xmlDoc.LoadXml(existingCouponCodes);
|
|
|
|
var nodeList1 = xmlDoc.SelectNodes(@"//DiscountCouponCodes/CouponCode");
|
|
foreach (XmlNode node1 in nodeList1)
|
|
{
|
|
if (node1.Attributes?["Code"] == null)
|
|
continue;
|
|
var code = node1.Attributes["Code"].InnerText.Trim();
|
|
couponCodes.Add(code);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// ignored
|
|
}
|
|
|
|
return couponCodes.ToArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a coupon code
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <param name="couponCode">Coupon code</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the new coupon codes document
|
|
/// </returns>
|
|
public virtual async Task ApplyDiscountCouponCodeAsync(Customer customer, string couponCode)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customer);
|
|
|
|
var result = string.Empty;
|
|
try
|
|
{
|
|
var existingCouponCodes = await _genericAttributeService.GetAttributeAsync<string>(customer, NopCustomerDefaults.DiscountCouponCodeAttribute);
|
|
|
|
couponCode = couponCode.Trim().ToLowerInvariant();
|
|
|
|
var xmlDoc = new XmlDocument();
|
|
if (string.IsNullOrEmpty(existingCouponCodes))
|
|
{
|
|
var element1 = xmlDoc.CreateElement("DiscountCouponCodes");
|
|
xmlDoc.AppendChild(element1);
|
|
}
|
|
else
|
|
xmlDoc.LoadXml(existingCouponCodes);
|
|
|
|
var rootElement = (XmlElement)xmlDoc.SelectSingleNode(@"//DiscountCouponCodes");
|
|
|
|
XmlElement gcElement = null;
|
|
//find existing
|
|
var nodeList1 = xmlDoc.SelectNodes(@"//DiscountCouponCodes/CouponCode");
|
|
foreach (XmlNode node1 in nodeList1)
|
|
{
|
|
if (node1.Attributes?["Code"] == null)
|
|
continue;
|
|
|
|
var couponCodeAttribute = node1.Attributes["Code"].InnerText.Trim();
|
|
|
|
if (couponCodeAttribute.ToLowerInvariant() != couponCode.ToLowerInvariant())
|
|
continue;
|
|
|
|
gcElement = (XmlElement)node1;
|
|
break;
|
|
}
|
|
|
|
//create new one if not found
|
|
if (gcElement == null)
|
|
{
|
|
gcElement = xmlDoc.CreateElement("CouponCode");
|
|
gcElement.SetAttribute("Code", couponCode);
|
|
rootElement.AppendChild(gcElement);
|
|
}
|
|
|
|
result = xmlDoc.OuterXml;
|
|
}
|
|
catch
|
|
{
|
|
// ignored
|
|
}
|
|
|
|
//apply new value
|
|
await _genericAttributeService.SaveAttributeAsync(customer, NopCustomerDefaults.DiscountCouponCodeAttribute, result);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes a coupon code
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <param name="couponCode">Coupon code to remove</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the new coupon codes document
|
|
/// </returns>
|
|
public virtual async Task RemoveDiscountCouponCodeAsync(Customer customer, string couponCode)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customer);
|
|
|
|
//get applied coupon codes
|
|
var existingCouponCodes = await ParseAppliedDiscountCouponCodesAsync(customer);
|
|
|
|
//clear them
|
|
await _genericAttributeService.SaveAttributeAsync<string>(customer, NopCustomerDefaults.DiscountCouponCodeAttribute, null);
|
|
|
|
//save again except removed one
|
|
foreach (var existingCouponCode in existingCouponCodes)
|
|
if (!existingCouponCode.Equals(couponCode, StringComparison.InvariantCultureIgnoreCase))
|
|
await ApplyDiscountCouponCodeAsync(customer, existingCouponCode);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets coupon codes
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the coupon codes
|
|
/// </returns>
|
|
public virtual async Task<string[]> ParseAppliedGiftCardCouponCodesAsync(Customer customer)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customer);
|
|
|
|
var existingCouponCodes = await _genericAttributeService.GetAttributeAsync<string>(customer, NopCustomerDefaults.GiftCardCouponCodesAttribute);
|
|
|
|
var couponCodes = new List<string>();
|
|
if (string.IsNullOrEmpty(existingCouponCodes))
|
|
return couponCodes.ToArray();
|
|
|
|
try
|
|
{
|
|
var xmlDoc = new XmlDocument();
|
|
xmlDoc.LoadXml(existingCouponCodes);
|
|
|
|
var nodeList1 = xmlDoc.SelectNodes(@"//GiftCardCouponCodes/CouponCode");
|
|
foreach (XmlNode node1 in nodeList1)
|
|
{
|
|
if (node1.Attributes?["Code"] == null)
|
|
continue;
|
|
|
|
var code = node1.Attributes["Code"].InnerText.Trim();
|
|
couponCodes.Add(code);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// ignored
|
|
}
|
|
|
|
return couponCodes.ToArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a coupon code
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <param name="couponCode">Coupon code</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the new coupon codes document
|
|
/// </returns>
|
|
public virtual async Task ApplyGiftCardCouponCodeAsync(Customer customer, string couponCode)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customer);
|
|
|
|
var result = string.Empty;
|
|
try
|
|
{
|
|
var existingCouponCodes = await _genericAttributeService.GetAttributeAsync<string>(customer, NopCustomerDefaults.GiftCardCouponCodesAttribute);
|
|
|
|
couponCode = couponCode.Trim().ToLowerInvariant();
|
|
|
|
var xmlDoc = new XmlDocument();
|
|
if (string.IsNullOrEmpty(existingCouponCodes))
|
|
{
|
|
var element1 = xmlDoc.CreateElement("GiftCardCouponCodes");
|
|
xmlDoc.AppendChild(element1);
|
|
}
|
|
else
|
|
xmlDoc.LoadXml(existingCouponCodes);
|
|
|
|
var rootElement = (XmlElement)xmlDoc.SelectSingleNode(@"//GiftCardCouponCodes");
|
|
|
|
XmlElement gcElement = null;
|
|
//find existing
|
|
var nodeList1 = xmlDoc.SelectNodes(@"//GiftCardCouponCodes/CouponCode");
|
|
foreach (XmlNode node1 in nodeList1)
|
|
{
|
|
if (node1.Attributes?["Code"] == null)
|
|
continue;
|
|
|
|
var couponCodeAttribute = node1.Attributes["Code"].InnerText.Trim();
|
|
if (couponCodeAttribute.ToLowerInvariant() != couponCode.ToLowerInvariant())
|
|
continue;
|
|
|
|
gcElement = (XmlElement)node1;
|
|
break;
|
|
}
|
|
|
|
//create new one if not found
|
|
if (gcElement == null)
|
|
{
|
|
gcElement = xmlDoc.CreateElement("CouponCode");
|
|
gcElement.SetAttribute("Code", couponCode);
|
|
rootElement.AppendChild(gcElement);
|
|
}
|
|
|
|
result = xmlDoc.OuterXml;
|
|
}
|
|
catch
|
|
{
|
|
// ignored
|
|
}
|
|
|
|
//apply new value
|
|
await _genericAttributeService.SaveAttributeAsync(customer, NopCustomerDefaults.GiftCardCouponCodesAttribute, result);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes a coupon code
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <param name="couponCode">Coupon code to remove</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the new coupon codes document
|
|
/// </returns>
|
|
public virtual async Task RemoveGiftCardCouponCodeAsync(Customer customer, string couponCode)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customer);
|
|
|
|
//get applied coupon codes
|
|
var existingCouponCodes = await ParseAppliedGiftCardCouponCodesAsync(customer);
|
|
|
|
//clear them
|
|
await _genericAttributeService.SaveAttributeAsync<string>(customer, NopCustomerDefaults.GiftCardCouponCodesAttribute, null);
|
|
|
|
//save again except removed one
|
|
foreach (var existingCouponCode in existingCouponCodes)
|
|
if (!existingCouponCode.Equals(couponCode, StringComparison.InvariantCultureIgnoreCase))
|
|
await ApplyGiftCardCouponCodeAsync(customer, existingCouponCode);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a list of guids of not existing customers
|
|
/// </summary>
|
|
/// <param name="guids">The guids of the customers to check</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the list of guids not existing customers
|
|
/// </returns>
|
|
public virtual async Task<Guid[]> GetNotExistingCustomersAsync(Guid[] guids)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(guids);
|
|
|
|
var query = _customerRepository.Table;
|
|
var queryFilter = guids.Distinct().ToArray();
|
|
//filtering by guid
|
|
var filter = await query.Select(c => c.CustomerGuid)
|
|
.Where(c => queryFilter.Contains(c))
|
|
.ToListAsync();
|
|
|
|
return queryFilter.Except(filter).ToArray();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Customer roles
|
|
|
|
/// <summary>
|
|
/// Add a customer-customer role mapping
|
|
/// </summary>
|
|
/// <param name="roleMapping">Customer-customer role mapping</param>
|
|
/// <returns>A task that represents the asynchronous operation</returns>
|
|
public async Task AddCustomerRoleMappingAsync(CustomerCustomerRoleMapping roleMapping)
|
|
{
|
|
await _customerCustomerRoleMappingRepository.InsertAsync(roleMapping);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove a customer-customer role mapping
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <param name="role">Customer role</param>
|
|
/// <returns>A task that represents the asynchronous operation</returns>
|
|
public async Task RemoveCustomerRoleMappingAsync(Customer customer, CustomerRole role)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customer);
|
|
|
|
ArgumentNullException.ThrowIfNull(role);
|
|
|
|
var mapping = await _customerCustomerRoleMappingRepository.Table
|
|
.SingleOrDefaultAsync(ccrm => ccrm.CustomerId == customer.Id && ccrm.CustomerRoleId == role.Id);
|
|
|
|
if (mapping != null)
|
|
await _customerCustomerRoleMappingRepository.DeleteAsync(mapping);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delete a customer role
|
|
/// </summary>
|
|
/// <param name="customerRole">Customer role</param>
|
|
/// <returns>A task that represents the asynchronous operation</returns>
|
|
public virtual async Task DeleteCustomerRoleAsync(CustomerRole customerRole)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customerRole);
|
|
|
|
if (customerRole.IsSystemRole)
|
|
throw new NopException("System role could not be deleted");
|
|
|
|
await _customerRoleRepository.DeleteAsync(customerRole);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a customer role
|
|
/// </summary>
|
|
/// <param name="customerRoleId">Customer role identifier</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the customer role
|
|
/// </returns>
|
|
public virtual async Task<CustomerRole> GetCustomerRoleByIdAsync(int customerRoleId)
|
|
{
|
|
var allRolesById = await GetAllCustomerRolesDictionaryAsync();
|
|
|
|
return allRolesById.TryGetValue(customerRoleId, out var role) ? role : null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a customer role
|
|
/// </summary>
|
|
/// <param name="systemName">Customer role system name</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the customer role
|
|
/// </returns>
|
|
public virtual async Task<CustomerRole> GetCustomerRoleBySystemNameAsync(string systemName)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(systemName))
|
|
return null;
|
|
|
|
var key = _staticCacheManager.PrepareKeyForDefaultCache(NopCustomerServicesDefaults.CustomerRolesBySystemNameCacheKey, systemName);
|
|
|
|
var query = from cr in _customerRoleRepository.Table
|
|
orderby cr.Id
|
|
where cr.SystemName == systemName
|
|
select cr;
|
|
|
|
var customerRole = await _staticCacheManager.GetAsync(key, async () => await query.FirstOrDefaultAsync());
|
|
|
|
return customerRole;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get customer role identifiers
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <param name="showHidden">A value indicating whether to load hidden records</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the customer role identifiers
|
|
/// </returns>
|
|
public virtual async Task<int[]> GetCustomerRoleIdsAsync(Customer customer, bool showHidden = false)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customer);
|
|
|
|
return (await GetCustomerRolesAsync(customer, showHidden: showHidden))
|
|
.Select(cr => cr.Id)
|
|
.ToArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets list of customer roles
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <param name="showHidden">A value indicating whether to load hidden records</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the result
|
|
/// </returns>
|
|
public virtual async Task<IList<CustomerRole>> GetCustomerRolesAsync(Customer customer, bool showHidden = false)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customer);
|
|
|
|
var allRolesById = await GetAllCustomerRolesDictionaryAsync();
|
|
|
|
var mappings = await _shortTermCacheManager.GetAsync(
|
|
async () => await _customerCustomerRoleMappingRepository.GetAllAsync(query => query.Where(crm => crm.CustomerId == customer.Id)), NopCustomerServicesDefaults.CustomerRolesCacheKey, customer);
|
|
|
|
return mappings.Select(mapping => allRolesById.TryGetValue(mapping.CustomerRoleId, out var role) ? role : null)
|
|
.Where(cr => cr != null && (showHidden || cr.Active))
|
|
.ToList();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets all customer roles
|
|
/// </summary>
|
|
/// <param name="showHidden">A value indicating whether to show hidden records</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the customer roles
|
|
/// </returns>
|
|
public virtual async Task<IList<CustomerRole>> GetAllCustomerRolesAsync(bool showHidden = false)
|
|
{
|
|
var allRolesById = await GetAllCustomerRolesDictionaryAsync();
|
|
|
|
return allRolesById.Values
|
|
.Where(cr => showHidden || cr.Active)
|
|
.ToList();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Inserts a customer role
|
|
/// </summary>
|
|
/// <param name="customerRole">Customer role</param>
|
|
/// <returns>A task that represents the asynchronous operation</returns>
|
|
public virtual async Task InsertCustomerRoleAsync(CustomerRole customerRole)
|
|
{
|
|
await _customerRoleRepository.InsertAsync(customerRole);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether customer is in a certain customer role
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <param name="customerRoleSystemName">Customer role system name</param>
|
|
/// <param name="onlyActiveCustomerRoles">A value indicating whether we should look only in active customer roles</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the result
|
|
/// </returns>
|
|
public virtual async Task<bool> IsInCustomerRoleAsync(Customer customer,
|
|
string customerRoleSystemName, bool onlyActiveCustomerRoles = true)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customer);
|
|
ArgumentException.ThrowIfNullOrEmpty(customerRoleSystemName);
|
|
|
|
var customerRoles = await GetCustomerRolesAsync(customer, !onlyActiveCustomerRoles);
|
|
|
|
return customerRoles?.Any(cr => cr.SystemName == customerRoleSystemName) ?? false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether customer is administrator
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <param name="onlyActiveCustomerRoles">A value indicating whether we should look only in active customer roles</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the result
|
|
/// </returns>
|
|
public virtual async Task<bool> IsAdminAsync(Customer customer, bool onlyActiveCustomerRoles = true)
|
|
{
|
|
return await IsInCustomerRoleAsync(customer, NopCustomerDefaults.AdministratorsRoleName, onlyActiveCustomerRoles);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether customer is a forum moderator
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <param name="onlyActiveCustomerRoles">A value indicating whether we should look only in active customer roles</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the result
|
|
/// </returns>
|
|
public virtual async Task<bool> IsForumModeratorAsync(Customer customer, bool onlyActiveCustomerRoles = true)
|
|
{
|
|
return await IsInCustomerRoleAsync(customer, NopCustomerDefaults.ForumModeratorsRoleName, onlyActiveCustomerRoles);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether customer is registered
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <param name="onlyActiveCustomerRoles">A value indicating whether we should look only in active customer roles</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the result
|
|
/// </returns>
|
|
public virtual async Task<bool> IsRegisteredAsync(Customer customer, bool onlyActiveCustomerRoles = true)
|
|
{
|
|
return await IsInCustomerRoleAsync(customer, NopCustomerDefaults.RegisteredRoleName, onlyActiveCustomerRoles);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether customer is guest
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <param name="onlyActiveCustomerRoles">A value indicating whether we should look only in active customer roles</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the result
|
|
/// </returns>
|
|
public virtual async Task<bool> IsGuestAsync(Customer customer, bool onlyActiveCustomerRoles = true)
|
|
{
|
|
return await IsInCustomerRoleAsync(customer, NopCustomerDefaults.GuestsRoleName, onlyActiveCustomerRoles);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether customer is vendor
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <param name="onlyActiveCustomerRoles">A value indicating whether we should look only in active customer roles</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the result
|
|
/// </returns>
|
|
public virtual async Task<bool> IsVendorAsync(Customer customer, bool onlyActiveCustomerRoles = true)
|
|
{
|
|
return await IsInCustomerRoleAsync(customer, NopCustomerDefaults.VendorsRoleName, onlyActiveCustomerRoles);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the customer role
|
|
/// </summary>
|
|
/// <param name="customerRole">Customer role</param>
|
|
/// <returns>A task that represents the asynchronous operation</returns>
|
|
public virtual async Task UpdateCustomerRoleAsync(CustomerRole customerRole)
|
|
{
|
|
await _customerRoleRepository.UpdateAsync(customerRole);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Customer passwords
|
|
|
|
/// <summary>
|
|
/// Gets customer passwords
|
|
/// </summary>
|
|
/// <param name="customerId">Customer identifier; pass null to load all records</param>
|
|
/// <param name="passwordFormat">Password format; pass null to load all records</param>
|
|
/// <param name="passwordsToReturn">Number of returning passwords; pass null to load all records</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the list of customer passwords
|
|
/// </returns>
|
|
public virtual async Task<IList<CustomerPassword>> GetCustomerPasswordsAsync(int? customerId = null,
|
|
PasswordFormat? passwordFormat = null, int? passwordsToReturn = null)
|
|
{
|
|
var query = _customerPasswordRepository.Table;
|
|
|
|
//filter by customer
|
|
if (customerId.HasValue)
|
|
query = query.Where(password => password.CustomerId == customerId.Value);
|
|
|
|
//filter by password format
|
|
if (passwordFormat.HasValue)
|
|
query = query.Where(password => password.PasswordFormatId == (int)passwordFormat.Value);
|
|
|
|
//get the latest passwords
|
|
if (passwordsToReturn.HasValue)
|
|
query = query.OrderByDescending(password => password.CreatedOnUtc).Take(passwordsToReturn.Value);
|
|
|
|
return await query.ToListAsync();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get current customer password
|
|
/// </summary>
|
|
/// <param name="customerId">Customer identifier</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the customer password
|
|
/// </returns>
|
|
public virtual async Task<CustomerPassword> GetCurrentPasswordAsync(int customerId)
|
|
{
|
|
if (customerId == 0)
|
|
return null;
|
|
|
|
//return the latest password
|
|
return (await GetCustomerPasswordsAsync(customerId, passwordsToReturn: 1)).FirstOrDefault();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Insert a customer password
|
|
/// </summary>
|
|
/// <param name="customerPassword">Customer password</param>
|
|
/// <returns>A task that represents the asynchronous operation</returns>
|
|
public virtual async Task InsertCustomerPasswordAsync(CustomerPassword customerPassword)
|
|
{
|
|
await _customerPasswordRepository.InsertAsync(customerPassword);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update a customer password
|
|
/// </summary>
|
|
/// <param name="customerPassword">Customer password</param>
|
|
/// <returns>A task that represents the asynchronous operation</returns>
|
|
public virtual async Task UpdateCustomerPasswordAsync(CustomerPassword customerPassword)
|
|
{
|
|
await _customerPasswordRepository.UpdateAsync(customerPassword);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check whether password recovery token is valid
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <param name="token">Token to validate</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the result
|
|
/// </returns>
|
|
public virtual async Task<bool> IsPasswordRecoveryTokenValidAsync(Customer customer, string token)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customer);
|
|
|
|
var cPrt = await _genericAttributeService.GetAttributeAsync<string>(customer, NopCustomerDefaults.PasswordRecoveryTokenAttribute);
|
|
if (string.IsNullOrEmpty(cPrt))
|
|
return false;
|
|
|
|
if (!cPrt.Equals(token, StringComparison.InvariantCultureIgnoreCase))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check whether password recovery link is expired
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the result
|
|
/// </returns>
|
|
public virtual async Task<bool> IsPasswordRecoveryLinkExpiredAsync(Customer customer)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customer);
|
|
|
|
if (_customerSettings.PasswordRecoveryLinkDaysValid == 0)
|
|
return false;
|
|
|
|
var generatedDate = await _genericAttributeService.GetAttributeAsync<DateTime?>(customer, NopCustomerDefaults.PasswordRecoveryTokenDateGeneratedAttribute);
|
|
if (!generatedDate.HasValue)
|
|
return false;
|
|
|
|
var daysPassed = (DateTime.UtcNow - generatedDate.Value).TotalDays;
|
|
if (daysPassed > _customerSettings.PasswordRecoveryLinkDaysValid)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check whether customer password is expired
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains true if password is expired; otherwise false
|
|
/// </returns>
|
|
public virtual async Task<bool> IsPasswordExpiredAsync(Customer customer)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customer);
|
|
|
|
//the guests don't have a password
|
|
if (await IsGuestAsync(customer))
|
|
return false;
|
|
|
|
//password lifetime is disabled for user
|
|
if (!(await GetCustomerRolesAsync(customer)).Any(role => role.Active && role.EnablePasswordLifetime))
|
|
return false;
|
|
|
|
//setting disabled for all
|
|
if (_customerSettings.PasswordLifetime == 0)
|
|
return false;
|
|
|
|
//get current password usage time
|
|
var currentLifetime = await _shortTermCacheManager.GetAsync(async () =>
|
|
{
|
|
var customerPassword = await GetCurrentPasswordAsync(customer.Id);
|
|
//password is not found, so return max value to force customer to change password
|
|
if (customerPassword == null)
|
|
return int.MaxValue;
|
|
|
|
return (DateTime.UtcNow - customerPassword.CreatedOnUtc).Days;
|
|
}, NopCustomerServicesDefaults.CustomerPasswordLifetimeCacheKey, customer);
|
|
|
|
return currentLifetime >= _customerSettings.PasswordLifetime;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Customer address mapping
|
|
|
|
/// <summary>
|
|
/// Remove a customer-address mapping record
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <param name="address">Address</param>
|
|
/// <returns>A task that represents the asynchronous operation</returns>
|
|
public virtual async Task RemoveCustomerAddressAsync(Customer customer, Address address)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customer);
|
|
|
|
if (await _customerAddressMappingRepository.Table
|
|
.FirstOrDefaultAsync(m => m.AddressId == address.Id && m.CustomerId == customer.Id)
|
|
is CustomerAddressMapping mapping)
|
|
{
|
|
if (customer.BillingAddressId == address.Id)
|
|
customer.BillingAddressId = null;
|
|
if (customer.ShippingAddressId == address.Id)
|
|
customer.ShippingAddressId = null;
|
|
|
|
await _customerAddressMappingRepository.DeleteAsync(mapping);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Inserts a customer-address mapping record
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <param name="address">Address</param>
|
|
/// <returns>A task that represents the asynchronous operation</returns>
|
|
public virtual async Task InsertCustomerAddressAsync(Customer customer, Address address)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customer);
|
|
|
|
ArgumentNullException.ThrowIfNull(address);
|
|
|
|
if (await _customerAddressMappingRepository.Table
|
|
.FirstOrDefaultAsync(m => m.AddressId == address.Id && m.CustomerId == customer.Id)
|
|
is null)
|
|
{
|
|
var mapping = new CustomerAddressMapping
|
|
{
|
|
AddressId = address.Id,
|
|
CustomerId = customer.Id
|
|
};
|
|
|
|
await _customerAddressMappingRepository.InsertAsync(mapping);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a list of addresses mapped to customer
|
|
/// </summary>
|
|
/// <param name="customerId">Customer identifier</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the result
|
|
/// </returns>
|
|
public virtual async Task<IList<Address>> GetAddressesByCustomerIdAsync(int customerId)
|
|
{
|
|
var query = from address in _customerAddressRepository.Table
|
|
join cam in _customerAddressMappingRepository.Table on address.Id equals cam.AddressId
|
|
where cam.CustomerId == customerId
|
|
select address;
|
|
|
|
return await _shortTermCacheManager.GetAsync(async () => await query.ToListAsync(), NopCustomerServicesDefaults.CustomerAddressesCacheKey, customerId);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a address mapped to customer
|
|
/// </summary>
|
|
/// <param name="customerId">Customer identifier</param>
|
|
/// <param name="addressId">Address identifier</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the result
|
|
/// </returns>
|
|
public virtual async Task<Address> GetCustomerAddressAsync(int customerId, int addressId)
|
|
{
|
|
if (customerId == 0 || addressId == 0)
|
|
return null;
|
|
|
|
var query = from address in _customerAddressRepository.Table
|
|
join cam in _customerAddressMappingRepository.Table on address.Id equals cam.AddressId
|
|
where cam.CustomerId == customerId && address.Id == addressId
|
|
select address;
|
|
|
|
return await _shortTermCacheManager.GetAsync(async () => await query.FirstOrDefaultAsync(), NopCustomerServicesDefaults.CustomerAddressCacheKey, customerId, addressId);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a customer billing address
|
|
/// </summary>
|
|
/// <param name="customer">Customer identifier</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the result
|
|
/// </returns>
|
|
public virtual async Task<Address> GetCustomerBillingAddressAsync(Customer customer)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customer);
|
|
|
|
return await GetCustomerAddressAsync(customer.Id, customer.BillingAddressId ?? 0);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a customer shipping address
|
|
/// </summary>
|
|
/// <param name="customer">Customer</param>
|
|
/// <returns>
|
|
/// A task that represents the asynchronous operation
|
|
/// The task result contains the result
|
|
/// </returns>
|
|
public virtual async Task<Address> GetCustomerShippingAddressAsync(Customer customer)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(customer);
|
|
|
|
return await GetCustomerAddressAsync(customer.Id, customer.ShippingAddressId ?? 0);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
} |