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 { #nullable enable public class WellOperationService : IWellOperationService { private readonly IAsbCloudDbContext db; private readonly IMemoryCache memoryCache; private readonly IWellService wellService; private Dictionary? firstOperationsCache = null; 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; public WellOperationService(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService) { this.db = db; this.memoryCache = memoryCache; this.wellService = wellService; } public IDictionary GetSectionTypes() => memoryCache .GetOrCreateBasic(db) .ToDictionary(s => s.Id, s => s.Caption); public IEnumerable GetCategories() { var operationCategories = memoryCache .GetOrCreateBasic(db) .Distinct() .OrderBy(o => o.Name); var result = operationCategories.Adapt>(); return result; } public DateTimeOffset? FirstOperationDate(int idWell) { if (firstOperationsCache is null) { var query = db.WellOperations .GroupBy(o => o.IdWell) .Select(g => new Tuple ( 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> GetOperationsAsync( int idWell, int? operationType = default, IEnumerable sectionTypeIds = default, IEnumerable 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 = db.WellOperations .Include(s => s.WellSectionType) .Include(s => s.OperationCategory) .Where(s => s.IdWell == idWell); var dateStart = query.Min(o => o.DateStart); if (operationType != default) query = query.Where(e => e.IdType == (int)operationType); 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); } var result = new PaginationContainer { Skip = skip, Take = take, Count = await query.CountAsync(token).ConfigureAwait(false), }; 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); var nptHours = 0d; foreach (var entity in entities) { var dto = entity.Adapt(); dto.Day = (entity.DateStart - dateStart).TotalDays; dto.WellSectionTypeName = entity.WellSectionType.Caption; dto.DateStart = entity.DateStart.ToRemoteDateTime(timezone.Hours); dto.CategoryName = entity.OperationCategory.Name; if (entity.IdType == idOperationTypeFact) { if (entity.IdCategory == idOperationNonProductiveTime) nptHours += entity.DurationHours; dto.NptHours = nptHours; } result.Items.Add(dto); } return result; } public async Task 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(); dto.WellSectionTypeName = entity.WellSectionType.Caption; dto.DateStart = entity.DateStart.ToRemoteDateTime(timezone.Hours); dto.CategoryName = entity.OperationCategory.Name; return dto; } public async Task InsertRangeAsync(int idWell, IEnumerable wellOperationDtos, CancellationToken token = default) { var timezone = wellService.GetTimezone(idWell); foreach (var dto in wellOperationDtos) { var entity = dto.Adapt(); 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 UpdateAsync(int idWell, int idOperation, WellOperationDto dto, CancellationToken token = default) { var timezone = wellService.GetTimezone(idWell); var entity = dto.Adapt(); entity.Id = idOperation; entity.DateStart = dto.DateStart.ToUtcDateTimeOffset(timezone.Hours); db.WellOperations.Update(entity); return await db.SaveChangesAsync(token) .ConfigureAwait(false); } public async Task DeleteAsync(IEnumerable 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); } } #nullable disable }