using System; using System.Collections.Generic; using System.IO; using System.Linq; using AsbCloudApp.Data; using AsbCloudApp.Data.WellOperationImport; using AsbCloudApp.Repositories; using AsbCloudApp.Services; using AsbCloudApp.Services.WellOperationImport; namespace AsbCloudInfrastructure.Services.WellOperationImport; public class WellOperationImportService : IWellOperationImportService { private readonly IWellService wellService; private readonly IWellOperationRepository wellOperationRepository; private readonly IWellOperationCategoryRepository wellOperationCategoryRepository; 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( IWellService wellService, IWellOperationRepository wellOperationRepository, IWellOperationCategoryRepository wellOperationCategoryRepository ) { this.wellService = wellService; this.wellOperationRepository = wellOperationRepository; this.wellOperationCategoryRepository = wellOperationCategoryRepository; } public IEnumerable Import(int idWell, int idUser, int idType, SheetDto sheet) { var validationErrors = new List(); var sections = wellOperationRepository.GetSectionTypes(); var categories = wellOperationCategoryRepository.Get(false); var wellOperations = new List(); var rows = sheet.Rows.OrderBy(r => r.Date); var prevRow = new RowDto(); foreach (var row in rows) { try { var section = sections.FirstOrDefault(s => string.Equals(s.Caption, row.Section, StringComparison.CurrentCultureIgnoreCase)); if (section is null) 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($"Лист '{sheet.Name}'. В строке '{row.Number}' не удалось определить операцию"); if (row.DepthStart is not (>= 0d and <= 20_000d)) throw new FileFormatException( $"Лист '{sheet.Name}'. Строка '{row.Number}' некорректная глубина на начало операции"); if (row.DepthEnd is not (>= 0d and <= 20_000d)) throw new FileFormatException( $"Лист '{sheet.Name}'. Строка '{row.Number}' некорректная глубина на конец операции"); if (row.Date < dateLimitMin && row.Date > dateLimitMax) throw new FileFormatException( $"Лист '{sheet.Name}'. Строка '{row.Number}' неправильно получена дата начала операции"); if (prevRow.Date > row.Date) throw new FileFormatException( $"Лист '{sheet.Name}' строка '{row.Number}' дата позднее даты предыдущей операции"); if (row.Duration is not (>= 0d and <= 240d)) throw new FileFormatException($"Лист '{sheet.Name}'. Строка '{row.Number}' некорректная длительность операции"); var timezone = wellService.GetTimezone(idWell); var timezoneOffset = TimeSpan.FromHours(timezone.Hours); var wellOperation = new WellOperationDto { IdWell = idWell, IdUser = idUser, IdType = idType, IdWellSectionType = section.Id, WellSectionTypeName = section.Caption, IdCategory = category.Id, CategoryName = category.Name, CategoryInfo = row.CategoryInfo, DepthStart = row.DepthStart, DepthEnd = row.DepthEnd, DateStart = new DateTimeOffset(row.Date, timezoneOffset), DurationHours = row.Duration, Comment = row.Comment }; wellOperations.Add(wellOperation); prevRow = row; } catch (FileFormatException ex) { validationErrors.Add(ex.Message); } } if (wellOperations.Any() && wellOperations.Min(o => o.DateStart) - wellOperations.Max(o => o.DateStart) > drillingDurationLimitMax) validationErrors.Add($"Лист {sheet.Name} содержит диапазон дат больше {drillingDurationLimitMax}"); if (validationErrors.Any()) throw new FileFormatException(string.Join("\r\n", validationErrors)); return wellOperations; } }