Merge branch 'dev' into feature/change-log-refactoring

This commit is contained in:
on.nemtina 2024-05-20 14:12:06 +05:00
commit 6af038496c
31 changed files with 1217 additions and 563 deletions

View File

@ -19,15 +19,6 @@ namespace AsbCloudApp.Repositories
Task<IEnumerable<DepositDto>> GetAsync(int idCompany, Task<IEnumerable<DepositDto>> GetAsync(int idCompany,
CancellationToken token); CancellationToken token);
/// <summary>
/// Список месторождений/кустов/скважин у которых заполненны параметры бурения
/// </summary>
/// <param name="idCompany"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<DepositDto>> GetAllWithDrillParamsAsync(int idCompany,
CancellationToken token = default);
/// <summary> /// <summary>
/// Список кустов месторождения доступных компании /// Список кустов месторождения доступных компании
/// </summary> /// </summary>

View File

@ -1,9 +1,9 @@
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Data.WellOperation;
using AsbCloudApp.Requests;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Data.WellOperation;
using AsbCloudApp.Requests;
namespace AsbCloudApp.Repositories namespace AsbCloudApp.Repositories
{ {
@ -18,7 +18,7 @@ namespace AsbCloudApp.Repositories
/// <returns></returns> /// <returns></returns>
IEnumerable<WellSectionTypeDto> GetSectionTypes(); IEnumerable<WellSectionTypeDto> GetSectionTypes();
/// <summary> /// <summary>
/// Получить страницу списка операций /// Получить страницу списка операций
/// </summary> /// </summary>
/// <param name="request"></param> /// <param name="request"></param>
@ -26,7 +26,7 @@ namespace AsbCloudApp.Repositories
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<WellOperationDto>> GetAsync(WellOperationRequest request, CancellationToken token); Task<IEnumerable<WellOperationDto>> GetAsync(WellOperationRequest request, CancellationToken token);
/// <summary> /// <summary>
/// Получить страницу списка операций /// Получить страницу списка операций
/// </summary> /// </summary>
/// <param name="request"></param> /// <param name="request"></param>
@ -34,7 +34,7 @@ namespace AsbCloudApp.Repositories
/// <returns></returns> /// <returns></returns>
Task<PaginationContainer<WellOperationDto>> GetPageAsync(WellOperationRequest request, CancellationToken token); Task<PaginationContainer<WellOperationDto>> GetPageAsync(WellOperationRequest request, CancellationToken token);
/// <summary> /// <summary>
/// Получить статистику операции по скважине с группировкой по категориям /// Получить статистику операции по скважине с группировкой по категориям
/// </summary> /// </summary>
/// <param name="request"></param> /// <param name="request"></param>
@ -42,19 +42,19 @@ namespace AsbCloudApp.Repositories
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<WellGroupOpertionDto>> GetGroupOperationsStatAsync(WellOperationRequest request, CancellationToken token); Task<IEnumerable<WellGroupOpertionDto>> GetGroupOperationsStatAsync(WellOperationRequest request, CancellationToken token);
/// <summary> /// <summary>
/// Добавить несколько операций /// Добавить несколько операций
/// </summary> /// </summary>
/// <param name="dtos"></param> /// <param name="dtos"></param>
/// <param name="deleteBeforeInsert"></param> /// <param name="deleteBeforeInsert"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<int> InsertRangeAsync(IEnumerable<WellOperationDto> dtos, bool deleteBeforeInsert, CancellationToken token); Task<int> InsertRangeAsync(IEnumerable<WellOperationDto> dtos, bool deleteBeforeInsert, CancellationToken token);
/// <summary> /// <summary>
/// Обновить существующую операцию /// Обновить существующую операцию
/// </summary> /// </summary>
/// <param name="dto"></param> /// <param name="dtos"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<int> UpdateRangeAsync(IEnumerable<WellOperationDto> dtos, CancellationToken token); Task<int> UpdateRangeAsync(IEnumerable<WellOperationDto> dtos, CancellationToken token);
@ -75,13 +75,20 @@ namespace AsbCloudApp.Repositories
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<SectionByOperationsDto>> GetSectionsAsync(IEnumerable<int> idsWells, CancellationToken token); Task<IEnumerable<SectionByOperationsDto>> GetSectionsAsync(IEnumerable<int> idsWells, CancellationToken token);
/// <summary> /// <summary>
/// Получить диапазон дат выполнения операций /// Получить диапазон дат выполнения операций
/// </summary> /// </summary>
/// <param name="idWell"></param> /// <param name="idWell"></param>
/// <param name="idType"></param> /// <param name="idType"></param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
Task<DatesRangeDto?> GetDatesRangeAsync(int idWell, int idType, CancellationToken cancellationToken); Task<DatesRangeDto?> GetDatesRangeAsync(int idWell, int idType, CancellationToken cancellationToken);
}
/// <summary>
/// Возвращает первую и последнюю фактическую операцию
/// </summary>
/// <param name="idWell"></param>
/// <returns></returns>
(WellOperationDto First, WellOperationDto Last)? GetFirstAndLastFact(int idWell);
}
} }

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Requests; namespace AsbCloudApp.Requests;
@ -8,44 +9,72 @@ namespace AsbCloudApp.Requests;
/// </summary> /// </summary>
public class WellOperationRequestBase : RequestBase public class WellOperationRequestBase : RequestBase
{ {
/// <summary> /// <summary>
/// Больше или равно дате начала операции /// Больше или равно дате начала операции
/// </summary> /// </summary>
public DateTimeOffset? GeDate { get; set; } public DateTimeOffset? GeDate { get; set; }
/// <summary> /// <summary>
/// Меньше или равно дате окончания операции /// Меньше или равно дате окончания операции
/// </summary> /// </summary>
public DateTimeOffset? LeDate { get; set; } public DateTimeOffset? LeDate { get; set; }
/// <summary> /// <summary>
/// Больше или равно глубины скважины на начало операции. /// Больше или равно глубины скважины на начало операции.
/// </summary> /// </summary>
public double? GeDepth { get; set; } public double? GeDepth { get; set; }
/// <summary> /// <summary>
/// Меньше или равно глубины скважины на конец операции. /// Меньше или равно глубины скважины на конец операции.
/// </summary> /// </summary>
public double? LeDepth { get; set; } public double? LeDepth { get; set; }
/// <summary> /// <summary>
/// Идентификаторы категорий операции /// Идентификаторы категорий операции
/// </summary> /// </summary>
public IEnumerable<int>? OperationCategoryIds { get; set; } public IEnumerable<int>? OperationCategoryIds { get; set; }
/// <summary> /// <summary>
/// Тип операций /// Тип операций
/// <list type="bullet"> /// <list type="bullet">
/// <item>0 - плановая операция</item> /// <item>0 - плановая операция</item>
/// <item>1 - фактическая операция</item> /// <item>1 - фактическая операция</item>
/// </list> /// </list>
/// </summary> /// </summary>
public int? OperationType { get; set; } public int? OperationType { get; set; }
/// <summary> /// <summary>
/// Идентификаторы конструкций секции /// Идентификаторы конструкций секции
/// </summary> /// </summary>
public IEnumerable<int>? SectionTypeIds { get; set; } public IEnumerable<int>? SectionTypeIds { get; set; }
/// <summary>
///
/// </summary>
public WellOperationRequestBase()
{
}
/// <summary>
///
/// </summary>
/// <param name="request"></param>
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;
}
} }
/// <summary> /// <summary>
@ -53,32 +82,23 @@ public class WellOperationRequestBase : RequestBase
/// </summary> /// </summary>
public class WellOperationRequest : WellOperationRequestBase public class WellOperationRequest : WellOperationRequestBase
{ {
/// <inheritdoc /> /// <inheritdoc />
public WellOperationRequest(IEnumerable<int> idsWell) public WellOperationRequest(IEnumerable<int> idsWell)
{ {
IdsWell = idsWell; IdsWell = idsWell;
} }
/// <inheritdoc /> /// <inheritdoc />
public WellOperationRequest(WellOperationRequestBase request, IEnumerable<int> idsWell) public WellOperationRequest(WellOperationRequestBase request, IEnumerable<int> idsWell)
: this(idsWell) : base(request)
{ {
GeDepth = request.GeDepth; IdsWell = idsWell;
LeDepth = request.LeDepth; }
GeDate = request.GeDate;
LeDate = request.LeDate;
OperationCategoryIds = request.OperationCategoryIds; /// <summary>
OperationType = request.OperationType; /// Идентификаторы скважин
SectionTypeIds = request.SectionTypeIds; /// </summary>
[Required]
Skip = request.Skip; [Length(1, 100)]
Take = request.Take; public IEnumerable<int> IdsWell { get; }
SortFields = request.SortFields;
}
/// <summary>
/// Идентификаторы скважин
/// </summary>
public IEnumerable<int>? IdsWell { get; }
} }

View File

