merge master to dev

This commit is contained in:
Frolov-Nikita 2024-02-21 11:55:38 +05:00
commit a771a6481a
No known key found for this signature in database
GPG Key ID: 719E3386D12B0760
8 changed files with 125 additions and 47 deletions

View File

@ -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)

View File

@ -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)
{ {

View File

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

View File

@ -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);
} }

View File

@ -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));
}
} }

View File

@ -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;
} }

View File

@ -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)