1. Создан WellOperationService.

2. Часть методов перенесены из WellOperationRepository в WellOperationService.
3. Перенастройка ссылок на новый сервис
4. Выделение WellOperationBaseDto
This commit is contained in:
Olga Nemt 2024-08-14 12:24:54 +05:00
parent 770a370d7f
commit b7d1d26722
14 changed files with 462 additions and 457 deletions

View File

@ -1,119 +1,22 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Data.WellOperation;
/// <summary>
/// Операция по скважине
/// Операция по скважине c Day и NPV
/// </summary>
public class WellOperationDto : ItemInfoDto,
IId,
IWellRelated,
IValidatableObject
public class WellOperationDto : WellOperationBaseDto
{
/// <inheritdoc/>
[Required]
public int Id { get; set; }
/// <summary>
/// Кол-во дней от даты начала первой плановой (а если её нет, то фактической) операции
/// </summary>
[Required]
public double Day { get; set; }
/// <inheritdoc/>
[Required]
public int IdWell { get; set; }
/// <summary>
/// Кол-во часов НПВ от даты начала первой плановой (а если её нет, то фактической) операции
/// </summary>
[Required]
public double NptHours { get; set; }
/// <summary>
/// Id секции скважины
/// </summary>
public int IdWellSectionType { get; set; }
/// <summary>
/// 0 = план или 1 = факт или прогноз = 2
/// </summary>
[Required]
public int IdType { get; set; }
/// <summary>
/// id категории операции
/// </summary>
public int IdCategory { get; set; }
/// <summary>
/// Глубина на начало операции, м
/// </summary>
public double DepthStart { get; set; }
/// <summary>
/// Глубина после завершения операции, м
/// </summary>
[Required]
[Range(0, 50_000)]
public double DepthEnd { get; set; }
/// <summary>
/// Дата начала операции
/// </summary>
[Required]
public DateTimeOffset DateStart { get; set; }
/// <summary>
/// Продолжительность, часы
/// </summary>
public double DurationHours { get; set; }
/// <summary>
/// Наименование секции
/// </summary>
public string? WellSectionTypeCaption { get; set; }
/// <summary>
/// Наименование категории
/// </summary>
public string? OperationCategoryName { get; set; }
/// <summary>
/// id плановой операции для сопоставления
/// </summary>
public int? IdPlan { get; set; }
/// <summary>
/// Ключ родителя у категории
/// </summary>
public int? IdParentCategory { get; set; }
/// <summary>
/// дополнительная информация по операции
/// </summary>
[StringLength(8192)]
public string? CategoryInfo { get; set; }
/// <summary>
/// Кол-во дней от даты начала первой плановой (а если её нет, то фактической) операции
/// </summary>
[Required]
public double Day { get; set; }
/// <summary>
/// Кол-во часов НПВ от даты начала первой плановой (а если её нет, то фактической) операции
/// </summary>
[Required]
public double NptHours { get; set; }
/// <summary>
/// Полезный комментарий
/// </summary>
[StringLength(4096, ErrorMessage = "Комментарий не может быть длиннее 4096 символов")]
public string? Comment { get; set; }
/// <summary>
/// Валидация даты
/// </summary>
/// <param name="validationContext"></param>
/// <returns></returns>
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var gtDate = new DateTimeOffset(2010, 1, 1, 0, 0, 0, TimeSpan.Zero);
if (DateStart <= gtDate)
yield return new ValidationResult(
$"{nameof(DateStart)}: DateStart не может быть меньше {gtDate}",
new[] { nameof(DateStart) });
}
}

View File

@ -18,46 +18,6 @@ namespace AsbCloudApp.Repositories
/// <returns></returns>
IEnumerable<WellSectionTypeDto> GetSectionTypes();
/// <summary>
/// Получить страницу списка операций
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<WellOperationDto>> GetAsync(WellOperationRequest request, CancellationToken token);
/// <summary>
/// Получить страницу списка операций
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<PaginationContainer<WellOperationDto>> GetPageAsync(WellOperationRequest request, CancellationToken token);
/// <summary>
/// Получить страницу с операцией
/// </summary>
/// <param name="idWell"></param>
/// <param name="id"></param>
/// <param name="operationType"></param>
/// <param name="take"></param>
/// <param name="sortFields"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<PaginationContainer<WellOperationDto>?> GetPageAsync(int idWell,
int id,
int operationType,
int? take,
IEnumerable<string>? sortFields,
CancellationToken token);
/// <summary>
/// Получить статистику операции по скважине с группировкой по категориям
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<WellGroupOpertionDto>> GetGroupOperationsStatAsync(WellOperationRequest request, CancellationToken token);
/// <summary>
/// Добавить несколько операций
@ -66,7 +26,7 @@ namespace AsbCloudApp.Repositories
/// <param name="deleteBeforeInsert"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> InsertRangeAsync(IEnumerable<WellOperationDto> dtos, bool deleteBeforeInsert, CancellationToken token);
Task<int> InsertRangeAsync(IEnumerable<WellOperationBaseDto> dtos, bool deleteBeforeInsert, CancellationToken token);
/// <summary>
/// Обновить существующую операцию
@ -74,7 +34,7 @@ namespace AsbCloudApp.Repositories
/// <param name="dtos"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> UpdateRangeAsync(IEnumerable<WellOperationDto> dtos, CancellationToken token);
Task<int> UpdateRangeAsync(IEnumerable<WellOperationBaseDto> dtos, CancellationToken token);
/// <summary>
/// Удалить операции по id
@ -106,6 +66,14 @@ namespace AsbCloudApp.Repositories
/// </summary>
/// <param name="idWell"></param>
/// <returns></returns>
(WellOperationDto First, WellOperationDto Last)? GetFirstAndLastFact(int idWell);
(WellOperationBaseDto First, WellOperationBaseDto Last)? GetFirstAndLastFact(int idWell);
/// <summary>
/// Получить список операций по запросу
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<WellOperationBaseDto>> GetAll(WellOperationRequest request, CancellationToken token);
}
}

