Merge pull request '#30770058, #30434678 Рефакторинг ГГД, унификация импорта' (#240) from feature/refactoring_well_operation into dev

Reviewed-on: http://test.digitaldrilling.ru:8080/DDrilling/AsbCloudServer/pulls/240
This commit is contained in:
Никита Фролов 2024-04-01 12:17:05 +05:00
commit cccbaa718d
153 changed files with 2419 additions and 3706 deletions

View File

@ -74,7 +74,7 @@ public class DailyReportDto : IId,
/// <summary> /// <summary>
/// Дата последнего обновления /// Дата последнего обновления
/// </summary> /// </summary>
public DateTime? DateLastUpdate { get; set; } public DateTimeOffset? DateLastUpdate { get; set; }
/// <summary> /// <summary>
/// Блок фактической траектории /// Блок фактической траектории

View File

@ -1,4 +1,5 @@
using System; using System;
using AsbCloudApp.Data.WellOperation;
namespace AsbCloudApp.Data namespace AsbCloudApp.Data
{ {

View File

@ -12,12 +12,12 @@ namespace AsbCloudApp.Data
/// Дата начала диапазона /// Дата начала диапазона
/// </summary> /// </summary>
[Required] [Required]
public DateTime From { get; set; } public DateTimeOffset From { get; set; }
/// <summary> /// <summary>
/// Дата окончания диапазона /// Дата окончания диапазона
/// </summary> /// </summary>
[Required] [Required]
public DateTime To { get; set; } public DateTimeOffset To { get; set; }
} }
} }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using AsbCloudApp.Data.WellOperation;
namespace AsbCloudApp.Data.DetectedOperation; namespace AsbCloudApp.Data.DetectedOperation;

View File

@ -21,6 +21,6 @@ namespace AsbCloudApp.Data.DrillTestReport
/// <summary> /// <summary>
/// Дата отчета /// Дата отчета
/// </summary> /// </summary>
public DateTime Date { get; set; } = DateTime.Now; public DateTimeOffset Date { get; set; } = DateTimeOffset.Now;
} }
} }

View File

@ -24,6 +24,6 @@ namespace AsbCloudApp.Data.DrillTestReport
/// Дата и время /// Дата и время
/// </summary> /// </summary>
[Required] [Required]
public DateTime DateTime { get; set; } public DateTimeOffset DateTime { get; set; }
} }
} }

View File

@ -43,7 +43,7 @@ namespace AsbCloudApp.Data
/// дата загрузки /// дата загрузки
/// </summary> /// </summary>
[Required] [Required]
public DateTime UploadDate { get; set; } public DateTimeOffset UploadDate { get; set; }
/// <summary> /// <summary>
/// размер в байтах /// размер в байтах

View File

@ -33,7 +33,7 @@ namespace AsbCloudApp.Data
/// Необязательно указывать в запросе на создание. /// Необязательно указывать в запросе на создание.
/// </summary> /// </summary>
[Required] [Required]
public DateTime DateCreated { get; set; } public DateTimeOffset DateCreated { get; set; }
/// <summary> /// <summary>
/// Полезный комментарий /// Полезный комментарий

View File

@ -20,12 +20,12 @@ namespace AsbCloudApp.Data
/// <summary> /// <summary>
/// Дата начала ограничения /// Дата начала ограничения
/// </summary> /// </summary>
public DateTime DateStart { get; set; } public DateTimeOffset DateStart { get; set; }
/// <summary> /// <summary>
/// Дата окончания ограничения /// Дата окончания ограничения
/// </summary> /// </summary>
public DateTime DateEnd { get; set; } public DateTimeOffset DateEnd { get; set; }
/// <summary> /// <summary>
/// Глубина начала ограничения /// Глубина начала ограничения

View File

@ -18,7 +18,7 @@ public class ManualDto : IId
/// <summary> /// <summary>
/// Дата загрузки /// Дата загрузки
/// </summary> /// </summary>
public DateTime DateDownload { get; set; } public DateTimeOffset DateDownload { get; set; }
/// <summary> /// <summary>
/// Id автора /// Id автора

View File

@ -36,7 +36,7 @@ namespace AsbCloudApp.Data
/// отметка времени замера /// отметка времени замера
/// </summary> /// </summary>
[Required] [Required]
public DateTime Timestamp { get; set; } public DateTimeOffset Timestamp { get; set; }
/// <summary> /// <summary>
/// данные замера /// данные замера

View File

@ -16,7 +16,7 @@ namespace AsbCloudApp.Data
/// дата появления события /// дата появления события
/// </summary> /// </summary>
[Required] [Required]
public DateTime DateTime { get; set; } public DateTimeOffset DateTime { get; set; }
/// <summary> /// <summary>
/// категория события /// категория события

View File

@ -42,17 +42,17 @@ public class NotificationDto : IId
/// Дата регистрации уведомления /// Дата регистрации уведомления
/// </summary> /// </summary>
[Required] [Required]
public DateTime RegistrationDate { get; set; } public DateTimeOffset RegistrationDate { get; set; }
/// <summary> /// <summary>
/// Дата отправки уведомления /// Дата отправки уведомления
/// </summary> /// </summary>
public DateTime? SentDate { get; set; } public DateTimeOffset? SentDate { get; set; }
/// <summary> /// <summary>
/// Дата прочтения уведомления /// Дата прочтения уведомления
/// </summary> /// </summary>
public DateTime? ReadDate { get; set; } public DateTimeOffset? ReadDate { get; set; }
/// <summary> /// <summary>
/// Состояние уведомления /// Состояние уведомления
@ -82,12 +82,12 @@ public class NotificationDto : IId
ReadDate = null; ReadDate = null;
break; break;
case 1: case 1:
SentDate = DateTime.UtcNow; SentDate = DateTimeOffset.UtcNow;
ReadDate = null; ReadDate = null;
break; break;
case 2: case 2:
SentDate = DateTime.UtcNow; SentDate = DateTimeOffset.UtcNow;
ReadDate = DateTime.UtcNow; ReadDate = DateTimeOffset.UtcNow;
break; break;
} }
} }

View File

@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace AsbCloudApp.Data; namespace AsbCloudApp.Data;
@ -9,4 +10,8 @@ namespace AsbCloudApp.Data;
public class ParserResultDto<TDto> : ValidationResultDto<IEnumerable<ValidationResultDto<TDto>>> public class ParserResultDto<TDto> : ValidationResultDto<IEnumerable<ValidationResultDto<TDto>>>
where TDto : class, IId where TDto : class, IId
{ {
/// <summary>
/// Объекты полученные из файла
/// </summary>
public override IEnumerable<ValidationResultDto<TDto>> Item { get; set; } = Enumerable.Empty<ValidationResultDto<TDto>>();
} }

View File

@ -44,7 +44,7 @@ public class ProcessMapReportDataSaubStatDto
/// на начало интервала /// на начало интервала
/// </para> /// </para>
/// </summary> /// </summary>
public DateTime DateStart { get; set; } public DateTimeOffset DateStart { get; set; }
/// <summary> /// <summary>
/// Режим бурения (Ротор/слайд/ручной) /// Режим бурения (Ротор/слайд/ручной)

View File

@ -44,7 +44,7 @@ public class ProcessMapReportWellDrillingDto
/// на начало интервала /// на начало интервала
/// </para> /// </para>
/// </summary> /// </summary>
public DateTime DateStart { get; set; } public DateTimeOffset DateStart { get; set; }
/// <summary> /// <summary>
/// Время мех бурения, ч /// Время мех бурения, ч

View File

@ -29,17 +29,17 @@ namespace AsbCloudApp.Data
/// <summary> /// <summary>
/// Дата формирования /// Дата формирования
/// </summary> /// </summary>
public DateTime Date { get; set; } public DateTimeOffset Date { get; set; }
/// <summary> /// <summary>
/// Дата начала рапорта /// Дата начала рапорта
/// </summary> /// </summary>
public DateTime Begin { get; set; } public DateTimeOffset Begin { get; set; }
/// <summary> /// <summary>
/// Дата окончания рапорта /// Дата окончания рапорта
/// </summary> /// </summary>
public DateTime End { get; set; } public DateTimeOffset End { get; set; }
/// <summary> /// <summary>
/// шаг между точками диаграммы /// шаг между точками диаграммы

View File

@ -33,7 +33,7 @@ namespace AsbCloudApp.Data.SAUB
/// <summary> /// <summary>
/// отметка времени создания запроса /// отметка времени создания запроса
/// </summary> /// </summary>
public DateTime UploadDate { get; set; } = DateTime.Now; public DateTimeOffset UploadDate { get; set; } = DateTimeOffset.Now;
/// <summary> /// <summary>
/// время в секундах актуальности этого запроса /// время в секундах актуальности этого запроса

View File

@ -15,7 +15,7 @@ namespace AsbCloudApp.Data.SAUB
/// <summary> /// <summary>
/// отметка времени /// отметка времени
/// </summary> /// </summary>
public DateTime Date { get; set; } public DateTimeOffset Date { get; set; }
/// <summary> /// <summary>
/// глубина забоя /// глубина забоя

View File

@ -10,7 +10,7 @@ namespace AsbCloudApp.Data.SAUB
/// <summary> /// <summary>
/// отметка времени /// отметка времени
/// </summary> /// </summary>
public DateTime DateTime { get; set; } public DateTimeOffset DateTime { get; set; }
/// <summary> /// <summary>
/// Наработка талевого каната с момента перетяжки каната, т*км /// Наработка талевого каната с момента перетяжки каната, т*км

View File

@ -39,13 +39,13 @@ namespace AsbCloudApp.Data
/// Начало бурения /// Начало бурения
/// </summary> /// </summary>
[Required] [Required]
public DateTime DrillStart { get; set; } public DateTimeOffset DrillStart { get; set; }
/// <summary> /// <summary>
/// Конец бурения /// Конец бурения
/// </summary> /// </summary>
[Required] [Required]
public DateTime DrillEnd { get; set; } public DateTimeOffset DrillEnd { get; set; }
/// <summary> /// <summary>
/// Бурильщик /// Бурильщик

View File

@ -11,12 +11,12 @@ namespace AsbCloudApp.Data
/// <summary> /// <summary>
/// Дата и время начала /// Дата и время начала
/// </summary> /// </summary>
public DateTime? Start { get; set; } public DateTimeOffset? Start { get; set; }
/// <summary> /// <summary>
/// Дата и время окончания /// Дата и время окончания
/// </summary> /// </summary>
public DateTime? End { get; set; } public DateTimeOffset? End { get; set; }
/// <summary> /// <summary>
/// Глубина, м /// Глубина, м

View File

@ -42,7 +42,7 @@ namespace AsbCloudApp.Data
/// дата прихода последней телеметрии /// дата прихода последней телеметрии
/// </summary> /// </summary>
[Required] [Required]
public DateTime LastTelemetryDate { get; set; } public DateTimeOffset LastTelemetryDate { get; set; }
/// <summary> /// <summary>
/// Статистика по секциям /// Статистика по секциям

View File

@ -46,7 +46,7 @@ namespace AsbCloudApp.Data.Trajectory
/// <summary> /// <summary>
/// Дата загрузки /// Дата загрузки
/// </summary> /// </summary>
public DateTime UpdateDate { get; set; } public DateTimeOffset UpdateDate { get; set; }
/// <summary> /// <summary>
/// ИД пользователя /// ИД пользователя

View File

@ -18,7 +18,7 @@ public class ValidationResultDto<T>
/// <summary> /// <summary>
/// Объект валидации /// Объект валидации
/// </summary> /// </summary>
public T Item { get; set; } = null!; public virtual T Item { get; set; } = null!;
/// <summary> /// <summary>
/// Предупреждения /// Предупреждения

View File

@ -67,12 +67,12 @@ namespace AsbCloudApp.Data
/// <summary> /// <summary>
/// Дата/время первой операции /// Дата/время первой операции
/// </summary> /// </summary>
public DateTime? StartDate { get; set; } public DateTimeOffset? StartDate { get; set; }
/// <summary> /// <summary>
/// Дата/время кода приходили данные последний раз /// Дата/время кода приходили данные последний раз
/// </summary> /// </summary>
public DateTime LastTelemetryDate { get; set; } public DateTimeOffset LastTelemetryDate { get; set; }
/// <summary> /// <summary>
/// ID телеметрии /// ID телеметрии

View File

@ -82,14 +82,14 @@ namespace AsbCloudApp.Data
/// <para>Дата начала первой фактической операции</para> /// <para>Дата начала первой фактической операции</para>
/// <para>Используется как дата начала бурения</para> /// <para>Используется как дата начала бурения</para>
/// </summary> /// </summary>
public DateTime? FirstFactOperationDateStart { get; set; } public DateTimeOffset? FirstFactOperationDateStart { get; set; }
/// <summary> /// <summary>
/// <para>Дата окончания последней прогнозируемой операции</para> /// <para>Дата окончания последней прогнозируемой операции</para>
/// <para>Если скважина завершена, то дата окончания последней фактической операции</para> /// <para>Если скважина завершена, то дата окончания последней фактической операции</para>
/// <para>Используется как прогноз окончания бурения</para> /// <para>Используется как прогноз окончания бурения</para>
/// </summary> /// </summary>
public DateTime? LastPredictOperationDateEnd { get; set; } public DateTimeOffset? LastPredictOperationDateEnd { get; set; }
/// <summary> /// <summary>
/// Рейсовая скорость проходки, последнего рейса /// Рейсовая скорость проходки, последнего рейса

View File

@ -1,6 +1,6 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Data namespace AsbCloudApp.Data.WellOperation
{ {
/// <summary> /// <summary>
/// DTO категория операции /// DTO категория операции

View File

@ -0,0 +1,116 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Data.WellOperation;
public class WellOperationDto : ItemInfoDto,
IId,
IWellRelated,
IValidatableObject
{
/// <inheritdoc/>
[Required]
public int Id { get; set; }
/// <inheritdoc/>
[Required]
public int IdWell { get; set; }
/// <summary>
/// Id секции скважины
/// </summary>
public int IdWellSectionType { get; set; }
/// <summary>
/// 0 = план или 1 = факт или прогноз = 2
/// </summary>
[Required]
public int IdType { get; set; }
/// <summary>
/// id категории операции
/// </summary>
public int IdCategory { get; set; }
/// <summary>
/// Глубина на начало операции, м
/// </summary>
public double DepthStart { get; set; }
/// <summary>
/// Глубина после завершения операции, м
/// </summary>
[Required]
[Range(0, 50_000)]
public double DepthEnd { get; set; }
/// <summary>
/// Дата начала операции
/// </summary>
[Required]
public DateTimeOffset DateStart { get; set; }
/// <summary>
/// Продолжительность, часы
/// </summary>
public double DurationHours { get; set; }
/// <summary>
/// Наименование секции
/// </summary>
public string? WellSectionTypeCaption { get; set; }
/// <summary>
/// Наименование категории
/// </summary>
public string? OperationCategoryName { get; set; }
/// <summary>
/// id плановой операции для сопоставления
/// </summary>
public int? IdPlan { get; set; }
/// <summary>
/// Ключ родителя у категории
/// </summary>
public int? IdParentCategory { get; set; }
/// <summary>
/// дополнительная информация по операции
/// </summary>
[StringLength(8192)]
public string? CategoryInfo { get; set; }
/// <summary>
/// Кол-во дней от даты начала первой плановой (а если её нет, то фактической) операции
/// </summary>
[Required]
public double Day { get; set; }
/// <summary>
/// Кол-во часов НПВ от даты начала первой плановой (а если её нет, то фактической) операции
/// </summary>
[Required]
public double NptHours { get; set; }
/// <summary>
/// Полезный комментарий
/// </summary>
[StringLength(4096, ErrorMessage = "Комментарий не может быть длиннее 4096 символов")]
public string? Comment { get; set; }
/// <summary>
/// Валидация даты
/// </summary>
/// <param name="validationContext"></param>
/// <returns></returns>
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var gtDate = new DateTimeOffset(2010, 1, 1, 0, 0, 0, TimeSpan.Zero);
if (DateStart <= gtDate)
yield return new ValidationResult(
$"{nameof(DateStart)}: DateStart не может быть меньше {gtDate}",
new[] { nameof(DateStart) });
}
}

View File

@ -1,39 +0,0 @@
namespace AsbCloudApp.Data
{
/// Операция на скважине
public class WellOperationDataDto : IWellRelated
{
/// <inheritdoc/>
public int IdWell { get; set; }
/// <summary>
/// id секции скважины
/// </summary>
public int IdWellSectionType { get; set; }
/// <summary>
/// id категории операции
/// </summary>
public int IdCategory { get; set; }
/// <summary>
/// Глубина на начало операции, м
/// </summary>
public double DepthStart { get; set; }
/// <summary>
/// Продолжительность, часы
/// </summary>
public double DurationHours { get; set; }
/// <summary>
/// Наименование секции
/// </summary>
public string WellSectionTypeCaption { get; set; } = string.Empty;
/// <summary>
/// Наименование категории
/// </summary>
public string OperationCategoryName { get; set; } = string.Empty;
}
}

View File

@ -1,124 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Data
{
/// <summary>
/// Операции на скважине (заведенные пользователем)
/// </summary>
public class WellOperationDto : ItemInfoDto, IId, IWellRelated, IValidatableObject
{
/// <inheritdoc/>
[Required]
public int Id { get; set; }
/// <inheritdoc/>
[Required]
public int IdWell { get; set; }
/// <summary>
/// id секции скважины
/// </summary>
[Required]
public int IdWellSectionType { get; set; }
/// <summary>
/// название секции скважины
/// </summary>
public string? WellSectionTypeName { get; set; }
/// <summary>
/// id категории операции
/// </summary>
[Required]
[Range(5000, int.MaxValue)]
public int IdCategory { get; set; }
/// <summary>
/// id плановой операции для сопоставления
/// </summary>
public int? IdPlan { get; set; }
/// <summary>
/// название категории операции
/// </summary>
public string? CategoryName { get; set; }
/// <summary>
/// ключ родителя у категории
/// </summary>
public int? IdParentCategory { get; set; }
/// <summary>
/// дополнительная информация по операции
/// </summary>
[StringLength(8192)]
public string? CategoryInfo { get; set; }
/// <summary>
/// 0 = план или 1 = факт или прогноз = 2
/// </summary>
[Required]
public int IdType { get; set; }
/// <summary>
/// Глубина на начало операции, м
/// </summary>
[Required]
[Range(0, 50_000)]
public double DepthStart { get; set; }
/// <summary>
/// Глубина после завершения операции, м
/// </summary>
[Required]
[Range(0, 50_000)]
public double DepthEnd { get; set; }
/// <summary>
/// Кол-во дней от даты начала первой плановой (а если её нет, то фактической) операции
/// </summary>
[Required]
public double Day { get; set; }
/// <summary>
/// Кол-во часов НПВ от даты начала первой плановой (а если её нет, то фактической) операции
/// </summary>
[Required]
public double NptHours { get; set; }
/// <summary>
/// Дата начала операции
/// </summary>
[Required]
public DateTimeOffset DateStart { get; set; }
/// <summary>
/// Продолжительность, часы
/// </summary>
[Required]
[Range(0, 50)]
public double DurationHours { get; set; }
/// <summary>
/// Полезный комментарий
/// </summary>
[StringLength(4096, ErrorMessage = "Комментарий не может быть длиннее 4096 символов")]
public string? Comment { get; set; }
/// <summary>
/// Валидация даты
/// </summary>
/// <param name="validationContext"></param>
/// <returns></returns>
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var gtDate = new DateTimeOffset(2010, 1, 1, 0, 0, 0, TimeSpan.Zero);
if (DateStart <= gtDate)
yield return new ValidationResult(
$"{nameof(DateStart)}: DateStart не может быть меньше {gtDate}",
new[] { nameof(DateStart) });
}
}
}

