diff --git a/AsbCloudApp/Services/WellOperationImport/IWellOperationExcelParser.cs b/AsbCloudApp/Services/WellOperationImport/IWellOperationExcelParser.cs deleted file mode 100644 index 7a695beb..00000000 --- a/AsbCloudApp/Services/WellOperationImport/IWellOperationExcelParser.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.IO; -using AsbCloudApp.Data.WellOperationImport; -using AsbCloudApp.Data.WellOperationImport.Options; - -namespace AsbCloudApp.Services.WellOperationImport; - -/// -/// Парсинг операций из excel файла -/// -public interface IWellOperationExcelParser - where TOptions : IWellOperationImportOptions -{ - /// - /// Метод парсинга документа - /// - /// - /// - /// - SheetDto Parse(Stream stream, TOptions options); -} \ No newline at end of file diff --git a/AsbCloudApp/Services/WellOperationImport/IWellOperationExportService.cs b/AsbCloudApp/Services/WellOperationImport/IWellOperationExportService.cs deleted file mode 100644 index 9b0a96ac..00000000 --- a/AsbCloudApp/Services/WellOperationImport/IWellOperationExportService.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace AsbCloudApp.Services.WellOperationImport; - -/// -/// Экспорт ГГД -/// -public interface IWellOperationExportService -{ - /// - /// Скачать в excel - /// - /// - /// - /// - Task ExportAsync(int idWell, CancellationToken cancellationToken); -} \ No newline at end of file diff --git a/AsbCloudApp/Services/WellOperationImport/IWellOperationImportService.cs b/AsbCloudApp/Services/WellOperationImport/IWellOperationImportService.cs deleted file mode 100644 index f65d8888..00000000 --- a/AsbCloudApp/Services/WellOperationImport/IWellOperationImportService.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Collections.Generic; -using AsbCloudApp.Data; -using AsbCloudApp.Data.WellOperationImport; - -namespace AsbCloudApp.Services.WellOperationImport; - -/// -/// Импорт ГГД -/// -public interface IWellOperationImportService -{ - /// - /// Загрузить из excel список операций - /// - /// - /// - /// - /// - IEnumerable Import(int idWell, int idUser, int idType, SheetDto sheet); -} \ No newline at end of file diff --git a/AsbCloudApp/Services/WellOperationImport/IWellOperationImportTemplateService.cs b/AsbCloudApp/Services/WellOperationImport/IWellOperationImportTemplateService.cs deleted file mode 100644 index 817f3ae5..00000000 --- a/AsbCloudApp/Services/WellOperationImport/IWellOperationImportTemplateService.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.IO; - -namespace AsbCloudApp.Services.WellOperationImport; - -/// -/// Сервис для получения шаблонов ГГД -/// -public interface IWellOperationImportTemplateService -{ - /// - /// Скачать шаблон для заполнения - /// - /// - Stream GetExcelTemplateStream(); -} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/ExcelServices/Templates/WellOperations/WellOperationFactTemplate.cs b/AsbCloudInfrastructure/Services/ExcelServices/Templates/WellOperations/WellOperationFactTemplate.cs new file mode 100644 index 00000000..afb5fe19 --- /dev/null +++ b/AsbCloudInfrastructure/Services/ExcelServices/Templates/WellOperations/WellOperationFactTemplate.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using AsbCloudApp.Data.WellOperation; + +namespace AsbCloudInfrastructure.Services.ExcelServices.Templates.WellOperations; + +public class WellOperationFactTemplate : ITemplateParameters +{ + public string SheetName => "Факт"; + + public int HeaderRowsCount => 1; + + public string FileName => "WellOperationFactTemplate.xlsx"; + + public IDictionary Cells => new Dictionary + { + { nameof(WellOperationDto.WellSectionTypeCaption), new Cell(1, typeof(string)) }, + { nameof(WellOperationDto.OperationCategoryName), new Cell(2, typeof(string)) }, + { nameof(WellOperationDto.CategoryInfo), new Cell(3, typeof(string)) }, + { nameof(WellOperationDto.DepthStart), new Cell(4, typeof(double)) }, + { nameof(WellOperationDto.DepthEnd), new Cell(5, typeof(double)) }, + { nameof(WellOperationDto.DateStart), new Cell(6, typeof(DateTime)) }, + { nameof(WellOperationDto.DurationHours), new Cell(7, typeof(double)) }, + { nameof(WellOperationDto.Comment), new Cell(8, typeof(string)) } + }; +} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/WellOperationImport/Constants/DefaultTemplateInfo.cs b/AsbCloudInfrastructure/Services/WellOperationImport/Constants/DefaultTemplateInfo.cs deleted file mode 100644 index 96f3272b..00000000 --- a/AsbCloudInfrastructure/Services/WellOperationImport/Constants/DefaultTemplateInfo.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace AsbCloudInfrastructure.Services.WellOperationImport.Constants; - -public static class DefaultTemplateInfo -{ - public const string SheetNamePlan = "План"; - public const string SheetNameFact = "Факт"; - - public const int HeaderRowsCount = 1; - public const int ColumnSection = 1; - public const int ColumnCategory = 2; - public const int ColumnCategoryInfo = 3; - public const int ColumnDepthStart = 4; - public const int ColumnDepthEnd = 5; - public const int ColumnDate = 6; - public const int ColumnDuration = 7; - public const int ColumnComment = 8; -} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/WellOperationImport/Constants/OperationAttributes.cs b/AsbCloudInfrastructure/Services/WellOperationImport/Constants/OperationAttributes.cs deleted file mode 100644 index c4049d03..00000000 --- a/AsbCloudInfrastructure/Services/WellOperationImport/Constants/OperationAttributes.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace AsbCloudInfrastructure.Services.WellOperationImport.Constants; - -public static class OperationAttributes -{ - public const string CategoryInfo = "Описание"; - public const string SectionDiameter = "ОК"; - public const string Depth = "Забой"; - public const string Duration = "Время операции"; - public const string Date = "Дата окончания операции"; -} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/WellOperationImport/Constants/Templates.cs b/AsbCloudInfrastructure/Services/WellOperationImport/Constants/Templates.cs deleted file mode 100644 index 631dc170..00000000 --- a/AsbCloudInfrastructure/Services/WellOperationImport/Constants/Templates.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace AsbCloudInfrastructure.Services.WellOperationImport.Constants; - -public static class Templates -{ - public const int IdDefaultTemplate = 0; - public const int IdGazpromKhantosTemplate = 1; -} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/WellOperationImport/FileParser/StringSimilarity/CosineSimilarity.cs b/AsbCloudInfrastructure/Services/WellOperationImport/FileParser/StringSimilarity/CosineSimilarity.cs deleted file mode 100644 index ae69f7f9..00000000 --- a/AsbCloudInfrastructure/Services/WellOperationImport/FileParser/StringSimilarity/CosineSimilarity.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; - -namespace AsbCloudInfrastructure.Services.WellOperationImport.FileParser.StringSimilarity; - -public class CosineSimilarity -{ - private const int DefaultK = 2; - - protected int K { get; } - - public CosineSimilarity(int k) - { - if (k <= 0) - { - throw new ArgumentOutOfRangeException(nameof(k), "k should be positive!"); - } - - K = k; - } - - public CosineSimilarity() : this(DefaultK) { } - - public double Similarity(IDictionary profile1, IDictionary profile2) - => DotProduct(profile1, profile2) - / (Norm(profile1) * Norm(profile2)); - - public Dictionary GetProfile(string s) - { - var shingles = new Dictionary(); - - if (string.IsNullOrWhiteSpace(s)) - return shingles; - - var cleanString = Stemming(s); - - for (int i = 0; i < (cleanString.Length - K + 1); i++) - { - var shingle = cleanString.Substring(i, K); - - if (shingles.TryGetValue(shingle, out var old)) - { - shingles[shingle] = old + 1; - } - else - { - shingles[shingle] = 1; - } - } - - return shingles; - } - - private static string Stemming(string s) - { - var cleaned = Regex.Replace(s.ToLower(), "[^a-zа-я0-9]", ""); - var words = cleaned.Split(' '); - var filteredWords = words.Where(word => word.Length > 1).ToArray(); - return string.Concat(filteredWords); - } - - private static double Norm(IDictionary profile) - { - double agg = 0; - - foreach (var entry in profile) - { - agg += 1.0 * entry.Value * entry.Value; - } - - return Math.Sqrt(agg); - } - - private static double DotProduct(IDictionary profile1, IDictionary profile2) - { - var smallProfile = profile2; - var largeProfile = profile1; - - if (profile1.Count < profile2.Count) - { - smallProfile = profile1; - largeProfile = profile2; - } - - double agg = 0; - foreach (var entry in smallProfile) - { - if (!largeProfile.TryGetValue(entry.Key, out var i)) - continue; - - agg += 1.0 * entry.Value * i; - } - - return agg; - } -} diff --git a/AsbCloudInfrastructure/Services/WellOperationImport/FileParser/WellOperationDefaultExcelParser.cs b/AsbCloudInfrastructure/Services/WellOperationImport/FileParser/WellOperationDefaultExcelParser.cs deleted file mode 100644 index 2996d642..00000000 --- a/AsbCloudInfrastructure/Services/WellOperationImport/FileParser/WellOperationDefaultExcelParser.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System; -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; -using ClosedXML.Excel; - -namespace AsbCloudInfrastructure.Services.WellOperationImport.FileParser; - -public class WellOperationDefaultExcelParser : IWellOperationExcelParser -{ - public SheetDto Parse(Stream stream, WellOperationImportDefaultOptionsDto options) - { - using var workbook = new XLWorkbook(stream); - - return ParseWorkbook(workbook, options); - } - - private static SheetDto ParseWorkbook(IXLWorkbook workbook, WellOperationImportDefaultOptionsDto options) - { - var sheetName = options.IdType == WellOperation.IdOperationTypePlan - ? DefaultTemplateInfo.SheetNamePlan - : DefaultTemplateInfo.SheetNameFact; - - var sheet = workbook.GetWorksheet(sheetName); - - return ParseSheet(sheet); - } - - private static SheetDto 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 new SheetDto { Name = sheet.Name }; - } - - 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 new SheetDto - { - Name = sheet.Name, - Rows = rows - }; - } - - private static RowDto ParseRow(IXLRow xlRow) - { - return new RowDto - { - Number = xlRow.RowNumber(), - Section = xlRow.Cell(DefaultTemplateInfo.ColumnSection).GetCellValue(), - Category = xlRow.Cell(DefaultTemplateInfo.ColumnCategory).GetCellValue(), - CategoryInfo = xlRow.Cell(DefaultTemplateInfo.ColumnCategoryInfo).GetCellValue(), - DepthStart = xlRow.Cell(DefaultTemplateInfo.ColumnDepthStart).GetCellValue(), - DepthEnd = xlRow.Cell(DefaultTemplateInfo.ColumnDepthEnd).GetCellValue(), - Date = xlRow.Cell(DefaultTemplateInfo.ColumnDate).GetCellValue(), - Duration = xlRow.Cell(DefaultTemplateInfo.ColumnDuration).GetCellValue(), - Comment = xlRow.Cell(DefaultTemplateInfo.ColumnComment).GetCellValue() - }; - } -} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/WellOperationImport/FileParser/WellOperationGazpromKhantosExcelParser.cs b/AsbCloudInfrastructure/Services/WellOperationImport/FileParser/WellOperationGazpromKhantosExcelParser.cs deleted file mode 100644 index 7eb62839..00000000 --- a/AsbCloudInfrastructure/Services/WellOperationImport/FileParser/WellOperationGazpromKhantosExcelParser.cs +++ /dev/null @@ -1,227 +0,0 @@ -using System; -using System.Collections.Generic; -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 AsbCloudInfrastructure.Services.WellOperationImport.Constants; -using AsbCloudInfrastructure.Services.WellOperationImport.FileParser.StringSimilarity; -using ClosedXML.Excel; - -namespace AsbCloudInfrastructure.Services.WellOperationImport.FileParser; - -public class WellOperationGazpromKhantosExcelParser : IWellOperationExcelParser -{ - private class Operation - { - public int RowNumber { get; set; } - - public string? CategoryInfo { get; set; } - - public double SectionDiameter { get; set; } - - public double Depth { get; set; } - - public double Duration { get; set; } - - public DateTime Date { get; set; } - } - - private readonly CosineSimilarity cosineSimilarity = new(); - - private readonly Dictionary operationDict = InitDict("Operations.txt", '='); - private readonly Dictionary sectionDict = InitDict("Sections.txt", '='); - private readonly Dictionary operationAttributesDict = InitDict("OperationAttributes.txt", '='); - - public SheetDto Parse(Stream stream, WellOperationImportGazpromKhantosOptionsDto options) - { - using var workbook = new XLWorkbook(stream); - - return ParseWorkBook(workbook, options); - } - - private SheetDto ParseWorkBook(IXLWorkbook workbook, WellOperationImportGazpromKhantosOptionsDto options) - { - if (options.StartRow is < 1 or > 1048576) - throw new ArgumentInvalidException(nameof(options.StartRow), "Некорректное значение начальной строки"); - - if (options.EndRow is < 1 or > 1048576) - throw new ArgumentInvalidException(nameof(options.EndRow), "Некорректное значение конечной строки"); - - if (options.EndRow < options.StartRow) - throw new ArgumentInvalidException(nameof(options.EndRow), "Конечный номер строки не может быть больше начального"); - - var sheet = workbook.GetWorksheet(options.SheetName); - return ParseSheet(sheet, options.StartRow, options.EndRow); - } - - private SheetDto ParseSheet(IXLWorksheet sheet, int startRow, int endRow) - { - var operationAttributes = GetOperationAttributes(sheet.RowsUsed()); - - if (operationAttributes is null) - return new SheetDto { Name = sheet.Name }; - - var rowsCount = endRow - startRow + 1; - - var operations = new List(); - - var cellValuesErrors = new List(); - - for (int i = 0; i < rowsCount; i++) - { - var xlRow = sheet.Row(startRow + i); - - try - { - operations.Add(new Operation - { - RowNumber = xlRow.RowNumber(), - CategoryInfo = xlRow.Cell(operationAttributes[OperationAttributes.CategoryInfo]).GetCellValue(), - SectionDiameter =xlRow.Cell(operationAttributes[OperationAttributes.SectionDiameter]).GetCellValue(), - Depth = xlRow.Cell(operationAttributes[OperationAttributes.Depth]).GetCellValue(), - Duration = xlRow.Cell(operationAttributes[OperationAttributes.Duration]).GetCellValue(), - Date = xlRow.Cell(operationAttributes[OperationAttributes.Date]).GetCellValue() - }); - } - catch (FileFormatException ex) - { - cellValuesErrors.Add(ex.Message); - } - } - - if (cellValuesErrors.Any()) - throw new FileFormatException(string.Join("\r\n", cellValuesErrors)); - - return new SheetDto() - { - Name = sheet.Name, - Rows = BuildRows() - }; - - IEnumerable<(double Diameter, string Name)> BuildSections() - { - var groupedOperations = operations.GroupBy(o => o.SectionDiameter) - .Select(s => new - { - Diameter = s.Key, - CategoryInfo = string.Concat(s.Select(o => o.CategoryInfo)) - }); - - var repeatedSections = new[] { "xвостовик" }; - - var sections = new List<(double diameter, string section)>(); - - foreach (var groupedOperation in groupedOperations) - { - var sectionNamesSet = new HashSet(sections.Select(s => s.section)); - - sections.Add(new ValueTuple(groupedOperation.Diameter, sectionDict.FirstOrDefault(item => - groupedOperation.CategoryInfo.Contains(item.Key) && - (!sectionNamesSet.Contains(item.Value) || repeatedSections.Contains(item.Value.ToLowerInvariant()))).Value)); - } - - return sections; - } - - IEnumerable BuildRows() - { - if (!operations.Any()) - return Enumerable.Empty(); - - var rows = new List(); - - for (int i = 0; i < operations.Count; i++) - { - var currentOperation = operations[i]; - var nextOperation = i + 1 < operations.Count ? operations[i + 1] : currentOperation; - - rows.Add(new RowDto - { - Number = currentOperation.RowNumber, - Section = BuildSections().FirstOrDefault(s => Math.Abs(s.Diameter - currentOperation.SectionDiameter) < 0.1).Name, - Category = GetValueDictionary(operationDict, currentOperation.CategoryInfo, 0.3), - CategoryInfo = currentOperation.CategoryInfo, - DepthStart = currentOperation.Depth, - DepthEnd = nextOperation.Depth, - Duration = currentOperation.Duration, - Date = currentOperation.Date.AddHours(-currentOperation.Duration) - }); - } - - return rows; - } - } - - private IDictionary? GetOperationAttributes(IXLRows xlRows) - { - const int countOperationAttributes = 5; - - IDictionary? operationAttributes = null; - - foreach (var xlRow in xlRows) - { - operationAttributes = new Dictionary(); - - var cells = xlRow.CellsUsed().ToArray(); - - foreach (var cell in cells) - { - var operationAttribute = GetValueDictionary(operationAttributesDict, cell.GetCellValue(), 0.7); - - if (operationAttribute is null || operationAttributes.Any(a => a.Key == operationAttribute)) - continue; - - operationAttributes.Add(operationAttribute, cell.Address.ColumnNumber); - } - - if (operationAttributes.Count >= countOperationAttributes) - break; - } - - return operationAttributes is not null && operationAttributes.Count == countOperationAttributes ? operationAttributes : null; - } - - private string? GetValueDictionary(IDictionary dict, string? cellValue, double? minSimilarity) - { - if (string.IsNullOrWhiteSpace(cellValue)) - return null; - - var similarValues = new List<(double similarity, string value)>(); - - var profile1 = cosineSimilarity.GetProfile(cellValue); - - foreach (var item in dict) - { - var profile2 = cosineSimilarity.GetProfile(item.Key); - - var similarity = cosineSimilarity.Similarity(profile1, profile2); - - similarValues.Add((similarity, item.Value)); - } - - var mostSimilarValue = similarValues.MaxBy(v => v.similarity); - - return minSimilarity.HasValue && mostSimilarValue.similarity >= minSimilarity ? mostSimilarValue.value : null; - } - - private static Dictionary InitDict(string fileName, char separator) - { - var resourceName = Assembly.GetExecutingAssembly() - .GetManifestResourceNames() - .FirstOrDefault(n => n.EndsWith(fileName))!; - - var stream = Assembly.GetExecutingAssembly() - .GetManifestResourceStream(resourceName)!; - - using var reader = new StreamReader(stream); - - return reader.ReadToEnd().Split('\r') - .Where(s => !string.IsNullOrWhiteSpace(s)) - .Select(line => line.Split(separator)) - .ToDictionary(parts => parts[0].Trim(), parts => parts[1].Trim()); - } -} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/WellOperationImport/Files/Dictionaries/OperationAttributes.txt b/AsbCloudInfrastructure/Services/WellOperationImport/Files/Dictionaries/OperationAttributes.txt deleted file mode 100644 index 7127ce99..00000000 --- a/AsbCloudInfrastructure/Services/WellOperationImport/Files/Dictionaries/OperationAttributes.txt +++ /dev/null @@ -1,8 +0,0 @@ -Описание=Описание -ОК=ОК -Секция=ОК -Забой, м=Забой -Время=Время операции -Плановое время бурения, сут=Время операции -Окончание=Дата окончания операции -Дата окончания План РГ=Дата окончания операции \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/WellOperationImport/Files/Dictionaries/Operations.txt b/AsbCloudInfrastructure/Services/WellOperationImport/Files/Dictionaries/Operations.txt deleted file mode 100644 index 68bc28c7..00000000 --- a/AsbCloudInfrastructure/Services/WellOperationImport/Files/Dictionaries/Operations.txt +++ /dev/null @@ -1,201 +0,0 @@ -Сборка КНБК=Сборка КНБК -Сборка роторной КНБК=Сборка КНБК -Шаблонирование спуск КНБК=Шаблонирование перед спуском -Бурение под направлением=Бурение ротором -Шаблонирование перед спуском=Шаблонирование перед спуском -Шаблонировка пробуренного интервала + промывка на забое+ подъем КНБК=Шаблонирование перед спуском -Разборка КНБК=Разборка КНБК -ПР к спуску направления 324мм=ПЗР при спуске ОК -Спуск направления=Спуск ОК -Спуск направления 324мм=Спуск ОК -Цементаж направления 324мм=Цементирование -ОЗЦ. Оборудование устья.=ОЗЦ -ОЗЦ. Чистка забурочной ямы. Чистка ВШН. Отворот доп. патрубка. ЗГР=ОЗЦ -Перетяжка талевого каната / замена.=Перетяжка талевого каната -Шаблонирование подъём КНБК=Шаблонировка подъем БИ, продувка -Сборка СБТ 127мм-300м=Сборка БИ с мостков на подсвечник -Сборка КНБК для бурения кондуктора=Сборка КНБК -Сборка КНБК для бурения. Компоновка БК согласно собранного БИ в п.10=Сборка КНБК -Cпуск КНБК=Спуск КНБК -Cпуск КНБК со сборкой БИ с мостков=Спуск бурильного инструмента со сборкой с мостков -Разбурка оснастки (ЦКОД, цем.стакан, БК), замена раствора=Разбуривание тех.оснастки -Бурение под кондуктор. Наращивание св.=Бурение ротором -Промывка, ОБР, МBТ БР<70 кг/м3=Промывка -Промывка на забое=Промывка -Шаблонирование (подъем)=Шаблонировка во время бурения -Шаблонирование (спуск)=Шаблонировка во время бурения -Промывка на забое. Прокачка ВУС, ОБР, МBТ БР <70 кг/м3=Промывка -Подъем=Подъем КНБК -Разборка КНБК с телесистемой=Разборка КНБК -ПЗР к спуску ОК 245мм=ПЗР при спуске ОК -Спуск ОК 245мм с промежуточными промывками (500 м, 1000м). Вывоз БР с БДЕ=Спуск ОК -Промывка перед цементажем=Промывка при спуске ОК -Цементаж кондуктора 245мм=Цементирование -Монтаж ОУС. Вывоз БР, Чистка емкостей=Чистка ЦСГО/емкостного блока -Монтаж ОУС=Монтаж ПВО -Заготовка бурового раствора, чистка емкостей.=Опрессовка ПВО -Монтаж ПВО, монтаж разрезной воронки и устьевого желоба. Вывоз БР, заготовка БР=Монтаж ПВО -Опрессовка глухих плашек ППГ, БГ, БД , выкидных линий, крестовины с коренными задвижками. ЗБР=Опрессовка ПВО -Сборка КНБК на бурение=Сборка КНБК -Сборка СБТ 127мм-465м=Сборка БИ с мостков на подсвечник -Спуск КНБК со сборкой с мостков СБТ -127 (1700м)=Спуск КНБК -Сборка КНБК на бурение транспортного ствола=Сборка КНБК -Опрессовка трубных плашек, ПУГ=Опрессовка ПВО -Разбурка оснастки (ЦКОД, цем.стакан, БК, углубление на 2 метра ниже БК, опрессовка цементного кольца)=Разбуривание тех.оснастки -Разбурка БК, ЦКОДа и цем.стакана=Разбуривание тех.оснастки -Перевод скважины на новый раствор, чистка ЦСГО=Промывка - перевод скважины на новый раствор -Перевод скважины на новый буровой раствор=Промывка - перевод скважины на новый раствор -Бурение транспортного ствола наращ.св. (прокачка укрепляющих пачек ч/з каждые 150-200м)=Бурение ротором -Промывка после ХМ св TVD - 1660 м (ниже на 50 м)=Промывка -Чистка ЦСГО (опрессовка цем. кольца кондуктора во время чистки ЦСГО)=Чистка ЦСГО/емкостного блока -Промывка после Алымской св TVD - 2140 м (ниже на 50 м)=Промывка -Бурение транспортного ствола наращ. cв. (прокачка укрепляющих пачек ч/з каждые 150-200м).=Бурение ротором -Бурение транспортного ствола (1000м первые сутки бурения)=Бурение ротором -Подъем КНБК шаблонировка ствола скважины=Шаблонировка подъем БИ, продувка -Промывка (по согласованию с ЦУСС)=Промывка -Шаблонировка. Подъем КНБК (по согласованию с ЦУСС)=Шаблонировка во время бурения -Шаблонировка.Спуск КНБК со сборкой БИ 300м (по согласованию с ЦУСС)=Шаблонировка во время бурения -Промывка=Промывка -Шаблонировка. Подъем КНБК=Шаблонировка во время бурения -Шаблонировка.Спуск КНБК=Шаблонировка во время бурения -Разборка КНБК с т/с=Разборка КНБК -Промывка на забое, прокачка кольмат. пачки=Помывка -ПЗР к спуску ОК-178мм.=ПЗР при спуске ОК -Спуск ОК 178 мм (до устья, не потайная) с промежуточными промывками=Спуск ОК -Цементирование ОК-178мм=Цементирование -Отворот и выброс допускной трубы, демонтаж ПВО, замыв шурфа для выброса СБТ-127мм, чистка емкостей, приготовление БР=Демонтаж ПВО -Промывка, установка смазывающей пачки=Промывка -Выброс СБТ-127мм на мостки, чистка емкостей, приготовление БР=Подъем БИ с выбросом на мостки -Подъем КНБК с выбросом БИ - 500м (выброс согласовать с куратором ЦУСС)=Подъем КНБК -Монтаж ПВО, замена трубных плашек 127мм на 102мм, замена рабочего переводника на СВП, приготовление БР=Перетяжка талевого каната -ПЗР к спуску ОК 178мм=ПЗР при спуске ОК -Спуск ОК 178мм с промывками. Вывоз БР с БДЕ=Спуск ОК -Цементирование 178мм ОК. Вывоз БР с БДЕ=Цементирование -Частичный демонтаж ПВО=Демонтаж ПВО -Выброс БИ 127 на мостки - 1600м (Оставляем БИ 127 1400 м на бурение под кондуктор). Вывоз БР, чистка емкостей=Подъем БИ с выбросом на мостки -Частичный монтаж ПВО=Монтаж ПВО -Опрессовка (200 атм) глухих плашек ППГ, БГ, БД, выкидных линий, крестовины с коренными задвижками, ЗБР. Сборка БИ-102мм - 1000м для бурения ГС свечами.=Опрессовка ПВО -Сборка КНБК на бурение секции под хвостовик 114мм=Сборка КНБК -Спуск КНБК со сборкой БИ 102 и промежуточными промывками.=Промывка - перевод скважины на новый раствор -Опрессовка трубных плашек ППГ, ПУГ. Промывка, перезапись гаммы=Опрессовка ПВО -Разбурка оснастки (ЦКОД, цем.стакан, БК)=Разбуривание тех.оснастки -Перевод на новый раствор=Промывка - перевод скважины на новый раствор -Чистка ЦСГО=Чистка ЦСГО/емкостного блока -Бурение горизонтального участка скважины (прокачка укрепляющих пачек ч/з каждые 100 м)=Бурение ротором -Подъем БИ в БК Ø178мм.=Подъем КНБК -Спуск БИ со сборкой ТБТ 88,9мм на опрессовку (20м до БК 178)=Спуск КНБК -Опрессовка БИ, установка на подсвечник ТБТ=Опрессовка БИ -Проработка в 2 этапа:1 этап - прямая принудительная проработка; 2 этап - спуск на "сухую"(имитация спуска хвостовика)=Проработка принудительная -Cборка хвостовика=Сборка хвостовика 114мм (согласно схеме) -Промывка, прокачка ВУС=Промывка -Подъем КНБК=Подъем КНБК -ПЗР к спуску хвостовика=ПЗР при спуске ОК -Сборка хвостовика 114мм (согласно схеме)=Сборка хвостовика 114мм (согласно схеме) -Спуск хвостовика 114мм на БИ. В БК 178 перевод на тех.воду (по согл.с ЦУСС)=Спуск ОК -Активация подвески (4ч). Перевод на жидкость заканчивания (2ч).=Активация подвески, опрессовка -Подъем БИ с выбросом на мостки. Оставляем ТБТ 89 (800 м) на следующую скв=Подъем БИ с выбросом на мостки -Демонтаж ПВО=Демонтаж ПВО -Монтаж, опрессовка ФА=Монтаж, опрессовка ФА -5% времени на ТО БУ=Ремонт -Монтаж ФА=Монтаж, опрессовка ФА -Подъем разъединителя с выбросом СБТ-102мм на мостки=Подъем инструмента -Активация подвески. Перевод на жидкость заканчивания. Опрессовка пакера подвески хвостовика.=Активация подвески (потайной колонны, хвостовика) -ПР к спуску хвостовика=ПЗР при спуске ОК -Подъем КНБК с частичным выбросом СБТ-102мм на приемные мостки=Подъем БИ с выбросом на мостки -Бурение горизонтального участка скважины (прокачка укрепляющих пачек ч/з каждые 100м)=Бурение ротором -Промывка перезапись ГК=Промывка -Спуск КНБК со сборкой СБТ-102мм с приемных мостков, с промежуточными промывками каждые 500м=Спуск бурильного инструмента со сборкой с мостков -Сборка КНБК для бурения горизонтального участка скважины=Сборка БИ с мостков на подсвечник -Опрессовка глухих плашек ППГ, БГ, БД, выкидных линий, крестовины с коренными задвижками, приготовление бур.раствора=Опрессовка ПВО -ВМР=ВМР -Долив затруба при подъёме=Долив затруба при подъёме -Закачка/прокачка пачки=Закачка/прокачка пачки -Комплекс ГИС на жестком кабеле=Комплекс ГИС на жестком кабеле -Комплекс ГИС на кабеле=Комплекс ГИС на кабеле -Комплекс ГИС на трубах=Комплекс ГИС на трубах -Контролируемое ГНВП=Контролируемое ГНВП -Ловильные работы=Ловильные работы -Наработка жёлоба=Наработка жёлоба -Наращивание=Наращивание -НПВ / прочее=НПВ / прочее -Обвязка устья с циркуляционной системой=Обвязка устья с циркуляционной системой -Оборудование устья=Оборудование устья -Обработка БР=Обработка БР -Обработка раствора (несоответствие параметров)=Обработка раствора (несоответствие параметров) -Ожидание=Ожидание -Определение места прихвата и ЛМ=Определение места прихвата и ЛМ -Опрессовка ОК=Опрессовка ОК -Ориентирование ТС при бурении=Ориентирование ТС при бурении -Отворот допускной трубы=Отворот допускной трубы -Перезапись гаммы-каротажа=Перезапись гаммы-каротажа -Перемонтаж ПВО=Перемонтаж ПВО -ПЗР к спуску УЭЦН=ПЗР к спуску УЭЦН -ПЗР при сборке КНБК=ПЗР при сборке КНБК -ПЗР при цементировании=ПЗР при цементировании -Поглощение=Поглощение -Подготовка ствола скважины. Перезапись ГК в интервале установки КО.=Подготовка ствола скважины. Перезапись ГК в интервале установки КО. -Подъем БИ с выбросом на мостки=Подъем БИ с выбросом на мостки -подъем ОК=подъем ОК -Подъем приборов ГИС (на трубах)=Подъем приборов ГИС (на трубах) -Полная замена талевого каната=Полная замена талевого каната -ПР перед забуркой направления=ПР перед забуркой направления -Приготовление БР=Приготовление БР -Продувка манифольда=Продувка манифольда -Промывка перед наращиванием=Промывка перед наращиванием -Проработка во время бурения=Проработка во время бурения -Проработка перед наращиванием=Проработка перед наращиванием -Работа яссом=Работа яссом -Разборка комплекса приборов ГИС=Разборка комплекса приборов ГИС -Разбуривание тех.оснастк=Разбуривание тех.оснастки -Расхаживани=Расхаживание -Ревизия КНБК/инструмента/ЗТС=Ревизия КНБК/инструмента/ЗТС -Ремонт бурового оборудования=Ремонт бурового оборудования -Сальникообразование=Сальникообразование -Сборка и спуск ТБТ=Сборка и спуск ТБТ -Сборка комплекса приборов ГИС=Сборка комплекса приборов ГИС -Сборка устройства ориентирования КО=Сборка устройства ориентирования КО -Смена рабочего переводника ВСП=Смена рабочего переводника ВСП -СПО - колокол=СПО - колокол -СПО - метчик=СПО - метчик -СПО - овершот=СПО - овершот -СПО - труболовка=СПО - труболовка -Спуск БИ со сборкой с мостков=Спуск БИ со сборкой с мостков -Спуск инструмента=Спуск инструмента -Спуск инструмента с проработкой=Спуск инструмента с проработкой -Спуск КО на транспотрной колонне=Спуск КО на транспотрной колонне -Спуск приборов ГИС (на трубах)=Спуск приборов ГИС (на трубах) -Срезка=Срезка -Тайм-дриллинг=Тайм-дриллинг -Тех.отстой=Тех.отстой -Торпедирование (встряхивание)=Торпедирование (встряхивание) -Торпедирование (отстрел)=Торпедирование (отстрел) -Удержание в клиньях=Удержание в клиньях -Установка ванн=Установка ванн -Утяжеление БР=Утяжеление БР -Учебная тревога "Выброс"=Учебная тревога "Выброс" -Фрезеровка=Фрезеровка -Шаблонировка подъем БИ, продувка=Шаблонировка подъем БИ, продувка -Шаблонировка перед наращиванием=Шаблонировка перед наращиванием -Демонтаж ПВО ( переоборудование устья скважины). Вывоз БР=Демонтаж ПВО -Сборка БИ 127/147с мостков установкой на подсвечник=Сборка БИ с мостков на подсвечник -Спуск приборов комплекса АМАК.=Спуск приборов ГИС (на трубах) -Подъем с записью=Подъем приборов ГИС (на трубах) -ОЗЦ под давлением (по согласованию с ЦУСС)=ОЗЦ -"Демонтаж ПВО ( переоборудование устья скважины). Вывоз БР=Демонтаж ПВО -Сборка CБТ-127 (0м) с мостков установкой на подсвечник (оставлено СБТ-127 (1500м) с пердыдущей скв). Заготовка БР=Сборка БИ с мостков на подсвечник -ПЗР к спуску ОК=ПЗР при спуске ОК -Выброс СБТ 127 (2100м), оставляется СБТ-127 (700 м) на след скв. ЗБР, чистка емкостей, вывоз БР.=Подъем БИ с выбросом на мостки -Монтаж ПВО повторный (смена плашек ПВО). ЗБР, чистка емкостей, вывоз БР=Монтаж ПВО -Опрессовка ПВО (200 атм), глухие=Опрессовка ПВО -Сборка ТБТ на 2 этапе (кол-во по согласованию с ЦУСС). Подъем/спуск БИ со сборкой ТБТ 102 мм. Опрессовка БИ (1.5 ч)=Сборка и спуск ТБТ -Спуск пакера=Спуск пакера -Запись гамма-каратожа=Запись гамма-каратожа -Шаблонирование спуск БИ=Шаблонирование спуск БИ -Сборка клин-отклонителя=Сборка клин-отклонителя -Ориентирование и посадка клина-отклонителя=Ориентирование и посадка клина-отклонителя -Протяжка подъемного патрубка подвески=Протяжка подъемного патрубка подвески -Подъем клина-отклонителя=Подъем клина-отклонителя -Стыковка стингера с хвостовиком основного ствола=Стыковка стингера с хвостовиком основного ствола -Ориентирование и установка стыковочного узла хвостовика=Ориентирование и установка стыковочного узла хвостовика -Бурение с отбором керна=Бурение с отбором керна -Работа пакером в обсадной колонне=Работа пакером в обсадной колонне \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/WellOperationImport/Files/Dictionaries/Sections.txt b/AsbCloudInfrastructure/Services/WellOperationImport/Files/Dictionaries/Sections.txt deleted file mode 100644 index b0b2df54..00000000 --- a/AsbCloudInfrastructure/Services/WellOperationImport/Files/Dictionaries/Sections.txt +++ /dev/null @@ -1,7 +0,0 @@ -направ=Направление -конд=Кондуктор -техн=Техническая колонна -экспл=Эксплуатационная колонна -транс=Транспортный ствол -пилот=Пилотный ствол -хвост=Хвостовик \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/WellOperationImport/Files/WellOperationImportTemplate.xlsx b/AsbCloudInfrastructure/Services/WellOperationImport/Files/WellOperationImportTemplate.xlsx deleted file mode 100644 index 6f53ccfb..00000000 Binary files a/AsbCloudInfrastructure/Services/WellOperationImport/Files/WellOperationImportTemplate.xlsx and /dev/null differ diff --git a/AsbCloudInfrastructure/Services/WellOperationImport/WellOperationExportService.cs b/AsbCloudInfrastructure/Services/WellOperationImport/WellOperationExportService.cs deleted file mode 100644 index 96e640b8..00000000 --- a/AsbCloudInfrastructure/Services/WellOperationImport/WellOperationExportService.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using AsbCloudApp.Data; -using AsbCloudApp.Repositories; -using AsbCloudApp.Requests; -using AsbCloudApp.Services.WellOperationImport; -using AsbCloudInfrastructure.Services.WellOperationImport.Constants; -using ClosedXML.Excel; - -namespace AsbCloudInfrastructure.Services.WellOperationImport; - -public class WellOperationExportService : IWellOperationExportService -{ - private readonly IWellOperationRepository wellOperationRepository; - private readonly IWellOperationImportTemplateService wellOperationImportTemplateService; - private readonly IWellOperationCategoryRepository wellOperationCategoryRepository; - - public WellOperationExportService( - IWellOperationRepository wellOperationRepository, - IWellOperationImportTemplateService wellOperationImportTemplateService, - IWellOperationCategoryRepository wellOperationCategoryRepository) - { - this.wellOperationRepository = wellOperationRepository; - this.wellOperationImportTemplateService = wellOperationImportTemplateService; - this.wellOperationCategoryRepository = wellOperationCategoryRepository; - } - - public async Task ExportAsync(int idWell, CancellationToken cancellationToken) - { - var operations = await wellOperationRepository.GetAsync(new WellOperationRequest() - { - IdWell = idWell - }, cancellationToken); - - return MakeExcelFileStream(operations); - } - - private Stream MakeExcelFileStream(IEnumerable operations) - { - using Stream ecxelTemplateStream = wellOperationImportTemplateService.GetExcelTemplateStream(); - - using var workbook = new XLWorkbook(ecxelTemplateStream); - AddOperationsToWorkbook(workbook, operations); - - var memoryStream = new MemoryStream(); - workbook.SaveAs(memoryStream, new SaveOptions { }); - memoryStream.Seek(0, SeekOrigin.Begin); - return memoryStream; - } - - private void AddOperationsToWorkbook(XLWorkbook workbook, IEnumerable operations) - { - var planOperations = operations.Where(o => o.IdType == 0); - if (planOperations.Any()) - { - var sheetPlan = workbook.GetWorksheet(DefaultTemplateInfo.SheetNamePlan); - - AddOperationsToSheet(sheetPlan, planOperations); - } - - var factOperations = operations.Where(o => o.IdType == 1); - if (factOperations.Any()) - { - var sheetFact = workbook.GetWorksheet(DefaultTemplateInfo.SheetNameFact); - - AddOperationsToSheet(sheetFact, factOperations); - } - } - - private void AddOperationsToSheet(IXLWorksheet sheet, IEnumerable operations) - { - var operationsToArray = operations.ToArray(); - - var sections = wellOperationRepository.GetSectionTypes(); - var categories = wellOperationCategoryRepository.Get(false); - - for (int i = 0; i < operationsToArray.Length; i++) - { - var row = sheet.Row(1 + i + DefaultTemplateInfo.HeaderRowsCount); - AddOperationToRow(row, operationsToArray[i], sections, categories); - } - } - - private static void AddOperationToRow(IXLRow row, WellOperationDto operation, IEnumerable sections, - IEnumerable categories) - { - var sectionCaption = sections.First(s => s.Id == operation.IdWellSectionType).Caption; - var categoryName = categories.First(o => o.Id == operation.IdCategory).Name; - - row.Cell(DefaultTemplateInfo.ColumnSection).SetCellValue(sectionCaption); - row.Cell(DefaultTemplateInfo.ColumnCategory).SetCellValue(categoryName); - row.Cell(DefaultTemplateInfo.ColumnCategoryInfo).SetCellValue(operation.CategoryInfo); - row.Cell(DefaultTemplateInfo.ColumnDepthStart).SetCellValue(operation.DepthStart); - row.Cell(DefaultTemplateInfo.ColumnDepthEnd).SetCellValue(operation.DepthEnd); - row.Cell(DefaultTemplateInfo.ColumnDate).SetCellValue(operation.DateStart.DateTime); - row.Cell(DefaultTemplateInfo.ColumnDuration).SetCellValue(operation.DurationHours); - row.Cell(DefaultTemplateInfo.ColumnComment).SetCellValue(operation.Comment); - } -} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/WellOperationImport/WellOperationImportService.cs b/AsbCloudInfrastructure/Services/WellOperationImport/WellOperationImportService.cs deleted file mode 100644 index 6ad227a3..00000000 --- a/AsbCloudInfrastructure/Services/WellOperationImport/WellOperationImportService.cs +++ /dev/null @@ -1,119 +0,0 @@ -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; - } -} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/WellOperationImport/WellOperationImportTemplateService.cs b/AsbCloudInfrastructure/Services/WellOperationImport/WellOperationImportTemplateService.cs deleted file mode 100644 index edb71c14..00000000 --- a/AsbCloudInfrastructure/Services/WellOperationImport/WellOperationImportTemplateService.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.IO; -using System.Linq; -using System.Reflection; -using AsbCloudApp.Services.WellOperationImport; - -namespace AsbCloudInfrastructure.Services.WellOperationImport; - -public class WellOperationImportTemplateService : IWellOperationImportTemplateService -{ - public Stream GetExcelTemplateStream() - { - var resourceName = Assembly.GetExecutingAssembly() - .GetManifestResourceNames() - .FirstOrDefault(n => n.EndsWith("WellOperationImportTemplate.xlsx"))!; - - var stream = Assembly.GetExecutingAssembly() - .GetManifestResourceStream(resourceName)!; - - return stream; - } -} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/WellOperations/Templates/WellOperationFactTemplate.xlsx b/AsbCloudInfrastructure/Services/WellOperations/Templates/WellOperationFactTemplate.xlsx new file mode 100644 index 00000000..065dc207 Binary files /dev/null and b/AsbCloudInfrastructure/Services/WellOperations/Templates/WellOperationFactTemplate.xlsx differ