Merge branch 'dev' into feature/#28093751-process-map-plan-drilling-dto

This commit is contained in:
Olga Nemt 2024-02-29 09:12:06 +05:00
commit 58729077fa
37 changed files with 713 additions and 294 deletions

View File

@ -14,7 +14,7 @@ jobs:
if: ${{ steps.cache-dotnet.outputs.cache-hit != 'true' }} if: ${{ steps.cache-dotnet.outputs.cache-hit != 'true' }}
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v4
with: with:
dotnet-version: 6.0.x dotnet-version: 8.0.x
- name: Check out repository code - name: Check out repository code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Add gitea as nuget source - name: Add gitea as nuget source

View File

@ -14,7 +14,7 @@ jobs:
if: ${{ steps.cache-dotnet.outputs.cache-hit != 'true' }} if: ${{ steps.cache-dotnet.outputs.cache-hit != 'true' }}
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v4
with: with:
dotnet-version: 6.0.x dotnet-version: 8.0.x
- name: Check out repository code - name: Check out repository code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Add gitea as nuget source - name: Add gitea as nuget source

View File

@ -14,7 +14,7 @@ jobs:
if: ${{ steps.cache-dotnet.outputs.cache-hit != 'true' }} if: ${{ steps.cache-dotnet.outputs.cache-hit != 'true' }}
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v4
with: with:
dotnet-version: 6.0.x dotnet-version: 8.0.x
- name: Check out repository code - name: Check out repository code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Add gitea as nuget source - name: Add gitea as nuget source

View File

@ -13,7 +13,7 @@ jobs:
if: ${{ steps.cache-dotnet.outputs.cache-hit != 'true' }} if: ${{ steps.cache-dotnet.outputs.cache-hit != 'true' }}
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v4
with: with:
dotnet-version: 6.0.x dotnet-version: 8.0.x
- name: Check out repository code - name: Check out repository code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Add gitea as nuget source - name: Add gitea as nuget source

View File

@ -1,19 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Linq" Version="4.3.0" />
</ItemGroup>
<ItemGroup>
<None Remove="Data\DailyReport\" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<EditorConfigFiles Remove="D:\Source\AsbCloudApp\Services\.editorconfig" /> <EditorConfigFiles Remove="D:\Source\AsbCloudApp\Services\.editorconfig" />
</ItemGroup> </ItemGroup>

View File

@ -1,7 +1,4 @@
using System.Collections.Generic; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using AsbCloudApp.Data.User;
namespace AsbCloudApp.Data namespace AsbCloudApp.Data
{ {

View File

@ -0,0 +1,25 @@
using System.Collections.Generic;
using AsbCloudApp.Data.Subsystems;
namespace AsbCloudApp.Data;
/// <summary>
/// ñòàòèñòèêà íàðàáîòêè ïî áóðèëüùèêàì
/// </summary>
public class DrillerDetectedOperationStatDto
{
/// <summary>
/// Ñòàòèñòèêè ïîäñèñòåì
/// </summary>
public IEnumerable<SubsystemStatDto> Statistic { get; set; } = null!;
/// <summary>
/// Ðàñïèñàíèå áóðèëüùèêà
/// </summary>
public ScheduleDto Schedule { get; set; } = null!;
/// <summary>
/// Ñêâàæèíà
/// </summary>
public WellDto Well { get; set; } = null!;
}

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Data namespace AsbCloudApp.Data
@ -6,7 +7,7 @@ namespace AsbCloudApp.Data
/// <summary> /// <summary>
/// Описание данных графика работ /// Описание данных графика работ
/// </summary> /// </summary>
public class ScheduleDto : IId, IWellRelated public class ScheduleDto : IId, IWellRelated, IValidatableObject
{ {
/// <inheritdoc/> /// <inheritdoc/>
[Required] [Required]
@ -50,5 +51,12 @@ namespace AsbCloudApp.Data
/// Бурильщик /// Бурильщик
/// </summary> /// </summary>
public DrillerDto? Driller { get; set; } public DrillerDto? Driller { get; set; }
/// <inheritdoc/>
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if(DrillStart >= DrillEnd)
yield return new ValidationResult($"DrillStart > DrillEnd");
}
} }
} }

View File

@ -2,7 +2,6 @@
using AsbCloudApp.Requests; using AsbCloudApp.Requests;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -13,14 +12,6 @@ namespace AsbCloudApp.Repositories
/// </summary> /// </summary>
public interface IWellOperationRepository public interface IWellOperationRepository
{ {
//TODO: replace all references
/// <summary>
/// список названий операций
/// </summary>
/// <returns></returns>
[Obsolete("use IWellOperationCategoryRepository.GetCategories(bool includeParents)")]
IEnumerable<WellOperationCategoryDto> GetCategories(bool includeParents);
/// <summary> /// <summary>
/// Список секций /// Список секций
/// </summary> /// </summary>

View File

@ -0,0 +1,20 @@
using System.Collections.Generic;
using System.Linq;
namespace AsbCloudApp.Requests;
/// <summary>
/// Çàïðîñ íà ïîëó÷åíèå ñòàòèñòèêè èñïîëüçîâàíèÿ ïîäñèñòåì áóðèëüùèêîì
/// </summary>
public class GetStatRequest: RequestBase
{
/// <summary>
/// id ñêâàæèí
/// </summary>
public IEnumerable<int> IdsWells { get; set; } = new List<int>();
/// <summary>
/// id Áóðèëüùèêà
/// </summary>
public int? IdDriller { get; set; }
}

View File

@ -3,6 +3,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Requests;
namespace AsbCloudApp.Services namespace AsbCloudApp.Services
{ {
@ -28,5 +29,13 @@ namespace AsbCloudApp.Services
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<DrillerDto?> GetOrDefaultDrillerAsync(int idWell, DateTime workTime, CancellationToken token); Task<DrillerDto?> GetOrDefaultDrillerAsync(int idWell, DateTime workTime, CancellationToken token);
/// <summary>
/// Получить расписание смен
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<ScheduleDto>> GetPageAsync(GetStatRequest request, CancellationToken token);
} }
} }

View File

@ -4,6 +4,7 @@ using System;
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;
namespace AsbCloudApp.Services; namespace AsbCloudApp.Services;
@ -26,5 +27,14 @@ public interface ISubsystemService
/// <param name="wellIds"></param> /// <param name="wellIds"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(IEnumerable<int> wellIds, CancellationToken token); Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(IEnumerable<int> wellIds, CancellationToken token);
/// <summary>
/// Получение статистики по бурильщику
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<DrillerDetectedOperationStatDto>> GetByWellsAsync(GetStatRequest request,
CancellationToken token);
} }

View File

@ -1,16 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.22"> <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.2">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.22" /> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>

View File

@ -52,6 +52,10 @@ namespace AsbCloudInfrastructure
{ {
public static void MapsterSetup() public static void MapsterSetup()
{ {
TypeAdapterConfig.GlobalSettings.Default.Config
.ForType<ScheduleDto, Schedule>()
.Ignore(source => source.Driller);
TypeAdapterConfig.GlobalSettings.Default.Config TypeAdapterConfig.GlobalSettings.Default.Config
.ForType<DateTimeOffset, DateTime>() .ForType<DateTimeOffset, DateTime>()
.MapWith((source) => source.DateTime); .MapWith((source) => source.DateTime);

View File

@ -43,5 +43,4 @@ namespace AsbCloudInfrastructure.Repository
return dtos; return dtos;
} }
} }
} }

View File

