Add WellInfoService

This commit is contained in:
ngfrolov 2023-02-16 16:27:14 +05:00
parent f30c3ce833
commit d41cff84a9
Signed by: ng.frolov
GPG Key ID: E99907A0357B29A7
10 changed files with 232 additions and 184 deletions

View File

@ -2,6 +2,7 @@
namespace AsbCloudApp.Data
{
#nullable enable
/// <summary>
/// Инфо о скважине для отображения на карте
/// </summary>
@ -22,7 +23,7 @@ namespace AsbCloudApp.Data
/// <summary>
/// Плановая и текущая глубина
/// </summary>
public PlanFactDto WellDepth { get; set; }
public PlanFactBase<double?> WellDepth { get; set; } = null!;
/// <summary>
/// Отставание от ГГД, %
@ -32,12 +33,12 @@ namespace AsbCloudApp.Data
/// <summary>
/// Механическая скорость проходки, последней операции бурения
/// </summary>
public PlanFactDto ROP { get; set; }
public PlanFactBase<double?> ROP { get; set; } = null!;
/// <summary>
/// Рейсовая скорость проходки, последнего рейса
/// </summary>
public PlanFactDto RaceSpeed { get; set; }
public PlanFactBase<double?> RaceSpeed { get; set; } = null!;
/// <summary>
/// Процент использования АКБ
@ -49,4 +50,5 @@ namespace AsbCloudApp.Data
/// </summary>
public double SpinUsage { get; set; }
}
#nullable disable
}

View File

@ -1,4 +1,6 @@
namespace AsbCloudApp.Requests
using System.Collections.Generic;
namespace AsbCloudApp.Requests
{
#nullable enable
/// <summary>
@ -15,6 +17,11 @@
/// id состояния
/// </summary>
public int? IdState { get; set; }
/// <summary>
/// Идентификаторы скважин
/// </summary>
public IEnumerable<int>? Ids { get; set; }
}
#nullable disable
}

View File

@ -103,7 +103,6 @@ namespace AsbCloudApp.Services
/// <param name="idCompany"></param>
/// <param name="token"></param>
/// <returns></returns>
#warning GetWellTreeAsync(..) is dummy. Remove it before pullrequest.
Task<IEnumerable<DepositBranchDto>> GetWellTreeAsync(int idCompany, CancellationToken token);
}
#nullable disable

View File

@ -47,6 +47,7 @@ namespace AsbCloudApp.Services.Subsystems
/// <param name="token"></param>
/// <returns></returns>
Task<DatesRangeDto?> GetDateRangeOperationTimeAsync(SubsystemOperationTimeRequest request, CancellationToken token);
/// <summary>
/// Получение статистики по наработке подсистем по активным скважинам
/// </summary>
@ -56,6 +57,14 @@ namespace AsbCloudApp.Services.Subsystems
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(int idCompany, DateTime? gtDate, DateTime? ltDate, CancellationToken token);
/// <summary>
/// Получение статистики по наработке подсистем по активным скважинам
/// </summary>
/// <param name="wellIds"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(IEnumerable<int> wellIds, CancellationToken token);
}
#nullable disable
}

View File

@ -67,5 +67,8 @@ namespace AsbCloudDb.Model
[InverseProperty(nameof(DrillingProgramPart.Well))]
public virtual ICollection<DrillingProgramPart> DrillingProgramParts { get; set; }
[InverseProperty(nameof(ProcessMap.Well))]
public virtual ICollection<ProcessMap> ProcessMaps { get; set; }
}
}

View File