View File

@ -0,0 +1,58 @@
using AsbCloudApp.Data;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data.WellOperation;
using AsbCloudApp.Requests;
namespace AsbCloudApp.Services
{
/// <summary>
/// Сервис по представлению данных по операциям
/// </summary>
public interface IWellOperationService
{
/// <summary>
/// Получить страницу списка операций
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<WellOperationDto>> GetAsync(WellOperationRequest request, CancellationToken token);
/// <summary>
/// Получить страницу списка операций
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<PaginationContainer<WellOperationDto>> GetPageAsync(WellOperationRequest request, CancellationToken token);
/// <summary>
/// Получить страницу с операцией
/// </summary>
/// <param name="idWell"></param>
/// <param name="id"></param>
/// <param name="operationType"></param>
/// <param name="take"></param>
/// <param name="sortFields"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<PaginationContainer<WellOperationDto>?> GetPageAsync(int idWell,
int id,
int operationType,
int? take,
IEnumerable<string>? sortFields,
CancellationToken token);
/// <summary>
/// Получить статистику операции по скважине с группировкой по категориям
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<WellGroupOpertionDto>> GetGroupOperationsStatAsync(WellOperationRequest request, CancellationToken token);
}
}

View File

@ -40,6 +40,7 @@ using AsbCloudInfrastructure.Services.Trajectory.Export;
using AsbCloudInfrastructure.Services.Trajectory.Parser;
using AsbCloudInfrastructure.Services.WellOperations.Factories;
using AsbCloudInfrastructure.Services.WellOperationService;
using AsbCloudInfrastructure.Services.WellOperationService.WellOperationService;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
@ -317,6 +318,7 @@ namespace AsbCloudInfrastructure
services.AddTransient<IScheduleReportService, ScheduleReportService>();
services.AddTransient<IDataSaubStatRepository, DataSaubStatRepository>();
services.AddTransient<IDataSaubStatService, DataSaubStatService>();
services.AddTransient<IWellOperationService, WellOperationService>();
services.AddTransient<
IChangeLogRepository<ProcessMapPlanRotorDto, ProcessMapPlanBaseRequestWithWell>,

View File

