forked from ddrilling/AsbCloudServer
Сделал рефакторинг сервисов для парсинга
This commit is contained in:
parent
7d00cfde1c
commit
92a909a029
@ -1,29 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using AsbCloudApp.Data.WellOperationImport;
|
||||
using AsbCloudApp.Data.WellOperationImport.Options;
|
||||
|
||||
namespace AsbCloudApp.Services.WellOperationImport;
|
||||
|
||||
/// <summary>
|
||||
/// Парсинг операций из excel файла
|
||||
/// </summary>
|
||||
public interface IWellOperationExcelParser
|
||||
public interface IWellOperationExcelParser<in TOptions>
|
||||
where TOptions : IWellOperationImportOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Id шаблона
|
||||
/// </summary>
|
||||
int IdTemplate { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Типы операций, которые можно получить из файла
|
||||
/// </summary>
|
||||
IEnumerable<int> IdTypes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Метод парсинга документа
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<RowDto> Parse(Stream stream, WellOperationParserOptionsDto options);
|
||||
/// <summary>
|
||||
/// Метод парсинга документа
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
SheetDto Parse(Stream stream, TOptions options);
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data.WellOperationImport;
|
||||
@ -10,15 +9,14 @@ namespace AsbCloudApp.Services.WellOperationImport;
|
||||
/// </summary>
|
||||
public interface IWellOperationImportService
|
||||
{
|
||||
/// <summary>
|
||||
/// Загрузить из excel список операций
|
||||
/// </summary>
|
||||
/// <param name="idWell"></param>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="idUser"></param>
|
||||
/// <param name="deleteBeforeImport"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <param name="options"></param>
|
||||
Task ImportAsync(int idWell, int idUser, Stream stream, WellOperationParserOptionsDto options, bool deleteBeforeImport,
|
||||
CancellationToken cancellationToken);
|
||||
/// <summary>
|
||||
/// Загрузить из excel список операций
|
||||
/// </summary>
|
||||
/// <param name="idWell"></param>
|
||||
/// <param name="idUser"></param>
|
||||
/// <param name="idType"></param>
|
||||
/// <param name="sheet"></param>
|
||||
/// <param name="deleteBeforeImport"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
Task ImportAsync(int idWell, int idUser, int idType, SheetDto sheet, bool deleteBeforeImport, CancellationToken cancellationToken);
|
||||
}
|
@ -32,6 +32,7 @@ using AsbCloudInfrastructure.Services.AutoGeneratedDailyReports;
|
||||
using AsbCloudInfrastructure.Services.WellOperationImport;
|
||||
using AsbCloudInfrastructure.Services.WellOperationImport.FileParser;
|
||||
using AsbCloudInfrastructure.Services.ProcessMap.ProcessMapWellboreDevelopment;
|
||||
using AsbCloudApp.Data.WellOperationImport.Options;
|
||||
|
||||
namespace AsbCloudInfrastructure
|
||||
{
|
||||
@ -239,8 +240,8 @@ namespace AsbCloudInfrastructure
|
||||
services.AddTransient<IWellOperationImportService, WellOperationImportService>();
|
||||
services.AddTransient<IWellOperationImportTemplateService, WellOperationImportTemplateService>();
|
||||
|
||||
services.AddTransient<IWellOperationExcelParser, WellOperationDefaultExcelParser>();
|
||||
services.AddTransient<IWellOperationExcelParser, WellOperationGazpromKhantosExcelParser>();
|
||||
services.AddTransient<IWellOperationExcelParser<WellOperationImportDefaultOptionsDto>, WellOperationDefaultExcelParser>();
|
||||
services.AddTransient<IWellOperationExcelParser<WellOperationImportGazpromKhantosOptionsDto>, WellOperationGazpromKhantosExcelParser>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using AsbCloudApp.Data.WellOperationImport;
|
||||
using AsbCloudApp.Data.WellOperationImport.Options;
|
||||
using AsbCloudApp.Services.WellOperationImport;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudInfrastructure.Services.WellOperationImport.Constants;
|
||||
@ -10,19 +11,16 @@ using ClosedXML.Excel;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.WellOperationImport.FileParser;
|
||||
|
||||
public class WellOperationDefaultExcelParser : IWellOperationExcelParser
|
||||
public class WellOperationDefaultExcelParser : IWellOperationExcelParser<WellOperationImportDefaultOptionsDto>
|
||||
{
|
||||
public int IdTemplate => Templates.IdDefaultTemplate;
|
||||
public IEnumerable<int> IdTypes => new[] { WellOperation.IdOperationTypePlan, WellOperation.IdOperationTypeFact };
|
||||
|
||||
public IEnumerable<RowDto> Parse(Stream stream, WellOperationParserOptionsDto options)
|
||||
public SheetDto Parse(Stream stream, WellOperationImportDefaultOptionsDto options)
|
||||
{
|
||||
using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled);
|
||||
|
||||
return ParseWorkbook(workbook, options);
|
||||
}
|
||||
|
||||
private static IEnumerable<RowDto> ParseWorkbook(IXLWorkbook workbook, WellOperationParserOptionsDto options)
|
||||
private static SheetDto ParseWorkbook(IXLWorkbook workbook, WellOperationImportDefaultOptionsDto options)
|
||||
{
|
||||
var sheetName = options.IdType == WellOperation.IdOperationTypePlan
|
||||
? DefaultTemplateInfo.SheetNamePlan
|
||||
@ -30,12 +28,12 @@ public class WellOperationDefaultExcelParser : IWellOperationExcelParser
|
||||
|
||||
var sheet = workbook.Worksheets.FirstOrDefault(ws =>
|
||||
string.Equals(ws.Name, sheetName, StringComparison.CurrentCultureIgnoreCase))
|
||||
?? throw new FileFormatException($"Книга excel не содержит листа '{options.SheetName}'");
|
||||
?? throw new FileFormatException($"Книга excel не содержит листа '{sheetName}'");
|
||||
|
||||
return ParseSheet(sheet);
|
||||
}
|
||||
|
||||
private static IEnumerable<RowDto> ParseSheet(IXLWorksheet sheet)
|
||||
private static SheetDto ParseSheet(IXLWorksheet sheet)
|
||||
{
|
||||
if (sheet.RangeUsed().RangeAddress.LastAddress.ColumnNumber < 7)
|
||||
throw new FileFormatException($"Лист {sheet.Name} содержит меньшее количество столбцов.");
|
||||
@ -47,7 +45,7 @@ public class WellOperationDefaultExcelParser : IWellOperationExcelParser
|
||||
case > 1024:
|
||||
throw new FileFormatException($"Лист {sheet.Name} содержит слишком большое количество операций.");
|
||||
case <= 0:
|
||||
return Enumerable.Empty<RowDto>();
|
||||
return new SheetDto { Name = sheet.Name };
|
||||
}
|
||||
|
||||
var rows = new RowDto[count];
|
||||
@ -71,7 +69,11 @@ public class WellOperationDefaultExcelParser : IWellOperationExcelParser
|
||||
if (cellValuesErrors.Any())
|
||||
throw new FileFormatException(string.Join("\r\n", cellValuesErrors));
|
||||
|
||||
return rows;
|
||||
return new SheetDto
|
||||
{
|
||||
Name = sheet.Name,
|
||||
Rows = rows
|
||||
};
|
||||
}
|
||||
|
||||
private static RowDto ParseRow(IXLRow xlRow)
|
||||
|
@ -4,16 +4,16 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using AsbCloudApp.Data.WellOperationImport;
|
||||
using AsbCloudApp.Data.WellOperationImport.Options;
|
||||
using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Services.WellOperationImport;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudInfrastructure.Services.WellOperationImport.Constants;
|
||||
using AsbCloudInfrastructure.Services.WellOperationImport.FileParser.StringSimilarity;
|
||||
using ClosedXML.Excel;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.WellOperationImport.FileParser;
|
||||
|
||||
public class WellOperationGazpromKhantosExcelParser : IWellOperationExcelParser
|
||||
public class WellOperationGazpromKhantosExcelParser : IWellOperationExcelParser<WellOperationImportGazpromKhantosOptionsDto>
|
||||
{
|
||||
private class Operation
|
||||
{
|
||||
@ -35,24 +35,20 @@ public class WellOperationGazpromKhantosExcelParser : IWellOperationExcelParser
|
||||
private readonly Dictionary<string, string> operationDict = InitDict("Operations.txt", '=');
|
||||
private readonly Dictionary<string, string> sectionDict = InitDict("Sections.txt", '=');
|
||||
private readonly Dictionary<string, string> operationAttributesDict = InitDict("OperationAttributes.txt", '=');
|
||||
|
||||
public int IdTemplate => Templates.IdGazpromKhantosTemplate;
|
||||
|
||||
public IEnumerable<int> IdTypes => new[] { WellOperation.IdOperationTypePlan };
|
||||
|
||||
public IEnumerable<RowDto> Parse(Stream stream, WellOperationParserOptionsDto options)
|
||||
public SheetDto Parse(Stream stream, WellOperationImportGazpromKhantosOptionsDto options)
|
||||
{
|
||||
using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled);
|
||||
|
||||
return ParseWorkBook(workbook, options);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<RowDto> ParseWorkBook(IXLWorkbook workbook, WellOperationParserOptionsDto options)
|
||||
private SheetDto ParseWorkBook(IXLWorkbook workbook, WellOperationImportGazpromKhantosOptionsDto options)
|
||||
{
|
||||
if (options.StartRow is null or < 1 or > 1048576)
|
||||
if (options.StartRow is < 1 or > 1048576)
|
||||
throw new ArgumentInvalidException(nameof(options.StartRow), "Некорректное значение начальной строки");
|
||||
|
||||
if (options.EndRow is null or < 1 or > 1048576)
|
||||
if (options.EndRow is < 1 or > 1048576)
|
||||
throw new ArgumentInvalidException(nameof(options.EndRow), "Некорректное значение конечной строки");
|
||||
|
||||
if (options.EndRow < options.StartRow)
|
||||
@ -62,15 +58,15 @@ public class WellOperationGazpromKhantosExcelParser : IWellOperationExcelParser
|
||||
string.Equals(ws.Name, options.SheetName, StringComparison.CurrentCultureIgnoreCase))
|
||||
?? throw new FileFormatException($"Книга excel не содержит листа '{options.SheetName}'");
|
||||
|
||||
return ParseSheet(sheet, options.StartRow.Value, options.EndRow.Value);
|
||||
return ParseSheet(sheet, options.StartRow, options.EndRow);
|
||||
}
|
||||
|
||||
private IEnumerable<RowDto> ParseSheet(IXLWorksheet sheet, int startRow, int endRow)
|
||||
private SheetDto ParseSheet(IXLWorksheet sheet, int startRow, int endRow)
|
||||
{
|
||||
var operationAttributes = GetOperationAttributes(sheet.RowsUsed());
|
||||
var operationAttributes = GetOperationAttributes(sheet.RowsUsed());
|
||||
|
||||
if (operationAttributes is null)
|
||||
return Enumerable.Empty<RowDto>();
|
||||
return new SheetDto { Name = sheet.Name };
|
||||
|
||||
var rowsCount = endRow - startRow + 1;
|
||||
|
||||
@ -103,7 +99,11 @@ public class WellOperationGazpromKhantosExcelParser : IWellOperationExcelParser
|
||||
if (cellValuesErrors.Any())
|
||||
throw new FileFormatException(string.Join("\r\n", cellValuesErrors));
|
||||
|
||||
return BuildRows();
|
||||
return new SheetDto()
|
||||
{
|
||||
Name = sheet.Name,
|
||||
Rows = BuildRows()
|
||||
};
|
||||
|
||||
IEnumerable<(double Diameter, string Name)> BuildSections()
|
||||
{
|
||||
|
@ -6,7 +6,6 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Data.WellOperationImport;
|
||||
using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudApp.Requests;
|
||||
using AsbCloudApp.Services.WellOperationImport;
|
||||
@ -15,43 +14,27 @@ namespace AsbCloudInfrastructure.Services.WellOperationImport;
|
||||
|
||||
public class WellOperationImportService : IWellOperationImportService
|
||||
{
|
||||
private readonly IEnumerable<IWellOperationExcelParser> excelParsers;
|
||||
private readonly IWellOperationRepository wellOperationRepository;
|
||||
|
||||
private static readonly DateTime dateLimitMin = new(2001, 1, 1, 0, 0, 0);
|
||||
private static readonly DateTime dateLimitMax = new(2099, 1, 1, 0, 0, 0);
|
||||
private static readonly TimeSpan drillingDurationLimitMax = TimeSpan.FromDays(366);
|
||||
|
||||
public WellOperationImportService(IEnumerable<IWellOperationExcelParser> excelParsers,
|
||||
IWellOperationRepository wellOperationRepository)
|
||||
public WellOperationImportService(IWellOperationRepository wellOperationRepository)
|
||||
{
|
||||
this.excelParsers = excelParsers;
|
||||
this.wellOperationRepository = wellOperationRepository;
|
||||
}
|
||||
|
||||
public async Task ImportAsync(int idWell, int idUser, Stream stream, WellOperationParserOptionsDto options, bool deleteBeforeImport,
|
||||
CancellationToken cancellationToken)
|
||||
public async Task ImportAsync(int idWell, int idUser, int idType, SheetDto sheet, bool deleteBeforeImport, CancellationToken cancellationToken)
|
||||
{
|
||||
var excelParser = excelParsers.FirstOrDefault(p =>
|
||||
p.IdTemplate == options.IdTemplate &&
|
||||
p.IdTypes.Contains(options.IdType))
|
||||
?? throw new ArgumentInvalidException(nameof(options.IdTemplate), "Невозможно импортировать файл");
|
||||
|
||||
IEnumerable<RowDto> rows;
|
||||
var validationErrors = new List<string>();
|
||||
|
||||
var sections = wellOperationRepository.GetSectionTypes();
|
||||
var categories = wellOperationRepository.GetCategories(false);
|
||||
|
||||
rows = options.IdTemplate switch
|
||||
{
|
||||
0 => excelParser.Parse(stream, options),
|
||||
_ => excelParser.Parse(stream, options)
|
||||
};
|
||||
|
||||
var operations = new List<WellOperationDto>();
|
||||
|
||||
foreach (var row in rows)
|
||||
foreach (var row in sheet.Rows)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -59,38 +42,38 @@ public class WellOperationImportService : IWellOperationImportService
|
||||
string.Equals(s.Caption, row.Section, StringComparison.CurrentCultureIgnoreCase));
|
||||
|
||||
if (section is null)
|
||||
throw new FileFormatException($"Лист '{options.SheetName}'. В строке '{row.Number}' не удалось определить секцию");
|
||||
throw new FileFormatException($"Лист '{sheet.Name}'. В строке '{row.Number}' не удалось определить секцию");
|
||||
|
||||
var category = categories.FirstOrDefault(c =>
|
||||
string.Equals(c.Name, row.Category, StringComparison.CurrentCultureIgnoreCase));
|
||||
|
||||
if (category is null)
|
||||
throw new FileFormatException($"Лист '{options.SheetName}'. В строке '{row.Number}' не удалось определить операцию");
|
||||
throw new FileFormatException($"Лист '{sheet.Name}'. В строке '{row.Number}' не удалось определить операцию");
|
||||
|
||||
if (row.DepthStart is not (>= 0d and <= 20_000d))
|
||||
throw new FileFormatException(
|
||||
$"Лист '{options.SheetName}'. Строка '{row.Number}' некорректная глубина на начало операции");
|
||||
$"Лист '{sheet.Name}'. Строка '{row.Number}' некорректная глубина на начало операции");
|
||||
|
||||
if (row.DepthEnd is not (>= 0d and <= 20_000d))
|
||||
throw new FileFormatException(
|
||||
$"Лист '{options.SheetName}'. Строка '{row.Number}' некорректная глубина на конец операции");
|
||||
$"Лист '{sheet.Name}'. Строка '{row.Number}' некорректная глубина на конец операции");
|
||||
|
||||
if (row.Date < dateLimitMin && row.Date > dateLimitMax)
|
||||
throw new FileFormatException(
|
||||
$"Лист '{options.SheetName}'. Строка '{row.Number}' неправильно получена дата начала операции");
|
||||
$"Лист '{sheet.Name}'. Строка '{row.Number}' неправильно получена дата начала операции");
|
||||
|
||||
if (operations.LastOrDefault()?.DateStart > row.Date)
|
||||
throw new FileFormatException(
|
||||
$"Лист '{options.SheetName}' строка '{row.Number}' дата позднее даты предыдущей операции");
|
||||
$"Лист '{sheet.Name}' строка '{row.Number}' дата позднее даты предыдущей операции");
|
||||
|
||||
if (row.Duration is not (>= 0d and <= 240d))
|
||||
throw new FileFormatException($"Лист '{options.SheetName}'. Строка '{row.Number}' некорректная длительность операции");
|
||||
throw new FileFormatException($"Лист '{sheet.Name}'. Строка '{row.Number}' некорректная длительность операции");
|
||||
|
||||
operations.Add(new WellOperationDto
|
||||
{
|
||||
IdWell = idWell,
|
||||
IdUser = idUser,
|
||||
IdType = options.IdType,
|
||||
IdType = idType,
|
||||
IdWellSectionType = section.Id,
|
||||
IdCategory = category.Id,
|
||||
CategoryInfo = row.CategoryInfo,
|
||||
@ -107,7 +90,7 @@ public class WellOperationImportService : IWellOperationImportService
|
||||
}
|
||||
|
||||
if (operations.Any() && operations.Min(o => o.DateStart) - operations.Max(o => o.DateStart) > drillingDurationLimitMax)
|
||||
validationErrors.Add($"Лист {options.SheetName} содержит диапазон дат больше {drillingDurationLimitMax}");
|
||||
validationErrors.Add($"Лист {sheet.Name} содержит диапазон дат больше {drillingDurationLimitMax}");
|
||||
|
||||
if (validationErrors.Any())
|
||||
throw new FileFormatException(string.Join("\r\n", validationErrors));
|
||||
@ -119,7 +102,8 @@ public class WellOperationImportService : IWellOperationImportService
|
||||
{
|
||||
var existingOperations = await wellOperationRepository.GetAsync(new WellOperationRequest
|
||||
{
|
||||
IdWell = idWell
|
||||
IdWell = idWell,
|
||||
OperationType = idType
|
||||
}, cancellationToken);
|
||||
|
||||
await wellOperationRepository.DeleteAsync(existingOperations.Select(o => o.Id), cancellationToken);
|
||||
|
Loading…
Reference in New Issue
Block a user