forked from ddrilling/AsbCloudServer
Добавлен сервис для работы с плановыми секциями конструкции скважины
This commit is contained in:
parent
9c68560d93
commit
6db3771cb4
73
AsbCloudApp/Data/WellSections/WellSectionPlanDto.cs
Normal file
73
AsbCloudApp/Data/WellSections/WellSectionPlanDto.cs
Normal file
@ -0,0 +1,73 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace AsbCloudApp.Data.WellSections;
|
||||
|
||||
/// <summary>
|
||||
/// Секция скважины - план
|
||||
/// </summary>
|
||||
public class WellSectionPlanDto : ItemInfoDto,
|
||||
IId,
|
||||
IWellRelated,
|
||||
IValidatableObject
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int IdWell { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Тип секции
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "Поле обязательно для заполнение")]
|
||||
[Range(1, int.MaxValue)]
|
||||
public int IdSectionType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Начальная глубина бурения, м
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "Поле обязательно для заполнение")]
|
||||
[Range(0, 10000, ErrorMessage = "Допустимое значение от 1 до 10000")]
|
||||
public double DepthStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Конечная глубина бурения, м
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "Поле обязательно для заполнение")]
|
||||
[Range(0, 10000, ErrorMessage = "Допустимое значение от 1 до 10000")]
|
||||
public double DepthEnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Внешний диаметр
|
||||
/// </summary>
|
||||
[Range(0, 10000, ErrorMessage = "Допустимое значение от 1 до 10000")]
|
||||
public double? OuterDiameter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Внутренний диаметр
|
||||
/// </summary>
|
||||
[Range(0, 10000, ErrorMessage = "Допустимое значение от 1 до 10000")]
|
||||
public double? InnerDiameter { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
if (!OuterDiameter.HasValue && !InnerDiameter.HasValue)
|
||||
yield break;
|
||||
|
||||
if (!OuterDiameter.HasValue)
|
||||
yield return new ValidationResult("Поле обязательно для заполнение", new[] { nameof(OuterDiameter) });
|
||||
|
||||
if (!InnerDiameter.HasValue)
|
||||
yield return new ValidationResult("Поле обязательно для заполнение", new[] { nameof(InnerDiameter) });
|
||||
|
||||
if (OuterDiameter <= InnerDiameter)
|
||||
yield return new ValidationResult("Внешний диаметр не должен быть больше или равен внутреннему",
|
||||
new[] { nameof(OuterDiameter) });
|
||||
|
||||
if (InnerDiameter >= OuterDiameter)
|
||||
yield return new ValidationResult("Внутренний диаметр не должен больше или равен внутреннему",
|
||||
new[] { nameof(InnerDiameter) });
|
||||
}
|
||||
}
|
37
AsbCloudApp/Services/WellSections/IWellSectionPlanService.cs
Normal file
37
AsbCloudApp/Services/WellSections/IWellSectionPlanService.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Data.WellSections;
|
||||
|
||||
namespace AsbCloudApp.Services.WellSections;
|
||||
|
||||
/// <summary>
|
||||
/// Секция скважины - план
|
||||
/// </summary>
|
||||
public interface IWellSectionPlanService
|
||||
{
|
||||
/// <summary>
|
||||
/// Добавить секцию
|
||||
/// </summary>
|
||||
/// <param name="wellSectionPlan"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> InsertAsync(WellSectionPlanDto wellSectionPlan, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Обновить секцию
|
||||
/// </summary>
|
||||
/// <param name="wellSectionPlan"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> UpdateAsync(WellSectionPlanDto wellSectionPlan, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Получить типы секций
|
||||
/// </summary>
|
||||
/// <param name="idWell"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<WellSectionTypeDto>> GetWellSectionTypesAsync(int idWell, CancellationToken cancellationToken);
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Data.WellSections;
|
||||
using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudApp.Services.WellSections;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.WellSections;
|
||||
|
||||
public class WellSectionPlanService : IWellSectionPlanService
|
||||
{
|
||||
private readonly IRepositoryWellRelated<WellSectionPlanDto> wellSectionPlanRepository;
|
||||
private readonly ICrudRepository<WellSectionTypeDto> wellSectionTypeRepository;
|
||||
|
||||
public WellSectionPlanService(IRepositoryWellRelated<WellSectionPlanDto> wellSectionPlanRepository,
|
||||
ICrudRepository<WellSectionTypeDto> wellSectionTypeRepository)
|
||||
{
|
||||
this.wellSectionPlanRepository = wellSectionPlanRepository;
|
||||
this.wellSectionTypeRepository = wellSectionTypeRepository;
|
||||
}
|
||||
|
||||
public async Task<int> InsertAsync(WellSectionPlanDto wellSectionPlan, CancellationToken cancellationToken)
|
||||
{
|
||||
await EnsureUniqueSectionTypeInWellAsync(wellSectionPlan, cancellationToken);
|
||||
|
||||
return await wellSectionPlanRepository.InsertAsync(wellSectionPlan, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<int> UpdateAsync(WellSectionPlanDto wellSectionPlan, CancellationToken cancellationToken)
|
||||
{
|
||||
await EnsureUniqueSectionTypeInWellAsync(wellSectionPlan, cancellationToken);
|
||||
|
||||
wellSectionPlan.LastUpdateDate = DateTime.UtcNow;
|
||||
|
||||
return await wellSectionPlanRepository.UpdateAsync(wellSectionPlan, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<WellSectionTypeDto>> GetWellSectionTypesAsync(int idWell, CancellationToken cancellationToken)
|
||||
{
|
||||
var wellSectionTypes = (await wellSectionTypeRepository.GetAllAsync(cancellationToken))
|
||||
.OrderBy(w => w.Order);
|
||||
|
||||
var planWellSections = await wellSectionPlanRepository.GetByIdWellAsync(idWell, cancellationToken);
|
||||
|
||||
if (!planWellSections.Any())
|
||||
return wellSectionTypes;
|
||||
|
||||
return wellSectionTypes.Where(w => planWellSections.Any(s => s.IdSectionType == w.Id));
|
||||
}
|
||||
|
||||
private async Task EnsureUniqueSectionTypeInWellAsync(WellSectionPlanDto section, CancellationToken cancellationToken)
|
||||
{
|
||||
var existingWellSectionPlan = (await wellSectionPlanRepository.GetByIdWellAsync(section.IdWell, cancellationToken))
|
||||
.SingleOrDefault(s => s.IdSectionType == section.IdSectionType);
|
||||
|
||||
if (existingWellSectionPlan is not null && existingWellSectionPlan.Id != section.Id)
|
||||
{
|
||||
var sectionType = await wellSectionTypeRepository.GetOrDefaultAsync(section.IdSectionType, cancellationToken);
|
||||
|
||||
throw new ArgumentInvalidException($"Секция '{sectionType?.Caption}' уже добавлена в конструкцию скважины",
|
||||
nameof(section.IdSectionType));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,169 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Data.WellSections;
|
||||
using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudInfrastructure.Services.WellSections;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace AsbCloudWebApi.Tests.UnitTests.Services.WellSections;
|
||||
|
||||
public class WellSectionPlanServiceTests
|
||||
{
|
||||
private const int idWellSectionPlan = 1;
|
||||
private const int idWell = 3;
|
||||
private const int idWellSectionType = 54;
|
||||
|
||||
private readonly IEnumerable<WellSectionPlanDto> fakePlanWellSections = new WellSectionPlanDto[]
|
||||
{
|
||||
new()
|
||||
{
|
||||
Id = idWellSectionPlan,
|
||||
IdWell = idWell,
|
||||
IdSectionType = idWellSectionType
|
||||
}
|
||||
};
|
||||
|
||||
private readonly IEnumerable<WellSectionTypeDto> fakeWellSectionTypes = new WellSectionTypeDto[]
|
||||
{
|
||||
new()
|
||||
{
|
||||
Id = idWellSectionType
|
||||
}
|
||||
};
|
||||
|
||||
private readonly IRepositoryWellRelated<WellSectionPlanDto> wellSectionPlanRepositoryMock =
|
||||
Substitute.For<IRepositoryWellRelated<WellSectionPlanDto>>();
|
||||
|
||||
private readonly ICrudRepository<WellSectionTypeDto> wellSectionTypeRepositoryMock =
|
||||
Substitute.For<ICrudRepository<WellSectionTypeDto>>();
|
||||
|
||||
private readonly WellSectionPlanService wellSectionPlanService;
|
||||
|
||||
public WellSectionPlanServiceTests()
|
||||
{
|
||||
wellSectionPlanService = new WellSectionPlanService(wellSectionPlanRepositoryMock, wellSectionTypeRepositoryMock);
|
||||
|
||||
wellSectionTypeRepositoryMock.GetAllAsync(Arg.Any<CancellationToken>())
|
||||
.ReturnsForAnyArgs(fakeWellSectionTypes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InsertAsync_InsertNewWellSectionTypeWithUniqueSectionTypeInWell_InvokesWellSectionPlanRepositoryInsertAsync()
|
||||
{
|
||||
//arrange
|
||||
var insertedWellSection = new WellSectionPlanDto();
|
||||
|
||||
//act
|
||||
await wellSectionPlanService.InsertAsync(insertedWellSection, CancellationToken.None);
|
||||
|
||||
//assert
|
||||
await wellSectionPlanRepositoryMock.Received().InsertAsync(Arg.Any<WellSectionPlanDto>(), Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InsertAsync_InsertNewWellSectionTypeWithNotUniqueSectionTypeInWell_ReturnsDuplicateException()
|
||||
{
|
||||
//arrange
|
||||
var insertedWellSection = new WellSectionPlanDto
|
||||
{
|
||||
Id = 2,
|
||||
IdSectionType = idWellSectionType
|
||||
};
|
||||
|
||||
wellSectionPlanRepositoryMock.GetByIdWellAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
|
||||
.ReturnsForAnyArgs(fakePlanWellSections);
|
||||
|
||||
//act
|
||||
Task Result() => wellSectionPlanService.InsertAsync(insertedWellSection, CancellationToken.None);
|
||||
|
||||
//assert
|
||||
await Assert.ThrowsAsync<ArgumentInvalidException>(Result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateAsync_UpdateExistingWellSectionTypeWithUniqueSectionTypeInWell_InvokesWellSectionPlanRepositoryUpdateAsync()
|
||||
{
|
||||
//arrange
|
||||
var updatedWellSection = new WellSectionPlanDto
|
||||
{
|
||||
Id = idWellSectionPlan,
|
||||
IdSectionType = idWellSectionType
|
||||
};
|
||||
|
||||
//act
|
||||
await wellSectionPlanService.UpdateAsync(updatedWellSection, CancellationToken.None);
|
||||
|
||||
//assert
|
||||
await wellSectionPlanRepositoryMock.Received().UpdateAsync(Arg.Any<WellSectionPlanDto>(), Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateAsync_ReturnsLastUpdateDateNotNull()
|
||||
{
|
||||
//arrange
|
||||
var updatedWellSection = new WellSectionPlanDto
|
||||
{
|
||||
Id = idWellSectionPlan,
|
||||
IdSectionType = idWellSectionType
|
||||
};
|
||||
|
||||
//act
|
||||
await wellSectionPlanService.UpdateAsync(updatedWellSection, CancellationToken.None);
|
||||
|
||||
//assert
|
||||
Assert.NotNull(updatedWellSection.LastUpdateDate);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateAsync_UpdateExistingWellSectionTypeWithNotUniqueSectionTypeInWell_ReturnsDuplicateException()
|
||||
{
|
||||
//arrange
|
||||
var updatedWellSection = new WellSectionPlanDto
|
||||
{
|
||||
Id = 2,
|
||||
IdSectionType = idWellSectionType
|
||||
};
|
||||
|
||||
wellSectionPlanRepositoryMock.GetByIdWellAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
|
||||
.ReturnsForAnyArgs(fakePlanWellSections);
|
||||
|
||||
//act
|
||||
Task Result() => wellSectionPlanService.UpdateAsync(updatedWellSection, CancellationToken.None);
|
||||
|
||||
//assert
|
||||
await Assert.ThrowsAsync<ArgumentInvalidException>(Result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetWellSectionTypesAsync_EmptyCollectionWellSectionPlan_ReturnsCollectionWellSectionType()
|
||||
{
|
||||
//arrange
|
||||
wellSectionPlanRepositoryMock.GetByIdWellAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
|
||||
.ReturnsForAnyArgs(Enumerable.Empty<WellSectionPlanDto>());
|
||||
|
||||
//act
|
||||
var result = await wellSectionPlanService.GetWellSectionTypesAsync(idWell, CancellationToken.None);
|
||||
|
||||
//assert
|
||||
Assert.Single(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetWellSectionTypesAsync_NotEmptyCollectionWellSectionPlan_ReturnsCollectionWellSectionType()
|
||||
{
|
||||
//arrange
|
||||
wellSectionPlanRepositoryMock.GetByIdWellAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
|
||||
.ReturnsForAnyArgs(fakePlanWellSections);
|
||||
|
||||
//act
|
||||
var result = await wellSectionPlanService.GetWellSectionTypesAsync(idWell, CancellationToken.None);
|
||||
|
||||
//assert
|
||||
Assert.Single(result);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user