using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data; using AsbCloudApp.Data.ProcessMaps.Operations; using AsbCloudApp.Data.Trajectory; using AsbCloudApp.Data.WellOperation; using AsbCloudApp.Data.WellReport; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudApp.Services.ProcessMaps.WellDrilling; using AsbCloudApp.Services.WellReport; using AsbCloudDb.Model; namespace AsbCloudInfrastructure.Services.WellReport; public class WellReportService : IWellReportService { private readonly IWellService wellService; private readonly IWellOperationService wellOperationService; private readonly IWellContactService wellContactService; private readonly IProcessMapReportDrillingService processMapReportDrillingService; private readonly ISubsystemService subsystemService; private readonly ITrajectoryRepository trajectoryPlanRepository; private readonly ITrajectoryRepository trajectoryFactRepository; private readonly IChangeLogRepository processMapPlanRotorRepository; private readonly IScheduleRepository scheduleRepository; private IEnumerable factWellOperations; private IEnumerable planWellOperations; public WellReportService(IWellService wellService, IWellOperationService wellOperationService, IWellContactService wellContactService, IProcessMapReportDrillingService processMapReportDrillingService, ISubsystemService subsystemService, ITrajectoryRepository trajectoryPlanRepository, ITrajectoryRepository trajectoryFactRepository, IChangeLogRepository processMapPlanRotorRepository, IScheduleRepository scheduleRepository) { this.wellService = wellService; this.wellOperationService = wellOperationService; this.wellContactService = wellContactService; this.processMapReportDrillingService = processMapReportDrillingService; this.subsystemService = subsystemService; this.trajectoryPlanRepository = trajectoryPlanRepository; this.trajectoryFactRepository = trajectoryFactRepository; this.processMapPlanRotorRepository = processMapPlanRotorRepository; this.scheduleRepository = scheduleRepository; } public async Task GetAsync(int idWell, CancellationToken token) { var well = await wellService.GetOrDefaultAsync(idWell, token); if (well == null) return null; await InitWellOperations(idWell, token); var wellContactRequest = new WellContactRequest { IdsWells = new[] { idWell }, }; var contacts = await wellContactService.GetAllAsync(wellContactRequest, token); var sectionReports = await GetSectionReportsAsync(idWell, token); var drillerReports = await GetDrillerReportsAsync(idWell, token); var firstFactOperation = factWellOperations.MinByOrDefault(x => x.DateStart); var lastPlanOperation = planWellOperations.MaxByOrDefault(x => x.DateStart); var planTrajectories = await trajectoryPlanRepository.GetAsync(idWell, token); var factTrajectories = await trajectoryFactRepository.GetAsync(idWell, token); var factOperationsWithoutNpt = factWellOperations.Where(o => !WellOperationCategory.NonProductiveTimeSubIds.Contains(o.IdCategory)); return new WellReportDto { Well = well, DateFrom = firstFactOperation?.DateStart, DateTo = lastPlanOperation?.DateStart.AddHours(lastPlanOperation.DurationHours), Days = new PlanFactDto { Plan = planWellOperations.Sum(x => x.DurationHours) / 24, Fact = factWellOperations.Sum(x => x.DurationHours) / 24 }, WellBoreDepth = new PlanFactDto { Plan = planWellOperations.MaxOrDefault(x => x.DepthEnd), Fact = factWellOperations.MaxOrDefault(x => x.DepthEnd) }, VerticalDepth = new PlanFactDto { Plan = planTrajectories.Max(x => x.VerticalDepth), Fact = factTrajectories.Max(x => x.VerticalDepth) }, WithoutNtpDays = factOperationsWithoutNpt.Sum(x => x.DurationHours) / 24, Contacts = contacts, SectionReports = sectionReports, DrillerReports = drillerReports, }; } private async Task InitWellOperations(int idWell, CancellationToken token) { var request = new WellOperationRequest(new[] { idWell }) { OperationType = WellOperation.IdOperationTypeFact }; factWellOperations = await wellOperationService.GetAsync(request, token); request.OperationType = WellOperation.IdOperationTypePlan; planWellOperations = await wellOperationService.GetAsync(request, token); } private async Task> GetSectionReportsAsync(int idWell, CancellationToken token) { var factWellOperationsBySection = factWellOperations.GroupBy(x => x.IdWellSectionType) .ToDictionary(x => x.Key, x => x.AsEnumerable()); var processMapPlanRequest = new ProcessMapPlanBaseRequestWithWell(idWell); var processMapPlanRotorBySection = (await processMapPlanRotorRepository.GetCurrent(processMapPlanRequest, token)) .GroupBy(x => x.IdWellSectionType) .ToDictionary(x => x.Key, x => x.AsEnumerable()); var dataSaubStatRequest = new DataSaubStatRequest(); var processMapReportBySection = (await processMapReportDrillingService.GetAsync(idWell, dataSaubStatRequest, token)) .GroupBy(x => x.IdWellSectionType) .ToDictionary(x => x.Key, x => x.AsEnumerable()); var idsSection = factWellOperationsBySection.Keys .Concat(processMapPlanRotorBySection.Keys) .Concat(processMapReportBySection.Keys) .Distinct(); var sectionReports = new List(); foreach (var idSection in idsSection) { var sectionReport = new SectionReportDto { IdSection = idSection, OperatingMode = new PlanFactDto() }; if (factWellOperationsBySection.TryGetValue(idSection, out var factOperations)) { var subsystemRequest = new SubsystemRequest { IdWell = idWell, GeDepth = factOperations.Min(y => y.DepthStart), LeDepth = factOperations.Max(y => y.DepthEnd) }; sectionReport.SubsystemsStat = await subsystemService.GetStatAsync(subsystemRequest, token); sectionReport.OperatingMode.Fact = new OperatingModeDto { DepthStart = factOperations.Min(w => w.DepthStart), DepthEnd = factOperations.Max(w => w.DepthEnd) }; } if (processMapPlanRotorBySection.TryGetValue(idSection, out var processMapPlanRotor)) sectionReport.OperatingMode.Plan = new OperatingModeDto { DepthStart = processMapPlanRotor.Min(p => p.DepthStart), DepthEnd = processMapPlanRotor.Max(p => p.DepthEnd), RopMin = processMapPlanRotor.Min(p => p.RopMax), RopMax = processMapPlanRotor.Max(p => p.RopMax), RopAvg = processMapPlanRotor.Average(p => p.RopMax), WeightOnBitMin = processMapPlanRotor.Min(p => p.WeightOnBit), WeightOnBitMax = processMapPlanRotor.Max(p => p.WeightOnBitMax), WeightOnBitAvg = processMapPlanRotor.Average(p => p.WeightOnBit), DriveTorqueMin = processMapPlanRotor.Min(p => p.TopDriveTorque), DriveTorqueMax = processMapPlanRotor.Max(p => p.TopDriveTorqueMax), DriveTorqueAvg = processMapPlanRotor.Average(p => p.TopDriveTorque), DifferentialPressureMin = processMapPlanRotor.Min(p => p.DifferentialPressure), DifferentialPressureMax = processMapPlanRotor.Max(p => p.DifferentialPressureMax), DifferentialPressureAvg = processMapPlanRotor.Average(p => p.DifferentialPressure), FrowRateMin = processMapPlanRotor.Min(p => p.FlowRate), FrowRateMax = processMapPlanRotor.Max(p => p.FlowRateMax) }; if (processMapReportBySection.TryGetValue(idSection, out var processMapReport)) sectionReport.DrillingBySetpoints = new DrillingBySetpointsDto { MetersByPressure = processMapReport.Sum(x => x.DeltaDepth * x.PressureDiff.SetpointUsage / 100), MetersByLoad = processMapReport.Sum(x => x.DeltaDepth * x.AxialLoad.SetpointUsage / 100), MetersByTorque = processMapReport.Sum(x => x.DeltaDepth * x.TopDriveTorque.SetpointUsage / 100), MetersBySpeed = processMapReport.Sum(x => x.DeltaDepth * x.SpeedLimit.SetpointUsage / 100) }; sectionReports.Add(sectionReport); } return sectionReports; } private async Task> GetDrillerReportsAsync(int idWell, CancellationToken token) { var schedules = await scheduleRepository.GetByIdWellAsync(idWell, token); var result = new List(); foreach (var schedule in schedules) { var subsystemRequest = new SubsystemRequest { IdWell = idWell, IdDriller = schedule.IdDriller }; var drillerReport = new DrillerReportDto { Shedule = schedule, SubsystemsStat = await subsystemService.GetStatAsync(subsystemRequest, token) }; result.Add(drillerReport); } return result; } }