Правки по результатам ревью

This commit is contained in:
Olga Nemt 2024-03-11 14:11:13 +05:00
parent a16ae3094e
commit 3828c78129
5 changed files with 207 additions and 86 deletions

View File

@ -42,6 +42,14 @@ namespace AsbCloudApp.Repositories
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<WellOperationDto>> GetAsync(WellOperationRequest request, CancellationToken token); Task<IEnumerable<WellOperationDto>> GetAsync(WellOperationRequest request, CancellationToken token);
/// <summary>
/// Получить список операций по запросу
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<WellOperationDataDto>> GetAsync(WellsOperationRequest request, CancellationToken token);
/// <summary> /// <summary>
/// Получить страницу списка операций /// Получить страницу списка операций
/// </summary> /// </summary>

View File

@ -72,7 +72,7 @@ namespace AsbCloudApp.Requests
this.LeDepth = request.LeDepth; this.LeDepth = request.LeDepth;
this.GeDate = request.GeDate; this.GeDate = request.GeDate;
this.LtDate = request.LtDate; this.LtDate = request.LtDate;
this.OperationCategoryIds = request.OperationCategoryIds; this.OperationCategoryIds = request.OperationCategoryIds;
this.OperationType = request.OperationType; this.OperationType = request.OperationType;
this.SectionTypeIds = request.SectionTypeIds; this.SectionTypeIds = request.SectionTypeIds;
@ -82,4 +82,20 @@ namespace AsbCloudApp.Requests
this.SortFields = request.SortFields; this.SortFields = request.SortFields;
} }
} }
/// <summary>
/// Параметры для запроса списка операций (с массивом id скважин)
/// </summary>
public class WellsOperationRequest : WellOperationRequestBase
{
/// <summary>
/// ids скважин
/// </summary>
public IEnumerable<int> IdsWell { get; set; } = null!;
/// <summary>
/// Тип 0 = План или 1 = Факт
/// </summary>
public int IdType { get; set; }
}
} }

View File