@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Requests;
using Mapster; using Mapster;
namespace AsbCloudInfrastructure.Repository namespace AsbCloudInfrastructure.Repository
@ -53,6 +54,21 @@ namespace AsbCloudInfrastructure.Repository
return entity?.Driller.Adapt<DrillerDto>(); return entity?.Driller.Adapt<DrillerDto>();
} }
public async Task<IEnumerable<ScheduleDto>> GetPageAsync(GetStatRequest request, CancellationToken token)
{
var idWell = request.IdsWells;
var idDriller = request.IdDriller;
var query = GetQuery().Where(s => request.IdsWells.Contains(s.IdWell));
if (idDriller is not null)
{
query.Where(s => s.IdDriller == idDriller);
}
var result = await query.ToArrayAsync(token);
return result.Select(Convert);
}
private IQueryable<Schedule> BuildQuery(int idWell, DateTime workTime) private IQueryable<Schedule> BuildQuery(int idWell, DateTime workTime)
{ {
var hoursOffset = wellService.GetTimezone(idWell).Hours; var hoursOffset = wellService.GetTimezone(idWell).Hours;

View File

@ -23,7 +23,6 @@ namespace AsbCloudInfrastructure.Repository;
public class WellOperationRepository : IWellOperationRepository public class WellOperationRepository : IWellOperationRepository
{ {
private const string KeyCacheSections = "OperationsBySectionSummarties"; private const string KeyCacheSections = "OperationsBySectionSummarties";
private const int Gap = 90;
private readonly IAsbCloudDbContext db; private readonly IAsbCloudDbContext db;
private readonly IMemoryCache memoryCache; private readonly IMemoryCache memoryCache;
@ -38,13 +37,6 @@ public class WellOperationRepository : IWellOperationRepository
this.wellOperationCategoryRepository = wellOperationCategoryRepository; this.wellOperationCategoryRepository = wellOperationCategoryRepository;
} }
/// <inheritdoc/>
public IEnumerable<WellOperationCategoryDto> GetCategories(bool includeParents)
{
return wellOperationCategoryRepository.Get(includeParents);
}
/// <inheritdoc/>
public IEnumerable<WellSectionTypeDto> GetSectionTypes() => public IEnumerable<WellSectionTypeDto> GetSectionTypes() =>
memoryCache memoryCache
.GetOrCreateBasic(db.Set<WellSectionType>()) .GetOrCreateBasic(db.Set<WellSectionType>())
@ -272,7 +264,7 @@ public class WellOperationRepository : IWellOperationRepository
DurationDepth = o.DepthEnd - o.DepthStart DurationDepth = o.DepthEnd - o.DepthStart
}) })
.ToListAsync(token); .ToListAsync(token);
var parentRelationDictionary = GetCategories(true) var parentRelationDictionary = wellOperationCategoryRepository.Get(true)
.ToDictionary(c => c.Id, c => new .ToDictionary(c => c.Id, c => new
{ {
c.Name, c.Name,

View File

@ -204,7 +204,7 @@ public class ReportService : IReportService
public async Task<int> DeleteAllOldReportsAsync(TimeSpan lifetime, CancellationToken token) public async Task<int> DeleteAllOldReportsAsync(TimeSpan lifetime, CancellationToken token)
{ {
var lifeTimeStartDate = DateTime.UtcNow.Date - lifetime; var lifeTimeStartDate = DateTimeOffset.UtcNow.Date - lifetime;
var fileIds = await db.ReportProperties var fileIds = await db.ReportProperties
.Where(r => r.File.UploadDate.Date < lifeTimeStartDate) .Where(r => r.File.UploadDate.Date < lifeTimeStartDate)
.Select(r => r.IdFile) .Select(r => r.IdFile)

View File

@ -1,245 +1,307 @@
using AsbCloudApp.Data; using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Data.DetectedOperation; using AsbCloudApp.Data.DetectedOperation;
using AsbCloudApp.Data.Subsystems; using AsbCloudApp.Data.Subsystems;
using AsbCloudApp.Exceptions; using AsbCloudApp.Exceptions;
using AsbCloudApp.Requests; using AsbCloudApp.Requests;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudDb.Model; using AsbCloudDb.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudInfrastructure.Services.DetectOperations; using AsbCloudInfrastructure.Services.DetectOperations;
namespace AsbCloudInfrastructure.Services.Subsystems; namespace AsbCloudInfrastructure.Services.Subsystems;
internal class SubsystemService : ISubsystemService internal class SubsystemService : ISubsystemService
{ {
private const int IdSubsystemAPD = 1; private const int IdSubsystemAPD = 1;
private const int IdSubsystemAPDRotor = 11; private const int IdSubsystemAPDRotor = 11;
private const int IdSubsystemAPDSlide = 12; private const int IdSubsystemAPDSlide = 12;
private const int IdSubsystemOscillation = 65536; private const int IdSubsystemOscillation = 65536;
private readonly ICrudRepository<SubsystemDto> subsystemRepository; private readonly ICrudRepository<SubsystemDto> subsystemRepository;
private readonly IWellService wellService; private readonly IWellService wellService;
private readonly IDetectedOperationService detectedOperationService; private readonly IDetectedOperationService detectedOperationService;
private readonly IScheduleRepository scheduleRepository;
private IDictionary<int, SubsystemDto> subsystems = new Dictionary<int, SubsystemDto>(); private IDictionary<int, SubsystemDto> subsystems = new Dictionary<int, SubsystemDto>();
public SubsystemService(ICrudRepository<SubsystemDto> subsystemRepository, public SubsystemService(ICrudRepository<SubsystemDto> subsystemRepository,
IWellService wellService, IWellService wellService,
IDetectedOperationService detectedOperationService) IDetectedOperationService detectedOperationService,
{ IScheduleRepository scheduleRepository)
this.wellService = wellService; {
this.subsystemRepository = subsystemRepository; this.wellService = wellService;
this.detectedOperationService = detectedOperationService; this.subsystemRepository = subsystemRepository;
} this.detectedOperationService = detectedOperationService;
this.scheduleRepository = scheduleRepository;
}
public async Task<IEnumerable<SubsystemStatDto>> GetStatAsync(SubsystemRequest request, CancellationToken token) // получить расписания бурильщиков по скважинам // ScheduleRepository добавить новый метод
{ // [
var well = await wellService.GetOrDefaultAsync(request.IdWell, token) // get telemetryId by idWell // IWellService.GetOrDefaultStatAsync
?? throw new ArgumentInvalidException(nameof(request.IdWell), $"Well Id: {request.IdWell} does not exist"); // получить detectedOperation by telemetry //detectedOperationService.GetOperationsAsync
// сгруппировать по бурильщикам
if(!well.IdTelemetry.HasValue) // [
return Enumerable.Empty<SubsystemStatDto>(); // рассчитать статистику // CalcStatAsync
// join driller from group
var detectedOperationSummaryRequest = new DetectedOperationByWellRequest // ]
// join well (cluster, deposit)
// ]
public async Task<IEnumerable<DrillerDetectedOperationStatDto>> GetByWellsAsync(GetStatRequest request,
CancellationToken token)
{
var result = new List<DrillerDetectedOperationStatDto>();
var schedulePage = await scheduleRepository.GetPageAsync(request, token);
var wells = await wellService.GetAsync(new WellRequest { Ids = request.IdsWells }, token);
foreach (var schedule in schedulePage)
{ {
IdWell = request.IdWell, var idWell = schedule.IdWell;
IdsCategories = WellOperationCategory.MechanicalDrillingSubIds, var well = wells.FirstOrDefault(w=> w.Id == idWell)!;
GeDateStart = request.GeDate, var byWellRequest = new DetectedOperationByWellRequest(idWell, new DetectedOperationRequest());
LeDateEnd = request.LeDate,
GeDepthStart = request.GeDepth, var detectedOperations = await detectedOperationService
LeDepthEnd = request.LeDepth, .GetOperationsAsync(byWellRequest, token);
};
var operations = await detectedOperationService.GetOperationsAsync(detectedOperationSummaryRequest, var groupByDriller = detectedOperations
token); .Where(operation => operation.Driller is not null)
.GroupBy(operation => operation.Driller);
if (request.IdDriller.HasValue) foreach (var entry in groupByDriller)
operations = operations.Where(o => o.Driller is not null && o.Driller.Id == request.IdDriller.Value); {
var drillerOperationsStat = await CalcStatAsync(entry, token);
var dto = new DrillerDetectedOperationStatDto
{
Statistic = drillerOperationsStat,
Schedule = schedule,
Well = well,
};
result.Add(dto);
}
}
if (!operations.Any()) return result;
return Enumerable.Empty<SubsystemStatDto>(); }
var stat = await CalcStatAsync(operations, token); public async Task<IEnumerable<SubsystemStatDto>> GetStatAsync(SubsystemRequest request, CancellationToken token)
return stat; {
} var well = await wellService.GetOrDefaultAsync(request.IdWell, token)
?? throw new ArgumentInvalidException(nameof(request.IdWell),
$"Well Id: {request.IdWell} does not exist");
public async Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(IEnumerable<int> wellIds, CancellationToken token) if (!well.IdTelemetry.HasValue)
{ return Enumerable.Empty<SubsystemStatDto>();
var activeWells = await wellService.GetAsync(new() { Ids = wellIds, IdState = 1 }, token);
var result = await GetStatAsync(activeWells, null, null, token);
return result;
}
private async Task<IEnumerable<SubsystemStatDto>> CalcStatAsync(IEnumerable<DetectedOperationWithDrillerDto> operations, CancellationToken token)
{
if (!subsystems.Any())
subsystems = (await subsystemRepository.GetAllAsync(token)).ToDictionary(s => s.Id, s => s);
var oscillationStat = CalcOscillationStat(operations); var detectedOperationSummaryRequest = new DetectedOperationByWellRequest
var apdStat = CalcApdStat(operations); {
IdWell = request.IdWell,
IdsCategories = WellOperationCategory.MechanicalDrillingSubIds,
var stat = new List<SubsystemStatDto> { oscillationStat }; GeDateStart = request.GeDate,
stat.AddRange(apdStat); LeDateEnd = request.LeDate,
return stat; GeDepthStart = request.GeDepth,
} LeDepthEnd = request.LeDepth,
};
private SubsystemStatDto CalcOscillationStat(IEnumerable<DetectedOperationWithDrillerDto> operations) var operations = await detectedOperationService.GetOperationsAsync(detectedOperationSummaryRequest,
{ token);
operations = operations.Where(o => o.IdCategory == WellOperationCategory.IdSlide);
var (sumDepthInterval, usedTimeHours, operationCount) = AggregateOperations(IdSubsystemOscillation, operations); if (request.IdDriller.HasValue)
operations = operations.Where(o => o.Driller is not null && o.Driller.Id == request.IdDriller.Value);
var oscillationStat = new SubsystemStatDto if (!operations.Any())
{ return Enumerable.Empty<SubsystemStatDto>();
IdSubsystem = IdSubsystemOscillation,
SubsystemName = subsystems.TryGetValue(IdSubsystemOscillation, out var subsystemDto) ? subsystemDto.Name : "unknown",
UsedTimeHours = usedTimeHours,
SumOperationDepthInterval = operations.Sum(o => o.DepthEnd - o.DepthStart),
SumOperationDurationHours = operations.Sum(o => o.DurationMinutes / 60),
SumDepthInterval = sumDepthInterval,
OperationCount = operationCount,
};
oscillationStat.KUsage = oscillationStat.SumDepthInterval / oscillationStat.SumOperationDepthInterval;
return oscillationStat;
}
private IEnumerable<SubsystemStatDto> CalcApdStat(IEnumerable<DetectedOperationWithDrillerDto> operations) var stat = await CalcStatAsync(operations, token);
{ return stat;
var apdRotorAndSlide = operations }
.Where(o => WellOperationCategory.MechanicalDrillingSubIds.Contains(o.IdCategory))
.GroupBy(o => o.IdCategory)
.Select(group =>
{
var idSubsystem = group.Key switch
{
WellOperationCategory.IdRotor => IdSubsystemAPDRotor,
WellOperationCategory.IdSlide => IdSubsystemAPDSlide,
_ => throw new ArgumentException($"IdCategory: {group.Key} does not supported in this method", nameof(group.Key))
};
var (sumDepthInterval, usedTimeHours, operationCount) = AggregateOperations(idSubsystem, group); public async Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(IEnumerable<int> wellIds,
CancellationToken token)
{
var activeWells = await wellService.GetAsync(new() { Ids = wellIds, IdState = 1 }, token);
var result = await GetStatAsync(activeWells, null, null, token);
return result;
}
var subsystemStat = new SubsystemStatDto private async Task<IEnumerable<SubsystemStatDto>> CalcStatAsync(
{ IEnumerable<DetectedOperationWithDrillerDto> operations, CancellationToken token)
IdSubsystem = idSubsystem, {
SubsystemName = subsystems.TryGetValue(idSubsystem, out var subsystemDto) ? subsystemDto.Name : "unknown", if (!subsystems.Any())
UsedTimeHours = usedTimeHours, subsystems = (await subsystemRepository.GetAllAsync(token)).ToDictionary(s => s.Id, s => s);
SumOperationDepthInterval = group.Sum(o => o.DepthEnd - o.DepthStart),
SumOperationDurationHours = group.Sum(o => o.DurationMinutes / 60),
SumDepthInterval = sumDepthInterval,
OperationCount = operationCount,
};
subsystemStat.KUsage = subsystemStat.SumDepthInterval / subsystemStat.SumOperationDepthInterval; var oscillationStat = CalcOscillationStat(operations);
var apdStat = CalcApdStat(operations);
return subsystemStat; var stat = new List<SubsystemStatDto> { oscillationStat };
}); stat.AddRange(apdStat);
if (!apdRotorAndSlide.Any())
return Enumerable.Empty<SubsystemStatDto>();
var apdSum = new SubsystemStatDto
{
IdSubsystem = IdSubsystemAPD,
SubsystemName = subsystems.TryGetValue(IdSubsystemAPD, out var subsystemDto) ? subsystemDto.Name : "unknown",
UsedTimeHours = apdRotorAndSlide.Sum(part => part.UsedTimeHours),
SumOperationDepthInterval = apdRotorAndSlide.Sum(part => part.SumOperationDepthInterval),
SumOperationDurationHours = apdRotorAndSlide.Sum(part => part.SumOperationDurationHours),
SumDepthInterval = apdRotorAndSlide.Sum(part => part.SumDepthInterval),
OperationCount = apdRotorAndSlide.Sum(part => part.OperationCount),
};
apdSum.KUsage = apdSum.SumDepthInterval / apdSum.SumOperationDepthInterval;
var apdStat = new List<SubsystemStatDto> { apdSum }; return stat;
apdStat.AddRange(apdRotorAndSlide); }
return apdStat; private SubsystemStatDto CalcOscillationStat(IEnumerable<DetectedOperationWithDrillerDto> operations)
} {
operations = operations.Where(o => o.IdCategory == WellOperationCategory.IdSlide);
private static (double SumDepthInterval, double UsedTimeHours, int Count) AggregateOperations(int idSubsystem, var (sumDepthInterval, usedTimeHours, operationCount) = AggregateOperations(IdSubsystemOscillation, operations);
IEnumerable<DetectedOperationWithDrillerDto> operations) =>
idSubsystem switch
{
IdSubsystemAPDRotor => CalcOperationsByEnableSubsystems(operations, EnabledSubsystemsFlags.AutoRotor),
IdSubsystemAPDSlide => CalcOperationsByEnableSubsystems(operations,
EnabledSubsystemsFlags.AutoSlide | EnabledSubsystemsFlags.AutoOscillation),
IdSubsystemOscillation => CalcOperationsByEnableSubsystems(operations, EnabledSubsystemsFlags.AutoOscillation),
_ => throw new ArgumentException($"IdSubsystem: {idSubsystem} does not supported in this method", nameof(idSubsystem))
};
private static (double SumDepthInterval, double UsedTimeHours, int OperationCount) CalcOperationsByEnableSubsystems( var oscillationStat = new SubsystemStatDto
IEnumerable<DetectedOperationWithDrillerDto> operations, {
EnabledSubsystemsFlags enabledSubsystems) IdSubsystem = IdSubsystemOscillation,
{ SubsystemName = subsystems.TryGetValue(IdSubsystemOscillation, out var subsystemDto)
var filtered = operations.Where(o => enabledSubsystems.HasEnabledSubsystems(o.EnabledSubsystems)); ? subsystemDto.Name
: "unknown",
UsedTimeHours = usedTimeHours,
SumOperationDepthInterval = operations.Sum(o => o.DepthEnd - o.DepthStart),
SumOperationDurationHours = operations.Sum(o => o.DurationMinutes / 60),
SumDepthInterval = sumDepthInterval,
OperationCount = operationCount,
};
var sumDepthInterval = filtered.Sum(o => o.DepthEnd - o.DepthStart); oscillationStat.KUsage = oscillationStat.SumDepthInterval / oscillationStat.SumOperationDepthInterval;
var usedTimeHours = filtered.Sum(o => o.DurationMinutes / 60);
var operationCount = filtered.Count();
return (sumDepthInterval, usedTimeHours, operationCount); return oscillationStat;
} }
private async Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatAsync(IEnumerable<WellDto> wells, private IEnumerable<SubsystemStatDto> CalcApdStat(IEnumerable<DetectedOperationWithDrillerDto> operations)
DateTime? geDate, {
DateTime? leDate, var apdRotorAndSlide = operations
CancellationToken token) .Where(o => WellOperationCategory.MechanicalDrillingSubIds.Contains(o.IdCategory))
{ .GroupBy(o => o.IdCategory)
if (!wells.Any()) .Select(group =>
return Enumerable.Empty<SubsystemActiveWellStatDto>(); {
var idSubsystem = group.Key switch
{
WellOperationCategory.IdRotor => IdSubsystemAPDRotor,
WellOperationCategory.IdSlide => IdSubsystemAPDSlide,
_ => throw new ArgumentException($"IdCategory: {group.Key} does not supported in this method",
nameof(group.Key))
};
var idsTelemetries = wells var (sumDepthInterval, usedTimeHours, operationCount) = AggregateOperations(idSubsystem, group);
.Where(w => w.IdTelemetry is not null)
.Select(w => w.IdTelemetry!.Value)
.Distinct();
var wellsStat = new List<SubsystemActiveWellStatDto>(); var subsystemStat = new SubsystemStatDto
{
IdSubsystem = idSubsystem,
SubsystemName = subsystems.TryGetValue(idSubsystem, out var subsystemDto)
? subsystemDto.Name
: "unknown",
UsedTimeHours = usedTimeHours,
SumOperationDepthInterval = group.Sum(o => o.DepthEnd - o.DepthStart),
SumOperationDurationHours = group.Sum(o => o.DurationMinutes / 60),
SumDepthInterval = sumDepthInterval,
OperationCount = operationCount,
};
foreach (var well in wells) subsystemStat.KUsage = subsystemStat.SumDepthInterval / subsystemStat.SumOperationDepthInterval;
{
var hoursOffset = well.Timezone.Hours;
var geDateStartUtc = geDate?.ToUtcDateTimeOffset(hoursOffset); return subsystemStat;
});
var leDateUtc = leDate?.ToUtcDateTimeOffset(hoursOffset); if (!apdRotorAndSlide.Any())
return Enumerable.Empty<SubsystemStatDto>();
var request = new DetectedOperationByWellRequest var apdSum = new SubsystemStatDto
{ {
IdWell = well.Id, IdSubsystem = IdSubsystemAPD,
IdsCategories = WellOperationCategory.MechanicalDrillingSubIds, SubsystemName =
GeDateStart = geDateStartUtc, subsystems.TryGetValue(IdSubsystemAPD, out var subsystemDto) ? subsystemDto.Name : "unknown",
LeDateEnd = leDateUtc, UsedTimeHours = apdRotorAndSlide.Sum(part => part.UsedTimeHours),
}; SumOperationDepthInterval = apdRotorAndSlide.Sum(part => part.SumOperationDepthInterval),
SumOperationDurationHours = apdRotorAndSlide.Sum(part => part.SumOperationDurationHours),
SumDepthInterval = apdRotorAndSlide.Sum(part => part.SumDepthInterval),
OperationCount = apdRotorAndSlide.Sum(part => part.OperationCount),
};
var telemetryOperations = await detectedOperationService apdSum.KUsage = apdSum.SumDepthInterval / apdSum.SumOperationDepthInterval;
.GetOperationsAsync(request, token);
var wellStat = new SubsystemActiveWellStatDto { Well = well }; var apdStat = new List<SubsystemStatDto> { apdSum };
apdStat.AddRange(apdRotorAndSlide);
if (!telemetryOperations.Any()) return apdStat;
continue; }
var subsystemStat = await CalcStatAsync(telemetryOperations, token); private static (double SumDepthInterval, double UsedTimeHours, int Count) AggregateOperations(int idSubsystem,
IEnumerable<DetectedOperationWithDrillerDto> operations) =>
idSubsystem switch
{
IdSubsystemAPDRotor => CalcOperationsByEnableSubsystems(operations, EnabledSubsystemsFlags.AutoRotor),
IdSubsystemAPDSlide => CalcOperationsByEnableSubsystems(operations,
EnabledSubsystemsFlags.AutoSlide | EnabledSubsystemsFlags.AutoOscillation),
IdSubsystemOscillation => CalcOperationsByEnableSubsystems(operations,
EnabledSubsystemsFlags.AutoOscillation),
_ => throw new ArgumentException($"IdSubsystem: {idSubsystem} does not supported in this method",
nameof(idSubsystem))
};
if (!subsystemStat.Any()) private static (double SumDepthInterval, double UsedTimeHours, int OperationCount) CalcOperationsByEnableSubsystems(
continue; IEnumerable<DetectedOperationWithDrillerDto> operations,
EnabledSubsystemsFlags enabledSubsystems)
{
var filtered = operations.Where(o => enabledSubsystems.HasEnabledSubsystems(o.EnabledSubsystems));
wellStat.SubsystemAPD = subsystemStat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemAPD); var sumDepthInterval = filtered.Sum(o => o.DepthEnd - o.DepthStart);
wellStat.SubsystemOscillation = subsystemStat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemOscillation); var usedTimeHours = filtered.Sum(o => o.DurationMinutes / 60);
wellsStat.Add(wellStat); var operationCount = filtered.Count();
}
return wellsStat; return (sumDepthInterval, usedTimeHours, operationCount);
} }
private async Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatAsync(IEnumerable<WellDto> wells,
DateTime? geDate,
DateTime? leDate,
CancellationToken token)
{
if (!wells.Any())
return Enumerable.Empty<SubsystemActiveWellStatDto>();
var idsTelemetries = wells
.Where(w => w.IdTelemetry is not null)
.Select(w => w.IdTelemetry!.Value)
.Distinct();
var wellsStat = new List<SubsystemActiveWellStatDto>();
foreach (var well in wells)
{
var hoursOffset = well.Timezone.Hours;
var geDateStartUtc = geDate?.ToUtcDateTimeOffset(hoursOffset);
var leDateUtc = leDate?.ToUtcDateTimeOffset(hoursOffset);
var request = new DetectedOperationByWellRequest
{
IdWell = well.Id,
IdsCategories = WellOperationCategory.MechanicalDrillingSubIds,
GeDateStart = geDateStartUtc,
LeDateEnd = leDateUtc,
};
var telemetryOperations = await detectedOperationService
.GetOperationsAsync(request, token);
var wellStat = new SubsystemActiveWellStatDto { Well = well };
if (!telemetryOperations.Any())
continue;
var subsystemStat = await CalcStatAsync(telemetryOperations, token);
if (!subsystemStat.Any())
continue;
wellStat.SubsystemAPD = subsystemStat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemAPD);
wellStat.SubsystemOscillation = subsystemStat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemOscillation);
wellsStat.Add(wellStat);
}
return wellsStat;
}
} }

View File

@ -6,7 +6,6 @@ using System.Threading.Tasks;
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Repositories; using AsbCloudApp.Repositories;
using AsbCloudApp.Requests; using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudApp.Services.WellOperationImport; using AsbCloudApp.Services.WellOperationImport;
using AsbCloudInfrastructure.Services.WellOperationImport.Constants; using AsbCloudInfrastructure.Services.WellOperationImport.Constants;
using ClosedXML.Excel; using ClosedXML.Excel;
@ -15,19 +14,19 @@ namespace AsbCloudInfrastructure.Services.WellOperationImport;
public class WellOperationExportService : IWellOperationExportService public class WellOperationExportService : IWellOperationExportService
{ {
//TODO: удалить неиспользуемую зависимость
private readonly IWellOperationRepository wellOperationRepository; private readonly IWellOperationRepository wellOperationRepository;
private readonly IWellService wellService;
private readonly IWellOperationImportTemplateService wellOperationImportTemplateService; private readonly IWellOperationImportTemplateService wellOperationImportTemplateService;
private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
public WellOperationExportService(IWellOperationRepository wellOperationRepository, public WellOperationExportService(
IWellService wellService, IWellOperationRepository wellOperationRepository,
IWellOperationImportTemplateService wellOperationImportTemplateService) IWellOperationImportTemplateService wellOperationImportTemplateService,
IWellOperationCategoryRepository wellOperationCategoryRepository)
{ {
this.wellOperationRepository = wellOperationRepository; this.wellOperationRepository = wellOperationRepository;
this.wellService = wellService;
this.wellOperationImportTemplateService = wellOperationImportTemplateService; this.wellOperationImportTemplateService = wellOperationImportTemplateService;
} this.wellOperationCategoryRepository = wellOperationCategoryRepository;
}
public async Task<Stream> ExportAsync(int idWell, CancellationToken cancellationToken) public async Task<Stream> ExportAsync(int idWell, CancellationToken cancellationToken)
{ {
@ -76,7 +75,7 @@ public class WellOperationExportService : IWellOperationExportService
var operationsToArray = operations.ToArray(); var operationsToArray = operations.ToArray();
var sections = wellOperationRepository.GetSectionTypes(); var sections = wellOperationRepository.GetSectionTypes();
var categories = wellOperationRepository.GetCategories(false); var categories = wellOperationCategoryRepository.Get(false);
for (int i = 0; i < operationsToArray.Length; i++) for (int i = 0; i < operationsToArray.Length; i++)
{ {
@ -96,7 +95,7 @@ public class WellOperationExportService : IWellOperationExportService
row.Cell(DefaultTemplateInfo.ColumnCategoryInfo).SetCellValue(operation.CategoryInfo); row.Cell(DefaultTemplateInfo.ColumnCategoryInfo).SetCellValue(operation.CategoryInfo);
row.Cell(DefaultTemplateInfo.ColumnDepthStart).SetCellValue(operation.DepthStart); row.Cell(DefaultTemplateInfo.ColumnDepthStart).SetCellValue(operation.DepthStart);
row.Cell(DefaultTemplateInfo.ColumnDepthEnd).SetCellValue(operation.DepthEnd); row.Cell(DefaultTemplateInfo.ColumnDepthEnd).SetCellValue(operation.DepthEnd);
row.Cell(DefaultTemplateInfo.ColumnDate).SetCellValue(operation.DateStart); row.Cell(DefaultTemplateInfo.ColumnDate).SetCellValue(operation.DateStart.DateTime);
row.Cell(DefaultTemplateInfo.ColumnDuration).SetCellValue(operation.DurationHours); row.Cell(DefaultTemplateInfo.ColumnDuration).SetCellValue(operation.DurationHours);
row.Cell(DefaultTemplateInfo.ColumnComment).SetCellValue(operation.Comment); row.Cell(DefaultTemplateInfo.ColumnComment).SetCellValue(operation.Comment);
} }

View File

@ -14,24 +14,28 @@ public class WellOperationImportService : IWellOperationImportService
{ {
private readonly IWellService wellService; private readonly IWellService wellService;
private readonly IWellOperationRepository wellOperationRepository; private readonly IWellOperationRepository wellOperationRepository;
private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
private static readonly DateTime dateLimitMin = new(2001, 1, 1, 0, 0, 0); private static readonly DateTime dateLimitMin = new(2001, 1, 1, 0, 0, 0);
private static readonly DateTime dateLimitMax = new(2099, 1, 1, 0, 0, 0); private static readonly DateTime dateLimitMax = new(2099, 1, 1, 0, 0, 0);
private static readonly TimeSpan drillingDurationLimitMax = TimeSpan.FromDays(366); private static readonly TimeSpan drillingDurationLimitMax = TimeSpan.FromDays(366);
public WellOperationImportService(IWellService wellService, public WellOperationImportService(
IWellOperationRepository wellOperationRepository) IWellService wellService,
IWellOperationRepository wellOperationRepository,
IWellOperationCategoryRepository wellOperationCategoryRepository
)
{ {
this.wellService = wellService; this.wellService = wellService;
this.wellOperationRepository = wellOperationRepository; this.wellOperationRepository = wellOperationRepository;
} this.wellOperationCategoryRepository = wellOperationCategoryRepository;
}
public IEnumerable<WellOperationDto> Import(int idWell, int idUser, int idType, SheetDto sheet) public IEnumerable<WellOperationDto> Import(int idWell, int idUser, int idType, SheetDto sheet)
{ {
var validationErrors = new List<string>(); var validationErrors = new List<string>();
var sections = wellOperationRepository.GetSectionTypes(); var sections = wellOperationRepository.GetSectionTypes();
var categories = wellOperationRepository.GetCategories(false); var categories = wellOperationCategoryRepository.Get(false);
var wellOperations = new List<WellOperationDto>(); var wellOperations = new List<WellOperationDto>();
@ -83,7 +87,9 @@ public class WellOperationImportService : IWellOperationImportService
IdUser = idUser, IdUser = idUser,
IdType = idType, IdType = idType,
IdWellSectionType = section.Id, IdWellSectionType = section.Id,
WellSectionTypeName = section.Caption,
IdCategory = category.Id, IdCategory = category.Id,
CategoryName = category.Name,
CategoryInfo = row.CategoryInfo, CategoryInfo = row.CategoryInfo,
DepthStart = row.DepthStart, DepthStart = row.DepthStart,
DepthEnd = row.DepthEnd, DepthEnd = row.DepthEnd,

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<UserSecretsId>af52bb94-3f08-4d6a-8895-8cfb7691c393</UserSecretsId> <UserSecretsId>af52bb94-3f08-4d6a-8895-8cfb7691c393</UserSecretsId>

View File

@ -0,0 +1,29 @@
using AsbCloudApp.Data;
using Refit;
namespace AsbCloudWebApi.IntegrationTests.Clients;
public interface ICrudWellRelatedClient<TDto>
where TDto : IId, IWellRelated
{
[Post("/")]
Task<IApiResponse<int>> InsertAsync([Body] TDto dto);
[Post("/range")]
Task<IApiResponse<int>> InsertRangeAsync([Body] IEnumerable<TDto> dtos);
[Get("/")]
Task<IApiResponse<IEnumerable<TDto>>> GetAllAsync();
[Get("/well/{idWell}")]
Task<IApiResponse<IEnumerable<TDto>>> GetByIdWellAsync(int idWell);
[Get("/{id}")]
Task<IApiResponse<TDto>> GetOrDefaultAsync(int id);
[Put("/")]
Task<IApiResponse<int>> UpdateAsync([Body] TDto dto);
[Delete("/{id}")]
Task<IApiResponse<int>> DeleteAsync(int id);
}

View File

@ -26,7 +26,7 @@ public class AdminDepositControllerTest : BaseIntegrationTest
public AdminDepositControllerTest(WebAppFactoryFixture factory) public AdminDepositControllerTest(WebAppFactoryFixture factory)
: base(factory) : base(factory)
{ {
client = factory.GetAuthorizedHttpClient<IAdminDepositClient>(); client = factory.GetAuthorizedHttpClient<IAdminDepositClient>(string.Empty);
dbContext.CleanupDbSet<Deposit>(); dbContext.CleanupDbSet<Deposit>();
} }

View File

@ -82,7 +82,7 @@ public class ProcessMapPlanDrillingControllerTest: BaseIntegrationTest
public ProcessMapPlanDrillingControllerTest(WebAppFactoryFixture factory) : base(factory) public ProcessMapPlanDrillingControllerTest(WebAppFactoryFixture factory) : base(factory)
{ {
dbContext.CleanupDbSet<ProcessMapPlanDrilling>(); dbContext.CleanupDbSet<ProcessMapPlanDrilling>();
client = factory.GetAuthorizedHttpClient<IProcessMapPlanDrillingClient>(); client = factory.GetAuthorizedHttpClient<IProcessMapPlanDrillingClient>(string.Empty);
} }
[Fact] [Fact]

View File

@ -0,0 +1,228 @@
using AsbCloudApp.Data;
using AsbCloudDb.Model;
using AsbCloudInfrastructure;
using AsbCloudWebApi.IntegrationTests.Clients;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System.Net;
using Xunit;
namespace AsbCloudWebApi.IntegrationTests.Controllers
{
public abstract class CrudWellRelatedClient<TDto, TEntity> : BaseIntegrationTest
where TDto : AsbCloudApp.Data.IId, AsbCloudApp.Data.IWellRelated
where TEntity : class, AsbCloudDb.Model.IId, AsbCloudDb.Model.IWellRelated
{
public abstract IEnumerable<TDto> ValidDtos { get; }
public abstract IEnumerable<TDto> InvalidDtos { get; }
public abstract IEnumerable<TDto> ForbiddenDtos { get; }
protected List<string> ExcludeProps { get; set; } = new() { "Id" };
protected ICrudWellRelatedClient<TDto> client;
public CrudWellRelatedClient(WebAppFactoryFixture factory, string uriSuffix)
: base(factory)
{
client = factory.GetAuthorizedHttpClient<ICrudWellRelatedClient<TDto>>(uriSuffix);
}
protected async Task<DbSet<TEntity>> GetCleanDbSet()
{
var dbset = dbContext.Set<TEntity>();
dbset.RemoveRange(dbset);
await dbContext.SaveChangesAsync(CancellationToken.None);
return dbset;
}
[Fact]
public async Task Insert_returns_success_for_validDtos()
{
foreach (var validDto in ValidDtos)
await Insert_returns_success(validDto);
}
private async Task Insert_returns_success(TDto validDto)
{
var dbset = await GetCleanDbSet();
//act
var response = await client.InsertAsync(validDto);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.True(response.Content > 0);
var entity = dbset.First();
var fromDbDto = Convert(entity);
MatchHelper.Match(validDto, fromDbDto, ExcludeProps);
}
[Fact]
public async Task Insert_returns_badRequest_for_invalidDtos()
{
foreach (var inValidDto in InvalidDtos)
await Insert_returns_badRequest(inValidDto);
}
private async Task Insert_returns_badRequest(TDto invalidDto)
{
await GetCleanDbSet();
//act
var response = await client.InsertAsync(invalidDto);
//assert
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
}
[Fact]
public async Task Insert_returns_forbidden_for_forbiddenDtos()
{
foreach (var forbiddenDto in ForbiddenDtos)
await Insert_returns_forbidden(forbiddenDto);
}
private async Task Insert_returns_forbidden(TDto forbiddenDto)
{
await GetCleanDbSet();
//act
var response = await client.InsertAsync(forbiddenDto);
//assert
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
}
[Fact]
public async Task GetAllAsync_returns_data()
{
//arrange
var dbset = await GetCleanDbSet();
var entries = new List<(EntityEntry<TEntity>, TDto)>();
foreach (var dto in ValidDtos)
{
var entity = Convert(dto);
entity.Id = 0;
var entry = dbset.Add(entity);
entries.Add((entry, dto));
}
dbContext.SaveChanges();
//act
var response = await client.GetAllAsync();
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.Equal(entries.Count, response.Content.Count());
foreach (var item in response.Content)
{
var entry = entries.First(e => e.Item1.Entity.Id == item.Id);
MatchHelper.Match(entry.Item2, item, ExcludeProps);
}
}
protected virtual TDto Convert(TEntity entity)
{
var dto = entity.Adapt<TDto>();
return dto;
}
protected virtual TEntity Convert(TDto dto)
{
var entity = dto.Adapt<TEntity>();
return entity;
}
}
public class ScheduleControllerTest : CrudWellRelatedClient<ScheduleDto, Schedule>
{
static Driller driller = Data.Defaults.Drillers.First();
static DrillerDto drillerDto = driller.Adapt<DrillerDto>();
static Well well = Data.Defaults.Wells.First();
public override IEnumerable<ScheduleDto> ValidDtos { get; } = new ScheduleDto[]
{
new() {
Id = 1,
IdWell = well.Id,
Driller = drillerDto,
IdDriller = driller.Id,
DrillStart = new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Unspecified),
DrillEnd = new DateTime(2024, 1, 2, 0, 0, 0, DateTimeKind.Unspecified),
ShiftStart = new TimeDto(8, 0, 0),
ShiftEnd = new TimeDto(20, 0, 0),
},
new() {
Id = 1,
IdWell = well.Id,
Driller = drillerDto,
IdDriller = driller.Id,
DrillStart = new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Unspecified),
DrillEnd = new DateTime(2024, 1, 2, 0, 0, 0, DateTimeKind.Unspecified),
ShiftStart = new TimeDto(20, 0, 0),
ShiftEnd = new TimeDto(8, 0, 0),
}
};
public override IEnumerable<ScheduleDto> InvalidDtos { get; } = new ScheduleDto[]
{
new() {
IdWell = well.Id,
Driller = drillerDto,
IdDriller = driller.Id,
DrillStart = new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Unspecified),
DrillEnd = new DateTime(2022, 1, 2, 0, 0, 0, DateTimeKind.Unspecified),
ShiftStart = new TimeDto(8, 0, 0),
ShiftEnd = new TimeDto(20, 0, 0),
},
new() {
IdWell = well.Id,
Driller = drillerDto,
IdDriller = int.MaxValue - 1,
DrillStart = new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Unspecified),
DrillEnd = new DateTime(2024, 1, 2, 0, 0, 0, DateTimeKind.Unspecified),
ShiftStart = new TimeDto(8, 0, 0),
ShiftEnd = new TimeDto(20, 0, 0),
}
};
public override IEnumerable<ScheduleDto> ForbiddenDtos { get; } = new ScheduleDto[] {
new() {
IdWell = int.MaxValue - 1,
Driller = drillerDto,
IdDriller = driller.Id,
DrillStart = new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Unspecified),
DrillEnd = new DateTime(2022, 1, 2, 0, 0, 0, DateTimeKind.Unspecified),
ShiftStart = new TimeDto(8, 0, 0),
ShiftEnd = new TimeDto(20, 0, 0),
}
};
public ScheduleControllerTest(WebAppFactoryFixture factory)
: base(factory, "api/schedule")
{
ExcludeProps.Add(nameof(ScheduleDto.Driller));
}
protected override ScheduleDto Convert(Schedule entity)
{
var dto = base.Convert(entity);
dto.DrillStart = entity.DrillStart.ToRemoteDateTime(well.Timezone.Hours);
dto.DrillEnd = entity.DrillEnd.ToRemoteDateTime(well.Timezone.Hours);
return dto;
}
protected override Schedule Convert(ScheduleDto dto)
{
var entity = base.Convert(dto);
entity.DrillStart = dto.DrillStart.FromTimeZoneOffsetHours(well.Timezone.Hours);
entity.DrillEnd = dto.DrillEnd.FromTimeZoneOffsetHours(well.Timezone.Hours);
return entity;
}
}
}

View File

@ -66,7 +66,7 @@ public class SlipsStatControllerTest : BaseIntegrationTest
wellOperations.Add(factWellOperation); wellOperations.Add(factWellOperation);
dbContext.SaveChanges(); dbContext.SaveChanges();
client = factory.GetAuthorizedHttpClient<ISlipsTimeClient>(); client = factory.GetAuthorizedHttpClient<ISlipsTimeClient>(string.Empty);
} }
[Fact] [Fact]

View File

@ -44,7 +44,7 @@ public class WellOperationControllerTest : BaseIntegrationTest
public WellOperationControllerTest(WebAppFactoryFixture factory) public WellOperationControllerTest(WebAppFactoryFixture factory)
: base(factory) : base(factory)
{ {
client = factory.GetAuthorizedHttpClient<IWellOperationClient>(); client = factory.GetAuthorizedHttpClient<IWellOperationClient>(string.Empty);
} }
/// <summary> /// <summary>

View File

@ -10,8 +10,16 @@ namespace AsbCloudWebApi.IntegrationTests.Data
new() new()
{ {
Id = 1, Id = 1,
Name = "test", Name = "test1",
Surname = "test" Surname = "test1",
Patronymic = "test1"
},
new()
{
Id = 2,
Name = "test2",
Surname = "test2",
Patronymic = "test2"
} }
}; };

View File

@ -83,10 +83,12 @@ public class WebAppFactoryFixture : WebApplicationFactory<Startup>,
return httpClient; return httpClient;
} }
public T GetAuthorizedHttpClient<T>() public T GetAuthorizedHttpClient<T>(string uriSuffix)
{ {
var httpClient = GetAuthorizedHttpClient(); var httpClient = GetAuthorizedHttpClient();
if (!string.IsNullOrEmpty(uriSuffix))
if(httpClient.BaseAddress is not null)
httpClient.BaseAddress = new Uri(httpClient.BaseAddress, uriSuffix);
return RestService.For<T>(httpClient, refitSettings); return RestService.For<T>(httpClient, refitSettings);
} }
} }

