using System; using System.Collections.Generic; using System.IO; using System.Linq; using AsbCloudApp.Data.WellOperationImport; using AsbCloudApp.Exceptions; using AsbCloudApp.Services.WellOperationImport; using AsbCloudDb.Model; using AsbCloudInfrastructure.Services.WellOperationImport.Constants; using ClosedXML.Excel; namespace AsbCloudInfrastructure.Services.WellOperationImport.FileParser; public class WellOperationDefaultExcelParser : IWellOperationExcelParser { public int IdTemplate => Templates.IdDefaultTemplate; public IEnumerable IdTypes => new[] { WellOperation.IdOperationTypePlan, WellOperation.IdOperationTypeFact }; public IEnumerable Parse(Stream stream, WellOperationParserOptionsDto options) { using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled); return ParseWorkbook(workbook, options); } private static IEnumerable ParseWorkbook(IXLWorkbook workbook, WellOperationParserOptionsDto options) { if (string.IsNullOrWhiteSpace(options.SheetName)) throw new ArgumentInvalidException(nameof(options.SheetName), "Не указано название листа"); var sheet = workbook.Worksheets.FirstOrDefault(ws => string.Equals(ws.Name, options.SheetName, StringComparison.CurrentCultureIgnoreCase)) ?? throw new FileFormatException($"Книга excel не содержит листа '{options.SheetName}'"); return ParseSheet(sheet); } private static IEnumerable ParseSheet(IXLWorksheet sheet) { if (sheet.RangeUsed().RangeAddress.LastAddress.ColumnNumber < 7) throw new FileFormatException($"Лист {sheet.Name} содержит меньшее количество столбцов."); var count = sheet.RowsUsed().Count() - DefaultTemplateInfo.HeaderRowsCount; switch (count) { case > 1024: throw new FileFormatException($"Лист {sheet.Name} содержит слишком большое количество операций."); case <= 0: return Enumerable.Empty(); } var rows = new RowDto[count]; var cellValuesErrors = new List(); for (int i = 0; i < rows.Length; i++) { try { var xlRow = sheet.Row(1 + i + DefaultTemplateInfo.HeaderRowsCount); rows[i] = ParseRow(xlRow); } catch (FileFormatException ex) { cellValuesErrors.Add(ex.Message); } } if (cellValuesErrors.Any()) throw new FileFormatException(string.Join("\r\n", cellValuesErrors)); return rows; } private static RowDto ParseRow(IXLRow xlRow) { return new RowDto { Number = xlRow.RowNumber(), Section = GetCellValue(xlRow.Cell(DefaultTemplateInfo.ColumnSection)), Category = GetCellValue(xlRow.Cell(DefaultTemplateInfo.ColumnCategory)), CategoryInfo = GetCellValue(xlRow.Cell(DefaultTemplateInfo.ColumnCategoryInfo)), DepthStart = GetCellValue(xlRow.Cell(DefaultTemplateInfo.ColumnDepthStart)), DepthEnd = GetCellValue(xlRow.Cell(DefaultTemplateInfo.ColumnDepthEnd)), Date = GetCellValue(xlRow.Cell(DefaultTemplateInfo.ColumnDate)), Duration = GetCellValue(xlRow.Cell(DefaultTemplateInfo.ColumnDuration)), Comment = GetCellValue(xlRow.Cell(DefaultTemplateInfo.ColumnComment)) }; } //TODO: вынести в метод расширения private static T GetCellValue(IXLCell cell) { try { return (T)Convert.ChangeType(cell.Value, typeof(T)); } catch { throw new FileFormatException( $"Лист '{cell.Worksheet.Name}'. Ячейка: ({cell.Address.RowNumber},{cell.Address.ColumnNumber}) содержит некорректное значение"); } } }