DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/Subsystems/SubsystemService.cs
2023-12-16 13:22:23 +05:00

218 lines
7.6 KiB
C#

using AsbCloudApp.Data;
using AsbCloudApp.Data.DetectedOperation;
using AsbCloudApp.Data.Subsystems;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services.Subsystems;
internal class SubsystemService : ISubsystemService
{
private const int IdEnabledSubsystemSpinMaster = 128;
private const int IdSubsystemAPD = 1;
private const int IdSubsystemAPDRotor = 11;
private const int IdSubsystemAPDSlide = 12;
private const int IdSubsystemSpinMaster = 65536;
private readonly ICrudRepository<SubsystemDto> subsystemRepository;
private readonly IWellService wellService;
private readonly IDetectedOperationService detectedOperationService;
private readonly ITelemetryDataSaubService telemetryDataSaubService;
public SubsystemService(ICrudRepository<SubsystemDto> subsystemRepository,
IWellService wellService,
IDetectedOperationService detectedOperationService,
ITelemetryDataSaubService telemetryDataSaubService)
{
this.wellService = wellService;
this.subsystemRepository = subsystemRepository;
this.detectedOperationService = detectedOperationService;
this.telemetryDataSaubService = telemetryDataSaubService;
}
public async Task<IEnumerable<SubsystemStatDto>> GetStatAsync(SubsystemTimeRequest request, CancellationToken token)
{
var well = await wellService.GetOrDefaultAsync(request.IdWell, token)
?? throw new ArgumentInvalidException(nameof(request.IdWell), $"Well Id: {request.IdWell} does not exist");
var detectedOperationSummaryRequest = new DetectedOperationSummaryRequest
{
IdsTelemetries = new[] { well.IdTelemetry!.Value },
IdsOperationCategories = WellOperationCategory.MechanicalDrillingSubIds,
GeDateStart = request.GeDate,
LeDateStart = request.LtDate,
GeDepthStart = request.GtDepth,
LeDepthStart = request.LtDepth,
};
var operations = await detectedOperationService.GetOperationSummaryAsync(detectedOperationSummaryRequest,
token);
if (!operations.Any())
return Enumerable.Empty<SubsystemStatDto>();
var stat = await CalcStatAsync(operations, token);
return stat;
}
public async Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(int idCompany, DateTime? gtDate, DateTime? ltDate,
CancellationToken token)
{
var activeWells = await wellService.GetAsync(new() { IdCompany = idCompany, IdState = 1 }, token);
var result = await GetStatAsync(activeWells, gtDate, ltDate, token);
return result;
}
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<SubsystemStatDto>> CalcStatAsync(IEnumerable<OperationsSummaryDto> operations, CancellationToken token)
{
var subsystems = await subsystemRepository.GetAllAsync(token);
var groupedOperations = operations
.GroupBy(o => o.IdCategory);
var stat = groupedOperations.Select(groupOperations =>
{
var idSubsystem = groupOperations.Key switch
{
WellOperationCategory.IdRotor => IdSubsystemAPDRotor,
WellOperationCategory.IdSlide => IdSubsystemAPDSlide,
_ => throw new ArgumentException($"IdCategory: {groupOperations.Key} does not supported in this method",
nameof(groupOperations.Key)),
};
var operationsWithEnableSubsystems = groupOperations.Where(o => o.EnabledSubsystems >= 1);
var subsystemStat = new SubsystemStatDto
{
IdSubsystem = idSubsystem,
SubsystemName = subsystems.FirstOrDefault(s => s.Id == idSubsystem)?.Name ?? "unknown",
UsedTimeHours = operationsWithEnableSubsystems.Sum(o => o.SumDurationHours),
SumOperationDepthInterval = groupOperations.Sum(o => o.SumDepthIntervals),
SumOperationDurationHours = groupOperations.Sum(o => o.SumDurationHours),
SumDepthInterval = operationsWithEnableSubsystems.Sum(o => o.SumDepthIntervals),
OperationCount = operationsWithEnableSubsystems.Sum(o => o.Count),
};
subsystemStat.KUsage = subsystemStat.SumDepthInterval / subsystemStat.SumOperationDepthInterval;
return subsystemStat;
});
var apdSlidePart = stat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemAPDSlide);
if (apdSlidePart is not null)
{
var operationsWithSpinMaster = operations.Where(s => s.EnabledSubsystems == IdEnabledSubsystemSpinMaster);
var spin = new SubsystemStatDto
{
IdSubsystem = IdSubsystemSpinMaster,
SubsystemName = subsystems.FirstOrDefault(s => s.Id == IdSubsystemSpinMaster)?.Name ?? "unknown",
UsedTimeHours = operationsWithSpinMaster.Sum(o => o.SumDurationHours),
SumOperationDepthInterval = apdSlidePart.SumOperationDepthInterval,
SumOperationDurationHours = apdSlidePart.SumOperationDurationHours,
SumDepthInterval = operationsWithSpinMaster.Sum(o => o.SumDepthIntervals),
OperationCount = operationsWithSpinMaster.Sum(s => s.Count)
};
spin.KUsage = spin.SumDepthInterval / spin.SumOperationDepthInterval;
stat = stat.Append(spin);
}
var apdParts = stat.Where(s => s.IdSubsystem is IdSubsystemAPDRotor or IdSubsystemAPDSlide);
if (!apdParts.Any())
return stat;
var apdSum = new SubsystemStatDto
{
IdSubsystem = IdSubsystemAPD,
SubsystemName = "АПД",
UsedTimeHours = apdParts.Sum(part => part.UsedTimeHours),
SumOperationDepthInterval = apdParts.Sum(part => part.SumOperationDepthInterval),
SumOperationDurationHours = apdParts.Sum(part => part.SumOperationDurationHours),
SumDepthInterval = apdParts.Sum(part => part.SumDepthInterval),
OperationCount = apdParts.Sum(part => part.OperationCount),
};
apdSum.KUsage = apdSum.SumDepthInterval / apdSum.SumOperationDepthInterval;
stat = stat.Append(apdSum).OrderBy(m => m.IdSubsystem);
return stat;
}
private async Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatAsync(IEnumerable<WellDto> wells, DateTime? gtDate, DateTime? ltDate,
CancellationToken token)
{
if (!wells.Any())
return Enumerable.Empty<SubsystemActiveWellStatDto>();
var idsTelemetries = wells
.Where(w => w.IdTelemetry is not null)
.Select(w => w.IdTelemetry!.Value)
.Distinct();
var wellsStat = new List<SubsystemActiveWellStatDto>();
foreach (var well in wells)
{
var hoursOffset = well.Timezone.Hours;
var dateRange = telemetryDataSaubService.GetRange(well.Id);
var beginUTC = gtDate.HasValue
? gtDate.Value.ToUtcDateTimeOffset(hoursOffset)
: dateRange.From.ToUtcDateTimeOffset(hoursOffset);
var endUTC = ltDate.HasValue
? ltDate.Value.ToUtcDateTimeOffset(hoursOffset)
: dateRange.To.ToUtcDateTimeOffset(hoursOffset);
var operations = await detectedOperationService
.GetOperationSummaryAsync(new()
{
IdsTelemetries = idsTelemetries,
IdsOperationCategories = WellOperationCategory.MechanicalDrillingSubIds,
GeDateStart = beginUTC,
LeDateEnd = endUTC,
}, token);
var wellStat = new SubsystemActiveWellStatDto { Well = well };
var telemetryOperations = operations.Where(o => o.IdTelemetry == well.IdTelemetry);
if (!telemetryOperations.Any())
continue;
var subsystemStat = await CalcStatAsync(telemetryOperations, token);
if (!subsystemStat.Any())
continue;
wellStat.SubsystemAPD = subsystemStat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemAPD);
wellStat.SubsystemSpinMaster = subsystemStat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemSpinMaster);
}
return wellsStat;
}
}