diff --git a/AsbCloudApp/Data/DetectedOperation/DetectedOperationDto.cs b/AsbCloudApp/Data/DetectedOperation/DetectedOperationDto.cs index 2b0fc768..e81a45fb 100644 --- a/AsbCloudApp/Data/DetectedOperation/DetectedOperationDto.cs +++ b/AsbCloudApp/Data/DetectedOperation/DetectedOperationDto.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace AsbCloudApp.Data.DetectedOperation; @@ -29,6 +30,11 @@ public class DetectedOperationDto: IId /// [Required] public int IdUserAtStart { get; set; } + + /// + /// Пользователь панели оператора + /// + public string? TelemetryUserName { get; set; } /// /// Дата завершения операции в часовом поясе скважины @@ -72,14 +78,14 @@ public class DetectedOperationDto: IId [Required] public WellOperationCategoryDto OperationCategory { get; set; } = null!; - /// - /// Пользователь панели оператора - /// - public string? TelemetryUserName { get; set; } - /// /// Ключевой параметр операции /// [Required] public double Value { get; set; } + + /// + /// Доп. инфо по операции + /// + public IDictionary ExtraData { get; set; } = new Dictionary(); } \ No newline at end of file diff --git a/AsbCloudApp/Data/SAUB/TelemetryDataSaubDto.cs b/AsbCloudApp/Data/SAUB/TelemetryDataSaubDto.cs index e1e7cf96..8f2794fc 100644 --- a/AsbCloudApp/Data/SAUB/TelemetryDataSaubDto.cs +++ b/AsbCloudApp/Data/SAUB/TelemetryDataSaubDto.cs @@ -13,6 +13,11 @@ namespace AsbCloudApp.Data.SAUB /// [Required] public DateTime DateTime { get; set; } + + /// + /// Пользователь САУБ + /// + public int? IdUser { get; set; } /// /// Режим работы САУБ: diff --git a/AsbCloudApp/Repositories/IDetectedOperationRepository.cs b/AsbCloudApp/Repositories/IDetectedOperationRepository.cs index 5a52b455..d7fe5865 100644 --- a/AsbCloudApp/Repositories/IDetectedOperationRepository.cs +++ b/AsbCloudApp/Repositories/IDetectedOperationRepository.cs @@ -1,15 +1,17 @@ -using AsbCloudApp.Data.DetectedOperation; +using System; +using AsbCloudApp.Data.DetectedOperation; using AsbCloudApp.Requests; using System.Collections.Generic; using System.Threading.Tasks; using System.Threading; +using AsbCloudApp.Services; namespace AsbCloudApp.Repositories; /// /// Таблица автоматически определенных операций /// -public interface IDetectedOperationRepository +public interface IDetectedOperationRepository : ICrudRepository { /// /// Добавление записей @@ -63,4 +65,11 @@ public interface IDetectedOperationRepository /// /// Task DeleteRange(int idUser, IEnumerable ids, CancellationToken token); + + /// + /// Получение дат последних определённых операций + /// + /// + /// + Task> GetLastDetectedDatesAsync(CancellationToken token); } diff --git a/AsbCloudApp/Services/IDetectedOperationService.cs b/AsbCloudApp/Services/IDetectedOperationService.cs index 5109fa56..998032ba 100644 --- a/AsbCloudApp/Services/IDetectedOperationService.cs +++ b/AsbCloudApp/Services/IDetectedOperationService.cs @@ -1,4 +1,5 @@ -using AsbCloudApp.Data; +using System; +using AsbCloudApp.Data; using AsbCloudApp.Data.DetectedOperation; using AsbCloudApp.Requests; using System.Collections.Generic; @@ -52,5 +53,14 @@ namespace AsbCloudApp.Services /// /// Task> GetOperationsStatAsync(DetectedOperationByWellRequest request, CancellationToken token); + + /// + /// Определение операций + /// + /// + /// + /// + /// + Task> DetectOperationsAsync(int idTelemetry, DateTimeOffset? beginDate, CancellationToken token); } } diff --git a/AsbCloudApp/Services/ITelemetryDataService.cs b/AsbCloudApp/Services/ITelemetryDataService.cs index bb40771b..9cf4a805 100644 --- a/AsbCloudApp/Services/ITelemetryDataService.cs +++ b/AsbCloudApp/Services/ITelemetryDataService.cs @@ -23,18 +23,27 @@ namespace AsbCloudApp.Services /// кол-во элементов до которых эти данные прореживаются /// /// - Task> GetAsync(int idWell, + Task> GetByWellAsync(int idWell, DateTime dateBegin = default, double intervalSec = 600d, int approxPointsCount = 1024, CancellationToken token = default); /// - /// Получить данные тех. процесса + /// Получить данные тех. процесса по скважине /// /// /// /// /// - Task> GetAsync(int idWell, TelemetryDataRequest request, CancellationToken token); + Task> GetByWellAsync(int idWell, TelemetryDataRequest request, CancellationToken token); + + /// + /// Получение данных тех. процесса по телеметрии + /// + /// + /// + /// + /// + Task> GetByTelemetryAsync(int idTelemetry, TelemetryDataRequest request, CancellationToken token); /// /// Период за который есть данные по скважине в рамках временного интервала diff --git a/AsbCloudDb/Model/DetectedOperation.cs b/AsbCloudDb/Model/DetectedOperation.cs index c1f66c79..df5abbb1 100644 --- a/AsbCloudDb/Model/DetectedOperation.cs +++ b/AsbCloudDb/Model/DetectedOperation.cs @@ -8,7 +8,7 @@ using System.Text.Json.Serialization; namespace AsbCloudDb.Model { [Table("t_detected_operation"), Comment("автоматически определенные операции по телеметрии")] - public class DetectedOperation + public class DetectedOperation : IId { [Key] [Column("id")] @@ -20,14 +20,14 @@ namespace AsbCloudDb.Model [Column("id_category"), Comment("Id категории операции")] public int IdCategory { get; set; } - [Column("id_user"), Comment("Id пользователя по телеметрии на момент начала операции")] - public int IdUsersAtStart { get; set; } - [Column("date_start", TypeName = "timestamp with time zone"), Comment("Дата начала операции")] public DateTimeOffset DateStart { get; set; } [Column("date_end", TypeName = "timestamp with time zone"), Comment("Дата начала операции")] public DateTimeOffset DateEnd { get; set; } + + [Column("id_user"), Comment("Id пользователя по телеметрии на момент начала операции")] + public int IdUsersAtStart { get; set; } [NotMapped] public double DurationMinutes => (DateEnd - DateStart).TotalMinutes; diff --git a/AsbCloudInfrastructure/Repository/DetectedOperationRepository.cs b/AsbCloudInfrastructure/Repository/DetectedOperationRepository.cs index 50ec6c9e..21db64ba 100644 --- a/AsbCloudInfrastructure/Repository/DetectedOperationRepository.cs +++ b/AsbCloudInfrastructure/Repository/DetectedOperationRepository.cs @@ -15,37 +15,46 @@ using System.Threading.Tasks; namespace AsbCloudInfrastructure.Repository; -public class DetectedOperationRepository : IDetectedOperationRepository +public class DetectedOperationRepository : CrudRepositoryBase, + IDetectedOperationRepository { - private readonly IAsbCloudDbContext db; private readonly ITelemetryService telemetryService; - public DetectedOperationRepository( - IAsbCloudDbContext db, + public DetectedOperationRepository(IAsbCloudDbContext context, ITelemetryService telemetryService) + : base(context) { - this.db = db; this.telemetryService = telemetryService; } public async Task Delete(int idUser, DetectedOperationByTelemetryRequest request, CancellationToken token) { var query = BuildQuery(request); - db.Set().RemoveRange(query); - return await db.SaveChangesAsync(token); + dbContext.Set().RemoveRange(query); + return await dbContext.SaveChangesAsync(token); } public async Task DeleteRange(int idUser, IEnumerable ids, CancellationToken token) { - var query = db.Set() + var query = dbContext.Set() .Where(e => ids.Contains( e.Id)); - db.Set() + dbContext.Set() .RemoveRange(query); - return await db.SaveChangesAsync(token); + return await dbContext.SaveChangesAsync(token); } + public async Task> GetLastDetectedDatesAsync(CancellationToken token) => + await dbContext.Set() + .GroupBy(o => o.IdTelemetry) + .Select(g => new + { + IdTelemetry = g.Key, + LastDate = g.Max(o => o.DateEnd) + }) + .ToDictionaryAsync(x => x.IdTelemetry, x => x.LastDate, token); + public async Task> Get(DetectedOperationByTelemetryRequest request, CancellationToken token) { var query = BuildQuery(request) @@ -63,14 +72,14 @@ public class DetectedOperationRepository : IDetectedOperationRepository return 0; var entities = dtos.Select(Convert); - var dbset = db.Set(); + var dbset = dbContext.Set(); foreach(var entity in entities) { entity.Id = default; dbset.Add(entity); } - return await db.SaveChangesWithExceptionHandling(token); + return await dbContext.SaveChangesWithExceptionHandling(token); } public async Task Update(int idUser, IEnumerable dtos, CancellationToken token) @@ -89,7 +98,7 @@ public class DetectedOperationRepository : IDetectedOperationRepository if (ids.Length != dtos.Count()) throw new ArgumentInvalidException(nameof(dtos), "Все записи должны иметь уникальные Id"); - var dbSet = db.Set(); + var dbSet = dbContext.Set(); var existingEntitiesCount = await dbSet .Where(o => ids.Contains(o.Id)) @@ -106,7 +115,7 @@ public class DetectedOperationRepository : IDetectedOperationRepository for(var i = 0; i < entities.Length; i++) entries[i] = dbSet.Update(entities[i]); - var result = await db.SaveChangesWithExceptionHandling(token); + var result = await dbContext.SaveChangesWithExceptionHandling(token); for (var i = 0; i < entries.Length; i++) entries[i].State = EntityState.Detached; @@ -131,7 +140,7 @@ public class DetectedOperationRepository : IDetectedOperationRepository private IQueryable BuildQuery(DetectedOperationByTelemetryRequest request) { - var query = db.Set() + var query = dbContext.Set() .Where(o => o.IdTelemetry == request.IdTelemetry); if (request.IdsCategories.Any()) @@ -173,19 +182,19 @@ public class DetectedOperationRepository : IDetectedOperationRepository return query; } - private static DetectedOperationDto Convert(DetectedOperation entity, TimeSpan offset) + protected virtual DetectedOperationDto Convert(DetectedOperation src, TimeSpan offset) { - var dto = entity.Adapt(); - dto.DateStart = entity.DateStart.ToOffset(offset); - dto.DateEnd = entity.DateEnd.ToOffset(offset); + var dto = src.Adapt(); + dto.DateStart = src.DateStart.ToOffset(offset); + dto.DateEnd = src.DateEnd.ToOffset(offset); return dto; } - private static DetectedOperation Convert(DetectedOperationDto dto) + protected override DetectedOperation Convert(DetectedOperationDto src) { - var entity = dto.Adapt(); - entity.DateStart = dto.DateStart.ToUniversalTime(); - entity.DateEnd = dto.DateEnd.ToUniversalTime(); + var entity = src.Adapt(); + entity.DateStart = src.DateStart.ToUniversalTime(); + entity.DateEnd = src.DateEnd.ToUniversalTime(); return entity; } } diff --git a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs index 00349a6c..c6edb30b 100644 --- a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs +++ b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs @@ -60,16 +60,15 @@ public class WellOperationRepository : IWellOperationRepository OperationType = WellOperation.IdOperationTypePlan, }; - var entities = await BuildQuery(request) + var dtos = await BuildQuery(request) .AsNoTracking() - .ToArrayAsync(token) - .ConfigureAwait(false); + .ToArrayAsync(token); var dateLastAssosiatedPlanOperation = await GetDateLastAssosiatedPlanOperationAsync(idWell, currentDate, timezone.Hours, token); - + var result = new WellOperationPlanDto() { - WellOperationsPlan = entities, + WellOperationsPlan = dtos.Select(Convert), DateLastAssosiatedPlanOperation = dateLastAssosiatedPlanOperation }; @@ -211,7 +210,7 @@ public class WellOperationRepository : IWellOperationRepository var dtos = await query.ToArrayAsync(token); - return dtos; + return dtos.Select(Convert); } /// @@ -219,21 +218,19 @@ public class WellOperationRepository : IWellOperationRepository WellOperationRequest request, CancellationToken token) { - var query = BuildQuery(request) - .AsNoTracking(); - + var query = BuildQuery(request); + var result = new PaginationContainer { Skip = request.Skip ?? 0, Take = request.Take ?? 32, - Count = await query.CountAsync(token).ConfigureAwait(false), + Count = await query.CountAsync(token), }; - query = query - .Skip(result.Skip) - .Take(result.Take); + var dtos = await query.ToArrayAsync(token); + + result.Items = dtos.Select(Convert); - result.Items = await query.ToArrayAsync(token); return result; } @@ -384,12 +381,13 @@ public class WellOperationRepository : IWellOperationRepository /// В результате попрежнему требуется конвертировать дату /// /// + /// /// private IQueryable BuildQuery(WellOperationRequest request) { var timezone = wellService.GetTimezone(request.IdWell); - var timeZoneOffset = TimeSpan.FromHours(timezone.Hours); - + var timeZoneOffset = timezone.Hours; + var query = db.WellOperations .Include(s => s.WellSectionType) .Include(s => s.OperationCategory) @@ -413,20 +411,20 @@ public class WellOperationRepository : IWellOperationRepository if (request.GeDate.HasValue) { - var geDateOffset = request.GeDate.Value.ToUtcDateTimeOffset(timezone.Hours); + var geDateOffset = request.GeDate.Value.ToUtcDateTimeOffset(timeZoneOffset); query = query.Where(e => e.DateStart >= geDateOffset); } if (request.LtDate.HasValue) { - var ltDateOffset = request.LtDate.Value.ToUtcDateTimeOffset(timezone.Hours); + var ltDateOffset = request.LtDate.Value.ToUtcDateTimeOffset(timeZoneOffset); query = query.Where(e => e.DateStart < ltDateOffset); } var currentWellOperations = db.WellOperations .Where(subOp => subOp.IdWell == request.IdWell); - var wellOperationsWithCategoryNPT = currentWellOperations + var wellOperationsWithCategoryNpt = currentWellOperations .Where(subOp => subOp.IdType == 1) .Where(subOp => WellOperationCategory.NonProductiveTimeSubIds.Contains(subOp.IdCategory)); @@ -442,14 +440,14 @@ public class WellOperationRepository : IWellOperationRepository CategoryName = o.OperationCategory.Name, WellSectionTypeName = o.WellSectionType.Caption, - DateStart = DateTime.SpecifyKind(o.DateStart.UtcDateTime + timeZoneOffset, DateTimeKind.Unspecified), + DateStart = o.DateStart, DepthStart = o.DepthStart, DepthEnd = o.DepthEnd, DurationHours = o.DurationHours, CategoryInfo = o.CategoryInfo, Comment = o.Comment, - NptHours = wellOperationsWithCategoryNPT + NptHours = wellOperationsWithCategoryNpt .Where(subOp => subOp.DateStart <= o.DateStart) .Select(subOp => subOp.DurationHours) .Sum(), @@ -460,22 +458,39 @@ public class WellOperationRepository : IWellOperationRepository .Min(subOp => subOp.DateStart)) .TotalDays, IdUser = o.IdUser, - LastUpdateDate = DateTime.SpecifyKind(o.LastUpdateDate.UtcDateTime + timeZoneOffset, DateTimeKind.Unspecified) + LastUpdateDate = o.LastUpdateDate, }); if (request.SortFields?.Any() == true) { dtos = dtos.SortBy(request.SortFields); } - else - { - dtos = dtos - .OrderBy(e => e.DateStart) - .ThenBy(e => e.DepthEnd) - .ThenBy(e => e.Id); - } - return dtos; + dtos = dtos + .OrderBy(e => e.DateStart) + .ThenBy(e => e.DepthEnd) + .ThenBy(e => e.Id); + + if (request.Skip.HasValue) + dtos = dtos.Skip(request.Skip.Value); + + if (request.Take.HasValue) + dtos = dtos.Take(request.Take.Value); + + return dtos.AsNoTracking(); + } + + private WellOperationDto Convert(WellOperationDto dto) + { + var timezone = wellService.GetTimezone(dto.IdWell); + var timezoneOffset = TimeSpan.FromHours(timezone.Hours); + + var dtoWithRemoteDateTime = dto.Adapt(); + + dtoWithRemoteDateTime.DateStart = dto.DateStart.ToOffset(TimeSpan.FromHours(timezoneOffset.Hours)); + dtoWithRemoteDateTime.LastUpdateDate = dto.LastUpdateDate?.ToOffset(TimeSpan.FromHours(timezoneOffset.Hours)); + + return dtoWithRemoteDateTime; } public async Task RemoveDuplicates(Action onProgressCallback, CancellationToken token) diff --git a/AsbCloudInfrastructure/Services/DetectOperations/DetectableTelemetry.cs b/AsbCloudInfrastructure/Services/DetectOperations/DetectableTelemetry.cs index 55a605f2..9c72c4e8 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/DetectableTelemetry.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/DetectableTelemetry.cs @@ -5,8 +5,8 @@ namespace AsbCloudInfrastructure.Services.DetectOperations; public class DetectableTelemetry { public DateTimeOffset DateTime { get; set; } - public int? IdUser { get; set; } public int Mode { get; set; } + public int? IdUser { get; set; } public float WellDepth { get; set; } public float Pressure { get; set; } public float HookWeight { get; set; } diff --git a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationExportService.cs b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationExportService.cs index 987f274f..3ba4350a 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationExportService.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationExportService.cs @@ -19,9 +19,9 @@ namespace AsbCloudInfrastructure.Services.DetectOperations; public class DetectedOperationExportService { - private readonly IAsbCloudDbContext db; - private readonly IWellService wellService; + private readonly IWellService wellService; private readonly IWellOperationCategoryRepository wellOperationCategoryRepository; + private readonly IDetectedOperationService detectedOperationService; private const int headerRowsCount = 1; private const string cellDepositName = "B1"; @@ -40,15 +40,14 @@ public class DetectedOperationExportService private const int columnIdReasonOfEnd = 9; private const int columnComment = 10; - public DetectedOperationExportService( - IAsbCloudDbContext db, - IWellService wellService, - IWellOperationCategoryRepository wellOperationCategoryRepository) + public DetectedOperationExportService(IWellService wellService, + IWellOperationCategoryRepository wellOperationCategoryRepository, + IDetectedOperationService detectedOperationService) { - this.db = db; - this.wellService = wellService; + this.wellService = wellService; this.wellOperationCategoryRepository = wellOperationCategoryRepository; - } + this.detectedOperationService = detectedOperationService; + } /// /// Экспорт excel файла с операциями по скважине @@ -68,12 +67,12 @@ public class DetectedOperationExportService if (!well.IdTelemetry.HasValue) throw new ArgumentInvalidException(nameof(idWell), $"Well {idWell} has no telemetry"); - var operations = await WorkOperationDetection.DetectOperationsAsync(well.IdTelemetry.Value, DateTime.UnixEpoch, db, token); + var operations = await detectedOperationService.DetectOperationsAsync(well.IdTelemetry.Value, DateTime.UnixEpoch, token); return await GenerateExcelFileStreamAsync(well, host, operations, token); } - private async Task GenerateExcelFileStreamAsync(WellDto well, string host, IEnumerable operationDetectorResults, + private async Task GenerateExcelFileStreamAsync(WellDto well, string host, IEnumerable operationDetectorResults, CancellationToken cancellationToken) { using var excelTemplateStream = await GetExcelTemplateStreamAsync(cancellationToken); @@ -88,7 +87,7 @@ public class DetectedOperationExportService return memoryStream; } - private void AddToWorkbook(XLWorkbook workbook, WellDto well, string host, IEnumerable operations) + private void AddToWorkbook(XLWorkbook workbook, WellDto well, string host, IEnumerable operations) { const string sheetName = "Операции"; @@ -104,14 +103,17 @@ public class DetectedOperationExportService AddToSheet(sheet, well, host, orderedOperations); } - private void AddToSheet(IXLWorksheet sheet, WellDto well, string host, IList operations) + private void AddToSheet(IXLWorksheet sheet, WellDto well, string host, IList operations) { var wellOperationCategories = wellOperationCategoryRepository.Get(true); sheet.Cell(cellDepositName).SetCellValue(well.Deposit); sheet.Cell(cellClusterName).SetCellValue(well.Cluster); sheet.Cell(cellWellName).SetCellValue(well.Caption); - sheet.Cell(cellDeltaDate).SetCellValue((TimeSpan)(Enumerable.Max(operations, (Func)(o => o.DateEnd)) - Enumerable.Min(operations, (Func)(o => o.DateStart)))); + + var deltaDate = operations.Max(o => o.DateEnd - o.DateStart); + + sheet.Cell(cellDeltaDate).SetCellValue(deltaDate); for (int i = 0; i < operations.Count; i++) { @@ -157,7 +159,7 @@ public class DetectedOperationExportService } } - private static string GetCategoryName(IEnumerable wellOperationCategories, DetectedOperation current) + private static string GetCategoryName(IEnumerable wellOperationCategories, DetectedOperationDto current) { var idCategory = current.IdCategory; if (idCategory == WellOperationCategory.IdSlide && @@ -198,7 +200,7 @@ public class DetectedOperationExportService return memoryStream; } - private static string CreateComment(DetectedOperation operation) + private static string CreateComment(DetectedOperationDto operation) { switch (operation.IdCategory) { diff --git a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs index bd8fba77..06415870 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs @@ -1,16 +1,16 @@ -using AsbCloudApp.Data; +using System; +using AsbCloudApp.Data; using AsbCloudApp.Data.DetectedOperation; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; -using AsbCloudDb; using AsbCloudDb.Model; using Mapster; -using Microsoft.EntityFrameworkCore; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using AsbCloudInfrastructure.Services.DetectOperations.Detectors; namespace AsbCloudInfrastructure.Services.DetectOperations; @@ -19,21 +19,29 @@ public class DetectedOperationService : IDetectedOperationService private readonly IDetectedOperationRepository operationRepository; private readonly IWellOperationCategoryRepository wellOperationCategoryRepository; private readonly IWellService wellService; - private readonly IRepositoryWellRelated operationValueService; - private readonly IScheduleRepository scheduleService; + private readonly IRepositoryWellRelated operationValueRepository; + private readonly IScheduleRepository scheduleRepository; + private readonly ITelemetryDataSaubService telemetryDataSaubService; + private static readonly DetectorAbstract[] detectors = { + new DetectorDrilling(), + new DetectorSlipsTime() + }; + public DetectedOperationService( IDetectedOperationRepository operationRepository, IWellOperationCategoryRepository wellOperationCategoryRepository, IWellService wellService, IRepositoryWellRelated operationValueRepository, - IScheduleRepository scheduleRepository) + IScheduleRepository scheduleRepository, + ITelemetryDataSaubService telemetryDataSaubService) { this.operationRepository = operationRepository; this.wellOperationCategoryRepository = wellOperationCategoryRepository; this.wellService = wellService; - this.operationValueService = operationValueRepository; - this.scheduleService = scheduleRepository; + this.operationValueRepository = operationValueRepository; + this.scheduleRepository = scheduleRepository; + this.telemetryDataSaubService = telemetryDataSaubService; } public async Task GetAsync(DetectedOperationByWellRequest request, CancellationToken token) @@ -60,8 +68,8 @@ public class DetectedOperationService : IDetectedOperationService var requestByTelemetry = new DetectedOperationByTelemetryRequest(well.IdTelemetry.Value, request); var data = await operationRepository.Get(requestByTelemetry, token); - var operationValues = await operationValueService.GetByIdWellAsync(request.IdWell, token); - var schedules = await scheduleService.GetByIdWellAsync(request.IdWell, token); + var operationValues = await operationValueRepository.GetByIdWellAsync(request.IdWell, token); + var schedules = await scheduleRepository.GetByIdWellAsync(request.IdWell, token); var dtos = data.Select(o => Convert(o, operationValues, schedules)); return dtos; } @@ -103,9 +111,7 @@ public class DetectedOperationService : IDetectedOperationService if (!operations.Any()) return Enumerable.Empty(); - - var operationValues = await operationValueService.GetByIdWellAsync(request.IdWell, token); - + var dtos = operations .GroupBy(o => (o.IdCategory, o.OperationCategory.Name)) .OrderBy(g => g.Key) @@ -126,6 +132,69 @@ public class DetectedOperationService : IDetectedOperationService return dtos; } + public async Task> DetectOperationsAsync(int idTelemetry, DateTimeOffset? beginDate, CancellationToken token) + { + const int take = 4 * 86_400; + + var detectedOperations = new List(); + DetectedOperationDto? lastDetectedOperation = null; + const int minOperationLength = 5; + const int maxDetectorsInterpolationFrameLength = 30; + const int gap = maxDetectorsInterpolationFrameLength + minOperationLength; + + while (true) + { + var request = new TelemetryDataRequest + { + GeDate = beginDate, + Take = take, + Order = 0 + }; + + var detectableTelemetries = (await telemetryDataSaubService.GetByTelemetryAsync(idTelemetry, request, token)) + .Where(t => t.BlockPosition >= 0) + .Select(t => new DetectableTelemetry + { + DateTime = t.DateTime, + IdUser = t.IdUser, + Mode = t.Mode, + WellDepth = t.WellDepth, + Pressure = t.Pressure, + HookWeight = t.HookWeight, + BlockPosition = t.BlockPosition, + BitDepth = t.BitDepth, + RotorSpeed = t.RotorSpeed, + }).ToArray(); + + if (detectableTelemetries.Length < gap) + break; + + var isDetected = false; + var positionBegin = 0; + var positionEnd = detectableTelemetries.Length - gap; + while (positionEnd > positionBegin) + { + foreach (var detector in detectors) + { + if (!detector.TryDetect(idTelemetry, detectableTelemetries, positionBegin, positionEnd, lastDetectedOperation, out var result)) + continue; + + detectedOperations.Add(result!.Operation); + lastDetectedOperation = result.Operation; + isDetected = true; + positionBegin = result.TelemetryEnd; + break; + } + + positionBegin += 1; + } + + beginDate = isDetected ? lastDetectedOperation!.DateEnd : detectableTelemetries[positionEnd].DateTime; + } + + return detectedOperations; + } + public async Task DeleteAsync(DetectedOperationByWellRequest request, CancellationToken token) { var well = await wellService.GetOrDefaultAsync(request.IdWell, token); diff --git a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs index 228d0810..6c5b99de 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorAbstract.cs @@ -35,7 +35,7 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors protected const int IdReasonOfEnd_Custom1 = 10_000; - public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end, DetectedOperation? previousOperation, + public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end, DetectedOperationDto? previousOperation, out OperationDetectorResult? result) { // Проверка соответствия критерию начала операции @@ -82,9 +82,9 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors protected virtual bool IsValidOperationDetectorResult(OperationDetectorResult operationDetectorResult) => operationDetectorResult.Operation.DateEnd - operationDetectorResult.Operation.DateStart > TimeSpan.FromSeconds(3); - protected abstract bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation); + protected abstract bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperationDto? previousOperation); - protected virtual int DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation) + protected virtual int DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperationDto? previousOperation) => DetectBegin(telemetry, position, previousOperation) ? IdReasonOfEnd_NotDetected : IdReasonOfEnd_NotDetectBegin; @@ -110,16 +110,16 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors return result; } - private DetectedOperation MakeDetectedOperation(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end) + private DetectedOperationDto MakeDetectedOperation(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end) { var pBegin = telemetry[begin]; var pEnd = telemetry[end]; var (IdCategory, ExtraData) = GetSpecificInformation(telemetry, begin, end); - var operation = new DetectedOperation + var operation = new DetectedOperationDto { IdCategory = IdCategory, IdTelemetry = idTelemetry, - IdUsersAtStart = pBegin.IdUser ?? -1, + IdUserAtStart = pBegin.IdUser ?? -1, DateStart = pBegin.DateTime, DateEnd = pEnd.DateTime, DepthStart = (double)pBegin.WellDepth, diff --git a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorDrilling.cs b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorDrilling.cs index 68eda39e..88084bfe 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorDrilling.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorDrilling.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using AsbCloudApp.Data.DetectedOperation; using AsbCloudDb.Model; namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors; @@ -12,7 +13,7 @@ public class DetectorDrilling : DetectorAbstract public const string ExtraDataKeyDispersionOfNormalizedRotorSpeed = "dispersionOfNormalizedRotorSpeed"; public const string ExtraDataKeyAvgRotorSpeed = "avgRotorSpeed"; - protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation) + protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperationDto? previousOperation) { var point0 = telemetry[position]; var delta = point0.WellDepth - point0.BitDepth; @@ -25,7 +26,7 @@ public class DetectorDrilling : DetectorAbstract return true; } - protected override int DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation) + protected override int DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperationDto? previousOperation) { var point0 = telemetry[position]; var delta = point0.WellDepth - point0.BitDepth; diff --git a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorSlipsTime.cs b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorSlipsTime.cs index 58bdba27..9388918d 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorSlipsTime.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/DetectorSlipsTime.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using AsbCloudApp.Data.DetectedOperation; using AsbCloudDb.Model; namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors; @@ -9,7 +10,7 @@ public class DetectorSlipsTime : DetectorAbstract protected override double CalcValue(DetectableTelemetry[] telemetry, int begin, int end) => CalcDeltaMinutes(telemetry, begin, end); - protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation) + protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperationDto? previousOperation) { var point0 = telemetry[position]; var delta = point0.WellDepth - point0.BitDepth; diff --git a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/OperationDetectorResult.cs b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/OperationDetectorResult.cs index fcab00bd..8325d86c 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/Detectors/OperationDetectorResult.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/Detectors/OperationDetectorResult.cs @@ -1,4 +1,4 @@ -using AsbCloudDb.Model; +using AsbCloudApp.Data.DetectedOperation; namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors { @@ -7,6 +7,6 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors { public int TelemetryBegin { get; set; } public int TelemetryEnd { get; set; } - public DetectedOperation Operation { get; set; } = null!; + public DetectedOperationDto Operation { get; set; } = null!; } } diff --git a/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs b/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs index aece226e..f562e744 100644 --- a/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs +++ b/AsbCloudInfrastructure/Services/DetectOperations/WorkOperationDetection.cs @@ -1,12 +1,11 @@ -using AsbCloudDb.Model; -using Microsoft.EntityFrameworkCore; -using System; -using System.Collections.Generic; +using System; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; -using AsbCloudInfrastructure.Services.DetectOperations.Detectors; +using AsbCloudApp.Data; +using AsbCloudApp.Repositories; +using AsbCloudApp.Services; using AsbCloudInfrastructure.Background; using Microsoft.Extensions.DependencyInjection; @@ -14,19 +13,6 @@ namespace AsbCloudInfrastructure.Services.DetectOperations; public class WorkOperationDetection: Work { - private static readonly DetectorAbstract[] detectors = new DetectorAbstract[] - { - new DetectorDrilling(), - new DetectorSlipsTime() - // new DetectorRotor(), - // new DetectorSlide(), - //new DetectorDevelopment(), - //new DetectorTemplating(), - //new DetectorStaticSurveying(), - //new DetectorFlashingBeforeConnection(), - //new DetectorFlashing(), - //new DetectorTemplatingWhileDrilling(), - }; public WorkOperationDetection() :base("Operation detection") @@ -42,115 +28,27 @@ public class WorkOperationDetection: Work protected override async Task Action(string id, IServiceProvider services, Action onProgressCallback, CancellationToken token) { - using var db = services.GetRequiredService(); - db.Database.SetCommandTimeout(TimeSpan.FromMinutes(5)); - var lastDetectedDates = await db.DetectedOperations - .GroupBy(o => o.IdTelemetry) - .Select(g => new - { - IdTelemetry = g.Key, - LastDate = g.Max(o => o.DateEnd) - }) - .ToListAsync(token); + var telemetryRepository = services.GetRequiredService>(); + var detectedOperationRepository = services.GetRequiredService(); + var detectedOperationService = services.GetRequiredService(); - var telemetryIds = await db.Telemetries - .Where(t => t.Info != null && t.TimeZone != null) + var telemetryIds = (await telemetryRepository.GetAllAsync(token)) .Select(t => t.Id) - .ToListAsync(token); + .ToArray(); - var joinedlastDetectedDates = telemetryIds - .GroupJoin(lastDetectedDates, - t => t, - o => o.IdTelemetry, - (outer, inner) => new - { - IdTelemetry = outer, - inner.SingleOrDefault()?.LastDate, - }); + var lastDetectedDates = await detectedOperationRepository.GetLastDetectedDatesAsync(token); - var affected = 0; - var count = joinedlastDetectedDates.Count(); - var i = 0d; - foreach (var item in joinedlastDetectedDates) + for (var i = 0; i < telemetryIds.Length; i++) { - var stopwatch = Stopwatch.StartNew(); - var startDate = item.LastDate ?? DateTimeOffset.MinValue; - onProgressCallback($"start detecting telemetry: {item.IdTelemetry} from {startDate}", i++ / count); - var newOperations = await DetectOperationsAsync(item.IdTelemetry, startDate, db, token); - stopwatch.Stop(); - if (newOperations.Any()) - { - db.DetectedOperations.AddRange(newOperations); - affected += await db.SaveChangesAsync(token); - } + var telemetryId = telemetryIds[i]; + + var beginDate = lastDetectedDates.TryGetValue(telemetryId, out var date) ? date : (DateTimeOffset?)null; + + onProgressCallback($"Start detecting telemetry: {telemetryId} from {beginDate}", i++ / telemetryIds.Length); + var detectedOperations = await detectedOperationService.DetectOperationsAsync(telemetryId, beginDate, token); + + if (detectedOperations.Any()) + await detectedOperationRepository.InsertRangeAsync(detectedOperations, token); } } - - //todo: move this logic to DetectedOperationsService - internal static async Task> DetectOperationsAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token) - { - var query = db.TelemetryDataSaub - .AsNoTracking() - .Where(d => d.IdTelemetry == idTelemetry) - .Where(d => d.BlockPosition >= 0) - .Select(d => new DetectableTelemetry - { - DateTime = d.DateTime, - IdUser = d.IdUser, - Mode = d.Mode, - WellDepth = d.WellDepth, - Pressure = d.Pressure, - HookWeight = d.HookWeight, - BlockPosition = d.BlockPosition, - BitDepth = d.BitDepth, - RotorSpeed = d.RotorSpeed, - }) - .OrderBy(d => d.DateTime); - - var take = 4 * 86_400; // 4 дня - var startDate = begin; - var detectedOperations = new List(8); - DetectedOperation? lastDetectedOperation = null; - const int minOperationLength = 5; - const int maxDetectorsInterpolationFrameLength = 30; - const int gap = maxDetectorsInterpolationFrameLength + minOperationLength; - - while (true) - { - var data = await query - .Where(d => d.DateTime > startDate) - .Take(take) - .ToArrayAsync(token); - - if (data.Length < gap) - break; - - var isDetected = false; - var positionBegin = 0; - var positionEnd = data.Length - gap; - while (positionEnd > positionBegin) - { - foreach (var detector in detectors) - { - if (!detector.TryDetect(idTelemetry, data, positionBegin, positionEnd, lastDetectedOperation, out var result)) - continue; - - detectedOperations.Add(result!.Operation); - lastDetectedOperation = result.Operation; - isDetected = true; - positionBegin = result.TelemetryEnd; - break; - } - - positionBegin += 1; - } - - if (isDetected) - startDate = lastDetectedOperation!.DateEnd; - else - startDate = data[positionEnd].DateTime; - } - - return detectedOperations; - } } diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs index e296692c..f9cc64ee 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs @@ -11,6 +11,7 @@ using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; +using AsbCloudApp.Requests; namespace AsbCloudInfrastructure.Services.SAUB { @@ -22,7 +23,7 @@ namespace AsbCloudInfrastructure.Services.SAUB protected readonly ITelemetryService telemetryService; protected readonly ITelemetryDataCache telemetryDataCache; - public TelemetryDataBaseService( + protected TelemetryDataBaseService( IAsbCloudDbContext db, ITelemetryService telemetryService, ITelemetryDataCache telemetryDataCache) @@ -86,7 +87,7 @@ namespace AsbCloudInfrastructure.Services.SAUB } /// - public virtual async Task> GetAsync(int idWell, + public virtual async Task> GetByWellAsync(int idWell, DateTime dateBegin = default, double intervalSec = 600d, int approxPointsCount = 1024, CancellationToken token = default) { @@ -146,23 +147,41 @@ namespace AsbCloudInfrastructure.Services.SAUB } /// - public virtual async Task> GetAsync(int idWell, AsbCloudApp.Requests.TelemetryDataRequest request, CancellationToken token) + public virtual async Task> GetByWellAsync(int idWell, TelemetryDataRequest request, CancellationToken token) { var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell); if (telemetry is null) return Enumerable.Empty(); - var timezone = telemetryService.GetTimezone(telemetry.Id); + return await GetByTelemetryAsync(telemetry.Id, request, token); + } - var cache = telemetryDataCache.GetOrDefault(telemetry.Id, request); + public async Task> GetByTelemetryAsync(int idTelemetry, TelemetryDataRequest request, CancellationToken token) + { + var timezone = telemetryService.GetTimezone(idTelemetry); + + var cache = telemetryDataCache.GetOrDefault(idTelemetry, request); + if(cache is not null) return cache; + + var query = BuildQuery(idTelemetry, request); + var entities = await query + .AsNoTracking() + .ToArrayAsync(token); + + var dtos = entities.Select(e => Convert(e, timezone.Hours)); + + return dtos; + } + + private IQueryable BuildQuery(int idTelemetry, TelemetryDataRequest request) + { var dbSet = db.Set(); var query = dbSet - .Where(d => d.IdTelemetry == telemetry.Id) - .AsNoTracking(); + .Where(d => d.IdTelemetry == idTelemetry); if (request.GeDate.HasValue) { @@ -196,12 +215,7 @@ namespace AsbCloudInfrastructure.Services.SAUB break; } - var entities = await query - .ToArrayAsync(token); - - var dtos = entities.Select(e => Convert(e, timezone.Hours)); - - return dtos; + return query; } /// @@ -263,9 +277,9 @@ namespace AsbCloudInfrastructure.Services.SAUB return telemetryDataCache.GetOrDefaultDataDateRange(telemetry.Id); } - public abstract TDto Convert(TEntity src, double timezoneOffset); + protected abstract TDto Convert(TEntity src, double timezoneOffset); - public abstract TEntity Convert(TDto src, double timezoneOffset); + protected abstract TEntity Convert(TDto src, double timezoneOffset); } } diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs index fdced02c..92db8e4d 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs @@ -111,7 +111,7 @@ public class TelemetryDataSaubService : TelemetryDataBaseService(); var telemetryUser = telemetryUserService @@ -122,7 +122,7 @@ public class TelemetryDataSaubService : TelemetryDataBaseService(); var telemetryUser = telemetryUserService.GetOrDefault(src.IdTelemetry, src.IdUser ?? int.MinValue); @@ -151,7 +151,7 @@ public class TelemetryDataSaubService : TelemetryDataBaseService 32_768 }; - var data = await GetAsync(idWell, beginDate, intervalSec, approxPointsCount, token); + var data = await GetByWellAsync(idWell, beginDate, intervalSec, approxPointsCount, token); var fileName = $"DataSaub idWell{idWell}"; if (telemetry.Info is not null) diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSpinService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSpinService.cs index dab1e851..3a6f60d4 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSpinService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSpinService.cs @@ -16,14 +16,14 @@ namespace AsbCloudInfrastructure.Services.SAUB : base(db, telemetryService, telemetryDataCache) { } - public override TelemetryDataSpin Convert(TelemetryDataSpinDto src, double timezoneOffset) + protected override TelemetryDataSpin Convert(TelemetryDataSpinDto src, double timezoneOffset) { var entity = src.Adapt(); entity.DateTime = src.DateTime.ToUtcDateTimeOffset(timezoneOffset); return entity; } - public override TelemetryDataSpinDto Convert(TelemetryDataSpin src, double timezoneOffset) + protected override TelemetryDataSpinDto Convert(TelemetryDataSpin src, double timezoneOffset) { var dto = src.Adapt(); dto.DateTime = src.DateTime.ToRemoteDateTime(timezoneOffset); diff --git a/AsbCloudInfrastructure/Services/WellOperationImport/WellOperationImportService.cs b/AsbCloudInfrastructure/Services/WellOperationImport/WellOperationImportService.cs index b8042275..800979e5 100644 --- a/AsbCloudInfrastructure/Services/WellOperationImport/WellOperationImportService.cs +++ b/AsbCloudInfrastructure/Services/WellOperationImport/WellOperationImportService.cs @@ -5,20 +5,24 @@ using System.Linq; using AsbCloudApp.Data; using AsbCloudApp.Data.WellOperationImport; using AsbCloudApp.Repositories; +using AsbCloudApp.Services; using AsbCloudApp.Services.WellOperationImport; namespace AsbCloudInfrastructure.Services.WellOperationImport; public class WellOperationImportService : IWellOperationImportService { + private readonly IWellService wellService; private readonly IWellOperationRepository wellOperationRepository; private static readonly DateTime dateLimitMin = new(2001, 1, 1, 0, 0, 0); private static readonly DateTime dateLimitMax = new(2099, 1, 1, 0, 0, 0); private static readonly TimeSpan drillingDurationLimitMax = TimeSpan.FromDays(366); - public WellOperationImportService(IWellOperationRepository wellOperationRepository) + public WellOperationImportService(IWellService wellService, + IWellOperationRepository wellOperationRepository) { + this.wellService = wellService; this.wellOperationRepository = wellOperationRepository; } @@ -30,8 +34,12 @@ public class WellOperationImportService : IWellOperationImportService var categories = wellOperationRepository.GetCategories(false); var wellOperations = new List(); - - foreach (var row in sheet.Rows) + + var rows = sheet.Rows.OrderBy(r => r.Date); + + var prevRow = new RowDto(); + + foreach (var row in rows) { try { @@ -58,15 +66,18 @@ public class WellOperationImportService : IWellOperationImportService if (row.Date < dateLimitMin && row.Date > dateLimitMax) throw new FileFormatException( $"Лист '{sheet.Name}'. Строка '{row.Number}' неправильно получена дата начала операции"); - - if (wellOperations.LastOrDefault()?.DateStart > row.Date) + + if (prevRow.Date > row.Date) throw new FileFormatException( $"Лист '{sheet.Name}' строка '{row.Number}' дата позднее даты предыдущей операции"); if (row.Duration is not (>= 0d and <= 240d)) throw new FileFormatException($"Лист '{sheet.Name}'. Строка '{row.Number}' некорректная длительность операции"); - wellOperations.Add(new WellOperationDto + var timezone = wellService.GetTimezone(idWell); + var timezoneOffset = TimeSpan.FromHours(timezone.Hours); + + var wellOperation = new WellOperationDto { IdWell = idWell, IdUser = idUser, @@ -76,10 +87,14 @@ public class WellOperationImportService : IWellOperationImportService CategoryInfo = row.CategoryInfo, DepthStart = row.DepthStart, DepthEnd = row.DepthEnd, - DateStart = row.Date, + DateStart = new DateTimeOffset(row.Date, timezoneOffset), DurationHours = row.Duration, Comment = row.Comment - }); + }; + + wellOperations.Add(wellOperation); + + prevRow = row; } catch (FileFormatException ex) { diff --git a/AsbCloudWebApi.IntegrationTests/AsbCloudWebApi.IntegrationTests.csproj b/AsbCloudWebApi.IntegrationTests/AsbCloudWebApi.IntegrationTests.csproj index a9d7713a..1c641f69 100644 --- a/AsbCloudWebApi.IntegrationTests/AsbCloudWebApi.IntegrationTests.csproj +++ b/AsbCloudWebApi.IntegrationTests/AsbCloudWebApi.IntegrationTests.csproj @@ -18,6 +18,14 @@ + + + + + + + + diff --git a/AsbCloudWebApi.IntegrationTests/Clients/IWellOperationClient.cs b/AsbCloudWebApi.IntegrationTests/Clients/IWellOperationClient.cs index 07754ed1..8e2db98f 100644 --- a/AsbCloudWebApi.IntegrationTests/Clients/IWellOperationClient.cs +++ b/AsbCloudWebApi.IntegrationTests/Clients/IWellOperationClient.cs @@ -6,16 +6,22 @@ namespace AsbCloudWebApi.IntegrationTests.Clients; public interface IWellOperationClient { - private const string BaseRoute = "/api/well/{idWell}/wellOperations"; + private const string BaseRoute = "/api/well/{idWell}/wellOperations"; - [Post(BaseRoute + "/{idType}/{deleteBeforeInsert}")] - Task> InsertRangeAsync(int idWell, int idType, bool deleteBeforeInsert, [Body] IEnumerable dtos); + [Post(BaseRoute + "/{idType}/{deleteBeforeInsert}")] + Task> InsertRangeAsync(int idWell, int idType, bool deleteBeforeInsert, [Body] IEnumerable dtos); - [Put(BaseRoute + "/{idOperation}")] - Task> UpdateAsync(int idWell, int idOperation, [Body] WellOperationDto value, CancellationToken token); + [Put(BaseRoute + "/{idOperation}")] + Task> UpdateAsync(int idWell, int idOperation, [Body] WellOperationDto value, CancellationToken token); [Get(BaseRoute + "/plan")] Task>> GetPageOperationsPlanAsync(int idWell, [Query] WellOperationRequestBase request, CancellationToken token); + + [Multipart] + [Post(BaseRoute + "/import/plan/default")] + Task>> ImportPlanDefaultExcelFileAsync(int idWell, + [AliasAs("files")] IEnumerable streams, + CancellationToken token); } \ No newline at end of file diff --git a/AsbCloudWebApi.IntegrationTests/Controllers/WellOperationControllerTest.cs b/AsbCloudWebApi.IntegrationTests/Controllers/WellOperationControllerTest.cs index 46ce1d4d..a47d5f09 100644 --- a/AsbCloudWebApi.IntegrationTests/Controllers/WellOperationControllerTest.cs +++ b/AsbCloudWebApi.IntegrationTests/Controllers/WellOperationControllerTest.cs @@ -2,7 +2,10 @@ using AsbCloudApp.Data; using AsbCloudDb.Model; using AsbCloudWebApi.IntegrationTests.Clients; using System.Net; +using System.Reflection; using AsbCloudApp.Requests; +using AsbCloudWebApi.IntegrationTests.Data; +using Refit; using Xunit; namespace AsbCloudWebApi.IntegrationTests.Controllers; @@ -28,7 +31,7 @@ public class WellOperationControllerTest : BaseIntegrationTest DepthEnd = 20.0, Day = 0.0, NptHours = 0.0, - DateStart = new DateTimeOffset(new DateTime(2023, 02, 03, 1, 0, 0, DateTimeKind.Unspecified)), + DateStart = new DateTimeOffset(new DateTime(2023, 1, 10), TimeSpan.FromHours(Defaults.Wells[0].Timezone.Hours)), DurationHours = 1.0, Comment = "1", IdUser = 1, @@ -117,4 +120,37 @@ public class WellOperationControllerTest : BaseIntegrationTest var excludeProps = new[] { nameof(WellOperationDto.Id) }; MatchHelper.Match(dto, wellOperation, excludeProps); } + + [Fact] + public async Task ImportPlanDefaultExcelFileAsync_returns_success() + { + //arrange + //TODO: вынести в метод расширения. Сделать когда доберёмся до рефакторинга операций по скважине + var resourceName = Assembly.GetExecutingAssembly() + .GetManifestResourceNames() + .FirstOrDefault(n => n.EndsWith("WellOperationsPlan.xlsx")); + + if (string.IsNullOrWhiteSpace(resourceName)) + throw new ArgumentNullException(nameof(resourceName)); + + var stream = Assembly.GetExecutingAssembly() + .GetManifestResourceStream(resourceName); + + if (stream is null) + throw new ArgumentNullException(nameof(stream)); + + var memoryStream = new MemoryStream(); + stream.CopyTo(memoryStream); + memoryStream.Position = 0; + + //act + var streamPart = new StreamPart(memoryStream, "WellOperations.xlsx", "application/octet-stream"); + + var response = await client.ImportPlanDefaultExcelFileAsync(idWell, new[] { streamPart }, CancellationToken.None); + + //assert + Assert.NotNull(response.Content); + Assert.Equal(4, response.Content.Count()); + Assert.True(response.Content.All(w => Math.Abs(w.DateStart.Offset.Hours - Defaults.Wells[0].Timezone.Hours) < 0.1)); + } } \ No newline at end of file diff --git a/AsbCloudWebApi.IntegrationTests/WellOperationsPlan.xlsx b/AsbCloudWebApi.IntegrationTests/WellOperationsPlan.xlsx new file mode 100644 index 00000000..dd1a2781 Binary files /dev/null and b/AsbCloudWebApi.IntegrationTests/WellOperationsPlan.xlsx differ diff --git a/AsbCloudWebApi.Tests/Services/DetectedOperations/Detectors/DetectorDrillingTests.cs b/AsbCloudWebApi.Tests/Services/DetectedOperations/Detectors/DetectorDrillingTests.cs index 8a61dd15..bd8c5690 100644 --- a/AsbCloudWebApi.Tests/Services/DetectedOperations/Detectors/DetectorDrillingTests.cs +++ b/AsbCloudWebApi.Tests/Services/DetectedOperations/Detectors/DetectorDrillingTests.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using AsbCloudDb.Model; +using AsbCloudApp.Data.DetectedOperation; using AsbCloudInfrastructure.Services.DetectOperations; using AsbCloudInfrastructure.Services.DetectOperations.Detectors; using Xunit; @@ -10,8 +10,7 @@ public class DetectorDrillingTests : DetectorDrilling { private const int idSlide = 5002; private const int idRotor = 5003; - private const int idSlideWithOscillation = 12000; - + [Theory] [MemberData(nameof(TelemetryRangeDrillingRotor))] public void DefineDrillingOperation_ShouldReturn_DrillingRotor(DetectableTelemetry[] telemetryRange) @@ -54,7 +53,7 @@ public class DetectorDrillingTests : DetectorDrilling //arrange var operationDetectorResult = new OperationDetectorResult { - Operation = new DetectedOperation + Operation = new DetectedOperationDto { DepthStart = 5000, DepthEnd = 6000, @@ -76,7 +75,7 @@ public class DetectorDrillingTests : DetectorDrilling //arrange var operationDetectorResult = new OperationDetectorResult { - Operation = new DetectedOperation + Operation = new DetectedOperationDto { DepthStart = 5000, DepthEnd = 5000, @@ -201,7 +200,6 @@ public class DetectorDrillingTests : DetectorDrilling { new DetectableTelemetry { - IdUser = 1, WellDepth = 415.306f, Pressure = 53.731934f, HookWeight = 41.049942f, @@ -211,7 +209,6 @@ public class DetectorDrillingTests : DetectorDrilling }, new DetectableTelemetry { - IdUser = 1, WellDepth = 415.311f, Pressure = 57.660595f, HookWeight = 40.898712f, @@ -221,7 +218,6 @@ public class DetectorDrillingTests : DetectorDrilling }, new DetectableTelemetry { - IdUser = 1, WellDepth = 415.326f, Pressure = 59.211086f, HookWeight = 40.882797f, @@ -231,7 +227,6 @@ public class DetectorDrillingTests : DetectorDrilling }, new DetectableTelemetry { - IdUser = 1, WellDepth = 415.344f, Pressure = 59.484406f, HookWeight = 40.91972f, @@ -241,7 +236,6 @@ public class DetectorDrillingTests : DetectorDrilling }, new DetectableTelemetry { - IdUser = 1, WellDepth = 415.364f, Pressure = 60.739918f, HookWeight = 40.795666f, @@ -251,7 +245,6 @@ public class DetectorDrillingTests : DetectorDrilling }, new DetectableTelemetry { - IdUser = 1, WellDepth = 415.378f, Pressure = 62.528984f, HookWeight = 40.52114f, @@ -261,7 +254,6 @@ public class DetectorDrillingTests : DetectorDrilling }, new DetectableTelemetry { - IdUser = 1, WellDepth = 415.392f, Pressure = 67.0039f, HookWeight = 38.878895f, @@ -271,7 +263,6 @@ public class DetectorDrillingTests : DetectorDrilling }, new DetectableTelemetry { - IdUser = 1, WellDepth = 415.392f, Pressure = 65.72418f, HookWeight = 42.53173f, @@ -281,7 +272,6 @@ public class DetectorDrillingTests : DetectorDrilling }, new DetectableTelemetry { - IdUser = 1, WellDepth = 415.392f, Pressure = 56.82195f, HookWeight = 43.15844f, diff --git a/AsbCloudWebApi.Tests/Services/WellOperationExport/WellOperationExportServiceTest.cs b/AsbCloudWebApi.Tests/Services/WellOperationExport/WellOperationExportServiceTest.cs index 2590df26..3d66aab9 100644 --- a/AsbCloudWebApi.Tests/Services/WellOperationExport/WellOperationExportServiceTest.cs +++ b/AsbCloudWebApi.Tests/Services/WellOperationExport/WellOperationExportServiceTest.cs @@ -117,7 +117,7 @@ namespace AsbCloudWebApi.Tests.Services.WellOperationExport wellOperationImportTemplateService = new WellOperationImportTemplateService(); wellOperationExportService = new WellOperationExportService(wellOperationRepository, wellService, wellOperationImportTemplateService); - wellOperationImportService = new WellOperationImportService(wellOperationRepository); + wellOperationImportService = new WellOperationImportService(wellService, wellOperationRepository); wellOperationDefaultExcelParser = new WellOperationDefaultExcelParser(); this.output = output; } diff --git a/AsbCloudWebApi/Controllers/SAUB/TelemetryDataBaseController.cs b/AsbCloudWebApi/Controllers/SAUB/TelemetryDataBaseController.cs index 4c8ec124..5ff378de 100644 --- a/AsbCloudWebApi/Controllers/SAUB/TelemetryDataBaseController.cs +++ b/AsbCloudWebApi/Controllers/SAUB/TelemetryDataBaseController.cs @@ -92,7 +92,7 @@ namespace AsbCloudWebApi.Controllers.SAUB if (!isCompanyOwnsWell) return Forbid(); - var content = await telemetryDataService.GetAsync(idWell, begin, + var content = await telemetryDataService.GetByWellAsync(idWell, begin, intervalSec, approxPointsCount, token).ConfigureAwait(false); return Ok(content); @@ -123,7 +123,7 @@ namespace AsbCloudWebApi.Controllers.SAUB if (!isCompanyOwnsWell) return Forbid(); - var content = await telemetryDataService.GetAsync(idWell, request, token); + var content = await telemetryDataService.GetByWellAsync(idWell, request, token); return Ok(content); } diff --git a/AsbCloudWebApi/Controllers/WellOperationController.cs b/AsbCloudWebApi/Controllers/WellOperationController.cs index 83f2987a..0d53a4ad 100644 --- a/AsbCloudWebApi/Controllers/WellOperationController.cs +++ b/AsbCloudWebApi/Controllers/WellOperationController.cs @@ -281,7 +281,6 @@ namespace AsbCloudWebApi.Controllers foreach (var wellOperation in wellOperations) { wellOperation.IdWell = idWell; - wellOperation.LastUpdateDate = DateTimeOffset.UtcNow; wellOperation.IdUser = User.GetUserId(); wellOperation.IdType = idType; } @@ -313,7 +312,6 @@ namespace AsbCloudWebApi.Controllers value.IdWell = idWell; value.Id = idOperation; - value.LastUpdateDate = DateTimeOffset.UtcNow; value.IdUser = User.GetUserId(); var result = await operationRepository.UpdateAsync(value, token)