calculate salaryyy

This commit is contained in:
2025-04-18 00:57:59 +04:00
parent 9f03eaa09e
commit b1a49bfde3
12 changed files with 548 additions and 256 deletions

View File

@@ -3,23 +3,23 @@ using SmallSoftwareContracts.BusinessLogicsContracts;
using SmallSoftwareContracts.DataModels;
using SmallSoftwareContracts.Exceptions;
using SmallSoftwareContracts.Extensions;
using SmallSoftwareContracts.Infrastructure;
using SmallSoftwareContracts.Infrastructure.PostConfigurations;
using SmallSoftwareContracts.StoragesContracts;
namespace SmallSoftwareBusinessLogic.Implementations;
internal class SalaryBusinessLogicContract(ISalaryStorageContract salaryStorageContract,
IRequestStorageContract requestStorageContract, IPostStorageContract postStorageContract,
IWorkerStorageContract workerStorageContract, ILogger logger) : ISalaryBusinessLogicContract
IWorkerStorageContract workerStorageContract, 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 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();
public List<SalaryDataModel> GetAllSalariesByPeriod(DateTime fromDate,
DateTime toDate)
{
@@ -61,14 +61,84 @@ internal class SalaryBusinessLogicContract(ISalaryStorageContract salaryStorageC
var workers = _workerStorageContract.GetList() ?? throw new NullListException();
foreach (var worker in workers)
{
var requests = _requestStorageContract.GetList(startDate, finishDate, workerId: worker.Id)?.Sum(x => x.Sum) ??
throw new NullListException();
var requests = _requestStorageContract.GetList(startDate, finishDate, workerId: worker.Id) ?? throw new NullListException();
var post = _postStorageContract.GetElementById(worker.PostId) ??
throw new NullListException();
var salary = post.Salary + requests * 0.1;
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;
}
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SmallSoftwareContracts.Infrastructure;
public interface IConfigurationSalary
{
double ExtraSaleSum { get; }
int MaxConcurrentThreads { get; }
}

View File

@@ -17,4 +17,5 @@ public interface IWorkerStorageContract
void AddElement(WorkerDataModel workerDataModel);
void UpdElement(WorkerDataModel workerDataModel);
void DelElement(string id);
int GetWorkerTrend(DateTime fromPeriod, DateTime toPeriod);
}

View File

@@ -135,11 +135,12 @@ internal class WorkerStorageContract : IWorkerStorageContract
var element = GetWorkerById(id) ?? throw new
ElementNotFoundException(id);
element.IsDeleted = true;
element.DateOfDelete = DateTime.UtcNow;
_dbContext.SaveChanges();
}
catch (ElementNotFoundException)
{
_dbContext.ChangeTracker.Clear();
_dbContext.ChangeTracker.Clear();
throw;
}
catch (Exception ex)
@@ -148,14 +149,29 @@ internal class WorkerStorageContract : IWorkerStorageContract
throw new StorageException(ex);
}
}
private Worker? GetWorkerById(string id) =>
AddPost(_dbContext.Workers.FirstOrDefault(x => x.Id == id && !x.IsDeleted));
private IQueryable<Worker> JoinPost(IQueryable<Worker> query)
=> query.GroupJoin(_dbContext.Posts.Where(x => x.IsActual), x =>
x.PostId, y => y.PostId, (x, y) => new { Worker = x, Post = y })
.SelectMany(xy => xy.Post.DefaultIfEmpty(), (x, y) =>
x.Worker.AddPost(y));
private Worker? AddPost(Worker? worker)
=> worker?.AddPost(_dbContext.Posts.FirstOrDefault(x => x.PostId ==
worker.PostId && x.IsActual));
public int GetWorkerTrend(DateTime fromPeriod, DateTime toPeriod)
{
try
{
var countWorkersOnBegining = _dbContext.Workers.Count(x =>
x.EmploymentDate < fromPeriod && (!x.IsDeleted || x.DateOfDelete > fromPeriod));
var countWorkersOnEnding = _dbContext.Workers.Count(x =>
x.EmploymentDate < toPeriod && (!x.IsDeleted || x.DateOfDelete > toPeriod));
return countWorkersOnEnding - countWorkersOnBegining;
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
private Worker? GetWorkerById(string id) => AddPost(_dbContext.Workers.FirstOrDefault(x => x.Id == id && !x.IsDeleted));
private IQueryable<Worker> JoinPost(IQueryable<Worker> query) => query.GroupJoin(_dbContext.Posts.Where(x => x.IsActual), x =>
x.PostId, y => y.PostId, (x, y) => new { Worker = x, Post = y }).SelectMany(xy => xy.Post.DefaultIfEmpty(), (x, y) => x.Worker.AddPost(y));
private Worker? AddPost(Worker? worker) => worker?.AddPost(_dbContext.Posts.FirstOrDefault(x => x.PostId == worker.PostId && x.IsActual));
}

View File

@@ -6,6 +6,8 @@ using SmallSoftwareContracts.Enums;
using SmallSoftwareContracts.Exceptions;
using SmallSoftwareContracts.Infrastructure.PostConfigurations;
using SmallSoftwareContracts.StoragesContracts;
using SmallSoftwareDatabase.Implementations;
using SmallSoftwareTests.Infrastructure;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -22,6 +24,7 @@ internal class SalaryBusinessLogicContractTests
private Mock<IRequestStorageContract> _requestStorageContract;
private Mock<IPostStorageContract> _postStorageContract;
private Mock<IWorkerStorageContract> _workerStorageContract;
private readonly ConfigurationSalaryTest _salaryConfigurationTest = new();
[OneTimeSetUp]
public void OneTimeSetUp()
{
@@ -29,10 +32,8 @@ internal class SalaryBusinessLogicContractTests
_requestStorageContract = new Mock<IRequestStorageContract>();
_postStorageContract = new Mock<IPostStorageContract>();
_workerStorageContract = new Mock<IWorkerStorageContract>();
_salaryBusinessLogicContract = new
SalaryBusinessLogicContract(_salaryStorageContract.Object,
_requestStorageContract.Object, _postStorageContract.Object,
_workerStorageContract.Object, new Mock<ILogger>().Object);
_salaryBusinessLogicContract = new SalaryBusinessLogicContract(_salaryStorageContract.Object, _requestStorageContract.Object,
_postStorageContract.Object, _workerStorageContract.Object, new Mock<ILogger>().Object, _salaryConfigurationTest);
}
[SetUp]
public void SetUp()
@@ -234,198 +235,347 @@ internal class SalaryBusinessLogicContractTests
}
[Test]
public void CalculateSalaryByMounth_WithSeveralWorkers_Test()
public void CalculateSalaryByMonth_CalculateSalary_Test()
{
//Arrange
var worker1Id = Guid.NewGuid().ToString();
var worker2Id = Guid.NewGuid().ToString();
var worker3Id = Guid.NewGuid().ToString();
var list = new List<WorkerDataModel>() {
new(worker1Id, "Test", Guid.NewGuid().ToString(),
DateTime.UtcNow, DateTime.UtcNow, false, new PostConfiguration() { Rate = 10 }),
new(worker2Id, "Test", Guid.NewGuid().ToString(),
DateTime.UtcNow, DateTime.UtcNow, false, new PostConfiguration() { Rate = 10 }),
new(worker3Id, "Test", Guid.NewGuid().ToString(),
DateTime.UtcNow, DateTime.UtcNow, false, new PostConfiguration() { Rate = 10 })
};
_requestStorageContract.Setup(x => x.GetList(It.IsAny<DateTime>(),
It.IsAny<DateTime>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns([new RequestDataModel(Guid.NewGuid().ToString(),
worker1Id, Guid.NewGuid().ToString(), false, [], DateTime.UtcNow),
new RequestDataModel(Guid.NewGuid().ToString(), worker1Id, Guid.NewGuid().ToString(),
false, [], DateTime.UtcNow),
new RequestDataModel(Guid.NewGuid().ToString(), worker2Id, Guid.NewGuid().ToString(),
false, [], DateTime.UtcNow),
new RequestDataModel(Guid.NewGuid().ToString(), worker3Id, Guid.NewGuid().ToString(),
false, [], DateTime.UtcNow),
new RequestDataModel(Guid.NewGuid().ToString(), worker3Id, Guid.NewGuid().ToString(),
false, [], DateTime.UtcNow)]);
_postStorageContract.Setup(x => x.GetElementById(It.IsAny<string>()))
.Returns(new PostDataModel(Guid.NewGuid().ToString(), "name",
PostType.SoftInstaller, 2000));
_workerStorageContract.Setup(x => x.GetList(It.IsAny<bool>(),
It.IsAny<string?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>(),
It.IsAny<DateTime?>(), It.IsAny<DateTime?>()))
.Returns(list);
//Act
_salaryBusinessLogicContract.CalculateSalaryByMonth(DateTime.UtcNow);
//Assert
_salaryStorageContract.Verify(x =>
x.AddElement(It.IsAny<SalaryDataModel>()), Times.Exactly(list.Count));
}
[Test]
public void CalculateSalaryByMounth_WithoitRequestsByWorker_Test()
{
//Arrange
var postSalary = 2000.0;
// Arrange
var workerId = Guid.NewGuid().ToString();
_requestStorageContract.Setup(x => x.GetList(It.IsAny<DateTime>(),
It.IsAny<DateTime>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns([]);
_postStorageContract.Setup(x => x.GetElementById(It.IsAny<string>()))
.Returns(new PostDataModel(Guid.NewGuid().ToString(), "name",
PostType.SoftInstaller, postSalary));
_workerStorageContract.Setup(x => x.GetList(It.IsAny<bool>(),
It.IsAny<string?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>(),
It.IsAny<DateTime?>(), It.IsAny<DateTime?>()))
.Returns([new WorkerDataModel(workerId, "Test",
Guid.NewGuid().ToString(), DateTime.UtcNow, DateTime.UtcNow, false, new PostConfiguration() { Rate = 10 })]);
var sum = 0.0;
var expectedSum = postSalary;
_salaryStorageContract.Setup(x =>
x.AddElement(It.IsAny<SalaryDataModel>()))
.Callback((SalaryDataModel x) =>
{
sum = x.Salary;
});
//Act
var postId = Guid.NewGuid().ToString();
var rate = 1000.0;
// Настраиваем моки
_postStorageContract.Setup(x => x.GetElementById(postId))
.Returns(new PostDataModel(postId, "TestPost", PostType.CashierConsultant, rate));
_requestStorageContract.Setup(x => x.GetList(It.IsAny<DateTime>(), It.IsAny<DateTime>(), It.IsAny<string>(),
It.IsAny<string>()))
.Returns([new RequestDataModel(Guid.NewGuid().ToString(), workerId, "emmmail@mail.ru", false,
[new InstallationRequestDataModel(Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), 5, 1.2)], DateTime.UtcNow)]);
_workerStorageContract.Setup(x => x.GetList(It.IsAny<bool>(), It.IsAny<string?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>(),
It.IsAny<DateTime?>(), It.IsAny<DateTime?>()))
.Returns([new WorkerDataModel(workerId, "Test", postId,
DateTime.UtcNow.AddYears(-20), DateTime.UtcNow.AddYears(-1),
false, new PostConfiguration { Rate = rate })]);
double actualSum = 0;
_salaryStorageContract.Setup(x => x.AddElement(It.IsAny<SalaryDataModel>())).Callback((SalaryDataModel x) => actualSum = x.Salary);
// Act
_salaryBusinessLogicContract.CalculateSalaryByMonth(DateTime.UtcNow);
//Assert
// Assert
Assert.That(actualSum, Is.EqualTo(rate));
}
[Test]
public void CalculateSalaryByMonth_WithSeveralWorkers_Test()
{
// Arrange
var postId = Guid.NewGuid().ToString();
var rate = 1000.0;
// Настраиваем мок для PostStorage
_postStorageContract.Setup(x => x.GetElementById(postId))
.Returns(new PostDataModel(postId, "TestPost", PostType.SoftInstaller, rate));
var workers = new List<WorkerDataModel>
{
new(Guid.NewGuid().ToString(), "Test1", postId, DateTime.UtcNow.AddYears(-20), DateTime.UtcNow.AddYears(-1), false, new PostConfiguration { Rate = rate }),
new(Guid.NewGuid().ToString(), "Test2", postId, DateTime.UtcNow.AddYears(-20), DateTime.UtcNow.AddYears(-1), false, new PostConfiguration { Rate = rate }),
new(Guid.NewGuid().ToString(), "Test3", postId, DateTime.UtcNow.AddYears(-20), DateTime.UtcNow.AddYears(-1), false, new PostConfiguration { Rate = rate })
};
// Настраиваем мок для WorkerStorage
_workerStorageContract.Setup(x => x.GetList(It.IsAny<bool>(), It.IsAny<string?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>(),
It.IsAny<DateTime?>(), It.IsAny<DateTime?>()))
.Returns(workers);
// Настраиваем мок для RequestStorage
_requestStorageContract.Setup(x => x.GetList(It.IsAny<DateTime>(), It.IsAny<DateTime>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns(workers.Select(w =>
new RequestDataModel(Guid.NewGuid().ToString(), w.Id, "email@mail.ru",false, [], DateTime.UtcNow)).ToList());
// Act
_salaryBusinessLogicContract.CalculateSalaryByMonth(DateTime.UtcNow);
// Assert
_salaryStorageContract.Verify(x => x.AddElement(It.IsAny<SalaryDataModel>()), Times.Exactly(workers.Count));
}
[Test]
public void CalculateSalaryByMonth_WithoutSalesByWorker_Test()
{
// Arrange
var workerId = Guid.NewGuid().ToString();
var postId = Guid.NewGuid().ToString();
var rate = 2000.0;
_postStorageContract.Setup(x => x.GetElementById(postId))
.Returns(new PostDataModel(postId, "TestPost", PostType.SoftInstaller, rate));
_requestStorageContract.Setup(x => x.GetList(It.IsAny<DateTime>(), It.IsAny<DateTime>(), It.IsAny<string>(), It.IsAny<string>())).Returns([]);
_workerStorageContract.Setup(x => x.GetList(It.IsAny<bool>(), It.IsAny<string?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>(),
It.IsAny<DateTime?>(), It.IsAny<DateTime?>()))
.Returns([new WorkerDataModel(workerId, "Test", postId,
DateTime.UtcNow.AddYears(-20), DateTime.UtcNow.AddYears(-1),
false, new PostConfiguration { Rate = rate })]);
double sum = 0;
_salaryStorageContract.Setup(x => x.AddElement(It.IsAny<SalaryDataModel>()))
.Callback((SalaryDataModel x) => sum = x.Salary);
// Act
_salaryBusinessLogicContract.CalculateSalaryByMonth(DateTime.UtcNow);
// Assert
Assert.That(sum, Is.EqualTo(rate));
}
[Test]
public void CalculateSalaryByMonth_RequestStorageReturnNull_ThrowException_Test()
{
// Arrange
var workerId = Guid.NewGuid().ToString();
var postId = Guid.NewGuid().ToString();
_postStorageContract.Setup(x => x.GetElementById(postId))
.Returns(new PostDataModel(postId, "TestPost", PostType.SoftInstaller, 1000));
_workerStorageContract.Setup(x => x.GetList(It.IsAny<bool>(), It.IsAny<string?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>(),
It.IsAny<DateTime?>(), It.IsAny<DateTime?>()))
.Returns([new WorkerDataModel(workerId, "Test", postId,
DateTime.UtcNow.AddYears(-20), DateTime.UtcNow.AddYears(-1),
false, new PostConfiguration { Rate = 1000 })]);
// Act & Assert
Assert.That(() => _salaryBusinessLogicContract.CalculateSalaryByMonth(DateTime.UtcNow),
Throws.TypeOf<NullListException>());
}
[Test]
public void CalculateSalaryByMonth_PostStorageReturnNull_ThrowException_Test()
{
// Arrange
var workerId = Guid.NewGuid().ToString();
var postId = Guid.NewGuid().ToString();
// Настраиваем моки
_requestStorageContract.Setup(x => x.GetList(It.IsAny<DateTime>(), It.IsAny<DateTime>(),
It.IsAny<string>(), It.IsAny<string>()))
.Returns([new RequestDataModel(Guid.NewGuid().ToString(), workerId, "email@mail.ru", false, [], DateTime.UtcNow)]);
_workerStorageContract.Setup(x => x.GetList(It.IsAny<bool>(), It.IsAny<string?>(),
It.IsAny<DateTime?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>()))
.Returns([new WorkerDataModel(workerId, "Test", postId,
DateTime.UtcNow.AddYears(-20), DateTime.UtcNow.AddYears(-1),
false, new PostConfiguration { Rate = 1000 })]);
// PostStorage возвращает null
_postStorageContract.Setup(x => x.GetElementById(It.IsAny<string>()))
.Returns((PostDataModel)null);
// Act & Assert
Assert.That(() => _salaryBusinessLogicContract.CalculateSalaryByMonth(DateTime.UtcNow),
Throws.TypeOf<NullListException>());
}
[Test]
public void CalculateSalaryByMonth_WorkerStorageReturnNull_ThrowException_Test()
{
// Arrange
var workerId = Guid.NewGuid().ToString();
var postId = Guid.NewGuid().ToString();
// Настраиваем моки
_requestStorageContract.Setup(x => x.GetList(It.IsAny<DateTime>(), It.IsAny<DateTime>(),
It.IsAny<string>(), It.IsAny<string>()))
.Returns([new RequestDataModel(Guid.NewGuid().ToString(), workerId, "email@mail.ru", false, [], DateTime.UtcNow)]);
// WorkerStorage возвращает null
_workerStorageContract.Setup(x => x.GetList(It.IsAny<bool>(), It.IsAny<string?>(),
It.IsAny<DateTime?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>()))
.Returns((List<WorkerDataModel>)null);
_postStorageContract.Setup(x => x.GetElementById(It.IsAny<string>()))
.Returns(new PostDataModel(postId, "TestPost", PostType.SoftInstaller, 1000));
// Act & Assert
Assert.That(() => _salaryBusinessLogicContract.CalculateSalaryByMonth(DateTime.UtcNow),
Throws.TypeOf<NullListException>());
}
[Test]
public void CalculateSalaryByMonth_RequestStorageThrowException_ThrowException_Test()
{
// Arrange
var workerId = Guid.NewGuid().ToString();
var postId = Guid.NewGuid().ToString();
// RequestStorage выбрасывает исключение
_requestStorageContract.Setup(x => x.GetList(It.IsAny<DateTime>(), It.IsAny<DateTime>(),
It.IsAny<string>(), It.IsAny<string>()))
.Throws(new StorageException(new InvalidOperationException()));
_workerStorageContract.Setup(x => x.GetList(It.IsAny<bool>(), It.IsAny<string?>(),
It.IsAny<DateTime?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>()))
.Returns([new WorkerDataModel(workerId, "Test", postId,
DateTime.UtcNow.AddYears(-20), DateTime.UtcNow.AddYears(-1),
false, new PostConfiguration { Rate = 1000 })]);
_postStorageContract.Setup(x => x.GetElementById(It.IsAny<string>()))
.Returns(new PostDataModel(postId, "TestPost", PostType.SoftInstaller, 1000));
// Act & Assert
Assert.That(() => _salaryBusinessLogicContract.CalculateSalaryByMonth(DateTime.UtcNow),
Throws.TypeOf<StorageException>());
}
[Test]
public void CalculateSalaryByMonth_PostStorageThrowException_ThrowException_Test()
{
// Arrange
var workerId = Guid.NewGuid().ToString();
var postId = Guid.NewGuid().ToString();
// Настраиваем моки
_requestStorageContract.Setup(x => x.GetList(It.IsAny<DateTime>(), It.IsAny<DateTime>(),
It.IsAny<string>(), It.IsAny<string>()))
.Returns([new RequestDataModel(Guid.NewGuid().ToString(), workerId, "email@mail.ru", false, [], DateTime.UtcNow)]);
_workerStorageContract.Setup(x => x.GetList(It.IsAny<bool>(), It.IsAny<string?>(),
It.IsAny<DateTime?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>()))
.Returns([new WorkerDataModel(workerId, "Test", postId,
DateTime.UtcNow.AddYears(-20), DateTime.UtcNow.AddYears(-1),
false, new PostConfiguration { Rate = 1000 })]);
// PostStorage выбрасывает исключение
_postStorageContract.Setup(x => x.GetElementById(It.IsAny<string>()))
.Throws(new StorageException(new InvalidOperationException()));
// Act & Assert
Assert.That(() => _salaryBusinessLogicContract.CalculateSalaryByMonth(DateTime.UtcNow),
Throws.TypeOf<StorageException>());
}
[Test]
public void CalculateSalaryByMonth_WorkerStorageThrowException_ThrowException_Test()
{
// Arrange
var workerId = Guid.NewGuid().ToString();
var postId = Guid.NewGuid().ToString();
// Настраиваем моки
_requestStorageContract.Setup(x => x.GetList(It.IsAny<DateTime>(), It.IsAny<DateTime>(),
It.IsAny<string>(), It.IsAny<string>()))
.Returns([new RequestDataModel(Guid.NewGuid().ToString(), workerId, "email@mail.ru", false, [], DateTime.UtcNow)]);
// WorkerStorage выбрасывает исключение
_workerStorageContract.Setup(x => x.GetList(It.IsAny<bool>(), It.IsAny<string?>(),
It.IsAny<DateTime?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>()))
.Throws(new StorageException(new InvalidOperationException()));
_postStorageContract.Setup(x => x.GetElementById(It.IsAny<string>()))
.Returns(new PostDataModel(postId, "TestPost", PostType.SoftInstaller, 1000));
// Act & Assert
Assert.That(() => _salaryBusinessLogicContract.CalculateSalaryByMonth(DateTime.UtcNow),
Throws.TypeOf<StorageException>());
}
[Test]
public void CalculateSalaryByMonth_WithCashierPostConfiguration_CalculateSalary_Test()
{
// Arrange
var workerId = Guid.NewGuid().ToString();
var postId = Guid.NewGuid().ToString();
var config = new CashierPostConfiguration
{
Rate = 2000,
SalePercent = 0.1,
BonusForExtraSales = 0.5
};
var sales = new List<RequestDataModel>()
{
new(Guid.NewGuid().ToString(), workerId, "eemail@maiil.ru", false,
[new InstallationRequestDataModel(Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), 5, 1.2)], DateTime.UtcNow),
new(Guid.NewGuid().ToString(), workerId, "eeemail@maiiil.ru", false,
[new InstallationRequestDataModel(Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), 5, 1.2)], DateTime.UtcNow),
new(Guid.NewGuid().ToString(), workerId, "eeeemail@mail.ru", false,
[new InstallationRequestDataModel(Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), 5000, 12)], DateTime.UtcNow)
};
_postStorageContract.Setup(x => x.GetElementById(postId))
.Returns(new PostDataModel(postId, "CashierConsultant", PostType.CashierConsultant, config.Rate));
_requestStorageContract.Setup(x => x.GetList(It.IsAny<DateTime>(), It.IsAny<DateTime>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns(sales);
_workerStorageContract.Setup(x => x.GetList(It.IsAny<bool>(), It.IsAny<string?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>(),
It.IsAny<DateTime?>(), It.IsAny<DateTime?>()))
.Returns([new WorkerDataModel(workerId, "Test", postId,
DateTime.UtcNow.AddYears(-20), DateTime.UtcNow.AddYears(-1),
false, config)]);
double sum = 0;
var expectedSum = config.Rate + (config.SalePercent * sales.Average(x => x.Sum)) +
(sales.Where(x => x.Sum > _salaryConfigurationTest.ExtraSaleSum).Sum(x => x.Sum) * config.BonusForExtraSales);
_salaryStorageContract.Setup(x => x.AddElement(It.IsAny<SalaryDataModel>()))
.Callback((SalaryDataModel x) => sum = x.Salary);
// Act
_salaryBusinessLogicContract.CalculateSalaryByMonth(DateTime.UtcNow);
// Assert
Assert.That(sum, Is.EqualTo(expectedSum));
}
[Test]
public void
CalculateSalaryByMounth_RequestStorageReturnNull_ThrowException_Test()
public void CalculateSalaryByMonth_WithSupervisorPostConfiguration_CalculateSalary_Test()
{
//Arrange
// Arrange
var workerId = Guid.NewGuid().ToString();
_postStorageContract.Setup(x => x.GetElementById(It.IsAny<string>()))
.Returns(new PostDataModel(Guid.NewGuid().ToString(), "name",
PostType.SoftInstaller, 2000));
_workerStorageContract.Setup(x => x.GetList(It.IsAny<bool>(),
It.IsAny<string?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>(),
It.IsAny<DateTime?>(), It.IsAny<DateTime?>()))
.Returns([new WorkerDataModel(workerId, "Test",
Guid.NewGuid().ToString(), DateTime.UtcNow, DateTime.UtcNow, false, new PostConfiguration() { Rate = 10 })]);
//Act&Assert
Assert.That(() =>
_salaryBusinessLogicContract.CalculateSalaryByMonth(DateTime.UtcNow),
Throws.TypeOf<NullListException>());
}
[Test]
public void
CalculateSalaryByMounth_PostStorageReturnNull_ThrowException_Test()
{
//Arrange
var workerId = Guid.NewGuid().ToString();
_requestStorageContract.Setup(x => x.GetList(It.IsAny<DateTime>(),
It.IsAny<DateTime>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns([new RequestDataModel(Guid.NewGuid().ToString(), workerId, Guid.NewGuid().ToString(), false, [], DateTime.UtcNow)]);
_workerStorageContract.Setup(x => x.GetList(It.IsAny<bool>(),
It.IsAny<string?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>(),
It.IsAny<DateTime?>(), It.IsAny<DateTime?>()))
.Returns([new WorkerDataModel(workerId, "Test",
Guid.NewGuid().ToString(), DateTime.UtcNow, DateTime.UtcNow, false, new PostConfiguration() { Rate = 10 })]);
//Act&Assert
Assert.That(() =>
_salaryBusinessLogicContract.CalculateSalaryByMonth(DateTime.UtcNow),
Throws.TypeOf<NullListException>());
}
[Test]
public void
CalculateSalaryByMounth_WorkerStorageReturnNull_ThrowException_Test()
{
//Arrange
var workerId = Guid.NewGuid().ToString();
_requestStorageContract.Setup(x => x.GetList(It.IsAny<DateTime>(),
It.IsAny<DateTime>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns([new RequestDataModel(Guid.NewGuid().ToString(),
workerId, Guid.NewGuid().ToString(), false, [], DateTime.UtcNow)]);
_postStorageContract.Setup(x => x.GetElementById(It.IsAny<string>()))
.Returns(new PostDataModel(Guid.NewGuid().ToString(), "name",
PostType.SoftInstaller, 2000));
//Act&Assert
Assert.That(() =>
_salaryBusinessLogicContract.CalculateSalaryByMonth(DateTime.UtcNow),
Throws.TypeOf<NullListException>());
}
[Test]
public void
CalculateSalaryByMounth_RequestStorageThrowException_ThrowException_Test()
{
//Arrange
var workerId = Guid.NewGuid().ToString();
_requestStorageContract.Setup(x => x.GetList(It.IsAny<DateTime>(),
It.IsAny<DateTime>(), It.IsAny<string>(), It.IsAny<string>()))
.Throws(new StorageException(new
InvalidOperationException()));
_postStorageContract.Setup(x => x.GetElementById(It.IsAny<string>()))
.Returns(new PostDataModel(Guid.NewGuid().ToString(), "name",
PostType.SoftInstaller, 2000));
_workerStorageContract.Setup(x => x.GetList(It.IsAny<bool>(),
It.IsAny<string?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>(),
It.IsAny<DateTime?>(), It.IsAny<DateTime?>()))
.Returns([new WorkerDataModel(workerId, "Test",
Guid.NewGuid().ToString(), DateTime.UtcNow, DateTime.UtcNow, false, new PostConfiguration() { Rate = 10 })]);
//Act&Assert
Assert.That(() =>
_salaryBusinessLogicContract.CalculateSalaryByMonth(DateTime.UtcNow),
Throws.TypeOf<StorageException>());
}
[Test]
public void
CalculateSalaryByMounth_PostStorageThrowException_ThrowException_Test()
{
//Arrange
var workerId = Guid.NewGuid().ToString();
_requestStorageContract.Setup(x => x.GetList(It.IsAny<DateTime>(),
It.IsAny<DateTime>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns([new RequestDataModel(Guid.NewGuid().ToString(),
workerId, Guid.NewGuid().ToString(), false, [], DateTime.UtcNow)]);
_postStorageContract.Setup(x => x.GetElementById(It.IsAny<string>()))
.Throws(new StorageException(new
InvalidOperationException()));
_workerStorageContract.Setup(x => x.GetList(It.IsAny<bool>(),
It.IsAny<string?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>(),
It.IsAny<DateTime?>(), It.IsAny<DateTime?>()))
.Returns([new WorkerDataModel(workerId, "Test",
Guid.NewGuid().ToString(), DateTime.UtcNow, DateTime.UtcNow, false, new PostConfiguration() { Rate = 10 })]);
//Act&Assert
Assert.That(() =>
_salaryBusinessLogicContract.CalculateSalaryByMonth(DateTime.UtcNow),
Throws.TypeOf<StorageException>());
}
[Test]
public void
CalculateSalaryByMounth_WorkerStorageThrowException_ThrowException_Test()
{
//Arrange
var workerId = Guid.NewGuid().ToString();
_requestStorageContract.Setup(x => x.GetList(It.IsAny<DateTime>(),
It.IsAny<DateTime>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns([new RequestDataModel(Guid.NewGuid().ToString(), workerId, Guid.NewGuid().ToString(), false, [], DateTime.UtcNow)]);
_postStorageContract.Setup(x => x.GetElementById(It.IsAny<string>()))
.Returns(new PostDataModel(Guid.NewGuid().ToString(), "name",
PostType.SoftInstaller, 2000));
_workerStorageContract.Setup(x => x.GetList(It.IsAny<bool>(),
It.IsAny<string?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>(),
It.IsAny<DateTime?>(), It.IsAny<DateTime?>()))
.Throws(new StorageException(new
InvalidOperationException()));
//Act&Assert
Assert.That(() =>
_salaryBusinessLogicContract.CalculateSalaryByMonth(DateTime.UtcNow),
Throws.TypeOf<StorageException>());
var postId = Guid.NewGuid().ToString();
var rate = 2000.0;
var trend = 3;
var bonus = 100;
// Конфигурация для супервайзера
var supervisorConfig = new SupervisorPostConfiguration()
{
Rate = rate,
PersonalCountTrendPremium = bonus
};
// Настраиваем моки
_requestStorageContract.Setup(x => x.GetList(It.IsAny<DateTime>(), It.IsAny<DateTime>(),
It.IsAny<string>(), It.IsAny<string>()))
.Returns([new RequestDataModel(Guid.NewGuid().ToString(), workerId, "email@mail.ru", false,
[new InstallationRequestDataModel(Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), 5, 1.2)], DateTime.UtcNow)]);
_postStorageContract.Setup(x => x.GetElementById(postId))
.Returns(new PostDataModel(postId, "Supervisor", PostType.Supervisor, supervisorConfig.Rate));
_workerStorageContract.Setup(x => x.GetList(It.IsAny<bool>(), It.IsAny<string?>(),
It.IsAny<DateTime?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>(), It.IsAny<DateTime?>()))
.Returns([new WorkerDataModel(workerId, "Test", postId,
DateTime.UtcNow.AddYears(-20), DateTime.UtcNow.AddYears(-1),
false, supervisorConfig)]);
_workerStorageContract.Setup(x => x.GetWorkerTrend(It.IsAny<DateTime>(), It.IsAny<DateTime>()))
.Returns(trend);
double actualSum = 0;
var expectedSum = rate + (trend * bonus);
_salaryStorageContract.Setup(x => x.AddElement(It.IsAny<SalaryDataModel>()))
.Callback((SalaryDataModel x) => actualSum = x.Salary);
// Act
_salaryBusinessLogicContract.CalculateSalaryByMonth(DateTime.UtcNow);
// Assert
Assert.That(actualSum, Is.EqualTo(expectedSum));
}
}

View File

@@ -0,0 +1,14 @@
using SmallSoftwareContracts.Infrastructure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SmallSoftwareTests.Infrastructure;
class ConfigurationSalaryTest : IConfigurationSalary
{
public double ExtraSaleSum => 10;
public int MaxConcurrentThreads => 4;
}

View File

@@ -144,41 +144,41 @@ internal class WorkerStorageContractTests : BaseStorageContractTest
});
}
//[Test]
//public void Try_GetWorkerTrend_WhenNoNewAndDeletedWorkers_Test()
//{
// var startDate = DateTime.UtcNow.AddDays(-5);
// var endDate = DateTime.UtcNow.AddDays(-3);
// SmallSoftwareDbContext.InsertWorkerToDatabaseAndReturn(employmentDate: DateTime.UtcNow.AddDays(-10));
// SmallSoftwareDbContext.InsertWorkerToDatabaseAndReturn(employmentDate: DateTime.UtcNow.AddDays(-10), isDeleted: true, dateDelete: DateTime.UtcNow.AddDays(-9));
// SmallSoftwareDbContext.InsertWorkerToDatabaseAndReturn(employmentDate: DateTime.UtcNow.AddDays(-10), isDeleted: true, dateDelete: DateTime.UtcNow.AddDays(-1));
// var count = _workerStorageContract.GetWorkerTrend(startDate, endDate);
// Assert.That(count, Is.EqualTo(0));
//}
[Test]
public void Try_GetWorkerTrend_WhenNoNewAndDeletedWorkers_Test()
{
var startDate = DateTime.UtcNow.AddDays(-5);
var endDate = DateTime.UtcNow.AddDays(-3);
SmallSoftwareDbContext.InsertWorkerToDatabaseAndReturn(employmentDate: DateTime.UtcNow.AddDays(-10));
SmallSoftwareDbContext.InsertWorkerToDatabaseAndReturn(employmentDate: DateTime.UtcNow.AddDays(-10), isDeleted: true, dateDelete: DateTime.UtcNow.AddDays(-9));
SmallSoftwareDbContext.InsertWorkerToDatabaseAndReturn(employmentDate: DateTime.UtcNow.AddDays(-10), isDeleted: true, dateDelete: DateTime.UtcNow.AddDays(-1));
var count = _workerStorageContract.GetWorkerTrend(startDate, endDate);
Assert.That(count, Is.EqualTo(0));
}
//[Test]
//public void Try_GetWorkerTrend_WhenHaveNewAndNoDeletedWorkers_Test()
//{
// var startDate = DateTime.UtcNow.AddDays(-5);
// var endDate = DateTime.UtcNow.AddDays(-3);
// SmallSoftwareDbContext.InsertWorkerToDatabaseAndReturn(employmentDate: DateTime.UtcNow.AddDays(-10));
// SmallSoftwareDbContext.InsertWorkerToDatabaseAndReturn(employmentDate: DateTime.UtcNow.AddDays(-4));
// SmallSoftwareDbContext.InsertWorkerToDatabaseAndReturn(employmentDate: DateTime.UtcNow.AddDays(-1));
// var count = _workerStorageContract.GetWorkerTrend(startDate, endDate);
// Assert.That(count, Is.EqualTo(1));
//}
[Test]
public void Try_GetWorkerTrend_WhenHaveNewAndNoDeletedWorkers_Test()
{
var startDate = DateTime.UtcNow.AddDays(-5);
var endDate = DateTime.UtcNow.AddDays(-3);
SmallSoftwareDbContext.InsertWorkerToDatabaseAndReturn(employmentDate: DateTime.UtcNow.AddDays(-10));
SmallSoftwareDbContext.InsertWorkerToDatabaseAndReturn(employmentDate: DateTime.UtcNow.AddDays(-4));
SmallSoftwareDbContext.InsertWorkerToDatabaseAndReturn(employmentDate: DateTime.UtcNow.AddDays(-1));
var count = _workerStorageContract.GetWorkerTrend(startDate, endDate);
Assert.That(count, Is.EqualTo(1));
}
//[Test]
//public void Try_GetWorkerTrend_WhenNoNewAndHaveDeletedWorkers_Test()
//{
// var startDate = DateTime.UtcNow.AddDays(-5);
// var endDate = DateTime.UtcNow.AddDays(-3);
// SmallSoftwareDbContext.InsertWorkerToDatabaseAndReturn(employmentDate: DateTime.UtcNow.AddDays(-10), isDeleted: true, dateDelete: DateTime.UtcNow.AddDays(-9));
// SmallSoftwareDbContext.InsertWorkerToDatabaseAndReturn(employmentDate: DateTime.UtcNow.AddDays(-10), isDeleted: true, dateDelete: DateTime.UtcNow.AddDays(-4));
// SmallSoftwareDbContext.InsertWorkerToDatabaseAndReturn(employmentDate: DateTime.UtcNow.AddDays(-10), isDeleted: true, dateDelete: DateTime.UtcNow.AddDays(-1));
// var count = _workerStorageContract.GetWorkerTrend(startDate, endDate);
// Assert.That(count, Is.EqualTo(-1));
//}
[Test]
public void Try_GetWorkerTrend_WhenNoNewAndHaveDeletedWorkers_Test()
{
var startDate = DateTime.UtcNow.AddDays(-5);
var endDate = DateTime.UtcNow.AddDays(-3);
SmallSoftwareDbContext.InsertWorkerToDatabaseAndReturn(employmentDate: DateTime.UtcNow.AddDays(-10), isDeleted: true, dateDelete: DateTime.UtcNow.AddDays(-9));
SmallSoftwareDbContext.InsertWorkerToDatabaseAndReturn(employmentDate: DateTime.UtcNow.AddDays(-10), isDeleted: true, dateDelete: DateTime.UtcNow.AddDays(-4));
SmallSoftwareDbContext.InsertWorkerToDatabaseAndReturn(employmentDate: DateTime.UtcNow.AddDays(-10), isDeleted: true, dateDelete: DateTime.UtcNow.AddDays(-1));
var count = _workerStorageContract.GetWorkerTrend(startDate, endDate);
Assert.That(count, Is.EqualTo(-1));
}
[Test]
@@ -355,13 +355,13 @@ internal class WorkerStorageContractTests : BaseStorageContractTest
Assert.That(actual.EmploymentDate,
Is.EqualTo(expected.EmploymentDate));
Assert.That(actual.IsDeleted, Is.EqualTo(expected.IsDeleted));
Assert.That(actual.ConfigurationModel.Rate, Is.EqualTo(expected.Configuration.Rate));
});
}
private static WorkerDataModel CreateModel(string id, string fio = "fio",
string? postId = null, DateTime? birthDate = null, DateTime? employmentDate =
null, bool isDeleted = false, PostConfiguration? config = null) =>
private static WorkerDataModel CreateModel(string id, string fio = "fio", string? postId = null,
DateTime? birthDate = null, DateTime? employmentDate = null, bool isDeleted = false, PostConfiguration? config = null) =>
new(id, fio, postId ?? Guid.NewGuid().ToString(), birthDate ??
DateTime.UtcNow.AddYears(-20), employmentDate ?? DateTime.UtcNow, isDeleted, config ?? new PostConfiguration() { Rate = 100 });
DateTime.UtcNow.AddYears(-20), employmentDate ?? DateTime.UtcNow, isDeleted, config ?? new PostConfiguration() { Rate = 100 });
private Worker? GetWorkerFromDatabase(string id) =>
SmallSoftwareDbContext.Workers.FirstOrDefault(x => x.Id == id);
private static void AssertElement(Worker? actual, WorkerDataModel expected)
@@ -373,9 +373,10 @@ internal class WorkerStorageContractTests : BaseStorageContractTest
Assert.That(actual.PostId, Is.EqualTo(expected.PostId));
Assert.That(actual.FIO, Is.EqualTo(expected.FIO));
Assert.That(actual.BirthDate, Is.EqualTo(expected.BirthDate));
Assert.That(actual.EmploymentDate,
Is.EqualTo(expected.EmploymentDate));
Assert.That(actual.EmploymentDate, Is.EqualTo(expected.EmploymentDate));
Assert.That(actual.IsDeleted, Is.EqualTo(expected.IsDeleted));
Assert.That(actual.Configuration.Rate, Is.EqualTo(expected.ConfigurationModel.Rate));
Assert.That(actual.DateOfDelete.HasValue, Is.EqualTo(expected.IsDeleted));
});
}
}

