Merge pull request 'Импорт фактических траекторий' (#160) from feature/#13123485--import-fact-trajectories into dev

Reviewed-on: http://test.digitaldrilling.ru:8080/DDrilling/AsbCloudServer/pulls/160
Reviewed-by: Никита Фролов <ng.frolov@digitaldrilling.ru>
This commit is contained in:
Никита Фролов 2023-12-01 09:13:36 +05:00
commit c28ea98569
59 changed files with 28825 additions and 780 deletions

View File

@ -1,4 +1,4 @@
namespace AsbCloudApp.Data
namespace AsbCloudApp.Data.Trajectory
{

View File

@ -1,7 +1,7 @@
namespace AsbCloudApp.Data
namespace AsbCloudApp.Data.Trajectory
{
/// <summary>
/// Визуализация траектории 3D для посторения радиуса цели
/// Визуализация траектории 3D для построения радиуса цели
/// </summary>
public class TrajectoryCartesianPlanDto : TrajectoryCartesianFactDto
{

View File

@ -0,0 +1,53 @@
using System;
namespace AsbCloudApp.Data.Trajectory
{
/// <summary>
/// Базовая географическая траектория
/// </summary>
public abstract class TrajectoryGeoDto
{
/// <summary>
/// ИД строки с координатами
/// </summary>
public int Id { get; set; }
/// <summary>
/// Id скважины
/// </summary>
public int IdWell { get; set; }
/// <summary>
/// Глубина по стволу
/// </summary>
public double WellboreDepth { get; set; }
/// <summary>
/// Угол зенитный
/// </summary>
public double ZenithAngle { get; set; }
/// <summary>
/// Азимут Географ.
/// </summary>
public double AzimuthGeo { get; set; }
/// <summary>
/// Азимут Магнитный
/// </summary>
public double? AzimuthMagnetic { get; set; }
/// <summary>
/// Глубина вертикальная
/// </summary>
public double? VerticalDepth { get; set; }
/// <summary>
/// Дата загрузки
/// </summary>
public DateTime UpdateDate { get; set; }
/// <summary>
/// ИД пользователя
/// </summary>
public int IdUser { get; set; }
}
}

View File

@ -0,0 +1,15 @@
namespace AsbCloudApp.Data.Trajectory;
/// <summary>
/// Формирование данных по фактической географической траектории
/// </summary>
public class TrajectoryGeoFactDto : TrajectoryGeoDto
{
/// <summary>
/// Комментарии
/// </summary>
public string? Comment { get; set; }
}

View File

@ -0,0 +1,21 @@
using System;
namespace AsbCloudApp.Data.Trajectory
{
/// <summary>
/// Формирование данных по плановой географической траектории
/// </summary>
public class TrajectoryGeoPlanDto : TrajectoryGeoDto
{
/// <summary>
/// Радиус цели
/// </summary>
public double? Radius { get; set; }
/// <summary>
/// Комментарии
/// </summary>
public string? Comment { get; set; }
}
}

View File

@ -0,0 +1,25 @@
namespace AsbCloudApp.Data.Trajectory
{
/// <summary>
/// DTO объединяющее плановые и фактические значения траекторий
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="V"></typeparam>
public class TrajectoryPlanFactDto<T, V>
{
/// <summary>
/// Плановое значение
/// </summary>
public T? Plan { get; set; }
/// <summary>
/// Фактическое значение
/// </summary>
public V? FactManual { get; set; }
/// <summary>
/// Фактическое ннб-значение
/// </summary>
public V? FactNnb { get; set; }
}
}

View File

@ -1,45 +0,0 @@
namespace AsbCloudApp.Data;
/// <summary>
/// Базовая географическая траектория
/// </summary>
public abstract class TrajectoryGeoDto
{
/// <summary>
/// Id скважины
/// </summary>
public int IdWell { get; set; }
/// <summary>
/// Глубина по стволу
/// </summary>
public double WellboreDepth { get; set; }
/// <summary>
/// Угол зенитный
/// </summary>
public double ZenithAngle { get; set; }
/// <summary>
/// Азимут Географ.
/// </summary>
public double AzimuthGeo { get; set; }
/// <summary>
/// Азимут Магнитный
/// </summary>
public double? AzimuthMagnetic { get; set; }
/// <summary>
/// Глубина вертикальная
/// </summary>
public double? VerticalDepth { get; set; }
}
/// <summary>
/// Формирование данных по фактической географической траектории
/// </summary>
public class TrajectoryGeoFactDto : TrajectoryGeoDto
{ }

View File

@ -1,35 +0,0 @@
using System;
namespace AsbCloudApp.Data
{
/// <summary>
/// Формирование данных по плановой географической траектории
/// </summary>
public class TrajectoryGeoPlanDto: TrajectoryGeoDto
{
/// <summary>
/// ИД строки с координатами
/// </summary>
public int Id { get; set; }
/// <summary>
/// Дата загрузки
/// </summary>
public DateTime UpdateDate { get; set; }
/// <summary>
/// ИД пользователя
/// </summary>
public int IdUser { get; set; }
/// <summary>
/// Радиус цели
/// </summary>
public double? Radius { get; set; }
/// <summary>
/// Комментарии
/// </summary>
public string? Comment { get; set; }
}
}

View File

@ -1,4 +1,4 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.Trajectory;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
@ -6,26 +6,27 @@ using System.Threading.Tasks;
namespace AsbCloudApp.Repositories
{
/// <summary>
/// CRUD для работы с плановой траекторией из клиента
/// CRUD-репозиторий для работы с траекторией из клиента (плановой и фактической)
/// </summary>
/// <returns></returns>
public interface ITrajectoryPlanRepository : ITrajectoryRepository<TrajectoryGeoPlanDto>
//TrajectoryGeoPlanDto
public interface ITrajectoryEditableRepository<T> : ITrajectoryRepository<T> where T : TrajectoryGeoDto
{
/// <summary>
/// Добавить строки с координатами по одной скважине. Если в коллекции координаты для разных скважин получаем exception.
/// </summary>
/// <param name="plannedTrajectoryRows"></param>
/// <param name="trajectoryRows"></param>
/// <param name="token"></param>
/// <returns>количество записанных строк или exception с описанием</returns>
Task<int> AddRangeAsync(IEnumerable<TrajectoryGeoPlanDto> plannedTrajectoryRows, CancellationToken token);
Task<int> AddRangeAsync(IEnumerable<T> trajectoryRows, CancellationToken token);
/// <summary>
/// Добавить одну строку с координатами
/// </summary>
/// <param name="plannedTrajectoryRow"></param>
/// <param name="trajectoryRow"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> AddAsync(TrajectoryGeoPlanDto plannedTrajectoryRow, CancellationToken token);
Task<int> AddAsync(T trajectoryRow, CancellationToken token);
/// <summary>
/// Обновить строку с координатами
@ -33,7 +34,7 @@ namespace AsbCloudApp.Repositories
/// <param name="row"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> UpdateAsync(TrajectoryGeoPlanDto row,
Task<int> UpdateAsync(T row,
CancellationToken token);
/// <summary>
@ -45,7 +46,7 @@ namespace AsbCloudApp.Repositories
Task<int> DeleteRangeAsync(IEnumerable<int> ids, CancellationToken token);
/// <summary>
/// Удалить всю плановую траекторию по ИД скважины
/// Удалить всю траекторию по ИД скважины
/// </summary>
/// <param name="idWell"></param>
/// <param name="token"></param>

View File

@ -1,23 +0,0 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Requests;
namespace AsbCloudApp.Repositories
{
/// <summary>
/// CRUD для работы с фактической траекторией из клиента
/// </summary>
/// <returns></returns>
public interface ITrajectoryFactRepository : ITrajectoryRepository<TrajectoryGeoFactDto>
{
/// <summary>
/// Получить траектории скважины
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<TrajectoryGeoFactDto>> GetAsync(TrajectoryGeoFactRequest request, CancellationToken token);
}
}

View File

@ -0,0 +1,23 @@
using AsbCloudApp.Data.Trajectory;
using AsbCloudApp.Requests;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudApp.Repositories
{
/// <summary>
/// репозиторий для работы с траекторией из ннб (фактической)
/// </summary>
/// <returns></returns>
public interface ITrajectoryNnbRepository : ITrajectoryRepository<TrajectoryGeoFactDto>
{
/// <summary>
/// получение списка траекторий по параметрам запроса
/// </summary>
/// <param name="trajectoryRequest">параметры запроса</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<IEnumerable<TrajectoryGeoFactDto>> GetByRequestAsync(TrajectoryRequest trajectoryRequest, CancellationToken cancellationToken);
}
}

View File

@ -1,8 +1,5 @@
using AsbCloudApp.Data;
using System;
using AsbCloudApp.Data.Trajectory;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@ -15,9 +12,9 @@ namespace AsbCloudApp.Repositories
where T : TrajectoryGeoDto
{
/// <summary>
/// Получить все добавленные по скважине координаты плановой траектории
/// Получить все добавленные по скважине координаты траектории
/// </summary>
/// <param name="idWell"></param>
/// <param name="idWell">ключ скважины</param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<T>> GetAsync(int idWell, CancellationToken token);

View File

@ -5,7 +5,7 @@ namespace AsbCloudApp.Requests;
/// <summary>
/// Запрос для получения фактической траектории
/// </summary>
public class TrajectoryGeoFactRequest : RequestBase
public class TrajectoryRequest : RequestBase
{
/// <summary>
/// Идентификатор скважины

View File

@ -1,40 +0,0 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudApp.Services
{
/// <summary>
/// Сервис загрузки и обработки плановой траектории из файла
/// </summary>
public interface IPlannedTrajectoryImportService
{
/// <summary>
/// скачать шаблон для заполнения плановой траектории
/// </summary>
/// <returns></returns>
Stream GetTemplateFile();
/// <summary>
/// Получить имя файла (исходя из названия скважины)
/// </summary>
/// <returns></returns>
Task<string> GetFileNameAsync(int idWell, CancellationToken token);
/// <summary>
/// загрузить текущую плановую траекторию в .xlsx
/// </summary>
/// <param name="idWell"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<Stream> ExportAsync(int idWell, CancellationToken token);
/// <summary>
/// импортировать из excel плановую траекторию
/// </summary>
/// <param name="idWell"></param>
/// <param name="idUser"></param>
/// <param name="stream"></param>
/// <param name="token"></param>
/// <param name="deleteBeforeImport">Очистить старые координаты перед импортом (если файл проходит валидацию)</param>
Task<int> ImportAsync(int idWell, int idUser, Stream stream, bool deleteBeforeImport, CancellationToken token);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,64 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace AsbCloudDb.Migrations
{
public partial class Add_Fact_Trajectory_Table : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "t_trajectory_fact",
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 скважины"),
update_date = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата загрузки траектории"),
wellbore_depth = table.Column<double>(type: "double precision", nullable: false, comment: "Глубина по стволу"),
zenith_angle = table.Column<double>(type: "double precision", nullable: false, comment: "Угол зенитный"),
azimuth_geo = table.Column<double>(type: "double precision", nullable: false, comment: "Азимут Географ."),
azimuth_magnetic = table.Column<double>(type: "double precision", nullable: false, comment: "Азимут Магнитный"),
vertical_depth = table.Column<double>(type: "double precision", nullable: false, comment: "Глубина вертикальная"),
comment = table.Column<string>(type: "text", nullable: true, comment: "Комментарии")
},
constraints: table =>
{
table.PrimaryKey("PK_t_trajectory_fact", x => x.id);
table.ForeignKey(
name: "FK_t_trajectory_fact_t_user_id_user",
column: x => x.id_user,
principalTable: "t_user",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_t_trajectory_fact_t_well_id_well",
column: x => x.id_well,
principalTable: "t_well",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
},
comment: "Загрузка фактической траектории");
migrationBuilder.CreateIndex(
name: "IX_t_trajectory_fact_id_user",
table: "t_trajectory_fact",
column: "id_user");
migrationBuilder.CreateIndex(
name: "IX_t_trajectory_fact_id_well",
table: "t_trajectory_fact",
column: "id_well");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "t_trajectory_fact");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,109 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace AsbCloudDb.Migrations
{
public partial class Update_t_planned_trajectory : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_t_planned_trajectory_t_user_id_user",
table: "t_planned_trajectory");
migrationBuilder.DropForeignKey(
name: "FK_t_planned_trajectory_t_well_id_well",
table: "t_planned_trajectory");
migrationBuilder.DropPrimaryKey(
name: "PK_t_planned_trajectory",
table: "t_planned_trajectory");
migrationBuilder.RenameTable(
name: "t_planned_trajectory",
newName: "t_trajectory_planned");
migrationBuilder.RenameIndex(
name: "IX_t_planned_trajectory_id_well",
table: "t_trajectory_planned",
newName: "IX_t_trajectory_planned_id_well");
migrationBuilder.RenameIndex(
name: "IX_t_planned_trajectory_id_user",
table: "t_trajectory_planned",
newName: "IX_t_trajectory_planned_id_user");
migrationBuilder.AddPrimaryKey(
name: "PK_t_trajectory_planned",
table: "t_trajectory_planned",
column: "id");
migrationBuilder.AddForeignKey(
name: "FK_t_trajectory_planned_t_user_id_user",
table: "t_trajectory_planned",
column: "id_user",
principalTable: "t_user",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_t_trajectory_planned_t_well_id_well",
table: "t_trajectory_planned",
column: "id_well",
principalTable: "t_well",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_t_trajectory_planned_t_user_id_user",
table: "t_trajectory_planned");
migrationBuilder.DropForeignKey(
name: "FK_t_trajectory_planned_t_well_id_well",
table: "t_trajectory_planned");
migrationBuilder.DropPrimaryKey(
name: "PK_t_trajectory_planned",
table: "t_trajectory_planned");
migrationBuilder.RenameTable(
name: "t_trajectory_planned",
newName: "t_planned_trajectory");
migrationBuilder.RenameIndex(
name: "IX_t_trajectory_planned_id_well",
table: "t_planned_trajectory",
newName: "IX_t_planned_trajectory_id_well");
migrationBuilder.RenameIndex(
name: "IX_t_trajectory_planned_id_user",
table: "t_planned_trajectory",
newName: "IX_t_planned_trajectory_id_user");
migrationBuilder.AddPrimaryKey(
name: "PK_t_planned_trajectory",
table: "t_planned_trajectory",
column: "id");
migrationBuilder.AddForeignKey(
name: "FK_t_planned_trajectory_t_user_id_user",
table: "t_planned_trajectory",
column: "id_user",
principalTable: "t_user",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_t_planned_trajectory_t_well_id_well",
table: "t_planned_trajectory",
column: "id_well",
principalTable: "t_well",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,109 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace AsbCloudDb.Migrations
{
public partial class Rename_t_trajectory_plan : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_t_trajectory_planned_t_user_id_user",
table: "t_trajectory_planned");
migrationBuilder.DropForeignKey(
name: "FK_t_trajectory_planned_t_well_id_well",
table: "t_trajectory_planned");
migrationBuilder.DropPrimaryKey(
name: "PK_t_trajectory_planned",
table: "t_trajectory_planned");
migrationBuilder.RenameTable(
name: "t_trajectory_planned",
newName: "t_trajectory_plan");
migrationBuilder.RenameIndex(
name: "IX_t_trajectory_planned_id_well",
table: "t_trajectory_plan",
newName: "IX_t_trajectory_plan_id_well");
migrationBuilder.RenameIndex(
name: "IX_t_trajectory_planned_id_user",
table: "t_trajectory_plan",
newName: "IX_t_trajectory_plan_id_user");
migrationBuilder.AddPrimaryKey(
name: "PK_t_trajectory_plan",
table: "t_trajectory_plan",
column: "id");
migrationBuilder.AddForeignKey(
name: "FK_t_trajectory_plan_t_user_id_user",
table: "t_trajectory_plan",
column: "id_user",
principalTable: "t_user",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_t_trajectory_plan_t_well_id_well",
table: "t_trajectory_plan",
column: "id_well",
principalTable: "t_well",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_t_trajectory_plan_t_user_id_user",
table: "t_trajectory_plan");
migrationBuilder.DropForeignKey(
name: "FK_t_trajectory_plan_t_well_id_well",
table: "t_trajectory_plan");
migrationBuilder.DropPrimaryKey(
name: "PK_t_trajectory_plan",
table: "t_trajectory_plan");
migrationBuilder.RenameTable(
name: "t_trajectory_plan",
newName: "t_trajectory_planned");
migrationBuilder.RenameIndex(
name: "IX_t_trajectory_plan_id_well",
table: "t_trajectory_planned",
newName: "IX_t_trajectory_planned_id_well");
migrationBuilder.RenameIndex(
name: "IX_t_trajectory_plan_id_user",
table: "t_trajectory_planned",
newName: "IX_t_trajectory_planned_id_user");
migrationBuilder.AddPrimaryKey(
name: "PK_t_trajectory_planned",
table: "t_trajectory_planned",
column: "id");
migrationBuilder.AddForeignKey(
name: "FK_t_trajectory_planned_t_user_id_user",
table: "t_trajectory_planned",
column: "id_user",
principalTable: "t_user",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_t_trajectory_planned_t_well_id_well",
table: "t_trajectory_planned",
column: "id_well",
principalTable: "t_well",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
}
}
}

View File

@ -264,46 +264,24 @@ namespace AsbCloudDb.Migrations
modelBuilder.Entity("AsbCloudDb.Model.DailyReports.DailyReport", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("Date")
.HasColumnType("timestamp with time zone")
.HasColumnName("date")
.HasComment("Дата формирования отчёта");
b.Property<DateTime?>("DateLastUpdate")
.HasColumnType("timestamp with time zone")
.HasColumnName("date_last_update")
.HasComment("Дата последнего обновления");
b.Property<int>("IdWell")
.HasColumnType("integer")
.HasColumnName("id_well")
.HasComment("ID скважины");
b.Property<string>("SignBlock")
b.Property<DateOnly>("StartDate")
.HasColumnType("date")
.HasColumnName("start_date")
.HasComment("Дата отчёта");
b.Property<string>("Info")
.IsRequired()
.HasColumnType("jsonb")
.HasColumnName("sign_block")
.HasComment("Подпись");
.HasColumnName("info")
.HasComment("Список параметров для отчёта");
b.Property<string>("SubsystemBlock")
.HasColumnType("jsonb")
.HasColumnName("subsystem_block")
.HasComment("Наработкой подсистем");
b.Property<string>("TimeBalanceBlock")
.HasColumnType("jsonb")
.HasColumnName("time_balance_block")
.HasComment("Баланс времени");
b.HasKey("Id");
b.HasIndex("IdWell", "Date")
.IsUnique();
b.HasKey("IdWell", "StartDate")
.HasName("t_id_well_date_start_pk");
b.ToTable("t_daily_report");
@ -2435,85 +2413,9 @@ namespace AsbCloudDb.Migrations
Id = 528,
Description = "Разрешение на удаление контакта",
Name = "WellContact.delete"
},
new
{
Id = 529,
Description = "Разрешение на получение отчетов drill test",
Name = "DrillTestReport.get"
});
});
modelBuilder.Entity("AsbCloudDb.Model.PlannedTrajectory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<double>("AzimuthGeo")
.HasColumnType("double precision")
.HasColumnName("azimuth_geo")
.HasComment("Азимут Географ.");
b.Property<double>("AzimuthMagnetic")
.HasColumnType("double precision")
.HasColumnName("azimuth_magnetic")
.HasComment("Азимут Магнитный");
b.Property<string>("Comment")
.HasColumnType("text")
.HasColumnName("comment")
.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<double?>("Radius")
.HasColumnType("double precision")
.HasColumnName("radius")
.HasComment("Радиус цели");
b.Property<DateTimeOffset>("UpdateDate")
.HasColumnType("timestamp with time zone")
.HasColumnName("update_date")
.HasComment("Дата загрузки траектории");
b.Property<double>("VerticalDepth")
.HasColumnType("double precision")
.HasColumnName("vertical_depth")
.HasComment("Глубина вертикальная");
b.Property<double>("WellboreDepth")
.HasColumnType("double precision")
.HasColumnName("wellbore_depth")
.HasComment("Глубина по стволу");
b.Property<double>("ZenithAngle")
.HasColumnType("double precision")
.HasColumnName("zenith_angle")
.HasComment("Угол зенитный");
b.HasKey("Id");
b.HasIndex("IdUser");
b.HasIndex("IdWell");
b.ToTable("t_planned_trajectory");
b.HasComment("Загрузка плановой траектории");
});
modelBuilder.Entity("AsbCloudDb.Model.ProcessMaps.ProcessMapWellDrilling", b =>
{
b.Property<int>("Id")
@ -4107,11 +4009,6 @@ namespace AsbCloudDb.Migrations
{
IdUserRole = 1,
IdPermission = 528
},
new
{
IdUserRole = 1,
IdPermission = 529
});
});
@ -5218,6 +5115,141 @@ namespace AsbCloudDb.Migrations
b.HasComment("Наработка талевого каната");
});
modelBuilder.Entity("AsbCloudDb.Model.Trajectory.TrajectoryFact", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<double>("AzimuthGeo")
.HasColumnType("double precision")
.HasColumnName("azimuth_geo")
.HasComment("Азимут Географ.");
b.Property<double>("AzimuthMagnetic")
.HasColumnType("double precision")
.HasColumnName("azimuth_magnetic")
.HasComment("Азимут Магнитный");
b.Property<string>("Comment")
.HasColumnType("text")
.HasColumnName("comment")
.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<DateTimeOffset>("UpdateDate")
.HasColumnType("timestamp with time zone")
.HasColumnName("update_date")
.HasComment("Дата загрузки траектории");
b.Property<double>("VerticalDepth")
.HasColumnType("double precision")
.HasColumnName("vertical_depth")
.HasComment("Глубина вертикальная");
b.Property<double>("WellboreDepth")
.HasColumnType("double precision")
.HasColumnName("wellbore_depth")
.HasComment("Глубина по стволу");
b.Property<double>("ZenithAngle")
.HasColumnType("double precision")
.HasColumnName("zenith_angle")
.HasComment("Угол зенитный");
b.HasKey("Id");
b.HasIndex("IdUser");
b.HasIndex("IdWell");
b.ToTable("t_trajectory_fact");
b.HasComment("Загрузка фактической траектории");
});
modelBuilder.Entity("AsbCloudDb.Model.Trajectory.TrajectoryPlan", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<double>("AzimuthGeo")
.HasColumnType("double precision")
.HasColumnName("azimuth_geo")
.HasComment("Азимут Географ.");
b.Property<double>("AzimuthMagnetic")
.HasColumnType("double precision")
.HasColumnName("azimuth_magnetic")
.HasComment("Азимут Магнитный");
b.Property<string>("Comment")
.HasColumnType("text")
.HasColumnName("comment")
.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<double?>("Radius")
.HasColumnType("double precision")
.HasColumnName("radius")
.HasComment("Радиус цели");
b.Property<DateTimeOffset>("UpdateDate")
.HasColumnType("timestamp with time zone")
.HasColumnName("update_date")
.HasComment("Дата загрузки траектории");
b.Property<double>("VerticalDepth")
.HasColumnType("double precision")
.HasColumnName("vertical_depth")
.HasComment("Глубина вертикальная");
b.Property<double>("WellboreDepth")
.HasColumnType("double precision")
.HasColumnName("wellbore_depth")
.HasComment("Глубина по стволу");
b.Property<double>("ZenithAngle")
.HasColumnType("double precision")
.HasColumnName("zenith_angle")
.HasComment("Угол зенитный");
b.HasKey("Id");
b.HasIndex("IdUser");
b.HasIndex("IdWell");
b.ToTable("t_trajectory_plan");
b.HasComment("Загрузка плановой траектории");
});
modelBuilder.Entity("AsbCloudDb.Model.User", b =>
{
b.Property<int>("Id")
@ -8034,7 +8066,7 @@ namespace AsbCloudDb.Migrations
b.Navigation("Well");
});
modelBuilder.Entity("AsbCloudDb.Model.DailyReports.DailyReport", b =>
modelBuilder.Entity("AsbCloudDb.Model.DailyReport.DailyReport", b =>
{
b.HasOne("AsbCloudDb.Model.Well", "Well")
.WithMany()
@ -8306,25 +8338,6 @@ namespace AsbCloudDb.Migrations
b.Navigation("Well");
});
modelBuilder.Entity("AsbCloudDb.Model.PlannedTrajectory", 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.Navigation("User");
b.Navigation("Well");
});
modelBuilder.Entity("AsbCloudDb.Model.ProcessMaps.ProcessMapWellDrilling", b =>
{
b.HasOne("AsbCloudDb.Model.User", "User")
@ -8632,6 +8645,44 @@ namespace AsbCloudDb.Migrations
b.Navigation("Telemetry");
});
modelBuilder.Entity("AsbCloudDb.Model.Trajectory.TrajectoryFact", 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.Navigation("User");
b.Navigation("Well");
});
modelBuilder.Entity("AsbCloudDb.Model.Trajectory.TrajectoryPlan", 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.Navigation("User");
b.Navigation("Well");
});
modelBuilder.Entity("AsbCloudDb.Model.User", b =>
{
b.HasOne("AsbCloudDb.Model.Company", "Company")

View File

@ -6,6 +6,7 @@ using System.Threading.Tasks;
using AsbCloudDb.Model.DailyReports;
using AsbCloudDb.Model.Manuals;
using AsbCloudDb.Model.ProcessMaps;
using AsbCloudDb.Model.Trajectory;
namespace AsbCloudDb.Model
{
@ -17,7 +18,7 @@ namespace AsbCloudDb.Model
public virtual DbSet<DailyReport> DailyReports => Set <DailyReport>();
public virtual DbSet<Deposit> Deposits => Set<Deposit>();
public virtual DbSet<DetectedOperation> DetectedOperations => Set<DetectedOperation>();
public virtual DbSet<PlannedTrajectory> PlannedTrajectories => Set<PlannedTrajectory>();
public virtual DbSet<TrajectoryPlan> TrajectoriesPlan => Set<TrajectoryPlan>();
public virtual DbSet<ProcessMapWellDrilling> ProcessMapWellDrillings => Set<ProcessMapWellDrilling>();
public virtual DbSet<ProcessMapWellReam> ProcessMapWellReams => Set<ProcessMapWellReam>();
public virtual DbSet<DrillingProgramPart> DrillingProgramParts => Set<DrillingProgramPart>();
@ -60,6 +61,7 @@ namespace AsbCloudDb.Model
public virtual DbSet<LimitingParameter> LimitingParameter => Set<LimitingParameter>();
public virtual DbSet<TelemetryWirelineRunOut> TelemetryWirelineRunOut => Set<TelemetryWirelineRunOut>();
public virtual DbSet<TrajectoryFact> TrajectoriesFact => Set<TrajectoryFact>();
// GTR WITS
public DbSet<WitsItemFloat> WitsItemFloat => Set<WitsItemFloat>();

View File

@ -160,9 +160,7 @@
new (){ Id = 526, Name = "WellOperation.editCompletedWell", Description = "Разрешение на редактирование операций у завершенной скважины"},
new() { Id = 527, Name = "Manual.delete", Description = "Разрешение на удаление инструкций"},
new (){ Id = 528, Name="WellContact.delete", Description="Разрешение на удаление контакта"},
new (){ Id = 529, Name="DrillTestReport.get", Description="Разрешение на получение отчетов drill test"},
new (){ Id = 528, Name="WellContact.delete", Description="Разрешение на удаление контакта"}
};
}
}