View File

@ -1,28 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace AsbCloudApp.Data
{
/// <summary>
/// класс, который хранит список плановых операций для сопоставления
/// и даты последней сопоставленной плановой операции
/// </summary>
#nullable enable
public class WellOperationPlanDto
{
/// <summary>
/// коллекция плановых операций
/// </summary>
[Required]
public IEnumerable<WellOperationDto> WellOperationsPlan { get; set; } = Enumerable.Empty<WellOperationDto>();
/// <summary>
/// дата последней сопоставленной плановой операции
/// </summary>
public DateTime? DateLastAssosiatedPlanOperation { get; set; }
}
}

View File

@ -1,5 +1,5 @@
using AsbCloudApp.Data; using System.Collections.Generic;
using System.Collections.Generic; using AsbCloudApp.Data.WellOperation;
namespace AsbCloudApp.Repositories namespace AsbCloudApp.Repositories
{ {

View File

@ -1,9 +1,9 @@
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Requests;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Data.WellOperation;
using AsbCloudApp.Requests;
namespace AsbCloudApp.Repositories namespace AsbCloudApp.Repositories
{ {
@ -18,22 +18,6 @@ namespace AsbCloudApp.Repositories
/// <returns></returns> /// <returns></returns>
IEnumerable<WellSectionTypeDto> GetSectionTypes(); IEnumerable<WellSectionTypeDto> GetSectionTypes();
/// <summary>
/// список плановых операций для сопоставления
/// <param name="idWell"></param>
/// <param name="currentDate"></param>
/// <param name="token"></param>
/// </summary>
/// <returns></returns>
Task<WellOperationPlanDto> GetOperationsPlanAsync(int idWell, DateTime? currentDate, CancellationToken token);
/// <summary>
/// дата/время первой операции по скважине
/// </summary>
/// <param name="idWell"></param>
/// <returns></returns>
DateTimeOffset? FirstOperationDate(int idWell);
/// <summary> /// <summary>
/// Получить страницу списка операций /// Получить страницу списка операций
/// </summary> /// </summary>
@ -42,14 +26,6 @@ namespace AsbCloudApp.Repositories
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<WellOperationDto>> GetAsync(WellOperationRequest request, CancellationToken token); Task<IEnumerable<WellOperationDto>> GetAsync(WellOperationRequest request, CancellationToken token);
/// <summary>
/// Получить список операций по запросу
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<WellOperationDataDto>> GetAsync(WellsOperationRequest request, CancellationToken token);
/// <summary> /// <summary>
/// Получить страницу списка операций /// Получить страницу списка операций
/// </summary> /// </summary>
@ -58,31 +34,22 @@ namespace AsbCloudApp.Repositories
/// <returns></returns> /// <returns></returns>
Task<PaginationContainer<WellOperationDto>> GetPageAsync(WellOperationRequest request, CancellationToken token); Task<PaginationContainer<WellOperationDto>> GetPageAsync(WellOperationRequest request, CancellationToken token);
/// <summary>
/// Получить операцию по id
/// </summary>
/// <param name="id"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<WellOperationDto?> GetOrDefaultAsync(int id, CancellationToken token);
/// <summary> /// <summary>
/// Получить статистику операции по скважине с группировкой по категориям /// Получить статистику операции по скважине с группировкой по категориям
/// </summary> /// </summary>
/// <param name="request"></param> /// <param name="request"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<WellGroupOpertionDto>> GetGroupOperationsStatAsync( Task<IEnumerable<WellGroupOpertionDto>> GetGroupOperationsStatAsync(WellOperationRequest request, CancellationToken token);
WellOperationRequest request,
CancellationToken token);
/// <summary> /// <summary>
/// Добавить несколько операций за один раз /// Добавить несколько операций
/// </summary> /// </summary>
/// <param name="wellOperationDtos"></param> /// <param name="dtos"></param>
/// <param name="deleteBeforeInsert"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<int> InsertRangeAsync(IEnumerable<WellOperationDto> wellOperationDtos, CancellationToken token); Task<int> InsertRangeAsync(IEnumerable<WellOperationDto> dtos, bool deleteBeforeInsert, CancellationToken token);
/// <summary> /// <summary>
/// Обновить существующую операцию /// Обновить существующую операцию
@ -90,7 +57,7 @@ namespace AsbCloudApp.Repositories
/// <param name="dto"></param> /// <param name="dto"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<int> UpdateAsync(WellOperationDto dto, CancellationToken token); Task<int> UpdateRangeAsync(IEnumerable<WellOperationDto> dtos, CancellationToken token);
/// <summary> /// <summary>
/// Удалить операции по id /// Удалить операции по id
@ -98,7 +65,7 @@ namespace AsbCloudApp.Repositories
/// <param name="ids"></param> /// <param name="ids"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<int> DeleteAsync(IEnumerable<int> ids, CancellationToken token); Task<int> DeleteRangeAsync(IEnumerable<int> ids, CancellationToken token);
/// <summary> /// <summary>
/// Получить секции скважин из операций ГГД. Секцие поделены на плановые и фактические. /// Получить секции скважин из операций ГГД. Секцие поделены на плановые и фактические.
@ -116,23 +83,5 @@ namespace AsbCloudApp.Repositories
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
Task<DatesRangeDto?> GetDatesRangeAsync(int idWell, int idType, CancellationToken cancellationToken); Task<DatesRangeDto?> GetDatesRangeAsync(int idWell, int idType, CancellationToken cancellationToken);
/// <summary>
/// Удаление полных дубликатов операций по всем скважинам
/// </summary>
/// <param name="onProgressCallback"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> RemoveDuplicates(Action<string, double?> onProgressCallback, CancellationToken token);
/// <summary>
/// Усечение пересекающейся последующей операции по дате и глубине забоя
/// </summary>
/// <param name="geDate">Фильтр по дате. Если хоть одна операция попадет в в фильтр, то будет обработана вся скважина, а не только эта операция</param>
/// <param name="leDate">Фильтр по дате. Если хоть одна операция попадет в в фильтр, то будет обработана вся скважина, а не только эта операция</param>
/// <param name="onProgressCallback"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> TrimOverlapping(DateTimeOffset? geDate, DateTimeOffset leDate, Action<string, double?> onProgressCallback, CancellationToken token);
} }
} }

View File

@ -0,0 +1,20 @@
namespace AsbCloudApp.Requests.ExportOptions;
/// <summary>
/// Параметры экспорта ГГД
/// </summary>
public class WellOperationExportRequest : WellRelatedExportRequest
{
/// <inheritdoc />
public WellOperationExportRequest(int idWell,
int idType)
: base(idWell)
{
IdType = idType;
}
/// <summary>
/// Тип операций
/// </summary>
public int IdType { get; }
}

View File

@ -33,12 +33,12 @@ namespace AsbCloudApp.Requests
/// <summary> /// <summary>
/// Дата начала периода /// Дата начала периода
/// </summary> /// </summary>
public DateTime? Begin { get; set; } public DateTimeOffset? Begin { get; set; }
/// <summary> /// <summary>
/// Дата окончания периода /// Дата окончания периода
/// </summary> /// </summary>
public DateTime? End { get; set; } public DateTimeOffset? End { get; set; }
/// <summary> /// <summary>
/// Признак удаления /// Признак удаления

View File

@ -17,12 +17,12 @@ namespace AsbCloudApp.Requests
/// <summary> /// <summary>
/// Больше или равно дате /// Больше или равно дате
/// </summary> /// </summary>
public DateTime? GtDate { get; set; } public DateTimeOffset? GtDate { get; set; }
/// <summary> /// <summary>
/// Меньше или равно дате /// Меньше или равно дате
/// </summary> /// </summary>
public DateTime? LtDate { get; set; } public DateTimeOffset? LtDate { get; set; }
/// <summary> /// <summary>
/// Больше или равно глубины забоя /// Больше или равно глубины забоя

View File

@ -17,12 +17,12 @@ namespace AsbCloudApp.Requests
/// <summary> /// <summary>
/// начальная дата /// начальная дата
/// </summary> /// </summary>
public DateTime? Begin { get; set; } public DateTimeOffset? Begin { get; set; }
/// <summary> /// <summary>
/// конечная дата /// конечная дата
/// </summary> /// </summary>
public DateTime? End { get; set; } public DateTimeOffset? End { get; set; }
/// <summary> /// <summary>
/// строка поиска /// строка поиска

View File

@ -15,10 +15,10 @@ public class NotificationDeleteRequest
/// <summary> /// <summary>
/// Меньше или равно дате отправки /// Меньше или равно дате отправки
/// </summary> /// </summary>
public DateTime? LtSentDate { get; set; } public DateTimeOffset? LtSentDate { get; set; }
/// <summary> /// <summary>
/// Меньше или равно дате прочтения /// Меньше или равно дате прочтения
/// </summary> /// </summary>
public DateTime? LtReadDate { get; set; } public DateTimeOffset? LtReadDate { get; set; }
} }

View File

@ -0,0 +1,29 @@
using AsbCloudApp.Data;
namespace AsbCloudApp.Requests.ParserOptions;
/// <summary>
/// Параметры парсинга ГГД
/// </summary>
public class WellOperationParserRequest : WellRelatedParserRequest
{
/// <inheritdoc />
public WellOperationParserRequest(int idWell,
int idType,
SimpleTimezoneDto wellTimezone)
: base(idWell)
{
IdType = idType;
WellTimezone = wellTimezone;
}
/// <summary>
/// Тип операции
/// </summary>
public int IdType { get; }
/// <summary>
/// Часовой пояс в котором находится скважина
/// </summary>
public SimpleTimezoneDto WellTimezone { get; }
}

View File

@ -20,5 +20,5 @@ public class ProcessMapPlanRequest
/// <summary> /// <summary>
/// Дата обновления /// Дата обновления
/// </summary> /// </summary>
public DateTime? UpdateFrom { get; set; } public DateTimeOffset? UpdateFrom { get; set; }
} }

View File

@ -24,12 +24,12 @@ public class ReportParametersRequest: IValidatableObject
/// <summary> /// <summary>
/// Дата начала интервала /// Дата начала интервала
/// </summary> /// </summary>
public DateTime Begin { get; set; } = default; public DateTimeOffset Begin { get; set; } = default;
/// <summary> /// <summary>
/// Дата окончания интервала /// Дата окончания интервала
/// </summary> /// </summary>
public DateTime End { get; set; } = default; public DateTimeOffset End { get; set; } = default;
/// <inheritdoc/> /// <inheritdoc/>
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
@ -37,7 +37,7 @@ public class ReportParametersRequest: IValidatableObject
if (End < Begin) if (End < Begin)
yield return new("End mast be less then begin"); yield return new("End mast be less then begin");
if (Begin < new DateTime(2000, 1, 1)) if (Begin < new DateTimeOffset(2000, 1, 1, 0, 0, 0, TimeSpan.Zero))
yield return new("Begin mast be > 2000-1-1"); yield return new("Begin mast be > 2000-1-1");
} }
} }

View File

@ -9,7 +9,7 @@ namespace AsbCloudApp.Requests
/// </summary> /// </summary>
public class SubsystemRequest: RequestBase, IValidatableObject public class SubsystemRequest: RequestBase, IValidatableObject
{ {
private static readonly DateTime validationMinDate = new DateTime(2020,01,01,0,0,0,DateTimeKind.Utc); private static readonly DateTimeOffset validationMinDate = new DateTimeOffset(2020,01,01,0,0,0, TimeSpan.Zero);
/// <summary> /// <summary>
/// идентификатор скважины /// идентификатор скважины

View File

@ -15,10 +15,10 @@ public class TrajectoryRequest : RequestBase
/// <summary> /// <summary>
/// Больше или равно дате /// Больше или равно дате
/// </summary> /// </summary>
public DateTime? GeDate { get; set; } public DateTimeOffset? GeDate { get; set; }
/// <summary> /// <summary>
/// Меньше или равно дате /// Меньше или равно дате
/// </summary> /// </summary>
public DateTime? LeDate { get; set; } public DateTimeOffset? LeDate { get; set; }
} }

View File

@ -1,66 +1,72 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace AsbCloudApp.Requests namespace AsbCloudApp.Requests;
/// <summary>
/// Запрос получения ГГД
/// </summary>
public class WellOperationRequestBase : RequestBase
{ {
/// <summary> /// <summary>
/// параметры для запроса списка операций /// Больше или равно дате начала операции
/// </summary> /// </summary>
public class WellOperationRequestBase : RequestBase public DateTimeOffset? GeDate { get; set; }
{
/// <summary>
/// фильтр по дате начала операции
/// </summary>
public DateTime? GeDate { get; set; }
/// <summary> /// <summary>
/// фильтр по дате окончания операции /// Меньше или равно дате окончания операции
/// </summary> /// </summary>
public DateTime? LtDate { get; set; } public DateTimeOffset? LeDate { get; set; }
/// <summary> /// <summary>
/// фильтр. Больше или равно глубины скважины на начало операции. /// Больше или равно глубины скважины на начало операции.
/// </summary> /// </summary>
public double? GeDepth { get; set; } public double? GeDepth { get; set; }
/// <summary> /// <summary>
/// фильтр. Меньше или равно глубины скважины на конец операции. /// Меньше или равно глубины скважины на конец операции.
/// </summary> /// </summary>
public double? LeDepth { get; set; } public double? LeDepth { get; set; }
/// <summary> /// <summary>
/// фильтр по списку id категорий операции /// Идентификаторы категорий операции
/// </summary> /// </summary>
public IEnumerable<int>? OperationCategoryIds { get; set; } public IEnumerable<int>? OperationCategoryIds { get; set; }
/// <summary> /// <summary>
/// фильтр по план = 0, факт = 1 /// Тип операций
/// <list type="bullet">
/// <item>0 - плановая операция</item>
/// <item>1 - фактическая операция</item>
/// </list>
/// </summary> /// </summary>
public int? OperationType { get; set; } public int? OperationType { get; set; }
/// <summary> /// <summary>
/// фильтр по списку id конструкций секции /// Идентификаторы конструкций секции
/// </summary> /// </summary>
public IEnumerable<int>? SectionTypeIds { get; set; } public IEnumerable<int>? SectionTypeIds { get; set; }
}
/// <summary> /// <summary>
/// Параметры для запроса списка операций. /// Запрос получения ГГД с идентификаторами скважин
/// Базовый конструктор /// </summary>
/// </summary> public class WellOperationRequest : WellOperationRequestBase
public WellOperationRequestBase() {
{ } /// <inheritdoc />
public WellOperationRequest(IEnumerable<int> idsWell)
{
IdsWell = idsWell;
}
/// <summary> /// <inheritdoc />
/// Параметры для запроса списка операций. public WellOperationRequest(WellOperationRequestBase request, IEnumerable<int> idsWell)
/// Копирующий конструктор : this(idsWell)
/// </summary>
/// <param name="request"></param>
public WellOperationRequestBase(WellOperationRequestBase request)
{ {
GeDepth = request.GeDepth; GeDepth = request.GeDepth;
LeDepth = request.LeDepth; LeDepth = request.LeDepth;
GeDate = request.GeDate; GeDate = request.GeDate;
LtDate = request.LtDate; LeDate = request.LeDate;
OperationCategoryIds = request.OperationCategoryIds; OperationCategoryIds = request.OperationCategoryIds;
OperationType = request.OperationType; OperationType = request.OperationType;
@ -70,43 +76,9 @@ namespace AsbCloudApp.Requests
Take = request.Take; Take = request.Take;
SortFields = request.SortFields; SortFields = request.SortFields;
} }
}
/// <summary> /// <summary>
/// Параметры для запроса списка операций (с id скважины) /// Идентификаторы скважин
/// </summary> /// </summary>
public class WellOperationRequest : WellOperationRequestBase public IEnumerable<int>? IdsWell { get; }
{
/// <summary>
/// id скважины
/// </summary>
public int IdWell { get; set; }
/// <summary>
/// ctor
/// </summary>
public WellOperationRequest() { }
/// <summary>
/// копирующий конструктор
/// </summary>
/// <param name="request"></param>
/// <param name="idWell"></param>
public WellOperationRequest(WellOperationRequestBase request, int idWell)
:base(request)
{
IdWell = idWell;
}
}
/// <summary>
/// Параметры для запроса списка операций (с массивом id скважин)
/// </summary>
public class WellsOperationRequest : WellOperationRequestBase
{
/// <summary>
/// ids скважин
/// </summary>
public IEnumerable<int> IdsWell { get; set; } = null!;
}
} }

View File

@ -42,12 +42,4 @@ public interface IDailyReportService
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
Task<PaginationContainer<DailyReportDto>> GetAsync(int idWell, FileReportRequest request, CancellationToken cancellationToken); Task<PaginationContainer<DailyReportDto>> GetAsync(int idWell, FileReportRequest request, CancellationToken cancellationToken);
/// <summary>
/// Получить диапазон дат по которым возможно сформировать суточный отчёты
/// </summary>
/// <param name="idWell"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<DatesRangeDto?> GetDatesRangeAsync(int idWell, CancellationToken cancellationToken);
} }

View File

