From f88381353e8b2880dd6011e0cfee9f66265e67b4 Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Thu, 7 Mar 2024 13:38:40 +0500 Subject: [PATCH 01/11] =?UTF-8?q?=D0=9F=D0=BE=D0=BB=D1=83=D1=87=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=BE=D0=BF=D0=B5=D1=80=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D0=B9=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D0=BE=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=B5=D0=BD=D0=B8=D1=8F=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?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IWellCompositeOperationService.cs | 21 +++ AsbCloudInfrastructure/DependencyInjection.cs | 1 + .../Services/WellCompositeOperationService.cs | 165 ++++++++++++++++++ .../WellCompositeOperationController.cs | 35 ++++ 4 files changed, 222 insertions(+) create mode 100644 AsbCloudApp/Services/IWellCompositeOperationService.cs create mode 100644 AsbCloudInfrastructure/Services/WellCompositeOperationService.cs create mode 100644 AsbCloudWebApi/Controllers/WellCompositeOperationController.cs diff --git a/AsbCloudApp/Services/IWellCompositeOperationService.cs b/AsbCloudApp/Services/IWellCompositeOperationService.cs new file mode 100644 index 00000000..94ba1f93 --- /dev/null +++ b/AsbCloudApp/Services/IWellCompositeOperationService.cs @@ -0,0 +1,21 @@ +using AsbCloudApp.Data; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace AsbCloudApp.Services +{ + /// + /// Интерфейс для вычисления композитной скважины + /// + public interface IWellCompositeOperationService + { + /// + /// Получение данных для построения композитной скважины + /// + /// + /// + /// + Task>> GetAsync(IEnumerable idsWells, CancellationToken token); + } +} diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs index 2111356b..6250112f 100644 --- a/AsbCloudInfrastructure/DependencyInjection.cs +++ b/AsbCloudInfrastructure/DependencyInjection.cs @@ -198,6 +198,7 @@ namespace AsbCloudInfrastructure services.AddTransient, CrudCacheRepositoryBase>(); services.AddTransient(); + services.AddTransient(); // admin crud services: services.AddTransient, CrudCacheRepositoryBase>(s => diff --git a/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs b/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs new file mode 100644 index 00000000..562b82c6 --- /dev/null +++ b/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs @@ -0,0 +1,165 @@ +using AsbCloudApp.Data; +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; + +namespace AsbCloudInfrastructure.Services +{ + public class WellCompositeOperationService : IWellCompositeOperationService + { + private IAsbCloudDbContext db; + + /// + /// Тип секции "Транспортный стол" + /// + 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 Dictionary> WellSectionTypesWithCategories = new Dictionary>() + { + { 2, new List{ 5001, 5003, 5013, 5000, 5022, 5017, 5023, 4007, 5090 } }, + { 3, new List{ 5001, 5015, 5037, 5057, 5003, 5036, 5084, 5013, 5000, 5022, 5017, 4007, 5090, 5045, 5042, 5046 } }, + { 31, new List{ 5001, 5015, 5037, 5057, 5003, 5036, 5013, 5022, 5017, 5023, 4007, 5045, 5042, 5046 } }, + { 4, new List{ 5001, 5015, 5046, 5037, 5097, 5057, 5003, 5036, 5008, 5003, 5036, 5013, 5000, 5029, 5022, 5017, 5019, 5042, 5046 } }, + { 6, new List{ 5001, 5015, 5034, 5037, 5097, 5057, 5003 } }, + }; + + + + public WellCompositeOperationService(IAsbCloudDbContext db) + { + this.db = db; + } + + public async Task>> GetAsync(IEnumerable idsWells, CancellationToken token) + { + var sections = await db.WellSectionTypes + .Select(t => t.Adapt()) + .ToArrayAsync(token); + var sectionsDict = sections.ToDictionary(s => s.Id, s => s.Caption); + + var categories = await db.WellOperationCategories + .Select(c => c.Adapt()) + .ToArrayAsync(token); + var categoriesDict = categories.ToDictionary(s => s.Id, s => s.Name); + + var idsWellSectionTypes = WellSectionTypesWithCategories.Select(t => t.Key); + + var groupedWellOperations = db.WellOperations + .Where(o => idsWells.Contains(o.IdWell)) + .Where(o => o.IdType == WellOperation.IdOperationTypeFact) + .Where(o => idsWellSectionTypes.Contains(o.IdWellSectionType)) + .AsEnumerable() + .GroupBy(o => o.IdWellSectionType, (key, group) => group.Where(x => WellSectionTypesWithCategories[key].Contains(x.IdCategory))) + .SelectMany(o => o) + .Select(x => Convert(x, sectionsDict, categoriesDict)) + .GroupBy(o => (o.IdWellSectionType, o.IdCategory, o.IdWell), (gr, o) => o.Count() == 1 ? o.FirstOrDefault()! : new WellOperationDataDto() + { + IdWellSectionType = o.FirstOrDefault()!.IdWellSectionType, + IdCategory = o.FirstOrDefault()!.IdCategory, + DepthStart = o.Max(x => x.DepthStart), + DurationHours = o.Sum(x => x.DurationHours), + IdWell = o.FirstOrDefault()!.IdWell, + WellSectionTypeCaption = o.FirstOrDefault()!.WellSectionTypeCaption, + OperationCategoryName = o.FirstOrDefault()!.OperationCategoryName + }); + + var wellOperationsWithComposite = new List>(); + var operationsGroupBySectionAndCategory = groupedWellOperations.GroupBy(o => (o.IdWellSectionType, o.IdCategory), (key, group) => group.ToList()); + foreach (var operationGroupBySectionAndCategory in operationsGroupBySectionAndCategory) + { + var dictElem = operationGroupBySectionAndCategory.ToDictionary(o => o.IdWell); + + var currentOperation = operationGroupBySectionAndCategory.FirstOrDefault()!; + var composite = new WellOperationDataDto() + { + IdWell = 0, + IdCategory = currentOperation.IdCategory, + IdWellSectionType = currentOperation.IdWellSectionType, + DurationHours = currentOperation.DurationHours, + DepthStart = currentOperation.DepthStart, + OperationCategoryName = currentOperation.OperationCategoryName, + WellSectionTypeCaption = currentOperation.WellSectionTypeCaption, + }; + dictElem.Add(0, composite); + + if (operationGroupBySectionAndCategory.Count() == 1) + { + wellOperationsWithComposite.Add(dictElem); + continue; + } + + var maxDurationHours = operationGroupBySectionAndCategory.Max(o => o.DurationHours); + var minDurationHours = operationGroupBySectionAndCategory.Min(o => o.DurationHours); + if (maxDurationHours == minDurationHours) + { + composite.DepthStart = operationGroupBySectionAndCategory.Max(o => o.DepthStart); + } + else + { + composite.DepthStart = operationGroupBySectionAndCategory.Min(o => o.DepthStart); + } + composite.DurationHours = minDurationHours; + dictElem[0] = composite; + wellOperationsWithComposite.Add(dictElem); + } + return wellOperationsWithComposite; + } + + private static WellOperationDataDto Convert(WellOperation entity, Dictionary sectionsDict, Dictionary categoriesDict) + { + var dto = new WellOperationDataDto(); + dto.IdWellSectionType = entity.IdWellSectionType == wellSectionTransportTable + ? wellSectionProductionString + : entity.IdWellSectionType; + dto.IdCategory = (SettingsForSectionCategoryChange.TryGetValue(((entity.IdWellSectionType == wellSectionTransportTable ? wellSectionProductionString : entity.IdWellSectionType), entity.IdCategory), out int newIdCategory)) + ? newIdCategory + : entity.IdCategory; + dto.DepthStart = entity.DepthStart; + dto.DurationHours = entity.DurationHours; + dto.IdWell = entity.IdWell; + dto.OperationCategoryName = categoriesDict.TryGetValue(dto.IdCategory, out string? CategoryName) + ? CategoryName + : string.Empty; + dto.WellSectionTypeCaption = sectionsDict.TryGetValue(dto.IdWellSectionType, out string? WellSectionName) + ? WellSectionName + : string.Empty; + + return dto; + } + } +} diff --git a/AsbCloudWebApi/Controllers/WellCompositeOperationController.cs b/AsbCloudWebApi/Controllers/WellCompositeOperationController.cs new file mode 100644 index 00000000..e2e4ee4b --- /dev/null +++ b/AsbCloudWebApi/Controllers/WellCompositeOperationController.cs @@ -0,0 +1,35 @@ +using AsbCloudApp.Data; +using AsbCloudApp.Services; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace AsbCloudWebApi.Controllers +{ + + [ApiController] + [Authorize] + [Route("api/[controller]")] + public class WellCompositeOperationController : ControllerBase + { + private readonly IWellCompositeOperationService wellCompositeOperationService; + + public WellCompositeOperationController(IWellCompositeOperationService wellCompositeOperationService, IWellService wellService) + { + this.wellCompositeOperationService = wellCompositeOperationService; + } + + [HttpGet] + [ProducesResponseType(typeof(List>), (int)System.Net.HttpStatusCode.OK)] + public async Task GetAsync([FromQuery] IEnumerable idsWells, CancellationToken token) + { + var result = await wellCompositeOperationService.GetAsync(idsWells, token) + .ConfigureAwait(false); + + return Ok(result); + } + } + +} From dc4d9b1708d67047f82810c0bc60598ea2068277 Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Thu, 7 Mar 2024 13:48:11 +0500 Subject: [PATCH 02/11] WellOperationDataDto --- AsbCloudApp/Data/WellOperationDataDto.cs | 39 ++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 AsbCloudApp/Data/WellOperationDataDto.cs diff --git a/AsbCloudApp/Data/WellOperationDataDto.cs b/AsbCloudApp/Data/WellOperationDataDto.cs new file mode 100644 index 00000000..874bd65c --- /dev/null +++ b/AsbCloudApp/Data/WellOperationDataDto.cs @@ -0,0 +1,39 @@ +namespace AsbCloudApp.Data +{ + /// Операция на скважине + public class WellOperationDataDto : IWellRelated + { + /// + public int IdWell { get; set; } + + /// + /// id секции скважины + /// + public int IdWellSectionType { get; set; } + + /// + /// id категории операции + /// + public int IdCategory { get; set; } + + /// + /// Глубина на начало операции, м + /// + public double DepthStart { get; set; } + + /// + /// Продолжительность, часы + /// + public double DurationHours { get; set; } + + /// + /// Наименование секции + /// + public string WellSectionTypeCaption { get; set; } = string.Empty; + + /// + /// Наименование категории + /// + public string OperationCategoryName { get; set; } = string.Empty; + } +} From 3828c781299d5ac3b8bbf13b4b0d279c4043dc8c Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Mon, 11 Mar 2024 14:11:13 +0500 Subject: [PATCH 03/11] =?UTF-8?q?=D0=9F=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=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 --- .../Repositories/IWellOperationRepository.cs | 8 + AsbCloudApp/Requests/WellOperationRequest.cs | 18 +- .../Repository/WellOperationRepository.cs | 25 ++ .../Services/WellCompositeOperationService.cs | 224 +++++++++++------- .../WellCompositeOperationController.cs | 18 +- 5 files changed, 207 insertions(+), 86 deletions(-) diff --git a/AsbCloudApp/Repositories/IWellOperationRepository.cs b/AsbCloudApp/Repositories/IWellOperationRepository.cs index cf277304..dd39ce52 100644 --- a/AsbCloudApp/Repositories/IWellOperationRepository.cs +++ b/AsbCloudApp/Repositories/IWellOperationRepository.cs @@ -42,6 +42,14 @@ namespace AsbCloudApp.Repositories /// Task> GetAsync(WellOperationRequest request, CancellationToken token); + /// + /// Получить список операций по запросу + /// + /// + /// + /// + Task> GetAsync(WellsOperationRequest request, CancellationToken token); + /// /// Получить страницу списка операций /// diff --git a/AsbCloudApp/Requests/WellOperationRequest.cs b/AsbCloudApp/Requests/WellOperationRequest.cs index ab5b901e..89cd6858 100644 --- a/AsbCloudApp/Requests/WellOperationRequest.cs +++ b/AsbCloudApp/Requests/WellOperationRequest.cs @@ -72,7 +72,7 @@ namespace AsbCloudApp.Requests this.LeDepth = request.LeDepth; this.GeDate = request.GeDate; this.LtDate = request.LtDate; - + this.OperationCategoryIds = request.OperationCategoryIds; this.OperationType = request.OperationType; this.SectionTypeIds = request.SectionTypeIds; @@ -82,4 +82,20 @@ namespace AsbCloudApp.Requests this.SortFields = request.SortFields; } } + + /// + /// Параметры для запроса списка операций (с массивом id скважин) + /// + public class WellsOperationRequest : WellOperationRequestBase + { + /// + /// ids скважин + /// + public IEnumerable IdsWell { get; set; } = null!; + + /// + /// Тип 0 = План или 1 = Факт + /// + public int IdType { get; set; } + } } diff --git a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs index 57bf3768..be039c86 100644 --- a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs +++ b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs @@ -205,6 +205,31 @@ public class WellOperationRepository : IWellOperationRepository return dtos.Select(Convert); } + public async Task> GetAsync( + WellsOperationRequest request, + CancellationToken token) + { + var query = db.WellOperations + .Where(o => request.IdsWell.Contains(o.IdWell)) + .Where(o => request.IdType == o.IdType) + .Where(o => request.SectionTypeIds != null ? request.SectionTypeIds.Contains(o.IdWellSectionType) : true) + .Where(o => request.OperationCategoryIds != null ? request.OperationCategoryIds.Contains(o.IdCategory) : true) + .Select(o => new WellOperationDataDto(){ + DepthStart = o.DepthStart, + DurationHours = o.DurationHours, + IdCategory = o.IdCategory, + IdWell = o.IdWell, + IdWellSectionType = o.IdWellSectionType, + OperationCategoryName = o.OperationCategory.Name, + WellSectionTypeCaption = o.WellSectionType.Caption, + }) + .AsNoTracking(); + + var dtos = await query.ToArrayAsync(token); + + return dtos; + } + /// public async Task> GetPageAsync( WellOperationRequest request, diff --git a/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs b/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs index 562b82c6..0056b267 100644 --- a/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs +++ b/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs @@ -1,7 +1,8 @@ using AsbCloudApp.Data; +using AsbCloudApp.Repositories; +using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudDb.Model; -using Mapster; using Microsoft.EntityFrameworkCore; using System.Collections.Generic; using System.Linq; @@ -12,7 +13,9 @@ namespace AsbCloudInfrastructure.Services { public class WellCompositeOperationService : IWellCompositeOperationService { - private IAsbCloudDbContext db; + private ICrudRepository wellSectionTypeRepository; + private IWellOperationCategoryRepository wellOperationCategoryRepository; + private IWellOperationRepository wellOperationRepository; /// /// Тип секции "Транспортный стол" @@ -49,115 +52,168 @@ namespace AsbCloudInfrastructure.Services { (6, 5035), 5097 } }; - private Dictionary> WellSectionTypesWithCategories = new Dictionary>() + private HashSet<(int IdSectionType, int IdCategory)> WellSectionTypesWithCategories = new HashSet<(int IdSectionType, int IdCategory)>() { - { 2, new List{ 5001, 5003, 5013, 5000, 5022, 5017, 5023, 4007, 5090 } }, - { 3, new List{ 5001, 5015, 5037, 5057, 5003, 5036, 5084, 5013, 5000, 5022, 5017, 4007, 5090, 5045, 5042, 5046 } }, - { 31, new List{ 5001, 5015, 5037, 5057, 5003, 5036, 5013, 5022, 5017, 5023, 4007, 5045, 5042, 5046 } }, - { 4, new List{ 5001, 5015, 5046, 5037, 5097, 5057, 5003, 5036, 5008, 5003, 5036, 5013, 5000, 5029, 5022, 5017, 5019, 5042, 5046 } }, - { 6, new List{ 5001, 5015, 5034, 5037, 5097, 5057, 5003 } }, + { (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) } }; - public WellCompositeOperationService(IAsbCloudDbContext db) + public WellCompositeOperationService( + ICrudRepository wellSectionTypeRepository, + IWellOperationCategoryRepository wellOperationCategoryRepository, + IWellOperationRepository wellOperationRepository) { - this.db = db; + this.wellSectionTypeRepository = wellSectionTypeRepository; + this.wellOperationCategoryRepository = wellOperationCategoryRepository; + this.wellOperationRepository = wellOperationRepository; } public async Task>> GetAsync(IEnumerable idsWells, CancellationToken token) { - var sections = await db.WellSectionTypes - .Select(t => t.Adapt()) - .ToArrayAsync(token); + var sections = await wellSectionTypeRepository.GetAllAsync(token); var sectionsDict = sections.ToDictionary(s => s.Id, s => s.Caption); - var categories = await db.WellOperationCategories - .Select(c => c.Adapt()) - .ToArrayAsync(token); + var categories = wellOperationCategoryRepository.Get(true); var categoriesDict = categories.ToDictionary(s => s.Id, s => s.Name); - var idsWellSectionTypes = WellSectionTypesWithCategories.Select(t => t.Key); + var idsWellSectionTypes = WellSectionTypesWithCategories.Select(t => t.IdSectionType); + var usedCategories = WellSectionTypesWithCategories.Select(c => c.IdCategory).Distinct(); - var groupedWellOperations = db.WellOperations - .Where(o => idsWells.Contains(o.IdWell)) - .Where(o => o.IdType == WellOperation.IdOperationTypeFact) - .Where(o => idsWellSectionTypes.Contains(o.IdWellSectionType)) - .AsEnumerable() - .GroupBy(o => o.IdWellSectionType, (key, group) => group.Where(x => WellSectionTypesWithCategories[key].Contains(x.IdCategory))) - .SelectMany(o => o) - .Select(x => Convert(x, sectionsDict, categoriesDict)) - .GroupBy(o => (o.IdWellSectionType, o.IdCategory, o.IdWell), (gr, o) => o.Count() == 1 ? o.FirstOrDefault()! : new WellOperationDataDto() - { - IdWellSectionType = o.FirstOrDefault()!.IdWellSectionType, - IdCategory = o.FirstOrDefault()!.IdCategory, - DepthStart = o.Max(x => x.DepthStart), - DurationHours = o.Sum(x => x.DurationHours), - IdWell = o.FirstOrDefault()!.IdWell, - WellSectionTypeCaption = o.FirstOrDefault()!.WellSectionTypeCaption, - OperationCategoryName = o.FirstOrDefault()!.OperationCategoryName - }); + var wellOperationRequest = new WellsOperationRequest() + { + IdsWell = idsWells, + OperationCategoryIds = usedCategories, + SectionTypeIds = idsWellSectionTypes, + IdType = WellOperation.IdOperationTypeFact + }; + var operations = await wellOperationRepository.GetAsync(wellOperationRequest, token); + + var renamedOperations = operations.Select(o => UpdateIdWellSectionAndIdCategory(o, sectionsDict, categoriesDict)); var wellOperationsWithComposite = new List>(); - var operationsGroupBySectionAndCategory = groupedWellOperations.GroupBy(o => (o.IdWellSectionType, o.IdCategory), (key, group) => group.ToList()); - foreach (var operationGroupBySectionAndCategory in operationsGroupBySectionAndCategory) + var compositeDepth = 0d; + foreach ((int IdSection, int IdCategory) in WellSectionTypesWithCategories) { - var dictElem = operationGroupBySectionAndCategory.ToDictionary(o => o.IdWell); + var filteredByTemplate = renamedOperations + .Where(o => o.IdWellSectionType == IdSection) + .Where(o => o.IdCategory == IdCategory); - var currentOperation = operationGroupBySectionAndCategory.FirstOrDefault()!; - var composite = new WellOperationDataDto() - { - IdWell = 0, - IdCategory = currentOperation.IdCategory, - IdWellSectionType = currentOperation.IdWellSectionType, - DurationHours = currentOperation.DurationHours, - DepthStart = currentOperation.DepthStart, - OperationCategoryName = currentOperation.OperationCategoryName, - WellSectionTypeCaption = currentOperation.WellSectionTypeCaption, - }; - dictElem.Add(0, composite); - - if (operationGroupBySectionAndCategory.Count() == 1) - { - wellOperationsWithComposite.Add(dictElem); + if (!filteredByTemplate.Any()) continue; - } - var maxDurationHours = operationGroupBySectionAndCategory.Max(o => o.DurationHours); - var minDurationHours = operationGroupBySectionAndCategory.Min(o => o.DurationHours); - if (maxDurationHours == minDurationHours) + var groupedByWell = filteredByTemplate.GroupBy(o => o.IdWell); + + var aggreagtedByWell = groupedByWell.Select(g => new WellOperationDataDto { - composite.DepthStart = operationGroupBySectionAndCategory.Max(o => o.DepthStart); - } - else - { - composite.DepthStart = operationGroupBySectionAndCategory.Min(o => o.DepthStart); - } - composite.DurationHours = minDurationHours; - dictElem[0] = composite; - wellOperationsWithComposite.Add(dictElem); + 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 composite = aggreagtedByWell + .OrderBy(o => o.DurationHours) + .ThenByDescending(o => o.DepthStart) + .First(); + composite.IdWell = 0; + if (compositeDepth > composite.DepthStart) + composite.DepthStart = compositeDepth; + + compositeDepth = composite.DepthStart; + + + var resultItem = aggreagtedByWell.ToDictionary(o => o.IdWell); + resultItem.Add(0, composite); + + wellOperationsWithComposite.Add(resultItem); } return wellOperationsWithComposite; } - private static WellOperationDataDto Convert(WellOperation entity, Dictionary sectionsDict, Dictionary categoriesDict) + private WellOperationDataDto UpdateIdWellSectionAndIdCategory( + WellOperationDataDto dto, + Dictionary sectionTypes, + Dictionary operationCategories) { - var dto = new WellOperationDataDto(); - dto.IdWellSectionType = entity.IdWellSectionType == wellSectionTransportTable - ? wellSectionProductionString - : entity.IdWellSectionType; - dto.IdCategory = (SettingsForSectionCategoryChange.TryGetValue(((entity.IdWellSectionType == wellSectionTransportTable ? wellSectionProductionString : entity.IdWellSectionType), entity.IdCategory), out int newIdCategory)) - ? newIdCategory - : entity.IdCategory; - dto.DepthStart = entity.DepthStart; - dto.DurationHours = entity.DurationHours; - dto.IdWell = entity.IdWell; - dto.OperationCategoryName = categoriesDict.TryGetValue(dto.IdCategory, out string? CategoryName) - ? CategoryName - : string.Empty; - dto.WellSectionTypeCaption = sectionsDict.TryGetValue(dto.IdWellSectionType, out string? WellSectionName) - ? WellSectionName - : string.Empty; + if (dto.IdWellSectionType == wellSectionTransportTable) + { + dto.IdWellSectionType = wellSectionProductionString; + dto.WellSectionTypeCaption = sectionTypes[dto.IdWellSectionType] ?? string.Empty; + } + + if ((SettingsForSectionCategoryChange.TryGetValue((dto.IdWellSectionType, dto.IdCategory), out int newIdCategory))) + { + dto.IdCategory = newIdCategory; + dto.OperationCategoryName = operationCategories[dto.IdCategory] ?? string.Empty; + } return dto; } diff --git a/AsbCloudWebApi/Controllers/WellCompositeOperationController.cs b/AsbCloudWebApi/Controllers/WellCompositeOperationController.cs index e2e4ee4b..d662e4e8 100644 --- a/AsbCloudWebApi/Controllers/WellCompositeOperationController.cs +++ b/AsbCloudWebApi/Controllers/WellCompositeOperationController.cs @@ -15,21 +15,37 @@ namespace AsbCloudWebApi.Controllers public class WellCompositeOperationController : ControllerBase { private readonly IWellCompositeOperationService wellCompositeOperationService; + private readonly IWellService wellService; public WellCompositeOperationController(IWellCompositeOperationService wellCompositeOperationService, IWellService wellService) { this.wellCompositeOperationService = wellCompositeOperationService; + this.wellService = wellService; } [HttpGet] - [ProducesResponseType(typeof(List>), (int)System.Net.HttpStatusCode.OK)] + [ProducesResponseType(typeof(IList>), (int)System.Net.HttpStatusCode.OK)] public async Task GetAsync([FromQuery] IEnumerable idsWells, CancellationToken token) { + foreach (var idWell in idsWells) + if (!await UserHasAccessToWellAsync(idWell, token)) + return Forbid(); + var result = await wellCompositeOperationService.GetAsync(idsWells, token) .ConfigureAwait(false); return Ok(result); } + + protected async Task UserHasAccessToWellAsync(int idWell, CancellationToken token) + { + var idCompany = User.GetCompanyId(); + if (idCompany is not null && + await wellService.IsCompanyInvolvedInWellAsync((int)idCompany, idWell, token) + .ConfigureAwait(false)) + return true; + return false; + } } } From 17454f762c53912696d9bc6279a9fa9300de072f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Tue, 12 Mar 2024 10:01:33 +0300 Subject: [PATCH 04/11] =?UTF-8?q?=D0=A0=D0=B5=D1=84=D0=B0=D0=BA=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D0=BF=D0=B0=D1=80=D1=81=D0=B5?= =?UTF-8?q?=D1=80=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ParserOptions/WellRelatedParserRequest.cs | 21 +++++++++++++++++ AsbCloudApp/Services/IParserService.cs | 7 +++--- .../Services/Parser/ParserExcelService.cs | 8 +++---- .../Parser/ProcessMapPlanDrillingParser.cs | 1 - .../Parser/ProcessMapPlanParser.cs | 16 +++++++++++-- .../Parser/ProcessMapPlanReamParser.cs | 4 +--- .../Parser/TrajectoryFactManualParser.cs | 6 ++--- .../Trajectory/Parser/TrajectoryParser.cs | 23 +++++++++++++++++++ .../Trajectory/Parser/TrajectoryPlanParser.cs | 6 ++--- 9 files changed, 71 insertions(+), 21 deletions(-) create mode 100644 AsbCloudApp/Requests/ParserOptions/WellRelatedParserRequest.cs create mode 100644 AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryParser.cs diff --git a/AsbCloudApp/Requests/ParserOptions/WellRelatedParserRequest.cs b/AsbCloudApp/Requests/ParserOptions/WellRelatedParserRequest.cs new file mode 100644 index 00000000..3ffbf4d5 --- /dev/null +++ b/AsbCloudApp/Requests/ParserOptions/WellRelatedParserRequest.cs @@ -0,0 +1,21 @@ +namespace AsbCloudApp.Requests.ParserOptions; + +/// +/// Параметры парсинга +/// +public class WellRelatedParserRequest : IParserOptionsRequest +{ + /// + /// Конструктор + /// + /// Id скважины + public WellRelatedParserRequest(int idWell) + { + IdWell = idWell; + } + + /// + /// Id скважины + /// + public int IdWell { get; } +} \ No newline at end of file diff --git a/AsbCloudApp/Services/IParserService.cs b/AsbCloudApp/Services/IParserService.cs index 8c01af5a..6fa095cd 100644 --- a/AsbCloudApp/Services/IParserService.cs +++ b/AsbCloudApp/Services/IParserService.cs @@ -8,8 +8,10 @@ namespace AsbCloudApp.Services; /// Сервис парсинга /// /// -public interface IParserService : IParserService +/// +public interface IParserService : IParserService where TDto : class, IId + where TOptions : IParserOptionsRequest { /// /// Распарсить файл @@ -17,8 +19,7 @@ public interface IParserService : IParserService /// /// /// - ParserResultDto Parse(Stream file, TOptions options) - where TOptions : IParserOptionsRequest; + ParserResultDto Parse(Stream file, TOptions options); /// /// Получение шаблона для заполнения diff --git a/AsbCloudInfrastructure/Services/Parser/ParserExcelService.cs b/AsbCloudInfrastructure/Services/Parser/ParserExcelService.cs index 661c729f..13c621af 100644 --- a/AsbCloudInfrastructure/Services/Parser/ParserExcelService.cs +++ b/AsbCloudInfrastructure/Services/Parser/ParserExcelService.cs @@ -12,8 +12,9 @@ using Mapster; namespace AsbCloudInfrastructure.Services.Parser; -public abstract class ParserExcelService : IParserService +public abstract class ParserExcelService : IParserService where TDto : class, IValidatableObject, IId + where TOptions : IParserOptionsRequest { protected abstract string SheetName { get; } @@ -22,9 +23,8 @@ public abstract class ParserExcelService : IParserService protected abstract string TemplateFileName { get; } protected abstract IDictionary Cells { get; } - - public virtual ParserResultDto Parse(Stream file, TOptions options) - where TOptions : IParserOptionsRequest + + public virtual ParserResultDto Parse(Stream file, TOptions options) { using var workbook = new XLWorkbook(file); var sheet = workbook.GetWorksheet(SheetName); diff --git a/AsbCloudInfrastructure/Services/ProcessMapPlan/Parser/ProcessMapPlanDrillingParser.cs b/AsbCloudInfrastructure/Services/ProcessMapPlan/Parser/ProcessMapPlanDrillingParser.cs index c1717db1..f4e829fc 100644 --- a/AsbCloudInfrastructure/Services/ProcessMapPlan/Parser/ProcessMapPlanDrillingParser.cs +++ b/AsbCloudInfrastructure/Services/ProcessMapPlan/Parser/ProcessMapPlanDrillingParser.cs @@ -6,7 +6,6 @@ using AsbCloudApp.Data; using AsbCloudApp.Data.ProcessMaps; using AsbCloudApp.Repositories; using AsbCloudInfrastructure.Services.Parser; -using Microsoft.Extensions.DependencyInjection; namespace AsbCloudInfrastructure.Services.ProcessMapPlan.Parser; diff --git a/AsbCloudInfrastructure/Services/ProcessMapPlan/Parser/ProcessMapPlanParser.cs b/AsbCloudInfrastructure/Services/ProcessMapPlan/Parser/ProcessMapPlanParser.cs index 1686779b..effe7ef6 100644 --- a/AsbCloudInfrastructure/Services/ProcessMapPlan/Parser/ProcessMapPlanParser.cs +++ b/AsbCloudInfrastructure/Services/ProcessMapPlan/Parser/ProcessMapPlanParser.cs @@ -1,14 +1,26 @@ -using System; +using System.IO; +using AsbCloudApp.Data; using AsbCloudApp.Data.ProcessMaps; +using AsbCloudApp.Requests.ParserOptions; using AsbCloudInfrastructure.Services.Parser; namespace AsbCloudInfrastructure.Services.ProcessMapPlan.Parser; -public abstract class ProcessMapPlanParser : ParserExcelService +public abstract class ProcessMapPlanParser : ParserExcelService where TDto : ProcessMapPlanBaseDto { protected override int HeaderRowsCount => 2; + public override ParserResultDto Parse(Stream file, WellRelatedParserRequest options) + { + var result = base.Parse(file, options); + + foreach (var item in result.Item) + item.Item.IdWell = options.IdWell; + + return result; + } + protected static int? GetIdMode(string? modeName) => modeName?.Trim().ToLower() switch { diff --git a/AsbCloudInfrastructure/Services/ProcessMapPlan/Parser/ProcessMapPlanReamParser.cs b/AsbCloudInfrastructure/Services/ProcessMapPlan/Parser/ProcessMapPlanReamParser.cs index 20aca5ed..6ca31714 100644 --- a/AsbCloudInfrastructure/Services/ProcessMapPlan/Parser/ProcessMapPlanReamParser.cs +++ b/AsbCloudInfrastructure/Services/ProcessMapPlan/Parser/ProcessMapPlanReamParser.cs @@ -22,14 +22,12 @@ public class ProcessMapPlanReamParser : ProcessMapPlanParser "ProcessMapPlanReamTemplate.xlsx"; private const int ColumnSection = 1; - private const int ColumnMode = 2; - + protected override IDictionary Cells => new Dictionary { { nameof(ProcessMapPlanReamDto.Section), new Cell(ColumnSection, typeof(string)) }, { nameof(ProcessMapPlanReamDto.DepthStart), new Cell(2, typeof(double)) }, { nameof(ProcessMapPlanReamDto.DepthEnd), new Cell(3, typeof(double)) }, - { nameof(ProcessMapPlanReamDto.Repeats), new Cell(4, typeof(double)) }, { nameof(ProcessMapPlanReamDto.SpinUpward), new Cell(5, typeof(double)) }, { nameof(ProcessMapPlanReamDto.SpinUpward), new Cell(6, typeof(double)) }, diff --git a/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryFactManualParser.cs b/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryFactManualParser.cs index 5de4e2c5..cf4b7118 100644 --- a/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryFactManualParser.cs +++ b/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryFactManualParser.cs @@ -4,12 +4,10 @@ using AsbCloudInfrastructure.Services.Parser; namespace AsbCloudInfrastructure.Services.Trajectory.Parser; -public class TrajectoryFactManualParser : ParserExcelService +public class TrajectoryFactManualParser : TrajectoryParser { protected override string SheetName => "Фактическая траектория"; - - protected override int HeaderRowsCount => 2; - + protected override string TemplateFileName => "TrajectoryFactManualTemplate.xlsx"; protected override IDictionary Cells => new Dictionary diff --git a/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryParser.cs b/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryParser.cs new file mode 100644 index 00000000..ce579fa6 --- /dev/null +++ b/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryParser.cs @@ -0,0 +1,23 @@ +using System.IO; +using AsbCloudApp.Data; +using AsbCloudApp.Data.Trajectory; +using AsbCloudApp.Requests.ParserOptions; +using AsbCloudInfrastructure.Services.Parser; + +namespace AsbCloudInfrastructure.Services.Trajectory.Parser; + +public abstract class TrajectoryParser : ParserExcelService + where TDto : TrajectoryGeoDto +{ + protected override int HeaderRowsCount => 2; + + public override ParserResultDto Parse(Stream file, WellRelatedParserRequest options) + { + var result = base.Parse(file, options); + + foreach (var item in result.Item) + item.Item.IdWell = options.IdWell; + + return result; + } +} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryPlanParser.cs b/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryPlanParser.cs index 4c100766..568bfa35 100644 --- a/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryPlanParser.cs +++ b/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryPlanParser.cs @@ -4,12 +4,10 @@ using AsbCloudInfrastructure.Services.Parser; namespace AsbCloudInfrastructure.Services.Trajectory.Parser; -public class TrajectoryPlanParser : ParserExcelService +public class TrajectoryPlanParser : TrajectoryParser { protected override string SheetName => "Плановая траектория"; - - protected override int HeaderRowsCount => 2; - + protected override string TemplateFileName => "TrajectoryPlanTemplate.xlsx"; protected override IDictionary Cells => new Dictionary From 84564c2a38f5e8a52c311e02fb012877223f8490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Tue, 12 Mar 2024 10:02:03 +0300 Subject: [PATCH 05/11] =?UTF-8?q?=D0=A0=D0=B5=D1=84=D0=B0=D0=BA=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=BB=D0=BB=D0=B5=D1=80=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ProcessMapPlanDrillingControllerTest.cs | 16 ++++++++-------- .../ProcessMaps/ProcessMapPlanBaseController.cs | 11 +++++------ .../Trajectory/TrajectoryEditableController.cs | 9 ++++++--- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/AsbCloudWebApi.IntegrationTests/Controllers/ProcessMapPlan/ProcessMapPlanDrillingControllerTest.cs b/AsbCloudWebApi.IntegrationTests/Controllers/ProcessMapPlan/ProcessMapPlanDrillingControllerTest.cs index 0ff8bb97..3a5815e9 100644 --- a/AsbCloudWebApi.IntegrationTests/Controllers/ProcessMapPlan/ProcessMapPlanDrillingControllerTest.cs +++ b/AsbCloudWebApi.IntegrationTests/Controllers/ProcessMapPlan/ProcessMapPlanDrillingControllerTest.cs @@ -571,10 +571,10 @@ public class ProcessMapPlanDrillingControllerTest: BaseIntegrationTest //arrange const string fileName = "ProcessMapPlanDrillingValid.xlsx"; var stream = Assembly.GetExecutingAssembly().GetFileCopyStream(fileName); - - //act var streamPart = new StreamPart(stream, fileName, "application/octet-stream"); - var response = await client.Parse(Defaults.Wells[0].Id, new[] { streamPart }); + + //act + var response = await client.Parse(Defaults.Wells[0].Id, streamPart); //assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); @@ -589,9 +589,8 @@ public class ProcessMapPlanDrillingControllerTest: BaseIntegrationTest var dtoActual = row.Item; Assert.True(row.IsValid); - - var excludeProps = new[] { nameof(ProcessMapPlanDrillingDto.IdWell) }; - MatchHelper.Match(dto, dtoActual, excludeProps); + + MatchHelper.Match(dto, dtoActual); } [Fact] @@ -600,11 +599,12 @@ public class ProcessMapPlanDrillingControllerTest: BaseIntegrationTest //arrange const string fileName = "ProcessMapPlanDrillingInvalid.xlsx"; var stream = Assembly.GetExecutingAssembly().GetFileCopyStream(fileName); + var streamPart = new StreamPart(stream, fileName, "application/octet-stream"); //act - var streamPart = new StreamPart(stream, fileName, "application/octet-stream"); - var response = await client.Parse(Defaults.Wells[0].Id, new[] { streamPart }); + var response = await client.Parse(Defaults.Wells[0].Id, streamPart); + //assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); var parserResult = response.Content; diff --git a/AsbCloudWebApi/Controllers/ProcessMaps/ProcessMapPlanBaseController.cs b/AsbCloudWebApi/Controllers/ProcessMaps/ProcessMapPlanBaseController.cs index 45da7f11..49513f2c 100644 --- a/AsbCloudWebApi/Controllers/ProcessMaps/ProcessMapPlanBaseController.cs +++ b/AsbCloudWebApi/Controllers/ProcessMaps/ProcessMapPlanBaseController.cs @@ -30,11 +30,11 @@ public abstract class ProcessMapPlanBaseController : ControllerBase { private readonly IChangeLogRepository repository; private readonly IWellService wellService; - private readonly ParserExcelService parserService; + private readonly ParserExcelService parserService; protected ProcessMapPlanBaseController(IChangeLogRepository repository, IWellService wellService, - ParserExcelService parserService) + ParserExcelService parserService) { this.repository = repository; this.wellService = wellService; @@ -213,7 +213,7 @@ public abstract class ProcessMapPlanBaseController : ControllerBase [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] public async Task>> Parse(int idWell, - [Required] IFormFile file, + [Required] IFormFile file, CancellationToken token) { await AssertUserHasAccessToWell(idWell, token); @@ -222,9 +222,8 @@ public abstract class ProcessMapPlanBaseController : ControllerBase try { - var dto = parserService.Parse(stream, IParserOptionsRequest.Empty()); - foreach (var item in dto.Item) - item.Item.IdWell = idWell; + var options = new WellRelatedParserRequest(idWell); + var dto = parserService.Parse(stream, options); return Ok(dto); } diff --git a/AsbCloudWebApi/Controllers/Trajectory/TrajectoryEditableController.cs b/AsbCloudWebApi/Controllers/Trajectory/TrajectoryEditableController.cs index 344ed707..814bcdcf 100644 --- a/AsbCloudWebApi/Controllers/Trajectory/TrajectoryEditableController.cs +++ b/AsbCloudWebApi/Controllers/Trajectory/TrajectoryEditableController.cs @@ -13,6 +13,7 @@ using System.Threading.Tasks; using AsbCloudApp.Data; using AsbCloudApp.Requests.ParserOptions; using AsbCloudInfrastructure.Services.Parser; +using AsbCloudInfrastructure.Services.Trajectory.Parser; namespace AsbCloudWebApi.Controllers.Trajectory { @@ -25,11 +26,11 @@ namespace AsbCloudWebApi.Controllers.Trajectory public abstract class TrajectoryEditableController : TrajectoryController where TDto : TrajectoryGeoDto { - private readonly ParserExcelService parserService; + private readonly TrajectoryParser parserService; private readonly ITrajectoryEditableRepository trajectoryRepository; protected TrajectoryEditableController(IWellService wellService, - ParserExcelService parserService, + TrajectoryParser parserService, TrajectoryExportService trajectoryExportService, ITrajectoryEditableRepository trajectoryRepository) : base(wellService, trajectoryExportService, trajectoryRepository) @@ -78,7 +79,9 @@ namespace AsbCloudWebApi.Controllers.Trajectory try { - var dto = parserService.Parse(stream, IParserOptionsRequest.Empty()); + var options = new WellRelatedParserRequest(idWell); + var dto = parserService.Parse(stream, options); + return Ok(dto); } catch (FileFormatException ex) From a53f5c3ac343a501f8f79066bf691b84d99a0915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Tue, 12 Mar 2024 10:02:16 +0300 Subject: [PATCH 06/11] =?UTF-8?q?=D0=A0=D0=B5=D1=84=D0=B0=D1=82=D0=BA?= =?UTF-8?q?=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D1=82=D0=B5=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Clients/IProcessMapPlanDrillingClient.cs | 2 +- .../Services/Trajectory/TrajectoryParserTest.cs | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/AsbCloudWebApi.IntegrationTests/Clients/IProcessMapPlanDrillingClient.cs b/AsbCloudWebApi.IntegrationTests/Clients/IProcessMapPlanDrillingClient.cs index 2a151573..93ce768b 100644 --- a/AsbCloudWebApi.IntegrationTests/Clients/IProcessMapPlanDrillingClient.cs +++ b/AsbCloudWebApi.IntegrationTests/Clients/IProcessMapPlanDrillingClient.cs @@ -35,5 +35,5 @@ public interface IProcessMapPlanDrillingClient [Multipart] [Post(BaseRoute + "/parse")] - Task>> Parse(int idWell, [AliasAs("files")] IEnumerable streams); + Task>> Parse(int idWell, [AliasAs("file")] StreamPart stream); } diff --git a/AsbCloudWebApi.Tests/Services/Trajectory/TrajectoryParserTest.cs b/AsbCloudWebApi.Tests/Services/Trajectory/TrajectoryParserTest.cs index 8921d982..8b9bd3e9 100644 --- a/AsbCloudWebApi.Tests/Services/Trajectory/TrajectoryParserTest.cs +++ b/AsbCloudWebApi.Tests/Services/Trajectory/TrajectoryParserTest.cs @@ -11,9 +11,11 @@ public class TrajectoryParserTest { private const string UsingTemplateFile = "AsbCloudWebApi.Tests.Services.Trajectory.Templates"; + private readonly WellRelatedParserRequest options = new(1); + private readonly TrajectoryPlanParser trajectoryPlanParser = new(); private readonly TrajectoryFactManualParser trajectoryFactManualParser = new(); - + [Fact] public void Parse_trajectory_plan() { @@ -22,8 +24,8 @@ public class TrajectoryParserTest if (stream is null) Assert.Fail("Файла для импорта не существует"); - - var trajectoryRows = trajectoryPlanParser.Parse(stream, IParserOptionsRequest.Empty()); + + var trajectoryRows = trajectoryPlanParser.Parse(stream, options); Assert.Equal(3, trajectoryRows.Item.Count()); } @@ -37,7 +39,7 @@ public class TrajectoryParserTest if (stream is null) Assert.Fail("Файла для импорта не существует"); - var trajectoryRows = trajectoryFactManualParser.Parse(stream, IParserOptionsRequest.Empty()); + var trajectoryRows = trajectoryFactManualParser.Parse(stream, options); Assert.Equal(4, trajectoryRows.Item.Count()); } From 45f0f50a347b63cab4572a98a706c9aeacc97d79 Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Tue, 12 Mar 2024 15:00:14 +0500 Subject: [PATCH 07/11] =?UTF-8?q?Bug=20fix=20+=20=D0=B0=D0=B2=D1=82=D0=BE?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D1=8B=20(=D1=8E=D0=BD=D0=B8=D1=82-?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/WellCompositeOperationService.cs | 10 +- .../WellCompositeOperationServiceTest.cs | 299 ++++++++++++++++++ 2 files changed, 304 insertions(+), 5 deletions(-) create mode 100644 AsbCloudWebApi.Tests/Services/WellCompositeOperation/WellCompositeOperationServiceTest.cs diff --git a/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs b/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs index 0056b267..3a02b6b2 100644 --- a/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs +++ b/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs @@ -141,7 +141,7 @@ namespace AsbCloudInfrastructure.Services var categories = wellOperationCategoryRepository.Get(true); var categoriesDict = categories.ToDictionary(s => s.Id, s => s.Name); - var idsWellSectionTypes = WellSectionTypesWithCategories.Select(t => t.IdSectionType); + var idsWellSectionTypes = WellSectionTypesWithCategories.Select(t => t.IdSectionType).Distinct(); var usedCategories = WellSectionTypesWithCategories.Select(c => c.IdCategory).Distinct(); var wellOperationRequest = new WellsOperationRequest() @@ -179,10 +179,10 @@ namespace AsbCloudInfrastructure.Services WellSectionTypeCaption = g.First().WellSectionTypeCaption, }); - var composite = aggreagtedByWell - .OrderBy(o => o.DurationHours) - .ThenByDescending(o => o.DepthStart) - .First(); + var composite = aggreagtedByWell.GroupBy(g => g.DurationHours).Count() == 1 + ? aggreagtedByWell.OrderByDescending(o => o.DepthStart).First() + : aggreagtedByWell.OrderBy(o => o.DepthStart).First(); + composite.IdWell = 0; if (compositeDepth > composite.DepthStart) composite.DepthStart = compositeDepth; diff --git a/AsbCloudWebApi.Tests/Services/WellCompositeOperation/WellCompositeOperationServiceTest.cs b/AsbCloudWebApi.Tests/Services/WellCompositeOperation/WellCompositeOperationServiceTest.cs new file mode 100644 index 00000000..eece10e8 --- /dev/null +++ b/AsbCloudWebApi.Tests/Services/WellCompositeOperation/WellCompositeOperationServiceTest.cs @@ -0,0 +1,299 @@ +using AsbCloudApp.Requests; +using AsbCloudDb.Model; +using AsbCloudInfrastructure.Repository; +using AsbCloudInfrastructure.Services.ProcessMaps.Report; +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.Services; + +namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation +{ + public class WellCompositeOperationServiceTest + { + private WellCompositeOperationService service; + + private ICrudRepository wellSectionTypeRepository + = Substitute.For>(); + private IWellOperationCategoryRepository wellOperationCategoryRepository + = Substitute.For(); + private IWellOperationRepository wellOperationRepository + = Substitute.For(); + + + + private readonly static IEnumerable operationCategories = new List() + { + new(){Id = 5096, Name = "Шаблонирование перед спуском"}, + new(){Id = 5008, Name = "Шаблонировка во время бурения"}, + new(){Id = 5013, Name = "Подъем КНБК"}, + new(){Id = 5003, Name = "Бурение ротором"}, + new(){Id = 5036, Name = "Промывка"}, + new(){Id = 5012, Name = "Подъем инструмента"}, + new(){Id = 5083, Name = "Проработка принудительная"}, + }; + + private readonly static IEnumerable sectionTypes = new List() + { + new() {Id = 2, Caption = "Направление", Order = 0}, + new() {Id = 3, Caption = "Кондуктор", Order = 1}, + new() {Id = 31, Caption = "Техническая колонна", Order = 2} + }; + + private readonly static IEnumerable wellOperations1 = new List() + { + new WellOperationDataDto() + { + DepthStart = 50, + DurationHours = 1, + IdCategory = 5096, + IdWell = 55, + IdWellSectionType = 2, + OperationCategoryName = "Шаблонирование перед спуском", + WellSectionTypeCaption = "Направление" + }, + new WellOperationDataDto() + { + DepthStart = 84, + DurationHours = 1, + IdCategory = 5008, + IdWell = 64, + IdWellSectionType = 2, + OperationCategoryName = "Шаблонировка во время бурения", + WellSectionTypeCaption = "Направление" + } + }; + + private readonly static IEnumerable wellOperations2 = new List() + { + new WellOperationDataDto() + { + DepthStart = 10, + DurationHours = 1.5, + IdCategory = 5003, + IdWell = 55, + IdWellSectionType = 2, + OperationCategoryName = "Бурение ротором", + WellSectionTypeCaption = "Направление" + }, + new WellOperationDataDto() + { + DepthStart = 20, + DurationHours = 3.5, + IdCategory = 5003, + IdWell = 64, + IdWellSectionType = 2, + OperationCategoryName = "Бурение ротором", + WellSectionTypeCaption = "Направление" + } + }; + + private readonly static IEnumerable wellOperations3 = new List() + { + new WellOperationDataDto() + { + DepthStart = 1372, + DurationHours = 3, + IdCategory = 5036, + IdWell = 55, + IdWellSectionType = 3, + OperationCategoryName = "Промывка", + WellSectionTypeCaption = "Кондуктор" + }, + new WellOperationDataDto() + { + DepthStart = 1435, + DurationHours = 4, + IdCategory = 5036, + IdWell = 64, + IdWellSectionType = 3, + OperationCategoryName = "Промывка", + WellSectionTypeCaption = "Кондуктор" + } + }; + + private readonly static IEnumerable wellOperations4 = new List() + { + new WellOperationDataDto() + { + DepthStart = 1000, + DurationHours = 10, + IdCategory = 5012, + IdWell = 55, + IdWellSectionType = 31, + OperationCategoryName = "Подъем инструмента", + WellSectionTypeCaption = "Техническая колонна" + }, + new WellOperationDataDto() + { + DepthStart = 500, + DurationHours = 5, + IdCategory = 5083, + IdWell = 55, + IdWellSectionType = 31, + OperationCategoryName = "Проработка принудительная", + WellSectionTypeCaption = "Техническая колонна" + }, + new WellOperationDataDto() + { + DepthStart = 600, + DurationHours = 5, + IdCategory = 5083, + IdWell = 64, + IdWellSectionType = 31, + OperationCategoryName = "Проработка принудительная", + WellSectionTypeCaption = "Техническая колонна" + } + }; + + public WellCompositeOperationServiceTest() + { + + wellSectionTypeRepository.GetAllAsync(Arg.Any()) + .Returns(sectionTypes); + + wellOperationCategoryRepository.Get(Arg.Any()) + .Returns(operationCategories); + + service = new WellCompositeOperationService( + wellSectionTypeRepository, + wellOperationCategoryRepository, + wellOperationRepository); + } + + [Fact] + public async Task GetAsync_return_data() + { + // arrange + wellOperationRepository.GetAsync(Arg.Any(), Arg.Any()) + .Returns(wellOperations1); + + var idsWell = new List() { 55, 64 }; + + // act + 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 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(); + Assert.Equal("Подъем КНБК", categoryName); + } + + + [Fact] + public async Task GetAsync_return_data2() + { + // arrange + wellOperationRepository.GetAsync(Arg.Any(), Arg.Any()) + .Returns(wellOperations2); + + var idsWell = new List() { 55, 64 }; + + // act + 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); + } + + [Fact] + public async Task GetAsync_return_data3() + { + // arrange + wellOperationRepository.GetAsync(Arg.Any(), Arg.Any()) + .Returns(wellOperations3); + + var idsWell = new List() { 55, 64 }; + + // act + 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); + } + + [Fact] + public async Task GetAsync_return_data4() + { + // arrange + wellOperationRepository.GetAsync(Arg.Any(), Arg.Any()) + .Returns(wellOperations4); + + var idsWell = new List() { 55, 64 }; + + // act + 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 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(15, compositeWellOperation.DurationHours); + Assert.Equal(500, compositeWellOperation.DepthStart); + } + + [Fact] + public async Task GetAsync_return_data5() + { + // arrange + var wellOperations = new List(); + wellOperations.AddRange(wellOperations1); + wellOperations.AddRange(wellOperations2); + wellOperations.AddRange(wellOperations3); + wellOperations.AddRange(wellOperations4); + + wellOperationRepository.GetAsync(Arg.Any(), Arg.Any()) + .Returns(wellOperations); + + var idsWell = new List() { 55, 64 }; + + // act + var result = await service.GetAsync(idsWell, CancellationToken.None); + + // assert + Assert.Equal(4, result.Count()); + + var lastOperation = result.Last(); + var lastOperationComposite = lastOperation[0]; + Assert.Equal(1372, lastOperationComposite.DepthStart); + } + } +} From a03e9bb7f2a5b223a12d580a6e760cc6f8610323 Mon Sep 17 00:00:00 2001 From: ngfrolov Date: Tue, 12 Mar 2024 17:21:05 +0500 Subject: [PATCH 08/11] WellOperationRequest move copeCtor to WellOperationRequestBase --- AsbCloudApp/Requests/WellOperationRequest.cs | 50 +++++++++++++------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/AsbCloudApp/Requests/WellOperationRequest.cs b/AsbCloudApp/Requests/WellOperationRequest.cs index 89cd6858..3296c4ad 100644 --- a/AsbCloudApp/Requests/WellOperationRequest.cs +++ b/AsbCloudApp/Requests/WellOperationRequest.cs @@ -6,7 +6,7 @@ namespace AsbCloudApp.Requests /// /// параметры для запроса списка операций /// - public class WellOperationRequestBase: RequestBase + public class WellOperationRequestBase : RequestBase { /// /// фильтр по дате начала операции @@ -42,12 +42,40 @@ namespace AsbCloudApp.Requests /// фильтр по списку id конструкций секции /// public IEnumerable? SectionTypeIds { get; set; } + + /// + /// Параметры для запроса списка операций. + /// Базовый конструктор + /// + public WellOperationRequestBase() + { } + + /// + /// Параметры для запроса списка операций. + /// Копирующий конструктор + /// + /// + public WellOperationRequestBase(WellOperationRequestBase request) + { + GeDepth = request.GeDepth; + LeDepth = request.LeDepth; + GeDate = request.GeDate; + LtDate = request.LtDate; + + OperationCategoryIds = request.OperationCategoryIds; + OperationType = request.OperationType; + SectionTypeIds = request.SectionTypeIds; + + Skip = request.Skip; + Take = request.Take; + SortFields = request.SortFields; + } } /// /// Параметры для запроса списка операций (с id скважины) /// - public class WellOperationRequest: WellOperationRequestBase + public class WellOperationRequest : WellOperationRequestBase { /// /// id скважины @@ -57,7 +85,7 @@ namespace AsbCloudApp.Requests /// /// ctor /// - public WellOperationRequest(){} + public WellOperationRequest() { } /// /// копирующий конструктор @@ -65,21 +93,9 @@ namespace AsbCloudApp.Requests /// /// public WellOperationRequest(WellOperationRequestBase request, int idWell) + :base(request) { - this.IdWell = idWell; - - this.GeDepth = request.GeDepth; - this.LeDepth = request.LeDepth; - this.GeDate = request.GeDate; - this.LtDate = request.LtDate; - - this.OperationCategoryIds = request.OperationCategoryIds; - this.OperationType = request.OperationType; - this.SectionTypeIds = request.SectionTypeIds; - - this.Skip= request.Skip; - this.Take= request.Take; - this.SortFields = request.SortFields; + IdWell = idWell; } } From fc2589b5a25205f8537a2072c06964e17f043aa7 Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Wed, 13 Mar 2024 09:52:21 +0500 Subject: [PATCH 09/11] =?UTF-8?q?fix=20=D0=BE=D0=BF=D1=80=D0=B5=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BE=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D0=B8,=20=D0=BA=D0=BE=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=B0=D1=8F=20=D0=B4=D0=BE=D0=BB=D0=B6=D0=BD=D0=B0=20=D0=B2?= =?UTF-8?q?=D0=BE=D0=B9=D1=82=D0=B8=20=D0=B2=20=D0=BA=D0=BE=D0=BC=D0=BF?= =?UTF-8?q?=D0=BE=D0=B7=D0=B8=D1=82=D0=BD=D1=83=D1=8E=20=D0=BE=D0=BF=D0=B5?= =?UTF-8?q?=D1=80=D0=B0=D1=86=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/WellCompositeOperationService.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs b/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs index 3a02b6b2..4730352d 100644 --- a/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs +++ b/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs @@ -179,9 +179,9 @@ namespace AsbCloudInfrastructure.Services WellSectionTypeCaption = g.First().WellSectionTypeCaption, }); - var composite = aggreagtedByWell.GroupBy(g => g.DurationHours).Count() == 1 - ? aggreagtedByWell.OrderByDescending(o => o.DepthStart).First() - : aggreagtedByWell.OrderBy(o => o.DepthStart).First(); + var composite = aggreagtedByWell.OrderBy(o => o.DurationHours). + ThenByDescending(o => o.DepthStart) + .First(); composite.IdWell = 0; if (compositeDepth > composite.DepthStart) From fa9095b2f0e9a4e21e83be9a4560dc7923789109 Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Wed, 13 Mar 2024 14:30:54 +0500 Subject: [PATCH 10/11] =?UTF-8?q?=D0=9A=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D1=82=D0=B0=D1=80=D0=B8=D0=B8=20=D0=BA=20=D0=B0=D0=B2=D1=82?= =?UTF-8?q?=D0=BE=D1=82=D0=B5=D1=81=D1=82=D0=B0=D0=BC=20+=20=D0=BF=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=D0=B3=D1=80=D1=83=D0=B7=D0=BA=D0=B0=20=D0=BC=D0=B5?= =?UTF-8?q?=D1=82=D0=BE=D0=B4=D0=B0=20BuildQuery?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Repository/WellOperationRepository.cs | 61 ++++++++++++++----- .../WellCompositeOperationServiceTest.cs | 48 +++++++++++++-- 2 files changed, 88 insertions(+), 21 deletions(-) diff --git a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs index be039c86..aa0d28ce 100644 --- a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs +++ b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs @@ -209,24 +209,10 @@ public class WellOperationRepository : IWellOperationRepository WellsOperationRequest request, CancellationToken token) { - var query = db.WellOperations - .Where(o => request.IdsWell.Contains(o.IdWell)) - .Where(o => request.IdType == o.IdType) - .Where(o => request.SectionTypeIds != null ? request.SectionTypeIds.Contains(o.IdWellSectionType) : true) - .Where(o => request.OperationCategoryIds != null ? request.OperationCategoryIds.Contains(o.IdCategory) : true) - .Select(o => new WellOperationDataDto(){ - DepthStart = o.DepthStart, - DurationHours = o.DurationHours, - IdCategory = o.IdCategory, - IdWell = o.IdWell, - IdWellSectionType = o.IdWellSectionType, - OperationCategoryName = o.OperationCategory.Name, - WellSectionTypeCaption = o.WellSectionType.Caption, - }) - .AsNoTracking(); + var query = BuildQuery(request) + .AsNoTracking(); var dtos = await query.ToArrayAsync(token); - return dtos; } @@ -497,6 +483,49 @@ public class WellOperationRepository : IWellOperationRepository return dtos.AsNoTracking(); } + /// + /// Получение данных по запросу + /// + /// + /// + /// + private IQueryable BuildQuery(WellsOperationRequest request) + { + var query = db.WellOperations + .Where(o => request.IdsWell.Contains(o.IdWell)) + .Where(o => request.IdType == o.IdType); + + if (request.SectionTypeIds?.Any() == true) + query = query.Where(o => request.SectionTypeIds.Contains(o.IdWellSectionType)); + + if (request.OperationCategoryIds?.Any() == true) + query = query.Where(o => request.OperationCategoryIds.Contains(o.IdCategory)); + + var dtos = query.Select(o => new WellOperationDataDto + { + DepthStart = o.DepthStart, + DurationHours = o.DurationHours, + IdCategory = o.IdCategory, + IdWell = o.IdWell, + IdWellSectionType = o.IdWellSectionType, + OperationCategoryName = o.OperationCategory.Name, + WellSectionTypeCaption = o.WellSectionType.Caption, + }); + + if (request.SortFields?.Any() == true) + { + dtos = dtos.SortBy(request.SortFields); + } + + if (request.Skip.HasValue) + dtos = dtos.Skip(request.Skip.Value); + + if (request.Take.HasValue) + dtos = dtos.Take(request.Take.Value); + + return dtos.AsNoTracking(); + } + private WellOperationDto Convert(WellOperationDto dto) { var timezone = wellService.GetTimezone(dto.IdWell); diff --git a/AsbCloudWebApi.Tests/Services/WellCompositeOperation/WellCompositeOperationServiceTest.cs b/AsbCloudWebApi.Tests/Services/WellCompositeOperation/WellCompositeOperationServiceTest.cs index eece10e8..d4659d8a 100644 --- a/AsbCloudWebApi.Tests/Services/WellCompositeOperation/WellCompositeOperationServiceTest.cs +++ b/AsbCloudWebApi.Tests/Services/WellCompositeOperation/WellCompositeOperationServiceTest.cs @@ -171,8 +171,14 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation wellOperationRepository); } + /// + /// На вход подаются 2 операции с одинаковыми секциями (id = 2), но разными категориями (ids = 5096, 5008) и ключами скважин (ids = 55, 64) + /// Метод возвращает список из одной операции в разрезе 3-х скважин: 2 текущие скважины и одна композитная + /// Операция должна иметь категорию 5013 для всех трех скважин + /// + /// [Fact] - public async Task GetAsync_return_data() + public async Task GetAsync_return_composite_and_others_with_category_5013() { // arrange wellOperationRepository.GetAsync(Arg.Any(), Arg.Any()) @@ -200,9 +206,14 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation Assert.Equal("Подъем КНБК", categoryName); } - + /// + /// На вход подаются 2 операции с одинаковыми секциями (id = 2) и категориями (id = 5003), но разными ключами скважин (ids = 55, 64) + /// Метод возвращает список из одной операции в разрезе 3-х скважин: 2 текущие скважины и одна композитная + /// Операция композитной скважины должна содержать данные той операции, которая содержит минимальный duration_hours + /// + /// [Fact] - public async Task GetAsync_return_data2() + public async Task GetAsync_return_composite_with_minimum_depth_start() { // arrange wellOperationRepository.GetAsync(Arg.Any(), Arg.Any()) @@ -221,6 +232,12 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation Assert.Equal(10, compositeWellOperation.DepthStart); } + /// + /// На вход подаются 2 операции с одинаковыми секциями (id = 3) и категориями (id = 5036), но разными ключами скважин (ids = 55, 64) + /// Метод возвращает список из одной операции в разрезе 3-х скважин: 2 текущие скважины и одна композитная + /// Операция композитной скважины должна содержать данные той операции, которая содержит минимальный duration_hours + /// + /// [Fact] public async Task GetAsync_return_data3() { @@ -241,6 +258,16 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation Assert.Equal(1372, compositeWellOperation.DepthStart); } + /// + /// На вход подаются 3 операции с одинаковыми секциями (id = 31), но разными категориями (ids = 5012, 5083) и ключами скважин (ids = 55, 64) + /// Метод возвращает список из одной операции в разрезе 3-х скважин: 2 текущие скважины и одна композитная + /// Операция композитной скважины должна содержать: + /// данные той операции, которая содержит минимальный duration_hours + /// категорию с ключом 5013 + /// Операции по скважине с ключом 55 должны объединиться в одну, + /// при этом их длительность складывается, а depth_start берется минимальный из двух + /// + /// [Fact] public async Task GetAsync_return_data4() { @@ -260,16 +287,27 @@ namespace AsbCloudWebApi.Tests.Services.WellCompositeOperation 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(15, compositeWellOperation.DurationHours); - Assert.Equal(500, compositeWellOperation.DepthStart); + Assert.Equal(5, compositeWellOperation.DurationHours); + Assert.Equal(600, compositeWellOperation.DepthStart); } + /// + /// На вход подаются список разных операций с разными ключами скважин (ids = 55, 64) + /// Метод возвращает список из 4-х операций в разрезе 3-х скважин: 2 текущие скважины и одна композитная + /// Операция композитной скважины должна содержать глубину забоя = 1372 + /// + /// [Fact] public async Task GetAsync_return_data5() { From a91fc4f213f904e75ef36efc342db0289af17e7a Mon Sep 17 00:00:00 2001 From: ngfrolov Date: Wed, 13 Mar 2024 16:04:49 +0500 Subject: [PATCH 11/11] =?UTF-8?q?WellsOperationRequest.IdType=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=20=D0=BD=D0=B0=20WellOpera?= =?UTF-8?q?tionRequestBase.OperationType.=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D1=8B=20=D1=82=D1=83=D0=B4=D1=83=D1=88=D0=BA?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AsbCloudApp/Requests/WellOperationRequest.cs | 5 ----- AsbCloudInfrastructure/Repository/WellOperationRepository.cs | 5 +++-- .../Services/WellCompositeOperationService.cs | 5 ++--- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/AsbCloudApp/Requests/WellOperationRequest.cs b/AsbCloudApp/Requests/WellOperationRequest.cs index 3296c4ad..1d190018 100644 --- a/AsbCloudApp/Requests/WellOperationRequest.cs +++ b/AsbCloudApp/Requests/WellOperationRequest.cs @@ -108,10 +108,5 @@ namespace AsbCloudApp.Requests /// ids скважин /// public IEnumerable IdsWell { get; set; } = null!; - - /// - /// Тип 0 = План или 1 = Факт - /// - public int IdType { get; set; } } } diff --git a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs index aa0d28ce..329d2502 100644 --- a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs +++ b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs @@ -396,7 +396,6 @@ public class WellOperationRepository : IWellOperationRepository .Include(s => s.OperationCategory) .Where(o => o.IdWell == request.IdWell); - if (request.OperationType.HasValue) query = query.Where(e => e.IdType == request.OperationType.Value); @@ -431,6 +430,7 @@ public class WellOperationRepository : IWellOperationRepository .Where(subOp => subOp.IdType == 1) .Where(subOp => WellOperationCategory.NonProductiveTimeSubIds.Contains(subOp.IdCategory)); + // TODO: Вынести query.Select из метода BuildQuery var dtos = query.Select(o => new WellOperationDto { Id = o.Id, @@ -493,7 +493,7 @@ public class WellOperationRepository : IWellOperationRepository { var query = db.WellOperations .Where(o => request.IdsWell.Contains(o.IdWell)) - .Where(o => request.IdType == o.IdType); + .Where(o => request.OperationType == o.IdType); if (request.SectionTypeIds?.Any() == true) query = query.Where(o => request.SectionTypeIds.Contains(o.IdWellSectionType)); @@ -501,6 +501,7 @@ public class WellOperationRepository : IWellOperationRepository if (request.OperationCategoryIds?.Any() == true) query = query.Where(o => request.OperationCategoryIds.Contains(o.IdCategory)); + // TODO: Вынести query.Select из метода BuildQuery var dtos = query.Select(o => new WellOperationDataDto { DepthStart = o.DepthStart, diff --git a/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs b/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs index 4730352d..6ba97ea0 100644 --- a/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs +++ b/AsbCloudInfrastructure/Services/WellCompositeOperationService.cs @@ -149,7 +149,7 @@ namespace AsbCloudInfrastructure.Services IdsWell = idsWells, OperationCategoryIds = usedCategories, SectionTypeIds = idsWellSectionTypes, - IdType = WellOperation.IdOperationTypeFact + OperationType = WellOperation.IdOperationTypeFact }; var operations = await wellOperationRepository.GetAsync(wellOperationRequest, token); @@ -189,7 +189,6 @@ namespace AsbCloudInfrastructure.Services compositeDepth = composite.DepthStart; - var resultItem = aggreagtedByWell.ToDictionary(o => o.IdWell); resultItem.Add(0, composite); @@ -198,7 +197,7 @@ namespace AsbCloudInfrastructure.Services return wellOperationsWithComposite; } - private WellOperationDataDto UpdateIdWellSectionAndIdCategory( + private static WellOperationDataDto UpdateIdWellSectionAndIdCategory( WellOperationDataDto dto, Dictionary sectionTypes, Dictionary operationCategories)