diff --git a/AsbCloudApp/Repositories/IGtrRepository.cs b/AsbCloudApp/Repositories/IGtrRepository.cs
index 706b6be2..39fbef07 100644
--- a/AsbCloudApp/Repositories/IGtrRepository.cs
+++ b/AsbCloudApp/Repositories/IGtrRepository.cs
@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Requests;
+using AsbCloudApp.Data;
namespace AsbCloudApp.Repositories
{
@@ -60,5 +61,15 @@ namespace AsbCloudApp.Repositories
///
[Obsolete]
IEnumerable GetLastData(int idWell);
+
+ ///
+ /// Доступные даты по скважине
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task GetRangeAsync(int idWell, DateTimeOffset? geDate, DateTimeOffset? leDate, CancellationToken token);
}
}
diff --git a/AsbCloudApp/Requests/GtrRequest.cs b/AsbCloudApp/Requests/GtrRequest.cs
index 43de25c4..89d281a3 100644
--- a/AsbCloudApp/Requests/GtrRequest.cs
+++ b/AsbCloudApp/Requests/GtrRequest.cs
@@ -10,7 +10,7 @@ public class GtrRequest
///
/// Дата начала выборки.По умолчанию: текущее время - IntervalSec
///
- public DateTime? Begin { get; set; }
+ public DateTimeOffset? Begin { get; set; }
///
/// Интервал времени даты начала выборки, секунды
diff --git a/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs b/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs
index cbf87456..3f8333c9 100644
--- a/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs
+++ b/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs
@@ -15,6 +15,8 @@ using System.Threading.Tasks;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Requests;
using Mapster;
+using AsbCloudApp.Data;
+using System.ComponentModel.DataAnnotations;
namespace AsbCloudInfrastructure.Repository
{
@@ -82,6 +84,42 @@ namespace AsbCloudInfrastructure.Repository
public async Task> GetAsync(int idWell, GtrRequest request, CancellationToken token) =>
await GetAsync(idWell, request, token);
+ public async Task GetRangeAsync(int idWell, DateTimeOffset? geDate, DateTimeOffset? leDate, CancellationToken token)
+ {
+ var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell);
+
+ if (telemetry is null)
+ return null;
+
+ var rangeQuery = db
+ .Set()
+ .Where(e => e.IdTelemetry == telemetry.Id);
+
+ if (geDate is not null)
+ rangeQuery = rangeQuery.Where(e => e.DateTime >= geDate);
+
+ if (leDate is not null)
+ rangeQuery = rangeQuery.Where(e => e.DateTime <= leDate);
+
+ var groupedQuery = rangeQuery.GroupBy(e => e.IdTelemetry)
+ .Select(group => new
+ {
+ Min = group.Min(e => e.DateTime),
+ Max = group.Max(e => e.DateTime)
+ });
+ var range = await groupedQuery.FirstOrDefaultAsync(token);
+
+ if (range is null)
+ return null;
+
+ var result = new DatesRangeDto
+ {
+ From = range.Min.ToOffset(telemetry.TimeZone!.Offset),
+ To = range.Max.ToOffset(telemetry.TimeZone!.Offset),
+ };
+ return result;
+ }
+
private async Task> GetAsync(int idWell, GtrRequest request, CancellationToken token)
where TEntity : WitsItemBase
where TType : notnull
@@ -116,8 +154,8 @@ namespace AsbCloudInfrastructure.Repository
{
var items = groupByInterval.Select(e => e);
var values = items.GroupBy(e => (e.IdRecord, e.IdItem))
- .Where(parameter => parameter.Any())
- .ToDictionary(parameter => WitsParameters[parameter.Key], g => g.Last().Value.ToString());
+ .Where(group => WitsParameters.ContainsKey(group.Key))
+ .ToDictionary(group => WitsParameters[group.Key], g => (object)g.Last().Value);
var dto = values.Adapt();
dto.DateTime = items.Last().DateTime.ToOffset(timezoneOffset);
@@ -142,6 +180,19 @@ namespace AsbCloudInfrastructure.Repository
.Where(e => e.DateTime >= dateBegin)
.Where(e => e.DateTime <= dateEnd);
}
+ else
+ {
+ var lastDate = query
+ .OrderBy(e=>e.DateTime)
+ .LastOrDefault()
+ ?.DateTime
+ ?? DateTimeOffset.UtcNow;
+ var dateBegin = lastDate.AddSeconds(-request.IntervalSec);
+ var dateEnd = lastDate;
+ query = query
+ .Where(e => e.DateTime >= dateBegin)
+ .Where(e => e.DateTime <= dateEnd);
+ }
return query;
}
diff --git a/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs b/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs
index 783228c3..d1312e6e 100644
--- a/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs
+++ b/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs
@@ -11,239 +11,232 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-namespace AsbCloudInfrastructure.Services
+namespace AsbCloudInfrastructure.Services;
+
+public class WellCompositeOperationService : IWellCompositeOperationService
{
- public class WellCompositeOperationService : IWellCompositeOperationService
+ private readonly ICrudRepository wellSectionTypeRepository;
+ private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
+ private readonly IWellOperationRepository wellOperationRepository;
+ private readonly IWellService wellService;
+
+ ///
+ /// Тип секции "Транспортный стол"
+ ///
+ private const int wellSectionTransportTable = 5;
+
+ ///
+ /// Тип секции "Эксплуатационная колонна"
+ ///
+ private const int wellSectionProductionString = 4;
+
+
+ ///
+ /// набор настроек для замены одной категории секции на другую
+ ///
+ private static Dictionary<(int, int), int> SettingsForSectionCategoryChange = new Dictionary<(int, int), int>() {
+ { (2, 5096), 5013 },
+ { (2, 5008), 5013 },
+ { (3, 5096), 5084 },
+ { (3, 5008), 5084 },
+ { (3, 5085), 5015 },
+ { (3, 5014), 5015 },
+ { (31, 5014), 5015 },
+ { (31, 5012), 5013 },
+ { (31, 5083), 5013 },
+ { (4, 5085), 5015 },
+ { (4, 5087), 5015 },
+ { (4, 5014), 5015 },
+ { (4, 5053), 5037 },
+ { (4, 5084), 5096 },
+ { (4, 5086), 5013 },
+ { (6, 5085), 5015 },
+ { (6, 5036), 5034 },
+ { (6, 5035), 5097 }
+ };
+
+ private HashSet<(int IdSectionType, int IdCategory)> WellSectionTypesWithCategories = new HashSet<(int IdSectionType, int IdCategory)>()
{
- private readonly ICrudRepository wellSectionTypeRepository;
- private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
- private readonly IWellOperationRepository wellOperationRepository;
- private readonly IWellService wellService;
+ { (2, 5001) },
+ { (2, 5003) },
+ { (2, 5013) },
+ { (2, 5000) },
+ { (2, 5022) },
+ { (2, 5017) },
+ { (2, 5023) },
+ { (2, 4007) },
+ { (2, 5090) },
+ { (3, 5001) },
+ { (3, 5015) },
+ { (3, 5037) },
+ { (3, 5057) },
+ { (3, 5003) },
+ { (3, 5036) },
+ { (3, 5084) },
+ { (3, 5013) },
+ { (3, 5000) },
+ { (3, 5022) },
+ { (3, 5017) },
+ { (3, 4007) },
+ { (3, 5090) },
+ { (3, 5045) },
+ { (3, 5042) },
+ { (3, 5046) },
+ { (31, 5001) },
+ { (31, 5015) },
+ { (31, 5037) },
+ { (31, 5057) },
+ { (31, 5003) },
+ { (31, 5036) },
+ { (31, 5013) },
+ { (31, 5022) },
+ { (31, 5017) },
+ { (31, 5023) },
+ { (31, 4007) },
+ { (31, 5045) },
+ { (31, 5042) },
+ { (31, 5046) },
+ { (4, 5001) },
+ { (4, 5015) },
+ { (4, 5046) },
+ { (4, 5037) },
+ { (4, 5097) },
+ { (4, 5057) },
+ { (4, 5003) },
+ { (4, 5036) },
+ { (4, 5008) },
+ { (4, 5003) },
+ { (4, 5036) },
+ { (4, 5013) },
+ { (4, 5000) },
+ { (4, 5029) },
+ { (4, 5022) },
+ { (4, 5017) },
+ { (4, 5019) },
+ { (4, 5042) },
+ { (4, 5046) },
+ { (6, 5001) },
+ { (6, 5015) },
+ { (6, 5034) },
+ { (6, 5037) },
+ { (6, 5097) },
+ { (6, 5057) },
+ { (6, 5003) }
+ };
- ///
- /// Тип секции "Транспортный стол"
- ///
- private const int wellSectionTransportTable = 5;
+ public WellCompositeOperationService(
+ ICrudRepository wellSectionTypeRepository,
+ IWellOperationCategoryRepository wellOperationCategoryRepository,
+ IWellOperationRepository wellOperationRepository,
+ IWellService wellService)
+ {
+ this.wellSectionTypeRepository = wellSectionTypeRepository;
+ this.wellOperationCategoryRepository = wellOperationCategoryRepository;
+ this.wellOperationRepository = wellOperationRepository;
+ this.wellService = wellService;
+ }
- ///
- /// Тип секции "Эксплуатационная колонна"
- ///
- private const int wellSectionProductionString = 4;
+ public async Task GetAsync(IEnumerable idsWells, CancellationToken token)
+ {
+ var sections = await wellSectionTypeRepository.GetAllAsync(token);
+ var sectionsDict = sections.ToDictionary(s => s.Id, s => s.Caption);
+ var categories = wellOperationCategoryRepository.Get(true);
+ var categoriesDict = categories.ToDictionary(s => s.Id, s => s.Name);
- ///
- /// набор настроек для замены одной категории секции на другую
- ///
- private static Dictionary<(int, int), int> SettingsForSectionCategoryChange = new Dictionary<(int, int), int>() {
- { (2, 5096), 5013 },
- { (2, 5008), 5013 },
- { (3, 5096), 5084 },
- { (3, 5008), 5084 },
- { (3, 5085), 5015 },
- { (3, 5014), 5015 },
- { (31, 5014), 5015 },
- { (31, 5012), 5013 },
- { (31, 5083), 5013 },
- { (4, 5085), 5015 },
- { (4, 5087), 5015 },
- { (4, 5014), 5015 },
- { (4, 5053), 5037 },
- { (4, 5084), 5096 },
- { (4, 5086), 5013 },
- { (6, 5085), 5015 },
- { (6, 5036), 5034 },
- { (6, 5035), 5097 }
+ var wells = await wellService.GetAsync(new WellRequest { Ids = idsWells }, token);
+ var wellsDict = wells.ToDictionary(w => w.Id);
+
+ var idsWellSectionTypes = WellSectionTypesWithCategories.Select(t => t.IdSectionType).Distinct();
+ var usedCategories = WellSectionTypesWithCategories.Select(c => c.IdCategory).Distinct();
+
+ var wellOperationRequest = new WellOperationRequest(idsWells)
+ {
+ OperationCategoryIds = usedCategories,
+ SectionTypeIds = idsWellSectionTypes,
+ OperationType = WellOperation.IdOperationTypeFact
};
+ var operations = await wellOperationRepository.GetAsync(wellOperationRequest, token);
- private HashSet<(int IdSectionType, int IdCategory)> WellSectionTypesWithCategories = new HashSet<(int IdSectionType, int IdCategory)>()
+ var operationsForComposite = operations.Select(o => CreateCompositeOperation(o, sectionsDict, categoriesDict));
+
+ var wellOperationsWithComposite = new List>();
+ var compositeDepth = 0d;
+ var compositeDay = 0d;
+ var result = new WellCompositeOperationDto();
+
+ var compositeOperations = new List();
+ foreach ((int IdSection, int IdCategory) in WellSectionTypesWithCategories)
{
- { (2, 5001) },
- { (2, 5003) },
- { (2, 5013) },
- { (2, 5000) },
- { (2, 5022) },
- { (2, 5017) },
- { (2, 5023) },
- { (2, 4007) },
- { (2, 5090) },
- { (3, 5001) },
- { (3, 5015) },
- { (3, 5037) },
- { (3, 5057) },
- { (3, 5003) },
- { (3, 5036) },
- { (3, 5084) },
- { (3, 5013) },
- { (3, 5000) },
- { (3, 5022) },
- { (3, 5017) },
- { (3, 4007) },
- { (3, 5090) },
- { (3, 5045) },
- { (3, 5042) },
- { (3, 5046) },
- { (31, 5001) },
- { (31, 5015) },
- { (31, 5037) },
- { (31, 5057) },
- { (31, 5003) },
- { (31, 5036) },
- { (31, 5013) },
- { (31, 5022) },
- { (31, 5017) },
- { (31, 5023) },
- { (31, 4007) },
- { (31, 5045) },
- { (31, 5042) },
- { (31, 5046) },
- { (4, 5001) },
- { (4, 5015) },
- { (4, 5046) },
- { (4, 5037) },
- { (4, 5097) },
- { (4, 5057) },
- { (4, 5003) },
- { (4, 5036) },
- { (4, 5008) },
- { (4, 5003) },
- { (4, 5036) },
- { (4, 5013) },
- { (4, 5000) },
- { (4, 5029) },
- { (4, 5022) },
- { (4, 5017) },
- { (4, 5019) },
- { (4, 5042) },
- { (4, 5046) },
- { (6, 5001) },
- { (6, 5015) },
- { (6, 5034) },
- { (6, 5037) },
- { (6, 5097) },
- { (6, 5057) },
- { (6, 5003) }
- };
+ var filteredByTemplate = operationsForComposite
+ .Where(o => o.IdWellSectionType == IdSection)
+ .Where(o => o.IdCategory == IdCategory);
+ if (!filteredByTemplate.Any())
+ continue;
+ var groupedByWell = filteredByTemplate.GroupBy(o => o.IdWell);
- public WellCompositeOperationService(
- ICrudRepository wellSectionTypeRepository,
- IWellOperationCategoryRepository wellOperationCategoryRepository,
- IWellOperationRepository wellOperationRepository,
- IWellService wellService)
- {
- this.wellSectionTypeRepository = wellSectionTypeRepository;
- this.wellOperationCategoryRepository = wellOperationCategoryRepository;
- this.wellOperationRepository = wellOperationRepository;
- this.wellService = wellService;
+ var aggreagtedByWell = groupedByWell.Select(g => new WellOperationDto
+ {
+ IdCategory = IdCategory,
+ IdWell = g.Key,
+ IdWellSectionType = IdSection,
+ DepthStart = g.Min(o => o.DepthStart),
+ DurationHours = g.Sum(o => o.DurationHours),
+ OperationCategoryName = g.First().OperationCategoryName,
+ WellSectionTypeCaption = g.First().WellSectionTypeCaption,
+ });
+
+ var compositeOperation = aggreagtedByWell.OrderBy(o => o.DurationHours).
+ ThenByDescending(o => o.DepthStart)
+ .First();
+
+ compositeOperation.IdWell = 0;
+
+ if (compositeDepth > compositeOperation.DepthStart)
+ compositeOperation.DepthStart = compositeDepth;
+ compositeDepth = compositeOperation.DepthStart;
+
+ compositeDay += compositeOperation.DurationHours;
+ compositeOperation.Day = compositeDay;
+
+ compositeOperations.Add(compositeOperation);
}
- public async Task GetAsync(IEnumerable idsWells, CancellationToken token)
+ var groupedByWellOperations = operations
+ .GroupBy(o => o.IdWell)
+ .ToDictionary(o => o.Key, o => o.ToArray())
+ .Select(o => new WellCompositeOperationSourceDto()
+ {
+ Operations = o.Value,
+ Well = wellsDict[o.Key],
+ });
+
+ result.WellOperationsComposite = compositeOperations;
+ result.WellCompositeSourceOperations = groupedByWellOperations;
+
+ return result;
+ }
+
+ private static WellOperationDto CreateCompositeOperation(
+ WellOperationDto dto,
+ IDictionary sectionTypes,
+ IDictionary operationCategories)
+ {
+ var newDto = dto.Adapt();
+ if (newDto.IdWellSectionType == wellSectionTransportTable)
{
- var sections = await wellSectionTypeRepository.GetAllAsync(token);
- var sectionsDict = sections.ToDictionary(s => s.Id, s => s.Caption);
-
- var categories = wellOperationCategoryRepository.Get(true);
- var categoriesDict = categories.ToDictionary(s => s.Id, s => s.Name);
-
- var wells = await wellService.GetAsync(new WellRequest { Ids = idsWells }, token);
- var wellsDict = wells.ToDictionary(w => w.Id);
-
- var idsWellSectionTypes = WellSectionTypesWithCategories.Select(t => t.IdSectionType).Distinct();
- var usedCategories = WellSectionTypesWithCategories.Select(c => c.IdCategory).Distinct();
-
- var wellOperationRequest = new WellOperationRequest(idsWells)
- {
- OperationCategoryIds = usedCategories,
- SectionTypeIds = idsWellSectionTypes,
- OperationType = WellOperation.IdOperationTypeFact
- };
- var operations = await wellOperationRepository.GetAsync(wellOperationRequest, token);
-
- var operationsForComposite = operations.Select(o => CreateCompositeOperation(o, sectionsDict, categoriesDict));
-
- var wellOperationsWithComposite = new List>();
- var compositeDepth = 0d;
- var compositeDay = 0d;
- var result = new WellCompositeOperationDto();
-
- var compositeOperations = new List();
- foreach ((int IdSection, int IdCategory) in WellSectionTypesWithCategories)
- {
- var filteredByTemplate = operationsForComposite
- .Where(o => o.IdWellSectionType == IdSection)
- .Where(o => o.IdCategory == IdCategory);
-
- if (!filteredByTemplate.Any())
- continue;
-
- var groupedByWell = filteredByTemplate.GroupBy(o => o.IdWell);
-
- var aggreagtedByWell = groupedByWell.Select(g => new WellOperationDto
- {
- IdCategory = IdCategory,
- IdWell = g.Key,
- IdWellSectionType = IdSection,
- DepthStart = g.Min(o => o.DepthStart),
- DurationHours = g.Sum(o => o.DurationHours),
- OperationCategoryName = g.First().OperationCategoryName,
- WellSectionTypeCaption = g.First().WellSectionTypeCaption,
- });
-
- var compositeOperation = aggreagtedByWell.OrderBy(o => o.DurationHours).
- ThenByDescending(o => o.DepthStart)
- .First();
-
- compositeOperation.IdWell = 0;
- compositeOperation.Day = compositeDay + compositeOperation.DurationHours;
-
- if (compositeDepth > compositeOperation.DepthStart)
- compositeOperation.DepthStart = compositeDepth;
-
- compositeOperations.Add(compositeOperation);
-
- compositeDepth = compositeOperation.DepthStart;
- compositeDay = compositeOperation.Day;
- }
-
- var groupedByWellOperations = operations
- .GroupBy(o => o.IdWell)
- .ToDictionary(o => o.Key, o => o.ToArray())
- .Select(o => new WellCompositeOperationSourceDto()
- {
- Operations = o.Value,
- Well = new WellDto()
- {
- Id = o.Key,
- Caption = wellsDict[o.Key].Caption,
- }
- });
-
- result.WellOperationsComposite = compositeOperations;
- result.WellCompositeSourceOperations = groupedByWellOperations;
-
- return result;
+ newDto.IdWellSectionType = wellSectionProductionString;
+ newDto.WellSectionTypeCaption = sectionTypes[newDto.IdWellSectionType];
}
- private static WellOperationDto CreateCompositeOperation(
- WellOperationDto dto,
- IDictionary sectionTypes,
- IDictionary operationCategories)
+ if ((SettingsForSectionCategoryChange.TryGetValue((newDto.IdWellSectionType, newDto.IdCategory), out int newIdCategory)))
{
- var newDto = dto.Adapt();
- if (newDto.IdWellSectionType == wellSectionTransportTable)
- {
- newDto.IdWellSectionType = wellSectionProductionString;
- newDto.WellSectionTypeCaption = sectionTypes[newDto.IdWellSectionType];
- }
-
- if ((SettingsForSectionCategoryChange.TryGetValue((newDto.IdWellSectionType, newDto.IdCategory), out int newIdCategory)))
- {
- newDto.IdCategory = newIdCategory;
- newDto.OperationCategoryName = operationCategories[newDto.IdCategory] ?? string.Empty;
- }
-
- return newDto;
+ newDto.IdCategory = newIdCategory;
+ newDto.OperationCategoryName = operationCategories[newDto.IdCategory] ?? string.Empty;
}
+
+ return newDto;
}
}
diff --git a/AsbCloudWebApi/Controllers/SAUB/GtrWitsController.cs b/AsbCloudWebApi/Controllers/SAUB/GtrWitsController.cs
index a339f1b8..f234d33c 100644
--- a/AsbCloudWebApi/Controllers/SAUB/GtrWitsController.cs
+++ b/AsbCloudWebApi/Controllers/SAUB/GtrWitsController.cs
@@ -11,6 +11,9 @@ using System.Threading.Tasks;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Requests;
using Microsoft.AspNetCore.Http;
+using AsbCloudApp.Data;
+using System;
+using Org.BouncyCastle.Asn1.Ocsp;
namespace AsbCloudWebApi.Controllers.SAUB
{
@@ -58,6 +61,31 @@ namespace AsbCloudWebApi.Controllers.SAUB
return Ok(dtos);
}
+ ///
+ /// Возвращает диапазон дат за которые есть телеметрия за период времени
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ [HttpGet("{idWell}/dateRange")]
+ [ProducesResponseType(typeof(DatesRangeDto), (int)System.Net.HttpStatusCode.OK)]
+ [ProducesResponseType((int)System.Net.HttpStatusCode.NotFound)]
+ [ProducesResponseType((int)System.Net.HttpStatusCode.NoContent)]
+ public virtual async Task> GetRangeAsync(
+ [FromRoute] int idWell,
+ DateTimeOffset? geDate,
+ DateTimeOffset? leDate,
+ CancellationToken token)
+ {
+ await AssertUserHasAccessToWellAsync(idWell, token);
+
+ var range = await gtrRepository.GetRangeAsync(idWell, geDate, leDate, token);
+
+ return Ok(range);
+ }
+
///
/// Получить загруженные данные ГТИ по скважине
///
@@ -81,7 +109,7 @@ namespace AsbCloudWebApi.Controllers.SAUB
if (!isCompanyOwnsWell)
return Forbid();
- var content = await gtrRepository.GetAsync(idWell, request.Begin,
+ var content = await gtrRepository.GetAsync(idWell, request.Begin?.DateTime,
request.IntervalSec, request.ApproxPointsCount, token).ConfigureAwait(false);
return Ok(content);