View File

@ -1,10 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>

View File

@ -5,6 +5,7 @@ using AsbCloudApp.Requests;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudApp.Services.WellOperationImport; using AsbCloudApp.Services.WellOperationImport;
using AsbCloudDb.Model; using AsbCloudDb.Model;
using AsbCloudInfrastructure.Repository;
using AsbCloudInfrastructure.Services.WellOperationImport; using AsbCloudInfrastructure.Services.WellOperationImport;
using AsbCloudInfrastructure.Services.WellOperationImport.FileParser; using AsbCloudInfrastructure.Services.WellOperationImport.FileParser;
using NSubstitute; using NSubstitute;
@ -27,6 +28,7 @@ namespace AsbCloudWebApi.Tests.Services.WellOperationExport
private IWellService wellService; private IWellService wellService;
private IWellOperationRepository wellOperationRepository; private IWellOperationRepository wellOperationRepository;
private IWellOperationCategoryRepository wellOperationCategoryRepository;
private IWellOperationImportTemplateService wellOperationImportTemplateService; private IWellOperationImportTemplateService wellOperationImportTemplateService;
private WellOperationExportService wellOperationExportService; private WellOperationExportService wellOperationExportService;
private WellOperationImportService wellOperationImportService; private WellOperationImportService wellOperationImportService;
@ -114,46 +116,46 @@ namespace AsbCloudWebApi.Tests.Services.WellOperationExport
{ {
wellService = Substitute.For<IWellService>(); wellService = Substitute.For<IWellService>();
wellOperationRepository = Substitute.For<IWellOperationRepository>(); wellOperationRepository = Substitute.For<IWellOperationRepository>();
wellOperationCategoryRepository = Substitute.For<IWellOperationCategoryRepository>();
wellOperationImportTemplateService = new WellOperationImportTemplateService(); wellOperationImportTemplateService = new WellOperationImportTemplateService();
wellOperationExportService = new WellOperationExportService(wellOperationRepository, wellService, wellOperationImportTemplateService); wellOperationExportService = new WellOperationExportService(wellOperationRepository, wellOperationImportTemplateService, wellOperationCategoryRepository);
wellOperationImportService = new WellOperationImportService(wellService, wellOperationRepository); wellOperationImportService = new WellOperationImportService(wellService, wellOperationRepository, wellOperationCategoryRepository);
wellOperationDefaultExcelParser = new WellOperationDefaultExcelParser(); wellOperationDefaultExcelParser = new WellOperationDefaultExcelParser();
this.output = output; this.output = output;
} }
#warning Test Check_Exported_WellOperations_With_Operations_In_Db Fails and commented for debug deployment task [Fact]
//[Fact] public async Task Check_Exported_WellOperations_With_Operations_In_Db()
//public async Task Check_Exported_WellOperations_With_Operations_In_Db() {
//{ wellService.GetTimezone(idWell).Returns(new SimpleTimezoneDto()
// wellService.GetTimezone(idWell).Returns(new SimpleTimezoneDto() {
// { Hours = 5
// Hours = 5 });
// });
// var localOperations = operations.ToArray(); var localOperations = operations.ToArray();
// foreach (var operation in localOperations) foreach (var operation in localOperations)
// operation.Id = 0; operation.Id = 0;
// wellOperationRepository.GetAsync(Arg.Any<WellOperationRequest>(), Arg.Any<CancellationToken>()) wellOperationRepository.GetAsync(Arg.Any<WellOperationRequest>(), Arg.Any<CancellationToken>())
// .ReturnsForAnyArgs(localOperations); .ReturnsForAnyArgs(localOperations);
// wellOperationRepository.GetSectionTypes().Returns(sectionTypes); wellOperationRepository.GetSectionTypes().Returns(sectionTypes);
// wellOperationRepository.GetCategories(false).Returns(categories); wellOperationCategoryRepository.Get(false).Returns(categories);
// var stream = await wellOperationExportService.ExportAsync(idWell, CancellationToken.None); var stream = await wellOperationExportService.ExportAsync(idWell, CancellationToken.None);
// var options = new WellOperationImportDefaultOptionsDto var options = new WellOperationImportDefaultOptionsDto
// { {
// IdType = WellOperation.IdOperationTypePlan IdType = WellOperation.IdOperationTypePlan
// }; };
// var sheet = wellOperationDefaultExcelParser.Parse(stream, options); var sheet = wellOperationDefaultExcelParser.Parse(stream, options);
// var result = wellOperationImportService.Import(idWell, 1, options.IdType, sheet); var result = wellOperationImportService.Import(idWell, 1, options.IdType, sheet);
// var expected = JsonSerializer.Serialize(localOperations); var expected = JsonSerializer.Serialize(localOperations);
// var actual = JsonSerializer.Serialize(result); var actual = JsonSerializer.Serialize(result);
// Assert.Equal(expected, actual); Assert.Equal(expected, actual);
//} }
[Fact] [Fact]
public void TestDataContainsNotDefaultProps() public void TestDataContainsNotDefaultProps()

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<ServerGarbageCollection>true</ServerGarbageCollection> <ServerGarbageCollection>true</ServerGarbageCollection>
<NoWarn>$(NoWarn);1591</NoWarn> <NoWarn>$(NoWarn);1591</NoWarn>