View File

@ -10,6 +10,7 @@ using System.Threading.Tasks;
using AsbCloudDb.Model.DailyReports;
using AsbCloudDb.Model.Manuals;
using AsbCloudDb.Model.ProcessMaps;
using AsbCloudDb.Model.Trajectory;
namespace AsbCloudDb.Model
{
@ -21,7 +22,7 @@ namespace AsbCloudDb.Model
DbSet<DailyReport> DailyReports { get; }
DbSet<Deposit> Deposits { get; }
DbSet<DetectedOperation> DetectedOperations { get; }
DbSet<PlannedTrajectory> PlannedTrajectories { get; }
DbSet<TrajectoryPlan> TrajectoriesPlan { get; }
DbSet<ProcessMapWellDrilling> ProcessMapWellDrillings { get; }
DbSet<ProcessMapWellReam> ProcessMapWellReams { get; }
DbSet<DrillingProgramPart> DrillingProgramParts { get; }
@ -78,6 +79,7 @@ namespace AsbCloudDb.Model
DbSet<ManualDirectory> ManualDirectories { get; }
DbSet<Contact> Contacts { get; }
DbSet<DrillTest> DrillTests { get; }
DbSet<TrajectoryFact> TrajectoriesFact { get; }
DatabaseFacade Database { get; }
Task<int> RefreshMaterializedViewAsync(string mwName, CancellationToken token);

View File

@ -3,10 +3,9 @@ using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace AsbCloudDb.Model
namespace AsbCloudDb.Model.Trajectory
{
[Table("t_planned_trajectory"), Comment("Загрузка плановой траектории")]
public class PlannedTrajectory : IId, IWellRelated
public abstract class Trajectory : IId, IWellRelated
{
[Column("id"), Key]
public int Id { get; set; }
@ -38,9 +37,6 @@ namespace AsbCloudDb.Model
[Column("comment"), Comment("Комментарии")]
public string? Comment { get; set; }
[Column("radius"), Comment("Радиус цели")]
public double? Radius { get; set; }
[ForeignKey(nameof(IdWell))]
public virtual Well Well { get; set; } = null!;

View File

@ -0,0 +1,10 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;
namespace AsbCloudDb.Model.Trajectory
{
[Table("t_trajectory_fact"), Comment("Загрузка фактической траектории")]
public class TrajectoryFact : Trajectory
{
}
}

View File

@ -0,0 +1,12 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;
namespace AsbCloudDb.Model.Trajectory
{
[Table("t_trajectory_plan"), Comment("Загрузка плановой траектории")]
public class TrajectoryPlan : Trajectory
{
[Column("radius"), Comment("Радиус цели")]
public double? Radius { get; set; }
}
}

View File

@ -14,7 +14,10 @@
<None Remove="CommonLibs\Readme.md" />
<None Remove="Services\DailyReport\DailyReportTemplate.xlsx" />
<None Remove="Services\DrillTestReport\DrillTestReportTemplate.xlsx" />
<None Remove="Services\Trajectory\FactTrajectoryTemplate.xlsx" />
<None Remove="Services\Trajectory\NnbTrajectoryTemplate.xlsx" />
<None Remove="Services\Trajectory\PlannedTrajectoryTemplate.xlsx" />
<None Remove="Services\Trajectory\Templates\TrajectoryFactNnbTemplate.xlsx" />
<None Remove="Services\WellOperationService\ScheduleReportTemplate.xlsx" />
<None Remove="Services\WellOperationService\WellOperationImportTemplate.xlsx" />
<None Remove="Services\DailyReport\DailyReportBlocks\" />
@ -33,7 +36,9 @@
<EmbeddedResource Include="Services\DetectOperations\DetectOperations.xlsx" />
<EmbeddedResource Include="Services\DailyReport\DailyReportTemplate.xlsx" />
<EmbeddedResource Include="Services\DrillTestReport\DrillTestReportTemplate.xlsx" />
<EmbeddedResource Include="Services\Trajectory\PlannedTrajectoryTemplate.xlsx" />
<EmbeddedResource Include="Services\Trajectory\Templates\TrajectoryFactNnbTemplate.xlsx" />
<EmbeddedResource Include="Services\Trajectory\Templates\TrajectoryFactManualTemplate.xlsx" />
<EmbeddedResource Include="Services\Trajectory\Templates\TrajectoryPlanTemplate.xlsx" />
<EmbeddedResource Include="Services\WellOperationService\ScheduleReportTemplate.xlsx" />
<EmbeddedResource Include="Services\WellOperationImport\Files\WellOperationImportTemplate.xlsx" />
<EmbeddedResource Include="Services\WellOperationImport\Files\Dictionaries\Operations.txt" />

View File

@ -5,6 +5,7 @@ using AsbCloudApp.Data.Manuals;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Data.Subsystems;
using AsbCloudApp.Data.Trajectory;
using AsbCloudApp.Data.WellOperationImport.Options;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
@ -17,6 +18,7 @@ using AsbCloudDb.Model;
using AsbCloudDb.Model.Manuals;
using AsbCloudDb.Model.ProcessMaps;
using AsbCloudDb.Model.Subsystems;
using AsbCloudDb.Model.Trajectory;
using AsbCloudInfrastructure.Background;
using AsbCloudInfrastructure.Repository;
using AsbCloudInfrastructure.Services;
@ -29,6 +31,8 @@ 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.Import;
using AsbCloudInfrastructure.Services.WellOperationImport;
using AsbCloudInfrastructure.Services.WellOperationImport.FileParser;
using AsbCloudInfrastructure.Services.WellOperationService;
@ -197,7 +201,11 @@ namespace AsbCloudInfrastructure
services.AddTransient<IWellService, WellService>();
services.AddTransient<IWellOperationImportService, WellOperationImportService>();
services.AddTransient<IProcessMapReportWellDrillingExportService, ProcessMapReportWellDrillingExportService>();
services.AddTransient<IPlannedTrajectoryImportService, PlannedTrajectoryImportService>();
services.AddTransient<TrajectoryPlanExportService>();
services.AddTransient<TrajectoryFactManualExportService>();
services.AddTransient<TrajectoryFactNnbExportService>();
services.AddTransient<TrajectoryPlanParserService>();
services.AddTransient<TrajectoryFactManualParserService>();
services.AddTransient<IWellOperationRepository, WellOperationRepository>();
services.AddTransient<IDailyReportService, DailyReportService>();
services.AddTransient<IDetectedOperationService, DetectedOperationService>();
@ -260,8 +268,9 @@ namespace AsbCloudInfrastructure
services.AddTransient<ILimitingParameterRepository, LimitingParameterRepository>();
services.AddTransient<ITelemetryWirelineRunOutRepository, TelemetryWirelineRunOutRepository>();
services.AddTransient<IWellFinalDocumentsRepository, WellFinalDocumentsRepository>();
services.AddTransient<ITrajectoryPlanRepository, TrajectoryPlanRepository>();
services.AddTransient<ITrajectoryFactRepository, TrajectoryFactRepository>();
services.AddTransient<ITrajectoryEditableRepository<TrajectoryGeoPlanDto>, TrajectoryEditableRepository<TrajectoryPlan, TrajectoryGeoPlanDto>>();
services.AddTransient<ITrajectoryEditableRepository<TrajectoryGeoFactDto>, TrajectoryEditableRepository<TrajectoryFact, TrajectoryGeoFactDto>>();
services.AddTransient<ITrajectoryNnbRepository, TrajectoryNnbRepository>();
services.AddTransient<IFaqRepository, FaqRepository>();
services.AddTransient<ISlipsStatService, SlipsStatService>();
services.AddTransient<IWellContactService, WellContactService>();

View File

@ -1,8 +1,9 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.Trajectory;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudDb.Model.Trajectory;
using Mapster;
using Microsoft.EntityFrameworkCore;
using System;
@ -13,25 +14,31 @@ using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Repository
{
public class TrajectoryPlanRepository : ITrajectoryPlanRepository
/// <summary>
/// CRUD-репозиторий для работы с траекториями (плановыми и фактическими)
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="Tdto"></typeparam>
public class TrajectoryEditableRepository<TEntity, Tdto> : ITrajectoryEditableRepository<Tdto>
where TEntity : Trajectory
where Tdto : TrajectoryGeoDto
{
private readonly IAsbCloudDbContext db;
private readonly IWellService wellService;
public TrajectoryPlanRepository(IAsbCloudDbContext db, IWellService wellService)
public TrajectoryEditableRepository(IAsbCloudDbContext db, IWellService wellService)
{
this.db = db;
this.wellService = wellService;
}
/// <inheritdoc/>
public async Task<int> AddRangeAsync(IEnumerable<TrajectoryGeoPlanDto> plannedTrajectoryRows, CancellationToken token)
public async Task<int> AddRangeAsync(IEnumerable<Tdto> trajectoryRows, CancellationToken token)
{
var idWell = plannedTrajectoryRows.First().IdWell;
if (!plannedTrajectoryRows.All(r => r.IdWell == idWell))
throw new ArgumentInvalidException(nameof(plannedTrajectoryRows), "Все строки должны относиться к одной скважине");
var idWell = trajectoryRows.First().IdWell;
if (!trajectoryRows.All(r => r.IdWell == idWell))
throw new ArgumentInvalidException(nameof(trajectoryRows), "Все строки должны относиться к одной скважине");
var offsetHours = wellService.GetTimezone(idWell).Hours;
var entities = plannedTrajectoryRows
var entities = trajectoryRows
.Select(e =>
{
var entity = Convert(e, offsetHours);
@ -39,80 +46,75 @@ namespace AsbCloudInfrastructure.Repository
return entity;
});
db.PlannedTrajectories.AddRange(entities);
return await db.SaveChangesAsync(token)
.ConfigureAwait(false);
db.Set<TEntity>().AddRange(entities);
return await db.SaveChangesAsync(token);
}
/// <inheritdoc/>
public async Task<int> AddAsync(TrajectoryGeoPlanDto plannedTrajectoryRow, CancellationToken token)
public async Task<int> AddAsync(Tdto trajectoryRow, CancellationToken token)
{
var offsetHours = wellService.GetTimezone(plannedTrajectoryRow.IdWell).Hours;
var entity = Convert(plannedTrajectoryRow, offsetHours);
var offsetHours = wellService.GetTimezone(trajectoryRow.IdWell).Hours;
var entity = Convert(trajectoryRow, offsetHours);
entity.Id = 0;
db.PlannedTrajectories.Add(entity);
db.Set<TEntity>().Add(entity);
return await db.SaveChangesAsync(token)
.ConfigureAwait(false);
}
/// <inheritdoc/>
public async Task<int> DeleteRangeAsync(IEnumerable<int> ids, CancellationToken token)
{
var query = db.PlannedTrajectories
var query = db.Set<TEntity>()
.Where(e => ids.Contains(e.Id));
db.PlannedTrajectories.RemoveRange(query);
db.Set<TEntity>().RemoveRange(query);
return await db.SaveChangesAsync(token)
.ConfigureAwait(false);
}
/// <inheritdoc/>
public async Task<int> DeleteByIdWellAsync(int idWell, CancellationToken token)
{
var query = db.PlannedTrajectories
var query = db.Set<TEntity>()
.Where(e => e.IdWell == idWell);
db.PlannedTrajectories.RemoveRange(query);
db.Set<TEntity>().RemoveRange(query);
return await db.SaveChangesAsync(token)
.ConfigureAwait(false);
}
/// <inheritdoc/>
public async Task<IEnumerable<TrajectoryGeoPlanDto>> GetAsync(int idWell, CancellationToken token)
public async Task<IEnumerable<Tdto>> GetAsync(int idWell, CancellationToken token)
{
var well = wellService.GetOrDefault(idWell)
?? throw new ArgumentInvalidException(nameof(idWell), "idWell doesn`t exist");
var offsetHours = well.Timezone.Hours;
var query = db.PlannedTrajectories
var query = db.Set<TEntity>()
.AsNoTracking()
.Where(x => x.IdWell == idWell);
.Where(x => x.IdWell == well.Id);
var entities = await query
.OrderBy(e => e.WellboreDepth)
.ToArrayAsync(token);
var result = entities
.Select(r => Convert(r, offsetHours));
return result;
}
/// <inheritdoc/>
public async Task<int> UpdateAsync(TrajectoryGeoPlanDto row, CancellationToken token)
public async Task<int> UpdateAsync(Tdto row, CancellationToken token)
{
var offsetHours = wellService.GetTimezone(row.IdWell).Hours;
var entity = Convert(row, offsetHours);
db.PlannedTrajectories.Update(entity);
db.Set<TEntity>().Update(entity);
return await db.SaveChangesAsync(token)
.ConfigureAwait(false);
}
private TrajectoryGeoPlanDto Convert(PlannedTrajectory entity, double offsetHours)
private static Tdto Convert(TEntity entity, double offsetHours)
{
var dto = entity.Adapt<TrajectoryGeoPlanDto>();
var dto = entity.Adapt<Tdto>();
dto.UpdateDate = entity.UpdateDate.ToRemoteDateTime(offsetHours);
return dto;
}
private PlannedTrajectory Convert(TrajectoryGeoPlanDto dto, double offsetHours)
private static TEntity Convert(Tdto dto, double offsetHours)
{
var entity = dto.Adapt<PlannedTrajectory>();
var entity = dto.Adapt<TEntity>();
entity.UpdateDate = DateTime.Now.ToUtcDateTimeOffset(offsetHours);
return entity;
}

View File

@ -1,65 +0,0 @@
using AsbCloudApp.Data;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudDb.Model;
using AsbCloudDb.Model.WITS;
using Microsoft.EntityFrameworkCore;
namespace AsbCloudInfrastructure.Repository;
public class TrajectoryFactRepository : ITrajectoryFactRepository
{
private readonly IAsbCloudDbContext dbContext;
public TrajectoryFactRepository(IAsbCloudDbContext dbContext)
{
this.dbContext = dbContext;
}
public async Task<IEnumerable<TrajectoryGeoFactDto>> GetAsync(TrajectoryGeoFactRequest request, CancellationToken token) =>
(await BuildQuery(request)
.Where(coord => coord.Deptsvym.HasValue &&
coord.Svyinc.HasValue &&
coord.Svyazc.HasValue)
.AsNoTracking()
.ToArrayAsync(token))
.Select(r => new TrajectoryGeoFactDto
{
IdWell = request.IdWell,
AzimuthMagnetic = r.Svymtf,
VerticalDepth = r.Deptsvyv,
WellboreDepth = r.Deptsvym!.Value,
ZenithAngle = r.Svyinc!.Value,
AzimuthGeo = r.Svyazc!.Value
});
public Task<IEnumerable<TrajectoryGeoFactDto>> GetAsync(int idWell, CancellationToken token) =>
GetAsync(new TrajectoryGeoFactRequest
{
IdWell = idWell
}, token);
private IQueryable<Record7> BuildQuery(TrajectoryGeoFactRequest request)
{
var well = dbContext.Wells.SingleOrDefault(w => w.Id == request.IdWell);
if (well is null)
throw new ArgumentInvalidException($"Скважина с Id: {request.IdWell} не найдена", nameof(request.IdWell));
var query = dbContext.Record7.Where(r => r.IdTelemetry == well.IdTelemetry)
.Where(x => x.IdTelemetry == well.IdTelemetry);
if (request.GeDate.HasValue)
query = query.Where(r => r.DateTime >= request.GeDate.Value);
if (request.LeDate.HasValue)
query = query.Where(r => r.DateTime <= request.LeDate.Value);
return query.OrderBy(e => e.Deptsvym);
}
}

View File

@ -0,0 +1,76 @@
using AsbCloudApp.Data.Trajectory;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudDb.Model;
using AsbCloudDb.Model.WITS;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Repository
{
public class TrajectoryNnbRepository : ITrajectoryNnbRepository
{
private readonly IAsbCloudDbContext db;
public TrajectoryNnbRepository(IAsbCloudDbContext db)
{
this.db = db;
}
private IQueryable<Record7> BuildQuery(TrajectoryRequest request)
{
var well = db.Wells.SingleOrDefault(w => w.Id == request.IdWell);
if (well is null)
throw new ArgumentInvalidException($"Скважина с Id: {request.IdWell} не найдена", nameof(request.IdWell));
var query = db.Record7.Where(r => r.IdTelemetry == well.IdTelemetry)
.Where(x => x.IdTelemetry == well.IdTelemetry);
if (request.GeDate.HasValue)
query = query.Where(r => r.DateTime >= request.GeDate.Value);
if (request.LeDate.HasValue)
query = query.Where(r => r.DateTime <= request.LeDate.Value);
return query.OrderBy(e => e.Deptsvym);
}
public async Task<IEnumerable<TrajectoryGeoFactDto>> GetAsync(int idWell, CancellationToken token)
{
var request = new TrajectoryRequest()
{
IdWell = idWell,
};
var result = await GetByRequestAsync(request, token);
return result;
}
public async Task<IEnumerable<TrajectoryGeoFactDto>> GetByRequestAsync(TrajectoryRequest request, CancellationToken token)
{
var entities = (await BuildQuery(request)
.Where(coord => coord.Deptsvym.HasValue &&
coord.Svyinc.HasValue &&
coord.Svyazc.HasValue)
.AsNoTracking()
.ToArrayAsync(token));
var result = entities
.Select(coord => new TrajectoryGeoFactDto
{
IdWell = request.IdWell,
AzimuthMagnetic = coord.Svymtf,
VerticalDepth = coord.Deptsvyv,
WellboreDepth = coord.Deptsvym!.Value,
ZenithAngle = coord.Svyinc!.Value,
AzimuthGeo = coord.Svyazc!.Value
})
.ToArray();
return result;
}
}
}

View File

@ -19,13 +19,14 @@ using AsbCloudApp.Services.ProcessMaps.WellDrilling;
using AsbCloudApp.Services.Subsystems;
using AsbCloudDb.Model;
using Mapster;
using AsbCloudApp.Data.Trajectory;
namespace AsbCloudInfrastructure.Services.DailyReport;
public class DailyReportService : IDailyReportService
{
private readonly IWellService wellService;
private readonly ITrajectoryFactRepository trajectoryFactRepository;
private readonly ITrajectoryNnbRepository trajectoryFactNnbRepository;
private readonly IDailyReportRepository dailyReportRepository;
private readonly IScheduleRepository scheduleRepository;
private readonly IWellOperationRepository wellOperationRepository;
@ -34,7 +35,7 @@ public class DailyReportService : IDailyReportService
private readonly IDetectedOperationService detectedOperationService;
public DailyReportService(IWellService wellService,
ITrajectoryFactRepository trajectoryFactRepository,
ITrajectoryNnbRepository trajectoryFactNnbRepository,
IDailyReportRepository dailyReportRepository,
IScheduleRepository scheduleRepository,
IWellOperationRepository wellOperationRepository,
@ -43,7 +44,7 @@ public class DailyReportService : IDailyReportService
IDetectedOperationService detectedOperationService)
{
this.wellService = wellService;
this.trajectoryFactRepository = trajectoryFactRepository;
this.trajectoryFactNnbRepository = trajectoryFactNnbRepository;
this.dailyReportRepository = dailyReportRepository;
this.scheduleRepository = scheduleRepository;
this.wellOperationRepository = wellOperationRepository;
@ -259,7 +260,7 @@ public class DailyReportService : IDailyReportService
private async Task AddTrajectoryBlockAsync(DailyReportDto dailyReport, CancellationToken cancellationToken)
{
var trajectory = (await trajectoryFactRepository.GetAsync(new TrajectoryGeoFactRequest
var trajectory = (await trajectoryFactNnbRepository.GetByRequestAsync(new TrajectoryRequest
{
IdWell = dailyReport.IdWell,
GeDate = dailyReport.Date,

View File

@ -0,0 +1,85 @@
using AsbCloudApp.Data.Trajectory;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using ClosedXML.Excel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services.Trajectory.Export
{
public abstract class TrajectoryExportService<T> where T : TrajectoryGeoDto
{
private readonly IWellService wellService;
private readonly ITrajectoryRepository<T> trajectoryRepository;
public abstract string templateFileName { get; }
public abstract string usingTemplateFile { get; }
public abstract string sheetName { get; }
public abstract int headerRowsCount { get; }
public TrajectoryExportService(IWellService wellService, ITrajectoryRepository<T> trajectoryRepository)
{
this.wellService = wellService;
this.trajectoryRepository = trajectoryRepository;
}
protected abstract void AddCoordinatesToRow(IXLRow row, T trajectory);
public async Task<Stream> ExportAsync(int idWell, CancellationToken token)
{
var trajectorys = await trajectoryRepository.GetAsync(idWell, token);
return MakeExelFileStream(trajectorys);
}
public async Task<string> GetFileNameAsync(int idWell, CancellationToken token)
{
var caption = await wellService.GetWellCaptionByIdAsync(idWell, token);
return string.Format("{0}_{1}", caption, templateFileName);
}
public Stream GetTemplateFile()
{
var stream = System.Reflection.Assembly.GetExecutingAssembly()
.GetManifestResourceStream($"{usingTemplateFile}.{templateFileName}");
if (stream is null)
throw new Exception($"Область {usingTemplateFile} не содержит файла с названием {templateFileName}");
return stream;
}
private Stream MakeExelFileStream(IEnumerable<T> trajectories)
{
using Stream ecxelTemplateStream = GetTemplateFile();
using var workbook = new XLWorkbook(ecxelTemplateStream, XLEventTracking.Disabled);
AddTrajecoryToWorkbook(workbook, trajectories);
MemoryStream memoryStream = new MemoryStream();
workbook.SaveAs(memoryStream, new SaveOptions { });
memoryStream.Seek(0, SeekOrigin.Begin);
return memoryStream;
}
private void AddTrajecoryToWorkbook(XLWorkbook workbook, IEnumerable<T> trajectories)
{
if (trajectories.Any())
{
var sheet = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetName);
if (sheet is null)
throw new FileFormatException($"Лист с именем {sheetName} отсутствует, либо имеет некорректное название");
AddTrajecoryToSheet(sheet, trajectories);
}
}
private void AddTrajecoryToSheet(IXLWorksheet sheet, IEnumerable<T> trajectories)
{
var rowList = trajectories.ToList();
for (int i = 0; i < rowList.Count; i++)
{
var row = sheet.Row(1 + i + headerRowsCount);
AddCoordinatesToRow(row, rowList[i]);
}
}
}
}

View File

@ -0,0 +1,35 @@
using AsbCloudApp.Data.Trajectory;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using ClosedXML.Excel;
namespace AsbCloudInfrastructure.Services.Trajectory.Export
{
public class TrajectoryFactManualExportService : TrajectoryExportService<TrajectoryGeoFactDto>
{
public override string templateFileName { get; } = "TrajectoryFactManualTemplate.xlsx";
public override string usingTemplateFile { get; } = "AsbCloudInfrastructure.Services.Trajectory.Templates";
public override string sheetName { get; } = "Фактическая траектория";
public override int headerRowsCount { get; } = 2;
public TrajectoryFactManualExportService(
IWellService wellService,
ITrajectoryEditableRepository<TrajectoryGeoFactDto> factTrajectoryService)
: base(wellService, factTrajectoryService)
{
}
protected override void AddCoordinatesToRow(IXLRow row, TrajectoryGeoFactDto trajectory)
{
row.Cell(1).Value = trajectory.WellboreDepth;
row.Cell(2).Value = trajectory.ZenithAngle;
row.Cell(3).Value = trajectory.AzimuthGeo;
row.Cell(4).Value = trajectory.AzimuthMagnetic;
row.Cell(5).Value = trajectory.VerticalDepth;
row.Cell(6).Value = trajectory.Comment;
}
}
}

View File

@ -0,0 +1,35 @@
using AsbCloudApp.Data.Trajectory;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using ClosedXML.Excel;
namespace AsbCloudInfrastructure.Services.Trajectory.Export
{
public class TrajectoryFactNnbExportService : TrajectoryExportService<TrajectoryGeoFactDto>
{
public override string templateFileName { get; } = "TrajectoryFactNnbTemplate.xlsx";
public override string usingTemplateFile { get; } = "AsbCloudInfrastructure.Services.Trajectory.Templates";
public override string sheetName { get; } = "Фактическая ннб-траектория";
public override int headerRowsCount { get; } = 2;
public TrajectoryFactNnbExportService(
IWellService wellService,
ITrajectoryNnbRepository nnbTrajectoryService)
: base(wellService, nnbTrajectoryService)
{
}
protected override void AddCoordinatesToRow(IXLRow row, TrajectoryGeoFactDto trajectory)
{
row.Cell(1).Value = trajectory.WellboreDepth;
row.Cell(2).Value = trajectory.ZenithAngle;
row.Cell(3).Value = trajectory.AzimuthGeo;
row.Cell(4).Value = trajectory.AzimuthMagnetic;
row.Cell(5).Value = trajectory.VerticalDepth;
row.Cell(6).Value = trajectory.Comment;
}
}
}

View File

@ -0,0 +1,38 @@
using AsbCloudApp.Data.Trajectory;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using ClosedXML.Excel;
namespace AsbCloudInfrastructure.Services.Trajectory.Export
{
public class TrajectoryPlanExportService : TrajectoryExportService<TrajectoryGeoPlanDto>
{
/*
* password for PlannedTrajectoryTemplate.xlsx is Drill2022
*/
public override string templateFileName { get; } = "TrajectoryPlanTemplate.xlsx";
public override string usingTemplateFile { get; } = "AsbCloudInfrastructure.Services.Trajectory.Templates";
public override string sheetName { get; } = "Плановая траектория";
public override int headerRowsCount { get; } = 2;
public TrajectoryPlanExportService(
IWellService wellService,
ITrajectoryEditableRepository<TrajectoryGeoPlanDto> trajectoryPlanService)
: base(wellService, trajectoryPlanService)
{
}
protected override void AddCoordinatesToRow(IXLRow row, TrajectoryGeoPlanDto trajectory)
{
row.Cell(1).Value = trajectory.WellboreDepth;
row.Cell(2).Value = trajectory.ZenithAngle;
row.Cell(3).Value = trajectory.AzimuthGeo;
row.Cell(4).Value = trajectory.AzimuthMagnetic;
row.Cell(5).Value = trajectory.VerticalDepth;
row.Cell(6).Value = trajectory.Radius;
row.Cell(7).Value = trajectory.Comment;
}
}
}

View File

@ -0,0 +1,30 @@
using AsbCloudApp.Data.Trajectory;
using ClosedXML.Excel;
namespace AsbCloudInfrastructure.Services.Trajectory.Import
{
public class TrajectoryFactManualParserService : TrajectoryParserService<TrajectoryGeoFactDto>
{
public override string templateFileName { get; } = "TrajectoryFactManualTemplate.xlsx";
public override string usingTemplateFile { get; } = "AsbCloudInfrastructure.Services.Trajectory.Templates";
public override string sheetName { get; } = "Фактическая траектория";
public override int headerRowsCount { get; } = 2;
protected override TrajectoryGeoFactDto ParseRow(IXLRow row)
{
var trajectoryRow = new TrajectoryGeoFactDto
{
WellboreDepth = row.Cell(1).GetCellValue<double>(),
ZenithAngle = row.Cell(2).GetCellValue<double>(),
AzimuthGeo = row.Cell(3).GetCellValue<double>(),
AzimuthMagnetic = row.Cell(4).GetCellValue<double>(),
VerticalDepth = row.Cell(5).GetCellValue<double>(),
Comment = row.Cell(6).GetCellValue<string?>()
};
//TODO: Добавить валидацию модели IValidatableObject
return trajectoryRow;
}
}
}

View File

@ -0,0 +1,78 @@
using AsbCloudApp.Data.Trajectory;
using ClosedXML.Excel;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace AsbCloudInfrastructure.Services.Trajectory.Import
{
public abstract class TrajectoryParserService<T>
where T : TrajectoryGeoDto
{
public abstract string templateFileName { get; }
public abstract string usingTemplateFile { get; }
public abstract string sheetName { get; }
public abstract int headerRowsCount { get; }
protected abstract T ParseRow(IXLRow row);
public IEnumerable<T> Import(Stream stream)
{
using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled);
var trajectoryRows = ParseFileStream(stream);
return trajectoryRows;
}
private IEnumerable<T> ParseFileStream(Stream stream)
{
using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled);
return ParseWorkbook(workbook);
}
private IEnumerable<T> ParseWorkbook(IXLWorkbook workbook)
{
var sheetTrajectory = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetName);
if (sheetTrajectory is null)
throw new FileFormatException($"Книга excel не содержит листа {sheetName}.");
var trajectoryRows = ParseSheet(sheetTrajectory);
return trajectoryRows;
}
private IEnumerable<T> ParseSheet(IXLWorksheet sheet)
{
if (sheet.RangeUsed().RangeAddress.LastAddress.ColumnNumber < 6)
throw new FileFormatException($"Лист {sheet.Name} содержит меньшее количество столбцов.");
var count = sheet.RowsUsed().Count() - headerRowsCount;
if (count > 1024)
throw new FileFormatException($"Лист {sheet.Name} содержит слишком большое количество строк.");
if (count <= 0)
throw new FileFormatException($"Лист {sheet.Name} некорректного формата либо пустой");
var trajectoryRows = new List<T>(count);
var parseErrors = new List<string>();
for (int i = 0; i < count; i++)
{
var row = sheet.Row(1 + i + headerRowsCount);
try
{
var trajectoryRow = ParseRow(row);
trajectoryRows.Add(trajectoryRow);
}
catch (FileFormatException ex)
{
parseErrors.Add(ex.Message);
}
}
if (parseErrors.Any())
throw new FileFormatException(string.Join("\r\n", parseErrors));
return trajectoryRows;
}
}
}

View File

@ -0,0 +1,33 @@
using AsbCloudApp.Data.Trajectory;
using ClosedXML.Excel;
namespace AsbCloudInfrastructure.Services.Trajectory.Import
{
public class TrajectoryPlanParserService : TrajectoryParserService<TrajectoryGeoPlanDto>
{
public override string templateFileName { get; } = "TrajectoryPlanTemplate.xlsx";
public override string usingTemplateFile { get; } = "AsbCloudInfrastructure.Services.Trajectory.Templates";
public override string sheetName { get; } = "Плановая траектория";
public override int headerRowsCount { get; } = 2;
protected override TrajectoryGeoPlanDto ParseRow(IXLRow row)
{
var trajectoryRow = new TrajectoryGeoPlanDto
{
WellboreDepth = row.Cell(1).GetCellValue<double>(),
ZenithAngle = row.Cell(2).GetCellValue<double>(),
AzimuthGeo = row.Cell(3).GetCellValue<double>(),
AzimuthMagnetic = row.Cell(4).GetCellValue<double>(),
VerticalDepth = row.Cell(5).GetCellValue<double>(),
Radius = row.Cell(6).GetCellValue<double>(),
Comment = row.Cell(7).GetCellValue<string?>()
};
//TODO: Добавить валидацию модели IValidatableObject
return trajectoryRow;
}
}
}

View File

@ -1,196 +0,0 @@
using AsbCloudApp.Data;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using ClosedXML.Excel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services.Trajectory
{
public class PlannedTrajectoryImportService : IPlannedTrajectoryImportService
{
/*
* password for PlannedTrajectoryTemplate.xlsx is Drill2022
*/
private readonly IWellService wellService;
private readonly ITrajectoryPlanRepository plannedTrajectoryService;
private const string templateFileName = "PlannedTrajectoryTemplate.xlsx";
private const string usingTemplateFile = "AsbCloudInfrastructure.Services.Trajectory";
private const string sheetNamePlannedTrajectory = "Плановая траектория";
private const int headerRowsCount = 2;
private const int ColumnWellboreDepth = 1;
private const int ColumnZenithAngle = 2;
private const int ColumnAzimuthGeo = 3;
private const int ColumnAzimuthMagnetic = 4;
private const int ColumnVerticalDepth = 5;
private const int ColumnRadius = 6;
private const int ColumnComment = 7;
public PlannedTrajectoryImportService(IWellService wellService, ITrajectoryPlanRepository plannedTrajectoryService)
{
this.wellService = wellService;
this.plannedTrajectoryService = plannedTrajectoryService;
}
public Stream GetTemplateFile()
{
var stream = System.Reflection.Assembly.GetExecutingAssembly()
.GetManifestResourceStream($"{usingTemplateFile}.{templateFileName}");
if (stream is null)
throw new Exception($"Область {usingTemplateFile} не содержит файла с названием {templateFileName}");
return stream;
}
public async Task<string> GetFileNameAsync(int idWell, CancellationToken token)
{
var fileName = await wellService.GetWellCaptionByIdAsync(idWell, token) + "_plannedTrajectory.xlsx";
return fileName;
}
public async Task<Stream> ExportAsync(int idWell, CancellationToken token)
{
var plannedTrajectorys = await plannedTrajectoryService.GetAsync(idWell, token);
return MakeExelFileStream(plannedTrajectorys);
}
private Stream MakeExelFileStream(IEnumerable<TrajectoryGeoPlanDto> plannedTrajectories)
{
using Stream ecxelTemplateStream = GetTemplateFile();
using var workbook = new XLWorkbook(ecxelTemplateStream, XLEventTracking.Disabled);
AddPlannedTrajecoryToWorkbook(workbook, plannedTrajectories);
MemoryStream memoryStream = new MemoryStream();
workbook.SaveAs(memoryStream, new SaveOptions { });
memoryStream.Seek(0, SeekOrigin.Begin);
return memoryStream;
}
private static void AddPlannedTrajecoryToWorkbook(XLWorkbook workbook, IEnumerable<TrajectoryGeoPlanDto> plannedTrajectories)
{
if (plannedTrajectories.Any())
{
var sheet = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetNamePlannedTrajectory);
if (sheet is null)
throw new FileFormatException($"Лист с именем {sheetNamePlannedTrajectory} отсутствует, либо имеет некорректное название");
AddPlannedTrajecoryToSheet(sheet, plannedTrajectories);
}
}
private static void AddPlannedTrajecoryToSheet(IXLWorksheet sheet, IEnumerable<TrajectoryGeoPlanDto> plannedTrajectories)
{
var rowList = plannedTrajectories.ToList();
for (int i = 0; i < rowList.Count; i++)
{
var row = sheet.Row(1 + i + headerRowsCount);
AddCoordinatesToRow(row, rowList[i]);
}
}
private static void AddCoordinatesToRow(IXLRow row, TrajectoryGeoPlanDto trajectory)
{
row.Cell(ColumnWellboreDepth).Value = trajectory.WellboreDepth;
row.Cell(ColumnZenithAngle).Value = trajectory.ZenithAngle;
row.Cell(ColumnAzimuthGeo).Value = trajectory.AzimuthGeo;
row.Cell(ColumnAzimuthMagnetic).Value = trajectory.AzimuthMagnetic;
row.Cell(ColumnVerticalDepth).Value = trajectory.VerticalDepth;
row.Cell(ColumnRadius).Value = trajectory.Radius;
row.Cell(ColumnComment).Value = trajectory.Comment;
}
public async Task<int> ImportAsync(int idWell, int idUser, Stream stream, bool deletePrevRows, CancellationToken token)
{
using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled);
var trajectoryRows = ParseFileStream(stream);
foreach (var row in trajectoryRows)
{
row.IdWell = idWell;
row.IdUser = idUser;
}
var rowsCount = await SavePlannedTrajectoryAsync(idWell, trajectoryRows, deletePrevRows, token);
return rowsCount;
}
private async Task<int> SavePlannedTrajectoryAsync(int idWell, IEnumerable<TrajectoryGeoPlanDto> newRows, bool deletePrevRow, CancellationToken token)
{
if (deletePrevRow)
await plannedTrajectoryService.DeleteByIdWellAsync(idWell, token);
var rowsCount = await plannedTrajectoryService.AddRangeAsync(newRows, token);
return rowsCount;
}
private IEnumerable<TrajectoryGeoPlanDto> ParseFileStream(Stream stream)
{
using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled);
return ParseWorkbook(workbook);
}
private IEnumerable<TrajectoryGeoPlanDto> ParseWorkbook(IXLWorkbook workbook)
{
var sheetPlannedTrajectory = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetNamePlannedTrajectory);
if (sheetPlannedTrajectory is null)
throw new FileFormatException($"Книга excel не содержит листа {sheetNamePlannedTrajectory}.");
var plannedTrajectoryRows = ParseSheet(sheetPlannedTrajectory);
return plannedTrajectoryRows;
}
private IEnumerable<TrajectoryGeoPlanDto> ParseSheet(IXLWorksheet sheet)
{
if (sheet.RangeUsed().RangeAddress.LastAddress.ColumnNumber < 7)
throw new FileFormatException($"Лист {sheet.Name} содержит меньшее количество столбцов.");
var count = sheet.RowsUsed().Count() - headerRowsCount;
if (count > 1024)
throw new FileFormatException($"Лист {sheet.Name} содержит слишком большое количество строк.");
if (count <= 0)
throw new FileFormatException($"Лист {sheet.Name} некорректного формата либо пустой");
var trajectoryRows = new List<TrajectoryGeoPlanDto>(count);
var parseErrors = new List<string>();
for (int i = 0; i < count; i++)
{
var row = sheet.Row(1 + i + headerRowsCount);
try
{
var trajectoryRow = ParseRow(row);
trajectoryRows.Add(trajectoryRow);
}
catch (FileFormatException ex)
{
parseErrors.Add(ex.Message);
}
}
if (parseErrors.Any())
throw new FileFormatException(string.Join("\r\n", parseErrors));
return trajectoryRows;
}
private TrajectoryGeoPlanDto ParseRow(IXLRow row)
{
var trajectoryRow = new TrajectoryGeoPlanDto
{
WellboreDepth = row.Cell(ColumnWellboreDepth).GetCellValue<double>(),
ZenithAngle = row.Cell(ColumnZenithAngle).GetCellValue<double>(),
AzimuthGeo = row.Cell(ColumnAzimuthGeo).GetCellValue<double>(),
AzimuthMagnetic = row.Cell(ColumnAzimuthMagnetic).GetCellValue<double>(),
VerticalDepth = row.Cell(ColumnVerticalDepth).GetCellValue<double>(),
Radius = row.Cell(ColumnRadius).GetCellValue<double>(),
Comment = row.Cell(ColumnComment).GetCellValue<string?>()
};
return trajectoryRow;
}
}
}

View File

@ -0,0 +1 @@
password for PlannedTrajectoryTemplate.xlsx is Drill2022

View File

@ -1,5 +1,6 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.Trajectory;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using System;
using System.Collections.Generic;
using System.Linq;
@ -91,7 +92,7 @@ abstract class TrajectoryBaseService<TGeo, TCartesian>
class TrajectoryPlanService: TrajectoryBaseService<TrajectoryGeoPlanDto, TrajectoryCartesianPlanDto>
{
public TrajectoryPlanService(ITrajectoryPlanRepository repository)
public TrajectoryPlanService(ITrajectoryEditableRepository<TrajectoryGeoPlanDto> repository)
:base(repository)
{}
@ -109,7 +110,14 @@ class TrajectoryPlanService: TrajectoryBaseService<TrajectoryGeoPlanDto, Traject
class TrajectoryFactService : TrajectoryBaseService<TrajectoryGeoFactDto, TrajectoryCartesianFactDto>
{
public TrajectoryFactService(ITrajectoryFactRepository repository)
public TrajectoryFactService(ITrajectoryEditableRepository<TrajectoryGeoFactDto> repository)
: base(repository)
{ }
}
class TrajectoryNnbService : TrajectoryBaseService<TrajectoryGeoFactDto, TrajectoryCartesianFactDto>
{
public TrajectoryNnbService(ITrajectoryNnbRepository repository)
: base(repository)
{ }
}
@ -119,11 +127,16 @@ public class TrajectoryService
{
private TrajectoryPlanService trajectoryPlanService;
private TrajectoryFactService trajectoryFactService;
private TrajectoryNnbService trajectoryNnbService;
public TrajectoryService(ITrajectoryPlanRepository plannedRepository, ITrajectoryFactRepository factRepository)
public TrajectoryService(
ITrajectoryEditableRepository<TrajectoryGeoPlanDto> planRepository,
ITrajectoryEditableRepository<TrajectoryGeoFactDto> factRepository,
ITrajectoryNnbRepository nnbRepository)
{
trajectoryPlanService = new TrajectoryPlanService(plannedRepository);
trajectoryPlanService = new TrajectoryPlanService(planRepository);
trajectoryFactService = new TrajectoryFactService(factRepository);
trajectoryNnbService = new TrajectoryNnbService(nnbRepository);
}
/// <summary>
@ -132,12 +145,13 @@ public class TrajectoryService
/// <param name="idWell">ключ скважины</param>
/// <param name="token"></param>
/// <returns></returns>
public async Task<PlanFactBase<IEnumerable<TrajectoryCartesianPlanDto>, IEnumerable<TrajectoryCartesianFactDto>>> GetTrajectoryCartesianAsync(int idWell, CancellationToken token)
public async Task<TrajectoryPlanFactDto<IEnumerable<TrajectoryCartesianPlanDto>, IEnumerable<TrajectoryCartesianFactDto>>> GetTrajectoryCartesianAsync(int idWell, CancellationToken token)
{
var result = new PlanFactBase<IEnumerable<TrajectoryCartesianPlanDto>, IEnumerable<TrajectoryCartesianFactDto>>();
var result = new TrajectoryPlanFactDto<IEnumerable<TrajectoryCartesianPlanDto>, IEnumerable<TrajectoryCartesianFactDto>>();
result.Plan = await trajectoryPlanService.GetAsync(idWell, token);
result.Fact = await trajectoryFactService.GetAsync(idWell, token);
result.FactManual = await trajectoryFactService.GetAsync(idWell, token);
result.FactNnb = await trajectoryNnbService.GetAsync(idWell, token);
return result;
}

View File

@ -8,6 +8,16 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<None Remove="UnitTests\Services\Trajectory\PlannedTrajectoryTemplate.xlsx" />
<None Remove="UnitTests\Services\Trajectory\Templates\TrajectoryFactManualTemplate.xlsx" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="UnitTests\Services\Trajectory\Templates\TrajectoryFactManualTemplate.xlsx" />
<EmbeddedResource Include="UnitTests\Services\Trajectory\Templates\TrajectoryPlanTemplate.xlsx" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
<PackageReference Include="NSubstitute" Version="5.1.0" />

View File

@ -11,6 +11,7 @@ using AsbCloudApp.Data.DailyReport.Blocks.TimeBalance;
using AsbCloudApp.Data.DetectedOperation;
using AsbCloudApp.Data.ProcessMaps.Report;
using AsbCloudApp.Data.Subsystems;
using AsbCloudApp.Data.Trajectory;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
@ -199,7 +200,7 @@ public class DailyReportServiceTest
};
private readonly IWellService wellServiceMock = Substitute.For<IWellService>();
private readonly ITrajectoryFactRepository trajectoryFactRepositoryMock = Substitute.For<ITrajectoryFactRepository>();
private readonly ITrajectoryNnbRepository trajectoryFactNnbRepositoryMock = Substitute.For<ITrajectoryNnbRepository>();
private readonly IDailyReportRepository dailyReportRepositoryMock = Substitute.For<IDailyReportRepository>();
private readonly IScheduleRepository scheduleRepositoryMock = Substitute.For<IScheduleRepository>();
private readonly IWellOperationRepository wellOperationRepositoryMock = Substitute.For<IWellOperationRepository>();
@ -233,7 +234,7 @@ public class DailyReportServiceTest
};
dailyReportService = new DailyReportService(wellServiceMock,
trajectoryFactRepositoryMock,
trajectoryFactNnbRepositoryMock,
dailyReportRepositoryMock,
scheduleRepositoryMock,
wellOperationRepositoryMock,
@ -253,7 +254,7 @@ public class DailyReportServiceTest
wellServiceMock.GetOrDefaultAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
.ReturnsForAnyArgs(fakeWell);
trajectoryFactRepositoryMock.GetAsync(Arg.Any<TrajectoryGeoFactRequest>(), Arg.Any<CancellationToken>())
trajectoryFactNnbRepositoryMock.GetAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
.ReturnsForAnyArgs(new[] { fakeLastFactTrajectory });
wellOperationRepositoryMock.GetAsync(Arg.Any<WellOperationRequest>(), Arg.Any<CancellationToken>())

View File

@ -0,0 +1,127 @@
using AsbCloudApp.Data.Trajectory;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudInfrastructure.Services.Trajectory.Export;
using NSubstitute;
using System;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace AsbCloudWebApi.Tests.UnitTests.Services.Trajectory
{
public class TrajectoryExportTest
{
private IWellService wellService;
private readonly ITrajectoryEditableRepository<TrajectoryGeoPlanDto> trajectoryPlanRepository;
private readonly TrajectoryPlanExportService trajectoryPlanExportService;
private readonly ITrajectoryEditableRepository<TrajectoryGeoFactDto> trajectoryFactManualReposirory;
private readonly TrajectoryFactManualExportService trajectoryFactManualExportService;
private readonly ITrajectoryNnbRepository trajectoryFactNnbRepository;
private readonly TrajectoryFactNnbExportService trajectoryFactNnbExportService;
private readonly int idWell = 4;
private readonly TrajectoryGeoPlanDto[] trajectoryPlanRows = new TrajectoryGeoPlanDto[2] {
new TrajectoryGeoPlanDto() {
Id = 1,
AzimuthGeo = 1,
AzimuthMagnetic = 2,
Comment = "комментарий",
IdUser = 1,
IdWell = 4,
Radius = 3,
UpdateDate = DateTime.Now,
VerticalDepth = 100,
WellboreDepth = 100,
ZenithAngle = 10
},
new TrajectoryGeoPlanDto() {
Id = 2,
AzimuthGeo = 1,
AzimuthMagnetic = 2,
Comment = "комментарий",
IdUser = 1,
IdWell = 4,
Radius = 3,
UpdateDate = DateTime.Now,
VerticalDepth = 100,
WellboreDepth = 100,
ZenithAngle = 10
},
};
private readonly TrajectoryGeoFactDto[] trajectoryFactRows = new TrajectoryGeoFactDto[2] {
new TrajectoryGeoFactDto() {
Id = 1,
AzimuthGeo = 1,
AzimuthMagnetic = 2,
Comment = "комментарий",
IdUser = 1,
IdWell = 4,
UpdateDate = DateTime.Now,
VerticalDepth = 100,
WellboreDepth = 100,
ZenithAngle = 10
},
new TrajectoryGeoFactDto() {
Id = 2,
AzimuthGeo = 1,
AzimuthMagnetic = 2,
Comment = "комментарий",
IdUser = 1,
IdWell = 4,
UpdateDate = DateTime.Now,
VerticalDepth = 100,
WellboreDepth = 100,
ZenithAngle = 10
},
};
public TrajectoryExportTest()
{
wellService = Substitute.For<IWellService>();
trajectoryPlanRepository = Substitute.For<ITrajectoryEditableRepository<TrajectoryGeoPlanDto>>();
trajectoryPlanExportService = new TrajectoryPlanExportService(wellService, trajectoryPlanRepository);
trajectoryFactManualReposirory = Substitute.For<ITrajectoryEditableRepository<TrajectoryGeoFactDto>>();
trajectoryFactManualExportService = new TrajectoryFactManualExportService(wellService, trajectoryFactManualReposirory);
trajectoryFactNnbRepository = Substitute.For<ITrajectoryNnbRepository>();
trajectoryFactNnbExportService = new TrajectoryFactNnbExportService(wellService, trajectoryFactNnbRepository);
}
[Fact]
public async Task Export_trajectory_plan()
{
trajectoryPlanRepository.GetAsync(idWell, CancellationToken.None)
.Returns(trajectoryPlanRows);
var stream = await trajectoryPlanExportService.ExportAsync(idWell, CancellationToken.None);
Assert.True(stream.Length > 0);
}
[Fact]
public async Task Export_trajectory_fact_manual()
{
trajectoryFactManualReposirory.GetAsync(idWell, CancellationToken.None)
.Returns(trajectoryFactRows);
var stream = await trajectoryFactManualExportService.ExportAsync(idWell, CancellationToken.None);
Assert.True(stream.Length > 0);
}
[Fact]
public async Task Export_trajectory_fact_nnb()
{
trajectoryFactNnbRepository.GetAsync(idWell, CancellationToken.None)
.Returns(trajectoryFactRows);
var stream = await trajectoryFactNnbExportService.ExportAsync(idWell, CancellationToken.None);
Assert.True(stream.Length > 0);
}
}
}

View File

@ -0,0 +1,48 @@
using AsbCloudInfrastructure.Services.Trajectory.Import;
using System.Linq;
using Xunit;
namespace AsbCloudWebApi.Tests.UnitTests.Services.Trajectory
{
public class TrajectoryImportTest
{
private readonly TrajectoryPlanParserService trajectoryPlanImportService;
private readonly TrajectoryFactManualParserService trajectoryFactManualImportService;
private string usingTemplateFile = "AsbCloudWebApi.Tests.UnitTests.Services.Trajectory.Templates";
public TrajectoryImportTest()
{
trajectoryPlanImportService = new TrajectoryPlanParserService();
trajectoryFactManualImportService = new TrajectoryFactManualParserService();
}
[Fact]
public void Import_trajectory_plan()
{
var stream = System.Reflection.Assembly.GetExecutingAssembly()
.GetManifestResourceStream($"{usingTemplateFile}.TrajectoryPlanTemplate.xlsx");
if (stream is null)
Assert.Fail("Файла для импорта не существует");
var trajectoryRows = trajectoryPlanImportService.Import(stream);
Assert.Equal(3, trajectoryRows.Count());
}
[Fact]
public void Import_trajectory_fact_manual()
{
var stream = System.Reflection.Assembly.GetExecutingAssembly()
.GetManifestResourceStream($"{usingTemplateFile}.TrajectoryFactManualTemplate.xlsx");
if (stream is null)
Assert.Fail("Файла для импорта не существует");
var trajectoryRows = trajectoryFactManualImportService.Import(stream);
Assert.Equal(4, trajectoryRows.Count());
}
}
}

View File

@ -2,7 +2,9 @@
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Data.Trajectory;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudInfrastructure.Services.Trajectory;
using NSubstitute;
using Xunit;
@ -11,14 +13,15 @@ namespace AsbCloudWebApi.Tests.UnitTests.Services;
public class TrajectoryVisualizationServiceTest
{
private readonly ITrajectoryPlanRepository trajectoryPlanRepositoryMock = Substitute.For<ITrajectoryPlanRepository>();
private readonly ITrajectoryFactRepository trajectoryFactRepositoryMock = Substitute.For<ITrajectoryFactRepository>();
private readonly ITrajectoryEditableRepository<TrajectoryGeoPlanDto> trajectoryPlanRepositoryMock = Substitute.For<ITrajectoryEditableRepository<TrajectoryGeoPlanDto>>();
private readonly ITrajectoryEditableRepository<TrajectoryGeoFactDto> trajectoryFactRepositoryMock = Substitute.For<ITrajectoryEditableRepository<TrajectoryGeoFactDto>>();
private readonly ITrajectoryNnbRepository trajectoryNnbRepositoryMock = Substitute.For<ITrajectoryNnbRepository>();
private readonly TrajectoryService trajectoryService;
public TrajectoryVisualizationServiceTest()
{
trajectoryService = new TrajectoryService(trajectoryPlanRepositoryMock, trajectoryFactRepositoryMock);
trajectoryService = new TrajectoryService(trajectoryPlanRepositoryMock, trajectoryFactRepositoryMock, trajectoryNnbRepositoryMock);
}
[Fact]
@ -42,18 +45,30 @@ public class TrajectoryVisualizationServiceTest
new() { WellboreDepth = 0, ZenithAngle = 0, AzimuthGeo = 20 },
};
var nnbTrajectory = new TrajectoryGeoFactDto[]
{
new() { WellboreDepth = 0, ZenithAngle = 0, AzimuthGeo = 0 },
new() { WellboreDepth = 30, ZenithAngle = 30, AzimuthGeo = 10 },
new() { WellboreDepth = 0, ZenithAngle = 0, AzimuthGeo = 20 },
new() { WellboreDepth = 0, ZenithAngle = 10, AzimuthGeo = 20 },
};
trajectoryPlanRepositoryMock.GetAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
.ReturnsForAnyArgs(plannedTrajectory);
trajectoryFactRepositoryMock.GetAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
.ReturnsForAnyArgs(actualTrajectory);
trajectoryNnbRepositoryMock.GetAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
.ReturnsForAnyArgs(nnbTrajectory);
//act
var result = await trajectoryService.GetTrajectoryCartesianAsync(1, CancellationToken.None);
//assert
Assert.Equal(plannedTrajectory.Count(), result.Plan?.Count());
Assert.Equal(actualTrajectory.Count(), result.Fact?.Count());
Assert.Equal(actualTrajectory.Count(), result.FactManual?.Count());
Assert.Equal(nnbTrajectory.Count(), result.FactNnb?.Count());
}
[Fact]
@ -80,18 +95,32 @@ public class TrajectoryVisualizationServiceTest
new() { WellboreDepth = 50, ZenithAngle = 0, AzimuthGeo = 0 },
};
var nnbTrajectory = new TrajectoryGeoFactDto[]
{
new() { WellboreDepth = 0, ZenithAngle = 0, AzimuthGeo = 0 },
new() { WellboreDepth = 0, ZenithAngle = 0, AzimuthGeo = 0 },
new() { WellboreDepth = 20, ZenithAngle = 0, AzimuthGeo = 0 },
new() { WellboreDepth = 20, ZenithAngle = 0, AzimuthGeo = 0 },
new() { WellboreDepth = 30, ZenithAngle = 0, AzimuthGeo = 0 },
new() { WellboreDepth = 50, ZenithAngle = 0, AzimuthGeo = 0 },
};
trajectoryPlanRepositoryMock.GetAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
.ReturnsForAnyArgs(plannedTrajectory);
trajectoryFactRepositoryMock.GetAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
.ReturnsForAnyArgs(actualTrajectory);
trajectoryNnbRepositoryMock.GetAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
.ReturnsForAnyArgs(nnbTrajectory);
//act
var result = await trajectoryService.GetTrajectoryCartesianAsync(1, CancellationToken.None);
//assert
var lastPointPlan = result.Plan!.Last();
var lastPointFact = result.Fact!.Last();
var lastPointFact = result.FactManual!.Last();
var lastPointNnb = result.FactNnb!.Last();
Assert.Equal(0d, lastPointPlan.X, 0.1d);
Assert.Equal(-50d, lastPointPlan.Y, 0.1d);
@ -100,6 +129,10 @@ public class TrajectoryVisualizationServiceTest
Assert.Equal(0d, lastPointFact.X, 0.1d);
Assert.Equal(-50d, lastPointFact.Y, 0.1d);
Assert.Equal(0d, lastPointFact.Z, 0.1d);
Assert.Equal(0d, lastPointNnb.X, 0.1d);
Assert.Equal(-50d, lastPointNnb.Y, 0.1d);
Assert.Equal(0d, lastPointNnb.Z, 0.1d);
}
[Fact]
@ -123,18 +156,30 @@ public class TrajectoryVisualizationServiceTest
new() { WellboreDepth = 20, ZenithAngle = 0, AzimuthGeo = 0 },
};
var nnbTrajectory = new TrajectoryGeoFactDto[]
{
new() { WellboreDepth = 0, ZenithAngle = 0, AzimuthGeo = 0 },
new() { WellboreDepth = 10, ZenithAngle = 30, AzimuthGeo = 30 },
new() { WellboreDepth = 20, ZenithAngle = 0, AzimuthGeo = 0 },
};
trajectoryPlanRepositoryMock.GetAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
.ReturnsForAnyArgs(plannedTrajectory);
trajectoryFactRepositoryMock.GetAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
.ReturnsForAnyArgs(actualTrajectory);
trajectoryNnbRepositoryMock.GetAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
.ReturnsForAnyArgs(nnbTrajectory);
//act
var result = await trajectoryService.GetTrajectoryCartesianAsync(1, CancellationToken.None);
//assert
var lastPointPlan = result.Plan!.Last();
var lastPointFact = result.Fact!.Last();
var lastPointFact = result.FactManual!.Last();
var lastPointNnb = result.FactManual!.Last();
Assert.InRange(lastPointPlan.Z, -10 - tolerancePlan, 0 - tolerancePlan);
Assert.InRange(lastPointPlan.Y, -20 - tolerancePlan, -10 + tolerancePlan);
@ -143,5 +188,9 @@ public class TrajectoryVisualizationServiceTest
Assert.InRange(lastPointFact.Z, -10 - toleranceFact, 0 - toleranceFact);
Assert.InRange(lastPointFact.Y, -20 - toleranceFact, -10 + toleranceFact);
Assert.InRange(lastPointFact.X, 0 + toleranceFact, 10 - toleranceFact);
Assert.InRange(lastPointNnb.Z, -10 - toleranceFact, 0 - toleranceFact);
Assert.InRange(lastPointNnb.Y, -20 - toleranceFact, -10 + toleranceFact);
Assert.InRange(lastPointNnb.X, 0 + toleranceFact, 10 - toleranceFact);
}
}