@ -223,11 +223,12 @@ namespace AsbCloudDb
private static string FormatValue(object? v) private static string FormatValue(object? v)
=> v switch => v switch
{ {
null => "NULL",
string vStr => $"'{EscapeCurlyBraces(vStr)}'", string vStr => $"'{EscapeCurlyBraces(vStr)}'",
DateTime vDate => $"'{FormatDateValue(vDate)}'", DateTime vDate => $"'{FormatDateValue(vDate)}'",
DateTimeOffset vDate => $"'{FormatDateValue(vDate.UtcDateTime)}'", DateTimeOffset vDate => $"'{FormatDateValue(vDate.UtcDateTime)}'",
IFormattable vFormattable => FormatFormattableValue(vFormattable), IFormattable vFormattable => FormatFormattableValue(vFormattable),
_ => System.Text.Json.JsonSerializer.Serialize(v), _ => $"'{EscapeCurlyBraces(JsonSerializer.Serialize(v))}'",
}; };
private static string EscapeCurlyBraces(string vStr) private static string EscapeCurlyBraces(string vStr)

View File

@ -10,118 +10,100 @@ using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Repository namespace AsbCloudInfrastructure.Repository;
public class DepositRepository : IDepositRepository
{ {
private readonly IAsbCloudDbContext db;
private readonly ITelemetryService telemetryService;
public class DepositRepository : IDepositRepository public DepositRepository(IAsbCloudDbContext db, ITelemetryService telemetryService)
{ {
private readonly IAsbCloudDbContext db; this.db = db;
private readonly IWellService wellService; this.telemetryService = telemetryService;
public DepositRepository(IAsbCloudDbContext db, IWellService wellService)
{
this.db = db;
this.wellService = wellService;
}
/// <inheritdoc/>
public async Task<IEnumerable<DepositDto>> GetAsync(int idCompany,
CancellationToken token = default)
{
var wellEntities = await (from well in db.Wells
.Include(w => w.RelationCompaniesWells)
.Include(w => w.WellType)
.Include(w => w.Cluster)
.ThenInclude(c => c.Deposit)
where well.RelationCompaniesWells.Any(r => r.IdCompany == idCompany)
select well).ToListAsync(token)
.ConfigureAwait(false);
var gDepositEntities = GroupWells(wellEntities);
var dtos = CreateDepositDto(gDepositEntities);
return dtos;
}
/// <inheritdoc/>
public async Task<IEnumerable<DepositDto>> GetAllWithDrillParamsAsync(int idCompany,
CancellationToken token = default)
{
var wellEntities = await (from well in db.Wells
.Include(w => w.RelationCompaniesWells)
.Include(w => w.WellType)
.Include(w => w.Cluster)
.ThenInclude(c => c.Deposit)
where well.RelationCompaniesWells.Any(r => r.IdCompany == idCompany)
select well).ToListAsync(token)
.ConfigureAwait(false);
var gDepositEntities = GroupWells(wellEntities);
var dtos = CreateDepositDto(gDepositEntities);
return dtos;
}
/// <inheritdoc/>
public async Task<IEnumerable<ClusterDto>> GetClustersAsync(int idCompany,
int depositId, CancellationToken token = default)
{
var entities = await GetWellsForCompany(idCompany)
.Select(e => e.Cluster)
.Where(e => e.IdDeposit == depositId)
.Distinct()
.AsNoTracking()
.ToListAsync(token)
.ConfigureAwait(false);
var dtos = entities.Adapt<IEnumerable<ClusterDto>>();
return dtos;
}
private static IEnumerable<IGrouping<Deposit, IGrouping<Cluster, Well>>> GroupWells(IEnumerable<Well> wellEntities)
=> wellEntities
.GroupBy(w => w.Cluster)
.GroupBy(c => c.Key.Deposit);
private IQueryable<Well> GetWellsForCompany(int idCompany)
=> db.Wells
.Include(w => w.RelationCompaniesWells)
.ThenInclude(r => r.Company)
.Include(w => w.Cluster)
.ThenInclude(c => c.Deposit)
.Where(w => w.RelationCompaniesWells.Any(c => c.IdCompany == idCompany));
private IEnumerable<DepositDto> CreateDepositDto(IEnumerable<IGrouping<Deposit, IGrouping<Cluster, Well>>> gDepositEntities)
{
var dtos = gDepositEntities.Select(gDeposit => new DepositDto
{
Id = gDeposit.Key.Id,
Caption = gDeposit.Key.Caption,
Latitude = gDeposit.Key.Latitude,
Longitude = gDeposit.Key.Longitude,
Clusters = gDeposit.Select(gCluster => new ClusterDto
{
Id = gCluster.Key.Id,
Caption = gCluster.Key.Caption,
Latitude = gCluster.Key.Latitude,
Longitude = gCluster.Key.Longitude,
Wells = gCluster.Select(well =>
{
var dto = well.Adapt<WellDto>();
dto.WellType = well.WellType.Caption;
dto.LastTelemetryDate = wellService.GetLastTelemetryDate(well.Id)
.ToOffset(TimeSpan.FromHours(well.Timezone.Hours));
dto.Cluster = gCluster.Key.Caption;
dto.Deposit = gDeposit.Key.Caption;
return dto;
}),
}),
});
return dtos;
}
} }
/// <inheritdoc/>
public async Task<IEnumerable<DepositDto>> GetAsync(int idCompany,
CancellationToken token = default)
{
var wellsQuery = db.Set<Well>()
.Include(w => w.RelationCompaniesWells)
.Include(w => w.WellType)
.Include(w => w.Cluster)
.ThenInclude(c => c.Deposit)
.Where(well => well.RelationCompaniesWells.Any(r => r.IdCompany == idCompany));
var wellEntities = await wellsQuery.ToArrayAsync(token);
var gDepositEntities = GroupWells(wellEntities);
var dtos = CreateDepositDto(gDepositEntities)
.ToArray();
return dtos;
}
/// <inheritdoc/>
public async Task<IEnumerable<ClusterDto>> GetClustersAsync(int idCompany,
int depositId, CancellationToken token = default)
{
var entities = await GetWellsForCompany(idCompany)
.Select(e => e.Cluster)
.Where(e => e.IdDeposit == depositId)
.Distinct()
.AsNoTracking()
.ToListAsync(token)
.ConfigureAwait(false);
var dtos = entities.Adapt<IEnumerable<ClusterDto>>();
return dtos;
}
private static IEnumerable<IGrouping<Deposit, IGrouping<Cluster, Well>>> GroupWells(IEnumerable<Well> wellEntities)
=> wellEntities
.GroupBy(w => w.Cluster)
.GroupBy(c => c.Key.Deposit);
private IQueryable<Well> GetWellsForCompany(int idCompany)
=> db.Set<Well>()
.Include(w => w.RelationCompaniesWells)
.ThenInclude(r => r.Company)
.Include(w => w.Cluster)
.ThenInclude(c => c.Deposit)
.Where(w => w.RelationCompaniesWells.Any(c => c.IdCompany == idCompany));
private IEnumerable<DepositDto> CreateDepositDto(IEnumerable<IGrouping<Deposit, IGrouping<Cluster, Well>>> gDepositEntities)
{
var dtos = gDepositEntities.Select(gDeposit => new DepositDto
{
Id = gDeposit.Key.Id,
Caption = gDeposit.Key.Caption,
Latitude = gDeposit.Key.Latitude,
Longitude = gDeposit.Key.Longitude,
Clusters = gDeposit.Select(gCluster => new ClusterDto
{
Id = gCluster.Key.Id,
Caption = gCluster.Key.Caption,
Latitude = gCluster.Key.Latitude,
Longitude = gCluster.Key.Longitude,
Wells = gCluster.Select(well =>
{
var dto = well.Adapt<WellDto>();
dto.WellType = well.WellType.Caption;
dto.LastTelemetryDate = DateTimeOffset.MinValue;
if (well.IdTelemetry != null)
dto.LastTelemetryDate = telemetryService.GetDatesRange(well.IdTelemetry.Value).To;
dto.Cluster = gCluster.Key.Caption;
dto.Deposit = gDeposit.Key.Caption;
return dto;
}),
}),
});
return dtos;
}
} }

View File

@ -2,6 +2,7 @@
using AsbCloudApp.Exceptions; using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories; using AsbCloudApp.Repositories;
using AsbCloudApp.Requests; using AsbCloudApp.Requests;
using AsbCloudDb;
using AsbCloudDb.Model; using AsbCloudDb.Model;
using Mapster; using Mapster;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -68,11 +69,12 @@ namespace AsbCloudInfrastructure.Repository
var entities = dtos.Select(dto => var entities = dtos.Select(dto =>
{ {
var entity = dto.Adapt<DrillTest>(); var entity = dto.Adapt<DrillTest>();
entity.TimeStampStart = dto.TimeStampStart.ToUniversalTime();
entity.IdTelemetry = idTelemetry; entity.IdTelemetry = idTelemetry;
return entity; return entity;
}); });
db.DrillTests.AddRange(entities);
var result = await db.SaveChangesAsync(token); var result = await db.Database.ExecInsertOrUpdateAsync(db.Set<DrillTest>(), entities, token);
return result; return result;
} }