View File

@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -22,7 +23,7 @@ namespace AsbCloudWebApi.Controllers.Subsystems
private readonly ISubsystemService subsystemService; private readonly ISubsystemService subsystemService;
private readonly ITelemetryDataSaubService telemetryDataSaubService; private readonly ITelemetryDataSaubService telemetryDataSaubService;
private readonly IWellService wellService; private readonly IWellService wellService;
public SubsystemController( public SubsystemController(
ISubsystemService subsystemService, ISubsystemService subsystemService,
IWellService wellService, IWellService wellService,
@ -32,6 +33,7 @@ namespace AsbCloudWebApi.Controllers.Subsystems
this.wellService = wellService; this.wellService = wellService;
this.telemetryDataSaubService = telemetryDataSaubService; this.telemetryDataSaubService = telemetryDataSaubService;
} }
/// <summary> /// <summary>
/// получить статистику /// получить статистику
/// </summary> /// </summary>
@ -61,6 +63,23 @@ namespace AsbCloudWebApi.Controllers.Subsystems
return Ok(dateRange); return Ok(dateRange);
} }
[HttpGet("drillerDetectedOperationStat")]
[ProducesResponseType(typeof(IEnumerable<DrillerDetectedOperationStatDto>), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetByWellsAsync([FromQuery] GetStatRequest request,
CancellationToken token)
{
if (!request.IdsWells.Any())
return NoContent();
foreach(var idWell in request.IdsWells)
if (!await UserHasAccessToWellAsync(idWell, token))
return Forbid();
var result = await subsystemService.GetByWellsAsync(request, token);
return Ok(result);
}
private async Task<bool> UserHasAccessToWellAsync(int idWell, CancellationToken token) private async Task<bool> UserHasAccessToWellAsync(int idWell, CancellationToken token)
{ {
var idCompany = User.GetCompanyId(); var idCompany = User.GetCompanyId();
@ -71,4 +90,4 @@ namespace AsbCloudWebApi.Controllers.Subsystems
return false; return false;
} }
} }
} }

