forked from ddrilling/AsbCloudServer
266 lines
11 KiB
C#
266 lines
11 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 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
|
||
}
|