2021-08-24 10:59:10 +05:00
|
|
|
|
using AsbCloudApp.Data;
|
2021-08-13 17:25:06 +05:00
|
|
|
|
using AsbCloudApp.Services;
|
|
|
|
|
using AsbCloudDb.Model;
|
|
|
|
|
using Mapster;
|
2021-08-24 10:59:10 +05:00
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
2022-11-18 15:17:04 +05:00
|
|
|
|
using Microsoft.Extensions.Caching.Memory;
|
2021-08-18 16:57:20 +05:00
|
|
|
|
using System;
|
2021-08-24 10:59:10 +05:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
2021-08-13 17:25:06 +05:00
|
|
|
|
|
2021-10-09 20:16:22 +05:00
|
|
|
|
namespace AsbCloudInfrastructure.Services.WellOperationService
|
2021-08-13 17:25:06 +05:00
|
|
|
|
{
|
2022-07-04 17:33:32 +05:00
|
|
|
|
#nullable enable
|
2021-08-13 17:25:06 +05:00
|
|
|
|
public class WellOperationService : IWellOperationService
|
|
|
|
|
{
|
2021-12-22 17:09:26 +05:00
|
|
|
|
private readonly IAsbCloudDbContext db;
|
2022-11-18 15:17:04 +05:00
|
|
|
|
private readonly IMemoryCache memoryCache;
|
2021-12-30 17:05:44 +05:00
|
|
|
|
private readonly IWellService wellService;
|
2021-08-13 17:25:06 +05:00
|
|
|
|
|
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 idOperationTypePlan = 0;
|
|
|
|
|
public const int idOperationTypeFact = 1;
|
|
|
|
|
|
2022-11-18 15:17:04 +05:00
|
|
|
|
public WellOperationService(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService)
|
2021-08-13 17:25:06 +05:00
|
|
|
|
{
|
2021-12-22 17:09:26 +05:00
|
|
|
|
this.db = db;
|
2022-11-18 15:17:04 +05:00
|
|
|
|
this.memoryCache = memoryCache;
|
2021-12-30 17:05:44 +05:00
|
|
|
|
this.wellService = wellService;
|
2021-08-16 14:19:43 +05:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-22 17:09:26 +05:00
|
|
|
|
public IDictionary<int, string> GetSectionTypes()
|
2022-11-18 15:17:04 +05:00
|
|
|
|
=> memoryCache
|
|
|
|
|
.GetOrCreateBasic<WellSectionType>(db)
|
|
|
|
|
.ToDictionary(s => s.Id, s => s.Caption);
|
2021-12-22 17:09:26 +05:00
|
|
|
|
|
2021-08-17 09:20:31 +05:00
|
|
|
|
public IEnumerable<WellOperationCategoryDto> GetCategories()
|
2021-08-16 14:19:43 +05:00
|
|
|
|
{
|
2022-12-09 18:32:18 +05:00
|
|
|
|
var allCategories = memoryCache
|
|
|
|
|
.GetOrCreateBasic<WellOperationCategory>(db);
|
|
|
|
|
|
|
|
|
|
var parentIds = allCategories
|
|
|
|
|
.Select(o => o.IdParent)
|
|
|
|
|
.Distinct();
|
|
|
|
|
|
|
|
|
|
var operationCategories = allCategories
|
|
|
|
|
.Where(o => !parentIds.Contains(o.Id))
|
|
|
|
|
.OrderBy(o => o.IdParent)
|
|
|
|
|
.ThenBy(o => o.Name);
|
|
|
|
|
|
2022-11-18 15:17:04 +05:00
|
|
|
|
var result = operationCategories.Adapt<IEnumerable<WellOperationCategoryDto>>();
|
2021-08-16 14:19:43 +05:00
|
|
|
|
return result;
|
2021-08-13 17:25:06 +05:00
|
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-18 16:57:20 +05:00
|
|
|
|
public async Task<PaginationContainer<WellOperationDto>> GetOperationsAsync(
|
|
|
|
|
int idWell,
|
2021-12-07 18:27:52 +05:00
|
|
|
|
int? operationType = default,
|
2022-12-06 22:34:10 +05:00
|
|
|
|
IEnumerable<int>? sectionTypeIds = null,
|
|
|
|
|
IEnumerable<int>? operationCategoryIds = null,
|
2021-08-18 16:57:20 +05:00
|
|
|
|
DateTime begin = default,
|
|
|
|
|
DateTime end = default,
|
2021-08-23 16:59:26 +05:00
|
|
|
|
double minDepth = double.MinValue,
|
|
|
|
|
double maxDepth = double.MaxValue,
|
2021-08-18 16:57:20 +05:00
|
|
|
|
int skip = 0,
|
|
|
|
|
int take = 32,
|
|
|
|
|
CancellationToken token = default)
|
2021-08-13 17:25:06 +05:00
|
|
|
|
{
|
2022-01-05 17:50:45 +05:00
|
|
|
|
var timezone = wellService.GetTimezone(idWell);
|
|
|
|
|
|
2022-12-02 15:54:55 +05:00
|
|
|
|
var query = BuildQuery(
|
|
|
|
|
idWell,
|
|
|
|
|
operationType,
|
|
|
|
|
sectionTypeIds,
|
|
|
|
|
operationCategoryIds,
|
|
|
|
|
begin,
|
|
|
|
|
end,
|
|
|
|
|
minDepth,
|
|
|
|
|
maxDepth,
|
|
|
|
|
token);
|
2021-08-18 16:57:20 +05:00
|
|
|
|
|
2021-08-13 17:25:06 +05:00
|
|
|
|
var result = new PaginationContainer<WellOperationDto>
|
|
|
|
|
{
|
|
|
|
|
Skip = skip,
|
|
|
|
|
Take = take,
|
|
|
|
|
Count = await query.CountAsync(token).ConfigureAwait(false),
|
|
|
|
|
};
|
2022-12-20 15:58:35 +05:00
|
|
|
|
|
2021-08-13 17:25:06 +05:00
|
|
|
|
query = query
|
2021-10-08 11:30:06 +05:00
|
|
|
|
.OrderBy(e => e.DateStart)
|
|
|
|
|
.ThenBy(e => e.DepthEnd)
|
2021-08-18 16:57:20 +05:00
|
|
|
|
.ThenBy(e => e.Id);
|
2021-08-13 17:25:06 +05:00
|
|
|
|
|
|
|
|
|
if (skip > 0)
|
|
|
|
|
query = query.Skip(skip);
|
|
|
|
|
|
2021-08-17 09:20:31 +05:00
|
|
|
|
var entities = await query.Take(take).AsNoTracking()
|
2021-08-16 14:19:43 +05:00
|
|
|
|
.ToListAsync(token).ConfigureAwait(false);
|
2021-08-13 17:25:06 +05:00
|
|
|
|
|
2022-12-20 15:58:35 +05:00
|
|
|
|
if (!entities.Any())
|
|
|
|
|
return result;
|
|
|
|
|
|
2022-03-11 16:53:31 +05:00
|
|
|
|
var nptHours = 0d;
|
|
|
|
|
|
2022-12-20 15:58:35 +05:00
|
|
|
|
var dateStart = query.Min(o => o.DateStart);
|
2022-01-05 17:50:45 +05:00
|
|
|
|
foreach (var entity in entities)
|
2021-08-13 17:25:06 +05:00
|
|
|
|
{
|
2022-01-05 17:50:45 +05:00
|
|
|
|
var dto = entity.Adapt<WellOperationDto>();
|
2022-03-11 16:53:31 +05:00
|
|
|
|
dto.Day = (entity.DateStart - dateStart).TotalDays;
|
2022-01-05 17:50:45 +05:00
|
|
|
|
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-12-09 18:32:18 +05:00
|
|
|
|
if (WellOperationCategory.NonProductiveTimeSubIds.Contains(entity.IdCategory))
|
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
|
|
|
|
}
|
2021-08-13 17:25:06 +05:00
|
|
|
|
result.Items.Add(dto);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2021-08-16 14:19:43 +05:00
|
|
|
|
|
2022-12-06 22:34:10 +05:00
|
|
|
|
public async Task<IEnumerable<WellGroupOpertionDto>> GetGroupOperationsStatAsync(
|
2022-12-02 15:54:55 +05:00
|
|
|
|
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,
|
2022-12-06 22:34:10 +05:00
|
|
|
|
token);
|
2022-12-02 15:54:55 +05:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-07 09:02:04 +05:00
|
|
|
|
public async Task<WellOperationDto?> GetOrDefaultAsync(int id,
|
2021-08-16 14:19:43 +05:00
|
|
|
|
CancellationToken token = default)
|
|
|
|
|
{
|
2022-01-05 17:50:45 +05:00
|
|
|
|
|
2021-12-22 17:09:26 +05:00
|
|
|
|
var entity = await db.WellOperations
|
2021-08-16 14:19:43 +05:00
|
|
|
|
.Include(s => s.WellSectionType)
|
|
|
|
|
.Include(s => s.OperationCategory)
|
|
|
|
|
.FirstOrDefaultAsync(e => e.Id == id, token)
|
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
if (entity is null)
|
|
|
|
|
return null;
|
|
|
|
|
|
2022-01-05 17:50:45 +05:00
|
|
|
|
var timezone = wellService.GetTimezone(entity.IdWell);
|
|
|
|
|
|
2021-08-16 14:19:43 +05:00
|
|
|
|
var dto = entity.Adapt<WellOperationDto>();
|
|
|
|
|
dto.WellSectionTypeName = entity.WellSectionType.Caption;
|
2022-01-05 17:50:45 +05:00
|
|
|
|
dto.DateStart = entity.DateStart.ToRemoteDateTime(timezone.Hours);
|
2021-08-16 14:19:43 +05:00
|
|
|
|
dto.CategoryName = entity.OperationCategory.Name;
|
|
|
|
|
return dto;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-24 10:59:10 +05:00
|
|
|
|
public async Task<int> InsertRangeAsync(int idWell,
|
|
|
|
|
IEnumerable<WellOperationDto> wellOperationDtos,
|
2021-08-16 14:19:43 +05:00
|
|
|
|
CancellationToken token = default)
|
|
|
|
|
{
|
2022-01-05 17:50:45 +05:00
|
|
|
|
var timezone = wellService.GetTimezone(idWell);
|
|
|
|
|
foreach (var dto in wellOperationDtos)
|
2021-08-16 14:19:43 +05:00
|
|
|
|
{
|
2022-01-05 17:50:45 +05:00
|
|
|
|
var entity = dto.Adapt<WellOperation>();
|
2021-09-30 18:02:50 +05:00
|
|
|
|
entity.Id = default;
|
2022-01-05 17:50:45 +05:00
|
|
|
|
entity.DateStart = dto.DateStart.ToUtcDateTimeOffset(timezone.Hours);
|
2021-08-18 16:57:20 +05:00
|
|
|
|
entity.IdWell = idWell;
|
2021-12-22 17:09:26 +05:00
|
|
|
|
db.WellOperations.Add(entity);
|
2021-08-16 14:19:43 +05:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-22 17:09:26 +05:00
|
|
|
|
return await db.SaveChangesAsync(token)
|
2021-08-16 14:19:43 +05:00
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-24 10:59:10 +05:00
|
|
|
|
public async Task<int> UpdateAsync(int idWell, int idOperation,
|
2022-01-05 17:50:45 +05:00
|
|
|
|
WellOperationDto dto, CancellationToken token = default)
|
2021-08-16 14:19:43 +05:00
|
|
|
|
{
|
2022-01-05 17:50:45 +05:00
|
|
|
|
var timezone = wellService.GetTimezone(idWell);
|
|
|
|
|
var entity = dto.Adapt<WellOperation>();
|
2021-08-18 16:57:20 +05:00
|
|
|
|
entity.Id = idOperation;
|
2022-01-05 17:50:45 +05:00
|
|
|
|
entity.DateStart = dto.DateStart.ToUtcDateTimeOffset(timezone.Hours);
|
2021-12-22 17:09:26 +05:00
|
|
|
|
db.WellOperations.Update(entity);
|
|
|
|
|
return await db.SaveChangesAsync(token)
|
2021-08-16 14:19:43 +05:00
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<int> DeleteAsync(IEnumerable<int> ids,
|
|
|
|
|
CancellationToken token = default)
|
|
|
|
|
{
|
2021-12-22 17:09:26 +05:00
|
|
|
|
var query = db.WellOperations.Where(e => ids.Contains(e.Id));
|
|
|
|
|
db.WellOperations.RemoveRange(query);
|
|
|
|
|
return await db.SaveChangesAsync(token)
|
2021-08-16 14:19:43 +05:00
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
|
}
|
2022-12-02 15:54:55 +05:00
|
|
|
|
|
|
|
|
|
private IQueryable<WellOperation> BuildQuery(
|
|
|
|
|
int idWell,
|
|
|
|
|
int? operationType = default,
|
2022-12-06 22:34:10 +05:00
|
|
|
|
IEnumerable<int>? sectionTypeIds = null,
|
|
|
|
|
IEnumerable<int>? operationCategoryIds = null,
|
2022-12-02 15:54:55 +05:00
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
}
|
2021-08-13 17:25:06 +05:00
|
|
|
|
}
|
2022-07-04 17:33:32 +05:00
|
|
|
|
#nullable disable
|
2021-08-13 17:25:06 +05:00
|
|
|
|
}
|