148 lines
6.1 KiB
C#
148 lines
6.1 KiB
C#
using Microsoft.Extensions.Localization;
|
||
using Microsoft.Extensions.Logging;
|
||
using SmallSoftwareContracts.BusinessLogicsContracts;
|
||
using SmallSoftwareContracts.DataModels;
|
||
using SmallSoftwareContracts.Exceptions;
|
||
using SmallSoftwareContracts.Extensions;
|
||
using SmallSoftwareContracts.Infrastructure;
|
||
using SmallSoftwareContracts.Infrastructure.PostConfigurations;
|
||
using SmallSoftwareContracts.Resources;
|
||
using SmallSoftwareContracts.StoragesContracts;
|
||
namespace SmallSoftwareBusinessLogic.Implementations;
|
||
|
||
|
||
internal class SalaryBusinessLogicContract(ISalaryStorageContract salaryStorageContract,
|
||
IRequestStorageContract requestStorageContract, IPostStorageContract postStorageContract,
|
||
IWorkerStorageContract workerStorageContract, IStringLocalizer<Messages> localizer, ILogger logger, IConfigurationSalary сonfiguration) : ISalaryBusinessLogicContract
|
||
{
|
||
private readonly ILogger _logger = logger;
|
||
private readonly ISalaryStorageContract _salaryStorageContract = salaryStorageContract;
|
||
private readonly IRequestStorageContract _requestStorageContract = requestStorageContract;
|
||
private readonly IPostStorageContract _postStorageContract = postStorageContract;
|
||
private readonly IWorkerStorageContract _workerStorageContract = workerStorageContract;
|
||
private readonly IConfigurationSalary _salaryConfiguration = сonfiguration;
|
||
private readonly Lock _lockObject = new();
|
||
private readonly IStringLocalizer<Messages> _localizer = localizer;
|
||
public List<SalaryDataModel> GetAllSalariesByPeriod(DateTime fromDate,
|
||
DateTime toDate)
|
||
{
|
||
_logger.LogInformation("GetAllSalaries params: {fromDate}, {toDate}",
|
||
fromDate, toDate);
|
||
if (fromDate.IsDateNotOlder(toDate))
|
||
{
|
||
throw new IncorrectDatesException(fromDate, toDate, _localizer);
|
||
}
|
||
return _salaryStorageContract.GetList(fromDate, toDate) ?? throw new
|
||
NullListException();
|
||
}
|
||
public List<SalaryDataModel> GetAllSalariesByPeriodByWorker(DateTime
|
||
fromDate, DateTime toDate, string workerId)
|
||
{
|
||
if (fromDate.IsDateNotOlder(toDate))
|
||
{
|
||
throw new IncorrectDatesException(fromDate, toDate, _localizer);
|
||
}
|
||
if (workerId.IsEmpty())
|
||
{
|
||
throw new ArgumentNullException(nameof(workerId));
|
||
}
|
||
if (!workerId.IsGuid())
|
||
{
|
||
throw new ValidationException(string.Format(localizer["ValidationExceptionMessageNotAId"], "WorkerId"));
|
||
}
|
||
_logger.LogInformation("GetAllSalaries params: {fromDate}, {toDate}, { workerId} ", fromDate, toDate, workerId);
|
||
return _salaryStorageContract.GetList(fromDate, toDate, workerId) ??
|
||
throw new NullListException();
|
||
}
|
||
|
||
|
||
public void CalculateSalaryByMonth(DateTime date)
|
||
{
|
||
_logger.LogInformation("CalculateSalaryByMounth: {date}", date);
|
||
var startDate = new DateTime(date.Year, date.Month, 1);
|
||
var finishDate = new DateTime(date.Year, date.Month, DateTime.DaysInMonth(date.Year, date.Month));
|
||
var workers = _workerStorageContract.GetList() ?? throw new NullListException();
|
||
foreach (var worker in workers)
|
||
{
|
||
var requests = _requestStorageContract.GetList(startDate, finishDate, workerId: worker.Id) ?? throw new NullListException();
|
||
var post = _postStorageContract.GetElementById(worker.PostId) ??
|
||
throw new NullListException();
|
||
var salary = worker.ConfigurationModel switch
|
||
{
|
||
null => 0,
|
||
CashierPostConfiguration cpc => CalculateSalaryForCashier(requests, startDate, finishDate, cpc),
|
||
SupervisorPostConfiguration spc => CalculateSalaryForSupervisor(startDate, finishDate, spc),
|
||
PostConfiguration pc => pc.Rate,
|
||
};
|
||
_logger.LogDebug("The employee {workerId} was paid a salary of {salary}", worker.Id, salary);
|
||
_salaryStorageContract.AddElement(new SalaryDataModel(worker.Id, finishDate, salary));
|
||
}
|
||
}
|
||
private double CalculateSalaryForCashier(List<RequestDataModel> requests, DateTime startDate, DateTime finishDate, CashierPostConfiguration config)
|
||
{
|
||
var parallelOptions = new ParallelOptions
|
||
{
|
||
MaxDegreeOfParallelism = _salaryConfiguration.MaxConcurrentThreads
|
||
};
|
||
|
||
double calcPercent = 0.0;
|
||
var dates = new List<DateTime>();
|
||
|
||
for (var date = startDate; date < finishDate; date = date.AddDays(1))
|
||
{
|
||
dates.Add(date);
|
||
}
|
||
|
||
Parallel.ForEach(dates, parallelOptions, date =>
|
||
{
|
||
var requestsInDay = requests.Where(x => x.RequestDate >= date && x.RequestDate < date.AddDays(1)).ToArray();
|
||
if (requestsInDay.Length > 0)
|
||
{
|
||
double dailySum = requestsInDay.Sum(x => x.Sum);
|
||
double dailyAverage = dailySum / requestsInDay.Length;
|
||
double dailyPercent = dailyAverage * config.SalePercent;
|
||
|
||
lock (_lockObject)
|
||
{
|
||
calcPercent += dailyPercent;
|
||
}
|
||
}
|
||
});
|
||
|
||
double bonus = 0;
|
||
try
|
||
{
|
||
bonus = requests
|
||
.AsParallel()
|
||
.WithDegreeOfParallelism(_salaryConfiguration.MaxConcurrentThreads)
|
||
.Where(x => x.Sum > _salaryConfiguration.ExtraSaleSum)
|
||
.Sum(x => x.Sum * config.BonusForExtraSales);
|
||
}
|
||
catch (AggregateException agEx)
|
||
{
|
||
foreach (var ex in agEx.InnerExceptions)
|
||
{
|
||
_logger.LogError(ex, "Error calculating bonus in cashier payroll");
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
return config.Rate + calcPercent + bonus;
|
||
}
|
||
|
||
private double CalculateSalaryForSupervisor(DateTime startDate, DateTime finishDate, SupervisorPostConfiguration config)
|
||
{
|
||
try
|
||
{
|
||
return config.Rate + config.PersonalCountTrendPremium *
|
||
_workerStorageContract.GetWorkerTrend(startDate, finishDate);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "Error in the supervisor payroll process");
|
||
return 0;
|
||
}
|
||
}
|
||
}
|
||
|