DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/DailyReport/DailyReportService.cs
Степанов Дмитрий dcaec8b4a2 Доработки
1. Добавлен шаблон суточного отчёта
2. Рефакторинг DTO для суточного отчёта
3. Обновлена валидация входных данных в методах контроллера
4. Небольшой рефакторинг сервисов
2023-11-07 15:57:15 +05:00

385 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using AsbCloudApp.Data.DailyReport;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Data.DailyReport.Blocks;
using AsbCloudApp.Data.DailyReport.Blocks.Sign;
using AsbCloudApp.Data.DailyReport.Blocks.Subsystems;
using AsbCloudApp.Data.DailyReport.Blocks.TimeBalance;
using AsbCloudApp.Data.DailyReport.Blocks.WellOperation;
using AsbCloudApp.Requests;
using AsbCloudApp.Services.DailyReport;
using AsbCloudApp.Services.ProcessMaps.WellDrilling;
using AsbCloudApp.Services.Subsystems;
using AsbCloudDb.Model;
using Mapster;
namespace AsbCloudInfrastructure.Services.DailyReport;
public class DailyReportService : IDailyReportService
{
private readonly IWellService wellService;
private readonly ITrajectoryFactRepository trajectoryFactRepository;
private readonly IDailyReportRepository dailyReportRepository;
private readonly IScheduleRepository scheduleRepository;
private readonly IWellOperationRepository wellOperationRepository;
private readonly ISubsystemOperationTimeService subsystemOperationTimeService;
private readonly IProcessMapReportWellDrillingService processMapReportWellDrillingService;
private readonly IDetectedOperationService detectedOperationService;
public DailyReportService(IWellService wellService,
ITrajectoryFactRepository trajectoryFactRepository,
IDailyReportRepository dailyReportRepository,
IScheduleRepository scheduleRepository,
IWellOperationRepository wellOperationRepository,
ISubsystemOperationTimeService subsystemOperationTimeService,
IProcessMapReportWellDrillingService processMapReportWellDrillingService,
IDetectedOperationService detectedOperationService)
{
this.wellService = wellService;
this.trajectoryFactRepository = trajectoryFactRepository;
this.dailyReportRepository = dailyReportRepository;
this.scheduleRepository = scheduleRepository;
this.wellOperationRepository = wellOperationRepository;
this.subsystemOperationTimeService = subsystemOperationTimeService;
this.processMapReportWellDrillingService = processMapReportWellDrillingService;
this.detectedOperationService = detectedOperationService;
}
public async Task<int> 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<int> UpdateBlockAsync<TBlock>(int idDailyReport, int idUser, TBlock editableBlock,
CancellationToken cancellationToken)
where TBlock : EditableBlock
{
var dailyReport = await dailyReportRepository.GetOrDefaultAsync(idDailyReport, cancellationToken)
?? throw new ArgumentInvalidException(nameof(idDailyReport), $"Суточный отчёт с Id: {idDailyReport} не найден");
editableBlock.IdUser = idUser;
dailyReport.DateLastUpdate = DateTime.UtcNow;
switch (editableBlock)
{
case SubsystemBlockDto subsystemBlock:
dailyReport.SubsystemBlock = subsystemBlock;
break;
case TimeBalanceBlockDto timeBalanceBlock:
dailyReport.TimeBalanceBlock = timeBalanceBlock;
break;
case SignBlockDto signBlock:
dailyReport.SignBlock = signBlock;
break;
}
return await dailyReportRepository.UpdateAsync(dailyReport, cancellationToken);
}
public async Task<DailyReportDto> GetAsync(int idWell, DateTime dateStart, 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
{
DateStart = dateStart.Date,
IdWell = well.Id
};
var factWellOperations = await GetFactWellOperationsAsync(idWell, dailyReport.DateStart, dailyReport.DateEnd,
cancellationToken);
dailyReport.WellName = 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);
}
await UpdateTimeBalanceBlockAsync(dailyReport, factWellOperations, cancellationToken);
await UpdateSubsystemBlockAsync(dailyReport, cancellationToken);
await AddTrajectoryBlockAsync(dailyReport, cancellationToken);
await AddScheduleBlockAsync(dailyReport, cancellationToken);
await AddProcessMapWellDrillingBlockAsync(dailyReport, cancellationToken);
AddFactWellOperationBlock(dailyReport, factWellOperations);
return dailyReport;
}
public async Task<PaginationContainer<DailyReportDto>> GetAsync(int idWell, FileReportRequest request,
CancellationToken cancellationToken)
{
var result = new PaginationContainer<DailyReportDto>
{
Skip = request.Skip ?? 0,
Take = request.Take ?? 10,
Items = Enumerable.Empty<DailyReportDto>()
};
var well = await wellService.GetOrDefaultAsync(idWell, cancellationToken)
?? throw new ArgumentInvalidException(nameof(idWell), "Скважина не найдена");
var datesRange = await GetDatesRangeAsync(idWell, cancellationToken);
if (datesRange is null)
return result;
var dailyReports = new List<DailyReportDto>();
var existingDailyReports = await dailyReportRepository.GetAsync(idWell, request, cancellationToken);
if (request.GeDate.HasValue)
{
var startDate = new DateTime(request.GeDate.Value.Year, request.GeDate.Value.Month,
request.GeDate.Value.Day);
if (startDate.Date >= datesRange.From.Date)
datesRange.From = startDate;
}
if (request.LeDate.HasValue)
{
var finishDate = new DateTime(request.LeDate.Value.Year, request.LeDate.Value.Month,
request.LeDate.Value.Day);
if (finishDate.Date <= datesRange.To.Date)
datesRange.To = finishDate;
}
if (datesRange.From.AddDays(result.Skip) <= datesRange.To)
result.Count = (int)(Math.Ceiling((datesRange.To - DateTime.UnixEpoch).TotalDays) -
Math.Floor((datesRange.From - DateTime.UnixEpoch).TotalDays));
if (request.SortFields?.Contains("DateStart desc") == true)
{
for (var day = result.Skip; day - result.Skip < result.Take && datesRange.To.AddDays(-day) >= datesRange.From; day++)
{
var dateStart = datesRange.To.AddDays(-day);
AddDailyReport(dateStart);
}
}
else
{
for (var day = result.Skip; day - result.Skip < result.Take && datesRange.From.AddDays(day) <= datesRange.To; day++)
{
var dateStart = datesRange.From.AddDays(day);
AddDailyReport(dateStart);
}
}
result.Items = dailyReports;
return result;
void AddDailyReport(DateTime dateStart)
{
var existingDailyReport = existingDailyReports.FirstOrDefault(d => d.IdWell == idWell &&
d.DateStart == dateStart);
if (existingDailyReport is not null)
{
dailyReports.Add(existingDailyReport);
return;
}
dailyReports.Add(new DailyReportDto
{
DateStart = dateStart,
IdWell = well.Id
});
}
}
public async Task<DatesRangeDto?> GetDatesRangeAsync(int idWell, CancellationToken cancellationToken)
{
var factOperations = await GetFactWellOperationsAsync(idWell, null, null,
cancellationToken);
if (!factOperations.Any())
return null;
return new DatesRangeDto
{
From = factOperations.Min(o => o.DateStart).Date,
To = factOperations.Max(o => o.DateStart).Date
};
}
private async Task UpdateTimeBalanceBlockAsync(DailyReportDto dailyReport, IEnumerable<WellOperationDto> factWellOperations,
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.CountWellOperationSlipsTime = (await detectedOperationService.GetAsync(
new DetectedOperationRequest
{
IdsCategories = new[] { idWellOperationSlipsTime },
IdWell = dailyReport.IdWell,
GtDate = dailyReport.DateStart,
LtDate = dailyReport.DateEnd
}, cancellationToken))?.Stats.Sum(s => s.Count);
dailyReport.TimeBalanceBlock.WellDepthFact = factWellOperations
.Where(o => o.IdWellSectionType == dailyReport.TimeBalanceBlock.IdSection)
.Sum(o => o.DepthEnd = o.DepthStart);
}
}
private async Task AddTrajectoryBlockAsync(DailyReportDto dailyReport, CancellationToken cancellationToken)
{
var trajectory = (await trajectoryFactRepository.GetAsync(new TrajectoryGeoFactRequest
{
IdWell = dailyReport.IdWell,
GeDate = dailyReport.DateStart,
LtDate = dailyReport.DateEnd
}, cancellationToken)).LastOrDefault();
dailyReport.TrajectoryBlock = new TrajectoryBlockDto
{
WellboreDepth = trajectory?.WellboreDepth,
VerticalDepth = trajectory?.VerticalDepth,
ZenithAngle = trajectory?.ZenithAngle,
AzimuthGeo = trajectory?.AzimuthGeo
};
}
private async Task AddScheduleBlockAsync(DailyReportDto dailyReport, CancellationToken cancellationToken) =>
dailyReport.ScheduleBlock = (await scheduleRepository.GetAsync(dailyReport.IdWell, dailyReport.DateStart, cancellationToken))
.Select(s => new ScheduleRecordDto
{
ShiftStart = s.ShiftStart,
ShiftEnd = s.ShiftEnd,
Name = s.Driller?.Name,
Surname = s.Driller?.Surname,
Patronymic = s.Driller?.Patronymic
});
private async Task UpdateSubsystemBlockAsync(DailyReportDto dailyReport, CancellationToken cancellationToken)
{
dailyReport.SubsystemBlock ??= new SubsystemBlockDto();
dailyReport.SubsystemBlock.Modules = await GetModulesAsync();
async Task<IEnumerable<SubsystemRecordDto>> GetModulesAsync()
{
var modules = new List<SubsystemRecordDto>();
var statSubsystemOperationTimePerDaily = (await subsystemOperationTimeService.GetStatAsync(new SubsystemOperationTimeRequest
{
IdWell = dailyReport.IdWell,
GtDate = dailyReport.DateStart,
LtDate = dailyReport.DateEnd
}, cancellationToken)).Select(s =>
{
var subsystemRecord = s.Adapt<SubsystemRecordDto>();
subsystemRecord.IdTimeInterval = 1;
return subsystemRecord;
});
var statSubsystemOperationTimePerWell = (await subsystemOperationTimeService.GetStatAsync(new SubsystemOperationTimeRequest
{
IdWell = dailyReport.IdWell
}, cancellationToken)).Select(s =>
{
var subsystemRecord = s.Adapt<SubsystemRecordDto>();
subsystemRecord.IdTimeInterval = 2;
return subsystemRecord;
});
modules.AddRange(statSubsystemOperationTimePerDaily);
modules.AddRange(statSubsystemOperationTimePerWell);
if (dailyReport.SubsystemBlock?.Modules != null && dailyReport.SubsystemBlock.Modules.Any())
modules.AddRange(dailyReport.SubsystemBlock.Modules);
return modules;
}
}
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 &&
p.IdMode.HasValue)
.GroupBy(p => p.DrillingMode)
.Select(g => new ProcessMapWellDrillingRecordDto
{
DrillingMode = g.Key,
WellBoreDepth = g.Sum(p => p.DeltaDepth),
Rop = new PlanFactDto<double?>
{
Plan = g.Sum(p => p.RopPlan),
Fact = g.Sum(p => p.RopFact)
},
MechDrillingHours = g.Sum(p => p.MechDrillingHours)
});
}
private void AddFactWellOperationBlock(DailyReportDto dailyReport, IEnumerable<WellOperationDto> factWellOperations)
{
const int idWellOperationCategoryDrilling = 4001;
dailyReport.FactWellOperationBlock = new WellOperationBlockDto
{
WellOperations = factWellOperations.GroupBy(o => o.IdParentCategory)
.Select(g => new WellOperationRecordDto
{
CategoryName = g.First().CategoryName,
DurationHours = g.Sum(o => o.DurationHours)
}),
DurationHoursDrillingPerSection = factWellOperations
.Where(o => o.IdParentCategory is idWellOperationCategoryDrilling)
.Sum(o => o.DurationHours)
};
}
private Task<IEnumerable<WellOperationDto>> GetFactWellOperationsAsync(int idWell, DateTime? dailyReportDateStart,
DateTime? dailyReportDateEnd, CancellationToken cancellationToken) =>
wellOperationRepository.GetAsync(new WellOperationRequest
{
IdWell = idWell,
OperationType = WellOperation.IdOperationTypeFact,
GeDate = dailyReportDateStart,
LtDate = dailyReportDateEnd
}, cancellationToken);
}