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,
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>

View File

@ -1,9 +1,9 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.WellOperation;
using AsbCloudApp.Requests;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data.WellOperation;
using AsbCloudApp.Requests;
namespace AsbCloudApp.Repositories
{
@ -17,8 +17,8 @@ namespace AsbCloudApp.Repositories
/// </summary>
/// <returns></returns>
IEnumerable<WellSectionTypeDto> GetSectionTypes();
/// <summary>
/// <summary>
/// Получить страницу списка операций
/// </summary>
/// <param name="request"></param>
@ -26,7 +26,7 @@ namespace AsbCloudApp.Repositories
/// <returns></returns>
Task<IEnumerable<WellOperationDto>> GetAsync(WellOperationRequest request, CancellationToken token);
/// <summary>
/// <summary>
/// Получить страницу списка операций
/// </summary>
/// <param name="request"></param>
@ -34,7 +34,7 @@ namespace AsbCloudApp.Repositories
/// <returns></returns>
Task<PaginationContainer<WellOperationDto>> GetPageAsync(WellOperationRequest request, CancellationToken token);
/// <summary>
/// <summary>
/// Получить статистику операции по скважине с группировкой по категориям
/// </summary>
/// <param name="request"></param>
@ -42,19 +42,19 @@ namespace AsbCloudApp.Repositories
/// <returns></returns>
Task<IEnumerable<WellGroupOpertionDto>> GetGroupOperationsStatAsync(WellOperationRequest request, CancellationToken token);
/// <summary>
/// Добавить несколько операций
/// </summary>
/// <param name="dtos"></param>
/// <param name="deleteBeforeInsert"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> InsertRangeAsync(IEnumerable<WellOperationDto> dtos, bool deleteBeforeInsert, CancellationToken token);
/// <summary>
/// Добавить несколько операций
/// </summary>
/// <param name="dtos"></param>
/// <param name="deleteBeforeInsert"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> InsertRangeAsync(IEnumerable<WellOperationDto> dtos, bool deleteBeforeInsert, CancellationToken token);
/// <summary>
/// Обновить существующую операцию
/// </summary>
/// <param name="dto"></param>
/// <param name="dtos"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> UpdateRangeAsync(IEnumerable<WellOperationDto> dtos, CancellationToken token);
@ -75,13 +75,20 @@ namespace AsbCloudApp.Repositories
/// <returns></returns>
Task<IEnumerable<SectionByOperationsDto>> GetSectionsAsync(IEnumerable<int> idsWells, CancellationToken token);
/// <summary>
/// Получить диапазон дат выполнения операций
/// </summary>
/// <param name="idWell"></param>
/// <param name="idType"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<DatesRangeDto?> GetDatesRangeAsync(int idWell, int idType, CancellationToken cancellationToken);
}
/// <summary>
/// Получить диапазон дат выполнения операций
/// </summary>
/// <param name="idWell"></param>
/// <param name="idType"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
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.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Requests;
@ -8,44 +9,72 @@ namespace AsbCloudApp.Requests;
/// </summary>
public class WellOperationRequestBase : RequestBase
{
/// <summary>
/// Больше или равно дате начала операции
/// </summary>
public DateTimeOffset? GeDate { get; set; }
/// <summary>
/// Больше или равно дате начала операции
/// </summary>
public DateTimeOffset? GeDate { get; set; }
/// <summary>
/// Меньше или равно дате окончания операции
/// </summary>
public DateTimeOffset? LeDate { get; set; }
/// <summary>
/// Меньше или равно дате окончания операции
/// </summary>
public DateTimeOffset? LeDate { get; set; }
/// <summary>
/// Больше или равно глубины скважины на начало операции.
/// </summary>
public double? GeDepth { get; set; }
/// <summary>
/// Больше или равно глубины скважины на начало операции.
/// </summary>
public double? GeDepth { get; set; }
/// <summary>
/// Меньше или равно глубины скважины на конец операции.
/// </summary>
public double? LeDepth { get; set; }
/// <summary>
/// Меньше или равно глубины скважины на конец операции.
/// </summary>
public double? LeDepth { get; set; }
/// <summary>
/// Идентификаторы категорий операции
/// </summary>
public IEnumerable<int>? OperationCategoryIds { get; set; }
/// <summary>
/// Идентификаторы категорий операции
/// </summary>
public IEnumerable<int>? OperationCategoryIds { get; set; }
/// <summary>
/// Тип операций
/// <list type="bullet">
/// <item>0 - плановая операция</item>
/// <item>1 - фактическая операция</item>
/// </list>
/// </summary>
public int? OperationType { get; set; }
/// <summary>
/// Тип операций
/// <list type="bullet">
/// <item>0 - плановая операция</item>
/// <item>1 - фактическая операция</item>
/// </list>
/// </summary>
public int? OperationType { get; set; }
/// <summary>
/// Идентификаторы конструкций секции
/// </summary>
public IEnumerable<int>? SectionTypeIds { get; set; }
/// <summary>
/// Идентификаторы конструкций секции
/// </summary>
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>
@ -53,32 +82,23 @@ public class WellOperationRequestBase : RequestBase
/// </summary>
public class WellOperationRequest : WellOperationRequestBase
{
/// <inheritdoc />
public WellOperationRequest(IEnumerable<int> idsWell)
{
IdsWell = idsWell;
}
/// <inheritdoc />
public WellOperationRequest(IEnumerable<int> idsWell)
{
IdsWell = idsWell;
}
/// <inheritdoc />
public WellOperationRequest(WellOperationRequestBase request, IEnumerable<int> idsWell)
: this(idsWell)
{
GeDepth = request.GeDepth;
LeDepth = request.LeDepth;
GeDate = request.GeDate;
LeDate = request.LeDate;
/// <inheritdoc />
public WellOperationRequest(WellOperationRequestBase request, IEnumerable<int> idsWell)
: base(request)
{
IdsWell = idsWell;
}
OperationCategoryIds = request.OperationCategoryIds;
OperationType = request.OperationType;
SectionTypeIds = request.SectionTypeIds;
Skip = request.Skip;
Take = request.Take;
SortFields = request.SortFields;
}
/// <summary>
/// Идентификаторы скважин
/// </summary>
public IEnumerable<int>? IdsWell { get; }
/// <summary>
/// Идентификаторы скважин
/// </summary>
[Required]
[Length(1, 100)]
public IEnumerable<int> IdsWell { get; }
}

View File

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

View File

@ -10,118 +10,100 @@ using System.Linq;
using System.Threading;
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;
private readonly IWellService wellService;
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;
}
this.db = db;
this.telemetryService = telemetryService;
}
/// <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.Repositories;
using AsbCloudApp.Requests;
using AsbCloudDb;
using AsbCloudDb.Model;
using Mapster;
using Microsoft.EntityFrameworkCore;
@ -68,11 +69,12 @@ namespace AsbCloudInfrastructure.Repository
var entities = dtos.Select(dto =>
{
var entity = dto.Adapt<DrillTest>();
entity.TimeStampStart = dto.TimeStampStart.ToUniversalTime();
entity.IdTelemetry = idTelemetry;
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;
}

View File

@ -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,436 @@ 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<WellOperationDto, WellOperation>,
IWellOperationRepository
IWellOperationRepository
{
private readonly IMemoryCache memoryCache;
private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
private readonly IWellService wellService;
private const string cacheKeyWellOperations = "FirstAndLastFactWellsOperations";
private readonly IMemoryCache memoryCache;
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,
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<WellSectionTypeDto> GetSectionTypes() =>
memoryCache
.GetOrCreateBasic(dbContext.WellSectionTypes)
.OrderBy(s => s.Order)
.Select(s => s.Adapt<WellSectionTypeDto>());
LazyWellCategories = new(() => wellOperationCategoryRepository.Get(true, false).ToDictionary(c => c.Id));
LazyWellSectionTypes = new(() => GetSectionTypes().ToDictionary(c => c.Id));
}
public async Task<IEnumerable<WellOperationDto>> GetAsync(WellOperationRequest request, CancellationToken token)
{
var query = BuildQuery(request);
public IEnumerable<WellSectionTypeDto> GetSectionTypes() =>
memoryCache
.GetOrCreateBasic(dbContext.WellSectionTypes)
.OrderBy(s => s.Order)
.Select(s => s.Adapt<WellSectionTypeDto>());
if (request.Skip.HasValue)
query = query.Skip(request.Skip.Value);
public async Task<IEnumerable<WellOperationDto>> 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<PaginationContainer<WellOperationDto>> GetPageAsync(WellOperationRequest request, CancellationToken token)
{
request.Skip = request.Skip ?? 0;
request.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<WellOperationDto>
{
Skip = request.Skip!.Value,
Take = request.Take!.Value,
Count = count,
Items = items
};
public async Task<PaginationContainer<WellOperationDto>> GetPageAsync(WellOperationRequest request, CancellationToken token)
{
var skip = request.Skip ?? 0;
var take = request.Take ?? 32;
return paginationContainer;
}
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)
.Take(take)
.AsNoTracking()
.ToArrayAsync(token);
var parentRelationDictionary = wellOperationCategoryRepository.Get(true)
.ToDictionary(c => c.Id, c => new
{
c.Name,
c.IdParent
});
var paginationContainer = new PaginationContainer<WellOperationDto>
{
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<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);
return dtos;
}
var parentRelationDictionary = wellOperationCategoryRepository.Get(true)
.ToDictionary(c => c.Id, c => new
{
c.Name,
c.IdParent
});
public async Task<int> InsertRangeAsync(IEnumerable<WellOperationDto> 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
});
var result = 0;
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;
});
}
if (!deleteBeforeInsert)
{
result = await InsertRangeAsync(dtos, token);
return dtos;
}
if (result > 0)
memoryCache.Remove(cacheKeyWellOperations);
public async Task<int> InsertRangeAsync(IEnumerable<WellOperationDto> dtos,
bool deleteBeforeInsert,
CancellationToken token)
{
EnsureValidWellOperations(dtos);
return result;
}
if (!deleteBeforeInsert)
return await InsertRangeAsync(dtos, token);
var idType = dtos.First().IdType;
var idWell = dtos.First().IdWell;
var idType = dtos.First().IdType;
var idWell = dtos.First().IdWell;
var existingOperationIds = await dbContext.WellOperations
.Where(e => e.IdWell == idWell && e.IdType == idType)
.Select(e => e.Id)
.ToArrayAsync(token);
var existingOperationIds = await dbContext.WellOperations
.Where(e => e.IdWell == idWell && e.IdType == idType)
.Select(e => e.Id)
.ToArrayAsync(token);
await DeleteRangeAsync(existingOperationIds, token);
await DeleteRangeAsync(existingOperationIds, token);
result = await InsertRangeAsync(dtos, token);
return await InsertRangeAsync(dtos, token);
}
if (result > 0)
memoryCache.Remove(cacheKeyWellOperations);
public override Task<int> UpdateRangeAsync(IEnumerable<WellOperationDto> dtos, CancellationToken token)
{
EnsureValidWellOperations(dtos);
return result;
return base.UpdateRangeAsync(dtos, token);
}
}
private static void EnsureValidWellOperations(IEnumerable<WellOperationDto> dtos)
{
if (dtos.GroupBy(d => d.IdType).Count() > 1)
throw new ArgumentInvalidException(nameof(dtos), "Все операции должны быть одного типа");
public override async Task<int> UpdateRangeAsync(IEnumerable<WellOperationDto> dtos, CancellationToken token)
{
EnsureValidWellOperations(dtos);
if (dtos.GroupBy(d => d.IdType).Count() > 1)
throw new ArgumentInvalidException(nameof(dtos), "Все операции должны принадлежать одной скважине");
}
var result = await base.UpdateRangeAsync(dtos, token);
private IQueryable<WellOperation> BuildQuery(WellOperationRequest request)
{
var query = GetQuery()
.Where(e => request.IdsWell != null && request.IdsWell.Contains(e.IdWell))
.OrderBy(e => e.DateStart)
.AsQueryable();
if (result > 0)
memoryCache.Remove(cacheKeyWellOperations);
if (request.OperationType.HasValue)
query = query.Where(e => e.IdType == request.OperationType.Value);
return result;
if (request.SectionTypeIds?.Any() is true)
query = query.Where(e => request.SectionTypeIds.Contains(e.IdWellSectionType));
}
if (request.OperationCategoryIds?.Any() is true)
query = query.Where(e => request.OperationCategoryIds.Contains(e.IdCategory));
private static void EnsureValidWellOperations(IEnumerable<WellOperationDto> dtos)
{
if (dtos.GroupBy(d => d.IdType).Count() > 1)
throw new ArgumentInvalidException(nameof(dtos), "Все операции должны быть одного типа");
if (request.GeDepth.HasValue)
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)
query = query.Where(e => e.DepthEnd <= request.LeDepth.Value);
private async Task<IEnumerable<WellOperation>> GetByIdsWells(IEnumerable<int> idsWells, CancellationToken token)
{
var query = GetQuery()
.Where(e => idsWells.Contains(e.IdWell))
.OrderBy(e => e.DateStart);
var entities = await query.ToArrayAsync(token);
return entities;
}
if (request.GeDate.HasValue)
{
var geDateUtc = request.GeDate.Value.UtcDateTime;
query = query.Where(e => e.DateStart >= geDateUtc);
}
private async Task<(IEnumerable<WellOperationDto> items, int count)> GetWithDaysAndNpvAsync(WellOperationRequest request, CancellationToken token)
{
var entities = await GetByIdsWells(request.IdsWell, token);
var groupedByWellAndType = entities
.GroupBy(e => new { e.IdWell, e.IdType });
if (request.LeDate.HasValue)
{
var leDateUtc = request.LeDate.Value.UtcDateTime;
query = query.Where(e => e.DateStart <= leDateUtc);
}
var result = new List<WellOperationDto>();
var count = 0;
foreach (var wellOperationsWithType in groupedByWellAndType)
{
var firstWellOperation = wellOperationsWithType
.OrderBy(e => e.DateStart)
.FirstOrDefault()!;
if (request.SortFields?.Any() is true)
query = query.SortBy(request.SortFields);
var operationsWithNpt = wellOperationsWithType
.Where(o => WellOperationCategory.NonProductiveTimeSubIds.Contains(o.IdCategory));
return query;
}
IEnumerable<WellOperation> filteredWellOperations = FilterByRequest(wellOperationsWithType.AsQueryable(), request);
public async Task<IEnumerable<SectionByOperationsDto>> GetSectionsAsync(IEnumerable<int> idsWells, CancellationToken token)
{
const string keyCacheSections = "OperationsBySectionSummarties";
count += filteredWellOperations.Count();
var cache = await memoryCache.GetOrCreateAsync(keyCacheSections, async (entry) =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30);
if (request.Skip != null)
filteredWellOperations = filteredWellOperations.Skip((int)request.Skip);
if (request.Take != null)
filteredWellOperations = filteredWellOperations.Take((int)request.Take);
var query = dbContext.Set<WellOperation>()
.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,
var dtos = filteredWellOperations
.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;
});
First = group
.OrderBy(operation => operation.DateStart)
.Select(operation => new
{
operation.DateStart,
operation.DepthStart,
})
.First(),
result.AddRange(dtos);
}
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,
return (result, count);
}
Caption = item.Caption,
private static IQueryable<WellOperation> FilterByRequest(IQueryable<WellOperation> 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);
DateStart = item.First.DateStart,
DepthStart = item.First.DepthStart,
if (request.GeDate.HasValue)
{
var geDateUtc = request.GeDate.Value.UtcDateTime;
entities = entities.Where(e => e.DateStart >= geDateUtc);
}
DateEnd = item.Last.DateStart.AddHours(item.Last.DurationHours),
DepthEnd = item.Last.DepthEnd,
})
.ToArray()
.AsEnumerable();
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);
entry.Value = sections;
return sections;
});
return entities;
}
return cache;
}
private IQueryable<WellOperation> BuildQuery(WellOperationRequest request)
{
var query = GetQuery()
.Where(e => request.IdsWell.Contains(e.IdWell))
.OrderBy(e => e.DateStart)
.AsQueryable();
query = FilterByRequest(query, request);
public async Task<DatesRangeDto?> GetDatesRangeAsync(int idWell, int idType, CancellationToken cancellationToken)
{
var query = dbContext.WellOperations.Where(o => o.IdWell == idWell && o.IdType == idType);
return query;
}
if (!await query.AnyAsync(cancellationToken))
return null;
public async Task<IEnumerable<SectionByOperationsDto>> GetSectionsAsync(IEnumerable<int> idsWells, CancellationToken token)
{
const string keyCacheSections = "OperationsBySectionSummarties";
var timeZoneOffset = wellService.GetTimezone(idWell).Offset;
var minDate = await query.MinAsync(o => o.DateStart, cancellationToken);
var maxDate = await query.MaxAsync(o => o.DateStart, cancellationToken);
var cache = await memoryCache.GetOrCreateAsync(keyCacheSections, async (entry) =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30);
return new DatesRangeDto
{
From = minDate.ToOffset(timeZoneOffset),
To = maxDate.ToOffset(timeZoneOffset)
};
}
var query = dbContext.Set<WellOperation>()
.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,
private async Task<IEnumerable<WellOperationDto>> ConvertWithDrillingDaysAndNpvHoursAsync(IEnumerable<WellOperation> entities,
CancellationToken token)
{
var idsWell = entities.Select(e => e.IdWell).Distinct();
First = group
.OrderBy(operation => operation.DateStart)
.Select(operation => new
{
operation.DateStart,
operation.DepthStart,
})
.First(),
var currentWellOperations = GetQuery()
.Where(entity => idsWell.Contains(entity.IdWell));
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 dateFirstDrillingOperationByIdWell = await currentWellOperations
.Where(entity => entity.IdType == WellOperation.IdOperationTypeFact)
.GroupBy(entity => entity.IdWell)
.ToDictionaryAsync(g => g.Key, g => g.Min(o => o.DateStart), token);
Caption = item.Caption,
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);
DateStart = item.First.DateStart,
DepthStart = item.First.DepthStart,
var dtos = entities.Select(entity =>
{
var dto = Convert(entity);
DateEnd = item.Last.DateStart.AddHours(item.Last.DurationHours),
DepthEnd = item.Last.DepthEnd,
})
.ToArray()
.AsEnumerable();
if (dateFirstDrillingOperationByIdWell.TryGetValue(entity.IdWell, out var dateFirstDrillingOperation))
dto.Day = (entity.DateStart - dateFirstDrillingOperation).TotalDays;
entry.Value = sections;
return sections;
});
if (operationsWithNptByIdWell.TryGetValue(entity.IdWell, out var wellOperationsWithNtp))
dto.NptHours = wellOperationsWithNtp
.Where(o => o.DateStart <= entity.DateStart)
.Sum(e => e.DurationHours);
return cache!;
}
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 entity = src.Adapt<WellOperation>();
entity.DateStart = src.DateStart.UtcDateTime;
return entity;
}
var timeZoneOffset = wellService.GetTimezone(idWell).Offset;
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);
return dto;
}
var minDate = await query.MinAsync(o => o.DateStart, cancellationToken);
var maxDate = await query.MaxAsync(o => o.DateStart, cancellationToken);
return new DatesRangeDto
{
From = minDate.ToOffset(timeZoneOffset),
To = maxDate.ToOffset(timeZoneOffset)
};
}
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;
var telemetry = telemetryService.GetOrCreateTelemetryByUid(uid);
var timezone = telemetryService.GetTimezone(telemetry.Id);
foreach (var dto in dtos)
{
var entity = dto.Adapt<TelemetryMessage>();
entity.Id = 0;
entity.IdTelemetry = telemetry.Id;
entity.DateTime = dto.Date.ToOffset(TimeSpan.FromHours(timezone.Hours));
entity.DateTime = dto.Date.ToUniversalTime();
db.TelemetryMessages.Add(entity);
}

