using AsbCloudApp.Data; using AsbCloudApp.Data.WellOperation; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudDb; using AsbCloudDb.Model; using Mapster; using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace AsbCloudInfrastructure.Services.WellOperationService.WellOperationService; public class WellOperationService : IWellOperationService { private readonly IWellService wellService; private readonly IWellOperationRepository wellOperationRepository; private readonly IWellOperationCategoryRepository wellOperationCategoryRepository; public WellOperationService( IWellService wellService, IWellOperationRepository wellOperationRepository, IWellOperationCategoryRepository wellOperationCategoryRepository) { this.wellService = wellService; this.wellOperationRepository = wellOperationRepository; this.wellOperationCategoryRepository = wellOperationCategoryRepository; } public async Task> GetAsync(WellOperationRequest request, CancellationToken token) { var (items, _) = await GetWithDaysAndNpvAsync(request, token); return items; } public async Task> GetPageAsync(WellOperationRequest request, CancellationToken token) { request.Skip = request.Skip ?? 0; request.Take = request.Take ?? 32; var (items, count) = await GetWithDaysAndNpvAsync(request, token); var paginationContainer = new PaginationContainer { Skip = request.Skip!.Value, Take = request.Take!.Value, Count = count, Items = items }; return paginationContainer; } public async Task?> GetPageAsync(int idWell, int id, int operationType, int? take, IEnumerable? sortFields, CancellationToken token) { var request = new WellOperationRequest(new[] { idWell }) { OperationType = operationType, SortFields = sortFields, }; var (wellOperations, count) = await GetWithDaysAndNpvAsync(request, token); var skip = 0; take ??= 32; while (skip < count) { var page = wellOperations.Skip(skip) .Take(take.Value); if (page.Any(x => x.Id == id)) { var paginationContainer = new PaginationContainer { Skip = skip, Take = take.Value, Items = page, Count = count }; return paginationContainer; } skip += take.Value; } return null; } public async Task> GetGroupOperationsStatAsync(WellOperationRequest request, CancellationToken token) { var wellOperationsBaseDto = await wellOperationRepository.GetAll(request, token); var wellOperationsData = wellOperationsBaseDto .Select(o => new { o.IdCategory, DurationMinutes = o.DurationHours * 60, DurationDepth = o.DepthEnd - o.DepthStart }); var parentRelationDictionary = wellOperationCategoryRepository.Get(true) .ToDictionary(c => c.Id, c => new { c.Name, c.IdParent }); var dtos = wellOperationsData .GroupBy(o => o.IdCategory) .Select(g => new WellGroupOpertionDto { IdCategory = g.Key, Category = parentRelationDictionary[g.Key].Name, Count = g.Count(), MinutesAverage = g.Average(o => o.DurationMinutes), MinutesMin = g.Min(o => o.DurationMinutes), MinutesMax = g.Max(o => o.DurationMinutes), TotalMinutes = g.Sum(o => o.DurationMinutes), DeltaDepth = g.Sum(o => o.DurationDepth), IdParent = parentRelationDictionary[g.Key].IdParent }); while (dtos.All(x => x.IdParent != null)) { dtos = dtos .GroupBy(o => o.IdParent!) .Select(g => { var idCategory = g.Key ?? int.MinValue; var category = parentRelationDictionary.GetValueOrDefault(idCategory); var newDto = new WellGroupOpertionDto { IdCategory = idCategory, Category = category?.Name ?? "unknown", Count = g.Sum(o => o.Count), DeltaDepth = g.Sum(o => o.DeltaDepth), TotalMinutes = g.Sum(o => o.TotalMinutes), Items = g.ToList(), IdParent = category?.IdParent, }; return newDto; }); } return dtos; } private async Task<(IEnumerable items, int count)> GetWithDaysAndNpvAsync(WellOperationRequest request, CancellationToken token) { var wellOperationRepositoryRequest = new WellOperationRepositoryRequest(request); var wellOperationsBaseDtos = await wellOperationRepository.GetAll(wellOperationRepositoryRequest, token); var groupedByWellAndTypeDtos = wellOperationsBaseDtos .GroupBy(e => new { e.IdWell, e.IdType }); var result = new List(); var count = 0; foreach (var wellOperationsWithTypeDto in groupedByWellAndTypeDtos) { var firstWellOperation = wellOperationsWithTypeDto.MinBy(e => e.DateStart)!; var operationsWithNpt = wellOperationsWithTypeDto .Where(o => WellOperationCategory.NonProductiveTimeSubIds.Contains(o.IdCategory)); var filteredWellOperations = FilterByRequest(wellOperationsWithTypeDto, request); count += filteredWellOperations.Count(); if (request.Skip != null) filteredWellOperations = filteredWellOperations.Skip((int)request.Skip); if (request.Take != null) filteredWellOperations = filteredWellOperations.Take((int)request.Take); var timezoneOffset = wellService.GetTimezone(wellOperationsWithTypeDto.Key.IdWell).Offset; var dtos = filteredWellOperations .Select(dto => { var newDto = dto.Adapt(); newDto.Day = (dto.DateStart - firstWellOperation.DateStart).TotalDays; newDto.NptHours = operationsWithNpt .Where(o => o.DateStart <= dto.DateStart) .Sum(e => e.DurationHours); return newDto; }); result.AddRange(dtos); } return (result, count); } private async Task> GetOperationsAsync(int idWell, CancellationToken token) { var request = new WellOperationRequest(new int[] { idWell }); var (items, _) = await GetWithDaysAndNpvAsync(request, token); var operationsFactWithNoPlan = items.Where(o => o.IdPlan == null && o.IdType == WellOperation.IdOperationTypeFact); var operationsFactWithPlan = items.Where(o => o.IdPlan != null && o.IdType == WellOperation.IdOperationTypeFact); var idsPlanWithFact = operationsFactWithPlan.Select(o => o.IdPlan).Distinct(); var operationsPlanWithNoFact = items.Where(o => o.IdType == WellOperation.IdOperationTypePlan && !idsPlanWithFact.Contains(o.IdPlan)); var capacity = operationsFactWithNoPlan.Count() + operationsFactWithPlan.Count() + operationsPlanWithNoFact.Count(); var result = new List<(WellOperationDto? Plan, WellOperationDto? Fact)>(capacity); var operationsPlan = items.Where(o => o.IdType == WellOperation.IdOperationTypePlan); foreach (var operation in operationsFactWithPlan) { var operationPlanDict = operationsPlan.FirstOrDefault(o => o.IdPlan == operation.IdPlan); result.Add((operationPlanDict, operation)); } foreach (var operation in operationsFactWithNoPlan) result.Add((null, operation)); foreach (var operation in operationsPlanWithNoFact) result.Add((operation, null)); return result .OrderBy(x => x.Plan?.DateStart) .ThenBy(x => x.Fact?.DateStart); } public async Task>> GetTvdAsync(int idWell, CancellationToken token) { var wellOperations = (await GetOperationsAsync(idWell, token)).ToArray(); if (!wellOperations.Any()) return Enumerable.Empty>(); var tvd = new List>(wellOperations.Length); var (Plan, Fact) = wellOperations.FirstOrDefault(); var dateStart = Plan?.DateStart ?? Fact!.DateStart; int? iLastMatch = null; int iLastFact = 0; for (int i = 0; i < wellOperations.Length; i++) { var item = wellOperations[i]; var planFactPredict = new PlanFactPredictBase() { Plan = item.Plan, Fact = item.Fact }; if (item.Plan is not null && item.Fact is not null) iLastMatch = i; if (item.Fact is not null) iLastFact = i; tvd.Add(planFactPredict); } if (iLastMatch is null || iLastMatch == wellOperations.Length - 1) return tvd; var lastMatchPlan = wellOperations[iLastMatch.Value].Plan!; var lastMatchPlanOperationEnd = lastMatchPlan.DateStart.AddHours(lastMatchPlan.DurationHours); var lastFact = wellOperations[iLastFact].Fact!; var lastFactDateEnd = lastFact.DateStart.AddHours(lastFact.DurationHours); var startOffset = lastFactDateEnd - lastMatchPlanOperationEnd; for (int i = iLastMatch.Value + 1; i < wellOperations.Length; i++) { if (wellOperations[i].Plan is null) continue; var predict = wellOperations[i].Plan!; predict.IdType = 2; predict.DateStart = predict.DateStart + startOffset; predict.Day = (predict.DateStart - dateStart).TotalDays; tvd[i].Predict = predict; } return tvd; } public static IEnumerable FilterByRequest(IEnumerable dtos, WellOperationRequest request) { if (request.OperationType.HasValue) dtos = dtos.Where(e => e.IdType == request.OperationType.Value); if (request.SectionTypeIds?.Any() is true) dtos = dtos.Where(e => request.SectionTypeIds.Contains(e.IdWellSectionType)); if (request.OperationCategoryIds?.Any() is true) dtos = dtos.Where(e => request.OperationCategoryIds.Contains(e.IdCategory)); if (request.GeDepth.HasValue) dtos = dtos.Where(e => e.DepthEnd >= request.GeDepth.Value); if (request.LeDepth.HasValue) dtos = dtos.Where(e => e.DepthEnd <= request.LeDepth.Value); if (request.GeDate.HasValue) { var geDateUtc = request.GeDate.Value.UtcDateTime; dtos = dtos.Where(e => e.DateStart >= geDateUtc); } if (request.LeDate.HasValue) { var leDateUtc = request.LeDate.Value.UtcDateTime; dtos = dtos.Where(e => e.DateStart <= leDateUtc); } if (request.SortFields?.Any() is true) dtos = dtos.AsQueryable().SortBy(request.SortFields); else dtos = dtos.AsQueryable().OrderBy(e => e.DateStart); return dtos; } }