diff --git a/AsbCloudApp/Repositories/IWellOperationRepository.cs b/AsbCloudApp/Repositories/IWellOperationRepository.cs
index c6b3c724..b7b433fe 100644
--- a/AsbCloudApp/Repositories/IWellOperationRepository.cs
+++ b/AsbCloudApp/Repositories/IWellOperationRepository.cs
@@ -75,5 +75,21 @@ namespace AsbCloudApp.Repositories
///
///
Task> GetAll(WellOperationRequest request, CancellationToken token);
+
+ ///
+ /// Получить список операций по запросу
+ ///
+ ///
+ ///
+ ///
+ Task> GetAll(WellOperationRepositoryRequest request, CancellationToken token);
+
+ ///
+ /// Получить список операций по ключу скважины
+ ///
+ ///
+ ///
+ ///
+ Task> GetAll(int idWell, CancellationToken token);
}
}
\ No newline at end of file
diff --git a/AsbCloudApp/Requests/WellOperationRequest.cs b/AsbCloudApp/Requests/WellOperationRequest.cs
index f80f4544..6f4cf24a 100644
--- a/AsbCloudApp/Requests/WellOperationRequest.cs
+++ b/AsbCloudApp/Requests/WellOperationRequest.cs
@@ -101,4 +101,48 @@ public class WellOperationRequest : WellOperationRequestBase
[Required]
[Length(1, 100)]
public IEnumerable IdsWell { get; }
+}
+
+///
+/// Запрос получения ГГД с идентификаторами скважин
+///
+public class WellOperationRepositoryRequest
+{
+ ///
+ /// Идентификаторы скважин
+ ///
+ [Required]
+ [Length(1, 100)]
+ public IEnumerable IdsWell { get; }
+
+ ///
+ /// Меньше или равно дате окончания операции
+ ///
+ public DateTimeOffset? LeDate { get; set; }
+
+ ///
+ /// Меньше или равно глубины скважины на конец операции.
+ ///
+ public double? LeDepth { get; set; }
+
+ ///
+ /// Тип операций
+ ///
+ /// - 0 - плановая операция
+ /// - 1 - фактическая операция
+ ///
+ ///
+ public int? OperationType { get; set; }
+
+ ///
+ ///
+ ///
+ ///
+ public WellOperationRepositoryRequest(WellOperationRequest request)
+ {
+ IdsWell = request.IdsWell;
+ LeDate = request.LeDate;
+ LeDepth = request.LeDepth;
+ OperationType = request.OperationType;
+ }
}
\ No newline at end of file
diff --git a/AsbCloudApp/Services/IWellOperationService.cs b/AsbCloudApp/Services/IWellOperationService.cs
index fc755237..ea4b466b 100644
--- a/AsbCloudApp/Services/IWellOperationService.cs
+++ b/AsbCloudApp/Services/IWellOperationService.cs
@@ -52,6 +52,14 @@ namespace AsbCloudApp.Services
///
///
Task> GetGroupOperationsStatAsync(WellOperationRequest request, CancellationToken token);
+
+ ///
+ /// Получить данные для графика TVD
+ ///
+ ///
+ ///
+ ///
+ Task>> GetTvdAsync(int idWell, CancellationToken token);
}
diff --git a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs
index 1e0d1add..f557d106 100644
--- a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs
+++ b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs
@@ -281,6 +281,44 @@ public class WellOperationRepository : CrudRepositoryBase> GetAll(WellOperationRepositoryRequest request, CancellationToken token)
+ {
+ var timezoneOffsetDictionary = new Dictionary();
+ foreach (var idWell in request.IdsWell)
+ {
+ var offset = wellService.GetTimezone(idWell).Offset;
+ timezoneOffsetDictionary.Add(idWell, offset);
+ }
+
+ var query = GetQuery()
+ .Where(e => request.IdsWell.Contains(e.IdWell))
+ .OrderBy(e => e.DateStart)
+ .AsQueryable();
+ query = FilterByRequest(query, request);
+
+ var entities = await query.ToArrayAsync(token);
+
+ var dtos = entities.Select(o => Convert(o, timezoneOffsetDictionary[o.IdWell]));
+ return dtos;
+ }
+
+ public async Task> GetAll(int idWell, CancellationToken token)
+ {
+ var offset = wellService.GetTimezone(idWell).Offset;
+
+ var query = GetQuery()
+ .Include(o => o.OperationCategory)
+ .Include(o => o.WellSectionType)
+ .Where(o => o.IdWell == idWell)
+ .OrderBy(o => o.DateStart)
+ .ThenBy(o => o.DepthEnd);
+
+ var entities = await query.ToArrayAsync(token);
+
+ var dtos = entities.Select(o => Convert(o, offset));
+ return dtos;
+ }
+
public static IQueryable FilterByRequest(IQueryable entities, WellOperationRequest request)
{
@@ -313,4 +351,20 @@ public class WellOperationRepository : CrudRepositoryBase FilterByRequest(IQueryable entities, WellOperationRepositoryRequest request)
+ {
+ if (request.OperationType.HasValue)
+ entities = entities.Where(e => e.IdType == request.OperationType.Value);
+ if (request.LeDepth.HasValue)
+ entities = entities.Where(e => e.DepthEnd <= request.LeDepth.Value);
+ if (request.LeDate.HasValue)
+ {
+ var leDateUtc = request.LeDate.Value.UtcDateTime;
+ entities = entities.Where(e => e.DateStart <= leDateUtc);
+ }
+ entities = entities.AsQueryable().OrderBy(e => e.DateStart);
+
+ return entities;
+ }
}
\ No newline at end of file
diff --git a/AsbCloudInfrastructure/Services/WellOperationService/WellOperationService.cs b/AsbCloudInfrastructure/Services/WellOperationService/WellOperationService.cs
index c1ff4eb3..17665e8c 100644
--- a/AsbCloudInfrastructure/Services/WellOperationService/WellOperationService.cs
+++ b/AsbCloudInfrastructure/Services/WellOperationService/WellOperationService.cs
@@ -156,8 +156,8 @@ public class WellOperationService : IWellOperationService
private async Task<(IEnumerable items, int count)> GetWithDaysAndNpvAsync(WellOperationRequest request, CancellationToken token)
{
- var requestByWellIds = new WellOperationRequest(request.IdsWell);
- var wellOperationsBaseDtos = await wellOperationRepository.GetAll(requestByWellIds, token);
+ var wellOperationRepositoryRequest = new WellOperationRepositoryRequest(request);
+ var wellOperationsBaseDtos = await wellOperationRepository.GetAll(wellOperationRepositoryRequest, token);
var groupedByWellAndTypeDtos = wellOperationsBaseDtos
.GroupBy(e => new { e.IdWell, e.IdType });
@@ -198,6 +198,92 @@ public class WellOperationService : IWellOperationService
return (result, count);
}
+ private async Task> GetOperationsAsync(int idWell, CancellationToken token)
+ {
+ var request = new WellOperationRequest(new int[] { idWell });
+ var (items, _) = await GetWithDaysAndNpvAsync(request, token);
+
+ var operationsFactWithNoPlan = items.Where(o => o.IdPlan == null && o.IdType == WellOperation.IdOperationTypeFact);
+
+ var operationsFactWithPlan = items.Where(o => o.IdPlan != null && o.IdType == WellOperation.IdOperationTypeFact);
+
+ var idsPlanWithFact = operationsFactWithPlan.Select(o => o.IdPlan).Distinct();
+ var operationsPlanWithNoFact = items.Where(o => o.IdType == WellOperation.IdOperationTypePlan && !idsPlanWithFact.Contains(o.IdPlan));
+
+ var capacity = operationsFactWithNoPlan.Count() + operationsFactWithPlan.Count() + operationsPlanWithNoFact.Count();
+ var result = new List<(WellOperationDto? Plan, WellOperationDto? Fact)>(capacity);
+
+ var operationsPlan = items.Where(o => o.IdType == WellOperation.IdOperationTypePlan);
+ foreach (var operation in operationsFactWithPlan)
+ {
+ var operationPlanDict = operationsPlan.FirstOrDefault(o => o.IdPlan == operation.IdPlan);
+ result.Add((operationPlanDict, operation));
+ }
+
+ foreach (var operation in operationsFactWithNoPlan)
+ result.Add((null, operation));
+
+ foreach (var operation in operationsPlanWithNoFact)
+ result.Add((operation, null));
+
+ return result
+ .OrderBy(x => x.Plan?.DateStart)
+ .ThenBy(x => x.Fact?.DateStart);
+ }
+
+ public async Task>> GetTvdAsync(int idWell, CancellationToken token)
+ {
+ var wellOperations = (await GetOperationsAsync(idWell, token)).ToArray();
+ if (!wellOperations.Any())
+ return Enumerable.Empty>();
+
+ var tvd = new List>(wellOperations.Length);
+ var (Plan, Fact) = wellOperations.FirstOrDefault();
+ var dateStart = Plan?.DateStart ?? Fact!.DateStart;
+ int? iLastMatch = null;
+ int iLastFact = 0;
+
+ for (int i = 0; i < wellOperations.Length; i++)
+ {
+ var item = wellOperations[i];
+
+ var planFactPredict = new PlanFactPredictBase()
+ {
+ Plan = item.Plan,
+ Fact = item.Fact
+ };
+ if (item.Plan is not null && item.Fact is not null)
+ iLastMatch = i;
+
+ if (item.Fact is not null)
+ iLastFact = i;
+
+ tvd.Add(planFactPredict);
+ }
+
+ if (iLastMatch is null || iLastMatch == wellOperations.Length - 1)
+ return tvd;
+
+ var lastMatchPlan = wellOperations[iLastMatch.Value].Plan!;
+ var lastMatchPlanOperationEnd = lastMatchPlan.DateStart.AddHours(lastMatchPlan.DurationHours);
+ var lastFact = wellOperations[iLastFact].Fact!;
+ var lastFactDateEnd = lastFact.DateStart.AddHours(lastFact.DurationHours);
+ var startOffset = lastFactDateEnd - lastMatchPlanOperationEnd;
+
+ for (int i = iLastMatch.Value + 1; i < wellOperations.Length; i++)
+ {
+ if (wellOperations[i].Plan is null)
+ continue;
+ var predict = wellOperations[i].Plan!;
+ predict.IdType = 2;
+ predict.DateStart = predict.DateStart + startOffset;
+ predict.Day = (predict.DateStart - dateStart).TotalDays;
+ tvd[i].Predict = predict;
+ }
+
+ return tvd;
+ }
+
public static IEnumerable FilterByRequest(IEnumerable dtos, WellOperationRequest request)
{
if (request.OperationType.HasValue)
diff --git a/AsbCloudWebApi/Controllers/OperationStatController.cs b/AsbCloudWebApi/Controllers/OperationStatController.cs
index a60cc14f..59f907bd 100644
--- a/AsbCloudWebApi/Controllers/OperationStatController.cs
+++ b/AsbCloudWebApi/Controllers/OperationStatController.cs
@@ -21,12 +21,17 @@ namespace AsbCloudWebApi.Controllers
public class OperationStatController : ControllerBase
{
private readonly IOperationsStatService operationsStatService;
+ private readonly IWellOperationService wellOperationService;
private readonly IWellService wellService;
- public OperationStatController(IOperationsStatService sectionsService, IWellService wellService)
+ public OperationStatController(
+ IOperationsStatService sectionsService,
+ IWellService wellService,
+ IWellOperationService wellOperationService)
{
this.operationsStatService = sectionsService;
this.wellService = wellService;
+ this.wellOperationService = wellOperationService;
}
///
@@ -152,7 +157,7 @@ namespace AsbCloudWebApi.Controllers
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
return Forbid();
- var result = await operationsStatService.GetTvdAsync(idWell, token);
+ var result = await wellOperationService.GetTvdAsync(idWell, token);
return Ok(result);
}