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

266 lines
11 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 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 AsbCloudDb.Model.DefaultData;
using Mapster;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services.DailyReport
{
#nullable enable
public class DailyReportService : IDailyReportService
{
private readonly IAsbCloudDbContext db;
private readonly IUserRepository userRepository;
private readonly IWellOperationRepository wellOperationRepository;
private readonly IWellService wellService;
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;
}
public async Task<IEnumerable<DailyReportDto>> GetListAsync(int idWell, DateTime? begin, DateTime? end, CancellationToken token)
{
var well = wellService.GetOrDefault(idWell);
if (well is null || well.Timezone is null)
throw new ArgumentInvalidException("idWell doesn`t exist", nameof(idWell));
var query = db.DailyReports.Where(r => r.IdWell == idWell);
if (begin is not null)
{
var beginDateOnly = ExtractDate(begin.Value, well);
query = query.Where(d => d.StartDate >= beginDateOnly);
}
if (end is not null)
{
var endDateOnly = ExtractDate(end.Value, well);
query = query.Where(d => d.StartDate <= endDateOnly);
}
var entities = await query.OrderByDescending(e => e.StartDate)
.AsNoTracking()
.ToArrayAsync(token)
.ConfigureAwait(false);
var factOperationsForDtos = await GetFactOperationsForDailyReportAsync(idWell, token);
var userDtos = await userRepository.GetAllAsync(token);
var dtos = entities.Select(entity => Convert(entity, factOperationsForDtos, userDtos));
return dtos;
}
/// <summary>
/// Получение фактических операций для суточного рапорта
/// </summary>
/// <param name="idWell"></param>
/// <param name="token"></param>
/// <returns></returns>
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;
}
public async Task<int> AddAsync(int idWell, DateTime startDate, int idUser, CancellationToken token)
{
var well = wellService.GetOrDefault(idWell);
if (well is null)
throw new ArgumentInvalidException("idWell doesn`t exist", nameof(idWell));
var startDateOnly = ExtractDate(startDate, well);
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));
var entity = new AsbCloudDb.Model.DailyReport.DailyReport
{
IdWell = idWell,
StartDate = startDateOnly,
Info = new DailyReportInfo()
{
Head = CreateHeadDailyReportBlock(well, startDate, idUser)
}
};
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)
{
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)
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;
}
public async Task<Stream?> MakeReportAsync(int idWell, DateTime date, CancellationToken token)
{
var stageIds = EntityFillerWellOperationCategory.WorkStages.Select(w => w.Id).ToArray();
var wellOperationCategories = wellOperationRepository.GetCategories(true)
.Where(o => o.IdParent is not null)
.Where(o => stageIds.Contains(o.IdParent!.Value));
var dailyReportDto = await GetOrDefaultAsync(idWell, date, token);
if (dailyReportDto is null)
return null;
var memoryStream = dailyReportMaker.MakeReportFromBlocks(dailyReportDto, wellOperationCategories);
return memoryStream;
}
private async Task<DailyReportDto?> GetOrDefaultAsync(int idWell, DateTime date, CancellationToken token)
{
var dateOffset = date.Date;
var entity = await db.DailyReports
.FirstOrDefaultAsync(r => r.IdWell == idWell &&
r.StartDate.Year == dateOffset.Year &&
r.StartDate.DayOfYear == dateOffset.DayOfYear
, token);
if (entity is null)
throw new ArgumentInvalidException("Daily report doesn`t exist", nameof(date));
var factOperationsForDtos = await GetFactOperationsForDailyReportAsync(idWell, token);
var userDtos = await userRepository.GetAllAsync(token);
var dto = Convert(entity, factOperationsForDtos, userDtos);
return dto;
}
/// <summary>
/// конвертация данных из модели базы данных в dto
/// </summary>
/// <param name="entity">модель базы данных</param>
/// <param name="factOperationsForDtos">список фактичских операций для формирования суточного рапорта</param>
/// <param name="users">список пользователей для нахождения последнего изменившего запись</param>
/// <returns></returns>
private DailyReportDto Convert(
AsbCloudDb.Model.DailyReport.DailyReport entity,
IEnumerable<WellOperationDto> factOperationsForDtos,
IEnumerable<UserExtendedDto> users)
{
var dto = entity.Info.Adapt<DailyReportDto>();
dto.StartDate = entity.StartDate;
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;
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 = users.FirstOrDefault(u => u.Id == block.IdUser.Value);
block.UserName = user is not null ? user.MakeDisplayName() : $"userId:{block.IdUser.Value}";
}
}
return dto;
}
/// <summary>
/// Приведение данных к формату DateOnly с учетом часового пояса скважины
/// </summary>
/// <param name="dateTime"></param>
/// <param name="well"></param>
/// <returns></returns>
private DateOnly ExtractDate(DateTime dateTime, WellDto well)
{
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,
};
}
}
#nullable disable
}