DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/WellService.cs

357 lines
14 KiB
C#
Raw Normal View History

using AsbCloudApp.Data;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Repository;
2021-07-28 09:46:58 +05:00
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
2021-07-21 15:29:19 +05:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services
{
public class WellService : CrudCacheRepositoryBase<WellDto, Well>, IWellService
2021-12-22 11:41:18 +05:00
{
private readonly ITelemetryService telemetryService;
private readonly ICrudRepository<CompanyTypeDto> companyTypesService;
private readonly ITimezoneService timezoneService;
private readonly WellInfoService wellInfoService;
private readonly IWellOperationRepository wellOperationRepository;
public ITelemetryService TelemetryService => telemetryService;
2022-06-15 14:57:37 +05:00
private static IQueryable<Well> MakeQueryWell(DbSet<Well> dbSet)
=> dbSet
.Include(w => w.Cluster)
.ThenInclude(c => c.Deposit)
.Include(w => w.Telemetry)
.Include(w => w.WellType)
.Include(w => w.RelationCompaniesWells)
.ThenInclude(r => r.Company)
.AsNoTracking();
2024-02-08 11:38:25 +05:00
public WellService(IAsbCloudDbContext db,
IMemoryCache memoryCache,
ITelemetryService telemetryService,
ITimezoneService timezoneService,
WellInfoService wellInfoService,
IWellOperationCategoryRepository wellOperationCategoryRepository)
: base(db, memoryCache, MakeQueryWell)
{
this.telemetryService = telemetryService;
this.timezoneService = timezoneService;
this.wellInfoService = wellInfoService;
wellOperationRepository = new WellOperationRepository(db, memoryCache, wellOperationCategoryRepository, this);
companyTypesService = new CrudCacheRepositoryBase<CompanyTypeDto, CompanyType>(dbContext, memoryCache);
}
private Task<IEnumerable<RelationCompanyWell>> GetCacheRelationCompanyWellAsync(CancellationToken token)
{
return memoryCache.GetOrCreateBasicAsync(
dbContext.Set<RelationCompanyWell>()
.Include(r => r.Company)
.Include(r => r.Well)
, token);
}
private void DropCacheRelationCompanyWell()
=> memoryCache.DropBasic<RelationCompanyWell>();
public DateTimeOffset GetLastTelemetryDate(int idWell)
{
var well = GetOrDefault(idWell);
2022-06-15 14:57:37 +05:00
if (well?.IdTelemetry is null)
return DateTimeOffset.MinValue;
2023-05-19 17:57:07 +05:00
var datesRange = telemetryService.GetDatesRange(well.IdTelemetry.Value);
2024-04-12 11:47:17 +05:00
return datesRange.To;
}
2023-02-16 16:27:14 +05:00
/// <inheritdoc/>
public async Task<IEnumerable<DepositBranchDto>> GetWellTreeAsync(int idCompany, CancellationToken token)
{
var wells = await GetEntitiesAsync(new() { IdCompany = idCompany }, token);
var groupedWells = wells
.GroupBy(w => w.Cluster)
.GroupBy(g => g.Key.Deposit);
2021-12-22 11:41:18 +05:00
var depositTree = groupedWells.Select(
gDeposit => new DepositBranchDto
{
Id = gDeposit.Key.Id,
Caption = gDeposit.Key.Caption,
Latitude = gDeposit.Key.Latitude,
Longitude = gDeposit.Key.Longitude,
Clusters = gDeposit.Select(gCluster => new ClusterBranchDto
{
Id = gCluster.Key.Id,
Caption = gCluster.Key.Caption,
Latitude = gCluster.Key.Latitude ?? gDeposit.Key.Latitude,
Longitude = gCluster.Key.Longitude ?? gDeposit.Key.Longitude,
Wells = gCluster.Select(well =>
{
var dto = wellInfoService.FirstOrDefault(w => w.Id == well.Id && well.IdState == 1);
dto ??= well.Adapt<WellMapInfoWithTelemetryStat>();
2023-02-16 16:27:14 +05:00
dto.Latitude ??= gCluster.Key.Latitude ?? gDeposit.Key.Latitude;
dto.Longitude ??= gCluster.Key.Longitude ?? gDeposit.Key.Longitude;
dto.Companies = well.RelationCompaniesWells.Select(r => Convert(r.Company));
return dto;
}),
}),
});
return depositTree;
}
2022-06-15 14:57:37 +05:00
public async Task<WellMapInfoWithTelemetryStat?> GetOrDefaultStatAsync(int idWell, CancellationToken token)
{
2023-10-22 17:57:39 +05:00
var well = await GetOrDefaultAsync(idWell, token);
2023-10-22 17:57:39 +05:00
if (well is null)
return null;
2023-10-22 17:57:39 +05:00
var wellInfo = wellInfoService.FirstOrDefault(well => well.Id == idWell);
2023-10-22 17:57:39 +05:00
if (wellInfo is null)
return well.Adapt<WellMapInfoWithTelemetryStat>();
2023-10-22 17:57:39 +05:00
wellInfo.IdState = well.IdState;
return wellInfo;
}
public async Task<IEnumerable<WellDto>> GetAsync(WellRequest request, CancellationToken token)
{
var wells = await GetEntitiesAsync(request, token);
var wellsDtos = wells.Select(Convert);
return wellsDtos;
}
private async Task<IEnumerable<Well>> GetEntitiesAsync(WellRequest request, CancellationToken token)
{
var wells = await GetCacheAsync(token);
2023-02-16 16:27:14 +05:00
if (request.Ids?.Any() == true)
wells = wells.Where(well => request.Ids.Contains(well.Id));
if (request.IdCompany.HasValue)
wells = wells.Where(well => well.RelationCompaniesWells.Any(r => r.IdCompany == request.IdCompany.Value));
if (request.IdState.HasValue)
wells = wells.Where(well => well.IdState == request.IdState.Value);
return wells;
}
public override async Task<int> InsertAsync(WellDto dto, CancellationToken token)
{
if (IsTelemetryAssignedToDifferentWell(dto))
2023-09-29 12:06:46 +05:00
throw new ArgumentInvalidException(nameof(dto), "Телеметрия уже была привязана к другой скважине.");
2022-11-16 17:07:47 +05:00
if (dto.Id != 0 && (await GetCacheAsync(token)).Any(w => w.Id == dto.Id))
2023-09-29 12:06:46 +05:00
throw new ArgumentInvalidException(nameof(dto), $"Нельзя повторно добавить скважину с id: {dto.Id}");
2021-12-22 11:41:18 +05:00
var entity = Convert(dto);
var result = await base.InsertAsync(dto, token);
2021-12-22 11:41:18 +05:00
if (dto.Companies.Any())
{
var newRelations = dto.Companies.Select(c => new RelationCompanyWell { IdWell = result, IdCompany = c.Id });
dbContext.RelationCompaniesWells.AddRange(newRelations);
await dbContext.SaveChangesAsync(token);
DropCacheRelationCompanyWell();
2021-12-22 11:41:18 +05:00
}
return result;
}
2021-12-21 11:52:53 +05:00
public override Task<int> InsertRangeAsync(IEnumerable<WellDto> dtos, CancellationToken token)
2021-12-21 11:52:53 +05:00
{
throw new NotImplementedException();
}
public override async Task<int> UpdateAsync(WellDto dto,
CancellationToken token)
{
if (IsTelemetryAssignedToDifferentWell(dto))
2023-09-29 12:06:46 +05:00
throw new ArgumentInvalidException(nameof(dto), "Телеметрия уже была привязана к другой скважине.");
var oldRelations = (await GetCacheRelationCompanyWellAsync(token))
.Where(r => r.IdWell == dto.Id).ToArray();
2021-12-22 11:41:18 +05:00
if (dto.Companies.Count() != oldRelations.Length ||
dto.Companies.Any(c => oldRelations.All(oldC => oldC.IdCompany != c.Id)))
2021-12-22 11:41:18 +05:00
{
dbContext.RelationCompaniesWells
.RemoveRange(dbContext.RelationCompaniesWells
.Where(r => r.IdWell == dto.Id));
DropCacheRelationCompanyWell();
var newRelations = dto.Companies
.Select(c => new RelationCompanyWell
{
IdWell = dto.Id,
IdCompany = c.Id
});
dbContext.RelationCompaniesWells.AddRange(newRelations);
2021-12-22 11:41:18 +05:00
}
var result = await base.UpdateAsync(dto, token);
2021-12-21 11:52:53 +05:00
return result;
}
public async Task<bool> IsCompanyInvolvedInWellAsync(int idCompany, int idWell, CancellationToken token)
=> (await GetCacheRelationCompanyWellAsync(token))
.Any(r => r.IdWell == idWell && r.IdCompany == idCompany);
2021-08-25 11:13:56 +05:00
public async Task<string> GetWellCaptionByIdAsync(int idWell, CancellationToken token)
{
var entity = await GetOrDefaultAsync(idWell, token).ConfigureAwait(false);
return entity!.Caption;
2021-08-25 11:13:56 +05:00
}
public async Task<IEnumerable<CompanyDto>> GetCompaniesAsync(int idWell, CancellationToken token)
{
var relations = (await GetCacheRelationCompanyWellAsync(token))
.Where(r => r.IdWell == idWell);
2021-12-21 11:52:53 +05:00
var dtos = relations.Select(r => Convert(r.Company));
return dtos;
}
public string GetStateText(int state)
{
return state switch
{
1 => "В работе",
2 => "Завершена",
_ => "Неизвестно",
};
}
2022-04-11 18:00:34 +05:00
public async Task<IEnumerable<int>> GetClusterWellsIdsAsync(int idWell, CancellationToken token)
{
var well = await GetOrDefaultAsync(idWell, token);
2022-04-11 18:00:34 +05:00
if (well is null)
return Enumerable.Empty<int>();
2022-04-11 18:00:34 +05:00
var cache = await GetCacheAsync(token);
2022-11-16 17:07:47 +05:00
var clusterWellsIds = cache
.Where((w) => w.IdCluster == well.IdCluster)
.Select(w => w.Id);
2022-04-11 18:00:34 +05:00
return clusterWellsIds;
}
2021-12-22 11:41:18 +05:00
protected override Well Convert(WellDto dto)
{
var entity = dto.Adapt<Well>();
entity.IdTelemetry = entity.IdTelemetry ?? dto.IdTelemetry ?? dto.Telemetry?.Id;
if (dto.Timezone is null)
entity.Timezone = GetTimezone(dto.Id)
.Adapt<SimpleTimezone>();
2021-12-22 11:41:18 +05:00
return entity;
}
2021-12-21 11:52:53 +05:00
protected override WellDto Convert(Well entity)
{
2021-12-21 11:52:53 +05:00
var dto = base.Convert(entity);
if (entity.Timezone is null)
dto.Timezone = GetTimezone(entity.Id);
dto.StartDate = wellOperationRepository
.GetFirstAndLastFact(entity.Id)?.First?.DateStart;
dto.WellType = entity.WellType.Caption;
dto.Cluster = entity.Cluster.Caption;
dto.Deposit = entity.Cluster.Deposit.Caption;
2022-06-15 14:57:37 +05:00
if (entity.IdTelemetry is not null)
dto.LastTelemetryDate = telemetryService.GetDatesRange(entity.IdTelemetry.Value).To.ToOffset(dto.Timezone.Offset);
dto.Companies = entity.RelationCompaniesWells
.Select(r => Convert(r.Company))
.ToList();
2021-12-21 11:52:53 +05:00
return dto;
}
private CompanyDto Convert(Company entity)
{
var dto = entity.Adapt<CompanyDto>();
2022-04-11 18:00:34 +05:00
dto.CompanyTypeCaption = entity.CompanyType?.Caption
?? companyTypesService.GetOrDefault(entity.IdCompanyType)?.Caption
?? string.Empty;
2021-12-21 11:52:53 +05:00
return dto;
}
public SimpleTimezoneDto GetTimezone(int idWell)
{
var cache = GetCache();
var cacheItem = cache.FirstOrDefault(d => d.Id == idWell)
2023-09-29 12:06:46 +05:00
?? throw new ArgumentInvalidException(nameof(idWell), $"idWell: {idWell} does not exist.");
return cacheItem.Timezone.Adapt<SimpleTimezoneDto>();
}
private bool IsTelemetryAssignedToDifferentWell(WellDto wellDto)
{
if (!wellDto.IdTelemetry.HasValue)
return false;
var existingWellWithAssignedTelemetry = GetCache()
.FirstOrDefault(x => x.IdTelemetry == wellDto.IdTelemetry);
if (existingWellWithAssignedTelemetry is null)
return false;
return existingWellWithAssignedTelemetry.Id != wellDto.Id;
}
private static AsbCloudDb.Model.IMapPoint GetCoordinates(Well well)
{
2022-04-11 18:00:34 +05:00
if (well is null)
throw new ArgumentNullException(nameof(well));
if (well.Latitude is not null & well.Longitude is not null)
return well;
var cluster = well.Cluster;
if (cluster.Latitude is not null & cluster.Longitude is not null)
return cluster;
if (cluster.Deposit is null)
throw new Exception($"Can't find coordinates of well by cluster {cluster.Caption} id: {cluster.Id}");
var deposit = cluster.Deposit;
if (deposit.Latitude is not null & deposit.Longitude is not null)
return deposit;
throw new Exception($"Can't find coordinates of well by deposit {deposit.Caption} id: {deposit.Id}");
}
public DatesRangeDto GetDatesRange(int idWell)
{
var well = GetOrDefault(idWell);
if (well is null)
throw new Exception($"Well id: {idWell} does not exist.");
if (well.IdTelemetry is null)
throw new KeyNotFoundException($"Well id: {idWell} does not contain telemetry.");
return telemetryService.GetDatesRange((int)well.IdTelemetry);
}
}
}