From 312d653aec96e14799a4f9eb19b429274435cd18 Mon Sep 17 00:00:00 2001 From: ngfrolov Date: Fri, 7 Apr 2023 16:49:28 +0500 Subject: [PATCH] fix #9844930; Enable nullable for OperationsStatService. --- .../Services/IOperationsStatService.cs | 6 +- .../Services/SAUB/TelemetryDataSaubService.cs | 2 +- .../OperationsStatService.cs | 178 +++++++++--------- .../Services/WellOperationService/Race.cs | 3 +- .../Controllers/OperationStatController.cs | 10 +- .../Controllers/WellOperationController.cs | 2 +- AsbCloudWebApi/Rest/OperationStat.http | 46 +++++ 7 files changed, 147 insertions(+), 100 deletions(-) create mode 100644 AsbCloudWebApi/Rest/OperationStat.http diff --git a/AsbCloudApp/Services/IOperationsStatService.cs b/AsbCloudApp/Services/IOperationsStatService.cs index 6ceb76e1..a92d0553 100644 --- a/AsbCloudApp/Services/IOperationsStatService.cs +++ b/AsbCloudApp/Services/IOperationsStatService.cs @@ -16,7 +16,7 @@ namespace AsbCloudApp.Services /// /// /// - Task GetRopStatAsync(int idWell, CancellationToken token); + Task GetOrDefaultRopStatAsync(int idWell, CancellationToken token); /// /// Получить статистику по скважинам куста, которые доступны компании @@ -25,7 +25,7 @@ namespace AsbCloudApp.Services /// /// /// - Task GetStatClusterAsync(int idCluster, int idCompany, CancellationToken token = default); + Task GetOrDefaultStatClusterAsync(int idCluster, int idCompany, CancellationToken token); /// /// получить статистику по скважине @@ -33,7 +33,7 @@ namespace AsbCloudApp.Services /// /// /// - Task GetWellStatAsync(int idWell, CancellationToken token = default); + Task GetOrDefaultWellStatAsync(int idWell, CancellationToken token); /// /// Получить данные для графика TVD diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs index ddebda4b..af16e2a1 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs @@ -43,7 +43,7 @@ namespace AsbCloudInfrastructure.Services.SAUB .Where(t => t.BlockPosition > 0.0001) .Where(t => t.WellDepth > 0.0001) .Where(t => t.Mode != null) - .Where(t => modes.Contains(t.Mode.Value)) + .Where(t => modes.Contains(t.Mode!.Value)) .Where(t => t.WellDepth - t.BitDepth < 0.01) .GroupBy(t => new { t.DateTime.Hour, diff --git a/AsbCloudInfrastructure/Services/WellOperationService/OperationsStatService.cs b/AsbCloudInfrastructure/Services/WellOperationService/OperationsStatService.cs index 1e1dd035..68368e63 100644 --- a/AsbCloudInfrastructure/Services/WellOperationService/OperationsStatService.cs +++ b/AsbCloudInfrastructure/Services/WellOperationService/OperationsStatService.cs @@ -7,12 +7,12 @@ using Microsoft.Extensions.Caching.Memory; using System; using System.Collections.Generic; using System.Linq; -using System.Numerics; using System.Threading; using System.Threading.Tasks; namespace AsbCloudInfrastructure.Services.WellOperationService { +#nullable enable public class OperationsStatService : IOperationsStatService { private readonly IAsbCloudDbContext db; @@ -26,8 +26,15 @@ namespace AsbCloudInfrastructure.Services.WellOperationService this.wellService = wellService; } - public async Task GetStatClusterAsync(int idCluster, int idCompany, CancellationToken token = default) + public async Task GetOrDefaultStatClusterAsync(int idCluster, int idCompany, CancellationToken token) { + var cluster = (await memoryCache + .GetOrCreateBasicAsync(db.Set(), token)) + .FirstOrDefault(c => c.Id == idCluster); + + if (cluster is null) + return null; + var allWellsByCompany = await wellService.GetAsync(new() { IdCompany = idCompany }, token).ConfigureAwait(false); var idWellsByCompany = allWellsByCompany.Select(w => w.Id).Distinct(); @@ -41,9 +48,6 @@ namespace AsbCloudInfrastructure.Services.WellOperationService var statsWells = await GetWellsStatAsync(wells, token).ConfigureAwait(false); - var cluster = (await memoryCache - .GetOrCreateBasicAsync(db.Set(), token)) - .FirstOrDefault(c => c.Id == idCluster); var statClusterDto = new StatClusterDto { Id = idCluster, @@ -71,7 +75,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService return statsWells; } - public async Task GetWellStatAsync(int idWell, + public async Task GetOrDefaultWellStatAsync(int idWell, CancellationToken token = default) { var well = await db.Wells @@ -79,11 +83,14 @@ namespace AsbCloudInfrastructure.Services.WellOperationService .FirstOrDefaultAsync(w => w.Id == idWell, token) .ConfigureAwait(false); + if(well is null) + return null; + var statWellDto = await CalcWellStatAsync(well, token); return statWellDto; } - public async Task GetRopStatAsync(int idWell, CancellationToken token) + public async Task GetOrDefaultRopStatAsync(int idWell, CancellationToken token) { var clusterWellsIds = await wellService.GetClusterWellsIdsAsync(idWell, token) .ConfigureAwait(false); @@ -110,13 +117,15 @@ namespace AsbCloudInfrastructure.Services.WellOperationService .ToListAsync(token) .ConfigureAwait(false); - var statsList = clusterWellsIds.Select(clusterWellId => + var statsList = new List(clusterWellsIds.Count()); + foreach (var clusterWellId in clusterWellsIds) { var currentWellOps = operations.Where(o => o.IdWell == clusterWellId); - var timezoneOffsetH = wellService.GetTimezone(clusterWellId).Hours; - var stat = CalcStat(currentWellOps, timezoneOffsetH); - return stat; - }).Where(c => c is not null); + var timezoneOffsetHours = wellService.GetTimezone(clusterWellId).Hours; + var stat = CalcStat(currentWellOps, timezoneOffsetHours); + if(stat is not null) + statsList.Add(stat); + }; if (!statsList.Any()) return null; @@ -130,7 +139,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService return clusterRops; } - private async Task CalcWellStatAsync(Well well, CancellationToken token = default) + private async Task CalcWellStatAsync(Well well, CancellationToken token) { var wellType = (await memoryCache .GetOrCreateBasicAsync(db.Set(), token)) @@ -164,7 +173,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService return statWellDto; } - private double CalcTvdLagDays(IOrderedEnumerable wellOperations) + private static double CalcTvdLagDays(IOrderedEnumerable wellOperations) { var operationsOrdered = wellOperations .OrderBy(o => o.DateStart); @@ -178,9 +187,13 @@ namespace AsbCloudInfrastructure.Services.WellOperationService if (lastCorrespondingFactOperation is null) return 0d; - var lastCorrespondingPlanOperation = wellOperations.FirstOrDefault(o => o.Id == lastCorrespondingFactOperation.IdPlan); + var lastCorrespondingPlanOperation = wellOperations + .FirstOrDefault(o => o.Id == lastCorrespondingFactOperation.IdPlan); - var lastFactOperation = factOperations.LastOrDefault(); + if (lastCorrespondingPlanOperation is null) + return 0d; + + var lastFactOperation = factOperations.Last(); var remainingPlanOperations = operationsOrdered .Where(o => o.IdType == WellOperation.IdOperationTypePlan) @@ -240,27 +253,27 @@ namespace AsbCloudInfrastructure.Services.WellOperationService return section; } - private static StatOperationsDto CalcSectionStat(IEnumerable operations, int idSectionType, double timezoneOffsetH) + private static StatOperationsDto? CalcSectionStat(IEnumerable operations, int idSectionType, double timezoneOffsetHours) { var sectionOperations = operations .Where(o => o.IdWellSectionType == idSectionType) .OrderBy(o => o.DateStart) .ThenBy(o => o.DepthStart); - return CalcStat(sectionOperations, timezoneOffsetH); + return CalcStat(sectionOperations, timezoneOffsetHours); } - private static StatOperationsDto CalcStat(IEnumerable operations, double timezoneOffsetH) + private static StatOperationsDto? CalcStat(IEnumerable operations, double timezoneOffsetHours) { if (!operations.Any()) return null; - var races = GetCompleteRaces(operations, timezoneOffsetH); + var races = GetCompleteRaces(operations, timezoneOffsetHours); var section = new StatOperationsDto { - Start = operations.FirstOrDefault()?.DateStart.ToRemoteDateTime(timezoneOffsetH), - End = operations.Max(o => o.DateStart.ToRemoteDateTime(timezoneOffsetH).AddHours(o.DurationHours)), + Start = operations.FirstOrDefault()?.DateStart.ToRemoteDateTime(timezoneOffsetHours), + End = operations.Max(o => o.DateStart.ToRemoteDateTime(timezoneOffsetHours).AddHours(o.DurationHours)), WellDepthStart = operations.Min(o => o.DepthStart), WellDepthEnd = operations.Max(o => o.DepthStart), Rop = CalcROP(operations), @@ -356,7 +369,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService { var dDepth = 0d; var dHours = 0d; - foreach (var race in races) + foreach (Race race in races) { dDepth += race.StartWellDepth; for (var i = 0; i < race.Operations.Count; i++) @@ -417,78 +430,71 @@ namespace AsbCloudInfrastructure.Services.WellOperationService var tzOffsetHours = wellService.GetTimezone(idWell).Hours; - if (!wellOperationsPlan.Any()) - return null; - - var merged = MergeArraysBySections(sectionsIds, wellOperationsPlan, wellOperationsFact); + var merged = MergeArraysBySections(sectionsIds, wellOperationsPlan, wellOperationsFact).ToList(); var tvd = new List>(merged.Count); - var firstPoint = merged.First(); - var dateStart = firstPoint.Item1?.DateStart ?? firstPoint.Item2.DateStart; - int iLastMatch = 0; + var (Plan, Fact) = merged.First(); + var dateStart = Plan?.DateStart ?? Fact!.DateStart; + int? iLastMatch = null; int iLastFact = 0; var nptHours = 0d; for (int i = 0; i < merged.Count; i++) { var item = merged[i]; - var plan = item.Item1; - var fact = item.Item2; + var plan = item.Plan; + var fact = item.Fact; - if (fact is not null && WellOperationCategory.NonProductiveTimeSubIds.Contains(fact.IdCategory)) + var planFactPredict = new PlanFactPredictBase(); + if (plan is not null) { - nptHours += fact.DurationHours; + planFactPredict.Plan = Convert(plan, tzOffsetHours); + planFactPredict.Plan.Day = (planFactPredict.Plan.DateStart - dateStart).TotalDays; + if (fact is not null) + iLastMatch = i; } - var planFactPredict = new PlanFactPredictBase + if (fact is not null) { - Plan = Convert(plan, tzOffsetHours), - Fact = Convert(fact, tzOffsetHours), - Predict = null, - }; + if(WellOperationCategory.NonProductiveTimeSubIds.Contains(fact.IdCategory)) + nptHours += fact.DurationHours; - if (planFactPredict.Plan is not null) - planFactPredict.Plan.Day = (planFactPredict.Plan.DateStart - dateStart).TotalDays; - - if (planFactPredict.Fact is not null) - { + planFactPredict.Fact = Convert(fact, tzOffsetHours); planFactPredict.Fact.Day = (planFactPredict.Fact.DateStart - dateStart).TotalDays; planFactPredict.Fact.NptHours = nptHours; + iLastFact = i; } - tvd.Add(planFactPredict); - if ((plan is not null) && (fact is not null)) - iLastMatch = i; - if (fact is not null) - iLastFact = i; + tvd.Add(planFactPredict); } - if (iLastMatch == 0 || iLastMatch == merged.Count - 1) + if (iLastMatch is null || iLastMatch == merged.Count - 1) return tvd; - var lastMatchPlan = merged[iLastMatch].Item1; + var lastMatchPlan = merged[iLastMatch.Value].Plan!; var lastMatchPlanOperationEnd = lastMatchPlan.DateStart.AddHours(lastMatchPlan.DurationHours); - var lastFact = merged[iLastFact].Item2; + var lastFact = merged[iLastFact].Fact!; var lastFactDateEnd = lastFact.DateStart.AddHours(lastFact.DurationHours); var startOffset = lastFactDateEnd - lastMatchPlanOperationEnd; - for (int i = iLastMatch + 1; i < merged.Count; i++) + for (int i = iLastMatch.Value + 1; i < merged.Count; i++) { - if (merged[i].Item1 is null) + if (merged[i].Plan is null) continue; - tvd[i].Predict = Convert(merged[i].Item1, tzOffsetHours); - tvd[i].Predict.IdType = 2; - tvd[i].Predict.DateStart = tvd[i].Predict.DateStart + startOffset; - tvd[i].Predict.Day = (tvd[i].Predict.DateStart - dateStart).TotalDays; + var predict = Convert(merged[i].Plan!, tzOffsetHours); + predict.IdType = 2; + predict.DateStart = predict.DateStart + startOffset; + predict.Day = (predict.DateStart - dateStart).TotalDays; + tvd[i].Predict = predict; } return tvd; } - private static List> MergeArraysBySections( + private static IEnumerable<(WellOperation? Plan, WellOperation? Fact)> MergeArraysBySections( IEnumerable sectionsIds, IOrderedEnumerable wellOperationsPlan, IOrderedEnumerable wellOperationsFact) { - var merged = new List>(wellOperationsPlan.Count()); + var merged = new List<(WellOperation? Plan, WellOperation? Fact)>(wellOperationsPlan.Count()); foreach (var sectionId in sectionsIds) { var sectionOperationsPlan = wellOperationsPlan @@ -501,46 +507,38 @@ namespace AsbCloudInfrastructure.Services.WellOperationService return merged; } - private static List> MergeArrays(IEnumerable operationsPlan, IEnumerable operationsFact) + private static IEnumerable<(WellOperation? Plan, WellOperation? Fact)> MergeArrays(IEnumerable operationsPlan, IEnumerable operationsFact) { - var result = new List>(); + var operationsFactWithNoPlan = operationsFact.Where(x => x.IdPlan == null).ToArray(); + var operationsFactWithPlan = operationsFact.Where(x => x.IdPlan != null).ToArray(); - var oparationsFactWithNoPlan = operationsFact - .Where(x => x.IdPlan == null) - .Select(x => new Tuple(null, x)); + var idsPlanWithFact = operationsFact.Where(x => x.IdPlan is not null).Select(x => x.IdPlan).Distinct(); + var operationsPlanWithNoFact = operationsPlan.Where(x => !idsPlanWithFact.Contains(x.IdPlan)).ToArray(); - var oparationsFactWithPlan = operationsFact - .Where(x => x.IdPlan != null) - .Select(x => new Tuple(x.OperationPlan, x)); + var result = new List<(WellOperation? Plan, WellOperation? Fact)>(operationsFactWithNoPlan.Length + operationsFactWithPlan.Length + operationsPlanWithNoFact.Length); - var idsPlanWithFact = operationsFact - .Where(x => x.IdPlan is not null) - .Select(x => x.IdPlan) - .Distinct(); - var oparationsPlanWithNoFact = operationsPlan - .Where(x => !idsPlanWithFact.Contains(x.IdPlan)) - .Select(x => new Tuple(x, null)); + foreach (var operation in operationsFactWithPlan) + result.Add((operation.OperationPlan, operation)); - result.AddRange(oparationsFactWithNoPlan); - result.AddRange(oparationsFactWithPlan); - result.AddRange(oparationsPlanWithNoFact); + foreach (var operation in operationsFactWithNoPlan) + result.Add((null, operation)); - result = result - .OrderBy(x => x.Item1?.DateStart) - .ThenBy(x => x.Item2?.DateStart) - .ToList(); - return result; + foreach (var operation in operationsPlanWithNoFact) + result.Add((operation, null)); + + return result + .OrderBy(x => x.Plan?.DateStart) + .ThenBy(x => x.Fact?.DateStart); } private static WellOperationDto Convert(WellOperation source, double tzOffsetHours) { - if (source is null) - return null; - var dest = source.Adapt(); - dest.CategoryName = source.OperationCategory?.Name; - dest.WellSectionTypeName = source.WellSectionType?.Caption; - dest.DateStart = source.DateStart.ToRemoteDateTime(tzOffsetHours); - return dest; + var destination = source.Adapt(); + destination.CategoryName = source.OperationCategory?.Name; + destination.WellSectionTypeName = source.WellSectionType?.Caption; + destination.DateStart = source.DateStart.ToRemoteDateTime(tzOffsetHours); + return destination; } } +#nullable disable } diff --git a/AsbCloudInfrastructure/Services/WellOperationService/Race.cs b/AsbCloudInfrastructure/Services/WellOperationService/Race.cs index e279111d..182ac88d 100644 --- a/AsbCloudInfrastructure/Services/WellOperationService/Race.cs +++ b/AsbCloudInfrastructure/Services/WellOperationService/Race.cs @@ -1,6 +1,7 @@ using AsbCloudDb.Model; using System; using System.Collections.Generic; +using System.Linq; namespace AsbCloudInfrastructure.Services.WellOperationService { @@ -60,7 +61,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService /// /// Список операций за рейс /// - public List? Operations { get; internal set; } + public List Operations { get; internal set; } = new List(); } #nullable disable } diff --git a/AsbCloudWebApi/Controllers/OperationStatController.cs b/AsbCloudWebApi/Controllers/OperationStatController.cs index cce509fb..d32ea4b7 100644 --- a/AsbCloudWebApi/Controllers/OperationStatController.cs +++ b/AsbCloudWebApi/Controllers/OperationStatController.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; namespace AsbCloudWebApi.Controllers { +#nullable enable /// /// Статистика по операциям (заведенным вручную) на скважине /// @@ -41,7 +42,7 @@ namespace AsbCloudWebApi.Controllers if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false)) return Forbid(); - var result = await operationsStatService.GetRopStatAsync( + var result = await operationsStatService.GetOrDefaultRopStatAsync( idWell, token).ConfigureAwait(false); return Ok(result); @@ -64,7 +65,7 @@ namespace AsbCloudWebApi.Controllers if (idWell is null) return NoContent(); - var result = await operationsStatService.GetRopStatAsync( + var result = await operationsStatService.GetOrDefaultRopStatAsync( (int)idWell, token).ConfigureAwait(false); return Ok(result); @@ -87,7 +88,7 @@ namespace AsbCloudWebApi.Controllers if (idCompany is null) return Forbid(); - var result = await operationsStatService.GetStatClusterAsync(idCluster, idCompany.Value, token) + var result = await operationsStatService.GetOrDefaultStatClusterAsync(idCluster, idCompany.Value, token) .ConfigureAwait(false); return Ok(result); } @@ -132,7 +133,7 @@ namespace AsbCloudWebApi.Controllers if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false)) return Forbid(); - var result = await operationsStatService.GetWellStatAsync(idWell, token) + var result = await operationsStatService.GetOrDefaultWellStatAsync(idWell, token) .ConfigureAwait(false); return Ok(result); } @@ -165,4 +166,5 @@ namespace AsbCloudWebApi.Controllers idWell, token).ConfigureAwait(false); } } +#nullable disable } diff --git a/AsbCloudWebApi/Controllers/WellOperationController.cs b/AsbCloudWebApi/Controllers/WellOperationController.cs index ae1943a6..c5174f2c 100644 --- a/AsbCloudWebApi/Controllers/WellOperationController.cs +++ b/AsbCloudWebApi/Controllers/WellOperationController.cs @@ -378,7 +378,7 @@ namespace AsbCloudWebApi.Controllers [Route("template")] [AllowAnonymous] [ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK)] - public IActionResult GetTamplate() + public IActionResult GetTemplate() { var stream = wellOperationImportService.GetExcelTemplateStream(); var fileName = "ЕЦП_шаблон_файла_операций.xlsx"; diff --git a/AsbCloudWebApi/Rest/OperationStat.http b/AsbCloudWebApi/Rest/OperationStat.http new file mode 100644 index 00000000..975f54b5 --- /dev/null +++ b/AsbCloudWebApi/Rest/OperationStat.http @@ -0,0 +1,46 @@ +@baseUrl = http://127.0.0.1:5000 +@contentType = application/json +@auth = Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImN0eSI6IkpXVCJ9.eyJpZCI6IjEiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiZGV2IiwiaWRDb21wYW55IjoiMSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6InJvb3QiLCJuYmYiOjE2NjI1NDgxNjIsImV4cCI6MTY5NDEwNTc2MiwiaXNzIjoiYSIsImF1ZCI6ImEifQ.OEAlNzxi7Jat6pzDBTAjTbChskc-tdJthJexyWwwUKE + +@uid = 20210910_012752700 +@idCluster = 1 +@idWell = 1 +#295 + +# https://marketplace.visualstudio.com/items?itemName=humao.rest-client + +### +GET {{baseUrl}}/api/well/{{idWell}}/ropStat +Content-Type: {{contentType}} +accept: */* +Authorization: {{auth}} + +### +GET {{baseUrl}}/api/telemetry/{{uid}}/ropStat +Content-Type: {{contentType}} +accept: */* +Authorization: {{auth}} + +### +GET {{baseUrl}}/api/cluster/{{idCluster}}/stat +Content-Type: {{contentType}} +accept: */* +Authorization: {{auth}} + +### +GET {{baseUrl}}/api/wellsStats?idWells=1&idWells={{idWell}} +Content-Type: {{contentType}} +accept: */* +Authorization: {{auth}} + +### +GET {{baseUrl}}/api/well/{{idWell}}/stat +Content-Type: {{contentType}} +accept: */* +Authorization: {{auth}} + +### +GET {{baseUrl}}/api/well/{{idWell}}/tvd +Content-Type: {{contentType}} +accept: */* +Authorization: {{auth}}