forked from ddrilling/AsbCloudServer
- Added request processing service for DailyReportController. Implemented all methods except DownloadAsync.
338 lines
12 KiB
C#
338 lines
12 KiB
C#
using AsbCloudApp.Data;
|
||
using AsbCloudApp.Services;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using System.Threading;
|
||
using System.Threading.Tasks;
|
||
using AsbCloudDb.Model;
|
||
using AsbCloudInfrastructure.Services.Cache;
|
||
using AsbCloudApp.Exceptions;
|
||
using Mapster;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using System.Collections;
|
||
using System.IO;
|
||
using ClosedXML.Excel;
|
||
|
||
namespace AsbCloudInfrastructure.Services
|
||
{
|
||
public class DailyReportService : IDailyReportService
|
||
{
|
||
private readonly IAsbCloudDbContext db;
|
||
private readonly IWellService wellService;
|
||
private readonly IOperationsStatService operationsStatService;
|
||
const string sheetNameSchedule = "Дневной отчёт";
|
||
private static readonly int[,] ParamsCellsIndexes = new int[42, 2] {
|
||
{0,0},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1},
|
||
{1,1}
|
||
};
|
||
|
||
|
||
public DailyReportService(IAsbCloudDbContext db, IWellService wellService)
|
||
{
|
||
this.db = db;
|
||
this.wellService = wellService;
|
||
}
|
||
private DateTimeOffset Convert(DateTime date, int idWell)
|
||
{
|
||
var hours = wellService.GetTimezone(idWell).Hours;
|
||
var dateOffset = DateTimeExtentions.ToUtcDateTimeOffset((DateTime)date, hours);
|
||
return dateOffset;
|
||
}
|
||
|
||
private DailyReportDto Convert(DailyReport data, int idWell)
|
||
{
|
||
var hours = wellService.GetTimezone(idWell).Hours;
|
||
var dto = data.Adapt<DailyReportDto>();
|
||
dto.ReportDate = data.StartDate.ToRemoteDateTime(hours);
|
||
return dto;
|
||
}
|
||
private static Stream GetExcelTemplateStream()
|
||
{
|
||
var assembly = System.Reflection.Assembly.GetAssembly(typeof(AsbCloudInfrastructure.IInfrastructureMarker));
|
||
var stream = assembly.GetManifestResourceStream("AsbCloudInfrastructure.Services.DailyReport.DailyReportTemplate.xlsx");
|
||
return stream;
|
||
}
|
||
|
||
public async Task<IEnumerable<DailyReportDto>> GetListAsync(int idWell, DateTime? begin, DateTime? end, CancellationToken token)
|
||
{
|
||
var hours = wellService.GetTimezone(idWell).Hours;
|
||
var query = db.DailyReport.Where(r => r.IdWell == idWell);
|
||
|
||
if (begin is not null)
|
||
query = query.Where(d => d.StartDate >= Convert((DateTime)begin, idWell));
|
||
|
||
if (end is not null)
|
||
query = query.Where(d => d.StartDate <= Convert((DateTime)end, idWell));
|
||
|
||
var data = await query.ToListAsync(token);
|
||
return data.Select(d=>Convert(d, idWell));
|
||
}
|
||
|
||
public IEnumerable<DailyReportDto> GetDefaultDailyReportDto()
|
||
{
|
||
var dto = new DailyReportDto()
|
||
{
|
||
ReportDate = DateTime.Now,
|
||
};
|
||
IEnumerable<DailyReportDto> result = new List<DailyReportDto> { dto };
|
||
return result;
|
||
}
|
||
public async Task<IEnumerable<DailyReportDto>> GetOrGenerateAsync(int idWell, DateTime date, CancellationToken token)
|
||
{
|
||
var query = db.DailyReport.Where(r => r.IdWell == idWell);
|
||
query = query.Where(d => d.StartDate == Convert(date, idWell));
|
||
|
||
var data = await query.ToListAsync(token);
|
||
if (data.Count == 0)
|
||
return GetDefaultDailyReportDto();
|
||
else
|
||
return data.Select(d => Convert(d, idWell));
|
||
}
|
||
public async Task<int> AddAsync(int idWell, DailyReportDto dto, CancellationToken token = default)
|
||
{
|
||
var entity = dto.Adapt<DailyReport>();
|
||
entity.StartDate = Convert(dto.ReportDate, idWell);
|
||
db.DailyReport.Add(entity);
|
||
var result = await db.SaveChangesAsync(token);
|
||
return result;
|
||
}
|
||
public async Task<int> UpdateAsync(int idWell, DateTime date, DailyReportDto dto, CancellationToken token)
|
||
{
|
||
var entity = dto.Adapt<DailyReport>();
|
||
entity.StartDate = Convert(dto.ReportDate, idWell);
|
||
db.DailyReport.Update(entity);
|
||
var result = await db.SaveChangesAsync(token);
|
||
return result;
|
||
}
|
||
|
||
public async Task<Stream> MakeReportAsync(int idWell, DateTime date, CancellationToken token = default)
|
||
{
|
||
var tvd = await operationsStatService.GetTvdAsync(idWell, token);
|
||
|
||
if (!tvd.Any())
|
||
return null;
|
||
|
||
var well = await wellService.GetAsync(idWell, token);
|
||
|
||
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;
|
||
}
|
||
|
||
private static void FillScheduleSheetToWorkbook(XLWorkbook workbook, IEnumerable<PlanFactPredictBase<WellOperationDto>> tvd, WellDto well)
|
||
{
|
||
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;
|
||
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;
|
||
|
||
var subTitle = $"на строительство скважины №{well.Caption}, куст: {well.Cluster}, м/р: {well.Deposit}";
|
||
sheet.Row(rowTitle).Cell(3).Value = subTitle;
|
||
|
||
var tvdList = tvd.ToList();
|
||
|
||
}
|
||
|
||
private static void FillTvdSheetToWorkbook(XLWorkbook workbook, IEnumerable<PlanFactPredictBase<WellOperationDto>> tvd, WellDto well)
|
||
{
|
||
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;
|
||
|
||
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();
|
||
|
||
static DateTime GetEndDate(WellOperationDto operation)
|
||
=> 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;
|
||
|
||
if (startDateFact is not null)
|
||
{
|
||
SetCell(sheet.Row(rowStartDateFact), colBottomStatvalue, startDateFact);
|
||
SetCell(sheet.Row(rowEndDatePlan), colBottomStatvalue, endDatePlan);
|
||
SetCell(sheet.Row(rowEndDateFact), colBottomStatvalue, endDate);
|
||
if (endDate != default)
|
||
{
|
||
var deltaEndDate = (endDatePlan - endDate).TotalDays;
|
||
SetCell(sheet.Row(rowTopStatTitle + 1), colTopStatvalue, Math.Abs(deltaEndDate));
|
||
if (deltaEndDate >= 0)
|
||
SetCell(sheet.Row(rowTopStatTitle + 1), colTopStatvalue - 1, "+")
|
||
.Style.Font.SetFontColor(XLColor.Green);
|
||
else
|
||
SetCell(sheet.Row(rowTopStatTitle + 1), colTopStatvalue - 1, "—")
|
||
.Style.Font.SetFontColor(XLColor.Red);
|
||
}
|
||
}
|
||
}
|
||
|
||
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;
|
||
|
||
SetBorder(cell.Style);
|
||
cell.Style.Alignment.WrapText = true;
|
||
|
||
if (value is string valueString && valueString.Length > maxChartsToWrap)
|
||
{
|
||
var baseHeight = row.Height;
|
||
row.Height = 0.82d * baseHeight * Math.Ceiling(1d + valueString.Length / maxChartsToWrap);
|
||
}
|
||
|
||
if (value is DateTime)
|
||
{
|
||
SetDateTime(cell);
|
||
}
|
||
else if (value is IFormattable)
|
||
{
|
||
SetNumber(cell);
|
||
}
|
||
|
||
return cell;
|
||
}
|
||
}
|
||
}
|