Merge branch 'dev' into CrudWellRelatedTest

This commit is contained in:
ngfrolov 2024-02-27 14:12:12 +05:00
commit 7eff73504b
Signed by untrusted user who does not match committer: ng.frolov
GPG Key ID: E99907A0357B29A7
68 changed files with 29346 additions and 2472 deletions

View File

@ -1,19 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Linq" Version="4.3.0" />
</ItemGroup>
<ItemGroup>
<None Remove="Data\DailyReport\" />
</ItemGroup>
<ItemGroup>
<EditorConfigFiles Remove="D:\Source\AsbCloudApp\Services\.editorconfig" />
</ItemGroup>

View File

@ -1,51 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Data.ProcessMapPlan;
/// <inheritdoc/>
public abstract class ProcessMapPlanBaseDto : ChangeLogAbstract, IId, IWellRelated, IValidatableObject
{
/// <summary>
/// Id скважины
/// </summary>
[Range(1, int.MaxValue, ErrorMessage = "Id скважины не может быть меньше 1")]
public int IdWell { get; set; }
/// <summary>
/// Тип секции
/// </summary>
[Range(1, int.MaxValue, ErrorMessage = "Id секции скважины не может быть меньше 1")]
public int IdWellSectionType { get; set; }
/// <summary>
/// Название секции
/// </summary>
public string? Section { get; set; }
/// <summary>
/// Глубина по стволу от, м
/// <para>
/// на начало интервала
/// </para>
/// </summary>
[Range(0, 99999.9, ErrorMessage = "Глубина не может быть отрицательной")]
public double DepthStart { get; set; }
/// <summary>
/// Глубина по стволу до, м
/// <para>
/// на конец интервала
/// </para>
/// </summary>
[Range(0, 99999.9, ErrorMessage = "Глубина не может быть отрицательной")]
public double DepthEnd { get; set; }
/// <inheritdoc/>
public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if(DepthEnd <= DepthStart)
yield return new ("Глубина окончания должна быть больше глубины начала", new string[] {nameof(DepthEnd), nameof(DepthStart) });
}
}

View File

@ -1,38 +1,28 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Data.ProcessMaps;
/// <inheritdoc/>
public abstract class ProcessMapPlanBaseDto : IId, IWellRelated
public abstract class ProcessMapPlanBaseDto : ChangeLogAbstract, IId, IWellRelated, IValidatableObject
{
/// <inheritdoc/>
[Required]
public int Id { get; set; }
/// <summary>
/// Id скважины
/// </summary>
[Required]
[Range(1, int.MaxValue, ErrorMessage = "Id скважины не может быть меньше 1")]
public int IdWell { get; set; }
/// <summary>
/// Id пользователя
/// </summary>
public int IdUser { get; set; }
/// <summary>
/// Тип секции
/// </summary>
[Required]
[Range(1, int.MaxValue, ErrorMessage = "Id секции скважины не может быть меньше 1")]
public int IdWellSectionType { get; set; }
/// <summary>
/// Дата последнего изменения
/// Название секции
/// </summary>
public DateTimeOffset LastUpdate { get; set; }
public string? Section { get; set; }
/// <summary>
/// Глубина по стволу от, м
@ -40,7 +30,6 @@ public abstract class ProcessMapPlanBaseDto : IId, IWellRelated
/// на начало интервала
/// </para>
/// </summary>
[Required]
[Range(0, 99999.9, ErrorMessage = "Глубина не может быть отрицательной")]
public double DepthStart { get; set; }
@ -50,12 +39,13 @@ public abstract class ProcessMapPlanBaseDto : IId, IWellRelated
/// на конец интервала
/// </para>
/// </summary>
[Required]
[Range(0, 99999.9, ErrorMessage = "Глубина не может быть отрицательной")]
public double DepthEnd { get; set; }
/// <summary>
/// Комментарий
/// </summary>
public string? Comment { get; set; }
/// <inheritdoc/>
public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (DepthEnd <= DepthStart)
yield return new("Глубина окончания должна быть больше глубины начала", new string[] { nameof(DepthEnd), nameof(DepthStart) });
}
}

View File

@ -1,6 +1,6 @@
using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Data.ProcessMapPlan;
namespace AsbCloudApp.Data.ProcessMaps;
/// <summary>
/// РТК план бурение скважины

View File

@ -6,7 +6,7 @@ namespace AsbCloudApp.Data.ProcessMaps;
/// <summary>
/// РТК план проработка скважины
/// </summary>
public class ProcessMapPlanWellReamDto : ProcessMapPlanBaseDto, IValidatableObject
public class ProcessMapPlanReamDto : ProcessMapPlanBaseDto, IValidatableObject
{
/// <summary>
/// Количество повторений

View File

@ -1,67 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Data.ProcessMaps;
/// <summary>
/// РТК план бурение скважины
/// </summary>
public class ProcessMapPlanWellDrillingDto : ProcessMapPlanBaseDto
{
/// <summary>
/// Id режима 0-ручной, 1-ротор, 2 - слайд
/// </summary>
[Required]
[Range(0, 2, ErrorMessage = "Id режима должен быть либо 0-ручной либо, 1-ротор либо 2-слайд")]
public int IdMode { get; set; }
/// <summary>
/// Нагрузка
/// </summary>
[Required]
public PlanLimitDto AxialLoad { get; set; } = null!;
/// <summary>
/// Перепад давления
/// </summary>
[Required]
public PlanLimitDto Pressure { get; set; } = null!;
/// <summary>
/// Момент на ВСП
/// </summary>
[Required]
public PlanLimitDto TopDriveTorque { get; set; } = null!;
/// <summary>
/// Обороты на ВСП
/// </summary>
[Required]
public PlanLimitDto TopDriveSpeed { get; set; } = null!;
/// <summary>
/// Расход
/// </summary>
[Required]
public PlanLimitDto Flow { get; set; } = null!;
/// <summary>
/// Плановая механическая скорость, м/ч
/// </summary>
[Required]
[Range(0, 99999.9, ErrorMessage = "Плановая механическая скорость должно быть в пределах от 0 до 99999.9")]
public double RopPlan { get; set; }
/// <summary>
/// Плановый процент использования АКБ
/// </summary>
[Required]
[Range(0, 100, ErrorMessage = "Процент использования АКБ должен быть в пределах от 0 до 100")]
public double UsageSaub { get; set; }
/// <summary>
/// Плановый процент использования spin master
/// </summary>
[Required]
[Range(0, 100, ErrorMessage = "Процент использования spin master должен быть в пределах от 0 до 100")]
public double UsageSpin { get; set; }
}

View File

@ -93,6 +93,4 @@ public interface IChangeLogRepository<TDto, TRequest>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<TDto>> Get(TRequest request, CancellationToken token);
}

View File

@ -1,32 +0,0 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Threading;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using System;
namespace AsbCloudApp.Repositories;
/// <summary>
/// РТК план
/// </summary>
[Obsolete]
public interface IProcessMapPlanRepository<TDto> : IRepositoryWellRelated<TDto>
where TDto : ProcessMapPlanBaseDto
{
/// <summary>
/// Получить РТК по коллекции параметров
/// </summary>
/// <param name="requests"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<IEnumerable<TDto>> GetAsync(IEnumerable<ProcessMapPlanRequest> requests, CancellationToken cancellationToken);
/// <summary>
/// Удалить РТК по скважине
/// </summary>
/// <param name="idWell"></param>
/// <returns></returns>
Task<int> RemoveByWellAsync(int idWell);
}

View File

@ -1,8 +1,8 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMaps;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data.ProcessMaps;
namespace AsbCloudApp.Repositories
{
@ -34,6 +34,6 @@ namespace AsbCloudApp.Repositories
/// <param name="idWell"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<ProcessMapPlanWellDrillingDto>> GetCompositeProcessMap(int idWell, CancellationToken token);
Task<IEnumerable<ProcessMapPlanDrillingDto>> GetCompositeProcessMap(int idWell, CancellationToken token);
}
}

View File

@ -8,7 +8,7 @@ namespace AsbCloudApp.Requests;
public class ChangeLogBaseRequest
{
/// <summary>
/// Дата/время на которую записи были актуальны. Если не задано, то не фильтруется
/// Дата/время на которую записи были актуальны. Если не задано, то возвращаются все данные без учета их актуальности
/// </summary>
public DateTimeOffset? Moment { get; set; }
}

View File

@ -1,39 +0,0 @@
using System;
using System.IO;
using System.Threading.Tasks;
using System.Threading;
namespace AsbCloudApp.Services.ProcessMaps;
/// <summary>
/// Сервис импорта РТК
/// </summary>
[Obsolete]
public interface IProcessMapPlanImportService
{
/// <summary>
/// Загрузить данные из файла
/// </summary>
/// <param name="idWell"></param>
/// <param name="idUser"></param>
/// <param name="deleteBeforeImport"></param>
/// <param name="stream"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task ImportAsync(int idWell, int idUser, bool deleteBeforeImport, Stream stream,
CancellationToken cancellationToken);
/// <summary>
/// Сформировать файл с данными
/// </summary>
/// <param name="idWell"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<(string Name, Stream File)> ExportAsync(int idWell, CancellationToken cancellationToken);
/// <summary>
/// Получение шаблона для заполнения
/// </summary>
/// <returns></returns>
Task<(string Name, Stream File)> GetExcelTemplateStreamAsync(CancellationToken cancellationToken);
}

View File

@ -1,22 +0,0 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMaps;
namespace AsbCloudApp.Services.ProcessMaps;
/// <summary>
/// РТК
/// </summary>
public interface IProcessMapPlanService<T>
where T : ProcessMapPlanBaseDto
{
/// <summary>
/// Получение РТК план по скважине
/// </summary>
/// <param name="idWell"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<IEnumerable<ValidationResultDto<T>>> GetAsync(int idWell, CancellationToken cancellationToken);
}

View File

@ -1,26 +0,0 @@
using AsbCloudApp.Data.ProcessMaps.Report;
using AsbCloudApp.Requests;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudApp.Services.ProcessMaps.WellDrilling
{
/// <summary>
/// Получить РТК-отчет по бурению
/// </summary>
public interface IProcessMapReportDataSaubStatService
{
/// <summary>
/// Получения строк РТК-отчёта
/// </summary>
/// <param name="idWell">ключ скважины</param>
/// <param name="request">параметры запроса</param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<ProcessMapReportDataSaubStatDto>> GetAsync(int idWell, DataSaubStatRequest request, CancellationToken token);
}
}

View File