@ -3,12 +3,12 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Requests.ExportOptions; using AsbCloudApp.Requests.ExportOptions;
namespace AsbCloudApp.Services; namespace AsbCloudApp.Services.Export;
/// <summary> /// <summary>
/// Экспорт данных /// Экспорт данных
/// </summary> /// </summary>
public interface IExportService<in TOptions> public interface IExportService<in TOptions> : IExportService
where TOptions : IExportOptionsRequest where TOptions : IExportOptionsRequest
{ {
/// <summary> /// <summary>
@ -19,3 +19,11 @@ public interface IExportService<in TOptions>
/// <returns></returns> /// <returns></returns>
Task<(string FileName, Stream File)> ExportAsync(TOptions options, CancellationToken token); Task<(string FileName, Stream File)> ExportAsync(TOptions options, CancellationToken token);
} }
/// <summary>
/// Экспорт данных
/// </summary>
public interface IExportService
{
}

View File

@ -0,0 +1,20 @@
using AsbCloudApp.Requests.ExportOptions;
namespace AsbCloudApp.Services.Export;
/// <summary>
/// Фабрика создания сервисов для экспорта
/// </summary>
/// <typeparam name="TId"></typeparam>
public interface IExportServiceFactory<in TId>
where TId : struct
{
/// <summary>
/// Создать сервис экспорта
/// </summary>
/// <param name="id"></param>
/// <typeparam name="TOptions"></typeparam>
/// <returns></returns>
IExportService<TOptions> CreateExportService<TOptions>(TId id)
where TOptions : IExportOptionsRequest;
}

View File

@ -1,10 +1,10 @@
using System; using System;
using AsbCloudApp.Data;
using AsbCloudApp.Data.DetectedOperation; using AsbCloudApp.Data.DetectedOperation;
using AsbCloudApp.Requests; using AsbCloudApp.Requests;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Data.WellOperation;
namespace AsbCloudApp.Services namespace AsbCloudApp.Services
{ {

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Data.WellOperation;
namespace AsbCloudApp.Services namespace AsbCloudApp.Services
{ {

View File

@ -46,7 +46,7 @@ namespace AsbCloudApp.Services
/// <param name="stepSeconds"></param> /// <param name="stepSeconds"></param>
/// <param name="format"></param> /// <param name="format"></param>
/// <returns></returns> /// <returns></returns>
int GetReportPagesCount(int idWell, DateTime begin, DateTime end, int GetReportPagesCount(int idWell, DateTimeOffset begin, DateTimeOffset end,
int stepSeconds, int format); int stepSeconds, int format);
/// <summary> /// <summary>

View File

@ -19,7 +19,7 @@ namespace AsbCloudApp.Services
/// <param name="workTime"></param> /// <param name="workTime"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<ScheduleDto>> GetAsync(int idWell, DateTime workTime, CancellationToken token); Task<IEnumerable<ScheduleDto>> GetAsync(int idWell, DateTimeOffset workTime, CancellationToken token);
/// <summary> /// <summary>
/// получить бурильщика по idWell и времени /// получить бурильщика по idWell и времени
@ -28,7 +28,7 @@ namespace AsbCloudApp.Services
/// <param name="workTime"></param> /// <param name="workTime"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<DrillerDto?> GetOrDefaultDrillerAsync(int idWell, DateTime workTime, CancellationToken token); Task<DrillerDto?> GetOrDefaultDrillerAsync(int idWell, DateTimeOffset workTime, CancellationToken token);
/// <summary> /// <summary>
/// Получить расписание смен /// Получить расписание смен

View File

@ -1,7 +1,7 @@
using AsbCloudApp.Data; using System.Collections.Generic;
using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Data.WellOperation;
namespace AsbCloudApp.Services namespace AsbCloudApp.Services
{ {
@ -16,6 +16,6 @@ namespace AsbCloudApp.Services
/// <param name="idsWells"></param> /// <param name="idsWells"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<List<Dictionary<int, WellOperationDataDto>>> GetAsync(IEnumerable<int> idsWells, CancellationToken token); Task<IEnumerable<Dictionary<int, WellOperationDto>>> GetAsync(IEnumerable<int> idsWells, CancellationToken token);
} }
} }

View File

@ -72,7 +72,7 @@ namespace AsbCloudApp.Services
/// </summary> /// </summary>
/// <param name="idWell"></param> /// <param name="idWell"></param>
/// <returns></returns> /// <returns></returns>
DateTime GetLastTelemetryDate(int idWell); DateTimeOffset GetLastTelemetryDate(int idWell);
//TODO: выяснить и удалить отсюда //TODO: выяснить и удалить отсюда
/// <summary> /// <summary>

View File

@ -49,7 +49,7 @@ public class NotificationService
var notification = new NotificationDto var notification = new NotificationDto
{ {
IdUser = request.IdUser, IdUser = request.IdUser,
RegistrationDate = DateTime.UtcNow, RegistrationDate = DateTimeOffset.UtcNow,
IdNotificationCategory = notificationCategory.Id, IdNotificationCategory = notificationCategory.Id,
Title = request.Title, Title = request.Title,
Message = request.Message, Message = request.Message,
@ -71,7 +71,7 @@ public class NotificationService
Console.WriteLine(ex.Message); Console.WriteLine(ex.Message);
} }
notification.SentDate = DateTime.UtcNow; notification.SentDate = DateTimeOffset.UtcNow;
await notificationRepository.UpdateAsync(notification, cancellationToken); await notificationRepository.UpdateAsync(notification, cancellationToken);
} }
@ -92,7 +92,7 @@ public class NotificationService
if(isRead && !notification.SentDate.HasValue) if(isRead && !notification.SentDate.HasValue)
throw new ArgumentInvalidException(nameof(isRead), "Уведомление не может быть прочитано"); throw new ArgumentInvalidException(nameof(isRead), "Уведомление не может быть прочитано");
notification.ReadDate = isRead ? DateTime.UtcNow : null; notification.ReadDate = isRead ? DateTimeOffset.UtcNow : null;
await notificationRepository.UpdateAsync(notification, await notificationRepository.UpdateAsync(notification,
cancellationToken); cancellationToken);
@ -119,7 +119,7 @@ public class NotificationService
var tasks = notifications.Select(notification => var tasks = notifications.Select(notification =>
{ {
notification.SentDate = DateTime.UtcNow; notification.SentDate = DateTimeOffset.UtcNow;
return notificationRepository.UpdateAsync(notification, cancellationToken); return notificationRepository.UpdateAsync(notification, cancellationToken);
}); });

View File

@ -0,0 +1,23 @@
using AsbCloudApp.Data;
using AsbCloudApp.Requests.ParserOptions;
namespace AsbCloudApp.Services.Parsers;
/// <summary>
/// Фабрика для создания сервиса парсинга
/// </summary>
/// <typeparam name="TId"></typeparam>
/// <typeparam name="TDto"></typeparam>
public interface IParserFactory<in TId, TDto>
where TId : struct
where TDto : class, IId
{
/// <summary>
/// Создать парсер
/// </summary>
/// <param name="id"></param>
/// <typeparam name="TOptions"></typeparam>
/// <returns></returns>
IParserService<TDto, TOptions> CreateParser<TOptions>(TId id)
where TOptions : IParserOptionsRequest;
}

View File

@ -2,14 +2,14 @@ using System.IO;
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Requests.ParserOptions; using AsbCloudApp.Requests.ParserOptions;
namespace AsbCloudApp.Services; namespace AsbCloudApp.Services.Parsers;
/// <summary> /// <summary>
/// Сервис парсинга /// Сервис парсинга
/// </summary> /// </summary>
/// <typeparam name="TDto"></typeparam> /// <typeparam name="TDto"></typeparam>
/// <typeparam name="TOptions"></typeparam> /// <typeparam name="TOptions"></typeparam>
public interface IParserService<TDto, in TOptions> public interface IParserService<TDto, in TOptions> : IParserService
where TDto : class, IId where TDto : class, IId
where TOptions : IParserOptionsRequest where TOptions : IParserOptionsRequest
{ {
@ -27,3 +27,10 @@ public interface IParserService<TDto, in TOptions>
/// <returns></returns> /// <returns></returns>
Stream GetTemplateFile(); Stream GetTemplateFile();
} }
/// <summary>
/// Сервис парсинга
/// </summary>
public interface IParserService
{
}

View File

@ -1,20 +0,0 @@
using System.IO;
using AsbCloudApp.Data.WellOperationImport;
using AsbCloudApp.Data.WellOperationImport.Options;
namespace AsbCloudApp.Services.WellOperationImport;
/// <summary>
/// Парсинг операций из excel файла
/// </summary>
public interface IWellOperationExcelParser<in TOptions>
where TOptions : IWellOperationImportOptions
{
/// <summary>
/// Метод парсинга документа
/// </summary>
/// <param name="stream"></param>
/// <param name="options"></param>
/// <returns></returns>
SheetDto Parse(Stream stream, TOptions options);
}

View File

@ -1,19 +0,0 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudApp.Services.WellOperationImport;
/// <summary>
/// Экспорт ГГД
/// </summary>
public interface IWellOperationExportService
{
/// <summary>
/// Скачать в excel
/// </summary>
/// <param name="idWell"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<Stream> ExportAsync(int idWell, CancellationToken cancellationToken);
}

View File

@ -1,20 +0,0 @@
using System.Collections.Generic;
using AsbCloudApp.Data;
using AsbCloudApp.Data.WellOperationImport;
namespace AsbCloudApp.Services.WellOperationImport;
/// <summary>
/// Импорт ГГД
/// </summary>
public interface IWellOperationImportService
{
/// <summary>
/// Загрузить из excel список операций
/// </summary>
/// <param name="idWell"></param>
/// <param name="idUser"></param>
/// <param name="idType"></param>
/// <param name="sheet"></param>
IEnumerable<WellOperationDto> Import(int idWell, int idUser, int idType, SheetDto sheet);
}

View File

@ -1,15 +0,0 @@
using System.IO;
namespace AsbCloudApp.Services.WellOperationImport;
/// <summary>
/// Сервис для получения шаблонов ГГД
/// </summary>
public interface IWellOperationImportTemplateService
{
/// <summary>
/// Скачать шаблон для заполнения
/// </summary>
/// <returns></returns>
Stream GetExcelTemplateStream();
}

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,7 @@ public class DailyReport : IId
public int IdWell { get; set; } public int IdWell { get; set; }
[Column("date_last_update", TypeName = "timestamp with time zone"), Comment("Дата последнего обновления")] [Column("date_last_update", TypeName = "timestamp with time zone"), Comment("Дата последнего обновления")]
public DateTime? DateLastUpdate { get; set; } public DateTimeOffset? DateLastUpdate { get; set; }
[Column("date", TypeName = "date"), Comment("Дата формирования отчёта")] [Column("date", TypeName = "date"), Comment("Дата формирования отчёта")]
public DateOnly Date { get; set; } public DateOnly Date { get; set; }

View File

@ -12,6 +12,6 @@ namespace AsbCloudDb.Model
/// <summary> /// <summary>
/// дата последнего обновления блока /// дата последнего обновления блока
/// </summary> /// </summary>
public DateTimeOffset LastUpdateDate { get; set; } = DateTimeOffset.Now; public DateTimeOffset LastUpdateDate { get; set; } = DateTimeOffset.UtcNow;
} }
} }

View File

@ -15,8 +15,8 @@ public class Manual : IId
[Column("name"), Comment("Название")] [Column("name"), Comment("Название")]
public string Name { get; set; } = null!; public string Name { get; set; } = null!;
[Column("date_download"), Comment("Дата загрузки")] [Column("date_download", TypeName = "timestamp with time zone"), Comment("Дата загрузки")]
public DateTime DateDownload { get; set; } public DateTimeOffset DateDownload { get; set; }
[Column("id_directory"), Comment("Id директории")] [Column("id_directory"), Comment("Id директории")]
public int IdDirectory { get; set; } public int IdDirectory { get; set; }

View File

@ -25,13 +25,13 @@ public class Notification : IId
public string Message { get; set; } = null!; public string Message { get; set; } = null!;
[Column("registration_date"), Comment("Дата регистрации уведомления")] [Column("registration_date"), Comment("Дата регистрации уведомления")]
public DateTime RegistrationDate { get; set; } public DateTimeOffset RegistrationDate { get; set; }
[Column("sent_date"), Comment("Дата отправки уведомления")] [Column("sent_date"), Comment("Дата отправки уведомления")]
public DateTime? SentDate { get; set; } public DateTimeOffset? SentDate { get; set; }
[Column("read_date"), Comment("Дата прочтения уведомления")] [Column("read_date"), Comment("Дата прочтения уведомления")]
public DateTime? ReadDate { get; set; } public DateTimeOffset? ReadDate { get; set; }
[Column("id_transport_type"), Comment("Id типа доставки уведомления")] [Column("id_transport_type"), Comment("Id типа доставки уведомления")]
public int IdTransportType { get; set; } public int IdTransportType { get; set; }

View File

@ -67,23 +67,6 @@ namespace AsbCloudDb.Model
[JsonIgnore] [JsonIgnore]
[ForeignKey(nameof(IdPlan))] [ForeignKey(nameof(IdPlan))]
public virtual WellOperation? OperationPlan { get; set; } = null!; public virtual WellOperation? OperationPlan { get; set; } = null!;
public bool IsSame(WellOperation other)
{
var isSame = IdWell == other.IdWell &&
IdWellSectionType == other.IdWellSectionType &&
IdCategory == other.IdCategory &&
IdType == other.IdType &&
IdPlan == other.IdPlan &&
DepthStart == other.DepthStart &&
DepthEnd == other.DepthEnd &&
DateStart == other.DateStart &&
DurationHours == other.DurationHours &&
CategoryInfo == other.CategoryInfo &&
Comment == other.Comment;
return isSame;
}
} }
} }

View File

@ -45,11 +45,9 @@
<EmbeddedResource Include="Services\Trajectory\Templates\TrajectoryFactManualTemplate.xlsx" /> <EmbeddedResource Include="Services\Trajectory\Templates\TrajectoryFactManualTemplate.xlsx" />
<EmbeddedResource Include="Services\Trajectory\Templates\TrajectoryPlanTemplate.xlsx" /> <EmbeddedResource Include="Services\Trajectory\Templates\TrajectoryPlanTemplate.xlsx" />
<EmbeddedResource Include="Services\WellOperationService\ScheduleReportTemplate.xlsx" /> <EmbeddedResource Include="Services\WellOperationService\ScheduleReportTemplate.xlsx" />
<EmbeddedResource Include="Services\WellOperationImport\Files\WellOperationImportTemplate.xlsx" />
<EmbeddedResource Include="Services\WellOperationImport\Files\Dictionaries\Operations.txt" />
<EmbeddedResource Include="Services\WellOperationImport\Files\Dictionaries\Sections.txt" />
<EmbeddedResource Include="Services\WellOperationImport\Files\Dictionaries\OperationAttributes.txt" />
<EmbeddedResource Include="Services\ProcessMaps\Report\ProcessMapReportTemplate.xlsx" /> <EmbeddedResource Include="Services\ProcessMaps\Report\ProcessMapReportTemplate.xlsx" />
<EmbeddedResource Include="Services\WellOperations\Templates\WellOperationFactTemplate.xlsx" />
<EmbeddedResource Include="Services\WellOperations\Templates\WellOperationPlanTemplate.xlsx" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -77,4 +75,5 @@
<HintPath>CommonLibs\AsbWitsInfo.dll</HintPath> <HintPath>CommonLibs\AsbWitsInfo.dll</HintPath>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -27,7 +27,7 @@ namespace AsbCloudInfrastructure.Background
await notificationService.SendAsync(notification, token); await notificationService.SendAsync(notification, token);
notification.SentDate = DateTime.UtcNow; notification.SentDate = DateTimeOffset.UtcNow;
await notificationRepository.UpdateAsync(notification, token); await notificationRepository.UpdateAsync(notification, token);
} }

View File

@ -14,7 +14,6 @@ using AsbCloudApp.Services.DailyReport;
using AsbCloudApp.Services.Notifications; using AsbCloudApp.Services.Notifications;
using AsbCloudApp.Services.ProcessMaps; using AsbCloudApp.Services.ProcessMaps;
using AsbCloudApp.Services.ProcessMaps.WellDrilling; using AsbCloudApp.Services.ProcessMaps.WellDrilling;
using AsbCloudApp.Services.WellOperationImport;
using AsbCloudDb.Model; using AsbCloudDb.Model;
using AsbCloudDb.Model.DailyReports.Blocks.TimeBalance; using AsbCloudDb.Model.DailyReports.Blocks.TimeBalance;
using AsbCloudDb.Model.Manuals; using AsbCloudDb.Model.Manuals;
@ -36,8 +35,6 @@ using AsbCloudInfrastructure.Services.Subsystems;
using AsbCloudInfrastructure.Services.Trajectory; using AsbCloudInfrastructure.Services.Trajectory;
using AsbCloudInfrastructure.Services.Trajectory.Export; using AsbCloudInfrastructure.Services.Trajectory.Export;
using AsbCloudInfrastructure.Services.Trajectory.Parser; using AsbCloudInfrastructure.Services.Trajectory.Parser;
using AsbCloudInfrastructure.Services.WellOperationImport;
using AsbCloudInfrastructure.Services.WellOperationImport.FileParser;
using AsbCloudInfrastructure.Services.WellOperationService; using AsbCloudInfrastructure.Services.WellOperationService;
using Mapster; using Mapster;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -46,6 +43,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using System; using System;
using AsbCloudInfrastructure.Services.ProcessMapPlan.Export; using AsbCloudInfrastructure.Services.ProcessMapPlan.Export;
using AsbCloudInfrastructure.Services.WellOperations.Factories;
namespace AsbCloudInfrastructure namespace AsbCloudInfrastructure
{ {
@ -160,7 +158,6 @@ namespace AsbCloudInfrastructure
services.AddTransient<ITelemetryUserService, TelemetryUserService>(); services.AddTransient<ITelemetryUserService, TelemetryUserService>();
services.AddTransient<ITimezoneService, TimezoneService>(); services.AddTransient<ITimezoneService, TimezoneService>();
services.AddScoped<IWellService, WellService>(); services.AddScoped<IWellService, WellService>();
services.AddTransient<IWellOperationImportService, WellOperationImportService>();
services.AddTransient<IProcessMapReportDrillingExportService, ProcessMapReportDataSaubStatExportService>(); services.AddTransient<IProcessMapReportDrillingExportService, ProcessMapReportDataSaubStatExportService>();
services.AddTransient<IWellOperationRepository, WellOperationRepository>(); services.AddTransient<IWellOperationRepository, WellOperationRepository>();
services.AddTransient<IDailyReportService, DailyReportService>(); services.AddTransient<IDailyReportService, DailyReportService>();
@ -270,13 +267,6 @@ namespace AsbCloudInfrastructure
services.AddTransient<IWellboreService, WellboreService>(); services.AddTransient<IWellboreService, WellboreService>();
services.AddTransient<IWellOperationExportService, WellOperationExportService>();
services.AddTransient<IWellOperationImportService, WellOperationImportService>();
services.AddTransient<IWellOperationImportTemplateService, WellOperationImportTemplateService>();
services.AddTransient<IWellOperationExcelParser<WellOperationImportDefaultOptionsDto>, WellOperationDefaultExcelParser>();
services.AddTransient<IWellOperationExcelParser<WellOperationImportGazpromKhantosOptionsDto>, WellOperationGazpromKhantosExcelParser>();
services.AddTransient<DetectedOperationExportService>(); services.AddTransient<DetectedOperationExportService>();
services.AddTransient<IDailyReportService, DailyReportService>(); services.AddTransient<IDailyReportService, DailyReportService>();
@ -301,6 +291,9 @@ namespace AsbCloudInfrastructure
services.AddTransient<ProcessMapPlanDrillingExportService>(); services.AddTransient<ProcessMapPlanDrillingExportService>();
services.AddTransient<ProcessMapPlanReamExportService>(); services.AddTransient<ProcessMapPlanReamExportService>();
services.AddTransient<WellOperationParserFactory>();
services.AddTransient<WellOperationExportServiceFactory>();
return services; return services;
} }
} }

