Try your search with a different keyword or use * as a wildcard.
using Nop.Core;
using Nop.Core.Domain.Customers;
using Nop.Core.Domain.Orders;
using Nop.Data;
using Nop.Services.Helpers;
using Nop.Services.Localization;
namespace Nop.Services.Orders;
///
/// Reward point service
///
public partial class RewardPointService : IRewardPointService
{
#region Fields
protected readonly IDateTimeHelper _dateTimeHelper;
protected readonly ILocalizationService _localizationService;
protected readonly IRepository _rewardPointsHistoryRepository;
protected readonly RewardPointsSettings _rewardPointsSettings;
#endregion
#region Ctor
public RewardPointService(IDateTimeHelper dateTimeHelper,
ILocalizationService localizationService,
IRepository rewardPointsHistoryRepository,
RewardPointsSettings rewardPointsSettings)
{
_dateTimeHelper = dateTimeHelper;
_localizationService = localizationService;
_rewardPointsHistoryRepository = rewardPointsHistoryRepository;
_rewardPointsSettings = rewardPointsSettings;
}
#endregion
#region Utilities
///
/// Get query to load reward points history
///
/// Customer identifier; pass 0 to load all records
/// Store identifier; pass null to load all records
/// Whether to load reward points that did not yet activated
///
/// A task that represents the asynchronous operation
/// The task result contains the query to load reward points history
///
protected virtual async Task> GetRewardPointsQueryAsync(int customerId, int? storeId, bool showNotActivated = false)
{
var query = _rewardPointsHistoryRepository.Table;
//filter by customer
if (customerId > 0)
query = query.Where(historyEntry => historyEntry.CustomerId == customerId);
//filter by store
if (!_rewardPointsSettings.PointsAccumulatedForAllStores && storeId > 0)
query = query.Where(historyEntry => historyEntry.StoreId == storeId);
//whether to show only the points that already activated
if (!showNotActivated)
query = query.Where(historyEntry => historyEntry.CreatedOnUtc < DateTime.UtcNow);
//update points balance
await UpdateRewardPointsBalanceAsync(query);
return query;
}
///
/// Update reward points balance if necessary
///
/// Input query
/// A task that represents the asynchronous operation
protected virtual async Task UpdateRewardPointsBalanceAsync(IQueryable query)
{
//get expired points
var nowUtc = DateTime.UtcNow;
var expiredPoints = query
.Where(historyEntry => historyEntry.EndDateUtc < nowUtc && historyEntry.ValidPoints > 0)
.OrderBy(historyEntry => historyEntry.CreatedOnUtc).ThenBy(historyEntry => historyEntry.Id).ToList();
//reduce the balance for these points
foreach (var historyEntry in expiredPoints)
{
await InsertRewardPointsHistoryEntryAsync(new RewardPointsHistory
{
CustomerId = historyEntry.CustomerId,
StoreId = historyEntry.StoreId,
Points = -historyEntry.ValidPoints.Value,
Message = string.Format(await _localizationService.GetResourceAsync("RewardPoints.Expired"),
await _dateTimeHelper.ConvertToUserTimeAsync(historyEntry.CreatedOnUtc, DateTimeKind.Utc)),
CreatedOnUtc = historyEntry.EndDateUtc.Value
});
historyEntry.ValidPoints = 0;
await UpdateRewardPointsHistoryEntryAsync(historyEntry);
}
//get has not yet activated points, but it's time to do it
var notActivatedPoints = query
.Where(historyEntry => !historyEntry.PointsBalance.HasValue && historyEntry.CreatedOnUtc < nowUtc)
.OrderBy(historyEntry => historyEntry.CreatedOnUtc).ThenBy(historyEntry => historyEntry.Id).ToList();
if (!notActivatedPoints.Any())
return;
//get current points balance
//LINQ to entities does not support Last method, thus order by desc and use First one
var currentPointsBalance = query
.OrderByDescending(historyEntry => historyEntry.CreatedOnUtc).ThenByDescending(historyEntry => historyEntry.Id)
.FirstOrDefault(historyEntry => historyEntry.PointsBalance.HasValue)
?.PointsBalance ?? 0;
//update appropriate records
foreach (var historyEntry in notActivatedPoints)
{
currentPointsBalance += historyEntry.Points;
historyEntry.PointsBalance = currentPointsBalance;
await UpdateRewardPointsHistoryEntryAsync(historyEntry);
}
}
///
/// Insert the reward point history entry
///
/// Reward point history entry
/// A task that represents the asynchronous operation
protected virtual async Task InsertRewardPointsHistoryEntryAsync(RewardPointsHistory rewardPointsHistory)
{
await _rewardPointsHistoryRepository.InsertAsync(rewardPointsHistory);
}
#endregion
#region Methods
///
/// Load reward point history records
///
/// Customer identifier; 0 to load all records
/// Store identifier; pass null to load all records
/// A value indicating whether to show reward points that did not yet activated
/// Order Guid; pass null to load all record
/// Page index
/// Page size
///
/// A task that represents the asynchronous operation
/// The task result contains the reward point history records
///
public virtual async Task> GetRewardPointsHistoryAsync(int customerId = 0, int? storeId = null,
bool showNotActivated = false, Guid? orderGuid = null, int pageIndex = 0, int pageSize = int.MaxValue)
{
var query = await GetRewardPointsQueryAsync(customerId, storeId, showNotActivated);
if (orderGuid.HasValue)
query = query.Where(historyEntry => historyEntry.UsedWithOrder == orderGuid.Value);
query = query.OrderByDescending(historyEntry => historyEntry.CreatedOnUtc)
.ThenByDescending(historyEntry => historyEntry.Id);
//return paged reward points history
return await query.ToPagedListAsync(pageIndex, pageSize);
}
///
/// Gets reward points balance
///
/// Customer identifier
/// Store identifier
///
/// A task that represents the asynchronous operation
/// The task result contains the balance
///
public virtual async Task GetRewardPointsBalanceAsync(int customerId, int storeId)
{
var query = (await GetRewardPointsQueryAsync(customerId, storeId))
.OrderByDescending(historyEntry => historyEntry.CreatedOnUtc).ThenByDescending(historyEntry => historyEntry.Id);
//return point balance of the first actual history entry
return (await query.FirstOrDefaultAsync())?.PointsBalance ?? 0;
}
///
/// Add reward points history record
///
/// Customer
/// Number of points to add
/// Store identifier
/// Message
/// The order for which points were redeemed (spent) as a payment
/// Used amount
/// Date and time of activating reward points; pass null to immediately activating
/// Date and time when the reward points will no longer be valid; pass null to add date termless points
///
/// A task that represents the asynchronous operation
/// The task result contains the reward points history entry identifier
///
public virtual async Task AddRewardPointsHistoryEntryAsync(Customer customer, int points, int storeId, string message = "",
Order usedWithOrder = null, decimal usedAmount = 0M, DateTime? activatingDate = null, DateTime? endDate = null)
{
ArgumentNullException.ThrowIfNull(customer);
if (storeId == 0)
throw new ArgumentException("Store ID should be valid");
if (points < 0 && endDate.HasValue)
throw new ArgumentException("End date is available only for positive points amount");
//insert new history entry
var newHistoryEntry = new RewardPointsHistory
{
CustomerId = customer.Id,
StoreId = storeId,
Points = points,
PointsBalance = activatingDate.HasValue ? null : (int?)(await GetRewardPointsBalanceAsync(customer.Id, storeId) + points),
UsedAmount = usedAmount,
Message = message,
CreatedOnUtc = activatingDate ?? DateTime.UtcNow,
EndDateUtc = endDate,
ValidPoints = points > 0 ? (int?)points : null,
UsedWithOrder = usedWithOrder?.OrderGuid
};
await InsertRewardPointsHistoryEntryAsync(newHistoryEntry);
//reduce valid points of previous entries
if (points >= 0)
return newHistoryEntry.Id;
var withValidPoints = (await GetRewardPointsQueryAsync(customer.Id, storeId))
.Where(historyEntry => historyEntry.ValidPoints > 0)
.OrderBy(historyEntry => historyEntry.CreatedOnUtc).ThenBy(historyEntry => historyEntry.Id).ToList();
foreach (var historyEntry in withValidPoints)
{
points += historyEntry.ValidPoints.Value;
historyEntry.ValidPoints = Math.Max(points, 0);
await UpdateRewardPointsHistoryEntryAsync(historyEntry);
if (points >= 0)
break;
}
return newHistoryEntry.Id;
}
///
/// Gets a reward point history entry
///
/// Reward point history entry identifier
///
/// A task that represents the asynchronous operation
/// The task result contains the reward point history entry
///
public virtual async Task GetRewardPointsHistoryEntryByIdAsync(int rewardPointsHistoryId)
{
return await _rewardPointsHistoryRepository.GetByIdAsync(rewardPointsHistoryId);
}
///
/// Update the reward point history entry
///
/// Reward point history entry
/// A task that represents the asynchronous operation
public virtual async Task UpdateRewardPointsHistoryEntryAsync(RewardPointsHistory rewardPointsHistory)
{
await _rewardPointsHistoryRepository.UpdateAsync(rewardPointsHistory);
}
///
/// Delete the reward point history entry
///
/// Reward point history entry
/// A task that represents the asynchronous operation
public virtual async Task DeleteRewardPointsHistoryEntryAsync(RewardPointsHistory rewardPointsHistory)
{
await _rewardPointsHistoryRepository.DeleteAsync(rewardPointsHistory);
}
#endregion
}