From 9ead473975ca3d775be14075beb99f47d0c69352 Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Wed, 17 Apr 2024 09:44:30 +0500 Subject: [PATCH 1/5] =?UTF-8?q?=D0=A0=D0=B0=D1=81=D1=87=D0=B5=D1=82=20?= =?UTF-8?q?=D0=B4=D0=BD=D1=8F=20(=D0=B4=D0=BB=D1=8F=20=D0=B3=D0=BE=D1=80?= =?UTF-8?q?=D0=B8=D0=B7=D0=BE=D0=BD=D1=82=D0=B0=D0=BB=D1=8C=D0=BD=D0=BE?= =?UTF-8?q?=D0=B9=20=D0=BE=D1=81=D0=B8=20=D0=B3=D1=80=D0=B0=D1=84=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=B2)=20=D0=B4=D0=BB=D1=8F=20=D0=BE=D0=BF=D0=B5?= =?UTF-8?q?=D1=80=D0=B0=D1=86=D0=B8=D0=B9=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE?= =?UTF-8?q?=D0=B7=D0=B8=D1=82=D0=BD=D0=BE=D0=B9=20=D1=81=D0=BA=D0=B2=D0=B0?= =?UTF-8?q?=D0=B6=D0=B8=D0=BD=D1=8B=20+=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B0=D0=BD=D0=B0=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB?= =?UTF-8?q?=D1=8C,=20=D0=B2=D0=BE=D0=B7=D0=B2=D1=80=D0=B0=D1=89=D0=B0?= =?UTF-8?q?=D1=8E=D1=89=D0=B0=D1=8F=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D0=B5?= =?UTF-8?q?=20(=D0=BD=D0=BE=D0=B2=D0=B0=D1=8F=20WellCompositeOperationDto)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AsbCloudApp/Data/WellCompositeOperationDto.cs | 26 ++++++ .../IWellCompositeOperationService.cs | 6 +- .../Services/WellCompositeOperationService.cs | 56 ++++++++----- .../WellCompositeOperationServiceTest.cs | 82 +++++++------------ .../WellCompositeOperationController.cs | 2 +- 5 files changed, 94 insertions(+), 78 deletions(-) create mode 100644 AsbCloudApp/Data/WellCompositeOperationDto.cs diff --git a/AsbCloudApp/Data/WellCompositeOperationDto.cs b/AsbCloudApp/Data/WellCompositeOperationDto.cs new file mode 100644 index 00000000..f6b98b4d --- /dev/null +++ b/AsbCloudApp/Data/WellCompositeOperationDto.cs @@ -0,0 +1,26 @@ +using AsbCloudApp.Data.WellOperation; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AsbCloudApp.Data +{ + /// + /// Хранение операций по композитной скважине + /// и по скважинам, на основе которых была рассчитана композитная скважина + /// + public class WellCompositeOperationDto + { + /// + /// Список операций композитной скважины + /// + public List WellOperationsComposite { get; set; } = new(); + + /// + /// Список операций, сгруппированный по скважинам + /// + public Dictionary WellOperationsGroupedByWell { get; set; } = new(); + } +} diff --git a/AsbCloudApp/Services/IWellCompositeOperationService.cs b/AsbCloudApp/Services/IWellCompositeOperationService.cs index 96dbcf2b..f1af9865 100644 --- a/AsbCloudApp/Services/IWellCompositeOperationService.cs +++ b/AsbCloudApp/Services/IWellCompositeOperationService.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; +using AsbCloudApp.Data; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using AsbCloudApp.Data.WellOperation; namespace AsbCloudApp.Services { @@ -16,6 +16,6 @@ namespace AsbCloudApp.Services /// /// /// - Task>> GetAsync(IEnumerable idsWells, CancellationToken token); + Task GetAsync(IEnumerable idsWells, CancellationToken token); } } diff --git a/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs b/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs index 8beb3c3e..79fb45ee 100644 --- a/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs +++ b/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data.WellOperation; +using Mapster; namespace AsbCloudInfrastructure.Services { @@ -134,7 +135,7 @@ namespace AsbCloudInfrastructure.Services this.wellOperationRepository = wellOperationRepository; } - public async Task>> GetAsync(IEnumerable idsWells, CancellationToken token) + public async Task GetAsync(IEnumerable idsWells, CancellationToken token) { var sections = await wellSectionTypeRepository.GetAllAsync(token); var sectionsDict = sections.ToDictionary(s => s.Id, s => s.Caption); @@ -153,13 +154,16 @@ namespace AsbCloudInfrastructure.Services }; var operations = await wellOperationRepository.GetAsync(wellOperationRequest, token); - var renamedOperations = operations.Select(o => UpdateIdWellSectionAndIdCategory(o, sectionsDict, categoriesDict)); + var operationsForComposite = operations.Select(o => CreateCompositeOperation(o, sectionsDict, categoriesDict)); var wellOperationsWithComposite = new List>(); var compositeDepth = 0d; + var result = new WellCompositeOperationDto(); + + var prevDay = 0.0; foreach ((int IdSection, int IdCategory) in WellSectionTypesWithCategories) { - var filteredByTemplate = renamedOperations + var filteredByTemplate = operationsForComposite .Where(o => o.IdWellSectionType == IdSection) .Where(o => o.IdCategory == IdCategory); @@ -179,42 +183,50 @@ namespace AsbCloudInfrastructure.Services WellSectionTypeCaption = g.First().WellSectionTypeCaption, }); - var composite = aggreagtedByWell.OrderBy(o => o.DurationHours). - ThenByDescending(o => o.DepthStart) - .First(); + var compositeOperation = aggreagtedByWell.OrderBy(o => o.DurationHours). + ThenByDescending(o => o.DepthStart) + .First(); - composite.IdWell = 0; - if (compositeDepth > composite.DepthStart) - composite.DepthStart = compositeDepth; + compositeOperation.IdWell = 0; + compositeOperation.Day = prevDay + compositeOperation.DurationHours; + + if (compositeDepth > compositeOperation.DepthStart) + compositeOperation.DepthStart = compositeDepth; - compositeDepth = composite.DepthStart; + compositeDepth = compositeOperation.DepthStart; - var resultItem = aggreagtedByWell.ToDictionary(o => o.IdWell); - resultItem.Add(0, composite); + result.WellOperationsComposite.Add(compositeOperation); - wellOperationsWithComposite.Add(resultItem); + prevDay = compositeOperation.Day; } - return wellOperationsWithComposite; + + var groupedByWellOperations = operations + .GroupBy(o => o.IdWell) + .ToDictionary(o => o.Key, o => o.ToArray()); + result.WellOperationsGroupedByWell = groupedByWellOperations; + + return result; } - private static WellOperationDto UpdateIdWellSectionAndIdCategory( + private static WellOperationDto CreateCompositeOperation( WellOperationDto dto, IDictionary sectionTypes, IDictionary operationCategories) { - if (dto.IdWellSectionType == wellSectionTransportTable) + var newDto = dto.Adapt(); + if (newDto.IdWellSectionType == wellSectionTransportTable) { - dto.IdWellSectionType = wellSectionProductionString; - dto.WellSectionTypeCaption = sectionTypes[dto.IdWellSectionType]; + newDto.IdWellSectionType = wellSectionProductionString; + newDto.WellSectionTypeCaption = sectionTypes[newDto.IdWellSectionType]; } - if ((SettingsForSectionCategoryChange.TryGetValue((dto.IdWellSectionType, dto.IdCategory), out int newIdCategory))) + if ((SettingsForSectionCategoryChange.TryGetValue((newDto.IdWellSectionType, newDto.IdCategory), out int newIdCategory))) { - dto.IdCategory = newIdCategory; - dto.OperationCategoryName = operationCategories[dto.IdCategory] ?? string.Empty; + newDto.IdCategory = newIdCategory; + newDto.OperationCategoryName = operationCategories[newDto.IdCategory] ?? string.Empty; } - return dto; + return newDto; } } } diff --git a/AsbCloudWebApi.Tests/Services/WellCompositeOperation/WellCompositeOperationServiceTest.cs b/AsbCloudWebApi.Tests/Services/WellCompositeOperation/WellCompositeOperationServiceTest.cs index 4018417c..cf9904d0 100644 --- a/AsbCloudWebApi.Tests/Services/WellCompositeOperation/WellCompositeOperationServiceTest.cs +++ b/AsbCloudWebApi.Tests/Services/WellCompositeOperation/WellCompositeOperationServiceTest.cs @@ -174,8 +174,8 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation /// /// На вход подаются 2 операции с одинаковыми секциями (id = 2), но разными категориями (ids = 5096, 5008) и ключами скважин (ids = 55, 64) - /// Метод возвращает список из одной операции в разрезе 3-х скважин: 2 текущие скважины и одна композитная - /// Операция должна иметь категорию 5013 для всех трех скважин + /// Метод возвращает объект с одной композитной операцией и списком операций в разрезе 2-х скважин + /// Композитная операция должна иметь категорию 5013 /// /// [Fact] @@ -191,25 +191,19 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation var result = await service.GetAsync(idsWell, CancellationToken.None); // assert - var compositeWellOperation = result.SelectMany(o => o.Values.Where(o => o.IdWell == 0)).FirstOrDefault(); - Assert.NotNull(compositeWellOperation); - Assert.Equal(5013, compositeWellOperation.IdCategory); - Assert.Equal(1, compositeWellOperation.DurationHours); - Assert.Equal(84, compositeWellOperation.DepthStart); + var compositeWellOperations = result.WellOperationsComposite; + Assert.Single(compositeWellOperations); + Assert.Equal(5013, compositeWellOperations.FirstOrDefault()?.IdCategory); + Assert.Equal(1, compositeWellOperations.FirstOrDefault()?.DurationHours); + Assert.Equal(84, compositeWellOperations.FirstOrDefault()?.DepthStart); - var currentWellOperations = result.SelectMany(o => o.Values.Where(o => o.IdWell != 0)); - var categories = currentWellOperations.Select(o => o.IdCategory).Distinct(); - Assert.NotNull(categories); - Assert.Single(categories); - Assert.Equal(5013, categories.First()); - - var categoryName = currentWellOperations.Select(o => o.OperationCategoryName).First(); + var categoryName = compositeWellOperations.Select(o => o.OperationCategoryName).First(); Assert.Equal("Подъем КНБК", categoryName); } /// /// На вход подаются 2 операции с одинаковыми секциями (id = 2) и категориями (id = 5003), но разными ключами скважин (ids = 55, 64) - /// Метод возвращает список из одной операции в разрезе 3-х скважин: 2 текущие скважины и одна композитная + /// Метод возвращает объект с одной композитной операцией и списком операций в разрезе 2-х скважин /// Операция композитной скважины должна содержать данные той операции, которая содержит минимальный duration_hours /// /// @@ -226,16 +220,16 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation var result = await service.GetAsync(idsWell, CancellationToken.None); // assert - var compositeWellOperation = result.SelectMany(o => o.Values.Where(o => o.IdWell == 0)).FirstOrDefault(); - Assert.NotNull(compositeWellOperation); - Assert.Equal(5003, compositeWellOperation.IdCategory); - Assert.Equal(1.5, compositeWellOperation.DurationHours); - Assert.Equal(10, compositeWellOperation.DepthStart); + var compositeWellOperations = result.WellOperationsComposite; + Assert.Single (compositeWellOperations); + Assert.Equal(5003, compositeWellOperations.FirstOrDefault()!.IdCategory); + Assert.Equal(1.5, compositeWellOperations.FirstOrDefault()!.DurationHours); + Assert.Equal(10, compositeWellOperations.FirstOrDefault()!.DepthStart); } /// /// На вход подаются 2 операции с одинаковыми секциями (id = 3) и категориями (id = 5036), но разными ключами скважин (ids = 55, 64) - /// Метод возвращает список из одной операции в разрезе 3-х скважин: 2 текущие скважины и одна композитная + /// Метод возвращает объект с одной композитной операцией и списком операций в разрезе 2-х скважин /// Операция композитной скважины должна содержать данные той операции, которая содержит минимальный duration_hours /// /// @@ -252,21 +246,19 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation var result = await service.GetAsync(idsWell, CancellationToken.None); // assert - var compositeWellOperation = result.SelectMany(o => o.Values.Where(o => o.IdWell == 0)).FirstOrDefault(); - Assert.NotNull(compositeWellOperation); - Assert.Equal(5036, compositeWellOperation.IdCategory); - Assert.Equal(3, compositeWellOperation.DurationHours); - Assert.Equal(1372, compositeWellOperation.DepthStart); + var compositeWellOperations = result.WellOperationsComposite; + Assert.Single(compositeWellOperations); + Assert.Equal(5036, compositeWellOperations.FirstOrDefault()!.IdCategory); + Assert.Equal(3, compositeWellOperations.FirstOrDefault()!.DurationHours); + Assert.Equal(1372, compositeWellOperations.FirstOrDefault()!.DepthStart); } /// /// На вход подаются 3 операции с одинаковыми секциями (id = 31), но разными категориями (ids = 5012, 5083) и ключами скважин (ids = 55, 64) - /// Метод возвращает список из одной операции в разрезе 3-х скважин: 2 текущие скважины и одна композитная + /// Метод возвращает объект с одной композитной операцией и списком операций в разрезе 2-х скважин /// Операция композитной скважины должна содержать: /// данные той операции, которая содержит минимальный duration_hours /// категорию с ключом 5013 - /// Операции по скважине с ключом 55 должны объединиться в одну, - /// при этом их длительность складывается, а depth_start берется минимальный из двух /// /// [Fact] @@ -282,30 +274,16 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation var result = await service.GetAsync(idsWell, CancellationToken.None); // assert - var currentWellOperations = result.SelectMany(o => o.Values.Where(o => o.IdWell != 0)); - var categories = currentWellOperations.Select(o => o.IdCategory).Distinct(); - Assert.NotNull(categories); - Assert.Single(categories); - Assert.Equal(5013, categories.First()); - - var currentOperationByWell55 = currentWellOperations.Where(o => o.IdWell == 55).FirstOrDefault(); - Assert.NotNull(currentOperationByWell55); - Assert.Equal(15, currentOperationByWell55.DurationHours); - Assert.Equal(500, currentOperationByWell55.DepthStart); - - var categoryName = currentWellOperations.Select(o => o.OperationCategoryName).First(); - Assert.Equal("Подъем КНБК", categoryName); - - var compositeWellOperation = result.SelectMany(o => o.Values.Where(o => o.IdWell == 0)).FirstOrDefault(); - Assert.NotNull(compositeWellOperation); - Assert.Equal(5013, compositeWellOperation.IdCategory); - Assert.Equal(5, compositeWellOperation.DurationHours); - Assert.Equal(600, compositeWellOperation.DepthStart); + var compositeWellOperations = result.WellOperationsComposite; + Assert.Single(compositeWellOperations); + Assert.Equal(5013, compositeWellOperations.FirstOrDefault()!.IdCategory); + Assert.Equal(5, compositeWellOperations.FirstOrDefault()!.DurationHours); + Assert.Equal(600, compositeWellOperations.FirstOrDefault()!.DepthStart); } /// /// На вход подаются список разных операций с разными ключами скважин (ids = 55, 64) - /// Метод возвращает список из 4-х операций в разрезе 3-х скважин: 2 текущие скважины и одна композитная + /// Метод возвращает объект с одной композитной операцией и списком операций в разрезе 2-х скважин /// Операция композитной скважины должна содержать глубину забоя = 1372 /// /// @@ -328,10 +306,10 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation var result = await service.GetAsync(idsWell, CancellationToken.None); // assert - Assert.Equal(4, result.Count()); + var wellOperationsCount = result.WellOperationsGroupedByWell.SelectMany(v => v.Value).Count(); + Assert.Equal(wellOperations.Count(), wellOperationsCount); - var lastOperation = result.Last(); - var lastOperationComposite = lastOperation[0]; + var lastOperationComposite = result.WellOperationsComposite.Last(); Assert.Equal(1372, lastOperationComposite.DepthStart); } } diff --git a/AsbCloudWebApi/Controllers/WellCompositeOperationController.cs b/AsbCloudWebApi/Controllers/WellCompositeOperationController.cs index ab4555c0..964addae 100644 --- a/AsbCloudWebApi/Controllers/WellCompositeOperationController.cs +++ b/AsbCloudWebApi/Controllers/WellCompositeOperationController.cs @@ -25,7 +25,7 @@ namespace AsbCloudWebApi.Controllers } [HttpGet] - [ProducesResponseType(typeof(IList>), (int)System.Net.HttpStatusCode.OK)] + [ProducesResponseType(typeof(WellCompositeOperationDto), (int)System.Net.HttpStatusCode.OK)] public async Task GetAsync([FromQuery] IEnumerable idsWells, CancellationToken token) { foreach (var idWell in idsWells) From cb54d40774f42f08de68398340bbf57009221165 Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Wed, 17 Apr 2024 11:10:56 +0500 Subject: [PATCH 2/5] =?UTF-8?q?=D0=9F=D1=80=D0=B0=D0=B2=D0=BA=D0=B0=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D1=80=D0=B5=D0=B7=D1=83=D0=BB=D1=8C=D1=82=D0=B0?= =?UTF-8?q?=D1=82=D0=B0=D0=BC=20=D1=80=D0=B5=D0=B2=D1=8C=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AsbCloudApp/Data/WellCompositeOperationDto.cs | 6 +-- .../Services/WellCompositeOperationService.cs | 47 +++++++++++++------ .../WellCompositeOperationServiceTest.cs | 34 +++++++------- 3 files changed, 51 insertions(+), 36 deletions(-) diff --git a/AsbCloudApp/Data/WellCompositeOperationDto.cs b/AsbCloudApp/Data/WellCompositeOperationDto.cs index f6b98b4d..ce8e44f9 100644 --- a/AsbCloudApp/Data/WellCompositeOperationDto.cs +++ b/AsbCloudApp/Data/WellCompositeOperationDto.cs @@ -16,11 +16,11 @@ namespace AsbCloudApp.Data /// /// Список операций композитной скважины /// - public List WellOperationsComposite { get; set; } = new(); + public IEnumerable WellOperationsComposite { get; set; } = null!; /// - /// Список операций, сгруппированный по скважинам + /// Список операций, на основе которых были рассчитаны операции по композитной скважине /// - public Dictionary WellOperationsGroupedByWell { get; set; } = new(); + public IEnumerable WellCompositeSourceOperations { get; set; } = null!; } } diff --git a/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs b/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs index 79fb45ee..2a4d0330 100644 --- a/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs +++ b/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs @@ -1,23 +1,24 @@ using AsbCloudApp.Data; +using AsbCloudApp.Data.WellOperation; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudDb.Model; +using Mapster; using Microsoft.EntityFrameworkCore; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; -using AsbCloudApp.Data.WellOperation; -using Mapster; namespace AsbCloudInfrastructure.Services { public class WellCompositeOperationService : IWellCompositeOperationService { - private ICrudRepository wellSectionTypeRepository; - private IWellOperationCategoryRepository wellOperationCategoryRepository; - private IWellOperationRepository wellOperationRepository; + private readonly ICrudRepository wellSectionTypeRepository; + private readonly IWellOperationCategoryRepository wellOperationCategoryRepository; + private readonly IWellOperationRepository wellOperationRepository; + private readonly IWellService wellService; /// /// Тип секции "Транспортный стол" @@ -128,11 +129,13 @@ namespace AsbCloudInfrastructure.Services public WellCompositeOperationService( ICrudRepository wellSectionTypeRepository, IWellOperationCategoryRepository wellOperationCategoryRepository, - IWellOperationRepository wellOperationRepository) + IWellOperationRepository wellOperationRepository, + IWellService wellService) { this.wellSectionTypeRepository = wellSectionTypeRepository; this.wellOperationCategoryRepository = wellOperationCategoryRepository; this.wellOperationRepository = wellOperationRepository; + this.wellService = wellService; } public async Task GetAsync(IEnumerable idsWells, CancellationToken token) @@ -143,6 +146,9 @@ namespace AsbCloudInfrastructure.Services var categories = wellOperationCategoryRepository.Get(true); var categoriesDict = categories.ToDictionary(s => s.Id, s => s.Name); + var wells = await wellService.GetAsync(new WellRequest { Ids = idsWells }, token); + var wellsDict = wells.ToDictionary(w => w.Id, w => w.Caption); + var idsWellSectionTypes = WellSectionTypesWithCategories.Select(t => t.IdSectionType).Distinct(); var usedCategories = WellSectionTypesWithCategories.Select(c => c.IdCategory).Distinct(); @@ -158,9 +164,10 @@ namespace AsbCloudInfrastructure.Services var wellOperationsWithComposite = new List>(); var compositeDepth = 0d; + var compositeDay = 0d; var result = new WellCompositeOperationDto(); - var prevDay = 0.0; + var compositeOperations = new List(); foreach ((int IdSection, int IdCategory) in WellSectionTypesWithCategories) { var filteredByTemplate = operationsForComposite @@ -188,22 +195,32 @@ namespace AsbCloudInfrastructure.Services .First(); compositeOperation.IdWell = 0; - compositeOperation.Day = prevDay + compositeOperation.DurationHours; - + compositeOperation.Day = compositeDay + compositeOperation.DurationHours; + if (compositeDepth > compositeOperation.DepthStart) compositeOperation.DepthStart = compositeDepth; + compositeOperations.Add(compositeOperation); + compositeDepth = compositeOperation.DepthStart; - - result.WellOperationsComposite.Add(compositeOperation); - - prevDay = compositeOperation.Day; + compositeDay = compositeOperation.Day; } var groupedByWellOperations = operations .GroupBy(o => o.IdWell) - .ToDictionary(o => o.Key, o => o.ToArray()); - result.WellOperationsGroupedByWell = groupedByWellOperations; + .ToDictionary(o => o.Key, o => o.ToArray()) + .Select(o => new WellCompositeOperationSourceDto() + { + Operations = o.Value, + Well = new WellDto() + { + Id = o.Key, + Caption = wellsDict.TryGetValue(o.Key, out string? caption) ? caption : string.Empty, + } + }); + + result.WellOperationsComposite = compositeOperations; + result.WellCompositeSourceOperations = groupedByWellOperations; return result; } diff --git a/AsbCloudWebApi.Tests/Services/WellCompositeOperation/WellCompositeOperationServiceTest.cs b/AsbCloudWebApi.Tests/Services/WellCompositeOperation/WellCompositeOperationServiceTest.cs index cf9904d0..14224abd 100644 --- a/AsbCloudWebApi.Tests/Services/WellCompositeOperation/WellCompositeOperationServiceTest.cs +++ b/AsbCloudWebApi.Tests/Services/WellCompositeOperation/WellCompositeOperationServiceTest.cs @@ -1,22 +1,16 @@ -using AsbCloudApp.Requests; -using AsbCloudDb.Model; -using AsbCloudInfrastructure.Repository; -using AsbCloudInfrastructure.Services.ProcessMaps.Report; +using AsbCloudApp.Data; +using AsbCloudApp.Data.WellOperation; +using AsbCloudApp.Repositories; +using AsbCloudApp.Requests; +using AsbCloudApp.Services; using AsbCloudInfrastructure.Services; using NSubstitute; -using ProtoBuf.Meta; -using SignalRSwaggerGen.Enums; using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; using Xunit; -using AsbCloudApp.Repositories; -using AsbCloudApp.Data; -using AsbCloudApp.Data.WellOperation; -using AsbCloudApp.Services; namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation { @@ -30,8 +24,10 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation = Substitute.For(); private IWellOperationRepository wellOperationRepository = Substitute.For(); + private IWellService wellService + = Substitute.For(); + - private readonly static IEnumerable operationCategories = new List() { @@ -61,7 +57,7 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation IdWell = 55, IdWellSectionType = 2, OperationCategoryName = "Шаблонирование перед спуском", - WellSectionTypeCaption = "Направление" + WellSectionTypeCaption = "Направление" }, new() { @@ -167,9 +163,10 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation .Returns(operationCategories); service = new WellCompositeOperationService( - wellSectionTypeRepository, + wellSectionTypeRepository, wellOperationCategoryRepository, - wellOperationRepository); + wellOperationRepository, + wellService); } /// @@ -185,7 +182,7 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation wellOperationRepository.GetAsync(Arg.Any(), Arg.Any()) .Returns(wellOperations1); - var idsWell = new List() { 55, 64 }; + var idsWell = new List() { 55, 64 }; // act var result = await service.GetAsync(idsWell, CancellationToken.None); @@ -221,7 +218,7 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation // assert var compositeWellOperations = result.WellOperationsComposite; - Assert.Single (compositeWellOperations); + Assert.Single(compositeWellOperations); Assert.Equal(5003, compositeWellOperations.FirstOrDefault()!.IdCategory); Assert.Equal(1.5, compositeWellOperations.FirstOrDefault()!.DurationHours); Assert.Equal(10, compositeWellOperations.FirstOrDefault()!.DepthStart); @@ -306,7 +303,8 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation var result = await service.GetAsync(idsWell, CancellationToken.None); // assert - var wellOperationsCount = result.WellOperationsGroupedByWell.SelectMany(v => v.Value).Count(); + var wellOperationsCount = result.WellCompositeSourceOperations + .SelectMany(o => o.Operations).Count(); Assert.Equal(wellOperations.Count(), wellOperationsCount); var lastOperationComposite = result.WellOperationsComposite.Last(); From 411e420a615fc70f4ab5d4e24f8a427b9063e238 Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Wed, 17 Apr 2024 11:31:20 +0500 Subject: [PATCH 3/5] =?UTF-8?q?WellCompositeOperationSourceDto=20=D0=B4?= =?UTF-8?q?=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Data/WellCompositeOperationSourceDto.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 AsbCloudApp/Data/WellCompositeOperationSourceDto.cs diff --git a/AsbCloudApp/Data/WellCompositeOperationSourceDto.cs b/AsbCloudApp/Data/WellCompositeOperationSourceDto.cs new file mode 100644 index 00000000..fd5d819c --- /dev/null +++ b/AsbCloudApp/Data/WellCompositeOperationSourceDto.cs @@ -0,0 +1,21 @@ +using AsbCloudApp.Data.WellOperation; +using System.Collections.Generic; + +namespace AsbCloudApp.Data +{ + /// + /// Операции по скважине, по которой рассчитывается композитная скважина + /// + public class WellCompositeOperationSourceDto + { + /// + /// Скважина + /// + public WellDto Well { get; set; } = new(); + + /// + /// Операции по скважине + /// + public IEnumerable Operations { get; set; } = null!; + } +} From ef8d559739831af741b867797926971c62bc492f Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Wed, 17 Apr 2024 16:17:52 +0500 Subject: [PATCH 4/5] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=BF=D0=BE=D1=81=D0=BB=D0=B5=20=D1=80=D0=B5?= =?UTF-8?q?=D0=B2=D1=8C=D1=8E-2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AsbCloudApp/Data/WellCompositeOperationSourceDto.cs | 2 +- .../Services/WellCompositeOperationService.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/AsbCloudApp/Data/WellCompositeOperationSourceDto.cs b/AsbCloudApp/Data/WellCompositeOperationSourceDto.cs index fd5d819c..04ec7b3b 100644 --- a/AsbCloudApp/Data/WellCompositeOperationSourceDto.cs +++ b/AsbCloudApp/Data/WellCompositeOperationSourceDto.cs @@ -11,7 +11,7 @@ namespace AsbCloudApp.Data /// /// Скважина /// - public WellDto Well { get; set; } = new(); + public WellDto Well { get; set; } = null!; /// /// Операции по скважине diff --git a/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs b/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs index 2a4d0330..783228c3 100644 --- a/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs +++ b/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs @@ -147,7 +147,7 @@ namespace AsbCloudInfrastructure.Services var categoriesDict = categories.ToDictionary(s => s.Id, s => s.Name); var wells = await wellService.GetAsync(new WellRequest { Ids = idsWells }, token); - var wellsDict = wells.ToDictionary(w => w.Id, w => w.Caption); + var wellsDict = wells.ToDictionary(w => w.Id); var idsWellSectionTypes = WellSectionTypesWithCategories.Select(t => t.IdSectionType).Distinct(); var usedCategories = WellSectionTypesWithCategories.Select(c => c.IdCategory).Distinct(); @@ -215,7 +215,7 @@ namespace AsbCloudInfrastructure.Services Well = new WellDto() { Id = o.Key, - Caption = wellsDict.TryGetValue(o.Key, out string? caption) ? caption : string.Empty, + Caption = wellsDict[o.Key].Caption, } }); From f5c4f63b2fd0d0773ea9f1cbccebcdd8c405c682 Mon Sep 17 00:00:00 2001 From: ngfrolov Date: Wed, 17 Apr 2024 16:23:36 +0500 Subject: [PATCH 5/5] format WellCompositeOperationService --- .../Services/WellCompositeOperationService.cs | 423 +++++++++--------- 1 file changed, 208 insertions(+), 215 deletions(-) diff --git a/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs b/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs index 783228c3..d1312e6e 100644 --- a/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs +++ b/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs @@ -11,239 +11,232 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -namespace AsbCloudInfrastructure.Services +namespace AsbCloudInfrastructure.Services; + +public class WellCompositeOperationService : IWellCompositeOperationService { - public class WellCompositeOperationService : IWellCompositeOperationService + private readonly ICrudRepository wellSectionTypeRepository; + private readonly IWellOperationCategoryRepository wellOperationCategoryRepository; + private readonly IWellOperationRepository wellOperationRepository; + private readonly IWellService wellService; + + /// + /// Тип секции "Транспортный стол" + /// + private const int wellSectionTransportTable = 5; + + /// + /// Тип секции "Эксплуатационная колонна" + /// + private const int wellSectionProductionString = 4; + + + /// + /// набор настроек для замены одной категории секции на другую + /// + private static Dictionary<(int, int), int> SettingsForSectionCategoryChange = new Dictionary<(int, int), int>() { + { (2, 5096), 5013 }, + { (2, 5008), 5013 }, + { (3, 5096), 5084 }, + { (3, 5008), 5084 }, + { (3, 5085), 5015 }, + { (3, 5014), 5015 }, + { (31, 5014), 5015 }, + { (31, 5012), 5013 }, + { (31, 5083), 5013 }, + { (4, 5085), 5015 }, + { (4, 5087), 5015 }, + { (4, 5014), 5015 }, + { (4, 5053), 5037 }, + { (4, 5084), 5096 }, + { (4, 5086), 5013 }, + { (6, 5085), 5015 }, + { (6, 5036), 5034 }, + { (6, 5035), 5097 } + }; + + private HashSet<(int IdSectionType, int IdCategory)> WellSectionTypesWithCategories = new HashSet<(int IdSectionType, int IdCategory)>() { - private readonly ICrudRepository wellSectionTypeRepository; - private readonly IWellOperationCategoryRepository wellOperationCategoryRepository; - private readonly IWellOperationRepository wellOperationRepository; - private readonly IWellService wellService; + { (2, 5001) }, + { (2, 5003) }, + { (2, 5013) }, + { (2, 5000) }, + { (2, 5022) }, + { (2, 5017) }, + { (2, 5023) }, + { (2, 4007) }, + { (2, 5090) }, + { (3, 5001) }, + { (3, 5015) }, + { (3, 5037) }, + { (3, 5057) }, + { (3, 5003) }, + { (3, 5036) }, + { (3, 5084) }, + { (3, 5013) }, + { (3, 5000) }, + { (3, 5022) }, + { (3, 5017) }, + { (3, 4007) }, + { (3, 5090) }, + { (3, 5045) }, + { (3, 5042) }, + { (3, 5046) }, + { (31, 5001) }, + { (31, 5015) }, + { (31, 5037) }, + { (31, 5057) }, + { (31, 5003) }, + { (31, 5036) }, + { (31, 5013) }, + { (31, 5022) }, + { (31, 5017) }, + { (31, 5023) }, + { (31, 4007) }, + { (31, 5045) }, + { (31, 5042) }, + { (31, 5046) }, + { (4, 5001) }, + { (4, 5015) }, + { (4, 5046) }, + { (4, 5037) }, + { (4, 5097) }, + { (4, 5057) }, + { (4, 5003) }, + { (4, 5036) }, + { (4, 5008) }, + { (4, 5003) }, + { (4, 5036) }, + { (4, 5013) }, + { (4, 5000) }, + { (4, 5029) }, + { (4, 5022) }, + { (4, 5017) }, + { (4, 5019) }, + { (4, 5042) }, + { (4, 5046) }, + { (6, 5001) }, + { (6, 5015) }, + { (6, 5034) }, + { (6, 5037) }, + { (6, 5097) }, + { (6, 5057) }, + { (6, 5003) } + }; - /// - /// Тип секции "Транспортный стол" - /// - private const int wellSectionTransportTable = 5; + public WellCompositeOperationService( + ICrudRepository wellSectionTypeRepository, + IWellOperationCategoryRepository wellOperationCategoryRepository, + IWellOperationRepository wellOperationRepository, + IWellService wellService) + { + this.wellSectionTypeRepository = wellSectionTypeRepository; + this.wellOperationCategoryRepository = wellOperationCategoryRepository; + this.wellOperationRepository = wellOperationRepository; + this.wellService = wellService; + } - /// - /// Тип секции "Эксплуатационная колонна" - /// - private const int wellSectionProductionString = 4; + public async Task GetAsync(IEnumerable idsWells, CancellationToken token) + { + var sections = await wellSectionTypeRepository.GetAllAsync(token); + var sectionsDict = sections.ToDictionary(s => s.Id, s => s.Caption); + var categories = wellOperationCategoryRepository.Get(true); + var categoriesDict = categories.ToDictionary(s => s.Id, s => s.Name); - /// - /// набор настроек для замены одной категории секции на другую - /// - private static Dictionary<(int, int), int> SettingsForSectionCategoryChange = new Dictionary<(int, int), int>() { - { (2, 5096), 5013 }, - { (2, 5008), 5013 }, - { (3, 5096), 5084 }, - { (3, 5008), 5084 }, - { (3, 5085), 5015 }, - { (3, 5014), 5015 }, - { (31, 5014), 5015 }, - { (31, 5012), 5013 }, - { (31, 5083), 5013 }, - { (4, 5085), 5015 }, - { (4, 5087), 5015 }, - { (4, 5014), 5015 }, - { (4, 5053), 5037 }, - { (4, 5084), 5096 }, - { (4, 5086), 5013 }, - { (6, 5085), 5015 }, - { (6, 5036), 5034 }, - { (6, 5035), 5097 } + var wells = await wellService.GetAsync(new WellRequest { Ids = idsWells }, token); + var wellsDict = wells.ToDictionary(w => w.Id); + + var idsWellSectionTypes = WellSectionTypesWithCategories.Select(t => t.IdSectionType).Distinct(); + var usedCategories = WellSectionTypesWithCategories.Select(c => c.IdCategory).Distinct(); + + var wellOperationRequest = new WellOperationRequest(idsWells) + { + OperationCategoryIds = usedCategories, + SectionTypeIds = idsWellSectionTypes, + OperationType = WellOperation.IdOperationTypeFact }; + var operations = await wellOperationRepository.GetAsync(wellOperationRequest, token); - private HashSet<(int IdSectionType, int IdCategory)> WellSectionTypesWithCategories = new HashSet<(int IdSectionType, int IdCategory)>() + var operationsForComposite = operations.Select(o => CreateCompositeOperation(o, sectionsDict, categoriesDict)); + + var wellOperationsWithComposite = new List>(); + var compositeDepth = 0d; + var compositeDay = 0d; + var result = new WellCompositeOperationDto(); + + var compositeOperations = new List(); + foreach ((int IdSection, int IdCategory) in WellSectionTypesWithCategories) { - { (2, 5001) }, - { (2, 5003) }, - { (2, 5013) }, - { (2, 5000) }, - { (2, 5022) }, - { (2, 5017) }, - { (2, 5023) }, - { (2, 4007) }, - { (2, 5090) }, - { (3, 5001) }, - { (3, 5015) }, - { (3, 5037) }, - { (3, 5057) }, - { (3, 5003) }, - { (3, 5036) }, - { (3, 5084) }, - { (3, 5013) }, - { (3, 5000) }, - { (3, 5022) }, - { (3, 5017) }, - { (3, 4007) }, - { (3, 5090) }, - { (3, 5045) }, - { (3, 5042) }, - { (3, 5046) }, - { (31, 5001) }, - { (31, 5015) }, - { (31, 5037) }, - { (31, 5057) }, - { (31, 5003) }, - { (31, 5036) }, - { (31, 5013) }, - { (31, 5022) }, - { (31, 5017) }, - { (31, 5023) }, - { (31, 4007) }, - { (31, 5045) }, - { (31, 5042) }, - { (31, 5046) }, - { (4, 5001) }, - { (4, 5015) }, - { (4, 5046) }, - { (4, 5037) }, - { (4, 5097) }, - { (4, 5057) }, - { (4, 5003) }, - { (4, 5036) }, - { (4, 5008) }, - { (4, 5003) }, - { (4, 5036) }, - { (4, 5013) }, - { (4, 5000) }, - { (4, 5029) }, - { (4, 5022) }, - { (4, 5017) }, - { (4, 5019) }, - { (4, 5042) }, - { (4, 5046) }, - { (6, 5001) }, - { (6, 5015) }, - { (6, 5034) }, - { (6, 5037) }, - { (6, 5097) }, - { (6, 5057) }, - { (6, 5003) } - }; + var filteredByTemplate = operationsForComposite + .Where(o => o.IdWellSectionType == IdSection) + .Where(o => o.IdCategory == IdCategory); + if (!filteredByTemplate.Any()) + continue; + var groupedByWell = filteredByTemplate.GroupBy(o => o.IdWell); - public WellCompositeOperationService( - ICrudRepository wellSectionTypeRepository, - IWellOperationCategoryRepository wellOperationCategoryRepository, - IWellOperationRepository wellOperationRepository, - IWellService wellService) - { - this.wellSectionTypeRepository = wellSectionTypeRepository; - this.wellOperationCategoryRepository = wellOperationCategoryRepository; - this.wellOperationRepository = wellOperationRepository; - this.wellService = wellService; + var aggreagtedByWell = groupedByWell.Select(g => new WellOperationDto + { + IdCategory = IdCategory, + IdWell = g.Key, + IdWellSectionType = IdSection, + DepthStart = g.Min(o => o.DepthStart), + DurationHours = g.Sum(o => o.DurationHours), + OperationCategoryName = g.First().OperationCategoryName, + WellSectionTypeCaption = g.First().WellSectionTypeCaption, + }); + + var compositeOperation = aggreagtedByWell.OrderBy(o => o.DurationHours). + ThenByDescending(o => o.DepthStart) + .First(); + + compositeOperation.IdWell = 0; + + if (compositeDepth > compositeOperation.DepthStart) + compositeOperation.DepthStart = compositeDepth; + compositeDepth = compositeOperation.DepthStart; + + compositeDay += compositeOperation.DurationHours; + compositeOperation.Day = compositeDay; + + compositeOperations.Add(compositeOperation); } - public async Task GetAsync(IEnumerable idsWells, CancellationToken token) + var groupedByWellOperations = operations + .GroupBy(o => o.IdWell) + .ToDictionary(o => o.Key, o => o.ToArray()) + .Select(o => new WellCompositeOperationSourceDto() + { + Operations = o.Value, + Well = wellsDict[o.Key], + }); + + result.WellOperationsComposite = compositeOperations; + result.WellCompositeSourceOperations = groupedByWellOperations; + + return result; + } + + private static WellOperationDto CreateCompositeOperation( + WellOperationDto dto, + IDictionary sectionTypes, + IDictionary operationCategories) + { + var newDto = dto.Adapt(); + if (newDto.IdWellSectionType == wellSectionTransportTable) { - var sections = await wellSectionTypeRepository.GetAllAsync(token); - var sectionsDict = sections.ToDictionary(s => s.Id, s => s.Caption); - - var categories = wellOperationCategoryRepository.Get(true); - var categoriesDict = categories.ToDictionary(s => s.Id, s => s.Name); - - var wells = await wellService.GetAsync(new WellRequest { Ids = idsWells }, token); - var wellsDict = wells.ToDictionary(w => w.Id); - - var idsWellSectionTypes = WellSectionTypesWithCategories.Select(t => t.IdSectionType).Distinct(); - var usedCategories = WellSectionTypesWithCategories.Select(c => c.IdCategory).Distinct(); - - var wellOperationRequest = new WellOperationRequest(idsWells) - { - OperationCategoryIds = usedCategories, - SectionTypeIds = idsWellSectionTypes, - OperationType = WellOperation.IdOperationTypeFact - }; - var operations = await wellOperationRepository.GetAsync(wellOperationRequest, token); - - var operationsForComposite = operations.Select(o => CreateCompositeOperation(o, sectionsDict, categoriesDict)); - - var wellOperationsWithComposite = new List>(); - var compositeDepth = 0d; - var compositeDay = 0d; - var result = new WellCompositeOperationDto(); - - var compositeOperations = new List(); - foreach ((int IdSection, int IdCategory) in WellSectionTypesWithCategories) - { - var filteredByTemplate = operationsForComposite - .Where(o => o.IdWellSectionType == IdSection) - .Where(o => o.IdCategory == IdCategory); - - if (!filteredByTemplate.Any()) - continue; - - var groupedByWell = filteredByTemplate.GroupBy(o => o.IdWell); - - var aggreagtedByWell = groupedByWell.Select(g => new WellOperationDto - { - IdCategory = IdCategory, - IdWell = g.Key, - IdWellSectionType = IdSection, - DepthStart = g.Min(o => o.DepthStart), - DurationHours = g.Sum(o => o.DurationHours), - OperationCategoryName = g.First().OperationCategoryName, - WellSectionTypeCaption = g.First().WellSectionTypeCaption, - }); - - var compositeOperation = aggreagtedByWell.OrderBy(o => o.DurationHours). - ThenByDescending(o => o.DepthStart) - .First(); - - compositeOperation.IdWell = 0; - compositeOperation.Day = compositeDay + compositeOperation.DurationHours; - - if (compositeDepth > compositeOperation.DepthStart) - compositeOperation.DepthStart = compositeDepth; - - compositeOperations.Add(compositeOperation); - - compositeDepth = compositeOperation.DepthStart; - compositeDay = compositeOperation.Day; - } - - var groupedByWellOperations = operations - .GroupBy(o => o.IdWell) - .ToDictionary(o => o.Key, o => o.ToArray()) - .Select(o => new WellCompositeOperationSourceDto() - { - Operations = o.Value, - Well = new WellDto() - { - Id = o.Key, - Caption = wellsDict[o.Key].Caption, - } - }); - - result.WellOperationsComposite = compositeOperations; - result.WellCompositeSourceOperations = groupedByWellOperations; - - return result; + newDto.IdWellSectionType = wellSectionProductionString; + newDto.WellSectionTypeCaption = sectionTypes[newDto.IdWellSectionType]; } - private static WellOperationDto CreateCompositeOperation( - WellOperationDto dto, - IDictionary sectionTypes, - IDictionary operationCategories) + if ((SettingsForSectionCategoryChange.TryGetValue((newDto.IdWellSectionType, newDto.IdCategory), out int newIdCategory))) { - var newDto = dto.Adapt(); - if (newDto.IdWellSectionType == wellSectionTransportTable) - { - newDto.IdWellSectionType = wellSectionProductionString; - newDto.WellSectionTypeCaption = sectionTypes[newDto.IdWellSectionType]; - } - - if ((SettingsForSectionCategoryChange.TryGetValue((newDto.IdWellSectionType, newDto.IdCategory), out int newIdCategory))) - { - newDto.IdCategory = newIdCategory; - newDto.OperationCategoryName = operationCategories[newDto.IdCategory] ?? string.Empty; - } - - return newDto; + newDto.IdCategory = newIdCategory; + newDto.OperationCategoryName = operationCategories[newDto.IdCategory] ?? string.Empty; } + + return newDto; } }