From 69fe2bf27743128ba23412621a0b038370b4754d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Fri, 3 Nov 2023 19:35:52 +0500 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8=D1=81=20=D1=8D=D0=BA?= =?UTF-8?q?=D1=81=D0=BF=D0=BE=D1=80=D1=82=D0=B0=20=D1=81=D1=83=D1=82=D0=BE?= =?UTF-8?q?=D1=87=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=BE=D1=82=D1=87=D1=91=D1=82?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DailyReport/IDailyReportExportService.cs | 21 ++ .../DailyReport/DailyReportExportService.cs | 259 ++++++++++++++++++ 2 files changed, 280 insertions(+) create mode 100644 AsbCloudApp/Services/DailyReport/IDailyReportExportService.cs create mode 100644 AsbCloudInfrastructure/Services/DailyReport/DailyReportExportService.cs diff --git a/AsbCloudApp/Services/DailyReport/IDailyReportExportService.cs b/AsbCloudApp/Services/DailyReport/IDailyReportExportService.cs new file mode 100644 index 00000000..fb9a897a --- /dev/null +++ b/AsbCloudApp/Services/DailyReport/IDailyReportExportService.cs @@ -0,0 +1,21 @@ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace AsbCloudApp.Services.DailyReport; + +/// +/// Сервис экспорта суточного отчёта +/// +public interface IDailyReportExportService +{ + /// + /// Экспортировать + /// + /// + /// + /// + /// + Task<(string FileName, Stream File)> ExportAsync(int idWell, DateTime dailyReportDateStart, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/DailyReport/DailyReportExportService.cs b/AsbCloudInfrastructure/Services/DailyReport/DailyReportExportService.cs new file mode 100644 index 00000000..8084c7c9 --- /dev/null +++ b/AsbCloudInfrastructure/Services/DailyReport/DailyReportExportService.cs @@ -0,0 +1,259 @@ +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 columnProcessMapWellDrillingBlockMode = 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 async Task 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.IdSection; + 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.IdSubsystem) + .GroupBy(m => m.IdSubsystem); + + 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 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 processMapWellDrillingBlock) + { + var rowCurrent = rowStartProcessMapWellDrillingBlock; + + foreach (var processMapWellDrilling in processMapWellDrillingBlock.OrderBy(p => p.IdMode)) + { + sheet.Cell(rowCurrent, columnProcessMapWellDrillingBlockMode).Value = processMapWellDrilling.IdMode; + 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.IdWellCategory)) + { + sheet.Cell(rowStartFactWellOperationBlock, columnWellOperationCategory).Value = factOperation.IdWellCategory; + 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(); + } +} \ No newline at end of file