forked from ddrilling/AsbCloudServer
Merge branch 'dev' into feature/detected_operations
This commit is contained in:
commit
640c32785f
@ -60,16 +60,15 @@ public class WellOperationRepository : IWellOperationRepository
|
|||||||
OperationType = WellOperation.IdOperationTypePlan,
|
OperationType = WellOperation.IdOperationTypePlan,
|
||||||
};
|
};
|
||||||
|
|
||||||
var entities = await BuildQuery(request)
|
var dtos = await BuildQuery(request)
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.ToArrayAsync(token)
|
.ToArrayAsync(token);
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
var dateLastAssosiatedPlanOperation = await GetDateLastAssosiatedPlanOperationAsync(idWell, currentDate, timezone.Hours, token);
|
var dateLastAssosiatedPlanOperation = await GetDateLastAssosiatedPlanOperationAsync(idWell, currentDate, timezone.Hours, token);
|
||||||
|
|
||||||
var result = new WellOperationPlanDto()
|
var result = new WellOperationPlanDto()
|
||||||
{
|
{
|
||||||
WellOperationsPlan = entities,
|
WellOperationsPlan = dtos.Select(Convert),
|
||||||
DateLastAssosiatedPlanOperation = dateLastAssosiatedPlanOperation
|
DateLastAssosiatedPlanOperation = dateLastAssosiatedPlanOperation
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -211,7 +210,7 @@ public class WellOperationRepository : IWellOperationRepository
|
|||||||
|
|
||||||
var dtos = await query.ToArrayAsync(token);
|
var dtos = await query.ToArrayAsync(token);
|
||||||
|
|
||||||
return dtos;
|
return dtos.Select(Convert);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@ -219,21 +218,19 @@ public class WellOperationRepository : IWellOperationRepository
|
|||||||
WellOperationRequest request,
|
WellOperationRequest request,
|
||||||
CancellationToken token)
|
CancellationToken token)
|
||||||
{
|
{
|
||||||
var query = BuildQuery(request)
|
var query = BuildQuery(request);
|
||||||
.AsNoTracking();
|
|
||||||
|
|
||||||
var result = new PaginationContainer<WellOperationDto>
|
var result = new PaginationContainer<WellOperationDto>
|
||||||
{
|
{
|
||||||
Skip = request.Skip ?? 0,
|
Skip = request.Skip ?? 0,
|
||||||
Take = request.Take ?? 32,
|
Take = request.Take ?? 32,
|
||||||
Count = await query.CountAsync(token).ConfigureAwait(false),
|
Count = await query.CountAsync(token),
|
||||||
};
|
};
|
||||||
|
|
||||||
query = query
|
var dtos = await query.ToArrayAsync(token);
|
||||||
.Skip(result.Skip)
|
|
||||||
.Take(result.Take);
|
result.Items = dtos.Select(Convert);
|
||||||
|
|
||||||
result.Items = await query.ToArrayAsync(token);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,11 +381,12 @@ public class WellOperationRepository : IWellOperationRepository
|
|||||||
/// В результате попрежнему требуется конвертировать дату
|
/// В результате попрежнему требуется конвертировать дату
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="request"></param>
|
/// <param name="request"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private IQueryable<WellOperationDto> BuildQuery(WellOperationRequest request)
|
private IQueryable<WellOperationDto> BuildQuery(WellOperationRequest request)
|
||||||
{
|
{
|
||||||
var timezone = wellService.GetTimezone(request.IdWell);
|
var timezone = wellService.GetTimezone(request.IdWell);
|
||||||
var timeZoneOffset = TimeSpan.FromHours(timezone.Hours);
|
var timeZoneOffset = timezone.Hours;
|
||||||
|
|
||||||
var query = db.WellOperations
|
var query = db.WellOperations
|
||||||
.Include(s => s.WellSectionType)
|
.Include(s => s.WellSectionType)
|
||||||
@ -413,20 +411,20 @@ public class WellOperationRepository : IWellOperationRepository
|
|||||||
|
|
||||||
if (request.GeDate.HasValue)
|
if (request.GeDate.HasValue)
|
||||||
{
|
{
|
||||||
var geDateOffset = request.GeDate.Value.ToUtcDateTimeOffset(timezone.Hours);
|
var geDateOffset = request.GeDate.Value.ToUtcDateTimeOffset(timeZoneOffset);
|
||||||
query = query.Where(e => e.DateStart >= geDateOffset);
|
query = query.Where(e => e.DateStart >= geDateOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.LtDate.HasValue)
|
if (request.LtDate.HasValue)
|
||||||
{
|
{
|
||||||
var ltDateOffset = request.LtDate.Value.ToUtcDateTimeOffset(timezone.Hours);
|
var ltDateOffset = request.LtDate.Value.ToUtcDateTimeOffset(timeZoneOffset);
|
||||||
query = query.Where(e => e.DateStart < ltDateOffset);
|
query = query.Where(e => e.DateStart < ltDateOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentWellOperations = db.WellOperations
|
var currentWellOperations = db.WellOperations
|
||||||
.Where(subOp => subOp.IdWell == request.IdWell);
|
.Where(subOp => subOp.IdWell == request.IdWell);
|
||||||
|
|
||||||
var wellOperationsWithCategoryNPT = currentWellOperations
|
var wellOperationsWithCategoryNpt = currentWellOperations
|
||||||
.Where(subOp => subOp.IdType == 1)
|
.Where(subOp => subOp.IdType == 1)
|
||||||
.Where(subOp => WellOperationCategory.NonProductiveTimeSubIds.Contains(subOp.IdCategory));
|
.Where(subOp => WellOperationCategory.NonProductiveTimeSubIds.Contains(subOp.IdCategory));
|
||||||
|
|
||||||
@ -442,14 +440,14 @@ public class WellOperationRepository : IWellOperationRepository
|
|||||||
|
|
||||||
CategoryName = o.OperationCategory.Name,
|
CategoryName = o.OperationCategory.Name,
|
||||||
WellSectionTypeName = o.WellSectionType.Caption,
|
WellSectionTypeName = o.WellSectionType.Caption,
|
||||||
DateStart = DateTime.SpecifyKind(o.DateStart.UtcDateTime + timeZoneOffset, DateTimeKind.Unspecified),
|
DateStart = o.DateStart,
|
||||||
DepthStart = o.DepthStart,
|
DepthStart = o.DepthStart,
|
||||||
DepthEnd = o.DepthEnd,
|
DepthEnd = o.DepthEnd,
|
||||||
DurationHours = o.DurationHours,
|
DurationHours = o.DurationHours,
|
||||||
CategoryInfo = o.CategoryInfo,
|
CategoryInfo = o.CategoryInfo,
|
||||||
Comment = o.Comment,
|
Comment = o.Comment,
|
||||||
|
|
||||||
NptHours = wellOperationsWithCategoryNPT
|
NptHours = wellOperationsWithCategoryNpt
|
||||||
.Where(subOp => subOp.DateStart <= o.DateStart)
|
.Where(subOp => subOp.DateStart <= o.DateStart)
|
||||||
.Select(subOp => subOp.DurationHours)
|
.Select(subOp => subOp.DurationHours)
|
||||||
.Sum(),
|
.Sum(),
|
||||||
@ -460,22 +458,39 @@ public class WellOperationRepository : IWellOperationRepository
|
|||||||
.Min(subOp => subOp.DateStart))
|
.Min(subOp => subOp.DateStart))
|
||||||
.TotalDays,
|
.TotalDays,
|
||||||
IdUser = o.IdUser,
|
IdUser = o.IdUser,
|
||||||
LastUpdateDate = DateTime.SpecifyKind(o.LastUpdateDate.UtcDateTime + timeZoneOffset, DateTimeKind.Unspecified)
|
LastUpdateDate = o.LastUpdateDate,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (request.SortFields?.Any() == true)
|
if (request.SortFields?.Any() == true)
|
||||||
{
|
{
|
||||||
dtos = dtos.SortBy(request.SortFields);
|
dtos = dtos.SortBy(request.SortFields);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
dtos = dtos
|
dtos = dtos
|
||||||
.OrderBy(e => e.DateStart)
|
.OrderBy(e => e.DateStart)
|
||||||
.ThenBy(e => e.DepthEnd)
|
.ThenBy(e => e.DepthEnd)
|
||||||
.ThenBy(e => e.Id);
|
.ThenBy(e => e.Id);
|
||||||
|
|
||||||
|
if (request.Skip.HasValue)
|
||||||
|
dtos = dtos.Skip(request.Skip.Value);
|
||||||
|
|
||||||
|
if (request.Take.HasValue)
|
||||||
|
dtos = dtos.Take(request.Take.Value);
|
||||||
|
|
||||||
|
return dtos.AsNoTracking();
|
||||||
}
|
}
|
||||||
|
|
||||||
return dtos;
|
private WellOperationDto Convert(WellOperationDto dto)
|
||||||
|
{
|
||||||
|
var timezone = wellService.GetTimezone(dto.IdWell);
|
||||||
|
var timezoneOffset = TimeSpan.FromHours(timezone.Hours);
|
||||||
|
|
||||||
|
var dtoWithRemoteDateTime = dto.Adapt<WellOperationDto>();
|
||||||
|
|
||||||
|
dtoWithRemoteDateTime.DateStart = dto.DateStart.ToOffset(TimeSpan.FromHours(timezoneOffset.Hours));
|
||||||
|
dtoWithRemoteDateTime.LastUpdateDate = dto.LastUpdateDate?.ToOffset(TimeSpan.FromHours(timezoneOffset.Hours));
|
||||||
|
|
||||||
|
return dtoWithRemoteDateTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> RemoveDuplicates(Action<string, double?> onProgressCallback, CancellationToken token)
|
public async Task<int> RemoveDuplicates(Action<string, double?> onProgressCallback, CancellationToken token)
|
||||||
|
@ -5,20 +5,24 @@ using System.Linq;
|
|||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Data.WellOperationImport;
|
using AsbCloudApp.Data.WellOperationImport;
|
||||||
using AsbCloudApp.Repositories;
|
using AsbCloudApp.Repositories;
|
||||||
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudApp.Services.WellOperationImport;
|
using AsbCloudApp.Services.WellOperationImport;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.WellOperationImport;
|
namespace AsbCloudInfrastructure.Services.WellOperationImport;
|
||||||
|
|
||||||
public class WellOperationImportService : IWellOperationImportService
|
public class WellOperationImportService : IWellOperationImportService
|
||||||
{
|
{
|
||||||
|
private readonly IWellService wellService;
|
||||||
private readonly IWellOperationRepository wellOperationRepository;
|
private readonly IWellOperationRepository wellOperationRepository;
|
||||||
|
|
||||||
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(IWellOperationRepository wellOperationRepository)
|
public WellOperationImportService(IWellService wellService,
|
||||||
|
IWellOperationRepository wellOperationRepository)
|
||||||
{
|
{
|
||||||
|
this.wellService = wellService;
|
||||||
this.wellOperationRepository = wellOperationRepository;
|
this.wellOperationRepository = wellOperationRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,7 +35,11 @@ public class WellOperationImportService : IWellOperationImportService
|
|||||||
|
|
||||||
var wellOperations = new List<WellOperationDto>();
|
var wellOperations = new List<WellOperationDto>();
|
||||||
|
|
||||||
foreach (var row in sheet.Rows)
|
var rows = sheet.Rows.OrderBy(r => r.Date);
|
||||||
|
|
||||||
|
var prevRow = new RowDto();
|
||||||
|
|
||||||
|
foreach (var row in rows)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -59,14 +67,17 @@ public class WellOperationImportService : IWellOperationImportService
|
|||||||
throw new FileFormatException(
|
throw new FileFormatException(
|
||||||
$"Лист '{sheet.Name}'. Строка '{row.Number}' неправильно получена дата начала операции");
|
$"Лист '{sheet.Name}'. Строка '{row.Number}' неправильно получена дата начала операции");
|
||||||
|
|
||||||
if (wellOperations.LastOrDefault()?.DateStart > row.Date)
|
if (prevRow.Date > row.Date)
|
||||||
throw new FileFormatException(
|
throw new FileFormatException(
|
||||||
$"Лист '{sheet.Name}' строка '{row.Number}' дата позднее даты предыдущей операции");
|
$"Лист '{sheet.Name}' строка '{row.Number}' дата позднее даты предыдущей операции");
|
||||||
|
|
||||||
if (row.Duration is not (>= 0d and <= 240d))
|
if (row.Duration is not (>= 0d and <= 240d))
|
||||||
throw new FileFormatException($"Лист '{sheet.Name}'. Строка '{row.Number}' некорректная длительность операции");
|
throw new FileFormatException($"Лист '{sheet.Name}'. Строка '{row.Number}' некорректная длительность операции");
|
||||||
|
|
||||||
wellOperations.Add(new WellOperationDto
|
var timezone = wellService.GetTimezone(idWell);
|
||||||
|
var timezoneOffset = TimeSpan.FromHours(timezone.Hours);
|
||||||
|
|
||||||
|
var wellOperation = new WellOperationDto
|
||||||
{
|
{
|
||||||
IdWell = idWell,
|
IdWell = idWell,
|
||||||
IdUser = idUser,
|
IdUser = idUser,
|
||||||
@ -76,10 +87,14 @@ public class WellOperationImportService : IWellOperationImportService
|
|||||||
CategoryInfo = row.CategoryInfo,
|
CategoryInfo = row.CategoryInfo,
|
||||||
DepthStart = row.DepthStart,
|
DepthStart = row.DepthStart,
|
||||||
DepthEnd = row.DepthEnd,
|
DepthEnd = row.DepthEnd,
|
||||||
DateStart = row.Date,
|
DateStart = new DateTimeOffset(row.Date, timezoneOffset),
|
||||||
DurationHours = row.Duration,
|
DurationHours = row.Duration,
|
||||||
Comment = row.Comment
|
Comment = row.Comment
|
||||||
});
|
};
|
||||||
|
|
||||||
|
wellOperations.Add(wellOperation);
|
||||||
|
|
||||||
|
prevRow = row;
|
||||||
}
|
}
|
||||||
catch (FileFormatException ex)
|
catch (FileFormatException ex)
|
||||||
{
|
{
|
||||||
|
@ -18,6 +18,14 @@
|
|||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="WellOperationsPlan.xlsx" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="WellOperationsPlan.xlsx" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\AsbCloudWebApi\AsbCloudWebApi.csproj" />
|
<ProjectReference Include="..\AsbCloudWebApi\AsbCloudWebApi.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -18,4 +18,10 @@ public interface IWellOperationClient
|
|||||||
Task<IApiResponse<PaginationContainer<WellOperationDto>>> GetPageOperationsPlanAsync(int idWell,
|
Task<IApiResponse<PaginationContainer<WellOperationDto>>> GetPageOperationsPlanAsync(int idWell,
|
||||||
[Query] WellOperationRequestBase request,
|
[Query] WellOperationRequestBase request,
|
||||||
CancellationToken token);
|
CancellationToken token);
|
||||||
|
|
||||||
|
[Multipart]
|
||||||
|
[Post(BaseRoute + "/import/plan/default")]
|
||||||
|
Task<IApiResponse<IEnumerable<WellOperationDto>>> ImportPlanDefaultExcelFileAsync(int idWell,
|
||||||
|
[AliasAs("files")] IEnumerable<StreamPart> streams,
|
||||||
|
CancellationToken token);
|
||||||
}
|
}
|
@ -2,7 +2,10 @@ using AsbCloudApp.Data;
|
|||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudWebApi.IntegrationTests.Clients;
|
using AsbCloudWebApi.IntegrationTests.Clients;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Reflection;
|
||||||
using AsbCloudApp.Requests;
|
using AsbCloudApp.Requests;
|
||||||
|
using AsbCloudWebApi.IntegrationTests.Data;
|
||||||
|
using Refit;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace AsbCloudWebApi.IntegrationTests.Controllers;
|
namespace AsbCloudWebApi.IntegrationTests.Controllers;
|
||||||
@ -28,7 +31,7 @@ public class WellOperationControllerTest : BaseIntegrationTest
|
|||||||
DepthEnd = 20.0,
|
DepthEnd = 20.0,
|
||||||
Day = 0.0,
|
Day = 0.0,
|
||||||
NptHours = 0.0,
|
NptHours = 0.0,
|
||||||
DateStart = new DateTimeOffset(new DateTime(2023, 02, 03, 1, 0, 0, DateTimeKind.Unspecified)),
|
DateStart = new DateTimeOffset(new DateTime(2023, 1, 10), TimeSpan.FromHours(Defaults.Wells[0].Timezone.Hours)),
|
||||||
DurationHours = 1.0,
|
DurationHours = 1.0,
|
||||||
Comment = "1",
|
Comment = "1",
|
||||||
IdUser = 1,
|
IdUser = 1,
|
||||||
@ -117,4 +120,37 @@ public class WellOperationControllerTest : BaseIntegrationTest
|
|||||||
var excludeProps = new[] { nameof(WellOperationDto.Id) };
|
var excludeProps = new[] { nameof(WellOperationDto.Id) };
|
||||||
MatchHelper.Match(dto, wellOperation, excludeProps);
|
MatchHelper.Match(dto, wellOperation, excludeProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ImportPlanDefaultExcelFileAsync_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
//TODO: вынести в метод расширения. Сделать когда доберёмся до рефакторинга операций по скважине
|
||||||
|
var resourceName = Assembly.GetExecutingAssembly()
|
||||||
|
.GetManifestResourceNames()
|
||||||
|
.FirstOrDefault(n => n.EndsWith("WellOperationsPlan.xlsx"));
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(resourceName))
|
||||||
|
throw new ArgumentNullException(nameof(resourceName));
|
||||||
|
|
||||||
|
var stream = Assembly.GetExecutingAssembly()
|
||||||
|
.GetManifestResourceStream(resourceName);
|
||||||
|
|
||||||
|
if (stream is null)
|
||||||
|
throw new ArgumentNullException(nameof(stream));
|
||||||
|
|
||||||
|
var memoryStream = new MemoryStream();
|
||||||
|
stream.CopyTo(memoryStream);
|
||||||
|
memoryStream.Position = 0;
|
||||||
|
|
||||||
|
//act
|
||||||
|
var streamPart = new StreamPart(memoryStream, "WellOperations.xlsx", "application/octet-stream");
|
||||||
|
|
||||||
|
var response = await client.ImportPlanDefaultExcelFileAsync(idWell, new[] { streamPart }, CancellationToken.None);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.NotNull(response.Content);
|
||||||
|
Assert.Equal(4, response.Content.Count());
|
||||||
|
Assert.True(response.Content.All(w => Math.Abs(w.DateStart.Offset.Hours - Defaults.Wells[0].Timezone.Hours) < 0.1));
|
||||||
|
}
|
||||||
}
|
}
|
BIN
AsbCloudWebApi.IntegrationTests/WellOperationsPlan.xlsx
Normal file
BIN
AsbCloudWebApi.IntegrationTests/WellOperationsPlan.xlsx
Normal file
Binary file not shown.
@ -117,7 +117,7 @@ namespace AsbCloudWebApi.Tests.Services.WellOperationExport
|
|||||||
wellOperationImportTemplateService = new WellOperationImportTemplateService();
|
wellOperationImportTemplateService = new WellOperationImportTemplateService();
|
||||||
wellOperationExportService = new WellOperationExportService(wellOperationRepository, wellService, wellOperationImportTemplateService);
|
wellOperationExportService = new WellOperationExportService(wellOperationRepository, wellService, wellOperationImportTemplateService);
|
||||||
|
|
||||||
wellOperationImportService = new WellOperationImportService(wellOperationRepository);
|
wellOperationImportService = new WellOperationImportService(wellService, wellOperationRepository);
|
||||||
wellOperationDefaultExcelParser = new WellOperationDefaultExcelParser();
|
wellOperationDefaultExcelParser = new WellOperationDefaultExcelParser();
|
||||||
this.output = output;
|
this.output = output;
|
||||||
}
|
}
|
||||||
|
@ -281,7 +281,6 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
foreach (var wellOperation in wellOperations)
|
foreach (var wellOperation in wellOperations)
|
||||||
{
|
{
|
||||||
wellOperation.IdWell = idWell;
|
wellOperation.IdWell = idWell;
|
||||||
wellOperation.LastUpdateDate = DateTimeOffset.UtcNow;
|
|
||||||
wellOperation.IdUser = User.GetUserId();
|
wellOperation.IdUser = User.GetUserId();
|
||||||
wellOperation.IdType = idType;
|
wellOperation.IdType = idType;
|
||||||
}
|
}
|
||||||
@ -313,7 +312,6 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
|
|
||||||
value.IdWell = idWell;
|
value.IdWell = idWell;
|
||||||
value.Id = idOperation;
|
value.Id = idOperation;
|
||||||
value.LastUpdateDate = DateTimeOffset.UtcNow;
|
|
||||||
value.IdUser = User.GetUserId();
|
value.IdUser = User.GetUserId();
|
||||||
|
|
||||||
var result = await operationRepository.UpdateAsync(value, token)
|
var result = await operationRepository.UpdateAsync(value, token)
|
||||||
|
Loading…
Reference in New Issue
Block a user