View File

@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore.ChangeTracking;
namespace AsbCloudInfrastructure.Repository namespace AsbCloudInfrastructure.Repository
{ {
@ -86,7 +87,7 @@ namespace AsbCloudInfrastructure.Repository
entity.Id = 0; entity.Id = 0;
return entity; return entity;
}); });
var entries = new List<Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry>(items.Count()); var entries = new List<EntityEntry>(items.Count());
foreach (var entity in entities) foreach (var entity in entities)
{ {
var entry = dbSet.Add(entity); var entry = dbSet.Add(entity);
@ -115,6 +116,27 @@ namespace AsbCloudInfrastructure.Repository
return entry.Entity.Id; return entry.Entity.Id;
} }
public virtual async Task<int> UpdateRangeAsync(IEnumerable<TDto> dtos, CancellationToken token)
{
if (!dtos.Any())
return 0;
var ids = dtos.Select(d => d.Id);
var countExistingEntities = await dbSet
.Where(d => ids.Contains(d.Id))
.CountAsync(token);
if (ids.Count() > countExistingEntities)
return ICrudRepository<TDto>.ErrorIdNotFound;
var entities = dtos.Select(Convert);
var entries = entities.Select(entity => dbSet.Update(entity)).Cast<EntityEntry>().ToList();
var affected = await dbContext.SaveChangesAsync(token);
entries.ForEach(e => e.State = EntityState.Detached);
return affected;
}
/// <inheritdoc/> /// <inheritdoc/>
public virtual Task<int> DeleteAsync(int id, CancellationToken token) public virtual Task<int> DeleteAsync(int id, CancellationToken token)
{ {
@ -129,6 +151,25 @@ namespace AsbCloudInfrastructure.Repository
return affected; return affected;
} }
public virtual async Task<int> DeleteRangeAsync(IEnumerable<int> ids, CancellationToken token)
{
if (!ids.Any())
return 0;
var countExistingEntities = await dbSet
.Where(d => ids.Contains(d.Id))
.CountAsync(token);
if (ids.Count() > countExistingEntities)
return ICrudRepository<TDto>.ErrorIdNotFound;
var entities = dbContext.Set<TEntity>().Where(e => ids.Contains(e.Id));
var entries = entities.Select(entity => dbSet.Remove(entity)).Cast<EntityEntry>().ToList();
var affected = await dbContext.SaveChangesAsync(token);
entries.ForEach(e => e.State = EntityState.Detached);
return affected;
}
protected virtual TDto Convert(TEntity src) => src.Adapt<TDto>(); protected virtual TDto Convert(TEntity src) => src.Adapt<TDto>();
protected virtual TEntity Convert(TDto src) => src.Adapt<TEntity>(); protected virtual TEntity Convert(TDto src) => src.Adapt<TEntity>();

View File