View File

@ -1,9 +1,4 @@
using System; using AsbCloudApp.Data;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Data.WellOperation; using AsbCloudApp.Data.WellOperation;
using AsbCloudApp.Exceptions; using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories; using AsbCloudApp.Repositories;
@ -14,350 +9,436 @@ using AsbCloudDb.Model;
using Mapster; using Mapster;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Repository; namespace AsbCloudInfrastructure.Repository;
public class WellOperationRepository : CrudRepositoryBase<WellOperationDto, WellOperation>, public class WellOperationRepository : CrudRepositoryBase<WellOperationDto, WellOperation>,
IWellOperationRepository IWellOperationRepository
{ {
private readonly IMemoryCache memoryCache; private const string cacheKeyWellOperations = "FirstAndLastFactWellsOperations";
private readonly IWellOperationCategoryRepository wellOperationCategoryRepository; private readonly IMemoryCache memoryCache;
private readonly IWellService wellService; private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
private readonly IWellService wellService;
private Lazy<IDictionary<int, WellOperationCategoryDto>> LazyWellCategories { get; }
private Lazy<IDictionary<int, WellSectionTypeDto>> LazyWellSectionTypes { get; }
public WellOperationRepository(IAsbCloudDbContext context, public WellOperationRepository(IAsbCloudDbContext context,
IMemoryCache memoryCache, IMemoryCache memoryCache,
IWellOperationCategoryRepository wellOperationCategoryRepository, IWellOperationCategoryRepository wellOperationCategoryRepository,
IWellService wellService) IWellService wellService)
: base(context, dbSet => dbSet.Include(e => e.WellSectionType) : base(context, dbSet => dbSet)
.Include(e => e.OperationCategory)) {
{ this.memoryCache = memoryCache;
this.memoryCache = memoryCache; this.wellOperationCategoryRepository = wellOperationCategoryRepository;
this.wellOperationCategoryRepository = wellOperationCategoryRepository; this.wellService = wellService;
this.wellService = wellService;
}
public IEnumerable<WellSectionTypeDto> GetSectionTypes() => LazyWellCategories = new(() => wellOperationCategoryRepository.Get(true, false).ToDictionary(c => c.Id));
memoryCache LazyWellSectionTypes = new(() => GetSectionTypes().ToDictionary(c => c.Id));
.GetOrCreateBasic(dbContext.WellSectionTypes) }
.OrderBy(s => s.Order)
.Select(s => s.Adapt<WellSectionTypeDto>());
public async Task<IEnumerable<WellOperationDto>> GetAsync(WellOperationRequest request, CancellationToken token) public IEnumerable<WellSectionTypeDto> GetSectionTypes() =>
{ memoryCache
var query = BuildQuery(request); .GetOrCreateBasic(dbContext.WellSectionTypes)
.OrderBy(s => s.Order)
.Select(s => s.Adapt<WellSectionTypeDto>());
if (request.Skip.HasValue) public async Task<IEnumerable<WellOperationDto>> GetAsync(WellOperationRequest request, CancellationToken token)
query = query.Skip(request.Skip.Value); {
var (items, _) = await GetWithDaysAndNpvAsync(request, token);
return items;
}
if (request.Take.HasValue) public async Task<PaginationContainer<WellOperationDto>> GetPageAsync(WellOperationRequest request, CancellationToken token)
query = query.Take(request.Take.Value); {
request.Skip = request.Skip ?? 0;
request.Take = request.Take ?? 32;
var entities = await query.AsNoTracking() var (items, count) = await GetWithDaysAndNpvAsync(request, token);
.ToArrayAsync(token);
return await ConvertWithDrillingDaysAndNpvHoursAsync(entities, token); var paginationContainer = new PaginationContainer<WellOperationDto>
} {
Skip = request.Skip!.Value,
Take = request.Take!.Value,
Count = count,
Items = items
};
public async Task<PaginationContainer<WellOperationDto>> GetPageAsync(WellOperationRequest request, CancellationToken token) return paginationContainer;
{ }
var skip = request.Skip ?? 0;
var take = request.Take ?? 32;
var query = BuildQuery(request); public async Task<IEnumerable<WellGroupOpertionDto>> 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) var parentRelationDictionary = wellOperationCategoryRepository.Get(true)
.Take(take) .ToDictionary(c => c.Id, c => new
.AsNoTracking() {
.ToArrayAsync(token); c.Name,
c.IdParent
});
var paginationContainer = new PaginationContainer<WellOperationDto> var dtos = entities
{ .GroupBy(o => o.IdCategory)
Skip = skip, .Select(g => new WellGroupOpertionDto
Take = take, {
Count = await query.CountAsync(token), IdCategory = g.Key,
Items = await ConvertWithDrillingDaysAndNpvHoursAsync(entities, token) 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<IEnumerable<WellGroupOpertionDto>> GetGroupOperationsStatAsync(WellOperationRequest request, CancellationToken token) return dtos;
{ }
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 parentRelationDictionary = wellOperationCategoryRepository.Get(true) public async Task<int> InsertRangeAsync(IEnumerable<WellOperationDto> dtos,
.ToDictionary(c => c.Id, c => new bool deleteBeforeInsert,
{ CancellationToken token)
c.Name, {
c.IdParent EnsureValidWellOperations(dtos);
});
var dtos = entities var result = 0;
.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
});
while (dtos.All(x => x.IdParent != null)) if (!deleteBeforeInsert)
{ {
dtos = dtos result = await InsertRangeAsync(dtos, token);
.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;
});
}
return dtos; if (result > 0)
} memoryCache.Remove(cacheKeyWellOperations);
public async Task<int> InsertRangeAsync(IEnumerable<WellOperationDto> dtos, return result;
bool deleteBeforeInsert, }
CancellationToken token)
{
EnsureValidWellOperations(dtos);
if (!deleteBeforeInsert)
return await InsertRangeAsync(dtos, token);
var idType = dtos.First().IdType; var idType = dtos.First().IdType;
var idWell = dtos.First().IdWell; var idWell = dtos.First().IdWell;
var existingOperationIds = await dbContext.WellOperations var existingOperationIds = await dbContext.WellOperations
.Where(e => e.IdWell == idWell && e.IdType == idType) .Where(e => e.IdWell == idWell && e.IdType == idType)
.Select(e => e.Id) .Select(e => e.Id)
.ToArrayAsync(token); .ToArrayAsync(token);
await DeleteRangeAsync(existingOperationIds, token); await DeleteRangeAsync(existingOperationIds, token);
return await InsertRangeAsync(dtos, token); result = await InsertRangeAsync(dtos, token);
}
public override Task<int> UpdateRangeAsync(IEnumerable<WellOperationDto> dtos, CancellationToken token) if (result > 0)
{ memoryCache.Remove(cacheKeyWellOperations);
EnsureValidWellOperations(dtos);
return base.UpdateRangeAsync(dtos, token); return result;
}
private static void EnsureValidWellOperations(IEnumerable<WellOperationDto> dtos) }
{
if (dtos.GroupBy(d => d.IdType).Count() > 1)
throw new ArgumentInvalidException(nameof(dtos), "Все операции должны быть одного типа");
if (dtos.GroupBy(d => d.IdType).Count() > 1) public override async Task<int> UpdateRangeAsync(IEnumerable<WellOperationDto> dtos, CancellationToken token)
throw new ArgumentInvalidException(nameof(dtos), "Все операции должны принадлежать одной скважине"); {
} EnsureValidWellOperations(dtos);
private IQueryable<WellOperation> BuildQuery(WellOperationRequest request) var result = await base.UpdateRangeAsync(dtos, token);
{
var query = GetQuery()
.Where(e => request.IdsWell != null && request.IdsWell.Contains(e.IdWell))
.OrderBy(e => e.DateStart)
.AsQueryable();
if (request.OperationType.HasValue) if (result > 0)
query = query.Where(e => e.IdType == request.OperationType.Value); memoryCache.Remove(cacheKeyWellOperations);
if (request.SectionTypeIds?.Any() is true) return result;
query = query.Where(e => request.SectionTypeIds.Contains(e.IdWellSectionType));
if (request.OperationCategoryIds?.Any() is true) }
query = query.Where(e => request.OperationCategoryIds.Contains(e.IdCategory));
if (request.GeDepth.HasValue) private static void EnsureValidWellOperations(IEnumerable<WellOperationDto> dtos)
query = query.Where(e => e.DepthEnd >= request.GeDepth.Value); {
if (dtos.GroupBy(d => d.IdType).Count() > 1)
throw new ArgumentInvalidException(nameof(dtos), "Все операции должны быть одного типа");
if (request.LeDepth.HasValue) if (dtos.GroupBy(d => d.IdType).Count() > 1)
query = query.Where(e => e.DepthEnd <= request.LeDepth.Value); throw new ArgumentInvalidException(nameof(dtos), "Все операции должны принадлежать одной скважине");
}
if (request.GeDate.HasValue) private async Task<IEnumerable<WellOperation>> GetByIdsWells(IEnumerable<int> idsWells, CancellationToken token)
{ {
var geDateUtc = request.GeDate.Value.UtcDateTime; var query = GetQuery()
query = query.Where(e => e.DateStart >= geDateUtc); .Where(e => idsWells.Contains(e.IdWell))
} .OrderBy(e => e.DateStart);
var entities = await query.ToArrayAsync(token);
return entities;
}
if (request.LeDate.HasValue) private async Task<(IEnumerable<WellOperationDto> items, int count)> GetWithDaysAndNpvAsync(WellOperationRequest request, CancellationToken token)
{ {
var leDateUtc = request.LeDate.Value.UtcDateTime; var entities = await GetByIdsWells(request.IdsWell, token);
query = query.Where(e => e.DateStart <= leDateUtc); var groupedByWellAndType = entities
} .GroupBy(e => new { e.IdWell, e.IdType });
if (request.SortFields?.Any() is true) var result = new List<WellOperationDto>();
query = query.SortBy(request.SortFields); var count = 0;
foreach (var wellOperationsWithType in groupedByWellAndType)
{
var firstWellOperation = wellOperationsWithType
.OrderBy(e => e.DateStart)
.FirstOrDefault()!;
return query; var operationsWithNpt = wellOperationsWithType
} .Where(o => WellOperationCategory.NonProductiveTimeSubIds.Contains(o.IdCategory));
public async Task<IEnumerable<SectionByOperationsDto>> GetSectionsAsync(IEnumerable<int> idsWells, CancellationToken token) IEnumerable<WellOperation> filteredWellOperations = FilterByRequest(wellOperationsWithType.AsQueryable(), request);
{
const string keyCacheSections = "OperationsBySectionSummarties";
var cache = await memoryCache.GetOrCreateAsync(keyCacheSections, async (entry) => count += filteredWellOperations.Count();
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30);
var query = dbContext.Set<WellOperation>() if (request.Skip != null)
.GroupBy(operation => new filteredWellOperations = filteredWellOperations.Skip((int)request.Skip);
{ if (request.Take != null)
operation.IdWell, filteredWellOperations = filteredWellOperations.Take((int)request.Take);
operation.IdType,
operation.IdWellSectionType,
operation.WellSectionType.Caption,
})
.Select(group => new
{
group.Key.IdWell,
group.Key.IdType,
group.Key.IdWellSectionType,
group.Key.Caption,
First = group var dtos = filteredWellOperations
.OrderBy(operation => operation.DateStart) .Select(entity =>
.Select(operation => new {
{ var dto = Convert(entity);
operation.DateStart, dto.Day = (entity.DateStart - firstWellOperation.DateStart).TotalDays;
operation.DepthStart, dto.NptHours = operationsWithNpt
}) .Where(o => o.DateStart <= entity.DateStart)
.First(), .Sum(e => e.DurationHours);
return dto;
});
Last = group result.AddRange(dtos);
.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,
Caption = item.Caption, return (result, count);
}
DateStart = item.First.DateStart, private static IQueryable<WellOperation> FilterByRequest(IQueryable<WellOperation> entities, WellOperationRequest request)
DepthStart = item.First.DepthStart, {
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);
DateEnd = item.Last.DateStart.AddHours(item.Last.DurationHours), if (request.GeDate.HasValue)
DepthEnd = item.Last.DepthEnd, {
}) var geDateUtc = request.GeDate.Value.UtcDateTime;
.ToArray() entities = entities.Where(e => e.DateStart >= geDateUtc);
.AsEnumerable(); }
entry.Value = sections; if (request.LeDate.HasValue)
return sections; {
}); 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 cache; return entities;
} }
public async Task<DatesRangeDto?> GetDatesRangeAsync(int idWell, int idType, CancellationToken cancellationToken) private IQueryable<WellOperation> BuildQuery(WellOperationRequest request)
{ {
var query = dbContext.WellOperations.Where(o => o.IdWell == idWell && o.IdType == idType); var query = GetQuery()
.Where(e => request.IdsWell.Contains(e.IdWell))
.OrderBy(e => e.DateStart)
.AsQueryable();
query = FilterByRequest(query, request);
if (!await query.AnyAsync(cancellationToken)) return query;
return null; }
var timeZoneOffset = wellService.GetTimezone(idWell).Offset; public async Task<IEnumerable<SectionByOperationsDto>> GetSectionsAsync(IEnumerable<int> idsWells, CancellationToken token)
{
const string keyCacheSections = "OperationsBySectionSummarties";
var minDate = await query.MinAsync(o => o.DateStart, cancellationToken); var cache = await memoryCache.GetOrCreateAsync(keyCacheSections, async (entry) =>
var maxDate = await query.MaxAsync(o => o.DateStart, cancellationToken); {
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30);
return new DatesRangeDto var query = dbContext.Set<WellOperation>()
{ .GroupBy(operation => new
From = minDate.ToOffset(timeZoneOffset), {
To = maxDate.ToOffset(timeZoneOffset) operation.IdWell,
}; operation.IdType,
} operation.IdWellSectionType,
operation.WellSectionType.Caption,
})
.Select(group => new
{
group.Key.IdWell,
group.Key.IdType,
group.Key.IdWellSectionType,
group.Key.Caption,
private async Task<IEnumerable<WellOperationDto>> ConvertWithDrillingDaysAndNpvHoursAsync(IEnumerable<WellOperation> entities, First = group
CancellationToken token) .OrderBy(operation => operation.DateStart)
{ .Select(operation => new
var idsWell = entities.Select(e => e.IdWell).Distinct(); {
operation.DateStart,
operation.DepthStart,
})
.First(),
var currentWellOperations = GetQuery() Last = group
.Where(entity => idsWell.Contains(entity.IdWell)); .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 dateFirstDrillingOperationByIdWell = await currentWellOperations Caption = item.Caption,
.Where(entity => entity.IdType == WellOperation.IdOperationTypeFact)
.GroupBy(entity => entity.IdWell)
.ToDictionaryAsync(g => g.Key, g => g.Min(o => o.DateStart), token);
var operationsWithNptByIdWell = await currentWellOperations.Where(entity => DateStart = item.First.DateStart,
entity.IdType == WellOperation.IdOperationTypeFact && DepthStart = item.First.DepthStart,
WellOperationCategory.NonProductiveTimeSubIds.Contains(entity.IdCategory))
.GroupBy(entity => entity.IdWell)
.ToDictionaryAsync(g => g.Key, g => g.Select(o => o), token);
var dtos = entities.Select(entity => DateEnd = item.Last.DateStart.AddHours(item.Last.DurationHours),
{ DepthEnd = item.Last.DepthEnd,
var dto = Convert(entity); })
.ToArray()
.AsEnumerable();
if (dateFirstDrillingOperationByIdWell.TryGetValue(entity.IdWell, out var dateFirstDrillingOperation)) entry.Value = sections;
dto.Day = (entity.DateStart - dateFirstDrillingOperation).TotalDays; return sections;
});
if (operationsWithNptByIdWell.TryGetValue(entity.IdWell, out var wellOperationsWithNtp)) return cache!;
dto.NptHours = wellOperationsWithNtp }
.Where(o => o.DateStart <= entity.DateStart)
.Sum(e => e.DurationHours);
return dto; public async Task<DatesRangeDto?> GetDatesRangeAsync(int idWell, int idType, CancellationToken cancellationToken)
}); {
var query = dbContext.WellOperations.Where(o => o.IdWell == idWell && o.IdType == idType);
return dtos; if (!await query.AnyAsync(cancellationToken))
} return null;
protected override WellOperation Convert(WellOperationDto src) var timeZoneOffset = wellService.GetTimezone(idWell).Offset;
{
var entity = src.Adapt<WellOperation>();
entity.DateStart = src.DateStart.UtcDateTime;
return entity;
}
protected override WellOperationDto Convert(WellOperation src) var minDate = await query.MinAsync(o => o.DateStart, cancellationToken);
{ var maxDate = await query.MaxAsync(o => o.DateStart, cancellationToken);
//TODO: пока такое получение TimeZone скважины, нужно исправить на Lazy
//Хоть мы и тянем данные из кэша, но от получения TimeZone в этом методе нужно избавиться, пока так return new DatesRangeDto
var timeZoneOffset = wellService.GetTimezone(src.IdWell).Offset; {
var dto = src.Adapt<WellOperationDto>(); From = minDate.ToOffset(timeZoneOffset),
dto.DateStart = src.DateStart.ToOffset(timeZoneOffset); To = maxDate.ToOffset(timeZoneOffset)
dto.LastUpdateDate = src.LastUpdateDate.ToOffset(timeZoneOffset); };
return dto; }
}
public (WellOperationDto First, WellOperationDto Last)? GetFirstAndLastFact(int idWell)
{
var cachedDictionary = memoryCache.GetOrCreate(cacheKeyWellOperations, (entry) =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5);
var query = dbContext.Set<WellOperation>()
.Where(o => o.IdType == WellOperation.IdOperationTypeFact)
.GroupBy(o => o.IdWell)
.Select(group => new
{
IdWell = group.Key,
FirstFact = group.OrderBy(o => o.DateStart).First(),
LastFact = group.OrderBy(o => o.DateStart).Last(),
});
var entities = query.ToArray();
var dictionary = entities.ToDictionary(s => s.IdWell, s => (Convert(s.FirstFact), Convert(s.LastFact)));
entry.Value = dictionary;
return dictionary;
})!;
var firstAndLast = cachedDictionary.GetValueOrDefault(idWell);
return firstAndLast;
}
public override async Task<int> DeleteAsync(int id, CancellationToken token)
{
var result = await base.DeleteAsync(id, token);
if (result > 0)
memoryCache.Remove(cacheKeyWellOperations);
return result;
}
public override async Task<int> DeleteRangeAsync(IEnumerable<int> ids, CancellationToken token)
{
var result = await base.DeleteRangeAsync(ids, token);
if (result > 0)
memoryCache.Remove(cacheKeyWellOperations);
return result;
}
protected override WellOperation Convert(WellOperationDto src)
{
var entity = src.Adapt<WellOperation>();
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<WellOperationDto>();
dto.DateStart = src.DateStart.ToOffset(timeZoneOffset);
dto.LastUpdateDate = src.LastUpdateDate.ToOffset(timeZoneOffset);
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;
}
} }

