DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/DailyReport/DailyReportService.cs

278 lines
11 KiB
C#
Raw Normal View History

using AsbCloudApp.Data;
using AsbCloudApp.Data.DailyReport;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudDb.Model.DailyReport;
using Mapster;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
2022-05-05 10:06:15 +05:00
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services.DailyReport
{
2022-05-05 10:06:15 +05:00
#nullable enable
public class DailyReportService : IDailyReportService
{
private readonly IAsbCloudDbContext db;
private readonly IUserRepository userRepository;
private readonly IWellOperationRepository wellOperationRepository;
private readonly IWellService wellService;
2022-05-05 10:06:15 +05:00
private readonly DailyReportMakerExcel dailyReportMaker = new DailyReportMakerExcel();
public DailyReportService(
IAsbCloudDbContext db,
IWellService wellService,
IUserRepository userRepository,
IWellOperationRepository wellOperationRepository)
{
this.db = db;
this.wellService = wellService;
this.userRepository = userRepository;
this.wellOperationRepository = wellOperationRepository;
}
2022-05-05 10:06:15 +05:00
public async Task<IEnumerable<DailyReportDto>> GetListAsync(int idWell, DateTime? begin, DateTime? end, CancellationToken token)
2022-06-15 14:57:37 +05:00
{
var well = wellService.GetOrDefault(idWell);
if (well is null || well.Timezone is null)
throw new ArgumentInvalidException("idWell doesn`t exist", nameof(idWell));
2022-05-05 10:06:15 +05:00
var query = db.DailyReports.Where(r => r.IdWell == idWell);
if (begin is not null)
{
2023-03-24 10:27:30 +05:00
var beginDateOnly = ExtractDate(begin.Value, well);
query = query.Where(d => d.StartDate >= beginDateOnly);
}
2022-05-05 10:06:15 +05:00
if (end is not null)
{
2023-03-24 10:27:30 +05:00
var endDateOnly = ExtractDate(end.Value, well);
query = query.Where(d => d.StartDate <= endDateOnly);
}
2022-06-15 14:57:37 +05:00
2023-03-24 10:27:30 +05:00
var entities = await query.OrderByDescending(e => e.StartDate)
.AsNoTracking()
.ToArrayAsync(token)
.ConfigureAwait(false);
2023-03-24 10:27:30 +05:00
var factOperationsForDtos = await GetFactOperationsForDailyReportAsync(idWell, token);
2023-03-24 10:27:30 +05:00
var dtos = new List<DailyReportDto>(entities.Length);
foreach (var entity in entities)
{
2023-03-24 10:27:30 +05:00
var dto = await Convert(entity, factOperationsForDtos, token);
dtos.Add(dto);
}
return dtos;
}
/// <summary>
2023-03-24 10:27:30 +05:00
/// Получение фактических операций для суточного рапорта
/// </summary>
/// <param name="idWell"></param>
/// <param name="token"></param>
/// <returns></returns>
2023-03-24 10:27:30 +05:00
private async Task<IEnumerable<WellOperationDto>> GetFactOperationsForDailyReportAsync(int idWell, CancellationToken token)
{
var request = new WellOperationRequest()
{
IdWell = idWell,
OperationType = WellOperation.IdOperationTypeFact,
};
var factOperations = await wellOperationRepository.GetAsync(request, token);
return factOperations;
}
/// <summary>
/// Заполнение DTO-модели данными о пользователях
/// </summary>
/// <param name="dto"></param>
/// <param name="token"></param>
/// <returns></returns>
private async Task<DailyReportDto> SetUserNamesToDailyReportDtoAsync(DailyReportDto dto, CancellationToken token)
{
var blocks = new ItemInfoDto[] {
dto.Head,
dto.Bha,
dto.NoDrilling,
dto.TimeBalance,
dto.Saub,
dto.Sign
};
foreach (var block in blocks)
{
if (block.IdUser is not null)
{
var user = await userRepository.GetOrDefaultAsync(block.IdUser.Value, token);
2023-03-24 10:27:30 +05:00
block.UserName = user is not null ? user.MakeDisplayName() : $"userId:{block.IdUser.Value}";
}
}
return dto;
}
public async Task<int> AddAsync(int idWell, DateTime startDate, int idUser, CancellationToken token = default)
{
var well = wellService.GetOrDefault(idWell);
2023-03-24 10:27:30 +05:00
if (well is null)
throw new ArgumentInvalidException("idWell doesn`t exist", nameof(idWell));
2023-03-24 10:27:30 +05:00
var startDateOnly = ExtractDate(startDate, well);
2023-03-24 10:27:30 +05:00
var hasEntity = await db.DailyReports
.AnyAsync(r => r.IdWell == idWell && r.StartDate == startDateOnly, token);
if (hasEntity)
throw new ArgumentInvalidException($"daily report on {startDateOnly} already exists", nameof(startDateOnly));
2023-03-24 10:27:30 +05:00
var entity = new AsbCloudDb.Model.DailyReport.DailyReport
{
2022-05-05 10:06:15 +05:00
IdWell = idWell,
StartDate = startDateOnly,
Info = new DailyReportInfo()
{
2023-03-24 10:27:30 +05:00
Head = CreateHeadDailyReportBlock(well, startDate, idUser)
}
};
2022-05-05 10:06:15 +05:00
db.DailyReports.Add(entity);
var result = await db.SaveChangesAsync(token);
return result;
}
public async Task<int> UpdateBlockAsync(int idWell, DateTime startDate, ItemInfoDto dto, CancellationToken token)
{
2023-03-24 10:27:30 +05:00
var well = wellService.GetOrDefault(idWell);
if (well is null)
throw new ArgumentInvalidException("idWell doesn`t exist", nameof(idWell));
var startDateOnly = DateOnly.FromDateTime(startDate);
var entity = await db.DailyReports.FirstOrDefaultAsync(r => r.IdWell == idWell && r.StartDate == startDateOnly, token);
if (entity is null)
2023-03-24 10:27:30 +05:00
throw new ArgumentInvalidException("Daily report doesn`t exist", nameof(startDate));
dto.LastUpdateDate = DateTimeOffset.Now;
if (dto is HeadDto headDto)
entity.Info.Head = headDto.Adapt<Head>();
if (dto is BhaDto bhaDto)
entity.Info.Bha = bhaDto.Adapt<Bha>();
if (dto is NoDrillingDto noDrillingDto)
entity.Info.NoDrilling = noDrillingDto.Adapt<NoDrilling>();
if (dto is SaubDto saubDto)
entity.Info.Saub = saubDto.Adapt<Saub>();
if (dto is SignDto signDto)
entity.Info.Sign = signDto.Adapt<Sign>();
db.DailyReports.Update(entity);
var result = await db.SaveChangesAsync(token);
return result;
}
2022-05-05 10:06:15 +05:00
public async Task<Stream?> MakeReportAsync(int idWell, DateTime date, CancellationToken token = default)
{
var wellOperationCategories = wellOperationRepository.GetCategories(true);
var dailyReportDto = await GetOrDefaultAsync(idWell, date, token);
2022-05-05 10:06:15 +05:00
if (dailyReportDto is null)
return null;
var memoryStream = dailyReportMaker.MakeReportFromBlocks(dailyReportDto, wellOperationCategories);
2022-05-05 10:06:15 +05:00
return memoryStream;
}
private async Task<DailyReportDto?> GetOrDefaultAsync(int idWell, DateTime date, CancellationToken token)
2022-05-05 10:06:15 +05:00
{
var dateOffset = date.Date;
2022-05-05 15:14:29 +05:00
var entity = await db.DailyReports
.FirstOrDefaultAsync(r => r.IdWell == idWell &&
r.StartDate.Year == dateOffset.Year &&
r.StartDate.DayOfYear == dateOffset.DayOfYear
, token);
2022-05-05 15:14:29 +05:00
if (entity is null)
2023-03-24 10:27:30 +05:00
throw new ArgumentInvalidException("Daily report doesn`t exist", nameof(date));
var factOperationsForDtos = await GetFactOperationsForDailyReportAsync(idWell, token);
var dto = await Convert(entity, factOperationsForDtos, token);
return dto;
}
2023-03-24 10:27:30 +05:00
/// <summary>
/// конвертация данных из модели базы данных в dto
/// </summary>
/// <param name="entity">модель базы данных</param>
/// <param name="factOperationsForDtos">список фактичских операций для формирования суточного рапорта</param>
/// <param name="token"></param>
/// <returns></returns>
private async Task<DailyReportDto> Convert(
AsbCloudDb.Model.DailyReport.DailyReport entity,
IEnumerable<WellOperationDto> factOperationsForDtos,
CancellationToken token)
{
var dto = entity.Info.Adapt<DailyReportDto>();
dto.StartDate = entity.StartDate;
2023-03-24 10:27:30 +05:00
var dailyFactOperation = factOperationsForDtos
.Where(o => DateOnly.FromDateTime(o.DateStart) == dto.StartDate)
.Where(o => o.IdParentCategory is not null)
.GroupBy(o => o.IdParentCategory!.Value)
.ToDictionary(g => g.Key, g => g.Sum(o => o.DurationHours));
dto.TimeBalance.OperationsStat = dailyFactOperation;
2023-03-24 10:27:30 +05:00
await SetUserNamesToDailyReportDtoAsync(dto, token);
2023-03-24 10:27:30 +05:00
2022-05-05 10:06:15 +05:00
return dto;
}
2023-03-24 10:27:30 +05:00
/// <summary>
/// Приведение данных к формату DateOnly с учетом часового пояса скважины
/// </summary>
/// <param name="dateTime"></param>
/// <param name="well"></param>
/// <returns></returns>
private DateOnly ExtractDate(DateTime dateTime, WellDto well)
{
2023-03-24 10:27:30 +05:00
var dateTimeOffset = dateTime.ToUtcDateTimeOffset(well!.Timezone.Hours);
var date = new DateOnly(dateTimeOffset.Year, dateTimeOffset.Month, dateTimeOffset.Day);
return date;
}
/// <summary>
/// Создание блока "Заголовок" по умолчанию
/// </summary>
/// <param name="well"></param>
/// <param name="startDate"></param>
/// <param name="idUser"></param>
/// <returns></returns>
private Head CreateHeadDailyReportBlock(WellDto well, DateTime startDate, int idUser)
{
var customer = well.Companies.FirstOrDefault(company => company.IdCompanyType == 1);
var contractor = well.Companies.FirstOrDefault(company => company.IdCompanyType == 2);
return new Head()
{
ReportDate = startDate.Date,
WellName = well.Caption,
ClusterName = well?.Cluster ?? string.Empty,
Customer = customer?.Caption ?? string.Empty,
Contractor = contractor?.Caption ?? string.Empty,
IdUser = idUser,
LastUpdateDate = DateTimeOffset.Now,
};
}
}
2022-05-05 10:06:15 +05:00
#nullable disable
}