diff --git a/AsbCloudApp/Data/AutogeneratedDailyReport/AutoGeneratedDailyReportInfoDto.cs b/AsbCloudApp/Data/AutogeneratedDailyReport/AutoGeneratedDailyReportInfoDto.cs index 0034879a..22e34cf2 100644 --- a/AsbCloudApp/Data/AutogeneratedDailyReport/AutoGeneratedDailyReportInfoDto.cs +++ b/AsbCloudApp/Data/AutogeneratedDailyReport/AutoGeneratedDailyReportInfoDto.cs @@ -5,21 +5,10 @@ namespace AsbCloudApp.Data.AutogeneratedDailyReport; /// /// Базовая информация о суточном отчёте /// -public class AutoGeneratedDailyReportInfoDto +public class AutoGeneratedDailyReportInfoDto : ReportInfoDto { - /// - /// Дата формирования отчёта - /// - public DateOnly ReportDate { get; set; } - - /// - /// Название файла - /// - public string FileName { get; set; } = null!; - - /// - /// Размер файла - /// - public int FileSize { get; set; } - + /// + /// Дата формирования отчёта + /// + public DateOnly ReportDate { get; set; } } \ No newline at end of file diff --git a/AsbCloudApp/Data/DrillTestReport/DrillTestReportDataDto.cs b/AsbCloudApp/Data/DrillTestReport/DrillTestReportDataDto.cs new file mode 100644 index 00000000..ee63bf9b --- /dev/null +++ b/AsbCloudApp/Data/DrillTestReport/DrillTestReportDataDto.cs @@ -0,0 +1,26 @@ +using AsbCloudApp.Data.SAUB; +using System; + +namespace AsbCloudApp.Data.DrillTestReport +{ + /// + /// Информация о drill test, выгружаемая в отчете + /// + public class DrillTestReportDataDto + { + /// + /// Данные для отчета + /// + public DrillTestDto Data { get; set; } = null!; + + /// + /// Заголовок отчета + /// + public string Caption { get; set; } = null!; + + /// + /// Дата отчета + /// + public DateTime Date { get; set; } = DateTime.Now; + } +} diff --git a/AsbCloudApp/Data/DrillTestReport/DrillTestReportInfoDto.cs b/AsbCloudApp/Data/DrillTestReport/DrillTestReportInfoDto.cs new file mode 100644 index 00000000..8d3a9244 --- /dev/null +++ b/AsbCloudApp/Data/DrillTestReport/DrillTestReportInfoDto.cs @@ -0,0 +1,25 @@ +using System; + +namespace AsbCloudApp.Data.DrillTestReport +{ + /// + /// Базовая информация о drill_test отчёте + /// + public class DrillTestReportInfoDto : ReportInfoDto + { + /// + /// Идентификатор отчета + /// + public int Id { get; set; } + + /// + /// Проходка + /// + public float DrillDepth { get; set; } + + /// + /// Дата и время + /// + public DateTime DateTime { get; set; } + } +} diff --git a/AsbCloudApp/Data/ReportInfoDto.cs b/AsbCloudApp/Data/ReportInfoDto.cs new file mode 100644 index 00000000..bd55d33c --- /dev/null +++ b/AsbCloudApp/Data/ReportInfoDto.cs @@ -0,0 +1,18 @@ +namespace AsbCloudApp.Data +{ + /// + /// Справочная информация об отчете + /// + public class ReportInfoDto + { + /// + /// Название файла + /// + public string FileName { get; set; } = null!; + + /// + /// Размер файла + /// + public int FileSize { get; set; } = 0; + } +} diff --git a/AsbCloudApp/Data/SAUB/DrillTestDto.cs b/AsbCloudApp/Data/SAUB/DrillTestDto.cs index e53ffbbb..03f344c2 100644 --- a/AsbCloudApp/Data/SAUB/DrillTestDto.cs +++ b/AsbCloudApp/Data/SAUB/DrillTestDto.cs @@ -24,6 +24,11 @@ namespace AsbCloudApp.Data.SAUB /// public float DepthStart { get; set; } + /// + /// Связанная с drill_test телеметрия + /// + public TelemetryDto? Telemetry { get; set; } + /// /// Параметры теста /// diff --git a/AsbCloudApp/Data/SAUB/DrillTestParamsDto.cs b/AsbCloudApp/Data/SAUB/DrillTestParamsDto.cs index f2b8ceac..f8d9d168 100644 --- a/AsbCloudApp/Data/SAUB/DrillTestParamsDto.cs +++ b/AsbCloudApp/Data/SAUB/DrillTestParamsDto.cs @@ -26,7 +26,7 @@ public float? DepthSpeed { get; set; } /// - /// Время бурения шага + /// Время бурения шага, сек /// public float? TimeDrillStep { get; set; } diff --git a/AsbCloudApp/Exceptions/ArgumentInvalidException.cs b/AsbCloudApp/Exceptions/ArgumentInvalidException.cs index 4fe150e3..5db63313 100644 --- a/AsbCloudApp/Exceptions/ArgumentInvalidException.cs +++ b/AsbCloudApp/Exceptions/ArgumentInvalidException.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; namespace AsbCloudApp.Exceptions { @@ -8,9 +10,9 @@ namespace AsbCloudApp.Exceptions public class ArgumentInvalidException : Exception { /// - /// название аргумента + /// словарь с ошибками, где ключ - имя аргумента, а значение - массив из одного сообщения /// - public string ParamName { get; } = string.Empty; + public IDictionary ErrorState { get; } = null!; /// /// конструктор @@ -20,7 +22,20 @@ namespace AsbCloudApp.Exceptions public ArgumentInvalidException(string paramName, string message) : base(message) { - ParamName = paramName; + ErrorState = new Dictionary() { + { paramName, new[]{ message } } + }; + } + + /// + /// конструктор + /// + /// + /// + public ArgumentInvalidException(string[] paramsNames, string message) + : base(message) + { + ErrorState = paramsNames.ToDictionary(paramName => paramName, item => new[] { message }); } } } diff --git a/AsbCloudApp/Repositories/IDrillTestRepository.cs b/AsbCloudApp/Repositories/IDrillTestRepository.cs index 45552871..9c7a2f50 100644 --- a/AsbCloudApp/Repositories/IDrillTestRepository.cs +++ b/AsbCloudApp/Repositories/IDrillTestRepository.cs @@ -1,4 +1,6 @@ using AsbCloudApp.Data.SAUB; +using AsbCloudApp.Requests; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -9,6 +11,24 @@ namespace AsbCloudApp.Repositories /// public interface IDrillTestRepository { + /// + /// Получить данные drill_test в соответствии с параметрами запроса + /// + /// ключ телеметрии + /// запрос + /// + /// + Task> GetAllAsync(int idTelemetry, FileReportRequest request, CancellationToken cancellationToken); + + /// + /// Получить запись drill_test + /// + /// ключ телеметрии + /// ключ записи drill_test + /// + /// + Task GetAsync(int idTelemetry, int id, CancellationToken cancellationToken); + /// /// Сохранить данные drill_test /// diff --git a/AsbCloudApp/Requests/AutoGeneratedDailyReportRequest.cs b/AsbCloudApp/Requests/AutoGeneratedDailyReportRequest.cs deleted file mode 100644 index 5e7dae7c..00000000 --- a/AsbCloudApp/Requests/AutoGeneratedDailyReportRequest.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; - -namespace AsbCloudApp.Requests; - -/// -/// Параметры запроса для получения авто-генерируемых суточных отчётов -/// -public class AutoGeneratedDailyReportRequest : RequestBase -{ - /// - /// Дата начала периода - /// - public DateOnly? StartDate { get; set; } - - /// - /// Дата конца периода - /// - public DateOnly? FinishDate { get; set; } -} \ No newline at end of file diff --git a/AsbCloudApp/Requests/FileReportRequest.cs b/AsbCloudApp/Requests/FileReportRequest.cs new file mode 100644 index 00000000..a9984016 --- /dev/null +++ b/AsbCloudApp/Requests/FileReportRequest.cs @@ -0,0 +1,19 @@ +using System; + +namespace AsbCloudApp.Requests; + +/// +/// Параметры запроса для получения отчетов (файлов) +/// +public class FileReportRequest : RequestBase +{ + /// + /// Дата начала периода + /// + public DateOnly? GeDate { get; set; } + + /// + /// Дата конца периода + /// + public DateOnly? LeDate { get; set; } +} \ No newline at end of file diff --git a/AsbCloudApp/Services/AutoGeneratedDailyReports/IAutoGeneratedDailyReportMakerService.cs b/AsbCloudApp/Services/AutoGeneratedDailyReports/IAutoGeneratedDailyReportMakerService.cs deleted file mode 100644 index 8571e356..00000000 --- a/AsbCloudApp/Services/AutoGeneratedDailyReports/IAutoGeneratedDailyReportMakerService.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using AsbCloudApp.Data.AutogeneratedDailyReport; - -namespace AsbCloudApp.Services.AutoGeneratedDailyReports; - -/// -/// Сервис для генерации файлов авто-генерируемых суточный отчётов -/// -public interface IAutoGeneratedDailyReportMakerService -{ - /// - /// Генерация файла - /// - /// - /// - /// - Task MakeReportAsync(AutoGeneratedDailyReportDto report, CancellationToken cancellationToken); -} \ No newline at end of file diff --git a/AsbCloudApp/Services/AutoGeneratedDailyReports/IAutoGeneratedDailyReportService.cs b/AsbCloudApp/Services/AutoGeneratedDailyReports/IAutoGeneratedDailyReportService.cs index 13bdb1ea..979f948c 100644 --- a/AsbCloudApp/Services/AutoGeneratedDailyReports/IAutoGeneratedDailyReportService.cs +++ b/AsbCloudApp/Services/AutoGeneratedDailyReports/IAutoGeneratedDailyReportService.cs @@ -21,7 +21,7 @@ public interface IAutoGeneratedDailyReportService /// /// Task> GetListAsync(int idWell, - AutoGeneratedDailyReportRequest request, + FileReportRequest request, CancellationToken cancellationToken); /// diff --git a/AsbCloudApp/Services/IDrillTestReportService.cs b/AsbCloudApp/Services/IDrillTestReportService.cs new file mode 100644 index 00000000..6dd97b83 --- /dev/null +++ b/AsbCloudApp/Services/IDrillTestReportService.cs @@ -0,0 +1,35 @@ +using AsbCloudApp.Data; +using AsbCloudApp.Data.DrillTestReport; +using AsbCloudApp.Requests; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace AsbCloudApp.Services +{ + /// + /// сервис по работе с отчетами drill test + /// + public interface IDrillTestReportService + { + /// + /// Список файлов drill test + /// + /// ключ скважины + /// параметры запроса + /// + /// + Task> GetListAsync(int idWell, + FileReportRequest request, + CancellationToken cancellationToken); + + /// + /// Генерация файла с отчётом + /// + /// ключ скважины + /// ключ drill test записи + /// + /// + Task<(string fileName, Stream stream)> GenerateAsync(int idWell, int id, CancellationToken cancellationToken); + } +} diff --git a/AsbCloudApp/Services/IReportMakerService.cs b/AsbCloudApp/Services/IReportMakerService.cs new file mode 100644 index 00000000..e1269a25 --- /dev/null +++ b/AsbCloudApp/Services/IReportMakerService.cs @@ -0,0 +1,19 @@ +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace AsbCloudApp.Services; + +/// +/// Сервис для генерации файлов отчётов +/// +public interface IReportMakerService +{ + /// + /// Генерация файла + /// + /// модель с данными для построения отчета + /// + /// + Task MakeReportAsync(T report, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/AsbCloudDb/Model/DefaultData/EntityFillerPermission.cs b/AsbCloudDb/Model/DefaultData/EntityFillerPermission.cs index b6bc8e6a..713fc6f0 100644 --- a/AsbCloudDb/Model/DefaultData/EntityFillerPermission.cs +++ b/AsbCloudDb/Model/DefaultData/EntityFillerPermission.cs @@ -161,6 +161,8 @@ new() { Id = 527, Name = "Manual.delete", Description = "Разрешение на удаление инструкций"}, new (){ Id = 528, Name="WellContact.delete", Description="Разрешение на удаление контакта"}, + + new (){ Id = 529, Name="DrillTestReport.get", Description="Разрешение на получение отчетов drill test"}, }; } } diff --git a/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj b/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj index bc825b4b..2c2bd528 100644 --- a/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj +++ b/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj @@ -13,6 +13,7 @@ + @@ -30,6 +31,7 @@ + diff --git a/AsbCloudInfrastructure/AssemblyExtensions.cs b/AsbCloudInfrastructure/AssemblyExtensions.cs new file mode 100644 index 00000000..9594261b --- /dev/null +++ b/AsbCloudInfrastructure/AssemblyExtensions.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace AsbCloudInfrastructure +{ + public static class AssemblyExtensions + { + public static async Task GetTemplateCopyStreamAsync(this Assembly assembly, string templateName, CancellationToken cancellationToken) + { + var resourceName = assembly + .GetManifestResourceNames() + .FirstOrDefault(n => n.EndsWith(templateName))!; + + using var stream = Assembly.GetExecutingAssembly() + .GetManifestResourceStream(resourceName)!; + + var memoryStream = new MemoryStream(); + await stream.CopyToAsync(memoryStream, cancellationToken); + memoryStream.Position = 0; + + return memoryStream; + } + } +} diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs index 85caf0b2..0ce35409 100644 --- a/AsbCloudInfrastructure/DependencyInjection.cs +++ b/AsbCloudInfrastructure/DependencyInjection.cs @@ -1,5 +1,6 @@ -using System; -using AsbCloudApp.Data; +using AsbCloudApp.Data; +using AsbCloudApp.Data.AutogeneratedDailyReport; +using AsbCloudApp.Data.DrillTestReport; using AsbCloudApp.Data.Manuals; using AsbCloudApp.Data.ProcessMaps; using AsbCloudApp.Data.SAUB; @@ -24,6 +25,7 @@ using AsbCloudInfrastructure.Services.AutoGeneratedDailyReports; using AsbCloudInfrastructure.Services.DailyReport; using AsbCloudInfrastructure.Services.DetectOperations; using AsbCloudInfrastructure.Services.DrillingProgram; +using AsbCloudInfrastructure.Services.DrillTestReport; using AsbCloudInfrastructure.Services.ProcessMaps.Report; using AsbCloudInfrastructure.Services.ProcessMaps.WellDrilling; using AsbCloudInfrastructure.Services.SAUB; @@ -37,273 +39,275 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using System; namespace AsbCloudInfrastructure { public static class DependencyInjection { - public static IAsbCloudDbContext MakeContext(string connectionString) - { - var options = new DbContextOptionsBuilder() - .UseNpgsql(connectionString) - .Options; - var context = new AsbCloudDbContext(options); - return context; - } + public static IAsbCloudDbContext MakeContext(string connectionString) + { + var options = new DbContextOptionsBuilder() + .UseNpgsql(connectionString) + .Options; + var context = new AsbCloudDbContext(options); + return context; + } - public static void MapsterSetup() - { - TypeAdapterConfig.GlobalSettings.Default.Config - .ForType() - .MapWith((source) => source.DateTime); + public static void MapsterSetup() + { + TypeAdapterConfig.GlobalSettings.Default.Config + .ForType() + .MapWith((source) => source.DateTime); - TypeAdapterConfig.GlobalSettings.Default.Config - .ForType() - .MapWith((source) => source == default ? new DateTime(0, DateTimeKind.Utc) : source); + TypeAdapterConfig.GlobalSettings.Default.Config + .ForType() + .MapWith((source) => source == default ? new DateTime(0, DateTimeKind.Utc) : source); - TypeAdapterConfig.GlobalSettings.Default.Config - .ForType() - .MapWith((source) => source.MakeTimeOnly()); + TypeAdapterConfig.GlobalSettings.Default.Config + .ForType() + .MapWith((source) => source.MakeTimeOnly()); - TypeAdapterConfig.GlobalSettings.Default.Config - .ForType() - .MapWith((source) => new(source)); + TypeAdapterConfig.GlobalSettings.Default.Config + .ForType() + .MapWith((source) => new(source)); - TypeAdapterConfig.GlobalSettings.Default.Config - .ForType() - .MapWith((source) => new(source)); + TypeAdapterConfig.GlobalSettings.Default.Config + .ForType() + .MapWith((source) => new(source)); #pragma warning disable CS8603 // Possible null reference return. - TypeAdapterConfig.GlobalSettings.Default.Config - .ForType() - .Ignore(dst => dst.Cluster, - dst => dst.RelationCompaniesWells, - dst => dst.Telemetry, - dst => dst.WellComposites, - dst => dst.WellCompositeSrcs, - dst => dst.WellOperations, - dst => dst.WellType); + TypeAdapterConfig.GlobalSettings.Default.Config + .ForType() + .Ignore(dst => dst.Cluster, + dst => dst.RelationCompaniesWells, + dst => dst.Telemetry, + dst => dst.WellComposites, + dst => dst.WellCompositeSrcs, + dst => dst.WellOperations, + dst => dst.WellType); #pragma warning restore CS8603 // Possible null reference return. - TypeAdapterConfig.GlobalSettings.Default.Config - .ForType() - .Ignore(dst => dst.Deposit, - dst => dst.Wells); + TypeAdapterConfig.GlobalSettings.Default.Config + .ForType() + .Ignore(dst => dst.Deposit, + dst => dst.Wells); - TypeAdapterConfig.GlobalSettings.Default.Config - .ForType(); + TypeAdapterConfig.GlobalSettings.Default.Config + .ForType(); - TypeAdapterConfig.GlobalSettings.Default.Config - .ForType(); + TypeAdapterConfig.GlobalSettings.Default.Config + .ForType(); - TypeAdapterConfig.GlobalSettings.Default.Config - .ForType() - .Ignore(dst => dst.NotificationCategory, - dst => dst.User); + TypeAdapterConfig.GlobalSettings.Default.Config + .ForType() + .Ignore(dst => dst.NotificationCategory, + dst => dst.User); - TypeAdapterConfig.GlobalSettings.Default.Config - .ForType() - .Map(dest => dest.AxialLoad, src => new PlanLimitDto - { - LimitMax = src.AxialLoadLimitMax, - Plan = src.AxialLoadPlan - }) - .Map(dest => dest.Flow, src => new PlanLimitDto - { - LimitMax = src.FlowLimitMax, - Plan = src.FlowPlan - }) - .Map(dest => dest.Pressure, src => new PlanLimitDto - { - LimitMax = src.PressureLimitMax, - Plan = src.PressurePlan - }) - .Map(dest => dest.TopDriveSpeed, src => new PlanLimitDto - { - LimitMax = src.TopDriveSpeedLimitMax, - Plan = src.TopDriveSpeedPlan - }) - .Map(dest => dest.TopDriveTorque, src => new PlanLimitDto - { - LimitMax = src.TopDriveTorqueLimitMax, - Plan = src.TopDriveTorquePlan - }); + TypeAdapterConfig.GlobalSettings.Default.Config + .ForType() + .Map(dest => dest.AxialLoad, src => new PlanLimitDto + { + LimitMax = src.AxialLoadLimitMax, + Plan = src.AxialLoadPlan + }) + .Map(dest => dest.Flow, src => new PlanLimitDto + { + LimitMax = src.FlowLimitMax, + Plan = src.FlowPlan + }) + .Map(dest => dest.Pressure, src => new PlanLimitDto + { + LimitMax = src.PressureLimitMax, + Plan = src.PressurePlan + }) + .Map(dest => dest.TopDriveSpeed, src => new PlanLimitDto + { + LimitMax = src.TopDriveSpeedLimitMax, + Plan = src.TopDriveSpeedPlan + }) + .Map(dest => dest.TopDriveTorque, src => new PlanLimitDto + { + LimitMax = src.TopDriveTorqueLimitMax, + Plan = src.TopDriveTorquePlan + }); - TypeAdapterConfig.GlobalSettings.Default.Config - .ForType() - .Map(dest => dest.AxialLoadPlan, src => src.AxialLoad.Plan) - .Map(dest => dest.AxialLoadLimitMax, src => src.AxialLoad.LimitMax) - .Map(dest => dest.FlowPlan, src => src.Flow.Plan) - .Map(dest => dest.FlowLimitMax, src => src.Flow.LimitMax) - .Map(dest => dest.PressurePlan, src => src.Pressure.Plan) - .Map(dest => dest.PressureLimitMax, src => src.Pressure.LimitMax) - .Map(dest => dest.TopDriveSpeedPlan, src => src.TopDriveSpeed.Plan) - .Map(dest => dest.TopDriveSpeedLimitMax, src => src.TopDriveSpeed.LimitMax) - .Map(dest => dest.TopDriveTorquePlan, src => src.TopDriveTorque.Plan) - .Map(dest => dest.TopDriveTorqueLimitMax, src => src.TopDriveTorque.LimitMax); - } + TypeAdapterConfig.GlobalSettings.Default.Config + .ForType() + .Map(dest => dest.AxialLoadPlan, src => src.AxialLoad.Plan) + .Map(dest => dest.AxialLoadLimitMax, src => src.AxialLoad.LimitMax) + .Map(dest => dest.FlowPlan, src => src.Flow.Plan) + .Map(dest => dest.FlowLimitMax, src => src.Flow.LimitMax) + .Map(dest => dest.PressurePlan, src => src.Pressure.Plan) + .Map(dest => dest.PressureLimitMax, src => src.Pressure.LimitMax) + .Map(dest => dest.TopDriveSpeedPlan, src => src.TopDriveSpeed.Plan) + .Map(dest => dest.TopDriveSpeedLimitMax, src => src.TopDriveSpeed.LimitMax) + .Map(dest => dest.TopDriveTorquePlan, src => src.TopDriveTorque.Plan) + .Map(dest => dest.TopDriveTorqueLimitMax, src => src.TopDriveTorque.LimitMax); + } - public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration) - { - MapsterSetup(); - string connectionStringName = "DefaultConnection"; + public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration) + { + MapsterSetup(); + string connectionStringName = "DefaultConnection"; #if DEBUG - connectionStringName = "DebugConnection"; + connectionStringName = "DebugConnection"; #endif - services.AddDbContext(options => - options.UseNpgsql(configuration.GetConnectionString(connectionStringName))); + services.AddDbContext(options => + options.UseNpgsql(configuration.GetConnectionString(connectionStringName))); - services.AddMemoryCache(); - services.AddScoped(provider => provider.GetRequiredService()); + services.AddMemoryCache(); + services.AddScoped(provider => provider.GetRequiredService()); - services.AddSingleton(new WitsInfoService()); - services.AddSingleton(provider => TelemetryDataCache.GetInstance(provider)); - services.AddSingleton(provider => TelemetryDataCache.GetInstance(provider)); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(provider => ReduceSamplingService.GetInstance(configuration)); + services.AddSingleton(new WitsInfoService()); + services.AddSingleton(provider => TelemetryDataCache.GetInstance(provider)); + services.AddSingleton(provider => TelemetryDataCache.GetInstance(provider)); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(provider => ReduceSamplingService.GetInstance(configuration)); - services.AddTransient(); - services.AddTransient, ProcessMapPlanRepository>(); - services.AddTransient, ProcessMapPlanRepository>(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient, CrudWellRelatedRepositoryBase>(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); + services.AddTransient(); + services.AddTransient, ProcessMapPlanRepository>(); + services.AddTransient, ProcessMapPlanRepository>(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient, CrudWellRelatedRepositoryBase>(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); - services.AddTransient(); + services.AddTransient(); - services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); - services.AddTransient, CrudCacheRepositoryBase, CrudCacheRepositoryBase>(); services.AddTransient(); - // admin crud services: - services.AddTransient, CrudCacheRepositoryBase>(s => - new CrudCacheRepositoryBase( - s.GetRequiredService(), - s.GetRequiredService(), - dbSet => dbSet.Include(t => t.Well))); // может быть включен в сервис TelemetryService - services.AddTransient, CrudCacheRepositoryBase>(s => - new CrudCacheRepositoryBase( - s.GetRequiredService(), - s.GetRequiredService(), - dbSet => dbSet.Include(d => d.Clusters))); - services.AddTransient, CrudCacheRepositoryBase>(s => - new CrudCacheRepositoryBase( - s.GetRequiredService(), - s.GetRequiredService(), - dbSet => dbSet.Include(c => c.CompanyType))); + // admin crud services: + services.AddTransient, CrudCacheRepositoryBase>(s => + new CrudCacheRepositoryBase( + s.GetRequiredService(), + s.GetRequiredService(), + dbSet => dbSet.Include(t => t.Well))); // может быть включен в сервис TelemetryService + services.AddTransient, CrudCacheRepositoryBase>(s => + new CrudCacheRepositoryBase( + s.GetRequiredService(), + s.GetRequiredService(), + dbSet => dbSet.Include(d => d.Clusters))); + services.AddTransient, CrudCacheRepositoryBase>(s => + new CrudCacheRepositoryBase( + s.GetRequiredService(), + s.GetRequiredService(), + dbSet => dbSet.Include(c => c.CompanyType))); - services.AddTransient, CrudCacheRepositoryBase>(); - services.AddTransient, CrudCacheRepositoryBase>(s => - new CrudCacheRepositoryBase( - s.GetRequiredService(), - s.GetRequiredService(), - dbSet => dbSet - .Include(c => c.Wells) - .Include(c => c.Deposit))); // может быть включен в сервис ClusterService + services.AddTransient, CrudCacheRepositoryBase>(); + services.AddTransient, CrudCacheRepositoryBase>(s => + new CrudCacheRepositoryBase( + s.GetRequiredService(), + s.GetRequiredService(), + dbSet => dbSet + .Include(c => c.Wells) + .Include(c => c.Deposit))); // может быть включен в сервис ClusterService - services.AddTransient, CrudCacheRepositoryBase>(); + services.AddTransient, CrudCacheRepositoryBase>(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient, CrudCacheRepositoryBase>(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient, CrudCacheRepositoryBase>(); - // Subsystem service - services.AddTransient, CrudCacheRepositoryBase>(); - services.AddTransient(); + // Subsystem service + services.AddTransient, CrudCacheRepositoryBase>(); + services.AddTransient(); - services.AddTransient, CrudCacheRepositoryBase>(); + services.AddTransient, CrudCacheRepositoryBase>(); - // TelemetryData services - services.AddTransient(); - services.AddTransient, TelemetryDataSpinService>(); + // TelemetryData services + services.AddTransient(); + services.AddTransient, TelemetryDataSpinService>(); - // Wits - services.AddTransient, WitsRecordRepository>(); - services.AddTransient, WitsRecordRepository>(); - services.AddTransient, WitsRecordRepository>(); - services.AddTransient, WitsRecordRepository>(); - services.AddTransient, WitsRecordRepository>(); - services.AddTransient, WitsRecordRepository>(); + // Wits + services.AddTransient, WitsRecordRepository>(); + services.AddTransient, WitsRecordRepository>(); + services.AddTransient, WitsRecordRepository>(); + services.AddTransient, WitsRecordRepository>(); + services.AddTransient, WitsRecordRepository>(); + services.AddTransient, WitsRecordRepository>(); - services.AddTransient(); - services.AddTransient(); + services.AddTransient(); + services.AddTransient, AutoGeneratedDailyReportMakerService>(); + services.AddTransient(); + services.AddTransient, DrillTestReportMakerService>(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient, CrudRepositoryBase>(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient, CrudRepositoryBase>(); - services.AddTransient(); + services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); - services.AddTransient, WellOperationDefaultExcelParser>(); - services.AddTransient, WellOperationGazpromKhantosExcelParser>(); + services.AddTransient, WellOperationDefaultExcelParser>(); + services.AddTransient, WellOperationGazpromKhantosExcelParser>(); - return services; - } + return services; + } - public static IServiceCollection AddTransientLazy(this IServiceCollection services) - where TService : class - where TImplementation : class, TService - => services.AddTransient() - .AddTransient(provider => new Lazy(provider.GetRequiredService)); + public static IServiceCollection AddTransientLazy(this IServiceCollection services) + where TService : class + where TImplementation : class, TService + => services.AddTransient() + .AddTransient(provider => new Lazy(provider.GetRequiredService)); - public static IServiceCollection AddTransientLazy(this IServiceCollection services, Func implementationFactory) - where TService : class - where TImplementation : class, TService - => services.AddTransient(implementationFactory) - .AddTransient(provider => new Lazy(() => implementationFactory(provider))); + public static IServiceCollection AddTransientLazy(this IServiceCollection services, Func implementationFactory) + where TService : class + where TImplementation : class, TService + => services.AddTransient(implementationFactory) + .AddTransient(provider => new Lazy(() => implementationFactory(provider))); } diff --git a/AsbCloudInfrastructure/Repository/DrillTestRepository.cs b/AsbCloudInfrastructure/Repository/DrillTestRepository.cs index a308cb0b..f5fb4ece 100644 --- a/AsbCloudInfrastructure/Repository/DrillTestRepository.cs +++ b/AsbCloudInfrastructure/Repository/DrillTestRepository.cs @@ -1,7 +1,13 @@ using AsbCloudApp.Data.SAUB; +using AsbCloudApp.Exceptions; using AsbCloudApp.Repositories; +using AsbCloudApp.Requests; using AsbCloudDb.Model; using Mapster; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -16,6 +22,47 @@ namespace AsbCloudInfrastructure.Repository this.db = db; } + public async Task> GetAllAsync(int idTelemetry, FileReportRequest request, CancellationToken cancellationToken) + { + var query = db.DrillTests + .Where(d => d.IdTelemetry == idTelemetry) + .Include(d => d.Telemetry) + .AsNoTracking(); + + if (request.GeDate.HasValue) + { + var startDateUTC = new DateTimeOffset(request.GeDate.Value.Year, request.GeDate.Value.Month, request.GeDate.Value.Day, 0, 0, 0, TimeSpan.Zero); + query = query.Where(q => q.TimeStampStart >= startDateUTC); + } + if (request.LeDate.HasValue) + { + var finishDateUTC = new DateTimeOffset(request.LeDate.Value.Year, request.LeDate.Value.Month, request.LeDate.Value.Day, 0, 0, 0, TimeSpan.Zero); + query = query.Where(q => q.TimeStampStart <= finishDateUTC); + } + + var entities = await query.ToListAsync(cancellationToken); + var dtos = entities.Select(e => Convert(e)); + + return dtos; + } + + + public async Task GetAsync(int idTelemetry, int id, CancellationToken cancellationToken) + { + var drillTest = await db.DrillTests + .Where(d => d.Id == id) + .Include(d => d.Telemetry) + .Where(d => d.Telemetry.Id == idTelemetry) + .FirstOrDefaultAsync(cancellationToken); + + if (drillTest is null) + throw new ArgumentInvalidException(new string[] { nameof(id), nameof(idTelemetry) }, $"Drill test with id: {id} and idTelemetry: {idTelemetry} does not exist."); + + var dto = Convert(drillTest); + + return dto; + } + public async Task SaveDataAsync(int idTelemetry, DrillTestDto dto, CancellationToken token) { var entity = dto.Adapt(); @@ -24,5 +71,12 @@ namespace AsbCloudInfrastructure.Repository var result = await db.SaveChangesAsync(token); return result; } + + private DrillTestDto Convert(DrillTest entity) + { + var dto = entity.Adapt(); + dto.TimeStampStart = dto.TimeStampStart.ToRemoteDateTime(dto.Telemetry?.TimeZone?.Hours ?? 0); + return dto; + } } } diff --git a/AsbCloudInfrastructure/Services/AutoGeneratedDailyReports/AutoGeneratedDailyReportMakerService.cs b/AsbCloudInfrastructure/Services/AutoGeneratedDailyReports/AutoGeneratedDailyReportMakerService.cs index 0f1c7076..cfc95753 100644 --- a/AsbCloudInfrastructure/Services/AutoGeneratedDailyReports/AutoGeneratedDailyReportMakerService.cs +++ b/AsbCloudInfrastructure/Services/AutoGeneratedDailyReports/AutoGeneratedDailyReportMakerService.cs @@ -5,14 +5,16 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data.AutogeneratedDailyReport; -using AsbCloudApp.Services.AutoGeneratedDailyReports; +using AsbCloudApp.Services; using AsbCloudInfrastructure.Services.AutoGeneratedDailyReports.AutogeneratedDailyReportBlocks; using ClosedXML.Excel; namespace AsbCloudInfrastructure.Services.AutoGeneratedDailyReports; -public class AutoGeneratedDailyReportMakerService : IAutoGeneratedDailyReportMakerService +public class AutoGeneratedDailyReportMakerService : IReportMakerService { + private readonly string templateName = "AutogeneratedDailyReportTemplate.xlsx"; + private readonly IEnumerable blockWriters = new List() { new HeadExcelBlockWriter(), @@ -20,10 +22,12 @@ public class AutoGeneratedDailyReportMakerService : IAutoGeneratedDailyReportMak new LimitingParameterExcelBlockWriter(), new TimeBalanceExcelBlockWriter() }; - - public async Task MakeReportAsync(AutoGeneratedDailyReportDto report, CancellationToken cancellationToken) + + public async Task MakeReportAsync(AutoGeneratedDailyReportDto report, CancellationToken cancellationToken) { - using var excelTemplateStream = await GetExcelTemplateStreamAsync(cancellationToken); + using var excelTemplateStream = await Assembly + .GetExecutingAssembly() + .GetTemplateCopyStreamAsync(templateName, cancellationToken); using var workbook = new XLWorkbook(excelTemplateStream, XLEventTracking.Disabled); @@ -35,22 +39,6 @@ public class AutoGeneratedDailyReportMakerService : IAutoGeneratedDailyReportMak return memoryStream; } - - private async Task GetExcelTemplateStreamAsync(CancellationToken cancellationToken) - { - var resourceName = Assembly.GetExecutingAssembly() - .GetManifestResourceNames() - .FirstOrDefault(n => n.EndsWith("AutogeneratedDailyReportTemplate.xlsx"))!; - - using var stream = Assembly.GetExecutingAssembly() - .GetManifestResourceStream(resourceName)!; - - var memoryStream = new MemoryStream(); - await stream.CopyToAsync(memoryStream, cancellationToken); - memoryStream.Position = 0; - - return memoryStream; - } private void AddToWorkbook(XLWorkbook workbook, AutoGeneratedDailyReportDto report) { diff --git a/AsbCloudInfrastructure/Services/AutoGeneratedDailyReports/AutoGeneratedDailyReportService.cs b/AsbCloudInfrastructure/Services/AutoGeneratedDailyReports/AutoGeneratedDailyReportService.cs index 03ed6e07..1ada2676 100644 --- a/AsbCloudInfrastructure/Services/AutoGeneratedDailyReports/AutoGeneratedDailyReportService.cs +++ b/AsbCloudInfrastructure/Services/AutoGeneratedDailyReports/AutoGeneratedDailyReportService.cs @@ -26,14 +26,14 @@ public class AutoGeneratedDailyReportService : IAutoGeneratedDailyReportService private readonly ISubsystemOperationTimeService subsystemOperationTimeService; private readonly ICrudRepository subsystemRepository; private readonly ILimitingParameterService limitingParameterService; - private readonly IAutoGeneratedDailyReportMakerService autoGeneratedDailyReportMakerService; + private readonly IReportMakerService autoGeneratedDailyReportMakerService; public AutoGeneratedDailyReportService(IWellService wellService, IWellOperationRepository wellOperationRepository, ISubsystemOperationTimeService subsystemOperationTimeService, ICrudRepository subsystemRepository, ILimitingParameterService limitingParameterService, - IAutoGeneratedDailyReportMakerService autoGeneratedDailyReportMakerService) + IReportMakerService autoGeneratedDailyReportMakerService) { this.wellOperationRepository = wellOperationRepository; this.wellService = wellService; @@ -44,7 +44,7 @@ public class AutoGeneratedDailyReportService : IAutoGeneratedDailyReportService } public async Task> GetListAsync(int idWell, - AutoGeneratedDailyReportRequest request, + FileReportRequest request, CancellationToken cancellationToken) { var result = new PaginationContainer @@ -67,19 +67,19 @@ public class AutoGeneratedDailyReportService : IAutoGeneratedDailyReportService if (datesRange is null) return result; - if (request.StartDate.HasValue) + if (request.GeDate.HasValue) { - var startDate = new DateTime(request.StartDate.Value.Year, request.StartDate.Value.Month, - request.StartDate.Value.Day); + var startDate = new DateTime(request.GeDate.Value.Year, request.GeDate.Value.Month, + request.GeDate.Value.Day); if(startDate.Date >= datesRange.From.Date) datesRange.From = startDate; } - if (request.FinishDate.HasValue) + if (request.LeDate.HasValue) { - var finishDate = new DateTime(request.FinishDate.Value.Year, request.FinishDate.Value.Month, - request.FinishDate.Value.Day); + var finishDate = new DateTime(request.LeDate.Value.Year, request.LeDate.Value.Month, + request.LeDate.Value.Day); if (finishDate.Date <= datesRange.To.Date) datesRange.To = finishDate; diff --git a/AsbCloudInfrastructure/Services/DrillTestReport/DrillTestReportMakerService.cs b/AsbCloudInfrastructure/Services/DrillTestReport/DrillTestReportMakerService.cs new file mode 100644 index 00000000..27a01e85 --- /dev/null +++ b/AsbCloudInfrastructure/Services/DrillTestReport/DrillTestReportMakerService.cs @@ -0,0 +1,90 @@ +using AsbCloudApp.Data.DrillTestReport; +using AsbCloudApp.Services; +using ClosedXML.Excel; +using System; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; + +namespace AsbCloudInfrastructure.Services.DrillTestReport +{ + public class DrillTestReportMakerService : IReportMakerService + { + private readonly string templateName = "DrillTestReportTemplate.xlsx"; + private readonly string sheetName = "Лист1"; + private readonly int startRowNumber = 8; + + public async Task MakeReportAsync(DrillTestReportDataDto report, CancellationToken cancellationToken) + { + using var excelTemplateStream = await Assembly.GetExecutingAssembly().GetTemplateCopyStreamAsync(templateName, cancellationToken); + + using var workbook = new XLWorkbook(excelTemplateStream, XLEventTracking.Disabled); + + AddToWorkbook(workbook, report); + + MemoryStream memoryStream = new MemoryStream(); + workbook.SaveAs(memoryStream, new SaveOptions { }); + memoryStream.Seek(0, SeekOrigin.Begin); + + return memoryStream; + } + + + private void AddToWorkbook(XLWorkbook workbook, DrillTestReportDataDto report) + { + var drillTestEntities = report.Data.Params; + if (!drillTestEntities.Any()) + return; + + var sheet = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetName) + ?? throw new FileFormatException($"Книга excel не содержит листа {sheetName}."); + + sheet.Cell(4, 2).Value = report.Caption; + sheet.Cell(5, 2)._SetValue(report.Date, setAllBorders: false); + + var rowNumber = startRowNumber; + + var stepWithMaxDepthSpeed = drillTestEntities.OrderByDescending(p => p.DepthSpeed).FirstOrDefault()!.Step; + var startDepth = report.Data.DepthStart; + var startDate = report.Data.TimeStampStart; + + foreach (var drillTestEntity in drillTestEntities) + { + var endDepth = startDepth + (drillTestEntity.DepthDrillStep ?? 0); + var endDateTime = startDate.AddSeconds(drillTestEntity.TimeDrillStep ?? 0); + + sheet.Cell(rowNumber, 2).Value = startDepth; + + sheet.Cell(rowNumber, 3).Value = endDepth; + + sheet.Cell(rowNumber, 4).Value = drillTestEntity.DepthDrillStep; + + sheet.Cell(rowNumber, 5).Value = drillTestEntity.Workload; + + sheet.Cell(rowNumber, 6).Value = drillTestEntity.Speed; + + var cell = sheet.Cell(rowNumber, 7); + cell._SetValue(startDate.DateTime); + + cell = sheet.Cell(rowNumber, 8); + cell._SetValue(endDateTime.DateTime); + + sheet.Cell(rowNumber, 9).Value = Math.Round((drillTestEntity.TimeDrillStep ?? 0) / (60 * 60), 2); + + sheet.Cell(rowNumber, 10).Value = drillTestEntity.DepthSpeed; + + if (drillTestEntity.Step == stepWithMaxDepthSpeed) + { + var currentCells = sheet.Row(rowNumber).Cells(1, 10); + currentCells.Style.Fill.BackgroundColor = XLColor.Yellow; + } + + startDepth = endDepth; + startDate = endDateTime; + rowNumber++; + } + } + } +} diff --git a/AsbCloudInfrastructure/Services/DrillTestReport/DrillTestReportService.cs b/AsbCloudInfrastructure/Services/DrillTestReport/DrillTestReportService.cs new file mode 100644 index 00000000..983d1f7c --- /dev/null +++ b/AsbCloudInfrastructure/Services/DrillTestReport/DrillTestReportService.cs @@ -0,0 +1,99 @@ +using AsbCloudApp.Data; +using AsbCloudApp.Data.DrillTestReport; +using AsbCloudApp.Exceptions; +using AsbCloudApp.Repositories; +using AsbCloudApp.Requests; +using AsbCloudApp.Services; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace AsbCloudInfrastructure.Services.DrillTestReport +{ + public class DrillTestReportService : IDrillTestReportService + { + private readonly IWellService wellService; + private readonly IDrillTestRepository drillTestRepository; + private readonly ITelemetryService telemetryService; + private readonly IReportMakerService drillTestReportMakerService; + + public DrillTestReportService( + IWellService wellService, + IDrillTestRepository drillTestRepository, + ITelemetryService telemetryService, + IReportMakerService drillTestReportMakerService) + { + this.wellService = wellService; + this.drillTestRepository = drillTestRepository; + this.telemetryService = telemetryService; + this.drillTestReportMakerService = drillTestReportMakerService; + } + + public async Task<(string fileName, Stream stream)> GenerateAsync(int idWell, int id, CancellationToken cancellationToken) + { + var well = wellService.GetOrDefault(idWell); + if (well is null) + throw new ArgumentInvalidException(nameof(idWell), $"Well with id: {idWell} does not exist."); + if (well.IdTelemetry is null) + throw new ArgumentInvalidException(nameof(well.IdTelemetry), $"Well with id: {idWell} does not have telemetry."); + + var dto = await drillTestRepository.GetAsync(well.IdTelemetry.Value, id, cancellationToken); + + var report = new DrillTestReportDataDto() + { + Data = dto, + Caption = string.Format("Месторождение: {0}, куст: {1}, скважина: {2}", + well.Deposit ?? "-", + well.Cluster ?? "-", + well.Caption ?? "-"), + Date = DateTime.Now, + }; + + var fileName = string.Format("Drill_test_{0}.xlsx", dto.TimeStampStart.ToString("dd.mm.yyyy_HH_MM_ss")); + var stream = await drillTestReportMakerService.MakeReportAsync(report, cancellationToken); + + return (fileName, stream); + } + + + public async Task> GetListAsync(int idWell, FileReportRequest request, CancellationToken cancellationToken) + { + var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell); + if (telemetry is null) + throw new Exception($"Telemetry with idWell: {idWell} does not exist."); + + var result = new PaginationContainer + { + Skip = request.Skip ?? 0, + Take = request.Take ?? 10, + Items = Enumerable.Empty() + }; + + var reports = new List(); + var timezone = telemetryService.GetTimezone(telemetry.Id); + + var dtos = await drillTestRepository.GetAllAsync(telemetry.Id, request, cancellationToken); + foreach (var dto in dtos) + { + var remoteDateTime = dto.TimeStampStart.ToRemoteDateTime(timezone.Hours); + + reports.Add(new DrillTestReportInfoDto + { + FileName = string.Format("Drill_test_{0}", dto.TimeStampStart.DateTime), + DrillDepth = (dto.Params + .Where(p => p.DepthDrillStep.HasValue) + .Sum(x => x.DepthDrillStep) ?? 0) + dto.DepthStart, + DateTime = dto.TimeStampStart.DateTime, + Id = dto.Id, + }); + } + + result.Items = reports; + + return result; + } + } +} diff --git a/AsbCloudInfrastructure/Services/DrillTestReport/DrillTestReportTemplate.xlsx b/AsbCloudInfrastructure/Services/DrillTestReport/DrillTestReportTemplate.xlsx new file mode 100644 index 00000000..c6336b88 Binary files /dev/null and b/AsbCloudInfrastructure/Services/DrillTestReport/DrillTestReportTemplate.xlsx differ diff --git a/AsbCloudInfrastructure/XLExtentions.cs b/AsbCloudInfrastructure/XLExtentions.cs index c1a463d0..ca083b6a 100644 --- a/AsbCloudInfrastructure/XLExtentions.cs +++ b/AsbCloudInfrastructure/XLExtentions.cs @@ -8,119 +8,123 @@ namespace AsbCloudInfrastructure; internal static class XLExtentions { - internal static IXLRange _SetValue(this IXLRange range, object value) - { - var mergedRange = range.Merge(); - mergedRange.FirstCell()._SetValue(value); - var colWidth = mergedRange.FirstCell().WorksheetColumn().Width; - var maxCharsToWrap = colWidth / (0.1d * mergedRange.FirstCell().Style.Font.FontSize); - if (value is string valueString && valueString.Length > maxCharsToWrap) - { - var row = mergedRange.FirstCell().WorksheetRow(); - var baseHeight = row.Height; - row.Height = 0.5d * baseHeight * Math.Ceiling(1d + valueString.Length / maxCharsToWrap); - } + internal static IXLRange _SetValue(this IXLRange range, object value) + { + var mergedRange = range.Merge(); + mergedRange.FirstCell()._SetValue(value); + var colWidth = mergedRange.FirstCell().WorksheetColumn().Width; + var maxCharsToWrap = colWidth / (0.1d * mergedRange.FirstCell().Style.Font.FontSize); + if (value is string valueString && valueString.Length > maxCharsToWrap) + { + var row = mergedRange.FirstCell().WorksheetRow(); + var baseHeight = row.Height; + row.Height = 0.5d * baseHeight * Math.Ceiling(1d + valueString.Length / maxCharsToWrap); + } - mergedRange.Style.SetAllBorders() - .Alignment.SetWrapText(true); - return mergedRange; - } + mergedRange.Style.SetAllBorders() + .Alignment.SetWrapText(true); + return mergedRange; + } - internal static IXLCell _SetValue(this IXLCell cell, object value) - { - switch (value) - { - case DateTime dateTime: - cell._SetValue(dateTime); - break; - case IFormattable formattable: - cell._SetValue(formattable); - break; - case string valueString: - cell._SetValue(valueString); - break; - default: - cell.Value = value; - break; - } + internal static IXLCell _SetValue(this IXLCell cell, object value) + { + switch (value) + { + case DateTime dateTime: + cell._SetValue(dateTime); + break; + case IFormattable formattable: + cell._SetValue(formattable); + break; + case string valueString: + cell._SetValue(valueString); + break; + default: + cell.Value = value; + break; + } - return cell; - } + return cell; + } - internal static IXLCell _SetValue(this IXLCell cell, string value, bool adaptRowHeight = false) - { - cell.Value = value; - cell.Style - .SetAllBorders() - .Alignment.WrapText = true; + internal static IXLCell _SetValue(this IXLCell cell, string value, bool adaptRowHeight = false) + { + cell.Value = value; + cell.Style + .SetAllBorders() + .Alignment.WrapText = true; - cell.Value = value; - if (adaptRowHeight) - { - var colWidth = cell.WorksheetColumn().Width; - var maxCharsToWrap = colWidth / (0.1d * cell.Style.Font.FontSize); - if (value.Length > maxCharsToWrap) - { - var row = cell.WorksheetRow(); - var baseHeight = row.Height; - row.Height = 0.5d * baseHeight * Math.Ceiling(1d + value.Length / maxCharsToWrap); - } - } + cell.Value = value; + if (adaptRowHeight) + { + var colWidth = cell.WorksheetColumn().Width; + var maxCharsToWrap = colWidth / (0.1d * cell.Style.Font.FontSize); + if (value.Length > maxCharsToWrap) + { + var row = cell.WorksheetRow(); + var baseHeight = row.Height; + row.Height = 0.5d * baseHeight * Math.Ceiling(1d + value.Length / maxCharsToWrap); + } + } - return cell; - } + return cell; + } - internal static IXLCell _ValueNoBorder(this IXLCell cell, string value, bool adaptRowHeight = false) - { - cell.Value = value; - cell.Style.Alignment.WrapText = true; + internal static IXLCell _ValueNoBorder(this IXLCell cell, string value, bool adaptRowHeight = false) + { + cell.Value = value; + cell.Style.Alignment.WrapText = true; - cell.Value = value; - if (adaptRowHeight) - { - var colWidth = cell.WorksheetColumn().Width; - var maxCharsToWrap = colWidth / (0.1d * cell.Style.Font.FontSize); - if (value.Length > maxCharsToWrap) - { - var row = cell.WorksheetRow(); - var baseHeight = row.Height; - row.Height = 0.5d * baseHeight * Math.Ceiling(1d + value.Length / maxCharsToWrap); - } - } + cell.Value = value; + if (adaptRowHeight) + { + var colWidth = cell.WorksheetColumn().Width; + var maxCharsToWrap = colWidth / (0.1d * cell.Style.Font.FontSize); + if (value.Length > maxCharsToWrap) + { + var row = cell.WorksheetRow(); + var baseHeight = row.Height; + row.Height = 0.5d * baseHeight * Math.Ceiling(1d + value.Length / maxCharsToWrap); + } + } - return cell; - } + return cell; + } - internal static IXLCell _SetValue(this IXLCell cell, DateTime value, string dateFormat = "DD.MM.YYYY HH:MM:SS") - { - cell.Value = value; - cell.Style - .SetAllBorders() - .Alignment.WrapText = true; + internal static IXLCell _SetValue(this IXLCell cell, DateTime value, string dateFormat = "DD.MM.YYYY HH:MM:SS", bool setAllBorders = true) + { + cell.Value = value; + if (setAllBorders == true) + { + cell.Style + .SetAllBorders() + .Alignment.WrapText = true; + } - cell.Value = value; - cell.DataType = XLDataType.DateTime; - cell.Style.DateFormat.Format = "DD.MM.YYYY HH:MM:SS"; + cell.Value = value; - return cell; - } + cell.DataType = XLDataType.DateTime; + cell.Style.DateFormat.Format = "DD.MM.YYYY HH:MM:SS"; - internal static IXLCell _SetValue(this IXLCell cell, IFormattable value, string format = "0.00") - { - cell.Value = value; - cell.Style - .SetAllBorders() - .Alignment.WrapText = true; + return cell; + } - cell.Value = value; + internal static IXLCell _SetValue(this IXLCell cell, IFormattable value, string format = "0.00") + { + cell.Value = value; + cell.Style + .SetAllBorders() + .Alignment.WrapText = true; - cell.DataType = XLDataType.Number; - cell.Style.NumberFormat.Format = "0.00"; + cell.Value = value; - return cell; - } + cell.DataType = XLDataType.Number; + cell.Style.NumberFormat.Format = "0.00"; + + return cell; + } public static IXLCell SetVal(this IXLCell cell, double? value, string format = "0.00") { @@ -158,60 +162,60 @@ internal static class XLExtentions } internal static IXLStyle SetAllBorders(this IXLStyle style, XLBorderStyleValues borderStyle = XLBorderStyleValues.Thin) - { - style.Border.RightBorder = borderStyle; - style.Border.LeftBorder = borderStyle; - style.Border.TopBorder = borderStyle; - style.Border.BottomBorder = borderStyle; - style.Border.InsideBorder = borderStyle; - style.Border.OutsideBorder = borderStyle; - return style; - } + { + style.Border.RightBorder = borderStyle; + style.Border.LeftBorder = borderStyle; + style.Border.TopBorder = borderStyle; + style.Border.BottomBorder = borderStyle; + style.Border.InsideBorder = borderStyle; + style.Border.OutsideBorder = borderStyle; + return style; + } - internal static IXLStyle SetBaseFont(this IXLStyle style) - { - style.Font.FontName = "Calibri"; - style.Font.FontSize = 10; - return style; - } + internal static IXLStyle SetBaseFont(this IXLStyle style) + { + style.Font.FontName = "Calibri"; + style.Font.FontSize = 10; + return style; + } - internal static IXLStyle SetH1(this IXLStyle style) - { - style.Font.FontName = "Calibri"; - style.Font.FontSize = 14; - return style; - } + internal static IXLStyle SetH1(this IXLStyle style) + { + style.Font.FontName = "Calibri"; + style.Font.FontSize = 14; + return style; + } - /// - /// Костыль исправляющий проблему в библиотеке IXLRange Range(this IXLWorksheet, IXLAddress, IXLAddress) с кастингом IXLAddress к XLAddress. - /// - /// - /// - /// - /// - internal static IXLRange _Range(this IXLWorksheet sheet, CellAddress begin, CellAddress end) - => sheet.Range(begin.RowNumber, begin.ColumnNumber, end.RowNumber, end.ColumnNumber); - - - internal static T? GetCellValue(this IXLCell cell) - { - try - { - if (cell.IsEmpty() && default(T) == null) - return default; - - if (typeof(T) != typeof(DateTime)) - return (T)Convert.ChangeType(cell.GetFormattedString(), typeof(T), CultureInfo.InvariantCulture); + /// + /// Костыль исправляющий проблему в библиотеке IXLRange Range(this IXLWorksheet, IXLAddress, IXLAddress) с кастингом IXLAddress к XLAddress. + /// + /// + /// + /// + /// + internal static IXLRange _Range(this IXLWorksheet sheet, CellAddress begin, CellAddress end) + => sheet.Range(begin.RowNumber, begin.ColumnNumber, end.RowNumber, end.ColumnNumber); + + + internal static T? GetCellValue(this IXLCell cell) + { + try + { + if (cell.IsEmpty() && default(T) == null) + return default; + + if (typeof(T) != typeof(DateTime)) + return (T)Convert.ChangeType(cell.GetFormattedString(), typeof(T), CultureInfo.InvariantCulture); if (cell.Value is DateTime dateTime) return (T)(object)dateTime; return (T)(object)DateTime.FromOADate((double)cell.Value); - } - catch - { - throw new FileFormatException( - $"Лист '{cell.Worksheet.Name}'. Ячейка: ({cell.Address.RowNumber},{cell.Address.ColumnNumber}) содержит некорректное значение"); - } - } + } + catch + { + throw new FileFormatException( + $"Лист '{cell.Worksheet.Name}'. Ячейка: ({cell.Address.RowNumber},{cell.Address.ColumnNumber}) содержит некорректное значение"); + } + } } \ No newline at end of file diff --git a/AsbCloudWebApi/Controllers/AutoGeneratedDailyReportController.cs b/AsbCloudWebApi/Controllers/AutoGeneratedDailyReportController.cs index de26e843..a392bf51 100644 --- a/AsbCloudWebApi/Controllers/AutoGeneratedDailyReportController.cs +++ b/AsbCloudWebApi/Controllers/AutoGeneratedDailyReportController.cs @@ -25,7 +25,8 @@ public class AutoGeneratedDailyReportController : ControllerBase private readonly IAutoGeneratedDailyReportService autoGeneratedDailyReportService; private readonly IWellService wellService; - public AutoGeneratedDailyReportController(IAutoGeneratedDailyReportService autoGeneratedDailyReportService, + public AutoGeneratedDailyReportController( + IAutoGeneratedDailyReportService autoGeneratedDailyReportService, IWellService wellService) { this.autoGeneratedDailyReportService = autoGeneratedDailyReportService; @@ -66,7 +67,7 @@ public class AutoGeneratedDailyReportController : ControllerBase [HttpGet("all")] [ProducesResponseType(typeof(PaginationContainer), (int)HttpStatusCode.OK)] public async Task GetListAsync([FromRoute][Required] int idWell, - [FromQuery] AutoGeneratedDailyReportRequest request, + [FromQuery] FileReportRequest request, CancellationToken cancellationToken) { if (!await CanUserAccessToWellAsync(idWell, cancellationToken)) diff --git a/AsbCloudWebApi/Controllers/DrillTestController.cs b/AsbCloudWebApi/Controllers/DrillTestController.cs new file mode 100644 index 00000000..bda32d6e --- /dev/null +++ b/AsbCloudWebApi/Controllers/DrillTestController.cs @@ -0,0 +1,133 @@ +using AsbCloudApp.Data; +using AsbCloudApp.Data.DrillTestReport; +using AsbCloudApp.Data.SAUB; +using AsbCloudApp.Repositories; +using AsbCloudApp.Requests; +using AsbCloudApp.Services; +using AsbCloudWebApi.SignalR; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.SignalR; +using System; +using System.ComponentModel.DataAnnotations; +using System.Net; +using System.Threading; +using System.Threading.Tasks; + +namespace AsbCloudWebApi.Controllers; + +/// +/// Контроллер для drill_test отчётов +/// +[ApiController] +[Authorize] +public class DrillTestController : ControllerBase +{ + private readonly IDrillTestReportService drillTestReportService; + private readonly IDrillTestRepository drillTestRepository; + private readonly IWellService wellService; + private readonly ITelemetryService telemetryService; + private readonly IHubContext telemetryHubContext; + + public string SignalRMethodGetDataName { get; protected set; } = "ReceiveDrilltestData"; + + public DrillTestController( + IDrillTestReportService drillTestReportService, + IDrillTestRepository drillTestRepository, + IWellService wellService, + ITelemetryService telemetryService, + IHubContext telemetryHubContext) + { + this.drillTestReportService = drillTestReportService; + this.drillTestRepository = drillTestRepository; + this.wellService = wellService; + this.telemetryService = telemetryService; + this.telemetryHubContext = telemetryHubContext; + } + + /// + /// Метод получения данных drill_test и drill_test_params от панели оператора. + /// Сохраняет в БД. + /// + /// уникальный идентификатор записи drill_test + /// запись drill test + /// + /// + [AllowAnonymous] + [HttpPost("api/telemetry/{uid}/[controller]")] + public async Task PostDataAsync( + string uid, + [FromBody] DrillTestDto dto, + CancellationToken token) + { + var telemetry = telemetryService.GetOrCreateTelemetryByUid(uid); + if (telemetry is null) + throw new Exception($"Telemetry with RemoteUid: {uid} does not exist."); + + await drillTestRepository.SaveDataAsync(telemetry.Id, dto, token); + var idWell = telemetryService.GetIdWellByTelemetryUid(uid); + if (idWell is not null) + _ = Task.Run(async () => + { + var clients = telemetryHubContext.Clients.Group($"well_{idWell}"); + await clients.SendAsync(SignalRMethodGetDataName, dto); + }, CancellationToken.None); + + return Ok(); + } + + /// + /// Формирование отчёта + /// + /// Id скважины + /// Ключ entity test записи + /// + /// + [HttpGet("api/well/{idWell}/[controller]")] + [Permission] + [ProducesResponseType(typeof(PhysicalFileResult), (int)HttpStatusCode.OK, "application/octet-stream")] + [ProducesResponseType(StatusCodes.Status204NoContent)] + public async Task GenerateReportAsync([FromRoute] int idWell, + [FromQuery] int id, + CancellationToken cancellationToken) + { + if (!await CanUserAccessToWellAsync(idWell, cancellationToken)) + return Forbid(); + + var reportFile = await drillTestReportService.GenerateAsync(idWell, id, cancellationToken); + + return File(reportFile.stream, "application/octet-stream", reportFile.fileName); + } + + /// + /// Список файлов drill test отчётов + /// + /// Id скважины + /// Параметры запроса + /// + /// + [HttpGet("api/well/{idWell}/[controller]/all")] + [Permission] + [ProducesResponseType(typeof(PaginationContainer), (int)HttpStatusCode.OK)] + public async Task GetListAsync([FromRoute][Required] int idWell, + [FromQuery] FileReportRequest request, + CancellationToken cancellationToken) + { + if (!await CanUserAccessToWellAsync(idWell, cancellationToken)) + return Forbid(); + + var reports = await drillTestReportService.GetListAsync(idWell, + request, + cancellationToken); + + return Ok(reports); + } + + private async Task CanUserAccessToWellAsync(int idWell, CancellationToken cancellationToken) + { + int? idCompany = User.GetCompanyId(); + return idCompany is not null && await wellService.IsCompanyInvolvedInWellAsync((int)idCompany, + idWell, cancellationToken).ConfigureAwait(false); + } +} \ No newline at end of file diff --git a/AsbCloudWebApi/Controllers/SAUB/DrillTestController.cs b/AsbCloudWebApi/Controllers/SAUB/DrillTestController.cs deleted file mode 100644 index 45330d26..00000000 --- a/AsbCloudWebApi/Controllers/SAUB/DrillTestController.cs +++ /dev/null @@ -1,69 +0,0 @@ -using AsbCloudApp.Data.SAUB; -using AsbCloudApp.Repositories; -using AsbCloudApp.Services; -using AsbCloudWebApi.SignalR; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.SignalR; -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace AsbCloudWebApi.Controllers.SAUB -{ - - [Route("api/telemetry")] - [ApiController] - public class DrillTestController : ControllerBase - - { - protected readonly IWellService wellService; - private readonly ITelemetryService telemetryService; - private readonly IDrillTestRepository drillTestRepository; - private readonly IHubContext telemetryHubContext; - - public string SignalRMethodGetDataName { get; protected set; } = "ReceiveDrilltestData"; - - public DrillTestController( - ITelemetryService telemetryService, - IDrillTestRepository drillTestRepository, - IWellService wellService, - IHubContext telemetryHubContext) - { - this.telemetryService = telemetryService; - this.drillTestRepository = drillTestRepository; - this.wellService = wellService; - this.telemetryHubContext = telemetryHubContext; - } - - /// - /// Метод получения данных drill_test и drill_test_params от панели оператора. - /// Сохраняет в БД. - /// - /// уникальный идентификатор записи drill_test - /// запись drill test - /// - /// - [HttpPost("{uid}/[controller]")] - public async Task PostDataAsync( - string uid, - [FromBody] DrillTestDto dto, - CancellationToken token) - { - var telemetry = telemetryService.GetOrCreateTelemetryByUid(uid); - if (telemetry is null) - throw new Exception($"Telemetry with RemoteUid: {uid} does not exist."); - - await drillTestRepository.SaveDataAsync(telemetry.Id, dto, token); - var idWell = telemetryService.GetIdWellByTelemetryUid(uid); - if (idWell is not null) - _ = Task.Run(async () => - { - var clients = telemetryHubContext.Clients.Group($"well_{idWell}"); - await clients.SendAsync(SignalRMethodGetDataName, dto); - }, CancellationToken.None); - - return Ok(); - } - } - -} diff --git a/AsbCloudWebApi/Middlewares/SimplifyExceptionsMiddleware.cs b/AsbCloudWebApi/Middlewares/SimplifyExceptionsMiddleware.cs index 3180f41d..3c444b4a 100644 --- a/AsbCloudWebApi/Middlewares/SimplifyExceptionsMiddleware.cs +++ b/AsbCloudWebApi/Middlewares/SimplifyExceptionsMiddleware.cs @@ -56,10 +56,7 @@ namespace AsbCloudWebApi.Middlewares private static string MakeJsonBody(ArgumentInvalidException ex) { - var errors = new Dictionary { - { ex.ParamName, new[]{ ex.Message } } - }; - var problem = new ValidationProblemDetails(errors); + var problem = new ValidationProblemDetails(ex.ErrorState); var buffer = System.Text.Json.JsonSerializer.Serialize(problem); return buffer; } diff --git a/AsbCloudWebApi/Rest/DrillTest.http b/AsbCloudWebApi/Rest/DrillTest.http new file mode 100644 index 00000000..a5348ead --- /dev/null +++ b/AsbCloudWebApi/Rest/DrillTest.http @@ -0,0 +1,45 @@ +@baseUrl = http://127.0.0.1:5000 +@contentType = application/json +@contentTypeForFiles = application/octet-stream +@auth = Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiZGV2IiwiaWRDb21wYW55IjoiMSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6InJvb3QiLCJuYmYiOjE2OTc0MzcwMzEsImV4cCI6MTcyODk5NDYzMSwiaXNzIjoiYSIsImF1ZCI6ImEifQ.vB7Qb3K9gG77iP8y25zB3RcZIQk9cHkq3I1SkcooYJs + +@uid = 20210101_000000000 +@id = 1 +@idWell = 55 + +### drill test +POST {{baseUrl}}/api/telemetry/{{uid}}/DrillTest +Content-Type: {{contentType}} +accept: */* + +{ + "id": {{id}}, + "timeStampStart": "2023-10-23T08:55:36.882Z", + "depthStart": 10, + "params": [ + { + "step": 1, + "workload": 2, + "speed": 3, + "depthSpeed": 4, + "timeDrillStep": 5, + "depthDrillStep": 15 + } + ] +} + + +### drill test +GET {{baseUrl}}/api/well/{{idWell}}/DrillTest/all +Content-Type: {{contentType}} +accept: */* +Authorization: {{auth}} + +### drill test +GET {{baseUrl}}/api/well/{{idWell}}/DrillTest?id={{id}} +Content-Type: {{contentTypeForFiles}} +accept: */* +Authorization: {{auth}} + + +