View File

@ -1,42 +0,0 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Repositories;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace AsbCloudWebApi.Controllers;
/// <summary>
/// Фактическая траектория
/// </summary>
[Authorize]
[ApiController]
[Route("api/well/{idWell}/[controller]")]
public class FactTrajectoryController : ControllerBase
{
private readonly ITrajectoryFactRepository trajectoryFactRepository;
public FactTrajectoryController(ITrajectoryFactRepository trajectoryFactRepository)
{
this.trajectoryFactRepository = trajectoryFactRepository;
}
/// <summary>
/// Метод получения всех строк траекторий по id скважины
/// </summary>
/// <param name="idWell">Id скважины</param>
/// <param name="cancellationToken">Токен отмены операции</param>
/// <returns></returns>
[HttpGet]
[ProducesResponseType(typeof(IEnumerable<TrajectoryGeoPlanDto>), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetRowsAsync([FromRoute] int idWell,
CancellationToken cancellationToken)
{
var factTrajectories = await trajectoryFactRepository.GetAsync(idWell,
cancellationToken);
return Ok(factTrajectories);
}
}

View File

@ -0,0 +1,82 @@
using AsbCloudApp.Data.Trajectory;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudInfrastructure.Services.Trajectory.Export;
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.Trajectory
{
/// <summary>
/// Плановые и фактические траектории (загрузка и хранение)
/// </summary>
[ApiController]
[Authorize]
public abstract class TrajectoryController<TDto> : ControllerBase
where TDto : TrajectoryGeoDto
{
protected abstract string fileName { get; set; }
private readonly IWellService wellService;
private readonly TrajectoryExportService<TDto> trajectoryExportService;
private readonly ITrajectoryRepository<TDto> trajectoryRepository;
public TrajectoryController(IWellService wellService,
TrajectoryExportService<TDto> trajectoryExportService,
ITrajectoryRepository<TDto> trajectoryRepository)
{
this.trajectoryExportService = trajectoryExportService;
this.wellService = wellService;
this.trajectoryRepository = trajectoryRepository;
}
/// <summary>
/// Формируем excel файл с текущими строками траектории
/// </summary>
/// <param name="idWell">id скважины</param>
/// <param name="token"> Токен отмены задачи </param>
/// <returns>Запрашиваемый файл</returns>
[HttpGet("export")]
[ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK, "application/octet-stream")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> ExportAsync([FromRoute] int idWell, CancellationToken token)
{
if (!await CanUserAccessToWellAsync(idWell,
token).ConfigureAwait(false))
return Forbid();
var stream = await trajectoryExportService.ExportAsync(idWell, token);
var fileName = await trajectoryExportService.GetFileNameAsync(idWell, token);
return File(stream, "application/octet-stream", fileName);
}
/// <summary>
/// Получаем список всех строк координат траектории (для клиента)
/// </summary>
/// <param name="idWell">ключ скважины</param>
/// <param name="token"> Токен отмены задачи </param>
/// <returns>Список добавленных координат траектории</returns>
[HttpGet]
public async Task<ActionResult<IEnumerable<TDto>>> GetAsync(int idWell, CancellationToken token)
{
if (!await CanUserAccessToWellAsync(idWell,
token).ConfigureAwait(false))
return Forbid();
var result = await trajectoryRepository.GetAsync(idWell, token);
return Ok(result);
}
protected async Task<bool> CanUserAccessToWellAsync(int idWell, CancellationToken token)
{
int? idCompany = User.GetCompanyId();
return idCompany is not null && await wellService.IsCompanyInvolvedInWellAsync((int)idCompany,
idWell, token).ConfigureAwait(false);
}
}
}

View File

@ -1,7 +1,8 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.Trajectory;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudInfrastructure.Services.Trajectory;
using AsbCloudInfrastructure.Services.Trajectory.Export;
using AsbCloudInfrastructure.Services.Trajectory.Import;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@ -10,35 +11,40 @@ using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudWebApi.Controllers
namespace AsbCloudWebApi.Controllers.Trajectory
{
/// <summary>
/// Плановая траектория (загрузка и хранение)
/// Плановые и фактические траектории (загрузка и хранение)
/// </summary>
[Route("api/well/{idWell}/plannedTrajectory")]
[ApiController]
[Authorize]
public class PlannedTrajectoryController : ControllerBase
public abstract class TrajectoryEditableController<Tdto> : TrajectoryController<Tdto>
where Tdto : TrajectoryGeoDto
{
private readonly IWellService wellService;
private readonly IPlannedTrajectoryImportService plannedTrajectoryImportService;
private readonly ITrajectoryPlanRepository plannedTrajectoryRepository;
private readonly TrajectoryService trajectoryVisualizationService;
protected override string fileName { get; set; }
public PlannedTrajectoryController(IWellService wellService,
IPlannedTrajectoryImportService plannedTrajectoryImportService,
ITrajectoryPlanRepository plannedTrajectoryRepository,
TrajectoryService trajectoryVisualizationService)
private readonly TrajectoryParserService<Tdto> trajectoryImportService;
private readonly TrajectoryExportService<Tdto> trajectoryExportService;
private readonly ITrajectoryEditableRepository<Tdto> trajectoryRepository;
public TrajectoryEditableController(IWellService wellService,
TrajectoryParserService<Tdto> trajectoryImportService,
TrajectoryExportService<Tdto> trajectoryExportService,
ITrajectoryEditableRepository<Tdto> trajectoryRepository)
: base(
wellService,
trajectoryExportService,
trajectoryRepository)
{
this.plannedTrajectoryImportService = plannedTrajectoryImportService;
this.wellService = wellService;
this.plannedTrajectoryRepository = plannedTrajectoryRepository;
this.trajectoryVisualizationService = trajectoryVisualizationService;
this.trajectoryImportService = trajectoryImportService;
this.trajectoryExportService = trajectoryExportService;
this.trajectoryRepository = trajectoryRepository;
}
/// <summary>
/// Возвращает excel шаблон для заполнения строк плановой траектории
/// Возвращает excel шаблон для заполнения строк траектории
/// </summary>
/// <returns>Запрашиваемый файл</returns>
[HttpGet("template")]
@ -47,27 +53,7 @@ namespace AsbCloudWebApi.Controllers
[ProducesResponseType(StatusCodes.Status204NoContent)]
public IActionResult GetTemplate()
{
var stream = plannedTrajectoryImportService.GetTemplateFile();
var fileName = "ЕЦП_шаблон_файла_плановая_траектория.xlsx";
return File(stream, "application/octet-stream", fileName);
}
/// <summary>
/// Формируем excel файл с текущими строками плановой траектории
/// </summary>
/// <param name="idWell">id скважины</param>
/// <param name="token"> Токен отмены задачи </param>
/// <returns>Запрашиваемый файл</returns>
[HttpGet("export")]
[ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK, "application/octet-stream")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> ExportAsync([FromRoute] int idWell, CancellationToken token)
{
if (!await CanUserAccessToWellAsync(idWell,
token).ConfigureAwait(false))
return Forbid();
var stream = await plannedTrajectoryImportService.ExportAsync(idWell, token);
var fileName = await plannedTrajectoryImportService.GetFileNameAsync(idWell, token);
var stream = trajectoryExportService.GetTemplateFile();
return File(stream, "application/octet-stream", fileName);
}
@ -102,8 +88,19 @@ namespace AsbCloudWebApi.Controllers
try
{
var result = await plannedTrajectoryImportService.ImportAsync(idWell, idUser.Value, stream, deleteBeforeImport, token);
return Ok(result);
var trajectoryRows = trajectoryImportService.Import(stream);
foreach (var row in trajectoryRows)
{
row.IdWell = idWell;
row.IdUser = idUser.Value;
}
if (deleteBeforeImport)
await trajectoryRepository.DeleteByIdWellAsync(idWell, token);
var rowsCount = await trajectoryRepository.AddRangeAsync(trajectoryRows, token);
return Ok(rowsCount);
}
catch (FileFormatException ex)
{
@ -111,22 +108,6 @@ namespace AsbCloudWebApi.Controllers
}
}
/// <summary>
/// Получаем список всех строк координат плановой траектории (для клиента)
/// </summary>
/// <param name="idWell">id скважины</param>
/// <param name="token"> Токен отмены задачи </param>
/// <returns>Список добавленных координат плановой траектории</returns>
[HttpGet]
[ProducesResponseType(typeof(IEnumerable<TrajectoryGeoPlanDto>), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetAsync([FromRoute] int idWell, CancellationToken token)
{
if (!await CanUserAccessToWellAsync(idWell,
token).ConfigureAwait(false))
return Forbid();
var result = await plannedTrajectoryRepository.GetAsync(idWell, token);
return Ok(result);
}
/// <summary>
/// Добавить одну новую строчку координат для плановой траектории
@ -137,7 +118,7 @@ namespace AsbCloudWebApi.Controllers
/// <returns>количество успешно записанных строк в БД</returns>
[HttpPost]
[ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> AddAsync(int idWell, [FromBody] TrajectoryGeoPlanDto row,
public async Task<IActionResult> AddAsync(int idWell, [FromBody] Tdto row,
CancellationToken token)
{
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
@ -147,7 +128,7 @@ namespace AsbCloudWebApi.Controllers
return Forbid();
row.IdUser = idUser.Value;
row.IdWell = idWell;
var result = await plannedTrajectoryRepository.AddAsync(row, token);
var result = await trajectoryRepository.AddAsync(row, token);
return Ok(result);
}
@ -160,7 +141,7 @@ namespace AsbCloudWebApi.Controllers
/// <returns>количество успешно записанных строк в БД</returns>
[HttpPost("range")]
[ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> AddRangeAsync(int idWell, [FromBody] IEnumerable<TrajectoryGeoPlanDto> rows,
public async Task<IActionResult> AddRangeAsync(int idWell, [FromBody] IEnumerable<Tdto> rows,
CancellationToken token)
{
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
@ -173,7 +154,7 @@ namespace AsbCloudWebApi.Controllers
item.IdUser = idUser.Value;
item.IdWell = idWell;
}
var result = await plannedTrajectoryRepository.AddRangeAsync(rows, token);
var result = await trajectoryRepository.AddRangeAsync(rows, token);
return Ok(result);
}
@ -188,7 +169,7 @@ namespace AsbCloudWebApi.Controllers
[HttpPut("{idRow}")]
[ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> UpdateAsync(int idWell, int idRow,
[FromBody] TrajectoryGeoPlanDto row, CancellationToken token)
[FromBody] Tdto row, CancellationToken token)
{
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
return Forbid();
@ -198,7 +179,7 @@ namespace AsbCloudWebApi.Controllers
row.Id = idRow;
row.IdUser = idUser.Value;
row.IdWell = idWell;
var result = await plannedTrajectoryRepository.UpdateAsync(row, token);
var result = await trajectoryRepository.UpdateAsync(row, token);
return Ok(result);
}
@ -217,35 +198,9 @@ namespace AsbCloudWebApi.Controllers
token).ConfigureAwait(false))
return Forbid();
var result = await plannedTrajectoryRepository.DeleteRangeAsync(new int[] { idRow }, token);
var result = await trajectoryRepository.DeleteRangeAsync(new int[] { idRow }, token);
return Ok(result);
}
/// <summary>
/// Получение координат для визуализации траектории (плановой и фактической)
/// </summary>
/// <param name="idWell"></param>
/// <param name="token"></param>
/// <returns></returns>
[HttpGet("trajectoryCartesianPlanFact")]
[ProducesResponseType(typeof(PlanFactBase<IEnumerable<TrajectoryCartesianPlanDto>, IEnumerable<TrajectoryCartesianFactDto>>), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetTrajectoryCartesianPlanFactAsync(int idWell, CancellationToken token)
{
if (!await CanUserAccessToWellAsync(idWell,
token).ConfigureAwait(false))
return Forbid();
var result = await trajectoryVisualizationService.GetTrajectoryCartesianAsync(idWell, token);
return Ok(result);
}
private async Task<bool> CanUserAccessToWellAsync(int idWell, CancellationToken token)
{
int? idCompany = User.GetCompanyId();
return idCompany is not null && await wellService.IsCompanyInvolvedInWellAsync((int)idCompany,
idWell, token).ConfigureAwait(false);
}
}
}

View File

@ -0,0 +1,30 @@
using AsbCloudApp.Data.Trajectory;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudInfrastructure.Services.Trajectory.Export;
using AsbCloudInfrastructure.Services.Trajectory.Import;
using Microsoft.AspNetCore.Mvc;
namespace AsbCloudWebApi.Controllers.Trajectory;
/// <summary>
/// Фактическая траектория
/// </summary>
[ApiController]
[Route("api/well/{idWell}/[controller]")]
public class TrajectoryFactManualController : TrajectoryEditableController<TrajectoryGeoFactDto>
{
protected override string fileName { get; set; }
public TrajectoryFactManualController(IWellService wellService,
TrajectoryFactManualParserService factTrajectoryImportService,
TrajectoryFactManualExportService factTrajectoryExportService,
ITrajectoryEditableRepository<TrajectoryGeoFactDto> trajectoryFactRepository)
: base(
wellService,
factTrajectoryImportService,
factTrajectoryExportService,
trajectoryFactRepository)
{
fileName = "ЕЦП_шаблон_файлаактическая_траектория.xlsx";
}
}

View File

@ -0,0 +1,30 @@
using AsbCloudApp.Data.Trajectory;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudInfrastructure.Services.Trajectory.Export;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace AsbCloudWebApi.Controllers.Trajectory;
/// <summary>
/// Фактическая траектория из ННБ
/// </summary>
[Authorize]
[ApiController]
[Route("api/well/{idWell}/[controller]")]
public class TrajectoryFactNnbController : TrajectoryController<TrajectoryGeoFactDto>
{
protected override string fileName { get; set; }
public TrajectoryFactNnbController(
ITrajectoryNnbRepository trajectoryNnbRepository,
TrajectoryFactNnbExportService trajectoryExportService,
IWellService wellService)
: base(
wellService,
trajectoryExportService,
trajectoryNnbRepository)
{
fileName = "ЕЦП_шаблон_файлаактическая_ннбраектория.xlsx";
}
}

View File

@ -0,0 +1,58 @@
using AsbCloudApp.Data.Trajectory;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudInfrastructure.Services.Trajectory;
using AsbCloudInfrastructure.Services.Trajectory.Import;
using AsbCloudInfrastructure.Services.Trajectory.Export;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudWebApi.Controllers.Trajectory
{
/// <summary>
/// Плановая траектория (загрузка и хранение)
/// </summary>
[Route("api/well/{idWell}/[controller]")]
[ApiController]
public class TrajectoryPlanController : TrajectoryEditableController<TrajectoryGeoPlanDto>
{
private readonly TrajectoryService trajectoryVisualizationService;
public TrajectoryPlanController(IWellService wellService,
TrajectoryPlanParserService trajectoryPlanImportService,
TrajectoryPlanExportService trajectoryPlanExportService,
ITrajectoryEditableRepository<TrajectoryGeoPlanDto> trajectoryPlanRepository,
TrajectoryService trajectoryVisualizationService)
: base(
wellService,
trajectoryPlanImportService,
trajectoryPlanExportService,
trajectoryPlanRepository)
{
fileName = "ЕЦП_шаблон_файла_плановая_траектория.xlsx";
this.trajectoryVisualizationService = trajectoryVisualizationService;
}
/// <summary>
/// Получение координат для визуализации траектории (плановой и фактической)
/// </summary>
/// <param name="idWell"></param>
/// <param name="token"></param>
/// <returns></returns>
[HttpGet("trajectoryCartesianPlanFact")]
[ProducesResponseType(typeof(TrajectoryPlanFactDto<IEnumerable<TrajectoryCartesianPlanDto>, IEnumerable<TrajectoryCartesianFactDto>>), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetTrajectoryCartesianPlanFactAsync(int idWell, CancellationToken token)
{
if (!await CanUserAccessToWellAsync(idWell,
token).ConfigureAwait(false))
return Forbid();
var result = await trajectoryVisualizationService.GetTrajectoryCartesianAsync(idWell, token);
return Ok(result);
}
}
}