@ -17,7 +17,7 @@ using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Repository;
public class WellOperationRepository : CrudRepositoryBase<WellOperationDto, WellOperation>,
public class WellOperationRepository : CrudRepositoryBase<WellOperationBaseDto, WellOperation>,
IWellOperationRepository
{
private const string cacheKeyWellOperations = "FirstAndLastFactWellsOperations";
@ -40,139 +40,14 @@ public class WellOperationRepository : CrudRepositoryBase<WellOperationDto, Well
LazyWellCategories = new(() => wellOperationCategoryRepository.Get(true, false).ToDictionary(c => c.Id));
LazyWellSectionTypes = new(() => GetSectionTypes().ToDictionary(c => c.Id));
}
public IEnumerable<WellSectionTypeDto> GetSectionTypes() =>
memoryCache
.GetOrCreateBasic(dbContext.WellSectionTypes)
.OrderBy(s => s.Order)
.Select(s => s.Adapt<WellSectionTypeDto>());
public async Task<IEnumerable<WellOperationDto>> GetAsync(WellOperationRequest request, CancellationToken token)
{
var (items, _) = await GetWithDaysAndNpvAsync(request, token);
return items;
}
public async Task<PaginationContainer<WellOperationDto>> GetPageAsync(WellOperationRequest request, CancellationToken token)
{
request.Skip = request.Skip ?? 0;
request.Take = request.Take ?? 32;
var (items, count) = await GetWithDaysAndNpvAsync(request, token);
var paginationContainer = new PaginationContainer<WellOperationDto>
{
Skip = request.Skip!.Value,
Take = request.Take!.Value,
Count = count,
Items = items
};
return paginationContainer;
}
public async Task<PaginationContainer<WellOperationDto>?> GetPageAsync(int idWell,
int id,
int operationType,
int? take,
IEnumerable<string>? sortFields,
CancellationToken token)
{
var request = new WellOperationRequest(new[] { idWell })
{
OperationType = operationType,
SortFields = sortFields,
};
var (wellOperations, count) = await GetWithDaysAndNpvAsync(request, token);
var skip = 0;
take ??= 32;
while (skip < count)
{
var page = wellOperations.Skip(skip)
.Take(take.Value);
if (page.Any(x => x.Id == id))
{
var paginationContainer = new PaginationContainer<WellOperationDto>
{
Skip = skip,
Take = take.Value,
Items = page,
Count = count
};
return paginationContainer;
}
skip += take.Value;
}
return null;
}
public async Task<IEnumerable<WellGroupOpertionDto>> GetGroupOperationsStatAsync(WellOperationRequest request, CancellationToken token)
{
var query = BuildQuery(request);
var entities = await query
.Select(o => new
{
o.IdCategory,
DurationMinutes = o.DurationHours * 60,
DurationDepth = o.DepthEnd - o.DepthStart
})
.ToArrayAsync(token);
var parentRelationDictionary = wellOperationCategoryRepository.Get(true)
.ToDictionary(c => c.Id, c => new
{
c.Name,
c.IdParent
});
var dtos = entities
.GroupBy(o => o.IdCategory)
.Select(g => new WellGroupOpertionDto
{
IdCategory = g.Key,
Category = parentRelationDictionary[g.Key].Name,
Count = g.Count(),
MinutesAverage = g.Average(o => o.DurationMinutes),
MinutesMin = g.Min(o => o.DurationMinutes),
MinutesMax = g.Max(o => o.DurationMinutes),
TotalMinutes = g.Sum(o => o.DurationMinutes),
DeltaDepth = g.Sum(o => o.DurationDepth),
IdParent = parentRelationDictionary[g.Key].IdParent
});
while (dtos.All(x => x.IdParent != null))
{
dtos = dtos
.GroupBy(o => o.IdParent!)
.Select(g =>
{
var idCategory = g.Key ?? int.MinValue;
var category = parentRelationDictionary.GetValueOrDefault(idCategory);
var newDto = new WellGroupOpertionDto
{
IdCategory = idCategory,
Category = category?.Name ?? "unknown",
Count = g.Sum(o => o.Count),
DeltaDepth = g.Sum(o => o.DeltaDepth),
TotalMinutes = g.Sum(o => o.TotalMinutes),
Items = g.ToList(),
IdParent = category?.IdParent,
};
return newDto;
});
}
return dtos;
}
public async Task<int> InsertRangeAsync(IEnumerable<WellOperationDto> dtos,
public async Task<int> InsertRangeAsync(IEnumerable<WellOperationBaseDto> dtos,
bool deleteBeforeInsert,
CancellationToken token)
{
@ -189,7 +64,7 @@ public class WellOperationRepository : CrudRepositoryBase<WellOperationDto, Well
return result;
}
var idType = dtos.First().IdType;
var idWell = dtos.First().IdWell;
@ -210,7 +85,7 @@ public class WellOperationRepository : CrudRepositoryBase<WellOperationDto, Well
}
public override async Task<int> UpdateRangeAsync(IEnumerable<WellOperationDto> dtos, CancellationToken token)
public override async Task<int> UpdateRangeAsync(IEnumerable<WellOperationBaseDto> dtos, CancellationToken token)
{
EnsureValidWellOperations(dtos);
@ -223,7 +98,7 @@ public class WellOperationRepository : CrudRepositoryBase<WellOperationDto, Well
}
private static void EnsureValidWellOperations(IEnumerable<WellOperationDto> dtos)
private static void EnsureValidWellOperations(IEnumerable<WellOperationBaseDto> dtos)
{
if (dtos.GroupBy(d => d.IdType).Count() > 1)
throw new ArgumentInvalidException(nameof(dtos), "Все операции должны быть одного типа");
@ -232,101 +107,6 @@ public class WellOperationRepository : CrudRepositoryBase<WellOperationDto, Well
throw new ArgumentInvalidException(nameof(dtos), "Все операции должны принадлежать одной скважине");
}
private async Task<IEnumerable<WellOperation>> GetByIdsWells(IEnumerable<int> idsWells, CancellationToken token)
{
var query = GetQuery()
.Where(e => idsWells.Contains(e.IdWell))
.OrderBy(e => e.DateStart);
var entities = await query.ToArrayAsync(token);
return entities;
}
private async Task<(IEnumerable<WellOperationDto> items, int count)> GetWithDaysAndNpvAsync(WellOperationRequest request, CancellationToken token)
{
var entities = await GetByIdsWells(request.IdsWell, token);
var groupedByWellAndType = entities
.GroupBy(e => new { e.IdWell, e.IdType });
var result = new List<WellOperationDto>();
var count = 0;
foreach (var wellOperationsWithType in groupedByWellAndType)
{
var firstWellOperation = wellOperationsWithType.MinBy(e => e.DateStart);
var operationsWithNpt = wellOperationsWithType
.Where(o => WellOperationCategory.NonProductiveTimeSubIds.Contains(o.IdCategory));
IEnumerable<WellOperation> filteredWellOperations = FilterByRequest(wellOperationsWithType.AsQueryable(), request);
count += filteredWellOperations.Count();
if (request.Skip != null)
filteredWellOperations = filteredWellOperations.Skip((int)request.Skip);
if (request.Take != null)
filteredWellOperations = filteredWellOperations.Take((int)request.Take);
var timezoneOffset = wellService.GetTimezone(wellOperationsWithType.Key.IdWell).Offset;
var dtos = filteredWellOperations
.Select(entity =>
{
var dto = Convert(entity, timezoneOffset);
dto.Day = (entity.DateStart - firstWellOperation.DateStart).TotalDays;
dto.NptHours = operationsWithNpt
.Where(o => o.DateStart <= entity.DateStart)
.Sum(e => e.DurationHours);
return dto;
});
result.AddRange(dtos);
}
return (result, count);
}
private static IQueryable<WellOperation> FilterByRequest(IQueryable<WellOperation> entities, WellOperationRequest request)
{
if (request.OperationType.HasValue)
entities = entities.Where(e => e.IdType == request.OperationType.Value);
if (request.SectionTypeIds?.Any() is true)
entities = entities.Where(e => request.SectionTypeIds.Contains(e.IdWellSectionType));
if (request.OperationCategoryIds?.Any() is true)
entities = entities.Where(e => request.OperationCategoryIds.Contains(e.IdCategory));
if (request.GeDepth.HasValue)
entities = entities.Where(e => e.DepthEnd >= request.GeDepth.Value);
if (request.LeDepth.HasValue)
entities = entities.Where(e => e.DepthEnd <= request.LeDepth.Value);
if (request.GeDate.HasValue)
{
var geDateUtc = request.GeDate.Value.UtcDateTime;
entities = entities.Where(e => e.DateStart >= geDateUtc);
}
if (request.LeDate.HasValue)
{
var leDateUtc = request.LeDate.Value.UtcDateTime;
entities = entities.Where(e => e.DateStart <= leDateUtc);
}
if (request.SortFields?.Any() is true)
entities = entities.AsQueryable().SortBy(request.SortFields);
else
entities = entities.AsQueryable().OrderBy(e => e.DateStart);
return entities;
}
private IQueryable<WellOperation> BuildQuery(WellOperationRequest request)
{
var query = GetQuery()
.Where(e => request.IdsWell.Contains(e.IdWell))
.OrderBy(e => e.DateStart)
.AsQueryable();
query = FilterByRequest(query, request);
return query;
}
public async Task<IEnumerable<SectionByOperationsDto>> GetSectionsAsync(IEnumerable<int> idsWells, CancellationToken token)
{
const string keyCacheSections = "OperationsBySectionSummarties";
@ -415,7 +195,7 @@ public class WellOperationRepository : CrudRepositoryBase<WellOperationDto, Well
};
}
public (WellOperationDto First, WellOperationDto Last)? GetFirstAndLastFact(int idWell)
public (WellOperationBaseDto First, WellOperationBaseDto Last)? GetFirstAndLastFact(int idWell)
{
var cachedDictionary = memoryCache.GetOrCreate(cacheKeyWellOperations, (entry) =>
{
@ -462,16 +242,16 @@ public class WellOperationRepository : CrudRepositoryBase<WellOperationDto, Well
return result;
}
protected override WellOperation Convert(WellOperationDto src)
protected override WellOperation Convert(WellOperationBaseDto src)
{
var entity = src.Adapt<WellOperation>();
entity.DateStart = src.DateStart.UtcDateTime;
return entity;
}
private WellOperationDto Convert(WellOperation src, TimeSpan timezoneOffset)
private WellOperationBaseDto Convert(WellOperation src, TimeSpan timezoneOffset)
{
var dto = src.Adapt<WellOperationDto>();
var dto = src.Adapt<WellOperationBaseDto>();
dto.DateStart = src.DateStart.ToOffset(timezoneOffset);
dto.LastUpdateDate = src.LastUpdateDate.ToOffset(timezoneOffset);
@ -479,4 +259,58 @@ public class WellOperationRepository : CrudRepositoryBase<WellOperationDto, Well
dto.WellSectionTypeCaption = LazyWellSectionTypes.Value.TryGetValue(src.IdWellSectionType, out WellSectionTypeDto? sectionType) ? sectionType.Caption : string.Empty;
return dto;
}
public async Task<IEnumerable<WellOperationBaseDto>> GetAll(WellOperationRequest request, CancellationToken token)
{
var timezoneOffsetDictionary = new Dictionary<int, TimeSpan>();
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 static IQueryable<WellOperation> FilterByRequest(IQueryable<WellOperation> entities, WellOperationRequest request)
{
if (request.OperationType.HasValue)
entities = entities.Where(e => e.IdType == request.OperationType.Value);
if (request.SectionTypeIds?.Any() is true)
entities = entities.Where(e => request.SectionTypeIds.Contains(e.IdWellSectionType));
if (request.OperationCategoryIds?.Any() is true)
entities = entities.Where(e => request.OperationCategoryIds.Contains(e.IdCategory));
if (request.GeDepth.HasValue)
entities = entities.Where(e => e.DepthEnd >= request.GeDepth.Value);
if (request.LeDepth.HasValue)
entities = entities.Where(e => e.DepthEnd <= request.LeDepth.Value);
if (request.GeDate.HasValue)
{
var geDateUtc = request.GeDate.Value.UtcDateTime;
entities = entities.Where(e => e.DateStart >= geDateUtc);
}
if (request.LeDate.HasValue)
{
var leDateUtc = request.LeDate.Value.UtcDateTime;
entities = entities.Where(e => e.DateStart <= leDateUtc);
}
if (request.SortFields?.Any() is true)
entities = entities.AsQueryable().SortBy(request.SortFields);
else
entities = entities.AsQueryable().OrderBy(e => e.DateStart);
return entities;
}
}

View File

@ -32,27 +32,30 @@ public class DailyReportService : IDailyReportService
private readonly ISubsystemService subsystemService;
private readonly IProcessMapReportDrillingService processMapReportDrillingService;
private readonly IDetectedOperationService detectedOperationService;
private readonly IWellOperationService wellOperationService;
public DailyReportService(IWellService wellService,
public DailyReportService(IWellService wellService,
ITrajectoryNnbRepository trajectoryFactNnbRepository,
IDailyReportRepository dailyReportRepository,
IScheduleRepository scheduleRepository,
IWellOperationRepository wellOperationRepository,
ISubsystemService subsystemService,
IDailyReportRepository dailyReportRepository,
IScheduleRepository scheduleRepository,
IWellOperationRepository wellOperationRepository,
ISubsystemService subsystemService,
IProcessMapReportDrillingService processMapReportDrillingService,
IDetectedOperationService detectedOperationService)
{
this.wellService = wellService;
this.trajectoryFactNnbRepository = trajectoryFactNnbRepository;
this.dailyReportRepository = dailyReportRepository;
this.scheduleRepository = scheduleRepository;
this.wellOperationRepository = wellOperationRepository;
this.subsystemService = subsystemService;
this.processMapReportDrillingService = processMapReportDrillingService;
this.detectedOperationService = detectedOperationService;
}
IDetectedOperationService detectedOperationService,
IWellOperationService wellOperationService)
{
this.wellService = wellService;
this.trajectoryFactNnbRepository = trajectoryFactNnbRepository;
this.dailyReportRepository = dailyReportRepository;
this.scheduleRepository = scheduleRepository;
this.wellOperationRepository = wellOperationRepository;
this.subsystemService = subsystemService;
this.processMapReportDrillingService = processMapReportDrillingService;
this.detectedOperationService = detectedOperationService;
this.wellOperationService = wellOperationService;
}
public async Task<int> UpdateOrInsertAsync<TBlock>(int idWell, DateOnly dateDailyReport, int idUser, TBlock editableBlock,
public async Task<int> UpdateOrInsertAsync<TBlock>(int idWell, DateOnly dateDailyReport, int idUser, TBlock editableBlock,
CancellationToken cancellationToken)
where TBlock : ItemInfoDto
{
@ -118,7 +121,7 @@ public class DailyReportService : IDailyReportService
LeDate = leDate
};
var factWellOperations = (await wellOperationRepository.GetAsync(factOperationRequest, cancellationToken))
var factWellOperations = (await wellOperationService.GetAsync(factOperationRequest, cancellationToken))
.OrderBy(o => o.DateStart)
.ThenBy(o => o.DepthStart);
@ -191,7 +194,7 @@ public class DailyReportService : IDailyReportService
LeDate = leDateFactWellOperation
};
var factWellOperations = await wellOperationRepository.GetAsync(factWellOperationRequest, cancellationToken);
var factWellOperations = await wellOperationService.GetAsync(factWellOperationRequest, cancellationToken);
if (request.SortFields?.Contains("DateStart desc") == true)
{

View File

@ -26,13 +26,15 @@ public class ProcessMapReportDrillingService : IProcessMapReportDrillingService
private readonly IDataSaubStatRepository dataSaubStatRepository;
private readonly IWellOperationRepository wellOperationRepository;
private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
private readonly IWellOperationService wellOperationService;
public ProcessMapReportDrillingService(IWellService wellService,
IChangeLogRepository<ProcessMapPlanRotorDto, ProcessMapPlanBaseRequestWithWell> processMapPlanRotorRepository,
IChangeLogRepository<ProcessMapPlanSlideDto, ProcessMapPlanBaseRequestWithWell> processMapPlanSlideRepository,
IDataSaubStatRepository dataSaubStatRepository,
IWellOperationRepository wellOperationRepository,
IWellOperationCategoryRepository wellOperationCategoryRepository
IWellOperationCategoryRepository wellOperationCategoryRepository,
IWellOperationService wellOperationService
)
{
this.wellService = wellService;
@ -41,6 +43,7 @@ public class ProcessMapReportDrillingService : IProcessMapReportDrillingService
this.dataSaubStatRepository = dataSaubStatRepository;
this.wellOperationRepository = wellOperationRepository;
this.wellOperationCategoryRepository = wellOperationCategoryRepository;
this.wellOperationService = wellOperationService;
}
public async Task<IEnumerable<ProcessMapReportDataSaubStatDto>> GetAsync(int idWell, DataSaubStatRequest request, CancellationToken token)
@ -72,7 +75,7 @@ public class ProcessMapReportDrillingService : IProcessMapReportDrillingService
GeDepth = geDepth,
LeDepth = leDepth
};
var wellOperations = await wellOperationRepository
var wellOperations = await wellOperationService
.GetAsync(requestWellOperationFact, token);
var orderedWellOperations = wellOperations

View File

@ -17,8 +17,8 @@ public class WellCompositeOperationService : IWellCompositeOperationService
{
private readonly ICrudRepository<WellSectionTypeDto> wellSectionTypeRepository;
private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
private readonly IWellOperationRepository wellOperationRepository;
private readonly IWellService wellService;
private readonly IWellOperationService wellOperationService;
/// <summary>
/// Тип секции "Транспортный стол"
@ -206,12 +206,10 @@ public class WellCompositeOperationService : IWellCompositeOperationService
public WellCompositeOperationService(
ICrudRepository<WellSectionTypeDto> wellSectionTypeRepository,
IWellOperationCategoryRepository wellOperationCategoryRepository,
IWellOperationRepository wellOperationRepository,
IWellService wellService)
{
this.wellSectionTypeRepository = wellSectionTypeRepository;
this.wellOperationCategoryRepository = wellOperationCategoryRepository;
this.wellOperationRepository = wellOperationRepository;
this.wellService = wellService;
}
@ -235,7 +233,7 @@ public class WellCompositeOperationService : IWellCompositeOperationService
SectionTypeIds = idsWellSectionTypes,
OperationType = WellOperation.IdOperationTypeFact
};
var operations = await wellOperationRepository.GetAsync(wellOperationRequest, token);
var operations = await wellOperationService.GetAsync(wellOperationRequest, token);
var operationsForComposite = operations.Select(o => CreateCompositeOperation(o, sectionsDict, categoriesDict));

View File

@ -0,0 +1,232 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.WellOperation;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb;
using AsbCloudDb.Model;
using Mapster;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services.WellOperationService.WellOperationService;
public class WellOperationService : IWellOperationService
{
private readonly IWellService wellService;
private readonly IWellOperationRepository wellOperationRepository;
private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
public WellOperationService(
IWellService wellService,
IWellOperationRepository wellOperationRepository,
IWellOperationCategoryRepository wellOperationCategoryRepository)
{
this.wellService = wellService;
this.wellOperationRepository = wellOperationRepository;
this.wellOperationCategoryRepository = wellOperationCategoryRepository;
}
public async Task<IEnumerable<WellOperationDto>> GetAsync(WellOperationRequest request, CancellationToken token)
{
var (items, _) = await GetWithDaysAndNpvAsync(request, token);
return items;
}
public async Task<PaginationContainer<WellOperationDto>> GetPageAsync(WellOperationRequest request, CancellationToken token)
{
request.Skip = request.Skip ?? 0;
request.Take = request.Take ?? 32;
var (items, count) = await GetWithDaysAndNpvAsync(request, token);
var paginationContainer = new PaginationContainer<WellOperationDto>
{
Skip = request.Skip!.Value,
Take = request.Take!.Value,
Count = count,
Items = items
};
return paginationContainer;
}
public async Task<PaginationContainer<WellOperationDto>?> GetPageAsync(int idWell,
int id,
int operationType,
int? take,
IEnumerable<string>? sortFields,
CancellationToken token)
{
var request = new WellOperationRequest(new[] { idWell })
{
OperationType = operationType,
SortFields = sortFields,
};
var (wellOperations, count) = await GetWithDaysAndNpvAsync(request, token);
var skip = 0;
take ??= 32;
while (skip < count)
{
var page = wellOperations.Skip(skip)
.Take(take.Value);
if (page.Any(x => x.Id == id))
{
var paginationContainer = new PaginationContainer<WellOperationDto>
{
Skip = skip,
Take = take.Value,
Items = page,
Count = count
};
return paginationContainer;
}
skip += take.Value;
}
return null;
}
public async Task<IEnumerable<WellGroupOpertionDto>> GetGroupOperationsStatAsync(WellOperationRequest request, CancellationToken token)
{
var wellOperationsBaseDto = await wellOperationRepository.GetAll(request, token);
var wellOperationsData = wellOperationsBaseDto
.Select(o => new
{
o.IdCategory,
DurationMinutes = o.DurationHours * 60,
DurationDepth = o.DepthEnd - o.DepthStart
});
var parentRelationDictionary = wellOperationCategoryRepository.Get(true)
.ToDictionary(c => c.Id, c => new
{
c.Name,
c.IdParent
});
var dtos = wellOperationsData
.GroupBy(o => o.IdCategory)
.Select(g => new WellGroupOpertionDto
{
IdCategory = g.Key,
Category = parentRelationDictionary[g.Key].Name,
Count = g.Count(),
MinutesAverage = g.Average(o => o.DurationMinutes),
MinutesMin = g.Min(o => o.DurationMinutes),
MinutesMax = g.Max(o => o.DurationMinutes),
TotalMinutes = g.Sum(o => o.DurationMinutes),
DeltaDepth = g.Sum(o => o.DurationDepth),
IdParent = parentRelationDictionary[g.Key].IdParent
});
while (dtos.All(x => x.IdParent != null))
{
dtos = dtos
.GroupBy(o => o.IdParent!)
.Select(g =>
{
var idCategory = g.Key ?? int.MinValue;
var category = parentRelationDictionary.GetValueOrDefault(idCategory);
var newDto = new WellGroupOpertionDto
{
IdCategory = idCategory,
Category = category?.Name ?? "unknown",
Count = g.Sum(o => o.Count),
DeltaDepth = g.Sum(o => o.DeltaDepth),
TotalMinutes = g.Sum(o => o.TotalMinutes),
Items = g.ToList(),
IdParent = category?.IdParent,
};
return newDto;
});
}
return dtos;
}
private async Task<(IEnumerable<WellOperationDto> items, int count)> GetWithDaysAndNpvAsync(WellOperationRequest request, CancellationToken token)
{
var requestByWellIds = new WellOperationRequest(request.IdsWell);
var wellOperationsBaseDtos = await wellOperationRepository.GetAll(requestByWellIds, token);
var groupedByWellAndTypeDtos = wellOperationsBaseDtos
.GroupBy(e => new { e.IdWell, e.IdType });
var result = new List<WellOperationDto>();
var count = 0;
foreach (var wellOperationsWithTypeDto in groupedByWellAndTypeDtos)
{
var firstWellOperation = wellOperationsWithTypeDto.MinBy(e => e.DateStart)!;
var operationsWithNpt = wellOperationsWithTypeDto
.Where(o => WellOperationCategory.NonProductiveTimeSubIds.Contains(o.IdCategory));
var filteredWellOperations = FilterByRequest(wellOperationsWithTypeDto, request);
count += filteredWellOperations.Count();
if (request.Skip != null)
filteredWellOperations = filteredWellOperations.Skip((int)request.Skip);
if (request.Take != null)
filteredWellOperations = filteredWellOperations.Take((int)request.Take);
var timezoneOffset = wellService.GetTimezone(wellOperationsWithTypeDto.Key.IdWell).Offset;
var dtos = filteredWellOperations
.Select(dto =>
{
var newDto = dto.Adapt<WellOperationDto>();
newDto.Day = (dto.DateStart - firstWellOperation.DateStart).TotalDays;
newDto.NptHours = operationsWithNpt
.Where(o => o.DateStart <= dto.DateStart)
.Sum(e => e.DurationHours);
return newDto;
});
result.AddRange(dtos);
}
return (result, count);
}
public static IEnumerable<WellOperationBaseDto> FilterByRequest(IEnumerable<WellOperationBaseDto> dtos, WellOperationRequest request)
{
if (request.OperationType.HasValue)
dtos = dtos.Where(e => e.IdType == request.OperationType.Value);
if (request.SectionTypeIds?.Any() is true)
dtos = dtos.Where(e => request.SectionTypeIds.Contains(e.IdWellSectionType));
if (request.OperationCategoryIds?.Any() is true)
dtos = dtos.Where(e => request.OperationCategoryIds.Contains(e.IdCategory));
if (request.GeDepth.HasValue)
dtos = dtos.Where(e => e.DepthEnd >= request.GeDepth.Value);
if (request.LeDepth.HasValue)
dtos = dtos.Where(e => e.DepthEnd <= request.LeDepth.Value);
if (request.GeDate.HasValue)
{
var geDateUtc = request.GeDate.Value.UtcDateTime;
dtos = dtos.Where(e => e.DateStart >= geDateUtc);
}
if (request.LeDate.HasValue)
{
var leDateUtc = request.LeDate.Value.UtcDateTime;
dtos = dtos.Where(e => e.DateStart <= leDateUtc);
}
if (request.SortFields?.Any() is true)
dtos = dtos.AsQueryable().SortBy(request.SortFields);
else
dtos = dtos.AsQueryable().OrderBy(e => e.DateStart);
return dtos;
}
}

View File

@ -16,18 +16,18 @@ public class WellOperationExportServiceFactory : IExportServiceFactory<int>
public WellOperationExportServiceFactory(IServiceProvider serviceProvider)
{
var wellOperationRepository = serviceProvider.GetRequiredService<IWellOperationRepository>();
var wellOperationService = serviceProvider.GetRequiredService<IWellOperationService>();
var wellService = serviceProvider.GetRequiredService<IWellService>();
exportServices = new Dictionary<int, Func<IExportService>>
{
{
WellOperation.IdOperationTypeFact,
() => new WellOperationExport<WellOperationFactTemplate>(wellOperationRepository, wellService)
() => new WellOperationExport<WellOperationFactTemplate>(wellOperationService, wellService)
},
{
WellOperation.IdOperationTypePlan,
() => new WellOperationExport<WellOperationPlanTemplate>(wellOperationRepository, wellService)
() => new WellOperationExport<WellOperationPlanTemplate>(wellOperationService, wellService)
}
};
}

View File

@ -1,50 +1,50 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data.WellOperation;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Requests.ExportOptions;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services.ExcelServices;
using AsbCloudInfrastructure.Services.ExcelServices.Templates;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services.WellOperations;
public class WellOperationExport<TTemplate> : ExcelExportService<WellOperationDto, WellOperationExportRequest, TTemplate>
where TTemplate : class, ITemplateParameters, new()
{
private readonly IWellService wellService;
private readonly IWellOperationRepository wellOperationRepository;
private readonly IWellService wellService;
private readonly IWellOperationService wellOperationService;
public WellOperationExport(IWellOperationRepository wellOperationRepository,
IWellService wellService)
{
this.wellOperationRepository = wellOperationRepository;
this.wellService = wellService;
}
public WellOperationExport(
IWellOperationService wellOperationService,
IWellService wellService)
{
this.wellService = wellService;
this.wellOperationService = wellOperationService;
}
protected override async Task<string> BuildFileNameAsync(WellOperationExportRequest options, CancellationToken token)
{
var caption = await wellService.GetWellCaptionByIdAsync(options.IdWell, token);
protected override async Task<string> BuildFileNameAsync(WellOperationExportRequest options, CancellationToken token)
{
var caption = await wellService.GetWellCaptionByIdAsync(options.IdWell, token);
return options.IdType switch
{
WellOperation.IdOperationTypeFact => $"{caption}_Фактические_операции.xlsx",
WellOperation.IdOperationTypePlan => $"{caption}_Плановые_операции.xlsx",
_ => throw new ArgumentOutOfRangeException(nameof(options.IdType))
};
}
return options.IdType switch
{
WellOperation.IdOperationTypeFact => $"{caption}_Фактические_операции.xlsx",
WellOperation.IdOperationTypePlan => $"{caption}_Плановые_операции.xlsx",
_ => throw new ArgumentOutOfRangeException(nameof(options.IdType))
};
}
protected override Task<IEnumerable<WellOperationDto>> GetDtosAsync(WellOperationExportRequest options, CancellationToken token)
{
var request = new WellOperationRequest(new[] { options.IdWell })
{
OperationType = options.IdType,
};
return wellOperationRepository.GetAsync(request, token);
}
protected override Task<IEnumerable<WellOperationDto>> GetDtosAsync(WellOperationExportRequest options, CancellationToken token)
{
var request = new WellOperationRequest(new[] { options.IdWell })
{
OperationType = options.IdType,
};
return wellOperationService.GetAsync(request, token);
}
}

View File

@ -207,10 +207,11 @@ public class DailyReportServiceTest
private readonly ITrajectoryNnbRepository trajectoryFactNnbRepositoryMock = Substitute.For<ITrajectoryNnbRepository>();
private readonly IDailyReportRepository dailyReportRepositoryMock = Substitute.For<IDailyReportRepository>();
private readonly IScheduleRepository scheduleRepositoryMock = Substitute.For<IScheduleRepository>();
private readonly IWellOperationRepository wellOperationRepositoryMock = Substitute.For<IWellOperationRepository>();
private readonly ISubsystemService subsystemServiceMock = Substitute.For<ISubsystemService>();
private readonly IProcessMapReportDrillingService processMapReportWellDrillingServiceMock = Substitute.For<IProcessMapReportDrillingService>();
private readonly IDetectedOperationService detectedOperationServiceMock = Substitute.For<IDetectedOperationService>();
private readonly IWellOperationService wellOperationServiceMock = Substitute.For<IWellOperationService>();
private readonly IWellOperationRepository wellOperationRepositoryMock = Substitute.For<IWellOperationRepository>();
private readonly DailyReportService dailyReportService;
@ -252,7 +253,8 @@ public class DailyReportServiceTest
wellOperationRepositoryMock,
subsystemServiceMock,
processMapReportWellDrillingServiceMock,
detectedOperationServiceMock);
detectedOperationServiceMock,
wellOperationServiceMock);
dailyReportRepositoryMock.InsertAsync(Arg.Any<DailyReportDto>(), Arg.Any<CancellationToken>())
.ReturnsForAnyArgs(idDailyReport);
@ -269,7 +271,7 @@ public class DailyReportServiceTest
trajectoryFactNnbRepositoryMock.GetByRequestAsync(Arg.Any<TrajectoryRequest>(), Arg.Any<CancellationToken>())
.ReturnsForAnyArgs(new[] { fakeLastFactTrajectory });
wellOperationRepositoryMock.GetAsync(Arg.Any<WellOperationRequest>(), Arg.Any<CancellationToken>())
wellOperationServiceMock.GetAsync(Arg.Any<WellOperationRequest>(), Arg.Any<CancellationToken>())
.ReturnsForAnyArgs(new[] { fakeFirstFactWellOperation, fakeLastFactWellOperation });
wellOperationRepositoryMock.GetDatesRangeAsync(Arg.Any<int>(), Arg.Any<int>(), Arg.Any<CancellationToken>())

