DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/WellSectionService.cs
2021-08-23 14:52:34 +05:00

224 lines
9.7 KiB
C#

using AsbCloudApp.Data;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using Mapster;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
using System.Threading;
using AsbCloudInfrastructure.Services.Cache;
namespace AsbCloudInfrastructure.Services
{
public class WellSectionService: IWellSectionService
{
private readonly IAsbCloudDbContext db;
private readonly CacheTable<WellSectionType> cachedSectionsTypes;
public WellSectionService(IAsbCloudDbContext db, Cache.CacheDb cache)
{
this.db = db;
cachedSectionsTypes = cache.GetCachedTable<WellSectionType>((DbContext)db);
}
public async Task<IEnumerable<WellSectionDto>> GetSectionsByWellIdAsync(int idWell,
CancellationToken token = default)
{
var wellOperations = await (from w in db.WellOperations
where w.IdWell == idWell
select w)
.Include(w => w.WellSectionType)
.ToListAsync(token)
.ConfigureAwait(false);
if (!wellOperations.Any())
return null;
var wellOperationsGroupedBySections = wellOperations
.GroupBy(op => op.IdWellSectionType).ToList();
var wellOperationsClone = wellOperations.Select(o => o.ShallowCopy()).ToList();
wellOperationsClone.ForEach(op =>
{
op.IdWellSectionType = 1;
op.WellSectionType = new WellSectionType { Caption = "Обобщенное по скважине" };
});
var groupedWellOperationsClone = wellOperationsClone.GroupBy(o => o.IdWell);
wellOperationsGroupedBySections.Add(groupedWellOperationsClone.First());
var depthsPlanList = GetWellDepthStats(wellOperationsGroupedBySections, 0).ToList();
var depthsFactList = GetWellDepthStats(wellOperationsGroupedBySections, 1).ToList();
var durationsPlanList = GetWellDurationStats(wellOperationsGroupedBySections, 0).ToList();
var durationsFactList = GetWellDurationStats(wellOperationsGroupedBySections, 1).ToList();
var mechSpeedsPlanList = GetWellStats(wellOperationsGroupedBySections, 1001, 0).ToList();
var mechSpeedsFactList = GetWellStats(wellOperationsGroupedBySections, 1001, 1).ToList();
var bhaUpSpeedPlanList = GetWellStats(wellOperationsGroupedBySections, 1046, 0).ToList();
var bhaUpSpeedFactList = GetWellStats(wellOperationsGroupedBySections, 1046, 1).ToList();
var bhaDownSpeedPlanList = GetWellStats(wellOperationsGroupedBySections, 1047, 0).ToList();
var bhaDownSpeedFactList = GetWellStats(wellOperationsGroupedBySections, 1047, 1).ToList();
var casingDownPlanList = GetWellStats(wellOperationsGroupedBySections, 1048, 0).ToList();
var casingDownFactList = GetWellStats(wellOperationsGroupedBySections, 1048, 1).ToList();
var routeSpeedsPlan = GetWellRouteSpeedStats(wellOperationsGroupedBySections, 0).ToList();
var routeSpeedsFact = GetWellRouteSpeedStats(wellOperationsGroupedBySections, 1).ToList();
var dtos = new List<WellSectionDto>();
for(int i = 0; i < wellOperationsGroupedBySections.Count; i++)
{
var dto = new WellSectionDto
{
SectionType = wellOperationsGroupedBySections[i]
.FirstOrDefault().WellSectionType.Caption,
WellDepthPlan = depthsPlanList[i],
WellDepthFact = depthsFactList[i],
DurationPlan = durationsPlanList[i],
DurationFact = durationsFactList[i],
MechSpeedPlan = mechSpeedsPlanList[i],
MechSpeedFact = mechSpeedsFactList[i],
BhaUpSpeedPlan = bhaUpSpeedPlanList[i],
BhaUpSpeedFact = bhaUpSpeedFactList[i],
BhaDownSpeedPlan = bhaDownSpeedPlanList[i],
BhaDownSpeedFact = bhaDownSpeedFactList[i],
CasingDownSpeedPlan = casingDownPlanList[i],
CasingDownSpeedFact = casingDownFactList[i],
RouteSpeedPlan = routeSpeedsPlan[i],
RouteSpeedFact = routeSpeedsFact[i]
};
dtos.Add(dto);
}
return dtos;
}
public async Task<WellSectionDto> GetSectionByWellIdAsync(int id, CancellationToken token = default)
{
var entity = await db.WellSections
.Include(s => s.WellSectionType)
.FirstOrDefaultAsync(e => e.Id == id, token)
.ConfigureAwait(false);
if (entity is null)
return null;
var dto = entity.Adapt<WellSectionDto>();
dto.SectionType = entity.WellSectionType.Caption;
return dto;
}
private static IEnumerable<double> GetWellDepthStats(
IEnumerable<IGrouping<int, WellOperation>> groupedOperations, int type)
{
return groupedOperations.Select(group => group.Where(o => o.IdType == type)
.DefaultIfEmpty().Max(w => w?.WellDepth ?? 0.0));
}
private static IEnumerable<double> GetWellDurationStats(
IEnumerable<IGrouping<int, WellOperation>> groupedOperations, int type)
{
var durationsPlanFactsBase = groupedOperations.Select(group => new
{
DurationMax = group.Where(o => o.IdType == type).DefaultIfEmpty()
.Max(op => op?.StartDate + TimeSpan.FromHours(op?.DurationHours ?? 0)) ?? default,
DurationMin = group.Where(o => o.IdType == type).DefaultIfEmpty()
.Min(op => op?.StartDate) ?? default
});
return durationsPlanFactsBase.Select(o =>
(o.DurationMax - o.DurationMin).TotalHours);
}
private static IEnumerable<double> GetWellStats(
IEnumerable<IGrouping<int, WellOperation>> groupedOperations, int idCategory, int type)
{
var mechSpeedBase = groupedOperations.Select(g =>
(
DepthDifferenceSum: g.Where(o => o.IdType == type && o.IdCategory == idCategory)
.Select((el, i) => i > 0 ? el.WellDepth - g.ElementAt(i - 1).WellDepth : 0).Sum(),
DurationDifferenceSum: g.Where(o => o.IdType == type && o.IdCategory == idCategory)
.Select(el => el.DurationHours).Sum()
));
return CalculateResult(mechSpeedBase);
}
private static IEnumerable<double> GetWellRouteSpeedStats(
IEnumerable<IGrouping<int, WellOperation>> groupedOperations, int type)
{
var bhaRaiseDecreaseCollection = new List<(WellOperation FirstBhaPositionDecrease,
WellOperation LastBhaPositionIncrease)>();
foreach (var group in groupedOperations)
{
var firstBhaPositionDecrease = group.Any(o => o.IdCategory == 1046 && o.IdType == type)
? group.First(o => o.IdCategory == 1046 && o.IdType == type)
: null;
var lastBhaPositionIncrease = group.Any(o => o.IdCategory == 1047 && o.IdType == type)
? group.Last(o => o.IdCategory == 1047 && o.IdType == type)
: null;
bhaRaiseDecreaseCollection.Add((firstBhaPositionDecrease, lastBhaPositionIncrease));
}
var routeSpeedsBase = bhaRaiseDecreaseCollection.Select(el =>
(
RouteDepth: (el.LastBhaPositionIncrease?.WellDepth - el.FirstBhaPositionDecrease?.WellDepth) ?? 0,
RouteDuration: (el.LastBhaPositionIncrease?.StartDate +
TimeSpan.FromHours(el.LastBhaPositionIncrease?.DurationHours ?? 0) -
el.FirstBhaPositionDecrease?.StartDate)?.TotalHours ?? 0
));
return CalculateResult(routeSpeedsBase);
}
private static IEnumerable<double> CalculateResult(IEnumerable<(double,
double)> rawData)
{
return rawData.Select(el =>
(el.Item1 / el.Item2) is double.NaN
? 0
: (el.Item1 / el.Item2)
);
}
private async Task<WellSectionType> GetWellSectionTypeFromCacheAndAssertAsync(string wellSectionType, CancellationToken token = default)
{
if (string.IsNullOrEmpty(wellSectionType))
throw new ArgumentException("Тип секции должен быть указан", nameof(WellSectionDto.SectionType));
var sectionType = await cachedSectionsTypes
.FirstOrDefaultAsync(s => s.Caption.Equals(wellSectionType, StringComparison.OrdinalIgnoreCase), token)
.ConfigureAwait(false);
if (sectionType is null)
{
throw new ArgumentException($"Тип секции '{wellSectionType}' отсутствует в справочнике", nameof(WellSectionDto.SectionType));
//sectionType = await cachedSectionsTypes.InsertAsync(new WellSectionType { Caption = item.SectionType}, token);
}
return sectionType;
}
}
}