View File

@ -142,14 +142,13 @@ namespace AsbCloudInfrastructure.Services.SAUB
return Task.CompletedTask; return Task.CompletedTask;
var telemetry = telemetryService.GetOrCreateTelemetryByUid(uid); var telemetry = telemetryService.GetOrCreateTelemetryByUid(uid);
var timezone = telemetryService.GetTimezone(telemetry.Id);
foreach (var dto in dtos) foreach (var dto in dtos)
{ {
var entity = dto.Adapt<TelemetryMessage>(); var entity = dto.Adapt<TelemetryMessage>();
entity.Id = 0; entity.Id = 0;
entity.IdTelemetry = telemetry.Id; entity.IdTelemetry = telemetry.Id;
entity.DateTime = dto.Date.ToOffset(TimeSpan.FromHours(timezone.Hours)); entity.DateTime = dto.Date.ToUniversalTime();
db.TelemetryMessages.Add(entity); db.TelemetryMessages.Add(entity);
} }

View File

@ -102,7 +102,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
if (dateBegin == default) if (dateBegin == default)
{ {
var dateRange = telemetryDataCache.GetOrDefaultDataDateRange(telemetry.Id); var dateRange = telemetryDataCache.GetOrDefaultDataDateRange(telemetry.Id);
dateBeginUtc = (dateRange?.To ?? DateTimeOffset.UtcNow) dateBeginUtc = (dateRange?.To.ToUniversalTime() ?? DateTimeOffset.UtcNow)
.AddSeconds(-intervalSec); .AddSeconds(-intervalSec);
} }
else else

