Adding
This commit is contained in:
+122
@@ -0,0 +1,122 @@
|
||||
using LCU.Library.Internal.IncentiveApiModels.Enums;
|
||||
using LCU.API.Internal.Operations.IncentiveApi.Models.Payout;
|
||||
using LCU.Library.Internal.IncentiveApiModels.Entities;
|
||||
|
||||
namespace LCU.API.Internal.Operations.IncentiveApi.Services.Payout;
|
||||
|
||||
public class DefaultPayoutStrategy : IPayoutStrategy
|
||||
{
|
||||
public bool CanPayoutProduct(Product product)
|
||||
{
|
||||
return product != Product.GAPInsurance;
|
||||
}
|
||||
|
||||
public IReadOnlyCollection<PayoutLineItem> CalculateLineItems(
|
||||
DepartmentPayout payoutPlan,
|
||||
UserDepartment userDepartment,
|
||||
List<PayoutProfile> departmentPayoutProfiles,
|
||||
ProductDetail product
|
||||
)
|
||||
{
|
||||
var lineItems = new List<PayoutLineItem>();
|
||||
|
||||
var eligiblePayoutProfiles = departmentPayoutProfiles.Where(p => p.Product == product.Product);
|
||||
|
||||
foreach (var eligiblePayoutProfile in eligiblePayoutProfiles.Where(x => x.Type == PayoutType.Personal))
|
||||
{
|
||||
var eligibleGoal = payoutPlan.PersonalGoals.FirstOrDefault(g => g.Product == product.Product);
|
||||
if (eligibleGoal == null) continue;
|
||||
|
||||
var relatedActivity = payoutPlan.PersonalActivity
|
||||
.Where(a => a.DepartmentId == userDepartment.DepartmentId &&
|
||||
a.Product == product.Product)
|
||||
.ToList();
|
||||
|
||||
if (!relatedActivity.Any()) continue;
|
||||
|
||||
var eligibleActivity = relatedActivity
|
||||
.Where(a => a.State == ActivityState.Accepted
|
||||
&& !payoutPlan.PersonalRules.Any(x => x.RestrictedByPayoutRule(a, product.Product)));
|
||||
|
||||
var lineItem = new PayoutLineItem(product.Product, eligiblePayoutProfile, eligibleGoal,
|
||||
userDepartment.SlidingPayout, eligibleActivity, payoutPlan.MonthRange.StartTime)
|
||||
{
|
||||
ActivityPeriod = payoutPlan.MonthRange.StartTime,
|
||||
AppUserId = userDepartment.Employee.Id,
|
||||
EmployeeId = userDepartment.Employee.EmployeeId,
|
||||
DepartmentId = userDepartment.DepartmentId,
|
||||
Role = userDepartment.Role
|
||||
};
|
||||
lineItem.PayoutTotal = CalculateLineItemPayout(eligiblePayoutProfile, lineItem.GoalValue, lineItem.ActivityTotal,
|
||||
payoutPlan.MonthRange.StartTime, lineItem.SlidingPayout);
|
||||
|
||||
if (lineItem.PayoutTotal > 0)
|
||||
{
|
||||
lineItems.Add(lineItem);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var eligiblePayoutProfile in eligiblePayoutProfiles.Where(x => x.Type == PayoutType.Department))
|
||||
{
|
||||
var eligibleGoal = payoutPlan.DepartmentGoals.FirstOrDefault(g => g.Product == product.Product);
|
||||
if (eligibleGoal == null) continue;
|
||||
|
||||
var relatedActivity = payoutPlan.DepartmentActivity
|
||||
.Where(a => a.Product == product.Product)
|
||||
.ToList();
|
||||
|
||||
var eligibleActivity = relatedActivity
|
||||
.Where(a => a.State == ActivityState.Accepted
|
||||
&& !payoutPlan.DepartmentRules.Any(x => x.RestrictedByPayoutRule(a, product.Product)));
|
||||
|
||||
var lineItem = new PayoutLineItem(product.Product, eligiblePayoutProfile, eligibleGoal,
|
||||
userDepartment.SlidingPayout, eligibleActivity, payoutPlan.MonthRange.StartTime)
|
||||
{
|
||||
ActivityPeriod = payoutPlan.MonthRange.StartTime,
|
||||
AppUserId = userDepartment.Employee.Id,
|
||||
EmployeeId = userDepartment.Employee.EmployeeId,
|
||||
DepartmentId = userDepartment.DepartmentId,
|
||||
Role = userDepartment.Role
|
||||
};
|
||||
lineItem.PayoutTotal = CalculateLineItemPayout(eligiblePayoutProfile, lineItem.GoalValue, lineItem.ActivityTotal,
|
||||
payoutPlan.MonthRange.StartTime, lineItem.SlidingPayout);
|
||||
|
||||
if (lineItem.PayoutTotal > 0)
|
||||
{
|
||||
lineItems.Add(lineItem);
|
||||
}
|
||||
}
|
||||
|
||||
return lineItems;
|
||||
}
|
||||
|
||||
public decimal CalculateLineItemPayout(PayoutProfile profile, int goal, decimal actual, DateTime runDate, decimal payoutPercent = 100)
|
||||
{
|
||||
if (profile == null)
|
||||
{
|
||||
throw new Exception("Attempt to calculate payout with null profile");
|
||||
}
|
||||
|
||||
if (goal == 0) return 0;
|
||||
|
||||
var goalPercentage = (double)actual / goal;
|
||||
var payoutRange = profile.FindPayoutRange(goalPercentage, runDate);
|
||||
|
||||
if (payoutRange == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
decimal payoutAmt = payoutRange.Payout;
|
||||
if (profile.PayEach)
|
||||
{
|
||||
payoutAmt *= actual;
|
||||
}
|
||||
|
||||
double payoutPercentage = (double)payoutPercent / (double)100;
|
||||
double finalPayout = (double)payoutAmt * payoutPercentage;
|
||||
payoutAmt = (decimal)Math.Round(finalPayout, 2);
|
||||
|
||||
return payoutAmt;
|
||||
}
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
using LCU.Library.Internal.IncentiveApiModels.Entities;
|
||||
using LCU.Library.Internal.IncentiveApiModels.Enums;
|
||||
using LCU.API.Internal.Operations.IncentiveApi.Models.Payout;
|
||||
|
||||
namespace LCU.API.Internal.Operations.IncentiveApi.Services.Payout;
|
||||
|
||||
public class GapPayoutStrategy : IPayoutStrategy
|
||||
{
|
||||
private const bool IsEnabled = false;
|
||||
|
||||
public bool CanPayoutProduct(Product product)
|
||||
{
|
||||
return product == Product.GAPInsurance && IsEnabled;
|
||||
}
|
||||
|
||||
public IReadOnlyCollection<PayoutLineItem> CalculateLineItems(
|
||||
DepartmentPayout payoutPlan,
|
||||
UserDepartment userDepartment,
|
||||
List<PayoutProfile> departmentPayouts,
|
||||
ProductDetail product
|
||||
)
|
||||
{
|
||||
var lineItems = new List<PayoutLineItem>();
|
||||
|
||||
if (!payoutPlan.Department.IsHome) return lineItems;
|
||||
|
||||
var eligiblePayouts = departmentPayouts.Where(p => p.Product == product.Product);
|
||||
|
||||
if (eligiblePayouts.Any(x => x.Type == PayoutType.Department))
|
||||
{
|
||||
throw new Exception("GAP Payouts configured for personal goals only, if you have enable department payouts you must add payout logic.");
|
||||
}
|
||||
|
||||
foreach (var eligiblePayoutProfile in eligiblePayouts.Where(x => x.Type == PayoutType.Personal))
|
||||
{
|
||||
var eligibleGoal = payoutPlan.PersonalActivity
|
||||
.Where(a => a.Detail is { IsDebtProtectionEligible: true } && a.State == ActivityState.Accepted)
|
||||
.ToList();
|
||||
|
||||
if (!eligibleGoal.Any()) continue;
|
||||
|
||||
var gapActivity = payoutPlan.PersonalActivity
|
||||
.Where(a => a.Product == product.Product
|
||||
&& a.State == ActivityState.Accepted
|
||||
&& !payoutPlan.PersonalRules.Any(x => x.RestrictedByPayoutRule(a, product.Product))
|
||||
)
|
||||
.ToList();
|
||||
|
||||
var goalCount = eligibleGoal.Count;
|
||||
var actualCount = eligibleGoal.Count(a => a.Detail.DebtProtectionAddDate != null && a.Detail.DebtProtectionRemoveDate == null);
|
||||
|
||||
gapActivity.AddRange(eligibleGoal);
|
||||
var lineItem = new PayoutLineItem(product.Product, eligiblePayoutProfile, eligibleGoal.Count,
|
||||
userDepartment.SlidingPayout, gapActivity)
|
||||
{
|
||||
ActivityPeriod = payoutPlan.MonthRange.StartTime,
|
||||
AppUserId = userDepartment.Employee.Id,
|
||||
EmployeeId = userDepartment.Employee.EmployeeId,
|
||||
DepartmentId = userDepartment.DepartmentId,
|
||||
Role = userDepartment.Role
|
||||
};
|
||||
lineItem.PayoutTotal = CalculateLineItemPayout(eligiblePayoutProfile, goalCount, actualCount, lineItem.ActivityTotal,
|
||||
payoutPlan.MonthRange.StartTime, lineItem.SlidingPayout);
|
||||
|
||||
if (lineItem.PayoutTotal > 0)
|
||||
{
|
||||
lineItems.Add(lineItem);
|
||||
}
|
||||
}
|
||||
|
||||
return lineItems;
|
||||
}
|
||||
|
||||
private decimal CalculateLineItemPayout(PayoutProfile profile, int goal, decimal actual, decimal each, DateTime runDate, decimal payoutPercent = 100)
|
||||
{
|
||||
if (profile == null)
|
||||
{
|
||||
throw new Exception("Attempt to calculate payout with null profile");
|
||||
}
|
||||
|
||||
if (goal == 0) return 0;
|
||||
|
||||
var goalPercentage = (double)actual / goal;
|
||||
var payoutRange = profile.FindPayoutRange(goalPercentage, runDate);
|
||||
|
||||
if (payoutRange == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
decimal payoutAmt = payoutRange.Payout;
|
||||
if (profile.PayEach)
|
||||
{
|
||||
payoutAmt *= each;
|
||||
}
|
||||
|
||||
var payoutPercentage = (double)payoutPercent / 100;
|
||||
var finalPayout = (double)payoutAmt * payoutPercentage;
|
||||
payoutAmt = (decimal)Math.Round(finalPayout, 2);
|
||||
|
||||
return payoutAmt;
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
using LCU.Library.Internal.IncentiveApiModels.Entities;
|
||||
using LCU.API.Internal.Operations.IncentiveApi.Models.Payout;
|
||||
using LCU.Library.Internal.IncentiveApiModels.Common;
|
||||
|
||||
namespace LCU.API.Internal.Operations.IncentiveApi.Services.Payout;
|
||||
|
||||
public interface IPayoutCalculateService
|
||||
{
|
||||
Task<DepartmentPayout> BuildDepartmentPayoutView(AppUser employee, UserDepartment userDepartment, MonthRange monthRange);
|
||||
List<PayoutLineItem> CalculateGoalLineItems(DepartmentPayout payoutPlan, UserDepartment userDepartment);
|
||||
List<PayoutLineItem> CalculateCommissionLineItems(DepartmentPayout payoutPlan, UserDepartment userDepartment);
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
using LCU.Library.Internal.IncentiveApiModels.Entities;
|
||||
using LCU.API.Internal.Operations.IncentiveApi.Models.Dayforce;
|
||||
using LCU.API.Internal.Operations.IncentiveApi.Models.Payout;
|
||||
using LCU.Library.Internal.IncentiveApiModels.Common;
|
||||
using LCU.Library.Internal.IncentiveApiModels.Requests;
|
||||
|
||||
namespace LCU.API.Internal.Operations.IncentiveApi.Services.Payout
|
||||
{
|
||||
public interface IPayoutService
|
||||
{
|
||||
Task<IReadOnlyCollection<DepartmentPayout>> BuildUserDepartmentsPayoutView(AppUser employee, MonthRange range);
|
||||
Task RunMonthlyIncentivePayouts(PayoutIncentiveRequest request);
|
||||
Task<IReadOnlyCollection<PayoutLineItem>> CreateMonthlyIncentivePayouts(PayoutIncentiveRequest request);
|
||||
Task<IReadOnlyCollection<PayoutEntry>> RetrieveMonthlyIncentivePayouts(DateTime period);
|
||||
Task<PayoutEntry> RetrieveUserMonthlyIncentivePayout(AppUser appUser, DateTime period);
|
||||
Task<IReadOnlyCollection<PayoutLineItem>> RetrieveCombinedDepartmentPayouts(AppUser incentiveAppUser, MonthRange range);
|
||||
Task<IReadOnlyCollection<PayoutLineItem>> CreateCombinedDepartmentPayouts(AppUser incentiveAppUser, MonthRange range);
|
||||
Task<TerminatedEmployeeReceipt> CreateTerminatedEmployeePayouts(AppUser appUser, AppUser manager);
|
||||
Task<AccountingSummary> CreateMonthlyAccountingPayouts(MonthRange range);
|
||||
Task<AccountingSummary> RetrieveMonthlyAccountingPayouts(MonthRange range);
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
using LCU.Library.Internal.IncentiveApiModels.Enums;
|
||||
using LCU.API.Internal.Operations.IncentiveApi.Models.Payout;
|
||||
using LCU.Library.Internal.IncentiveApiModels.Entities;
|
||||
|
||||
namespace LCU.API.Internal.Operations.IncentiveApi.Services.Payout;
|
||||
|
||||
public interface IPayoutStrategy
|
||||
{
|
||||
bool CanPayoutProduct(Product product);
|
||||
|
||||
IReadOnlyCollection<PayoutLineItem> CalculateLineItems(
|
||||
DepartmentPayout payoutPlan,
|
||||
UserDepartment userDepartment,
|
||||
List<PayoutProfile> departmentPayouts,
|
||||
ProductDetail product
|
||||
);
|
||||
}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
using LCU.Library.Internal.IncentiveApiModels.Entities;
|
||||
using LCU.Library.Internal.IncentiveApiModels.Enums;
|
||||
using LCU.API.Internal.Operations.IncentiveApi.Services.Rules;
|
||||
using LCU.API.Internal.Operations.IncentiveApi.Models.Payout;
|
||||
using LCU.API.Internal.Operations.IncentiveApiLib.Repositories;
|
||||
using LCU.Library.Internal.IncentiveApiModels.Common;
|
||||
|
||||
namespace LCU.API.Internal.Operations.IncentiveApi.Services.Payout;
|
||||
|
||||
public class PayoutCalculateService : IPayoutCalculateService
|
||||
{
|
||||
private readonly IActivityRepository _activityRepository;
|
||||
private readonly IGoalRepository _goalRepository;
|
||||
private readonly ICommissionRepository _commissionRepository;
|
||||
private readonly IEnumerable<IPayoutStrategy> _payoutStrategies;
|
||||
private readonly IBusinessRuleService _businessRuleService;
|
||||
|
||||
public PayoutCalculateService(
|
||||
IActivityRepository activityRepository,
|
||||
IGoalRepository goalRepository,
|
||||
ICommissionRepository commissionRepository,
|
||||
IEnumerable<IPayoutStrategy> payoutStrategies,
|
||||
IBusinessRuleService businessRuleService
|
||||
)
|
||||
{
|
||||
_activityRepository = activityRepository;
|
||||
_goalRepository = goalRepository;
|
||||
_commissionRepository = commissionRepository;
|
||||
_payoutStrategies = payoutStrategies;
|
||||
_businessRuleService = businessRuleService;
|
||||
}
|
||||
|
||||
public async Task<DepartmentPayout> BuildDepartmentPayoutView(
|
||||
AppUser employee,
|
||||
UserDepartment userDepartment,
|
||||
MonthRange monthRange
|
||||
)
|
||||
{
|
||||
var payoutPlan = new DepartmentPayout(employee, userDepartment, monthRange,
|
||||
_businessRuleService.GetRules(PayoutType.Department),
|
||||
_businessRuleService.GetRules(PayoutType.Personal))
|
||||
{
|
||||
EligibleCommissions = await _commissionRepository.FindProductCommissions(userDepartment.Role)
|
||||
};
|
||||
|
||||
if (!payoutPlan.HasEligibleIncentives())
|
||||
{
|
||||
return payoutPlan;
|
||||
}
|
||||
|
||||
payoutPlan.PersonalActivity =
|
||||
await _activityRepository.FindEmployeeActivityByMonthRange(payoutPlan.Employee, payoutPlan.MonthRange);
|
||||
|
||||
payoutPlan.DepartmentActivity =
|
||||
await _activityRepository.FindDepartmentActivityByMonthRange(userDepartment.DepartmentId,
|
||||
payoutPlan.MonthRange);
|
||||
|
||||
if (!payoutPlan.HasEligibleActivity())
|
||||
{
|
||||
return payoutPlan;
|
||||
}
|
||||
|
||||
var users = new List<AppUser>()
|
||||
{
|
||||
payoutPlan.Employee
|
||||
};
|
||||
|
||||
payoutPlan.PersonalGoals = await _goalRepository.FindPersonnelGoalsByMonthRange(userDepartment.DepartmentId,
|
||||
users, payoutPlan.MonthRange);
|
||||
|
||||
payoutPlan.DepartmentGoals = await _goalRepository.FindDepartmentGoalsByMonthRange(
|
||||
userDepartment.DepartmentId,
|
||||
payoutPlan.MonthRange);
|
||||
|
||||
if (payoutPlan.HasEligibleCommissions())
|
||||
{
|
||||
payoutPlan.CommissionPayouts = CalculateCommissionLineItems(payoutPlan, userDepartment);
|
||||
}
|
||||
|
||||
payoutPlan.GoalPayouts = CalculateGoalLineItems(payoutPlan, userDepartment);
|
||||
|
||||
return payoutPlan;
|
||||
}
|
||||
|
||||
public List<PayoutLineItem> CalculateCommissionLineItems(DepartmentPayout payoutPlan, UserDepartment userDepartment)
|
||||
{
|
||||
var lineItems = new List<PayoutLineItem>();
|
||||
var departmentCommissions = payoutPlan.EligibleCommissions;
|
||||
|
||||
if (departmentCommissions == null || !departmentCommissions.Any()) return lineItems;
|
||||
|
||||
foreach (var product in departmentCommissions.Select(x => x.Product).Distinct().ToList())
|
||||
{
|
||||
var eligibleCommission = departmentCommissions.FirstOrDefault(c => c.Product == product);
|
||||
if (eligibleCommission == null) continue;
|
||||
var eligibleActivity = payoutPlan.PersonalActivity
|
||||
.Where(a => a.DepartmentId == userDepartment.DepartmentId &&
|
||||
a.Product == product &&
|
||||
a.Type != ActivityType.Other
|
||||
&& a.State == ActivityState.Accepted
|
||||
&& !payoutPlan.PersonalRules.Any(x => x.RestrictedByPayoutRule(a, product)))
|
||||
.ToList();
|
||||
|
||||
var lineItem = new PayoutLineItem(product, eligibleCommission, eligibleActivity)
|
||||
{
|
||||
ActivityPeriod = payoutPlan.MonthRange.StartTime,
|
||||
AppUserId = userDepartment.Employee.Id,
|
||||
EmployeeId = userDepartment.Employee.EmployeeId,
|
||||
DepartmentId = userDepartment.DepartmentId,
|
||||
Role = userDepartment.Role
|
||||
};
|
||||
|
||||
if (lineItem.PayoutTotal > 0)
|
||||
{
|
||||
lineItems.Add(lineItem);
|
||||
}
|
||||
}
|
||||
|
||||
return lineItems;
|
||||
}
|
||||
|
||||
public List<PayoutLineItem> CalculateGoalLineItems(DepartmentPayout payoutPlan, UserDepartment userDepartment)
|
||||
{
|
||||
var lineItems = new List<PayoutLineItem>();
|
||||
var departmentPayouts = payoutPlan.EligiblePayouts.ToList();
|
||||
if (!departmentPayouts.Any()) return lineItems;
|
||||
|
||||
foreach (var product in ProductDetail.ProductDetails)
|
||||
{
|
||||
var strategy = _payoutStrategies.FirstOrDefault(x => x.CanPayoutProduct(product.Product));
|
||||
if (strategy == null) continue;
|
||||
var items = strategy.CalculateLineItems(payoutPlan, userDepartment, departmentPayouts, product);
|
||||
lineItems.AddRange(items);
|
||||
}
|
||||
|
||||
return lineItems;
|
||||
}
|
||||
}
|
||||
+243
@@ -0,0 +1,243 @@
|
||||
using LCU.API.Internal.Operations.IncentiveApi.Models.Dayforce;
|
||||
using LCU.API.Internal.Operations.IncentiveApi.Models.Payout;
|
||||
using LCU.API.Internal.Operations.IncentiveApiLib.Repositories;
|
||||
using LCU.Library.Internal.IncentiveApiModels.Entities;
|
||||
using LCU.Library.Internal.IncentiveApiModels.Common;
|
||||
using LCU.Library.Internal.IncentiveApiModels.Requests;
|
||||
using LCU.Library.Internal.ApiResponse.Services;
|
||||
using LCU.Library.Internal.Exceptions;
|
||||
using ProcessResult = LCU.Library.Internal.IncentiveApiModels.Results.ProcessResult;
|
||||
|
||||
namespace LCU.API.Internal.Operations.IncentiveApi.Services.Payout;
|
||||
|
||||
public class PayoutService : IPayoutService
|
||||
{
|
||||
private readonly IUserRepository _userRepository;
|
||||
private readonly IPayoutRepository _payoutRepository;
|
||||
private readonly IAccountingRepository _accountingRepository;
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly IPayoutCalculateService _payoutCalculateService;
|
||||
private readonly IActivityService _activityService;
|
||||
private readonly ProcessResult _payoutIncentiveProcessResult;
|
||||
private const int MonthsBack = -2;
|
||||
|
||||
public PayoutService(IUserRepository userRepository, IPayoutRepository payoutRepository, IUnitOfWork unitOfWork, IPayoutCalculateService payoutCalculateService,
|
||||
IAccountingRepository accountingRepository, IActivityService activityService)
|
||||
{
|
||||
_userRepository = userRepository;
|
||||
_payoutRepository = payoutRepository;
|
||||
_unitOfWork = unitOfWork;
|
||||
_payoutCalculateService = payoutCalculateService;
|
||||
_accountingRepository = accountingRepository;
|
||||
_activityService = activityService;
|
||||
_payoutIncentiveProcessResult = new ProcessResult();
|
||||
}
|
||||
|
||||
public async Task RunMonthlyIncentivePayouts(PayoutIncentiveRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
Log.Information("Running Monthly Incentive Payout Process");
|
||||
var result = await CreateMonthlyIncentivePayouts(request);
|
||||
|
||||
Log.Information("Successfully Processed Monthly Incentive Payouts.");
|
||||
await QueueReturnResponse.QueueResponse(request, _payoutIncentiveProcessResult.Success, _payoutIncentiveProcessResult.MessageStack);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.Fatal(exception, "There was an Unhandled error with Monthly Incentive Payout Process");
|
||||
var message = $"There was an Unhandled error with Monthly Incentive Payout Process from {request.MonthsBack} months back from today's date. Exception Message: {exception.Message}.";
|
||||
_payoutIncentiveProcessResult.MessageStack.Add(message);
|
||||
_payoutIncentiveProcessResult.Success = false;
|
||||
await QueueReturnResponse.QueueResponse(request, _payoutIncentiveProcessResult.Success, _payoutIncentiveProcessResult.MessageStack);
|
||||
throw new ServiceException(message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyCollection<PayoutLineItem>> CreateMonthlyIncentivePayouts(PayoutIncentiveRequest request)
|
||||
{
|
||||
var period = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
|
||||
period = request.MonthsBack == 0 ? period.AddMonths(MonthsBack) : period.AddMonths(request.MonthsBack);
|
||||
|
||||
var range = new MonthRange(period);
|
||||
_activityService.CancelPendingTransfersBetween(range).GetAwaiter().GetResult();
|
||||
|
||||
var users = await _userRepository.GetAllUsersToPayoutAsync(range);
|
||||
var allNewPayouts = new List<PayoutLineItem>();
|
||||
IReadOnlyCollection<PayoutLineItem> combinedPayouts;
|
||||
|
||||
foreach (var incentiveUser in users)
|
||||
{
|
||||
try
|
||||
{
|
||||
combinedPayouts = await CreateCombinedDepartmentPayouts(incentiveUser, range);
|
||||
if (!combinedPayouts.Any()) continue;
|
||||
await _payoutRepository.SavePayoutLineItemRangeAsync(combinedPayouts);
|
||||
allNewPayouts.AddRange(combinedPayouts);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Fatal(ex, $"Employee {incentiveUser.EmployeeId} - {incentiveUser.FullName} experienced a failed payout calculation!");
|
||||
}
|
||||
}
|
||||
|
||||
await _unitOfWork.CompleteAsync();
|
||||
return allNewPayouts;
|
||||
}
|
||||
|
||||
public async Task<AccountingSummary> CreateMonthlyAccountingPayouts(MonthRange range)
|
||||
{
|
||||
var existing = await RetrieveMonthlyAccountingPayouts(range);
|
||||
if (existing != null)
|
||||
{
|
||||
return existing;
|
||||
}
|
||||
var users = await _userRepository.GetAllUsersToPayoutAsync(range);
|
||||
var allNewPayouts = new List<PayoutLineItem>();
|
||||
var deptNames = new Dictionary<int, string>();
|
||||
|
||||
foreach (var incentiveUser in users)
|
||||
{
|
||||
try
|
||||
{
|
||||
var departments = incentiveUser.ActiveDepartmentsForRange(range);
|
||||
foreach (var userDepartment in departments)
|
||||
{
|
||||
if (!deptNames.ContainsKey(userDepartment.Department.Id.Value))
|
||||
{
|
||||
deptNames.Add(userDepartment.Department.Id.Value, userDepartment.Department.DepartmentName);
|
||||
}
|
||||
|
||||
var newPlan =
|
||||
await _payoutCalculateService.BuildDepartmentPayoutView(incentiveUser, userDepartment,
|
||||
range);
|
||||
allNewPayouts.AddRange(newPlan.CommissionPayouts);
|
||||
allNewPayouts.AddRange(newPlan.GoalPayouts);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Fatal(ex, $"Employee {incentiveUser.EmployeeId} - {incentiveUser.FullName} experienced a failed accounting calculation!");
|
||||
}
|
||||
}
|
||||
|
||||
var summary = new AccountingSummary(range.StartTime.Date);
|
||||
summary.Apply(allNewPayouts, deptNames);
|
||||
await _accountingRepository.SaveAccountingSummaryAsync(summary);
|
||||
await _unitOfWork.CompleteAsync();
|
||||
return summary;
|
||||
}
|
||||
|
||||
public async Task<AccountingSummary> RetrieveMonthlyAccountingPayouts(MonthRange range)
|
||||
{
|
||||
return await _accountingRepository.GetAccountingSummaryAsync(range.StartTime);
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyCollection<DepartmentPayout>> BuildUserDepartmentsPayoutView(AppUser employee,
|
||||
MonthRange range)
|
||||
{
|
||||
var list = new List<DepartmentPayout>();
|
||||
var departments = employee.ActiveDepartmentsForRange(range);
|
||||
|
||||
foreach (var userDepartment in departments)
|
||||
{
|
||||
var newPlan = await _payoutCalculateService.BuildDepartmentPayoutView(employee, userDepartment, range);
|
||||
list.Add(newPlan);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyCollection<PayoutEntry>> RetrieveMonthlyIncentivePayouts(DateTime period)
|
||||
{
|
||||
var payoutsRaw = await _payoutRepository.GetPayoutLineItemsForPeriodAsync(period);
|
||||
var payouts = new Dictionary<string, PayoutEntry>();
|
||||
foreach (var lineItem in payoutsRaw)
|
||||
{
|
||||
if (payouts.ContainsKey(lineItem.EmployeeId))
|
||||
{
|
||||
payouts[lineItem.EmployeeId].PayoutTotal += lineItem.PayoutTotal;
|
||||
}
|
||||
else
|
||||
{
|
||||
var employee = await _userRepository.FindUserByEmployeeIdAsync(lineItem.EmployeeId);
|
||||
payouts[lineItem.EmployeeId] = new PayoutEntry()
|
||||
{
|
||||
Code = "Incentive",
|
||||
EmployeeId = lineItem.EmployeeId,
|
||||
PayoutTotal = lineItem.PayoutTotal,
|
||||
EmployeeName = employee.FullName
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return payouts.Values;
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyCollection<PayoutLineItem>> CreateCombinedDepartmentPayouts(AppUser incentiveAppUser, MonthRange range)
|
||||
{
|
||||
var combinedPayouts = new List<PayoutLineItem>();
|
||||
var existing = await _payoutRepository.GetEmployeePayoutsForPeriod(incentiveAppUser, range.StartTime);
|
||||
|
||||
if (existing.Any()) return combinedPayouts;
|
||||
|
||||
var payouts = await BuildUserDepartmentsPayoutView(incentiveAppUser, range);
|
||||
foreach (var departmentPayout in payouts)
|
||||
{
|
||||
combinedPayouts.AddRange(departmentPayout.CommissionPayouts);
|
||||
combinedPayouts.AddRange(departmentPayout.GoalPayouts);
|
||||
}
|
||||
|
||||
return combinedPayouts;
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyCollection<PayoutLineItem>> RetrieveCombinedDepartmentPayouts(AppUser incentiveAppUser, MonthRange range)
|
||||
{
|
||||
var existing = await _payoutRepository.GetEmployeePayoutsForPeriod(incentiveAppUser, range.StartTime);
|
||||
if (existing.Any()) return existing;
|
||||
|
||||
return await CreateCombinedDepartmentPayouts(incentiveAppUser, range);
|
||||
}
|
||||
|
||||
public async Task<PayoutEntry> RetrieveUserMonthlyIncentivePayout(AppUser appUser, DateTime period)
|
||||
{
|
||||
var payoutsRaw = await _payoutRepository.GetEmployeePayoutsForPeriod(appUser, period);
|
||||
var payout = new PayoutEntry()
|
||||
{
|
||||
Code = "Incentive",
|
||||
EmployeeId = appUser.EmployeeId,
|
||||
PayoutTotal = 0,
|
||||
EmployeeName = appUser.FullName
|
||||
};
|
||||
|
||||
foreach (var lineItem in payoutsRaw)
|
||||
{
|
||||
payout.PayoutTotal += lineItem.PayoutTotal;
|
||||
}
|
||||
|
||||
return payout;
|
||||
}
|
||||
|
||||
public async Task<TerminatedEmployeeReceipt> CreateTerminatedEmployeePayouts(AppUser appUser, AppUser manager)
|
||||
{
|
||||
var firstOfThisMonth = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
|
||||
var rangeThisMonth = new MonthRange(firstOfThisMonth);
|
||||
var rangeLastMonth = new MonthRange(firstOfThisMonth.AddMonths(-1));
|
||||
var payouts = await CreateCombinedDepartmentPayouts(appUser, rangeThisMonth);
|
||||
if (payouts.Any())
|
||||
{
|
||||
await _payoutRepository.SavePayoutLineItemRangeAsync(payouts);
|
||||
}
|
||||
|
||||
payouts = await CreateCombinedDepartmentPayouts(appUser, rangeLastMonth);
|
||||
if (payouts.Any())
|
||||
{
|
||||
await _payoutRepository.SavePayoutLineItemRangeAsync(payouts);
|
||||
}
|
||||
|
||||
await _unitOfWork.CompleteAsync();
|
||||
var payoutThisMonth = await RetrieveUserMonthlyIncentivePayout(appUser, rangeThisMonth.StartTime);
|
||||
var payoutLastMonth = await RetrieveUserMonthlyIncentivePayout(appUser, rangeLastMonth.StartTime);
|
||||
return new TerminatedEmployeeReceipt(appUser, payoutLastMonth, payoutThisMonth, manager);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user