Удержание в клиньях получение статистики

1. Добавлены интеграционные тесты
2. Добавлены TODO дял дальнейшего рефакторинга
3. Сделан небольшой рефакторинг метода получения статистики по удержанию в клиньях
This commit is contained in:
Степанов Дмитрий 2024-01-22 17:22:11 +05:00
parent 6045333f53
commit c1729d06c7
7 changed files with 172 additions and 29 deletions

View File

@ -7,21 +7,25 @@ namespace AsbCloudApp.Requests
/// </summary>
public class OperationStatRequest
{
//TODO: использовать DateOnly. Поправить naming
/// <summary>
/// Дата начала операции в UTC
/// </summary>
public DateTime? DateStartUTC { get; set; }
//TODO: использовать DateOnly. Поправить naming
/// <summary>
/// Дата окончания операции в UTC
/// </summary>
public DateTime? DateEndUTC { get; set; }
//TODO: поправить naming
/// <summary>
/// Минимальная продолжительность операции, мин
/// </summary>
public double? DurationMinutesMin { get; set; }
//TODO: поправить naming
/// <summary>
/// Максимальная продолжительность операции, мин
/// </summary>

View File

@ -78,11 +78,14 @@ public class SlipsStatService : ISlipsStatService
.Where(o => o.IdCategory == WellOperationCategory.IdSlipsTime)
.AsNoTracking();
if (request.DateStartUTC.HasValue && request.DateEndUTC.HasValue)
if (request.DateStartUTC.HasValue)
detectedOperationsQuery = detectedOperationsQuery
.Where(o => o.DateStart < request.DateEndUTC)
.Where(o => o.DateEnd > request.DateStartUTC);
if (request.DateEndUTC.HasValue)
detectedOperationsQuery = detectedOperationsQuery
.Where(o => o.DateStart < request.DateEndUTC);
if (request.DurationMinutesMin.HasValue)
{
var durationMinutesMin = TimeSpan.FromMinutes(request.DurationMinutesMin.Value);
@ -101,21 +104,23 @@ public class SlipsStatService : ISlipsStatService
.ToArrayAsync(token);
var detectedOperationsGroupedByDrillerAndSection = detectedOperations.Select(o => new
{
Operation = o,
IdWell = telemetries[o.IdTelemetry],
schedules.FirstOrDefault(s =>
s.IdWell == telemetries[o.IdTelemetry]
&& s.DrillStart <= o.DateStart
&& s.DrillEnd >= o.DateStart
&& new TimeDto(s.ShiftStart) <= new TimeDto(o.DateStart.DateTime)
&& new TimeDto(s.ShiftEnd) >= new TimeDto(o.DateStart.DateTime))
?.Driller,
Section = sections.FirstOrDefault(s =>
s.IdWell == telemetries[o.IdTelemetry]
&& s.DepthStart <= o.DepthStart
&& s.DepthEnd >= o.DepthStart)
})
{
Operation = o,
IdWell = telemetries[o.IdTelemetry],
schedules.FirstOrDefault(s =>
s.IdWell == telemetries[o.IdTelemetry] &&
s.DrillStart <= o.DateStart &&
s.DrillEnd > o.DateStart && (
s.ShiftStart > s.ShiftEnd
) ^ (s.ShiftStart <= new TimeDto(o.DateStart.DateTime).MakeTimeOnly() &&
s.ShiftEnd > new TimeDto(o.DateStart.DateTime).MakeTimeOnly()
))
?.Driller,
Section = sections.FirstOrDefault(s =>
s.IdWell == telemetries[o.IdTelemetry]
&& s.DepthStart <= o.DepthStart
&& s.DepthEnd >= o.DepthStart)
})
.Where(o => o.Driller != null)
.Where(o => o.Section != null)
.Select(o => new
@ -133,20 +138,21 @@ public class SlipsStatService : ISlipsStatService
{
Operation = o,
schedules.FirstOrDefault(s =>
s.IdWell == o.IdWell
&& s.DrillStart <= o.DateStart
&& s.DrillEnd >= o.DateStart
&& new TimeDto(s.ShiftStart) <= new TimeDto(o.DateStart.DateTime)
&& new TimeDto(s.ShiftEnd) >= new TimeDto(o.DateStart.DateTime))
?.Driller,
s.IdWell == o.IdWell &&
s.DrillStart <= o.DateStart &&
s.DrillEnd > o.DateStart && (
s.ShiftStart > s.ShiftEnd
) ^ (s.ShiftStart <= new TimeDto(o.DateStart.DateTime).MakeTimeOnly() &&
s.ShiftEnd > new TimeDto(o.DateStart.DateTime).MakeTimeOnly()
))
?.Driller,
})
.Where(o => o.Driller != null)
.GroupBy(o => new { o.Driller!.Id, o.Operation.IdWellSectionType });
var stats = detectedOperationsGroupedByDrillerAndSection.Select(group => new SlipsStatDto
{
DrillerName = $"{group.First().Driller!.Name} {group.First().Driller!.Patronymic} {group.First().Driller!.Surname}",
DrillerName = $"{group.First().Driller!.Surname} {group.First().Driller!.Name} {group.First().Driller!.Patronymic}",
SlipsCount = group.Count(),
SlipsTimeInMinutes = group
.Sum(y => (y.Operation.DateEnd - y.Operation.DateStart).TotalMinutes),

View File

@ -0,0 +1,13 @@
using AsbCloudApp.Data;
using AsbCloudApp.Requests;
using Refit;
namespace AsbCloudWebApi.IntegrationTests.Clients;
public interface ISlipsTimeClient
{
private const string BaseRoute = "/api/slipsStat";
[Get(BaseRoute)]
Task<IApiResponse<IEnumerable<SlipsStatDto>>> GetAll([Query] OperationStatRequest request);
}

View File

@ -0,0 +1,94 @@
using AsbCloudApp.Data;
using AsbCloudApp.Requests;
using AsbCloudDb.Model;
using AsbCloudWebApi.IntegrationTests.Clients;
using Xunit;
namespace AsbCloudWebApi.IntegrationTests.Controllers;
public class SlipsStatControllerTest : BaseIntegrationTest
{
private static readonly Schedule schedule = new()
{
Id = 1,
IdDriller = Data.Defaults.Drillers[0].Id,
IdWell = Data.Defaults.Wells[0].Id,
ShiftStart = new TimeOnly(8, 0, 0),
ShiftEnd = new TimeOnly(20, 0, 0),
DrillStart = new DateTimeOffset(new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Utc)),
DrillEnd = new DateTimeOffset(new DateTime(2024, 2, 1, 0, 0, 0, DateTimeKind.Utc))
};
private static readonly DetectedOperation detectedOperation = new()
{
Id = 1,
IdTelemetry = Data.Defaults.Telemetries[0].Id,
IdCategory = WellOperationCategory.IdSlipsTime,
DateStart = new DateTimeOffset(new DateTime(2024, 1, 23, 15, 0, 0, 0, DateTimeKind.Utc)),
DateEnd = new DateTimeOffset(new DateTime(2024, 1, 23, 15, 2, 0, 0, DateTimeKind.Utc)),
ExtraData = new Dictionary<string, object>
{
{ "test", 5 }
}
};
private static readonly WellOperation factWellOperation = new()
{
Id = 1,
IdWell = Data.Defaults.Wells[0].Id,
IdWellSectionType = 1,
IdCategory = WellOperationCategory.IdRotor,
IdType = WellOperation.IdOperationTypeFact,
DepthStart = 0,
DepthEnd = 100,
LastUpdateDate = DateTimeOffset.UtcNow,
DateStart = new DateTimeOffset(new DateTime(2024, 1, 15, 15, 0, 0, DateTimeKind.Utc)),
DurationHours = 1
};
private readonly ISlipsTimeClient slipsTimeClient;
public SlipsStatControllerTest(WebAppFactoryFixture factory)
: base(factory)
{
slipsTimeClient = factory.GetAuthorizedHttpClient<ISlipsTimeClient>();
}
[Fact]
public async Task GetAll_returns_success()
{
//arrange
dbContext.Schedule.Add(schedule);
dbContext.DetectedOperations.Add(detectedOperation);
dbContext.WellOperations.Add(factWellOperation);
dbContext.SaveChanges();
var request = new OperationStatRequest
{
DateStartUTC = schedule.DrillStart.DateTime,
DateEndUTC = schedule.DrillEnd.DateTime,
DurationMinutesMin = 0,
DurationMinutesMax = 5
};
var dtoExpected = new SlipsStatDto
{
DrillerName = $"{Data.Defaults.Drillers[0].Surname} {Data.Defaults.Drillers[0].Name} {Data.Defaults.Drillers[0].Patronymic}",
WellCount = 1,
SectionCaption = "Пилотный ствол",
SlipsCount = 1,
SlipsTimeInMinutes = (detectedOperation.DateEnd - detectedOperation.DateStart).TotalMinutes,
SectionDepth = factWellOperation.DepthEnd - factWellOperation.DepthStart,
};
//act
var response = await slipsTimeClient.GetAll(request);
//assert
Assert.NotNull(response.Content);
Assert.Single(response.Content);
var dtoActual = response.Content.First();
MatchHelper.Match(dtoExpected, dtoActual);
}
}

View File

@ -4,7 +4,17 @@ namespace AsbCloudWebApi.IntegrationTests.Data
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2211:Поля, не являющиеся константами, не должны быть видимыми", Justification = "<Ожидание>")]
public static class Defaults
{
{
public static Driller[] Drillers = new Driller[]
{
new()
{
Id = 1,
Name = "test",
Surname = "test"
}
};
public static Deposit[] Deposits = new Deposit[] {
new()
{
@ -32,6 +42,19 @@ namespace AsbCloudWebApi.IntegrationTests.Data
}
};
public static Telemetry[] Telemetries = new Telemetry[]
{
new()
{
Id = 1,
RemoteUid = "555-555-555",
TimeZone = new SimpleTimezone
{
Hours = 1
}
}
};
public static Well[] Wells = new Well[] {
new()
{
@ -42,7 +65,7 @@ namespace AsbCloudWebApi.IntegrationTests.Data
Caption = "Well1",
Latitude = 10,
Longitude = 20,
IdTelemetry = null,
IdTelemetry = Telemetries[0].Id,
Timezone = new SimpleTimezone{
Hours = 1
}

View File

@ -3,6 +3,7 @@ using Bogus;
namespace AsbCloudWebApi.IntegrationTests.TestFakers;
//TODO: выпилить
public static class EntitiesFaker
{
public static Faker<Deposit> Deposit { get; } = new Faker<Deposit>()

View File

@ -60,7 +60,9 @@ public class WebAppFactoryFixture : WebApplicationFactory<Startup>,
dbContext.AddRange(Data.Defaults.Clusters);
dbContext.AddRange(Data.Defaults.Wells);
dbContext.AddRange(Data.Defaults.RelationsCompanyWell);
await dbContext.SaveChangesAsync();
dbContext.AddRange(Data.Defaults.Telemetries);
dbContext.AddRange(Data.Defaults.Drillers);
await dbContext.SaveChangesAsync();
}
public new async Task DisposeAsync()