View File

@ -152,8 +152,8 @@ namespace AsbCloudInfrastructure.Services.SAUB
if (!cacheItem.LastData.Any()) if (!cacheItem.LastData.Any())
return null; return null;
var from = cacheItem.FirstByDate.DateTime; var from = DateTime.SpecifyKind(cacheItem.FirstByDate.DateTime, DateTimeKind.Unspecified);
var to = cacheItem.LastData[^1].DateTime; var to = DateTime.SpecifyKind(cacheItem.LastData[^1].DateTime, DateTimeKind.Unspecified);
return new DatesRangeDto return new DatesRangeDto
{ {

View File

@ -144,7 +144,63 @@ public class WellCompositeOperationService : IWellCompositeOperationService
{ (6, 5095) }, { (6, 5095) },
{ (6, 5012) }, { (6, 5012) },
{ (6, 5040) }, { (6, 5040) },
{ (6, 5092) } { (6, 5092) },
{ (5, 5001) },
{ (5, 5015) },
{ (5, 5046) },
{ (5, 5037) },
{ (5, 5097) },
{ (5, 5057) },
{ (5, 5113) },
{ (5, 5036) },
{ (5, 5008) },
{ (5, 5003) },
{ (5, 5036) },
{ (5, 5013) },
{ (5, 5000) },
{ (5, 5029) },
{ (5, 5022) },
{ (5, 5017) },
{ (5, 5019) },
{ (5, 5042) },
{ (5, 5046) },
{ (2, 5096) },
{ (2, 5008) },
{ (2, 5002) },
{ (2, 5003) },
{ (3, 5096) },
{ (3, 5008) },
{ (3, 5002) },
{ (3, 5003) },
{ (3, 5085) },
{ (3, 5014) },
{ (31, 5002) },
{ (31, 5003) },
{ (31, 5014) },
{ (31, 5012) },
{ (31, 5083) },
{ (4, 5002) },
{ (4, 5003) },
{ (4, 5085) },
{ (4, 5087) },
{ (4, 5014) },
{ (4, 5053) },
{ (4, 5084) },
{ (4, 5086) },
{ (6, 5002) },
{ (6, 5003) },
{ (6, 5085) },
{ (6, 5036) },
{ (6, 5035) },
{ (6, 5021) },
{ (6, 5086) },
}; };
public WellCompositeOperationService( public WellCompositeOperationService(
@ -221,8 +277,8 @@ public class WellCompositeOperationService : IWellCompositeOperationService
compositeOperation.DepthStart = compositeDepth; compositeOperation.DepthStart = compositeDepth;
compositeDepth = compositeOperation.DepthStart; compositeDepth = compositeOperation.DepthStart;
compositeDay += compositeOperation.DurationHours;
compositeOperation.Day = compositeDay / 24; compositeOperation.Day = compositeDay / 24;
compositeDay += compositeOperation.DurationHours;
compositeOperations.Add(compositeOperation); compositeOperations.Add(compositeOperation);
} }

View File

