From 1bda2d5b770e8824f1ea9fa0be1349689bafd92a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Tue, 14 Nov 2023 11:01:34 +0500 Subject: [PATCH] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81=20=D1=81=D0=B5=D1=80?= =?UTF-8?q?=D0=B2=D0=B8=D1=81=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Устранение багов выявленных при тестировании 2. Изменение имён методов в сервисе суточных отчётов 3. Фикс получения фиктивных суточных отчётов 4. Фикс шаблона 5. Правки в контроллере 6. Фикс в репозитории. Приведение к utc доа выполнения запроса 7. Покрытие сервиса тестами --- .../DailyReport/IDailyReportService.cs | 31 +- .../Repository/DailyReportRepository.cs | 10 +- .../DailyReport/DailyReportExportService.cs | 24 +- .../DailyReport/DailyReportService.cs | 136 +++-- .../DailyReport/DailyReportTemplate.xlsx | Bin 15683 -> 15704 bytes .../Services/DailyReportServiceTest.cs | 532 ++++++++++++++---- .../Controllers/DailyReportController.cs | 75 +-- 7 files changed, 542 insertions(+), 266 deletions(-) diff --git a/AsbCloudApp/Services/DailyReport/IDailyReportService.cs b/AsbCloudApp/Services/DailyReport/IDailyReportService.cs index c07a5c06..44283a44 100644 --- a/AsbCloudApp/Services/DailyReport/IDailyReportService.cs +++ b/AsbCloudApp/Services/DailyReport/IDailyReportService.cs @@ -3,42 +3,36 @@ using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data; using AsbCloudApp.Data.DailyReport; -using AsbCloudApp.Data.DailyReport.Blocks; using AsbCloudApp.Requests; namespace AsbCloudApp.Services.DailyReport; +/// +/// Суточные отчёты +/// public interface IDailyReportService { /// - /// Создать отчёт + /// Обновить или создать суточный отчёт /// - /// - /// - /// - /// - Task InsertAsync(int idWell, DateTime dateStart, CancellationToken cancellationToken); - - /// - /// Обновить блок - /// - /// + /// /// /// /// - /// + /// /// - Task UpdateBlockAsync(int idDailyReport, int idUser, TBlock editableBlock, CancellationToken cancellationToken) - where TBlock : EditableBlock; + Task UpdateOrInsertAsync(int idWell, DateTime dateDailyReport, int idUser, TBlock editableBlock, + CancellationToken cancellationToken) + where TBlock : ItemInfoDto; /// /// Получить сформированный суточный отчёт /// /// - /// + /// /// /// - Task GetAsync(int idWell, DateTime dateStart, CancellationToken cancellationToken); + Task GetAsync(int idWell, DateTime dateDailyReport, CancellationToken cancellationToken); /// /// Получить список суточных отчётов по скважине @@ -47,8 +41,7 @@ public interface IDailyReportService /// /// /// - Task> GetAsync(int idWell, FileReportRequest request, - CancellationToken cancellationToken); + Task> GetAsync(int idWell, FileReportRequest request, CancellationToken cancellationToken); /// /// Получить диапазон дат по которым возможно сформировать суточный отчёты diff --git a/AsbCloudInfrastructure/Repository/DailyReportRepository.cs b/AsbCloudInfrastructure/Repository/DailyReportRepository.cs index 147cae3e..add98668 100644 --- a/AsbCloudInfrastructure/Repository/DailyReportRepository.cs +++ b/AsbCloudInfrastructure/Repository/DailyReportRepository.cs @@ -32,10 +32,16 @@ public class DailyReportRepository : CrudRepositoryBase d.IdWell == idWell); if (request.GeDate.HasValue) - query = query.Where(d => d.Date >= request.GeDate.Value.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc)); + { + var geDate = request.GeDate.Value.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc); + query = query.Where(d => d.Date >= geDate); + } if (request.LeDate.HasValue) - query = query.Where(d => d.Date <= request.LeDate.Value.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc)); + { + var leDate = request.LeDate.Value.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc); + query = query.Where(d => d.Date <= leDate); + } if (request.SortFields?.Any() == true) { diff --git a/AsbCloudInfrastructure/Services/DailyReport/DailyReportExportService.cs b/AsbCloudInfrastructure/Services/DailyReport/DailyReportExportService.cs index 6fbc0c12..53bb24f3 100644 --- a/AsbCloudInfrastructure/Services/DailyReport/DailyReportExportService.cs +++ b/AsbCloudInfrastructure/Services/DailyReport/DailyReportExportService.cs @@ -28,7 +28,7 @@ public class DailyReportExportService : IDailyReportExportService private const int columnTimeBalanceDurationFact = 4; private const int columnTimeBalanceReasonDeviation = 8; private const int columnTimeBalanceDrillingDeviationPerSection = 10; - private const int columnTimeBalanceDrillingDeviationPerDaily = 11; + private const int columnTimeBalanceDrillingDeviationPerDay = 11; private const int columnSheduleDriller = 3; private const int columnSheduleShiftStart = 7; @@ -56,10 +56,9 @@ public class DailyReportExportService : IDailyReportExportService private const string cellContractor = "C3"; private const string cellDeposit = "C5"; private const string cellCluster = "C6"; - private const string cellWellName = "C7"; + private const string cellWellCaption = "C7"; private const string cellWellType = "C8"; - private const string cellDateStart = "C12"; - private const string cellDateEnd = "D12"; + private const string cellDate = "C12"; private const string cellDepthStart = "C13"; private const string cellDepthEnd = "D13"; @@ -95,7 +94,7 @@ public class DailyReportExportService : IDailyReportExportService var stream = await GenerateFileAsync(dailyReport, cancellationToken); - var fileName = $"Суточный_рапорт_по_скважине_{dailyReport.WellName}_куст_{dailyReport.Cluster}_от_{dailyReport.DateStart:yy-MM-dd}.xlsx"; + var fileName = $"Суточный_рапорт_по_скважине_{dailyReport.WellCaption}_куст_{dailyReport.Cluster}_от_{dailyReport.Date:yy-MM-dd}.xlsx"; return (fileName, stream); } @@ -127,10 +126,9 @@ public class DailyReportExportService : IDailyReportExportService sheet.Cell(cellContractor).Value = dailyReport.Contractor; sheet.Cell(cellDeposit).Value = dailyReport.Deposit; sheet.Cell(cellCluster).Value = dailyReport.Cluster; - sheet.Cell(cellWellName).Value = dailyReport.WellName; + sheet.Cell(cellWellCaption).Value = dailyReport.WellCaption; sheet.Cell(cellWellType).Value = dailyReport.WellType; - sheet.Cell(cellDateStart).Value = dailyReport.DateStart; - sheet.Cell(cellDateEnd).Value = dailyReport.DateEnd; + sheet.Cell(cellDate).Value = dailyReport.Date; sheet.Cell(cellDepthStart).Value = dailyReport.DepthStart; sheet.Cell(cellDepthEnd).Value = dailyReport.DepthEnd; @@ -163,18 +161,18 @@ public class DailyReportExportService : IDailyReportExportService foreach (var wellOperation in timeBalanceBlock.WellOperations.OrderBy(w => w.IdWellOperation)) { - sheet.Cell(rowCurrent, columnTimeBalanceDurationPlan).Value = wellOperation.DurationHours?.Plan; - sheet.Cell(rowCurrent, columnTimeBalanceDurationFact).Value = wellOperation.DurationHours?.Fact; + sheet.Cell(rowCurrent, columnTimeBalanceDurationPlan).Value = wellOperation.DurationHours.Plan; + sheet.Cell(rowCurrent, columnTimeBalanceDurationFact).Value = wellOperation.DurationHours.Fact; sheet.Cell(rowCurrent, columnTimeBalanceReasonDeviation).Value = wellOperation.ReasonDeviation; sheet.Cell(rowCurrent, columnTimeBalanceDrillingDeviationPerSection).Value = wellOperation.DrillingDeviationPerSection; - sheet.Cell(rowCurrent, columnTimeBalanceDrillingDeviationPerDaily).Value = wellOperation.DrillingDeviationPerDaily; + sheet.Cell(rowCurrent, columnTimeBalanceDrillingDeviationPerDay).Value = wellOperation.DrillingDeviationPerDay; rowCurrent++; } sheet.Cell(cellTimeBalanceBlockSection).Value = timeBalanceBlock.SectionName; - sheet.Cell(cellTimeBalanceBlockWellDepthPlan).Value = timeBalanceBlock.WellDepthPlan; - sheet.Cell(cellTimeBalanceBlockWellDepthFact).Value = timeBalanceBlock.WellDepthFact; + sheet.Cell(cellTimeBalanceBlockWellDepthPlan).Value = timeBalanceBlock.WellDepth.Plan; + sheet.Cell(cellTimeBalanceBlockWellDepthFact).Value = timeBalanceBlock.WellDepth.Fact; sheet.Cell(cellTimeBalanceBlockWellOperationSlipsTimeCount).Value = timeBalanceBlock.WellOperationSlipsTimeCount; } diff --git a/AsbCloudInfrastructure/Services/DailyReport/DailyReportService.cs b/AsbCloudInfrastructure/Services/DailyReport/DailyReportService.cs index 95d42411..97cc4e85 100644 --- a/AsbCloudInfrastructure/Services/DailyReport/DailyReportService.cs +++ b/AsbCloudInfrastructure/Services/DailyReport/DailyReportService.cs @@ -52,31 +52,16 @@ public class DailyReportService : IDailyReportService this.detectedOperationService = detectedOperationService; } - public async Task InsertAsync(int idWell, DateTime dateStart, CancellationToken cancellationToken) - { - if (await dailyReportRepository.AnyAsync(idWell, dateStart, cancellationToken)) - throw new ArgumentInvalidException(nameof(dateStart), "Суточный отчёт уже существует"); - - var dailyReport = new DailyReportDto - { - IdWell = idWell, - DateStart = dateStart, - }; - - return await dailyReportRepository.InsertAsync(dailyReport, cancellationToken); - } - - public async Task UpdateBlockAsync(int idDailyReport, int idUser, TBlock editableBlock, + public async Task UpdateOrInsertAsync(int idWell, DateTime dateDailyReport, int idUser, TBlock editableBlock, CancellationToken cancellationToken) - where TBlock : EditableBlock + where TBlock : ItemInfoDto { - var dailyReport = await dailyReportRepository.GetOrDefaultAsync(idDailyReport, cancellationToken) - ?? throw new ArgumentInvalidException(nameof(idDailyReport), $"Суточный отчёт с Id: {idDailyReport} не найден"); - - editableBlock.IdUser = idUser; - - editableBlock.DateLastUpdate = DateTime.UtcNow; - dailyReport.DateLastUpdate = DateTime.UtcNow; + var dailyReport = await dailyReportRepository.GetOrDefaultAsync(idWell, dateDailyReport, cancellationToken) ?? + new DailyReportDto + { + IdWell = idWell, + Date = dateDailyReport + }; switch (editableBlock) { @@ -89,39 +74,46 @@ public class DailyReportService : IDailyReportService case SignBlockDto signBlock: dailyReport.SignBlock = signBlock; break; + default: + throw new InvalidOperationException("Unexpected type of editableBlock"); } + editableBlock.IdUser = idUser; + editableBlock.LastUpdateDate = DateTime.UtcNow; + + dailyReport.DateLastUpdate = DateTime.UtcNow; + + if (dailyReport.Id == 0) + return await dailyReportRepository.InsertAsync(dailyReport, cancellationToken); + return await dailyReportRepository.UpdateAsync(dailyReport, cancellationToken); } - public async Task GetAsync(int idWell, DateTime dateStart, CancellationToken cancellationToken) + public async Task GetAsync(int idWell, DateTime dateDailyReport, CancellationToken cancellationToken) { var well = await wellService.GetOrDefaultAsync(idWell, cancellationToken); if (well is null) throw new ArgumentInvalidException($"Скважина с Id: {idWell} не найдена", nameof(idWell)); - var dailyReport = await dailyReportRepository.GetOrDefaultAsync(idWell, dateStart, cancellationToken) ?? new DailyReportDto + var dailyReport = await dailyReportRepository.GetOrDefaultAsync(idWell, dateDailyReport, cancellationToken) ?? new DailyReportDto { - DateStart = dateStart.Date, + Date = dateDailyReport.Date, IdWell = well.Id }; - var factWellOperations = await GetFactWellOperationsAsync(idWell, dailyReport.DateStart, dailyReport.DateEnd, - cancellationToken); + var factWellOperations = (await GetFactWellOperationsAsync(idWell, dailyReport.Date, cancellationToken)) + .OrderBy(o => o.DateStart) + .ThenBy(o => o.DepthStart); - dailyReport.WellName = well.Caption; + dailyReport.WellCaption = well.Caption; dailyReport.WellType = well.WellType; dailyReport.Cluster = well.Cluster; dailyReport.Deposit = well.Deposit; dailyReport.Customer = well.Companies.FirstOrDefault(c => c.IdCompanyType == 1)?.Caption; dailyReport.Contractor = well.Companies.FirstOrDefault(c => c.IdCompanyType == 2)?.Caption; - - if (factWellOperations.Any()) - { - dailyReport.DepthStart = factWellOperations.Min(o => o.DepthStart); - dailyReport.DepthEnd = factWellOperations.Max(o => o.DepthEnd); - } + dailyReport.DepthStart = factWellOperations.FirstOrDefault()?.DepthStart; + dailyReport.DepthEnd = factWellOperations.LastOrDefault()?.DepthEnd; await UpdateTimeBalanceBlockAsync(dailyReport, factWellOperations, cancellationToken); await UpdateSubsystemBlockAsync(dailyReport, cancellationToken); @@ -184,18 +176,18 @@ public class DailyReportService : IDailyReportService { for (var day = result.Skip; day - result.Skip < result.Take && datesRange.To.AddDays(-day) >= datesRange.From; day++) { - var dateStart = datesRange.To.AddDays(-day); + var dateDailyReport = datesRange.To.AddDays(-day).Date; - AddDailyReport(dateStart); + AddDailyReport(dateDailyReport); } } else { for (var day = result.Skip; day - result.Skip < result.Take && datesRange.From.AddDays(day) <= datesRange.To; day++) { - var dateStart = datesRange.From.AddDays(day); + var dateDailyReport = datesRange.From.AddDays(day).Date; - AddDailyReport(dateStart); + AddDailyReport(dateDailyReport); } } @@ -203,10 +195,9 @@ public class DailyReportService : IDailyReportService return result; - void AddDailyReport(DateTime dateStart) + void AddDailyReport(DateTime date) { - var existingDailyReport = existingDailyReports.FirstOrDefault(d => d.IdWell == idWell && - d.DateStart == dateStart); + var existingDailyReport = existingDailyReports.FirstOrDefault(d => d.IdWell == idWell && d.Date == date); if (existingDailyReport is not null) { @@ -216,7 +207,7 @@ public class DailyReportService : IDailyReportService dailyReports.Add(new DailyReportDto { - DateStart = dateStart, + Date = date, IdWell = well.Id }); } @@ -224,16 +215,18 @@ public class DailyReportService : IDailyReportService public async Task GetDatesRangeAsync(int idWell, CancellationToken cancellationToken) { - var factOperations = await GetFactWellOperationsAsync(idWell, null, null, - cancellationToken); + var factOperations = await GetFactWellOperationsAsync(idWell, null, cancellationToken); if (!factOperations.Any()) return null; + var minDateStart = factOperations.Min(o => o.DateStart); + var maxDateStart = factOperations.Max(o => o.DateStart); + return new DatesRangeDto { - From = factOperations.Min(o => o.DateStart).Date, - To = factOperations.Max(o => o.DateStart).Date + From = minDateStart.Date.AddDays(1) <= DateTime.UtcNow ? minDateStart : DateTime.UtcNow.Date.AddDays(-1), + To = maxDateStart.AddDays(1) <= DateTime.UtcNow ? maxDateStart : DateTime.UtcNow.Date.AddDays(-1) }; } @@ -241,24 +234,24 @@ public class DailyReportService : IDailyReportService CancellationToken cancellationToken) { const int idWellOperationSlipsTime = 5011; - + if (dailyReport.TimeBalanceBlock is not null) { dailyReport.TimeBalanceBlock.SectionName = wellOperationRepository.GetSectionTypes() .FirstOrDefault(s => s.Id == dailyReport.TimeBalanceBlock.IdSection)?.Caption; - + dailyReport.TimeBalanceBlock.WellOperationSlipsTimeCount = (await detectedOperationService.GetAsync( new DetectedOperationRequest { IdsCategories = new[] { idWellOperationSlipsTime }, IdWell = dailyReport.IdWell, - GtDate = dailyReport.DateStart, - LtDate = dailyReport.DateEnd + GtDate = dailyReport.Date, + LtDate = dailyReport.Date.AddHours(24) }, cancellationToken))?.Stats.Sum(s => s.Count); - dailyReport.TimeBalanceBlock.WellDepthFact = factWellOperations + dailyReport.TimeBalanceBlock.WellDepth.Fact = factWellOperations .Where(o => o.IdWellSectionType == dailyReport.TimeBalanceBlock.IdSection) - .Sum(o => o.DepthEnd = o.DepthStart); + .Sum(o => o.DepthEnd - o.DepthStart); } } @@ -267,9 +260,9 @@ public class DailyReportService : IDailyReportService var trajectory = (await trajectoryFactRepository.GetAsync(new TrajectoryGeoFactRequest { IdWell = dailyReport.IdWell, - GeDate = dailyReport.DateStart, - LeDate = dailyReport.DateEnd - }, cancellationToken)).LastOrDefault(); + GeDate = dailyReport.Date, + LeDate = dailyReport.Date.AddHours(24) + }, cancellationToken)).MaxBy(t => t.WellboreDepth); dailyReport.TrajectoryBlock = new TrajectoryBlockDto { @@ -281,7 +274,7 @@ public class DailyReportService : IDailyReportService } private async Task AddScheduleBlockAsync(DailyReportDto dailyReport, CancellationToken cancellationToken) => - dailyReport.ScheduleBlock = (await scheduleRepository.GetAsync(dailyReport.IdWell, dailyReport.DateStart, cancellationToken)) + dailyReport.ScheduleBlock = (await scheduleRepository.GetAsync(dailyReport.IdWell, dailyReport.Date, cancellationToken)) .Select(s => new ScheduleRecordDto { ShiftStart = s.ShiftStart, @@ -299,13 +292,13 @@ public class DailyReportService : IDailyReportService async Task> GetSubsystemsAsync() { - var modules = new List(); + var subsystems = new List(); - var statSubsystemOperationTimePerDaily = (await subsystemOperationTimeService.GetStatAsync(new SubsystemOperationTimeRequest + var statSubsystemOperationTimePerDay = (await subsystemOperationTimeService.GetStatAsync(new SubsystemOperationTimeRequest { IdWell = dailyReport.IdWell, - GtDate = dailyReport.DateStart, - LtDate = dailyReport.DateEnd + GtDate = dailyReport.Date, + LtDate = dailyReport.Date.AddHours(24) }, cancellationToken)).Select(s => { var subsystemRecord = s.Adapt(); @@ -325,21 +318,21 @@ public class DailyReportService : IDailyReportService return subsystemRecord; }); - modules.AddRange(statSubsystemOperationTimePerDaily); - modules.AddRange(statSubsystemOperationTimePerWell); + subsystems.AddRange(statSubsystemOperationTimePerDay); + subsystems.AddRange(statSubsystemOperationTimePerWell); if (dailyReport.SubsystemBlock?.Subsystems != null && dailyReport.SubsystemBlock.Subsystems.Any()) - modules.AddRange(dailyReport.SubsystemBlock.Subsystems); + subsystems.AddRange(dailyReport.SubsystemBlock.Subsystems); - return modules; + return subsystems.OrderBy(s => s.SubsystemName); } } private async Task AddProcessMapWellDrillingBlockAsync(DailyReportDto dailyReport, CancellationToken cancellationToken) { dailyReport.ProcessMapWellDrillingBlock = (await processMapReportWellDrillingService.GetAsync(dailyReport.IdWell, - cancellationToken)).Where(p => p.DateStart >= dailyReport.DateStart && - p.DateStart <= dailyReport.DateEnd) + cancellationToken)).Where(p => p.DateStart >= dailyReport.Date && + p.DateStart <= dailyReport.Date.AddHours(24)) .GroupBy(p => p.DrillingMode) .Select(g => new ProcessMapWellDrillingRecordDto { @@ -354,7 +347,7 @@ public class DailyReportService : IDailyReportService }); } - private void AddFactWellOperationBlock(DailyReportDto dailyReport, IEnumerable factWellOperations) + private static void AddFactWellOperationBlock(DailyReportDto dailyReport, IEnumerable factWellOperations) { const int idWellOperationCategoryDrilling = 4001; @@ -373,13 +366,12 @@ public class DailyReportService : IDailyReportService }; } - private Task> GetFactWellOperationsAsync(int idWell, DateTime? dailyReportDateStart, - DateTime? dailyReportDateEnd, CancellationToken cancellationToken) => + private Task> GetFactWellOperationsAsync(int idWell, DateTime? dateDailyReport, CancellationToken cancellationToken) => wellOperationRepository.GetAsync(new WellOperationRequest { IdWell = idWell, OperationType = WellOperation.IdOperationTypeFact, - GeDate = dailyReportDateStart, - LtDate = dailyReportDateEnd + GeDate = dateDailyReport, + LtDate = dateDailyReport?.AddHours(24) }, cancellationToken); } \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/DailyReport/DailyReportTemplate.xlsx b/AsbCloudInfrastructure/Services/DailyReport/DailyReportTemplate.xlsx index 6bf8da35adb1125099d0724f4be9c53c964186ef..7594507cd457c29274987a0f59022078215bb26e 100644 GIT binary patch delta 5555 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 delta 5514 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 diff --git a/AsbCloudWebApi.Tests/Services/DailyReportServiceTest.cs b/AsbCloudWebApi.Tests/Services/DailyReportServiceTest.cs index 7e7046a8..a8447fa2 100644 --- a/AsbCloudWebApi.Tests/Services/DailyReportServiceTest.cs +++ b/AsbCloudWebApi.Tests/Services/DailyReportServiceTest.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data; @@ -6,11 +8,15 @@ using AsbCloudApp.Data.DailyReport; using AsbCloudApp.Data.DailyReport.Blocks.Sign; using AsbCloudApp.Data.DailyReport.Blocks.Subsystems; using AsbCloudApp.Data.DailyReport.Blocks.TimeBalance; -using AsbCloudApp.Exceptions; +using AsbCloudApp.Data.DetectedOperation; +using AsbCloudApp.Data.ProcessMaps.Report; +using AsbCloudApp.Data.Subsystems; using AsbCloudApp.Repositories; +using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudApp.Services.ProcessMaps.WellDrilling; using AsbCloudApp.Services.Subsystems; +using AsbCloudDb.Model; using AsbCloudInfrastructure.Services.DailyReport; using NSubstitute; using Xunit; @@ -20,10 +26,169 @@ namespace AsbCloudWebApi.Tests.Services; public class DailyReportServiceTest { private const int idDailyReport = 1; - private const int idWell = 2; private const int idUser = 3; + private const int idWell = 2; - private readonly DateTime dateStart = new DateOnly(2023, 10, 26).ToDateTime(TimeOnly.MinValue); + private readonly DateTime dateDailyReport = new DateOnly(2023, 10, 26).ToDateTime(TimeOnly.MinValue); + + private readonly SubsystemBlockDto fakeSubsystemBlock = new() + { + IdUser = idUser, + WellBore = 999, + MeasurementsPerDay = 999, + TotalRopPlan = 999, + Comment = "Увеличить обороты", + Subsystems = new[] + { + new SubsystemRecordDto + { + SubsystemName = "АвтоСПО", + IdTimeInterval = 2, + UsedTimeHours = 24, + SumDepthInterval = 1500, + KUsage = 100 + } + } + }; + + private readonly SignBlockDto fakeSignBlock = new() + { + IdUser = idUser, + DrillingMaster = new SignRecordDto + { + Name = "Иван", + Patronymic = "Иванович", + Surname = "Иванов" + }, + Supervisor = new SignRecordDto() + { + Name = "Илья", + Patronymic = "Ильич", + Surname = "Бурилов" + } + }; + + private readonly TimeBalanceBlockDto fakeTimeBalanceBlock = new() + { + IdUser = idUser, + IdSection = 1, + WellDepth = new PlanFactDto + { + Plan = 2000 + }, + WellOperations = new[] + { + new TimeBalanceRecordDto + { + IdWellOperation = 1, + DurationHours = new PlanFactDto + { + Fact = 100, + Plan = 150, + }, + DrillingDeviationPerSection = 90, + DrillingDeviationPerDay = 100, + ReasonDeviation = "Отклонение" + } + } + }; + + private readonly DetectedOperationListDto fakeWellOperationSlipsTime = new() + { + Stats = new[] + { + new DetectedOperationDrillersStatDto + { + Count = 40 + } + } + }; + + private readonly ProcessMapReportWellDrillingDto fakeProcessMapReportWellDrilling = new() + { + DrillingMode = "Ротор", + DateStart = new DateTime(2023, 10, 26), + DeltaDepth = 500, + Rop = new PlanFactDto + { + Plan = 300, + Fact = 500 + }, + MechDrillingHours = 100 + }; + + private readonly WellSectionTypeDto fakeSectionType = new() + { + Id = 1, + Caption = "Пилотный ствол", + }; + + private readonly TrajectoryGeoFactDto fakeLastFactTrajectory = new() + { + WellboreDepth = 100, + VerticalDepth = 150, + ZenithAngle = 3, + AzimuthGeo = 5 + }; + + private readonly CompanyDto fakeCustomer = new() + { + Caption = "Тестовый заказчик", + IdCompanyType = 1 + }; + + private readonly CompanyDto fakeContractor = new() + { + Caption = "Тестовый подрядчик", + IdCompanyType = 2 + }; + + private readonly WellOperationDto fakeFirstFactWellOperation = new() + { + IdWell = idWell, + IdParentCategory = 4001, + IdWellSectionType = 1, + CategoryName = "Механическое. бурение", + DateStart = new DateTime(2023, 10, 26), + DepthStart = 80, + DepthEnd = 150, + DurationHours = 8, + }; + + private readonly WellOperationDto fakeLastFactWellOperation = new() + { + IdWell = idWell, + CategoryName = "Механическое. бурение", + IdWellSectionType = 1, + IdParentCategory = 4001, + DateStart = new DateTime(2023, 10, 26), + DepthStart = 150, + DepthEnd = 200, + DurationHours = 8, + }; + + private readonly ScheduleDto fakeShedule = new() + { + IdWell = idWell, + ShiftStart = new TimeDto(1), + ShiftEnd = new TimeDto(5), + DrillStart = new DateTime(2023, 01, 26), + DrillEnd = new DateTime(2023, 12, 26), + Driller = new() + { + Name = "Иван", + Surname = "Иванов", + Patronymic = "Бурила" + } + }; + + private readonly SubsystemStatDto fakeStatSubsystemOperationTimePerDay = new() + { + SubsystemName = "АПД", + SumDepthInterval = 250, + UsedTimeHours = 200, + KUsage = 30 + }; private readonly IWellService wellServiceMock = Substitute.For(); private readonly ITrajectoryFactRepository trajectoryFactRepositoryMock = Substitute.For(); @@ -33,18 +198,30 @@ public class DailyReportServiceTest private readonly ISubsystemOperationTimeService subsystemOperationTimeServiceMock = Substitute.For(); private readonly IProcessMapReportWellDrillingService processMapReportWellDrillingServiceMock = Substitute.For(); private readonly IDetectedOperationService detectedOperationServiceMock = Substitute.For(); - + private readonly DailyReportService dailyReportService; private readonly DailyReportDto fakeDailyReport; + private readonly WellDto fakeWell; public DailyReportServiceTest() { - fakeDailyReport = new() + fakeDailyReport = new DailyReportDto { Id = idDailyReport, IdWell = idWell, - DateStart = dateStart + Date = dateDailyReport, + DateLastUpdate = null + }; + + fakeWell = new WellDto + { + Id = idWell, + Caption = "Тестовое название", + WellType = "Горизонтальная", + Cluster = "Тестовый куст", + Deposit = "Тестовое месторождение", + Companies = new[] { fakeCustomer, fakeContractor } }; dailyReportService = new DailyReportService(wellServiceMock, @@ -59,139 +236,276 @@ public class DailyReportServiceTest dailyReportRepositoryMock.InsertAsync(Arg.Any(), Arg.Any()) .ReturnsForAnyArgs(idDailyReport); - dailyReportRepositoryMock.GetOrDefaultAsync(idDailyReport, Arg.Any()) - .Returns(fakeDailyReport); + dailyReportRepositoryMock.GetOrDefaultAsync(Arg.Any(), Arg.Any(), Arg.Any()) + .ReturnsForAnyArgs(fakeDailyReport); dailyReportRepositoryMock.UpdateAsync(Arg.Any(), Arg.Any()) .ReturnsForAnyArgs(idDailyReport); + + wellServiceMock.GetOrDefaultAsync(Arg.Any(), Arg.Any()) + .ReturnsForAnyArgs(fakeWell); + + trajectoryFactRepositoryMock.GetAsync(Arg.Any(), Arg.Any()) + .ReturnsForAnyArgs(new[] { fakeLastFactTrajectory }); + + wellOperationRepositoryMock.GetAsync(Arg.Any(), Arg.Any()) + .ReturnsForAnyArgs(new[] { fakeFirstFactWellOperation, fakeLastFactWellOperation }); + + wellOperationRepositoryMock.GetSectionTypes() + .ReturnsForAnyArgs(new[] { fakeSectionType }); + + detectedOperationServiceMock.GetAsync(Arg.Any(), Arg.Any()) + .ReturnsForAnyArgs(fakeWellOperationSlipsTime); + + subsystemOperationTimeServiceMock.GetStatAsync(Arg.Any(), Arg.Any()) + .ReturnsForAnyArgs(new[] { fakeStatSubsystemOperationTimePerDay }); + + scheduleRepositoryMock.GetAsync(idWell, dateDailyReport, Arg.Any()) + .ReturnsForAnyArgs(new[] { fakeShedule }); + + processMapReportWellDrillingServiceMock.GetAsync(idWell, Arg.Any()) + .ReturnsForAnyArgs(new[] { fakeProcessMapReportWellDrilling }); } [Fact] - public async Task InsertAsync_ShouldReturn_ExceptionAboutDuplicate() + public async Task UpdateOrInsertAsync_ShouldReturn_UpdatedSubsystemBlock() { - //arrange - dailyReportRepositoryMock.AnyAsync(Arg.Any(), Arg.Any(), Arg.Any()) - .ReturnsForAnyArgs(true); - //act - Task Result() => dailyReportService.InsertAsync(idWell, dateStart, CancellationToken.None); - - //assert - var exception = await Assert.ThrowsAsync(Result); - Assert.Equal("Суточный отчёт уже существует", exception.Message); - } - - [Fact] - public async Task InsertAsync_ShouldReturn_PositiveId() - { - //arrange - dailyReportRepositoryMock.AnyAsync(Arg.Any(), Arg.Any(), Arg.Any()) - .ReturnsForAnyArgs(false); - - //act - var result = await dailyReportService.InsertAsync(idWell, dateStart, CancellationToken.None); + var result = await dailyReportService.UpdateOrInsertAsync(idWell, dateDailyReport, idUser, fakeSubsystemBlock, CancellationToken.None); //assert + Assert.NotNull(fakeSubsystemBlock.LastUpdateDate); + Assert.NotNull(fakeDailyReport.DateLastUpdate); + Assert.Equal(fakeSubsystemBlock.IdUser, idUser); + Assert.Equal(fakeDailyReport.SubsystemBlock, fakeSubsystemBlock); Assert.Equal(idDailyReport, result); } [Fact] - public async Task UpdateSubsystemBlock_ShouldReturn_Success() + public async Task UpdateOrInsertAsync_ShouldReturn_UpdatedSignBlock() { - //arrange - var fakeSubsystemBlock = new SubsystemBlockDto - { - IdUser = idUser, - WellBore = 999, - MeasurementsPerDay = 999, - TotalRopPlan = 999, - Comment = "Увеличить обороты", - Subsystems = new[] - { - new SubsystemRecordDto - { - SubsystemName = "АвтоСПО", - IdTimeInterval = 1, - UsedTimeHours = 24, - SumDepthInterval = 1500, - KUsage = 100 - } - } - }; - //act - var result = await dailyReportService.UpdateBlockAsync(idDailyReport, idUser, fakeSubsystemBlock, CancellationToken.None); - - //assert - Assert.NotNull(fakeSubsystemBlock.DateLastUpdate); - Assert.NotNull(fakeDailyReport.DateLastUpdate); - Assert.Equal(fakeDailyReport.SubsystemBlock, fakeSubsystemBlock); - Assert.Equal(idDailyReport, result); - } - - [Fact] - public async Task UpdateSignBlock_ShouldReturn_Success() - { - //arrange - var fakeSignBlock = new SignBlockDto - { - IdUser = idUser, - DrillingMaster = new SignRecordDto() - { - Name = "Иван", - Patronymic = "Иванович", - Surname = "Иванов" - }, - Supervisor = new SignRecordDto() - { - Name = "Илья", - Patronymic = "Ильич", - Surname = "Бурилов" - } - }; - - //act - var result = await dailyReportService.UpdateBlockAsync(idDailyReport, idUser, fakeSignBlock, CancellationToken.None); + var result = await dailyReportService.UpdateOrInsertAsync(idWell, dateDailyReport, idUser, fakeSignBlock, CancellationToken.None); //assert - Assert.NotNull(fakeSignBlock.DateLastUpdate); + Assert.NotNull(fakeSignBlock.LastUpdateDate); Assert.NotNull(fakeDailyReport.DateLastUpdate); + Assert.Equal(fakeSignBlock.IdUser, idUser); Assert.Equal(fakeDailyReport.SignBlock, fakeSignBlock); Assert.Equal(idDailyReport, result); } [Fact] - public async Task UpdateTimeBalance_ShouldReturn_Success() + public async Task UpdateOrInsertAsync_ShouldReturn_UpdatedTimeBalanceBlock() { - //arrange - var fakeTimeBalanceBlock = new TimeBalanceBlockDto - { - IdUser = idUser, - IdSection = 1, - WellDepthPlan = 2000, - WellOperations = new[] - { - new TimeBalanceRecordDto() - { - DurationHours = new PlanFactDto() - { - Fact = 100, - Plan = 150, - }, - DrillingDeviationPerSection = 90, - DrillingDeviationPerDaily = 100, - ReasonDeviation = "Отклонение" - } - } - }; - //act - var result = await dailyReportService.UpdateBlockAsync(idDailyReport, idUser, fakeTimeBalanceBlock, CancellationToken.None); + var result = await dailyReportService.UpdateOrInsertAsync(idWell, dateDailyReport, idUser, fakeTimeBalanceBlock, + CancellationToken.None); //assert - Assert.NotNull(fakeTimeBalanceBlock.DateLastUpdate); + Assert.NotNull(fakeTimeBalanceBlock.LastUpdateDate); Assert.NotNull(fakeDailyReport.DateLastUpdate); + Assert.Equal(fakeTimeBalanceBlock.IdUser, idUser); Assert.Equal(fakeDailyReport.TimeBalanceBlock, fakeTimeBalanceBlock); Assert.Equal(idDailyReport, result); } + + [Fact] + public async Task GetAsync_ShouldReturn_AddedWellInfo() + { + //act + var result = await dailyReportService.GetAsync(idWell, dateDailyReport, CancellationToken.None); + + //assert + Assert.Equal(result.IdWell, fakeWell.Id); + Assert.Equal(result.WellCaption, fakeWell.Caption); + Assert.Equal(result.WellType, fakeWell.WellType); + Assert.Equal(result.Cluster, fakeWell.Cluster); + Assert.Equal(result.Deposit, fakeWell.Deposit); + Assert.Equal(result.Customer, fakeCustomer.Caption); + Assert.Equal(result.Contractor, fakeContractor.Caption); + Assert.Equal(result.DepthStart, fakeFirstFactWellOperation.DepthStart); + Assert.Equal(result.DepthEnd, fakeLastFactWellOperation.DepthEnd); + } + + [Fact] + public async Task GetAsync_ShouldReturn_AddedTrajectoryBlock() + { + //act + var result = await dailyReportService.GetAsync(idWell, dateDailyReport, CancellationToken.None); + + //assert + Assert.Equal(fakeLastFactTrajectory.WellboreDepth, result.TrajectoryBlock.WellboreDepth); + Assert.Equal(fakeLastFactTrajectory.VerticalDepth, result.TrajectoryBlock.VerticalDepth); + Assert.Equal(fakeLastFactTrajectory.ZenithAngle, result.TrajectoryBlock.ZenithAngle); + Assert.Equal(fakeLastFactTrajectory.AzimuthGeo, result.TrajectoryBlock.AzimuthGeo); + } + + [Fact] + public async Task GetAsync_ShouldReturn_AddedFactWellOperationBlock() + { + //act + var result = await dailyReportService.GetAsync(idWell, dateDailyReport, CancellationToken.None); + + //assert + Assert.Equal(16, result.FactWellOperationBlock.SectionDrillingHours); + Assert.Single(result.FactWellOperationBlock.WellOperations); + + var wellOperation = result.FactWellOperationBlock.WellOperations.Single(); + + Assert.Equal("Механическое. бурение", wellOperation.CategoryName); + Assert.Equal(16, wellOperation.DurationHours); + } + + [Fact] + public async Task GetAsync_ShouldReturn_AddedScheduleBlock() + { + //act + var result = await dailyReportService.GetAsync(idWell, dateDailyReport, CancellationToken.None); + + //assert + Assert.Single(result.ScheduleBlock); + + var sheduleRecord = result.ScheduleBlock.Single(); + + Assert.Equal(fakeShedule.ShiftStart, sheduleRecord.ShiftStart); + Assert.Equal(fakeShedule.ShiftEnd, sheduleRecord.ShiftEnd); + Assert.Equal(fakeShedule.Driller?.Name, sheduleRecord.Name); + Assert.Equal(fakeShedule.Driller?.Surname, sheduleRecord.Surname); + Assert.Equal(fakeShedule.Driller?.Patronymic, sheduleRecord.Patronymic); + } + + [Fact] + public async Task GetAsync_ShouldReturn_UpdatedTimeBalanceBlock() + { + //arrange + fakeDailyReport.TimeBalanceBlock = fakeTimeBalanceBlock; + + //act + var result = await dailyReportService.GetAsync(idWell, dateDailyReport, CancellationToken.None); + + //assert + Assert.NotNull(result.TimeBalanceBlock); + Assert.Equal(fakeSectionType.Id, result.TimeBalanceBlock.IdSection); + Assert.Equal(fakeSectionType.Caption, result.TimeBalanceBlock.SectionName); + Assert.Equal(2000, result.TimeBalanceBlock?.WellDepth.Plan); + Assert.Equal(120, result.TimeBalanceBlock?.WellDepth.Fact); + Assert.Equal(40, result.TimeBalanceBlock?.WellOperationSlipsTimeCount); + } + + [Fact] + public async Task GetAsync_ShouldReturn_AddedProcessMapWellDrillingBlock() + { + //act + var result = await dailyReportService.GetAsync(idWell, dateDailyReport, CancellationToken.None); + + //assert + Assert.Single(result.ProcessMapWellDrillingBlock); + + var processMapWellDrillingRecord = result.ProcessMapWellDrillingBlock.Single(); + + Assert.Equal(fakeProcessMapReportWellDrilling.DrillingMode, processMapWellDrillingRecord.DrillingMode); + Assert.Equal(fakeProcessMapReportWellDrilling.Rop.Plan, processMapWellDrillingRecord.Rop.Plan); + Assert.Equal(fakeProcessMapReportWellDrilling.Rop.Fact, processMapWellDrillingRecord.Rop.Fact); + Assert.Equal(fakeProcessMapReportWellDrilling.DeltaDepth, processMapWellDrillingRecord.WellBoreDepth); + Assert.Equal(fakeProcessMapReportWellDrilling.MechDrillingHours, processMapWellDrillingRecord.MechDrillingHours); + } + + [Fact] + public async Task GetAsync_ShouldReturn_UpdatedSubsystemBlock() + { + //arrange + fakeDailyReport.SubsystemBlock = fakeSubsystemBlock; + + //act + var result = await dailyReportService.GetAsync(idDailyReport, dateDailyReport, CancellationToken.None); + + //assert + Assert.NotNull(result.SubsystemBlock); + Assert.Equal(3, result.SubsystemBlock?.Subsystems.Count()); + + var subsystemRecord0 = result.SubsystemBlock?.Subsystems.ElementAt(0); + + Assert.Equal("АвтоСПО", subsystemRecord0?.SubsystemName); + Assert.Equal(2, subsystemRecord0?.IdTimeInterval); + Assert.Equal(24, subsystemRecord0?.UsedTimeHours); + Assert.Equal(1500, subsystemRecord0?.SumDepthInterval); + Assert.Equal(100, subsystemRecord0?.KUsage); + + var subsystemRecord1 = result.SubsystemBlock?.Subsystems.ElementAt(1); + + Assert.Equal(fakeStatSubsystemOperationTimePerDay.SubsystemName, subsystemRecord1?.SubsystemName); + Assert.Equal(1, subsystemRecord1?.IdTimeInterval); + Assert.Equal(fakeStatSubsystemOperationTimePerDay.UsedTimeHours, subsystemRecord1?.UsedTimeHours); + Assert.Equal(fakeStatSubsystemOperationTimePerDay.SumDepthInterval, subsystemRecord1?.SumDepthInterval); + Assert.Equal(fakeStatSubsystemOperationTimePerDay.KUsage, subsystemRecord1?.KUsage); + } + + [Fact] + public async Task GetAsync_ShouldReturn_FictiveDailyReport() + { + //act + var result = await dailyReportService.GetAsync(idWell, new FileReportRequest(), CancellationToken.None); + + //assert + Assert.True((fakeLastFactWellOperation.DateStart - fakeFirstFactWellOperation.DateStart).Days == result.Count); + } + + [Theory] + [MemberData(nameof(FactWellOperationDates))] + public async Task GetDatesRangeAsync_ShouldReturn_DateRangeByFactWellOperations(IEnumerable factWellOperationDates) + { + //arrange + wellOperationRepositoryMock.GetAsync(Arg.Any(), CancellationToken.None) + .ReturnsForAnyArgs(factWellOperationDates.Select(dateStart => new WellOperationDto { DateStart = dateStart })); + + //act + var result = await dailyReportService.GetDatesRangeAsync(idWell, CancellationToken.None); + + //assert + Assert.NotNull(result); + Assert.True(result.From <= result.To); + Assert.True(result.To < DateTime.UtcNow.Date); + } + + public static IEnumerable FactWellOperationDates() + { + yield return new object[] + { + new[] + { + new DateTime(2023, 11, 1), + new DateTime(2023, 11, 9), + DateTime.UtcNow + } + }; + + yield return new object[] + { + new[] + { + new DateTime(2023, 11, 1), + new DateTime(2023, 11, 1) + } + }; + + yield return new object[] + { + new[] + { + DateTime.UtcNow, + DateTime.UtcNow + } + }; + + yield return new object[] + { + new[] + { + new DateTime(2023, 11, 1), + new DateTime(2023, 11, 9), + new DateTime(2023, 11, 11) + } + }; + } } \ No newline at end of file diff --git a/AsbCloudWebApi/Controllers/DailyReportController.cs b/AsbCloudWebApi/Controllers/DailyReportController.cs index 222eb74c..0a73a881 100644 --- a/AsbCloudWebApi/Controllers/DailyReportController.cs +++ b/AsbCloudWebApi/Controllers/DailyReportController.cs @@ -5,7 +5,6 @@ using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data; using AsbCloudApp.Data.DailyReport; -using AsbCloudApp.Data.DailyReport.Blocks; using AsbCloudApp.Data.DailyReport.Blocks.Sign; using AsbCloudApp.Data.DailyReport.Blocks.Subsystems; using AsbCloudApp.Data.DailyReport.Blocks.TimeBalance; @@ -57,39 +56,11 @@ public class DailyReportController : ControllerBase } } - /// - /// Создать суточный отчёт - /// - /// Id скважины - /// Дата формирования суточного отчёта - /// - /// - [HttpPost] - [Permission] - [ProducesResponseType(typeof(int), StatusCodes.Status200OK)] - [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] - public async Task InsertAsync(int idWell, DateOnly dateStart, CancellationToken cancellationToken) - { - var dateStartToDateTime = dateStart.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc); - - var datesRange = await dailyReportService.GetDatesRangeAsync(idWell, cancellationToken); - - if (dateStartToDateTime < datesRange?.From || dateStartToDateTime > datesRange?.To) - throw new ArgumentInvalidException("Невозможно сформировать суточный отчёт", nameof(dateStart)); - - await AssertUserAccessToWell(idWell, cancellationToken); - - var id = await dailyReportService.InsertAsync(idWell, dateStart.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc), - cancellationToken); - - return Ok(id); - } - /// /// Обновить подпись /// /// Id скважины - /// Id суточного отчёта + /// Дата суточного отчёта /// Обновляемый блок /// /// @@ -97,14 +68,15 @@ public class DailyReportController : ControllerBase [Permission] [ProducesResponseType(typeof(int), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] - public Task UpdateSignBlockAsync(int idWell, int idDailyReport, SignBlockDto signBlock, CancellationToken cancellationToken) => - UpdateBlockAsync(idWell, idDailyReport, signBlock, cancellationToken); + public Task UpdateSignBlockAsync(int idWell, DateOnly dateDailyReport, SignBlockDto signBlock, + CancellationToken cancellationToken) => + UpdateOrInsertAsync(idWell, dateDailyReport, signBlock, cancellationToken); /// /// Обновить наработку подсистем /// /// Id скважины - /// Id суточного отчёта + /// Дата суточного отчёта /// Обновляемый блок /// /// @@ -112,7 +84,7 @@ public class DailyReportController : ControllerBase [Permission] [ProducesResponseType(typeof(int), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] - public Task UpdateSubsystemBlockAsync(int idWell, int idDailyReport, SubsystemBlockDto subsystemBlock, + public Task UpdateSubsystemBlockAsync(int idWell, DateOnly dateDailyReport, SubsystemBlockDto subsystemBlock, CancellationToken cancellationToken) { var validSubsystemNames = new[] { "АвтоСПО", "Автопроработка" }; @@ -121,14 +93,14 @@ public class DailyReportController : ControllerBase throw new ArgumentInvalidException($"Возможно добавить подсистемы с именами {string.Join(", ", validSubsystemNames)}", nameof(subsystemBlock.Subsystems)); - return UpdateBlockAsync(idWell, idDailyReport, subsystemBlock, cancellationToken); + return UpdateOrInsertAsync(idWell, dateDailyReport, subsystemBlock, cancellationToken); } /// /// Обновить баланс времени /// /// Id скважины - /// Id суточного отчёта + /// Дата суточного отчёта /// Обновляемый блок /// /// @@ -136,7 +108,7 @@ public class DailyReportController : ControllerBase [Permission] [ProducesResponseType(typeof(int), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] - public Task UpdateTimeBalanceBlockAsync(int idWell, int idDailyReport, TimeBalanceBlockDto timeBalanceBlock, + public Task UpdateTimeBalanceBlockAsync(int idWell, DateOnly dateDailyReport, TimeBalanceBlockDto timeBalanceBlock, CancellationToken cancellationToken) { var validWellOperationsIds = new[] { 1, 2, 3, 4 }; @@ -144,13 +116,13 @@ public class DailyReportController : ControllerBase if (timeBalanceBlock.WellOperations.Any(o => !validWellOperationsIds.Contains(o.IdWellOperation))) throw new ArgumentInvalidException($"Возможно добавить операции только с Id: {string.Join(", ", validWellOperationsIds)}", nameof(timeBalanceBlock.WellOperations)); - + var wellSections = wellOperationRepository.GetSectionTypes(); if (wellSections.All(s => s.Id != timeBalanceBlock.IdSection)) throw new ArgumentInvalidException($"Секция с Id: {timeBalanceBlock.IdSection} не найдена", nameof(timeBalanceBlock.IdSection)); - return UpdateBlockAsync(idWell, idDailyReport, timeBalanceBlock, cancellationToken); + return UpdateOrInsertAsync(idWell, dateDailyReport, timeBalanceBlock, cancellationToken); } /// @@ -193,36 +165,37 @@ public class DailyReportController : ControllerBase /// Экспорт суточного рапорта /// /// Id скважины - /// Дата формирования суточного отчёта + /// Дата формирования суточного отчёта /// /// - [HttpGet("{dateStart}")] + [HttpGet("{dateDailyReport}")] [ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] - public async Task ExportAsync(int idWell, DateOnly dateStart, CancellationToken cancellationToken) + public async Task ExportAsync(int idWell, DateOnly dateDailyReport, CancellationToken cancellationToken) { - var dateStartToDateTime = dateStart.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc); - + var dateStartToDateTime = dateDailyReport.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc); + var datesRange = await dailyReportService.GetDatesRangeAsync(idWell, cancellationToken); if (dateStartToDateTime < datesRange?.From || dateStartToDateTime > datesRange?.To) - throw new ArgumentInvalidException("Невозможно получить суточный отчёт", nameof(dateStart)); - + throw new ArgumentInvalidException("Невозможно получить суточный отчёт", nameof(dateDailyReport)); + await AssertUserAccessToWell(idWell, cancellationToken); var dailyReport = await dailyReportExportService.ExportAsync(idWell, - dateStart.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc), cancellationToken); + dateDailyReport.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc), cancellationToken); return File(dailyReport.File, "application/octet-stream", dailyReport.FileName); } - private async Task UpdateBlockAsync(int idWell, int idDailyReport, TBlock block, + private async Task UpdateOrInsertAsync(int idWell, DateOnly dateDailyReport, TBlock block, CancellationToken cancellationToken) - where TBlock : EditableBlock + where TBlock : ItemInfoDto { await AssertUserAccessToWell(idWell, cancellationToken); - - var id = await dailyReportService.UpdateBlockAsync(idDailyReport, IdUser, block, cancellationToken); + + var id = await dailyReportService.UpdateOrInsertAsync(idWell, dateDailyReport.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc), IdUser, + block, cancellationToken); return Ok(id); }