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:
Olga Nemt 2024-04-17 11:11:03 +05:00
commit d1195df203
10 changed files with 69 additions and 94 deletions

View File

@ -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) });
} }
} }

View File

@ -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; }
} }
} }

View File

@ -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;

View File

@ -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);

View File

@ -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));

View File

@ -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);
} }
} }

View File

@ -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

View File

@ -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);

View File

@ -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);
} }

View File

@ -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);