@ -1,28 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data.DailyReport; using AsbCloudApp.Data.DailyReport;
using AsbCloudApp.Data.DailyReport.Blocks.Sign; using AsbCloudApp.Data.DailyReport.Blocks.Sign;
using AsbCloudApp.Data.DailyReport.Blocks.Subsystems; using AsbCloudApp.Data.DailyReport.Blocks.Subsystems;
using AsbCloudApp.Data.DailyReport.Blocks.TimeBalance; using AsbCloudApp.Data.DailyReport.Blocks.TimeBalance;
using AsbCloudApp.Repositories; using AsbCloudApp.Repositories;
using AsbCloudApp.Requests; using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb; using AsbCloudDb;
using AsbCloudDb.Model; using AsbCloudDb.Model;
using AsbCloudDb.Model.DailyReports; using AsbCloudDb.Model.DailyReports;
using Mapster; using Mapster;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Repository; namespace AsbCloudInfrastructure.Repository;
public class DailyReportRepository : CrudRepositoryBase<DailyReportDto, DailyReport>, public class DailyReportRepository : CrudRepositoryBase<DailyReportDto, DailyReport>,
IDailyReportRepository IDailyReportRepository
{ {
public DailyReportRepository(IAsbCloudDbContext dbContext) private IWellService wellService;
public DailyReportRepository(IAsbCloudDbContext dbContext, IWellService wellService)
: base(dbContext) : base(dbContext)
{ {
this.wellService = wellService;
} }
public async Task<IEnumerable<DailyReportDto>> GetAsync(int idWell, FileReportRequest request, CancellationToken cancellationToken) public async Task<IEnumerable<DailyReportDto>> GetAsync(int idWell, FileReportRequest request, CancellationToken cancellationToken)
@ -48,7 +52,8 @@ public class DailyReportRepository : CrudRepositoryBase<DailyReportDto, DailyRep
.AsNoTracking() .AsNoTracking()
.ToArrayAsync(cancellationToken); .ToArrayAsync(cancellationToken);
var dtos = entities.Select(Convert); var timezoneOffset = wellService.GetTimezone(idWell).Offset;
var dtos = entities.Select(entity => Convert(entity, timezoneOffset));
return dtos; return dtos;
} }
@ -62,13 +67,13 @@ public class DailyReportRepository : CrudRepositoryBase<DailyReportDto, DailyRep
return entity is null ? null : Convert(entity); return entity is null ? null : Convert(entity);
} }
protected override DailyReportDto Convert(DailyReport src) protected DailyReportDto Convert(DailyReport src, TimeSpan timezoneOffset)
{ {
var dto = new DailyReportDto var dto = new DailyReportDto
{ {
Id = src.Id, Id = src.Id,
IdWell = src.IdWell, IdWell = src.IdWell,
DateLastUpdate = src.DateLastUpdate, DateLastUpdate = src.DateLastUpdate?.ToOffset(timezoneOffset),
Date = src.Date, Date = src.Date,
SignBlock = src.SignBlock?.Adapt<SignBlockDto>(), SignBlock = src.SignBlock?.Adapt<SignBlockDto>(),
TimeBalanceBlock = src.TimeBalanceBlock?.Adapt<TimeBalanceBlockDto>(), TimeBalanceBlock = src.TimeBalanceBlock?.Adapt<TimeBalanceBlockDto>(),

View File

@ -4,6 +4,7 @@ using AsbCloudApp.Services;
using AsbCloudDb.Model; using AsbCloudDb.Model;
using Mapster; using Mapster;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
@ -111,7 +112,8 @@ namespace AsbCloudInfrastructure.Repository
{ {
var dto = well.Adapt<WellDto>(); var dto = well.Adapt<WellDto>();
dto.WellType = well.WellType.Caption; dto.WellType = well.WellType.Caption;
dto.LastTelemetryDate = wellService.GetLastTelemetryDate(well.Id); dto.LastTelemetryDate = wellService.GetLastTelemetryDate(well.Id)
.ToOffset(TimeSpan.FromHours(well.Timezone.Hours));
dto.Cluster = gCluster.Key.Caption; dto.Cluster = gCluster.Key.Caption;
dto.Deposit = gDeposit.Key.Caption; dto.Deposit = gDeposit.Key.Caption;
return dto; return dto;

View File

@ -36,9 +36,6 @@ namespace AsbCloudInfrastructure.Repository
var query = dbSetConfigured var query = dbSetConfigured
.Where(e => e.IdWell == request.IdWell); .Where(e => e.IdWell == request.IdWell);
double timezoneOffsetHours = query.FirstOrDefault()
?.Well.Timezone.Hours ?? 5d;
if (request.IdCategory is not null) if (request.IdCategory is not null)
query = query.Where(x => x.IdCategory == request.IdCategory); query = query.Where(x => x.IdCategory == request.IdCategory);
@ -53,13 +50,13 @@ namespace AsbCloudInfrastructure.Repository
if (request.Begin is not null) if (request.Begin is not null)
{ {
var beginUtc = request.Begin.Value.ToUtcDateTimeOffset(timezoneOffsetHours); var beginUtc = request.Begin.Value.ToUniversalTime();
query = query.Where(e => e.UploadDate >= beginUtc); query = query.Where(e => e.UploadDate >= beginUtc);
} }
if (request.End is not null) if (request.End is not null)
{ {
var endUtc = request.End.Value.ToUtcDateTimeOffset(timezoneOffsetHours); var endUtc = request.End.Value.ToUniversalTime();
query = query.Where(e => e.UploadDate <= endUtc); query = query.Where(e => e.UploadDate <= endUtc);
} }
@ -184,7 +181,7 @@ namespace AsbCloudInfrastructure.Repository
var newFileMark = fileMarkDto.Adapt<FileMark>(); var newFileMark = fileMarkDto.Adapt<FileMark>();
newFileMark.Id = default; newFileMark.Id = default;
newFileMark.DateCreated = DateTime.UtcNow; newFileMark.DateCreated = DateTimeOffset.UtcNow;
newFileMark.IdUser = idUser; newFileMark.IdUser = idUser;
newFileMark.User = null!; newFileMark.User = null!;
@ -244,7 +241,7 @@ namespace AsbCloudInfrastructure.Repository
IdAuthor = newItem.IdAuthor, IdAuthor = newItem.IdAuthor,
IdCategory = newItem.IdCategory, IdCategory = newItem.IdCategory,
Name = newItem.Name, Name = newItem.Name,
UploadDate = DateTime.UtcNow, UploadDate = DateTimeOffset.UtcNow,
IsDeleted = false, IsDeleted = false,
Size = newItem.Size, Size = newItem.Size,
}; };
@ -278,11 +275,11 @@ namespace AsbCloudInfrastructure.Repository
private static FileInfoDto Convert(FileInfo entity, double timezoneOffset) private static FileInfoDto Convert(FileInfo entity, double timezoneOffset)
{ {
var dto = entity.Adapt<FileInfoDto>(); var dto = entity.Adapt<FileInfoDto>();
dto.UploadDate = entity.UploadDate.ToRemoteDateTime(timezoneOffset); dto.UploadDate = entity.UploadDate.ToOffset(TimeSpan.FromHours(timezoneOffset));
dto.FileMarks = entity.FileMarks.Select(m => dto.FileMarks = entity.FileMarks.Select(m =>
{ {
var mark = m.Adapt<FileMarkDto>(); var mark = m.Adapt<FileMarkDto>();
mark.DateCreated = m.DateCreated.ToRemoteDateTime(timezoneOffset); mark.DateCreated = m.DateCreated.ToOffset(TimeSpan.FromHours(timezoneOffset));
return mark; return mark;
}); });
return dto; return dto;

View File

@ -39,8 +39,8 @@ namespace AsbCloudInfrastructure.Repository
IdWell = request.IdWell, IdWell = request.IdWell,
IdTelemetry = x.IdTelemetry, IdTelemetry = x.IdTelemetry,
IdFeedRegulator = x.IdFeedRegulator, IdFeedRegulator = x.IdFeedRegulator,
DateStart = DateTime.SpecifyKind(x.DateStart.UtcDateTime + timezoneSpan, DateTimeKind.Unspecified), DateStart = x.DateStart.ToOffset(timezoneSpan),
DateEnd = DateTime.SpecifyKind(x.DateEnd.UtcDateTime + timezoneSpan, DateTimeKind.Unspecified), DateEnd = x.DateEnd.ToOffset(timezoneSpan),
DepthStart = x.DepthStart, DepthStart = x.DepthStart,
DepthEnd = x.DepthEnd DepthEnd = x.DepthEnd
}); });
@ -56,13 +56,13 @@ namespace AsbCloudInfrastructure.Repository
if (request.GtDate.HasValue) if (request.GtDate.HasValue)
{ {
var gtDate = request.GtDate.Value.ToUtcDateTimeOffset(timezoneHours); var gtDate = request.GtDate.Value.ToUniversalTime();
query = query.Where(x => x.DateEnd >= gtDate); query = query.Where(x => x.DateEnd >= gtDate);
} }
if (request.LtDate.HasValue) if (request.LtDate.HasValue)
{ {
var ltDate = request.LtDate.Value.ToUtcDateTimeOffset(timezoneHours); var ltDate = request.LtDate.Value.ToUniversalTime();
query = query.Where(x => x.DateStart <= ltDate); query = query.Where(x => x.DateStart <= ltDate);
} }

View File

@ -110,10 +110,10 @@ public class NotificationRepository : CrudRepositoryBase<NotificationDto, Notifi
query = query.Where(n => n.IdNotificationCategory == request.IdCategory.Value); query = query.Where(n => n.IdNotificationCategory == request.IdCategory.Value);
if (request.LtSentDate.HasValue) if (request.LtSentDate.HasValue)
query = query.Where(n => n.SentDate <= request.LtSentDate.Value); query = query.Where(n => n.SentDate <= request.LtSentDate.Value.ToUniversalTime());
if (request.LtReadDate.HasValue) if (request.LtReadDate.HasValue)
query = query.Where(n => n.ReadDate <= request.LtReadDate.Value); query = query.Where(n => n.ReadDate <= request.LtReadDate.Value.ToUniversalTime());
dbContext.Notifications.RemoveRange(query); dbContext.Notifications.RemoveRange(query);

View File

@ -24,7 +24,7 @@ namespace AsbCloudInfrastructure.Repository
this.wellService = wellService; this.wellService = wellService;
} }
public async Task<IEnumerable<ScheduleDto>> GetAsync(int idWell, DateTime workTime, CancellationToken token) public async Task<IEnumerable<ScheduleDto>> GetAsync(int idWell, DateTimeOffset workTime, CancellationToken token)
{ {
var entities = await BuildQuery(idWell, workTime) var entities = await BuildQuery(idWell, workTime)
.AsNoTracking() .AsNoTracking()
@ -33,7 +33,7 @@ namespace AsbCloudInfrastructure.Repository
return entities.Select(Convert); return entities.Select(Convert);
} }
public async Task<DrillerDto?> GetOrDefaultDrillerAsync(int idWell, DateTime workTime, CancellationToken token) public async Task<DrillerDto?> GetOrDefaultDrillerAsync(int idWell, DateTimeOffset workTime, CancellationToken token)
{ {
var entities = await BuildQuery(idWell, workTime) var entities = await BuildQuery(idWell, workTime)
.AsNoTracking() .AsNoTracking()
@ -43,8 +43,7 @@ namespace AsbCloudInfrastructure.Repository
return null; return null;
var hoursOffset = wellService.GetTimezone(idWell).Hours; var hoursOffset = wellService.GetTimezone(idWell).Hours;
var remoteDate = workTime.ToUtcDateTimeOffset(hoursOffset).ToRemoteDateTime(hoursOffset); var time = new TimeOnly(workTime.Hour, workTime.Minute, workTime.Second);
var time = new TimeOnly(remoteDate.Hour, remoteDate.Minute, remoteDate.Second);
var entity = entities.FirstOrDefault(s => var entity = entities.FirstOrDefault(s =>
s.ShiftStart > s.ShiftEnd ^ s.ShiftStart > s.ShiftEnd ^
@ -69,11 +68,11 @@ namespace AsbCloudInfrastructure.Repository
} }
private IQueryable<Schedule> BuildQuery(int idWell, DateTime workTime) private IQueryable<Schedule> BuildQuery(int idWell, DateTimeOffset workTime)
{ {
var hoursOffset = wellService.GetTimezone(idWell).Hours; var hoursOffset = wellService.GetTimezone(idWell).Hours;
var workTimeDateTime = workTime.ToUtcDateTimeOffset(hoursOffset); var workTimeDateTime = workTime.ToUniversalTime();
return GetQuery().Where(s => s.IdWell == idWell return GetQuery().Where(s => s.IdWell == idWell
&& s.DrillStart <= workTimeDateTime && s.DrillStart <= workTimeDateTime
@ -82,19 +81,20 @@ namespace AsbCloudInfrastructure.Repository
protected override Schedule Convert(ScheduleDto dto) protected override Schedule Convert(ScheduleDto dto)
{ {
var hoursOffset = wellService.GetTimezone(dto.IdWell).Hours;
var entity = base.Convert(dto); var entity = base.Convert(dto);
entity.DrillStart = dto.DrillStart.ToUtcDateTimeOffset(hoursOffset); entity.DrillStart = dto.DrillStart.ToUniversalTime();
entity.DrillEnd = dto.DrillEnd.ToUtcDateTimeOffset(hoursOffset); entity.DrillEnd = dto.DrillEnd.ToUniversalTime();
return entity; return entity;
} }
protected override ScheduleDto Convert(Schedule entity) protected override ScheduleDto Convert(Schedule entity)
{ {
var hoursOffset = wellService.GetTimezone(entity.IdWell).Hours; var hoursOffset = wellService.GetTimezone(entity.IdWell).Hours;
var timeSpan = TimeSpan.FromHours(hoursOffset);
var dto = base.Convert(entity); var dto = base.Convert(entity);
dto.DrillStart = entity.DrillStart.ToRemoteDateTime(hoursOffset); dto.DrillStart = entity.DrillStart.ToOffset(timeSpan);
dto.DrillEnd = entity.DrillEnd.ToRemoteDateTime(hoursOffset); dto.DrillEnd = entity.DrillEnd.ToOffset(timeSpan);
return dto; return dto;
} }
} }

View File

@ -50,15 +50,14 @@ namespace AsbCloudInfrastructure.Repository
{ {
var result = base.Convert(src); var result = base.Convert(src);
var timezoneOffsetHours = wellService.GetTimezone(src.IdWell).Hours; var timezoneOffsetHours = wellService.GetTimezone(src.IdWell).Hours;
result.UploadDate = src.UploadDate.ToRemoteDateTime(timezoneOffsetHours); result.UploadDate = src.UploadDate.ToOffset(TimeSpan.FromHours(timezoneOffsetHours));
return result; return result;
} }
protected override SetpointsRequest Convert(SetpointsRequestDto src) protected override SetpointsRequest Convert(SetpointsRequestDto src)
{ {
var result = base.Convert(src); var result = base.Convert(src);
var timezoneOffsetHours = wellService.GetTimezone(src.IdWell).Hours; result.UploadDate = src.UploadDate.ToUniversalTime();
result.UploadDate = src.UploadDate.ToUtcDateTimeOffset(timezoneOffsetHours);
return result; return result;
} }
} }

View File

@ -5,6 +5,7 @@ using AsbCloudApp.Services;
using AsbCloudDb.Model; using AsbCloudDb.Model;
using Mapster; using Mapster;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
@ -93,14 +94,14 @@ namespace AsbCloudInfrastructure.Repository
{ {
var entity = dto.Adapt<TelemetryWirelineRunOut>(); var entity = dto.Adapt<TelemetryWirelineRunOut>();
entity.IdTelemetry = idTelemetry; entity.IdTelemetry = idTelemetry;
entity.DateTime = dto.DateTime.ToUtcDateTimeOffset(timezoneOffset); entity.DateTime = dto.DateTime.ToUniversalTime();
return entity; return entity;
} }
private static TelemetryWirelineRunOutDto Convert(TelemetryWirelineRunOut entity, WellDto well, double timezoneOffset) private static TelemetryWirelineRunOutDto Convert(TelemetryWirelineRunOut entity, WellDto well, double timezoneOffset)
{ {
var dto = entity.Adapt<TelemetryWirelineRunOutDto>(); var dto = entity.Adapt<TelemetryWirelineRunOutDto>();
dto.DateTime = entity.DateTime.ToRemoteDateTime(timezoneOffset); dto.DateTime = entity.DateTime.ToOffset(TimeSpan.FromHours(timezoneOffset));
dto.WellInfo = well; dto.WellInfo = well;
return dto; return dto;
} }

View File

@ -37,11 +37,10 @@ namespace AsbCloudInfrastructure.Repository
if (!trajectoryRows.All(r => r.IdWell == idWell)) if (!trajectoryRows.All(r => r.IdWell == idWell))
throw new ArgumentInvalidException(nameof(trajectoryRows), "Все строки должны относиться к одной скважине"); throw new ArgumentInvalidException(nameof(trajectoryRows), "Все строки должны относиться к одной скважине");
var offsetHours = wellService.GetTimezone(idWell).Hours;
var entities = trajectoryRows var entities = trajectoryRows
.Select(e => .Select(e =>
{ {
var entity = Convert(e, offsetHours); var entity = Convert(e);
entity.Id = 0; entity.Id = 0;
return entity; return entity;
}); });
@ -52,8 +51,7 @@ namespace AsbCloudInfrastructure.Repository
public async Task<int> AddAsync(Tdto trajectoryRow, CancellationToken token) public async Task<int> AddAsync(Tdto trajectoryRow, CancellationToken token)
{ {
var offsetHours = wellService.GetTimezone(trajectoryRow.IdWell).Hours; var entity = Convert(trajectoryRow);
var entity = Convert(trajectoryRow, offsetHours);
entity.Id = 0; entity.Id = 0;
db.Set<TEntity>().Add(entity); db.Set<TEntity>().Add(entity);
return await db.SaveChangesAsync(token) return await db.SaveChangesAsync(token)
@ -98,8 +96,7 @@ namespace AsbCloudInfrastructure.Repository
public async Task<int> UpdateAsync(Tdto row, CancellationToken token) public async Task<int> UpdateAsync(Tdto row, CancellationToken token)
{ {
var offsetHours = wellService.GetTimezone(row.IdWell).Hours; var entity = Convert(row);
var entity = Convert(row, offsetHours);
db.Set<TEntity>().Update(entity); db.Set<TEntity>().Update(entity);
return await db.SaveChangesAsync(token) return await db.SaveChangesAsync(token)
.ConfigureAwait(false); .ConfigureAwait(false);
@ -108,14 +105,14 @@ namespace AsbCloudInfrastructure.Repository
private static Tdto Convert(TEntity entity, double offsetHours) private static Tdto Convert(TEntity entity, double offsetHours)
{ {
var dto = entity.Adapt<Tdto>(); var dto = entity.Adapt<Tdto>();
dto.UpdateDate = entity.UpdateDate.ToRemoteDateTime(offsetHours); dto.UpdateDate = entity.UpdateDate.ToOffset(TimeSpan.FromHours(offsetHours));
return dto; return dto;
} }
private static TEntity Convert(Tdto dto, double offsetHours) private static TEntity Convert(Tdto dto)
{ {
var entity = dto.Adapt<TEntity>(); var entity = dto.Adapt<TEntity>();
entity.UpdateDate = DateTime.Now.ToUtcDateTimeOffset(offsetHours); entity.UpdateDate = DateTimeOffset.UtcNow;
return entity; return entity;
} }
} }

View File

@ -38,13 +38,13 @@ namespace AsbCloudInfrastructure.Repository
if (request.GeDate.HasValue) if (request.GeDate.HasValue)
{ {
var geDate = request.GeDate.Value.ToUtcDateTimeOffset(timezone.Hours); var geDate = request.GeDate.Value.ToUniversalTime();
query = query.Where(r => r.DateTime >= geDate); query = query.Where(r => r.DateTime >= geDate);
} }
if (request.LeDate.HasValue) if (request.LeDate.HasValue)
{ {
var leDate = request.LeDate.Value.ToUtcDateTimeOffset(timezone.Hours); var leDate = request.LeDate.Value.ToUniversalTime();
query = query.Where(r => r.DateTime <= leDate); query = query.Where(r => r.DateTime <= leDate);
} }

View File

@ -1,11 +1,10 @@
using AsbCloudApp.Data; using AsbCloudApp.Repositories;
using AsbCloudApp.Repositories;
using AsbCloudDb.Model; using AsbCloudDb.Model;
using Mapster; using Mapster;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using AsbCloudApp.Data.WellOperation;
namespace AsbCloudInfrastructure.Repository; namespace AsbCloudInfrastructure.Repository;

View File

@ -1,4 +1,11 @@
using AsbCloudApp.Data; using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Data.WellOperation;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories; using AsbCloudApp.Repositories;
using AsbCloudApp.Requests; using AsbCloudApp.Requests;
using AsbCloudApp.Services; using AsbCloudApp.Services;
@ -7,265 +14,75 @@ using AsbCloudDb.Model;
using Mapster; using Mapster;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Repository; namespace AsbCloudInfrastructure.Repository;
/// <summary> public class WellOperationRepository : CrudRepositoryBase<WellOperationDto, WellOperation>,
/// репозиторий операций по скважине IWellOperationRepository
/// </summary>
public class WellOperationRepository : IWellOperationRepository
{ {
private const string KeyCacheSections = "OperationsBySectionSummarties";
private readonly IAsbCloudDbContext db;
private readonly IMemoryCache memoryCache; private readonly IMemoryCache memoryCache;
private readonly IWellService wellService;
private readonly IWellOperationCategoryRepository wellOperationCategoryRepository; private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
private readonly IWellService wellService;
public WellOperationRepository(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService, IWellOperationCategoryRepository wellOperationCategoryRepository) public WellOperationRepository(IAsbCloudDbContext context,
IMemoryCache memoryCache,
IWellOperationCategoryRepository wellOperationCategoryRepository,
IWellService wellService)
: base(context, dbSet => dbSet.Include(e => e.WellSectionType)
.Include(e => e.OperationCategory))
{ {
this.db = db;
this.memoryCache = memoryCache; this.memoryCache = memoryCache;
this.wellService = wellService;
this.wellOperationCategoryRepository = wellOperationCategoryRepository; this.wellOperationCategoryRepository = wellOperationCategoryRepository;
this.wellService = wellService;
} }
public IEnumerable<WellSectionTypeDto> GetSectionTypes() => public IEnumerable<WellSectionTypeDto> GetSectionTypes() =>
memoryCache memoryCache
.GetOrCreateBasic(db.Set<WellSectionType>()) .GetOrCreateBasic(dbContext.WellSectionTypes)
.OrderBy(s => s.Order) .OrderBy(s => s.Order)
.Select(s => s.Adapt<WellSectionTypeDto>()); .Select(s => s.Adapt<WellSectionTypeDto>());
public async Task<WellOperationPlanDto> GetOperationsPlanAsync(int idWell, DateTime? currentDate, CancellationToken token) public async Task<IEnumerable<WellOperationDto>> GetAsync(WellOperationRequest request, CancellationToken token)
{
var timezone = wellService.GetTimezone(idWell);
var request = new WellOperationRequest()
{
IdWell = idWell,
OperationType = WellOperation.IdOperationTypePlan,
};
var dtos = await BuildQuery(request)
.AsNoTracking()
.ToArrayAsync(token);
var dateLastAssosiatedPlanOperation = await GetDateLastAssosiatedPlanOperationAsync(idWell, currentDate, timezone.Hours, token);
var result = new WellOperationPlanDto()
{
WellOperationsPlan = dtos.Select(Convert),
DateLastAssosiatedPlanOperation = dateLastAssosiatedPlanOperation
};
return result;
}
private async Task<DateTime?> GetDateLastAssosiatedPlanOperationAsync(
int idWell,
DateTime? lessThenDate,
double timeZoneHours,
CancellationToken token)
{
if (lessThenDate is null)
return null;
var currentDateOffset = lessThenDate.Value.ToUtcDateTimeOffset(timeZoneHours);
var timeZoneOffset = TimeSpan.FromHours(timeZoneHours);
var lastFactOperation = await db.WellOperations
.Where(o => o.IdWell == idWell)
.Where(o => o.IdType == WellOperation.IdOperationTypeFact)
.Where(o => o.IdPlan != null)
.Where(o => o.DateStart < currentDateOffset)
.Include(x => x.OperationPlan)
.OrderByDescending(x => x.DateStart)
.FirstOrDefaultAsync(token)
.ConfigureAwait(false);
if (lastFactOperation is not null)
return DateTime.SpecifyKind(lastFactOperation.OperationPlan!.DateStart.UtcDateTime + timeZoneOffset, DateTimeKind.Unspecified);
return null;
}
/// <inheritdoc/>
public async Task<IEnumerable<SectionByOperationsDto>> GetSectionsAsync(IEnumerable<int> idsWells, CancellationToken token)
{
var cache = await memoryCache.GetOrCreateAsync(KeyCacheSections, async (entry) =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30);
var query = db.Set<WellOperation>()
.GroupBy(operation => new
{
operation.IdWell,
operation.IdType,
operation.IdWellSectionType,
operation.WellSectionType.Caption,
})
.Select(group => new
{
group.Key.IdWell,
group.Key.IdType,
group.Key.IdWellSectionType,
group.Key.Caption,
First = group
.OrderBy(operation => operation.DateStart)
.Select(operation => new
{
operation.DateStart,
operation.DepthStart,
})
.First(),
Last = group
.OrderByDescending(operation => operation.DateStart)
.Select(operation => new
{
operation.DateStart,
operation.DurationHours,
operation.DepthEnd,
})
.First(),
});
var dbData = await query.ToArrayAsync(token);
var sections = dbData.Select(
item => new SectionByOperationsDto
{
IdWell = item.IdWell,
IdType = item.IdType,
IdWellSectionType = item.IdWellSectionType,
Caption = item.Caption,
DateStart = item.First.DateStart,
DepthStart = item.First.DepthStart,
DateEnd = item.Last.DateStart.AddHours(item.Last.DurationHours),
DepthEnd = item.Last.DepthEnd,
})
.ToArray()
.AsEnumerable();
entry.Value = sections;
return sections;
});
var sections = cache.Where(s => idsWells.Contains(s.IdWell));
return sections;
}
public async Task<DatesRangeDto?> GetDatesRangeAsync(int idWell, int idType, CancellationToken cancellationToken)
{
var timezone = wellService.GetTimezone(idWell);
var query = db.WellOperations.Where(o => o.IdWell == idWell && o.IdType == idType);
if (!await query.AnyAsync(cancellationToken))
return null;
var minDate = await query.MinAsync(o => o.DateStart, cancellationToken);
var maxDate = await query.MaxAsync(o => o.DateStart, cancellationToken);
return new DatesRangeDto
{
From = minDate.ToRemoteDateTime(timezone.Hours),
To = maxDate.ToRemoteDateTime(timezone.Hours)
};
}
/// <inheritdoc/>
public DateTimeOffset? FirstOperationDate(int idWell)
{
var sections = GetSectionsAsync(new[] { idWell }, CancellationToken.None).Result;
var first = sections.FirstOrDefault(section => section.IdType == WellOperation.IdOperationTypeFact)
?? sections.FirstOrDefault(section => section.IdType == WellOperation.IdOperationTypePlan);
return first?.DateStart;
}
/// <inheritdoc/>
public async Task<IEnumerable<WellOperationDto>> GetAsync(
WellOperationRequest request,
CancellationToken token)
{
var query = BuildQuery(request)
.AsNoTracking();
var dtos = await query.ToArrayAsync(token);
return dtos.Select(Convert);
}
public async Task<IEnumerable<WellOperationDataDto>> GetAsync(
WellsOperationRequest request,
CancellationToken token)
{
var query = BuildQuery(request)
.AsNoTracking();
var dtos = await query.ToArrayAsync(token);
return dtos;
}
/// <inheritdoc/>
public async Task<PaginationContainer<WellOperationDto>> GetPageAsync(
WellOperationRequest request,
CancellationToken token)
{ {
var query = BuildQuery(request); var query = BuildQuery(request);
var result = new PaginationContainer<WellOperationDto> if (request.Skip.HasValue)
query = query.Skip(request.Skip.Value);
if (request.Take.HasValue)
query = query.Take(request.Take.Value);
var entities = await query.AsNoTracking()
.ToArrayAsync(token);
return await ConvertWithDrillingDaysAndNpvHoursAsync(entities, token);
}
public async Task<PaginationContainer<WellOperationDto>> GetPageAsync(WellOperationRequest request, CancellationToken token)
{ {
Skip = request.Skip ?? 0, var skip = request.Skip ?? 0;
Take = request.Take ?? 32, var take = request.Take ?? 32;
var query = BuildQuery(request);
var entities = await query.Skip(skip)
.Take(take)
.AsNoTracking()
.ToArrayAsync(token);
var paginationContainer = new PaginationContainer<WellOperationDto>
{
Skip = skip,
Take = take,
Count = await query.CountAsync(token), Count = await query.CountAsync(token),
Items = await ConvertWithDrillingDaysAndNpvHoursAsync(entities, token)
}; };
var dtos = await query.ToArrayAsync(token); return paginationContainer;
result.Items = dtos.Select(Convert);
return result;
} }
/// <inheritdoc/> public async Task<IEnumerable<WellGroupOpertionDto>> GetGroupOperationsStatAsync(WellOperationRequest request, CancellationToken token)
public async Task<WellOperationDto?> GetOrDefaultAsync(int id,
CancellationToken token)
{ {
var entity = await db.WellOperations
.Include(s => s.WellSectionType)
.Include(s => s.OperationCategory)
.FirstOrDefaultAsync(e => e.Id == id, token)
.ConfigureAwait(false);
if (entity is null)
return null;
var timezone = wellService.GetTimezone(entity.IdWell);
var dto = entity.Adapt<WellOperationDto>();
dto.WellSectionTypeName = entity.WellSectionType.Caption;
dto.DateStart = entity.DateStart.ToRemoteDateTime(timezone.Hours);
dto.CategoryName = entity.OperationCategory.Name;
return dto;
}
/// <inheritdoc/>
public async Task<IEnumerable<WellGroupOpertionDto>> GetGroupOperationsStatAsync(
WellOperationRequest request,
CancellationToken token)
{
// TODO: Rename controller method
request.OperationType = WellOperation.IdOperationTypeFact;
var query = BuildQuery(request); var query = BuildQuery(request);
var entities = await query var entities = await query
.Select(o => new .Select(o => new
@ -274,7 +91,8 @@ public class WellOperationRepository : IWellOperationRepository
DurationMinutes = o.DurationHours * 60, DurationMinutes = o.DurationHours * 60,
DurationDepth = o.DepthEnd - o.DepthStart DurationDepth = o.DepthEnd - o.DepthStart
}) })
.ToListAsync(token); .ToArrayAsync(token);
var parentRelationDictionary = wellOperationCategoryRepository.Get(true) var parentRelationDictionary = wellOperationCategoryRepository.Get(true)
.ToDictionary(c => c.Id, c => new .ToDictionary(c => c.Id, c => new
{ {
@ -318,91 +136,62 @@ public class WellOperationRepository : IWellOperationRepository
return newDto; return newDto;
}); });
} }
return dtos; return dtos;
} }
/// <inheritdoc/> public async Task<int> InsertRangeAsync(IEnumerable<WellOperationDto> dtos,
public async Task<int> InsertRangeAsync( bool deleteBeforeInsert,
IEnumerable<WellOperationDto> wellOperationDtos,
CancellationToken token) CancellationToken token)
{ {
var firstOperation = wellOperationDtos EnsureValidWellOperations(dtos);
.FirstOrDefault();
if (firstOperation is null)
return 0;
var idWell = firstOperation.IdWell; if (!deleteBeforeInsert)
return await InsertRangeAsync(dtos, token);
var timezone = wellService.GetTimezone(idWell); var idType = dtos.First().IdType;
foreach (var dto in wellOperationDtos) var idWell = dtos.First().IdWell;
{
var entity = dto.Adapt<WellOperation>(); var existingOperationIds = await dbContext.WellOperations
entity.Id = default; .Where(e => e.IdWell == idWell && e.IdType == idType)
entity.DateStart = dto.DateStart.DateTime.ToUtcDateTimeOffset(timezone.Hours); .Select(e => e.Id)
entity.IdWell = idWell; .ToArrayAsync(token);
entity.LastUpdateDate = DateTimeOffset.UtcNow;
db.WellOperations.Add(entity); await DeleteRangeAsync(existingOperationIds, token);
return await InsertRangeAsync(dtos, token);
} }
var result = await db.SaveChangesAsync(token); public override Task<int> UpdateRangeAsync(IEnumerable<WellOperationDto> dtos, CancellationToken token)
if (result > 0) {
memoryCache.Remove(KeyCacheSections); EnsureValidWellOperations(dtos);
return result;
return base.UpdateRangeAsync(dtos, token);
} }
/// <inheritdoc/> private static void EnsureValidWellOperations(IEnumerable<WellOperationDto> dtos)
public async Task<int> UpdateAsync(
WellOperationDto dto, CancellationToken token)
{ {
var timezone = wellService.GetTimezone(dto.IdWell); if (dtos.GroupBy(d => d.IdType).Count() > 1)
var entity = dto.Adapt<WellOperation>(); throw new ArgumentInvalidException(nameof(dtos), "Все операции должны быть одного типа");
entity.DateStart = dto.DateStart.DateTime.ToUtcDateTimeOffset(timezone.Hours);
entity.LastUpdateDate = DateTimeOffset.UtcNow;
db.WellOperations.Update(entity);
var result = await db.SaveChangesAsync(token); if (dtos.GroupBy(d => d.IdType).Count() > 1)
if (result > 0) throw new ArgumentInvalidException(nameof(dtos), "Все операции должны принадлежать одной скважине");
memoryCache.Remove(KeyCacheSections);
return result;
} }
/// <inheritdoc/> private IQueryable<WellOperation> BuildQuery(WellOperationRequest request)
public async Task<int> DeleteAsync(IEnumerable<int> ids,
CancellationToken token)
{ {
var query = db.WellOperations.Where(e => ids.Contains(e.Id)); var query = GetQuery()
db.WellOperations.RemoveRange(query); .Where(e => request.IdsWell != null && request.IdsWell.Contains(e.IdWell))
.OrderBy(e => e.DateStart)
var result = await db.SaveChangesAsync(token); .AsQueryable();
if (result > 0)
memoryCache.Remove(KeyCacheSections);
return result;
}
/// <summary>
/// В результате попрежнему требуется конвертировать дату
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
private IQueryable<WellOperationDto> BuildQuery(WellOperationRequest request)
{
var timezone = wellService.GetTimezone(request.IdWell);
var timeZoneOffset = timezone.Hours;
var query = db.WellOperations
.Include(s => s.WellSectionType)
.Include(s => s.OperationCategory)
.Where(o => o.IdWell == request.IdWell);
if (request.OperationType.HasValue) if (request.OperationType.HasValue)
query = query.Where(e => e.IdType == request.OperationType.Value); query = query.Where(e => e.IdType == request.OperationType.Value);
if (request.SectionTypeIds?.Any() == true) if (request.SectionTypeIds?.Any() is true)
query = query.Where(e => request.SectionTypeIds.Contains(e.IdWellSectionType)); query = query.Where(e => request.SectionTypeIds.Contains(e.IdWellSectionType));
if (request.OperationCategoryIds?.Any() == true) if (request.OperationCategoryIds?.Any() is true)
query = query.Where(e => request.OperationCategoryIds.Contains(e.IdCategory)); query = query.Where(e => request.OperationCategoryIds.Contains(e.IdCategory));
if (request.GeDepth.HasValue) if (request.GeDepth.HasValue)
@ -413,291 +202,162 @@ public class WellOperationRepository : IWellOperationRepository
if (request.GeDate.HasValue) if (request.GeDate.HasValue)
{ {
var geDateOffset = request.GeDate.Value.ToUtcDateTimeOffset(timeZoneOffset); var geDateUtc = request.GeDate.Value.UtcDateTime;
query = query.Where(e => e.DateStart >= geDateOffset);
}
if (request.LtDate.HasValue)
{
var ltDateOffset = request.LtDate.Value.ToUtcDateTimeOffset(timeZoneOffset);
query = query.Where(e => e.DateStart < ltDateOffset);
}
var currentWellOperations = db.WellOperations
.Where(subOp => subOp.IdWell == request.IdWell);
var wellOperationsWithCategoryNpt = currentWellOperations
.Where(subOp => subOp.IdType == 1)
.Where(subOp => WellOperationCategory.NonProductiveTimeSubIds.Contains(subOp.IdCategory));
var firstOperations = db.Set<WellOperation>()
.Where(o => o.IdWell == request.IdWell)
.GroupBy(o => o.IdType)
.Select(group => new {
idType = group.Key,
Date = group.Min(o => o.DateStart),
}).ToDictionary(e => e.idType, e => e.Date);
var dtos = query.Select(o => new WellOperationDto
{
Id = o.Id,
IdPlan = o.IdPlan,
IdType = o.IdType,
IdWell = o.IdWell,
IdWellSectionType = o.IdWellSectionType,
IdCategory = o.IdCategory,
IdParentCategory = o.OperationCategory.IdParent,
CategoryName = o.OperationCategory.Name,
WellSectionTypeName = o.WellSectionType.Caption,
DateStart = o.DateStart,
DepthStart = o.DepthStart,
DepthEnd = o.DepthEnd,
DurationHours = o.DurationHours,
CategoryInfo = o.CategoryInfo,
Comment = o.Comment,
NptHours = wellOperationsWithCategoryNpt
.Where(subOp => subOp.DateStart <= o.DateStart)
.Select(subOp => subOp.DurationHours)
.Sum(),
Day = (o.DateStart - firstOperations[o.IdType])
.TotalDays,
IdUser = o.IdUser,
LastUpdateDate = o.LastUpdateDate,
});
if (request.SortFields?.Any() == true)
{
dtos = dtos.SortBy(request.SortFields);
}
dtos = dtos
.OrderBy(e => e.DateStart)
.ThenBy(e => e.DepthEnd)
.ThenBy(e => e.Id);
if (request.Skip.HasValue)
dtos = dtos.Skip(request.Skip.Value);
if (request.Take.HasValue)
dtos = dtos.Take(request.Take.Value);
return dtos.AsNoTracking();
}
/// <summary>
/// Получение данных по запросу
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
private IQueryable<WellOperationDataDto> BuildQuery(WellsOperationRequest request)
{
var query = db.WellOperations
.Where(o => request.IdsWell.Contains(o.IdWell))
.Where(o => request.OperationType == o.IdType);
if (request.SectionTypeIds?.Any() == true)
query = query.Where(o => request.SectionTypeIds.Contains(o.IdWellSectionType));
if (request.OperationCategoryIds?.Any() == true)
query = query.Where(o => request.OperationCategoryIds.Contains(o.IdCategory));
// TODO: Вынести query.Select из метода BuildQuery
var dtos = query.Select(o => new WellOperationDataDto
{
DepthStart = o.DepthStart,
DurationHours = o.DurationHours,
IdCategory = o.IdCategory,
IdWell = o.IdWell,
IdWellSectionType = o.IdWellSectionType,
OperationCategoryName = o.OperationCategory.Name,
WellSectionTypeCaption = o.WellSectionType.Caption,
});
if (request.SortFields?.Any() == true)
{
dtos = dtos.SortBy(request.SortFields);
}
if (request.Skip.HasValue)
dtos = dtos.Skip(request.Skip.Value);
if (request.Take.HasValue)
dtos = dtos.Take(request.Take.Value);
return dtos.AsNoTracking();
}
private WellOperationDto Convert(WellOperationDto dto)
{
var timezone = wellService.GetTimezone(dto.IdWell);
var timezoneOffset = TimeSpan.FromHours(timezone.Hours);
var dtoWithRemoteDateTime = dto.Adapt<WellOperationDto>();
dtoWithRemoteDateTime.DateStart = dto.DateStart.ToOffset(TimeSpan.FromHours(timezoneOffset.Hours));
dtoWithRemoteDateTime.LastUpdateDate = dto.LastUpdateDate?.ToOffset(TimeSpan.FromHours(timezoneOffset.Hours));
return dtoWithRemoteDateTime;
}
public async Task<int> RemoveDuplicates(Action<string, double?> onProgressCallback, CancellationToken token)
{
IQueryable<WellOperation> dbset = db.Set<WellOperation>();
var query = dbset
.GroupBy(o => new { o.IdWell, o.IdType })
.Select(g => new { g.Key.IdWell, g.Key.IdType });
var groups = await query
.ToArrayAsync(token);
var count = groups.Count();
var i = 0;
var totalRemoved = 0;
var total = 0;
foreach (var group in groups)
{
var result = await RemoveDuplicatesInGroup(group.IdWell, group.IdType, token);
totalRemoved += result.removed;
total += result.total;
var percent = i++ / count;
var message = $"RemoveDuplicates [{i} of {count}] wellId: {group.IdWell}, opType: {group.IdType}, affected: {result.removed} of {result.total}";
onProgressCallback?.Invoke(message, percent);
Trace.TraceInformation(message);
}
var messageDone = $"RemoveDuplicates done [{i} of {count}] totalAffected: {totalRemoved} of {total}";
Trace.TraceInformation(messageDone);
onProgressCallback?.Invoke(messageDone, 1);
return totalRemoved;
}
private async Task<(int removed, int total)> RemoveDuplicatesInGroup(int idWell, int idType, CancellationToken token)
{
var dbset = db.Set<WellOperation>();
var entities = await dbset
.Where(o => o.IdWell == idWell && o.IdType == idType)
.OrderBy(o => o.DateStart)
.ToListAsync(token);
using var entitiesEnumerator = entities.GetEnumerator();
if (!entitiesEnumerator.MoveNext())
return (0, 0);
var preEntity = entitiesEnumerator.Current;
while (entitiesEnumerator.MoveNext())
{
var entity = entitiesEnumerator.Current;
if (preEntity.IsSame(entity))
dbset.Remove(entity);
else
preEntity = entity;
}
var removed = await db.SaveChangesAsync(token);
return (removed, entities.Count);
}
public async Task<int> TrimOverlapping(DateTimeOffset? geDate, DateTimeOffset leDate, Action<string, double?> onProgressCallback, CancellationToken token)
{
var leDateUtc = leDate.ToUniversalTime();
IQueryable<WellOperation> query = db.Set<WellOperation>();
if (geDate.HasValue)
{
var geDateUtc = geDate.Value.ToUniversalTime();
query = query.Where(e => e.DateStart >= geDateUtc); query = query.Where(e => e.DateStart >= geDateUtc);
} }
var groups = await query if (request.LeDate.HasValue)
.GroupBy(o => new { o.IdWell, o.IdType }) {
.Select(g => new{ var leDateUtc = request.LeDate.Value.UtcDateTime;
MaxDate = g.Max(o => o.DateStart), query = query.Where(e => e.DateStart <= leDateUtc);
g.Key.IdWell, }
g.Key.IdType,
if (request.SortFields?.Any() is true)
query = query.SortBy(request.SortFields);
return query;
}
public async Task<IEnumerable<SectionByOperationsDto>> GetSectionsAsync(IEnumerable<int> idsWells, CancellationToken token)
{
const string keyCacheSections = "OperationsBySectionSummarties";
var cache = await memoryCache.GetOrCreateAsync(keyCacheSections, async (entry) =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30);
var query = dbContext.Set<WellOperation>()
.GroupBy(operation => new
{
operation.IdWell,
operation.IdType,
operation.IdWellSectionType,
operation.WellSectionType.Caption,
}) })
.Where(g => g.MaxDate <= leDateUtc) .Select(group => new
.ToArrayAsync(token);
var count = groups.Count();
var i = 0;
(int takeover, int trimmed,int total) totalResult = (0, 0, 0);
foreach (var group in groups)
{ {
var result = await TrimOverlapping(group.IdWell, group.IdType, token); group.Key.IdWell,
totalResult.takeover += result.takeover; group.Key.IdType,
totalResult.trimmed += result.trimmed; group.Key.IdWellSectionType,
totalResult.total += result.total; group.Key.Caption,
var percent = i++ / count;
var message = $"TrimOverlapping [{i} of {count}] wellId: {group.IdWell}, opType: {group.IdType}, takeover:{result.takeover}, trimmed:{result.trimmed}, of {result.total}"; First = group
onProgressCallback?.Invoke(message, percent); .OrderBy(operation => operation.DateStart)
Trace.TraceInformation(message); .Select(operation => new
} {
var messageDone = $"TrimOverlapping done [{i} of {count}] total takeover:{totalResult.takeover}, total trimmed:{totalResult.trimmed} of {totalResult.total}"; operation.DateStart,
Trace.TraceInformation(messageDone); operation.DepthStart,
onProgressCallback?.Invoke(messageDone, 1); })
return totalResult.takeover + totalResult.trimmed; .First(),
Last = group
.OrderByDescending(operation => operation.DateStart)
.Select(operation => new
{
operation.DateStart,
operation.DurationHours,
operation.DepthEnd,
})
.First(),
})
.Where(s => idsWells.Contains(s.IdWell));
var dbData = await query.ToArrayAsync(token);
var sections = dbData.Select(
item => new SectionByOperationsDto
{
IdWell = item.IdWell,
IdType = item.IdType,
IdWellSectionType = item.IdWellSectionType,
Caption = item.Caption,
DateStart = item.First.DateStart,
DepthStart = item.First.DepthStart,
DateEnd = item.Last.DateStart.AddHours(item.Last.DurationHours),
DepthEnd = item.Last.DepthEnd,
})
.ToArray()
.AsEnumerable();
entry.Value = sections;
return sections;
});
return cache;
} }
private async Task<(int takeover, int trimmed, int total)> TrimOverlapping(int idWell, int idType, CancellationToken token) public async Task<DatesRangeDto?> GetDatesRangeAsync(int idWell, int idType, CancellationToken cancellationToken)
{ {
var dbset = db.Set<WellOperation>(); var query = dbContext.WellOperations.Where(o => o.IdWell == idWell && o.IdType == idType);
var query = dbset
.Where(o => o.IdWell == idWell)
.Where(o => o.IdType == idType)
.OrderBy(o => o.DateStart)
.ThenBy(o => o.DepthStart);
var entities = await query if (!await query.AnyAsync(cancellationToken))
.ToListAsync(token); return null;
using var entitiesEnumerator = entities.GetEnumerator(); var timeZoneOffset = wellService.GetTimezone(idWell).Offset;
if (!entitiesEnumerator.MoveNext()) var minDate = await query.MinAsync(o => o.DateStart, cancellationToken);
return (0, 0, 0); var maxDate = await query.MaxAsync(o => o.DateStart, cancellationToken);
int takeover = 0; return new DatesRangeDto
int trimmed = 0;
var preEntity = entitiesEnumerator.Current;
while (entitiesEnumerator.MoveNext())
{ {
var entity = entitiesEnumerator.Current; From = minDate.ToOffset(timeZoneOffset),
var preDepth = preEntity.DepthEnd; To = maxDate.ToOffset(timeZoneOffset)
};
if (preEntity.DepthEnd >= entity.DepthEnd)
{
dbset.Remove(entity);
takeover++;
continue;
} }
if (preEntity.DepthEnd > entity.DepthStart) private async Task<IEnumerable<WellOperationDto>> ConvertWithDrillingDaysAndNpvHoursAsync(IEnumerable<WellOperation> entities,
CancellationToken token)
{ {
entity.DepthStart = preEntity.DepthEnd; var idsWell = entities.Select(e => e.IdWell).Distinct();
trimmed++;
}
var preDate = preEntity.DateStart.AddHours(preEntity.DurationHours); var currentWellOperations = GetQuery()
.Where(entity => idsWell.Contains(entity.IdWell));
if (preDate >= entity.DateStart.AddHours(entity.DurationHours)) var dateFirstDrillingOperationByIdWell = await currentWellOperations
.Where(entity => entity.IdType == WellOperation.IdOperationTypeFact)
.GroupBy(entity => entity.IdWell)
.ToDictionaryAsync(g => g.Key, g => g.Min(o => o.DateStart), token);
var operationsWithNptByIdWell = await currentWellOperations.Where(entity =>
entity.IdType == WellOperation.IdOperationTypeFact &&
WellOperationCategory.NonProductiveTimeSubIds.Contains(entity.IdCategory))
.GroupBy(entity => entity.IdWell)
.ToDictionaryAsync(g => g.Key, g => g.Select(o => o), token);
var dtos = entities.Select(entity =>
{ {
dbset.Remove(entity); var dto = Convert(entity);
takeover++;
continue; if (dateFirstDrillingOperationByIdWell.TryGetValue(entity.IdWell, out var dateFirstDrillingOperation))
dto.Day = (entity.DateStart - dateFirstDrillingOperation).TotalDays;
if (operationsWithNptByIdWell.TryGetValue(entity.IdWell, out var wellOperationsWithNtp))
dto.NptHours = wellOperationsWithNtp
.Where(o => o.DateStart <= entity.DateStart)
.Sum(e => e.DurationHours);
return dto;
});
return dtos;
} }
if (preDate > entity.DateStart) protected override WellOperation Convert(WellOperationDto src)
{ {
var entityDateEnd = entity.DateStart.AddHours(entity.DurationHours); var entity = src.Adapt<WellOperation>();
entity.DateStart = preDate; entity.DateStart = src.DateStart.UtcDateTime;
entity.DurationHours = (entityDateEnd - entity.DateStart).TotalHours; return entity;
trimmed++;
} }
preEntity = entity; protected override WellOperationDto Convert(WellOperation src)
} {
var affected = await db.SaveChangesAsync(token); //TODO: пока такое получение TimeZone скважины, нужно исправить на Lazy
return (takeover, trimmed, entities.Count); //Хоть мы и тянем данные из кэша, но от получения TimeZone в этом методе нужно избавиться, пока так
var timeZoneOffset = wellService.GetTimezone(src.IdWell).Offset;
var dto = src.Adapt<WellOperationDto>();
dto.DateStart = src.DateStart.ToOffset(timeZoneOffset);
dto.LastUpdateDate = src.LastUpdateDate.ToOffset(timeZoneOffset);
return dto;
} }
} }

