forked from ddrilling/AsbCloudServer
Merge branch 'dev' into feature/28518041-rtk-report-export
This commit is contained in:
commit
ca4b058b94
@ -19,6 +19,11 @@ public abstract class ProcessMapPlanBaseDto : ChangeLogAbstract, IId, IWellRelat
|
|||||||
[Range(1, int.MaxValue, ErrorMessage = "Id секции скважины не может быть меньше 1")]
|
[Range(1, int.MaxValue, ErrorMessage = "Id секции скважины не может быть меньше 1")]
|
||||||
public int IdWellSectionType { get; set; }
|
public int IdWellSectionType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Название секции
|
||||||
|
/// </summary>
|
||||||
|
public string? Section { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Глубина по стволу от, м
|
/// Глубина по стволу от, м
|
||||||
/// <para>
|
/// <para>
|
||||||
@ -41,6 +46,6 @@ public abstract class ProcessMapPlanBaseDto : ChangeLogAbstract, IId, IWellRelat
|
|||||||
public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||||
{
|
{
|
||||||
if(DepthEnd <= DepthStart)
|
if(DepthEnd <= DepthStart)
|
||||||
yield return new ("глубина окончания должна быть больше глубины начала", new string[] {nameof(DepthEnd), nameof(DepthStart) });
|
yield return new ("Глубина окончания должна быть больше глубины начала", new string[] {nameof(DepthEnd), nameof(DepthStart) });
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -13,6 +13,11 @@ public class ProcessMapPlanDrillingDto : ProcessMapPlanBaseDto
|
|||||||
[Range(1, 2, ErrorMessage = "Id режима должен быть либо 1-ротор либо 2-слайд")]
|
[Range(1, 2, ErrorMessage = "Id режима должен быть либо 1-ротор либо 2-слайд")]
|
||||||
public int IdMode { get; set; }
|
public int IdMode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Название режима бурения
|
||||||
|
/// </summary>
|
||||||
|
public string? Mode { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Осевая нагрузка, т план
|
/// Осевая нагрузка, т план
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace AsbCloudApp.Data.Trajectory
|
namespace AsbCloudApp.Data.Trajectory
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Базовая географическая траектория
|
/// Базовая географическая траектория
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class TrajectoryGeoDto : IId
|
public abstract class TrajectoryGeoDto : IId, IValidatableObject
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ИД строки с координатами
|
/// ИД строки с координатами
|
||||||
@ -49,5 +52,11 @@ namespace AsbCloudApp.Data.Trajectory
|
|||||||
/// ИД пользователя
|
/// ИД пользователя
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int IdUser { get; set; }
|
public int IdUser { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||||
|
{
|
||||||
|
return Enumerable.Empty<ValidationResult>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Requests.ParserOptions;
|
using AsbCloudApp.Requests.ParserOptions;
|
||||||
|
|
||||||
@ -10,10 +8,8 @@ namespace AsbCloudApp.Services;
|
|||||||
/// Сервис парсинга
|
/// Сервис парсинга
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TDto"></typeparam>
|
/// <typeparam name="TDto"></typeparam>
|
||||||
/// <typeparam name="TOptions"></typeparam>
|
public interface IParserService<TDto> : IParserService
|
||||||
public interface IParserService<TDto, in TOptions> : IParserService
|
|
||||||
where TDto : class, IId
|
where TDto : class, IId
|
||||||
where TOptions : IParserOptionsRequest
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Распарсить файл
|
/// Распарсить файл
|
||||||
@ -21,7 +17,8 @@ public interface IParserService<TDto, in TOptions> : IParserService
|
|||||||
/// <param name="file"></param>
|
/// <param name="file"></param>
|
||||||
/// <param name="options"></param>
|
/// <param name="options"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
ParserResultDto<TDto> Parse(Stream file, TOptions options);
|
ParserResultDto<TDto> Parse<TOptions>(Stream file, TOptions options)
|
||||||
|
where TOptions : IParserOptionsRequest;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получение шаблона для заполнения
|
/// Получение шаблона для заполнения
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.IO;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
@ -7,6 +8,7 @@ namespace AsbCloudApp.Services.ProcessMaps;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Сервис импорта РТК
|
/// Сервис импорта РТК
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Obsolete]
|
||||||
public interface IProcessMapPlanImportService
|
public interface IProcessMapPlanImportService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
<EmbeddedResource Include="Services\DetectOperations\DetectOperations.xlsx" />
|
<EmbeddedResource Include="Services\DetectOperations\DetectOperations.xlsx" />
|
||||||
<EmbeddedResource Include="Services\DailyReport\DailyReportTemplate.xlsx" />
|
<EmbeddedResource Include="Services\DailyReport\DailyReportTemplate.xlsx" />
|
||||||
<EmbeddedResource Include="Services\DrillTestReport\DrillTestReportTemplate.xlsx" />
|
<EmbeddedResource Include="Services\DrillTestReport\DrillTestReportTemplate.xlsx" />
|
||||||
|
<EmbeddedResource Include="Services\ProcessMapPlan\Templates\ProcessMapPlanDrillingTemplate.xlsx" />
|
||||||
<EmbeddedResource Include="Services\ProcessMaps\Report\ProcessMapReportDataSaubStatTemplate.xlsx" />
|
<EmbeddedResource Include="Services\ProcessMaps\Report\ProcessMapReportDataSaubStatTemplate.xlsx" />
|
||||||
<EmbeddedResource Include="Services\Trajectory\Templates\TrajectoryFactNnbTemplate.xlsx" />
|
<EmbeddedResource Include="Services\Trajectory\Templates\TrajectoryFactNnbTemplate.xlsx" />
|
||||||
<EmbeddedResource Include="Services\Trajectory\Templates\TrajectoryFactManualTemplate.xlsx" />
|
<EmbeddedResource Include="Services\Trajectory\Templates\TrajectoryFactManualTemplate.xlsx" />
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Data.DrillTestReport;
|
using AsbCloudApp.Data.DrillTestReport;
|
||||||
using AsbCloudApp.Data.Manuals;
|
using AsbCloudApp.Data.Manuals;
|
||||||
@ -45,6 +46,8 @@ using AsbCloudDb.Model.WellSections;
|
|||||||
using AsbCloudInfrastructure.Services.ProcessMaps;
|
using AsbCloudInfrastructure.Services.ProcessMaps;
|
||||||
using AsbCloudApp.Data.ProcessMapPlan;
|
using AsbCloudApp.Data.ProcessMapPlan;
|
||||||
using AsbCloudApp.Requests;
|
using AsbCloudApp.Requests;
|
||||||
|
using AsbCloudInfrastructure.Services.Parser;
|
||||||
|
using AsbCloudInfrastructure.Services.ProcessMapPlan.Parser;
|
||||||
using AsbCloudInfrastructure.Services.Trajectory.Parser;
|
using AsbCloudInfrastructure.Services.Trajectory.Parser;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure
|
namespace AsbCloudInfrastructure
|
||||||
@ -206,8 +209,6 @@ namespace AsbCloudInfrastructure
|
|||||||
services.AddTransient<TrajectoryPlanExportService>();
|
services.AddTransient<TrajectoryPlanExportService>();
|
||||||
services.AddTransient<TrajectoryFactManualExportService>();
|
services.AddTransient<TrajectoryFactManualExportService>();
|
||||||
services.AddTransient<TrajectoryFactNnbExportService>();
|
services.AddTransient<TrajectoryFactNnbExportService>();
|
||||||
services.AddTransient<TrajectoryPlanParserService>();
|
|
||||||
services.AddTransient<TrajectoryFactManualParserService>();
|
|
||||||
services.AddTransient<IWellOperationRepository, WellOperationRepository>();
|
services.AddTransient<IWellOperationRepository, WellOperationRepository>();
|
||||||
services.AddTransient<IDailyReportService, DailyReportService>();
|
services.AddTransient<IDailyReportService, DailyReportService>();
|
||||||
services.AddTransient<IDetectedOperationService, DetectedOperationService>();
|
services.AddTransient<IDetectedOperationService, DetectedOperationService>();
|
||||||
@ -335,7 +336,9 @@ namespace AsbCloudInfrastructure
|
|||||||
services.AddTransient<IWellOperationCategoryRepository, WellOperationCategoryRepository>();
|
services.AddTransient<IWellOperationCategoryRepository, WellOperationCategoryRepository>();
|
||||||
services.AddTransient<IDetectedOperationRepository, DetectedOperationRepository>();
|
services.AddTransient<IDetectedOperationRepository, DetectedOperationRepository>();
|
||||||
|
|
||||||
services.AddSingleton<ParserServiceFactory>();
|
services.AddTransient<TrajectoryPlanParser>();
|
||||||
|
services.AddTransient<TrajectoryFactManualParser>();
|
||||||
|
services.AddTransient<ProcessMapPlanDrillingParser>();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using AsbCloudApp.Data;
|
|
||||||
using AsbCloudApp.Requests.ParserOptions;
|
|
||||||
using AsbCloudApp.Services;
|
|
||||||
using ClosedXML.Excel;
|
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure;
|
|
||||||
|
|
||||||
public abstract class ParserServiceBase<TDto, TOptions> : IParserService<TDto, TOptions>
|
|
||||||
where TDto : class, IId
|
|
||||||
where TOptions : IParserOptionsRequest
|
|
||||||
{
|
|
||||||
protected readonly IServiceProvider serviceProvider;
|
|
||||||
|
|
||||||
protected ParserServiceBase(IServiceProvider serviceProvider)
|
|
||||||
{
|
|
||||||
this.serviceProvider = serviceProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract ParserResultDto<TDto> Parse(Stream file, TOptions options);
|
|
||||||
public abstract Stream GetTemplateFile();
|
|
||||||
|
|
||||||
protected virtual ParserResultDto<TDto> ParseExcelSheet(IXLWorksheet sheet,
|
|
||||||
Func<IXLRow, ValidationResultDto<TDto>> parseRow,
|
|
||||||
int columnCount,
|
|
||||||
int headerRowsCount = 0)
|
|
||||||
{
|
|
||||||
if (sheet.RangeUsed().RangeAddress.LastAddress.ColumnNumber < columnCount)
|
|
||||||
throw new FileFormatException($"Лист {sheet.Name} содержит меньшее количество столбцов.");
|
|
||||||
|
|
||||||
var count = sheet.RowsUsed().Count() - headerRowsCount;
|
|
||||||
|
|
||||||
if (count > 1024)
|
|
||||||
throw new FileFormatException($"Лист {sheet.Name} содержит слишком большое количество строк.");
|
|
||||||
|
|
||||||
if (count <= 0)
|
|
||||||
return new ParserResultDto<TDto>();
|
|
||||||
|
|
||||||
var dtos = new List<ValidationResultDto<TDto>>(count);
|
|
||||||
var warnings = new List<ValidationResult>();
|
|
||||||
|
|
||||||
for (var i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
var row = sheet.Row(1 + i + headerRowsCount);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var dto = parseRow.Invoke(row);
|
|
||||||
dtos.Add(dto);
|
|
||||||
}
|
|
||||||
catch (FileFormatException ex)
|
|
||||||
{
|
|
||||||
var warning = new ValidationResult(ex.Message);
|
|
||||||
warnings.Add(warning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var parserResult = new ParserResultDto<TDto>
|
|
||||||
{
|
|
||||||
Item = dtos
|
|
||||||
};
|
|
||||||
|
|
||||||
if (warnings.Any())
|
|
||||||
parserResult.Warnings = warnings;
|
|
||||||
|
|
||||||
return parserResult;
|
|
||||||
}
|
|
||||||
}
|
|
@ -30,7 +30,6 @@ public abstract class ChangeLogRepositoryAbstract<TDto, TEntity, TRequest> : ICh
|
|||||||
var result = 0;
|
var result = 0;
|
||||||
if (dtos.Any())
|
if (dtos.Any())
|
||||||
{
|
{
|
||||||
using var transaction = await db.Database.BeginTransactionAsync(token);
|
|
||||||
var entities = dtos.Select(Convert);
|
var entities = dtos.Select(Convert);
|
||||||
var creation = DateTimeOffset.UtcNow;
|
var creation = DateTimeOffset.UtcNow;
|
||||||
var dbSet = db.Set<TEntity>();
|
var dbSet = db.Set<TEntity>();
|
||||||
@ -47,7 +46,6 @@ public abstract class ChangeLogRepositoryAbstract<TDto, TEntity, TRequest> : ICh
|
|||||||
}
|
}
|
||||||
|
|
||||||
result += await SaveChangesWithExceptionHandling(token);
|
result += await SaveChangesWithExceptionHandling(token);
|
||||||
await transaction.CommitAsync(token);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -82,6 +80,8 @@ public abstract class ChangeLogRepositoryAbstract<TDto, TEntity, TRequest> : ICh
|
|||||||
}
|
}
|
||||||
|
|
||||||
using var transaction = db.Database.BeginTransaction();
|
using var transaction = db.Database.BeginTransaction();
|
||||||
|
try
|
||||||
|
{
|
||||||
foreach (var entity in entitiesToDelete)
|
foreach (var entity in entitiesToDelete)
|
||||||
{
|
{
|
||||||
entity.IdState = ChangeLogAbstract.IdStateReplaced;
|
entity.IdState = ChangeLogAbstract.IdStateReplaced;
|
||||||
@ -104,9 +104,16 @@ public abstract class ChangeLogRepositoryAbstract<TDto, TEntity, TRequest> : ICh
|
|||||||
}
|
}
|
||||||
|
|
||||||
result += await SaveChangesWithExceptionHandling(token);
|
result += await SaveChangesWithExceptionHandling(token);
|
||||||
|
|
||||||
await transaction.CommitAsync(token);
|
await transaction.CommitAsync(token);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
await transaction.RollbackAsync(token);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<int> UpdateOrInsertRange(int idUser, IEnumerable<TDto> dtos, CancellationToken token)
|
public async Task<int> UpdateOrInsertRange(int idUser, IEnumerable<TDto> dtos, CancellationToken token)
|
||||||
{
|
{
|
||||||
@ -146,11 +153,20 @@ public abstract class ChangeLogRepositoryAbstract<TDto, TEntity, TRequest> : ICh
|
|||||||
{
|
{
|
||||||
var result = 0;
|
var result = 0;
|
||||||
using var transaction = await db.Database.BeginTransactionAsync(token);
|
using var transaction = await db.Database.BeginTransactionAsync(token);
|
||||||
|
try
|
||||||
|
{
|
||||||
result += await Clear(idUser, request, token);
|
result += await Clear(idUser, request, token);
|
||||||
result += await InsertRange(idUser, dtos, token);
|
result += await InsertRange(idUser, dtos, token);
|
||||||
|
|
||||||
await transaction.CommitAsync(token);
|
await transaction.CommitAsync(token);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
await transaction.RollbackAsync(token);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<int> DeleteRange(int idUser, IEnumerable<int> ids, CancellationToken token)
|
public async Task<int> DeleteRange(int idUser, IEnumerable<int> ids, CancellationToken token)
|
||||||
{
|
{
|
||||||
|
94
AsbCloudInfrastructure/Services/Parser/Cell.cs
Normal file
94
AsbCloudInfrastructure/Services/Parser/Cell.cs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using ClosedXML.Excel;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Services.Parser;
|
||||||
|
|
||||||
|
public class Cell
|
||||||
|
{
|
||||||
|
private static IDictionary<Type, Func<IXLCell, object?>> converters = new Dictionary<Type, Func<IXLCell, object?>>()
|
||||||
|
{
|
||||||
|
{ typeof(bool), cell => cell.GetBoolean() },
|
||||||
|
{ typeof(double), cell => cell.GetValue<double>() },
|
||||||
|
{ typeof(float), cell => cell.GetValue<float>() },
|
||||||
|
{ typeof(long), cell => cell.GetValue<long>() },
|
||||||
|
{ typeof(ulong), cell => cell.GetValue<ulong>() },
|
||||||
|
{ typeof(int), cell => cell.GetValue<int>() },
|
||||||
|
{ typeof(uint), cell => cell.GetValue<uint>() },
|
||||||
|
{ typeof(short), cell => cell.GetValue<short>() },
|
||||||
|
{ typeof(ushort), cell => cell.GetValue<ushort>() },
|
||||||
|
{ typeof(string), cell => cell.GetString() },
|
||||||
|
|
||||||
|
{
|
||||||
|
typeof(DateTime), cell =>
|
||||||
|
{
|
||||||
|
if (cell.DataType == XLDataType.DateTime)
|
||||||
|
return cell.GetDateTime();
|
||||||
|
|
||||||
|
var stringValue = cell.GetString();
|
||||||
|
return DateTime.Parse(stringValue);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
typeof(DateTimeOffset), cell =>
|
||||||
|
{
|
||||||
|
var stringValue = cell.GetString();
|
||||||
|
return DateTimeOffset.Parse(stringValue);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
typeof(DateOnly), cell =>
|
||||||
|
{
|
||||||
|
var stringValue = cell.GetString();
|
||||||
|
return DateOnly.Parse(stringValue);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
typeof(TimeOnly), cell =>
|
||||||
|
{
|
||||||
|
var stringValue = cell.GetString();
|
||||||
|
return TimeOnly.Parse(stringValue);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
typeof(TimeSpan), cell =>
|
||||||
|
{
|
||||||
|
if (cell.DataType == XLDataType.TimeSpan)
|
||||||
|
return cell.GetTimeSpan();
|
||||||
|
|
||||||
|
var stringValue = cell.GetString();
|
||||||
|
return TimeSpan.Parse(stringValue);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly Type type;
|
||||||
|
|
||||||
|
public Cell(int columnNumber,
|
||||||
|
Type type)
|
||||||
|
{
|
||||||
|
ColumnNumber = columnNumber;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ColumnNumber { get; }
|
||||||
|
|
||||||
|
public object? GetValueFromCell(IXLCell cell)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return converters[type].Invoke(cell);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
var message = string.Format(XLExtentions.InvalidValueTemplate, cell.Worksheet.Name, cell.Address.RowNumber,
|
||||||
|
cell.Address.ColumnNumber);
|
||||||
|
throw new FileFormatException(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
135
AsbCloudInfrastructure/Services/Parser/ParserExcelService.cs
Normal file
135
AsbCloudInfrastructure/Services/Parser/ParserExcelService.cs
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Requests.ParserOptions;
|
||||||
|
using AsbCloudApp.Services;
|
||||||
|
using ClosedXML.Excel;
|
||||||
|
using Mapster;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Services.Parser;
|
||||||
|
|
||||||
|
public abstract class ParserExcelService<TDto> : IParserService<TDto>
|
||||||
|
where TDto : class, IValidatableObject, IId
|
||||||
|
{
|
||||||
|
protected abstract string SheetName { get; }
|
||||||
|
|
||||||
|
protected virtual int HeaderRowsCount => 0;
|
||||||
|
|
||||||
|
protected abstract string TemplateFileName { get; }
|
||||||
|
|
||||||
|
protected abstract IDictionary<string, Cell> Cells { get; }
|
||||||
|
|
||||||
|
public virtual ParserResultDto<TDto> Parse<TOptions>(Stream file, TOptions options)
|
||||||
|
where TOptions : IParserOptionsRequest
|
||||||
|
{
|
||||||
|
using var workbook = new XLWorkbook(file);
|
||||||
|
var sheet = workbook.GetWorksheet(SheetName);
|
||||||
|
var dtos = ParseExcelSheet(sheet);
|
||||||
|
return dtos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual Stream GetTemplateFile() =>
|
||||||
|
Assembly.GetExecutingAssembly().GetTemplateCopyStream(TemplateFileName)
|
||||||
|
?? throw new ArgumentNullException($"Файл '{TemplateFileName}' не найден");
|
||||||
|
|
||||||
|
|
||||||
|
protected virtual IDictionary<string, object?> ParseRow(IXLRow xlRow)
|
||||||
|
{
|
||||||
|
var cells = Cells.ToDictionary(x => x.Key, x =>
|
||||||
|
{
|
||||||
|
var columnNumber = x.Value.ColumnNumber;
|
||||||
|
var xlCell = xlRow.Cell(columnNumber);
|
||||||
|
var cellValue = x.Value.GetValueFromCell(xlCell);
|
||||||
|
return cellValue;
|
||||||
|
});
|
||||||
|
|
||||||
|
return cells;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual TDto BuildDto(IDictionary<string, object?> row, int rowNumber)
|
||||||
|
{
|
||||||
|
var dto = row.Adapt<TDto>();
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ValidationResultDto<TDto> Validate(TDto dto, int rowNumber)
|
||||||
|
{
|
||||||
|
var validationResults = new List<ValidationResult>();
|
||||||
|
|
||||||
|
var isValid = dto.Validate(validationResults);
|
||||||
|
|
||||||
|
if (isValid)
|
||||||
|
{
|
||||||
|
var validDto = new ValidationResultDto<TDto>
|
||||||
|
{
|
||||||
|
Item = dto
|
||||||
|
};
|
||||||
|
|
||||||
|
return validDto;
|
||||||
|
}
|
||||||
|
|
||||||
|
var columnsDict = Cells.ToDictionary(x => x.Key, x => x.Value.ColumnNumber);
|
||||||
|
|
||||||
|
var invalidDto = new ValidationResultDto<TDto>
|
||||||
|
{
|
||||||
|
Item = dto,
|
||||||
|
Warnings = validationResults
|
||||||
|
.SelectMany(v => v.MemberNames
|
||||||
|
.Where(columnsDict.ContainsKey)
|
||||||
|
.Select(m =>
|
||||||
|
{
|
||||||
|
var columnNumber = columnsDict[m];
|
||||||
|
var errorMessage = v.ErrorMessage;
|
||||||
|
var warningMessage = string.Format(XLExtentions.ProblemDetailsTemplate, SheetName, rowNumber, columnNumber,
|
||||||
|
errorMessage);
|
||||||
|
var warning = new ValidationResult(warningMessage, new[] { m });
|
||||||
|
return warning;
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
|
||||||
|
return invalidDto;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual ParserResultDto<TDto> ParseExcelSheet(IXLWorksheet sheet)
|
||||||
|
{
|
||||||
|
var count = sheet.RowsUsed().Count() - HeaderRowsCount;
|
||||||
|
if (count <= 0)
|
||||||
|
return new ParserResultDto<TDto>();
|
||||||
|
|
||||||
|
var valiationResults = new List<ValidationResultDto<TDto>>(count);
|
||||||
|
var warnings = new List<ValidationResult>();
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var xlRow = sheet.Row(1 + i + HeaderRowsCount);
|
||||||
|
var rowNumber = xlRow.RowNumber();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var row = ParseRow(xlRow);
|
||||||
|
var dto = BuildDto(row, rowNumber);
|
||||||
|
var validationResult = Validate(dto, rowNumber);
|
||||||
|
valiationResults.Add(validationResult);
|
||||||
|
}
|
||||||
|
catch (FileFormatException ex)
|
||||||
|
{
|
||||||
|
var warning = new ValidationResult(ex.Message);
|
||||||
|
warnings.Add(warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var parserResult = new ParserResultDto<TDto>
|
||||||
|
{
|
||||||
|
Item = valiationResults
|
||||||
|
};
|
||||||
|
|
||||||
|
if (warnings.Any())
|
||||||
|
parserResult.Warnings = warnings;
|
||||||
|
|
||||||
|
return parserResult;
|
||||||
|
}
|
||||||
|
}
|
@ -1,36 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using AsbCloudApp.Data;
|
|
||||||
using AsbCloudApp.Requests.ParserOptions;
|
|
||||||
using AsbCloudApp.Services;
|
|
||||||
using AsbCloudInfrastructure.Services.Trajectory.Parser;
|
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services;
|
|
||||||
|
|
||||||
public class ParserServiceFactory
|
|
||||||
{
|
|
||||||
public const int IdTrajectoryFactManualParserService = 1;
|
|
||||||
public const int IdTrajectoryPlanParserService = 2;
|
|
||||||
|
|
||||||
private readonly IDictionary<int, Func<IParserService>> parsers;
|
|
||||||
|
|
||||||
public ParserServiceFactory(IServiceProvider serviceProvider)
|
|
||||||
{
|
|
||||||
parsers = new Dictionary<int, Func<IParserService>>
|
|
||||||
{
|
|
||||||
{ IdTrajectoryPlanParserService, () => new TrajectoryPlanParserService(serviceProvider) },
|
|
||||||
{ IdTrajectoryFactManualParserService, () => new TrajectoryFactManualParserService(serviceProvider) }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public IParserService<TDto, TOptions> Create<TDto, TOptions>(int idParserService)
|
|
||||||
where TDto : class, IId
|
|
||||||
where TOptions : IParserOptionsRequest
|
|
||||||
{
|
|
||||||
if (!parsers.TryGetValue(idParserService, out var parserService))
|
|
||||||
throw new ArgumentNullException(nameof(idParserService), "Не правильный идентификатор парсера");
|
|
||||||
|
|
||||||
return parserService.Invoke() as IParserService<TDto, TOptions>
|
|
||||||
?? throw new ArgumentNullException(nameof(idParserService), "Ошибка приведения типа");
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,78 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Data.ProcessMapPlan;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
|
using AsbCloudInfrastructure.Services.Parser;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Services.ProcessMapPlan.Parser;
|
||||||
|
|
||||||
|
public class ProcessMapPlanDrillingParser : ProcessMapPlanParser<ProcessMapPlanDrillingDto>
|
||||||
|
{
|
||||||
|
private readonly IEnumerable<WellSectionTypeDto> sections;
|
||||||
|
|
||||||
|
public ProcessMapPlanDrillingParser(IWellOperationRepository wellOperationRepository)
|
||||||
|
{
|
||||||
|
sections = wellOperationRepository.GetSectionTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string SheetName => "План";
|
||||||
|
protected override string TemplateFileName => "ProcessMapPlanDrillingTemplate.xlsx";
|
||||||
|
|
||||||
|
private const int ColumnSection = 1;
|
||||||
|
private const int ColumnMode = 2;
|
||||||
|
|
||||||
|
protected override IDictionary<string, Cell> Cells => new Dictionary<string, Cell>
|
||||||
|
{
|
||||||
|
{ nameof(ProcessMapPlanDrillingDto.Section), new Cell(ColumnSection, typeof(string)) },
|
||||||
|
{ nameof(ProcessMapPlanDrillingDto.Mode), new Cell(ColumnMode, typeof(string)) },
|
||||||
|
{ nameof(ProcessMapPlanDrillingDto.DepthStart), new Cell(3, typeof(double)) },
|
||||||
|
{ nameof(ProcessMapPlanDrillingDto.DepthEnd), new Cell(4, typeof(double)) },
|
||||||
|
{ nameof(ProcessMapPlanDrillingDto.DeltaPressurePlan), new Cell(5, typeof(double)) },
|
||||||
|
{ nameof(ProcessMapPlanDrillingDto.DeltaPressureLimitMax), new Cell(6, typeof(double)) },
|
||||||
|
{ nameof(ProcessMapPlanDrillingDto.AxialLoadPlan), new Cell(7, typeof(double)) },
|
||||||
|
{ nameof(ProcessMapPlanDrillingDto.AxialLoadLimitMax), new Cell(8, typeof(double)) },
|
||||||
|
{ nameof(ProcessMapPlanDrillingDto.TopDriveTorquePlan), new Cell(9, typeof(double)) },
|
||||||
|
{ nameof(ProcessMapPlanDrillingDto.TopDriveTorqueLimitMax), new Cell(10, typeof(double)) },
|
||||||
|
{ nameof(ProcessMapPlanDrillingDto.TopDriveSpeedPlan), new Cell(11, typeof(double)) },
|
||||||
|
{ nameof(ProcessMapPlanDrillingDto.TopDriveSpeedLimitMax), new Cell(12, typeof(double)) },
|
||||||
|
{ nameof(ProcessMapPlanDrillingDto.FlowPlan), new Cell(13, typeof(double)) },
|
||||||
|
{ nameof(ProcessMapPlanDrillingDto.FlowLimitMax), new Cell(14, typeof(double)) },
|
||||||
|
{ nameof(ProcessMapPlanDrillingDto.RopPlan), new Cell(15, typeof(double)) },
|
||||||
|
{ nameof(ProcessMapPlanDrillingDto.UsageSaub), new Cell(16, typeof(double)) },
|
||||||
|
{ nameof(ProcessMapPlanDrillingDto.UsageSpin), new Cell(17, typeof(double)) },
|
||||||
|
{ nameof(ProcessMapPlanDrillingDto.Comment), new Cell(18, typeof(string)) }
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override ProcessMapPlanDrillingDto BuildDto(IDictionary<string, object?> row, int rowNumber)
|
||||||
|
{
|
||||||
|
var dto = base.BuildDto(row, rowNumber);
|
||||||
|
|
||||||
|
var section = sections.FirstOrDefault(s =>
|
||||||
|
string.Equals(s.Caption.Trim(), dto.Section?.Trim(), StringComparison.CurrentCultureIgnoreCase));
|
||||||
|
|
||||||
|
if (section is null)
|
||||||
|
{
|
||||||
|
var message = string.Format(XLExtentions.ProblemDetailsTemplate, SheetName, rowNumber, ColumnSection,
|
||||||
|
"Указана некорректная секция");
|
||||||
|
throw new FileFormatException(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
var idMode = GetIdMode(dto.Mode);
|
||||||
|
|
||||||
|
if (idMode is null)
|
||||||
|
{
|
||||||
|
var message = string.Format(XLExtentions.ProblemDetailsTemplate, SheetName, rowNumber, ColumnSection,
|
||||||
|
"Указан некорректный режим бурения");
|
||||||
|
throw new FileFormatException(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
dto.IdWellSectionType = section.Id;
|
||||||
|
dto.IdMode = idMode.Value;
|
||||||
|
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using AsbCloudApp.Data.ProcessMapPlan;
|
||||||
|
using AsbCloudInfrastructure.Services.Parser;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Services.ProcessMapPlan.Parser;
|
||||||
|
|
||||||
|
public abstract class ProcessMapPlanParser<TDto> : ParserExcelService<TDto>
|
||||||
|
where TDto : ProcessMapPlanBaseDto
|
||||||
|
{
|
||||||
|
protected override int HeaderRowsCount => 2;
|
||||||
|
|
||||||
|
protected static int? GetIdMode(string? modeName) =>
|
||||||
|
modeName?.Trim().ToLower() switch
|
||||||
|
{
|
||||||
|
"ротор" => 1,
|
||||||
|
"слайд" => 2,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
}
|
Binary file not shown.
@ -10,18 +10,18 @@ using System.Reflection;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.ProcessMaps.Report
|
namespace AsbCloudInfrastructure.Services.ProcessMaps.Report;
|
||||||
{
|
|
||||||
public class ProcessMapReportDataSaubStatExportService : IProcessMapReportDataSaubStatExportService
|
public class ProcessMapReportDataSaubStatExportService : IProcessMapReportDataSaubStatExportService
|
||||||
{
|
{
|
||||||
const int firstColumn = 2;
|
private const int firstColumn = 2;
|
||||||
const int lastColumn = 35;
|
private const int lastColumn = 35;
|
||||||
|
private const int headerRowsCount = 5;
|
||||||
const int headerRowsCount = 5;
|
private const string TemplateName = "ProcessMapReportDataSaubStatTemplate.xlsx";
|
||||||
|
private const string sheetName = "Отчёт";
|
||||||
|
|
||||||
private readonly IWellService wellService;
|
private readonly IWellService wellService;
|
||||||
private readonly IProcessMapReportDataSaubStatService processMapReportDataSaubStatService;
|
private readonly IProcessMapReportDataSaubStatService processMapReportDataSaubStatService;
|
||||||
private readonly string TemplateName = "ProcessMapReportDataSaubStatTemplate.xlsx";
|
|
||||||
|
|
||||||
public ProcessMapReportDataSaubStatExportService(IWellService wellService,
|
public ProcessMapReportDataSaubStatExportService(IWellService wellService,
|
||||||
IProcessMapReportDataSaubStatService processMapReportDataSaubStatService)
|
IProcessMapReportDataSaubStatService processMapReportDataSaubStatService)
|
||||||
@ -53,11 +53,8 @@ namespace AsbCloudInfrastructure.Services.ProcessMaps.Report
|
|||||||
return (name, memoryStream);
|
return (name, memoryStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void FillProcessMapToWorkbook(XLWorkbook workbook,
|
private static void FillProcessMapToWorkbook(XLWorkbook workbook, IEnumerable<ProcessMapReportDataSaubStatDto> data)
|
||||||
IEnumerable<ProcessMapReportDataSaubStatDto> data)
|
|
||||||
{
|
{
|
||||||
const string sheetName = "Отчёт";
|
|
||||||
|
|
||||||
var sheet = workbook.GetWorksheet(sheetName);
|
var sheet = workbook.GetWorksheet(sheetName);
|
||||||
|
|
||||||
var startRow = headerRowsCount + 1;
|
var startRow = headerRowsCount + 1;
|
||||||
@ -68,8 +65,7 @@ namespace AsbCloudInfrastructure.Services.ProcessMaps.Report
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static int FillRow(IXLWorksheet sheet, ProcessMapReportDataSaubStatDto item,
|
private static int FillRow(IXLWorksheet sheet, ProcessMapReportDataSaubStatDto item, int startRow)
|
||||||
int startRow)
|
|
||||||
{
|
{
|
||||||
var endRow = FillIntervalData(sheet, item, startRow);
|
var endRow = FillIntervalData(sheet, item, startRow);
|
||||||
|
|
||||||
@ -256,4 +252,3 @@ namespace AsbCloudInfrastructure.Services.ProcessMaps.Report
|
|||||||
style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
|
style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -18,6 +18,8 @@ namespace AsbCloudInfrastructure.Services.ProcessMaps.WellDrilling;
|
|||||||
/*
|
/*
|
||||||
* password for ProcessMapImportTemplate.xlsx is ASB2020!
|
* password for ProcessMapImportTemplate.xlsx is ASB2020!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
[Obsolete]
|
||||||
public class ProcessMapPlanImportWellDrillingService : IProcessMapPlanImportService
|
public class ProcessMapPlanImportWellDrillingService : IProcessMapPlanImportService
|
||||||
{
|
{
|
||||||
private readonly IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto> processMapPlanWellDrillingRepository;
|
private readonly IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto> processMapPlanWellDrillingRepository;
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using AsbCloudApp.Data.Trajectory;
|
||||||
|
using AsbCloudInfrastructure.Services.Parser;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
|
||||||
|
|
||||||
|
public class TrajectoryFactManualParser : ParserExcelService<TrajectoryGeoFactDto>
|
||||||
|
{
|
||||||
|
protected override string SheetName => "Фактическая траектория";
|
||||||
|
|
||||||
|
protected override int HeaderRowsCount => 2;
|
||||||
|
|
||||||
|
protected override string TemplateFileName => "TrajectoryFactManualTemplate.xlsx";
|
||||||
|
|
||||||
|
protected override IDictionary<string, Cell> Cells => new Dictionary<string, Cell>
|
||||||
|
{
|
||||||
|
{ nameof(TrajectoryGeoFactDto.WellboreDepth), new Cell(1, typeof(double)) },
|
||||||
|
{ nameof(TrajectoryGeoFactDto.ZenithAngle), new Cell(2, typeof(double)) },
|
||||||
|
{ nameof(TrajectoryGeoFactDto.AzimuthGeo), new Cell(3, typeof(double)) },
|
||||||
|
{ nameof(TrajectoryGeoFactDto.AzimuthMagnetic), new Cell(4, typeof(double)) },
|
||||||
|
{ nameof(TrajectoryGeoFactDto.VerticalDepth), new Cell(5, typeof(double)) },
|
||||||
|
{ nameof(TrajectoryGeoFactDto.Comment), new Cell(6, typeof(string)) }
|
||||||
|
};
|
||||||
|
}
|
@ -1,39 +0,0 @@
|
|||||||
using System;
|
|
||||||
using AsbCloudApp.Data;
|
|
||||||
using AsbCloudApp.Data.Trajectory;
|
|
||||||
using ClosedXML.Excel;
|
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
|
|
||||||
|
|
||||||
public class TrajectoryFactManualParserService : TrajectoryParserService<TrajectoryGeoFactDto>
|
|
||||||
{
|
|
||||||
protected override string SheetName => "Фактическая траектория";
|
|
||||||
protected override string TemplateFileName => "TrajectoryFactManualTemplate.xlsx";
|
|
||||||
|
|
||||||
public TrajectoryFactManualParserService(IServiceProvider serviceProvider)
|
|
||||||
: base(serviceProvider)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override ValidationResultDto<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: Добавить валидацию модели
|
|
||||||
|
|
||||||
var validationResult = new ValidationResultDto<TrajectoryGeoFactDto>
|
|
||||||
{
|
|
||||||
Item = trajectoryRow
|
|
||||||
};
|
|
||||||
|
|
||||||
return validationResult;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
using System;
|
|
||||||
using AsbCloudApp.Data.Trajectory;
|
|
||||||
using ClosedXML.Excel;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using AsbCloudApp.Data;
|
|
||||||
using AsbCloudApp.Requests.ParserOptions;
|
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
|
|
||||||
|
|
||||||
public abstract class TrajectoryParserService<T> : ParserServiceBase<T, IParserOptionsRequest>
|
|
||||||
where T : TrajectoryGeoDto
|
|
||||||
{
|
|
||||||
private const int HeaderRowsCount = 2;
|
|
||||||
private const int ColumnCount = 6;
|
|
||||||
|
|
||||||
protected TrajectoryParserService(IServiceProvider serviceProvider)
|
|
||||||
: base(serviceProvider)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract string SheetName { get; }
|
|
||||||
|
|
||||||
protected abstract string TemplateFileName { get; }
|
|
||||||
|
|
||||||
protected abstract ValidationResultDto<T> ParseRow(IXLRow row);
|
|
||||||
|
|
||||||
public override Stream GetTemplateFile() =>
|
|
||||||
Assembly.GetExecutingAssembly().GetTemplateCopyStream(TemplateFileName)
|
|
||||||
?? throw new ArgumentNullException($"Файл '{TemplateFileName}' не найден");
|
|
||||||
|
|
||||||
public override ParserResultDto<T> Parse(Stream file, IParserOptionsRequest options)
|
|
||||||
{
|
|
||||||
using var workbook = new XLWorkbook(file);
|
|
||||||
|
|
||||||
var sheet = workbook.GetWorksheet(SheetName);
|
|
||||||
|
|
||||||
var trajectoryRows = ParseExcelSheet(sheet, ParseRow, ColumnCount, HeaderRowsCount);
|
|
||||||
return trajectoryRows;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,25 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using AsbCloudApp.Data.Trajectory;
|
||||||
|
using AsbCloudInfrastructure.Services.Parser;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
|
||||||
|
|
||||||
|
public class TrajectoryPlanParser : ParserExcelService<TrajectoryGeoPlanDto>
|
||||||
|
{
|
||||||
|
protected override string SheetName => "Плановая траектория";
|
||||||
|
|
||||||
|
protected override int HeaderRowsCount => 2;
|
||||||
|
|
||||||
|
protected override string TemplateFileName => "TrajectoryPlanTemplate.xlsx";
|
||||||
|
|
||||||
|
protected override IDictionary<string, Cell> Cells => new Dictionary<string, Cell>
|
||||||
|
{
|
||||||
|
{ nameof(TrajectoryGeoPlanDto.WellboreDepth), new Cell(1, typeof(double)) },
|
||||||
|
{ nameof(TrajectoryGeoPlanDto.ZenithAngle), new Cell(2, typeof(double)) },
|
||||||
|
{ nameof(TrajectoryGeoPlanDto.AzimuthGeo), new Cell(3, typeof(double)) },
|
||||||
|
{ nameof(TrajectoryGeoPlanDto.AzimuthMagnetic), new Cell(4, typeof(double)) },
|
||||||
|
{ nameof(TrajectoryGeoPlanDto.VerticalDepth), new Cell(5, typeof(double)) },
|
||||||
|
{ nameof(TrajectoryGeoPlanDto.Radius), new Cell(6, typeof(double)) },
|
||||||
|
{ nameof(TrajectoryGeoPlanDto.Comment), new Cell(7, typeof(string)) }
|
||||||
|
};
|
||||||
|
}
|
@ -1,40 +0,0 @@
|
|||||||
using System;
|
|
||||||
using AsbCloudApp.Data;
|
|
||||||
using AsbCloudApp.Data.Trajectory;
|
|
||||||
using ClosedXML.Excel;
|
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
|
|
||||||
|
|
||||||
public class TrajectoryPlanParserService : TrajectoryParserService<TrajectoryGeoPlanDto>
|
|
||||||
{
|
|
||||||
protected override string SheetName => "Плановая траектория";
|
|
||||||
protected override string TemplateFileName => "TrajectoryPlanTemplate.xlsx";
|
|
||||||
|
|
||||||
public TrajectoryPlanParserService(IServiceProvider serviceProvider)
|
|
||||||
: base(serviceProvider)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override ValidationResultDto<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: Добавить валидацию модели
|
|
||||||
|
|
||||||
var validationResult = new ValidationResultDto<TrajectoryGeoPlanDto>
|
|
||||||
{
|
|
||||||
Item = trajectoryRow
|
|
||||||
};
|
|
||||||
|
|
||||||
return validationResult;
|
|
||||||
}
|
|
||||||
}
|
|
17
AsbCloudInfrastructure/ValidationExtensions.cs
Normal file
17
AsbCloudInfrastructure/ValidationExtensions.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure;
|
||||||
|
|
||||||
|
public static class ValidationExtensions
|
||||||
|
{
|
||||||
|
public static bool Validate(this IValidatableObject validatableObject, ICollection<ValidationResult> validationResults)
|
||||||
|
{
|
||||||
|
var validationContext = new ValidationContext(validatableObject, serviceProvider: null, items: null);
|
||||||
|
|
||||||
|
foreach (var validationResult in validatableObject.Validate(validationContext))
|
||||||
|
validationResults.Add(validationResult);
|
||||||
|
|
||||||
|
return Validator.TryValidateObject(validatableObject, validationContext, validationResults, true);
|
||||||
|
}
|
||||||
|
}
|
@ -7,9 +7,13 @@ namespace AsbCloudInfrastructure;
|
|||||||
|
|
||||||
public static class XLExtentions
|
public static class XLExtentions
|
||||||
{
|
{
|
||||||
|
public const string ProblemDetailsTemplate = "Лист: {0}, Строка: {1}, Столбец: {2}. {3}";
|
||||||
|
public const string NotFoundSheetTemplate = "Книга excel не содержит листа {0}";
|
||||||
|
public const string InvalidValueTemplate = "Лист: {0}, Строка: {1}, Столбец: {2}. Содержит некорректное значение";
|
||||||
|
|
||||||
public static IXLWorksheet GetWorksheet(this IXLWorkbook workbook, string sheetName) =>
|
public static IXLWorksheet GetWorksheet(this IXLWorkbook workbook, string sheetName) =>
|
||||||
workbook.Worksheets.FirstOrDefault(ws => string.Equals(ws.Name.Trim(), sheetName.Trim(), StringComparison.CurrentCultureIgnoreCase))
|
workbook.Worksheets.FirstOrDefault(ws => string.Equals(ws.Name.Trim(), sheetName.Trim(), StringComparison.CurrentCultureIgnoreCase))
|
||||||
?? throw new FileFormatException($"Книга excel не содержит листа {sheetName}.");
|
?? throw new FileFormatException(string.Format(NotFoundSheetTemplate, sheetName));
|
||||||
|
|
||||||
public static IXLCell SetCellValue<T>(this IXLCell cell, T value, string? format = null)
|
public static IXLCell SetCellValue<T>(this IXLCell cell, T value, string? format = null)
|
||||||
{
|
{
|
||||||
@ -41,8 +45,8 @@ public static class XLExtentions
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
throw new FileFormatException(
|
var message = string.Format(InvalidValueTemplate, cell.Worksheet.Name, cell.Address.RowNumber, cell.Address.ColumnNumber);
|
||||||
$"Лист '{cell.Worksheet.Name}'. {cell.Address.RowNumber} строка содержит некорректное значение в {cell.Address.ColumnNumber} столбце");
|
throw new FileFormatException(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -22,4 +22,9 @@
|
|||||||
<ProjectReference Include="..\AsbCloudWebApi\AsbCloudWebApi.csproj" />
|
<ProjectReference Include="..\AsbCloudWebApi\AsbCloudWebApi.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Controllers\ProcessMapPlan\Files\ProcessMapPlanDrillingInvalid.xlsx" />
|
||||||
|
<EmbeddedResource Include="Controllers\ProcessMapPlan\Files\ProcessMapPlanDrillingValid.xlsx" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
25
AsbCloudWebApi.IntegrationTests/AssemblyExtensions.cs
Normal file
25
AsbCloudWebApi.IntegrationTests/AssemblyExtensions.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.IntegrationTests;
|
||||||
|
|
||||||
|
internal static class AssemblyExtensions
|
||||||
|
{
|
||||||
|
internal static Stream GetFileCopyStream(this Assembly assembly, string templateName)
|
||||||
|
{
|
||||||
|
var resourceName = assembly
|
||||||
|
.GetManifestResourceNames()
|
||||||
|
.FirstOrDefault(n => n.EndsWith(templateName));
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(resourceName))
|
||||||
|
throw new ArgumentNullException(nameof(resourceName));
|
||||||
|
|
||||||
|
using var stream = Assembly.GetExecutingAssembly()
|
||||||
|
.GetManifestResourceStream(resourceName);
|
||||||
|
|
||||||
|
var memoryStream = new MemoryStream();
|
||||||
|
stream?.CopyTo(memoryStream);
|
||||||
|
memoryStream.Position = 0;
|
||||||
|
|
||||||
|
return memoryStream;
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
using AsbCloudApp.Data.ProcessMapPlan;
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Data.ProcessMapPlan;
|
||||||
using AsbCloudApp.Requests;
|
using AsbCloudApp.Requests;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Refit;
|
using Refit;
|
||||||
|
|
||||||
namespace AsbCloudWebApi.IntegrationTests.Clients;
|
namespace AsbCloudWebApi.IntegrationTests.Clients;
|
||||||
@ -32,4 +32,8 @@ public interface IProcessMapPlanDrillingClient
|
|||||||
|
|
||||||
[Put(BaseRoute)]
|
[Put(BaseRoute)]
|
||||||
Task<IApiResponse<int>> UpdateOrInsertRange(int idWell, IEnumerable<ProcessMapPlanDrillingDto> dtos);
|
Task<IApiResponse<int>> UpdateOrInsertRange(int idWell, IEnumerable<ProcessMapPlanDrillingDto> dtos);
|
||||||
|
|
||||||
|
[Multipart]
|
||||||
|
[Post(BaseRoute + "/parse")]
|
||||||
|
Task<IApiResponse<ParserResultDto<ProcessMapPlanDrillingDto>>> Parse(int idWell, [AliasAs("files")] IEnumerable<StreamPart> streams);
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Binary file not shown.
@ -1,18 +1,20 @@
|
|||||||
using AsbCloudApp.Data.ProcessMapPlan;
|
using AsbCloudApp.Data.ProcessMapPlan;
|
||||||
using AsbCloudApp.Requests;
|
using AsbCloudApp.Requests;
|
||||||
using AsbCloudDb.Model.ProcessMapPlan;
|
using AsbCloudDb.Model.ProcessMapPlan;
|
||||||
using AsbCloudDb.Model.ProcessMaps;
|
|
||||||
using AsbCloudWebApi.IntegrationTests.Clients;
|
using AsbCloudWebApi.IntegrationTests.Clients;
|
||||||
using Mapster;
|
using Mapster;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Reflection;
|
||||||
|
using AsbCloudDb.Model.ProcessMaps;
|
||||||
|
using AsbCloudWebApi.IntegrationTests.Data;
|
||||||
|
using Refit;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace AsbCloudWebApi.IntegrationTests.Controllers;
|
namespace AsbCloudWebApi.IntegrationTests.Controllers.ProcessMapPlan;
|
||||||
|
|
||||||
public class ProcessMapPlanDrillingControllerTest: BaseIntegrationTest
|
public class ProcessMapPlanDrillingControllerTest: BaseIntegrationTest
|
||||||
{
|
{
|
||||||
private IProcessMapPlanDrillingClient client;
|
|
||||||
private readonly ProcessMapPlanDrillingDto dto = new (){
|
private readonly ProcessMapPlanDrillingDto dto = new (){
|
||||||
Id = 0,
|
Id = 0,
|
||||||
Creation = new(),
|
Creation = new(),
|
||||||
@ -21,11 +23,13 @@ public class ProcessMapPlanDrillingControllerTest: BaseIntegrationTest
|
|||||||
IdPrevious = null,
|
IdPrevious = null,
|
||||||
|
|
||||||
IdWell = 1,
|
IdWell = 1,
|
||||||
IdWellSectionType = 1,
|
Section = "Кондуктор",
|
||||||
|
IdWellSectionType = 3,
|
||||||
DepthStart = 0.5,
|
DepthStart = 0.5,
|
||||||
DepthEnd = 1.5,
|
DepthEnd = 1.5,
|
||||||
|
|
||||||
IdMode = 1,
|
IdMode = 1,
|
||||||
|
Mode = "Ротор",
|
||||||
AxialLoadPlan = 2.718281,
|
AxialLoadPlan = 2.718281,
|
||||||
AxialLoadLimitMax = 3.1415926,
|
AxialLoadLimitMax = 3.1415926,
|
||||||
DeltaPressurePlan = 4,
|
DeltaPressurePlan = 4,
|
||||||
@ -73,6 +77,8 @@ public class ProcessMapPlanDrillingControllerTest: BaseIntegrationTest
|
|||||||
Comment = "это тестовая запись",
|
Comment = "это тестовая запись",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private IProcessMapPlanDrillingClient client;
|
||||||
|
|
||||||
public ProcessMapPlanDrillingControllerTest(WebAppFactoryFixture factory) : base(factory)
|
public ProcessMapPlanDrillingControllerTest(WebAppFactoryFixture factory) : base(factory)
|
||||||
{
|
{
|
||||||
dbContext.CleanupDbSet<ProcessMapPlanDrilling>();
|
dbContext.CleanupDbSet<ProcessMapPlanDrilling>();
|
||||||
@ -109,6 +115,8 @@ public class ProcessMapPlanDrillingControllerTest: BaseIntegrationTest
|
|||||||
nameof(ProcessMapPlanDrillingDto.IdState),
|
nameof(ProcessMapPlanDrillingDto.IdState),
|
||||||
nameof(ProcessMapPlanDrillingDto.Author),
|
nameof(ProcessMapPlanDrillingDto.Author),
|
||||||
nameof(ProcessMapPlanDrillingDto.Creation),
|
nameof(ProcessMapPlanDrillingDto.Creation),
|
||||||
|
nameof(ProcessMapPlanDrillingDto.Mode),
|
||||||
|
nameof(ProcessMapPlanDrillingDto.Section)
|
||||||
};
|
};
|
||||||
MatchHelper.Match(expected, actual, excludeProps);
|
MatchHelper.Match(expected, actual, excludeProps);
|
||||||
}
|
}
|
||||||
@ -556,4 +564,59 @@ public class ProcessMapPlanDrillingControllerTest: BaseIntegrationTest
|
|||||||
};
|
};
|
||||||
MatchHelper.Match(expected, actual, excludeProps);
|
MatchHelper.Match(expected, actual, excludeProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Parse_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
const string fileName = "ProcessMapPlanDrillingValid.xlsx";
|
||||||
|
var stream = Assembly.GetExecutingAssembly().GetFileCopyStream(fileName);
|
||||||
|
|
||||||
|
//act
|
||||||
|
var streamPart = new StreamPart(stream, fileName, "application/octet-stream");
|
||||||
|
var response = await client.Parse(Defaults.Wells[0].Id, new[] { streamPart });
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
|
||||||
|
var parserResult = response.Content;
|
||||||
|
|
||||||
|
Assert.NotNull(parserResult);
|
||||||
|
Assert.Single(parserResult.Item);
|
||||||
|
Assert.True(parserResult.IsValid);
|
||||||
|
|
||||||
|
var row = parserResult.Item.First();
|
||||||
|
var dtoActual = row.Item;
|
||||||
|
|
||||||
|
Assert.True(row.IsValid);
|
||||||
|
|
||||||
|
var excludeProps = new[] { nameof(ProcessMapPlanDrillingDto.IdWell) };
|
||||||
|
MatchHelper.Match(dto, dtoActual, excludeProps);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Parse_returns_success_for_result_with_warnings()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
const string fileName = "ProcessMapPlanDrillingInvalid.xlsx";
|
||||||
|
var stream = Assembly.GetExecutingAssembly().GetFileCopyStream(fileName);
|
||||||
|
|
||||||
|
//act
|
||||||
|
var streamPart = new StreamPart(stream, fileName, "application/octet-stream");
|
||||||
|
var response = await client.Parse(Defaults.Wells[0].Id, new[] { streamPart });
|
||||||
|
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
|
||||||
|
var parserResult = response.Content;
|
||||||
|
|
||||||
|
Assert.NotNull(parserResult);
|
||||||
|
Assert.False(parserResult.IsValid);
|
||||||
|
Assert.Single(parserResult.Warnings);
|
||||||
|
Assert.Single(parserResult.Item);
|
||||||
|
|
||||||
|
var row = parserResult.Item.First();
|
||||||
|
|
||||||
|
Assert.False(row.IsValid);
|
||||||
|
Assert.Equal(2, row.Warnings.Count());
|
||||||
|
}
|
||||||
}
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.IntegrationTests.Converters;
|
||||||
|
|
||||||
|
public class ValidationResultConverter : JsonConverter<ValidationResult>
|
||||||
|
{
|
||||||
|
public override ValidationResult Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
if (reader.TokenType != JsonTokenType.StartObject)
|
||||||
|
{
|
||||||
|
throw new JsonException("Expected the start of an object.");
|
||||||
|
}
|
||||||
|
|
||||||
|
string? errorMessage = null;
|
||||||
|
List<string>? memberNames = null;
|
||||||
|
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
if (reader.TokenType == JsonTokenType.EndObject)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reader.TokenType != JsonTokenType.PropertyName)
|
||||||
|
{
|
||||||
|
throw new JsonException($"Unexpected token type: {reader.TokenType}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var propertyName = reader.GetString();
|
||||||
|
reader.Read();
|
||||||
|
|
||||||
|
switch (propertyName)
|
||||||
|
{
|
||||||
|
case "errorMessage":
|
||||||
|
errorMessage = reader.GetString();
|
||||||
|
break;
|
||||||
|
case "memberNames":
|
||||||
|
if (reader.TokenType != JsonTokenType.StartArray)
|
||||||
|
{
|
||||||
|
throw new JsonException("Expected the start of an array for 'memberNames'.");
|
||||||
|
}
|
||||||
|
memberNames = new List<string>();
|
||||||
|
while (reader.Read() && reader.TokenType != JsonTokenType.EndArray)
|
||||||
|
{
|
||||||
|
memberNames.Add(reader.GetString() ?? string.Empty);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
reader.Skip();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorMessage == null)
|
||||||
|
{
|
||||||
|
throw new JsonException("Missing 'errorMessage' property.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ValidationResult(errorMessage, memberNames ?? Enumerable.Empty<string>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(Utf8JsonWriter writer, ValidationResult value, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@ using Microsoft.Extensions.DependencyInjection;
|
|||||||
using Refit;
|
using Refit;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using AsbCloudWebApi.IntegrationTests.Converters;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace AsbCloudWebApi.IntegrationTests;
|
namespace AsbCloudWebApi.IntegrationTests;
|
||||||
@ -18,7 +19,8 @@ public class WebAppFactoryFixture : WebApplicationFactory<Startup>,
|
|||||||
private static readonly JsonSerializerOptions jsonSerializerOptions = new()
|
private static readonly JsonSerializerOptions jsonSerializerOptions = new()
|
||||||
{
|
{
|
||||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||||
PropertyNameCaseInsensitive = true
|
PropertyNameCaseInsensitive = true,
|
||||||
|
Converters = { new ValidationResultConverter() }
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly RefitSettings refitSettings = new RefitSettings(new SystemTextJsonContentSerializer(jsonSerializerOptions));
|
private static readonly RefitSettings refitSettings = new RefitSettings(new SystemTextJsonContentSerializer(jsonSerializerOptions));
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
using System;
|
using System.Linq;
|
||||||
using System.Linq;
|
|
||||||
using AsbCloudApp.Data.Trajectory;
|
using AsbCloudApp.Data.Trajectory;
|
||||||
using AsbCloudApp.Requests.ParserOptions;
|
using AsbCloudApp.Requests.ParserOptions;
|
||||||
using AsbCloudInfrastructure.Services;
|
using AsbCloudInfrastructure.Services.Parser;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using AsbCloudInfrastructure.Services.Trajectory.Parser;
|
||||||
using NSubstitute;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace AsbCloudWebApi.Tests.Services.Trajectory;
|
namespace AsbCloudWebApi.Tests.Services.Trajectory;
|
||||||
@ -13,19 +11,8 @@ public class TrajectoryParserTest
|
|||||||
{
|
{
|
||||||
private const string UsingTemplateFile = "AsbCloudWebApi.Tests.Services.Trajectory.Templates";
|
private const string UsingTemplateFile = "AsbCloudWebApi.Tests.Services.Trajectory.Templates";
|
||||||
|
|
||||||
private readonly IServiceProvider serviceProviderMock = Substitute.For<IServiceProvider, ISupportRequiredService>();
|
private readonly TrajectoryPlanParser trajectoryPlanParser = new();
|
||||||
private readonly IServiceScope serviceScopeMock = Substitute.For<IServiceScope>();
|
private readonly TrajectoryFactManualParser trajectoryFactManualParser = new();
|
||||||
private readonly IServiceScopeFactory serviceScopeFactoryMock = Substitute.For<IServiceScopeFactory>();
|
|
||||||
|
|
||||||
private readonly ParserServiceFactory parserServiceFactory;
|
|
||||||
|
|
||||||
public TrajectoryParserTest()
|
|
||||||
{
|
|
||||||
serviceScopeFactoryMock.CreateScope().Returns(serviceScopeMock);
|
|
||||||
((ISupportRequiredService)serviceProviderMock).GetRequiredService(typeof(IServiceScopeFactory)).Returns(serviceScopeFactoryMock);
|
|
||||||
|
|
||||||
parserServiceFactory = new ParserServiceFactory(serviceProviderMock);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Parse_trajectory_plan()
|
public void Parse_trajectory_plan()
|
||||||
@ -36,10 +23,7 @@ public class TrajectoryParserTest
|
|||||||
if (stream is null)
|
if (stream is null)
|
||||||
Assert.Fail("Файла для импорта не существует");
|
Assert.Fail("Файла для импорта не существует");
|
||||||
|
|
||||||
var parserService = parserServiceFactory.Create<TrajectoryGeoPlanDto, IParserOptionsRequest>(
|
var trajectoryRows = trajectoryPlanParser.Parse(stream, IParserOptionsRequest.Empty());
|
||||||
ParserServiceFactory.IdTrajectoryPlanParserService);
|
|
||||||
|
|
||||||
var trajectoryRows = parserService.Parse(stream, IParserOptionsRequest.Empty());
|
|
||||||
|
|
||||||
Assert.Equal(3, trajectoryRows.Item.Count());
|
Assert.Equal(3, trajectoryRows.Item.Count());
|
||||||
}
|
}
|
||||||
@ -53,10 +37,7 @@ public class TrajectoryParserTest
|
|||||||
if (stream is null)
|
if (stream is null)
|
||||||
Assert.Fail("Файла для импорта не существует");
|
Assert.Fail("Файла для импорта не существует");
|
||||||
|
|
||||||
var parserService = parserServiceFactory.Create<TrajectoryGeoFactDto, IParserOptionsRequest>(
|
var trajectoryRows = trajectoryFactManualParser.Parse(stream, IParserOptionsRequest.Empty());
|
||||||
ParserServiceFactory.IdTrajectoryFactManualParserService);
|
|
||||||
|
|
||||||
var trajectoryRows = parserService.Parse(stream, IParserOptionsRequest.Empty());
|
|
||||||
|
|
||||||
Assert.Equal(4, trajectoryRows.Item.Count());
|
Assert.Equal(4, trajectoryRows.Item.Count());
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using AsbCloudInfrastructure;
|
using AsbCloudInfrastructure;
|
||||||
using ClosedXML.Excel;
|
using ClosedXML.Excel;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
@ -112,6 +113,16 @@ public class XLExtensionsTests
|
|||||||
Assert.Equal(DateTimeKind.Unspecified, actualValue.Kind);
|
Assert.Equal(DateTimeKind.Unspecified, actualValue.Kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetCellValue_returns_exception()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
SetCellValue("test");
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Throws<FileFormatException>(() => GetCell(cellUsed).GetCellValue<double>());
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetCellValue_returns_nullable()
|
public void GetCellValue_returns_nullable()
|
||||||
{
|
{
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
using System.IO;
|
|
||||||
using AsbCloudApp.Data;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
|
|
||||||
namespace AsbCloudWebApi.Controllers.Interfaces;
|
|
||||||
|
|
||||||
public interface IControllerWithParser<TDto, in TOptions>
|
|
||||||
where TDto : class, IId
|
|
||||||
{
|
|
||||||
ActionResult<ParserResultDto<TDto>> Parse(Stream file, TOptions options);
|
|
||||||
|
|
||||||
IActionResult GetTemplate();
|
|
||||||
}
|
|
@ -9,8 +9,12 @@ using Microsoft.AspNetCore.Http;
|
|||||||
using AsbCloudApp.Exceptions;
|
using AsbCloudApp.Exceptions;
|
||||||
using AsbCloudApp.Requests;
|
using AsbCloudApp.Requests;
|
||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Requests.ParserOptions;
|
||||||
|
using AsbCloudInfrastructure.Services.Parser;
|
||||||
|
|
||||||
namespace AsbCloudWebApi.Controllers.ProcessMapPlan;
|
namespace AsbCloudWebApi.Controllers.ProcessMapPlan;
|
||||||
|
|
||||||
@ -25,13 +29,19 @@ public abstract class ProcessMapPlanBaseController<TDto> : ControllerBase
|
|||||||
{
|
{
|
||||||
private readonly IChangeLogRepository<TDto, ProcessMapPlanBaseRequestWithWell> repository;
|
private readonly IChangeLogRepository<TDto, ProcessMapPlanBaseRequestWithWell> repository;
|
||||||
private readonly IWellService wellService;
|
private readonly IWellService wellService;
|
||||||
|
private readonly ParserExcelService<TDto> parserService;
|
||||||
|
|
||||||
public ProcessMapPlanBaseController(IChangeLogRepository<TDto, ProcessMapPlanBaseRequestWithWell> repository, IWellService wellService)
|
protected ProcessMapPlanBaseController(IChangeLogRepository<TDto, ProcessMapPlanBaseRequestWithWell> repository,
|
||||||
|
IWellService wellService,
|
||||||
|
ParserExcelService<TDto> parserService)
|
||||||
{
|
{
|
||||||
this.repository = repository;
|
this.repository = repository;
|
||||||
this.wellService = wellService;
|
this.wellService = wellService;
|
||||||
|
this.parserService = parserService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract string TemplateFileName { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Добавление
|
/// Добавление
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -191,6 +201,49 @@ public abstract class ProcessMapPlanBaseController<TDto> : ControllerBase
|
|||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Импорт РТК из excel (xlsx) файла
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idWell"></param>
|
||||||
|
/// <param name="files"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("parse")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
|
||||||
|
public async Task<ActionResult<ParserResultDto<TDto>>> Parse(int idWell,
|
||||||
|
[FromForm] IFormFileCollection files,
|
||||||
|
CancellationToken token)
|
||||||
|
{
|
||||||
|
await AssertUserHasAccessToWell(idWell, token);
|
||||||
|
|
||||||
|
var stream = files.GetExcelFile();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var dto = parserService.Parse(stream, IParserOptionsRequest.Empty());
|
||||||
|
return Ok(dto);
|
||||||
|
}
|
||||||
|
catch (FileFormatException ex)
|
||||||
|
{
|
||||||
|
return this.ValidationBadRequest(nameof(files), ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение шаблона для заполнения РТК
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("template")]
|
||||||
|
[AllowAnonymous]
|
||||||
|
[ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK, "application/octet-stream")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||||
|
public IActionResult GetTemplate()
|
||||||
|
{
|
||||||
|
var stream = parserService.GetTemplateFile();
|
||||||
|
return File(stream, "application/octet-stream", TemplateFileName);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// returns user id, if he has access to well
|
/// returns user id, if he has access to well
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -2,15 +2,18 @@
|
|||||||
using AsbCloudApp.Repositories;
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudApp.Requests;
|
using AsbCloudApp.Requests;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
|
using AsbCloudInfrastructure.Services.ProcessMapPlan.Parser;
|
||||||
|
|
||||||
namespace AsbCloudWebApi.Controllers.ProcessMapPlan;
|
namespace AsbCloudWebApi.Controllers.ProcessMapPlan;
|
||||||
|
|
||||||
public class ProcessMapPlanDrillingController : ProcessMapPlanBaseController<ProcessMapPlanDrillingDto>
|
public class ProcessMapPlanDrillingController : ProcessMapPlanBaseController<ProcessMapPlanDrillingDto>
|
||||||
{
|
{
|
||||||
public ProcessMapPlanDrillingController(
|
public ProcessMapPlanDrillingController(IChangeLogRepository<ProcessMapPlanDrillingDto, ProcessMapPlanBaseRequestWithWell> repository,
|
||||||
IChangeLogRepository<ProcessMapPlanDrillingDto, ProcessMapPlanBaseRequestWithWell> repository,
|
IWellService wellService,
|
||||||
IWellService wellService)
|
ProcessMapPlanDrillingParser parserService)
|
||||||
: base(repository, wellService)
|
: base(repository, wellService, parserService)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override string TemplateFileName => "ЕЦП_шаблон_файла_РТК_план_бурение.xlsx";
|
||||||
}
|
}
|
@ -11,6 +11,7 @@ using AsbCloudWebApi.SignalR.Clients;
|
|||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -91,6 +92,7 @@ public class ProcessMapWellDrillingController : ProcessMapBaseController<Process
|
|||||||
/// <param name="file"></param>
|
/// <param name="file"></param>
|
||||||
/// <param name="cancellationToken"></param>
|
/// <param name="cancellationToken"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
|
[Obsolete]
|
||||||
[HttpPost("import/{options}")]
|
[HttpPost("import/{options}")]
|
||||||
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
|
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
|
||||||
public async Task<IActionResult> ImportAsync(int idWell,
|
public async Task<IActionResult> ImportAsync(int idWell,
|
||||||
@ -129,6 +131,7 @@ public class ProcessMapWellDrillingController : ProcessMapBaseController<Process
|
|||||||
/// <param name="idWell">Id скважины</param>
|
/// <param name="idWell">Id скважины</param>
|
||||||
/// <param name="cancellationToken"></param>
|
/// <param name="cancellationToken"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
|
[Obsolete]
|
||||||
[HttpGet("export")]
|
[HttpGet("export")]
|
||||||
[ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK, "application/octet-stream")]
|
[ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK, "application/octet-stream")]
|
||||||
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
|
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
|
||||||
@ -143,6 +146,7 @@ public class ProcessMapWellDrillingController : ProcessMapBaseController<Process
|
|||||||
/// Возвращает шаблон файла для импорта
|
/// Возвращает шаблон файла для импорта
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Запрашиваемый файл</returns>
|
/// <returns>Запрашиваемый файл</returns>
|
||||||
|
[Obsolete]
|
||||||
[HttpGet("template")]
|
[HttpGet("template")]
|
||||||
[ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK, "application/octet-stream")]
|
[ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK, "application/octet-stream")]
|
||||||
public async Task<IActionResult> GetTemplateAsync(CancellationToken cancellationToken)
|
public async Task<IActionResult> GetTemplateAsync(CancellationToken cancellationToken)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using AsbCloudApp.Data.Trajectory;
|
using System;
|
||||||
|
using AsbCloudApp.Data.Trajectory;
|
||||||
using AsbCloudApp.Repositories;
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudInfrastructure.Services.Trajectory.Export;
|
using AsbCloudInfrastructure.Services.Trajectory.Export;
|
||||||
@ -11,8 +12,7 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Requests.ParserOptions;
|
using AsbCloudApp.Requests.ParserOptions;
|
||||||
using AsbCloudInfrastructure.Services;
|
using AsbCloudInfrastructure.Services.Parser;
|
||||||
using AsbCloudWebApi.Controllers.Interfaces;
|
|
||||||
|
|
||||||
namespace AsbCloudWebApi.Controllers.Trajectory
|
namespace AsbCloudWebApi.Controllers.Trajectory
|
||||||
{
|
{
|
||||||
@ -22,41 +22,22 @@ namespace AsbCloudWebApi.Controllers.Trajectory
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public abstract class TrajectoryEditableController<TDto> : TrajectoryController<TDto>,
|
public abstract class TrajectoryEditableController<TDto> : TrajectoryController<TDto>
|
||||||
IControllerWithParser<TDto, IParserOptionsRequest>
|
|
||||||
where TDto : TrajectoryGeoDto
|
where TDto : TrajectoryGeoDto
|
||||||
{
|
{
|
||||||
private readonly IParserService<TDto, IParserOptionsRequest> parserService;
|
private readonly ParserExcelService<TDto> parserService;
|
||||||
private readonly ITrajectoryEditableRepository<TDto> trajectoryRepository;
|
private readonly ITrajectoryEditableRepository<TDto> trajectoryRepository;
|
||||||
|
|
||||||
protected TrajectoryEditableController(IWellService wellService,
|
protected TrajectoryEditableController(IWellService wellService,
|
||||||
ParserServiceFactory parserServiceFactory,
|
ParserExcelService<TDto> parserService,
|
||||||
TrajectoryExportService<TDto> trajectoryExportService,
|
TrajectoryExportService<TDto> trajectoryExportService,
|
||||||
ITrajectoryEditableRepository<TDto> trajectoryRepository,
|
ITrajectoryEditableRepository<TDto> trajectoryRepository)
|
||||||
int idParserService)
|
: base(wellService, trajectoryExportService, trajectoryRepository)
|
||||||
: base(
|
|
||||||
wellService,
|
|
||||||
trajectoryExportService,
|
|
||||||
trajectoryRepository)
|
|
||||||
{
|
{
|
||||||
parserService = parserServiceFactory.Create<TDto, IParserOptionsRequest>(idParserService);
|
this.parserService = parserService;
|
||||||
this.trajectoryRepository = trajectoryRepository;
|
this.trajectoryRepository = trajectoryRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
ActionResult<ParserResultDto<TDto>> IControllerWithParser<TDto, IParserOptionsRequest>.Parse(Stream file,
|
|
||||||
IParserOptionsRequest options)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var parserResult = parserService.Parse(file, options);
|
|
||||||
return Ok(parserResult);
|
|
||||||
}
|
|
||||||
catch (FileFormatException ex)
|
|
||||||
{
|
|
||||||
return this.ValidationBadRequest("files", ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Возвращает excel шаблон для заполнения строк траектории
|
/// Возвращает excel шаблон для заполнения строк траектории
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -93,7 +74,17 @@ namespace AsbCloudWebApi.Controllers.Trajectory
|
|||||||
if (!await CanUserAccessToWellAsync(idWell, token))
|
if (!await CanUserAccessToWellAsync(idWell, token))
|
||||||
return Forbid();
|
return Forbid();
|
||||||
|
|
||||||
return this.ParseExcelFile(files, IParserOptionsRequest.Empty());
|
var stream = files.GetExcelFile();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var dto = parserService.Parse(stream, IParserOptionsRequest.Empty());
|
||||||
|
return Ok(dto);
|
||||||
|
}
|
||||||
|
catch (FileFormatException ex)
|
||||||
|
{
|
||||||
|
return this.ValidationBadRequest(nameof(files), ex.Message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
using AsbCloudApp.Data.Trajectory;
|
using AsbCloudApp.Data.Trajectory;
|
||||||
using AsbCloudApp.Repositories;
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudInfrastructure.Services;
|
|
||||||
using AsbCloudInfrastructure.Services.Trajectory.Export;
|
using AsbCloudInfrastructure.Services.Trajectory.Export;
|
||||||
|
using AsbCloudInfrastructure.Services.Trajectory.Parser;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace AsbCloudWebApi.Controllers.Trajectory;
|
namespace AsbCloudWebApi.Controllers.Trajectory;
|
||||||
@ -18,13 +18,9 @@ public class TrajectoryFactManualController : TrajectoryEditableController<Traje
|
|||||||
|
|
||||||
public TrajectoryFactManualController(IWellService wellService,
|
public TrajectoryFactManualController(IWellService wellService,
|
||||||
TrajectoryFactManualExportService trajectoryExportService,
|
TrajectoryFactManualExportService trajectoryExportService,
|
||||||
ParserServiceFactory parserServiceFactory,
|
TrajectoryFactManualParser parserService,
|
||||||
ITrajectoryEditableRepository<TrajectoryGeoFactDto> trajectoryRepository)
|
ITrajectoryEditableRepository<TrajectoryGeoFactDto> trajectoryRepository)
|
||||||
: base(wellService,
|
: base(wellService, parserService, trajectoryExportService, trajectoryRepository)
|
||||||
parserServiceFactory,
|
|
||||||
trajectoryExportService,
|
|
||||||
trajectoryRepository,
|
|
||||||
ParserServiceFactory.IdTrajectoryFactManualParserService)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AsbCloudInfrastructure.Services;
|
using AsbCloudInfrastructure.Services.Trajectory.Parser;
|
||||||
|
|
||||||
namespace AsbCloudWebApi.Controllers.Trajectory
|
namespace AsbCloudWebApi.Controllers.Trajectory
|
||||||
{
|
{
|
||||||
@ -23,15 +23,11 @@ namespace AsbCloudWebApi.Controllers.Trajectory
|
|||||||
protected override string fileName => "ЕЦП_шаблон_файла_плановая_траектория.xlsx";
|
protected override string fileName => "ЕЦП_шаблон_файла_плановая_траектория.xlsx";
|
||||||
|
|
||||||
public TrajectoryPlanController(IWellService wellService,
|
public TrajectoryPlanController(IWellService wellService,
|
||||||
|
TrajectoryPlanParser parserService,
|
||||||
TrajectoryPlanExportService trajectoryExportService,
|
TrajectoryPlanExportService trajectoryExportService,
|
||||||
ParserServiceFactory parserServiceFactory,
|
|
||||||
ITrajectoryEditableRepository<TrajectoryGeoPlanDto> trajectoryRepository,
|
ITrajectoryEditableRepository<TrajectoryGeoPlanDto> trajectoryRepository,
|
||||||
TrajectoryService trajectoryVisualizationService)
|
TrajectoryService trajectoryVisualizationService)
|
||||||
: base(wellService,
|
: base(wellService, parserService, trajectoryExportService, trajectoryRepository)
|
||||||
parserServiceFactory,
|
|
||||||
trajectoryExportService,
|
|
||||||
trajectoryRepository,
|
|
||||||
ParserServiceFactory.IdTrajectoryPlanParserService)
|
|
||||||
{
|
{
|
||||||
this.trajectoryVisualizationService = trajectoryVisualizationService;
|
this.trajectoryVisualizationService = trajectoryVisualizationService;
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,9 @@ using System.ComponentModel.DataAnnotations;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Exceptions;
|
||||||
using AsbCloudApp.Requests.ParserOptions;
|
using AsbCloudApp.Requests.ParserOptions;
|
||||||
using AsbCloudWebApi.Controllers.Interfaces;
|
using AsbCloudInfrastructure.Services.Parser;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc;
|
namespace Microsoft.AspNetCore.Mvc;
|
||||||
@ -96,30 +97,20 @@ public static class Extensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Вызов парсера со стандартной валидацией входного файла
|
/// Получение Excel
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TDto"></typeparam>
|
|
||||||
/// <typeparam name="TOptions"></typeparam>
|
|
||||||
/// <param name="controller"></param>
|
|
||||||
/// <param name="files"></param>
|
/// <param name="files"></param>
|
||||||
/// <param name="options"></param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static ActionResult<ParserResultDto<TDto>> ParseExcelFile<TDto, TOptions>(
|
/// <exception cref="ArgumentInvalidException"></exception>
|
||||||
this IControllerWithParser<TDto, TOptions> controller,
|
public static Stream GetExcelFile(this IFormFileCollection files)
|
||||||
IFormFileCollection files,
|
|
||||||
TOptions options)
|
|
||||||
where TDto : class, IId
|
|
||||||
where TOptions : class, IParserOptionsRequest
|
|
||||||
{
|
{
|
||||||
if (files.Count < 1)
|
if (files.Count < 1)
|
||||||
return MakeBadRequestObjectResult(nameof(files), "Нет файла");
|
throw new ArgumentInvalidException(nameof(files), "Нет файла");
|
||||||
|
|
||||||
var file = files[0];
|
var file = files[0];
|
||||||
if (Path.GetExtension(file.FileName).ToLower() != ".xlsx")
|
if (Path.GetExtension(file.FileName).ToLower() != ".xlsx")
|
||||||
return MakeBadRequestObjectResult(nameof(files), "Требуется .xlsx файл.");
|
throw new ArgumentInvalidException(nameof(files), "Требуется .xlsx файл.");
|
||||||
|
|
||||||
var stream = file.OpenReadStream();
|
return file.OpenReadStream();
|
||||||
|
|
||||||
return controller.Parse(stream, options);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user