diff --git a/AsbCloudApp/Data/GTR/GtrWitsDto.cs b/AsbCloudApp/Data/GTR/GtrWitsDto.cs
new file mode 100644
index 00000000..20d08dd6
--- /dev/null
+++ b/AsbCloudApp/Data/GTR/GtrWitsDto.cs
@@ -0,0 +1,234 @@
+using System;
+
+namespace AsbCloudApp.Data.GTR;
+
+///
+/// ГТИ
+///
+public class GtrWitsDto
+{
+ ///
+ /// Дата получения записи
+ ///
+ public DateTimeOffset DateTime { get; set; }
+
+ ///
+ /// Забой (скважины), м
+ ///
+ public float? DEPTMEAS { get; set; }
+
+ ///
+ /// Долото, м
+ ///
+ public float DEPTBITM { get; set; }
+
+ ///
+ /// Вес на крюке
+ ///
+ public float? HKLA { get; set; }
+
+ ///
+ /// Высота крюка
+ ///
+ public float? BLKPOS { get; set; }
+
+ ///
+ /// Нагрузка на долото
+ ///
+ public float? WOBA { get; set; }
+
+ ///
+ /// Момент на роторе/ВСП
+ ///
+ public float? TORQA { get; set; }
+
+ ///
+ /// Давление на входе (на стояке)
+ ///
+ public float? SPPA { get; set; }
+
+ ///
+ /// Обороты ротора/ВСП
+ ///
+ public float? RPMA { get; set; }
+
+ ///
+ /// Механическая скорость
+ ///
+ public float? ROPA { get; set; }
+
+ ///
+ /// Скорость инструмента вверх
+ ///
+ public float? RSUX { get; set; }
+
+ ///
+ /// Скорость инструмента вниз
+ ///
+ public float? RSDX { get; set; }
+
+ ///
+ /// Расход на входе
+ ///
+ public float? MFIA { get; set; }
+
+ ///
+ /// Расход на выходе
+ ///
+ public float? MFOA { get; set; }
+
+ ///
+ /// Температура на входе
+ ///
+ public float? MTIA { get; set; }
+
+ ///
+ /// Температура на выходе
+ ///
+ public float? MTOA { get; set; }
+
+ ///
+ /// Ходы насоса №1
+ ///
+ public float? SPM1 { get; set; }
+
+ ///
+ /// Ходы насоса №2
+ ///
+ public float? SPM2 { get; set; }
+
+ ///
+ /// Ходы насоса №3
+ ///
+ public float? SPM3 { get; set; }
+
+ ///
+ /// Общий объем бурового раствора на поверхности
+ ///
+ public float? TVOLACT { get; set; }
+
+ ///
+ /// Объем бурового раствора в доливной емкости №1
+ ///
+ public float? TTVOL1 { get; set; }
+
+ ///
+ /// Объем бурового раствора в доливной емкости №2
+ ///
+ public float? TTVOL2 { get; set; }
+
+ ///
+ /// Объем бурового раствора в емкости №1
+ ///
+ public float? TVOL01 { get; set; }
+
+ ///
+ /// Объем бурового раствора в емкости №2
+ ///
+ public float? TVOL02 { get; set; }
+
+ ///
+ /// Объем бурового раствора в емкости №3
+ ///
+ public float? TVOL03 { get; set; }
+
+ ///
+ /// Объем бурового раствора в емкости №4
+ ///
+ public float? TVOL04 { get; set; }
+
+ ///
+ /// Объем бурового раствора в емкости №5
+ ///
+ public float? TVOL05 { get; set; }
+
+ ///
+ /// Объем бурового раствора в емкости №6
+ ///
+ public float? TVOL06 { get; set; }
+
+ ///
+ /// Объем бурового раствора в емкости №7
+ ///
+ public float? TVOL07 { get; set; }
+
+ ///
+ /// Объем бурового раствора в емкости №8
+ ///
+ public float? TVOL08 { get; set; }
+
+ ///
+ /// Объем бурового раствора в емкости №9
+ ///
+ public float? TVOL09 { get; set; }
+
+ ///
+ /// Объем бурового раствора в емкости №10
+ ///
+ public float? TVOL10 { get; set; }
+
+ ///
+ /// Объем бурового раствора в емкости №11
+ ///
+ public float? TVOL11 { get; set; }
+
+ ///
+ /// Объем бурового раствора в емкости №12
+ ///
+ public float? TVOL12 { get; set; }
+
+ ///
+ /// Объем бурового раствора в емкости №13
+ ///
+ public float? TVOL13 { get; set; }
+
+ ///
+ /// Объем бурового раствора в емкости №14
+ ///
+ public float? TVOL14 { get; set; }
+
+ ///
+ /// Плотность (удельный вес) бурового раствора на выходе
+ ///
+ public float? MDOA { get; set; }
+
+ ///
+ /// Плотность (удельный вес) бурового раствора на входе
+ ///
+ public float? MDIA { get; set; }
+
+ ///
+ /// Процентное содержание метана
+ ///
+ public float? METHANE { get; set; }
+
+ ///
+ /// Процентное содержание этана
+ ///
+ public float? ETHANE { get; set; }
+
+ ///
+ /// Процентное содержание пропана
+ ///
+ public float? PROPANE { get; set; }
+
+ ///
+ /// Процентное содержание бутана
+ ///
+ public float? IBUTANE { get; set; }
+
+ ///
+ /// Процентное содержание пентана
+ ///
+ public float? NBUTANE { get; set; }
+
+ ///
+ /// Процентное содержание углеводородов
+ ///
+ public float? HydrocarbonPercentage => METHANE + ETHANE + PROPANE + IBUTANE + NBUTANE;
+
+ ///
+ /// Процентное содержание газов
+ ///
+ public float? GASA { get; set; }
+}
\ No newline at end of file
diff --git a/AsbCloudApp/Repositories/IGtrRepository.cs b/AsbCloudApp/Repositories/IGtrRepository.cs
index 0d597dde..706b6be2 100644
--- a/AsbCloudApp/Repositories/IGtrRepository.cs
+++ b/AsbCloudApp/Repositories/IGtrRepository.cs
@@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using AsbCloudApp.Requests;
namespace AsbCloudApp.Repositories
{
@@ -19,6 +20,15 @@ namespace AsbCloudApp.Repositories
///
///
Task SaveDataAsync(int idTelemetry, IEnumerable dtos, CancellationToken token);
+
+ ///
+ /// получить данные ГТИ
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task> GetAsync(int idWell, GtrRequest request, CancellationToken token);
///
/// получить данные для клиента
@@ -29,6 +39,7 @@ namespace AsbCloudApp.Repositories
/// кол-во элементов до которых эти данные прореживаются
///
///
+ [Obsolete]
Task> GetAsync(int idWell,
DateTime? dateBegin, double intervalSec = 600d,
int approxPointsCount = 1024, CancellationToken token = default);
@@ -39,6 +50,7 @@ namespace AsbCloudApp.Repositories
///
///
///
+ [Obsolete]
IEnumerable GetLastDataByRecordId(int idWell, int idRecord);
///
@@ -46,6 +58,7 @@ namespace AsbCloudApp.Repositories
///
///
///
+ [Obsolete]
IEnumerable GetLastData(int idWell);
}
}
diff --git a/AsbCloudApp/Requests/GtrWithGetDataRequest.cs b/AsbCloudApp/Requests/GtrRequest.cs
similarity index 95%
rename from AsbCloudApp/Requests/GtrWithGetDataRequest.cs
rename to AsbCloudApp/Requests/GtrRequest.cs
index 8e93a02c..43de25c4 100644
--- a/AsbCloudApp/Requests/GtrWithGetDataRequest.cs
+++ b/AsbCloudApp/Requests/GtrRequest.cs
@@ -5,7 +5,7 @@ namespace AsbCloudApp.Requests;
///
/// Параметры запроса для получения загруженных данных ГТИ по скважине
///
-public class GtrWithGetDataRequest
+public class GtrRequest
{
///
/// Дата начала выборки.По умолчанию: текущее время - IntervalSec
@@ -20,5 +20,6 @@ public class GtrWithGetDataRequest
///
/// Желаемое количество точек. Если в выборке точек будет больше, то выборка будет прорежена.
///
+ [Obsolete]
public int ApproxPointsCount { get; set; } = 1024;
}
\ No newline at end of file
diff --git a/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs b/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs
index 2a871553..57b36ef2 100644
--- a/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs
+++ b/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs
@@ -12,11 +12,61 @@ using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using AsbCloudApp.Exceptions;
+using AsbCloudApp.Requests;
+using Mapster;
namespace AsbCloudInfrastructure.Repository
{
public class GtrWitsRepository : IGtrRepository
{
+ private static IDictionary<(int IdRecord, int IdItem), string> WitsParameters = new Dictionary<(int, int), string>
+ {
+ { (1, 8), nameof(GtrWitsDto.DEPTBITM) },
+ { (1, 10), nameof(GtrWitsDto.DEPTMEAS) },
+ { (1, 14), nameof(GtrWitsDto.HKLA) },
+ { (1, 12), nameof(GtrWitsDto.BLKPOS) },
+ { (1, 16), nameof(GtrWitsDto.WOBA) },
+ { (1, 18), nameof(GtrWitsDto.TORQA) },
+ { (1, 21), nameof(GtrWitsDto.SPPA) },
+ { (2, 15), nameof(GtrWitsDto.RPMA) },
+ { (1, 13), nameof(GtrWitsDto.ROPA) },
+ { (3, 16), nameof(GtrWitsDto.RSUX) },
+ { (3, 17), nameof(GtrWitsDto.RSDX) },
+ { (1, 30), nameof(GtrWitsDto.MFIA) },
+ { (1, 29), nameof(GtrWitsDto.MFOA)},
+ { (1, 34), nameof(GtrWitsDto.MTIA) },
+ { (1, 33), nameof(GtrWitsDto.MTOA) },
+ { (1, 23), nameof(GtrWitsDto.SPM1) },
+ { (1, 24), nameof(GtrWitsDto.SPM2) },
+ { (1, 25), nameof(GtrWitsDto.SPM3) },
+ { (1, 26), nameof(GtrWitsDto.TVOLACT) },
+ { (11, 29), nameof(GtrWitsDto.TTVOL1) },
+ { (11, 30), nameof(GtrWitsDto.TTVOL2) },
+ { (11, 15), nameof(GtrWitsDto.TVOL01) },
+ { (11, 16), nameof(GtrWitsDto.TVOL02) },
+ { (11, 17), nameof(GtrWitsDto.TVOL03) },
+ { (11, 18), nameof(GtrWitsDto.TVOL04) },
+ { (11, 19), nameof(GtrWitsDto.TVOL05) },
+ { (11, 20), nameof(GtrWitsDto.TVOL06) },
+ { (11, 21), nameof(GtrWitsDto.TVOL07) },
+ { (11, 22), nameof(GtrWitsDto.TVOL08) },
+ { (11, 23), nameof(GtrWitsDto.TVOL09) },
+ { (11, 24), nameof(GtrWitsDto.TVOL10) },
+ { (11, 25), nameof(GtrWitsDto.TVOL11) },
+ { (11, 26), nameof(GtrWitsDto.TVOL12) },
+ { (11, 27), nameof(GtrWitsDto.TVOL13) },
+ { (11, 28), nameof(GtrWitsDto.TVOL14) },
+ { (1, 31), nameof(GtrWitsDto.MDOA) },
+ { (1, 32), nameof(GtrWitsDto.MDIA) },
+ { (12, 12), nameof(GtrWitsDto.METHANE) },
+ { (12, 13), nameof(GtrWitsDto.ETHANE) },
+ { (12, 14), nameof(GtrWitsDto.PROPANE) },
+ { (12, 15), nameof(GtrWitsDto.IBUTANE) },
+ { (12, 16), nameof(GtrWitsDto.NBUTANE) },
+ { (1, 40), nameof(GtrWitsDto.GASA) },
+ };
+
private readonly IAsbCloudDbContext db;
private readonly ITelemetryService telemetryService;
private static ConcurrentDictionary> cache = new();
@@ -29,6 +79,75 @@ namespace AsbCloudInfrastructure.Repository
this.telemetryService = telemetryService;
}
+ public async Task> GetAsync(int idWell, GtrRequest request, CancellationToken token) =>
+ await GetAsync(idWell, request, token);
+
+ private async Task> GetAsync(int idWell, GtrRequest request, CancellationToken token)
+ where TEntity : WitsItemBase
+ where TType : notnull
+ {
+ var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell);
+
+ if (telemetry is null)
+ return Enumerable.Empty();
+
+ if (telemetry.TimeZone is null)
+ throw new ArgumentInvalidException(nameof(idWell),$"Telemetry id: {telemetry.Id} can't find timezone");
+
+ var timezoneOffset = TimeSpan.FromHours(telemetry.TimeZone.Hours);
+
+ var query = BuildQuery(telemetry.Id, request);
+
+ if (!await query.AnyAsync(token))
+ return Enumerable.Empty();
+
+ var interval = TimeSpan.FromSeconds(10);
+
+ var idsRecord = WitsParameters.Select(p => p.Key.IdRecord);
+
+ var entities = await query
+ .Where(e => idsRecord.Contains(e.IdRecord))
+ .OrderBy(e => e.DateTime)
+ .AsNoTracking()
+ .ToArrayAsync(token);
+
+ var dtos = entities
+ .GroupBy(e => e.DateTime.Ticks / interval.Ticks)
+ .Select(groupByInterval =>
+ {
+ 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());
+
+ var dto = values.Adapt();
+ dto.DateTime = items.Last().DateTime.ToOffset(timezoneOffset);
+ return dto;
+ });
+
+ return dtos;
+ }
+
+ private IQueryable BuildQuery(int idTelemetry, GtrRequest request)
+ where TEntity : WitsItemBase
+ where TType : notnull
+ {
+ var dateIntervalStart = DateTime.UtcNow.AddSeconds(-request.IntervalSec);
+
+ var query = db.Set()
+ .Where(e => e.IdTelemetry == idTelemetry)
+ .Where(e => e.DateTime >= dateIntervalStart);
+
+ if (request.Begin.HasValue)
+ {
+ var dateBeginUtc = request.Begin.Value.ToUniversalTime();
+ query = query.Where(e => e.DateTime >= dateBeginUtc);
+ }
+
+ return query;
+ }
+
+ [Obsolete]
public async Task> GetAsync(int idWell, DateTime? dateBegin, double intervalSec = 600, int approxPointsCount = 1024, CancellationToken token = default)
{
var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell);
diff --git a/AsbCloudWebApi.IntegrationTests/Clients/IGtrWitsClient.cs b/AsbCloudWebApi.IntegrationTests/Clients/IGtrWitsClient.cs
new file mode 100644
index 00000000..517b98ef
--- /dev/null
+++ b/AsbCloudWebApi.IntegrationTests/Clients/IGtrWitsClient.cs
@@ -0,0 +1,13 @@
+using AsbCloudApp.Data.GTR;
+using AsbCloudApp.Requests;
+using Refit;
+
+namespace AsbCloudWebApi.IntegrationTests.Clients;
+
+public interface IGtrWitsClient
+{
+ private const string BaseRoute = "/api/gtrWits";
+
+ [Get(BaseRoute)]
+ Task>> GetAllAsync(int idWell, [Query] GtrRequest request);
+}
\ No newline at end of file
diff --git a/AsbCloudWebApi.IntegrationTests/Controllers/GtrControllerTests.cs b/AsbCloudWebApi.IntegrationTests/Controllers/GtrControllerTests.cs
new file mode 100644
index 00000000..e951c13e
--- /dev/null
+++ b/AsbCloudWebApi.IntegrationTests/Controllers/GtrControllerTests.cs
@@ -0,0 +1,68 @@
+using System.Net;
+using AsbCloudApp.Requests;
+using AsbCloudDb.Model.GTR;
+using AsbCloudWebApi.IntegrationTests.Clients;
+using Xunit;
+
+namespace AsbCloudWebApi.IntegrationTests.Controllers;
+
+public class GtrControllerTests : BaseIntegrationTest
+{
+ private readonly IGtrWitsClient client;
+
+ public GtrControllerTests(WebAppFactoryFixture factory)
+ : base(factory)
+ {
+ client = factory.GetAuthorizedHttpClient(string.Empty);
+ }
+
+ [Fact]
+ public async Task GetAll_returns_success()
+ {
+ //arrange
+ var well = dbContext.Wells.First();
+
+ var witsItems = CreateWitsItems(well.IdTelemetry!.Value);
+ dbContext.WitsItemFloat.AddRange(witsItems);
+ await dbContext.SaveChangesAsync();
+
+ var request = new GtrRequest();
+
+ //act
+ var response = await client.GetAllAsync(well.Id, request);
+
+ //assert
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ Assert.NotNull(response.Content);
+ Assert.True(response.Content.Any());
+ }
+
+ private static IEnumerable CreateWitsItems(int idTelemetry) =>
+ new[]
+ {
+ new WitsItemFloat
+ {
+ IdRecord = 1,
+ IdItem = 14,
+ Value = 4,
+ IdTelemetry = idTelemetry,
+ DateTime = DateTimeOffset.UtcNow
+ },
+ new WitsItemFloat
+ {
+ IdRecord = 1,
+ IdItem = 14,
+ Value = 5,
+ IdTelemetry = idTelemetry,
+ DateTime = DateTimeOffset.UtcNow
+ },
+ new WitsItemFloat
+ {
+ IdRecord = 1,
+ IdItem = 12,
+ Value = 5,
+ IdTelemetry = idTelemetry,
+ DateTime = DateTimeOffset.UtcNow.AddSeconds(10)
+ }
+ };
+}
\ No newline at end of file
diff --git a/AsbCloudWebApi/Controllers/SAUB/GtrWitsController.cs b/AsbCloudWebApi/Controllers/SAUB/GtrWitsController.cs
index f4cfe0b4..8f38b2ad 100644
--- a/AsbCloudWebApi/Controllers/SAUB/GtrWitsController.cs
+++ b/AsbCloudWebApi/Controllers/SAUB/GtrWitsController.cs
@@ -8,7 +8,9 @@ using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Threading;
using System.Threading.Tasks;
+using AsbCloudApp.Exceptions;
using AsbCloudApp.Requests;
+using Microsoft.AspNetCore.Http;
namespace AsbCloudWebApi.Controllers.SAUB
{
@@ -36,6 +38,25 @@ namespace AsbCloudWebApi.Controllers.SAUB
this.wellService = wellService;
this.telemetryHubContext = telemetryHubContext;
}
+
+ ///
+ /// Получить значение от ГТИ
+ ///
+ ///
+ ///
+ ///
+ ///
+ [HttpGet]
+ [Permission]
+ [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)]
+ public async Task GetAllAsync(int idWell, [FromQuery] GtrRequest request, CancellationToken token)
+ {
+ await AssertUserHasAccessToWellAsync(idWell, token);
+
+ var dtos = await gtrRepository.GetAsync(idWell, request, token);
+
+ return Ok(dtos);
+ }
///
/// Получить загруженные данные ГТИ по скважине
@@ -46,7 +67,7 @@ namespace AsbCloudWebApi.Controllers.SAUB
///
[HttpGet("{idWell}")]
public async Task>> GetDataAsync([Required] int idWell,
- [FromQuery] GtrWithGetDataRequest request,
+ [FromQuery] GtrRequest request,
CancellationToken token)
{
int? idCompany = User.GetCompanyId();
@@ -114,6 +135,21 @@ namespace AsbCloudWebApi.Controllers.SAUB
.SendAsync(SignalRMethodGetDataName, dtos), CancellationToken.None);
return Ok();
}
+
+ private async Task AssertUserHasAccessToWellAsync(int idWell, CancellationToken token)
+ {
+ var idUser = User.GetUserId();
+ var idCompany = User.GetCompanyId();
+
+ if (!idUser.HasValue)
+ throw new ForbidException("Нет доступа к скважине");
+
+ if (!idCompany.HasValue)
+ throw new ForbidException("Нет доступа к скважине");
+
+ if (!await wellService.IsCompanyInvolvedInWellAsync(idCompany.Value, idWell, token))
+ throw new ForbidException("Нет доступа к скважине");
+ }
}
}