@ -37,12 +37,16 @@ public class WellInfoService
var telemetryDataSaubCache = services.GetRequiredService<ITelemetryDataCache<TelemetryDataSaubDto>>(); var telemetryDataSaubCache = services.GetRequiredService<ITelemetryDataCache<TelemetryDataSaubDto>>();
var messageHub = services.GetRequiredService<IIntegrationEventHandler<UpdateWellInfoEvent>>(); var messageHub = services.GetRequiredService<IIntegrationEventHandler<UpdateWellInfoEvent>>();
var wells = await wellService.GetAllAsync(token); var entries = await wellService.GetAllAsync(token);
var wells = entries.ToList();
var activeWells = wells.Where(well => well.IdState == 1); var activeWells = wells.Where(well => well.IdState == 1);
var wellsIds = activeWells.Select(w => w.Id); var wellsIds = activeWells.Select(w => w.Id);
var processMapPlanWellDrillingRequests = wellsIds.Select(id => new ProcessMapPlanBaseRequestWithWell(id)); var processMapPlanWellDrillingRequests = wellsIds.Select(id => new ProcessMapPlanBaseRequestWithWell(id)
{
Moment = DateTimeOffset.UtcNow.AddDays(1)
});
var processMapPlanWellDrillings = new List<ProcessMapPlanDrillingDto>(); var processMapPlanWellDrillings = new List<ProcessMapPlanDrillingDto>();
foreach (var processMapPlanWellDrillingRequest in processMapPlanWellDrillingRequests) foreach (var processMapPlanWellDrillingRequest in processMapPlanWellDrillingRequests)
{ {
@ -96,14 +100,21 @@ public class WellInfoService
int? idSection = wellLastFactSection?.Id; int? idSection = wellLastFactSection?.Id;
ProcessMapPlanDrillingDto? processMapPlanWellDrilling = null; ProcessMapPlanDrillingDto? processMapPlanWellDrilling = null;
if (idSection.HasValue) if(idSection.HasValue && currentDepth.HasValue)
{ {
processMapPlanWellDrilling = wellProcessMaps.FirstOrDefault(p => p.IdWellSectionType == idSection); processMapPlanWellDrilling = wellProcessMaps
.Where(p => p.IdWellSectionType == idSection)
.Where(p => p.DepthStart <= currentDepth.Value && p.DepthEnd >= currentDepth.Value)
.FirstOrDefault();
} }
else if (currentDepth.HasValue) else if(currentDepth.HasValue)
{ {
processMapPlanWellDrilling = wellProcessMaps.FirstOrDefault(p => p.DepthStart <= currentDepth.Value && p.DepthEnd >= currentDepth.Value); processMapPlanWellDrilling = wellProcessMaps.FirstOrDefault(p => p.DepthStart <= currentDepth.Value && p.DepthEnd >= currentDepth.Value);
} }
else if (idSection.HasValue)
{
processMapPlanWellDrilling = wellProcessMaps.FirstOrDefault(p => p.IdWellSectionType == idSection);
}
double? planTotalDepth = null; double? planTotalDepth = null;
planTotalDepth = wellDepthByProcessMap.FirstOrDefault(p => p.Id == well.Id)?.DepthEnd; planTotalDepth = wellDepthByProcessMap.FirstOrDefault(p => p.Id == well.Id)?.DepthEnd;

View File

@ -42,7 +42,7 @@ public class WellOperationExport<TTemplate> : ExcelExportService<WellOperationDt
{ {
var request = new WellOperationRequest(new[] { options.IdWell }) var request = new WellOperationRequest(new[] { options.IdWell })
{ {
OperationType = options.IdType OperationType = options.IdType,
}; };
return wellOperationRepository.GetAsync(request, token); return wellOperationRepository.GetAsync(request, token);

View File

@ -273,9 +273,8 @@ namespace AsbCloudInfrastructure.Services
if (entity.Timezone is null) if (entity.Timezone is null)
dto.Timezone = GetTimezone(entity.Id); dto.Timezone = GetTimezone(entity.Id);
dto.StartDate = dbContext.WellOperations.Where(e => e.IdType == WellOperation.IdOperationTypeFact) dto.StartDate = wellOperationRepository
.AsNoTracking() .GetFirstAndLastFact(entity.Id)?.First?.DateStart;
.MinOrDefault(e => e.DateStart)?.ToRemoteDateTime(dto.Timezone.Hours);
dto.WellType = entity.WellType.Caption; dto.WellType = entity.WellType.Caption;
dto.Cluster = entity.Cluster.Caption; dto.Cluster = entity.Cluster.Caption;
dto.Deposit = entity.Cluster.Deposit.Caption; dto.Deposit = entity.Cluster.Deposit.Caption;

View File

@ -0,0 +1,29 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.DrillTestReport;
using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Requests;
using Microsoft.AspNetCore.Mvc;
using Refit;
namespace AsbCloudWebApi.IntegrationTests.Clients;
public interface IDrillTestControllerClient
{
[Post("/api/telemetry/{uid}/DrillTest")]
Task<IApiResponse> PostDataAsync(
string uid,
IEnumerable<DrillTestBaseDto> dtos,
CancellationToken token);
[Get("/api/well/{idWell}/DrillTest")]
Task<IApiResponse<PhysicalFileResult>> GenerateReportAsync(
int idWell,
int id,
CancellationToken cancellationToken);
[HttpGet("/api/well/{idWell}/DrillTest/all")]
Task<IApiResponse<PaginationContainer<DrillTestReportInfoDto>>> GetListAsync(
int idWell,
FileReportRequest request,
CancellationToken cancellationToken);
}

View File

@ -0,0 +1,23 @@
using AsbCloudApp.Data.SAUB;
using Refit;
namespace AsbCloudWebApi.IntegrationTests.Clients;
public interface ITelemetryControllerClient
{
private const string BaseRoute = "/api/telemetry";
[Get($"{BaseRoute}/Active")]
Task<IApiResponse> GetTelemetriesInfoByLastData(CancellationToken token);
[Post($"{BaseRoute}/{{uid}}/info")]
Task<IApiResponse> PostInfoAsync(string uid, [Body] TelemetryInfoDto info, CancellationToken token);
[Post($"{BaseRoute}/{{uid}}/message")]
Task<IApiResponse> PostMessagesAsync(string uid, [Body] IEnumerable<TelemetryMessageDto> dtos, CancellationToken token);
[Post($"{BaseRoute}/{{uid}}/event")]
Task<IApiResponse> PostEventsAsync(string uid, [Body] IEnumerable<EventDto> dtos, CancellationToken token);
[Post($"{BaseRoute}/{{uid}}/user")]
Task<IApiResponse> PostUsersAsync(string uid, [Body] IEnumerable<TelemetryUserDto> dtos, CancellationToken token);
}

View File

@ -0,0 +1,12 @@
using AsbCloudApp.Data;
using Refit;
namespace AsbCloudWebApi.IntegrationTests.Clients;
public interface IWellClient
{
private const string BaseRoute = "/api/well";
[Get(BaseRoute)]
Task<IApiResponse<IEnumerable<WellDto>>> GetWellsAsync();
}

View File

@ -1,9 +1,6 @@
using AsbCloudApp.Data;
using AsbCloudApp.Requests;
using AsbCloudDb.Model; using AsbCloudDb.Model;
using AsbCloudWebApi.IntegrationTests.Clients; using AsbCloudWebApi.IntegrationTests.Clients;
using AsbCloudWebApi.IntegrationTests.Data; using AsbCloudWebApi.IntegrationTests.Data;
using System;
using Xunit; using Xunit;
namespace AsbCloudWebApi.IntegrationTests.Controllers; namespace AsbCloudWebApi.IntegrationTests.Controllers;

View File

@ -0,0 +1,77 @@
using AsbCloudApp.Data.SAUB;
using AsbCloudDb.Model;
using AsbCloudWebApi.IntegrationTests.Clients;
using Xunit;
namespace AsbCloudWebApi.IntegrationTests.Controllers;
public class DrillTestControllerTest : BaseIntegrationTest
{
private readonly IDrillTestControllerClient client;
static readonly string uid = DateTime.UtcNow.ToString("yyyyMMdd_HHmmssfff");
private static readonly SimpleTimezone timezone = new() { TimezoneId = "a", Hours = 5 };
private static readonly Telemetry telemetry = new Telemetry() { Id = 1, RemoteUid = uid, TimeZone = timezone, Info = new() };
private readonly IEnumerable<DrillTestBaseDto> drillTests = [new DrillTestBaseDto {
DepthStart = 12,
Id = 1,
Params = [ new DrillTestParamsDto() {
DepthDrillStep = 1,
DepthSpeed = 2,
Speed = 3,
Step = 4,
TimeDrillStep = 5,
Workload = 6,
}, new DrillTestParamsDto() {
DepthDrillStep = 7,
DepthSpeed = 8,
Speed = 9,
Step = 10,
TimeDrillStep = 11,
Workload = 12,
}],
TimeStampStart = DateTimeOffset.UtcNow.ToOffset(TimeSpan.FromHours(5))
}];
public DrillTestControllerTest(WebAppFactoryFixture factory)
: base(factory)
{
client = factory.GetAuthorizedHttpClient<IDrillTestControllerClient>(string.Empty);
}
[Fact]
public async Task PostDataAsync()
{
// arrange
dbContext.CleanupDbSet<DrillTest>();
dbContext.CleanupDbSet<Telemetry>();
dbContext.Set<Telemetry>().Add(telemetry);
dbContext.SaveChanges();
// act
var response = await client.PostDataAsync(uid, drillTests, CancellationToken.None);
// assert
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
var count = dbContext.Set<DrillTest>().Count();
Assert.Equal(1, count);
}
[Fact]
public async Task PostDataAsync_twice_should_be_ok()
{
// arrange
dbContext.CleanupDbSet<DrillTest>();
dbContext.CleanupDbSet<Telemetry>();
dbContext.Set<Telemetry>().Add(telemetry);
dbContext.SaveChanges();
// act
_ = await client.PostDataAsync(uid, drillTests, CancellationToken.None);
var response = await client.PostDataAsync(uid, drillTests, CancellationToken.None);
// assert
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
var count = dbContext.Set<DrillTest>().Count();
Assert.Equal(1, count);
}
}

View File

@ -0,0 +1,233 @@
using AsbCloudApp.Data.SAUB;
using AsbCloudDb.Model;
using AsbCloudWebApi.IntegrationTests.Clients;
using Xunit;
namespace AsbCloudWebApi.IntegrationTests.Controllers;
public class TelemetryControllerTest : BaseIntegrationTest
{
private ITelemetryControllerClient client;
static readonly string uid = DateTime.UtcNow.ToString("yyyyMMdd_HHmmssfff");
private static readonly SimpleTimezone timezone = new() {TimezoneId = "a", Hours = 5 };
private static readonly Telemetry telemetry = new Telemetry() {Id = 1, RemoteUid = uid, TimeZone = timezone, Info = new() };
private readonly IEnumerable<EventDto> events = [new() { Id = 1, EventType = 1, IdCategory = 1, IdSound = 1, Message = "there is no spoon {tag1}", Tag = "tag1" }];
private readonly IEnumerable<TelemetryUserDto> users = [new TelemetryUserDto() { Id = 1, Level = 0, Name = "Neo", Patronymic = "Kianovich", Surname = "Theone" }];
private readonly IEnumerable<TelemetryMessageDto> messages = [new TelemetryMessageDto() { Id = 100, IdEvent = 1, WellDepth = 5, Date = DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(5)), Arg0 = "3.14", IdTelemetryUser = 1 }];
private readonly IEnumerable<TelemetryDataSaub> telemetryDataSaubEntities = [new TelemetryDataSaub()
{
IdTelemetry = telemetry.Id,
DateTime = DateTimeOffset.UtcNow,
AxialLoad = 2,
WellDepth = 5,
BitDepth = 5,
BlockPosition = 5,
BlockSpeed = 5,
}];
private readonly TelemetryInfoDto telemetryInfoDto = new()
{
TimeZoneId = timezone.TimezoneId,
TimeZoneOffsetTotalHours = timezone.Hours,
Cluster = "cluster1",
};
public TelemetryControllerTest(WebAppFactoryFixture factory)
: base(factory)
{
client = factory.GetAuthorizedHttpClient<ITelemetryControllerClient>(string.Empty);
}
[Fact]
public async Task GetTelemetriesInfoByLastData()
{
// Arrange
dbContext.CleanupDbSet<Telemetry>();
dbContext.Set<Telemetry>().Add(telemetry);
dbContext.Set<TelemetryDataSaub>().AddRange(telemetryDataSaubEntities);
dbContext.SaveChanges();
// Act
var response = await client.GetTelemetriesInfoByLastData(CancellationToken.None);
// Assert
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
}
[Fact]
public async Task PostInfoAsync()
{
// arrange
dbContext.CleanupDbSet<Telemetry>();
// act
var response = await client.PostInfoAsync(uid, telemetryInfoDto, CancellationToken.None);
// Assert
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
var telemetriesCount = dbContext.Set<Telemetry>().Count();
Assert.Equal(1, telemetriesCount);
}
[Fact]
public async Task PostInfoAsync_twice_should_be_ok()
{
// arrange
dbContext.CleanupDbSet<Telemetry>();
// act
_ = await client.PostInfoAsync(uid, telemetryInfoDto, CancellationToken.None);
var response = await client.PostInfoAsync(uid, telemetryInfoDto, CancellationToken.None);
// Assert
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
var telemetriesCount = dbContext.Set<Telemetry>().Count();
Assert.Equal(1, telemetriesCount);
}
[Fact]
public async Task PostUsersAsync()
{
// arrange
dbContext.CleanupDbSet<Telemetry>();
dbContext.Set<Telemetry>().Add(telemetry);
dbContext.SaveChanges();
// act
var response = await client.PostUsersAsync(uid, users, CancellationToken.None);
// Assert
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
var telemetriesCount = dbContext.Set<Telemetry>().Count();
var telemetryUserCount = dbContext.Set<TelemetryUser>().Count();
Assert.Equal(1, telemetriesCount);
Assert.Equal(1, telemetryUserCount);
}
[Fact]
public async Task PostUsers_twice_should_be_ok()
{
// arrange
dbContext.CleanupDbSet<TelemetryUser>();
dbContext.CleanupDbSet<Telemetry>();
dbContext.Set<Telemetry>().Add(telemetry);
dbContext.SaveChanges();
// act
_ = await client.PostUsersAsync(uid, users, CancellationToken.None);
var response = await client.PostUsersAsync(uid, users, CancellationToken.None);
// Assert
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
var telemetriesCount = dbContext.Set<Telemetry>().Count();
var telemetryUserCount = dbContext.Set<TelemetryUser>().Count();
Assert.Equal(1, telemetriesCount);
Assert.Equal(1, telemetryUserCount);
}
[Fact]
public async Task PostEventsAsync()
{
// arrange
dbContext.CleanupDbSet<TelemetryEvent>();
dbContext.CleanupDbSet<Telemetry>();
dbContext.Set<Telemetry>().Add(telemetry);
dbContext.SaveChanges();
// act
var response = await client.PostEventsAsync(uid, events, CancellationToken.None);
// Assert
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
var telemetriesCount = dbContext.Set<Telemetry>().Count();
var telemetryEventCount = dbContext.Set<TelemetryEvent>().Count();
Assert.Equal(1, telemetriesCount);
Assert.Equal(1, telemetryEventCount);
}
[Fact]
public async Task PostEventsAsync_twice_should_be_ok()
{
// arrange
dbContext.CleanupDbSet<TelemetryEvent>();
dbContext.CleanupDbSet<Telemetry>();
dbContext.Set<Telemetry>().Add(telemetry);
dbContext.SaveChanges();
// act
_ = await client.PostEventsAsync(uid, events, CancellationToken.None);
var response = await client.PostEventsAsync(uid, events, CancellationToken.None);
// Assert
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
var telemetriesCount = dbContext.Set<Telemetry>().Count();
var telemetryEventCount = dbContext.Set<TelemetryEvent>().Count();
Assert.Equal(1, telemetriesCount);
Assert.Equal(1, telemetryEventCount);
}
[Fact]
public async Task PostMessagesAsync()
{
// arrange
dbContext.CleanupDbSet<TelemetryMessage>();
dbContext.CleanupDbSet<TelemetryEvent>();
dbContext.CleanupDbSet<TelemetryUser>();
dbContext.CleanupDbSet<Telemetry>();
dbContext.Set<Telemetry>().Add(telemetry);
dbContext.SaveChanges();
// act
_ = await client.PostEventsAsync(uid, events, CancellationToken.None);
_ = await client.PostUsersAsync(uid, users, CancellationToken.None);
var response = await client.PostMessagesAsync(uid, messages, CancellationToken.None);
// Assert
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
var telemetriesCount = dbContext.Set<Telemetry>().Count();
var telemetryEventCount = dbContext.Set<TelemetryEvent>().Count();
var telemetryUserCount = dbContext.Set<TelemetryUser>().Count();
var telemetryMessageCount = dbContext.Set<TelemetryMessage>().Count();
Assert.Equal(1, telemetriesCount);
Assert.Equal(1, telemetryEventCount);
Assert.Equal(1, telemetryUserCount);
Assert.Equal(1, telemetryMessageCount);
}
[Fact]
public async Task PostMessagesAsync_twice_should_be_ok()
{
// arrange
dbContext.CleanupDbSet<TelemetryMessage>();
dbContext.CleanupDbSet<TelemetryEvent>();
dbContext.CleanupDbSet<TelemetryUser>();
dbContext.CleanupDbSet<Telemetry>();
dbContext.Set<Telemetry>().Add(telemetry);
dbContext.SaveChanges();
// act
_ = await client.PostEventsAsync(uid, events, CancellationToken.None);
_ = await client.PostUsersAsync(uid, users, CancellationToken.None);
_ = await client.PostMessagesAsync(uid, messages, CancellationToken.None);
var response = await client.PostMessagesAsync(uid, messages, CancellationToken.None);
// Assert
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
var telemetriesCount = dbContext.Set<Telemetry>().Count();
var telemetryEventCount = dbContext.Set<TelemetryEvent>().Count();
var telemetryUserCount = dbContext.Set<TelemetryUser>().Count();
var telemetryMessageCount = dbContext.Set<TelemetryMessage>().Count();
Assert.Equal(1, telemetriesCount);
Assert.Equal(1, telemetryEventCount);
Assert.Equal(1, telemetryUserCount);
Assert.Equal(2, telemetryMessageCount);
}
}

View File

@ -0,0 +1,67 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.WellOperation;
using AsbCloudDb.Model;
using AsbCloudInfrastructure;
using AsbCloudWebApi.IntegrationTests.Clients;
using Mapster;
using Microsoft.EntityFrameworkCore;
using System.Net;
using Xunit;
namespace AsbCloudWebApi.IntegrationTests.Controllers;
public class WellControllerTest : BaseIntegrationTest
{
private static readonly WellOperationDto wellOperationDto = new()
{
DateStart = DateTimeOffset.UtcNow,
Day = 1,
DepthEnd = 1000,
DepthStart = 500,
DurationHours = 5,
Id = 1,
IdCategory = 5095,
IdPlan = null,
IdType = 1,
IdUser = 1,
IdWell = 1,
IdWellSectionType = 1,
NptHours = 5
};
private readonly IWellClient wellClient;
private readonly IWellOperationClient wellOperationClient;
public WellControllerTest(WebAppFactoryFixture factory)
: base(factory)
{
wellClient = factory.GetAuthorizedHttpClient<IWellClient>(string.Empty);
wellOperationClient = factory.GetAuthorizedHttpClient<IWellOperationClient>(string.Empty);
}
[Fact]
public async Task CheckDateStartForWell_returns_success()
{
//act
var wellOperationDto1 = wellOperationDto.Adapt<WellOperationDto>();
wellOperationDto1.DateStart = DateTimeOffset.UtcNow;
wellOperationDto1.Id = 2;
var wellOperations = new List<WellOperationDto>() { wellOperationDto, wellOperationDto1 };
var insertedRedult = await wellOperationClient.InsertRangeAsync(1, false, wellOperations);
var wellResponse = await wellClient.GetWellsAsync();
//assert
Assert.Equal(HttpStatusCode.OK, wellResponse.StatusCode);
Assert.NotNull(wellResponse.Content);
var expectedCount = await dbContext.Wells.CountAsync();
Assert.Equal(expectedCount, wellResponse.Content.Count());
var actualFirstStartDate = wellResponse.Content.ElementAt(0).StartDate!.Value.ToUniversalTime();
var expectedFirstStartDate = wellOperations.MinByOrDefault(o => o.DateStart)!.DateStart.ToUniversalTime();
Assert.Equal(expectedFirstStartDate.ToString(), actualFirstStartDate.ToString());
}
}

View File

@ -27,7 +27,7 @@ public class WellOperationControllerTest : BaseIntegrationTest
} }
/// <summary> /// <summary>
/// Успешное добавление операций (без предварительной очистки данных) /// Óñïåøíîå äîáàâëåíèå îïåðàöèé (áåç ïðåäâàðèòåëüíîé î÷èñòêè äàííûõ)
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Fact] [Fact]
@ -46,7 +46,7 @@ public class WellOperationControllerTest : BaseIntegrationTest
} }
/// <summary> /// <summary>
/// Успешное добавление операций (с предварительной очисткой данных) /// Óñïåøíîå äîáàâëåíèå îïåðàöèé (ñ ïðåäâàðèòåëüíîé î÷èñòêîé äàííûõ)
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Fact] [Fact]
@ -65,7 +65,7 @@ public class WellOperationControllerTest : BaseIntegrationTest
} }
/// <summary> /// <summary>
/// Успешное обновление операций /// Óñïåøíîå îáíîâëåíèå îïåðàöèé
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Fact] [Fact]
@ -87,7 +87,7 @@ public class WellOperationControllerTest : BaseIntegrationTest
} }
/// <summary> /// <summary>
/// Получение плановых операций /// Ïîëó÷åíèå ïëàíîâûõ îïåðàöèé
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Fact] [Fact]
@ -144,7 +144,7 @@ public class WellOperationControllerTest : BaseIntegrationTest
IdWellSectionType = 2, IdWellSectionType = 2,
IdCategory = WellOperationCategory.IdSlide, IdCategory = WellOperationCategory.IdSlide,
IdPlan = null, IdPlan = null,
CategoryInfo = "Доп.инфо", CategoryInfo = "Äîï.èíôî",
IdType = idType, IdType = idType,
DepthStart = 10.0, DepthStart = 10.0,
DepthEnd = 20.0, DepthEnd = 20.0,
@ -201,7 +201,7 @@ public class WellOperationControllerTest : BaseIntegrationTest
var stream = responseTemplate.Content; var stream = responseTemplate.Content;
using var workbook = new XLWorkbook(stream); using var workbook = new XLWorkbook(stream);
var sheet = workbook.GetWorksheet("Справочники"); var sheet = workbook.GetWorksheet("Ñïðàâî÷íèêè");
var count = sheet.RowsUsed().Count() - 1; var count = sheet.RowsUsed().Count() - 1;
@ -230,21 +230,75 @@ public class WellOperationControllerTest : BaseIntegrationTest
Assert.True(notExistedInDb.Count() == 0); Assert.True(notExistedInDb.Count() == 0);
} }
private static WellOperation CreateWellOperation(int idWell, int idType = WellOperation.IdOperationTypePlan) => [Theory]
new() [InlineData(WellOperation.IdOperationTypePlan)]
{ [InlineData(WellOperation.IdOperationTypeFact)]
IdWell = idWell, public async Task GetPageOperationsAsyncWithDaysAndNpv_returns_success(int idType)
IdWellSectionType = 2, {
IdCategory = WellOperationCategory.IdSlide, //arrange
IdPlan = null, const int pageSize = 10;
CategoryInfo = "Доп.инфо", const int pageIndex = 0;
LastUpdateDate = new DateTimeOffset(new DateTime(2023, 1, 10)).ToUniversalTime(),
IdType = idType, var well = await dbContext.Wells.FirstAsync();
DepthStart = 10.0, var entity1 = CreateWellOperation(well.Id);
DepthEnd = 20.0,
DateStart = new DateTimeOffset(new DateTime(2023, 1, 10), TimeSpan.FromHours(Defaults.Timezone.Hours)).ToUniversalTime(), var entity2 = entity1.Adapt<WellOperation>();
DurationHours = 1.0, entity2.DateStart = entity2.DateStart.AddDays(1);
Comment = "1", entity2.IdCategory = WellOperationCategory.IdEquipmentDrillingRepair;
IdUser = 1, entity2.DurationHours = 2;
var entity3 = entity2.Adapt<WellOperation>();
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,
};
} }

