DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/WellOperationService/WellOperationService.cs

331 lines
12 KiB
C#
Raw Normal View History

using AsbCloudApp.Data;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services.WellOperationService
{
2022-07-04 17:33:32 +05:00
#nullable enable
public class WellOperationService : IWellOperationService
{
private readonly IAsbCloudDbContext db;
private readonly IMemoryCache memoryCache;
private readonly IWellService wellService;
2022-05-06 16:35:16 +05:00
private Dictionary<int, DateTimeOffset?>? firstOperationsCache = null;
2022-03-11 16:53:31 +05:00
public const int idOperationBhaAssembly = 1025;
public const int idOperationBhaDisassembly = 1026;
public const int idOperationNonProductiveTime = 1043;
public const int idOperationDrilling = 1001;
public const int idOperationBhaDown = 1046;
public const int idOperationBhaUp = 1047;
public const int idOperationCasingDown = 1048;
public const int idOperationTypePlan = 0;
public const int idOperationTypeFact = 1;
public const int idOperationTypeRepair = 1031;
2022-03-11 16:53:31 +05:00
public WellOperationService(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService)
{
this.db = db;
this.memoryCache = memoryCache;
this.wellService = wellService;
}
public IDictionary<int, string> GetSectionTypes()
=> memoryCache
.GetOrCreateBasic<WellSectionType>(db)
.ToDictionary(s => s.Id, s => s.Caption);
public IEnumerable<WellOperationCategoryDto> GetCategories()
{
var operationCategories = memoryCache
.GetOrCreateBasic<WellOperationCategory>(db)
.Distinct()
.OrderBy(o => o.Name);
var result = operationCategories.Adapt<IEnumerable<WellOperationCategoryDto>>();
return result;
}
2022-05-06 16:35:16 +05:00
public DateTimeOffset? FirstOperationDate(int idWell)
{
2022-06-15 14:57:37 +05:00
if (firstOperationsCache is null)
2022-05-06 16:35:16 +05:00
{
var query = db.WellOperations
.GroupBy(o => o.IdWell)
.Select(g => new Tuple<int, DateTimeOffset?, DateTimeOffset?>
(
g.Key,
g.Where(o => o.IdType == idOperationTypePlan).Min(o => o.DateStart),
g.Where(o => o.IdType == idOperationTypeFact).Min(o => o.DateStart)
));
firstOperationsCache = query
.ToDictionary(f => f.Item1, f => f.Item3 ?? f.Item2);
}
return firstOperationsCache?.GetValueOrDefault(idWell);
}
public async Task<PaginationContainer<WellOperationDto>> GetOperationsAsync(
int idWell,
int? operationType = default,
IEnumerable<int> sectionTypeIds = default,
IEnumerable<int> operationCategoryIds = default,
DateTime begin = default,
DateTime end = default,
double minDepth = double.MinValue,
double maxDepth = double.MaxValue,
int skip = 0,
int take = 32,
CancellationToken token = default)
{
var timezone = wellService.GetTimezone(idWell);
var query = BuildQuery(
idWell,
operationType,
sectionTypeIds,
operationCategoryIds,
begin,
end,
minDepth,
maxDepth,
token);
var result = new PaginationContainer<WellOperationDto>
{
Skip = skip,
Take = take,
Count = await query.CountAsync(token).ConfigureAwait(false),
};
var dateStart = query.Min(o => o.DateStart);
query = query
.OrderBy(e => e.DateStart)
.ThenBy(e => e.DepthEnd)
.ThenBy(e => e.Id);
if (skip > 0)
query = query.Skip(skip);
var entities = await query.Take(take).AsNoTracking()
.ToListAsync(token).ConfigureAwait(false);
2022-03-11 16:53:31 +05:00
var nptHours = 0d;
foreach (var entity in entities)
{
var dto = entity.Adapt<WellOperationDto>();
2022-03-11 16:53:31 +05:00
dto.Day = (entity.DateStart - dateStart).TotalDays;
dto.WellSectionTypeName = entity.WellSectionType.Caption;
dto.DateStart = entity.DateStart.ToRemoteDateTime(timezone.Hours);
dto.CategoryName = entity.OperationCategory.Name;
2022-04-11 18:00:34 +05:00
if (entity.IdType == idOperationTypeFact)
2022-03-11 16:53:31 +05:00
{
2022-04-11 18:00:34 +05:00
if (entity.IdCategory == idOperationNonProductiveTime)
2022-03-11 16:53:31 +05:00
nptHours += entity.DurationHours;
2022-04-11 18:00:34 +05:00
dto.NptHours = nptHours;
2022-03-11 16:53:31 +05:00
}
result.Items.Add(dto);
}
return result;
}
public async Task<IEnumerable<WellGroupOpertionDto>?> GetGroupOperationsStatAsync(
int idWell,
int? operationType = default,
IEnumerable<int>? sectionTypeIds = default,
IEnumerable<int>? operationCategoryIds = default,
DateTime begin = default,
DateTime end = default,
double minDepth = double.MinValue,
double maxDepth = double.MaxValue,
CancellationToken token = default)
{
var query = BuildQuery(
idWell,
operationType,
sectionTypeIds,
operationCategoryIds,
begin,
end,
minDepth,
maxDepth,
token);
if (query is null)
return null;
var entities = await query
.Select(o => new {
o.IdCategory,
DurationMinutes = o.DurationHours * 60,
DurationDepth = o.DepthEnd - o.DepthStart
})
.ToListAsync(token);
var parentRelationDictionary = GetCategories()
.ToDictionary(c => c.Id, cc => new
{
Name = cc.Name,
IdParent = cc.IdParent
});
var dtos = entities
.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
});
var defaultId = 0;
while (dtos.Any(x => x.IdParent != null))
{
defaultId--;
dtos = dtos
.GroupBy(o => o.IdParent)
.Select(g => new WellGroupOpertionDto
{
IdCategory = g.Key.HasValue ? g.Key.Value : defaultId,
Category = g.Key.HasValue ? parentRelationDictionary[g.Key.Value].Name : "unknown",
Count = g.Sum(o => o.Count),
DeltaDepth = g.Sum(o => o.DeltaDepth),
TotalMinutes = g.Sum(o => o.TotalMinutes),
Items = g.ToList(),
IdParent = g.Key.HasValue ? parentRelationDictionary[g.Key.Value].IdParent : defaultId,
});
}
return dtos;
}
public async Task<WellOperationDto> GetAsync(int id,
CancellationToken token = default)
{
var entity = await db.WellOperations
.Include(s => s.WellSectionType)
.Include(s => s.OperationCategory)
.FirstOrDefaultAsync(e => e.Id == id, token)
.ConfigureAwait(false);
if (entity is null)
return null;
var timezone = wellService.GetTimezone(entity.IdWell);
var dto = entity.Adapt<WellOperationDto>();
dto.WellSectionTypeName = entity.WellSectionType.Caption;
dto.DateStart = entity.DateStart.ToRemoteDateTime(timezone.Hours);
dto.CategoryName = entity.OperationCategory.Name;
return dto;
}
public async Task<int> InsertRangeAsync(int idWell,
IEnumerable<WellOperationDto> wellOperationDtos,
CancellationToken token = default)
{
var timezone = wellService.GetTimezone(idWell);
foreach (var dto in wellOperationDtos)
{
var entity = dto.Adapt<WellOperation>();
2021-09-30 18:02:50 +05:00
entity.Id = default;
entity.DateStart = dto.DateStart.ToUtcDateTimeOffset(timezone.Hours);
entity.IdWell = idWell;
db.WellOperations.Add(entity);
}
return await db.SaveChangesAsync(token)
.ConfigureAwait(false);
}
public async Task<int> UpdateAsync(int idWell, int idOperation,
WellOperationDto dto, CancellationToken token = default)
{
var timezone = wellService.GetTimezone(idWell);
var entity = dto.Adapt<WellOperation>();
entity.Id = idOperation;
entity.DateStart = dto.DateStart.ToUtcDateTimeOffset(timezone.Hours);
db.WellOperations.Update(entity);
return await db.SaveChangesAsync(token)
.ConfigureAwait(false);
}
public async Task<int> DeleteAsync(IEnumerable<int> ids,
CancellationToken token = default)
{
var query = db.WellOperations.Where(e => ids.Contains(e.Id));
db.WellOperations.RemoveRange(query);
return await db.SaveChangesAsync(token)
.ConfigureAwait(false);
}
private IQueryable<WellOperation> BuildQuery(
int idWell,
int? operationType = default,
IEnumerable<int> sectionTypeIds = default,
IEnumerable<int> operationCategoryIds = default,
DateTime begin = default,
DateTime end = default,
double minDepth = double.MinValue,
double maxDepth = double.MaxValue,
CancellationToken token = default)
{
var timezone = wellService.GetTimezone(idWell);
var query = db.WellOperations
.Include(s => s.WellSectionType)
.Include(s => s.OperationCategory)
.Where(s => s.IdWell == idWell);
var dateStart = query.Min(o => o.DateStart);
if (operationType.HasValue)
query = query.Where(e => e.IdType == operationType.Value);
if (sectionTypeIds != default && sectionTypeIds.Any())
query = query.Where(e => sectionTypeIds.Contains(e.IdWellSectionType));
if (operationCategoryIds != default && operationCategoryIds.Any())
query = query.Where(e => operationCategoryIds.Contains(e.IdCategory));
if (minDepth != double.MinValue)
query = query.Where(e => e.DepthEnd >= minDepth);
if (maxDepth != double.MaxValue)
query = query.Where(e => e.DepthEnd <= maxDepth);
if (begin != default)
{
var beginOffset = begin.ToUtcDateTimeOffset(timezone.Hours);
query = query.Where(e => e.DateStart >= beginOffset);
}
if (end != default)
{
var endOffset = end.ToUtcDateTimeOffset(timezone.Hours);
query = query.Where(e => e.DateStart <= endOffset);
}
query = query
.OrderBy(e => e.DateStart)
.ThenBy(e => e.DepthEnd)
.ThenBy(e => e.Id);
return query;
}
}
2022-07-04 17:33:32 +05:00
#nullable disable
}