edit
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
using CandyHouseContracts.DataModels;
|
||||
using CandyHouseContracts.Exceptions;
|
||||
using CandyHouseContracts.Extensions;
|
||||
using CandyHouseContracts.Infrastructure;
|
||||
using CandyHouseContracts.Infrastructure.PostConfigurations;
|
||||
using CandyHouseContracts.StoragesContracts;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
@@ -12,13 +14,15 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace CandyHouseBusinessLogic.Implementations;
|
||||
public class SalaryBusinessLogicContract(ISalaryStorageContract salaryStorageContract,ISaleStorageContract saleStorageContract,
|
||||
IPostStorageContract postStorageContract, IEmployeeStorageContract employeeStorageContract, ILogger logger) : ISalaryBusinessLogicContract
|
||||
IPostStorageContract postStorageContract, IEmployeeStorageContract employeeStorageContract, ILogger logger, IConfigurationSalary сonfiguration) : ISalaryBusinessLogicContract
|
||||
{
|
||||
private readonly ILogger _logger = logger;
|
||||
private readonly ISalaryStorageContract _salaryStorageContract = salaryStorageContract;
|
||||
private readonly ISaleStorageContract _saleStorageContract = saleStorageContract;
|
||||
private readonly IPostStorageContract _postStorageContract = postStorageContract;
|
||||
private readonly IEmployeeStorageContract _employeeStorageContract = employeeStorageContract;
|
||||
private readonly IConfigurationSalary _salaryConfiguration = сonfiguration;
|
||||
private readonly Lock _lockObject = new();
|
||||
public List<SalaryDataModel> GetAllSalariesByPeriod(DateTime fromDate, DateTime toDate)
|
||||
{
|
||||
_logger.LogInformation("GetAllSalaries params: {fromDate}, {toDate}", fromDate, toDate);
|
||||
@@ -55,13 +59,66 @@ public class SalaryBusinessLogicContract(ISalaryStorageContract salaryStorageCon
|
||||
var employees = _employeeStorageContract.GetList() ?? throw new NullListException();
|
||||
foreach (var employee in employees)
|
||||
{
|
||||
var sales = _saleStorageContract.GetList(startDate, finishDate, employeeId: employee.Id)?.Sum(x => x.Sum) ??
|
||||
throw new NullListException();
|
||||
var post = _postStorageContract.GetElementById(employee.PostId) ??
|
||||
throw new NullListException();
|
||||
var salary = post.Salary + sales * 0.1;
|
||||
var sales = _saleStorageContract.GetList(startDate, finishDate, employeeId: employee.Id) ?? throw new NullListException();
|
||||
var post = _postStorageContract.GetElementById(employee.PostId) ?? throw new NullListException();
|
||||
var salary = post.ConfigurationModel switch
|
||||
{
|
||||
null => 0,
|
||||
ManagerPostConfiguration cpc => CalculateSalaryForTravelAgent(sales, startDate, finishDate, cpc),
|
||||
BakerPostConfiguration spc => CalculateSalaryForChief(startDate, finishDate, spc),
|
||||
PostConfiguration pc => pc.Rate,
|
||||
};
|
||||
_logger.LogDebug("The employee {employeeId} was paid a salary of {salary}", employee.Id, salary);
|
||||
_salaryStorageContract.AddElement(new SalaryDataModel(employee.Id, DateTime.SpecifyKind(finishDate, DateTimeKind.Utc), salary));
|
||||
_salaryStorageContract.AddElement(new SalaryDataModel(employee.Id, finishDate, salary));
|
||||
}
|
||||
}
|
||||
private double CalculateSalaryForTravelAgent(List<SaleDataModel> sales, DateTime startDate, DateTime finishDate, ManagerPostConfiguration config)
|
||||
{
|
||||
var calcPercent = 0.0;
|
||||
var dates = new List<DateTime>();
|
||||
for (var date = startDate; date < finishDate; date = date.AddDays(1))
|
||||
{
|
||||
dates.Add(date);
|
||||
}
|
||||
|
||||
var parallelOptions = new ParallelOptions
|
||||
{
|
||||
MaxDegreeOfParallelism = _salaryConfiguration.MaxConcurrentThreads
|
||||
};
|
||||
|
||||
Parallel.ForEach(dates, parallelOptions, date =>
|
||||
{
|
||||
var salesInDay = sales.Where(x => x.SaleDate.Date == date.Date).ToArray();
|
||||
if (salesInDay.Length > 0)
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
calcPercent += (salesInDay.Sum(x => x.Sum) / salesInDay.Length) * config.SalePercent;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
double calcBonusTask = 0;
|
||||
try
|
||||
{
|
||||
calcBonusTask = sales.Where(x => x.Sum > _salaryConfiguration.ExtraSaleSum).Sum(x => x.Sum) * config.BonusForExtraSales;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error in bonus calculation");
|
||||
}
|
||||
return config.Rate + calcPercent + calcBonusTask;
|
||||
}
|
||||
private double CalculateSalaryForChief(DateTime startDate, DateTime finishDate, BakerPostConfiguration config)
|
||||
{
|
||||
try
|
||||
{
|
||||
return config.Rate + config.PersonalCountTrendPremium * _employeeStorageContract.GetEmployeeTrend(startDate, finishDate);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error in the chief payroll process");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ public class PostBindingModel
|
||||
|
||||
public string? PostName { get; set; }
|
||||
|
||||
public string? PostType { get; set; }
|
||||
public string? ConfigurationJson { get; set; }
|
||||
|
||||
public double Salary { get; set; }
|
||||
}
|
||||
|
||||
@@ -2,20 +2,32 @@
|
||||
using CandyHouseContracts.Exceptions;
|
||||
using CandyHouseContracts.Extensions;
|
||||
using CandyHouseContracts.Infrastructure;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CandyHouseContracts.Infrastructure.PostConfigurations;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace CandyHouseContracts.DataModels;
|
||||
|
||||
public class PostDataModel(string postId, string postName, PostType postType, double salary) : IValidation
|
||||
public class PostDataModel(string postId, string postName, PostType postType, PostConfiguration configuration) : IValidation
|
||||
{
|
||||
public string Id { get; private set; } = postId;
|
||||
public string PostName { get; private set; } = postName;
|
||||
public PostType PostType { get; private set; } = postType;
|
||||
public double Salary { get; private set; } = salary;
|
||||
public PostConfiguration ConfigurationModel { get; private set; } = configuration;
|
||||
|
||||
public PostDataModel(string postId, string postName, PostType postType, string configurationJson) : this(postId, postName, postType, (PostConfiguration)null)
|
||||
{
|
||||
var obj = JToken.Parse(configurationJson);
|
||||
if (obj is not null)
|
||||
{
|
||||
ConfigurationModel = obj.Value<string>("Type") switch
|
||||
{
|
||||
nameof(ManagerPostConfiguration) => JsonConvert.DeserializeObject<ManagerPostConfiguration>(configurationJson)!,
|
||||
nameof(BakerPostConfiguration) => JsonConvert.DeserializeObject<BakerPostConfiguration>(configurationJson)!,
|
||||
_ => JsonConvert.DeserializeObject<PostConfiguration>(configurationJson)!,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
@@ -27,7 +39,9 @@ public class PostDataModel(string postId, string postName, PostType postType, do
|
||||
throw new ValidationException("Field PostName is empty");
|
||||
if (PostType == PostType.None)
|
||||
throw new ValidationException("Field PostType is empty");
|
||||
if (Salary <= 0)
|
||||
throw new ValidationException("Field Salary is empty");
|
||||
if (ConfigurationModel is null)
|
||||
throw new ValidationException("Field ConfigurationModel is not initialized");
|
||||
if (ConfigurationModel!.Rate <= 0)
|
||||
throw new ValidationException("Field Rate is less or equal zero");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace CandyHouseContracts.Infrastructure;
|
||||
|
||||
public interface IConfigurationSalary
|
||||
{
|
||||
double ExtraSaleSum { get; }
|
||||
|
||||
int MaxConcurrentThreads { get; }
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace CandyHouseContracts.Infrastructure.PostConfigurations;
|
||||
|
||||
public class BakerPostConfiguration : PostConfiguration
|
||||
{
|
||||
public override string Type => nameof(BakerPostConfiguration);
|
||||
public double PersonalCountTrendPremium { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace CandyHouseContracts.Infrastructure.PostConfigurations;
|
||||
|
||||
public class ManagerPostConfiguration : PostConfiguration
|
||||
{
|
||||
public override string Type => nameof(ManagerPostConfiguration);
|
||||
public double SalePercent { get; set; }
|
||||
public double BonusForExtraSales { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace CandyHouseContracts.Infrastructure.PostConfigurations;
|
||||
|
||||
public class PostConfiguration
|
||||
{
|
||||
public virtual string Type => nameof(PostConfiguration);
|
||||
public double Rate { get; set; }
|
||||
}
|
||||
@@ -23,4 +23,6 @@ public interface IEmployeeStorageContract
|
||||
void UpdElement(EmployeeDataModel employeeDataModel);
|
||||
|
||||
void DelElement(string id);
|
||||
|
||||
int GetEmployeeTrend(DateTime fromPeriod, DateTime toPeriod);
|
||||
}
|
||||
|
||||
@@ -14,5 +14,5 @@ public class PostViewModel
|
||||
|
||||
public required string PostType { get; set; }
|
||||
|
||||
public double Salary { get; set; }
|
||||
public required string Configuration { get; set; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
using CandyHouseContracts.Infrastructure;
|
||||
|
||||
namespace CandyHouseDatabase;
|
||||
|
||||
class DefaultConfigurationDatabase : IConfigurationDatabase
|
||||
{
|
||||
public string ConnectionString => "";
|
||||
}
|
||||
Reference in New Issue
Block a user