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> 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 dtos = new List(entities.Length); foreach (var entity in entities) { var dto = await Convert(entity, factOperationsForDtos, token); dtos.Add(dto); } return dtos; } /// /// Получение фактических операций для суточного рапорта /// /// /// /// private async Task> GetFactOperationsForDailyReportAsync(int idWell, CancellationToken token) { var request = new WellOperationRequest() { IdWell = idWell, OperationType = WellOperation.IdOperationTypeFact, }; var factOperations = await wellOperationRepository.GetAsync(request, token); return factOperations; } /// /// Заполнение DTO-модели данными о пользователях /// /// /// /// private async Task 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); block.UserName = user is not null ? user.MakeDisplayName() : $"userId:{block.IdUser.Value}"; } } return dto; } public async Task AddAsync(int idWell, DateTime startDate, int idUser, CancellationToken token = default) { 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 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(); if (dto is BhaDto bhaDto) entity.Info.Bha = bhaDto.Adapt(); if (dto is NoDrillingDto noDrillingDto) entity.Info.NoDrilling = noDrillingDto.Adapt(); if (dto is SaubDto saubDto) entity.Info.Saub = saubDto.Adapt(); if (dto is SignDto signDto) entity.Info.Sign = signDto.Adapt(); db.DailyReports.Update(entity); var result = await db.SaveChangesAsync(token); return result; } public async Task MakeReportAsync(int idWell, DateTime date, CancellationToken token = default) { var dailyReportDto = await GetOrDefaultAsync(idWell, date, token); if (dailyReportDto is null) return null; var memoryStream = dailyReportMaker.MakeReportFromBlocks(dailyReportDto); return memoryStream; } private async Task 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 dto = await Convert(entity, factOperationsForDtos, token); return dto; } /// /// конвертация данных из модели базы данных в dto /// /// модель базы данных /// список фактичских операций для формирования суточного рапорта /// /// private async Task Convert( AsbCloudDb.Model.DailyReport.DailyReport entity, IEnumerable factOperationsForDtos, CancellationToken token) { var dto = entity.Info.Adapt(); dto.StartDate = entity.StartDate; dto.TimeBalance.OperationsStat = (factOperationsForDtos .Where(o => DateOnly.FromDateTime(o.DateStart) == dto.StartDate) .GroupBy(o => o.IdCategory) .Select(g => new OperationStatDto() { Depth = g.Sum(o => o.DepthEnd - o.DepthStart) })); await SetUserNamesToDailyReportDtoAsync(dto, token); return dto; } /// /// Приведение данных к формату DateOnly с учетом часового пояса скважины /// /// /// /// 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; } /// /// Создание блока "Заголовок" по умолчанию /// /// /// /// /// 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 }