DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/Trajectory/PlannedTrajectoryImportService.cs

212 lines
9.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 _wellboreDepth = row.Cell(ColumnWellboreDepth).Value;
var _zenithAngle = row.Cell(ColumnZenithAngle).Value;
var _azimuthGeo = row.Cell(ColumnAzimuthGeo).Value;
var _azimuthMagnetic = row.Cell(ColumnAzimuthMagnetic).Value;
var _verticalDepth = row.Cell(ColumnVerticalDepth).Value;
var _radius = row.Cell(ColumnRadius).Value;
var _comment = row.Cell(ColumnComment).Value;
var trajectoryRow = new TrajectoryGeoPlanDto();
static double getDoubleValue(object value, string nameParam, IXLRow row)
{
if (value is double _value)
return _value;
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} - некорректные данные - {nameParam}");
}
trajectoryRow.WellboreDepth = getDoubleValue(_wellboreDepth, "Глубина по стволу", row);
trajectoryRow.ZenithAngle = getDoubleValue(_zenithAngle, "Зенитный угол", row);
trajectoryRow.AzimuthGeo = getDoubleValue(_azimuthGeo, "Азимут географический", row);
trajectoryRow.AzimuthMagnetic = getDoubleValue(_azimuthMagnetic, "Азимут магнитный", row);
trajectoryRow.VerticalDepth = getDoubleValue(_verticalDepth, "Глубина вертикальная", row);
trajectoryRow.Radius = getDoubleValue(_radius, "Радиус цели", row);
if (_comment is not null)
trajectoryRow.Comment = _comment.ToString();
return trajectoryRow;
}
}
}