DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/WellService.cs
2022-05-06 16:35:16 +05:00

365 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.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services.Cache;
using Mapster;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services
{
public class WellService : CrudCacheServiceBase<WellDto, Well>, IWellService
{
private static readonly TypeAdapterConfig typeAdapterConfig = TypeAdapterConfig<WellDto, Well>
.NewConfig()
.Ignore(dst => dst.Cluster,
dst => dst.RelationCompaniesWells,
dst => dst.Telemetry,
dst => dst.WellComposites,
dst => dst.WellCompositeSrcs,
dst => dst.WellOperations,
dst => dst.WellType)
.Config;
private readonly ITelemetryService telemetryService;
private readonly CacheTable<RelationCompanyWell> cacheRelationCompaniesWells;
private readonly CacheTable<CompanyType> cacheCompanyWellTypes;
private readonly ITimezoneService timezoneService;
private readonly Lazy<IWellOperationService> wellOperationService;
public ITelemetryService TelemetryService => telemetryService;
public WellService(IAsbCloudDbContext db, CacheDb cacheDb, ITelemetryService telemetryService, ITimezoneService timezoneService)
: base(db, cacheDb)
{
this.telemetryService = telemetryService;
this.timezoneService = timezoneService;
this.wellOperationService = new Lazy<IWellOperationService>(() => new WellOperationService.WellOperationService(db, cacheDb, this));
cacheRelationCompaniesWells = cacheDb.GetCachedTable<RelationCompanyWell>((AsbCloudDbContext)db, nameof(RelationCompanyWell.Company), nameof(RelationCompanyWell.Well));
cacheCompanyWellTypes = cacheDb.GetCachedTable<CompanyType>((AsbCloudDbContext)db);
Includes.Add($"{nameof(Well.Cluster)}.{nameof(Cluster.Deposit)}");
Includes.Add(nameof(Well.Telemetry));
Includes.Add($"{nameof(Well.RelationCompaniesWells)}.{nameof(RelationCompanyWell.Company)}");
Includes.Add(nameof(Well.WellType));
}
public DateTimeOffset GetLastTelemetryDate(int idWell)
{
var well = Cache.FirstOrDefault(w => w.Id == idWell);
if (well?.IdTelemetry is null)
return DateTimeOffset.MinValue;
var lastTelemetryDate = telemetryService.GetLastTelemetryDate((int)well.IdTelemetry);
return lastTelemetryDate;
}
public async Task<IEnumerable<WellDto>> GetWellsByCompanyAsync(int idCompany, CancellationToken token)
{
var relations = await cacheRelationCompaniesWells
.WhereAsync(r => r.IdCompany == idCompany, token);
var wellsIds = relations.Select(r => r.IdWell);
var wells = await Cache.WhereAsync(w => wellsIds.Contains(w.Id), token);
var dtos = wells.Select(Convert);
return dtos;
}
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 Cache.ContainsAsync(w => w.Id == dto.Id, token))
throw new ArgumentInvalidException($"Нельзя повторно добавить скважину с id: {dto.Id}", nameof(dto));
var entity = Convert(dto);
var result = await Cache.InsertAsync(entity, token);
if (dto.Companies.Any())
{
var newRelations = dto.Companies.Select(c => new RelationCompanyWell { IdWell = result.Id, IdCompany = c.Id });
await cacheRelationCompaniesWells.InsertAsync(newRelations, token);
}
return result.Id;
}
public override Task<int> InsertRangeAsync(IEnumerable<WellDto> dtos, CancellationToken token)
{
throw new NotImplementedException();
}
public override async Task<int> UpdateAsync(int idWell, 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 != idWell)
throw new ArgumentInvalidException($"Нельзя поменять id для скважины: {idWell} => {dto.Id}.", nameof(dto));
var entity = Convert(dto);
var oldRelations = await cacheRelationCompaniesWells
.WhereAsync(r => r.IdWell == idWell, token);
if (dto.Companies.Count() != oldRelations.Count() ||
dto.Companies.Any(c => !oldRelations.Any(oldC => oldC.IdCompany == c.Id)))
{
await cacheRelationCompaniesWells.RemoveAsync(r => r.IdWell == idWell, token);
var newRelations = dto.Companies.Select(c => new RelationCompanyWell { IdWell = idWell, IdCompany = c.Id });
await cacheRelationCompaniesWells.InsertAsync(newRelations, token);
}
var result = await Cache.UpsertAsync(entity, token);
return result;
}
public bool IsCompanyInvolvedInWell(int idCompany, int idWell)
=> cacheRelationCompaniesWells.Contains(r => r.IdWell == idWell && r.IdCompany == idCompany);
public async Task<bool> IsCompanyInvolvedInWellAsync(int idCompany, int idWell, CancellationToken token)
=> await cacheRelationCompaniesWells.ContainsAsync(r => r.IdWell == idWell &&
r.IdCompany == idCompany, token).ConfigureAwait(false);
public async Task<string> GetWellCaptionByIdAsync(int idWell, CancellationToken token)
{
var entity = await Cache.FirstOrDefaultAsync(w => w.Id == idWell, token).ConfigureAwait(false);
var dto = Convert(entity);
return dto.Caption;
}
public async Task<IEnumerable<CompanyDto>> GetCompaniesAsync(int idWell, CancellationToken token)
{
var relations = await cacheRelationCompaniesWells.WhereAsync(r => r.IdWell == idWell, token);
var dtos = relations.Select(r => Convert(r.Company));
return dtos;
}
private IEnumerable<CompanyDto> GetCompanies(int idWell)
{
var relations = cacheRelationCompaniesWells.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 Cache.FirstOrDefaultAsync(w => w.Id == idWell, token)
.ConfigureAwait(false);
if (well is null)
return null;
var clusterWells = await Cache.WhereAsync(w => w.IdCluster == well.IdCluster, token)
.ConfigureAwait(false);
return clusterWells.Select(w => w.Id);
}
protected override Well Convert(WellDto dto)
{
var entity = dto.Adapt<Well>(typeAdapterConfig);
entity.IdTelemetry = entity.IdTelemetry ?? dto.IdTelemetry ?? dto.Telemetry?.Id;
if (dto.Timezone is null)
if (TryGetTimezone(dto.Id, out var timezoneDto))
entity.Timezone = timezoneDto.Adapt<SimpleTimezone>();
return entity;
}
protected override WellDto Convert(Well entity)
{
if (entity is null)
return null;
var dto = base.Convert(entity);
if (entity.Timezone is null)
if (TryGetTimezone(entity, out var timezone))
dto.Timezone = timezone;
dto.StartDate = wellOperationService.Value.FirstOperationDate(entity.Id)?.ToRemoteDateTime(dto.Timezone.Hours);
dto.WellType = entity.WellType?.Caption;
dto.Cluster = entity.Cluster?.Caption;
dto.Deposit = entity.Cluster?.Deposit?.Caption;
dto.LastTelemetryDate = GetLastTelemetryDate(entity.Id).DateTime;
dto.Companies = GetCompanies(entity.Id);
return dto;
}
private CompanyDto Convert(Company entity)
{
var dto = entity.Adapt<CompanyDto>();
dto.CompanyTypeCaption = entity.CompanyType?.Caption
?? cacheCompanyWellTypes.FirstOrDefault(c => c.Id == entity.IdCompanyType).Caption;
return dto;
}
public void EnshureTimezonesIsSet()
{
var wells = Cache.Where(w => w.Timezone is null).ToList();
foreach (var well in wells)
{
if (TryGetTimezone(well, out var timezone))
well.Timezone = timezone.Adapt<SimpleTimezone>();
else
well.Timezone = new SimpleTimezone
{
Hours = 5,
IsOverride = false,
TimeZoneId = "Assumed",
};
}
var wellsWithTz = wells.Where(w => w.Timezone is not null);
if (wellsWithTz.Any())
{
var adaptedWells = wellsWithTz.Adapt<WellDto>().Select(Convert);
Cache.Upsert(adaptedWells);
}
}
private bool TryGetTimezone(int idWell, out SimpleTimezoneDto timezone)
{
timezone = null;
try
{
timezone = GetTimezone(idWell);
return timezone is not null;
}
catch
{
return false;
}
}
public SimpleTimezoneDto GetTimezone(int idWell)
{
var well = Cache.FirstOrDefault(c => c.Id == idWell);
if (well == null)
throw new ArgumentInvalidException($"idWell: {idWell} does not exist.", nameof(idWell));
return GetTimezone(well);
}
private bool TryGetTimezone(Well well, out SimpleTimezoneDto timezone)
{
timezone = null;
try
{
timezone = GetTimezone(well);
return timezone is not null;
}
catch
{
return false;
}
}
private SimpleTimezoneDto GetTimezone(Well well)
{
if (well == null)
throw new ArgumentNullException(nameof(well));
if (well.Timezone is not null)
return well.Timezone.Adapt<SimpleTimezoneDto>();
if (well.Telemetry is not null)
{
var timezone = telemetryService.GetTimezone(well.Telemetry.Id);
if (timezone is not null)
{
well.Timezone = timezone.Adapt<SimpleTimezone>();
return timezone;
}
}
var point = GetCoordinates(well);
if (point is not null)
{
if (point.Timezone is not null)
{
well.Timezone = point.Timezone;
return point.Timezone.Adapt<SimpleTimezoneDto>();
}
if (point.Latitude is not null & point.Longitude is not null)
{
var timezone = timezoneService.GetByCoordinates((double)point.Latitude, (double)point.Longitude);
if (timezone is not null)
{
well.Timezone = timezone.Adapt<SimpleTimezone>();
return timezone;
}
}
}
throw new Exception($"Can't find timezone for well {well.Caption} id: {well.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;
if (well.Cluster is null)
throw new Exception($"Can't find coordinates of well {well.Caption} id: {well.Id}");
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 = Cache.FirstOrDefault(w => w.Id == idWell);
if (well is null)
throw new Exception($"Well id: {idWell} does not exist.");
if (well.IdTelemetry is null)
throw new Exception($"Well id: {idWell} does not contain telemetry.");
return telemetryService.GetDatesRange((int)well.IdTelemetry);
}
}
}