2023-07-24 11:14:07 +05:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using AsbCloudApp.Data;
|
|
|
|
|
using AsbCloudApp.Data.AutogeneratedDailyReport;
|
|
|
|
|
using AsbCloudApp.Data.SAUB;
|
|
|
|
|
using AsbCloudApp.Data.Subsystems;
|
|
|
|
|
using AsbCloudApp.Exceptions;
|
|
|
|
|
using AsbCloudApp.Repositories;
|
|
|
|
|
using AsbCloudApp.Requests;
|
|
|
|
|
using AsbCloudApp.Services;
|
|
|
|
|
using AsbCloudApp.Services.AutoGeneratedDailyReports;
|
|
|
|
|
using AsbCloudApp.Services.Subsystems;
|
|
|
|
|
using AsbCloudDb.Model;
|
|
|
|
|
using AsbCloudInfrastructure.Services.SAUB;
|
|
|
|
|
|
|
|
|
|
namespace AsbCloudInfrastructure.Services.AutoGeneratedDailyReports;
|
|
|
|
|
|
|
|
|
|
public class AutoGeneratedDailyReportService : IAutoGeneratedDailyReportService
|
|
|
|
|
{
|
|
|
|
|
private const string fileNameTemplate = "Суточный_отчёт_по_скважине_{0}_куст_{1}_от_{2}.xlsx";
|
|
|
|
|
|
|
|
|
|
private readonly IWellService wellService;
|
|
|
|
|
private readonly IWellOperationRepository wellOperationRepository;
|
|
|
|
|
private readonly TelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache;
|
|
|
|
|
private readonly ISubsystemOperationTimeService subsystemOperationTimeService;
|
|
|
|
|
private readonly ICrudRepository<SubsystemDto> subsystemRepository;
|
|
|
|
|
private readonly ILimitingParameterService limitingParameterService;
|
|
|
|
|
private readonly IAutoGeneratedDailyReportMakerService autoGeneratedDailyReportMakerService;
|
|
|
|
|
|
|
|
|
|
public AutoGeneratedDailyReportService(IWellService wellService,
|
|
|
|
|
IWellOperationRepository wellOperationRepository,
|
|
|
|
|
TelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache,
|
|
|
|
|
ISubsystemOperationTimeService subsystemOperationTimeService,
|
|
|
|
|
ICrudRepository<SubsystemDto> subsystemRepository,
|
|
|
|
|
ILimitingParameterService limitingParameterService,
|
|
|
|
|
IAutoGeneratedDailyReportMakerService autoGeneratedDailyReportMakerService)
|
|
|
|
|
{
|
|
|
|
|
this.wellOperationRepository = wellOperationRepository;
|
|
|
|
|
this.wellService = wellService;
|
|
|
|
|
this.telemetryDataCache = telemetryDataCache;
|
|
|
|
|
this.subsystemOperationTimeService = subsystemOperationTimeService;
|
|
|
|
|
this.subsystemRepository = subsystemRepository;
|
|
|
|
|
this.limitingParameterService = limitingParameterService;
|
|
|
|
|
this.autoGeneratedDailyReportMakerService = autoGeneratedDailyReportMakerService;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-25 17:07:50 +05:00
|
|
|
|
public async Task<PaginationContainer<AutoGeneratedDailyReportInfoDto>> GetListAsync(int idWell,
|
2023-07-24 11:14:07 +05:00
|
|
|
|
AutoGeneratedDailyReportRequest request,
|
|
|
|
|
CancellationToken cancellationToken)
|
|
|
|
|
{
|
2023-07-25 17:07:50 +05:00
|
|
|
|
var result = new PaginationContainer<AutoGeneratedDailyReportInfoDto>
|
2023-07-24 11:14:07 +05:00
|
|
|
|
{
|
|
|
|
|
Skip = request.Skip ?? 0,
|
|
|
|
|
Take = request.Take ?? 10,
|
2023-07-25 17:07:50 +05:00
|
|
|
|
Items = Enumerable.Empty<AutoGeneratedDailyReportInfoDto>()
|
2023-07-24 11:14:07 +05:00
|
|
|
|
};
|
|
|
|
|
|
2023-07-25 17:07:50 +05:00
|
|
|
|
var reports = new List<AutoGeneratedDailyReportInfoDto>();
|
2023-07-24 11:14:07 +05:00
|
|
|
|
|
|
|
|
|
var well = await wellService.GetOrDefaultAsync(idWell, cancellationToken)
|
|
|
|
|
?? throw new ArgumentInvalidException("Скважина не найдена", nameof(idWell));
|
|
|
|
|
|
|
|
|
|
if (!well.IdTelemetry.HasValue)
|
|
|
|
|
throw new ArgumentInvalidException("Телеметрия для скважины отсутствует", nameof(idWell));
|
|
|
|
|
|
|
|
|
|
var datesRange = telemetryDataCache.GetOrDefaultDataDateRange(well.IdTelemetry.Value);
|
|
|
|
|
|
2023-07-25 17:31:54 +05:00
|
|
|
|
if (datesRange is null)
|
2023-07-24 11:14:07 +05:00
|
|
|
|
return result;
|
2023-07-25 17:31:54 +05:00
|
|
|
|
|
|
|
|
|
result.Count = (int)(Math.Ceiling((datesRange.To - DateTime.UnixEpoch).TotalDays) - Math.Floor((datesRange.From - DateTime.UnixEpoch).TotalDays));
|
2023-07-24 11:14:07 +05:00
|
|
|
|
|
|
|
|
|
if (request.StartDate.HasValue)
|
|
|
|
|
{
|
2023-07-25 17:31:54 +05:00
|
|
|
|
var startDate = new DateTime(request.StartDate.Value.Year, request.StartDate.Value.Month,
|
2023-07-24 11:14:07 +05:00
|
|
|
|
request.StartDate.Value.Day);
|
2023-07-25 17:07:50 +05:00
|
|
|
|
|
|
|
|
|
if(startDate.Date >= datesRange.From.Date)
|
|
|
|
|
datesRange.From = startDate;
|
2023-07-24 11:14:07 +05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (request.FinishDate.HasValue)
|
|
|
|
|
{
|
|
|
|
|
var finishDate = new DateTime(request.FinishDate.Value.Year, request.FinishDate.Value.Month,
|
|
|
|
|
request.FinishDate.Value.Day);
|
|
|
|
|
|
2023-07-25 17:07:50 +05:00
|
|
|
|
if (finishDate.Date <= datesRange.To.Date)
|
|
|
|
|
datesRange.To = finishDate;
|
2023-07-24 11:14:07 +05:00
|
|
|
|
}
|
2023-07-25 17:07:50 +05:00
|
|
|
|
|
|
|
|
|
for (int day = result.Skip; (day - result.Skip) < result.Take && (datesRange.From.AddDays(day)) <= datesRange.To; day++)
|
2023-07-24 11:14:07 +05:00
|
|
|
|
{
|
2023-07-25 17:07:50 +05:00
|
|
|
|
var dateFrom = datesRange.From.AddDays(day);
|
|
|
|
|
|
2023-07-24 11:14:07 +05:00
|
|
|
|
reports.Add(new AutoGeneratedDailyReportDto
|
|
|
|
|
{
|
|
|
|
|
FileName = string.Format(fileNameTemplate, well.Caption, well.Cluster, DateOnly.FromDateTime(dateFrom)),
|
|
|
|
|
ReportDate = DateOnly.FromDateTime(dateFrom),
|
|
|
|
|
FileSize = GetFileSize() / 1024,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-25 17:07:50 +05:00
|
|
|
|
result.Items = reports;
|
|
|
|
|
|
2023-07-24 11:14:07 +05:00
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<(string fileName, Stream stream)> GenerateReportAsync(int idWell, DateOnly reportDate,
|
|
|
|
|
CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
var startDate = new DateTime(reportDate.Year, reportDate.Month, reportDate.Day);
|
|
|
|
|
var finishDate = startDate.AddDays(1);
|
|
|
|
|
|
|
|
|
|
var well = await wellService.GetOrDefaultAsync(idWell, cancellationToken)
|
|
|
|
|
?? throw new ArgumentInvalidException("Скважина не найдена", nameof(idWell));
|
|
|
|
|
|
|
|
|
|
if (!well.IdTelemetry.HasValue)
|
|
|
|
|
throw new ArgumentInvalidException("Телеметрия для скважины отсутствует", nameof(idWell));
|
|
|
|
|
|
|
|
|
|
var factOperations = (await GetFactOperationsAsync(well.Id, startDate, finishDate,
|
|
|
|
|
cancellationToken)).ToArray();
|
|
|
|
|
|
|
|
|
|
var report = new AutoGeneratedDailyReportDto
|
|
|
|
|
{
|
|
|
|
|
FileName = string.Format(fileNameTemplate, well.Caption, well.Cluster, reportDate),
|
|
|
|
|
FileSize = GetFileSize() / 1024,
|
|
|
|
|
ReportDate = reportDate,
|
|
|
|
|
Head = CreateHeadBlock(well, reportDate, factOperations),
|
|
|
|
|
Subsystems = (await CreateSubsystemBlockAsync(idWell, startDate, finishDate, cancellationToken)).ToArray(),
|
|
|
|
|
LimitingParameters = (await CreateLimitingParameterBlockAsync(idWell, startDate, finishDate, cancellationToken)).ToArray(),
|
|
|
|
|
TimeBalance = factOperations.GroupBy(w => w.CategoryName).Select(x => new TimeBalanceRecordDto
|
|
|
|
|
{
|
|
|
|
|
Name = x.Key ?? "Название операции отсутствует",
|
|
|
|
|
DurationHours = x.Sum(o => o.DurationHours)
|
|
|
|
|
}).ToArray(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var stream = await autoGeneratedDailyReportMakerService.MakeReportAsync(report, cancellationToken);
|
|
|
|
|
|
|
|
|
|
return (report.FileName, stream);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private HeadBlockDto CreateHeadBlock(WellDto well, DateOnly reportDate, WellOperationDto[] factOperations)
|
|
|
|
|
{
|
|
|
|
|
var customer = well.Companies.FirstOrDefault(company => company.IdCompanyType == 1);
|
|
|
|
|
|
|
|
|
|
return new HeadBlockDto
|
|
|
|
|
{
|
|
|
|
|
Customer = customer?.Caption ?? string.Empty,
|
|
|
|
|
Deposit = well.Deposit ?? string.Empty,
|
2023-07-25 17:07:50 +05:00
|
|
|
|
Cluster = well.Cluster ?? string.Empty,
|
|
|
|
|
Well = well.Caption,
|
|
|
|
|
DepthFrom = factOperations.FirstOrDefault()?.DepthStart ?? 0.00,
|
|
|
|
|
DepthTo = factOperations.LastOrDefault()?.DepthEnd ?? 0.00
|
2023-07-24 11:14:07 +05:00
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task<IEnumerable<SubsystemRecordDto>> CreateSubsystemBlockAsync(int idWell, DateTime startDate,
|
|
|
|
|
DateTime finishDate,
|
|
|
|
|
CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
var subsystems = await subsystemRepository.GetAllAsync(cancellationToken);
|
|
|
|
|
var subsystemStats = await GetSubsystemStatsAsync(idWell, startDate, finishDate,
|
|
|
|
|
cancellationToken);
|
|
|
|
|
|
|
|
|
|
return subsystems.Select(subsystem =>
|
|
|
|
|
{
|
|
|
|
|
var subsytemStat = subsystemStats?.FirstOrDefault(s => s.IdSubsystem == subsystem.Id);
|
|
|
|
|
|
|
|
|
|
return new SubsystemRecordDto
|
|
|
|
|
{
|
|
|
|
|
Name = subsystem.Name,
|
|
|
|
|
KUsage = subsytemStat?.KUsage ?? 0.00,
|
|
|
|
|
UsedTimeHours = subsytemStat?.UsedTimeHours ?? 0.00,
|
|
|
|
|
Depth = subsytemStat?.SumDepthInterval ?? 0.00,
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task<IEnumerable<LimitingParameterRecordDto>> CreateLimitingParameterBlockAsync(int idWell,
|
|
|
|
|
DateTime startDate, DateTime finishDate, CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
var limitingParameterStats = (await GetLimitingParameterStatsAsync(idWell,
|
|
|
|
|
startDate, finishDate, cancellationToken)).ToArray();
|
|
|
|
|
|
|
|
|
|
var sumDepths = limitingParameterStats.Sum(x => x.Depth);
|
|
|
|
|
|
|
|
|
|
return limitingParameterStats.Select(l => new LimitingParameterRecordDto
|
|
|
|
|
{
|
|
|
|
|
NameFeedRegulator = l.NameFeedRegulator,
|
2023-07-25 17:07:50 +05:00
|
|
|
|
Hours = l.TotalMinutes,
|
2023-07-24 11:14:07 +05:00
|
|
|
|
PercentDepth = l.Depth / sumDepths,
|
|
|
|
|
Depth = l.Depth,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Task<IEnumerable<WellOperationDto>> GetFactOperationsAsync(int idWell, DateTime startDate,
|
|
|
|
|
DateTime finishDate, CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
var request = new WellOperationRequest
|
|
|
|
|
{
|
|
|
|
|
IdWell = idWell,
|
|
|
|
|
OperationType = WellOperation.IdOperationTypeFact,
|
|
|
|
|
GeDate = startDate,
|
|
|
|
|
LtDate = finishDate,
|
|
|
|
|
SortFields = new[] { "DateStart asc" },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return wellOperationRepository.GetAsync(request, cancellationToken);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Task<IEnumerable<SubsystemStatDto>?> GetSubsystemStatsAsync(int idWell, DateTime startDate,
|
|
|
|
|
DateTime finishDate, CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
var request = new SubsystemOperationTimeRequest
|
|
|
|
|
{
|
|
|
|
|
IdWell = idWell,
|
|
|
|
|
GtDate = startDate,
|
|
|
|
|
LtDate = finishDate,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return subsystemOperationTimeService.GetStatAsync(request, cancellationToken);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Task<IEnumerable<LimitingParameterDto>> GetLimitingParameterStatsAsync(int idWell,
|
|
|
|
|
DateTime startDate, DateTime finishDate, CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
var request = new LimitingParameterRequest
|
|
|
|
|
{
|
|
|
|
|
IdWell = idWell,
|
|
|
|
|
GtDate = startDate,
|
|
|
|
|
LtDate = finishDate,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return limitingParameterService.GetStatAsync(request, cancellationToken);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int GetFileSize()
|
|
|
|
|
{
|
2023-07-25 17:07:50 +05:00
|
|
|
|
const int fileSizeTemplate = 10240;
|
2023-07-25 17:38:58 +05:00
|
|
|
|
// TODO: Добавку размера сделать более предсказуемой на основе даты рапорта. что то типа `(Date.Ticks * idWell) % (fileSizeTemplate / 10)`
|
|
|
|
|
return new Random().Next(1, 8193) + fileSizeTemplate;
|
2023-07-24 11:14:07 +05:00
|
|
|
|
}
|
|
|
|
|
}
|