forked from ddrilling/AsbCloudServer
Merge branch 'feature/#32181043-add-durationHours-to-compositeWell' of http://test.digitaldrilling.ru:8080/DDrilling/AsbCloudServer into feature/#32181043-add-durationHours-to-compositeWell
This commit is contained in:
commit
d1195df203
@ -45,6 +45,6 @@ public abstract class ProcessMapPlanBaseDto : ChangeLogAbstract, IId, IWellRelat
|
|||||||
public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||||
{
|
{
|
||||||
if (DepthEnd <= DepthStart)
|
if (DepthEnd <= DepthStart)
|
||||||
yield return new("Глубина окончания должна быть больше глубины начала", new string[] { nameof(DepthEnd), nameof(DepthStart) });
|
yield return new("Глубина окончания должна быть больше глубины начала", new string[] { nameof(DepthEnd) });
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -66,7 +66,7 @@ namespace AsbCloudDb.Model
|
|||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
[ForeignKey(nameof(IdPlan))]
|
[ForeignKey(nameof(IdPlan))]
|
||||||
public virtual WellOperation? OperationPlan { get; set; } = null!;
|
public virtual WellOperation? OperationPlan { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -94,15 +94,8 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
if (telemetry.TimeZone is null)
|
if (telemetry.TimeZone is null)
|
||||||
throw new ArgumentInvalidException(nameof(idWell),$"Telemetry id: {telemetry.Id} can't find timezone");
|
throw new ArgumentInvalidException(nameof(idWell),$"Telemetry id: {telemetry.Id} can't find timezone");
|
||||||
|
|
||||||
var timezoneOffset = TimeSpan.FromHours(telemetry.TimeZone.Hours);
|
|
||||||
|
|
||||||
var query = BuildQuery<TEntity, TType>(telemetry.Id, request);
|
var query = BuildQuery<TEntity, TType>(telemetry.Id, request);
|
||||||
|
|
||||||
if (!await query.AnyAsync(token))
|
|
||||||
return Enumerable.Empty<GtrWitsDto>();
|
|
||||||
|
|
||||||
var interval = TimeSpan.FromSeconds(10);
|
|
||||||
|
|
||||||
var idsRecord = WitsParameters.Select(p => p.Key.IdRecord);
|
var idsRecord = WitsParameters.Select(p => p.Key.IdRecord);
|
||||||
|
|
||||||
var entities = await query
|
var entities = await query
|
||||||
@ -111,6 +104,12 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.ToArrayAsync(token);
|
.ToArrayAsync(token);
|
||||||
|
|
||||||
|
if (!entities.Any())
|
||||||
|
return Enumerable.Empty<GtrWitsDto>();
|
||||||
|
|
||||||
|
var interval = TimeSpan.FromSeconds(10);
|
||||||
|
var timezoneOffset = TimeSpan.FromHours(telemetry.TimeZone.Hours);
|
||||||
|
|
||||||
var dtos = entities
|
var dtos = entities
|
||||||
.GroupBy(e => e.DateTime.Ticks / interval.Ticks)
|
.GroupBy(e => e.DateTime.Ticks / interval.Ticks)
|
||||||
.Select(groupByInterval =>
|
.Select(groupByInterval =>
|
||||||
@ -131,17 +130,17 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
private IQueryable<TEntity> BuildQuery<TEntity, TType>(int idTelemetry, GtrRequest request)
|
private IQueryable<TEntity> BuildQuery<TEntity, TType>(int idTelemetry, GtrRequest request)
|
||||||
where TEntity : WitsItemBase<TType>
|
where TEntity : WitsItemBase<TType>
|
||||||
where TType : notnull
|
where TType : notnull
|
||||||
{
|
{
|
||||||
var dateIntervalStart = DateTime.UtcNow.AddSeconds(-request.IntervalSec);
|
|
||||||
|
|
||||||
var query = db.Set<TEntity>()
|
var query = db.Set<TEntity>()
|
||||||
.Where(e => e.IdTelemetry == idTelemetry)
|
.Where(e => e.IdTelemetry == idTelemetry);
|
||||||
.Where(e => e.DateTime >= dateIntervalStart);
|
|
||||||
|
|
||||||
if (request.Begin.HasValue)
|
if (request.Begin.HasValue)
|
||||||
{
|
{
|
||||||
var dateBeginUtc = request.Begin.Value.ToUniversalTime();
|
var dateBegin = request.Begin.Value.ToUniversalTime();
|
||||||
query = query.Where(e => e.DateTime >= dateBeginUtc);
|
var dateEnd = dateBegin.AddSeconds(request.IntervalSec);
|
||||||
|
query = query
|
||||||
|
.Where(e => e.DateTime >= dateBegin)
|
||||||
|
.Where(e => e.DateTime <= dateEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
return query;
|
return query;
|
||||||
|
@ -177,8 +177,7 @@ public class DailyReportService : IDailyReportService
|
|||||||
datesRange.To = finishDate;
|
datesRange.To = finishDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Count = (int)(Math.Ceiling((datesRange.To - DateTimeOffset.UnixEpoch).TotalDays)
|
result.Count = (datesRange.To.Day - DateTimeOffset.UnixEpoch.Day) - (datesRange.From.Day - DateTimeOffset.UnixEpoch.Day);
|
||||||
- Math.Floor((datesRange.From - DateTimeOffset.UnixEpoch).TotalDays));
|
|
||||||
|
|
||||||
var existingDailyReports = await dailyReportRepository.GetAsync(idWell, request, cancellationToken);
|
var existingDailyReports = await dailyReportRepository.GetAsync(idWell, request, cancellationToken);
|
||||||
|
|
||||||
|
@ -420,46 +420,20 @@ public class OperationsStatService : IOperationsStatService
|
|||||||
|
|
||||||
public async Task<IEnumerable<PlanFactPredictBase<WellOperationDto>>> GetTvdAsync(int idWell, CancellationToken token)
|
public async Task<IEnumerable<PlanFactPredictBase<WellOperationDto>>> GetTvdAsync(int idWell, CancellationToken token)
|
||||||
{
|
{
|
||||||
var wellOperations = await db.WellOperations
|
var wellOperations = (await GetOperationsAsync(idWell, token)).ToArray();
|
||||||
.Include(o => o.OperationCategory)
|
if (!wellOperations.Any())
|
||||||
.Include(o => o.WellSectionType)
|
|
||||||
.Include(o => o.OperationPlan)
|
|
||||||
.Where(o => o.IdWell == idWell)
|
|
||||||
.OrderBy(o => o.DateStart)
|
|
||||||
.ThenBy(o => o.DepthEnd)
|
|
||||||
.AsNoTracking()
|
|
||||||
.ToListAsync(token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
var wellOperationsPlan = wellOperations
|
|
||||||
.Where(o => o.IdType == WellOperation.IdOperationTypePlan)
|
|
||||||
.OrderBy(o => o.DateStart)
|
|
||||||
.ThenBy(o => o.DepthEnd);
|
|
||||||
|
|
||||||
var wellOperationsFact = wellOperations
|
|
||||||
.Where(o => o.IdType == WellOperation.IdOperationTypeFact)
|
|
||||||
.OrderBy(o => o.DateStart)
|
|
||||||
.ThenBy(o => o.DepthEnd);
|
|
||||||
|
|
||||||
var sectionsIds = wellOperations
|
|
||||||
.Select(o => o.IdWellSectionType)
|
|
||||||
.Distinct();
|
|
||||||
|
|
||||||
var tzOffsetHours = wellService.GetTimezone(idWell).Hours;
|
|
||||||
|
|
||||||
var merged = MergeArraysBySections(sectionsIds, wellOperationsPlan, wellOperationsFact).ToList();
|
|
||||||
if (merged.Count ==0)
|
|
||||||
return Enumerable.Empty<PlanFactPredictBase<WellOperationDto>>();
|
return Enumerable.Empty<PlanFactPredictBase<WellOperationDto>>();
|
||||||
|
|
||||||
var tvd = new List<PlanFactPredictBase<WellOperationDto>>(merged.Count);
|
var tzOffsetHours = wellService.GetTimezone(idWell).Hours;
|
||||||
var (Plan, Fact) = merged.FirstOrDefault();
|
var tvd = new List<PlanFactPredictBase<WellOperationDto>>(wellOperations.Length);
|
||||||
|
var (Plan, Fact) = wellOperations.FirstOrDefault();
|
||||||
var dateStart = Plan?.DateStart ?? Fact!.DateStart;
|
var dateStart = Plan?.DateStart ?? Fact!.DateStart;
|
||||||
int? iLastMatch = null;
|
int? iLastMatch = null;
|
||||||
int iLastFact = 0;
|
int iLastFact = 0;
|
||||||
var nptHours = 0d;
|
var nptHours = 0d;
|
||||||
for (int i = 0; i < merged.Count; i++)
|
for (int i = 0; i < wellOperations.Length; i++)
|
||||||
{
|
{
|
||||||
var item = merged[i];
|
var item = wellOperations[i];
|
||||||
var plan = item.Plan;
|
var plan = item.Plan;
|
||||||
var fact = item.Fact;
|
var fact = item.Fact;
|
||||||
|
|
||||||
@ -483,23 +457,23 @@ public class OperationsStatService : IOperationsStatService
|
|||||||
iLastFact = i;
|
iLastFact = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
tvd.Add(planFactPredict);
|
tvd.Add(planFactPredict);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iLastMatch is null || iLastMatch == merged.Count - 1)
|
if (iLastMatch is null || iLastMatch == wellOperations.Length - 1)
|
||||||
return tvd;
|
return tvd;
|
||||||
|
|
||||||
var lastMatchPlan = merged[iLastMatch.Value].Plan!;
|
var lastMatchPlan = wellOperations[iLastMatch.Value].Plan!;
|
||||||
var lastMatchPlanOperationEnd = lastMatchPlan.DateStart.AddHours(lastMatchPlan.DurationHours);
|
var lastMatchPlanOperationEnd = lastMatchPlan.DateStart.AddHours(lastMatchPlan.DurationHours);
|
||||||
var lastFact = merged[iLastFact].Fact!;
|
var lastFact = wellOperations[iLastFact].Fact!;
|
||||||
var lastFactDateEnd = lastFact.DateStart.AddHours(lastFact.DurationHours);
|
var lastFactDateEnd = lastFact.DateStart.AddHours(lastFact.DurationHours);
|
||||||
var startOffset = lastFactDateEnd - lastMatchPlanOperationEnd;
|
var startOffset = lastFactDateEnd - lastMatchPlanOperationEnd;
|
||||||
|
|
||||||
for (int i = iLastMatch.Value + 1; i < merged.Count; i++)
|
for (int i = iLastMatch.Value + 1; i < wellOperations.Length; i++)
|
||||||
{
|
{
|
||||||
if (merged[i].Plan is null)
|
if (wellOperations[i].Plan is null)
|
||||||
continue;
|
continue;
|
||||||
var predict = Convert(merged[i].Plan!, tzOffsetHours);
|
var predict = Convert(wellOperations[i].Plan!, tzOffsetHours);
|
||||||
predict.IdType = 2;
|
predict.IdType = 2;
|
||||||
predict.DateStart = predict.DateStart + startOffset;
|
predict.DateStart = predict.DateStart + startOffset;
|
||||||
predict.Day = (predict.DateStart - dateStart).TotalDays;
|
predict.Day = (predict.DateStart - dateStart).TotalDays;
|
||||||
@ -509,33 +483,33 @@ public class OperationsStatService : IOperationsStatService
|
|||||||
return tvd;
|
return tvd;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<(WellOperation? Plan, WellOperation? Fact)> MergeArraysBySections(
|
private async Task<IEnumerable<(WellOperation? Plan, WellOperation? Fact)>> GetOperationsAsync(int idWell, CancellationToken token)
|
||||||
IEnumerable<int> sectionsIds,
|
|
||||||
IOrderedEnumerable<WellOperation> wellOperationsPlan,
|
|
||||||
IOrderedEnumerable<WellOperation> wellOperationsFact)
|
|
||||||
{
|
{
|
||||||
var merged = new List<(WellOperation? Plan, WellOperation? Fact)>(wellOperationsPlan.Count());
|
var query = db.WellOperations
|
||||||
foreach (var sectionId in sectionsIds)
|
.Include(o => o.OperationCategory)
|
||||||
{
|
.Include(o => o.WellSectionType)
|
||||||
var sectionOperationsPlan = wellOperationsPlan
|
.Where(o => o.IdWell == idWell)
|
||||||
.Where(o => o.IdWellSectionType == sectionId);
|
.OrderBy(o => o.DateStart)
|
||||||
var sectionOperationsFact = wellOperationsFact
|
.ThenBy(o => o.DepthEnd);
|
||||||
.Where(o => o.IdWellSectionType == sectionId);
|
|
||||||
var sectionMerged = MergeArrays(sectionOperationsPlan, sectionOperationsFact);
|
|
||||||
merged.AddRange(sectionMerged);
|
|
||||||
}
|
|
||||||
return merged;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<(WellOperation? Plan, WellOperation? Fact)> MergeArrays(IEnumerable<WellOperation> operationsPlan, IEnumerable<WellOperation> operationsFact)
|
var operationsFactWithNoPlan = await query.Where(o => o.IdPlan == null && o.IdType == WellOperation.IdOperationTypeFact)
|
||||||
{
|
.AsNoTracking()
|
||||||
var operationsFactWithNoPlan = operationsFact.Where(x => x.IdPlan == null).ToArray();
|
.ToArrayAsync(token);
|
||||||
var operationsFactWithPlan = operationsFact.Where(x => x.IdPlan != null).ToArray();
|
|
||||||
|
|
||||||
var idsPlanWithFact = operationsFact.Where(x => x.IdPlan is not null).Select(x => x.IdPlan).Distinct();
|
var operationsFactWithPlan = await query.Where(o => o.IdPlan != null && o.IdType == WellOperation.IdOperationTypeFact)
|
||||||
var operationsPlanWithNoFact = operationsPlan.Where(x => !idsPlanWithFact.Contains(x.IdPlan)).ToArray();
|
.Include(o => o.OperationPlan)
|
||||||
|
.ThenInclude(o => o!.WellSectionType)
|
||||||
|
.Include(o => o.OperationPlan)
|
||||||
|
.ThenInclude(o => o!.OperationCategory)
|
||||||
|
.AsNoTracking()
|
||||||
|
.ToArrayAsync(token);
|
||||||
|
|
||||||
var result = new List<(WellOperation? Plan, WellOperation? Fact)>(operationsFactWithNoPlan.Length + operationsFactWithPlan.Length + operationsPlanWithNoFact.Length);
|
var idsPlanWithFact = operationsFactWithPlan.Select(o => o.IdPlan).Distinct();
|
||||||
|
var operationsPlanWithNoFact = await query
|
||||||
|
.Where(o => o.IdType == WellOperation.IdOperationTypePlan && !idsPlanWithFact.Contains(o.IdPlan)).ToArrayAsync(token);
|
||||||
|
|
||||||
|
var capacity = operationsFactWithNoPlan.Length + operationsFactWithPlan.Length + operationsPlanWithNoFact.Length;
|
||||||
|
var result = new List<(WellOperation? Plan, WellOperation? Fact)>(capacity);
|
||||||
|
|
||||||
foreach (var operation in operationsFactWithPlan)
|
foreach (var operation in operationsFactWithPlan)
|
||||||
result.Add((operation.OperationPlan, operation));
|
result.Add((operation.OperationPlan, operation));
|
||||||
|
@ -67,10 +67,12 @@ public class PeriodicBackgroundWorkerTest
|
|||||||
{
|
{
|
||||||
var expectadResult = 42;
|
var expectadResult = 42;
|
||||||
var result = 0;
|
var result = 0;
|
||||||
|
using var semaphore = new SemaphoreSlim(0, 1);
|
||||||
|
|
||||||
Task workAction(string id, IServiceProvider services, Action<string, double?> callback, CancellationToken token)
|
Task workAction(string id, IServiceProvider services, Action<string, double?> callback, CancellationToken token)
|
||||||
{
|
{
|
||||||
result = expectadResult;
|
result = expectadResult;
|
||||||
|
semaphore.Release();
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
var goodWork = Work.CreateByDelegate("", workAction);
|
var goodWork = Work.CreateByDelegate("", workAction);
|
||||||
@ -85,12 +87,12 @@ public class PeriodicBackgroundWorkerTest
|
|||||||
service.Add(badWork, TimeSpan.FromSeconds(2));
|
service.Add(badWork, TimeSpan.FromSeconds(2));
|
||||||
service.Add(goodWork, TimeSpan.FromSeconds(2));
|
service.Add(goodWork, TimeSpan.FromSeconds(2));
|
||||||
|
|
||||||
await Task.Delay(TimeSpan.FromMilliseconds(256));
|
await semaphore.WaitAsync(4_100);
|
||||||
|
|
||||||
//assert
|
//assert
|
||||||
Assert.Equal(expectadResult, result);
|
|
||||||
Assert.Equal(1, badWork.CountErrors);
|
Assert.Equal(1, badWork.CountErrors);
|
||||||
Assert.Equal(1, goodWork.CountComplete);
|
Assert.Equal(1, goodWork.CountComplete);
|
||||||
Assert.Equal(1, goodWork.CountStart);
|
Assert.Equal(1, goodWork.CountStart);
|
||||||
|
Assert.Equal(expectadResult, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AsbCloudInfrastructure.Background;
|
using AsbCloudInfrastructure.Background;
|
||||||
@ -87,7 +88,7 @@ public class WorkTest
|
|||||||
Assert.Equal(expectedProgress, currentState.Progress);
|
Assert.Equal(expectedProgress, currentState.Progress);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact, MethodImpl(MethodImplOptions.NoOptimization)]
|
||||||
public async Task ExecutionWork_ShouldReturn_FailsWithInfo()
|
public async Task ExecutionWork_ShouldReturn_FailsWithInfo()
|
||||||
{
|
{
|
||||||
//arrange
|
//arrange
|
||||||
|
@ -157,7 +157,7 @@ public class DailyReportServiceTest
|
|||||||
IdParentCategory = 4001,
|
IdParentCategory = 4001,
|
||||||
IdWellSectionType = 1,
|
IdWellSectionType = 1,
|
||||||
OperationCategoryName = "Механическое. бурение",
|
OperationCategoryName = "Механическое. бурение",
|
||||||
DateStart = new DateTime(2023, 10, 26),
|
DateStart = new DateTime(2023, 10, 26, 0, 0, 0),
|
||||||
DepthStart = 80,
|
DepthStart = 80,
|
||||||
DepthEnd = 150,
|
DepthEnd = 150,
|
||||||
DurationHours = 8,
|
DurationHours = 8,
|
||||||
@ -169,7 +169,7 @@ public class DailyReportServiceTest
|
|||||||
OperationCategoryName = "Механическое. бурение",
|
OperationCategoryName = "Механическое. бурение",
|
||||||
IdWellSectionType = 1,
|
IdWellSectionType = 1,
|
||||||
IdParentCategory = 4001,
|
IdParentCategory = 4001,
|
||||||
DateStart = new DateTime(2023, 10, 26),
|
DateStart = new DateTime(2023, 10, 26, 23, 59, 59),
|
||||||
DepthStart = 150,
|
DepthStart = 150,
|
||||||
DepthEnd = 200,
|
DepthEnd = 200,
|
||||||
DurationHours = 8,
|
DurationHours = 8,
|
||||||
@ -507,7 +507,7 @@ public class DailyReportServiceTest
|
|||||||
public async Task GetAsync_ShouldReturn_FictiveDailyReport()
|
public async Task GetAsync_ShouldReturn_FictiveDailyReport()
|
||||||
{
|
{
|
||||||
//arrange
|
//arrange
|
||||||
var expectedCount = (fakeLastFactWellOperation.DateStart - fakeFirstFactWellOperation.DateStart).TotalDays + 1;
|
var expectedCount = fakeLastFactWellOperation.DateStart.Day - fakeFirstFactWellOperation.DateStart.Day;
|
||||||
|
|
||||||
//act
|
//act
|
||||||
var result = await dailyReportService.GetAsync(idWell, new FileReportRequest(), CancellationToken.None);
|
var result = await dailyReportService.GetAsync(idWell, new FileReportRequest(), CancellationToken.None);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using AsbCloudApp.Data;
|
using System;
|
||||||
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
@ -150,9 +151,8 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
{
|
{
|
||||||
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
|
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
|
||||||
return Forbid();
|
return Forbid();
|
||||||
|
|
||||||
var result = await operationsStatService.GetTvdAsync(idWell, token)
|
var result = await operationsStatService.GetTvdAsync(idWell, token);
|
||||||
.ConfigureAwait(false);
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ namespace AsbCloudWebApi.Controllers.SAUB
|
|||||||
this.wellService = wellService;
|
this.wellService = wellService;
|
||||||
this.telemetryHubContext = telemetryHubContext;
|
this.telemetryHubContext = telemetryHubContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получить значение от ГТИ
|
/// Получить значение от ГТИ
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -49,7 +49,7 @@ namespace AsbCloudWebApi.Controllers.SAUB
|
|||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Permission]
|
[Permission]
|
||||||
[ProducesResponseType(typeof(IEnumerable<GtrWitsDto>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(IEnumerable<GtrWitsDto>), StatusCodes.Status200OK)]
|
||||||
public async Task<IActionResult> GetAllAsync(int idWell, [FromQuery] GtrRequest request, CancellationToken token)
|
public async Task<IActionResult> GetAllAsync([Required] int idWell, [FromQuery] GtrRequest request, CancellationToken token)
|
||||||
{
|
{
|
||||||
await AssertUserHasAccessToWellAsync(idWell, token);
|
await AssertUserHasAccessToWellAsync(idWell, token);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user