View File

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

View File

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

View File

@ -144,7 +144,63 @@ public class WellCompositeOperationService : IWellCompositeOperationService
{ (6, 5095) },
{ (6, 5012) },
{ (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(
@ -221,8 +277,8 @@ public class WellCompositeOperationService : IWellCompositeOperationService
compositeOperation.DepthStart = compositeDepth;
compositeDepth = compositeOperation.DepthStart;
compositeDay += compositeOperation.DurationHours;
compositeOperation.Day = compositeDay / 24;
compositeDay += compositeOperation.DurationHours;
compositeOperations.Add(compositeOperation);
}

View File

@ -37,12 +37,16 @@ public class WellInfoService
var telemetryDataSaubCache = services.GetRequiredService<ITelemetryDataCache<TelemetryDataSaubDto>>();
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 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>();
foreach (var processMapPlanWellDrillingRequest in processMapPlanWellDrillingRequests)
{
@ -96,14 +100,21 @@ public class WellInfoService
int? idSection = wellLastFactSection?.Id;
ProcessMapPlanDrillingDto? processMapPlanWellDrilling = null;
if (idSection.HasValue)
if(idSection.HasValue && currentDepth.HasValue)
{
processMapPlanWellDrilling = wellProcessMaps.FirstOrDefault(p => p.IdWellSectionType == idSection);
}
else if (currentDepth.HasValue)
processMapPlanWellDrilling = wellProcessMaps
.Where(p => p.IdWellSectionType == idSection)
.Where(p => p.DepthStart <= currentDepth.Value && p.DepthEnd >= currentDepth.Value)
.FirstOrDefault();
}
else if(currentDepth.HasValue)
{
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;
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 })
{
OperationType = options.IdType
OperationType = options.IdType,
};
return wellOperationRepository.GetAsync(request, token);

View File

@ -116,12 +116,12 @@ namespace AsbCloudInfrastructure.Services
if (well is null)
return null;
var wellInfo = wellInfoService.FirstOrDefault(well => well.Id == idWell);
if (wellInfo is null)
return well.Adapt<WellMapInfoWithTelemetryStat>();
wellInfo.IdState = well.IdState;
return wellInfo;
}
@ -153,7 +153,7 @@ namespace AsbCloudInfrastructure.Services
{
if (IsTelemetryAssignedToDifferentWell(dto))
throw new ArgumentInvalidException(nameof(dto), "Телеметрия уже была привязана к другой скважине.");
if (dto.Id != 0 && (await GetCacheAsync(token)).Any(w => w.Id == dto.Id))
throw new ArgumentInvalidException(nameof(dto), $"Нельзя повторно добавить скважину с id: {dto.Id}");
@ -177,12 +177,12 @@ namespace AsbCloudInfrastructure.Services
throw new NotImplementedException();
}
public override async Task<int> UpdateAsync(WellDto dto,
public override async Task<int> UpdateAsync(WellDto dto,
CancellationToken token)
{
if (IsTelemetryAssignedToDifferentWell(dto))
throw new ArgumentInvalidException(nameof(dto), "Телеметрия уже была привязана к другой скважине.");
var oldRelations = (await GetCacheRelationCompanyWellAsync(token))
.Where(r => r.IdWell == dto.Id).ToArray();
@ -192,16 +192,16 @@ namespace AsbCloudInfrastructure.Services
dbContext.RelationCompaniesWells
.RemoveRange(dbContext.RelationCompaniesWells
.Where(r => r.IdWell == dto.Id));
DropCacheRelationCompanyWell();
var newRelations = dto.Companies
.Select(c => new RelationCompanyWell
{
IdWell = dto.Id,
IdWell = dto.Id,
IdCompany = c.Id
});
dbContext.RelationCompaniesWells.AddRange(newRelations);
}
@ -215,7 +215,7 @@ namespace AsbCloudInfrastructure.Services
public async Task<string> GetWellCaptionByIdAsync(int idWell, CancellationToken token)
{
var entity = await GetOrDefaultAsync(idWell, token).ConfigureAwait(false);
var entity = await GetOrDefaultAsync(idWell, token).ConfigureAwait(false);
return entity!.Caption;
}
@ -272,10 +272,9 @@ namespace AsbCloudInfrastructure.Services
if (entity.Timezone is null)
dto.Timezone = GetTimezone(entity.Id);
dto.StartDate = dbContext.WellOperations.Where(e => e.IdType == WellOperation.IdOperationTypeFact)
.AsNoTracking()
.MinOrDefault(e => e.DateStart)?.ToRemoteDateTime(dto.Timezone.Hours);
dto.StartDate = wellOperationRepository
.GetFirstAndLastFact(entity.Id)?.First?.DateStart;
dto.WellType = entity.WellType.Caption;
dto.Cluster = entity.Cluster.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 AsbCloudWebApi.IntegrationTests.Clients;
using AsbCloudWebApi.IntegrationTests.Data;
using System;
using Xunit;
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>
/// <returns></returns>
[Fact]
@ -46,7 +46,7 @@ public class WellOperationControllerTest : BaseIntegrationTest
}
/// <summary>
/// Успешное добавление операций (с предварительной очисткой данных)
/// Óñïåøíîå äîáàâëåíèå îïåðàöèé (ñ ïðåäâàðèòåëüíîé î÷èñòêîé äàííûõ)
/// </summary>
/// <returns></returns>
[Fact]
@ -65,7 +65,7 @@ public class WellOperationControllerTest : BaseIntegrationTest
}
/// <summary>
/// Успешное обновление операций
/// Óñïåøíîå îáíîâëåíèå îïåðàöèé
/// </summary>
/// <returns></returns>
[Fact]
@ -87,7 +87,7 @@ public class WellOperationControllerTest : BaseIntegrationTest
}
/// <summary>
/// Получение плановых операций
/// Ïîëó÷åíèå ïëàíîâûõ îïåðàöèé
/// </summary>
/// <returns></returns>
[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<WellOperation>();
entity2.DateStart = entity2.DateStart.AddDays(1);
entity2.IdCategory = WellOperationCategory.IdEquipmentDrillingRepair;
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);
}
[Fact]
[Fact, MethodImpl(MethodImplOptions.NoOptimization)]
public async Task Start_ShouldReturn_Success()
{
//arrange
@ -50,7 +50,7 @@ public class WorkTest
Assert.InRange(lastState.ExecutionTime, TimeSpan.Zero, executionTime);
}
[Fact]
[Fact, MethodImpl(MethodImplOptions.NoOptimization)]
public async Task ExecutionWork_Invokes_Callback()
{
//arrange

View File

@ -43,26 +43,6 @@ namespace AsbCloudWebApi.Controllers
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>

View File

@ -16,6 +16,7 @@ using AsbCloudApp.Requests.ExportOptions;
using AsbCloudApp.Requests.ParserOptions;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services.WellOperations.Factories;
using System.Linq;
namespace AsbCloudWebApi.Controllers;
@ -250,6 +251,35 @@ public class WellOperationController : ControllerBase
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>
/// Формирование excel файла с операциями на скважине
/// </summary>

View File

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