View File

@@ -182,7 +182,7 @@ internal class SalaryControllerTests : BaseWebApiControllerTest
Assert.Multiple(() =>
{
Assert.That(salaries, Has.Length.EqualTo(1));
Assert.That(salaries.First().WorkerSalary, Is.EqualTo(10.1d));
Assert.That(salaries.First().WorkerSalary, Is.EqualTo(100));
Assert.That(salaries.First().SalaryDate.Month, Is.EqualTo(DateTime.UtcNow.Month));
});
}

View File

@@ -0,0 +1,13 @@
using SmallSoftwareContracts.Infrastructure;
namespace SmallSoftwareWebApi.Infrastructure;
public class ConfigurationSalary(IConfiguration configuration) : IConfigurationSalary
{
private readonly Lazy<SalarySettings> _salarySettings = new(() =>
{
return configuration.GetValue<SalarySettings>("SalarySettings") ?? throw new InvalidDataException(nameof(SalarySettings));
});
public double ExtraSaleSum => _salarySettings.Value.ExtraSaleSum;
public int MaxConcurrentThreads => _salarySettings.Value.MaxConcurrentThreads;
}

View File

@@ -0,0 +1,7 @@
namespace SmallSoftwareWebApi.Infrastructure;
public class SalarySettings
{
public double ExtraSaleSum { get; set; }
public int MaxConcurrentThreads { get; set; }
}

View File

@@ -49,6 +49,8 @@ builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
});
builder.Services.AddSingleton<IConfigurationDatabase, ConfigurationDatabase>();
builder.Services.AddSingleton<IConfigurationSalary, ConfigurationSalary>();
builder.Services.AddTransient<IManufacturerBusinessLogicContract, ManufacturerBusinessLogicContract>();
builder.Services.AddTransient<IPostBusinessLogicContract, PostBusinessLogicContract>();
builder.Services.AddTransient<ISoftwareBusinessLogicContract, SoftwareBusinessLogicContract>();

View File

@@ -22,7 +22,11 @@
]
},
"AllowedHosts": "*",
"DataBaseSettings": {
"ConnectionString": ""
"SalarySettings": {
"ExtraSaleSum": 1000,
"MaxConcurrentThreads": 4
},
"SupervisorPostSettings": {
"PersonalCountTrendPremium": 1.1
}
}