View File

@ -35,6 +35,7 @@ namespace AsbCloudWebApi.Controllers
private readonly IWellOperationExportService wellOperationExportService; private readonly IWellOperationExportService wellOperationExportService;
private readonly IWellOperationImportTemplateService wellOperationImportTemplateService; private readonly IWellOperationImportTemplateService wellOperationImportTemplateService;
private readonly IWellOperationImportService wellOperationImportService; private readonly IWellOperationImportService wellOperationImportService;
private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
private readonly IWellOperationExcelParser<WellOperationImportDefaultOptionsDto> wellOperationDefaultExcelParser; private readonly IWellOperationExcelParser<WellOperationImportDefaultOptionsDto> wellOperationDefaultExcelParser;
private readonly IWellOperationExcelParser<WellOperationImportGazpromKhantosOptionsDto> wellOperationGazpromKhantosExcelParser; private readonly IWellOperationExcelParser<WellOperationImportGazpromKhantosOptionsDto> wellOperationGazpromKhantosExcelParser;
private readonly IUserRepository userRepository; private readonly IUserRepository userRepository;
@ -44,6 +45,7 @@ namespace AsbCloudWebApi.Controllers
IWellOperationImportTemplateService wellOperationImportTemplateService, IWellOperationImportTemplateService wellOperationImportTemplateService,
IWellOperationExportService wellOperationExportService, IWellOperationExportService wellOperationExportService,
IWellOperationImportService wellOperationImportService, IWellOperationImportService wellOperationImportService,
IWellOperationCategoryRepository wellOperationCategoryRepository,
IWellOperationExcelParser<WellOperationImportDefaultOptionsDto> wellOperationDefaultExcelParser, IWellOperationExcelParser<WellOperationImportDefaultOptionsDto> wellOperationDefaultExcelParser,
IWellOperationExcelParser<WellOperationImportGazpromKhantosOptionsDto> wellOperationGazpromKhantosExcelParser, IWellOperationExcelParser<WellOperationImportGazpromKhantosOptionsDto> wellOperationGazpromKhantosExcelParser,
IUserRepository userRepository) IUserRepository userRepository)
@ -53,6 +55,7 @@ namespace AsbCloudWebApi.Controllers
this.wellOperationImportTemplateService = wellOperationImportTemplateService; this.wellOperationImportTemplateService = wellOperationImportTemplateService;
this.wellOperationExportService = wellOperationExportService; this.wellOperationExportService = wellOperationExportService;
this.wellOperationImportService = wellOperationImportService; this.wellOperationImportService = wellOperationImportService;
this.wellOperationCategoryRepository = wellOperationCategoryRepository;
this.wellOperationDefaultExcelParser = wellOperationDefaultExcelParser; this.wellOperationDefaultExcelParser = wellOperationDefaultExcelParser;
this.wellOperationGazpromKhantosExcelParser = wellOperationGazpromKhantosExcelParser; this.wellOperationGazpromKhantosExcelParser = wellOperationGazpromKhantosExcelParser;
this.userRepository = userRepository; this.userRepository = userRepository;
@ -81,7 +84,7 @@ namespace AsbCloudWebApi.Controllers
[ProducesResponseType(typeof(IEnumerable<WellOperationCategoryDto>), (int)System.Net.HttpStatusCode.OK)] [ProducesResponseType(typeof(IEnumerable<WellOperationCategoryDto>), (int)System.Net.HttpStatusCode.OK)]
public IActionResult GetCategories(bool includeParents = true) public IActionResult GetCategories(bool includeParents = true)
{ {
var result = operationRepository.GetCategories(includeParents); var result = wellOperationCategoryRepository.Get(includeParents);
return Ok(result); return Ok(result);
} }
@ -163,7 +166,7 @@ namespace AsbCloudWebApi.Controllers
} }
/// <summary> /// <summary>
/// Статистика операций по скважине, группированая по категориям /// Статистика операций по скважине, группированная по категориям
/// </summary> /// </summary>
/// <param name="idWell">id скважины</param> /// <param name="idWell">id скважины</param>
/// <param name="request"></param> /// <param name="request"></param>

View File

@ -13,7 +13,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<PublishUrl>bin\publishLinux\</PublishUrl> <PublishUrl>bin\publishLinux\</PublishUrl>
<WebPublishMethod>FileSystem</WebPublishMethod> <WebPublishMethod>FileSystem</WebPublishMethod>
<SiteUrlToLaunchAfterPublish /> <SiteUrlToLaunchAfterPublish />
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ProjectGuid>a2768702-47cb-4127-941c-e339d5efcffe</ProjectGuid> <ProjectGuid>a2768702-47cb-4127-941c-e339d5efcffe</ProjectGuid>
<SelfContained>true</SelfContained> <SelfContained>true</SelfContained>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier> <RuntimeIdentifier>linux-x64</RuntimeIdentifier>