DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/DailyReport/DailyReportExportService.cs
Степанов Дмитрий dcaec8b4a2 Доработки
1. Добавлен шаблон суточного отчёта
2. Рефакторинг DTO для суточного отчёта
3. Обновлена валидация входных данных в методах контроллера
4. Небольшой рефакторинг сервисов
2023-11-07 15:57:15 +05:00

259 lines
12 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.Reflection;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data.DailyReport;
using AsbCloudApp.Data.DailyReport.Blocks;
using AsbCloudApp.Data.DailyReport.Blocks.Sign;
using AsbCloudApp.Data.DailyReport.Blocks.Subsystems;
using AsbCloudApp.Data.DailyReport.Blocks.TimeBalance;
using AsbCloudApp.Data.DailyReport.Blocks.WellOperation;
using AsbCloudApp.Services.DailyReport;
using ClosedXML.Excel;
namespace AsbCloudInfrastructure.Services.DailyReport;
public class DailyReportExportService : IDailyReportExportService
{
private const int rowStartScheduleBlock = 20;
private const int rowStartSubsystemBlock = 26;
private const int rowStartFactWellOperationBlock = 39;
private const int rowStartTimeBalanceBlock = 62;
private const int rowStartProcessMapWellDrillingBlock = 68;
private const int columnTimeBalanceDurationPlan = 3;
private const int columnTimeBalanceDurationFact = 4;
private const int columnTimeBalanceReasonDeviation = 8;
private const int columnTimeBalanceDrillingDeviationPerSection = 10;
private const int columnTimeBalanceDrillingDeviationPerDaily = 11;
private const int columnSheduleDriller = 3;
private const int columnSheduleShiftStart = 7;
private const int columnSheduleShiftEnd = 8;
private const int columnSubsystemName = 2;
private const int columnUseSubsystemPerDayUsedTimeHours = 3;
private const int columnUseSubsystemPerDaySumDepthInterval = 4;
private const int columnUseSubsystemPerDayKUsage = 5;
private const int columnUseSubsystemPerWellUsedTimeHours = 6;
private const int columnUseSubsystemPerWellSumDepthInterval = 7;
private const int columnUseSubsystemPerWellKUsage = 8;
private const int columnProcessMapWellDrillingBlockDrillingMode = 2;
private const int columnProcessMapWellDrillingBlockWellBoreDepth = 3;
private const int columnProcessMapWellDrillingBlockMechDrillingHours = 4;
private const int columnProcessMapWellDrillingBlockRopPlan = 5;
private const int columnProcessMapWellDrillingBlockRopFact = 6;
private const int columnWellOperationCategory = 2;
private const int columnWellOperationDurationHours = 4;
private const string cellCustomer = "C2";
private const string cellContractor = "C3";
private const string cellDeposit = "C5";
private const string cellCluster = "C6";
private const string cellWellName = "C7";
private const string cellWellType = "C8";
private const string cellDateStart = "C12";
private const string cellDateEnd = "D12";
private const string cellDepthStart = "C13";
private const string cellDepthEnd = "D13";
private const string cellTrajectoryBlockWellboreDepth = "B17";
private const string cellTrajectoryBlockVerticalDepth = "C17";
private const string cellTrajectoryBlockZenithAngle = "D17";
private const string cellTrajectoryBlockAzimuthGeo = "E17";
private const string cellTimeBalanceBlockSection = "C60";
private const string cellTimeBalanceBlockWellDepthPlan = "C61";
private const string cellDurationHoursDrillingPerSection = "F77";
private const string cellTimeBalanceBlockWellDepthFact = "F78";
private const string cellTimeBalanceBlockCountWellOperationSlipsTime = "F79";
private const string cellSubsystemComment = "D35";
private const string cellSubsystemMeasurementsPerDaily = "F80";
private const string cellSubsystemWellBoreDepth = "C9";
private const string cellSubsystemTotalRopPlan = "E70";
private const string cellSignDrillingMaster = "C84";
private const string cellSignSupervisor = "C85";
private readonly IDailyReportService dailyReportService;
public DailyReportExportService(IDailyReportService dailyReportService)
{
this.dailyReportService = dailyReportService;
}
public async Task<(string FileName, Stream File)> ExportAsync(int idWell, DateTime dailyReportDateStart, CancellationToken cancellationToken)
{
var dailyReport = await dailyReportService.GetAsync(idWell, dailyReportDateStart, cancellationToken);
var stream = await GenerateFileAsync(dailyReport, cancellationToken);
var fileName = $"Суточный_рапорт_по_скважине_{dailyReport.WellName}_куст_{dailyReport.Cluster}_от_{dailyReport.DateStart:yy-MM-dd}.xlsx";
return (fileName, stream);
}
private static async Task<Stream> GenerateFileAsync(DailyReportDto dailyReport, CancellationToken cancellationToken)
{
using var excelTemplateStream = await Assembly
.GetExecutingAssembly()
.GetTemplateCopyStreamAsync("DailyReportTemplate.xlsx", cancellationToken);
using var workbook = new XLWorkbook(excelTemplateStream, XLEventTracking.Disabled);
AddDailyReportToWorkBook(workbook, dailyReport);
var memoryStream = new MemoryStream();
workbook.SaveAs(memoryStream, new SaveOptions { });
memoryStream.Seek(0, SeekOrigin.Begin);
return memoryStream;
}
private static void AddDailyReportToWorkBook(IXLWorkbook workbook, DailyReportDto dailyReport)
{
const string sheetName = "Суточный отчёт";
var sheet = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetName)
?? throw new FileFormatException($"Книга excel не содержит листа {sheetName}.");
sheet.Cell(cellCustomer).Value = dailyReport.Customer;
sheet.Cell(cellContractor).Value = dailyReport.Contractor;
sheet.Cell(cellDeposit).Value = dailyReport.Deposit;
sheet.Cell(cellCluster).Value = dailyReport.Cluster;
sheet.Cell(cellWellName).Value = dailyReport.WellName;
sheet.Cell(cellWellType).Value = dailyReport.WellType;
sheet.Cell(cellDateStart).Value = dailyReport.DateStart;
sheet.Cell(cellDateEnd).Value = dailyReport.DateEnd;
sheet.Cell(cellDepthStart).Value = dailyReport.DepthStart;
sheet.Cell(cellDepthEnd).Value = dailyReport.DepthEnd;
if (dailyReport.TimeBalanceBlock is not null)
AddTimeBalanceBlockToSheet(sheet, dailyReport.TimeBalanceBlock);
if (dailyReport.SubsystemBlock is not null)
AddSubsystemBlockToSheet(sheet, dailyReport.SubsystemBlock);
if (dailyReport.SignBlock is not null)
AddSignBlockToSheet(sheet, dailyReport.SignBlock);
AddTrajectoryBlockToSheet(sheet, dailyReport.TrajectoryBlock);
AddScheduleBlockToSheet(sheet, dailyReport.ScheduleBlock);
AddProcessMapWellDrillingBlockToSheet(sheet, dailyReport.ProcessMapWellDrillingBlock);
AddFactWellOperationBlockToSheet(sheet, dailyReport.FactWellOperationBlock);
}
private static void AddTrajectoryBlockToSheet(IXLWorksheet sheet, TrajectoryBlockDto trajectoryBlock)
{
sheet.Cell(cellTrajectoryBlockWellboreDepth).Value = trajectoryBlock.WellboreDepth;
sheet.Cell(cellTrajectoryBlockVerticalDepth).Value = trajectoryBlock.VerticalDepth;
sheet.Cell(cellTrajectoryBlockZenithAngle).Value = trajectoryBlock.ZenithAngle;
sheet.Cell(cellTrajectoryBlockAzimuthGeo).Value = trajectoryBlock.AzimuthGeo;
}
private static void AddTimeBalanceBlockToSheet(IXLWorksheet sheet, TimeBalanceBlockDto timeBalanceBlock)
{
var rowCurrent = rowStartTimeBalanceBlock;
foreach (var wellOperation in timeBalanceBlock.WellOperations.OrderBy(w => w.IdWellOperation))
{
sheet.Cell(rowCurrent, columnTimeBalanceDurationPlan).Value = wellOperation.DurationHours?.Plan;
sheet.Cell(rowCurrent, columnTimeBalanceDurationFact).Value = wellOperation.DurationHours?.Fact;
sheet.Cell(rowCurrent, columnTimeBalanceReasonDeviation).Value = wellOperation.ReasonDeviation;
sheet.Cell(rowCurrent, columnTimeBalanceDrillingDeviationPerSection).Value = wellOperation.DrillingDeviationPerSection;
sheet.Cell(rowCurrent, columnTimeBalanceDrillingDeviationPerDaily).Value = wellOperation.DrillingDeviationPerDaily;
rowCurrent++;
}
sheet.Cell(cellTimeBalanceBlockSection).Value = timeBalanceBlock.SectionName;
sheet.Cell(cellTimeBalanceBlockWellDepthPlan).Value = timeBalanceBlock.WellDepthPlan;
sheet.Cell(cellTimeBalanceBlockWellDepthFact).Value = timeBalanceBlock.WellDepthFact;
sheet.Cell(cellTimeBalanceBlockCountWellOperationSlipsTime).Value = timeBalanceBlock.CountWellOperationSlipsTime;
}
private static void AddSubsystemBlockToSheet(IXLWorksheet sheet, SubsystemBlockDto subsystemBlock)
{
var groupedModules = subsystemBlock.Modules.OrderBy(m => m.SubsystemName)
.GroupBy(m => m.SubsystemName);
var rowСurrent = rowStartSubsystemBlock;
foreach (var groupedModule in groupedModules)
{
var useSubsystemPerDay = groupedModule.FirstOrDefault(m => m.IdTimeInterval == 1);
var useSubsystemPerWell = groupedModule.FirstOrDefault(m => m.IdTimeInterval == 2);
sheet.Cell(rowСurrent, columnSubsystemName).Value = groupedModule.Key;
sheet.Cell(rowСurrent, columnUseSubsystemPerDayUsedTimeHours).Value = useSubsystemPerDay?.UsedTimeHours;
sheet.Cell(rowСurrent, columnUseSubsystemPerDaySumDepthInterval).Value = useSubsystemPerDay?.SumDepthInterval;
sheet.Cell(rowСurrent, columnUseSubsystemPerDayKUsage).Value = useSubsystemPerDay?.KUsage;
sheet.Cell(rowСurrent, columnUseSubsystemPerWellUsedTimeHours).Value = useSubsystemPerWell?.UsedTimeHours;
sheet.Cell(rowСurrent, columnUseSubsystemPerWellSumDepthInterval).Value = useSubsystemPerWell?.SumDepthInterval;
sheet.Cell(rowСurrent, columnUseSubsystemPerWellKUsage).Value = useSubsystemPerWell?.KUsage;
rowСurrent++;
}
sheet.Cell(cellSubsystemComment).Value = subsystemBlock.Comment;
sheet.Cell(cellSubsystemMeasurementsPerDaily).Value = subsystemBlock.MeasurementsPerDaily;
sheet.Cell(cellSubsystemWellBoreDepth).Value = subsystemBlock.WellBoreDepth;
sheet.Cell(cellSubsystemTotalRopPlan).Value = subsystemBlock.TotalRopPlan;
}
private static void AddScheduleBlockToSheet(IXLWorksheet sheet, IEnumerable<ScheduleRecordDto> scheduleBlock)
{
var rowCurrent = rowStartScheduleBlock;
foreach (var schedule in scheduleBlock.OrderBy(s => s.ShiftStart))
{
sheet.Cell(rowCurrent, columnSheduleDriller).Value = $"{schedule.Surname} {schedule.Name} {schedule.Patronymic}";
sheet.Cell(rowCurrent, columnSheduleShiftStart).Value = schedule.ShiftStart;
sheet.Cell(rowCurrent, columnSheduleShiftEnd).Value = schedule.ShiftEnd;
rowCurrent++;
}
}
private static void AddProcessMapWellDrillingBlockToSheet(IXLWorksheet sheet,
IEnumerable<ProcessMapWellDrillingRecordDto> processMapWellDrillingBlock)
{
var rowCurrent = rowStartProcessMapWellDrillingBlock;
foreach (var processMapWellDrilling in processMapWellDrillingBlock.OrderBy(p => p.DrillingMode))
{
sheet.Cell(rowCurrent, columnProcessMapWellDrillingBlockDrillingMode).Value = processMapWellDrilling.DrillingMode;
sheet.Cell(rowCurrent, columnProcessMapWellDrillingBlockWellBoreDepth).Value = processMapWellDrilling.WellBoreDepth;
sheet.Cell(rowCurrent, columnProcessMapWellDrillingBlockMechDrillingHours).Value = processMapWellDrilling.MechDrillingHours;
sheet.Cell(rowCurrent, columnProcessMapWellDrillingBlockRopPlan).Value = processMapWellDrilling.Rop.Plan;
sheet.Cell(rowCurrent, columnProcessMapWellDrillingBlockRopFact).Value = processMapWellDrilling.Rop.Fact;
rowCurrent++;
}
}
private static void AddFactWellOperationBlockToSheet(IXLWorksheet sheet, WellOperationBlockDto factWellOperationBlock)
{
sheet.Cell(cellDurationHoursDrillingPerSection).Value = factWellOperationBlock.DurationHoursDrillingPerSection;
foreach (var factOperation in factWellOperationBlock.WellOperations.OrderBy(w => w.CategoryName))
{
sheet.Cell(rowStartFactWellOperationBlock, columnWellOperationCategory).Value = factOperation.CategoryName;
sheet.Cell(rowStartFactWellOperationBlock, columnWellOperationDurationHours).Value = factOperation.DurationHours;
}
}
private static void AddSignBlockToSheet(IXLWorksheet sheet, SignBlockDto signBlock)
{
sheet.Cell(cellSignDrillingMaster).Value = signBlock.DrillingMaster?.ToString();
sheet.Cell(cellSignSupervisor).Value = signBlock.Supervisor?.ToString();
}
}