DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/AutoGeneratedDailyReports/AutoGeneratedDailyReportService.cs

262 lines
9.3 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 System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Data.AutogeneratedDailyReport;
using AsbCloudApp.Data.Subsystems;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudApp.Services.AutoGeneratedDailyReports;
using AsbCloudApp.Services.Subsystems;
using AsbCloudDb.Model;
namespace AsbCloudInfrastructure.Services.AutoGeneratedDailyReports;
public class AutoGeneratedDailyReportService : IAutoGeneratedDailyReportService
{
private const string fileNameTemplate = "Суточный_отчёт_по_скважине_{0}_куст_{1}_от_{2}.xlsx";
private readonly IWellService wellService;
private readonly IWellOperationRepository wellOperationRepository;
private readonly ISubsystemOperationTimeService subsystemOperationTimeService;
private readonly ICrudRepository<SubsystemDto> subsystemRepository;
private readonly ILimitingParameterService limitingParameterService;
private readonly IAutoGeneratedDailyReportMakerService autoGeneratedDailyReportMakerService;
public AutoGeneratedDailyReportService(IWellService wellService,
IWellOperationRepository wellOperationRepository,
ISubsystemOperationTimeService subsystemOperationTimeService,
ICrudRepository<SubsystemDto> subsystemRepository,
ILimitingParameterService limitingParameterService,
IAutoGeneratedDailyReportMakerService autoGeneratedDailyReportMakerService)
{
this.wellOperationRepository = wellOperationRepository;
this.wellService = wellService;
this.subsystemOperationTimeService = subsystemOperationTimeService;
this.subsystemRepository = subsystemRepository;
this.limitingParameterService = limitingParameterService;
this.autoGeneratedDailyReportMakerService = autoGeneratedDailyReportMakerService;
}
public async Task<PaginationContainer<AutoGeneratedDailyReportInfoDto>> GetListAsync(int idWell,
AutoGeneratedDailyReportRequest request,
CancellationToken cancellationToken)
{
var result = new PaginationContainer<AutoGeneratedDailyReportInfoDto>
{
Skip = request.Skip ?? 0,
Take = request.Take ?? 10,
Items = Enumerable.Empty<AutoGeneratedDailyReportInfoDto>()
};
var reports = new List<AutoGeneratedDailyReportInfoDto>();
var well = await wellService.GetOrDefaultAsync(idWell, cancellationToken)
?? throw new ArgumentInvalidException("Скважина не найдена", nameof(idWell));
if (!well.IdTelemetry.HasValue)
throw new ArgumentInvalidException("Телеметрия для скважины отсутствует", nameof(idWell));
var datesRange = await GetDatesRangeAsync(idWell, cancellationToken);
if (datesRange is null)
return result;
if (request.StartDate.HasValue)
{
var startDate = new DateTime(request.StartDate.Value.Year, request.StartDate.Value.Month,
request.StartDate.Value.Day);
if(startDate.Date >= datesRange.From.Date)
datesRange.From = startDate;
}
if (request.FinishDate.HasValue)
{
var finishDate = new DateTime(request.FinishDate.Value.Year, request.FinishDate.Value.Month,
request.FinishDate.Value.Day);
if (finishDate.Date <= datesRange.To.Date)
datesRange.To = finishDate;
}
if (datesRange.From.AddDays(result.Skip) <= datesRange.To)
result.Count = (int)(Math.Ceiling((datesRange.To - DateTime.UnixEpoch).TotalDays) - Math.Floor((datesRange.From - DateTime.UnixEpoch).TotalDays));
for (int day = result.Skip; (day - result.Skip) < result.Take && (datesRange.From.AddDays(day)) <= datesRange.To; day++)
{
var reportDate = DateOnly.FromDateTime(datesRange.From.AddDays(day));
reports.Add(new AutoGeneratedDailyReportInfoDto
{
FileName = string.Format(fileNameTemplate, well.Caption, well.Cluster, reportDate),
ReportDate = reportDate,
FileSize = GetFileSize(reportDate, idWell),
});
}
result.Items = reports;
return result;
}
public async Task<(string fileName, Stream stream)> GenerateAsync(int idWell, DateOnly reportDate,
CancellationToken cancellationToken)
{
var startDate = new DateTime(reportDate.Year, reportDate.Month, reportDate.Day);
var finishDate = startDate.AddDays(1);
var well = await wellService.GetOrDefaultAsync(idWell, cancellationToken)
?? throw new ArgumentInvalidException("Скважина не найдена", nameof(idWell));
if (!well.IdTelemetry.HasValue)
throw new ArgumentInvalidException("Телеметрия для скважины отсутствует", nameof(idWell));
var factOperations = await GetFactOperationsAsync(well.Id, startDate, finishDate,
cancellationToken);
var report = new AutoGeneratedDailyReportDto
{
FileName = string.Format(fileNameTemplate, well.Caption, well.Cluster, reportDate),
FileSize = GetFileSize(reportDate, idWell),
ReportDate = reportDate,
Head = CreateHeadBlock(well, factOperations),
Subsystems = (await CreateSubsystemBlockAsync(idWell, startDate, finishDate, cancellationToken)).ToArray(),
LimitingParameters = (await CreateLimitingParameterBlockAsync(idWell, startDate, finishDate, cancellationToken)).ToArray(),
TimeBalance = factOperations.GroupBy(w => w.CategoryName).Select(x => new TimeBalanceRecordDto
{
Name = x.Key ?? "Название операции отсутствует",
DurationHours = x.Sum(o => o.DurationHours)
}).ToArray(),
};
var stream = await autoGeneratedDailyReportMakerService.MakeReportAsync(report, cancellationToken);
return (report.FileName, stream);
}
public async Task<DatesRangeDto?> GetDatesRangeAsync(int idWell, CancellationToken cancellationToken)
{
var factOperations = await GetFactOperationsAsync(idWell, null, null,
cancellationToken);
if (!factOperations.Any())
return null;
return new DatesRangeDto
{
From = factOperations.Min(o => o.DateStart).Date,
To = factOperations.Max(o => o.DateStart).Date
};
}
private HeadBlockDto CreateHeadBlock(WellDto well, IEnumerable<WellOperationDto> factOperations)
{
var customer = well.Companies.FirstOrDefault(company => company.IdCompanyType == 1);
var sortedFactOperations = factOperations.OrderBy(o => o.DateStart);
return new HeadBlockDto
{
Customer = customer?.Caption ?? string.Empty,
Deposit = well.Deposit ?? string.Empty,
Cluster = well.Cluster ?? string.Empty,
Well = well.Caption,
DepthFrom = sortedFactOperations.FirstOrDefault()?.DepthStart ?? 0.00,
DepthTo = sortedFactOperations.LastOrDefault()?.DepthEnd ?? 0.00
};
}
private async Task<IEnumerable<SubsystemRecordDto>> CreateSubsystemBlockAsync(int idWell, DateTime startDate,
DateTime finishDate,
CancellationToken cancellationToken)
{
var subsystems = await subsystemRepository.GetAllAsync(cancellationToken);
var subsystemStats = await GetSubsystemStatsAsync(idWell, startDate, finishDate,
cancellationToken);
return subsystems.Select(subsystem =>
{
var subsytemStat = subsystemStats?.FirstOrDefault(s => s.IdSubsystem == subsystem.Id);
return new SubsystemRecordDto
{
Name = subsystem.Name,
KUsage = subsytemStat?.KUsage ?? 0.00,
UsedTimeHours = subsytemStat?.UsedTimeHours ?? 0.00,
Depth = subsytemStat?.SumDepthInterval ?? 0.00,
};
});
}
private async Task<IEnumerable<LimitingParameterRecordDto>> CreateLimitingParameterBlockAsync(int idWell,
DateTime startDate, DateTime finishDate, CancellationToken cancellationToken)
{
var limitingParameterStats = (await GetLimitingParameterStatsAsync(idWell,
startDate, finishDate, cancellationToken)).ToArray();
var sumDepths = limitingParameterStats.Sum(x => x.Depth);
return limitingParameterStats.Select(l => new LimitingParameterRecordDto
{
NameFeedRegulator = l.NameFeedRegulator,
Hours = l.TotalMinutes,
PercentDepth = sumDepths != 0 ? l.Depth / sumDepths : 0,
Depth = l.Depth,
});
}
private async Task<IOrderedEnumerable<WellOperationDto>> GetFactOperationsAsync(int idWell, DateTime? startDate,
DateTime? finishDate, CancellationToken cancellationToken)
{
var request = new WellOperationRequest
{
IdWell = idWell,
OperationType = WellOperation.IdOperationTypeFact,
GeDate = startDate,
LtDate = finishDate,
SortFields = new[] { "DateStart asc" },
};
return (await wellOperationRepository.GetAsync(request, cancellationToken))
.OrderBy(w => w.DateStart);
}
private Task<IEnumerable<SubsystemStatDto>?> GetSubsystemStatsAsync(int idWell, DateTime startDate,
DateTime finishDate, CancellationToken cancellationToken)
{
var request = new SubsystemOperationTimeRequest
{
IdWell = idWell,
GtDate = startDate,
LtDate = finishDate,
};
return subsystemOperationTimeService.GetStatAsync(request, cancellationToken);
}
private Task<IEnumerable<LimitingParameterDto>> GetLimitingParameterStatsAsync(int idWell,
DateTime startDate, DateTime finishDate, CancellationToken cancellationToken)
{
var request = new LimitingParameterRequest
{
IdWell = idWell,
GtDate = startDate,
LtDate = finishDate,
};
return limitingParameterService.GetStatAsync(request, cancellationToken);
}
private int GetFileSize(DateOnly reportDate, int idWell)
{
const int fileSizeTemplate = 10240;
long ticks = 1L * reportDate.Year * reportDate.Month * reportDate.Day * idWell;
int remainder = (int)(ticks % (fileSizeTemplate / 10));
return fileSizeTemplate + remainder;
}
}