@ -12,7 +12,7 @@ namespace AsbCloudApp.Services.ProcessMaps.WellDrilling
/// <summary>
/// Сервис экспорт РТК
/// </summary>
public interface IProcessMapReportDataSaubStatExportService
public interface IProcessMapReportDrillingExportService
{
/// <summary>
/// Сформировать файл с данными

View File

@ -0,0 +1,22 @@
using AsbCloudApp.Data.ProcessMaps.Report;
using AsbCloudApp.Requests;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudApp.Services.ProcessMaps.WellDrilling;
/// <summary>
/// РТК-отчет по бурению
/// </summary>
public interface IProcessMapReportDrillingService
{
/// <summary>
/// Получения строк РТК-отчёта
/// </summary>
/// <param name="idWell">ключ скважины</param>
/// <param name="request">параметры запроса</param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<ProcessMapReportDataSaubStatDto>> GetAsync(int idWell, DataSaubStatRequest request, CancellationToken token);
}

View File

@ -1,19 +0,0 @@
using System.IO;
using System.Threading.Tasks;
using System.Threading;
namespace AsbCloudApp.Services.ProcessMaps.WellDrilling;
/// <summary>
/// Сервис экспорт РТК
/// </summary>
public interface IProcessMapReportWellDrillingExportService
{
/// <summary>
/// Сформировать файл с данными
/// </summary>
/// <param name="idWell"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<(string Name, Stream File)?> ExportAsync(int idWell, CancellationToken cancellationToken);
}

View File

@ -1,20 +0,0 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data.ProcessMaps.Report;
namespace AsbCloudApp.Services.ProcessMaps.WellDrilling;
/// <summary>
/// Сервис формирования отчёта РТК бурение
/// </summary>
public interface IProcessMapReportWellDrillingService
{
/// <summary>
/// Получить отчёт РТК по бурению
/// </summary>
/// <param name="idWell"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<ProcessMapReportWellDrillingDto>> GetAsync(int idWell, CancellationToken token);
}

View File

@ -1,16 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.22">
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.22" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.2" />
</ItemGroup>
<ItemGroup>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,76 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace AsbCloudDb.Migrations
{
public partial class Migrate_ProcessMapPlanDrilling : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql
(@"insert " +
@"into " +
@"public.t_process_map_plan_drilling " +
@"(id, " +
@"id_mode, " +
@"axial_load_plan, " +
@"axial_load_limit_max, " +
@"delta_pressure_plan, " +
@"delta_pressure_limit_max, " +
@"top_drive_torque_plan, " +
@"top_drive_torque_limit_max, " +
@"top_drive_speed_plan, " +
@"top_drive_speed_limit_max, " +
@"flow_plan, " +
@"flow_limit_max, " +
@"rop_plan, " +
@"usage_saub, " +
@"usage_spin, " +
@"""comment"", " +
@"id_author, " +
@"id_editor, " +
@"creation, " +
@"obsolete, " +
@"id_state, " +
@"id_previous, " +
@"id_well, " +
@"id_wellsection_type, " +
@"depth_start, " +
@"depth_end) " +
@"select " +
@"tpmwd.id, " +
@"tpmwd.id_mode, " +
@"tpmwd.axial_load_plan, " +
@"tpmwd.axial_load_limit_max, " +
@"tpmwd.pressure_plan, " +
@"tpmwd.pressure_limit_max, " +
@"tpmwd.top_drive_torque_plan, " +
@"tpmwd.top_drive_torque_limit_max, " +
@"tpmwd.top_drive_speed_plan, " +
@"tpmwd.top_drive_speed_limit_max, " +
@"tpmwd.flow_plan, " +
@"tpmwd.flow_limit_max, " +
@"tpmwd.rop_plan, " +
@"tpmwd.usage_saub, " +
@"tpmwd.usage_spin, " +
@"format('%s', tpmwd.""comment""), " +
@"tpmwd.id_user, " +
@"null, " +
@"tpmwd.last_update - interval '1 year', " +
@"null, " +
@"0, " +
@"null, " +
@"tpmwd.id_well, " +
@"tpmwd.id_wellsection_type, " +
@"tpmwd.depth_start, " +
@"tpmwd.depth_end " +
@"from t_process_map_well_drilling tpmwd;");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,95 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace AsbCloudDb.Migrations
{
public partial class Add_ProcessMapPlanReams : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "t_process_map_plan_ream",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false, comment: "Идентификатор")
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
repeats = table.Column<double>(type: "double precision", nullable: false, comment: "Количество повторений"),
spin_upward = table.Column<double>(type: "double precision", nullable: false, comment: "Вращение при движении вверх, об/мин"),
spin_downward = table.Column<double>(type: "double precision", nullable: false, comment: "Вращение при движении вниз, об/мин"),
speed_upward = table.Column<double>(type: "double precision", nullable: false, comment: "Скорость подъёма, м/ч"),
speed_downward = table.Column<double>(type: "double precision", nullable: false, comment: "Скорость спуска, м/ч"),
setpoint_drag = table.Column<double>(type: "double precision", nullable: false, comment: "Уставка зятяжки, т"),
setpoint_tight = table.Column<double>(type: "double precision", nullable: false, comment: "Уставка посадки, т"),
pressure = table.Column<double>(type: "double precision", nullable: false, comment: "Давление, атм"),
torque = table.Column<double>(type: "double precision", nullable: false, comment: "Момент, кН*м"),
id_author = table.Column<int>(type: "integer", nullable: false, comment: "Автор"),
id_editor = table.Column<int>(type: "integer", nullable: true, comment: "Редактор"),
creation = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "дата создания"),
obsolete = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true, comment: "дата устаревания"),
id_state = table.Column<int>(type: "integer", nullable: false, comment: "ИД состояния записи: \n0 - актуальная\n1 - замененная\n2 - удаленная"),
id_previous = table.Column<int>(type: "integer", nullable: true, comment: "ИД состояния записи: \n0 - актуальная\n1 - замененная\n2 - удаленная"),
id_well = table.Column<int>(type: "integer", nullable: false, comment: "Id скважины"),
id_wellsection_type = table.Column<int>(type: "integer", nullable: false, comment: "Тип секции"),
depth_start = table.Column<double>(type: "double precision", nullable: false, comment: "Глубина по стволу от, м"),
depth_end = table.Column<double>(type: "double precision", nullable: false, comment: "Глубина по стволу до, м")
},
constraints: table =>
{
table.PrimaryKey("PK_t_process_map_plan_ream", x => x.id);
table.ForeignKey(
name: "FK_t_process_map_plan_ream_t_user_id_author",
column: x => x.id_author,
principalTable: "t_user",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_t_process_map_plan_ream_t_user_id_editor",
column: x => x.id_editor,
principalTable: "t_user",
principalColumn: "id");
table.ForeignKey(
name: "FK_t_process_map_plan_ream_t_well_id_well",
column: x => x.id_well,
principalTable: "t_well",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_t_process_map_plan_ream_t_well_section_type_id_wellsection_~",
column: x => x.id_wellsection_type,
principalTable: "t_well_section_type",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
},
comment: "РТК проработка скважины");
migrationBuilder.CreateIndex(
name: "IX_t_process_map_plan_ream_id_author",
table: "t_process_map_plan_ream",
column: "id_author");
migrationBuilder.CreateIndex(
name: "IX_t_process_map_plan_ream_id_editor",
table: "t_process_map_plan_ream",
column: "id_editor");
migrationBuilder.CreateIndex(
name: "IX_t_process_map_plan_ream_id_well",
table: "t_process_map_plan_ream",
column: "id_well");
migrationBuilder.CreateIndex(
name: "IX_t_process_map_plan_ream_id_wellsection_type",
table: "t_process_map_plan_ream",
column: "id_wellsection_type");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "t_process_map_plan_ream");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,152 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace AsbCloudDb.Migrations
{
public partial class Remove_old_ProcessMapPlans : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "t_process_map_well_drilling");
migrationBuilder.DropTable(
name: "t_process_map_well_ream");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "t_process_map_well_drilling",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
id_user = table.Column<int>(type: "integer", nullable: false, comment: "Id пользователя"),
id_well = table.Column<int>(type: "integer", nullable: false, comment: "Id скважины"),
id_wellsection_type = table.Column<int>(type: "integer", nullable: false, comment: "Тип секции"),
axial_load_limit_max = table.Column<double>(type: "double precision", nullable: false, comment: "Нагрузка, допустимый максимум"),
axial_load_plan = table.Column<double>(type: "double precision", nullable: false, comment: "Нагрузка, план"),
comment = table.Column<string>(type: "text", nullable: true, comment: "Комментарий"),
depth_end = table.Column<double>(type: "double precision", nullable: false, comment: "Глубина по стволу до, м"),
depth_start = table.Column<double>(type: "double precision", nullable: false, comment: "Глубина по стволу от, м"),
flow_limit_max = table.Column<double>(type: "double precision", nullable: false, comment: "Расход, допустимый максимум"),
flow_plan = table.Column<double>(type: "double precision", nullable: false, comment: "Расход, план"),
id_mode = table.Column<int>(type: "integer", nullable: false, comment: "Id режима (1- ротор, 2 слайд)"),
last_update = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата последнего изменения"),
pressure_limit_max = table.Column<double>(type: "double precision", nullable: false, comment: "Перепад давления, допустимый максимум"),
pressure_plan = table.Column<double>(type: "double precision", nullable: false, comment: "Перепад давления, план"),
rop_plan = table.Column<double>(type: "double precision", nullable: false, comment: "Плановая механическая скорость, м/ч"),
top_drive_speed_limit_max = table.Column<double>(type: "double precision", nullable: false, comment: "Обороты на ВСП, допустимый максимум"),
top_drive_speed_plan = table.Column<double>(type: "double precision", nullable: false, comment: "Обороты на ВСП, план"),
top_drive_torque_limit_max = table.Column<double>(type: "double precision", nullable: false, comment: "Момент на ВСП, допустимый максимум"),
top_drive_torque_plan = table.Column<double>(type: "double precision", nullable: false, comment: "Момент на ВСП, план"),
usage_saub = table.Column<double>(type: "double precision", nullable: false, comment: "Плановый процент использования АКБ"),
usage_spin = table.Column<double>(type: "double precision", nullable: false, comment: "Плановый процент использования spin master")
},
constraints: table =>
{
table.PrimaryKey("PK_t_process_map_well_drilling", x => x.id);
table.ForeignKey(
name: "FK_t_process_map_well_drilling_t_user_id_user",
column: x => x.id_user,
principalTable: "t_user",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_t_process_map_well_drilling_t_well_id_well",
column: x => x.id_well,
principalTable: "t_well",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_t_process_map_well_drilling_t_well_section_type_id_wellsect~",
column: x => x.id_wellsection_type,
principalTable: "t_well_section_type",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
},
comment: "РТК бурение скважины");
migrationBuilder.CreateTable(
name: "t_process_map_well_ream",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
id_user = table.Column<int>(type: "integer", nullable: false, comment: "Id пользователя"),
id_well = table.Column<int>(type: "integer", nullable: false, comment: "Id скважины"),
id_wellsection_type = table.Column<int>(type: "integer", nullable: false, comment: "Тип секции"),
comment = table.Column<string>(type: "text", nullable: true, comment: "Комментарий"),
depth_end = table.Column<double>(type: "double precision", nullable: false, comment: "Глубина по стволу до, м"),
depth_start = table.Column<double>(type: "double precision", nullable: false, comment: "Глубина по стволу от, м"),
last_update = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата последнего изменения"),
pressure = table.Column<double>(type: "double precision", nullable: false, comment: "Давление, атм"),
repeats = table.Column<double>(type: "double precision", nullable: false, comment: "Количество повторений"),
setpoint_drag = table.Column<double>(type: "double precision", nullable: false, comment: "Уставка зятяжки, т"),
setpoint_tight = table.Column<double>(type: "double precision", nullable: false, comment: "Уставка посадки, т"),
speed_downward = table.Column<double>(type: "double precision", nullable: false, comment: "Скорость спуска, м/ч"),
speed_upward = table.Column<double>(type: "double precision", nullable: false, comment: "Скорость подъёма, м/ч"),
spin_downward = table.Column<double>(type: "double precision", nullable: false, comment: "Вращение при движении вниз, об/мин"),
spin_upward = table.Column<double>(type: "double precision", nullable: false, comment: "Вращение при движении вверх, об/мин"),
torque = table.Column<double>(type: "double precision", nullable: false, comment: "Момент, кН*м")
},
constraints: table =>
{
table.PrimaryKey("PK_t_process_map_well_ream", x => x.id);
table.ForeignKey(
name: "FK_t_process_map_well_ream_t_user_id_user",
column: x => x.id_user,
principalTable: "t_user",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_t_process_map_well_ream_t_well_id_well",
column: x => x.id_well,
principalTable: "t_well",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_t_process_map_well_ream_t_well_section_type_id_wellsection_~",
column: x => x.id_wellsection_type,
principalTable: "t_well_section_type",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
},
comment: "РТК проработка скважины");
migrationBuilder.CreateIndex(
name: "IX_t_process_map_well_drilling_id_user",
table: "t_process_map_well_drilling",
column: "id_user");
migrationBuilder.CreateIndex(
name: "IX_t_process_map_well_drilling_id_well",
table: "t_process_map_well_drilling",
column: "id_well");
migrationBuilder.CreateIndex(
name: "IX_t_process_map_well_drilling_id_wellsection_type",
table: "t_process_map_well_drilling",
column: "id_wellsection_type");
migrationBuilder.CreateIndex(
name: "IX_t_process_map_well_ream_id_user",
table: "t_process_map_well_ream",
column: "id_user");
migrationBuilder.CreateIndex(
name: "IX_t_process_map_well_ream_id_well",
table: "t_process_map_well_ream",
column: "id_well");
migrationBuilder.CreateIndex(
name: "IX_t_process_map_well_ream_id_wellsection_type",
table: "t_process_map_well_ream",
column: "id_wellsection_type");
}
}
}

View File

@ -2747,29 +2747,20 @@ namespace AsbCloudDb.Migrations
b.HasComment("РТК план бурение");
});
modelBuilder.Entity("AsbCloudDb.Model.ProcessMaps.ProcessMapWellDrilling", b =>
modelBuilder.Entity("AsbCloudDb.Model.ProcessMaps.ProcessMapPlanReam", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
.HasColumnName("id")
.HasComment("Идентификатор");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<double>("AxialLoadLimitMax")
.HasColumnType("double precision")
.HasColumnName("axial_load_limit_max")
.HasComment("Нагрузка, допустимый максимум");
b.Property<double>("AxialLoadPlan")
.HasColumnType("double precision")
.HasColumnName("axial_load_plan")
.HasComment("Нагрузка, план");
b.Property<string>("Comment")
.HasColumnType("text")
.HasColumnName("comment")
.HasComment("Комментарий");
b.Property<DateTimeOffset>("Creation")
.HasColumnType("timestamp with time zone")
.HasColumnName("creation")
.HasComment("дата создания");
b.Property<double>("DepthEnd")
.HasColumnType("double precision")
@ -2781,25 +2772,25 @@ namespace AsbCloudDb.Migrations
.HasColumnName("depth_start")
.HasComment("Глубина по стволу от, м");
b.Property<double>("FlowLimitMax")
.HasColumnType("double precision")
.HasColumnName("flow_limit_max")
.HasComment("Расход, допустимый максимум");
b.Property<double>("FlowPlan")
.HasColumnType("double precision")
.HasColumnName("flow_plan")
.HasComment("Расход, план");
b.Property<int>("IdMode")
b.Property<int>("IdAuthor")
.HasColumnType("integer")
.HasColumnName("id_mode")
.HasComment("Id режима (1- ротор, 2 слайд)");
.HasColumnName("id_author")
.HasComment("Автор");
b.Property<int>("IdUser")
b.Property<int?>("IdEditor")
.HasColumnType("integer")
.HasColumnName("id_user")
.HasComment("Id пользователя");
.HasColumnName("id_editor")
.HasComment("Редактор");
b.Property<int?>("IdPrevious")
.HasColumnType("integer")
.HasColumnName("id_previous")
.HasComment("ИД состояния записи: \n0 - актуальная\n1 - замененная\n2 - удаленная");
b.Property<int>("IdState")
.HasColumnType("integer")
.HasColumnName("id_state")
.HasComment("ИД состояния записи: \n0 - актуальная\n1 - замененная\n2 - удаленная");
b.Property<int>("IdWell")
.HasColumnType("integer")
@ -2811,112 +2802,10 @@ namespace AsbCloudDb.Migrations
.HasColumnName("id_wellsection_type")
.HasComment("Тип секции");
b.Property<DateTimeOffset>("LastUpdate")
b.Property<DateTimeOffset?>("Obsolete")
.HasColumnType("timestamp with time zone")
.HasColumnName("last_update")
.HasComment("Дата последнего изменения");
b.Property<double>("PressureLimitMax")
.HasColumnType("double precision")
.HasColumnName("pressure_limit_max")
.HasComment("Перепад давления, допустимый максимум");
b.Property<double>("PressurePlan")
.HasColumnType("double precision")
.HasColumnName("pressure_plan")
.HasComment("Перепад давления, план");
b.Property<double>("RopPlan")
.HasColumnType("double precision")
.HasColumnName("rop_plan")
.HasComment("Плановая механическая скорость, м/ч");
b.Property<double>("TopDriveSpeedLimitMax")
.HasColumnType("double precision")
.HasColumnName("top_drive_speed_limit_max")
.HasComment("Обороты на ВСП, допустимый максимум");
b.Property<double>("TopDriveSpeedPlan")
.HasColumnType("double precision")
.HasColumnName("top_drive_speed_plan")
.HasComment("Обороты на ВСП, план");
b.Property<double>("TopDriveTorqueLimitMax")
.HasColumnType("double precision")
.HasColumnName("top_drive_torque_limit_max")
.HasComment("Момент на ВСП, допустимый максимум");
b.Property<double>("TopDriveTorquePlan")
.HasColumnType("double precision")
.HasColumnName("top_drive_torque_plan")
.HasComment("Момент на ВСП, план");
b.Property<double>("UsageSaub")
.HasColumnType("double precision")
.HasColumnName("usage_saub")
.HasComment("Плановый процент использования АКБ");
b.Property<double>("UsageSpin")
.HasColumnType("double precision")
.HasColumnName("usage_spin")
.HasComment("Плановый процент использования spin master");
b.HasKey("Id");
b.HasIndex("IdUser");
b.HasIndex("IdWell");
b.HasIndex("IdWellSectionType");
b.ToTable("t_process_map_well_drilling");
b.HasComment("РТК бурение скважины");
});
modelBuilder.Entity("AsbCloudDb.Model.ProcessMaps.ProcessMapWellReam", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Comment")
.HasColumnType("text")
.HasColumnName("comment")
.HasComment("Комментарий");
b.Property<double>("DepthEnd")
.HasColumnType("double precision")
.HasColumnName("depth_end")
.HasComment("Глубина по стволу до, м");
b.Property<double>("DepthStart")
.HasColumnType("double precision")
.HasColumnName("depth_start")
.HasComment("Глубина по стволу от, м");
b.Property<int>("IdUser")
.HasColumnType("integer")
.HasColumnName("id_user")
.HasComment("Id пользователя");
b.Property<int>("IdWell")
.HasColumnType("integer")
.HasColumnName("id_well")
.HasComment("Id скважины");
b.Property<int>("IdWellSectionType")
.HasColumnType("integer")
.HasColumnName("id_wellsection_type")
.HasComment("Тип секции");
b.Property<DateTimeOffset>("LastUpdate")
.HasColumnType("timestamp with time zone")
.HasColumnName("last_update")
.HasComment("Дата последнего изменения");
.HasColumnName("obsolete")
.HasComment("дата устаревания");
b.Property<double>("Pressure")
.HasColumnType("double precision")
@ -2965,13 +2854,15 @@ namespace AsbCloudDb.Migrations
b.HasKey("Id");
b.HasIndex("IdUser");
b.HasIndex("IdAuthor");
b.HasIndex("IdEditor");
b.HasIndex("IdWell");
b.HasIndex("IdWellSectionType");
b.ToTable("t_process_map_well_ream");
b.ToTable("t_process_map_plan_ream");
b.HasComment("РТК проработка скважины");
});
@ -8742,14 +8633,18 @@ namespace AsbCloudDb.Migrations
b.Navigation("WellSectionType");
});
modelBuilder.Entity("AsbCloudDb.Model.ProcessMaps.ProcessMapWellDrilling", b =>
modelBuilder.Entity("AsbCloudDb.Model.ProcessMaps.ProcessMapPlanReam", b =>
{
b.HasOne("AsbCloudDb.Model.User", "User")
b.HasOne("AsbCloudDb.Model.User", "Author")
.WithMany()
.HasForeignKey("IdUser")
.HasForeignKey("IdAuthor")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AsbCloudDb.Model.User", "Editor")
.WithMany()
.HasForeignKey("IdEditor");
b.HasOne("AsbCloudDb.Model.Well", "Well")
.WithMany()
.HasForeignKey("IdWell")
@ -8762,34 +8657,9 @@ namespace AsbCloudDb.Migrations
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
b.Navigation("Author");
b.Navigation("Well");
b.Navigation("WellSectionType");
});
modelBuilder.Entity("AsbCloudDb.Model.ProcessMaps.ProcessMapWellReam", b =>
{
b.HasOne("AsbCloudDb.Model.User", "User")
.WithMany()
.HasForeignKey("IdUser")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AsbCloudDb.Model.Well", "Well")
.WithMany()
.HasForeignKey("IdWell")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AsbCloudDb.Model.WellSectionType", "WellSectionType")
.WithMany()
.HasForeignKey("IdWellSectionType")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
b.Navigation("Editor");
b.Navigation("Well");

View File

@ -19,9 +19,8 @@ namespace AsbCloudDb.Model
public virtual DbSet<Deposit> Deposits => Set<Deposit>();
public virtual DbSet<DetectedOperation> DetectedOperations => Set<DetectedOperation>();
public virtual DbSet<TrajectoryPlan> TrajectoriesPlan => Set<TrajectoryPlan>();
public virtual DbSet<ProcessMapWellDrilling> ProcessMapWellDrillings => Set<ProcessMapWellDrilling>();
public virtual DbSet<ProcessMapWellReam> ProcessMapWellReams => Set<ProcessMapWellReam>();
public virtual DbSet<ProcessMapPlanDrilling> ProcessMapPlanDrilling => Set<ProcessMapPlanDrilling>();
public virtual DbSet<ProcessMapPlanReam> ProcessMapPlanReams => Set<ProcessMapPlanReam>();
public virtual DbSet<DrillingProgramPart> DrillingProgramParts => Set<DrillingProgramPart>();
public virtual DbSet<FileCategory> FileCategories => Set<FileCategory>();
public virtual DbSet<FileInfo> Files => Set<FileInfo>();

View File

@ -23,8 +23,6 @@ namespace AsbCloudDb.Model
DbSet<Deposit> Deposits { get; }
DbSet<DetectedOperation> DetectedOperations { get; }
DbSet<TrajectoryPlan> TrajectoriesPlan { get; }
DbSet<ProcessMapWellDrilling> ProcessMapWellDrillings { get; }
DbSet<ProcessMapWellReam> ProcessMapWellReams { get; }
DbSet<DrillingProgramPart> DrillingProgramParts { get; }
DbSet<FileCategory> FileCategories { get; }
DbSet<FileInfo> Files { get; }
@ -82,6 +80,7 @@ namespace AsbCloudDb.Model
DbSet<WellSectionPlan> WellSectionsPlan { get; }
DbSet<DataSaubStat> DataSaubStat { get; }
DatabaseFacade Database { get; }
DbSet<ProcessMapPlanReam> ProcessMapPlanReams { get; }
Task<int> RefreshMaterializedViewAsync(string mwName, CancellationToken token);
Task<int> RefreshMaterializedViewAsync<TEntity>(CancellationToken token) where TEntity : class;

View File

@ -1,10 +1,11 @@
using System.ComponentModel.DataAnnotations.Schema;
using AsbCloudDb.Model.ProcessMapPlan;
using Microsoft.EntityFrameworkCore;
namespace AsbCloudDb.Model.ProcessMaps;
[Table("t_process_map_well_ream"), Comment("РТК проработка скважины")]
public class ProcessMapWellReam : ProcessMapBase
[Table("t_process_map_plan_ream"), Comment("РТК проработка скважины")]
public class ProcessMapPlanReam : ProcessMapPlanBase
{
[Column("repeats"), Comment("Количество повторений")]
public double Repeats { get; set; }

View File

@ -1,43 +0,0 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace AsbCloudDb.Model.ProcessMaps;
public abstract class ProcessMapBase : IId, IWellRelated
{
[Key]
[Column("id")]
public int Id { get; set; }
[Column("id_well"), Comment("Id скважины")]
public int IdWell { get; set; }
[Column("id_wellsection_type"), Comment("Тип секции")]
public int IdWellSectionType { get; set; }
[Column("id_user"), Comment("Id пользователя")]
public int IdUser { get; set; }
[Column("last_update", TypeName = "timestamp with time zone"), Comment("Дата последнего изменения")]
public DateTimeOffset LastUpdate { get; set; }
[Column("depth_start"), Comment("Глубина по стволу от, м")]
public double DepthStart { get; set; }
[Column("depth_end"), Comment("Глубина по стволу до, м")]
public double DepthEnd { get; set; }
[Column("comment"), Comment("Комментарий")]
public string? Comment { get; set; }
[ForeignKey(nameof(IdWell))]
public virtual Well Well { get; set; } = null!;
[ForeignKey(nameof(IdUser))]
public virtual User User { get; set; } = null!;
[ForeignKey(nameof(IdWellSectionType))]
public virtual WellSectionType WellSectionType { get; set; } = null!;
}

View File

@ -1,50 +0,0 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;
namespace AsbCloudDb.Model.ProcessMaps;
[Table("t_process_map_well_drilling"), Comment("РТК бурение скважины")]
public class ProcessMapWellDrilling : ProcessMapBase
{
[Column("id_mode"), Comment("Id режима (1- ротор, 2 слайд)")]
public int IdMode { get; set; }
[Column("axial_load_plan"), Comment("Нагрузка, план")]
public double AxialLoadPlan { get; set; }
[Column("axial_load_limit_max"), Comment("Нагрузка, допустимый максимум")]
public double AxialLoadLimitMax { get; set; }
[Column("pressure_plan"), Comment("Перепад давления, план")]
public double PressurePlan { get; set; }
[Column("pressure_limit_max"), Comment("Перепад давления, допустимый максимум")]
public double PressureLimitMax { get; set; }
[Column("top_drive_torque_plan"), Comment("Момент на ВСП, план")]
public double TopDriveTorquePlan { get; set; }
[Column("top_drive_torque_limit_max"), Comment("Момент на ВСП, допустимый максимум")]
public double TopDriveTorqueLimitMax { get; set; }
[Column("top_drive_speed_plan"), Comment("Обороты на ВСП, план")]
public double TopDriveSpeedPlan { get; set; }
[Column("top_drive_speed_limit_max"), Comment("Обороты на ВСП, допустимый максимум")]
public double TopDriveSpeedLimitMax { get; set; }
[Column("flow_plan"), Comment("Расход, план")]
public double FlowPlan { get; set; }
[Column("flow_limit_max"), Comment("Расход, допустимый максимум")]
public double FlowLimitMax { get; set; }
[Column("rop_plan"), Comment("Плановая механическая скорость, м/ч")]
public double RopPlan { get; set; }
[Column("usage_saub"), Comment("Плановый процент использования АКБ")]
public double UsageSaub { get; set; }
[Column("usage_spin"), Comment("Плановый процент использования spin master")]
public double UsageSpin { get; set; }
}

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
@ -14,6 +14,7 @@
<None Remove="CommonLibs\Readme.md" />
<None Remove="Services\DailyReport\DailyReportTemplate.xlsx" />
<None Remove="Services\DrillTestReport\DrillTestReportTemplate.xlsx" />
<None Remove="Services\ProcessMapPlan\Templates\ProcessMapPlanReamTemplate.xlsx" />
<None Remove="Services\ProcessMaps\Report\ProcessMapReportDataSaubStatTemplate.xlsx" />
<None Remove="Services\Trajectory\FactTrajectoryTemplate.xlsx" />
<None Remove="Services\Trajectory\NnbTrajectoryTemplate.xlsx" />
@ -37,6 +38,7 @@
<EmbeddedResource Include="Services\DetectOperations\DetectOperations.xlsx" />
<EmbeddedResource Include="Services\DailyReport\DailyReportTemplate.xlsx" />
<EmbeddedResource Include="Services\DrillTestReport\DrillTestReportTemplate.xlsx" />
<EmbeddedResource Include="Services\ProcessMapPlan\Templates\ProcessMapPlanReamTemplate.xlsx" />
<EmbeddedResource Include="Services\ProcessMapPlan\Templates\ProcessMapPlanDrillingTemplate.xlsx" />
<EmbeddedResource Include="Services\ProcessMaps\Report\ProcessMapReportDataSaubStatTemplate.xlsx" />
<EmbeddedResource Include="Services\Trajectory\Templates\TrajectoryFactNnbTemplate.xlsx" />
@ -48,7 +50,6 @@
<EmbeddedResource Include="Services\WellOperationImport\Files\Dictionaries\Sections.txt" />
<EmbeddedResource Include="Services\WellOperationImport\Files\Dictionaries\OperationAttributes.txt" />
<EmbeddedResource Include="Services\ProcessMaps\Report\ProcessMapReportTemplate.xlsx" />
<EmbeddedResource Include="Services\ProcessMaps\WellDrilling\ProcessMapPlanImportWellDrillingTemplate.xlsx" />
</ItemGroup>
<ItemGroup>

View File

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using AsbCloudApp.Data;
using AsbCloudApp.Data;
using AsbCloudApp.Data.DailyReport.Blocks.TimeBalance;
using AsbCloudApp.Data.DrillTestReport;
using AsbCloudApp.Data.Manuals;
using AsbCloudApp.Data.ProcessMaps;
@ -9,15 +8,19 @@ using AsbCloudApp.Data.Subsystems;
using AsbCloudApp.Data.Trajectory;
using AsbCloudApp.Data.WellOperationImport.Options;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudApp.Services.DailyReport;
using AsbCloudApp.Services.Notifications;
using AsbCloudApp.Services.ProcessMaps;
using AsbCloudApp.Services.ProcessMaps.WellDrilling;
using AsbCloudApp.Services.WellOperationImport;
using AsbCloudDb.Model;
using AsbCloudDb.Model.DailyReports.Blocks.TimeBalance;
using AsbCloudDb.Model.Manuals;
using AsbCloudDb.Model.ProcessMaps;
using AsbCloudDb.Model.Trajectory;
using AsbCloudDb.Model.WellSections;
using AsbCloudInfrastructure.Background;
using AsbCloudInfrastructure.Repository;
using AsbCloudInfrastructure.Services;
@ -25,12 +28,14 @@ using AsbCloudInfrastructure.Services.DailyReport;
using AsbCloudInfrastructure.Services.DetectOperations;
using AsbCloudInfrastructure.Services.DrillingProgram;
using AsbCloudInfrastructure.Services.DrillTestReport;
using AsbCloudInfrastructure.Services.ProcessMapPlan.Parser;
using AsbCloudInfrastructure.Services.ProcessMaps;
using AsbCloudInfrastructure.Services.ProcessMaps.Report;
using AsbCloudInfrastructure.Services.ProcessMaps.WellDrilling;
using AsbCloudInfrastructure.Services.SAUB;
using AsbCloudInfrastructure.Services.Subsystems;
using AsbCloudInfrastructure.Services.Trajectory;
using AsbCloudInfrastructure.Services.Trajectory.Export;
using AsbCloudInfrastructure.Services.Trajectory.Parser;
using AsbCloudInfrastructure.Services.WellOperationImport;
using AsbCloudInfrastructure.Services.WellOperationImport.FileParser;
using AsbCloudInfrastructure.Services.WellOperationService;
@ -39,16 +44,7 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using AsbCloudApp.Data.DailyReport.Blocks.TimeBalance;
using AsbCloudApp.Services.DailyReport;
using AsbCloudDb.Model.DailyReports.Blocks.TimeBalance;
using AsbCloudDb.Model.WellSections;
using AsbCloudInfrastructure.Services.ProcessMaps;
using AsbCloudApp.Data.ProcessMapPlan;
using AsbCloudApp.Requests;
using AsbCloudInfrastructure.Services.Parser;
using AsbCloudInfrastructure.Services.ProcessMapPlan.Parser;
using AsbCloudInfrastructure.Services.Trajectory.Parser;
using System;
namespace AsbCloudInfrastructure
{
@ -108,48 +104,6 @@ namespace AsbCloudInfrastructure
.Ignore(dst => dst.NotificationCategory,
dst => dst.User);
TypeAdapterConfig.GlobalSettings.Default.Config
.ForType<ProcessMapWellDrilling, ProcessMapPlanWellDrillingDto>()
.Map(dest => dest.AxialLoad, src => new PlanLimitDto
{
LimitMax = src.AxialLoadLimitMax,
Plan = src.AxialLoadPlan
})
.Map(dest => dest.Flow, src => new PlanLimitDto
{
LimitMax = src.FlowLimitMax,
Plan = src.FlowPlan
})
.Map(dest => dest.Pressure, src => new PlanLimitDto
{
LimitMax = src.PressureLimitMax,
Plan = src.PressurePlan
})
.Map(dest => dest.TopDriveSpeed, src => new PlanLimitDto
{
LimitMax = src.TopDriveSpeedLimitMax,
Plan = src.TopDriveSpeedPlan
})
.Map(dest => dest.TopDriveTorque, src => new PlanLimitDto
{
LimitMax = src.TopDriveTorqueLimitMax,
Plan = src.TopDriveTorquePlan
});
TypeAdapterConfig.GlobalSettings.Default.Config
.ForType<ProcessMapPlanWellDrillingDto, ProcessMapWellDrilling>()
.Map(dest => dest.AxialLoadPlan, src => src.AxialLoad.Plan)
.Map(dest => dest.AxialLoadLimitMax, src => src.AxialLoad.LimitMax)
.Map(dest => dest.FlowPlan, src => src.Flow.Plan)
.Map(dest => dest.FlowLimitMax, src => src.Flow.LimitMax)
.Map(dest => dest.PressurePlan, src => src.Pressure.Plan)
.Map(dest => dest.PressureLimitMax, src => src.Pressure.LimitMax)
.Map(dest => dest.TopDriveSpeedPlan, src => src.TopDriveSpeed.Plan)
.Map(dest => dest.TopDriveSpeedLimitMax, src => src.TopDriveSpeed.LimitMax)
.Map(dest => dest.TopDriveTorquePlan, src => src.TopDriveTorque.Plan)
.Map(dest => dest.TopDriveTorqueLimitMax, src => src.TopDriveTorque.LimitMax);
TypeAdapterConfig.GlobalSettings.Default.Config
.ForType<TimeBalanceRecord, TimeBalanceRecordDto>()
.Map(dest => dest.DurationHours, src => new PlanFactDto<double?>()
@ -192,8 +146,6 @@ namespace AsbCloudInfrastructure
services.AddSingleton<IReduceSamplingService>(provider => ReduceSamplingService.GetInstance(configuration));
services.AddTransient<IAuthService, AuthService>();
services.AddTransient<IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto>, ProcessMapPlanRepository<ProcessMapPlanWellDrillingDto, ProcessMapWellDrilling>>();
services.AddTransient<IProcessMapPlanRepository<ProcessMapPlanWellReamDto>, ProcessMapPlanRepository<ProcessMapPlanWellReamDto, ProcessMapWellReam>>();
services.AddTransient<IDepositRepository, DepositRepository>();
services.AddTransient<IDrillingProgramService, DrillingProgramService>();
services.AddTransient<IEventService, EventService>();
@ -208,8 +160,7 @@ namespace AsbCloudInfrastructure
services.AddTransient<ITimezoneService, TimezoneService>();
services.AddScoped<IWellService, WellService>();
services.AddTransient<IWellOperationImportService, WellOperationImportService>();
services.AddTransient<IProcessMapReportWellDrillingExportService, ProcessMapReportWellDrillingExportService>();
services.AddTransient<IProcessMapReportDataSaubStatExportService, ProcessMapReportDataSaubStatExportService>();
services.AddTransient<IProcessMapReportDrillingExportService, ProcessMapReportDataSaubStatExportService>();
services.AddTransient<TrajectoryPlanExportService>();
services.AddTransient<TrajectoryFactManualExportService>();
services.AddTransient<TrajectoryFactNnbExportService>();
@ -223,8 +174,6 @@ namespace AsbCloudInfrastructure
services.AddTransient<IWellFinalDocumentsService, WellFinalDocumentsService>();
services.AddTransient<IFileCategoryService, FileCategoryService>();
services.AddTransient<ILimitingParameterService, LimitingParameterService>();
services.AddTransient<IProcessMapReportWellDrillingService, ProcessMapReportWellDrillingService>();
services.AddTransient<IProcessMapPlanImportService, ProcessMapPlanImportWellDrillingService>();
services.AddTransient<WellInfoService>();
services.AddTransient<IHelpPageService, HelpPageService>();
services.AddTransient<IScheduleReportService, ScheduleReportService>();
@ -234,7 +183,11 @@ namespace AsbCloudInfrastructure
IChangeLogRepository<ProcessMapPlanDrillingDto, ProcessMapPlanBaseRequestWithWell>,
ProcessMapPlanBaseRepository<ProcessMapPlanDrillingDto, ProcessMapPlanDrilling>>();
services.AddTransient<IProcessMapReportDataSaubStatService, ProcessMapReportDataSaubStatService>();
services.AddTransient<
IChangeLogRepository<ProcessMapPlanReamDto, ProcessMapPlanBaseRequestWithWell>,
ProcessMapPlanBaseRepository<ProcessMapPlanReamDto, ProcessMapPlanDrilling>>();
services.AddTransient<IProcessMapReportDrillingService, ProcessMapReportDrillingService>();
services.AddTransient<TrajectoryService>();
@ -333,9 +286,6 @@ namespace AsbCloudInfrastructure
services.AddTransient<IRepositoryWellRelated<WellSectionPlanDto>, CrudWellRelatedRepositoryBase<WellSectionPlanDto, WellSectionPlan>>();
services.AddTransient<IProcessMapPlanService<ProcessMapPlanWellDrillingDto>, ProcessMapPlanService<ProcessMapPlanWellDrillingDto>>();
services.AddTransient<IProcessMapPlanService<ProcessMapPlanWellReamDto>, ProcessMapPlanService<ProcessMapPlanWellReamDto>>();
services.AddTransient<IWellSectionPlanRepository, WellSectionPlanRepository>();
services.AddTransient<IWellOperationCategoryRepository, WellOperationCategoryRepository>();
services.AddTransient<IDetectedOperationRepository, DetectedOperationRepository>();
@ -343,6 +293,7 @@ namespace AsbCloudInfrastructure
services.AddTransient<TrajectoryPlanParser>();
services.AddTransient<TrajectoryFactManualParser>();
services.AddTransient<ProcessMapPlanDrillingParser>();
services.AddTransient<ProcessMapPlanReamParser>();
return services;
}

View File

@ -1,4 +1,4 @@
using AsbCloudApp.Data.ProcessMapPlan;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb.Model;

View File

@ -1,89 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudDb.Model.ProcessMaps;
using Microsoft.EntityFrameworkCore;
namespace AsbCloudInfrastructure.Repository;
public class ProcessMapPlanRepository<TDto, TEntity> : CrudWellRelatedRepositoryBase<TDto, TEntity>,
IProcessMapPlanRepository<TDto>
where TDto : ProcessMapPlanBaseDto
where TEntity : ProcessMapBase
{
private readonly IWellService wellService;
public ProcessMapPlanRepository(IAsbCloudDbContext context, IWellService wellService)
: base(context, dbSet =>
dbSet
.Include(p => p.WellSectionType)
.Include(p => p.Well))
{
this.wellService = wellService;
}
public async Task<IEnumerable<TDto>> GetAsync(IEnumerable<ProcessMapPlanRequest> requests, CancellationToken cancellationToken)
{
var query = BuildQuery(requests);
var entities = await query.ToArrayAsync(cancellationToken);
return entities.Select(Convert);
}
public Task<int> RemoveByWellAsync(int idWell)
{
var query = GetQuery().Where(x => x.IdWell == idWell);
dbSet.RemoveRange(query);
return dbContext.SaveChangesAsync(CancellationToken.None);
}
private IQueryable<TEntity> BuildQuery(IEnumerable<ProcessMapPlanRequest> requests)
{
var queries = requests
.Select(request => BuildQuery(request))
.ToArray();
var query = queries.FirstOrDefault()
?? throw new ArgumentInvalidException(nameof(requests), "Пустые запросы недопустимы");
for ( var i = 1; i < queries.Length; i++)
query = query.Union(queries[i]);
query = query
.Distinct()
.OrderBy(e => e.DepthStart)
.ThenBy(e => e.Id)
.AsNoTracking();
return query;
}
private IQueryable<TEntity> BuildQuery(ProcessMapPlanRequest request)
{
var query = GetQuery();
query = query.Where(p => p.IdWell == request.IdWell);
if (request.IdWellSectionType is not null)
query = query.Where(p => p.IdWellSectionType == request.IdWellSectionType);
if (request.UpdateFrom is not null)
{
var timezone = wellService.GetTimezone(request.IdWell);
var updateFromUtc = request.UpdateFrom?.ToUtcDateTimeOffset(timezone.Hours);
query = query.Where(p => p.LastUpdate >= updateFromUtc);
}
return query;
}
}

View File

@ -11,18 +11,19 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Repository
{
namespace AsbCloudInfrastructure.Repository;
public class WellCompositeRepository : IWellCompositeRepository
{
private readonly IAsbCloudDbContext db;
private readonly IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto> processMapPlanWellDrillingRepository;
private readonly IChangeLogRepository<ProcessMapPlanDrillingDto, ProcessMapPlanBaseRequestWithWell> processMapPlanDrillingRepository;
public WellCompositeRepository(IAsbCloudDbContext db, IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto> processMapPlanWellDrillingRepository)
public WellCompositeRepository(
IAsbCloudDbContext db,
IChangeLogRepository<ProcessMapPlanDrillingDto, ProcessMapPlanBaseRequestWithWell> processMapPlanDrillingRepository)
{
this.db = db;
this.processMapPlanWellDrillingRepository = processMapPlanWellDrillingRepository;
this.processMapPlanDrillingRepository = processMapPlanDrillingRepository;
}
/// <inheritdoc/>
@ -50,7 +51,7 @@ namespace AsbCloudInfrastructure.Repository
}
/// <inheritdoc/>
public async Task<IEnumerable<ProcessMapPlanWellDrillingDto>> GetCompositeProcessMap(int idWell, CancellationToken token)
public async Task<IEnumerable<ProcessMapPlanDrillingDto>> GetCompositeProcessMap(int idWell, CancellationToken token)
{
var dtos = await GetAsync(idWell, token);
@ -59,8 +60,8 @@ namespace AsbCloudInfrastructure.Repository
IdWellSectionType = x.IdWellSectionType
});
var result = await processMapPlanWellDrillingRepository.GetAsync(requests, token);
return result;
//var result = await processMapPlanDrillingRepository.GetAsync(requests, token);
return Enumerable.Empty<ProcessMapPlanDrillingDto>();
}
private static WellComposite Convert(int idWell, WellCompositeDto dto)
@ -76,4 +77,3 @@ namespace AsbCloudInfrastructure.Repository
}
}
}

View File

@ -29,7 +29,7 @@ public class DailyReportService : IDailyReportService
private readonly IScheduleRepository scheduleRepository;
private readonly IWellOperationRepository wellOperationRepository;
private readonly ISubsystemService subsystemService;
private readonly IProcessMapReportWellDrillingService processMapReportWellDrillingService;
private readonly IProcessMapReportDrillingService processMapReportDrillingService;
private readonly IDetectedOperationService detectedOperationService;
public DailyReportService(IWellService wellService,
@ -38,7 +38,7 @@ public class DailyReportService : IDailyReportService
IScheduleRepository scheduleRepository,
IWellOperationRepository wellOperationRepository,
ISubsystemService subsystemService,
IProcessMapReportWellDrillingService processMapReportWellDrillingService,
IProcessMapReportDrillingService processMapReportDrillingService,
IDetectedOperationService detectedOperationService)
{
this.wellService = wellService;
@ -47,7 +47,7 @@ public class DailyReportService : IDailyReportService
this.scheduleRepository = scheduleRepository;
this.wellOperationRepository = wellOperationRepository;
this.subsystemService = subsystemService;
this.processMapReportWellDrillingService = processMapReportWellDrillingService;
this.processMapReportDrillingService = processMapReportDrillingService;
this.detectedOperationService = detectedOperationService;
}
@ -375,7 +375,8 @@ public class DailyReportService : IDailyReportService
var geDate = dailyReport.Date.ToDateTime(TimeOnly.MinValue, DateTimeKind.Unspecified);
var leDate = dailyReport.Date.AddDays(1).ToDateTime(TimeOnly.MinValue, DateTimeKind.Unspecified);
dailyReport.ProcessMapWellDrillingBlock = (await processMapReportWellDrillingService.GetAsync(dailyReport.IdWell,
var request = new DataSaubStatRequest();
dailyReport.ProcessMapWellDrillingBlock = (await processMapReportDrillingService.GetAsync(dailyReport.IdWell, request,
cancellationToken)).Where(p => p.DateStart >= geDate && p.DateStart <= leDate)
.GroupBy(p => p.DrillingMode)
.Select(g => new ProcessMapWellDrillingRecordDto
@ -387,7 +388,7 @@ public class DailyReportService : IDailyReportService
Plan = g.Sum(p => p.Rop.Plan),
Fact = g.Sum(p => p.Rop.Fact)
},
MechDrillingHours = g.Sum(p => p.MechDrillingHours)
MechDrillingHours = g.Sum(p => p.DrilledTime)
});
}

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMapPlan;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Repositories;
using AsbCloudInfrastructure.Services.Parser;
using Microsoft.Extensions.DependencyInjection;

View File

@ -1,5 +1,5 @@
using System;
using AsbCloudApp.Data.ProcessMapPlan;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudInfrastructure.Services.Parser;
namespace AsbCloudInfrastructure.Services.ProcessMapPlan.Parser;

View File

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Repositories;
using AsbCloudInfrastructure.Services.Parser;
namespace AsbCloudInfrastructure.Services.ProcessMapPlan.Parser;
public class ProcessMapPlanReamParser : ProcessMapPlanParser<ProcessMapPlanReamDto>
{
private readonly IEnumerable<WellSectionTypeDto> sections;
public ProcessMapPlanReamParser(IWellOperationRepository wellOperationRepository)
{
sections = wellOperationRepository.GetSectionTypes();
}
protected override string SheetName => "План";
protected override string TemplateFileName => "ProcessMapPlanReamTemplate.xlsx";
private const int ColumnSection = 1;
private const int ColumnMode = 2;
protected override IDictionary<string, Cell> Cells => new Dictionary<string, Cell>
{
{ nameof(ProcessMapPlanReamDto.Section), new Cell(ColumnSection, typeof(string)) },
{ nameof(ProcessMapPlanReamDto.DepthStart), new Cell(2, typeof(double)) },
{ nameof(ProcessMapPlanReamDto.DepthEnd), new Cell(3, typeof(double)) },
{ nameof(ProcessMapPlanReamDto.Repeats), new Cell(4, typeof(double)) },
{ nameof(ProcessMapPlanReamDto.SpinUpward), new Cell(5, typeof(double)) },
{ nameof(ProcessMapPlanReamDto.SpinUpward), new Cell(6, typeof(double)) },
{ nameof(ProcessMapPlanReamDto.SpeedDownward), new Cell(7, typeof(double)) },
{ nameof(ProcessMapPlanReamDto.SpeedUpward), new Cell(8, typeof(double)) },
{ nameof(ProcessMapPlanReamDto.SetpointDrag), new Cell(9, typeof(double)) },
{ nameof(ProcessMapPlanReamDto.SetpointTight), new Cell(10, typeof(double)) },
{ nameof(ProcessMapPlanReamDto.Pressure), new Cell(11, typeof(double)) },
{ nameof(ProcessMapPlanReamDto.Torque), new Cell(12, typeof(double)) },
};
protected override ProcessMapPlanReamDto BuildDto(IDictionary<string, object?> row, int rowNumber)
{
var dto = base.BuildDto(row, rowNumber);
var section = sections.FirstOrDefault(s =>
string.Equals(s.Caption.Trim(), dto.Section?.Trim(), StringComparison.CurrentCultureIgnoreCase));
if (section is null)
{
var message = string.Format(XLExtentions.ProblemDetailsTemplate, SheetName, rowNumber, ColumnSection,
"Указана некорректная секция");
throw new FileFormatException(message);
}
dto.IdWellSectionType = section.Id;
return dto;
}
}

View File

@ -1,65 +0,0 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudApp.Services.ProcessMaps;
namespace AsbCloudInfrastructure.Services.ProcessMaps;
public class ProcessMapPlanService<T> : IProcessMapPlanService<T>
where T : ProcessMapPlanBaseDto
{
private readonly ICrudRepository<WellSectionTypeDto> wellSectionTypeRepository;
private readonly IProcessMapPlanRepository<T> processMapPlanRepository;
private readonly IRepositoryWellRelated<WellSectionPlanDto> wellSectionPlanRepository;
public ProcessMapPlanService(ICrudRepository<WellSectionTypeDto> wellSectionTypeRepository,
IProcessMapPlanRepository<T> processMapPlanRepository,
IRepositoryWellRelated<WellSectionPlanDto> wellSectionPlanRepository)
{
this.wellSectionTypeRepository = wellSectionTypeRepository;
this.processMapPlanRepository = processMapPlanRepository;
this.wellSectionPlanRepository = wellSectionPlanRepository;
}
public async Task<IEnumerable<ValidationResultDto<T>>> GetAsync(int idWell, CancellationToken cancellationToken)
{
var wellSectionTypes = await wellSectionTypeRepository.GetAllAsync(cancellationToken);
var processMapsPlan = await processMapPlanRepository.GetByIdWellAsync(idWell, cancellationToken);
var wellSectionsPlan = await wellSectionPlanRepository.GetByIdWellAsync(idWell, cancellationToken);
return processMapsPlan.Select(processMapPlan =>
{
var wellSectionPlan = wellSectionsPlan.FirstOrDefault(s => s.IdSectionType == processMapPlan.IdWellSectionType);
var isValid = wellSectionPlan is not null && wellSectionPlan.DepthStart <= processMapPlan.DepthStart &&
wellSectionPlan.DepthEnd >= processMapPlan.DepthEnd;
var validationResult = new ValidationResultDto<T>
{
Item = processMapPlan
};
if (isValid)
return validationResult;
var wellSectionType = wellSectionTypes.FirstOrDefault(s => s.Id == processMapPlan.IdWellSectionType);
validationResult.Warnings = new ValidationResult[]
{
new($"Конструкция секции: {wellSectionType?.Caption}; " +
$"Интервал бурения от {processMapPlan.DepthStart} до {processMapPlan.DepthEnd} не совпадает с данными указанными на странице " +
$"Конструкция скважины / План", new[] { nameof(processMapPlan.DepthStart), nameof(processMapPlan.DepthEnd) })
};
return validationResult;
});
}
}

View File

@ -12,7 +12,7 @@ using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services.ProcessMaps.Report;
public class ProcessMapReportDataSaubStatExportService : IProcessMapReportDataSaubStatExportService
public class ProcessMapReportDataSaubStatExportService : IProcessMapReportDrillingExportService
{
private const int firstColumn = 2;
private const int lastColumn = 35;
@ -21,13 +21,13 @@ public class ProcessMapReportDataSaubStatExportService : IProcessMapReportDataSa
private const string sheetName = "Отчёт";
private readonly IWellService wellService;
private readonly IProcessMapReportDataSaubStatService processMapReportDataSaubStatService;
private readonly IProcessMapReportDrillingService processMapReportDrillingService;
public ProcessMapReportDataSaubStatExportService(IWellService wellService,
IProcessMapReportDataSaubStatService processMapReportDataSaubStatService)
IProcessMapReportDrillingService processMapReportDrillingService)
{
this.wellService = wellService;
this.processMapReportDataSaubStatService = processMapReportDataSaubStatService;
this.processMapReportDrillingService = processMapReportDrillingService;
}
public async Task<(string Name, Stream File)?> ExportAsync(int idWell, DataSaubStatRequest request, CancellationToken cancellationToken)
@ -40,7 +40,7 @@ public class ProcessMapReportDataSaubStatExportService : IProcessMapReportDataSa
var stream = Assembly.GetExecutingAssembly().GetTemplateCopyStream(TemplateName);
using var workbook = new XLWorkbook(stream);
var data = await processMapReportDataSaubStatService.GetAsync(idWell, request, cancellationToken);
var data = await processMapReportDrillingService.GetAsync(idWell, request, cancellationToken);
FillProcessMapToWorkbook(workbook, data);

View File

@ -1,5 +1,5 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMapPlan;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Data.ProcessMaps.Report;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Extensions;
@ -16,7 +16,7 @@ using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services.ProcessMaps.Report;
public class ProcessMapReportDataSaubStatService : IProcessMapReportDataSaubStatService
public class ProcessMapReportDrillingService : IProcessMapReportDrillingService
{
private readonly IWellService wellService;
private readonly IChangeLogRepository<ProcessMapPlanDrillingDto, ProcessMapPlanBaseRequestWithWell> processMapPlanBaseRepository;
@ -24,7 +24,7 @@ public class ProcessMapReportDataSaubStatService : IProcessMapReportDataSaubStat
private readonly IWellOperationRepository wellOperationRepository;
private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
public ProcessMapReportDataSaubStatService(IWellService wellService,
public ProcessMapReportDrillingService(IWellService wellService,
IChangeLogRepository<ProcessMapPlanDrillingDto, ProcessMapPlanBaseRequestWithWell> processMapPlanBaseRepository,
IDataSaubStatRepository dataSaubStatRepository,
IWellOperationRepository wellOperationRepository,

View File

@ -1,195 +0,0 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data.ProcessMaps.Report;
using AsbCloudApp.Services;
using AsbCloudApp.Services.ProcessMaps.WellDrilling;
using ClosedXML.Excel;
namespace AsbCloudInfrastructure.Services.ProcessMaps.Report;
public class ProcessMapReportWellDrillingExportService : IProcessMapReportWellDrillingExportService
{
const int firstColumn = 2;
const int lastColumn = 42;
const int headerRowsCount = 5;
private readonly IWellService wellService;
private readonly IProcessMapReportWellDrillingService processMapReportWellDrillingService;
public ProcessMapReportWellDrillingExportService(IWellService wellService,
IProcessMapReportWellDrillingService processMapReportWellDrillingService)
{
this.wellService = wellService;
this.processMapReportWellDrillingService = processMapReportWellDrillingService;
}
public async Task<(string Name, Stream File)?> ExportAsync(int idWell, CancellationToken cancellationToken)
{
var well = await wellService.GetOrDefaultAsync(idWell, cancellationToken);
if (well is null)
return null;
var stream = GetExcelTemplateStream();
using var workbook = new XLWorkbook(stream);
var data = await processMapReportWellDrillingService.GetAsync(idWell, cancellationToken);
FillProcessMapToWorkbook(workbook, data);
MemoryStream memoryStream = new();
workbook.SaveAs(memoryStream, new SaveOptions { });
memoryStream.Seek(0, SeekOrigin.Begin);
var name = $"РТК бурение. Отчёт по скважине {well.Caption} куст {well.Cluster}.xlsx";
return (name, memoryStream);
}
private static void FillProcessMapToWorkbook(XLWorkbook workbook,
IEnumerable<ProcessMapReportWellDrillingDto> data)
{
const string sheetName = "Отчёт";
var sheet = workbook.GetWorksheet(sheetName);
var dataBySections = data.GroupBy(p => p.IdWellSectionType);
FillSheet(sheet, dataBySections);
}
private static void FillSheet(IXLWorksheet sheet,
IEnumerable<IGrouping<int, ProcessMapReportWellDrillingDto>> dataBySections)
{
var startRow = headerRowsCount + 1;
foreach (var sectionData in dataBySections)
{
if (sectionData.Any())
startRow = FillSection(sheet, sectionData, startRow);
}
}
private static int FillSection(IXLWorksheet sheet, IGrouping<int, ProcessMapReportWellDrillingDto> sectionData,
int row)
{
var rowStart = row;
var sectionName = sectionData.FirstOrDefault()?.WellSectionTypeName
?? sectionData.Key.ToString();
sheet.Range(row, firstColumn, row, lastColumn)
.Merge()
.FirstCell()
.SetCellValue(sectionName)
.Style
.Fill.SetBackgroundColor(XLColor.LightGray);
row++;
foreach (var interval in sectionData)
row = FillIntervalData(sheet, interval, row);
var sectionStyle = sheet.Range(rowStart, firstColumn, row - 1, lastColumn).Style;
SetBorders(sectionStyle);
return row;
}
private static int FillIntervalData(IXLWorksheet sheet, ProcessMapReportWellDrillingDto interval, int row)
{
const int columnDepth = firstColumn + 1;
const int columnDate = firstColumn + 2;
const int columnRopTime = firstColumn + 3;
const int columnMode = firstColumn + 4;
sheet.Cell(row, firstColumn).SetCellValue(interval.DepthStart);
sheet.Cell(row, columnDepth).SetCellValue(interval.DepthEnd);
sheet.Cell(row, columnDate).SetCellValue(interval.DateStart);
sheet.Cell(row, columnRopTime).SetCellValue(interval.MechDrillingHours);
row = FillIntervalModeData(sheet, interval, columnMode, row);
return row;
}
private static int FillIntervalModeData(IXLWorksheet sheet, ProcessMapReportWellDrillingDto modeData,
int column, int row)
{
int columnDeltaDepth = column + 1;
int columnPressure = columnDeltaDepth + 1;
int columnLoad = columnPressure + 5;
int columnTorque = columnLoad + 5;
int columnSpeed = columnTorque + 5;
int columnUsagePlan = columnSpeed + 5;
int columnUsageFact = columnUsagePlan + 1;
int columnRop = columnUsageFact + 12;
sheet.Cell(row, column).SetCellValue(modeData.DrillingMode);
sheet.Cell(row, columnDeltaDepth).SetCellValue(modeData.DeltaDepth);
FillIntervalModeDataParam(sheet, modeData.PressureDiff, columnPressure, row);
FillIntervalModeDataParam(sheet, modeData.AxialLoad, columnLoad, row);
FillIntervalModeDataParam(sheet, modeData.TopDriveTorque, columnTorque, row);
FillIntervalModeDataSpeed(sheet, modeData.SpeedLimit, columnSpeed, row);
sheet.Cell(row, columnUsagePlan).SetCellValue(modeData.UsagePlan);
sheet.Cell(row, columnUsageFact).SetCellValue(modeData.UsageFact);
sheet.Cell(row, columnRop).SetCellValue(modeData.Rop.Fact);
return row + 1;
}
private static void FillIntervalModeDataParam(IXLWorksheet sheet,
ProcessMapReportWellDrillingParamsDto dataParam, int column, int row)
{
const int columnOffsetSpPlan = 0;
const int columnOffsetSpFact = 1;
const int columnOffsetFact = 2;
const int columnOffsetLimit = 3;
const int columnOffsetPercent = 4;
sheet.Cell(row, column + columnOffsetSpPlan).SetCellValue(dataParam.SetpointPlan);
sheet.Cell(row, column + columnOffsetSpFact).SetCellValue(dataParam.SetpointFact);
sheet.Cell(row, column + columnOffsetFact).SetCellValue(dataParam.Fact);
sheet.Cell(row, column + columnOffsetLimit).SetCellValue(dataParam.Limit);
sheet.Cell(row, column + columnOffsetPercent).SetCellValue(dataParam.SetpointUsage);
}
private static void FillIntervalModeDataSpeed(IXLWorksheet sheet,
ProcessMapReportWellDrillingParamsDto dataParam, int column, int row)
{
const int columnOffsetSpPlan = 0;
const int columnOffsetSpFact = 1;
const int columnOffsetFact = 2;
const int columnOffsetLimit = 3;
const int columnOffsetPercent = 4;
sheet.Cell(row, column + columnOffsetSpPlan).SetCellValue(dataParam.SetpointPlan);
sheet.Cell(row, column + columnOffsetSpFact).SetCellValue(dataParam.SetpointFact);
sheet.Cell(row, column + columnOffsetFact).SetCellValue(dataParam.Fact);
sheet.Cell(row, column + columnOffsetLimit).SetCellValue(dataParam.Limit);
sheet.Cell(row, column + columnOffsetPercent).SetCellValue(dataParam.SetpointUsage);
}
//TODO: использовать метод расширения, избавиться от этого метода
private static Stream GetExcelTemplateStream()
{
var stream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream(
"AsbCloudInfrastructure.Services.ProcessMaps.Report.ProcessMapReportTemplate.xlsx");
return stream!;
}
//TODO: нужен ли этот метод? Это можно настроить в шаблоне
private static void SetBorders(IXLStyle style)
{
style.Border.RightBorder = XLBorderStyleValues.Thin;
style.Border.LeftBorder = XLBorderStyleValues.Thin;
style.Border.TopBorder = XLBorderStyleValues.Thin;
style.Border.BottomBorder = XLBorderStyleValues.Thin;
style.Border.InsideBorder = XLBorderStyleValues.Thin;
}
}

View File

@ -1,235 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Data.ProcessMaps.Report;
using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudApp.Services.ProcessMaps.WellDrilling;
using AsbCloudInfrastructure.Services.ProcessMaps.Report.Data;
namespace AsbCloudInfrastructure.Services.ProcessMaps.Report;
public class ProcessMapReportWellDrillingService : IProcessMapReportWellDrillingService
{
private readonly IWellService wellService;
private readonly IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto> processMapPlanWellDrillingRepository;
private readonly ITelemetryDataSaubService telemetryDataSaubService;
private readonly IWellOperationRepository wellOperationRepository;
public ProcessMapReportWellDrillingService(IWellService wellService,
IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto> processMapPlanWellDrillingRepository,
ITelemetryDataSaubService telemetryDataSaubService,
IWellOperationRepository wellOperationRepository)
{
this.wellService = wellService;
this.processMapPlanWellDrillingRepository = processMapPlanWellDrillingRepository;
this.telemetryDataSaubService = telemetryDataSaubService;
this.wellOperationRepository = wellOperationRepository;
}
public async Task<IEnumerable<ProcessMapReportWellDrillingDto>> GetAsync(int idWell,
CancellationToken token)
{
var well = await wellService.GetOrDefaultAsync(idWell, token)
?? throw new ArgumentInvalidException(nameof(idWell), $"Скважина с Id: {idWell} не найдена");
if (!well.IdTelemetry.HasValue)
return Enumerable.Empty<ProcessMapReportWellDrillingDto>();
var processMapPlanWellDrillings = await processMapPlanWellDrillingRepository.GetByIdWellAsync(idWell, token);
if (!processMapPlanWellDrillings.Any())
return Enumerable.Empty<ProcessMapReportWellDrillingDto>();
var telemetryDataStat =
(await telemetryDataSaubService.GetTelemetryDataStatAsync(well.IdTelemetry.Value, token)).ToArray();
if (!telemetryDataStat.Any())
return Enumerable.Empty<ProcessMapReportWellDrillingDto>();
var result = CalcByIntervals(processMapPlanWellDrillings, telemetryDataStat);
return result;
}
private IEnumerable<ProcessMapReportWellDrillingDto> CalcByIntervals(
IEnumerable<ProcessMapPlanWellDrillingDto> processMapPlanWellDrillings,
TelemetryDataSaubStatDto[] telemetryDataStat)
{
var processMapIntervals = CalcDepthIntervals(processMapPlanWellDrillings);
var result = new List<ProcessMapReportWellDrillingDto>(processMapIntervals.Count() * 4);
var telemetryIndexStart =
Array.FindIndex(telemetryDataStat, t => t.WellDepthMin >= processMapIntervals.First().DepthStart);
if (telemetryIndexStart < 0)
return Enumerable.Empty<ProcessMapReportWellDrillingDto>();
IDictionary<int, string> sectionTypes = wellOperationRepository
.GetSectionTypes()
.ToDictionary(s => s.Id, s => s.Caption);
foreach (var interval in processMapIntervals)
{
var processMapPlanWellDrillingInterval = processMapPlanWellDrillings
.Where(p => p.DepthStart <= interval.DepthEnd && p.DepthEnd >= interval.DepthStart);
if (!processMapPlanWellDrillingInterval.Any())
continue;
var telemetryIndexEnd = Array.FindIndex(telemetryDataStat, telemetryIndexStart,
t => t.WellDepthMin >= interval.DepthEnd);
if (telemetryIndexEnd < 0)
telemetryIndexEnd = telemetryDataStat.Length - 1;
var telemetryDataInterval =
telemetryDataStat.AsSpan(telemetryIndexStart, telemetryIndexEnd - telemetryIndexStart);
IEnumerable<ProcessMapReportWellDrillingDto> subIntervalsResult =
CalcSubIntervals(interval, processMapPlanWellDrillingInterval, telemetryDataInterval, sectionTypes);
result.AddRange(subIntervalsResult);
telemetryIndexStart = telemetryIndexEnd;
}
return result;
}
private static IEnumerable<(double DepthStart, double DepthEnd)> CalcDepthIntervals(
IEnumerable<ProcessMapPlanWellDrillingDto> processMapPlanWellDrillings)
{
if (!processMapPlanWellDrillings.Any())
yield break;
var intervalStarts = processMapPlanWellDrillings
.OrderBy(i => i.DepthStart)
.Select(p => p.DepthStart)
.Distinct()
.ToArray();
for (var i = 1; i < intervalStarts.Length; i++)
yield return (intervalStarts[i - 1], intervalStarts[i]);
yield return (intervalStarts[^1], processMapPlanWellDrillings.Max(p => p.DepthEnd));
}
private static IEnumerable<ProcessMapReportWellDrillingDto> CalcSubIntervals(
(double DepthStart, double DepthEnd) interval,
IEnumerable<ProcessMapPlanWellDrillingDto> processMapPlanWellDrillingInterval,
Span<TelemetryDataSaubStatDto> telemetryDataInterval,
IDictionary<int, string> sectionTypes)
{
var telemetryDataIntervalLength = telemetryDataInterval.Length;
if (telemetryDataInterval.Length == 0)
return Enumerable.Empty<ProcessMapReportWellDrillingDto>();
var result = new List<ProcessMapReportWellDrillingDto>();
var telemetryIndexStart = 0;
var subInterval = interval;
for (var i = telemetryIndexStart + 1; i < telemetryDataIntervalLength; i++)
{
if (IsDifferent(telemetryDataInterval[telemetryIndexStart], telemetryDataInterval[i]))
{
subInterval.DepthEnd = telemetryDataInterval[i - 1].WellDepthMax;
var telemetryRowSpan = telemetryDataInterval[telemetryIndexStart..(i - 1)];
if (!telemetryRowSpan.IsEmpty)
{
var intervalReportRow = CalcSubIntervalReportRow(subInterval, processMapPlanWellDrillingInterval,
telemetryRowSpan, sectionTypes);
result.Add(intervalReportRow);
}
telemetryIndexStart = i;
subInterval.DepthStart = subInterval.DepthEnd;
}
}
subInterval.DepthEnd = interval.DepthEnd;
var intervalReportRowLast = CalcSubIntervalReportRow(subInterval, processMapPlanWellDrillingInterval,
telemetryDataInterval[telemetryIndexStart..telemetryDataIntervalLength], sectionTypes);
result.Add(intervalReportRowLast);
return result;
}
private static ProcessMapReportWellDrillingDto CalcSubIntervalReportRow(
(double DepthStart, double DepthEnd) subInterval,
IEnumerable<ProcessMapPlanWellDrillingDto> processMapPlanWellDrillings,
Span<TelemetryDataSaubStatDto> telemetryRowSpan,
IDictionary<int, string> sectionTypes)
{
var telemetryStat = new TelemetryStat(telemetryRowSpan);
var processMapByMode = processMapPlanWellDrillings.FirstOrDefault(p => p.IdMode == telemetryStat.IdMode);
var processMapFirst = processMapPlanWellDrillings.First();
var idWellSectionType = processMapByMode?.IdWellSectionType ?? processMapFirst.IdWellSectionType;
var result = new ProcessMapReportWellDrillingDto
{
IdWell = processMapByMode?.IdWell ?? processMapFirst.IdWell,
IdWellSectionType = idWellSectionType,
WellSectionTypeName = sectionTypes[idWellSectionType],
DepthStart = subInterval.DepthStart,
DepthEnd = subInterval.DepthEnd,
DateStart = telemetryStat.DateStart,
MechDrillingHours = telemetryStat.DrillingHours,
DrillingMode = telemetryStat.ModeName,
DeltaDepth = telemetryStat.DeltaDepth,
PressureDiff = telemetryStat.Pressure.MakeParams(processMapByMode?.Pressure.Plan),
AxialLoad = telemetryStat.AxialLoad.MakeParams(processMapByMode?.AxialLoad.Plan),
TopDriveTorque = telemetryStat.RotorTorque.MakeParams(processMapByMode?.TopDriveTorque.Plan),
SpeedLimit = telemetryStat.BlockSpeed.MakeParams(processMapByMode?.RopPlan),
Rop = new PlanFactDto<double?>
{
Plan = processMapByMode?.RopPlan,
Fact = telemetryStat.Rop
},
UsagePlan = processMapByMode?.UsageSaub ?? telemetryStat.UsagePredictPlan,
UsageFact = telemetryStat.UsageSaub,
};
return result;
}
private static bool IsDifferent(TelemetryDataSaubStatDto intervalStart, TelemetryDataSaubStatDto current)
{
if (intervalStart.WellDepthMin > current.WellDepthMin)
return true;
if (intervalStart.IdMode != current.IdMode)
return true;
if (Math.Abs(intervalStart.PressureSp - current.PressureSp) > 5d)
return true;
if (Math.Abs(intervalStart.AxialLoadSp - current.AxialLoadSp) > 1d)
return true;
if (Math.Abs(intervalStart.RotorTorqueSp - current.RotorTorqueSp) > 5d)
return true;
var blockSpeedSpDiff = Math.Abs(intervalStart.BlockSpeedSp - current.BlockSpeedSp);
if (!(blockSpeedSpDiff > 5d))
return false;
switch (intervalStart.BlockSpeedSp)
{
case <= 30:
case > 30 when blockSpeedSpDiff > 15d:
case > 80 when blockSpeedSpDiff > 20d:
return true;
}
return false;
}
}

View File

@ -1,368 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudApp.Services.ProcessMaps;
using ClosedXML.Excel;
namespace AsbCloudInfrastructure.Services.ProcessMaps.WellDrilling;
/*
* password for ProcessMapImportTemplate.xlsx is ASB2020!
*/
[Obsolete]
public class ProcessMapPlanImportWellDrillingService : IProcessMapPlanImportService
{
private readonly IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto> processMapPlanWellDrillingRepository;
private readonly ICrudRepository<WellSectionTypeDto> wellSectionTypeRepository;
private readonly IWellService wellService;
private const string sheetNamePlan = "План";
private const int headerRowsCount = 2;
private const int columnSection = 1;
private const int columnMode = 2;
private const int columnDepthStart = 3;
private const int columnDepthEnd = 4;
private const int columnPressurePlan = 5;
private const int columnPressureLimitMax = 6;
private const int columnAxialLoadPlan = 7;
private const int columnAxialLoadLimitMax = 8;
private const int columnTopDriveTorquePlan = 9;
private const int columnTopDriveTorqueLimitMax = 10;
private const int columnTopDriveSpeedPlan = 11;
private const int columnTopDriveSpeedLimitMax = 12;
private const int columnFlowPlan = 13;
private const int columnFlowLimitMax = 14;
private const int columnRopPlan = 15;
private const int columnUsageSaub = 16;
private const int columnUsageSpin = 17;
private const int columnComment = 18;
private WellSectionTypeDto[] sections = null!;
public ProcessMapPlanImportWellDrillingService(IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto> processMapPlanWellDrillingRepository,
ICrudRepository<WellSectionTypeDto> wellSectionTypeRepository,
IWellService wellService)
{
this.processMapPlanWellDrillingRepository = processMapPlanWellDrillingRepository;
this.wellSectionTypeRepository = wellSectionTypeRepository;
this.wellService = wellService;
}
public async Task ImportAsync(int idWell, int idUser, bool deleteProcessMapPlansBeforeImport, Stream stream,
CancellationToken cancellationToken)
{
sections = (await wellSectionTypeRepository.GetAllAsync(cancellationToken)).ToArray();
using var workBook = new XLWorkbook(stream);
var wellDrillingProcessMaps = ParseWorkBook(workBook);
if (deleteProcessMapPlansBeforeImport)
await processMapPlanWellDrillingRepository.RemoveByWellAsync(idWell);
foreach (var wellDrillingProcessMap in wellDrillingProcessMaps)
{
wellDrillingProcessMap.IdWell = idWell;
wellDrillingProcessMap.IdUser = idUser;
}
await processMapPlanWellDrillingRepository.InsertRangeAsync(wellDrillingProcessMaps, cancellationToken);
}
public async Task<(string Name, Stream File)> ExportAsync(int idWell, CancellationToken cancellationToken)
{
var well = await wellService.GetOrDefaultAsync(idWell, cancellationToken)
?? throw new ArgumentInvalidException(nameof(idWell), $"Скважины с {idWell} не существует");
sections = (await wellSectionTypeRepository.GetAllAsync(cancellationToken)).ToArray();
var processMapPlans = (await processMapPlanWellDrillingRepository.GetByIdWellAsync(idWell,
cancellationToken)).ToArray();
var file = await GenerateExcelFileStreamAsync(processMapPlans, cancellationToken);
var fileName = $"РТК-план бурение по скважине {well.Caption} куст {well.Cluster}.xlsx";
return (fileName, file);
}
public async Task<(string Name, Stream File)> GetExcelTemplateStreamAsync(CancellationToken cancellationToken)
{
var resourceName = Assembly.GetExecutingAssembly()
.GetManifestResourceNames()
.FirstOrDefault(n => n.EndsWith("ProcessMapPlanImportWellDrillingTemplate.xlsx"))!;
using var stream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream(resourceName)!;
var memoryStream = new MemoryStream();
await stream.CopyToAsync(memoryStream, cancellationToken);
memoryStream.Position = 0;
var name = "ЕЦП_шаблон_файла_РТК_бурение.xlsx";
return (name, memoryStream);
}
private void AddToWorkbook(XLWorkbook workbook, IEnumerable<ProcessMapPlanWellDrillingDto> processMapPlanWellDrillings)
{
var sheet = workbook.GetWorksheet(sheetNamePlan);
AddToSheet(sheet, processMapPlanWellDrillings.ToArray());
}
private void AddToSheet(IXLWorksheet sheet, IList<ProcessMapPlanWellDrillingDto> processMapPlanWellDrillings)
{
if (!processMapPlanWellDrillings.Any())
return;
for (int i = 0; i < processMapPlanWellDrillings.Count; i++)
{
var row = sheet.Row(1 + i + headerRowsCount);
AddToRow(row, processMapPlanWellDrillings[i]);
}
}
private void AddToRow(IXLRow row, ProcessMapPlanWellDrillingDto processMapPlanWellDrillings)
{
var section = sections.First(x => x.Id == processMapPlanWellDrillings.IdWellSectionType).Caption;
var modeCaption = GetModeCaption(processMapPlanWellDrillings.IdMode);
row.Cell(columnSection).SetCellValue(section);
row.Cell(columnMode).SetCellValue(modeCaption);
row.Cell(columnDepthStart).SetCellValue(processMapPlanWellDrillings.DepthStart);
row.Cell(columnDepthEnd).SetCellValue(processMapPlanWellDrillings.DepthEnd);
row.Cell(columnPressurePlan).SetCellValue(processMapPlanWellDrillings.Pressure.Plan);
row.Cell(columnPressureLimitMax).SetCellValue(processMapPlanWellDrillings.Pressure.LimitMax);
row.Cell(columnAxialLoadPlan).SetCellValue(processMapPlanWellDrillings.AxialLoad.Plan);
row.Cell(columnAxialLoadLimitMax).SetCellValue(processMapPlanWellDrillings.AxialLoad.LimitMax);
row.Cell(columnTopDriveTorquePlan).SetCellValue(processMapPlanWellDrillings.TopDriveTorque.Plan);
row.Cell(columnTopDriveTorqueLimitMax).SetCellValue(processMapPlanWellDrillings.TopDriveTorque.LimitMax);
row.Cell(columnTopDriveSpeedPlan).SetCellValue(processMapPlanWellDrillings.TopDriveSpeed.Plan);
row.Cell(columnTopDriveSpeedLimitMax).SetCellValue(processMapPlanWellDrillings.TopDriveSpeed.LimitMax);
row.Cell(columnFlowPlan).SetCellValue(processMapPlanWellDrillings.Flow.Plan);
row.Cell(columnFlowLimitMax).SetCellValue(processMapPlanWellDrillings.Flow.LimitMax);
row.Cell(columnRopPlan).SetCellValue(processMapPlanWellDrillings.RopPlan);
row.Cell(columnUsageSaub).SetCellValue(processMapPlanWellDrillings.UsageSaub);
row.Cell(columnUsageSpin).SetCellValue(processMapPlanWellDrillings.UsageSpin);
row.Cell(columnComment).SetCellValue(processMapPlanWellDrillings.Comment);
}
private IEnumerable<ProcessMapPlanWellDrillingDto> ParseWorkBook(IXLWorkbook workbook)
{
var sheet = workbook.GetWorksheet(sheetNamePlan);
return ParseSheet(sheet);
}
private IEnumerable<ProcessMapPlanWellDrillingDto> ParseSheet(IXLWorksheet sheet)
{
const int columnsCount = 17;
if (sheet.RangeUsed().RangeAddress.LastAddress.ColumnNumber < columnsCount)
throw new FileFormatException($"Лист {sheet.Name} содержит меньшее количество столбцов.");
var rowsCount = sheet.RowsUsed().Count() - headerRowsCount;
if (rowsCount <= 0)
return Array.Empty<ProcessMapPlanWellDrillingDto>();
var processMapPlans = new ProcessMapPlanWellDrillingDto[rowsCount];
var parseErrors = new List<string>();
for (int i = 0; i < processMapPlans.Length; i++)
{
var row = sheet.Row(1 + i + headerRowsCount);
try
{
processMapPlans[i] = ParseRow(row);
}
catch (FileFormatException ex)
{
parseErrors.Add(ex.Message);
}
}
if (parseErrors.Any())
throw new FileFormatException(string.Join("\r\n", parseErrors));
return processMapPlans;
}
private ProcessMapPlanWellDrillingDto ParseRow(IXLRow row)
{
var wellSectionTypeCaption = row.Cell(columnSection).GetCellValue<string>()?.Trim().ToLower();
var modeName = row.Cell(columnMode).GetCellValue<string>()?.Trim().ToLower();
var depthStart = row.Cell(columnDepthStart).GetCellValue<double>();
var depthEnd = row.Cell(columnDepthEnd).GetCellValue<double>();
var pressurePlan = row.Cell(columnPressurePlan).GetCellValue<double>();
var pressureLimitMax = row.Cell(columnPressureLimitMax).GetCellValue<double>();
var axialLoadPlan = row.Cell(columnAxialLoadPlan).GetCellValue<double>();
var axialLoadLimitMax = row.Cell(columnAxialLoadLimitMax).GetCellValue<double>();
var topDriveTorquePlan = row.Cell(columnTopDriveTorquePlan).GetCellValue<double>();
var topDriveTorqueLimitMax = row.Cell(columnTopDriveTorqueLimitMax).GetCellValue<double>();
var topDriveSpeedPlan = row.Cell(columnTopDriveSpeedPlan).GetCellValue<double>();
var topDriveSpeedLimitMax = row.Cell(columnTopDriveSpeedLimitMax).GetCellValue<double>();
var flowPlan = row.Cell(columnFlowPlan).GetCellValue<double>();
var flowLimitMax = row.Cell(columnFlowLimitMax).GetCellValue<double>();
var ropPlan = row.Cell(columnRopPlan).GetCellValue<double>();
var usageSaub = row.Cell(columnUsageSaub).GetCellValue<double>();
var usageSpin = row.Cell(columnUsageSpin).GetCellValue<double>();
var comment = row.Cell(columnComment).GetCellValue<string?>();
var wellSection = sections.FirstOrDefault(s => s.Caption.Trim().ToLower() == wellSectionTypeCaption)
?? throw new FileFormatException(
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указана некорректная секция");
if(string.IsNullOrEmpty(modeName))
throw new FileFormatException(
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} не указан режим");
var idMode = GetIdMode(modeName)
?? throw new FileFormatException(
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указан некорректный режим");
if (depthStart is < 0 or > 99999.9)
throw new FileFormatException(
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указана некорректная стартовая глубина");
if (depthEnd is < 0 or > 99999.9)
throw new FileFormatException(
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указана некорректная конечная глубина");
if (pressurePlan is < 0 or > 50000)
throw new FileFormatException(
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указано некорректное плановое значение перепада давления");
if (pressureLimitMax is < 0 or > 50000)
throw new FileFormatException(
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указано некорректное ограничение перепада давления");
if (axialLoadPlan is < 0 or > 50000)
throw new FileFormatException(
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указано некорректное плановое значение нагрузки");
if (axialLoadLimitMax is < 0 or > 50000)
throw new FileFormatException(
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указано некорректное ограничение нагрузки");
if (topDriveTorquePlan is < 0 or > 50000)
throw new FileFormatException(
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указано некорректное плановое значение момента на ВСП");
if (topDriveTorqueLimitMax is < 0 or > 50000)
throw new FileFormatException(
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указано некорректное ограничение момента на ВСП");
if (topDriveSpeedPlan is < 0 or > 50000)
throw new FileFormatException(
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указано некорректное плановое значение оборотов на ВСП");
if (topDriveSpeedLimitMax is < 0 or > 50000)
throw new FileFormatException(
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указано некорректное ограничения оборота на ВСП");
if (flowPlan is < 0 or > 50000)
throw new FileFormatException(
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указано некорректное плановое значение расхода");
if (flowLimitMax is < 0 or > 50000)
throw new FileFormatException(
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указано некорректное ограничение расхода");
if (ropPlan is < 0 or > 99999.9)
throw new FileFormatException(
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указано некорректное плановое значение механической скорости");
if (usageSaub is < 0 or > 100)
throw new FileFormatException(
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указан некорректный плановый процент использования АКБ");
if (usageSpin is < 0 or > 100)
throw new FileFormatException(
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указан некорректные плановый процент использования spin master");
return new()
{
IdWellSectionType = wellSection.Id,
IdMode = idMode,
DepthStart = depthStart,
LastUpdate = DateTime.UtcNow,
DepthEnd = depthEnd,
Pressure = new()
{
Plan = pressurePlan,
LimitMax = pressureLimitMax
},
AxialLoad = new()
{
Plan = axialLoadPlan,
LimitMax = axialLoadLimitMax
},
TopDriveTorque = new()
{
Plan = topDriveTorquePlan,
LimitMax = topDriveTorqueLimitMax
},
TopDriveSpeed = new()
{
Plan = topDriveSpeedPlan,
LimitMax = topDriveSpeedLimitMax
},
Flow = new()
{
Plan = flowPlan,
LimitMax = flowLimitMax
},
RopPlan = ropPlan,
UsageSaub = usageSaub,
UsageSpin = usageSpin,
Comment = comment
};
}
private async Task<Stream> GenerateExcelFileStreamAsync(ProcessMapPlanWellDrillingDto[] processMapPlanWellDrillings,
CancellationToken cancellationToken)
{
using var excelTemplateStream = (await GetExcelTemplateStreamAsync(cancellationToken)).File;
using var workbook = new XLWorkbook(excelTemplateStream);
AddToWorkbook(workbook, processMapPlanWellDrillings);
MemoryStream memoryStream = new();
workbook.SaveAs(memoryStream, new SaveOptions { });
memoryStream.Seek(0, SeekOrigin.Begin);
return memoryStream;
}
private static int? GetIdMode(string modeName) =>
modeName switch
{
"ручной" => 0,
"ротор" => 1,
"слайд" => 2,
_ => null
};
private static string GetModeCaption(int idMode)
=> idMode switch
{
1 => "Ротор",
2 => "Слайд",
_ => "Ручной",
};
}

View File

@ -204,7 +204,7 @@ public class ReportService : IReportService
public async Task<int> DeleteAllOldReportsAsync(TimeSpan lifetime, CancellationToken token)
{
var lifeTimeStartDate = DateTime.UtcNow.Date - lifetime;
var lifeTimeStartDate = DateTimeOffset.UtcNow.Date - lifetime;
var fileIds = await db.ReportProperties
.Where(r => r.File.UploadDate.Date < lifeTimeStartDate)
.Select(r => r.IdFile)

View File

@ -1,6 +1,9 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Data.WITS;
using AsbCloudApp.IntegrationEvents;
using AsbCloudApp.IntegrationEvents.Interfaces;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
@ -12,9 +15,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.IntegrationEvents;
using AsbCloudApp.IntegrationEvents.Interfaces;
namespace AsbCloudInfrastructure.Services;
@ -32,7 +32,7 @@ public class WellInfoService
{
var wellService = services.GetRequiredService<IWellService>();
var operationsStatService = services.GetRequiredService<IOperationsStatService>();
var processMapPlanWellDrillingRepository = services.GetRequiredService<IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto>>();
var processMapPlanWellDrillingRepository = services.GetRequiredService<IChangeLogRepository<ProcessMapPlanDrillingDto, ProcessMapPlanBaseRequestWithWell>>();
var subsystemService = services.GetRequiredService<ISubsystemService>();
var telemetryDataSaubCache = services.GetRequiredService<ITelemetryDataCache<TelemetryDataSaubDto>>();
var messageHub = services.GetRequiredService<IIntegrationEventHandler<UpdateWellInfoEvent>>();
@ -42,8 +42,13 @@ public class WellInfoService
var wellsIds = activeWells.Select(w => w.Id);
var processMapPlanWellDrillingRequests = wellsIds.Select(id => new ProcessMapPlanRequest { IdWell = id });
var processMapPlanWellDrillings = await processMapPlanWellDrillingRepository.GetAsync(processMapPlanWellDrillingRequests, token);
var processMapPlanWellDrillingRequests = wellsIds.Select(id => new ProcessMapPlanBaseRequestWithWell(id));
var processMapPlanWellDrillings = new List<ProcessMapPlanDrillingDto>();
foreach (var processMapPlanWellDrillingRequest in processMapPlanWellDrillingRequests)
{
var processMaps = await processMapPlanWellDrillingRepository.Get(processMapPlanWellDrillingRequest, token);
processMapPlanWellDrillings.AddRange(processMaps);
}
var wellDepthByProcessMap = processMapPlanWellDrillings
.GroupBy(p => p.IdWell)
@ -61,7 +66,8 @@ public class WellInfoService
var count = activeWells.Count();
var i = 0d;
WellMapInfo = activeWells.Select(well => {
WellMapInfo = activeWells.Select(well =>
{
var wellMapInfo = well.Adapt<WellMapInfoWithComanies>();
wellMapInfo.IdState = well.IdState;
onProgressCallback($"Start updating info by well({well.Id}): {well.Caption}", i++ / count);
@ -88,7 +94,7 @@ public class WellInfoService
.OrderBy(p => p.DepthEnd);
int? idSection = wellLastFactSection?.Id;
ProcessMapPlanWellDrillingDto? processMapPlanWellDrilling = null;
ProcessMapPlanDrillingDto? processMapPlanWellDrilling = null;
if (idSection.HasValue)
{
@ -112,25 +118,25 @@ public class WellInfoService
wellMapInfo.AxialLoad = new()
{
Plan = processMapPlanWellDrilling?.AxialLoad.Plan,
Plan = processMapPlanWellDrilling?.AxialLoadPlan,
Fact = lastSaubTelemetry?.AxialLoad
};
wellMapInfo.TopDriveSpeed = new()
{
Plan = processMapPlanWellDrilling?.TopDriveSpeed.Plan,
Plan = processMapPlanWellDrilling?.TopDriveSpeedPlan,
Fact = lastSaubTelemetry?.RotorSpeed
};
wellMapInfo.TopDriveTorque = new()
{
Plan = processMapPlanWellDrilling?.TopDriveTorque.Plan,
Plan = processMapPlanWellDrilling?.TopDriveTorquePlan,
Fact = lastSaubTelemetry?.RotorTorque
};
wellMapInfo.Pressure = new()
{
Plan = processMapPlanWellDrilling?.Pressure.Plan,
Plan = processMapPlanWellDrilling?.DeltaPressurePlan,
Fact = lastSaubTelemetry?.Pressure
};

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<UserSecretsId>af52bb94-3f08-4d6a-8895-8cfb7691c393</UserSecretsId>

View File

@ -1,5 +1,5 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMapPlan;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Requests;
using Refit;

View File

@ -1,5 +1,4 @@
using AsbCloudApp.Data.ProcessMapPlan;
using AsbCloudApp.Requests;
using AsbCloudApp.Requests;
using AsbCloudDb.Model.ProcessMapPlan;
using AsbCloudWebApi.IntegrationTests.Clients;
using Mapster;
@ -10,6 +9,7 @@ using AsbCloudDb.Model.ProcessMaps;
using AsbCloudWebApi.IntegrationTests.Data;
using Refit;
using Xunit;
using AsbCloudApp.Data.ProcessMaps;
namespace AsbCloudWebApi.IntegrationTests.Controllers.ProcessMapPlan;

View File

@ -1,10 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
<Nullable>enable</Nullable>
</PropertyGroup>

View File

@ -1,8 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Data.DailyReport;
using AsbCloudApp.Data.DailyReport.Blocks.Sign;
@ -19,6 +14,11 @@ using AsbCloudApp.Services;
using AsbCloudApp.Services.ProcessMaps.WellDrilling;
using AsbCloudInfrastructure.Services.DailyReport;
using NSubstitute;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace AsbCloudWebApi.Tests.Services;
@ -110,7 +110,7 @@ public class DailyReportServiceTest
}
};
private readonly ProcessMapReportWellDrillingDto fakeProcessMapReportWellDrilling = new()
private readonly ProcessMapReportDataSaubStatDto fakeProcessMapReportWellDrilling = new()
{
DrillingMode = "Ротор",
DateStart = new DateTime(2023, 10, 26),
@ -120,7 +120,7 @@ public class DailyReportServiceTest
Plan = 300,
Fact = 500
},
MechDrillingHours = 100
DrilledTime = 100
};
private readonly WellSectionTypeDto fakeSectionType = new()
@ -207,7 +207,7 @@ public class DailyReportServiceTest
private readonly IScheduleRepository scheduleRepositoryMock = Substitute.For<IScheduleRepository>();
private readonly IWellOperationRepository wellOperationRepositoryMock = Substitute.For<IWellOperationRepository>();
private readonly ISubsystemService subsystemServiceMock = Substitute.For<ISubsystemService>();
private readonly IProcessMapReportWellDrillingService processMapReportWellDrillingServiceMock = Substitute.For<IProcessMapReportWellDrillingService>();
private readonly IProcessMapReportDrillingService processMapReportWellDrillingServiceMock = Substitute.For<IProcessMapReportDrillingService>();
private readonly IDetectedOperationService detectedOperationServiceMock = Substitute.For<IDetectedOperationService>();
private readonly DailyReportService dailyReportService;
@ -215,6 +215,7 @@ public class DailyReportServiceTest
private readonly DailyReportDto fakeDailyReport;
private readonly WellDto fakeWell;
private readonly DatesRangeDto fakeDatesRange;
private readonly DataSaubStatRequest fakeRequest = new DataSaubStatRequest();
public DailyReportServiceTest()
{
@ -284,7 +285,7 @@ public class DailyReportServiceTest
scheduleRepositoryMock.GetAsync(Arg.Any<int>(), Arg.Any<DateTime>(), Arg.Any<CancellationToken>())
.ReturnsForAnyArgs(new[] { fakeShedule });
processMapReportWellDrillingServiceMock.GetAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
processMapReportWellDrillingServiceMock.GetAsync(Arg.Any<int>(), fakeRequest, Arg.Any<CancellationToken>())
.ReturnsForAnyArgs(new[] { fakeProcessMapReportWellDrilling });
wellServiceMock.GetTimezone(Arg.Any<int>())
@ -461,7 +462,7 @@ public class DailyReportServiceTest
Assert.Equal(fakeProcessMapReportWellDrilling.Rop.Plan, processMapWellDrillingRecord.Rop.Plan);
Assert.Equal(fakeProcessMapReportWellDrilling.Rop.Fact, processMapWellDrillingRecord.Rop.Fact);
Assert.Equal(fakeProcessMapReportWellDrilling.DeltaDepth, processMapWellDrillingRecord.WellBoreDepth);
Assert.Equal(fakeProcessMapReportWellDrilling.MechDrillingHours, processMapWellDrillingRecord.MechDrillingHours);
Assert.Equal(fakeProcessMapReportWellDrilling.DrilledTime, processMapWellDrillingRecord.MechDrillingHours);
}
[Fact]

View File

@ -1,94 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudInfrastructure.Services.ProcessMaps;
using NSubstitute;
using Xunit;
namespace AsbCloudWebApi.Tests.Services.ProcessMaps;
public class ProcessMapPlanServiceTests
{
private const int idWellSectionPlan = 1;
private const int idWell = 3;
private const int idWellSectionType = 54;
private readonly IEnumerable<WellSectionPlanDto> fakeCollectionWellSectionPlan = new WellSectionPlanDto[]
{
new()
{
Id = idWellSectionPlan,
IdWell = idWell,
IdSectionType = idWellSectionType,
DepthStart = 80,
DepthEnd = 150
}
};
private readonly IEnumerable<WellSectionTypeDto> fakeCollectionWellSectionTypes = new WellSectionTypeDto[]
{
new()
{
Id = idWellSectionType,
Caption = "Направление 1",
Order = 1
}
};
private readonly ICrudRepository<WellSectionTypeDto> wellSectionTypeRepositoryMock =
Substitute.For<ICrudRepository<WellSectionTypeDto>>();
private readonly IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto> processMapPlanRepositoryMock =
Substitute.For<IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto>>();
private readonly IRepositoryWellRelated<WellSectionPlanDto> wellSectionPlanRepositoryMock =
Substitute.For<IRepositoryWellRelated<WellSectionPlanDto>>();
private readonly ProcessMapPlanService<ProcessMapPlanWellDrillingDto> processMapPlanService;
public ProcessMapPlanServiceTests()
{
processMapPlanService = new ProcessMapPlanService<ProcessMapPlanWellDrillingDto>(wellSectionTypeRepositoryMock,
processMapPlanRepositoryMock, wellSectionPlanRepositoryMock);
wellSectionPlanRepositoryMock.GetByIdWellAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
.ReturnsForAnyArgs(fakeCollectionWellSectionPlan);
wellSectionTypeRepositoryMock.GetAllAsync(Arg.Any<CancellationToken>())
.ReturnsForAnyArgs(fakeCollectionWellSectionTypes);
}
[Theory]
[InlineData(80, 150, true)]
[InlineData(90, 140, true)]
[InlineData(0, 110, false)]
[InlineData(110, 200, false)]
public async Task GetAsync_ReturnsValidatedCollectionProcessMapPlanWellDrilling(int depthStart, int depthEnd, bool isValidCollection)
{
//arrange
var fakeCollectionProcessMapPlanWellDrilling = new ProcessMapPlanWellDrillingDto[]
{
new()
{
IdWellSectionType = idWellSectionType,
DepthStart = depthStart,
DepthEnd = depthEnd
}
};
processMapPlanRepositoryMock.GetByIdWellAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
.ReturnsForAnyArgs(fakeCollectionProcessMapPlanWellDrilling);
//act
var result = (await processMapPlanService.GetAsync(idWell, CancellationToken.None)).ToArray();
//assert
Assert.Equal(isValidCollection, result.All(r => r.IsValid));
Assert.Single(result);
}
}

View File

@ -4,7 +4,6 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMapPlan;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
@ -39,7 +38,7 @@ public class ProcessMapReportDataSaubStatServiceTest
private IDataSaubStatRepository dataSaubStatRepository
= Substitute.For<IDataSaubStatRepository>();
private ProcessMapReportDataSaubStatService service;
private ProcessMapReportDrillingService service;
private readonly static SimpleTimezoneDto timezone = new() { Hours = 2 };
private static readonly DateTimeOffset dateStart = new (2024, 01, 01, 00, 11, 11, timezone.Offset);
@ -274,7 +273,7 @@ public class ProcessMapReportDataSaubStatServiceTest
dataSaubStatRepository.GetAsync(Arg.Any<int>(), Arg.Any<DateTimeOffset>(), Arg.Any<DateTimeOffset>(), Arg.Any<CancellationToken>())
.Returns(dataSaubStat);
service = new ProcessMapReportDataSaubStatService(wellService, processMapPlanBaseRepository, dataSaubStatRepository, wellOperationRepository, wellOperationCategoryRepository);
service = new ProcessMapReportDrillingService(wellService, processMapPlanBaseRepository, dataSaubStatRepository, wellOperationRepository, wellOperationCategoryRepository);
}
[Fact]

View File

@ -118,7 +118,7 @@ namespace AsbCloudWebApi.Tests.Services.WellOperationExport
wellOperationRepository = Substitute.For<IWellOperationRepository>();
wellOperationCategoryRepository = Substitute.For<IWellOperationCategoryRepository>();
wellOperationImportTemplateService = new WellOperationImportTemplateService();
wellOperationExportService = new WellOperationExportService(wellOperationRepository, wellService, wellOperationImportTemplateService, wellOperationCategoryRepository);
wellOperationExportService = new WellOperationExportService(wellOperationRepository, wellOperationImportTemplateService, wellOperationCategoryRepository);
wellOperationImportService = new WellOperationImportService(wellService, wellOperationRepository, wellOperationCategoryRepository);
wellOperationDefaultExcelParser = new WellOperationDefaultExcelParser();

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<ServerGarbageCollection>true</ServerGarbageCollection>
<NoWarn>$(NoWarn);1591</NoWarn>

View File

@ -1,19 +0,0 @@
using AsbCloudApp.Data.ProcessMapPlan;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudInfrastructure.Services.ProcessMapPlan.Parser;
namespace AsbCloudWebApi.Controllers.ProcessMapPlan;
public class ProcessMapPlanDrillingController : ProcessMapPlanBaseController<ProcessMapPlanDrillingDto>
{
public ProcessMapPlanDrillingController(IChangeLogRepository<ProcessMapPlanDrillingDto, ProcessMapPlanBaseRequestWithWell> repository,
IWellService wellService,
ProcessMapPlanDrillingParser parserService)
: base(repository, wellService, parserService)
{
}
protected override string TemplateFileName => "ЕЦП_шаблон_файла_РТК_план_бурение.xlsx";
}

View File

@ -1,227 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudApp.Services.ProcessMaps;
using AsbCloudWebApi.SignalR;
using AsbCloudWebApi.SignalR.Clients;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
namespace AsbCloudWebApi.Controllers.ProcessMaps;
/// <summary>
/// РТК
/// </summary>
[ApiController]
[Route("api/well/{idWell}/[controller]")]
[Authorize]
public abstract class ProcessMapBaseController<T> : ControllerBase
where T : ProcessMapPlanBaseDto
{
private readonly IHubContext<TelemetryHub, ITelemetryHubClient> telemetryHubContext;
private readonly ITelemetryService telemetryService;
private readonly IWellService wellService;
private readonly IUserRepository userRepository;
private readonly ICrudRepository<WellSectionTypeDto> wellSectionRepository;
private readonly IProcessMapPlanRepository<T> repository;
private readonly IProcessMapPlanService<T> service;
protected ProcessMapBaseController(IWellService wellService,
IProcessMapPlanRepository<T> repository,
IUserRepository userRepository,
ICrudRepository<WellSectionTypeDto> wellSectionRepository,
IHubContext<TelemetryHub, ITelemetryHubClient> telemetryHubContext,
ITelemetryService telemetryService,
IProcessMapPlanService<T> service)
{
this.wellService = wellService;
this.repository = repository;
this.userRepository = userRepository;
this.wellSectionRepository = wellSectionRepository;
this.telemetryHubContext = telemetryHubContext;
this.telemetryService = telemetryService;
this.service = service;
}
protected abstract string SignalRGroup { get; }
protected int IdUser
{
get
{
var idUser = User.GetUserId();
if (!idUser.HasValue)
throw new ForbidException("Неизвестный пользователь");
return idUser.Value;
}
}
/// <summary>
/// Создание плановой РТК
/// </summary>
/// <param name="processMap">Тело запроса</param>
/// <param name="idWell">Id скважины</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[HttpPost]
[ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
public virtual async Task<IActionResult> InsertAsync(T processMap, int idWell, CancellationToken cancellationToken)
{
processMap.IdWell = idWell;
processMap.IdUser = IdUser;
processMap.LastUpdate = DateTime.UtcNow;
await CheckIsExistsWellSectionTypeAsync(processMap.IdWellSectionType, cancellationToken);
await AssertUserHasAccessToEditProcessMapAsync(processMap.IdWell, cancellationToken);
var result = await repository.InsertAsync(processMap, cancellationToken);
await NotifyUsersBySignalR(idWell, cancellationToken);
return Ok(result);
}
/// <summary>
/// Обновление плановой РТК
/// </summary>
/// <param name="processMap">Тело запроса</param>
/// <param name="idWell">Id скважины</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[HttpPut]
[ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
public virtual async Task<IActionResult> UpdateAsync(T processMap, int idWell, CancellationToken cancellationToken)
{
processMap.IdWell = idWell;
processMap.IdUser = IdUser;
processMap.LastUpdate = DateTime.UtcNow;
await CheckIsExistsWellSectionTypeAsync(processMap.IdWellSectionType, cancellationToken);
await AssertUserHasAccessToEditProcessMapAsync(idWell, cancellationToken);
var result = await repository.UpdateAsync(processMap, cancellationToken);
if (result == ICrudRepository<T>.ErrorIdNotFound)
return this.ValidationBadRequest(nameof(processMap.Id), $"РТК с Id: {processMap.Id} не существует");
await NotifyUsersBySignalR(idWell, cancellationToken);
return Ok(result);
}
/// <summary>
/// Удаление плановой РТК
/// </summary>
/// <param name="id">Id удаляемой РТК</param>
/// <param name="idWell">Id скважины</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[HttpDelete]
[ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
public virtual async Task<IActionResult> DeleteAsync(int id, int idWell, CancellationToken cancellationToken)
{
await AssertUserHasAccessToEditProcessMapAsync(idWell, cancellationToken);
var result = await repository.DeleteAsync(id, cancellationToken);
await NotifyUsersBySignalR(idWell, cancellationToken);
return Ok(result);
}
/// <summary>
/// Получение РТК по Id скважины
/// </summary>
/// <param name="idWell">Id скважины</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<ActionResult<IEnumerable<ValidationResultDto<T>>>> GetAsync(int idWell, CancellationToken cancellationToken)
{
var processMaps = await service.GetAsync(idWell, cancellationToken);
if (!processMaps.Any())
return NoContent();
return Ok(processMaps);
}
/// <summary>
/// Получение РТК по телеметрии
/// </summary>
/// <param name="uid">Уникальный ключ телеметрии</param>
/// <param name="updateFrom">Дата с которой требуется получить РТК</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[HttpGet("/api/telemetry/{uid}/[controller]")]
[AllowAnonymous]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
public async Task<ActionResult<IEnumerable<T>>> GetProcessMapPlanByTelemetry(string uid, DateTime updateFrom, CancellationToken cancellationToken)
{
var idWell = telemetryService.GetIdWellByTelemetryUid(uid);
if (!idWell.HasValue)
return this.ValidationBadRequest(nameof(uid), $"Wrong uid {uid}");
var requests = new[] { new ProcessMapPlanRequest
{
IdWell = idWell.Value,
UpdateFrom = updateFrom
}
};
var processMaps = await repository.GetAsync(requests, cancellationToken);
return Ok(processMaps);
}
protected async Task AssertUserHasAccessToEditProcessMapAsync(int idWell, CancellationToken cancellationToken)
{
var well = await wellService.GetOrDefaultAsync(idWell, cancellationToken)
?? throw new ArgumentInvalidException(nameof(idWell), $"Скважины с {idWell} не существует");
var idCompany = User.GetCompanyId();
if (!idCompany.HasValue ||
!await wellService.IsCompanyInvolvedInWellAsync(idCompany.Value, idWell, cancellationToken))
throw new ForbidException("Нет доступа к скважине");
if (well.IdState == 2 && !userRepository.HasPermission(IdUser, "ProcessMap.editCompletedWell"))
throw new ForbidException("Недостаточно прав для редактирования РТК завершенной скважины");
}
protected async Task NotifyUsersBySignalR(int idWell, CancellationToken cancellationToken)
{
var dtos = await repository.GetByIdWellAsync(idWell, cancellationToken);
await telemetryHubContext.Clients
.Group($"{SignalRGroup}_{idWell}")
.UpdateProcessMap(dtos, cancellationToken);
}
private async Task CheckIsExistsWellSectionTypeAsync(int idWellSectionType, CancellationToken cancellationToken)
{
_ = await wellSectionRepository.GetOrDefaultAsync(idWellSectionType, cancellationToken)
?? throw new ArgumentInvalidException(nameof(ProcessMapPlanWellDrillingDto.IdWellSectionType), $"Тип секции с Id: {idWellSectionType} не найден");
}
}

View File

@ -1,5 +1,4 @@
using AsbCloudApp.Data.ProcessMapPlan;
using AsbCloudApp.Repositories;
using AsbCloudApp.Repositories;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
@ -15,11 +14,12 @@ using System.Linq;
using AsbCloudApp.Data;
using AsbCloudApp.Requests.ParserOptions;
using AsbCloudInfrastructure.Services.Parser;
using AsbCloudApp.Data.ProcessMaps;
namespace AsbCloudWebApi.Controllers.ProcessMapPlan;
namespace AsbCloudWebApi.Controllers.ProcessMaps;
/// <summary>
/// РТК план
/// РТК план базовый
/// </summary>
[ApiController]
[Route("api/well/{idWell}/[controller]")]

View File

@ -0,0 +1,22 @@
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudInfrastructure.Services.ProcessMapPlan.Parser;
namespace AsbCloudWebApi.Controllers.ProcessMaps;
/// <summary>
/// РТК план бурения
/// </summary>
public class ProcessMapPlanDrillingController : ProcessMapPlanBaseController<ProcessMapPlanDrillingDto>
{
public ProcessMapPlanDrillingController(IChangeLogRepository<ProcessMapPlanDrillingDto, ProcessMapPlanBaseRequestWithWell> repository,
IWellService wellService,
ProcessMapPlanDrillingParser parserService)
: base(repository, wellService, parserService)
{
}
protected override string TemplateFileName => "ЕЦП_шаблон_файла_РТК_план_бурение.xlsx";
}

View File

@ -0,0 +1,22 @@
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudInfrastructure.Services.ProcessMapPlan.Parser;
namespace AsbCloudWebApi.Controllers.ProcessMaps;
/// <summary>
/// РТК план проработка
/// </summary>
public class ProcessMapPlanReamController : ProcessMapPlanBaseController<ProcessMapPlanReamDto>
{
public ProcessMapPlanReamController(IChangeLogRepository<ProcessMapPlanReamDto, ProcessMapPlanBaseRequestWithWell> repository,
IWellService wellService,
ProcessMapPlanReamParser parserService)
: base(repository, wellService, parserService)
{
}
protected override string TemplateFileName => "ЕЦП_шаблон_файла_РТК_план_проработка.xlsx";
}

View File

@ -0,0 +1,67 @@
using AsbCloudApp.Data.ProcessMaps.Report;
using AsbCloudApp.Requests;
using AsbCloudApp.Services.ProcessMaps.WellDrilling;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudWebApi.Controllers.ProcessMaps;
/// <summary>
/// РТК отчет по бурению
/// </summary>
[ApiController]
[Route("api/well/{idWell:int}/[controller]")]
[Authorize]
public class ProcessMapReportDrillingController: ControllerBase
{
private readonly IProcessMapReportDrillingService processMapReportDrillingService;
private readonly IProcessMapReportDrillingExportService processMapReportDrillingExportService;
public ProcessMapReportDrillingController(
IProcessMapReportDrillingExportService processMapReportDrillingExportService,
IProcessMapReportDrillingService processMapReportDrillingService)
{
this.processMapReportDrillingExportService = processMapReportDrillingExportService;
this.processMapReportDrillingService = processMapReportDrillingService;
}
/// <summary>
/// Получение данных для отчета РТК бурение
/// </summary>
/// <param name="idWell">Id</param>
/// <param name="request">параметры запроса</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[HttpGet("report")]
[ProducesResponseType(typeof(IEnumerable<ProcessMapReportDataSaubStatDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetReportAsync(int idWell, [FromQuery] DataSaubStatRequest request, CancellationToken cancellationToken)
{
var report = await processMapReportDrillingService.GetAsync(idWell, request, cancellationToken);
return Ok(report);
}
/// <summary>
/// Экспорт отчета РТК бурение
/// </summary>
/// <param name="idWell">Id скважины</param>
/// <param name="request">Параметры запроса</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[HttpGet("report/export")]
[ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK, "application/octet-stream")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> ExportReportAsync(int idWell, [FromQuery] DataSaubStatRequest request, CancellationToken cancellationToken)
{
var report = await processMapReportDrillingExportService.ExportAsync(idWell, request, cancellationToken);
if (report is null)
return NoContent();
return File(report.Value.File, "application/octet-stream", report.Value.Name);
}
}

View File

@ -1,157 +0,0 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Data.ProcessMaps.Report;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudApp.Services.ProcessMaps;
using AsbCloudApp.Services.ProcessMaps.WellDrilling;
using AsbCloudWebApi.SignalR;
using AsbCloudWebApi.SignalR.Clients;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudWebApi.Controllers.ProcessMaps;
/// <summary>
/// РТК бурение
/// </summary>
public class ProcessMapWellDrillingController : ProcessMapBaseController<ProcessMapPlanWellDrillingDto>
{
private readonly IProcessMapReportDataSaubStatService processMapReportDataSaubStatService;
private readonly IProcessMapReportDataSaubStatExportService processMapReportDataSaubStatExportService;
private readonly IProcessMapPlanImportService processMapPlanImportService;
protected override string SignalRGroup => "ProcessMapWellDrilling";
public ProcessMapWellDrillingController(IWellService wellService,
IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto> repository,
IUserRepository userRepository,
IProcessMapReportDataSaubStatExportService processMapReportDataSaubStatExportService,
IProcessMapPlanImportService processMapPlanImportService,
IProcessMapReportDataSaubStatService processMapReportDataSaubStatService,
ICrudRepository<WellSectionTypeDto> wellSectionRepository,
IHubContext<TelemetryHub, ITelemetryHubClient> telemetryHubContext,
ITelemetryService telemetryService,
IProcessMapPlanService<ProcessMapPlanWellDrillingDto> service)
: base(wellService, repository, userRepository, wellSectionRepository, telemetryHubContext, telemetryService, service)
{
this.processMapReportDataSaubStatExportService = processMapReportDataSaubStatExportService;
this.processMapPlanImportService = processMapPlanImportService;
this.processMapReportDataSaubStatService = processMapReportDataSaubStatService;
}
/// <summary>
/// Получение данных для отчета РТК бурение
/// </summary>
/// <param name="idWell">Id</param>
/// <param name="request">параметры запроса</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[HttpPost("report")]
[ProducesResponseType(typeof(IEnumerable<ProcessMapReportDataSaubStatDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetReportAsync(int idWell, DataSaubStatRequest request, CancellationToken cancellationToken)
{
var report = await processMapReportDataSaubStatService.GetAsync(idWell, request, cancellationToken);
return Ok(report);
}
/// <summary>
/// Экспорт отчета РТК бурение
/// </summary>
/// <param name="idWell">Id скважины</param>
/// <param name="request">Параметры запроса</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[HttpGet("report/export")]
[ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK, "application/octet-stream")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> ExportReportAsync(int idWell, [FromQuery] DataSaubStatRequest request, CancellationToken cancellationToken)
{
var report = await processMapReportDataSaubStatExportService.ExportAsync(idWell, request, cancellationToken);
if (report is null)
return NoContent();
return File(report.Value.File, "application/octet-stream", report.Value.Name);
}
/// <summary>
/// Импорт РТК бурение план
/// </summary>
/// <param name="idWell">Id скважины</param>
/// <param name="options"></param>
/// <param name="file"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[Obsolete]
[HttpPost("import/{options}")]
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
public async Task<IActionResult> ImportAsync(int idWell,
int options,
[Required] IFormFile file,
CancellationToken cancellationToken)
{
await AssertUserHasAccessToEditProcessMapAsync(idWell, cancellationToken);
if (Path.GetExtension(file.FileName).ToLower() != ".xlsx")
return this.ValidationBadRequest(nameof(file), "Требуется xlsx файл.");
using Stream stream = file.OpenReadStream();
try
{
await processMapPlanImportService.ImportAsync(idWell,
IdUser,
(options & 1) > 0,
stream,
cancellationToken);
await NotifyUsersBySignalR(idWell, cancellationToken);
}
catch (FileFormatException ex)
{
return this.ValidationBadRequest(nameof(file), ex.Message);
}
return Ok();
}
/// <summary>
/// Экспорт РТК бурение план
/// </summary>
/// <param name="idWell">Id скважины</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[Obsolete]
[HttpGet("export")]
[ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK, "application/octet-stream")]
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
public async Task<IActionResult> ExportAsync(int idWell, CancellationToken cancellationToken)
{
var processMapsFile = await processMapPlanImportService.ExportAsync(idWell, cancellationToken);
return File(processMapsFile.File, "application/octet-stream", processMapsFile.Name);
}
/// <summary>
/// Возвращает шаблон файла для импорта
/// </summary>
/// <returns>Запрашиваемый файл</returns>
[Obsolete]
[HttpGet("template")]
[ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK, "application/octet-stream")]
public async Task<IActionResult> GetTemplateAsync(CancellationToken cancellationToken)
{
var template = await processMapPlanImportService.GetExcelTemplateStreamAsync(cancellationToken);
return File(template.File, "application/octet-stream", template.Name);
}
}

View File

@ -1,29 +0,0 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudApp.Services.ProcessMaps;
using AsbCloudWebApi.SignalR;
using AsbCloudWebApi.SignalR.Clients;
using Microsoft.AspNetCore.SignalR;
namespace AsbCloudWebApi.Controllers.ProcessMaps;
/// <summary>
/// РТК проработки скважины
/// </summary>
public class ProcessMapWellReamController : ProcessMapBaseController<ProcessMapPlanWellReamDto>
{
public ProcessMapWellReamController(IWellService wellService,
IProcessMapPlanRepository<ProcessMapPlanWellReamDto> repository,
IUserRepository userRepository,
ICrudRepository<WellSectionTypeDto> wellSectionRepository,
IHubContext<TelemetryHub, ITelemetryHubClient> telemetryHubContext,
ITelemetryService telemetryService,
IProcessMapPlanService<ProcessMapPlanWellReamDto> service)
: base(wellService, repository, userRepository, wellSectionRepository, telemetryHubContext, telemetryService, service)
{
}
protected override string SignalRGroup => "ProcessMapWellReam";
}

View File

@ -1,8 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Exceptions;
@ -11,6 +6,11 @@ using AsbCloudApp.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudWebApi.Controllers.ProcessMaps;
@ -182,7 +182,7 @@ public class WellSectionPlanController : ControllerBase
private async Task CheckIsExistsWellSectionTypeAsync(int idWellSectionType, CancellationToken cancellationToken)
{
_ = await wellSectionRepository.GetOrDefaultAsync(idWellSectionType, cancellationToken)
?? throw new ArgumentInvalidException(nameof(ProcessMapPlanWellDrillingDto.IdWellSectionType),
?? throw new ArgumentInvalidException(nameof(ProcessMapPlanDrillingDto.IdWellSectionType),
$"Тип секции с Id: {idWellSectionType} не найден");
}
}

View File

@ -1,4 +1,5 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using Microsoft.AspNetCore.Authorization;
@ -6,7 +7,6 @@ using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data.ProcessMaps;
namespace AsbCloudWebApi.Controllers
{
@ -73,7 +73,7 @@ namespace AsbCloudWebApi.Controllers
/// <returns></returns>
[HttpGet("compositeProcessMap")]
[Permission]
[ProducesResponseType(typeof(IEnumerable<ProcessMapPlanWellDrillingDto>), (int)System.Net.HttpStatusCode.OK)]
[ProducesResponseType(typeof(IEnumerable<ProcessMapPlanDrillingDto>), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetCompositeProcessMap(int idWell, CancellationToken token)
{
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))