diff --git a/AsbCloudApp/Repositories/IWellOperationRepository.cs b/AsbCloudApp/Repositories/IWellOperationRepository.cs
index 0409969e..d37a1e90 100644
--- a/AsbCloudApp/Repositories/IWellOperationRepository.cs
+++ b/AsbCloudApp/Repositories/IWellOperationRepository.cs
@@ -54,7 +54,7 @@ namespace AsbCloudApp.Repositories
///
/// Обновить существующую операцию
///
- ///
+ ///
///
///
Task UpdateRangeAsync(IEnumerable dtos, CancellationToken token);
diff --git a/AsbCloudApp/Requests/WellOperationRequest.cs b/AsbCloudApp/Requests/WellOperationRequest.cs
index 356ef52d..fa866378 100644
--- a/AsbCloudApp/Requests/WellOperationRequest.cs
+++ b/AsbCloudApp/Requests/WellOperationRequest.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Requests;
@@ -8,44 +9,72 @@ namespace AsbCloudApp.Requests;
///
public class WellOperationRequestBase : RequestBase
{
- ///
- /// Больше или равно дате начала операции
- ///
- public DateTimeOffset? GeDate { get; set; }
+ ///
+ /// Больше или равно дате начала операции
+ ///
+ public DateTimeOffset? GeDate { get; set; }
- ///
- /// Меньше или равно дате окончания операции
- ///
- public DateTimeOffset? LeDate { get; set; }
+ ///
+ /// Меньше или равно дате окончания операции
+ ///
+ public DateTimeOffset? LeDate { get; set; }
- ///
- /// Больше или равно глубины скважины на начало операции.
- ///
- public double? GeDepth { get; set; }
+ ///
+ /// Больше или равно глубины скважины на начало операции.
+ ///
+ public double? GeDepth { get; set; }
- ///
- /// Меньше или равно глубины скважины на конец операции.
- ///
- public double? LeDepth { get; set; }
+ ///
+ /// Меньше или равно глубины скважины на конец операции.
+ ///
+ public double? LeDepth { get; set; }
- ///
- /// Идентификаторы категорий операции
- ///
- public IEnumerable? OperationCategoryIds { get; set; }
+ ///
+ /// Идентификаторы категорий операции
+ ///
+ public IEnumerable? OperationCategoryIds { get; set; }
- ///
- /// Тип операций
- ///
- /// - 0 - плановая операция
- /// - 1 - фактическая операция
- ///
- ///
- public int? OperationType { get; set; }
+ ///
+ /// Тип операций
+ ///
+ /// - 0 - плановая операция
+ /// - 1 - фактическая операция
+ ///
+ ///
+ public int? OperationType { get; set; }
- ///
- /// Идентификаторы конструкций секции
- ///
- public IEnumerable? SectionTypeIds { get; set; }
+ ///
+ /// Идентификаторы конструкций секции
+ ///
+ public IEnumerable? SectionTypeIds { get; set; }
+
+ ///
+ ///
+ ///
+ public WellOperationRequestBase()
+ {
+
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public WellOperationRequestBase(WellOperationRequestBase request)
+ {
+ GeDepth = request.GeDepth;
+ LeDepth = request.LeDepth;
+ GeDate = request.GeDate;
+ LeDate = request.LeDate;
+
+ OperationCategoryIds = request.OperationCategoryIds;
+ OperationType = request.OperationType;
+ SectionTypeIds = request.SectionTypeIds;
+
+ Skip = request.Skip;
+ Take = request.Take;
+ SortFields = request.SortFields;
+ }
}
///
@@ -53,32 +82,23 @@ public class WellOperationRequestBase : RequestBase
///
public class WellOperationRequest : WellOperationRequestBase
{
- ///
- public WellOperationRequest(IEnumerable idsWell)
- {
- IdsWell = idsWell;
- }
+ ///
+ public WellOperationRequest(IEnumerable idsWell)
+ {
+ IdsWell = idsWell;
+ }
- ///
- public WellOperationRequest(WellOperationRequestBase request, IEnumerable idsWell)
- : this(idsWell)
- {
- GeDepth = request.GeDepth;
- LeDepth = request.LeDepth;
- GeDate = request.GeDate;
- LeDate = request.LeDate;
+ ///
+ public WellOperationRequest(WellOperationRequestBase request, IEnumerable idsWell)
+ : base(request)
+ {
+ IdsWell = idsWell;
+ }
- OperationCategoryIds = request.OperationCategoryIds;
- OperationType = request.OperationType;
- SectionTypeIds = request.SectionTypeIds;
-
- Skip = request.Skip;
- Take = request.Take;
- SortFields = request.SortFields;
- }
-
- ///
- /// Идентификаторы скважин
- ///
- public IEnumerable? IdsWell { get; }
+ ///
+ /// Идентификаторы скважин
+ ///
+ [Required]
+ [Length(1, 100)]
+ public IEnumerable IdsWell { get; }
}
\ No newline at end of file
diff --git a/AsbCloudDb/Model/DefaultData/WellOperationCategories.xlsx b/AsbCloudDb/Model/DefaultData/WellOperationCategories.xlsx
index 1f41a051..7d257567 100644
Binary files a/AsbCloudDb/Model/DefaultData/WellOperationCategories.xlsx and b/AsbCloudDb/Model/DefaultData/WellOperationCategories.xlsx differ
diff --git a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs
index 3b67eb54..9bcc718b 100644
--- a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs
+++ b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs
@@ -1,9 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using AsbCloudApp.Data;
+using AsbCloudApp.Data;
using AsbCloudApp.Data.WellOperation;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
@@ -14,350 +9,367 @@ 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.Repository;
public class WellOperationRepository : CrudRepositoryBase,
- IWellOperationRepository
+ IWellOperationRepository
{
- private readonly IMemoryCache memoryCache;
- private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
- private readonly IWellService wellService;
+ private readonly IMemoryCache memoryCache;
+ private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
+ private readonly IWellService wellService;
+ private Lazy> LazyWellCategories { get; }
+ private Lazy> LazyWellSectionTypes { get; }
- public WellOperationRepository(IAsbCloudDbContext context,
- IMemoryCache memoryCache,
- IWellOperationCategoryRepository wellOperationCategoryRepository,
- IWellService wellService)
- : base(context, dbSet => dbSet.Include(e => e.WellSectionType)
- .Include(e => e.OperationCategory))
- {
- this.memoryCache = memoryCache;
- this.wellOperationCategoryRepository = wellOperationCategoryRepository;
- this.wellService = wellService;
- }
+ public WellOperationRepository(IAsbCloudDbContext context,
+ IMemoryCache memoryCache,
+ IWellOperationCategoryRepository wellOperationCategoryRepository,
+ IWellService wellService)
+ : base(context, dbSet => dbSet)
+ {
+ this.memoryCache = memoryCache;
+ this.wellOperationCategoryRepository = wellOperationCategoryRepository;
+ this.wellService = wellService;
- public IEnumerable GetSectionTypes() =>
- memoryCache
- .GetOrCreateBasic(dbContext.WellSectionTypes)
- .OrderBy(s => s.Order)
- .Select(s => s.Adapt());
+ LazyWellCategories = new(() => wellOperationCategoryRepository.Get(true, false).ToDictionary(c => c.Id));
+ LazyWellSectionTypes = new(() => GetSectionTypes().ToDictionary(c => c.Id));
+ }
- public async Task> GetAsync(WellOperationRequest request, CancellationToken token)
- {
- var query = BuildQuery(request);
+ public IEnumerable GetSectionTypes() =>
+ memoryCache
+ .GetOrCreateBasic(dbContext.WellSectionTypes)
+ .OrderBy(s => s.Order)
+ .Select(s => s.Adapt());
- if (request.Skip.HasValue)
- query = query.Skip(request.Skip.Value);
+ public async Task> GetAsync(WellOperationRequest request, CancellationToken token)
+ {
+ var (items, _) = await GetWithDaysAndNpvAsync(request, token);
+ return items;
+ }
- if (request.Take.HasValue)
- query = query.Take(request.Take.Value);
+ public async Task> GetPageAsync(WellOperationRequest request, CancellationToken token)
+ {
+ var skip = request.Skip ?? 0;
+ var take = request.Take ?? 32;
- var entities = await query.AsNoTracking()
- .ToArrayAsync(token);
+ var (items, count) = await GetWithDaysAndNpvAsync(request, token);
- return await ConvertWithDrillingDaysAndNpvHoursAsync(entities, token);
- }
+ var paginationContainer = new PaginationContainer
+ {
+ Skip = skip,
+ Take = take,
+ Count = count,
+ Items = items
+ };
- public async Task> GetPageAsync(WellOperationRequest request, CancellationToken token)
- {
- var skip = request.Skip ?? 0;
- var take = request.Take ?? 32;
+ return paginationContainer;
+ }
- var query = BuildQuery(request);
+ public async Task> GetGroupOperationsStatAsync(WellOperationRequest request, CancellationToken token)
+ {
+ var query = BuildQuery(request);
+ var entities = await query
+ .Select(o => new
+ {
+ o.IdCategory,
+ DurationMinutes = o.DurationHours * 60,
+ DurationDepth = o.DepthEnd - o.DepthStart
+ })
+ .ToArrayAsync(token);
- var entities = await query.Skip(skip)
- .Take(take)
- .AsNoTracking()
- .ToArrayAsync(token);
+ var parentRelationDictionary = wellOperationCategoryRepository.Get(true)
+ .ToDictionary(c => c.Id, c => new
+ {
+ c.Name,
+ c.IdParent
+ });
- var paginationContainer = new PaginationContainer
- {
- Skip = skip,
- Take = take,
- Count = await query.CountAsync(token),
- Items = await ConvertWithDrillingDaysAndNpvHoursAsync(entities, token)
- };
+ 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
+ });
- return paginationContainer;
- }
+ 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;
+ });
+ }
- public async Task> GetGroupOperationsStatAsync(WellOperationRequest request, CancellationToken token)
- {
- var query = BuildQuery(request);
- var entities = await query
- .Select(o => new
- {
- o.IdCategory,
- DurationMinutes = o.DurationHours * 60,
- DurationDepth = o.DepthEnd - o.DepthStart
- })
- .ToArrayAsync(token);
+ return dtos;
+ }
- var parentRelationDictionary = wellOperationCategoryRepository.Get(true)
- .ToDictionary(c => c.Id, c => new
- {
- c.Name,
- c.IdParent
- });
+ public async Task InsertRangeAsync(IEnumerable dtos,
+ bool deleteBeforeInsert,
+ CancellationToken token)
+ {
+ EnsureValidWellOperations(dtos);
- 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
- });
+ if (!deleteBeforeInsert)
+ return await InsertRangeAsync(dtos, token);
- 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;
- });
- }
+ var idType = dtos.First().IdType;
+ var idWell = dtos.First().IdWell;
- return dtos;
- }
+ var existingOperationIds = await dbContext.WellOperations
+ .Where(e => e.IdWell == idWell && e.IdType == idType)
+ .Select(e => e.Id)
+ .ToArrayAsync(token);
- public async Task InsertRangeAsync(IEnumerable dtos,
- bool deleteBeforeInsert,
- CancellationToken token)
- {
- EnsureValidWellOperations(dtos);
+ await DeleteRangeAsync(existingOperationIds, token);
- if (!deleteBeforeInsert)
- return await InsertRangeAsync(dtos, token);
+ return await InsertRangeAsync(dtos, token);
+ }
- var idType = dtos.First().IdType;
- var idWell = dtos.First().IdWell;
+ public override Task UpdateRangeAsync(IEnumerable dtos, CancellationToken token)
+ {
+ EnsureValidWellOperations(dtos);
- var existingOperationIds = await dbContext.WellOperations
- .Where(e => e.IdWell == idWell && e.IdType == idType)
- .Select(e => e.Id)
- .ToArrayAsync(token);
+ return base.UpdateRangeAsync(dtos, token);
+ }
- await DeleteRangeAsync(existingOperationIds, token);
+ private static void EnsureValidWellOperations(IEnumerable dtos)
+ {
+ if (dtos.GroupBy(d => d.IdType).Count() > 1)
+ throw new ArgumentInvalidException(nameof(dtos), "Все операции должны быть одного типа");
- return await InsertRangeAsync(dtos, token);
- }
+ if (dtos.GroupBy(d => d.IdType).Count() > 1)
+ throw new ArgumentInvalidException(nameof(dtos), "Все операции должны принадлежать одной скважине");
+ }
- public override Task UpdateRangeAsync(IEnumerable dtos, CancellationToken token)
- {
- EnsureValidWellOperations(dtos);
+ private async Task> GetByIdsWells(IEnumerable idsWells, CancellationToken token)
+ {
+ var query = GetQuery()
+ .Where(e => idsWells.Contains(e.IdWell))
+ .OrderBy(e => e.DateStart);
+ var entities = await query.ToArrayAsync(token);
+ return entities;
+ }
- return base.UpdateRangeAsync(dtos, token);
- }
+ private async Task<(IEnumerable items, int count)> GetWithDaysAndNpvAsync(WellOperationRequest request, CancellationToken token)
+ {
+ var skip = request.Skip ?? 0;
+ var take = request.Take ?? 32;
- private static void EnsureValidWellOperations(IEnumerable dtos)
- {
- if (dtos.GroupBy(d => d.IdType).Count() > 1)
- throw new ArgumentInvalidException(nameof(dtos), "Все операции должны быть одного типа");
+ var entities = await GetByIdsWells(request.IdsWell, token);
+ var groupedByWellAndType = entities
+ .GroupBy(e => new { e.IdWell, e.IdType });
- if (dtos.GroupBy(d => d.IdType).Count() > 1)
- throw new ArgumentInvalidException(nameof(dtos), "Все операции должны принадлежать одной скважине");
- }
+ var result = new List();
+ var count = 0;
+ foreach (var wellOperationsWithType in groupedByWellAndType)
+ {
+ var firstWellOperation = wellOperationsWithType
+ .OrderBy(e => e.DateStart)
+ .FirstOrDefault()!;
- private IQueryable BuildQuery(WellOperationRequest request)
- {
- var query = GetQuery()
- .Where(e => request.IdsWell != null && request.IdsWell.Contains(e.IdWell))
- .OrderBy(e => e.DateStart)
- .AsQueryable();
+ var operationsWithNpt = wellOperationsWithType
+ .Where(o => WellOperationCategory.NonProductiveTimeSubIds.Contains(o.IdCategory));
- if (request.OperationType.HasValue)
- query = query.Where(e => e.IdType == request.OperationType.Value);
+ IEnumerable filteredWellOperations = FilterByRequest(wellOperationsWithType.AsQueryable(), request);
- if (request.SectionTypeIds?.Any() is true)
- query = query.Where(e => request.SectionTypeIds.Contains(e.IdWellSectionType));
+ var filteredWellOperationsPart = filteredWellOperations
+ .Skip(skip)
+ .Take(take);
- if (request.OperationCategoryIds?.Any() is true)
- query = query.Where(e => request.OperationCategoryIds.Contains(e.IdCategory));
+ var dtos = filteredWellOperationsPart
+ .Select(entity =>
+ {
+ var dto = Convert(entity);
+ dto.Day = (entity.DateStart - firstWellOperation.DateStart).TotalDays;
+ dto.NptHours = operationsWithNpt
+ .Where(o => o.DateStart <= entity.DateStart)
+ .Sum(e => e.DurationHours);
+ return dto;
+ });
- if (request.GeDepth.HasValue)
- query = query.Where(e => e.DepthEnd >= request.GeDepth.Value);
+ result.AddRange(dtos);
+ count += filteredWellOperations.Count();
+ }
- if (request.LeDepth.HasValue)
- query = query.Where(e => e.DepthEnd <= request.LeDepth.Value);
+ return (result, count);
+ }
- if (request.GeDate.HasValue)
- {
- var geDateUtc = request.GeDate.Value.UtcDateTime;
- query = query.Where(e => e.DateStart >= geDateUtc);
- }
+ private static IQueryable FilterByRequest(IQueryable entities, WellOperationRequest request)
+ {
+ if (request.OperationType.HasValue)
+ entities = entities.Where(e => e.IdType == request.OperationType.Value);
+ if (request.SectionTypeIds?.Any() is true)
+ entities = entities.Where(e => request.SectionTypeIds.Contains(e.IdWellSectionType));
+ if (request.OperationCategoryIds?.Any() is true)
+ entities = entities.Where(e => request.OperationCategoryIds.Contains(e.IdCategory));
+ if (request.GeDepth.HasValue)
+ entities = entities.Where(e => e.DepthEnd >= request.GeDepth.Value);
+ if (request.LeDepth.HasValue)
+ entities = entities.Where(e => e.DepthEnd <= request.LeDepth.Value);
- if (request.LeDate.HasValue)
- {
- var leDateUtc = request.LeDate.Value.UtcDateTime;
- query = query.Where(e => e.DateStart <= leDateUtc);
- }
+ if (request.GeDate.HasValue)
+ {
+ var geDateUtc = request.GeDate.Value.UtcDateTime;
+ entities = entities.Where(e => e.DateStart >= geDateUtc);
+ }
- if (request.SortFields?.Any() is true)
- query = query.SortBy(request.SortFields);
+ if (request.LeDate.HasValue)
+ {
+ var leDateUtc = request.LeDate.Value.UtcDateTime;
+ entities = entities.Where(e => e.DateStart <= leDateUtc);
+ }
+ if (request.SortFields?.Any() is true)
+ entities = entities.AsQueryable().SortBy(request.SortFields);
+ else
+ entities = entities.AsQueryable().OrderBy(e => e.DateStart);
- return query;
- }
+ return entities;
+ }
- public async Task> GetSectionsAsync(IEnumerable idsWells, CancellationToken token)
- {
- const string keyCacheSections = "OperationsBySectionSummarties";
+ private IQueryable BuildQuery(WellOperationRequest request)
+ {
+ var query = GetQuery()
+ .Where(e => request.IdsWell.Contains(e.IdWell))
+ .OrderBy(e => e.DateStart)
+ .AsQueryable();
+ query = FilterByRequest(query, request);
- var cache = await memoryCache.GetOrCreateAsync(keyCacheSections, async (entry) =>
- {
- entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30);
+ return query;
+ }
- var query = dbContext.Set()
- .GroupBy(operation => new
- {
- operation.IdWell,
- operation.IdType,
- operation.IdWellSectionType,
- operation.WellSectionType.Caption,
- })
- .Select(group => new
- {
- group.Key.IdWell,
- group.Key.IdType,
- group.Key.IdWellSectionType,
- group.Key.Caption,
+ public async Task> GetSectionsAsync(IEnumerable idsWells, CancellationToken token)
+ {
+ const string keyCacheSections = "OperationsBySectionSummarties";
- First = group
- .OrderBy(operation => operation.DateStart)
- .Select(operation => new
- {
- operation.DateStart,
- operation.DepthStart,
- })
- .First(),
+ var cache = await memoryCache.GetOrCreateAsync(keyCacheSections, async (entry) =>
+ {
+ entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30);
- Last = group
- .OrderByDescending(operation => operation.DateStart)
- .Select(operation => new
- {
- operation.DateStart,
- operation.DurationHours,
- operation.DepthEnd,
- })
- .First(),
- })
- .Where(s => idsWells.Contains(s.IdWell));
- var dbData = await query.ToArrayAsync(token);
- var sections = dbData.Select(
- item => new SectionByOperationsDto
- {
- IdWell = item.IdWell,
- IdType = item.IdType,
- IdWellSectionType = item.IdWellSectionType,
+ var query = dbContext.Set()
+ .GroupBy(operation => new
+ {
+ operation.IdWell,
+ operation.IdType,
+ operation.IdWellSectionType,
+ operation.WellSectionType.Caption,
+ })
+ .Select(group => new
+ {
+ group.Key.IdWell,
+ group.Key.IdType,
+ group.Key.IdWellSectionType,
+ group.Key.Caption,
- Caption = item.Caption,
+ First = group
+ .OrderBy(operation => operation.DateStart)
+ .Select(operation => new
+ {
+ operation.DateStart,
+ operation.DepthStart,
+ })
+ .First(),
- DateStart = item.First.DateStart,
- DepthStart = item.First.DepthStart,
+ Last = group
+ .OrderByDescending(operation => operation.DateStart)
+ .Select(operation => new
+ {
+ operation.DateStart,
+ operation.DurationHours,
+ operation.DepthEnd,
+ })
+ .First(),
+ })
+ .Where(s => idsWells.Contains(s.IdWell));
+ var dbData = await query.ToArrayAsync(token);
+ var sections = dbData.Select(
+ item => new SectionByOperationsDto
+ {
+ IdWell = item.IdWell,
+ IdType = item.IdType,
+ IdWellSectionType = item.IdWellSectionType,
- DateEnd = item.Last.DateStart.AddHours(item.Last.DurationHours),
- DepthEnd = item.Last.DepthEnd,
- })
- .ToArray()
- .AsEnumerable();
+ Caption = item.Caption,
- entry.Value = sections;
- return sections;
- });
+ DateStart = item.First.DateStart,
+ DepthStart = item.First.DepthStart,
- return cache;
- }
+ DateEnd = item.Last.DateStart.AddHours(item.Last.DurationHours),
+ DepthEnd = item.Last.DepthEnd,
+ })
+ .ToArray()
+ .AsEnumerable();
- public async Task GetDatesRangeAsync(int idWell, int idType, CancellationToken cancellationToken)
- {
- var query = dbContext.WellOperations.Where(o => o.IdWell == idWell && o.IdType == idType);
+ entry.Value = sections;
+ return sections;
+ });
- if (!await query.AnyAsync(cancellationToken))
- return null;
+ return cache!;
+ }
- var timeZoneOffset = wellService.GetTimezone(idWell).Offset;
-
- var minDate = await query.MinAsync(o => o.DateStart, cancellationToken);
- var maxDate = await query.MaxAsync(o => o.DateStart, cancellationToken);
+ public async Task GetDatesRangeAsync(int idWell, int idType, CancellationToken cancellationToken)
+ {
+ var query = dbContext.WellOperations.Where(o => o.IdWell == idWell && o.IdType == idType);
- return new DatesRangeDto
- {
- From = minDate.ToOffset(timeZoneOffset),
- To = maxDate.ToOffset(timeZoneOffset)
- };
- }
+ if (!await query.AnyAsync(cancellationToken))
+ return null;
- private async Task> ConvertWithDrillingDaysAndNpvHoursAsync(IEnumerable entities,
- CancellationToken token)
- {
- var idsWell = entities.Select(e => e.IdWell).Distinct();
+ var timeZoneOffset = wellService.GetTimezone(idWell).Offset;
- var currentWellOperations = GetQuery()
- .Where(entity => idsWell.Contains(entity.IdWell));
+ var minDate = await query.MinAsync(o => o.DateStart, cancellationToken);
+ var maxDate = await query.MaxAsync(o => o.DateStart, cancellationToken);
- var dateFirstDrillingOperationByIdWell = await currentWellOperations
- .Where(entity => entity.IdType == WellOperation.IdOperationTypeFact)
- .GroupBy(entity => entity.IdWell)
- .ToDictionaryAsync(g => g.Key, g => g.Min(o => o.DateStart), token);
+ return new DatesRangeDto
+ {
+ From = minDate.ToOffset(timeZoneOffset),
+ To = maxDate.ToOffset(timeZoneOffset)
+ };
+ }
- var operationsWithNptByIdWell = await currentWellOperations.Where(entity =>
- entity.IdType == WellOperation.IdOperationTypeFact &&
- WellOperationCategory.NonProductiveTimeSubIds.Contains(entity.IdCategory))
- .GroupBy(entity => entity.IdWell)
- .ToDictionaryAsync(g => g.Key, g => g.Select(o => o), token);
+ protected override WellOperation Convert(WellOperationDto src)
+ {
+ var entity = src.Adapt();
+ entity.DateStart = src.DateStart.UtcDateTime;
+ return entity;
+ }
- var dtos = entities.Select(entity =>
- {
- var dto = Convert(entity);
+ protected override WellOperationDto Convert(WellOperation src)
+ {
+ //TODO: пока такое получение TimeZone скважины, нужно исправить на Lazy
+ //Хоть мы и тянем данные из кэша, но от получения TimeZone в этом методе нужно избавиться, пока так
+ var timeZoneOffset = wellService.GetTimezone(src.IdWell).Offset;
- if (dateFirstDrillingOperationByIdWell.TryGetValue(entity.IdWell, out var dateFirstDrillingOperation))
- dto.Day = (entity.DateStart - dateFirstDrillingOperation).TotalDays;
+ var dto = src.Adapt();
+ dto.DateStart = src.DateStart.ToOffset(timeZoneOffset);
+ dto.LastUpdateDate = src.LastUpdateDate.ToOffset(timeZoneOffset);
- if (operationsWithNptByIdWell.TryGetValue(entity.IdWell, out var wellOperationsWithNtp))
- dto.NptHours = wellOperationsWithNtp
- .Where(o => o.DateStart <= entity.DateStart)
- .Sum(e => e.DurationHours);
-
- return dto;
- });
-
- return dtos;
- }
-
- protected override WellOperation Convert(WellOperationDto src)
- {
- var entity = src.Adapt();
- entity.DateStart = src.DateStart.UtcDateTime;
- return entity;
- }
-
- protected override WellOperationDto Convert(WellOperation src)
- {
- //TODO: пока такое получение TimeZone скважины, нужно исправить на Lazy
- //Хоть мы и тянем данные из кэша, но от получения TimeZone в этом методе нужно избавиться, пока так
- var timeZoneOffset = wellService.GetTimezone(src.IdWell).Offset;
- var dto = src.Adapt();
- dto.DateStart = src.DateStart.ToOffset(timeZoneOffset);
- dto.LastUpdateDate = src.LastUpdateDate.ToOffset(timeZoneOffset);
- return dto;
- }
+ dto.OperationCategoryName = LazyWellCategories.Value.TryGetValue(src.IdCategory, out WellOperationCategoryDto? category) ? category.Name : string.Empty;
+ dto.WellSectionTypeCaption = LazyWellSectionTypes.Value.TryGetValue(src.IdWellSectionType, out WellSectionTypeDto? sectionType) ? sectionType.Caption : string.Empty;
+ return dto;
+ }
}
\ No newline at end of file
diff --git a/AsbCloudInfrastructure/Services/WellOperations/Templates/WellOperationFactTemplate.xlsx b/AsbCloudInfrastructure/Services/WellOperations/Templates/WellOperationFactTemplate.xlsx
index 928ffeb6..12fc2a44 100644
Binary files a/AsbCloudInfrastructure/Services/WellOperations/Templates/WellOperationFactTemplate.xlsx and b/AsbCloudInfrastructure/Services/WellOperations/Templates/WellOperationFactTemplate.xlsx differ
diff --git a/AsbCloudInfrastructure/Services/WellOperations/Templates/WellOperationPlanTemplate.xlsx b/AsbCloudInfrastructure/Services/WellOperations/Templates/WellOperationPlanTemplate.xlsx
index ffacf2e5..ca2d01c7 100644
Binary files a/AsbCloudInfrastructure/Services/WellOperations/Templates/WellOperationPlanTemplate.xlsx and b/AsbCloudInfrastructure/Services/WellOperations/Templates/WellOperationPlanTemplate.xlsx differ
diff --git a/AsbCloudWebApi.IntegrationTests/Controllers/WellOperations/Files/FactWellOperations.xlsx b/AsbCloudWebApi.IntegrationTests/Controllers/WellOperations/Files/FactWellOperations.xlsx
index 45ee8a0b..a7af0814 100644
Binary files a/AsbCloudWebApi.IntegrationTests/Controllers/WellOperations/Files/FactWellOperations.xlsx and b/AsbCloudWebApi.IntegrationTests/Controllers/WellOperations/Files/FactWellOperations.xlsx differ
diff --git a/AsbCloudWebApi.IntegrationTests/Controllers/WellOperations/Files/PlanWellOperations.xlsx b/AsbCloudWebApi.IntegrationTests/Controllers/WellOperations/Files/PlanWellOperations.xlsx
index 3083297e..d54dd669 100644
Binary files a/AsbCloudWebApi.IntegrationTests/Controllers/WellOperations/Files/PlanWellOperations.xlsx and b/AsbCloudWebApi.IntegrationTests/Controllers/WellOperations/Files/PlanWellOperations.xlsx differ
diff --git a/AsbCloudWebApi.IntegrationTests/Controllers/WellOperations/WellOperationControllerTest.cs b/AsbCloudWebApi.IntegrationTests/Controllers/WellOperations/WellOperationControllerTest.cs
index 9d05aea6..117ddae1 100644
--- a/AsbCloudWebApi.IntegrationTests/Controllers/WellOperations/WellOperationControllerTest.cs
+++ b/AsbCloudWebApi.IntegrationTests/Controllers/WellOperations/WellOperationControllerTest.cs
@@ -27,7 +27,7 @@ public class WellOperationControllerTest : BaseIntegrationTest
}
///
- /// Успешное добавление операций (без предварительной очистки данных)
+ /// ( )
///
///
[Fact]
@@ -46,7 +46,7 @@ public class WellOperationControllerTest : BaseIntegrationTest
}
///
- /// Успешное добавление операций (с предварительной очисткой данных)
+ /// ( )
///
///
[Fact]
@@ -65,7 +65,7 @@ public class WellOperationControllerTest : BaseIntegrationTest
}
///
- /// Успешное обновление операций
+ ///
///
///
[Fact]
@@ -87,7 +87,7 @@ public class WellOperationControllerTest : BaseIntegrationTest
}
///
- /// Получение плановых операций
+ ///
///
///
[Fact]
@@ -144,7 +144,7 @@ public class WellOperationControllerTest : BaseIntegrationTest
IdWellSectionType = 2,
IdCategory = WellOperationCategory.IdSlide,
IdPlan = null,
- CategoryInfo = "Доп.инфо",
+ CategoryInfo = ".",
IdType = idType,
DepthStart = 10.0,
DepthEnd = 20.0,
@@ -201,7 +201,7 @@ public class WellOperationControllerTest : BaseIntegrationTest
var stream = responseTemplate.Content;
using var workbook = new XLWorkbook(stream);
- var sheet = workbook.GetWorksheet("Справочники");
+ var sheet = workbook.GetWorksheet("");
var count = sheet.RowsUsed().Count() - 1;
@@ -230,21 +230,75 @@ public class WellOperationControllerTest : BaseIntegrationTest
Assert.True(notExistedInDb.Count() == 0);
}
- private static WellOperation CreateWellOperation(int idWell, int idType = WellOperation.IdOperationTypePlan) =>
- new()
- {
- IdWell = idWell,
- IdWellSectionType = 2,
- IdCategory = WellOperationCategory.IdSlide,
- IdPlan = null,
- CategoryInfo = "Доп.инфо",
- LastUpdateDate = new DateTimeOffset(new DateTime(2023, 1, 10)).ToUniversalTime(),
- IdType = idType,
- DepthStart = 10.0,
- DepthEnd = 20.0,
- DateStart = new DateTimeOffset(new DateTime(2023, 1, 10), TimeSpan.FromHours(Defaults.Timezone.Hours)).ToUniversalTime(),
- DurationHours = 1.0,
- Comment = "1",
- IdUser = 1,
+ [Theory]
+ [InlineData(WellOperation.IdOperationTypePlan)]
+ [InlineData(WellOperation.IdOperationTypeFact)]
+ public async Task GetPageOperationsAsyncWithDaysAndNpv_returns_success(int idType)
+ {
+ //arrange
+ const int pageSize = 10;
+ const int pageIndex = 0;
+
+ var well = await dbContext.Wells.FirstAsync();
+ var entity1 = CreateWellOperation(well.Id);
+
+ var entity2 = entity1.Adapt();
+ entity2.DateStart = entity2.DateStart.AddDays(1);
+ entity2.IdCategory = WellOperationCategory.IdEquipmentDrillingRepair;
+ entity2.DurationHours = 2;
+
+ var entity3 = entity2.Adapt();
+ entity3.DateStart = entity3.DateStart.AddDays(1);
+ entity3.IdCategory = WellOperationCategory.IdEquipmentDrillingRepair;
+ entity3.DurationHours = 3;
+
+ dbContext.WellOperations.Add(entity1);
+ dbContext.WellOperations.Add(entity2);
+ dbContext.WellOperations.Add(entity3);
+
+ await dbContext.SaveChangesAsync();
+
+ var request = new WellOperationRequestBase
+ {
+ OperationType = WellOperation.IdOperationTypePlan,
+ Skip = pageIndex,
+ Take = pageSize,
+ SortFields = [nameof(WellOperation.DateStart)]
};
+
+ //act
+ var response = await client.GetPageOperationsAsync(well.Id, request);
+
+ //assert
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ Assert.NotNull(response.Content);
+
+ var items = response.Content.Items.ToArray();
+
+ Assert.Equal(0, items[0].Day);
+ Assert.Equal(1, items[1].Day);
+ Assert.Equal(2, items[2].Day);
+
+ Assert.Equal(0, items[0].NptHours);
+ Assert.Equal(2, items[1].NptHours);
+ Assert.Equal(5, items[2].NptHours);
+ }
+
+ private static WellOperation CreateWellOperation(int idWell, int idType = WellOperation.IdOperationTypePlan) =>
+ new()
+ {
+ IdWell = idWell,
+ IdWellSectionType = 2,
+ IdCategory = WellOperationCategory.IdSlide,
+ IdPlan = null,
+ CategoryInfo = ".",
+ LastUpdateDate = new DateTimeOffset(new DateTime(2023, 1, 10)).ToUniversalTime(),
+ IdType = idType,
+ DepthStart = 10.0,
+ DepthEnd = 20.0,
+ DateStart = new DateTimeOffset(new DateTime(2023, 1, 10), TimeSpan.FromHours(Defaults.Timezone.Hours)).ToUniversalTime(),
+ DurationHours = 1.0,
+ Comment = "1",
+ IdUser = 1,
+ };
}
\ No newline at end of file