View File

@ -22,8 +22,8 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation
= Substitute.For<ICrudRepository<WellSectionTypeDto>>();
private IWellOperationCategoryRepository wellOperationCategoryRepository
= Substitute.For<IWellOperationCategoryRepository>();
private IWellOperationRepository wellOperationRepository
= Substitute.For<IWellOperationRepository>();
private IWellOperationService wellOperationService
= Substitute.For<IWellOperationService>();
private IWellService wellService
= Substitute.For<IWellService>();
private List<int> idsWells;
@ -175,7 +175,6 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation
service = new WellCompositeOperationService(
wellSectionTypeRepository,
wellOperationCategoryRepository,
wellOperationRepository,
wellService);
}
@ -189,7 +188,7 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation
public async Task GetAsync_return_composite_and_others_with_category_5013()
{
// arrange
wellOperationRepository.GetAsync(Arg.Any<WellOperationRequest>(), Arg.Any<CancellationToken>())
wellOperationService.GetAsync(Arg.Any<WellOperationRequest>(), Arg.Any<CancellationToken>())
.Returns(wellOperations1);
// act
@ -216,7 +215,7 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation
public async Task GetAsync_return_composite_with_minimum_depth_start()
{
// arrange
wellOperationRepository.GetAsync(Arg.Any<WellOperationRequest>(), Arg.Any<CancellationToken>())
wellOperationService.GetAsync(Arg.Any<WellOperationRequest>(), Arg.Any<CancellationToken>())
.Returns(wellOperations2);
// act
@ -240,7 +239,7 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation
public async Task GetAsync_return_data3()
{
// arrange
wellOperationRepository.GetAsync(Arg.Any<WellOperationRequest>(), Arg.Any<CancellationToken>())
wellOperationService.GetAsync(Arg.Any<WellOperationRequest>(), Arg.Any<CancellationToken>())
.Returns(wellOperations3);
// act
@ -266,7 +265,7 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation
public async Task GetAsync_return_data4()
{
// arrange
wellOperationRepository.GetAsync(Arg.Any<WellOperationRequest>(), Arg.Any<CancellationToken>())
wellOperationService.GetAsync(Arg.Any<WellOperationRequest>(), Arg.Any<CancellationToken>())
.Returns(wellOperations4);
// act
@ -296,7 +295,7 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation
wellOperations.AddRange(wellOperations3);
wellOperations.AddRange(wellOperations4);
wellOperationRepository.GetAsync(Arg.Any<WellOperationRequest>(), Arg.Any<CancellationToken>())
wellOperationService.GetAsync(Arg.Any<WellOperationRequest>(), Arg.Any<CancellationToken>())
.Returns(wellOperations);
// act

View File

@ -38,6 +38,7 @@ public class WellOperationController : ControllerBase
private readonly IWellOperationRepository wellOperationRepository;
private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
private readonly IWellService wellService;
private readonly IWellOperationService wellOperationService;
private readonly WellOperationParserFactory wellOperationParserFactory;
private readonly WellOperationExportServiceFactory wellOperationExportServiceFactory;
@ -47,7 +48,8 @@ public class WellOperationController : ControllerBase
IWellService wellService,
IUserRepository userRepository,
WellOperationParserFactory wellOperationParserFactory,
WellOperationExportServiceFactory wellOperationExportServiceFactory)
WellOperationExportServiceFactory wellOperationExportServiceFactory,
IWellOperationService wellOperationService)
{
this.wellOperationRepository = wellOperationRepository;
this.wellOperationCategoryRepository = wellOperationCategoryRepository;
@ -55,6 +57,7 @@ public class WellOperationController : ControllerBase
this.userRepository = userRepository;
this.wellOperationParserFactory = wellOperationParserFactory;
this.wellOperationExportServiceFactory = wellOperationExportServiceFactory;
this.wellOperationService = wellOperationService;
}
/// <summary>
@ -159,7 +162,7 @@ public class WellOperationController : ControllerBase
var requestToservice = new WellOperationRequest(request, new[] { idWell });
var result = await wellOperationRepository.GetGroupOperationsStatAsync(requestToservice, token);
var result = await wellOperationService.GetGroupOperationsStatAsync(requestToservice, token);
return Ok(result);
}
@ -197,7 +200,7 @@ public class WellOperationController : ControllerBase
var requestToService = new WellOperationRequest(request, new[] { idWell });
var result = await wellOperationRepository.GetPageAsync(requestToService, token);
var result = await wellOperationService.GetPageAsync(requestToService, token);
return Ok(result);
}
@ -224,7 +227,7 @@ public class WellOperationController : ControllerBase
if (!await CanUserAccessToWellAsync(idWell, token))
return Forbid();
var paginationContainer = await wellOperationRepository.GetPageAsync(idWell, id, operationType, take, sortFields, token);
var paginationContainer = await wellOperationService.GetPageAsync(idWell, id, operationType, take, sortFields, token);
if (paginationContainer == null)
return NoContent();