2022-03-17 16:56:13 +05:00
|
|
|
|
using AsbCloudApp.Data;
|
|
|
|
|
using AsbCloudApp.Services;
|
|
|
|
|
using ClosedXML.Excel;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace AsbCloudInfrastructure.Services.WellOperationService
|
|
|
|
|
{
|
2022-04-11 18:00:34 +05:00
|
|
|
|
public class ScheduleReportService : IScheduleReportService
|
2022-03-17 16:56:13 +05:00
|
|
|
|
{
|
|
|
|
|
private readonly IOperationsStatService operationsStatService;
|
|
|
|
|
private readonly IWellService wellService;
|
|
|
|
|
const string sheetNameSchedule = "Сетевой график";
|
|
|
|
|
const string sheetNameTvd = "ГГД";
|
2022-03-18 16:54:40 +05:00
|
|
|
|
const int maxChartsToWrap = 88;
|
2022-03-17 16:56:13 +05:00
|
|
|
|
|
|
|
|
|
public ScheduleReportService(IOperationsStatService operationsStatService, IWellService wellService)
|
|
|
|
|
{
|
2022-04-11 18:00:34 +05:00
|
|
|
|
this.operationsStatService = operationsStatService;
|
2022-03-17 16:56:13 +05:00
|
|
|
|
this.wellService = wellService;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<Stream> MakeReportAsync(int idWell, CancellationToken token = default)
|
|
|
|
|
{
|
|
|
|
|
var tvd = await operationsStatService.GetTvdAsync(idWell, token);
|
|
|
|
|
|
|
|
|
|
if (!tvd.Any())
|
|
|
|
|
return null;
|
|
|
|
|
|
2022-06-16 12:33:05 +05:00
|
|
|
|
var well = await wellService.GetOrDefaultAsync(idWell, token);
|
2022-03-17 16:56:13 +05:00
|
|
|
|
|
|
|
|
|
var ecxelTemplateStream = GetExcelTemplateStream();
|
|
|
|
|
using var workbook = new XLWorkbook(ecxelTemplateStream, XLEventTracking.Disabled);
|
|
|
|
|
FillScheduleSheetToWorkbook(workbook, tvd, well);
|
|
|
|
|
FillTvdSheetToWorkbook(workbook, tvd, well);
|
|
|
|
|
MemoryStream memoryStream = new MemoryStream();
|
|
|
|
|
workbook.SaveAs(memoryStream, new SaveOptions { });
|
|
|
|
|
memoryStream.Seek(0, SeekOrigin.Begin);
|
|
|
|
|
return memoryStream;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-18 16:54:40 +05:00
|
|
|
|
private static void FillScheduleSheetToWorkbook(XLWorkbook workbook, IEnumerable<PlanFactPredictBase<WellOperationDto>> tvd, WellDto well)
|
2022-03-17 16:56:13 +05:00
|
|
|
|
{
|
|
|
|
|
var sheet = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetNameSchedule);
|
|
|
|
|
if (sheet is null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const int headerRowsCount = 6;
|
|
|
|
|
const int rowTitle = 3;
|
|
|
|
|
|
|
|
|
|
const int columnRowNumber = 2;
|
|
|
|
|
const int columnCaption = 3;
|
2022-03-18 16:54:40 +05:00
|
|
|
|
const int columnWellDepthStartPlan = 4;
|
|
|
|
|
const int columnWellDepthStartFact = 5;
|
|
|
|
|
const int columnWellDepthStartPredict = 6;
|
|
|
|
|
const int columnWellDepthEndPlan = 7;
|
|
|
|
|
const int columnWellDepthEndFact = 8;
|
|
|
|
|
const int columnWellDepthEndPredict = 9;
|
|
|
|
|
const int columnDeltaWellDepthPerDay = 10;
|
|
|
|
|
const int columnDurationPlan = 11;
|
|
|
|
|
const int columnDurationFact = 12;
|
|
|
|
|
const int columnDurationPredict = 13;
|
|
|
|
|
const int columnDateStartPlan = 14;
|
|
|
|
|
const int columnDateStartFact = 15;
|
|
|
|
|
const int columnDateStartPredict = 16;
|
|
|
|
|
const int columnDateEndPlan = 17;
|
|
|
|
|
const int columnDateEndFact = 18;
|
|
|
|
|
const int columnDateEndPredict = 19;
|
|
|
|
|
const int columnGuilty = 20;
|
|
|
|
|
const int columnNpt = 21;
|
2022-03-17 16:56:13 +05:00
|
|
|
|
|
|
|
|
|
var subTitle = $"на строительство скважины №{well.Caption}, куст: {well.Cluster}, м/р: {well.Deposit}";
|
|
|
|
|
sheet.Row(rowTitle).Cell(3).Value = subTitle;
|
|
|
|
|
|
|
|
|
|
var tvdList = tvd.ToList();
|
2022-03-18 16:54:40 +05:00
|
|
|
|
var facts = tvd
|
2022-04-11 18:00:34 +05:00
|
|
|
|
.Where(t => t.Fact is not null)
|
|
|
|
|
.Select(t => t.Fact)
|
2022-03-18 16:54:40 +05:00
|
|
|
|
.ToList();
|
|
|
|
|
|
|
|
|
|
DateTime lastFactDate = default;
|
|
|
|
|
var lastFactI = 0;
|
2022-03-17 16:56:13 +05:00
|
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
for (; i < tvdList.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
var tvdItem = tvdList[i];
|
|
|
|
|
var operation = tvdItem.Fact ?? tvdItem.Plan;
|
|
|
|
|
if (operation is null)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
var row = sheet.Row(1 + i + headerRowsCount);
|
|
|
|
|
|
|
|
|
|
SetCell(row, columnRowNumber, $"{1 + i}");
|
|
|
|
|
SetCell(row, columnCaption, $"{operation.CategoryName} {operation.CategoryInfo}".Trim());
|
2022-03-18 16:54:40 +05:00
|
|
|
|
|
|
|
|
|
SetCell(row, columnWellDepthStartPlan, tvdItem.Plan?.DepthStart);
|
|
|
|
|
SetCell(row, columnWellDepthStartFact, tvdItem.Fact?.DepthStart);
|
|
|
|
|
SetCell(row, columnWellDepthStartPredict, tvdItem.Predict?.DepthStart);
|
|
|
|
|
|
|
|
|
|
SetCell(row, columnWellDepthEndPlan, tvdItem.Plan?.DepthEnd);
|
|
|
|
|
SetCell(row, columnWellDepthEndFact, tvdItem.Fact?.DepthEnd);
|
|
|
|
|
SetCell(row, columnWellDepthEndPredict, tvdItem.Predict?.DepthEnd);
|
2022-03-17 16:56:13 +05:00
|
|
|
|
|
|
|
|
|
SetCell(row, columnDeltaWellDepthPerDay, null);
|
|
|
|
|
if (tvdItem.Fact is not null)
|
|
|
|
|
{
|
2022-03-18 16:54:40 +05:00
|
|
|
|
var fact = tvdItem.Fact;
|
|
|
|
|
if (lastFactDate == default)
|
|
|
|
|
lastFactDate = fact.DateStart;
|
2022-03-17 16:56:13 +05:00
|
|
|
|
|
2022-03-18 16:54:40 +05:00
|
|
|
|
if (i > 0 && fact.DateStart.DayOfYear != lastFactDate.DayOfYear)
|
2022-03-17 16:56:13 +05:00
|
|
|
|
{
|
2022-03-18 16:54:40 +05:00
|
|
|
|
var daylyOperations = facts
|
|
|
|
|
.Where(t => t.DateStart >= lastFactDate && t.DateStart < fact.DateStart);
|
|
|
|
|
if (daylyOperations.Any())
|
|
|
|
|
{
|
|
|
|
|
var depthDayStart = daylyOperations.Min(o => o.DepthStart);
|
|
|
|
|
var depthDayEnd = daylyOperations.Max(o => o.DepthEnd);
|
|
|
|
|
var delta = depthDayEnd - depthDayStart;
|
|
|
|
|
SetCell(sheet.Row(1 + lastFactI + headerRowsCount), columnDeltaWellDepthPerDay, delta);
|
|
|
|
|
lastFactDate = fact.DateStart;
|
|
|
|
|
}
|
2022-03-17 16:56:13 +05:00
|
|
|
|
}
|
2022-03-18 16:54:40 +05:00
|
|
|
|
lastFactI = i;
|
2022-03-17 16:56:13 +05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetCell(row, columnDurationPlan, tvdItem.Plan?.DurationHours);
|
|
|
|
|
SetCell(row, columnDurationFact, tvdItem.Fact?.DurationHours);
|
|
|
|
|
SetCell(row, columnDurationPredict, tvdItem.Predict?.DurationHours);
|
|
|
|
|
|
2022-03-18 16:54:40 +05:00
|
|
|
|
SetCell(row, columnDateStartPlan, tvdItem.Plan?.DateStart);
|
|
|
|
|
SetCell(row, columnDateStartFact, tvdItem.Fact?.DateStart);
|
|
|
|
|
SetCell(row, columnDateStartPredict, tvdItem.Predict?.DateStart);
|
|
|
|
|
|
2022-03-17 16:56:13 +05:00
|
|
|
|
SetCell(row, columnDateEndPlan, tvdItem.Plan?.DateStart.AddHours(tvdItem.Plan?.DurationHours ?? 0));
|
|
|
|
|
SetCell(row, columnDateEndFact, tvdItem.Fact?.DateStart.AddHours(tvdItem.Fact?.DurationHours ?? 0));
|
|
|
|
|
SetCell(row, columnDateEndPredict, tvdItem.Predict?.DateStart.AddHours(tvdItem.Predict?.DurationHours ?? 0));
|
|
|
|
|
|
|
|
|
|
if (tvdItem.Fact?.IdCategory == WellOperationService.idOperationNonProductiveTime)
|
|
|
|
|
{
|
|
|
|
|
SetCell(row, columnGuilty, tvdItem.Fact.Comment);
|
|
|
|
|
SetCell(row, columnNpt, tvdItem.Fact.DurationHours);
|
|
|
|
|
row.Row(columnRowNumber, columnNpt).Style.Fill.BackgroundColor = XLColor.Red;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SetCell(row, columnGuilty, null);
|
|
|
|
|
SetCell(row, columnNpt, null);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var rowNumSummary = 1 + i + headerRowsCount;
|
|
|
|
|
var rowNumStart = 1 + headerRowsCount;
|
|
|
|
|
var rowNumEnd = i + headerRowsCount;
|
|
|
|
|
|
|
|
|
|
string MakeRangeFunction(string funcName, int column)
|
|
|
|
|
=> $"={funcName}({GetColunmLetter(column)}{rowNumStart}:{GetColunmLetter(column)}{rowNumEnd})";
|
|
|
|
|
|
|
|
|
|
IXLCell AddRangeFormula(IXLRow row, string funcName, int column)
|
|
|
|
|
{
|
|
|
|
|
var cell = row.Cell(column);
|
|
|
|
|
cell.FormulaA1 = MakeRangeFunction(funcName, column);
|
|
|
|
|
return cell;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var rowSummary = sheet.Row(rowNumSummary);
|
|
|
|
|
rowSummary.Style.Font.Bold = true;
|
|
|
|
|
rowSummary.Cell(columnCaption).Value = "Итого:";
|
2022-04-11 18:00:34 +05:00
|
|
|
|
|
2022-03-17 16:56:13 +05:00
|
|
|
|
AddRangeFormula(rowSummary, "sum", columnDeltaWellDepthPerDay);
|
|
|
|
|
AddRangeFormula(rowSummary, "sum", columnDurationPlan);
|
|
|
|
|
AddRangeFormula(rowSummary, "sum", columnDurationFact);
|
|
|
|
|
var cell = AddRangeFormula(rowSummary, "max", columnDateEndPlan);
|
|
|
|
|
SetDateTime(cell);
|
|
|
|
|
cell = AddRangeFormula(rowSummary, "max", columnDateEndFact);
|
|
|
|
|
SetDateTime(cell);
|
|
|
|
|
AddRangeFormula(rowSummary, "sum", columnNpt);
|
|
|
|
|
SetBorder(rowSummary.Cells(true).Style);
|
|
|
|
|
|
|
|
|
|
var rowSummary2 = sheet.Row(rowNumSummary + 1);
|
|
|
|
|
rowSummary2.DataType = XLDataType.Number;
|
|
|
|
|
rowSummary2.Style.NumberFormat.Format = "0,00";
|
|
|
|
|
rowSummary2.Cell(columnCaption).Value = "в сутках:";
|
|
|
|
|
rowSummary2.Cell(columnDurationPlan).FormulaA1 = $"={GetColunmLetter(columnDurationPlan)}{rowNumSummary}/24";
|
|
|
|
|
SetNumber(rowSummary2.Cell(columnDurationPlan));
|
|
|
|
|
rowSummary2.Cell(columnDurationFact).FormulaA1 = $"={GetColunmLetter(columnDurationFact)}{rowNumSummary}/24";
|
|
|
|
|
SetNumber(rowSummary2.Cell(columnDurationFact));
|
|
|
|
|
rowSummary2.Cell(columnNpt).FormulaA1 = $"={GetColunmLetter(columnNpt)}{rowNumSummary}/24";
|
|
|
|
|
SetNumber(rowSummary2.Cell(columnNpt));
|
2022-04-11 18:00:34 +05:00
|
|
|
|
SetBorder(rowSummary2.Cells(true).Style);
|
2022-03-17 16:56:13 +05:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-18 16:54:40 +05:00
|
|
|
|
private static void FillTvdSheetToWorkbook(XLWorkbook workbook, IEnumerable<PlanFactPredictBase<WellOperationDto>> tvd, WellDto well)
|
2022-03-17 16:56:13 +05:00
|
|
|
|
{
|
|
|
|
|
var sheet = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetNameTvd);
|
|
|
|
|
if (sheet is null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const int rowTitle = 2;
|
|
|
|
|
const int rowSubtitle = 3;
|
|
|
|
|
const int colTitle = 5;
|
2022-04-11 18:00:34 +05:00
|
|
|
|
|
2022-03-17 16:56:13 +05:00
|
|
|
|
const int rowTopStatTitle = 2;
|
|
|
|
|
const int colTopStatvalue = 10;
|
|
|
|
|
|
|
|
|
|
const int colBottomStatvalue = 3;
|
|
|
|
|
const int rowStartDateFact = 43;
|
|
|
|
|
const int rowEndDatePlan = 44;
|
|
|
|
|
const int rowEndDateFact = 45;
|
|
|
|
|
|
|
|
|
|
sheet.Row(rowSubtitle).Cell(colTitle).Value
|
|
|
|
|
= $"скважины №{well.Caption}, куст: {well.Cluster}, м/р: {well.Deposit}";
|
|
|
|
|
|
|
|
|
|
SetCell(sheet.Row(rowTitle), colTopStatvalue, DateTime.Now);
|
|
|
|
|
|
|
|
|
|
var Plan = tvd.Where(t => t.Plan is not null)
|
|
|
|
|
.Select(t => t.Plan);
|
|
|
|
|
var Fact = tvd.Where(t => t.Fact is not null)
|
|
|
|
|
.Select(t => t.Fact);
|
|
|
|
|
var Predict = tvd.Where(t => t.Predict is not null)
|
|
|
|
|
.Select(t => t.Predict);
|
|
|
|
|
|
|
|
|
|
var startDateFact = Fact.FirstOrDefault()?.DateStart;
|
|
|
|
|
var planLast = Plan.LastOrDefault();
|
|
|
|
|
var factLast = Fact.LastOrDefault();
|
|
|
|
|
var predictLast = Predict.LastOrDefault();
|
|
|
|
|
|
2022-03-18 16:54:40 +05:00
|
|
|
|
static DateTime GetEndDate(WellOperationDto operation)
|
2022-03-17 16:56:13 +05:00
|
|
|
|
=> operation is not null
|
|
|
|
|
? operation.DateStart.AddHours(operation.DurationHours)
|
|
|
|
|
: default;
|
|
|
|
|
|
|
|
|
|
var endDatePlan = GetEndDate(planLast);
|
|
|
|
|
var endDateFact = GetEndDate(factLast);
|
|
|
|
|
var endDatePredict = GetEndDate(predictLast);
|
|
|
|
|
|
|
|
|
|
var endDate = endDatePredict > endDateFact
|
|
|
|
|
? endDatePredict
|
|
|
|
|
: endDateFact;
|
2022-04-11 18:00:34 +05:00
|
|
|
|
|
|
|
|
|
if (startDateFact is not null)
|
2022-03-17 16:56:13 +05:00
|
|
|
|
{
|
|
|
|
|
SetCell(sheet.Row(rowStartDateFact), colBottomStatvalue, startDateFact);
|
|
|
|
|
SetCell(sheet.Row(rowEndDatePlan), colBottomStatvalue, endDatePlan);
|
|
|
|
|
SetCell(sheet.Row(rowEndDateFact), colBottomStatvalue, endDate);
|
2022-04-11 18:00:34 +05:00
|
|
|
|
if (endDate != default)
|
2022-03-17 16:56:13 +05:00
|
|
|
|
{
|
|
|
|
|
var deltaEndDate = (endDatePlan - endDate).TotalDays;
|
|
|
|
|
SetCell(sheet.Row(rowTopStatTitle + 1), colTopStatvalue, Math.Abs(deltaEndDate));
|
2022-04-11 18:00:34 +05:00
|
|
|
|
if (deltaEndDate >= 0)
|
2022-03-17 16:56:13 +05:00
|
|
|
|
SetCell(sheet.Row(rowTopStatTitle + 1), colTopStatvalue - 1, "+")
|
|
|
|
|
.Style.Font.SetFontColor(XLColor.Green);
|
|
|
|
|
else
|
2022-03-18 16:54:40 +05:00
|
|
|
|
SetCell(sheet.Row(rowTopStatTitle + 1), colTopStatvalue - 1, "—")
|
2022-03-17 16:56:13 +05:00
|
|
|
|
.Style.Font.SetFontColor(XLColor.Red);
|
|
|
|
|
}
|
2022-04-11 18:00:34 +05:00
|
|
|
|
}
|
2022-03-17 16:56:13 +05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static string GetColunmLetter(int columnNumber)
|
|
|
|
|
{
|
|
|
|
|
string letter = "";
|
|
|
|
|
|
|
|
|
|
while (columnNumber > 0)
|
|
|
|
|
{
|
|
|
|
|
int modulo = (columnNumber - 1) % 26;
|
|
|
|
|
letter = Convert.ToChar('A' + modulo) + letter;
|
|
|
|
|
columnNumber = (columnNumber - modulo) / 26;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return letter;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static IXLStyle SetBorder(IXLStyle style)
|
|
|
|
|
{
|
|
|
|
|
style.Border.RightBorder = XLBorderStyleValues.Thin;
|
|
|
|
|
style.Border.LeftBorder = XLBorderStyleValues.Thin;
|
|
|
|
|
style.Border.TopBorder = XLBorderStyleValues.Thin;
|
|
|
|
|
style.Border.BottomBorder = XLBorderStyleValues.Thin;
|
|
|
|
|
style.Border.InsideBorder = XLBorderStyleValues.Thin;
|
|
|
|
|
return style;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static IXLCell SetDateTime(IXLCell cell)
|
|
|
|
|
{
|
|
|
|
|
cell.DataType = XLDataType.DateTime;
|
|
|
|
|
cell.Style.DateFormat.Format = "DD.MM.YYYY HH:MM:SS";
|
|
|
|
|
return cell;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static IXLCell SetNumber(IXLCell cell)
|
|
|
|
|
{
|
|
|
|
|
cell.DataType = XLDataType.Number;
|
|
|
|
|
cell.Style.NumberFormat.Format = "0.00";
|
|
|
|
|
return cell;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static IXLCell SetCell(IXLRow row, int colunm, object value)
|
|
|
|
|
{
|
|
|
|
|
var cell = row.Cell(colunm);
|
|
|
|
|
cell.Value = value;
|
2022-04-11 18:00:34 +05:00
|
|
|
|
|
2022-03-17 16:56:13 +05:00
|
|
|
|
SetBorder(cell.Style);
|
|
|
|
|
cell.Style.Alignment.WrapText = true;
|
|
|
|
|
|
|
|
|
|
if (value is string valueString && valueString.Length > maxChartsToWrap)
|
|
|
|
|
{
|
|
|
|
|
var baseHeight = row.Height;
|
2022-03-18 16:54:40 +05:00
|
|
|
|
row.Height = 0.82d * baseHeight * Math.Ceiling(1d + valueString.Length / maxChartsToWrap);
|
2022-03-17 16:56:13 +05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (value is DateTime)
|
|
|
|
|
{
|
|
|
|
|
SetDateTime(cell);
|
|
|
|
|
}
|
|
|
|
|
else if (value is IFormattable)
|
|
|
|
|
{
|
|
|
|
|
SetNumber(cell);
|
|
|
|
|
}
|
2022-04-11 18:00:34 +05:00
|
|
|
|
|
2022-03-17 16:56:13 +05:00
|
|
|
|
return cell;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static Stream GetExcelTemplateStream()
|
|
|
|
|
{
|
|
|
|
|
var stream = System.Reflection.Assembly.GetExecutingAssembly()
|
|
|
|
|
.GetManifestResourceStream("AsbCloudInfrastructure.Services.WellOperationService.ScheduleReportTemplate.xlsx");
|
|
|
|
|
return stream;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|