@ -187,20 +187,27 @@ namespace AsbCloudInfrastructure.Services.Subsystems
return depthIntervalSubsystem;
}
private async Task<IEnumerable<WellDto>> GetActiveWellsByCompany(int idCompany, CancellationToken token)
{
var listWell = await wellService.GetAsync(new() { IdCompany = idCompany }, token);
var active = listWell.Where(w => w.IdState == 1);
return active;
}
/// <inheritdoc/>
public async Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(int idCompany, DateTime? gtDate, DateTime? ltDate, CancellationToken token)
{
var wells = await GetActiveWellsByCompany(idCompany, token);
{
var activeWells = await wellService.GetAsync(new() { IdCompany = idCompany, IdState = 1 }, token);
var result = await GetStatAsync(activeWells, gtDate, ltDate, token);
return result;
}
/// <inheritdoc/>
public async Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(IEnumerable<int> wellIds, CancellationToken token)
{
var activeWells = await wellService.GetAsync(new() { Ids = wellIds, IdState = 1 }, token);
var result = await GetStatAsync(activeWells, null, null, token);
return result;
}
private async Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatAsync(IEnumerable<WellDto> wells, DateTime? gtDate, DateTime? ltDate, CancellationToken token)
{
if (!wells.Any())
return Enumerable.Empty<SubsystemActiveWellStatDto>();
return Enumerable.Empty<SubsystemActiveWellStatDto>();
var hoursOffset = wells
.FirstOrDefault(well => well.Timezone is not null)
@ -209,7 +216,7 @@ namespace AsbCloudInfrastructure.Services.Subsystems
var beginUTC = gtDate.HasValue
? gtDate.Value.ToUtcDateTimeOffset(hoursOffset)
:DateTime.Today.AddDays(-1).ToUtcDateTimeOffset(hoursOffset);
: DateTime.Today.AddDays(-1).ToUtcDateTimeOffset(hoursOffset);
var endUTC = ltDate.HasValue
? ltDate.Value.ToUtcDateTimeOffset(hoursOffset)
@ -243,7 +250,7 @@ namespace AsbCloudInfrastructure.Services.Subsystems
var subsystemStat = idTelemetry > 0 && dtos.Any()
? CalcStat(dtos, (depthIntervalRotor, depthIntervalSlide))
: Enumerable.Empty<SubsystemStatDto>();
return new SubsystemActiveWellStatDto
{
Well = well,

View File

@ -0,0 +1,154 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMap;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudApp.Services.Subsystems;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Background;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services
{
#nullable enable
public class WellInfoService
{
class WellMapInfoWithComanies : WellMapInfoDto
{
public IEnumerable<int> IdsCompanies { get; set; } = null!;
}
private const string workId = "Well statistics update";
private static readonly TimeSpan workPeriod = TimeSpan.FromMinutes(30);
private static IEnumerable<WellMapInfoWithComanies> WellMapInfo = Enumerable.Empty<WellMapInfoWithComanies>();
public static WorkPeriodic MakeWork()
{
var workPeriodic = new WorkPeriodic(workId, WorkAction, workPeriod)
{
Timeout = TimeSpan.FromMinutes(30)
};
return workPeriodic;
}
private static async Task WorkAction(string workName, IServiceProvider serviceProvider, CancellationToken token)
{
var db = serviceProvider.GetRequiredService<IAsbCloudDbContext>();
var wellService = serviceProvider.GetRequiredService<IWellService>();
var operationsStatService = serviceProvider.GetRequiredService<IOperationsStatService>();
var processMapRepository = serviceProvider.GetRequiredService<IProcessMapRepository>();
var subsystemOperationTimeService = serviceProvider.GetRequiredService<ISubsystemOperationTimeService>();
var activeWells = await wellService.GetAsync(new() {IdState = 1}, token);
IEnumerable<int> activeWellsIds = activeWells
.Select(w => w.Id);
var idTelemetries = activeWells
.Where(w => w.IdTelemetry != null)
.Select(t => t.IdTelemetry);
var lastTelemetryInfo = await db.TelemetryDataSaub
.Where(t => idTelemetries.Contains(t.IdTelemetry))
.Select(t => new
{
t.IdTelemetry,
t.WellDepth,
t.DateTime,
})
.GroupBy(t => t.IdTelemetry)
.Select(g => g.OrderByDescending(t => t.DateTime)
.First()
)
.AsNoTracking()
.ToArrayAsync(token);
var processMapRequests = activeWellsIds.Select(id => new ProcessMapRequest { IdWell = id });
var processMaps = await processMapRepository.GetProcessMapAsync(processMapRequests, token);
var wellDepthByProcessMap = processMaps
.GroupBy(p => p.IdWell)
.Select(g => new
{
Id = g.Key,
DepthEnd = g.Max(p => p.DepthEnd)
});
var operationsStat = await operationsStatService.GetWellsStatAsync(activeWellsIds, token);
var subsystemStat = await subsystemOperationTimeService.GetStatByActiveWells(activeWellsIds, token);
WellMapInfo = activeWells.Select(well => {
var wellMapInfo = well.Adapt<WellMapInfoWithComanies>();
// From teltemetryTracker
var wellLastTelemetryInfo = lastTelemetryInfo.FirstOrDefault(t => t.IdTelemetry == well.IdTelemetry);
var wellOperationsStat = operationsStat.FirstOrDefault(s => s.Id == well.Id);
var wellLastFactSection = wellOperationsStat?.Sections.LastOrDefault(s => s.Fact is not null);
var wellSubsystemStat = subsystemStat.FirstOrDefault(s => s.Well.Id == well.Id);
double currentDepth = wellLastTelemetryInfo?.WellDepth
?? wellLastFactSection?.Fact.WellDepthEnd
?? 0d;
var wellProcessMaps = processMaps
.Where(p => p.IdWell == well.Id)
.OrderBy(p => p.DepthEnd);
int? idSection = wellLastFactSection?.Id;
ProcessMapDto? welllProcessMap;
if (idSection is not null)
{
welllProcessMap = wellProcessMaps.FirstOrDefault(p => p.IdWellSectionType == idSection);
}
else
{
welllProcessMap = wellProcessMaps.FirstOrDefault(p => p.DepthStart <= currentDepth && p.DepthEnd >= currentDepth);
idSection ??= welllProcessMap?.IdWellSectionType;
}
wellMapInfo.LastTelemetryDate = wellLastTelemetryInfo?.DateTime.ToRemoteDateTime(5) ?? new DateTime();
wellMapInfo.WellDepth = new()
{
Plan = wellDepthByProcessMap.FirstOrDefault(p => p.Id == well.Id)?.DepthEnd,
Fact = currentDepth,
};
wellMapInfo.ROP = new()
{
Plan = welllProcessMap?.RopPlan,
Fact = wellOperationsStat?.Total.Fact?.Rop,
};
wellMapInfo.RaceSpeed = new()
{
Plan = wellOperationsStat?.Total.Plan?.RouteSpeed,
Fact = wellOperationsStat?.Total.Fact?.RouteSpeed,
};
wellMapInfo.SaubUsage = wellSubsystemStat?.SubsystemAKB?.KUsage ?? 0d;
wellMapInfo.SpinUsage = wellSubsystemStat?.SubsystemSpinMaster?.KUsage ?? 0d;
wellMapInfo.TvdLagPercent = 0;// From WellOperationService?
wellMapInfo.IdsCompanies = well.Companies.Select(c => c.Id);
return wellMapInfo;
}).ToArray();
}
public static IEnumerable<WellMapInfoDto> Where(Func<WellMapInfoDto, bool> predicate)
=> WellMapInfo.Where(predicate);
public static WellMapInfoDto? FirstOrDefault(Func<WellMapInfoDto, bool> predicate)
=> WellMapInfo.FirstOrDefault(predicate);
}
#nullable disable
}

View File

@ -69,7 +69,7 @@ namespace AsbCloudInfrastructure.Services
return lastTelemetryDate;
}
#warning GetWellTreeAsync(..) is dummy. Remove it before pullrequest.
/// <inheritdoc/>
public async Task<IEnumerable<DepositBranchDto>> GetWellTreeAsync(int idCompany, CancellationToken token)
{
var wells = await GetEntitiesAsync(new() { IdCompany = idCompany }, token);
@ -93,15 +93,13 @@ namespace AsbCloudInfrastructure.Services
Longitude = gCluster.Key.Longitude ?? gDeposit.Key.Longitude,
Wells = gCluster.Select(well =>
{
var dto = well.Adapt<WellMapInfoDto>();
if (dto.Latitude is null)
dto.Latitude = gCluster.Key.Latitude ?? gDeposit.Key.Latitude;
if (dto.Longitude is null)
dto.Longitude = gCluster.Key.Longitude ?? gDeposit.Key.Longitude;
var dto = WellInfoService.FirstOrDefault(w => w.Id == well.Id);
dto ??= well.Adapt<WellMapInfoDto>();
dto.Latitude ??= gCluster.Key.Latitude ?? gDeposit.Key.Latitude;
dto.Longitude ??= gCluster.Key.Longitude ?? gDeposit.Key.Longitude;
if (well.IdTelemetry is not null)
dto.LastTelemetryDate = telemetryService.GetLastTelemetryDate(well.IdTelemetry.Value);
return dto;
}),
}),
@ -120,10 +118,12 @@ namespace AsbCloudInfrastructure.Services
{
var wells = await GetCacheAsync(token);
if (request.Ids?.Any() == true)
wells = wells.Where(well => request.Ids.Contains(well.Id));
if (request.IdCompany.HasValue)
wells = wells.Where(well => well.RelationCompaniesWells.Any(r => r.IdCompany == request.IdCompany.Value));
if (request.IdState.HasValue)
wells = wells.Where(well => well.IdState == request.IdState.Value);

View File

@ -27,7 +27,8 @@ namespace AsbCloudInfrastructure
var wellService = provider.GetRequiredService<IWellService>();
wellService.EnshureTimezonesIsSetAsync(CancellationToken.None).Wait();// TODO: make this background work
var backgroundWorker = provider.GetRequiredService<Background.BackgroundWorker>();
var backgroundWorker = provider.GetRequiredService<BackgroundWorker>();
backgroundWorker.Push(WellInfoService.MakeWork());
backgroundWorker.Push(OperationDetectionWorkFactory.MakeWork());
backgroundWorker.Push(SubsystemOperationTimeCalcWorkFactory.MakeWork());
backgroundWorker.Push(LimitingParameterCalcWorkFactory.MakeWork());

View File

@ -1,11 +1,17 @@
using iTextSharp.text.pdf;
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Document = iTextSharp.text.Document;
using AsbCloudApp.Data;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure;
using CliWrap;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace ConsoleApp1
{
@ -13,160 +19,20 @@ namespace ConsoleApp1
{
static void Main(/*string[] args*/)
{
// string[] fileExtension = { ".xlsx", ".xls", ".ods", ".odt", ".doc", ".docx", ".pdf" };
// Console.WriteLine($"start convert");
// var inputFiles = new List<string>();
// var resultFile = "C:\\Test\\result.pdf";
// inputFiles.Add("11112222.docx");
// inputFiles.Add("11117777.pdf");
// inputFiles.Add("22223333.xls");
// inputFiles.Add("33334444.xlsx");
// //inputFiles.Add("33334444.tts");
// var listOutNames = new List<string>();
// var filteredFilesNames = inputFiles
// .Distinct()
// .Where(f => fileExtension.Any(fe => f.ToLower().EndsWith(fe)))
// .ToList();
// FileInfo fileInfo = new FileInfo(resultFile);
// //matchesExtensions(inputFiles);
// foreach (var FileName in inputFiles)
// {
// var outputFile = Path.ChangeExtension(FileName, ".pdf");
// var outFile = StartConvertProcessAsync(FileName, outputFile);
// Console.WriteLine($"convert file - {FileName}");
// Console.ReadLine();
// listOutNames.Add(outFile.Result.ToString());
// }
// Console.WriteLine("merged files");
// Console.ReadLine();
// DoMerged(listOutNames, resultFile);
//static void matchesExtensions(List<string> inputFiles)
// {
// string[] fileExtension = { ".xlsx", ".xls", ".ods", ".odt", ".doc", ".docx", ".pdf" };
// foreach (var file in inputFiles)
// {
// var fileExt = Path.GetExtension(file);
// if (fileExtension.All(fe => fileExt != fe))
// {
// throw new FileFormatException($"Файл с именем: {file} не может быть добавлен в список файлов для конвертации и слияния в общий файл программы бурения. Не поддерживаемый формат файла");
// }
// }
// }
if (OperatingSystem.IsWindows())
{
Console.WriteLine("win");
Console.ReadLine();
}
if (OperatingSystem.IsLinux())
{
Console.WriteLine("linux");
Console.ReadLine();
}
}
public static void DoMerged(IEnumerable<string> inputFiles, string outFile)
{
using var stream = new FileStream(outFile, FileMode.Create);
using var doc = new Document();
using var pdf = new PdfCopy(doc, stream);
doc.Open();
var inputFilesList = inputFiles.ToList();
foreach (var file in inputFilesList)
{
var reader = new PdfReader(file);
for (int i = 0; i < reader.NumberOfPages; i++)
{
PdfImportedPage page = pdf.GetImportedPage(reader, i + 1);
pdf.AddPage(page);
}
pdf.FreeReader(reader);
reader.Close();
};
}
private static (string programFile, string programArg) getOptionsStartupProcess(string inputFileName, string resultFileDir)
{
(string programFile, string programArg) startupOptions;
if (OperatingSystem.IsWindows())
{
startupOptions.programFile = "C:\\Program Files\\LibreOffice\\program\\soffice.exe";
startupOptions.programArg = $"-headless -convert-to pdf {inputFileName} --outdir {resultFileDir}";
return startupOptions;
}
if (OperatingSystem.IsLinux())
{
startupOptions.programFile = "/usr/bin/soffice";
startupOptions.programArg = $"--headless --convert-to pdf {inputFileName} --outdir {resultFileDir}";
return (startupOptions);
}
throw new NotSupportedException("Вызов процесса в текущей операционной системе не возможен");
}
//public static void StartConvertProcess(string inputFileName, string outFileName)
//{
// using (Process pdfprocess = new Process())
// {
// pdfprocess.StartInfo.UseShellExecute = true;
// //pdfprocess.StartInfo.LoadUserProfile = true;
// pdfprocess.StartInfo.FileName = "soffice";
// pdfprocess.StartInfo.Arguments = $"--headless --convert-to pdf {inputFileName} --outdir {outFileName}";
// pdfprocess.StartInfo.WorkingDirectory = "/usr/bin";
// pdfprocess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
// pdfprocess.Start();
// if (!pdfprocess.WaitForExit(1000 * 60 * 1))
// {
// pdfprocess.Kill();
// }
// pdfprocess.Close();
// }
//}
private static async Task<string> StartConvertProcessAsync(string inputFileName, string outFileName)
{
var progrAndArg = getOptionsStartupProcess(inputFileName, outFileName);
//string outPath = "/home/eddie/Test/OutFiles";
string outPath = "C:\\Test\\OutFiles";
var result = Cli.Wrap("C:\\Program Files\\LibreOffice\\program\\soffice.exe")
.WithArguments($"-headless -convert-to pdf C:\\Test\\InFiles\\{inputFileName} -outdir {outPath}");
await result.ExecuteAsync();
var outFile = $"{outPath}\\{outFileName}";
return outFile;
}
public static async Task GetConverteAndMergedFileAsync(IEnumerable<string> filesNames, string resultPath)
{
string[] fileExtension = { ".xlsx", ".xls", ".ods", ".odt", ".doc", ".docx", ".pdf" };
//var filteredFilesNames = filesNames.Distinct();
var filteredFilesNames = filesNames
.Distinct()
.Where(f => fileExtension.Any(fe => f.ToLower().EndsWith(fe)))
.ToList();
var listFileNames = filteredFilesNames
.ToList()
.Select(o => new {
inputFile = o,
convertedFile = Path.ChangeExtension(o, ".pdf")
var db = ServiceFactory.Context;
var q = db.TelemetryDataSaub
.Select(t => new {
t.IdTelemetry,
t.DateTime,
t.WellDepth,
})
.GroupBy(t => t.IdTelemetry)
.Select(g => new {
Id = g.Key,
First = g.OrderBy(t => t.DateTime).FirstOrDefault(),
Last = g.OrderBy(t => t.DateTime).LastOrDefault(),
});
foreach (var excelFileName in listFileNames)
{
await StartConvertProcessAsync(excelFileName.inputFile, excelFileName.convertedFile);
Console.WriteLine($"convert file - {excelFileName.inputFile}");
Console.ReadLine();
}
Console.WriteLine("merged files");
Console.ReadLine();
DoMerged(listFileNames.Select(c => c.convertedFile), resultPath);
}
var d = q.AsNoTracking().ToArray();
}
}
}