View File

@ -21,7 +21,7 @@ public class WorkTest
((ISupportRequiredService)serviceProviderMock).GetRequiredService(typeof(IServiceScopeFactory)).Returns(serviceScopeFactoryMock); ((ISupportRequiredService)serviceProviderMock).GetRequiredService(typeof(IServiceScopeFactory)).Returns(serviceScopeFactoryMock);
} }
[Fact] [Fact, MethodImpl(MethodImplOptions.NoOptimization)]
public async Task Start_ShouldReturn_Success() public async Task Start_ShouldReturn_Success()
{ {
//arrange //arrange
@ -50,7 +50,7 @@ public class WorkTest
Assert.InRange(lastState.ExecutionTime, TimeSpan.Zero, executionTime); Assert.InRange(lastState.ExecutionTime, TimeSpan.Zero, executionTime);
} }
[Fact] [Fact, MethodImpl(MethodImplOptions.NoOptimization)]
public async Task ExecutionWork_Invokes_Callback() public async Task ExecutionWork_Invokes_Callback()
{ {
//arrange //arrange

View File

@ -43,26 +43,6 @@ namespace AsbCloudWebApi.Controllers
return Ok(result); return Ok(result);
} }
/// <summary>
/// Получает список доступных пользователю месторождений (только скважины с параметрами бурения)
/// </summary>
/// <param name="token"> Токен отмены задачи </param>
/// <returns></returns>
[HttpGet("drillParamsWells")]
[Permission]
[ProducesResponseType(typeof(IEnumerable<DepositDto>), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetDepositsDrillParamsAsync(CancellationToken token)
{
int? idCompany = User.GetCompanyId();
if (idCompany is null)
return Forbid();
var result = await depositService.GetAllWithDrillParamsAsync((int)idCompany,
token).ConfigureAwait(false);
return Ok(result);
}
/// <summary> /// <summary>
/// Получает список доступных пользователю кустов месторождения /// Получает список доступных пользователю кустов месторождения
/// </summary> /// </summary>

View File

@ -16,6 +16,7 @@ using AsbCloudApp.Requests.ExportOptions;
using AsbCloudApp.Requests.ParserOptions; using AsbCloudApp.Requests.ParserOptions;
using AsbCloudDb.Model; using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services.WellOperations.Factories; using AsbCloudInfrastructure.Services.WellOperations.Factories;
using System.Linq;
namespace AsbCloudWebApi.Controllers; namespace AsbCloudWebApi.Controllers;
@ -250,6 +251,35 @@ public class WellOperationController : ControllerBase
return Ok(result); return Ok(result);
} }
/// <summary>
/// Удаляет выбранные операции по скважине
/// </summary>
/// <param name="idWell">id скважины</param>
/// <param name="ids">ids выбранных операций</param>
/// <param name="token">Токен отмены задачи</param>
/// <returns>Количество удаленных из БД строк</returns>
[HttpDelete]
[ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
public async Task<IActionResult> DeleteRangeAsync([FromRoute] int idWell, IEnumerable<int> ids, CancellationToken token)
{
if (!await CanUserAccessToWellAsync(idWell, token))
return Forbid();
if (!await CanUserEditWellOperationsAsync(idWell, token))
return Forbid();
if (!ids.Any())
return this.ValidationBadRequest(nameof(ids), "Пустой список операций");
var result = await wellOperationRepository.DeleteRangeAsync(ids, token);
if(result == ICrudRepository<WellOperationDto>.ErrorIdNotFound)
return this.ValidationBadRequest(nameof(ids), "Минимум одна из операций не найдена в базе");
return Ok(result);
}
/// <summary> /// <summary>
/// Формирование excel файла с операциями на скважине /// Формирование excel файла с операциями на скважине
/// </summary> /// </summary>

View File

@ -44,6 +44,9 @@ namespace AsbCloudWebApi.Middlewares
} }
catch (Exception ex) // TODO: find explicit exception. Use Trace. Add body size to message. catch (Exception ex) // TODO: find explicit exception. Use Trace. Add body size to message.
{ {
if (context.Response.HasStarted)
throw;
context.Response.Clear(); context.Response.Clear();
context.Response.StatusCode = 500; context.Response.StatusCode = 500;