@ -205,6 +205,31 @@ public class WellOperationRepository : IWellOperationRepository
return dtos.Select(Convert); return dtos.Select(Convert);
} }
public async Task<IEnumerable<WellOperationDataDto>> GetAsync(
WellsOperationRequest request,
CancellationToken token)
{
var query = db.WellOperations
.Where(o => request.IdsWell.Contains(o.IdWell))
.Where(o => request.IdType == o.IdType)
.Where(o => request.SectionTypeIds != null ? request.SectionTypeIds.Contains(o.IdWellSectionType) : true)
.Where(o => request.OperationCategoryIds != null ? request.OperationCategoryIds.Contains(o.IdCategory) : true)
.Select(o => new WellOperationDataDto(){
DepthStart = o.DepthStart,
DurationHours = o.DurationHours,
IdCategory = o.IdCategory,
IdWell = o.IdWell,
IdWellSectionType = o.IdWellSectionType,
OperationCategoryName = o.OperationCategory.Name,
WellSectionTypeCaption = o.WellSectionType.Caption,
})
.AsNoTracking();
var dtos = await query.ToArrayAsync(token);
return dtos;
}
/// <inheritdoc/> /// <inheritdoc/>
public async Task<PaginationContainer<WellOperationDto>> GetPageAsync( public async Task<PaginationContainer<WellOperationDto>> GetPageAsync(
WellOperationRequest request, WellOperationRequest request,

View File

@ -1,7 +1,8 @@
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudDb.Model; using AsbCloudDb.Model;
using Mapster;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -12,7 +13,9 @@ namespace AsbCloudInfrastructure.Services
{ {
public class WellCompositeOperationService : IWellCompositeOperationService public class WellCompositeOperationService : IWellCompositeOperationService
{ {
private IAsbCloudDbContext db; private ICrudRepository<WellSectionTypeDto> wellSectionTypeRepository;
private IWellOperationCategoryRepository wellOperationCategoryRepository;
private IWellOperationRepository wellOperationRepository;
/// <summary> /// <summary>
/// Тип секции "Транспортный стол" /// Тип секции "Транспортный стол"
@ -49,115 +52,168 @@ namespace AsbCloudInfrastructure.Services
{ (6, 5035), 5097 } { (6, 5035), 5097 }
}; };
private Dictionary<int, List<int>> WellSectionTypesWithCategories = new Dictionary<int, List<int>>() private HashSet<(int IdSectionType, int IdCategory)> WellSectionTypesWithCategories = new HashSet<(int IdSectionType, int IdCategory)>()
{ {
{ 2, new List<int>{ 5001, 5003, 5013, 5000, 5022, 5017, 5023, 4007, 5090 } }, { (2, 5001) },
{ 3, new List<int>{ 5001, 5015, 5037, 5057, 5003, 5036, 5084, 5013, 5000, 5022, 5017, 4007, 5090, 5045, 5042, 5046 } }, { (2, 5003) },
{ 31, new List<int>{ 5001, 5015, 5037, 5057, 5003, 5036, 5013, 5022, 5017, 5023, 4007, 5045, 5042, 5046 } }, { (2, 5013) },
{ 4, new List<int>{ 5001, 5015, 5046, 5037, 5097, 5057, 5003, 5036, 5008, 5003, 5036, 5013, 5000, 5029, 5022, 5017, 5019, 5042, 5046 } }, { (2, 5000) },
{ 6, new List<int>{ 5001, 5015, 5034, 5037, 5097, 5057, 5003 } }, { (2, 5022) },
{ (2, 5017) },
{ (2, 5023) },
{ (2, 4007) },
{ (2, 5090) },
{ (3, 5001) },
{ (3, 5015) },
{ (3, 5037) },
{ (3, 5057) },
{ (3, 5003) },
{ (3, 5036) },
{ (3, 5084) },
{ (3, 5013) },
{ (3, 5000) },
{ (3, 5022) },
{ (3, 5017) },
{ (3, 4007) },
{ (3, 5090) },
{ (3, 5045) },
{ (3, 5042) },
{ (3, 5046) },
{ (31, 5001) },
{ (31, 5015) },
{ (31, 5037) },
{ (31, 5057) },
{ (31, 5003) },
{ (31, 5036) },
{ (31, 5013) },
{ (31, 5022) },
{ (31, 5017) },
{ (31, 5023) },
{ (31, 4007) },
{ (31, 5045) },
{ (31, 5042) },
{ (31, 5046) },
{ (4, 5001) },
{ (4, 5015) },
{ (4, 5046) },
{ (4, 5037) },
{ (4, 5097) },
{ (4, 5057) },
{ (4, 5003) },
{ (4, 5036) },
{ (4, 5008) },
{ (4, 5003) },
{ (4, 5036) },
{ (4, 5013) },
{ (4, 5000) },
{ (4, 5029) },
{ (4, 5022) },
{ (4, 5017) },
{ (4, 5019) },
{ (4, 5042) },
{ (4, 5046) },
{ (6, 5001) },
{ (6, 5015) },
{ (6, 5034) },
{ (6, 5037) },
{ (6, 5097) },
{ (6, 5057) },
{ (6, 5003) }
}; };
public WellCompositeOperationService(IAsbCloudDbContext db) public WellCompositeOperationService(
ICrudRepository<WellSectionTypeDto> wellSectionTypeRepository,
IWellOperationCategoryRepository wellOperationCategoryRepository,
IWellOperationRepository wellOperationRepository)
{ {
this.db = db; this.wellSectionTypeRepository = wellSectionTypeRepository;
this.wellOperationCategoryRepository = wellOperationCategoryRepository;
this.wellOperationRepository = wellOperationRepository;
} }
public async Task<List<Dictionary<int, WellOperationDataDto>>> GetAsync(IEnumerable<int> idsWells, CancellationToken token) public async Task<List<Dictionary<int, WellOperationDataDto>>> GetAsync(IEnumerable<int> idsWells, CancellationToken token)
{ {
var sections = await db.WellSectionTypes var sections = await wellSectionTypeRepository.GetAllAsync(token);
.Select(t => t.Adapt<WellSectionTypeDto>())
.ToArrayAsync(token);
var sectionsDict = sections.ToDictionary(s => s.Id, s => s.Caption); var sectionsDict = sections.ToDictionary(s => s.Id, s => s.Caption);
var categories = await db.WellOperationCategories var categories = wellOperationCategoryRepository.Get(true);
.Select(c => c.Adapt<WellOperationCategoryDto>())
.ToArrayAsync(token);
var categoriesDict = categories.ToDictionary(s => s.Id, s => s.Name); var categoriesDict = categories.ToDictionary(s => s.Id, s => s.Name);
var idsWellSectionTypes = WellSectionTypesWithCategories.Select(t => t.Key); var idsWellSectionTypes = WellSectionTypesWithCategories.Select(t => t.IdSectionType);
var usedCategories = WellSectionTypesWithCategories.Select(c => c.IdCategory).Distinct();
var groupedWellOperations = db.WellOperations var wellOperationRequest = new WellsOperationRequest()
.Where(o => idsWells.Contains(o.IdWell)) {
.Where(o => o.IdType == WellOperation.IdOperationTypeFact) IdsWell = idsWells,
.Where(o => idsWellSectionTypes.Contains(o.IdWellSectionType)) OperationCategoryIds = usedCategories,
.AsEnumerable() SectionTypeIds = idsWellSectionTypes,
.GroupBy(o => o.IdWellSectionType, (key, group) => group.Where(x => WellSectionTypesWithCategories[key].Contains(x.IdCategory))) IdType = WellOperation.IdOperationTypeFact
.SelectMany(o => o) };
.Select(x => Convert(x, sectionsDict, categoriesDict)) var operations = await wellOperationRepository.GetAsync(wellOperationRequest, token);
.GroupBy(o => (o.IdWellSectionType, o.IdCategory, o.IdWell), (gr, o) => o.Count() == 1 ? o.FirstOrDefault()! : new WellOperationDataDto()
{ var renamedOperations = operations.Select(o => UpdateIdWellSectionAndIdCategory(o, sectionsDict, categoriesDict));
IdWellSectionType = o.FirstOrDefault()!.IdWellSectionType,
IdCategory = o.FirstOrDefault()!.IdCategory,
DepthStart = o.Max(x => x.DepthStart),
DurationHours = o.Sum(x => x.DurationHours),
IdWell = o.FirstOrDefault()!.IdWell,
WellSectionTypeCaption = o.FirstOrDefault()!.WellSectionTypeCaption,
OperationCategoryName = o.FirstOrDefault()!.OperationCategoryName
});
var wellOperationsWithComposite = new List<Dictionary<int, WellOperationDataDto>>(); var wellOperationsWithComposite = new List<Dictionary<int, WellOperationDataDto>>();
var operationsGroupBySectionAndCategory = groupedWellOperations.GroupBy(o => (o.IdWellSectionType, o.IdCategory), (key, group) => group.ToList()); var compositeDepth = 0d;
foreach (var operationGroupBySectionAndCategory in operationsGroupBySectionAndCategory) foreach ((int IdSection, int IdCategory) in WellSectionTypesWithCategories)
{ {
var dictElem = operationGroupBySectionAndCategory.ToDictionary(o => o.IdWell); var filteredByTemplate = renamedOperations
.Where(o => o.IdWellSectionType == IdSection)
.Where(o => o.IdCategory == IdCategory);
var currentOperation = operationGroupBySectionAndCategory.FirstOrDefault()!; if (!filteredByTemplate.Any())
var composite = new WellOperationDataDto()
{
IdWell = 0,
IdCategory = currentOperation.IdCategory,
IdWellSectionType = currentOperation.IdWellSectionType,
DurationHours = currentOperation.DurationHours,
DepthStart = currentOperation.DepthStart,
OperationCategoryName = currentOperation.OperationCategoryName,
WellSectionTypeCaption = currentOperation.WellSectionTypeCaption,
};
dictElem.Add(0, composite);
if (operationGroupBySectionAndCategory.Count() == 1)
{
wellOperationsWithComposite.Add(dictElem);
continue; continue;
}
var maxDurationHours = operationGroupBySectionAndCategory.Max(o => o.DurationHours); var groupedByWell = filteredByTemplate.GroupBy(o => o.IdWell);
var minDurationHours = operationGroupBySectionAndCategory.Min(o => o.DurationHours);
if (maxDurationHours == minDurationHours) var aggreagtedByWell = groupedByWell.Select(g => new WellOperationDataDto
{ {
composite.DepthStart = operationGroupBySectionAndCategory.Max(o => o.DepthStart); IdCategory = IdCategory,
} IdWell = g.Key,
else IdWellSectionType = IdSection,
{ DepthStart = g.Min(o => o.DepthStart),
composite.DepthStart = operationGroupBySectionAndCategory.Min(o => o.DepthStart); DurationHours = g.Sum(o => o.DurationHours),
} OperationCategoryName = g.First().OperationCategoryName,
composite.DurationHours = minDurationHours; WellSectionTypeCaption = g.First().WellSectionTypeCaption,
dictElem[0] = composite; });
wellOperationsWithComposite.Add(dictElem);
var composite = aggreagtedByWell
.OrderBy(o => o.DurationHours)
.ThenByDescending(o => o.DepthStart)
.First();
composite.IdWell = 0;
if (compositeDepth > composite.DepthStart)
composite.DepthStart = compositeDepth;
compositeDepth = composite.DepthStart;
var resultItem = aggreagtedByWell.ToDictionary(o => o.IdWell);
resultItem.Add(0, composite);
wellOperationsWithComposite.Add(resultItem);
} }
return wellOperationsWithComposite; return wellOperationsWithComposite;
} }
private static WellOperationDataDto Convert(WellOperation entity, Dictionary<int, string> sectionsDict, Dictionary<int, string> categoriesDict) private WellOperationDataDto UpdateIdWellSectionAndIdCategory(
WellOperationDataDto dto,
Dictionary<int, string> sectionTypes,
Dictionary<int, string> operationCategories)
{ {
var dto = new WellOperationDataDto(); if (dto.IdWellSectionType == wellSectionTransportTable)
dto.IdWellSectionType = entity.IdWellSectionType == wellSectionTransportTable {
? wellSectionProductionString dto.IdWellSectionType = wellSectionProductionString;
: entity.IdWellSectionType; dto.WellSectionTypeCaption = sectionTypes[dto.IdWellSectionType] ?? string.Empty;
dto.IdCategory = (SettingsForSectionCategoryChange.TryGetValue(((entity.IdWellSectionType == wellSectionTransportTable ? wellSectionProductionString : entity.IdWellSectionType), entity.IdCategory), out int newIdCategory)) }
? newIdCategory
: entity.IdCategory; if ((SettingsForSectionCategoryChange.TryGetValue((dto.IdWellSectionType, dto.IdCategory), out int newIdCategory)))
dto.DepthStart = entity.DepthStart; {
dto.DurationHours = entity.DurationHours; dto.IdCategory = newIdCategory;
dto.IdWell = entity.IdWell; dto.OperationCategoryName = operationCategories[dto.IdCategory] ?? string.Empty;
dto.OperationCategoryName = categoriesDict.TryGetValue(dto.IdCategory, out string? CategoryName) }
? CategoryName
: string.Empty;
dto.WellSectionTypeCaption = sectionsDict.TryGetValue(dto.IdWellSectionType, out string? WellSectionName)
? WellSectionName
: string.Empty;
return dto; return dto;
} }

View File

@ -15,21 +15,37 @@ namespace AsbCloudWebApi.Controllers
public class WellCompositeOperationController : ControllerBase public class WellCompositeOperationController : ControllerBase
{ {
private readonly IWellCompositeOperationService wellCompositeOperationService; private readonly IWellCompositeOperationService wellCompositeOperationService;
private readonly IWellService wellService;
public WellCompositeOperationController(IWellCompositeOperationService wellCompositeOperationService, IWellService wellService) public WellCompositeOperationController(IWellCompositeOperationService wellCompositeOperationService, IWellService wellService)
{ {
this.wellCompositeOperationService = wellCompositeOperationService; this.wellCompositeOperationService = wellCompositeOperationService;
this.wellService = wellService;
} }
[HttpGet] [HttpGet]
[ProducesResponseType(typeof(List<Dictionary<int, WellOperationDataDto>>), (int)System.Net.HttpStatusCode.OK)] [ProducesResponseType(typeof(IList<IDictionary<int, WellOperationDataDto>>), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetAsync([FromQuery] IEnumerable<int> idsWells, CancellationToken token) public async Task<IActionResult> GetAsync([FromQuery] IEnumerable<int> idsWells, CancellationToken token)
{ {
foreach (var idWell in idsWells)
if (!await UserHasAccessToWellAsync(idWell, token))
return Forbid();
var result = await wellCompositeOperationService.GetAsync(idsWells, token) var result = await wellCompositeOperationService.GetAsync(idsWells, token)
.ConfigureAwait(false); .ConfigureAwait(false);
return Ok(result); return Ok(result);
} }
protected async Task<bool> UserHasAccessToWellAsync(int idWell, CancellationToken token)
{
var idCompany = User.GetCompanyId();
if (idCompany is not null &&
await wellService.IsCompanyInvolvedInWellAsync((int)idCompany, idWell, token)
.ConfigureAwait(false))
return true;
return false;
}
} }
} }