View File

@ -13,6 +13,7 @@ using AsbCloudApp.Data.DailyReport.Blocks.Sign;
using AsbCloudApp.Data.DailyReport.Blocks.Subsystems; using AsbCloudApp.Data.DailyReport.Blocks.Subsystems;
using AsbCloudApp.Data.DailyReport.Blocks.TimeBalance; using AsbCloudApp.Data.DailyReport.Blocks.TimeBalance;
using AsbCloudApp.Data.DailyReport.Blocks.WellOperation; using AsbCloudApp.Data.DailyReport.Blocks.WellOperation;
using AsbCloudApp.Data.WellOperation;
using AsbCloudApp.Requests; using AsbCloudApp.Requests;
using AsbCloudApp.Services.DailyReport; using AsbCloudApp.Services.DailyReport;
using AsbCloudApp.Services.ProcessMaps.WellDrilling; using AsbCloudApp.Services.ProcessMaps.WellDrilling;
@ -83,7 +84,7 @@ public class DailyReportService : IDailyReportService
editableBlock.IdUser = idUser; editableBlock.IdUser = idUser;
editableBlock.LastUpdateDate = DateTime.UtcNow; editableBlock.LastUpdateDate = DateTime.UtcNow;
dailyReport.DateLastUpdate = DateTime.UtcNow; dailyReport.DateLastUpdate = DateTimeOffset.UtcNow;
if (dailyReport.Id == 0) if (dailyReport.Id == 0)
return await dailyReportRepository.InsertAsync(dailyReport, cancellationToken); return await dailyReportRepository.InsertAsync(dailyReport, cancellationToken);
@ -106,15 +107,15 @@ public class DailyReportService : IDailyReportService
IdWell = well.Id IdWell = well.Id
}; };
var geDate = dailyReport.Date.ToDateTime(TimeOnly.MinValue, DateTimeKind.Unspecified); var offsetHours = wellService.GetTimezone(dailyReport.IdWell).Hours;
var ltDate = dailyReport.Date.AddDays(1).ToDateTime(TimeOnly.MinValue, DateTimeKind.Unspecified); var geDate = new DateTimeOffset(dailyReport.Date, TimeOnly.MinValue, TimeSpan.FromHours(offsetHours));
var leDate = new DateTimeOffset(dailyReport.Date.AddDays(1), TimeOnly.MinValue, TimeSpan.FromHours(offsetHours));
var factOperationRequest = new WellOperationRequest var factOperationRequest = new WellOperationRequest(new []{ idWell })
{ {
IdWell = idWell,
OperationType = WellOperation.IdOperationTypeFact, OperationType = WellOperation.IdOperationTypeFact,
GeDate = geDate, GeDate = geDate,
LtDate = ltDate LeDate = leDate
}; };
var factWellOperations = (await wellOperationRepository.GetAsync(factOperationRequest, cancellationToken)) var factWellOperations = (await wellOperationRepository.GetAsync(factOperationRequest, cancellationToken))
@ -130,12 +131,12 @@ public class DailyReportService : IDailyReportService
dailyReport.DepthStart = factWellOperations.FirstOrDefault()?.DepthStart; dailyReport.DepthStart = factWellOperations.FirstOrDefault()?.DepthStart;
dailyReport.DepthEnd = factWellOperations.LastOrDefault()?.DepthEnd; dailyReport.DepthEnd = factWellOperations.LastOrDefault()?.DepthEnd;
await UpdateTimeBalanceBlockAsync(dailyReport, factWellOperations, cancellationToken); await UpdateTimeBalanceBlockAsync(dailyReport, factWellOperations, geDate, leDate, cancellationToken);
await UpdateSubsystemBlockAsync(dailyReport, cancellationToken); await UpdateSubsystemBlockAsync(dailyReport, geDate, leDate, cancellationToken);
await AddTrajectoryBlockAsync(dailyReport, cancellationToken); await AddTrajectoryBlockAsync(dailyReport, geDate, leDate, cancellationToken);
await AddScheduleBlockAsync(dailyReport, cancellationToken); await AddScheduleBlockAsync(dailyReport, geDate, cancellationToken);
await AddProcessMapWellDrillingBlockAsync(dailyReport, cancellationToken); await AddProcessMapWellDrillingBlockAsync(dailyReport, geDate, leDate, cancellationToken);
AddFactWellOperationBlock(dailyReport, factWellOperations); AddFactWellOperationBlock(dailyReport, factWellOperations);
@ -152,46 +153,43 @@ public class DailyReportService : IDailyReportService
Items = Enumerable.Empty<DailyReportDto>() Items = Enumerable.Empty<DailyReportDto>()
}; };
var datesRange = await GetDatesRangeAsync(idWell, cancellationToken); var datesRange = await wellOperationRepository.GetDatesRangeAsync(idWell, WellOperation.IdOperationTypeFact, cancellationToken);
if (datesRange is null) if (datesRange is null)
return result; return result;
var dailyReports = new List<DailyReportDto>(); var dailyReports = new List<DailyReportDto>();
TimeSpan offset = wellService.GetTimezone(idWell).Offset;
if (request.GeDate.HasValue) if (request.GeDate.HasValue)
{ {
var startDate = new DateTime(request.GeDate.Value.Year, request.GeDate.Value.Month, var startDate = new DateTimeOffset(request.GeDate.Value, TimeOnly.MinValue, offset);
request.GeDate.Value.Day);
if (startDate.Date >= datesRange.From.Date) if (startDate >= datesRange.From)
datesRange.From = startDate; datesRange.From = startDate;
} }
if (request.LeDate.HasValue) if (request.LeDate.HasValue)
{ {
var finishDate = new DateTime(request.LeDate.Value.Year, request.LeDate.Value.Month, var finishDate = new DateTimeOffset(request.LeDate.Value, TimeOnly.MinValue, offset);
request.LeDate.Value.Day);
if (finishDate.Date <= datesRange.To.Date) if (finishDate <= datesRange.To)
datesRange.To = finishDate; datesRange.To = finishDate;
} }
if (datesRange.From.AddDays(result.Skip) <= datesRange.To) result.Count = (int)(Math.Ceiling((datesRange.To - DateTimeOffset.UnixEpoch).TotalDays)
result.Count = (int)(Math.Ceiling((datesRange.To - DateTime.UnixEpoch).TotalDays) - - Math.Floor((datesRange.From - DateTimeOffset.UnixEpoch).TotalDays));
Math.Floor((datesRange.From - DateTime.UnixEpoch).TotalDays)) + 1;
var existingDailyReports = await dailyReportRepository.GetAsync(idWell, request, cancellationToken); var existingDailyReports = await dailyReportRepository.GetAsync(idWell, request, cancellationToken);
var geDateFactWellOperation = datesRange.From.AddDays(result.Skip); var geDateFactWellOperation = datesRange.From.AddDays(result.Skip);
var ltDateFactWellOperation = geDateFactWellOperation.AddDays(result.Take); var leDateFactWellOperation = geDateFactWellOperation.AddDays(result.Take);
var factWellOperationRequest = new WellOperationRequest var factWellOperationRequest = new WellOperationRequest(new[] { idWell })
{ {
IdWell = idWell,
OperationType = WellOperation.IdOperationTypeFact, OperationType = WellOperation.IdOperationTypeFact,
GeDate = geDateFactWellOperation, GeDate = geDateFactWellOperation,
LtDate = ltDateFactWellOperation LeDate = leDateFactWellOperation
}; };
var factWellOperations = await wellOperationRepository.GetAsync(factWellOperationRequest, cancellationToken); var factWellOperations = await wellOperationRepository.GetAsync(factWellOperationRequest, cancellationToken);
@ -200,7 +198,7 @@ public class DailyReportService : IDailyReportService
{ {
for (var day = result.Skip; day - result.Skip < result.Take && datesRange.To.AddDays(-day) >= datesRange.From; day++) for (var day = result.Skip; day - result.Skip < result.Take && datesRange.To.AddDays(-day) >= datesRange.From; day++)
{ {
var dateDailyReport = DateOnly.FromDateTime(datesRange.To.AddDays(-day)); var dateDailyReport = DateOnly.FromDateTime(datesRange.To.AddDays(-day).DateTime);
AddDailyReport(dateDailyReport); AddDailyReport(dateDailyReport);
} }
@ -209,7 +207,7 @@ public class DailyReportService : IDailyReportService
{ {
for (var day = result.Skip; day - result.Skip < result.Take && datesRange.From.AddDays(day) <= datesRange.To; day++) for (var day = result.Skip; day - result.Skip < result.Take && datesRange.From.AddDays(day) <= datesRange.To; day++)
{ {
var dateDailyReport = DateOnly.FromDateTime(datesRange.From.AddDays(day)); var dateDailyReport = DateOnly.FromDateTime(datesRange.From.AddDays(day).DateTime);
AddDailyReport(dateDailyReport); AddDailyReport(dateDailyReport);
} }
@ -228,11 +226,11 @@ public class DailyReportService : IDailyReportService
IdWell = idWell IdWell = idWell
}; };
var geDate = date.ToDateTime(TimeOnly.MinValue, DateTimeKind.Unspecified); var geDate = new DateTimeOffset(date, TimeOnly.MinValue, offset);
var leDate = date.AddDays(1).ToDateTime(TimeOnly.MinValue, DateTimeKind.Unspecified); var leDate = new DateTimeOffset(date.AddDays(1), TimeOnly.MinValue, offset);
var factWellOperationPerDay = factWellOperations.Where(o => o.DateStart.Date >= geDate && var factWellOperationPerDay = factWellOperations.Where(o => o.DateStart >= geDate &&
o.DateStart.Date <= leDate); o.DateStart <= leDate);
AddFactWellOperationBlock(dailyReport, factWellOperationPerDay); AddFactWellOperationBlock(dailyReport, factWellOperationPerDay);
@ -240,36 +238,8 @@ public class DailyReportService : IDailyReportService
} }
} }
public async Task<DatesRangeDto?> GetDatesRangeAsync(int idWell, CancellationToken cancellationToken)
{
var timezone = wellService.GetTimezone(idWell);
var currentDate = DateTimeOffset.UtcNow.ToRemoteDateTime(timezone.Hours);
var factOperationDatesRange = await wellOperationRepository.GetDatesRangeAsync(idWell, WellOperation.IdOperationTypeFact,
cancellationToken);
if (factOperationDatesRange is null)
return null;
var from = (factOperationDatesRange.From.AddDays(1) <= DateTime.UtcNow ?
factOperationDatesRange.From :
currentDate.AddDays(-1))
.Date;
var to = (factOperationDatesRange.To.AddDays(1) <= DateTime.UtcNow ?
factOperationDatesRange.To :
currentDate.AddDays(-1))
.Date;
return new DatesRangeDto
{
From = from,
To = to
};
}
private async Task UpdateTimeBalanceBlockAsync(DailyReportDto dailyReport, IEnumerable<WellOperationDto> factWellOperations, private async Task UpdateTimeBalanceBlockAsync(DailyReportDto dailyReport, IEnumerable<WellOperationDto> factWellOperations,
CancellationToken cancellationToken) DateTimeOffset geDateStart, DateTimeOffset leDateEnd, CancellationToken cancellationToken)
{ {
const int idWellOperationSlipsTime = 5011; const int idWellOperationSlipsTime = 5011;
@ -278,9 +248,6 @@ public class DailyReportService : IDailyReportService
dailyReport.TimeBalanceBlock.SectionName = wellOperationRepository.GetSectionTypes() dailyReport.TimeBalanceBlock.SectionName = wellOperationRepository.GetSectionTypes()
.FirstOrDefault(s => s.Id == dailyReport.TimeBalanceBlock.IdSection)?.Caption; .FirstOrDefault(s => s.Id == dailyReport.TimeBalanceBlock.IdSection)?.Caption;
var geDateStart = dailyReport.Date.ToDateTime(TimeOnly.MinValue, DateTimeKind.Unspecified);
var leDateEnd = dailyReport.Date.AddDays(1).ToDateTime(TimeOnly.MinValue, DateTimeKind.Unspecified);
dailyReport.TimeBalanceBlock.WellOperationSlipsTimeCount = (await detectedOperationService.GetAsync( dailyReport.TimeBalanceBlock.WellOperationSlipsTimeCount = (await detectedOperationService.GetAsync(
new DetectedOperationByWellRequest new DetectedOperationByWellRequest
{ {
@ -296,11 +263,9 @@ public class DailyReportService : IDailyReportService
} }
} }
private async Task AddTrajectoryBlockAsync(DailyReportDto dailyReport, CancellationToken cancellationToken) private async Task AddTrajectoryBlockAsync(DailyReportDto dailyReport,
DateTimeOffset geDate, DateTimeOffset leDate, CancellationToken cancellationToken)
{ {
var geDate = dailyReport.Date.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc);
var leDate = dailyReport.Date.AddDays(1).ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc);
var trajectory = (await trajectoryFactNnbRepository.GetByRequestAsync(new TrajectoryRequest var trajectory = (await trajectoryFactNnbRepository.GetByRequestAsync(new TrajectoryRequest
{ {
IdWell = dailyReport.IdWell, IdWell = dailyReport.IdWell,
@ -317,10 +282,8 @@ public class DailyReportService : IDailyReportService
}; };
} }
private async Task AddScheduleBlockAsync(DailyReportDto dailyReport, CancellationToken cancellationToken) private async Task AddScheduleBlockAsync(DailyReportDto dailyReport, DateTimeOffset workDate, CancellationToken cancellationToken)
{ {
var workDate = dailyReport.Date.ToDateTime(TimeOnly.MinValue, DateTimeKind.Unspecified);
dailyReport.ScheduleBlock = (await scheduleRepository.GetAsync(dailyReport.IdWell, workDate, cancellationToken)) dailyReport.ScheduleBlock = (await scheduleRepository.GetAsync(dailyReport.IdWell, workDate, cancellationToken))
.Select(s => new ScheduleRecordDto .Select(s => new ScheduleRecordDto
{ {
@ -332,7 +295,8 @@ public class DailyReportService : IDailyReportService
}); });
} }
private async Task UpdateSubsystemBlockAsync(DailyReportDto dailyReport, CancellationToken cancellationToken) private async Task UpdateSubsystemBlockAsync(DailyReportDto dailyReport,
DateTimeOffset geDate, DateTimeOffset leDate, CancellationToken cancellationToken)
{ {
dailyReport.SubsystemBlock ??= new SubsystemBlockDto(); dailyReport.SubsystemBlock ??= new SubsystemBlockDto();
@ -345,9 +309,6 @@ public class DailyReportService : IDailyReportService
IdWell = dailyReport.IdWell IdWell = dailyReport.IdWell
}, cancellationToken); }, cancellationToken);
var geDate = dailyReport.Date.ToDateTime(TimeOnly.MinValue, DateTimeKind.Unspecified);
var leDate = dailyReport.Date.AddDays(1).ToDateTime(TimeOnly.MinValue, DateTimeKind.Unspecified);
var subsystemsStatPerDay = await subsystemService.GetStatAsync(new SubsystemRequest var subsystemsStatPerDay = await subsystemService.GetStatAsync(new SubsystemRequest
{ {
IdWell = dailyReport.IdWell, IdWell = dailyReport.IdWell,
@ -370,11 +331,9 @@ public class DailyReportService : IDailyReportService
} }
} }
private async Task AddProcessMapWellDrillingBlockAsync(DailyReportDto dailyReport, CancellationToken cancellationToken) private async Task AddProcessMapWellDrillingBlockAsync(DailyReportDto dailyReport,
DateTimeOffset geDate, DateTimeOffset leDate, CancellationToken cancellationToken)
{ {
var geDate = dailyReport.Date.ToDateTime(TimeOnly.MinValue, DateTimeKind.Unspecified);
var leDate = dailyReport.Date.AddDays(1).ToDateTime(TimeOnly.MinValue, DateTimeKind.Unspecified);
var request = new DataSaubStatRequest(); var request = new DataSaubStatRequest();
dailyReport.ProcessMapWellDrillingBlock = (await processMapReportDrillingService.GetAsync(dailyReport.IdWell, request, dailyReport.ProcessMapWellDrillingBlock = (await processMapReportDrillingService.GetAsync(dailyReport.IdWell, request,
cancellationToken)).Where(p => p.DateStart >= geDate && p.DateStart <= leDate) cancellationToken)).Where(p => p.DateStart >= geDate && p.DateStart <= leDate)
@ -401,7 +360,7 @@ public class DailyReportService : IDailyReportService
WellOperations = factWellOperations.GroupBy(o => o.IdCategory) WellOperations = factWellOperations.GroupBy(o => o.IdCategory)
.Select(g => new WellOperationRecordDto .Select(g => new WellOperationRecordDto
{ {
CategoryName = g.First().CategoryName, CategoryName = g.First().OperationCategoryName,
DurationHours = g.Sum(o => o.DurationHours) DurationHours = g.Sum(o => o.DurationHours)
}), }),
@ -413,13 +372,12 @@ public class DailyReportService : IDailyReportService
private async Task<bool> IsDateDailyReportInRangeAsync(int idWell, DateOnly dateDailyReport, CancellationToken cancellationToken) private async Task<bool> IsDateDailyReportInRangeAsync(int idWell, DateOnly dateDailyReport, CancellationToken cancellationToken)
{ {
var datesRange = await GetDatesRangeAsync(idWell, cancellationToken); var datesRange = await wellOperationRepository.GetDatesRangeAsync(idWell, WellOperation.IdOperationTypeFact, cancellationToken);
if (datesRange is null) if (datesRange is null)
return false; return false;
var from = DateOnly.FromDateTime(datesRange.From.DateTime);
var from = DateOnly.FromDateTime(datesRange.From); var to = DateOnly.FromDateTime(datesRange.To.DateTime);
var to = DateOnly.FromDateTime(datesRange.To);
return dateDailyReport >= from && dateDailyReport <= to; return dateDailyReport >= from && dateDailyReport <= to;
} }

View File

@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Http.Extensions;
using AsbCloudApp.Exceptions; using AsbCloudApp.Exceptions;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Data.WellOperation;
using AsbCloudInfrastructure.Services.DetectOperations.Detectors; using AsbCloudInfrastructure.Services.DetectOperations.Detectors;
namespace AsbCloudInfrastructure.Services.DetectOperations; namespace AsbCloudInfrastructure.Services.DetectOperations;

View File

@ -10,6 +10,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Data.WellOperation;
using AsbCloudInfrastructure.Services.DetectOperations.Detectors; using AsbCloudInfrastructure.Services.DetectOperations.Detectors;
namespace AsbCloudInfrastructure.Services.DetectOperations; namespace AsbCloudInfrastructure.Services.DetectOperations;
@ -272,7 +273,7 @@ public class DetectedOperationService : IDetectedOperationService
&& v.DepthStart <= dto.DepthStart && v.DepthStart <= dto.DepthStart
&& v.DepthEnd > dto.DepthStart); && v.DepthEnd > dto.DepthStart);
var dateStart = dto.DateStart; var dateStart = dto.DateStart.ToUniversalTime();
var timeStart = new TimeDto(dateStart); var timeStart = new TimeDto(dateStart);
var driller = schedules.FirstOrDefault(s => var driller = schedules.FirstOrDefault(s =>
s.DrillStart <= dateStart && s.DrillStart <= dateStart &&

View File

@ -49,7 +49,7 @@ namespace AsbCloudInfrastructure.Services.DrillTestReport
well.Deposit ?? "-", well.Deposit ?? "-",
well.Cluster ?? "-", well.Cluster ?? "-",
well.Caption ?? "-"), well.Caption ?? "-"),
Date = DateTime.Now, Date = DateTimeOffset.Now,
}; };
var fileName = string.Format("Drill_test_{0}.xlsx", dto.TimeStampStart.ToString("dd.mm.yyyy_HH_MM_ss")); var fileName = string.Format("Drill_test_{0}.xlsx", dto.TimeStampStart.ToString("dd.mm.yyyy_HH_MM_ss"));
@ -78,15 +78,15 @@ namespace AsbCloudInfrastructure.Services.DrillTestReport
var dtos = await drillTestRepository.GetAllAsync(telemetry.Id, request, cancellationToken); var dtos = await drillTestRepository.GetAllAsync(telemetry.Id, request, cancellationToken);
foreach (var dto in dtos) foreach (var dto in dtos)
{ {
var remoteDateTime = dto.TimeStampStart.ToRemoteDateTime(timezone.Hours); var remoteDateTime = dto.TimeStampStart.ToOffset(TimeSpan.FromHours(timezone.Hours));
reports.Add(new DrillTestReportInfoDto reports.Add(new DrillTestReportInfoDto
{ {
FileName = string.Format("Drill_test_{0}", dto.TimeStampStart.DateTime), FileName = string.Format("Drill_test_{0}", remoteDateTime),
DrillDepth = (dto.Params DrillDepth = (dto.Params
.Where(p => p.DepthDrillStep.HasValue) .Where(p => p.DepthDrillStep.HasValue)
.Sum(x => x.DepthDrillStep) ?? 0) + dto.DepthStart, .Sum(x => x.DepthDrillStep) ?? 0) + dto.DepthStart,
DateTime = dto.TimeStampStart.DateTime, DateTime = remoteDateTime,
Id = dto.Id, Id = dto.Id,
}); });
} }

View File

@ -480,7 +480,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
IdWell = fileEntity.IdWell, IdWell = fileEntity.IdWell,
Name = fileEntity.Name, Name = fileEntity.Name,
Size = fileEntity.Size, Size = fileEntity.Size,
UploadDate = fileEntity.UploadDate.ToRemoteDateTime(timezoneOffset), UploadDate = fileEntity.UploadDate.ToOffset(TimeSpan.FromHours(timezoneOffset)),
}; };
var marks = fileEntity.FileMarks?.Where(m => !m.IsDeleted); var marks = fileEntity.FileMarks?.Where(m => !m.IsDeleted);
@ -489,7 +489,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
part.File.FileMarks = marks.Select(m => part.File.FileMarks = marks.Select(m =>
{ {
var mark = m.Adapt<FileMarkDto>(); var mark = m.Adapt<FileMarkDto>();
mark.DateCreated = m.DateCreated.ToRemoteDateTime(timezoneOffset); mark.DateCreated = m.DateCreated.ToOffset(TimeSpan.FromHours(timezoneOffset));
return mark; return mark;
}); });
var hasReject = marks.Any(m => m.IdMarkType == idMarkTypeReject); var hasReject = marks.Any(m => m.IdMarkType == idMarkTypeReject);

