all done lab_6
This commit is contained in:
@@ -9,13 +9,20 @@ using SmallSoftwareContracts.StoragesContracts;
|
||||
namespace SmallSoftwareBusinessLogic.Implementations;
|
||||
|
||||
internal class ReportContract(ISoftwareStorageContract softwareStorageContract,
|
||||
IRequestStorageContract requestStorageContract, BaseWordBuilder baseWordBuilder, BaseExcelBuilder baseExcelBuilder, ILogger logger) : IReportContract
|
||||
IRequestStorageContract requestStorageContract,
|
||||
ISalaryStorageContract salaryStorageContract,
|
||||
BaseWordBuilder baseWordBuilder,
|
||||
BaseExcelBuilder baseExcelBuilder,
|
||||
BasePdfBuilder basePdfBuilder, ILogger logger) : IReportContract
|
||||
{
|
||||
private readonly ISoftwareStorageContract _softwareStorageContract = softwareStorageContract;
|
||||
private readonly ILogger _logger = logger;
|
||||
private readonly IRequestStorageContract _requestStorageContract = requestStorageContract;
|
||||
private readonly ISalaryStorageContract _salaryStorageContract = salaryStorageContract;
|
||||
private readonly BaseWordBuilder _baseWordBuilder = baseWordBuilder;
|
||||
private readonly BaseExcelBuilder _baseExcelBuilder = baseExcelBuilder;
|
||||
private readonly ILogger _logger = logger;
|
||||
|
||||
private readonly BasePdfBuilder _basePdfBuilder = basePdfBuilder;
|
||||
|
||||
internal static readonly string[] tableHeader = ["Дата", "Сумма", "Товар", "Кол-во"];
|
||||
internal static readonly string[] documentHeader = ["Название ПО", "Старая цена", "Дата"];
|
||||
@@ -118,4 +125,28 @@ internal class ReportContract(ISoftwareStorageContract softwareStorageContract,
|
||||
.Build();
|
||||
}
|
||||
|
||||
public Task<List<WorkerSalaryByPeriodDataModel>> GetDataSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
|
||||
{
|
||||
logger.LogInformation("Get data SalaryByPeriod from {dateStart} to { dateFinish}", dateStart, dateFinish);
|
||||
return GetDataBySalaryAsync(dateStart, dateFinish, ct);
|
||||
}
|
||||
|
||||
private async Task<List<WorkerSalaryByPeriodDataModel>> GetDataBySalaryAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
|
||||
{
|
||||
if (dateStart.IsDateNotOlder(dateFinish))
|
||||
{
|
||||
throw new IncorrectDatesException(dateStart, dateFinish);
|
||||
}
|
||||
return [.. (await _salaryStorageContract.GetListAsync(dateStart, dateFinish, ct)).GroupBy(x => x.WorkerFIO).Select(x => new
|
||||
WorkerSalaryByPeriodDataModel { WorkerFIO = x.Key, TotalSalary = x.Sum(y => y.Salary),
|
||||
FromPeriod = x.Min(y => y.SalaryDate), ToPeriod = x.Max(y => y.SalaryDate) }).OrderBy(x => x.WorkerFIO)];
|
||||
}
|
||||
|
||||
public async Task<Stream> CreateDocumentSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Create report SalaryByPeriod from {dateStart} to { dateFinish}", dateStart, dateFinish);
|
||||
var data = await GetDataBySalaryAsync(dateStart, dateFinish, ct) ?? throw new InvalidOperationException("No found data");
|
||||
return _basePdfBuilder.AddHeader("Зарплатная ведомость").AddParagraph($"за период с {dateStart.ToShortDateString()} по {dateFinish.ToShortDateString()}")
|
||||
.AddPieChart("Начисления", [.. data.Select(x => (x.WorkerFIO, x.TotalSalary))]).Build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SmallSoftwareBusinessLogic.OfficePackage;
|
||||
|
||||
public abstract class BasePdfBuilder
|
||||
{
|
||||
public abstract BasePdfBuilder AddHeader(string header);
|
||||
public abstract BasePdfBuilder AddParagraph(string text);
|
||||
public abstract BasePdfBuilder AddPieChart(string title, List<(string Caption, double Value)> data);
|
||||
public abstract Stream Build();
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
using MigraDoc.DocumentObjectModel;
|
||||
using MigraDoc.DocumentObjectModel.Shapes.Charts;
|
||||
using MigraDoc.Rendering;
|
||||
using System.Text;
|
||||
|
||||
namespace SmallSoftwareBusinessLogic.OfficePackage;
|
||||
|
||||
|
||||
public class MigraDocPdfBuilder : BasePdfBuilder
|
||||
{
|
||||
private readonly Document _document;
|
||||
|
||||
public MigraDocPdfBuilder()
|
||||
{
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
_document = new Document();
|
||||
DefineStyles();
|
||||
}
|
||||
|
||||
public override BasePdfBuilder AddHeader(string header)
|
||||
{
|
||||
_document.AddSection().AddParagraph(header, "NormalBold");
|
||||
return this;
|
||||
}
|
||||
|
||||
public override BasePdfBuilder AddParagraph(string text)
|
||||
{
|
||||
_document.LastSection.AddParagraph(text, "Normal");
|
||||
return this;
|
||||
}
|
||||
|
||||
public override BasePdfBuilder AddPieChart(string title, List<(string Caption, double Value)> data)
|
||||
{
|
||||
if (data == null || data.Count == 0)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
var chart = new Chart(ChartType.Pie2D);
|
||||
var series = chart.SeriesCollection.AddSeries();
|
||||
series.Add(data.Select(x => x.Value).ToArray());
|
||||
var xseries = chart.XValues.AddXSeries();
|
||||
xseries.Add(data.Select(x => x.Caption).ToArray());
|
||||
chart.DataLabel.Type = DataLabelType.Percent;
|
||||
chart.DataLabel.Position = DataLabelPosition.OutsideEnd;
|
||||
chart.Width = Unit.FromCentimeter(16);
|
||||
chart.Height = Unit.FromCentimeter(12);
|
||||
chart.TopArea.AddParagraph(title);
|
||||
chart.XAxis.MajorTickMark = TickMarkType.Outside;
|
||||
chart.YAxis.MajorTickMark = TickMarkType.Outside;
|
||||
chart.YAxis.HasMajorGridlines = true;
|
||||
chart.PlotArea.LineFormat.Width = 1;
|
||||
chart.PlotArea.LineFormat.Visible = true;
|
||||
chart.TopArea.AddLegend();
|
||||
_document.LastSection.Add(chart);
|
||||
return this;
|
||||
}
|
||||
|
||||
public override Stream Build()
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
var renderer = new PdfDocumentRenderer(true)
|
||||
{
|
||||
Document = _document
|
||||
};
|
||||
renderer.RenderDocument();
|
||||
renderer.PdfDocument.Save(stream);
|
||||
return stream;
|
||||
}
|
||||
|
||||
private void DefineStyles()
|
||||
{
|
||||
var headerStyle = _document.Styles.AddStyle("NormalBold", "Normal");
|
||||
headerStyle.Font.Bold = true;
|
||||
headerStyle.Font.Size = 14;
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DocumentFormat.OpenXml" Version="3.3.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.2" />
|
||||
<PackageReference Include="PdfSharp.MigraDoc.Standard" Version="1.51.15" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -8,5 +8,6 @@ public interface IReportAdapter
|
||||
Task<ReportOperationResponse> CreateDocumentSoftwaresByManufacturerAsync(CancellationToken ct);
|
||||
Task<ReportOperationResponse> GetDataRequestByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
Task<ReportOperationResponse> CreateDocumentRequestsByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
|
||||
Task<ReportOperationResponse> GetDataSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
Task<ReportOperationResponse> CreateDocumentSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
}
|
||||
|
||||
@@ -11,4 +11,5 @@ public class ReportOperationResponse : OperationResponse
|
||||
public static ReportOperationResponse OK(Stream data, string filename) => OK<ReportOperationResponse, Stream>(data, filename);
|
||||
public static ReportOperationResponse BadRequest(string message) => BadRequest<ReportOperationResponse>(message);
|
||||
public static ReportOperationResponse InternalServerError(string message) => InternalServerError<ReportOperationResponse>(message);
|
||||
public static ReportOperationResponse OK(List<WorkerSalaryByPeriodViewModel> data) => OK<ReportOperationResponse, List<WorkerSalaryByPeriodViewModel>>(data);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,6 @@ public interface IReportContract
|
||||
Task<List<RequestDataModel>> GetDataRequestByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
Task<Stream> CreateDocumentSoftwaresByHistoryAsync(CancellationToken ct);
|
||||
Task<Stream> CreateDocumentRequestsByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
|
||||
|
||||
Task<List<WorkerSalaryByPeriodDataModel>> GetDataSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
Task<Stream> CreateDocumentSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace SmallSoftwareContracts.DataModels;
|
||||
|
||||
public class WorkerSalaryByPeriodDataModel
|
||||
{
|
||||
public required string WorkerFIO { get; set; }
|
||||
public double TotalSalary { get; set; }
|
||||
public DateTime FromPeriod { get; set; }
|
||||
public DateTime ToPeriod { get; set; }
|
||||
}
|
||||
|
||||
@@ -6,5 +6,6 @@ public interface ISalaryStorageContract
|
||||
{
|
||||
List<SalaryDataModel> GetList(DateTime startDate, DateTime endDate, string? workerId = null);
|
||||
void AddElement(SalaryDataModel salaryDataModel);
|
||||
Task<List<SalaryDataModel>> GetListAsync(DateTime startDate, DateTime endDate, CancellationToken ct);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace SmallSoftwareContracts.ViewModels;
|
||||
|
||||
public class WorkerSalaryByPeriodViewModel
|
||||
{
|
||||
public required string WorkerFIO { get; set; }
|
||||
public double TotalSalary { get; set; }
|
||||
public DateTime FromPeriod { get; set; }
|
||||
public DateTime ToPeriod { get; set; }
|
||||
}
|
||||
@@ -53,4 +53,17 @@ internal class SalaryStorageContract : ISalaryStorageContract
|
||||
throw new StorageException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<SalaryDataModel>> GetListAsync(DateTime startDate, DateTime endDate, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
return [.. await _dbContext.Salaries.Include(x => x.Worker).Where(x => x.SalaryDate >= startDate && x.SalaryDate <= endDate).Select(x => _mapper.Map<SalaryDataModel>(x)).ToListAsync(ct)];
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_dbContext.ChangeTracker.Clear();
|
||||
throw new StorageException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ internal class ReportContractTests
|
||||
private Mock<ISalaryStorageContract> _salaryStorageContract;
|
||||
private Mock<BaseWordBuilder> _baseWordBuilder;
|
||||
private Mock<BaseExcelBuilder> _baseExcelBuilder;
|
||||
private Mock<BasePdfBuilder> _basePdfBuilder;
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetUp()
|
||||
{
|
||||
@@ -26,8 +27,9 @@ internal class ReportContractTests
|
||||
_requestStorageContract = new Mock<IRequestStorageContract>();
|
||||
_salaryStorageContract = new Mock<ISalaryStorageContract>();
|
||||
_baseWordBuilder = new Mock<BaseWordBuilder>();
|
||||
_baseExcelBuilder = new Mock<BaseExcelBuilder>();
|
||||
_reportContract = new ReportContract(_softwareStorageContract.Object, _requestStorageContract.Object, _baseWordBuilder.Object, _baseExcelBuilder.Object, new Mock<ILogger>().Object);
|
||||
_baseExcelBuilder = new Mock<BaseExcelBuilder>();
|
||||
_basePdfBuilder = new Mock<BasePdfBuilder>();
|
||||
_reportContract = new ReportContract(_softwareStorageContract.Object, _requestStorageContract.Object, _salaryStorageContract.Object, _baseWordBuilder.Object, _baseExcelBuilder.Object, _basePdfBuilder.Object, new Mock<ILogger>().Object);
|
||||
}
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
@@ -229,6 +231,119 @@ internal class ReportContractTests
|
||||
It.IsAny<DateTime>(), It.IsAny<CancellationToken>()), Times.Once);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetDataSalaryByPeriod_ShouldSuccess_Test()
|
||||
{
|
||||
// Arrange
|
||||
var startDate = DateTime.UtcNow.AddDays(-20);
|
||||
var endDate = DateTime.UtcNow.AddDays(5);
|
||||
|
||||
var worker1 = new WorkerDataModel(
|
||||
Guid.NewGuid().ToString(),
|
||||
"fio 1",
|
||||
Guid.NewGuid().ToString(),
|
||||
DateTime.UtcNow.AddYears(-20),
|
||||
DateTime.UtcNow.AddDays(-3));
|
||||
|
||||
var worker2 = new WorkerDataModel(
|
||||
Guid.NewGuid().ToString(),
|
||||
"fio 2",
|
||||
Guid.NewGuid().ToString(),
|
||||
DateTime.UtcNow.AddYears(-20),
|
||||
DateTime.UtcNow.AddDays(-3));
|
||||
|
||||
_salaryStorageContract.Setup(x =>
|
||||
x.GetListAsync(It.IsAny<DateTime>(), It.IsAny<DateTime>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new List<SalaryDataModel>()
|
||||
{
|
||||
new(worker1.Id, DateTime.UtcNow.AddDays(-10), 100),
|
||||
new(worker1.Id, endDate, 1000),
|
||||
new(worker1.Id, startDate, 1000),
|
||||
new(worker2.Id, DateTime.UtcNow.AddDays(-10), 100),
|
||||
new(worker2.Id, DateTime.UtcNow.AddDays(-5), 200)
|
||||
});
|
||||
|
||||
// Act
|
||||
var data = await _reportContract.GetDataSalaryByPeriodAsync(
|
||||
DateTime.UtcNow.AddDays(-1),
|
||||
DateTime.UtcNow,
|
||||
CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.That(data, Is.Not.Null);
|
||||
Assert.That(data, Has.Count.EqualTo(1));
|
||||
|
||||
var totalSalary = data.First();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(totalSalary, Is.Not.Null);
|
||||
Assert.That(totalSalary.TotalSalary, Is.EqualTo(2400));
|
||||
});
|
||||
|
||||
_salaryStorageContract.Verify(x => x.GetListAsync(It.IsAny<DateTime>(), It.IsAny<DateTime>(),
|
||||
It.IsAny<CancellationToken>()), Times.Once);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetDataSalaryByPeriod_WhenNoRecords_ShouldSuccess_Test()
|
||||
{
|
||||
// Arrange
|
||||
_salaryStorageContract.Setup(x =>
|
||||
x.GetListAsync(It.IsAny<DateTime>(), It.IsAny<DateTime>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new List<SalaryDataModel>());
|
||||
|
||||
// Act
|
||||
var data = await _reportContract.GetDataSalaryByPeriodAsync(
|
||||
DateTime.UtcNow.AddDays(-1),
|
||||
DateTime.UtcNow,
|
||||
CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.That(data, Is.Not.Null);
|
||||
Assert.That(data, Has.Count.EqualTo(0));
|
||||
|
||||
_salaryStorageContract.Verify(x =>
|
||||
x.GetListAsync(It.IsAny<DateTime>(), It.IsAny<DateTime>(), It.IsAny<CancellationToken>()),
|
||||
Times.Once);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetDataSalaryByPeriod_WhenIncorrectDates_ShouldFail_Test()
|
||||
{
|
||||
// Arrange
|
||||
var date = DateTime.UtcNow;
|
||||
|
||||
// Act & Assert
|
||||
Assert.That(async () => await _reportContract.GetDataSalaryByPeriodAsync(
|
||||
date, date, CancellationToken.None),
|
||||
Throws.TypeOf<IncorrectDatesException>());
|
||||
|
||||
Assert.That(async () => await _reportContract.GetDataSalaryByPeriodAsync(
|
||||
date, DateTime.UtcNow.AddDays(-1), CancellationToken.None),
|
||||
Throws.TypeOf<IncorrectDatesException>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetDataBySalaryByPeriod_WhenStorageThrowError_ShouldFail_Test()
|
||||
{
|
||||
// Arrange
|
||||
_salaryStorageContract.Setup(x =>
|
||||
x.GetListAsync(It.IsAny<DateTime>(), It.IsAny<DateTime>(), It.IsAny<CancellationToken>()))
|
||||
.ThrowsAsync(new StorageException(new InvalidOperationException()));
|
||||
|
||||
// Act & Assert
|
||||
Assert.That(async () => await _reportContract.GetDataSalaryByPeriodAsync(
|
||||
DateTime.UtcNow.AddDays(-1),
|
||||
DateTime.UtcNow,
|
||||
CancellationToken.None),
|
||||
Throws.TypeOf<StorageException>());
|
||||
|
||||
_salaryStorageContract.Verify(x =>
|
||||
x.GetListAsync(It.IsAny<DateTime>(), It.IsAny<DateTime>(), It.IsAny<CancellationToken>()),
|
||||
Times.Once);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task CreateDocumentRequestsByPeriod_ShouldSuccess_Test()
|
||||
{
|
||||
@@ -335,4 +450,60 @@ internal class ReportContractTests
|
||||
|
||||
_baseExcelBuilder.Verify(x => x.Build(), Times.Once);
|
||||
}
|
||||
[Test]
|
||||
public async Task CreateDocumentSalaryByPeriod_ShouldeSuccess_Test()
|
||||
{
|
||||
//Arrange
|
||||
var startDate = DateTime.UtcNow.AddDays(-20);
|
||||
var endDate = DateTime.UtcNow.AddDays(5);
|
||||
var worker1 = new WorkerDataModel(Guid.NewGuid().ToString(), "fio 1", Guid.NewGuid().ToString(), DateTime.UtcNow.AddYears(-20), DateTime.UtcNow.AddDays(-3));
|
||||
var worker2 = new WorkerDataModel(Guid.NewGuid().ToString(), "fio 2", Guid.NewGuid().ToString(), DateTime.UtcNow.AddYears(-20), DateTime.UtcNow.AddDays(-3));
|
||||
|
||||
_salaryStorageContract.Setup(x => x.GetListAsync(It.IsAny<DateTime>(), It.IsAny<DateTime>(),
|
||||
It.IsAny<CancellationToken>())).Returns(Task.FromResult(new List<SalaryDataModel>()
|
||||
{
|
||||
new(worker1.Id, DateTime.UtcNow.AddDays(-10), 100, worker1),
|
||||
new(worker1.Id, endDate, 1000, worker1),
|
||||
new(worker1.Id, startDate, 1000, worker1),
|
||||
new(worker2.Id, DateTime.UtcNow.AddDays(-10), 100, worker2),
|
||||
new(worker2.Id, DateTime.UtcNow.AddDays(-5), 200, worker2)
|
||||
}));
|
||||
|
||||
_basePdfBuilder.Setup(x => x.AddHeader(It.IsAny<string>())).Returns(_basePdfBuilder.Object);
|
||||
_basePdfBuilder.Setup(x => x.AddParagraph(It.IsAny<string>())).Returns(_basePdfBuilder.Object);
|
||||
var countRows = 0;
|
||||
(string, double) firstRow = default;
|
||||
(string, double) secondRow = default;
|
||||
_basePdfBuilder.Setup(x => x.AddPieChart(It.IsAny<string>(), It.IsAny<List<(string, double)>>())).Callback((string header, List<(string, double)> data) =>
|
||||
{
|
||||
countRows = data.Count;
|
||||
firstRow = data[0];
|
||||
secondRow = data[1];
|
||||
}).Returns(_basePdfBuilder.Object);
|
||||
|
||||
//Act
|
||||
var data = await _reportContract.CreateDocumentSalaryByPeriodAsync(DateTime.UtcNow.AddDays(-1), DateTime.UtcNow, CancellationToken.None);
|
||||
|
||||
//Assert
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(countRows, Is.EqualTo(2));
|
||||
Assert.That(firstRow, Is.Not.EqualTo(default));
|
||||
Assert.That(secondRow, Is.Not.EqualTo(default));
|
||||
});
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(firstRow.Item1, Is.EqualTo(worker1.FIO));
|
||||
Assert.That(firstRow.Item2, Is.EqualTo(2100));
|
||||
Assert.That(secondRow.Item1, Is.EqualTo(worker2.FIO));
|
||||
Assert.That(secondRow.Item2, Is.EqualTo(300));
|
||||
});
|
||||
|
||||
_salaryStorageContract.Verify(x => x.GetListAsync(It.IsAny<DateTime>(), It.IsAny<DateTime>(), It.IsAny<CancellationToken>()), Times.Once);
|
||||
_basePdfBuilder.Verify(x => x.AddHeader(It.IsAny<string>()), Times.Once);
|
||||
_basePdfBuilder.Verify(x => x.AddParagraph(It.IsAny<string>()), Times.Once);
|
||||
_basePdfBuilder.Verify(x => x.AddPieChart(It.IsAny<string>(), It.IsAny<List<(string, double)>>()), Times.Once);
|
||||
_basePdfBuilder.Verify(x => x.Build(), Times.Once);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,7 +113,35 @@ internal class SalaryStorageContractTests : BaseStorageContractTest
|
||||
Assert.That(list, Has.Count.EqualTo(2));
|
||||
Assert.That(list.All(x => x.WorkerId == _worker.Id));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Try_GetListAsync_ByPeriod_Test()
|
||||
{
|
||||
SmallSoftwareDbContext.InsertSalaryToDatabaseAndReturn(_worker.Id, salaryDate: DateTime.UtcNow.AddDays(-2));
|
||||
SmallSoftwareDbContext.InsertSalaryToDatabaseAndReturn(_worker.Id, salaryDate: DateTime.UtcNow.AddDays(-1).AddMinutes(-5));
|
||||
SmallSoftwareDbContext.InsertSalaryToDatabaseAndReturn(_worker.Id, salaryDate: DateTime.UtcNow.AddDays(-1).AddMinutes(5));
|
||||
SmallSoftwareDbContext.InsertSalaryToDatabaseAndReturn(_worker.Id, salaryDate: DateTime.UtcNow.AddDays(1).AddMinutes(-5));
|
||||
SmallSoftwareDbContext.InsertSalaryToDatabaseAndReturn(_worker.Id, salaryDate: DateTime.UtcNow.AddDays(1).AddMinutes(5));
|
||||
SmallSoftwareDbContext.InsertSalaryToDatabaseAndReturn(_worker.Id, salaryDate: DateTime.UtcNow.AddDays(-2));
|
||||
var list = await _salaryStorageContract.GetListAsync(DateTime.UtcNow.AddDays(-1),
|
||||
DateTime.UtcNow.AddDays(1), CancellationToken.None);
|
||||
Assert.That(list, Is.Not.Null);
|
||||
Assert.Multiple(() => {
|
||||
Assert.That(list, Has.Count.EqualTo(2));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Try_GetListAsync_WhenNoRecords_Test()
|
||||
{
|
||||
var list = await _salaryStorageContract.GetListAsync(DateTime.UtcNow.AddDays(-10),
|
||||
DateTime.UtcNow.AddDays(10), CancellationToken.None);
|
||||
Assert.That(list, Is.Not.Null);
|
||||
Assert.That(list, Is.Empty);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void Try_AddElement_Test()
|
||||
{
|
||||
|
||||
@@ -29,7 +29,6 @@ internal class ReportControllerTests : BaseWebApiControllerTest
|
||||
SmallSoftwareDbContext.InsertManufacturerToDatabaseAndReturn(manufacturer1.Id, manufacturerName: manufacturer1.ManufacturerName);
|
||||
SmallSoftwareDbContext.InsertManufacturerToDatabaseAndReturn(manufacturer2.Id, manufacturerName: manufacturer2.ManufacturerName);
|
||||
|
||||
|
||||
var software1 = new SoftwareDataModel(Guid.NewGuid().ToString(), "soft1", SoftwareType.AudioDriver, manufacturer1.Id, 10, false);
|
||||
var software2 = new SoftwareDataModel(Guid.NewGuid().ToString(), "soft2", SoftwareType.AudioDriver, manufacturer2.Id, 10, false);
|
||||
|
||||
@@ -94,25 +93,109 @@ internal class ReportControllerTests : BaseWebApiControllerTest
|
||||
Is.EqualTo(HttpStatusCode.BadRequest));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetSalary_WhenHaveRecords_ShouldSuccess_Test()
|
||||
{
|
||||
// Arrange
|
||||
var post = SmallSoftwareDbContext.InsertPostToDatabaseAndReturn();
|
||||
|
||||
var worker1 = SmallSoftwareDbContext.InsertWorkerToDatabaseAndReturn(fio: "fio 1", postId: post.PostId).AddPost(post);
|
||||
var worker2 = SmallSoftwareDbContext.InsertWorkerToDatabaseAndReturn(fio: "fio 2", postId: post.PostId).AddPost(post);
|
||||
|
||||
SmallSoftwareDbContext.InsertSalaryToDatabaseAndReturn(
|
||||
worker1.Id,
|
||||
workerSalary: 100,
|
||||
salaryDate: DateTime.UtcNow.AddDays(-10));
|
||||
|
||||
SmallSoftwareDbContext.InsertSalaryToDatabaseAndReturn(
|
||||
worker1.Id,
|
||||
workerSalary: 1000,
|
||||
salaryDate: DateTime.UtcNow.AddDays(-5));
|
||||
|
||||
SmallSoftwareDbContext.InsertSalaryToDatabaseAndReturn(
|
||||
worker1.Id,
|
||||
workerSalary: 200,
|
||||
salaryDate: DateTime.UtcNow.AddDays(5));
|
||||
|
||||
SmallSoftwareDbContext.InsertSalaryToDatabaseAndReturn(
|
||||
worker2.Id,
|
||||
workerSalary: 500,
|
||||
salaryDate: DateTime.UtcNow.AddDays(-5));
|
||||
|
||||
SmallSoftwareDbContext.InsertSalaryToDatabaseAndReturn(
|
||||
worker2.Id,
|
||||
workerSalary: 300,
|
||||
salaryDate: DateTime.UtcNow.AddDays(-3));
|
||||
|
||||
// Act
|
||||
var response = await HttpClient.GetAsync(
|
||||
$"/api/report/getsalary?" +
|
||||
$"fromDate={DateTime.UtcNow.AddDays(-7):MM/dd/yyyy HH:mm:ss}&" +
|
||||
$"toDate={DateTime.UtcNow.AddDays(-1):MM/dd/yyyy HH:mm:ss}");
|
||||
|
||||
// Assert
|
||||
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
|
||||
|
||||
var data = await GetModelFromResponseAsync<List<WorkerSalaryByPeriodViewModel>>(response);
|
||||
|
||||
Assert.That(data, Is.Not.Null);
|
||||
Assert.That(data, Has.Count.EqualTo(2));
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(
|
||||
data.First(x => x.WorkerFIO == worker1.FIO).TotalSalary,
|
||||
Is.EqualTo(1000));
|
||||
|
||||
Assert.That(
|
||||
data.First(x => x.WorkerFIO == worker2.FIO).TotalSalary,
|
||||
Is.EqualTo(800));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetSalary_WhenDateIsIncorrect_ShouldBadRequest_Test()
|
||||
{
|
||||
// Act
|
||||
var response = await HttpClient.GetAsync(
|
||||
$"/api/report/getsalary?" +
|
||||
$"fromDate={DateTime.UtcNow.AddDays(1):MM/dd/yyyy HH:mm:ss}&" +
|
||||
$"toDate={DateTime.UtcNow.AddDays(-1):MM/dd/yyyy HH:mm:ss}");
|
||||
|
||||
// Assert
|
||||
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task LoadSoftwares_WhenHaveRecords_ShouldSuccess_Test()
|
||||
{
|
||||
{
|
||||
//Arrange
|
||||
var manufacturer1 = SmallSoftwareDbContext.InsertManufacturerToDatabaseAndReturn(manufacturerName: "name 1");
|
||||
var manufacturer2 = SmallSoftwareDbContext.InsertManufacturerToDatabaseAndReturn(manufacturerName: "name 2");
|
||||
SmallSoftwareDbContext.InsertSoftwareToDatabaseAndReturn(manufacturer1.Id, softwareName: "name 1.1");
|
||||
SmallSoftwareDbContext.InsertSoftwareToDatabaseAndReturn(manufacturer1.Id, softwareName: "name 1.2");
|
||||
SmallSoftwareDbContext.InsertSoftwareToDatabaseAndReturn(manufacturer1.Id, softwareName: "name 1.3");
|
||||
SmallSoftwareDbContext.InsertSoftwareToDatabaseAndReturn(manufacturer2.Id, softwareName: "name 2.1");
|
||||
SmallSoftwareDbContext.InsertSoftwareToDatabaseAndReturn(manufacturer2.Id, softwareName: "name 2.2");
|
||||
var manufacturer1 = new ManufacturerDataModel(Guid.NewGuid().ToString(), "name1");
|
||||
var manufacturer2 = new ManufacturerDataModel(Guid.NewGuid().ToString(), "name2");
|
||||
SmallSoftwareDbContext.InsertManufacturerToDatabaseAndReturn(manufacturer1.Id, manufacturerName: manufacturer1.ManufacturerName);
|
||||
SmallSoftwareDbContext.InsertManufacturerToDatabaseAndReturn(manufacturer2.Id, manufacturerName: manufacturer2.ManufacturerName);
|
||||
|
||||
var softwareId1 = Guid.NewGuid().ToString();
|
||||
var softwareId2 = Guid.NewGuid().ToString();
|
||||
|
||||
var software1 = SmallSoftwareDbContext.InsertSoftwareToDatabaseAndReturn(manufacturer1.Id,softwareId1, "name1", SoftwareType.Windows, 10, false);
|
||||
var software2 = SmallSoftwareDbContext.InsertSoftwareToDatabaseAndReturn(manufacturer2.Id, softwareId2, "name2", SoftwareType.Windows, 10, false);
|
||||
|
||||
SmallSoftwareDbContext.InsertSoftwareHistoryToDatabaseAndReturn(softwareId1, 22, DateTime.UtcNow);
|
||||
SmallSoftwareDbContext.InsertSoftwareHistoryToDatabaseAndReturn(softwareId2, 21, DateTime.UtcNow);
|
||||
SmallSoftwareDbContext.InsertSoftwareHistoryToDatabaseAndReturn(softwareId1, 33, DateTime.UtcNow);
|
||||
SmallSoftwareDbContext.InsertSoftwareHistoryToDatabaseAndReturn(softwareId1, 32, DateTime.UtcNow);
|
||||
SmallSoftwareDbContext.InsertSoftwareHistoryToDatabaseAndReturn(softwareId2, 65, DateTime.UtcNow);
|
||||
|
||||
//Act
|
||||
var response = await HttpClient.GetAsync("/api/report/LoadSoftwares");
|
||||
|
||||
//Assert
|
||||
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
|
||||
using var data = await response.Content.ReadAsStreamAsync();
|
||||
Assert.That(data, Is.Not.Null);
|
||||
Assert.That(data.Length, Is.GreaterThan(0));
|
||||
await AssertStreamAsync(response, "file.docx");
|
||||
}
|
||||
[Test]
|
||||
public async Task LoadRequests_WhenHaveRecords_ShouldSuccess_Test()
|
||||
@@ -164,6 +247,68 @@ internal class ReportControllerTests : BaseWebApiControllerTest
|
||||
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task LoadSalary_WhenHaveRecords_ShouldSuccess_Test()
|
||||
{
|
||||
// Arrange
|
||||
var post = SmallSoftwareDbContext.InsertPostToDatabaseAndReturn();
|
||||
|
||||
var worker1 = SmallSoftwareDbContext.InsertWorkerToDatabaseAndReturn(
|
||||
fio: "fio 1",
|
||||
postId: post.PostId).AddPost(post);
|
||||
|
||||
var worker2 = SmallSoftwareDbContext.InsertWorkerToDatabaseAndReturn(
|
||||
fio: "fio 2",
|
||||
postId: post.PostId).AddPost(post);
|
||||
|
||||
SmallSoftwareDbContext.InsertSalaryToDatabaseAndReturn(
|
||||
worker1.Id,
|
||||
workerSalary: 100,
|
||||
salaryDate: DateTime.UtcNow.AddDays(-10));
|
||||
|
||||
SmallSoftwareDbContext.InsertSalaryToDatabaseAndReturn(
|
||||
worker1.Id,
|
||||
workerSalary: 1000,
|
||||
salaryDate: DateTime.UtcNow.AddDays(-5));
|
||||
|
||||
SmallSoftwareDbContext.InsertSalaryToDatabaseAndReturn(
|
||||
worker1.Id,
|
||||
workerSalary: 200,
|
||||
salaryDate: DateTime.UtcNow.AddDays(5));
|
||||
|
||||
SmallSoftwareDbContext.InsertSalaryToDatabaseAndReturn(
|
||||
worker2.Id,
|
||||
workerSalary: 500,
|
||||
salaryDate: DateTime.UtcNow.AddDays(-5));
|
||||
|
||||
SmallSoftwareDbContext.InsertSalaryToDatabaseAndReturn(
|
||||
worker2.Id,
|
||||
workerSalary: 300,
|
||||
salaryDate: DateTime.UtcNow.AddDays(-3));
|
||||
|
||||
// Act
|
||||
var response = await HttpClient.GetAsync(
|
||||
$"/api/report/loadsalary?" +
|
||||
$"fromDate={DateTime.UtcNow.AddDays(-7):MM/dd/yyyy HH:mm:ss}&" +
|
||||
$"toDate={DateTime.UtcNow.AddDays(-1):MM/dd/yyyy HH:mm:ss}");
|
||||
|
||||
// Assert
|
||||
await AssertStreamAsync(response, "file.pdf");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task LoadSalary_WhenDateIsIncorrect_ShouldBadRequest_Test()
|
||||
{
|
||||
// Act
|
||||
var response = await HttpClient.GetAsync(
|
||||
$"/api/report/loadsalary?" +
|
||||
$"fromDate={DateTime.UtcNow.AddDays(1):MM/dd/yyyy HH:mm:ss}&" +
|
||||
$"toDate={DateTime.UtcNow.AddDays(-1):MM/dd/yyyy HH:mm:ss}");
|
||||
|
||||
// Assert
|
||||
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
|
||||
}
|
||||
|
||||
private static async Task AssertStreamAsync(HttpResponseMessage response, string fileNameForSave = "")
|
||||
{
|
||||
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
|
||||
|
||||
@@ -23,6 +23,7 @@ public class ReportAdapter : IReportAdapter
|
||||
cfg.CreateMap<HistoryOfSoftwareDataModel, HistoryOfSoftwareViewModel>();
|
||||
cfg.CreateMap<RequestDataModel, RequestViewModel>();
|
||||
cfg.CreateMap<InstallationRequestDataModel, InstallationRequestViewModel>();
|
||||
cfg.CreateMap<WorkerSalaryByPeriodDataModel, WorkerSalaryByPeriodViewModel>();
|
||||
});
|
||||
_mapper = new Mapper(config);
|
||||
|
||||
@@ -146,4 +147,61 @@ public class ReportAdapter : IReportAdapter
|
||||
return ReportOperationResponse.OK(stream, fileName);
|
||||
}
|
||||
|
||||
public async Task<ReportOperationResponse> GetDataSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ReportOperationResponse.OK((await _reportContract.GetDataSalaryByPeriodAsync(dateStart, dateFinish, ct))
|
||||
.Select(x => _mapper.Map<WorkerSalaryByPeriodViewModel>(x)).ToList());
|
||||
}
|
||||
catch (IncorrectDatesException ex)
|
||||
{
|
||||
_logger.LogError(ex, "IncorrectDatesException");
|
||||
return ReportOperationResponse.BadRequest($"Incorrect dates: {ex.Message}");
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
_logger.LogError(ex, "InvalidOperationException");
|
||||
return ReportOperationResponse.InternalServerError($"Error while working with data storage: {ex.InnerException!.Message}");
|
||||
}
|
||||
catch (StorageException ex)
|
||||
{
|
||||
_logger.LogError(ex, "StorageException");
|
||||
return ReportOperationResponse.InternalServerError($"Error while working with data storage: {ex.InnerException!.Message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Exception");
|
||||
return
|
||||
ReportOperationResponse.InternalServerError(ex.Message);
|
||||
}
|
||||
}
|
||||
public async Task<ReportOperationResponse> CreateDocumentSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
return SendStream(await _reportContract.CreateDocumentSalaryByPeriodAsync(dateStart, dateFinish, ct), "salary.pdf");
|
||||
}
|
||||
catch (IncorrectDatesException ex)
|
||||
{
|
||||
_logger.LogError(ex, "IncorrectDatesException");
|
||||
return ReportOperationResponse.BadRequest($"Incorrect dates: {ex.Message} ");
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
_logger.LogError(ex, "InvalidOperationException");
|
||||
return ReportOperationResponse.InternalServerError($"Error while working with data storage: {ex.InnerException!.Message}");
|
||||
}
|
||||
catch (StorageException ex)
|
||||
{
|
||||
_logger.LogError(ex, "StorageException");
|
||||
return ReportOperationResponse.InternalServerError($"Error while working with data storage: {ex.InnerException!.Message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Exception");
|
||||
return
|
||||
ReportOperationResponse.InternalServerError(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,11 +36,25 @@ public class ReportController(IReportAdapter adapter) : ControllerBase
|
||||
|
||||
[HttpGet]
|
||||
[Consumes("application/octet-stream")]
|
||||
public async Task<IActionResult> LoadRequests(DateTime fromDate, DateTime
|
||||
toDate, CancellationToken cancellationToken)
|
||||
public async Task<IActionResult> LoadRequests(DateTime fromDate, DateTime toDate, CancellationToken cancellationToken)
|
||||
{
|
||||
return (await _adapter.CreateDocumentRequestsByPeriodAsync(fromDate,
|
||||
toDate, cancellationToken)).GetResponse(Request, Response);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Consumes("application/json")]
|
||||
public async Task<IActionResult> GetSalary(DateTime fromDate, DateTime toDate, CancellationToken cancellationToken)
|
||||
{
|
||||
return (await _adapter.GetDataSalaryByPeriodAsync(fromDate, toDate,
|
||||
cancellationToken)).GetResponse(Request, Response);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Consumes("application/octet-stream")]
|
||||
public async Task<IActionResult> LoadSalary(DateTime fromDate, DateTime toDate, CancellationToken cancellationToken)
|
||||
{
|
||||
return (await _adapter.CreateDocumentSalaryByPeriodAsync(fromDate, toDate, cancellationToken)).GetResponse(Request, Response);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -78,6 +78,7 @@ builder.Services.AddTransient<IReportContract, ReportContract>();
|
||||
builder.Services.AddTransient<IReportAdapter, ReportAdapter>();
|
||||
builder.Services.AddTransient<BaseWordBuilder, OpenXmlWordBuilder>();
|
||||
builder.Services.AddTransient<BaseExcelBuilder, OpenXmlExcelBuilder>();
|
||||
builder.Services.AddTransient<BasePdfBuilder, MigraDocPdfBuilder>();
|
||||
|
||||
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
|
||||
builder.Services.AddOpenApi();
|
||||
|
||||
Reference in New Issue
Block a user