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

249 lines
10 KiB
C#

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;
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, DateOnly? begin, DateOnly? 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)
{
query = query.Where(d => d.StartDate >= begin);
}
if (end is not null)
{
query = query.Where(d => d.StartDate <= end);
}
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, DateOnly startDate, int idUser, CancellationToken token)
{
var well = wellService.GetOrDefault(idWell);
if (well is null)
throw new ArgumentInvalidException("idWell doesn`t exist", nameof(idWell));
var hasEntity = await db.DailyReports
.AnyAsync(r => r.IdWell == idWell && r.StartDate == startDate, token);
if (hasEntity)
throw new ArgumentInvalidException($"daily report on {startDate} already exists", nameof(startDate));
var entity = new AsbCloudDb.Model.DailyReport.DailyReport
{
IdWell = idWell,
StartDate = startDate,
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, DateOnly startDate, ItemInfoDto dto, CancellationToken token)
{
var well = wellService.GetOrDefault(idWell);
if (well is null)
throw new ArgumentInvalidException("idWell doesn`t exist", nameof(idWell));
var entity = await db.DailyReports.FirstOrDefaultAsync(r => r.IdWell == idWell && r.StartDate == startDate, 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, DateOnly date, CancellationToken token)
{
var stageIds = WellOperationCategory.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, DateOnly date, CancellationToken token)
{
var entity = await db.DailyReports
.FirstOrDefaultAsync(r => r.IdWell == idWell && r.StartDate == date, 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 dailyFactOperations = factOperationsForDtos
.Where(o => DateOnly.FromDateTime(o.DateStart) == dto.StartDate)
.Where(o => o.IdParentCategory is not null);
var lastDailyFactOperation = dailyFactOperations
.OrderByDescending(o => o.LastUpdateDate)
.FirstOrDefault();
dto.TimeBalance.IdUser = lastDailyFactOperation?.IdUser;
dto.TimeBalance.LastUpdateDate = lastDailyFactOperation?.LastUpdateDate;
dto.TimeBalance.OperationsStat = dailyFactOperations
.GroupBy(o => o.IdParentCategory!.Value)
.ToDictionary(g => g.Key, g => g.Sum(o => o.DurationHours));
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)
{
block.UserName = users.FirstOrDefault(u => u.Id == block.IdUser.Value)?.MakeDisplayName()
?? $"userId:{block.IdUser.Value}";
}
}
return dto;
}
/// <summary>
/// Создание блока "Заголовок" по умолчанию
/// </summary>
/// <param name="well"></param>
/// <param name="startDate"></param>
/// <param name="idUser"></param>
/// <returns></returns>
private Head CreateHeadDailyReportBlock(WellDto well, DateOnly 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,
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
}