View File

@ -11,7 +11,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
{ {
private const string directionDirectorPositionName = "Руководитель направления по ТСБ"; private const string directionDirectorPositionName = "Руководитель направления по ТСБ";
private readonly DateTime totalDate; private readonly DateTimeOffset totalDate;
private readonly FileMarkDto? acceptDirectionDirector; private readonly FileMarkDto? acceptDirectionDirector;
private readonly List<FileMarkDto> acceptsOthers; private readonly List<FileMarkDto> acceptsOthers;
private readonly WellDto well; private readonly WellDto well;
@ -157,7 +157,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
.Alignment.SetHorizontal(XLAlignmentHorizontalValues.Left); .Alignment.SetHorizontal(XLAlignmentHorizontalValues.Left);
} }
private static string FormatDate(DateTime dateTime) private static string FormatDate(DateTimeOffset dateTime)
=> $"{dateTime.Day:00}.{dateTime.Month:00}.{dateTime.Year:00}"; => $"{dateTime.Day:00}.{dateTime.Month:00}.{dateTime.Year:00}";
} }

View File

@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Requests.ExportOptions;
using AsbCloudApp.Services.Export;
using AsbCloudInfrastructure.Services.ExcelServices.Templates;
using ClosedXML.Excel;
using Mapster;
namespace AsbCloudInfrastructure.Services.ExcelServices;
public abstract class ExcelExportService<TDto, TOptions, TTemplate> : IExportService<TOptions>
where TOptions : IExportOptionsRequest
where TTemplate : class, ITemplateParameters, new()
{
protected TTemplate TemplateParameters => new();
protected abstract Task<string> BuildFileNameAsync(TOptions options, CancellationToken token);
protected abstract Task<IEnumerable<TDto>> GetDtosAsync(TOptions options, CancellationToken token);
public async Task<(string FileName, Stream File)> ExportAsync(TOptions options, CancellationToken token)
{
var dtos = await GetDtosAsync(options, token);
var fileName = await BuildFileNameAsync(options, token);
var file = BuildFile(dtos);
return (fileName, file);
}
private Stream BuildFile(IEnumerable<TDto> dtos)
{
using var template = GetTemplateFile();
using var workbook = new XLWorkbook(template);
AddDtosToWorkbook(workbook, dtos);
var memoryStream = new MemoryStream();
workbook.SaveAs(memoryStream, new SaveOptions { });
memoryStream.Seek(0, SeekOrigin.Begin);
return memoryStream;
}
private void AddDtosToWorkbook(XLWorkbook workbook, IEnumerable<TDto> dtos)
{
var dtosToArray = dtos.ToArray();
if (!dtosToArray.Any())
return;
var sheet = workbook.GetWorksheet(TemplateParameters.SheetName);
for (var i = 0; i < dtosToArray.Length; i++)
{
var row = sheet.Row(1 + i + TemplateParameters.HeaderRowsCount);
AddRow(row, dtosToArray[i]);
}
}
private void AddRow(IXLRow xlRow, TDto dto)
{
var properties = dto.Adapt<IDictionary<string, object>>();
foreach (var (name, cellValue) in properties)
{
if (TemplateParameters.Cells.TryGetValue(name, out var cell))
xlRow.Cell(cell.ColumnNumber).SetCellValue(cellValue);
}
}
private Stream GetTemplateFile() =>
Assembly.GetExecutingAssembly().GetTemplateCopyStream(TemplateParameters.FileName)
?? throw new ArgumentNullException($"Файл '{TemplateParameters.FileName}' не найден");
}

