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

378 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using AsbCloudApp.Data;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Repository;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services
{
#nullable enable
public class WellService : CrudCacheRepositoryBase<WellDto, Well>, IWellService
{
private readonly ITelemetryService telemetryService;
private readonly ICrudRepository<CompanyTypeDto> companyTypesService;
private readonly ITimezoneService timezoneService;
private readonly IWellOperationRepository wellOperationRepository;
public ITelemetryService TelemetryService => telemetryService;
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);
public WellService(IAsbCloudDbContext db, IMemoryCache memoryCache, ITelemetryService telemetryService, ITimezoneService timezoneService)
: base(db, memoryCache, MakeQueryWell)
{
this.telemetryService = telemetryService;
this.timezoneService = timezoneService;
this.wellOperationRepository = new WellOperationRepository(db, memoryCache, 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);
if (well?.IdTelemetry is null)
return DateTimeOffset.MinValue;
var lastTelemetryDate = telemetryService.GetLastTelemetryDate((int)well.IdTelemetry);
return lastTelemetryDate;
}
/// <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);
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);
dto ??= well.Adapt<WellMapInfoDto>();
dto.Latitude ??= gCluster.Key.Latitude ?? gDeposit.Key.Latitude;
dto.Longitude ??= gCluster.Key.Longitude ?? gDeposit.Key.Longitude;
if (well.IdTelemetry is not null)
dto.LastTelemetryDate = telemetryService.GetLastTelemetryDate(well.IdTelemetry.Value);
return dto;
}),
}),
});
return depositTree;
}
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);
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 = default)
{
if (dto.IdWellType is < 1 or > 2)
throw new ArgumentInvalidException("Тип скважины указан неправильно.", nameof(dto));
if (dto.IdState is < 0 or > 2)
throw new ArgumentInvalidException("Текущее состояние работы скважины указано неправильно.", nameof(dto));
if (dto.Id != 0 && (await GetCacheAsync(token)).Any(w => w.Id == dto.Id))
throw new ArgumentInvalidException($"Нельзя повторно добавить скважину с id: {dto.Id}", nameof(dto));
var entity = Convert(dto);
var result = await base.InsertAsync(dto, token);
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();
}
return result;
}
public override Task<int> InsertRangeAsync(IEnumerable<WellDto> dtos, CancellationToken token)
{
throw new NotImplementedException();
}
public override async Task<int> UpdateAsync(WellDto dto,
CancellationToken token = default)
{
if (dto.IdWellType is < 1 or > 2)
throw new ArgumentInvalidException("Тип скважины указан неправильно.", nameof(dto));
if (dto.IdState is < 0 or > 2)
throw new ArgumentInvalidException("Текущее состояние работы скважины указано неправильно.", nameof(dto));
var oldRelations = (await GetCacheRelationCompanyWellAsync(token))
.Where(r => r.IdWell == dto.Id);
if (dto.Companies.Count() != oldRelations.Count() ||
dto.Companies.Any(c => !oldRelations.Any(oldC => oldC.IdCompany == c.Id)))
{
dbContext.RelationCompaniesWells
.RemoveRange(dbContext.RelationCompaniesWells
.Where(r => r.IdWell == dto.Id));
var newRelations = dto.Companies.Select(c => new RelationCompanyWell { IdWell = dto.Id, IdCompany = c.Id });
dbContext.RelationCompaniesWells.AddRange(newRelations);
}
var result = await base.UpdateAsync(dto, token);
return result;
}
public async Task<bool> IsCompanyInvolvedInWellAsync(int idCompany, int idWell, CancellationToken token)
=> (await GetCacheRelationCompanyWellAsync(token))
.Any(r => r.IdWell == idWell && r.IdCompany == idCompany);
public async Task<string> GetWellCaptionByIdAsync(int idWell, CancellationToken token)
{
var entity = await GetOrDefaultAsync(idWell, token).ConfigureAwait(false);
return entity!.Caption;
}
public async Task<IEnumerable<CompanyDto>> GetCompaniesAsync(int idWell, CancellationToken token)
{
var relations = (await GetCacheRelationCompanyWellAsync(token))
.Where(r => r.IdWell == idWell);
var dtos = relations.Select(r => Convert(r.Company));
return dtos;
}
public string GetStateText(int state)
{
return state switch
{
1 => "В работе",
2 => "Завершена",
_ => "Неизвестно",
};
}
public async Task<IEnumerable<int>> GetClusterWellsIdsAsync(int idWell, CancellationToken token)
{
var well = await GetOrDefaultAsync(idWell, token);
if (well is null)
return Enumerable.Empty<int>();
var cache = await GetCacheAsync(token);
var clusterWellsIds = cache
.Where((w) => w.IdCluster == well.IdCluster)
.Select(w => w.Id);
return clusterWellsIds;
}
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>();
return entity;
}
protected override WellDto Convert(Well entity)
{
var dto = base.Convert(entity);
if (entity.Timezone is null)
dto.Timezone = GetTimezone(entity.Id);
dto.StartDate = wellOperationRepository.FirstOperationDate(entity.Id)?.ToRemoteDateTime(dto.Timezone.Hours);
dto.WellType = entity.WellType.Caption;
dto.Cluster = entity.Cluster.Caption;
dto.Deposit = entity.Cluster.Deposit.Caption;
if (entity.IdTelemetry is not null)
dto.LastTelemetryDate = telemetryService.GetLastTelemetryDate((int)entity.IdTelemetry);
dto.Companies = entity.RelationCompaniesWells
.Select(r => Convert(r.Company))
.ToList();
return dto;
}
private CompanyDto Convert(Company entity)
{
var dto = entity.Adapt<CompanyDto>();
dto.CompanyTypeCaption = entity.CompanyType?.Caption
?? companyTypesService.GetOrDefault(entity.IdCompanyType)?.Caption
?? string.Empty;
return dto;
}
public async Task EnshureTimezonesIsSetAsync(CancellationToken token)
{
var cache = await GetCacheAsync(token);
if (!cache.Any(w => w.Timezone is null))
return;
var defaultTimeZone = new SimpleTimezone
{
Hours = 5,
IsOverride = false,
TimezoneId = "Assumed",
};
await dbSet.Where(w => w.Timezone == null)
.ForEachAsync(w => w.Timezone = defaultTimeZone, token);
await dbContext.SaveChangesAsync(token);
DropCache();
}
public SimpleTimezoneDto GetTimezone(int idWell)
{
var well = GetOrDefault(idWell);
if (well == null)
throw new ArgumentInvalidException($"idWell: {idWell} does not exist.", nameof(idWell));
return GetTimezone(well);
}
private SimpleTimezoneDto GetTimezone(WellDto wellDto)
{
if (wellDto.Timezone is not null)
return wellDto.Timezone;
if (wellDto.Telemetry is not null)
{
var timezone = telemetryService.GetTimezone(wellDto.Telemetry.Id);
if (timezone is not null)
return timezone;
}
var well = GetQuery().FirstOrDefault(w => w.Id == wellDto.Id);
if (well is not null)
{
var point = GetCoordinates(well);
if (point is not null)
{
if (point.Timezone is not null)
{
return point.Timezone.Adapt<SimpleTimezoneDto>();
}
if (point.Latitude is not null & point.Longitude is not null)
{
var timezone = timezoneService.GetByCoordinates(point.Latitude!.Value, point.Longitude!.Value);
if (timezone is not null)
{
return timezone;
}
}
}
}
throw new Exception($"Can't find timezone for well {wellDto.Caption} id: {wellDto.Id}");
}
private static AsbCloudDb.Model.IMapPoint GetCoordinates(Well well)
{
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);
}
}
#nullable disable
}