forked from ddrilling/AsbCloudServer
Merge branch 'dev' into feature/integration_tests
# Conflicts: # AsbCloudWebApi.IntegrationTests/Controllers/ProcessMapPlan/ProcessMapPlanDrillingControllerTest.cs
This commit is contained in:
commit
91002da6ac
39
AsbCloudApp/Data/WellOperationDataDto.cs
Normal file
39
AsbCloudApp/Data/WellOperationDataDto.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
namespace AsbCloudApp.Data
|
||||||
|
{
|
||||||
|
/// Операция на скважине
|
||||||
|
public class WellOperationDataDto : IWellRelated
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public int IdWell { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// id секции скважины
|
||||||
|
/// </summary>
|
||||||
|
public int IdWellSectionType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// id категории операции
|
||||||
|
/// </summary>
|
||||||
|
public int IdCategory { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Глубина на начало операции, м
|
||||||
|
/// </summary>
|
||||||
|
public double DepthStart { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Продолжительность, часы
|
||||||
|
/// </summary>
|
||||||
|
public double DurationHours { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Наименование секции
|
||||||
|
/// </summary>
|
||||||
|
public string WellSectionTypeCaption { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Наименование категории
|
||||||
|
/// </summary>
|
||||||
|
public string OperationCategoryName { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
@ -42,6 +42,14 @@ namespace AsbCloudApp.Repositories
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<IEnumerable<WellOperationDto>> GetAsync(WellOperationRequest request, CancellationToken token);
|
Task<IEnumerable<WellOperationDto>> GetAsync(WellOperationRequest request, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить список операций по запросу
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<IEnumerable<WellOperationDataDto>> GetAsync(WellsOperationRequest request, CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получить страницу списка операций
|
/// Получить страницу списка операций
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
namespace AsbCloudApp.Requests.ParserOptions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Параметры парсинга
|
||||||
|
/// </summary>
|
||||||
|
public class WellRelatedParserRequest : IParserOptionsRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Конструктор
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idWell">Id скважины</param>
|
||||||
|
public WellRelatedParserRequest(int idWell)
|
||||||
|
{
|
||||||
|
IdWell = idWell;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id скважины
|
||||||
|
/// </summary>
|
||||||
|
public int IdWell { get; }
|
||||||
|
}
|
@ -6,7 +6,7 @@ namespace AsbCloudApp.Requests
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// параметры для запроса списка операций
|
/// параметры для запроса списка операций
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WellOperationRequestBase: RequestBase
|
public class WellOperationRequestBase : RequestBase
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// фильтр по дате начала операции
|
/// фильтр по дате начала операции
|
||||||
@ -42,12 +42,40 @@ namespace AsbCloudApp.Requests
|
|||||||
/// фильтр по списку id конструкций секции
|
/// фильтр по списку id конструкций секции
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<int>? SectionTypeIds { get; set; }
|
public IEnumerable<int>? SectionTypeIds { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Параметры для запроса списка операций.
|
||||||
|
/// Базовый конструктор
|
||||||
|
/// </summary>
|
||||||
|
public WellOperationRequestBase()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Параметры для запроса списка операций.
|
||||||
|
/// Копирующий конструктор
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
public WellOperationRequestBase(WellOperationRequestBase request)
|
||||||
|
{
|
||||||
|
GeDepth = request.GeDepth;
|
||||||
|
LeDepth = request.LeDepth;
|
||||||
|
GeDate = request.GeDate;
|
||||||
|
LtDate = request.LtDate;
|
||||||
|
|
||||||
|
OperationCategoryIds = request.OperationCategoryIds;
|
||||||
|
OperationType = request.OperationType;
|
||||||
|
SectionTypeIds = request.SectionTypeIds;
|
||||||
|
|
||||||
|
Skip = request.Skip;
|
||||||
|
Take = request.Take;
|
||||||
|
SortFields = request.SortFields;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Параметры для запроса списка операций (с id скважины)
|
/// Параметры для запроса списка операций (с id скважины)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WellOperationRequest: WellOperationRequestBase
|
public class WellOperationRequest : WellOperationRequestBase
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// id скважины
|
/// id скважины
|
||||||
@ -57,7 +85,7 @@ namespace AsbCloudApp.Requests
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public WellOperationRequest(){}
|
public WellOperationRequest() { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// копирующий конструктор
|
/// копирующий конструктор
|
||||||
@ -65,21 +93,20 @@ namespace AsbCloudApp.Requests
|
|||||||
/// <param name="request"></param>
|
/// <param name="request"></param>
|
||||||
/// <param name="idWell"></param>
|
/// <param name="idWell"></param>
|
||||||
public WellOperationRequest(WellOperationRequestBase request, int idWell)
|
public WellOperationRequest(WellOperationRequestBase request, int idWell)
|
||||||
|
:base(request)
|
||||||
{
|
{
|
||||||
this.IdWell = idWell;
|
IdWell = idWell;
|
||||||
|
|
||||||
this.GeDepth = request.GeDepth;
|
|
||||||
this.LeDepth = request.LeDepth;
|
|
||||||
this.GeDate = request.GeDate;
|
|
||||||
this.LtDate = request.LtDate;
|
|
||||||
|
|
||||||
this.OperationCategoryIds = request.OperationCategoryIds;
|
|
||||||
this.OperationType = request.OperationType;
|
|
||||||
this.SectionTypeIds = request.SectionTypeIds;
|
|
||||||
|
|
||||||
this.Skip= request.Skip;
|
|
||||||
this.Take= request.Take;
|
|
||||||
this.SortFields = request.SortFields;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Параметры для запроса списка операций (с массивом id скважин)
|
||||||
|
/// </summary>
|
||||||
|
public class WellsOperationRequest : WellOperationRequestBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ids скважин
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<int> IdsWell { get; set; } = null!;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,10 @@ namespace AsbCloudApp.Services;
|
|||||||
/// Сервис парсинга
|
/// Сервис парсинга
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TDto"></typeparam>
|
/// <typeparam name="TDto"></typeparam>
|
||||||
public interface IParserService<TDto> : IParserService
|
/// <typeparam name="TOptions"></typeparam>
|
||||||
|
public interface IParserService<TDto, in TOptions> : IParserService
|
||||||
where TDto : class, IId
|
where TDto : class, IId
|
||||||
|
where TOptions : IParserOptionsRequest
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Распарсить файл
|
/// Распарсить файл
|
||||||
@ -17,8 +19,7 @@ public interface IParserService<TDto> : IParserService
|
|||||||
/// <param name="file"></param>
|
/// <param name="file"></param>
|
||||||
/// <param name="options"></param>
|
/// <param name="options"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
ParserResultDto<TDto> Parse<TOptions>(Stream file, TOptions options)
|
ParserResultDto<TDto> Parse(Stream file, TOptions options);
|
||||||
where TOptions : IParserOptionsRequest;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получение шаблона для заполнения
|
/// Получение шаблона для заполнения
|
||||||
|
21
AsbCloudApp/Services/IWellCompositeOperationService.cs
Normal file
21
AsbCloudApp/Services/IWellCompositeOperationService.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using AsbCloudApp.Data;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.Services
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Интерфейс для вычисления композитной скважины
|
||||||
|
/// </summary>
|
||||||
|
public interface IWellCompositeOperationService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Получение данных для построения композитной скважины
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idsWells"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<List<Dictionary<int, WellOperationDataDto>>> GetAsync(IEnumerable<int> idsWells, CancellationToken token);
|
||||||
|
}
|
||||||
|
}
|
@ -198,6 +198,7 @@ namespace AsbCloudInfrastructure
|
|||||||
services.AddTransient<ICrudRepository<NotificationCategoryDto>, CrudCacheRepositoryBase<NotificationCategoryDto,
|
services.AddTransient<ICrudRepository<NotificationCategoryDto>, CrudCacheRepositoryBase<NotificationCategoryDto,
|
||||||
NotificationCategory>>();
|
NotificationCategory>>();
|
||||||
services.AddTransient<IDrillTestRepository, DrillTestRepository>();
|
services.AddTransient<IDrillTestRepository, DrillTestRepository>();
|
||||||
|
services.AddTransient<IWellCompositeOperationService, WellCompositeOperationService>();
|
||||||
|
|
||||||
// admin crud services:
|
// admin crud services:
|
||||||
services.AddTransient<ICrudRepository<TelemetryDto>, CrudCacheRepositoryBase<TelemetryDto, Telemetry>>(s =>
|
services.AddTransient<ICrudRepository<TelemetryDto>, CrudCacheRepositoryBase<TelemetryDto, Telemetry>>(s =>
|
||||||
|
@ -205,6 +205,17 @@ public class WellOperationRepository : IWellOperationRepository
|
|||||||
return dtos.Select(Convert);
|
return dtos.Select(Convert);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<WellOperationDataDto>> GetAsync(
|
||||||
|
WellsOperationRequest request,
|
||||||
|
CancellationToken token)
|
||||||
|
{
|
||||||
|
var query = BuildQuery(request)
|
||||||
|
.AsNoTracking();
|
||||||
|
|
||||||
|
var dtos = await query.ToArrayAsync(token);
|
||||||
|
return dtos;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<PaginationContainer<WellOperationDto>> GetPageAsync(
|
public async Task<PaginationContainer<WellOperationDto>> GetPageAsync(
|
||||||
WellOperationRequest request,
|
WellOperationRequest request,
|
||||||
@ -385,7 +396,6 @@ public class WellOperationRepository : IWellOperationRepository
|
|||||||
.Include(s => s.OperationCategory)
|
.Include(s => s.OperationCategory)
|
||||||
.Where(o => o.IdWell == request.IdWell);
|
.Where(o => o.IdWell == request.IdWell);
|
||||||
|
|
||||||
|
|
||||||
if (request.OperationType.HasValue)
|
if (request.OperationType.HasValue)
|
||||||
query = query.Where(e => e.IdType == request.OperationType.Value);
|
query = query.Where(e => e.IdType == request.OperationType.Value);
|
||||||
|
|
||||||
@ -420,6 +430,7 @@ public class WellOperationRepository : IWellOperationRepository
|
|||||||
.Where(subOp => subOp.IdType == 1)
|
.Where(subOp => subOp.IdType == 1)
|
||||||
.Where(subOp => WellOperationCategory.NonProductiveTimeSubIds.Contains(subOp.IdCategory));
|
.Where(subOp => WellOperationCategory.NonProductiveTimeSubIds.Contains(subOp.IdCategory));
|
||||||
|
|
||||||
|
// TODO: Вынести query.Select из метода BuildQuery
|
||||||
var dtos = query.Select(o => new WellOperationDto
|
var dtos = query.Select(o => new WellOperationDto
|
||||||
{
|
{
|
||||||
Id = o.Id,
|
Id = o.Id,
|
||||||
@ -472,6 +483,50 @@ public class WellOperationRepository : IWellOperationRepository
|
|||||||
return dtos.AsNoTracking();
|
return dtos.AsNoTracking();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение данных по запросу
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private IQueryable<WellOperationDataDto> BuildQuery(WellsOperationRequest request)
|
||||||
|
{
|
||||||
|
var query = db.WellOperations
|
||||||
|
.Where(o => request.IdsWell.Contains(o.IdWell))
|
||||||
|
.Where(o => request.OperationType == o.IdType);
|
||||||
|
|
||||||
|
if (request.SectionTypeIds?.Any() == true)
|
||||||
|
query = query.Where(o => request.SectionTypeIds.Contains(o.IdWellSectionType));
|
||||||
|
|
||||||
|
if (request.OperationCategoryIds?.Any() == true)
|
||||||
|
query = query.Where(o => request.OperationCategoryIds.Contains(o.IdCategory));
|
||||||
|
|
||||||
|
// TODO: Вынести query.Select из метода BuildQuery
|
||||||
|
var dtos = query.Select(o => new WellOperationDataDto
|
||||||
|
{
|
||||||
|
DepthStart = o.DepthStart,
|
||||||
|
DurationHours = o.DurationHours,
|
||||||
|
IdCategory = o.IdCategory,
|
||||||
|
IdWell = o.IdWell,
|
||||||
|
IdWellSectionType = o.IdWellSectionType,
|
||||||
|
OperationCategoryName = o.OperationCategory.Name,
|
||||||
|
WellSectionTypeCaption = o.WellSectionType.Caption,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (request.SortFields?.Any() == true)
|
||||||
|
{
|
||||||
|
dtos = dtos.SortBy(request.SortFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
private WellOperationDto Convert(WellOperationDto dto)
|
||||||
{
|
{
|
||||||
var timezone = wellService.GetTimezone(dto.IdWell);
|
var timezone = wellService.GetTimezone(dto.IdWell);
|
||||||
|
@ -12,8 +12,9 @@ using Mapster;
|
|||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.Parser;
|
namespace AsbCloudInfrastructure.Services.Parser;
|
||||||
|
|
||||||
public abstract class ParserExcelService<TDto> : IParserService<TDto>
|
public abstract class ParserExcelService<TDto, TOptions> : IParserService<TDto, TOptions>
|
||||||
where TDto : class, IValidatableObject, IId
|
where TDto : class, IValidatableObject, IId
|
||||||
|
where TOptions : IParserOptionsRequest
|
||||||
{
|
{
|
||||||
protected abstract string SheetName { get; }
|
protected abstract string SheetName { get; }
|
||||||
|
|
||||||
@ -22,9 +23,8 @@ public abstract class ParserExcelService<TDto> : IParserService<TDto>
|
|||||||
protected abstract string TemplateFileName { get; }
|
protected abstract string TemplateFileName { get; }
|
||||||
|
|
||||||
protected abstract IDictionary<string, Cell> Cells { get; }
|
protected abstract IDictionary<string, Cell> Cells { get; }
|
||||||
|
|
||||||
public virtual ParserResultDto<TDto> Parse<TOptions>(Stream file, TOptions options)
|
public virtual ParserResultDto<TDto> Parse(Stream file, TOptions options)
|
||||||
where TOptions : IParserOptionsRequest
|
|
||||||
{
|
{
|
||||||
using var workbook = new XLWorkbook(file);
|
using var workbook = new XLWorkbook(file);
|
||||||
var sheet = workbook.GetWorksheet(SheetName);
|
var sheet = workbook.GetWorksheet(SheetName);
|
||||||
|
@ -6,7 +6,6 @@ using AsbCloudApp.Data;
|
|||||||
using AsbCloudApp.Data.ProcessMaps;
|
using AsbCloudApp.Data.ProcessMaps;
|
||||||
using AsbCloudApp.Repositories;
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudInfrastructure.Services.Parser;
|
using AsbCloudInfrastructure.Services.Parser;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.ProcessMapPlan.Parser;
|
namespace AsbCloudInfrastructure.Services.ProcessMapPlan.Parser;
|
||||||
|
|
||||||
|
@ -1,14 +1,26 @@
|
|||||||
using System;
|
using System.IO;
|
||||||
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Data.ProcessMaps;
|
using AsbCloudApp.Data.ProcessMaps;
|
||||||
|
using AsbCloudApp.Requests.ParserOptions;
|
||||||
using AsbCloudInfrastructure.Services.Parser;
|
using AsbCloudInfrastructure.Services.Parser;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.ProcessMapPlan.Parser;
|
namespace AsbCloudInfrastructure.Services.ProcessMapPlan.Parser;
|
||||||
|
|
||||||
public abstract class ProcessMapPlanParser<TDto> : ParserExcelService<TDto>
|
public abstract class ProcessMapPlanParser<TDto> : ParserExcelService<TDto, WellRelatedParserRequest>
|
||||||
where TDto : ProcessMapPlanBaseDto
|
where TDto : ProcessMapPlanBaseDto
|
||||||
{
|
{
|
||||||
protected override int HeaderRowsCount => 2;
|
protected override int HeaderRowsCount => 2;
|
||||||
|
|
||||||
|
public override ParserResultDto<TDto> Parse(Stream file, WellRelatedParserRequest options)
|
||||||
|
{
|
||||||
|
var result = base.Parse(file, options);
|
||||||
|
|
||||||
|
foreach (var item in result.Item)
|
||||||
|
item.Item.IdWell = options.IdWell;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
protected static int? GetIdMode(string? modeName) =>
|
protected static int? GetIdMode(string? modeName) =>
|
||||||
modeName?.Trim().ToLower() switch
|
modeName?.Trim().ToLower() switch
|
||||||
{
|
{
|
||||||
|
@ -22,14 +22,12 @@ public class ProcessMapPlanReamParser : ProcessMapPlanParser<ProcessMapPlanReamD
|
|||||||
protected override string TemplateFileName => "ProcessMapPlanReamTemplate.xlsx";
|
protected override string TemplateFileName => "ProcessMapPlanReamTemplate.xlsx";
|
||||||
|
|
||||||
private const int ColumnSection = 1;
|
private const int ColumnSection = 1;
|
||||||
private const int ColumnMode = 2;
|
|
||||||
|
|
||||||
protected override IDictionary<string, Cell> Cells => new Dictionary<string, Cell>
|
protected override IDictionary<string, Cell> Cells => new Dictionary<string, Cell>
|
||||||
{
|
{
|
||||||
{ nameof(ProcessMapPlanReamDto.Section), new Cell(ColumnSection, typeof(string)) },
|
{ nameof(ProcessMapPlanReamDto.Section), new Cell(ColumnSection, typeof(string)) },
|
||||||
{ nameof(ProcessMapPlanReamDto.DepthStart), new Cell(2, typeof(double)) },
|
{ nameof(ProcessMapPlanReamDto.DepthStart), new Cell(2, typeof(double)) },
|
||||||
{ nameof(ProcessMapPlanReamDto.DepthEnd), new Cell(3, typeof(double)) },
|
{ nameof(ProcessMapPlanReamDto.DepthEnd), new Cell(3, typeof(double)) },
|
||||||
|
|
||||||
{ nameof(ProcessMapPlanReamDto.Repeats), new Cell(4, typeof(double)) },
|
{ nameof(ProcessMapPlanReamDto.Repeats), new Cell(4, typeof(double)) },
|
||||||
{ nameof(ProcessMapPlanReamDto.SpinUpward), new Cell(5, typeof(double)) },
|
{ nameof(ProcessMapPlanReamDto.SpinUpward), new Cell(5, typeof(double)) },
|
||||||
{ nameof(ProcessMapPlanReamDto.SpinUpward), new Cell(6, typeof(double)) },
|
{ nameof(ProcessMapPlanReamDto.SpinUpward), new Cell(6, typeof(double)) },
|
||||||
|
@ -4,12 +4,10 @@ using AsbCloudInfrastructure.Services.Parser;
|
|||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
|
namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
|
||||||
|
|
||||||
public class TrajectoryFactManualParser : ParserExcelService<TrajectoryGeoFactDto>
|
public class TrajectoryFactManualParser : TrajectoryParser<TrajectoryGeoFactDto>
|
||||||
{
|
{
|
||||||
protected override string SheetName => "Фактическая траектория";
|
protected override string SheetName => "Фактическая траектория";
|
||||||
|
|
||||||
protected override int HeaderRowsCount => 2;
|
|
||||||
|
|
||||||
protected override string TemplateFileName => "TrajectoryFactManualTemplate.xlsx";
|
protected override string TemplateFileName => "TrajectoryFactManualTemplate.xlsx";
|
||||||
|
|
||||||
protected override IDictionary<string, Cell> Cells => new Dictionary<string, Cell>
|
protected override IDictionary<string, Cell> Cells => new Dictionary<string, Cell>
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
using System.IO;
|
||||||
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Data.Trajectory;
|
||||||
|
using AsbCloudApp.Requests.ParserOptions;
|
||||||
|
using AsbCloudInfrastructure.Services.Parser;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
|
||||||
|
|
||||||
|
public abstract class TrajectoryParser<TDto> : ParserExcelService<TDto, WellRelatedParserRequest>
|
||||||
|
where TDto : TrajectoryGeoDto
|
||||||
|
{
|
||||||
|
protected override int HeaderRowsCount => 2;
|
||||||
|
|
||||||
|
public override ParserResultDto<TDto> Parse(Stream file, WellRelatedParserRequest options)
|
||||||
|
{
|
||||||
|
var result = base.Parse(file, options);
|
||||||
|
|
||||||
|
foreach (var item in result.Item)
|
||||||
|
item.Item.IdWell = options.IdWell;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -4,12 +4,10 @@ using AsbCloudInfrastructure.Services.Parser;
|
|||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
|
namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
|
||||||
|
|
||||||
public class TrajectoryPlanParser : ParserExcelService<TrajectoryGeoPlanDto>
|
public class TrajectoryPlanParser : TrajectoryParser<TrajectoryGeoPlanDto>
|
||||||
{
|
{
|
||||||
protected override string SheetName => "Плановая траектория";
|
protected override string SheetName => "Плановая траектория";
|
||||||
|
|
||||||
protected override int HeaderRowsCount => 2;
|
|
||||||
|
|
||||||
protected override string TemplateFileName => "TrajectoryPlanTemplate.xlsx";
|
protected override string TemplateFileName => "TrajectoryPlanTemplate.xlsx";
|
||||||
|
|
||||||
protected override IDictionary<string, Cell> Cells => new Dictionary<string, Cell>
|
protected override IDictionary<string, Cell> Cells => new Dictionary<string, Cell>
|
||||||
|
220
AsbCloudInfrastructure/Services/WellCompositeOperationService.cs
Normal file
220
AsbCloudInfrastructure/Services/WellCompositeOperationService.cs
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
|
using AsbCloudApp.Requests;
|
||||||
|
using AsbCloudApp.Services;
|
||||||
|
using AsbCloudDb.Model;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Services
|
||||||
|
{
|
||||||
|
public class WellCompositeOperationService : IWellCompositeOperationService
|
||||||
|
{
|
||||||
|
private ICrudRepository<WellSectionTypeDto> wellSectionTypeRepository;
|
||||||
|
private IWellOperationCategoryRepository wellOperationCategoryRepository;
|
||||||
|
private IWellOperationRepository wellOperationRepository;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Тип секции "Транспортный стол"
|
||||||
|
/// </summary>
|
||||||
|
private const int wellSectionTransportTable = 5;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Тип секции "Эксплуатационная колонна"
|
||||||
|
/// </summary>
|
||||||
|
private const int wellSectionProductionString = 4;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// набор настроек для замены одной категории секции на другую
|
||||||
|
/// </summary>
|
||||||
|
private static Dictionary<(int, int), int> SettingsForSectionCategoryChange = new Dictionary<(int, int), int>() {
|
||||||
|
{ (2, 5096), 5013 },
|
||||||
|
{ (2, 5008), 5013 },
|
||||||
|
{ (3, 5096), 5084 },
|
||||||
|
{ (3, 5008), 5084 },
|
||||||
|
{ (3, 5085), 5015 },
|
||||||
|
{ (3, 5014), 5015 },
|
||||||
|
{ (31, 5014), 5015 },
|
||||||
|
{ (31, 5012), 5013 },
|
||||||
|
{ (31, 5083), 5013 },
|
||||||
|
{ (4, 5085), 5015 },
|
||||||
|
{ (4, 5087), 5015 },
|
||||||
|
{ (4, 5014), 5015 },
|
||||||
|
{ (4, 5053), 5037 },
|
||||||
|
{ (4, 5084), 5096 },
|
||||||
|
{ (4, 5086), 5013 },
|
||||||
|
{ (6, 5085), 5015 },
|
||||||
|
{ (6, 5036), 5034 },
|
||||||
|
{ (6, 5035), 5097 }
|
||||||
|
};
|
||||||
|
|
||||||
|
private HashSet<(int IdSectionType, int IdCategory)> WellSectionTypesWithCategories = new HashSet<(int IdSectionType, int IdCategory)>()
|
||||||
|
{
|
||||||
|
{ (2, 5001) },
|
||||||
|
{ (2, 5003) },
|
||||||
|
{ (2, 5013) },
|
||||||
|
{ (2, 5000) },
|
||||||
|
{ (2, 5022) },
|
||||||
|
{ (2, 5017) },
|
||||||
|
{ (2, 5023) },
|
||||||
|
{ (2, 4007) },
|
||||||
|
{ (2, 5090) },
|
||||||
|
{ (3, 5001) },
|
||||||
|
{ (3, 5015) },
|
||||||
|
{ (3, 5037) },
|
||||||
|
{ (3, 5057) },
|
||||||
|
{ (3, 5003) },
|
||||||
|
{ (3, 5036) },
|
||||||
|
{ (3, 5084) },
|
||||||
|
{ (3, 5013) },
|
||||||
|
{ (3, 5000) },
|
||||||
|
{ (3, 5022) },
|
||||||
|
{ (3, 5017) },
|
||||||
|
{ (3, 4007) },
|
||||||
|
{ (3, 5090) },
|
||||||
|
{ (3, 5045) },
|
||||||
|
{ (3, 5042) },
|
||||||
|
{ (3, 5046) },
|
||||||
|
{ (31, 5001) },
|
||||||
|
{ (31, 5015) },
|
||||||
|
{ (31, 5037) },
|
||||||
|
{ (31, 5057) },
|
||||||
|
{ (31, 5003) },
|
||||||
|
{ (31, 5036) },
|
||||||
|
{ (31, 5013) },
|
||||||
|
{ (31, 5022) },
|
||||||
|
{ (31, 5017) },
|
||||||
|
{ (31, 5023) },
|
||||||
|
{ (31, 4007) },
|
||||||
|
{ (31, 5045) },
|
||||||
|
{ (31, 5042) },
|
||||||
|
{ (31, 5046) },
|
||||||
|
{ (4, 5001) },
|
||||||
|
{ (4, 5015) },
|
||||||
|
{ (4, 5046) },
|
||||||
|
{ (4, 5037) },
|
||||||
|
{ (4, 5097) },
|
||||||
|
{ (4, 5057) },
|
||||||
|
{ (4, 5003) },
|
||||||
|
{ (4, 5036) },
|
||||||
|
{ (4, 5008) },
|
||||||
|
{ (4, 5003) },
|
||||||
|
{ (4, 5036) },
|
||||||
|
{ (4, 5013) },
|
||||||
|
{ (4, 5000) },
|
||||||
|
{ (4, 5029) },
|
||||||
|
{ (4, 5022) },
|
||||||
|
{ (4, 5017) },
|
||||||
|
{ (4, 5019) },
|
||||||
|
{ (4, 5042) },
|
||||||
|
{ (4, 5046) },
|
||||||
|
{ (6, 5001) },
|
||||||
|
{ (6, 5015) },
|
||||||
|
{ (6, 5034) },
|
||||||
|
{ (6, 5037) },
|
||||||
|
{ (6, 5097) },
|
||||||
|
{ (6, 5057) },
|
||||||
|
{ (6, 5003) }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public WellCompositeOperationService(
|
||||||
|
ICrudRepository<WellSectionTypeDto> wellSectionTypeRepository,
|
||||||
|
IWellOperationCategoryRepository wellOperationCategoryRepository,
|
||||||
|
IWellOperationRepository wellOperationRepository)
|
||||||
|
{
|
||||||
|
this.wellSectionTypeRepository = wellSectionTypeRepository;
|
||||||
|
this.wellOperationCategoryRepository = wellOperationCategoryRepository;
|
||||||
|
this.wellOperationRepository = wellOperationRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<Dictionary<int, WellOperationDataDto>>> GetAsync(IEnumerable<int> idsWells, CancellationToken token)
|
||||||
|
{
|
||||||
|
var sections = await wellSectionTypeRepository.GetAllAsync(token);
|
||||||
|
var sectionsDict = sections.ToDictionary(s => s.Id, s => s.Caption);
|
||||||
|
|
||||||
|
var categories = wellOperationCategoryRepository.Get(true);
|
||||||
|
var categoriesDict = categories.ToDictionary(s => s.Id, s => s.Name);
|
||||||
|
|
||||||
|
var idsWellSectionTypes = WellSectionTypesWithCategories.Select(t => t.IdSectionType).Distinct();
|
||||||
|
var usedCategories = WellSectionTypesWithCategories.Select(c => c.IdCategory).Distinct();
|
||||||
|
|
||||||
|
var wellOperationRequest = new WellsOperationRequest()
|
||||||
|
{
|
||||||
|
IdsWell = idsWells,
|
||||||
|
OperationCategoryIds = usedCategories,
|
||||||
|
SectionTypeIds = idsWellSectionTypes,
|
||||||
|
OperationType = WellOperation.IdOperationTypeFact
|
||||||
|
};
|
||||||
|
var operations = await wellOperationRepository.GetAsync(wellOperationRequest, token);
|
||||||
|
|
||||||
|
var renamedOperations = operations.Select(o => UpdateIdWellSectionAndIdCategory(o, sectionsDict, categoriesDict));
|
||||||
|
|
||||||
|
var wellOperationsWithComposite = new List<Dictionary<int, WellOperationDataDto>>();
|
||||||
|
var compositeDepth = 0d;
|
||||||
|
foreach ((int IdSection, int IdCategory) in WellSectionTypesWithCategories)
|
||||||
|
{
|
||||||
|
var filteredByTemplate = renamedOperations
|
||||||
|
.Where(o => o.IdWellSectionType == IdSection)
|
||||||
|
.Where(o => o.IdCategory == IdCategory);
|
||||||
|
|
||||||
|
if (!filteredByTemplate.Any())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var groupedByWell = filteredByTemplate.GroupBy(o => o.IdWell);
|
||||||
|
|
||||||
|
var aggreagtedByWell = groupedByWell.Select(g => new WellOperationDataDto
|
||||||
|
{
|
||||||
|
IdCategory = IdCategory,
|
||||||
|
IdWell = g.Key,
|
||||||
|
IdWellSectionType = IdSection,
|
||||||
|
DepthStart = g.Min(o => o.DepthStart),
|
||||||
|
DurationHours = g.Sum(o => o.DurationHours),
|
||||||
|
OperationCategoryName = g.First().OperationCategoryName,
|
||||||
|
WellSectionTypeCaption = g.First().WellSectionTypeCaption,
|
||||||
|
});
|
||||||
|
|
||||||
|
var composite = aggreagtedByWell.OrderBy(o => o.DurationHours).
|
||||||
|
ThenByDescending(o => o.DepthStart)
|
||||||
|
.First();
|
||||||
|
|
||||||
|
composite.IdWell = 0;
|
||||||
|
if (compositeDepth > composite.DepthStart)
|
||||||
|
composite.DepthStart = compositeDepth;
|
||||||
|
|
||||||
|
compositeDepth = composite.DepthStart;
|
||||||
|
|
||||||
|
var resultItem = aggreagtedByWell.ToDictionary(o => o.IdWell);
|
||||||
|
resultItem.Add(0, composite);
|
||||||
|
|
||||||
|
wellOperationsWithComposite.Add(resultItem);
|
||||||
|
}
|
||||||
|
return wellOperationsWithComposite;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static WellOperationDataDto UpdateIdWellSectionAndIdCategory(
|
||||||
|
WellOperationDataDto dto,
|
||||||
|
Dictionary<int, string> sectionTypes,
|
||||||
|
Dictionary<int, string> operationCategories)
|
||||||
|
{
|
||||||
|
if (dto.IdWellSectionType == wellSectionTransportTable)
|
||||||
|
{
|
||||||
|
dto.IdWellSectionType = wellSectionProductionString;
|
||||||
|
dto.WellSectionTypeCaption = sectionTypes[dto.IdWellSectionType] ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((SettingsForSectionCategoryChange.TryGetValue((dto.IdWellSectionType, dto.IdCategory), out int newIdCategory)))
|
||||||
|
{
|
||||||
|
dto.IdCategory = newIdCategory;
|
||||||
|
dto.OperationCategoryName = operationCategories[dto.IdCategory] ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -35,5 +35,5 @@ public interface IProcessMapPlanDrillingClient
|
|||||||
|
|
||||||
[Multipart]
|
[Multipart]
|
||||||
[Post(BaseRoute + "/parse")]
|
[Post(BaseRoute + "/parse")]
|
||||||
Task<IApiResponse<ParserResultDto<ProcessMapPlanDrillingDto>>> Parse(int idWell, [AliasAs("files")] IEnumerable<StreamPart> streams);
|
Task<IApiResponse<ParserResultDto<ProcessMapPlanDrillingDto>>> Parse(int idWell, [AliasAs("file")] StreamPart stream);
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,11 @@ public class TrajectoryParserTest
|
|||||||
{
|
{
|
||||||
private const string UsingTemplateFile = "AsbCloudWebApi.Tests.Services.Trajectory.Templates";
|
private const string UsingTemplateFile = "AsbCloudWebApi.Tests.Services.Trajectory.Templates";
|
||||||
|
|
||||||
|
private readonly WellRelatedParserRequest options = new(1);
|
||||||
|
|
||||||
private readonly TrajectoryPlanParser trajectoryPlanParser = new();
|
private readonly TrajectoryPlanParser trajectoryPlanParser = new();
|
||||||
private readonly TrajectoryFactManualParser trajectoryFactManualParser = new();
|
private readonly TrajectoryFactManualParser trajectoryFactManualParser = new();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Parse_trajectory_plan()
|
public void Parse_trajectory_plan()
|
||||||
{
|
{
|
||||||
@ -22,8 +24,8 @@ public class TrajectoryParserTest
|
|||||||
|
|
||||||
if (stream is null)
|
if (stream is null)
|
||||||
Assert.Fail("Файла для импорта не существует");
|
Assert.Fail("Файла для импорта не существует");
|
||||||
|
|
||||||
var trajectoryRows = trajectoryPlanParser.Parse(stream, IParserOptionsRequest.Empty());
|
var trajectoryRows = trajectoryPlanParser.Parse(stream, options);
|
||||||
|
|
||||||
Assert.Equal(3, trajectoryRows.Item.Count());
|
Assert.Equal(3, trajectoryRows.Item.Count());
|
||||||
}
|
}
|
||||||
@ -37,7 +39,7 @@ public class TrajectoryParserTest
|
|||||||
if (stream is null)
|
if (stream is null)
|
||||||
Assert.Fail("Файла для импорта не существует");
|
Assert.Fail("Файла для импорта не существует");
|
||||||
|
|
||||||
var trajectoryRows = trajectoryFactManualParser.Parse(stream, IParserOptionsRequest.Empty());
|
var trajectoryRows = trajectoryFactManualParser.Parse(stream, options);
|
||||||
|
|
||||||
Assert.Equal(4, trajectoryRows.Item.Count());
|
Assert.Equal(4, trajectoryRows.Item.Count());
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,337 @@
|
|||||||
|
using AsbCloudApp.Requests;
|
||||||
|
using AsbCloudDb.Model;
|
||||||
|
using AsbCloudInfrastructure.Repository;
|
||||||
|
using AsbCloudInfrastructure.Services.ProcessMaps.Report;
|
||||||
|
using AsbCloudInfrastructure.Services;
|
||||||
|
using NSubstitute;
|
||||||
|
using ProtoBuf.Meta;
|
||||||
|
using SignalRSwaggerGen.Enums;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Services;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation
|
||||||
|
{
|
||||||
|
public class WellCompositeOperationServiceTest
|
||||||
|
{
|
||||||
|
private WellCompositeOperationService service;
|
||||||
|
|
||||||
|
private ICrudRepository<WellSectionTypeDto> wellSectionTypeRepository
|
||||||
|
= Substitute.For<ICrudRepository<WellSectionTypeDto>>();
|
||||||
|
private IWellOperationCategoryRepository wellOperationCategoryRepository
|
||||||
|
= Substitute.For<IWellOperationCategoryRepository>();
|
||||||
|
private IWellOperationRepository wellOperationRepository
|
||||||
|
= Substitute.For<IWellOperationRepository>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private readonly static IEnumerable<WellOperationCategoryDto> operationCategories = new List<WellOperationCategoryDto>()
|
||||||
|
{
|
||||||
|
new(){Id = 5096, Name = "Шаблонирование перед спуском"},
|
||||||
|
new(){Id = 5008, Name = "Шаблонировка во время бурения"},
|
||||||
|
new(){Id = 5013, Name = "Подъем КНБК"},
|
||||||
|
new(){Id = 5003, Name = "Бурение ротором"},
|
||||||
|
new(){Id = 5036, Name = "Промывка"},
|
||||||
|
new(){Id = 5012, Name = "Подъем инструмента"},
|
||||||
|
new(){Id = 5083, Name = "Проработка принудительная"},
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly static IEnumerable<WellSectionTypeDto> sectionTypes = new List<WellSectionTypeDto>()
|
||||||
|
{
|
||||||
|
new() {Id = 2, Caption = "Направление", Order = 0},
|
||||||
|
new() {Id = 3, Caption = "Кондуктор", Order = 1},
|
||||||
|
new() {Id = 31, Caption = "Техническая колонна", Order = 2}
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly static IEnumerable<WellOperationDataDto> wellOperations1 = new List<WellOperationDataDto>()
|
||||||
|
{
|
||||||
|
new WellOperationDataDto()
|
||||||
|
{
|
||||||
|
DepthStart = 50,
|
||||||
|
DurationHours = 1,
|
||||||
|
IdCategory = 5096,
|
||||||
|
IdWell = 55,
|
||||||
|
IdWellSectionType = 2,
|
||||||
|
OperationCategoryName = "Шаблонирование перед спуском",
|
||||||
|
WellSectionTypeCaption = "Направление"
|
||||||
|
},
|
||||||
|
new WellOperationDataDto()
|
||||||
|
{
|
||||||
|
DepthStart = 84,
|
||||||
|
DurationHours = 1,
|
||||||
|
IdCategory = 5008,
|
||||||
|
IdWell = 64,
|
||||||
|
IdWellSectionType = 2,
|
||||||
|
OperationCategoryName = "Шаблонировка во время бурения",
|
||||||
|
WellSectionTypeCaption = "Направление"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly static IEnumerable<WellOperationDataDto> wellOperations2 = new List<WellOperationDataDto>()
|
||||||
|
{
|
||||||
|
new WellOperationDataDto()
|
||||||
|
{
|
||||||
|
DepthStart = 10,
|
||||||
|
DurationHours = 1.5,
|
||||||
|
IdCategory = 5003,
|
||||||
|
IdWell = 55,
|
||||||
|
IdWellSectionType = 2,
|
||||||
|
OperationCategoryName = "Бурение ротором",
|
||||||
|
WellSectionTypeCaption = "Направление"
|
||||||
|
},
|
||||||
|
new WellOperationDataDto()
|
||||||
|
{
|
||||||
|
DepthStart = 20,
|
||||||
|
DurationHours = 3.5,
|
||||||
|
IdCategory = 5003,
|
||||||
|
IdWell = 64,
|
||||||
|
IdWellSectionType = 2,
|
||||||
|
OperationCategoryName = "Бурение ротором",
|
||||||
|
WellSectionTypeCaption = "Направление"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly static IEnumerable<WellOperationDataDto> wellOperations3 = new List<WellOperationDataDto>()
|
||||||
|
{
|
||||||
|
new WellOperationDataDto()
|
||||||
|
{
|
||||||
|
DepthStart = 1372,
|
||||||
|
DurationHours = 3,
|
||||||
|
IdCategory = 5036,
|
||||||
|
IdWell = 55,
|
||||||
|
IdWellSectionType = 3,
|
||||||
|
OperationCategoryName = "Промывка",
|
||||||
|
WellSectionTypeCaption = "Кондуктор"
|
||||||
|
},
|
||||||
|
new WellOperationDataDto()
|
||||||
|
{
|
||||||
|
DepthStart = 1435,
|
||||||
|
DurationHours = 4,
|
||||||
|
IdCategory = 5036,
|
||||||
|
IdWell = 64,
|
||||||
|
IdWellSectionType = 3,
|
||||||
|
OperationCategoryName = "Промывка",
|
||||||
|
WellSectionTypeCaption = "Кондуктор"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly static IEnumerable<WellOperationDataDto> wellOperations4 = new List<WellOperationDataDto>()
|
||||||
|
{
|
||||||
|
new WellOperationDataDto()
|
||||||
|
{
|
||||||
|
DepthStart = 1000,
|
||||||
|
DurationHours = 10,
|
||||||
|
IdCategory = 5012,
|
||||||
|
IdWell = 55,
|
||||||
|
IdWellSectionType = 31,
|
||||||
|
OperationCategoryName = "Подъем инструмента",
|
||||||
|
WellSectionTypeCaption = "Техническая колонна"
|
||||||
|
},
|
||||||
|
new WellOperationDataDto()
|
||||||
|
{
|
||||||
|
DepthStart = 500,
|
||||||
|
DurationHours = 5,
|
||||||
|
IdCategory = 5083,
|
||||||
|
IdWell = 55,
|
||||||
|
IdWellSectionType = 31,
|
||||||
|
OperationCategoryName = "Проработка принудительная",
|
||||||
|
WellSectionTypeCaption = "Техническая колонна"
|
||||||
|
},
|
||||||
|
new WellOperationDataDto()
|
||||||
|
{
|
||||||
|
DepthStart = 600,
|
||||||
|
DurationHours = 5,
|
||||||
|
IdCategory = 5083,
|
||||||
|
IdWell = 64,
|
||||||
|
IdWellSectionType = 31,
|
||||||
|
OperationCategoryName = "Проработка принудительная",
|
||||||
|
WellSectionTypeCaption = "Техническая колонна"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public WellCompositeOperationServiceTest()
|
||||||
|
{
|
||||||
|
|
||||||
|
wellSectionTypeRepository.GetAllAsync(Arg.Any<CancellationToken>())
|
||||||
|
.Returns(sectionTypes);
|
||||||
|
|
||||||
|
wellOperationCategoryRepository.Get(Arg.Any<bool>())
|
||||||
|
.Returns(operationCategories);
|
||||||
|
|
||||||
|
service = new WellCompositeOperationService(
|
||||||
|
wellSectionTypeRepository,
|
||||||
|
wellOperationCategoryRepository,
|
||||||
|
wellOperationRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// На вход подаются 2 операции с одинаковыми секциями (id = 2), но разными категориями (ids = 5096, 5008) и ключами скважин (ids = 55, 64)
|
||||||
|
/// Метод возвращает список из одной операции в разрезе 3-х скважин: 2 текущие скважины и одна композитная
|
||||||
|
/// Операция должна иметь категорию 5013 для всех трех скважин
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[Fact]
|
||||||
|
public async Task GetAsync_return_composite_and_others_with_category_5013()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
wellOperationRepository.GetAsync(Arg.Any<WellsOperationRequest>(), Arg.Any<CancellationToken>())
|
||||||
|
.Returns(wellOperations1);
|
||||||
|
|
||||||
|
var idsWell = new List<int>() { 55, 64 };
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = await service.GetAsync(idsWell, CancellationToken.None);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
var compositeWellOperation = result.SelectMany(o => o.Values.Where(o => o.IdWell == 0)).FirstOrDefault();
|
||||||
|
Assert.NotNull(compositeWellOperation);
|
||||||
|
Assert.Equal(5013, compositeWellOperation.IdCategory);
|
||||||
|
Assert.Equal(1, compositeWellOperation.DurationHours);
|
||||||
|
Assert.Equal(84, compositeWellOperation.DepthStart);
|
||||||
|
|
||||||
|
var currentWellOperations = result.SelectMany(o => o.Values.Where(o => o.IdWell != 0));
|
||||||
|
var categories = currentWellOperations.Select(o => o.IdCategory).Distinct();
|
||||||
|
Assert.NotNull(categories);
|
||||||
|
Assert.Single(categories);
|
||||||
|
Assert.Equal(5013, categories.First());
|
||||||
|
|
||||||
|
var categoryName = currentWellOperations.Select(o => o.OperationCategoryName).First();
|
||||||
|
Assert.Equal("Подъем КНБК", categoryName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// На вход подаются 2 операции с одинаковыми секциями (id = 2) и категориями (id = 5003), но разными ключами скважин (ids = 55, 64)
|
||||||
|
/// Метод возвращает список из одной операции в разрезе 3-х скважин: 2 текущие скважины и одна композитная
|
||||||
|
/// Операция композитной скважины должна содержать данные той операции, которая содержит минимальный duration_hours
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[Fact]
|
||||||
|
public async Task GetAsync_return_composite_with_minimum_depth_start()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
wellOperationRepository.GetAsync(Arg.Any<WellsOperationRequest>(), Arg.Any<CancellationToken>())
|
||||||
|
.Returns(wellOperations2);
|
||||||
|
|
||||||
|
var idsWell = new List<int>() { 55, 64 };
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = await service.GetAsync(idsWell, CancellationToken.None);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
var compositeWellOperation = result.SelectMany(o => o.Values.Where(o => o.IdWell == 0)).FirstOrDefault();
|
||||||
|
Assert.NotNull(compositeWellOperation);
|
||||||
|
Assert.Equal(5003, compositeWellOperation.IdCategory);
|
||||||
|
Assert.Equal(1.5, compositeWellOperation.DurationHours);
|
||||||
|
Assert.Equal(10, compositeWellOperation.DepthStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// На вход подаются 2 операции с одинаковыми секциями (id = 3) и категориями (id = 5036), но разными ключами скважин (ids = 55, 64)
|
||||||
|
/// Метод возвращает список из одной операции в разрезе 3-х скважин: 2 текущие скважины и одна композитная
|
||||||
|
/// Операция композитной скважины должна содержать данные той операции, которая содержит минимальный duration_hours
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[Fact]
|
||||||
|
public async Task GetAsync_return_data3()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
wellOperationRepository.GetAsync(Arg.Any<WellsOperationRequest>(), Arg.Any<CancellationToken>())
|
||||||
|
.Returns(wellOperations3);
|
||||||
|
|
||||||
|
var idsWell = new List<int>() { 55, 64 };
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = await service.GetAsync(idsWell, CancellationToken.None);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
var compositeWellOperation = result.SelectMany(o => o.Values.Where(o => o.IdWell == 0)).FirstOrDefault();
|
||||||
|
Assert.NotNull(compositeWellOperation);
|
||||||
|
Assert.Equal(5036, compositeWellOperation.IdCategory);
|
||||||
|
Assert.Equal(3, compositeWellOperation.DurationHours);
|
||||||
|
Assert.Equal(1372, compositeWellOperation.DepthStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// На вход подаются 3 операции с одинаковыми секциями (id = 31), но разными категориями (ids = 5012, 5083) и ключами скважин (ids = 55, 64)
|
||||||
|
/// Метод возвращает список из одной операции в разрезе 3-х скважин: 2 текущие скважины и одна композитная
|
||||||
|
/// Операция композитной скважины должна содержать:
|
||||||
|
/// данные той операции, которая содержит минимальный duration_hours
|
||||||
|
/// категорию с ключом 5013
|
||||||
|
/// Операции по скважине с ключом 55 должны объединиться в одну,
|
||||||
|
/// при этом их длительность складывается, а depth_start берется минимальный из двух
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[Fact]
|
||||||
|
public async Task GetAsync_return_data4()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
wellOperationRepository.GetAsync(Arg.Any<WellsOperationRequest>(), Arg.Any<CancellationToken>())
|
||||||
|
.Returns(wellOperations4);
|
||||||
|
|
||||||
|
var idsWell = new List<int>() { 55, 64 };
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = await service.GetAsync(idsWell, CancellationToken.None);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
var currentWellOperations = result.SelectMany(o => o.Values.Where(o => o.IdWell != 0));
|
||||||
|
var categories = currentWellOperations.Select(o => o.IdCategory).Distinct();
|
||||||
|
Assert.NotNull(categories);
|
||||||
|
Assert.Single(categories);
|
||||||
|
Assert.Equal(5013, categories.First());
|
||||||
|
|
||||||
|
var currentOperationByWell55 = currentWellOperations.Where(o => o.IdWell == 55).FirstOrDefault();
|
||||||
|
Assert.NotNull(currentOperationByWell55);
|
||||||
|
Assert.Equal(15, currentOperationByWell55.DurationHours);
|
||||||
|
Assert.Equal(500, currentOperationByWell55.DepthStart);
|
||||||
|
|
||||||
|
var categoryName = currentWellOperations.Select(o => o.OperationCategoryName).First();
|
||||||
|
Assert.Equal("Подъем КНБК", categoryName);
|
||||||
|
|
||||||
|
var compositeWellOperation = result.SelectMany(o => o.Values.Where(o => o.IdWell == 0)).FirstOrDefault();
|
||||||
|
Assert.NotNull(compositeWellOperation);
|
||||||
|
Assert.Equal(5013, compositeWellOperation.IdCategory);
|
||||||
|
Assert.Equal(5, compositeWellOperation.DurationHours);
|
||||||
|
Assert.Equal(600, compositeWellOperation.DepthStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// На вход подаются список разных операций с разными ключами скважин (ids = 55, 64)
|
||||||
|
/// Метод возвращает список из 4-х операций в разрезе 3-х скважин: 2 текущие скважины и одна композитная
|
||||||
|
/// Операция композитной скважины должна содержать глубину забоя = 1372
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[Fact]
|
||||||
|
public async Task GetAsync_return_data5()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var wellOperations = new List<WellOperationDataDto>();
|
||||||
|
wellOperations.AddRange(wellOperations1);
|
||||||
|
wellOperations.AddRange(wellOperations2);
|
||||||
|
wellOperations.AddRange(wellOperations3);
|
||||||
|
wellOperations.AddRange(wellOperations4);
|
||||||
|
|
||||||
|
wellOperationRepository.GetAsync(Arg.Any<WellsOperationRequest>(), Arg.Any<CancellationToken>())
|
||||||
|
.Returns(wellOperations);
|
||||||
|
|
||||||
|
var idsWell = new List<int>() { 55, 64 };
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = await service.GetAsync(idsWell, CancellationToken.None);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.Equal(4, result.Count());
|
||||||
|
|
||||||
|
var lastOperation = result.Last();
|
||||||
|
var lastOperationComposite = lastOperation[0];
|
||||||
|
Assert.Equal(1372, lastOperationComposite.DepthStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -30,11 +30,11 @@ public abstract class ProcessMapPlanBaseController<TDto> : ControllerBase
|
|||||||
{
|
{
|
||||||
private readonly IChangeLogRepository<TDto, ProcessMapPlanBaseRequestWithWell> repository;
|
private readonly IChangeLogRepository<TDto, ProcessMapPlanBaseRequestWithWell> repository;
|
||||||
private readonly IWellService wellService;
|
private readonly IWellService wellService;
|
||||||
private readonly ParserExcelService<TDto> parserService;
|
private readonly ParserExcelService<TDto, WellRelatedParserRequest> parserService;
|
||||||
|
|
||||||
protected ProcessMapPlanBaseController(IChangeLogRepository<TDto, ProcessMapPlanBaseRequestWithWell> repository,
|
protected ProcessMapPlanBaseController(IChangeLogRepository<TDto, ProcessMapPlanBaseRequestWithWell> repository,
|
||||||
IWellService wellService,
|
IWellService wellService,
|
||||||
ParserExcelService<TDto> parserService)
|
ParserExcelService<TDto, WellRelatedParserRequest> parserService)
|
||||||
{
|
{
|
||||||
this.repository = repository;
|
this.repository = repository;
|
||||||
this.wellService = wellService;
|
this.wellService = wellService;
|
||||||
@ -213,7 +213,7 @@ public abstract class ProcessMapPlanBaseController<TDto> : ControllerBase
|
|||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
|
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
|
||||||
public async Task<ActionResult<ParserResultDto<TDto>>> Parse(int idWell,
|
public async Task<ActionResult<ParserResultDto<TDto>>> Parse(int idWell,
|
||||||
[Required] IFormFile file,
|
[Required] IFormFile file,
|
||||||
CancellationToken token)
|
CancellationToken token)
|
||||||
{
|
{
|
||||||
await AssertUserHasAccessToWell(idWell, token);
|
await AssertUserHasAccessToWell(idWell, token);
|
||||||
@ -222,9 +222,8 @@ public abstract class ProcessMapPlanBaseController<TDto> : ControllerBase
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var dto = parserService.Parse(stream, IParserOptionsRequest.Empty());
|
var options = new WellRelatedParserRequest(idWell);
|
||||||
foreach (var item in dto.Item)
|
var dto = parserService.Parse(stream, options);
|
||||||
item.Item.IdWell = idWell;
|
|
||||||
|
|
||||||
return Ok(dto);
|
return Ok(dto);
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ using System.Threading.Tasks;
|
|||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Requests.ParserOptions;
|
using AsbCloudApp.Requests.ParserOptions;
|
||||||
using AsbCloudInfrastructure.Services.Parser;
|
using AsbCloudInfrastructure.Services.Parser;
|
||||||
|
using AsbCloudInfrastructure.Services.Trajectory.Parser;
|
||||||
|
|
||||||
namespace AsbCloudWebApi.Controllers.Trajectory
|
namespace AsbCloudWebApi.Controllers.Trajectory
|
||||||
{
|
{
|
||||||
@ -25,11 +26,11 @@ namespace AsbCloudWebApi.Controllers.Trajectory
|
|||||||
public abstract class TrajectoryEditableController<TDto> : TrajectoryController<TDto>
|
public abstract class TrajectoryEditableController<TDto> : TrajectoryController<TDto>
|
||||||
where TDto : TrajectoryGeoDto
|
where TDto : TrajectoryGeoDto
|
||||||
{
|
{
|
||||||
private readonly ParserExcelService<TDto> parserService;
|
private readonly TrajectoryParser<TDto> parserService;
|
||||||
private readonly ITrajectoryEditableRepository<TDto> trajectoryRepository;
|
private readonly ITrajectoryEditableRepository<TDto> trajectoryRepository;
|
||||||
|
|
||||||
protected TrajectoryEditableController(IWellService wellService,
|
protected TrajectoryEditableController(IWellService wellService,
|
||||||
ParserExcelService<TDto> parserService,
|
TrajectoryParser<TDto> parserService,
|
||||||
TrajectoryExportService<TDto> trajectoryExportService,
|
TrajectoryExportService<TDto> trajectoryExportService,
|
||||||
ITrajectoryEditableRepository<TDto> trajectoryRepository)
|
ITrajectoryEditableRepository<TDto> trajectoryRepository)
|
||||||
: base(wellService, trajectoryExportService, trajectoryRepository)
|
: base(wellService, trajectoryExportService, trajectoryRepository)
|
||||||
@ -78,7 +79,9 @@ namespace AsbCloudWebApi.Controllers.Trajectory
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var dto = parserService.Parse(stream, IParserOptionsRequest.Empty());
|
var options = new WellRelatedParserRequest(idWell);
|
||||||
|
var dto = parserService.Parse(stream, options);
|
||||||
|
|
||||||
return Ok(dto);
|
return Ok(dto);
|
||||||
}
|
}
|
||||||
catch (FileFormatException ex)
|
catch (FileFormatException ex)
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Services;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.Controllers
|
||||||
|
{
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
public class WellCompositeOperationController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IWellCompositeOperationService wellCompositeOperationService;
|
||||||
|
private readonly IWellService wellService;
|
||||||
|
|
||||||
|
public WellCompositeOperationController(IWellCompositeOperationService wellCompositeOperationService, IWellService wellService)
|
||||||
|
{
|
||||||
|
this.wellCompositeOperationService = wellCompositeOperationService;
|
||||||
|
this.wellService = wellService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[ProducesResponseType(typeof(IList<IDictionary<int, WellOperationDataDto>>), (int)System.Net.HttpStatusCode.OK)]
|
||||||
|
public async Task<IActionResult> GetAsync([FromQuery] IEnumerable<int> idsWells, CancellationToken token)
|
||||||
|
{
|
||||||
|
foreach (var idWell in idsWells)
|
||||||
|
if (!await UserHasAccessToWellAsync(idWell, token))
|
||||||
|
return Forbid();
|
||||||
|
|
||||||
|
var result = await wellCompositeOperationService.GetAsync(idsWells, token)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async Task<bool> UserHasAccessToWellAsync(int idWell, CancellationToken token)
|
||||||
|
{
|
||||||
|
var idCompany = User.GetCompanyId();
|
||||||
|
if (idCompany is not null &&
|
||||||
|
await wellService.IsCompanyInvolvedInWellAsync((int)idCompany, idWell, token)
|
||||||
|
.ConfigureAwait(false))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user