View File

@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Reflection;
using AsbCloudApp.Data;
using AsbCloudApp.Requests.ParserOptions;
using AsbCloudApp.Services.Parsers;
using AsbCloudInfrastructure.Services.ExcelServices.Templates;
using ClosedXML.Excel;
using Mapster;
namespace AsbCloudInfrastructure.Services.ExcelServices;
public abstract class ExcelParser<TDto, TOptions, TTemplate> : IParserService<TDto, TOptions>
where TDto : class, IValidatableObject, IId
where TOptions : IParserOptionsRequest
where TTemplate : class, ITemplateParameters, new()
{
protected TTemplate TemplateParameters => new();
public virtual ParserResultDto<TDto> Parse(Stream file, TOptions options)
{
using var workbook = new XLWorkbook(file);
var sheet = workbook.GetWorksheet(TemplateParameters.SheetName);
var dtos = ParseExcelSheet(sheet);
return dtos;
}
public virtual Stream GetTemplateFile() =>
Assembly.GetExecutingAssembly().GetTemplateCopyStream(TemplateParameters.FileName)
?? throw new ArgumentNullException($"Файл '{TemplateParameters.FileName}' не найден");
protected virtual IDictionary<string, object?> ParseRow(IXLRow xlRow)
{
var cells = TemplateParameters.Cells.ToDictionary(x => x.Key, x =>
{
var columnNumber = x.Value.ColumnNumber;
var xlCell = xlRow.Cell(columnNumber);
var cellValue = x.Value.GetValueFromCell(xlCell);
return cellValue;
});
return cells;
}
protected virtual TDto BuildDto(IDictionary<string, object?> row, int rowNumber)
{
var dto = row.Adapt<TDto>();
return dto;
}
private ValidationResultDto<TDto> Validate(TDto dto, int rowNumber)
{
var validationResults = new List<ValidationResult>();
var isValid = dto.Validate(validationResults);
if (isValid)
{
var validDto = new ValidationResultDto<TDto>
{
Item = dto
};
return validDto;
}
var columnsDict = TemplateParameters.Cells.ToDictionary(x => x.Key, x => x.Value.ColumnNumber);
var invalidDto = new ValidationResultDto<TDto>
{
Item = dto,
Warnings = validationResults
.SelectMany(v => v.MemberNames
.Where(columnsDict.ContainsKey)
.Select(m =>
{
var columnNumber = columnsDict[m];
var errorMessage = v.ErrorMessage;
var warningMessage = string.Format(XLExtentions.ProblemDetailsTemplate,
TemplateParameters.SheetName,
rowNumber,
columnNumber,
errorMessage);
var warning = new ValidationResult(warningMessage, new[] { m });
return warning;
}))
};
return invalidDto;
}
protected virtual ParserResultDto<TDto> ParseExcelSheet(IXLWorksheet sheet)
{
var count = sheet.RowsUsed().Count() - TemplateParameters.HeaderRowsCount;
if (count <= 0)
return new ParserResultDto<TDto>();
var valiationResults = new List<ValidationResultDto<TDto>>(count);
var warnings = new List<ValidationResult>();
for (var i = 0; i < count; i++)
{
var xlRow = sheet.Row(1 + i + TemplateParameters.HeaderRowsCount);
var rowNumber = xlRow.RowNumber();
try
{
var row = ParseRow(xlRow);
var dto = BuildDto(row, rowNumber);
var validationResult = Validate(dto, rowNumber);
valiationResults.Add(validationResult);
}
catch (FileFormatException ex)
{
var warning = new ValidationResult(ex.Message);
warnings.Add(warning);
}
}
var parserResult = new ParserResultDto<TDto>
{
Item = valiationResults
};
if (warnings.Any())
parserResult.Warnings = warnings;
return parserResult;
}
}

View File

@ -0,0 +1,23 @@
using System.ComponentModel.DataAnnotations;
using System.IO;
using AsbCloudApp.Data;
using AsbCloudApp.Requests.ParserOptions;
using AsbCloudInfrastructure.Services.ExcelServices.Templates;
namespace AsbCloudInfrastructure.Services.ExcelServices;
public abstract class ExcelWellRelatedParser<TDto, TOptions, TTemplate> : ExcelParser<TDto, TOptions, TTemplate>
where TDto : class, IValidatableObject, IId, IWellRelated
where TOptions : WellRelatedParserRequest
where TTemplate : class, ITemplateParameters, new()
{
public override ParserResultDto<TDto> Parse(Stream file, TOptions options)
{
var result = base.Parse(file, options);
foreach (var dto in result.Item)
dto.Item.IdWell = options.IdWell;
return result;
}
}

View File

@ -6,13 +6,14 @@ using System.Reflection;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Requests.ExportOptions; using AsbCloudApp.Requests.ExportOptions;
using AsbCloudApp.Services; using AsbCloudApp.Services.Export;
using AsbCloudInfrastructure.Services.ExcelServices.Templates; using AsbCloudInfrastructure.Services.ExcelServices.Templates;
using ClosedXML.Excel; using ClosedXML.Excel;
using Mapster; using Mapster;
namespace AsbCloudInfrastructure.Services.ExcelServices; namespace AsbCloudInfrastructure.Services.ExcelServices;
[Obsolete]
public abstract class ExportExcelService<TDto, TOptions> : IExportService<TOptions> public abstract class ExportExcelService<TDto, TOptions> : IExportService<TOptions>
where TOptions : IExportOptionsRequest where TOptions : IExportOptionsRequest
{ {

View File

@ -6,13 +6,14 @@ using System.Linq;
using System.Reflection; using System.Reflection;
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Requests.ParserOptions; using AsbCloudApp.Requests.ParserOptions;
using AsbCloudApp.Services; using AsbCloudApp.Services.Parsers;
using AsbCloudInfrastructure.Services.ExcelServices.Templates; using AsbCloudInfrastructure.Services.ExcelServices.Templates;
using ClosedXML.Excel; using ClosedXML.Excel;
using Mapster; using Mapster;
namespace AsbCloudInfrastructure.Services.ExcelServices; namespace AsbCloudInfrastructure.Services.ExcelServices;
[Obsolete]
public abstract class ParserExcelService<TDto, TOptions> : IParserService<TDto, TOptions> public abstract class ParserExcelService<TDto, TOptions> : IParserService<TDto, TOptions>
where TDto : class, IValidatableObject, IId where TDto : class, IValidatableObject, IId
where TOptions : IParserOptionsRequest where TOptions : IParserOptionsRequest

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using AsbCloudApp.Data.WellOperation;
namespace AsbCloudInfrastructure.Services.ExcelServices.Templates.WellOperations;
public class WellOperationFactTemplate : ITemplateParameters
{
public string SheetName => "Факт";
public int HeaderRowsCount => 1;
public string FileName => "WellOperationFactTemplate.xlsx";
public IDictionary<string, Cell> Cells => new Dictionary<string, Cell>
{
{ nameof(WellOperationDto.WellSectionTypeCaption), new Cell(1, typeof(string)) },
{ nameof(WellOperationDto.OperationCategoryName), new Cell(2, typeof(string)) },
{ nameof(WellOperationDto.CategoryInfo), new Cell(3, typeof(string)) },
{ nameof(WellOperationDto.DepthStart), new Cell(4, typeof(double)) },
{ nameof(WellOperationDto.DepthEnd), new Cell(5, typeof(double)) },
{ nameof(WellOperationDto.DateStart), new Cell(6, typeof(DateTime)) },
{ nameof(WellOperationDto.DurationHours), new Cell(7, typeof(double)) },
{ nameof(WellOperationDto.Comment), new Cell(8, typeof(string)) }
};
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using AsbCloudApp.Data.WellOperation;
namespace AsbCloudInfrastructure.Services.ExcelServices.Templates.WellOperations;
public class WellOperationPlanTemplate : ITemplateParameters
{
public string SheetName => "План";
public int HeaderRowsCount => 1;
public string FileName => "WellOperationPlanTemplate.xlsx";
public IDictionary<string, Cell> Cells => new Dictionary<string, Cell>()
{
{ nameof(WellOperationDto.WellSectionTypeCaption), new Cell(1, typeof(string)) },
{ nameof(WellOperationDto.OperationCategoryName), new Cell(2, typeof(string)) },
{ nameof(WellOperationDto.CategoryInfo), new Cell(3, typeof(string)) },
{ nameof(WellOperationDto.DepthStart), new Cell(4, typeof(double)) },
{ nameof(WellOperationDto.DepthEnd), new Cell(5, typeof(double)) },
{ nameof(WellOperationDto.DateStart), new Cell(6, typeof(DateTime)) },
{ nameof(WellOperationDto.DurationHours), new Cell(7, typeof(double)) },
{ nameof(WellOperationDto.Comment), new Cell(8, typeof(string)) }
};
}

View File

@ -106,7 +106,7 @@ namespace AsbCloudInfrastructure.Services
return (float)result; return (float)result;
} }
private DateTime GetDate(double depth, LimitingParameterDataDto dto) private DateTimeOffset GetDate(double depth, LimitingParameterDataDto dto)
{ {
var a = depth - dto.DepthStart; var a = depth - dto.DepthStart;
var b = dto.DepthEnd - dto.DepthStart; var b = dto.DepthEnd - dto.DepthStart;

View File

@ -57,7 +57,7 @@ public class ManualCatalogService : IManualCatalogService
var manual = new ManualDto var manual = new ManualDto
{ {
Name = name, Name = name,
DateDownload = DateTime.UtcNow, DateDownload = DateTimeOffset.UtcNow,
IdDirectory = idDirectory, IdDirectory = idDirectory,
IdCategory = IdFileCategory, IdCategory = IdFileCategory,
IdAuthor = idAuthor IdAuthor = idAuthor

View File

@ -87,8 +87,7 @@ namespace AsbCloudInfrastructure.Services
throw new ArgumentInvalidException(nameof(dto), "wrong idCategory"); throw new ArgumentInvalidException(nameof(dto), "wrong idCategory");
if (!dto.Data.Any()) if (!dto.Data.Any())
throw new ArgumentInvalidException(nameof(dto), "data.data is not optional"); throw new ArgumentInvalidException(nameof(dto), "data.data is not optional");
var timezone = wellService.GetTimezone(idWell); var entity = Convert(dto);
var entity = Convert(dto, timezone.Hours);
entity.IdWell = idWell; entity.IdWell = idWell;
db.Measures.Add(entity); db.Measures.Add(entity);
return db.SaveChangesAsync(token); return db.SaveChangesAsync(token);
@ -110,7 +109,7 @@ namespace AsbCloudInfrastructure.Services
var timezone = wellService.GetTimezone(idWell); var timezone = wellService.GetTimezone(idWell);
entity.IdWell = idWell; entity.IdWell = idWell;
entity.Timestamp = dto.Timestamp.ToUtcDateTimeOffset(timezone.Hours); entity.Timestamp = dto.Timestamp.ToOffset(TimeSpan.FromHours(timezone.Hours));
entity.Data = dto.Data.Adapt<RawData>(); entity.Data = dto.Data.Adapt<RawData>();
return await db.SaveChangesAsync(token).ConfigureAwait(false); return await db.SaveChangesAsync(token).ConfigureAwait(false);
@ -142,13 +141,13 @@ namespace AsbCloudInfrastructure.Services
{ {
var dto = entity.Adapt<MeasureDto>(); var dto = entity.Adapt<MeasureDto>();
dto.CategoryName = entity.Category?.Name ?? String.Empty; dto.CategoryName = entity.Category?.Name ?? String.Empty;
dto.Timestamp = entity.Timestamp.ToRemoteDateTime(hours); dto.Timestamp = entity.Timestamp.ToOffset(TimeSpan.FromHours(hours));
return dto; return dto;
} }
private Measure Convert(MeasureDto dto, double hours) private Measure Convert(MeasureDto dto)
{ {
var entity = dto.Adapt<Measure>(); var entity = dto.Adapt<Measure>();
entity.Timestamp = dto.Timestamp.ToUtcDateTimeOffset(hours); entity.Timestamp = dto.Timestamp.ToUniversalTime();
return entity; return entity;
} }
} }

Some files were not shown because too many files have changed in this diff Show More