diff --git a/api/Erp.Platform.sln b/api/Erp.Platform.sln
index e8dba0e3..a9b23d0d 100644
--- a/api/Erp.Platform.sln
+++ b/api/Erp.Platform.sln
@@ -92,6 +92,18 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Erp.SqlQueryManager.Applica
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Erp.SqlQueryManager.EntityFrameworkCore", "modules\Erp.SqlQueryManager\Erp.SqlQueryManager.EntityFrameworkCore\Erp.SqlQueryManager.EntityFrameworkCore.csproj", "{1DA666D8-DBFE-40F7-8EBF-95CC892E4EB6}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Erp.Reports", "Erp.Reports", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Erp.Reports.Application", "modules\Erp.Reports\Erp.Reports.Application\Erp.Reports.Application.csproj", "{3E1C9BC6-90C2-20F1-567F-2BA043D81721}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Erp.Reports.Application.Contracts", "modules\Erp.Reports\Erp.Reports.Application.Contracts\Erp.Reports.Application.Contracts.csproj", "{6E1A7691-CD09-860C-C6B3-86FDFDD3E372}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Erp.Reports.Domain", "modules\Erp.Reports\Erp.Reports.Domain\Erp.Reports.Domain.csproj", "{0924ACE7-6A32-F683-9F4D-A15B07D14A5E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Erp.Reports.Domain.Shared", "modules\Erp.Reports\Erp.Reports.Domain.Shared\Erp.Reports.Domain.Shared.csproj", "{E65E10EE-41CC-B0E2-1004-E40D0CD26011}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Erp.Reports.EntityFrameworkCore", "modules\Erp.Reports\Erp.Reports.EntityFrameworkCore\Erp.Reports.EntityFrameworkCore.csproj", "{02E91CDA-E54C-9D5C-76AB-B07BE6D3E7FF}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -230,6 +242,26 @@ Global
{1DA666D8-DBFE-40F7-8EBF-95CC892E4EB6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1DA666D8-DBFE-40F7-8EBF-95CC892E4EB6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1DA666D8-DBFE-40F7-8EBF-95CC892E4EB6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3E1C9BC6-90C2-20F1-567F-2BA043D81721}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3E1C9BC6-90C2-20F1-567F-2BA043D81721}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3E1C9BC6-90C2-20F1-567F-2BA043D81721}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3E1C9BC6-90C2-20F1-567F-2BA043D81721}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6E1A7691-CD09-860C-C6B3-86FDFDD3E372}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6E1A7691-CD09-860C-C6B3-86FDFDD3E372}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6E1A7691-CD09-860C-C6B3-86FDFDD3E372}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6E1A7691-CD09-860C-C6B3-86FDFDD3E372}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0924ACE7-6A32-F683-9F4D-A15B07D14A5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0924ACE7-6A32-F683-9F4D-A15B07D14A5E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0924ACE7-6A32-F683-9F4D-A15B07D14A5E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0924ACE7-6A32-F683-9F4D-A15B07D14A5E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E65E10EE-41CC-B0E2-1004-E40D0CD26011}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E65E10EE-41CC-B0E2-1004-E40D0CD26011}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E65E10EE-41CC-B0E2-1004-E40D0CD26011}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E65E10EE-41CC-B0E2-1004-E40D0CD26011}.Release|Any CPU.Build.0 = Release|Any CPU
+ {02E91CDA-E54C-9D5C-76AB-B07BE6D3E7FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {02E91CDA-E54C-9D5C-76AB-B07BE6D3E7FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {02E91CDA-E54C-9D5C-76AB-B07BE6D3E7FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {02E91CDA-E54C-9D5C-76AB-B07BE6D3E7FF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -274,6 +306,12 @@ Global
{B45A3E8B-286B-4A74-9602-FC192ACEE8C4} = {2889482E-64CA-4A25-91D8-5B963D83681B}
{ED9C639A-A706-4ECB-9638-A15B3681BDEC} = {2889482E-64CA-4A25-91D8-5B963D83681B}
{1DA666D8-DBFE-40F7-8EBF-95CC892E4EB6} = {2889482E-64CA-4A25-91D8-5B963D83681B}
+ {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {03E1C8DA-035E-4882-AF81-F392139FCF38}
+ {3E1C9BC6-90C2-20F1-567F-2BA043D81721} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
+ {6E1A7691-CD09-860C-C6B3-86FDFDD3E372} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
+ {0924ACE7-6A32-F683-9F4D-A15B07D14A5E} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
+ {E65E10EE-41CC-B0E2-1004-E40D0CD26011} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
+ {02E91CDA-E54C-9D5C-76AB-B07BE6D3E7FF} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {28315BFD-90E7-4E14-A2EA-F3D23AF4126F}
diff --git a/api/modules/Erp.Reports/Erp.Reports.Application.Contracts/Erp.Reports.Application.Contracts.csproj b/api/modules/Erp.Reports/Erp.Reports.Application.Contracts/Erp.Reports.Application.Contracts.csproj
new file mode 100644
index 00000000..7f8c933e
--- /dev/null
+++ b/api/modules/Erp.Reports/Erp.Reports.Application.Contracts/Erp.Reports.Application.Contracts.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net9.0
+ enable
+ enable
+ Erp.Reports
+
+
+
+
+
+
+
+
+
+
+
diff --git a/api/modules/Erp.Reports/Erp.Reports.Application.Contracts/ErpReportsApplicationContractsModule.cs b/api/modules/Erp.Reports/Erp.Reports.Application.Contracts/ErpReportsApplicationContractsModule.cs
new file mode 100644
index 00000000..ee72d765
--- /dev/null
+++ b/api/modules/Erp.Reports/Erp.Reports.Application.Contracts/ErpReportsApplicationContractsModule.cs
@@ -0,0 +1,12 @@
+using Volo.Abp.Application;
+using Volo.Abp.Modularity;
+
+namespace Erp.Reports;
+
+[DependsOn(
+ typeof(ErpReportsDomainSharedModule),
+ typeof(AbpDddApplicationContractsModule)
+)]
+public class ErpReportsApplicationContractsModule : AbpModule
+{
+}
diff --git a/api/modules/Erp.Reports/Erp.Reports.Application.Contracts/ReportDefinitions/CreateReportDefinitionDto.cs b/api/modules/Erp.Reports/Erp.Reports.Application.Contracts/ReportDefinitions/CreateReportDefinitionDto.cs
new file mode 100644
index 00000000..96bc1e89
--- /dev/null
+++ b/api/modules/Erp.Reports/Erp.Reports.Application.Contracts/ReportDefinitions/CreateReportDefinitionDto.cs
@@ -0,0 +1,17 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Erp.Reports.ReportDefinitions;
+
+public class CreateReportDefinitionDto
+{
+ [Required]
+ [StringLength(256)]
+ public string Name { get; set; }
+
+ [Required]
+ [StringLength(512)]
+ public string DisplayName { get; set; }
+
+ [Required]
+ public byte[] Content { get; set; }
+}
diff --git a/api/modules/Erp.Reports/Erp.Reports.Application.Contracts/ReportDefinitions/IReportDefinitionAppService.cs b/api/modules/Erp.Reports/Erp.Reports.Application.Contracts/ReportDefinitions/IReportDefinitionAppService.cs
new file mode 100644
index 00000000..51134e24
--- /dev/null
+++ b/api/modules/Erp.Reports/Erp.Reports.Application.Contracts/ReportDefinitions/IReportDefinitionAppService.cs
@@ -0,0 +1,13 @@
+using Volo.Abp.Application.Services;
+
+namespace Erp.Reports.ReportDefinitions;
+
+public interface IReportDefinitionAppService : IApplicationService
+{
+ Task GetAsync(Guid id);
+ Task GetByNameAsync(string name);
+ Task GetContentAsync(string name);
+ Task CreateAsync(CreateReportDefinitionDto input);
+ Task UpdateAsync(Guid id, UpdateReportDefinitionDto input);
+ Task DeleteAsync(Guid id);
+}
diff --git a/api/modules/Erp.Reports/Erp.Reports.Application.Contracts/ReportDefinitions/ReportDefinitionDto.cs b/api/modules/Erp.Reports/Erp.Reports.Application.Contracts/ReportDefinitions/ReportDefinitionDto.cs
new file mode 100644
index 00000000..6ad8a60b
--- /dev/null
+++ b/api/modules/Erp.Reports/Erp.Reports.Application.Contracts/ReportDefinitions/ReportDefinitionDto.cs
@@ -0,0 +1,9 @@
+using Volo.Abp.Application.Dtos;
+
+namespace Erp.Reports.ReportDefinitions;
+
+public class ReportDefinitionDto : FullAuditedEntityDto
+{
+ public string Name { get; set; }
+ public string DisplayName { get; set; }
+}
diff --git a/api/modules/Erp.Reports/Erp.Reports.Application.Contracts/ReportDefinitions/UpdateReportDefinitionDto.cs b/api/modules/Erp.Reports/Erp.Reports.Application.Contracts/ReportDefinitions/UpdateReportDefinitionDto.cs
new file mode 100644
index 00000000..73d71594
--- /dev/null
+++ b/api/modules/Erp.Reports/Erp.Reports.Application.Contracts/ReportDefinitions/UpdateReportDefinitionDto.cs
@@ -0,0 +1,11 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Erp.Reports.ReportDefinitions;
+
+public class UpdateReportDefinitionDto
+{
+ [StringLength(512)]
+ public string DisplayName { get; set; }
+
+ public byte[] Content { get; set; }
+}
diff --git a/api/modules/Erp.Reports/Erp.Reports.Application/Erp.Reports.Application.csproj b/api/modules/Erp.Reports/Erp.Reports.Application/Erp.Reports.Application.csproj
new file mode 100644
index 00000000..9002073a
--- /dev/null
+++ b/api/modules/Erp.Reports/Erp.Reports.Application/Erp.Reports.Application.csproj
@@ -0,0 +1,20 @@
+
+
+
+ net9.0
+ enable
+ enable
+ Erp.Reports
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/api/modules/Erp.Reports/Erp.Reports.Application/ErpReportsApplicationAutoMapperProfile.cs b/api/modules/Erp.Reports/Erp.Reports.Application/ErpReportsApplicationAutoMapperProfile.cs
new file mode 100644
index 00000000..42530c50
--- /dev/null
+++ b/api/modules/Erp.Reports/Erp.Reports.Application/ErpReportsApplicationAutoMapperProfile.cs
@@ -0,0 +1,12 @@
+using AutoMapper;
+using Erp.Reports.ReportDefinitions;
+
+namespace Erp.Reports;
+
+public class ErpReportsApplicationAutoMapperProfile : Profile
+{
+ public ErpReportsApplicationAutoMapperProfile()
+ {
+ CreateMap();
+ }
+}
diff --git a/api/modules/Erp.Reports/Erp.Reports.Application/ErpReportsApplicationModule.cs b/api/modules/Erp.Reports/Erp.Reports.Application/ErpReportsApplicationModule.cs
new file mode 100644
index 00000000..c2e49c3f
--- /dev/null
+++ b/api/modules/Erp.Reports/Erp.Reports.Application/ErpReportsApplicationModule.cs
@@ -0,0 +1,22 @@
+using Volo.Abp.Application;
+using Volo.Abp.AutoMapper;
+using Volo.Abp.Modularity;
+
+namespace Erp.Reports;
+
+[DependsOn(
+ typeof(ErpReportsDomainModule),
+ typeof(ErpReportsApplicationContractsModule),
+ typeof(AbpDddApplicationModule),
+ typeof(AbpAutoMapperModule)
+)]
+public class ErpReportsApplicationModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ Configure(options =>
+ {
+ options.AddMaps();
+ });
+ }
+}
diff --git a/api/modules/Erp.Reports/Erp.Reports.Application/ReportDefinitionAppService.cs b/api/modules/Erp.Reports/Erp.Reports.Application/ReportDefinitionAppService.cs
new file mode 100644
index 00000000..3eb4b023
--- /dev/null
+++ b/api/modules/Erp.Reports/Erp.Reports.Application/ReportDefinitionAppService.cs
@@ -0,0 +1,76 @@
+using Volo.Abp.Application.Services;
+using Volo.Abp.Domain.Repositories;
+
+namespace Erp.Reports.ReportDefinitions;
+
+public class ReportDefinitionAppService : ApplicationService, IReportDefinitionAppService
+{
+ private readonly IRepository _reportDefinitionRepository;
+
+ public ReportDefinitionAppService(IRepository reportDefinitionRepository)
+ {
+ _reportDefinitionRepository = reportDefinitionRepository;
+ }
+
+ public async Task GetAsync(Guid id)
+ {
+ var report = await _reportDefinitionRepository.GetAsync(id);
+ return ObjectMapper.Map(report);
+ }
+
+ public async Task GetByNameAsync(string name)
+ {
+ var report = await _reportDefinitionRepository.FirstOrDefaultAsync(x => x.Name == name);
+ if (report == null)
+ {
+ throw new Volo.Abp.UserFriendlyException($"Report '{name}' not found");
+ }
+ return ObjectMapper.Map(report);
+ }
+
+ public async Task GetContentAsync(string name)
+ {
+ var report = await _reportDefinitionRepository.FirstOrDefaultAsync(x => x.Name == name);
+ if (report == null)
+ {
+ throw new Volo.Abp.UserFriendlyException($"Report '{name}' not found");
+ }
+ return report.Content;
+ }
+
+ public async Task CreateAsync(CreateReportDefinitionDto input)
+ {
+ var report = new ReportDefinition(
+ GuidGenerator.Create(),
+ input.Name,
+ input.DisplayName,
+ input.Content
+ );
+
+ await _reportDefinitionRepository.InsertAsync(report);
+ return ObjectMapper.Map(report);
+ }
+
+ public async Task UpdateAsync(Guid id, UpdateReportDefinitionDto input)
+ {
+ var report = await _reportDefinitionRepository.GetAsync(id);
+
+ if (!string.IsNullOrEmpty(input.DisplayName))
+ {
+ report.DisplayName = input.DisplayName;
+ }
+
+ if (input.Content != null && input.Content.Length > 0)
+ {
+ report.UpdateContent(input.Content);
+ }
+
+ await _reportDefinitionRepository.UpdateAsync(report);
+ return ObjectMapper.Map(report);
+ }
+
+ public async Task DeleteAsync(Guid id)
+ {
+ await _reportDefinitionRepository.DeleteAsync(id);
+ }
+}
diff --git a/api/modules/Erp.Reports/Erp.Reports.Domain.Shared/Erp.Reports.Domain.Shared.csproj b/api/modules/Erp.Reports/Erp.Reports.Domain.Shared/Erp.Reports.Domain.Shared.csproj
new file mode 100644
index 00000000..da280b1c
--- /dev/null
+++ b/api/modules/Erp.Reports/Erp.Reports.Domain.Shared/Erp.Reports.Domain.Shared.csproj
@@ -0,0 +1,15 @@
+
+
+
+ net9.0
+ enable
+ enable
+ Erp.Reports
+
+
+
+
+
+
+
+
diff --git a/api/modules/Erp.Reports/Erp.Reports.Domain.Shared/ErpReportsDomainSharedModule.cs b/api/modules/Erp.Reports/Erp.Reports.Domain.Shared/ErpReportsDomainSharedModule.cs
new file mode 100644
index 00000000..bbfa9a6e
--- /dev/null
+++ b/api/modules/Erp.Reports/Erp.Reports.Domain.Shared/ErpReportsDomainSharedModule.cs
@@ -0,0 +1,15 @@
+using Volo.Abp.Modularity;
+using Volo.Abp.VirtualFileSystem;
+
+namespace Erp.Reports;
+
+public class ErpReportsDomainSharedModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ Configure(options =>
+ {
+ options.FileSets.AddEmbedded();
+ });
+ }
+}
diff --git a/api/modules/Erp.Reports/Erp.Reports.Domain.Shared/ReportsConsts.cs b/api/modules/Erp.Reports/Erp.Reports.Domain.Shared/ReportsConsts.cs
new file mode 100644
index 00000000..f1ccb381
--- /dev/null
+++ b/api/modules/Erp.Reports/Erp.Reports.Domain.Shared/ReportsConsts.cs
@@ -0,0 +1,7 @@
+namespace Erp.Reports;
+
+public static class ReportsConsts
+{
+ public const string DbTablePrefix = "Erp";
+ public const string DbSchema = null;
+}
diff --git a/api/modules/Erp.Reports/Erp.Reports.Domain/Erp.Reports.Domain.csproj b/api/modules/Erp.Reports/Erp.Reports.Domain/Erp.Reports.Domain.csproj
new file mode 100644
index 00000000..5e0b875c
--- /dev/null
+++ b/api/modules/Erp.Reports/Erp.Reports.Domain/Erp.Reports.Domain.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net9.0
+ enable
+ enable
+ Erp.Reports
+
+
+
+
+
+
+
+
+
+
+
diff --git a/api/modules/Erp.Reports/Erp.Reports.Domain/ErpReportsDbProperties.cs b/api/modules/Erp.Reports/Erp.Reports.Domain/ErpReportsDbProperties.cs
new file mode 100644
index 00000000..d6b7d72e
--- /dev/null
+++ b/api/modules/Erp.Reports/Erp.Reports.Domain/ErpReportsDbProperties.cs
@@ -0,0 +1,18 @@
+namespace Erp.Reports.Domain;
+
+public static class Prefix
+{
+ public static string MenuPrefix { get; set; } = "Plat";
+ public static string HostPrefix { get; set; } = "H";
+ public static string? DbSchema { get; set; } = null;
+
+ public const string ConnectionStringName = "Reports";
+}
+
+public static class TablePrefix
+{
+ public static string ByName(string tableName)
+ {
+ return $"{Prefix.MenuPrefix}_{Prefix.HostPrefix}_{tableName}";
+ }
+}
diff --git a/api/modules/Erp.Reports/Erp.Reports.Domain/ErpReportsDomainModule.cs b/api/modules/Erp.Reports/Erp.Reports.Domain/ErpReportsDomainModule.cs
new file mode 100644
index 00000000..0d0f349a
--- /dev/null
+++ b/api/modules/Erp.Reports/Erp.Reports.Domain/ErpReportsDomainModule.cs
@@ -0,0 +1,16 @@
+using Volo.Abp.Domain;
+using Volo.Abp.Modularity;
+
+namespace Erp.Reports;
+
+[DependsOn(
+ typeof(AbpDddDomainModule),
+ typeof(ErpReportsDomainSharedModule)
+)]
+public class ErpReportsDomainModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ // Domain services configuration can be added here
+ }
+}
diff --git a/api/modules/Erp.Reports/Erp.Reports.Domain/ReportDefinitions/ReportDefinition.cs b/api/modules/Erp.Reports/Erp.Reports.Domain/ReportDefinitions/ReportDefinition.cs
new file mode 100644
index 00000000..9378362b
--- /dev/null
+++ b/api/modules/Erp.Reports/Erp.Reports.Domain/ReportDefinitions/ReportDefinition.cs
@@ -0,0 +1,23 @@
+using Volo.Abp.Domain.Entities.Auditing;
+
+namespace Erp.Reports.ReportDefinitions;
+
+public class ReportDefinition : FullAuditedEntity
+{
+ public string Name { get; set; }
+ public string DisplayName { get; set; }
+ public byte[] Content { get; set; }
+
+ public ReportDefinition(Guid id, string name, string displayName, byte[] content)
+ : base(id)
+ {
+ Name = name;
+ DisplayName = displayName;
+ Content = content;
+ }
+
+ public void UpdateContent(byte[] content)
+ {
+ Content = content;
+ }
+}
diff --git a/api/modules/Erp.Reports/Erp.Reports.EntityFrameworkCore/Erp.Reports.EntityFrameworkCore.csproj b/api/modules/Erp.Reports/Erp.Reports.EntityFrameworkCore/Erp.Reports.EntityFrameworkCore.csproj
new file mode 100644
index 00000000..4b56e317
--- /dev/null
+++ b/api/modules/Erp.Reports/Erp.Reports.EntityFrameworkCore/Erp.Reports.EntityFrameworkCore.csproj
@@ -0,0 +1,24 @@
+
+
+
+ net9.0
+ enable
+ enable
+ Erp.Reports.EntityFrameworkCore
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+
+
+
+
+
+
diff --git a/api/modules/Erp.Reports/Erp.Reports.EntityFrameworkCore/ErpReportsDbContext.cs b/api/modules/Erp.Reports/Erp.Reports.EntityFrameworkCore/ErpReportsDbContext.cs
new file mode 100644
index 00000000..f8455934
--- /dev/null
+++ b/api/modules/Erp.Reports/Erp.Reports.EntityFrameworkCore/ErpReportsDbContext.cs
@@ -0,0 +1,25 @@
+using Microsoft.EntityFrameworkCore;
+using Volo.Abp.Data;
+using Volo.Abp.EntityFrameworkCore;
+using Erp.Reports.ReportDefinitions;
+using Erp.Reports.Domain;
+
+namespace Erp.Reports.EntityFrameworkCore;
+
+[ConnectionStringName(Prefix.ConnectionStringName)]
+public class ErpReportsDbContext : AbpDbContext
+{
+ public DbSet ReportDefinitions { get; set; }
+
+ public ErpReportsDbContext(DbContextOptions options)
+ : base(options)
+ {
+ }
+
+ protected override void OnModelCreating(ModelBuilder builder)
+ {
+ base.OnModelCreating(builder);
+
+ builder.ConfigureReports();
+ }
+}
diff --git a/api/modules/Erp.Reports/Erp.Reports.EntityFrameworkCore/ErpReportsDbContextFactory.cs b/api/modules/Erp.Reports/Erp.Reports.EntityFrameworkCore/ErpReportsDbContextFactory.cs
new file mode 100644
index 00000000..8d110fae
--- /dev/null
+++ b/api/modules/Erp.Reports/Erp.Reports.EntityFrameworkCore/ErpReportsDbContextFactory.cs
@@ -0,0 +1,27 @@
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Design;
+using Microsoft.Extensions.Configuration;
+
+namespace Erp.Reports.EntityFrameworkCore;
+
+public class ErpReportsDbContextFactory : IDesignTimeDbContextFactory
+{
+ public ErpReportsDbContext CreateDbContext(string[] args)
+ {
+ var configuration = BuildConfiguration();
+
+ var builder = new DbContextOptionsBuilder()
+ .UseSqlServer(configuration.GetConnectionString("SqlServer"));
+
+ return new ErpReportsDbContext(builder.Options);
+ }
+
+ private static IConfigurationRoot BuildConfiguration()
+ {
+ var builder = new ConfigurationBuilder()
+ .SetBasePath(Path.Combine(Directory.GetCurrentDirectory(), "../Erp.Reports.HttpApi.Host/"))
+ .AddJsonFile("appsettings.json", optional: false);
+
+ return builder.Build();
+ }
+}
diff --git a/api/modules/Erp.Reports/Erp.Reports.EntityFrameworkCore/ErpReportsDbContextModelCreatingExtensions.cs b/api/modules/Erp.Reports/Erp.Reports.EntityFrameworkCore/ErpReportsDbContextModelCreatingExtensions.cs
new file mode 100644
index 00000000..2338aeaa
--- /dev/null
+++ b/api/modules/Erp.Reports/Erp.Reports.EntityFrameworkCore/ErpReportsDbContextModelCreatingExtensions.cs
@@ -0,0 +1,28 @@
+using Microsoft.EntityFrameworkCore;
+using Volo.Abp;
+using Volo.Abp.EntityFrameworkCore.Modeling;
+using Erp.Reports.ReportDefinitions;
+using Erp.Reports.Domain;
+
+namespace Erp.Reports.EntityFrameworkCore;
+
+public static class ErpReportsDbContextModelCreatingExtensions
+{
+ public static void ConfigureReports(
+ this ModelBuilder builder)
+ {
+ Check.NotNull(builder, nameof(builder));
+
+ builder.Entity(b =>
+ {
+ b.ToTable(TablePrefix.ByName(nameof(ReportDefinition)), Prefix.DbSchema);
+ b.ConfigureByConvention();
+
+ b.Property(x => x.Name).IsRequired().HasMaxLength(256);
+ b.Property(x => x.DisplayName).IsRequired().HasMaxLength(512);
+ b.Property(x => x.Content).IsRequired();
+
+ b.HasIndex(x => x.Name);
+ });
+ }
+}
diff --git a/api/modules/Erp.Reports/Erp.Reports.EntityFrameworkCore/ErpReportsEntityFrameworkCoreModule.cs b/api/modules/Erp.Reports/Erp.Reports.EntityFrameworkCore/ErpReportsEntityFrameworkCoreModule.cs
new file mode 100644
index 00000000..6b6189ee
--- /dev/null
+++ b/api/modules/Erp.Reports/Erp.Reports.EntityFrameworkCore/ErpReportsEntityFrameworkCoreModule.cs
@@ -0,0 +1,26 @@
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.EntityFrameworkCore;
+using Volo.Abp.EntityFrameworkCore.SqlServer;
+using Volo.Abp.Modularity;
+
+namespace Erp.Reports.EntityFrameworkCore;
+
+[DependsOn(
+ typeof(ErpReportsDomainModule),
+ typeof(AbpEntityFrameworkCoreSqlServerModule)
+)]
+public class ErpReportsEntityFrameworkCoreModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ context.Services.AddAbpDbContext(options =>
+ {
+ options.AddDefaultRepositories(includeAllEntities: true);
+ });
+
+ Configure(options =>
+ {
+ options.UseSqlServer();
+ });
+ }
+}
diff --git a/api/src/Erp.Platform.Application.Contracts/Erp.Platform.Application.Contracts.csproj b/api/src/Erp.Platform.Application.Contracts/Erp.Platform.Application.Contracts.csproj
index 67f11d41..421309b8 100644
--- a/api/src/Erp.Platform.Application.Contracts/Erp.Platform.Application.Contracts.csproj
+++ b/api/src/Erp.Platform.Application.Contracts/Erp.Platform.Application.Contracts.csproj
@@ -11,6 +11,7 @@
+
diff --git a/api/src/Erp.Platform.Application.Contracts/PlatformApplicationContractsModule.cs b/api/src/Erp.Platform.Application.Contracts/PlatformApplicationContractsModule.cs
index 7700a58e..83caab29 100644
--- a/api/src/Erp.Platform.Application.Contracts/PlatformApplicationContractsModule.cs
+++ b/api/src/Erp.Platform.Application.Contracts/PlatformApplicationContractsModule.cs
@@ -1,5 +1,6 @@
using Erp.Languages;
using Erp.Notifications.Application;
+using Erp.Reports;
using Erp.Settings;
using Volo.Abp.Account;
using Volo.Abp.FeatureManagement;
@@ -21,7 +22,8 @@ namespace Erp.Platform;
typeof(AbpObjectExtendingModule),
typeof(LanguagesApplicationContractsModule),
typeof(SettingsApplicationContractsModule),
- typeof(NotificationApplicationContractsModule)
+ typeof(NotificationApplicationContractsModule),
+ typeof(ErpReportsApplicationContractsModule)
)]
public class PlatformApplicationContractsModule : AbpModule
{
diff --git a/api/src/Erp.Platform.Application/Erp.Platform.Application.csproj b/api/src/Erp.Platform.Application/Erp.Platform.Application.csproj
index c5557c5b..197aadae 100644
--- a/api/src/Erp.Platform.Application/Erp.Platform.Application.csproj
+++ b/api/src/Erp.Platform.Application/Erp.Platform.Application.csproj
@@ -15,6 +15,7 @@
+
diff --git a/api/src/Erp.Platform.Application/PlatformApplicationModule.cs b/api/src/Erp.Platform.Application/PlatformApplicationModule.cs
index 5121c36f..224c6d7d 100644
--- a/api/src/Erp.Platform.Application/PlatformApplicationModule.cs
+++ b/api/src/Erp.Platform.Application/PlatformApplicationModule.cs
@@ -1,5 +1,6 @@
using Erp.Languages;
using Erp.Notifications.Application;
+using Erp.Reports;
using Erp.Settings;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Account;
@@ -23,7 +24,8 @@ namespace Erp.Platform;
typeof(AbpFeatureManagementApplicationModule),
typeof(LanguagesApplicationModule),
typeof(SettingsApplicationModule),
- typeof(NotificationApplicationModule)
+ typeof(NotificationApplicationModule),
+ typeof(ErpReportsApplicationModule)
)]
public class PlatformApplicationModule : AbpModule
{
diff --git a/api/src/Erp.Platform.DbMigrator/Seeds/MenusData.json b/api/src/Erp.Platform.DbMigrator/Seeds/MenusData.json
index cd247dfe..75ea0af3 100644
--- a/api/src/Erp.Platform.DbMigrator/Seeds/MenusData.json
+++ b/api/src/Erp.Platform.DbMigrator/Seeds/MenusData.json
@@ -454,6 +454,13 @@
"componentPath": "@/views/coordinator/ExamInterface/PDFTestInterface",
"routeType": "protected",
"authority": ["App.Coordinator.Tests"]
+ },
+ {
+ "key": "admin.devexpressReportView",
+ "path": "/admin/reports/reportviewer",
+ "componentPath": "@/views/report/DevexpressReportViewer",
+ "routeType": "protected",
+ "authority": []
}
],
"Menus": [
diff --git a/api/src/Erp.Platform.Domain.Shared/Erp.Platform.Domain.Shared.csproj b/api/src/Erp.Platform.Domain.Shared/Erp.Platform.Domain.Shared.csproj
index 9a635bdc..b7868197 100644
--- a/api/src/Erp.Platform.Domain.Shared/Erp.Platform.Domain.Shared.csproj
+++ b/api/src/Erp.Platform.Domain.Shared/Erp.Platform.Domain.Shared.csproj
@@ -30,6 +30,7 @@
+
diff --git a/api/src/Erp.Platform.Domain.Shared/PlatformDomainSharedModule.cs b/api/src/Erp.Platform.Domain.Shared/PlatformDomainSharedModule.cs
index 01d4db7a..ca0d3cd4 100644
--- a/api/src/Erp.Platform.Domain.Shared/PlatformDomainSharedModule.cs
+++ b/api/src/Erp.Platform.Domain.Shared/PlatformDomainSharedModule.cs
@@ -1,5 +1,6 @@
using Erp.Languages;
using Erp.Notifications.Domain;
+using Erp.Reports;
using Erp.Platform.Localization;
using Erp.Settings;
using Volo.Abp.AuditLogging;
@@ -27,7 +28,8 @@ namespace Erp.Platform;
typeof(AbpTenantManagementDomainSharedModule),
typeof(LanguagesDomainSharedModule),
typeof(SettingsDomainSharedModule),
- typeof(NotificationDomainSharedModule)
+ typeof(NotificationDomainSharedModule),
+ typeof(ErpReportsDomainSharedModule)
)]
public class PlatformDomainSharedModule : AbpModule
{
diff --git a/api/src/Erp.Platform.Domain/Erp.Platform.Domain.csproj b/api/src/Erp.Platform.Domain/Erp.Platform.Domain.csproj
index c12cf031..a53f8293 100644
--- a/api/src/Erp.Platform.Domain/Erp.Platform.Domain.csproj
+++ b/api/src/Erp.Platform.Domain/Erp.Platform.Domain.csproj
@@ -13,6 +13,7 @@
+
diff --git a/api/src/Erp.Platform.Domain/PlatformDomainModule.cs b/api/src/Erp.Platform.Domain/PlatformDomainModule.cs
index 1218f1fd..68d200a7 100644
--- a/api/src/Erp.Platform.Domain/PlatformDomainModule.cs
+++ b/api/src/Erp.Platform.Domain/PlatformDomainModule.cs
@@ -17,6 +17,7 @@ using Volo.Abp.TenantManagement;
using Volo.Abp.BlobStoring;
using Volo.Abp.BlobStoring.FileSystem;
using Volo.Abp.Timing;
+using Erp.Reports;
namespace Erp.Platform;
@@ -35,6 +36,7 @@ namespace Erp.Platform;
typeof(SettingsDomainModule),
typeof(ErpMailQueueModule),
typeof(NotificationDomainModule),
+ typeof(ErpReportsDomainModule),
typeof(AbpBlobStoringModule),
typeof(AbpBlobStoringFileSystemModule)
)]
diff --git a/api/src/Erp.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs b/api/src/Erp.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs
index 32080161..68ee5350 100644
--- a/api/src/Erp.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs
+++ b/api/src/Erp.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs
@@ -27,6 +27,7 @@ using static Erp.Platform.PlatformConsts;
using static Erp.Settings.SettingsConsts;
using Erp.Platform.Enums;
using Erp.SqlQueryManager.EntityFrameworkCore;
+using Erp.Reports.EntityFrameworkCore;
namespace Erp.Platform.EntityFrameworkCore;
@@ -351,6 +352,7 @@ public class PlatformDbContext :
builder.ConfigureMailQueue();
builder.ConfigureNotification();
builder.ConfigureSqlQueryManager();
+ builder.ConfigureReports();
//Saas
builder.Entity(b =>
diff --git a/api/src/Erp.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformEntityFrameworkCoreModule.cs b/api/src/Erp.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformEntityFrameworkCoreModule.cs
index 725e2d7c..15925cd9 100644
--- a/api/src/Erp.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformEntityFrameworkCoreModule.cs
+++ b/api/src/Erp.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformEntityFrameworkCoreModule.cs
@@ -1,6 +1,7 @@
using System;
using Erp.Languages.EntityFrameworkCore;
using Erp.Notifications.EntityFrameworkCore;
+using Erp.Reports.EntityFrameworkCore;
using Erp.Settings.EntityFrameworkCore;
using Erp.SqlQueryManager.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
@@ -36,7 +37,8 @@ namespace Erp.Platform.EntityFrameworkCore;
typeof(LanguagesEntityFrameworkCoreModule),
typeof(SettingsEntityFrameworkCoreModule),
typeof(NotificationEntityFrameworkCoreModule),
- typeof(SqlQueryManagerEntityFrameworkCoreModule)
+ typeof(SqlQueryManagerEntityFrameworkCoreModule),
+ typeof(ErpReportsEntityFrameworkCoreModule)
)]
public class PlatformEntityFrameworkCoreModule : AbpModule
{
diff --git a/api/src/Erp.Platform.EntityFrameworkCore/Erp.Platform.EntityFrameworkCore.csproj b/api/src/Erp.Platform.EntityFrameworkCore/Erp.Platform.EntityFrameworkCore.csproj
index 36f011bf..7676d08f 100644
--- a/api/src/Erp.Platform.EntityFrameworkCore/Erp.Platform.EntityFrameworkCore.csproj
+++ b/api/src/Erp.Platform.EntityFrameworkCore/Erp.Platform.EntityFrameworkCore.csproj
@@ -27,6 +27,7 @@
+
diff --git a/api/src/Erp.Platform.EntityFrameworkCore/Migrations/20251214195617_Initial.Designer.cs b/api/src/Erp.Platform.EntityFrameworkCore/Migrations/20260106110136_Initial.Designer.cs
similarity index 99%
rename from api/src/Erp.Platform.EntityFrameworkCore/Migrations/20251214195617_Initial.Designer.cs
rename to api/src/Erp.Platform.EntityFrameworkCore/Migrations/20260106110136_Initial.Designer.cs
index 46f9209f..6beac0df 100644
--- a/api/src/Erp.Platform.EntityFrameworkCore/Migrations/20251214195617_Initial.Designer.cs
+++ b/api/src/Erp.Platform.EntityFrameworkCore/Migrations/20260106110136_Initial.Designer.cs
@@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
namespace Erp.Platform.Migrations
{
[DbContext(typeof(PlatformDbContext))]
- [Migration("20251214195617_Initial")]
+ [Migration("20260106110136_Initial")]
partial class Initial
{
///
@@ -17773,6 +17773,63 @@ namespace Erp.Platform.Migrations
b.ToTable("Sas_H_ForumTopic", (string)null);
});
+ modelBuilder.Entity("Erp.Reports.ReportDefinitions.ReportDefinition", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uniqueidentifier");
+
+ b.Property("Content")
+ .IsRequired()
+ .HasColumnType("varbinary(max)");
+
+ b.Property("CreationTime")
+ .HasColumnType("datetime2")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("CreatorId");
+
+ b.Property("DeleterId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("DeleterId");
+
+ b.Property("DeletionTime")
+ .HasColumnType("datetime2")
+ .HasColumnName("DeletionTime");
+
+ b.Property("DisplayName")
+ .IsRequired()
+ .HasMaxLength(512)
+ .HasColumnType("nvarchar(512)");
+
+ b.Property("IsDeleted")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bit")
+ .HasDefaultValue(false)
+ .HasColumnName("IsDeleted");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("datetime2")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("LastModifierId");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("nvarchar(256)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Name");
+
+ b.ToTable("Plat_H_ReportDefinition", (string)null);
+ });
+
modelBuilder.Entity("Erp.Settings.Entities.SettingDefinition", b =>
{
b.Property("Id")
diff --git a/api/src/Erp.Platform.EntityFrameworkCore/Migrations/20251214195617_Initial.cs b/api/src/Erp.Platform.EntityFrameworkCore/Migrations/20260106110136_Initial.cs
similarity index 99%
rename from api/src/Erp.Platform.EntityFrameworkCore/Migrations/20251214195617_Initial.cs
rename to api/src/Erp.Platform.EntityFrameworkCore/Migrations/20260106110136_Initial.cs
index 5a6e10e3..a3f2e145 100644
--- a/api/src/Erp.Platform.EntityFrameworkCore/Migrations/20251214195617_Initial.cs
+++ b/api/src/Erp.Platform.EntityFrameworkCore/Migrations/20260106110136_Initial.cs
@@ -2009,6 +2009,27 @@ namespace Erp.Platform.Migrations
table.PrimaryKey("PK_Plat_H_NotificationRule", x => x.Id);
});
+ migrationBuilder.CreateTable(
+ name: "Plat_H_ReportDefinition",
+ columns: table => new
+ {
+ Id = table.Column(type: "uniqueidentifier", nullable: false),
+ Name = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false),
+ DisplayName = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: false),
+ Content = table.Column(type: "varbinary(max)", nullable: false),
+ CreationTime = table.Column(type: "datetime2", nullable: false),
+ CreatorId = table.Column(type: "uniqueidentifier", nullable: true),
+ LastModificationTime = table.Column(type: "datetime2", nullable: true),
+ LastModifierId = table.Column(type: "uniqueidentifier", nullable: true),
+ IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false),
+ DeleterId = table.Column(type: "uniqueidentifier", nullable: true),
+ DeletionTime = table.Column(type: "datetime2", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Plat_H_ReportDefinition", x => x.Id);
+ });
+
migrationBuilder.CreateTable(
name: "Plat_H_SettingDefinition",
columns: table => new
@@ -9505,6 +9526,11 @@ namespace Erp.Platform.Migrations
table: "Plat_H_Notification",
column: "NotificationRuleId");
+ migrationBuilder.CreateIndex(
+ name: "IX_Plat_H_ReportDefinition_Name",
+ table: "Plat_H_ReportDefinition",
+ column: "Name");
+
migrationBuilder.CreateIndex(
name: "IX_Prj_T_ProjectPhase_CategoryId",
table: "Prj_T_ProjectPhase",
@@ -10675,6 +10701,9 @@ namespace Erp.Platform.Migrations
migrationBuilder.DropTable(
name: "Plat_H_Notification");
+ migrationBuilder.DropTable(
+ name: "Plat_H_ReportDefinition");
+
migrationBuilder.DropTable(
name: "Plat_H_SettingDefinition");
diff --git a/api/src/Erp.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs b/api/src/Erp.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs
index f8f86f8b..047d0422 100644
--- a/api/src/Erp.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs
+++ b/api/src/Erp.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs
@@ -17770,6 +17770,63 @@ namespace Erp.Platform.Migrations
b.ToTable("Sas_H_ForumTopic", (string)null);
});
+ modelBuilder.Entity("Erp.Reports.ReportDefinitions.ReportDefinition", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uniqueidentifier");
+
+ b.Property("Content")
+ .IsRequired()
+ .HasColumnType("varbinary(max)");
+
+ b.Property("CreationTime")
+ .HasColumnType("datetime2")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("CreatorId");
+
+ b.Property("DeleterId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("DeleterId");
+
+ b.Property("DeletionTime")
+ .HasColumnType("datetime2")
+ .HasColumnName("DeletionTime");
+
+ b.Property("DisplayName")
+ .IsRequired()
+ .HasMaxLength(512)
+ .HasColumnType("nvarchar(512)");
+
+ b.Property("IsDeleted")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bit")
+ .HasDefaultValue(false)
+ .HasColumnName("IsDeleted");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("datetime2")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uniqueidentifier")
+ .HasColumnName("LastModifierId");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("nvarchar(256)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Name");
+
+ b.ToTable("Plat_H_ReportDefinition", (string)null);
+ });
+
modelBuilder.Entity("Erp.Settings.Entities.SettingDefinition", b =>
{
b.Property("Id")
diff --git a/api/src/Erp.Platform.HttpApi.Host/Controllers/CustomWebDocumentViewerController.cs b/api/src/Erp.Platform.HttpApi.Host/Controllers/CustomWebDocumentViewerController.cs
new file mode 100644
index 00000000..08ef7e63
--- /dev/null
+++ b/api/src/Erp.Platform.HttpApi.Host/Controllers/CustomWebDocumentViewerController.cs
@@ -0,0 +1,15 @@
+using DevExpress.AspNetCore.Reporting.WebDocumentViewer;
+using DevExpress.AspNetCore.Reporting.WebDocumentViewer.Native.Services;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Erp.Platform.Controllers;
+
+[Route("DXXRDV")]
+[ApiExplorerSettings(IgnoreApi = true)]
+public class CustomWebDocumentViewerController : WebDocumentViewerController
+{
+ public CustomWebDocumentViewerController(IWebDocumentViewerMvcControllerService controllerService)
+ : base(controllerService)
+ {
+ }
+}
diff --git a/api/src/Erp.Platform.HttpApi.Host/Data/LegacyReportDbContext.cs b/api/src/Erp.Platform.HttpApi.Host/Data/LegacyReportDbContext.cs
new file mode 100644
index 00000000..6484326c
--- /dev/null
+++ b/api/src/Erp.Platform.HttpApi.Host/Data/LegacyReportDbContext.cs
@@ -0,0 +1,67 @@
+using System.Linq;
+using Microsoft.EntityFrameworkCore;
+
+namespace Erp.Reports.HttpApi.Host.Data;
+
+public class SqlDataConnectionDescription : DataConnection { }
+public class JsonDataConnectionDescription : DataConnection { }
+
+public abstract class DataConnection
+{
+ public int Id { get; set; }
+ public string Name { get; set; }
+ public string DisplayName { get; set; }
+ public string ConnectionString { get; set; }
+}
+
+public class LegacyReportDbContext : DbContext
+{
+ public DbSet JsonDataConnections { get; set; }
+ public DbSet SqlDataConnections { get; set; }
+
+ public LegacyReportDbContext(DbContextOptions options) : base(options)
+ {
+ }
+
+ public void InitializeDatabase()
+ {
+ Database.EnsureCreated();
+
+ var nwindJsonDataConnectionName = "NWindProductsJson";
+ if (!JsonDataConnections.Any(x => x.Name == nwindJsonDataConnectionName))
+ {
+ var newData = new JsonDataConnectionDescription
+ {
+ Name = nwindJsonDataConnectionName,
+ DisplayName = "Northwind Products (JSON)",
+ ConnectionString = "Uri=Data/nwind.json"
+ };
+ JsonDataConnections.Add(newData);
+ }
+
+ var nwindSqlDataConnectionName = "NWindConnectionString";
+ if (!SqlDataConnections.Any(x => x.Name == nwindSqlDataConnectionName))
+ {
+ var newData = new SqlDataConnectionDescription
+ {
+ Name = nwindSqlDataConnectionName,
+ DisplayName = "Northwind Data Connection",
+ ConnectionString = "XpoProvider=SQLite;Data Source=|DataDirectory|Data/nwind.db"
+ };
+ SqlDataConnections.Add(newData);
+ }
+
+ var reportsDataConnectionName = "ReportsDataSqlite";
+ if (!SqlDataConnections.Any(x => x.Name == reportsDataConnectionName))
+ {
+ var newData = new SqlDataConnectionDescription
+ {
+ Name = reportsDataConnectionName,
+ DisplayName = "Reports Data (Demo)",
+ ConnectionString = "XpoProvider=SQLite;Data Source=|DataDirectory|Data/reportsData.db"
+ };
+ SqlDataConnections.Add(newData);
+ }
+ SaveChanges();
+ }
+}
diff --git a/api/src/Erp.Platform.HttpApi.Host/Data/nwind.db b/api/src/Erp.Platform.HttpApi.Host/Data/nwind.db
new file mode 100644
index 00000000..ef5dea89
Binary files /dev/null and b/api/src/Erp.Platform.HttpApi.Host/Data/nwind.db differ
diff --git a/api/src/Erp.Platform.HttpApi.Host/Data/nwind.json b/api/src/Erp.Platform.HttpApi.Host/Data/nwind.json
new file mode 100644
index 00000000..49aa018c
--- /dev/null
+++ b/api/src/Erp.Platform.HttpApi.Host/Data/nwind.json
@@ -0,0 +1,1005 @@
+{
+ "Products": [
+ {
+ "ProductID": 1,
+ "ProductName": "Chai",
+ "SupplierID": 1,
+ "CategoryID": 1,
+ "QuantityPerUnit": "10 boxes x 20 bags",
+ "UnitPrice": 18,
+ "UnitsInStock": 39,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 10,
+ "Discontinued": 0,
+ "EAN13": "070684900001"
+ },
+ {
+ "ProductID": 2,
+ "ProductName": "Chang",
+ "SupplierID": 1,
+ "CategoryID": 1,
+ "QuantityPerUnit": "24 - 12 oz bottles",
+ "UnitPrice": 19,
+ "UnitsInStock": 17,
+ "UnitsOnOrder": 40,
+ "ReorderLevel": 25,
+ "Discontinued": 0,
+ "EAN13": "070684900002"
+ },
+ {
+ "ProductID": 3,
+ "ProductName": "Aniseed Syrup",
+ "SupplierID": 1,
+ "CategoryID": 2,
+ "QuantityPerUnit": "12 - 550 ml bottles",
+ "UnitPrice": 10,
+ "UnitsInStock": 13,
+ "UnitsOnOrder": 70,
+ "ReorderLevel": 25,
+ "Discontinued": 0,
+ "EAN13": "070684900003"
+ },
+ {
+ "ProductID": 4,
+ "ProductName": "Chef Anton's Cajun Seasoning",
+ "SupplierID": 2,
+ "CategoryID": 2,
+ "QuantityPerUnit": "48 - 6 oz jars",
+ "UnitPrice": 22,
+ "UnitsInStock": 53,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 0,
+ "EAN13": "070684900004"
+ },
+ {
+ "ProductID": 5,
+ "ProductName": "Chef Anton's Gumbo Mix",
+ "SupplierID": 2,
+ "CategoryID": 2,
+ "QuantityPerUnit": "36 boxes",
+ "UnitPrice": 21.35,
+ "UnitsInStock": 0,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 1,
+ "EAN13": "070684900005"
+ },
+ {
+ "ProductID": 6,
+ "ProductName": "Grandma's Boysenberry Spread",
+ "SupplierID": 3,
+ "CategoryID": 2,
+ "QuantityPerUnit": "12 - 8 oz jars",
+ "UnitPrice": 25,
+ "UnitsInStock": 120,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 25,
+ "Discontinued": 0,
+ "EAN13": "070684900006"
+ },
+ {
+ "ProductID": 7,
+ "ProductName": "Uncle Bob's Organic Dried Pears",
+ "SupplierID": 3,
+ "CategoryID": 7,
+ "QuantityPerUnit": "12 - 1 lb pkgs.",
+ "UnitPrice": 30,
+ "UnitsInStock": 15,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 10,
+ "Discontinued": 0,
+ "EAN13": "070684900007"
+ },
+ {
+ "ProductID": 8,
+ "ProductName": "Northwoods Cranberry Sauce",
+ "SupplierID": 3,
+ "CategoryID": 2,
+ "QuantityPerUnit": "12 - 12 oz jars",
+ "UnitPrice": 40,
+ "UnitsInStock": 6,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 0,
+ "EAN13": "070684900008"
+ },
+ {
+ "ProductID": 9,
+ "ProductName": "Mishi Kobe Niku",
+ "SupplierID": 4,
+ "CategoryID": 6,
+ "QuantityPerUnit": "18 - 500 g pkgs.",
+ "UnitPrice": 97,
+ "UnitsInStock": 29,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 1,
+ "EAN13": "070684900009"
+ },
+ {
+ "ProductID": 10,
+ "ProductName": "Ikura",
+ "SupplierID": 4,
+ "CategoryID": 8,
+ "QuantityPerUnit": "12 - 200 ml jars",
+ "UnitPrice": 31,
+ "UnitsInStock": 31,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 0,
+ "EAN13": "070684900010"
+ },
+ {
+ "ProductID": 11,
+ "ProductName": "Queso Cabrales",
+ "SupplierID": 5,
+ "CategoryID": 4,
+ "QuantityPerUnit": "1 kg pkg.",
+ "UnitPrice": 21,
+ "UnitsInStock": 22,
+ "UnitsOnOrder": 30,
+ "ReorderLevel": 30,
+ "Discontinued": 0,
+ "EAN13": "070684900011"
+ },
+ {
+ "ProductID": 12,
+ "ProductName": "Queso Manchego La Pastora",
+ "SupplierID": 5,
+ "CategoryID": 4,
+ "QuantityPerUnit": "10 - 500 g pkgs.",
+ "UnitPrice": 38,
+ "UnitsInStock": 86,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 0,
+ "EAN13": "070684900012"
+ },
+ {
+ "ProductID": 13,
+ "ProductName": "Konbu",
+ "SupplierID": 6,
+ "CategoryID": 8,
+ "QuantityPerUnit": "2 kg box",
+ "UnitPrice": 6,
+ "UnitsInStock": 24,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 5,
+ "Discontinued": 0,
+ "EAN13": "070684900013"
+ },
+ {
+ "ProductID": 14,
+ "ProductName": "Tofu",
+ "SupplierID": 6,
+ "CategoryID": 7,
+ "QuantityPerUnit": "40 - 100 g pkgs.",
+ "UnitPrice": 23.25,
+ "UnitsInStock": 35,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 0,
+ "EAN13": "070684900014"
+ },
+ {
+ "ProductID": 15,
+ "ProductName": "Genen Shouyu",
+ "SupplierID": 6,
+ "CategoryID": 2,
+ "QuantityPerUnit": "24 - 250 ml bottles",
+ "UnitPrice": 15.5,
+ "UnitsInStock": 39,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 5,
+ "Discontinued": 0,
+ "EAN13": "070684900015"
+ },
+ {
+ "ProductID": 16,
+ "ProductName": "Pavlova",
+ "SupplierID": 7,
+ "CategoryID": 3,
+ "QuantityPerUnit": "32 - 500 g boxes",
+ "UnitPrice": 17.45,
+ "UnitsInStock": 29,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 10,
+ "Discontinued": 0,
+ "EAN13": "070684900016"
+ },
+ {
+ "ProductID": 17,
+ "ProductName": "Alice Mutton",
+ "SupplierID": 7,
+ "CategoryID": 6,
+ "QuantityPerUnit": "20 - 1 kg tins",
+ "UnitPrice": 39,
+ "UnitsInStock": 0,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 1,
+ "EAN13": "070684900017"
+ },
+ {
+ "ProductID": 18,
+ "ProductName": "Carnarvon Tigers",
+ "SupplierID": 7,
+ "CategoryID": 8,
+ "QuantityPerUnit": "16 kg pkg.",
+ "UnitPrice": 62.5,
+ "UnitsInStock": 42,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 0,
+ "EAN13": "070684900018"
+ },
+ {
+ "ProductID": 19,
+ "ProductName": "Teatime Chocolate Biscuits",
+ "SupplierID": 8,
+ "CategoryID": 3,
+ "QuantityPerUnit": "10 boxes x 12 pieces",
+ "UnitPrice": 9.2,
+ "UnitsInStock": 25,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 5,
+ "Discontinued": 0,
+ "EAN13": "070684900019"
+ },
+ {
+ "ProductID": 20,
+ "ProductName": "Sir Rodney's Marmalade",
+ "SupplierID": 8,
+ "CategoryID": 3,
+ "QuantityPerUnit": "30 gift boxes",
+ "UnitPrice": 81,
+ "UnitsInStock": 40,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 0,
+ "EAN13": "070684900020"
+ },
+ {
+ "ProductID": 21,
+ "ProductName": "Sir Rodney's Scones",
+ "SupplierID": 8,
+ "CategoryID": 3,
+ "QuantityPerUnit": "24 pkgs. x 4 pieces",
+ "UnitPrice": 10,
+ "UnitsInStock": 3,
+ "UnitsOnOrder": 40,
+ "ReorderLevel": 5,
+ "Discontinued": 0,
+ "EAN13": "070684900021"
+ },
+ {
+ "ProductID": 22,
+ "ProductName": "Gustaf's Knäckebröd",
+ "SupplierID": 9,
+ "CategoryID": 5,
+ "QuantityPerUnit": "24 - 500 g pkgs.",
+ "UnitPrice": 21,
+ "UnitsInStock": 104,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 25,
+ "Discontinued": 0,
+ "EAN13": "070684900022"
+ },
+ {
+ "ProductID": 23,
+ "ProductName": "Tunnbröd",
+ "SupplierID": 9,
+ "CategoryID": 5,
+ "QuantityPerUnit": "12 - 250 g pkgs.",
+ "UnitPrice": 9,
+ "UnitsInStock": 61,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 25,
+ "Discontinued": 0,
+ "EAN13": "070684900023"
+ },
+ {
+ "ProductID": 24,
+ "ProductName": "Guaraná Fantástica",
+ "SupplierID": 10,
+ "CategoryID": 1,
+ "QuantityPerUnit": "12 - 355 ml cans",
+ "UnitPrice": 4.5,
+ "UnitsInStock": 20,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 1,
+ "EAN13": "070684900024"
+ },
+ {
+ "ProductID": 25,
+ "ProductName": "NuNuCa Nuß-Nougat-Creme",
+ "SupplierID": 11,
+ "CategoryID": 3,
+ "QuantityPerUnit": "20 - 450 g glasses",
+ "UnitPrice": 14,
+ "UnitsInStock": 76,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 30,
+ "Discontinued": 0,
+ "EAN13": "070684900025"
+ },
+ {
+ "ProductID": 26,
+ "ProductName": "Gumbär Gummibärchen",
+ "SupplierID": 11,
+ "CategoryID": 3,
+ "QuantityPerUnit": "100 - 250 g bags",
+ "UnitPrice": 31.23,
+ "UnitsInStock": 15,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 0,
+ "EAN13": "070684900026"
+ },
+ {
+ "ProductID": 27,
+ "ProductName": "Schoggi Schokolade",
+ "SupplierID": 11,
+ "CategoryID": 3,
+ "QuantityPerUnit": "100 - 100 g pieces",
+ "UnitPrice": 43.9,
+ "UnitsInStock": 49,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 30,
+ "Discontinued": 0,
+ "EAN13": "070684900027"
+ },
+ {
+ "ProductID": 28,
+ "ProductName": "Rössle Sauerkraut",
+ "SupplierID": 12,
+ "CategoryID": 7,
+ "QuantityPerUnit": "25 - 825 g cans",
+ "UnitPrice": 45.6,
+ "UnitsInStock": 26,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 1,
+ "EAN13": "070684900028"
+ },
+ {
+ "ProductID": 29,
+ "ProductName": "Thüringer Rostbratwurst",
+ "SupplierID": 12,
+ "CategoryID": 6,
+ "QuantityPerUnit": "50 bags x 30 sausgs.",
+ "UnitPrice": 123.79,
+ "UnitsInStock": 0,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 1,
+ "EAN13": "070684900029"
+ },
+ {
+ "ProductID": 30,
+ "ProductName": "Nord-Ost Matjeshering",
+ "SupplierID": 13,
+ "CategoryID": 8,
+ "QuantityPerUnit": "10 - 200 g glasses",
+ "UnitPrice": 25.89,
+ "UnitsInStock": 10,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 15,
+ "Discontinued": 0,
+ "EAN13": "070684900030"
+ },
+ {
+ "ProductID": 31,
+ "ProductName": "Gorgonzola Telino",
+ "SupplierID": 14,
+ "CategoryID": 4,
+ "QuantityPerUnit": "12 - 100 g pkgs",
+ "UnitPrice": 12.5,
+ "UnitsInStock": 0,
+ "UnitsOnOrder": 70,
+ "ReorderLevel": 20,
+ "Discontinued": 0,
+ "EAN13": "070684900031"
+ },
+ {
+ "ProductID": 32,
+ "ProductName": "Mascarpone Fabioli",
+ "SupplierID": 14,
+ "CategoryID": 4,
+ "QuantityPerUnit": "24 - 200 g pkgs.",
+ "UnitPrice": 32,
+ "UnitsInStock": 9,
+ "UnitsOnOrder": 40,
+ "ReorderLevel": 25,
+ "Discontinued": 0,
+ "EAN13": "070684900032"
+ },
+ {
+ "ProductID": 33,
+ "ProductName": "Geitost",
+ "SupplierID": 15,
+ "CategoryID": 4,
+ "QuantityPerUnit": "500 g",
+ "UnitPrice": 2.5,
+ "UnitsInStock": 112,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 20,
+ "Discontinued": 0,
+ "EAN13": "070684900033"
+ },
+ {
+ "ProductID": 34,
+ "ProductName": "Sasquatch Ale",
+ "SupplierID": 16,
+ "CategoryID": 1,
+ "QuantityPerUnit": "24 - 12 oz bottles",
+ "UnitPrice": 14,
+ "UnitsInStock": 111,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 15,
+ "Discontinued": 0,
+ "EAN13": "070684900034"
+ },
+ {
+ "ProductID": 35,
+ "ProductName": "Steeleye Stout",
+ "SupplierID": 16,
+ "CategoryID": 1,
+ "QuantityPerUnit": "24 - 12 oz bottles",
+ "UnitPrice": 18,
+ "UnitsInStock": 20,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 15,
+ "Discontinued": 0,
+ "EAN13": "070684900035"
+ },
+ {
+ "ProductID": 36,
+ "ProductName": "Inlagd Sill",
+ "SupplierID": 17,
+ "CategoryID": 8,
+ "QuantityPerUnit": "24 - 250 g jars",
+ "UnitPrice": 19,
+ "UnitsInStock": 112,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 20,
+ "Discontinued": 0,
+ "EAN13": "070684900036"
+ },
+ {
+ "ProductID": 37,
+ "ProductName": "Gravad lax",
+ "SupplierID": 17,
+ "CategoryID": 8,
+ "QuantityPerUnit": "12 - 500 g pkgs.",
+ "UnitPrice": 26,
+ "UnitsInStock": 11,
+ "UnitsOnOrder": 50,
+ "ReorderLevel": 25,
+ "Discontinued": 0,
+ "EAN13": "070684900037"
+ },
+ {
+ "ProductID": 38,
+ "ProductName": "Côte de Blaye",
+ "SupplierID": 18,
+ "CategoryID": 1,
+ "QuantityPerUnit": "12 - 75 cl bottles",
+ "UnitPrice": 263.5,
+ "UnitsInStock": 17,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 15,
+ "Discontinued": 0,
+ "EAN13": "070684900038"
+ },
+ {
+ "ProductID": 39,
+ "ProductName": "Chartreuse verte",
+ "SupplierID": 18,
+ "CategoryID": 1,
+ "QuantityPerUnit": "750 cc per bottle",
+ "UnitPrice": 18,
+ "UnitsInStock": 69,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 5,
+ "Discontinued": 0,
+ "EAN13": "070684900039"
+ },
+ {
+ "ProductID": 40,
+ "ProductName": "Boston Crab Meat",
+ "SupplierID": 19,
+ "CategoryID": 8,
+ "QuantityPerUnit": "24 - 4 oz tins",
+ "UnitPrice": 18.4,
+ "UnitsInStock": 123,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 30,
+ "Discontinued": 0,
+ "EAN13": "070684900040"
+ },
+ {
+ "ProductID": 41,
+ "ProductName": "Jack's New England Clam Chowder",
+ "SupplierID": 19,
+ "CategoryID": 8,
+ "QuantityPerUnit": "12 - 12 oz cans",
+ "UnitPrice": 9.65,
+ "UnitsInStock": 85,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 10,
+ "Discontinued": 0,
+ "EAN13": "070684900041"
+ },
+ {
+ "ProductID": 42,
+ "ProductName": "Singaporean Hokkien Fried Mee",
+ "SupplierID": 20,
+ "CategoryID": 5,
+ "QuantityPerUnit": "32 - 1 kg pkgs.",
+ "UnitPrice": 14,
+ "UnitsInStock": 26,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 1,
+ "EAN13": "070684900042"
+ },
+ {
+ "ProductID": 43,
+ "ProductName": "Ipoh Coffee",
+ "SupplierID": 20,
+ "CategoryID": 1,
+ "QuantityPerUnit": "16 - 500 g tins",
+ "UnitPrice": 46,
+ "UnitsInStock": 17,
+ "UnitsOnOrder": 10,
+ "ReorderLevel": 25,
+ "Discontinued": 0,
+ "EAN13": "070684900043"
+ },
+ {
+ "ProductID": 44,
+ "ProductName": "Gula Malacca",
+ "SupplierID": 20,
+ "CategoryID": 2,
+ "QuantityPerUnit": "20 - 2 kg bags",
+ "UnitPrice": 19.45,
+ "UnitsInStock": 27,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 15,
+ "Discontinued": 0,
+ "EAN13": "070684900044"
+ },
+ {
+ "ProductID": 45,
+ "ProductName": "Rogede sild",
+ "SupplierID": 21,
+ "CategoryID": 8,
+ "QuantityPerUnit": "1k pkg.",
+ "UnitPrice": 9.5,
+ "UnitsInStock": 5,
+ "UnitsOnOrder": 70,
+ "ReorderLevel": 15,
+ "Discontinued": 0,
+ "EAN13": "070684900045"
+ },
+ {
+ "ProductID": 46,
+ "ProductName": "Spegesild",
+ "SupplierID": 21,
+ "CategoryID": 8,
+ "QuantityPerUnit": "4 - 450 g glasses",
+ "UnitPrice": 12,
+ "UnitsInStock": 95,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 0,
+ "EAN13": "070684900046"
+ },
+ {
+ "ProductID": 47,
+ "ProductName": "Zaanse koeken",
+ "SupplierID": 22,
+ "CategoryID": 3,
+ "QuantityPerUnit": "10 - 4 oz boxes",
+ "UnitPrice": 9.5,
+ "UnitsInStock": 36,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 0,
+ "EAN13": "070684900047"
+ },
+ {
+ "ProductID": 48,
+ "ProductName": "Chocolade",
+ "SupplierID": 22,
+ "CategoryID": 3,
+ "QuantityPerUnit": "10 pkgs.",
+ "UnitPrice": 12.75,
+ "UnitsInStock": 15,
+ "UnitsOnOrder": 70,
+ "ReorderLevel": 25,
+ "Discontinued": 0,
+ "EAN13": "070684900048"
+ },
+ {
+ "ProductID": 49,
+ "ProductName": "Maxilaku",
+ "SupplierID": 23,
+ "CategoryID": 3,
+ "QuantityPerUnit": "24 - 50 g pkgs.",
+ "UnitPrice": 20,
+ "UnitsInStock": 10,
+ "UnitsOnOrder": 60,
+ "ReorderLevel": 15,
+ "Discontinued": 0,
+ "EAN13": "070684900049"
+ },
+ {
+ "ProductID": 50,
+ "ProductName": "Valkoinen suklaa",
+ "SupplierID": 23,
+ "CategoryID": 3,
+ "QuantityPerUnit": "12 - 100 g bars",
+ "UnitPrice": 16.25,
+ "UnitsInStock": 65,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 30,
+ "Discontinued": 0,
+ "EAN13": "070684900050"
+ },
+ {
+ "ProductID": 51,
+ "ProductName": "Manjimup Dried Apples",
+ "SupplierID": 24,
+ "CategoryID": 7,
+ "QuantityPerUnit": "50 - 300 g pkgs.",
+ "UnitPrice": 53,
+ "UnitsInStock": 20,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 10,
+ "Discontinued": 0,
+ "EAN13": "070684900051"
+ },
+ {
+ "ProductID": 52,
+ "ProductName": "Filo Mix",
+ "SupplierID": 24,
+ "CategoryID": 5,
+ "QuantityPerUnit": "16 - 2 kg boxes",
+ "UnitPrice": 7,
+ "UnitsInStock": 38,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 25,
+ "Discontinued": 0,
+ "EAN13": "070684900052"
+ },
+ {
+ "ProductID": 53,
+ "ProductName": "Perth Pasties",
+ "SupplierID": 24,
+ "CategoryID": 6,
+ "QuantityPerUnit": "48 pieces",
+ "UnitPrice": 32.8,
+ "UnitsInStock": 0,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 1,
+ "EAN13": "070684900053"
+ },
+ {
+ "ProductID": 54,
+ "ProductName": "Tourtière",
+ "SupplierID": 25,
+ "CategoryID": 6,
+ "QuantityPerUnit": "16 pies",
+ "UnitPrice": 7.45,
+ "UnitsInStock": 21,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 10,
+ "Discontinued": 0,
+ "EAN13": "070684900054"
+ },
+ {
+ "ProductID": 55,
+ "ProductName": "Pâté chinois",
+ "SupplierID": 25,
+ "CategoryID": 6,
+ "QuantityPerUnit": "24 boxes x 2 pies",
+ "UnitPrice": 24,
+ "UnitsInStock": 115,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 20,
+ "Discontinued": 0,
+ "EAN13": "070684900055"
+ },
+ {
+ "ProductID": 56,
+ "ProductName": "Gnocchi di nonna Alice",
+ "SupplierID": 26,
+ "CategoryID": 5,
+ "QuantityPerUnit": "24 - 250 g pkgs.",
+ "UnitPrice": 38,
+ "UnitsInStock": 21,
+ "UnitsOnOrder": 10,
+ "ReorderLevel": 30,
+ "Discontinued": 0,
+ "EAN13": "070684900056"
+ },
+ {
+ "ProductID": 57,
+ "ProductName": "Ravioli Angelo",
+ "SupplierID": 26,
+ "CategoryID": 5,
+ "QuantityPerUnit": "24 - 250 g pkgs.",
+ "UnitPrice": 19.5,
+ "UnitsInStock": 36,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 20,
+ "Discontinued": 0,
+ "EAN13": "070684900057"
+ },
+ {
+ "ProductID": 58,
+ "ProductName": "Escargots de Bourgogne",
+ "SupplierID": 27,
+ "CategoryID": 8,
+ "QuantityPerUnit": "24 pieces",
+ "UnitPrice": 13.25,
+ "UnitsInStock": 62,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 20,
+ "Discontinued": 0,
+ "EAN13": "070684900058"
+ },
+ {
+ "ProductID": 59,
+ "ProductName": "Raclette Courdavault",
+ "SupplierID": 28,
+ "CategoryID": 4,
+ "QuantityPerUnit": "5 kg pkg.",
+ "UnitPrice": 55,
+ "UnitsInStock": 79,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 0,
+ "EAN13": "070684900059"
+ },
+ {
+ "ProductID": 60,
+ "ProductName": "Camembert Pierrot",
+ "SupplierID": 28,
+ "CategoryID": 4,
+ "QuantityPerUnit": "15 - 300 g rounds",
+ "UnitPrice": 34,
+ "UnitsInStock": 19,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 0,
+ "EAN13": "070684900060"
+ },
+ {
+ "ProductID": 61,
+ "ProductName": "Sirop d'érable",
+ "SupplierID": 29,
+ "CategoryID": 2,
+ "QuantityPerUnit": "24 - 500 ml bottles",
+ "UnitPrice": 28.5,
+ "UnitsInStock": 113,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 25,
+ "Discontinued": 0,
+ "EAN13": "070684900061"
+ },
+ {
+ "ProductID": 62,
+ "ProductName": "Tarte au sucre",
+ "SupplierID": 29,
+ "CategoryID": 3,
+ "QuantityPerUnit": "48 pies",
+ "UnitPrice": 49.3,
+ "UnitsInStock": 17,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 0,
+ "EAN13": "070684900062"
+ },
+ {
+ "ProductID": 63,
+ "ProductName": "Vegie-spread",
+ "SupplierID": 7,
+ "CategoryID": 2,
+ "QuantityPerUnit": "15 - 625 g jars",
+ "UnitPrice": 43.9,
+ "UnitsInStock": 24,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 5,
+ "Discontinued": 0,
+ "EAN13": "070684900063"
+ },
+ {
+ "ProductID": 64,
+ "ProductName": "Wimmers gute Semmelknödel",
+ "SupplierID": 12,
+ "CategoryID": 5,
+ "QuantityPerUnit": "20 bags x 4 pieces",
+ "UnitPrice": 33.25,
+ "UnitsInStock": 22,
+ "UnitsOnOrder": 80,
+ "ReorderLevel": 30,
+ "Discontinued": 0,
+ "EAN13": "070684900064"
+ },
+ {
+ "ProductID": 65,
+ "ProductName": "Louisiana Fiery Hot Pepper Sauce",
+ "SupplierID": 2,
+ "CategoryID": 2,
+ "QuantityPerUnit": "32 - 8 oz bottles",
+ "UnitPrice": 21.05,
+ "UnitsInStock": 76,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 0,
+ "EAN13": "070684900065"
+ },
+ {
+ "ProductID": 66,
+ "ProductName": "Louisiana Hot Spiced Okra",
+ "SupplierID": 2,
+ "CategoryID": 2,
+ "QuantityPerUnit": "24 - 8 oz jars",
+ "UnitPrice": 17,
+ "UnitsInStock": 4,
+ "UnitsOnOrder": 100,
+ "ReorderLevel": 20,
+ "Discontinued": 0,
+ "EAN13": "070684900066"
+ },
+ {
+ "ProductID": 67,
+ "ProductName": "Laughing Lumberjack Lager",
+ "SupplierID": 16,
+ "CategoryID": 1,
+ "QuantityPerUnit": "24 - 12 oz bottles",
+ "UnitPrice": 14,
+ "UnitsInStock": 52,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 10,
+ "Discontinued": 0,
+ "EAN13": "070684900067"
+ },
+ {
+ "ProductID": 68,
+ "ProductName": "Scottish Longbreads",
+ "SupplierID": 8,
+ "CategoryID": 3,
+ "QuantityPerUnit": "10 boxes x 8 pieces",
+ "UnitPrice": 12.5,
+ "UnitsInStock": 6,
+ "UnitsOnOrder": 10,
+ "ReorderLevel": 15,
+ "Discontinued": 0,
+ "EAN13": "070684900068"
+ },
+ {
+ "ProductID": 69,
+ "ProductName": "Gudbrandsdalsost",
+ "SupplierID": 15,
+ "CategoryID": 4,
+ "QuantityPerUnit": "10 kg pkg.",
+ "UnitPrice": 36,
+ "UnitsInStock": 26,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 15,
+ "Discontinued": 0,
+ "EAN13": "070684900069"
+ },
+ {
+ "ProductID": 70,
+ "ProductName": "Outback Lager",
+ "SupplierID": 7,
+ "CategoryID": 1,
+ "QuantityPerUnit": "24 - 355 ml bottles",
+ "UnitPrice": 15,
+ "UnitsInStock": 15,
+ "UnitsOnOrder": 10,
+ "ReorderLevel": 30,
+ "Discontinued": 0,
+ "EAN13": "070684900070"
+ },
+ {
+ "ProductID": 71,
+ "ProductName": "Flotemysost",
+ "SupplierID": 15,
+ "CategoryID": 4,
+ "QuantityPerUnit": "10 - 500 g pkgs.",
+ "UnitPrice": 21.5,
+ "UnitsInStock": 26,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 0,
+ "EAN13": "070684900071"
+ },
+ {
+ "ProductID": 72,
+ "ProductName": "Mozzarella di Giovanni",
+ "SupplierID": 14,
+ "CategoryID": 4,
+ "QuantityPerUnit": "24 - 200 g pkgs.",
+ "UnitPrice": 34.8,
+ "UnitsInStock": 14,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 0,
+ "Discontinued": 0,
+ "EAN13": "070684900072"
+ },
+ {
+ "ProductID": 73,
+ "ProductName": "Röd Kaviar",
+ "SupplierID": 17,
+ "CategoryID": 8,
+ "QuantityPerUnit": "24 - 150 g jars",
+ "UnitPrice": 15,
+ "UnitsInStock": 101,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 5,
+ "Discontinued": 0,
+ "EAN13": "070684900073"
+ },
+ {
+ "ProductID": 74,
+ "ProductName": "Longlife Tofu",
+ "SupplierID": 4,
+ "CategoryID": 7,
+ "QuantityPerUnit": "5 kg pkg.",
+ "UnitPrice": 10,
+ "UnitsInStock": 4,
+ "UnitsOnOrder": 20,
+ "ReorderLevel": 5,
+ "Discontinued": 0,
+ "EAN13": "070684900074"
+ },
+ {
+ "ProductID": 75,
+ "ProductName": "Rhönbräu Klosterbier",
+ "SupplierID": 12,
+ "CategoryID": 1,
+ "QuantityPerUnit": "24 - 0.5 l bottles",
+ "UnitPrice": 7.75,
+ "UnitsInStock": 125,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 25,
+ "Discontinued": 0,
+ "EAN13": "070684900075"
+ },
+ {
+ "ProductID": 76,
+ "ProductName": "Lakkalikööri",
+ "SupplierID": 23,
+ "CategoryID": 1,
+ "QuantityPerUnit": "500 ml",
+ "UnitPrice": 18,
+ "UnitsInStock": 57,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 20,
+ "Discontinued": 0,
+ "EAN13": "070684900076"
+ },
+ {
+ "ProductID": 77,
+ "ProductName": "Original Frankfurter grüne Soße",
+ "SupplierID": 12,
+ "CategoryID": 2,
+ "QuantityPerUnit": "12 boxes",
+ "UnitPrice": 13,
+ "UnitsInStock": 32,
+ "UnitsOnOrder": 0,
+ "ReorderLevel": 15,
+ "Discontinued": 0,
+ "EAN13": "070684900077"
+ }
+ ]
+}
diff --git a/api/src/Erp.Platform.HttpApi.Host/Data/reportsData.db b/api/src/Erp.Platform.HttpApi.Host/Data/reportsData.db
new file mode 100644
index 00000000..7a11360f
Binary files /dev/null and b/api/src/Erp.Platform.HttpApi.Host/Data/reportsData.db differ
diff --git a/api/src/Erp.Platform.HttpApi.Host/Erp.Platform.HttpApi.Host.csproj b/api/src/Erp.Platform.HttpApi.Host/Erp.Platform.HttpApi.Host.csproj
index 4905e2ac..8fe09174 100644
--- a/api/src/Erp.Platform.HttpApi.Host/Erp.Platform.HttpApi.Host.csproj
+++ b/api/src/Erp.Platform.HttpApi.Host/Erp.Platform.HttpApi.Host.csproj
@@ -10,6 +10,8 @@
+
+
@@ -42,5 +44,20 @@
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+
+
+ XtraReport
+
+
+
diff --git a/api/src/Erp.Platform.HttpApi.Host/PlatformHttpApiHostModule.cs b/api/src/Erp.Platform.HttpApi.Host/PlatformHttpApiHostModule.cs
index 960fe1f9..3e91cb4c 100644
--- a/api/src/Erp.Platform.HttpApi.Host/PlatformHttpApiHostModule.cs
+++ b/api/src/Erp.Platform.HttpApi.Host/PlatformHttpApiHostModule.cs
@@ -9,6 +9,7 @@ using Erp.MailQueue;
using Erp.Notifications.Application;
using Erp.Platform.Classrooms;
using Erp.Platform.EntityFrameworkCore;
+using Erp.Reports;
using Erp.SqlQueryManager;
using Erp.Platform.Extensions;
using Erp.Platform.FileManagement;
@@ -55,6 +56,10 @@ using Erp.Platform.DynamicServices;
using static Erp.Platform.PlatformConsts;
using static Erp.Settings.SettingsConsts;
using Hangfire.SqlServer;
+using DevExpress.AspNetCore;
+using DevExpress.AspNetCore.Reporting;
+using DevExpress.XtraReports.Web.Extensions;
+using Erp.Platform.ReportServices;
namespace Erp.Platform;
@@ -69,7 +74,8 @@ namespace Erp.Platform;
typeof(AbpAspNetCoreSerilogModule),
typeof(AbpSwashbuckleModule),
typeof(AbpBackgroundWorkersHangfireModule),
- typeof(SqlQueryManagerApplicationModule)
+ typeof(SqlQueryManagerApplicationModule),
+ typeof(ErpReportsApplicationModule)
)]
public class PlatformHttpApiHostModule : AbpModule
{
@@ -127,6 +133,7 @@ public class PlatformHttpApiHostModule : AbpModule
ConfigureAuditing();
ConfigureDynamicServices(context);
+ ConfigureDevExpressReporting(context);
context.Services.AddSignalR();
@@ -207,6 +214,7 @@ public class PlatformHttpApiHostModule : AbpModule
options.ConventionalControllers.Create(typeof(ErpMailQueueModule).Assembly);
options.ConventionalControllers.Create(typeof(NotificationApplicationModule).Assembly);
options.ConventionalControllers.Create(typeof(SqlQueryManagerApplicationModule).Assembly);
+ options.ConventionalControllers.Create(typeof(ErpReportsApplicationModule).Assembly);
options.ChangeControllerModelApiExplorerGroupName = false;
options.ConventionalControllers.FormBodyBindingIgnoredTypes.Add(typeof(PlatformUpdateProfileDto));
options.ConventionalControllers.FormBodyBindingIgnoredTypes.Add(typeof(UploadFileDto));
@@ -386,6 +394,30 @@ public class PlatformHttpApiHostModule : AbpModule
context.Services.AddSingleton();
}
+ private void ConfigureDevExpressReporting(ServiceConfigurationContext context)
+ {
+ context.Services.AddDevExpressControls();
+ context.Services.ConfigureReportingServices(configurator =>
+ {
+ configurator.ConfigureReportDesigner(designerConfigurator =>
+ {
+ });
+ configurator.ConfigureWebDocumentViewer(viewerConfigurator =>
+ {
+ viewerConfigurator.UseCachedReportSourceBuilder();
+ });
+ });
+
+ // Register report storage extension
+ context.Services.AddScoped();
+
+ // Register custom data connection providers
+ context.Services.AddScoped();
+ context.Services.AddScoped();
+ context.Services.AddScoped();
+ context.Services.AddScoped();
+ }
+
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
diff --git a/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/ReportsFactory.cs b/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/ReportsFactory.cs
new file mode 100644
index 00000000..50779f8c
--- /dev/null
+++ b/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/ReportsFactory.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using DevExpress.XtraReports.UI;
+
+namespace Erp.Reports.PredefinedReports;
+
+public static class ReportsFactory
+{
+ public static Dictionary> Reports = new Dictionary>()
+ {
+ ["TestReport"] = () => new TestReport()
+ };
+}
diff --git a/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TestReport.Designer.cs b/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TestReport.Designer.cs
new file mode 100644
index 00000000..e9a8fad3
--- /dev/null
+++ b/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TestReport.Designer.cs
@@ -0,0 +1,559 @@
+namespace Erp.Reports.PredefinedReports
+{
+ partial class TestReport
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing) {
+ if(disposing && (components != null)) {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent() {
+ this.components = new System.ComponentModel.Container();
+ DevExpress.DataAccess.Sql.SelectQuery selectQuery1 = new DevExpress.DataAccess.Sql.SelectQuery();
+ DevExpress.DataAccess.Sql.Column column1 = new DevExpress.DataAccess.Sql.Column();
+ DevExpress.DataAccess.Sql.ColumnExpression columnExpression1 = new DevExpress.DataAccess.Sql.ColumnExpression();
+ DevExpress.DataAccess.Sql.Table table4 = new DevExpress.DataAccess.Sql.Table();
+ DevExpress.DataAccess.Sql.Column column2 = new DevExpress.DataAccess.Sql.Column();
+ DevExpress.DataAccess.Sql.ColumnExpression columnExpression2 = new DevExpress.DataAccess.Sql.ColumnExpression();
+ DevExpress.DataAccess.Sql.Column column3 = new DevExpress.DataAccess.Sql.Column();
+ DevExpress.DataAccess.Sql.ColumnExpression columnExpression3 = new DevExpress.DataAccess.Sql.ColumnExpression();
+ DevExpress.DataAccess.Sql.Column column4 = new DevExpress.DataAccess.Sql.Column();
+ DevExpress.DataAccess.Sql.ColumnExpression columnExpression4 = new DevExpress.DataAccess.Sql.ColumnExpression();
+ DevExpress.DataAccess.Sql.Column column5 = new DevExpress.DataAccess.Sql.Column();
+ DevExpress.DataAccess.Sql.ColumnExpression columnExpression5 = new DevExpress.DataAccess.Sql.ColumnExpression();
+ DevExpress.DataAccess.Sql.Column column6 = new DevExpress.DataAccess.Sql.Column();
+ DevExpress.DataAccess.Sql.ColumnExpression columnExpression6 = new DevExpress.DataAccess.Sql.ColumnExpression();
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TestReport));
+ this.TopMargin = new DevExpress.XtraReports.UI.TopMarginBand();
+ this.BottomMargin = new DevExpress.XtraReports.UI.BottomMarginBand();
+ this.pageInfo1 = new DevExpress.XtraReports.UI.XRPageInfo();
+ this.pageInfo2 = new DevExpress.XtraReports.UI.XRPageInfo();
+ this.ReportHeader = new DevExpress.XtraReports.UI.ReportHeaderBand();
+ this.label1 = new DevExpress.XtraReports.UI.XRLabel();
+ this.GroupHeader1 = new DevExpress.XtraReports.UI.GroupHeaderBand();
+ this.table1 = new DevExpress.XtraReports.UI.XRTable();
+ this.tableRow1 = new DevExpress.XtraReports.UI.XRTableRow();
+ this.tableCell1 = new DevExpress.XtraReports.UI.XRTableCell();
+ this.tableCell2 = new DevExpress.XtraReports.UI.XRTableCell();
+ this.GroupHeader2 = new DevExpress.XtraReports.UI.GroupHeaderBand();
+ this.table2 = new DevExpress.XtraReports.UI.XRTable();
+ this.tableRow2 = new DevExpress.XtraReports.UI.XRTableRow();
+ this.tableCell3 = new DevExpress.XtraReports.UI.XRTableCell();
+ this.tableCell4 = new DevExpress.XtraReports.UI.XRTableCell();
+ this.tableCell5 = new DevExpress.XtraReports.UI.XRTableCell();
+ this.tableCell6 = new DevExpress.XtraReports.UI.XRTableCell();
+ this.tableCell7 = new DevExpress.XtraReports.UI.XRTableCell();
+ this.Detail = new DevExpress.XtraReports.UI.DetailBand();
+ this.table3 = new DevExpress.XtraReports.UI.XRTable();
+ this.tableRow3 = new DevExpress.XtraReports.UI.XRTableRow();
+ this.tableCell8 = new DevExpress.XtraReports.UI.XRTableCell();
+ this.tableCell9 = new DevExpress.XtraReports.UI.XRTableCell();
+ this.tableCell10 = new DevExpress.XtraReports.UI.XRTableCell();
+ this.pictureBox1 = new DevExpress.XtraReports.UI.XRPictureBox();
+ this.tableCell11 = new DevExpress.XtraReports.UI.XRTableCell();
+ this.pictureBox2 = new DevExpress.XtraReports.UI.XRPictureBox();
+ this.tableCell12 = new DevExpress.XtraReports.UI.XRTableCell();
+ this.pictureBox3 = new DevExpress.XtraReports.UI.XRPictureBox();
+ this.GroupFooter1 = new DevExpress.XtraReports.UI.GroupFooterBand();
+ this.label2 = new DevExpress.XtraReports.UI.XRLabel();
+ this.sqlDataSource1 = new DevExpress.DataAccess.Sql.SqlDataSource(this.components);
+ this.Title = new DevExpress.XtraReports.UI.XRControlStyle();
+ this.GroupCaption1 = new DevExpress.XtraReports.UI.XRControlStyle();
+ this.GroupData1 = new DevExpress.XtraReports.UI.XRControlStyle();
+ this.DetailCaption1 = new DevExpress.XtraReports.UI.XRControlStyle();
+ this.DetailData1 = new DevExpress.XtraReports.UI.XRControlStyle();
+ this.GroupFooterBackground3 = new DevExpress.XtraReports.UI.XRControlStyle();
+ this.DetailData3_Odd = new DevExpress.XtraReports.UI.XRControlStyle();
+ this.PageInfo = new DevExpress.XtraReports.UI.XRControlStyle();
+ ((System.ComponentModel.ISupportInitialize)(this.table1)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.table2)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.table3)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this)).BeginInit();
+ //
+ // TopMargin
+ //
+ this.TopMargin.Name = "TopMargin";
+ //
+ // BottomMargin
+ //
+ this.BottomMargin.Controls.AddRange(new DevExpress.XtraReports.UI.XRControl[] {
+ this.pageInfo1,
+ this.pageInfo2});
+ this.BottomMargin.Name = "BottomMargin";
+ //
+ // pageInfo1
+ //
+ this.pageInfo1.LocationFloat = new DevExpress.Utils.PointFloat(0F, 0F);
+ this.pageInfo1.Name = "pageInfo1";
+ this.pageInfo1.PageInfo = DevExpress.XtraPrinting.PageInfo.DateTime;
+ this.pageInfo1.SizeF = new System.Drawing.SizeF(325F, 23F);
+ this.pageInfo1.StyleName = "PageInfo";
+ //
+ // pageInfo2
+ //
+ this.pageInfo2.LocationFloat = new DevExpress.Utils.PointFloat(325F, 0F);
+ this.pageInfo2.Name = "pageInfo2";
+ this.pageInfo2.SizeF = new System.Drawing.SizeF(325F, 23F);
+ this.pageInfo2.StyleName = "PageInfo";
+ this.pageInfo2.TextAlignment = DevExpress.XtraPrinting.TextAlignment.TopRight;
+ this.pageInfo2.TextFormatString = "Page {0} of {1}";
+ //
+ // ReportHeader
+ //
+ this.ReportHeader.Controls.AddRange(new DevExpress.XtraReports.UI.XRControl[] {
+ this.label1});
+ this.ReportHeader.HeightF = 60F;
+ this.ReportHeader.Name = "ReportHeader";
+ //
+ // label1
+ //
+ this.label1.LocationFloat = new DevExpress.Utils.PointFloat(0F, 0F);
+ this.label1.Name = "label1";
+ this.label1.SizeF = new System.Drawing.SizeF(650F, 24.19433F);
+ this.label1.StyleName = "Title";
+ this.label1.Text = "Report";
+ //
+ // GroupHeader1
+ //
+ this.GroupHeader1.Controls.AddRange(new DevExpress.XtraReports.UI.XRControl[] {
+ this.table1});
+ this.GroupHeader1.GroupFields.AddRange(new DevExpress.XtraReports.UI.GroupField[] {
+ new DevExpress.XtraReports.UI.GroupField("CategoryID", DevExpress.XtraReports.UI.XRColumnSortOrder.Ascending)});
+ this.GroupHeader1.GroupUnion = DevExpress.XtraReports.UI.GroupUnion.WithFirstDetail;
+ this.GroupHeader1.HeightF = 27F;
+ this.GroupHeader1.Level = 1;
+ this.GroupHeader1.Name = "GroupHeader1";
+ //
+ // table1
+ //
+ this.table1.LocationFloat = new DevExpress.Utils.PointFloat(0F, 2F);
+ this.table1.Name = "table1";
+ this.table1.Rows.AddRange(new DevExpress.XtraReports.UI.XRTableRow[] {
+ this.tableRow1});
+ this.table1.SizeF = new System.Drawing.SizeF(650F, 25F);
+ //
+ // tableRow1
+ //
+ this.tableRow1.Cells.AddRange(new DevExpress.XtraReports.UI.XRTableCell[] {
+ this.tableCell1,
+ this.tableCell2});
+ this.tableRow1.Name = "tableRow1";
+ this.tableRow1.Weight = 1D;
+ //
+ // tableCell1
+ //
+ this.tableCell1.Name = "tableCell1";
+ this.tableCell1.StyleName = "GroupCaption1";
+ this.tableCell1.Text = "CATEGORY ID";
+ this.tableCell1.Weight = 1434852.375D;
+ //
+ // tableCell2
+ //
+ this.tableCell2.ExpressionBindings.AddRange(new DevExpress.XtraReports.UI.ExpressionBinding[] {
+ new DevExpress.XtraReports.UI.ExpressionBinding("BeforePrint", "Text", "[CategoryID]")});
+ this.tableCell2.Name = "tableCell2";
+ this.tableCell2.StyleName = "GroupData1";
+ this.tableCell2.Weight = 9214747D;
+ //
+ // GroupHeader2
+ //
+ this.GroupHeader2.Controls.AddRange(new DevExpress.XtraReports.UI.XRControl[] {
+ this.table2});
+ this.GroupHeader2.GroupUnion = DevExpress.XtraReports.UI.GroupUnion.WithFirstDetail;
+ this.GroupHeader2.HeightF = 28F;
+ this.GroupHeader2.Level = 2;
+ this.GroupHeader2.Name = "GroupHeader2";
+ //
+ // table2
+ //
+ this.table2.LocationFloat = new DevExpress.Utils.PointFloat(0F, 0F);
+ this.table2.Name = "table2";
+ this.table2.Rows.AddRange(new DevExpress.XtraReports.UI.XRTableRow[] {
+ this.tableRow2});
+ this.table2.SizeF = new System.Drawing.SizeF(650F, 28F);
+ //
+ // tableRow2
+ //
+ this.tableRow2.Cells.AddRange(new DevExpress.XtraReports.UI.XRTableCell[] {
+ this.tableCell3,
+ this.tableCell4,
+ this.tableCell5,
+ this.tableCell6,
+ this.tableCell7});
+ this.tableRow2.Name = "tableRow2";
+ this.tableRow2.Weight = 1D;
+ //
+ // tableCell3
+ //
+ this.tableCell3.Borders = DevExpress.XtraPrinting.BorderSide.None;
+ this.tableCell3.Name = "tableCell3";
+ this.tableCell3.StyleName = "DetailCaption1";
+ this.tableCell3.StylePriority.UseBorders = false;
+ this.tableCell3.Text = "Category Name";
+ this.tableCell3.Weight = 0.29834482046274041D;
+ //
+ // tableCell4
+ //
+ this.tableCell4.Name = "tableCell4";
+ this.tableCell4.StyleName = "DetailCaption1";
+ this.tableCell4.Text = "Description";
+ this.tableCell4.Weight = 0.2344280066856971D;
+ //
+ // tableCell5
+ //
+ this.tableCell5.Name = "tableCell5";
+ this.tableCell5.StyleName = "DetailCaption1";
+ this.tableCell5.Text = "Picture";
+ this.tableCell5.Weight = 0.1609015596829928D;
+ //
+ // tableCell6
+ //
+ this.tableCell6.Name = "tableCell6";
+ this.tableCell6.StyleName = "DetailCaption1";
+ this.tableCell6.Text = "Icon17";
+ this.tableCell6.Weight = 0.153162841796875D;
+ //
+ // tableCell7
+ //
+ this.tableCell7.Name = "tableCell7";
+ this.tableCell7.StyleName = "DetailCaption1";
+ this.tableCell7.Text = "Icon25";
+ this.tableCell7.Weight = 0.15316274789663462D;
+ //
+ // Detail
+ //
+ this.Detail.Controls.AddRange(new DevExpress.XtraReports.UI.XRControl[] {
+ this.table3});
+ this.Detail.HeightF = 25F;
+ this.Detail.Name = "Detail";
+ //
+ // table3
+ //
+ this.table3.LocationFloat = new DevExpress.Utils.PointFloat(0F, 0F);
+ this.table3.Name = "table3";
+ this.table3.OddStyleName = "DetailData3_Odd";
+ this.table3.Rows.AddRange(new DevExpress.XtraReports.UI.XRTableRow[] {
+ this.tableRow3});
+ this.table3.SizeF = new System.Drawing.SizeF(650F, 25F);
+ //
+ // tableRow3
+ //
+ this.tableRow3.Cells.AddRange(new DevExpress.XtraReports.UI.XRTableCell[] {
+ this.tableCell8,
+ this.tableCell9,
+ this.tableCell10,
+ this.tableCell11,
+ this.tableCell12});
+ this.tableRow3.Name = "tableRow3";
+ this.tableRow3.Weight = 11.5D;
+ //
+ // tableCell8
+ //
+ this.tableCell8.Borders = DevExpress.XtraPrinting.BorderSide.None;
+ this.tableCell8.ExpressionBindings.AddRange(new DevExpress.XtraReports.UI.ExpressionBinding[] {
+ new DevExpress.XtraReports.UI.ExpressionBinding("BeforePrint", "Text", "[CategoryName]")});
+ this.tableCell8.Name = "tableCell8";
+ this.tableCell8.StyleName = "DetailData1";
+ this.tableCell8.StylePriority.UseBorders = false;
+ this.tableCell8.Weight = 0.29834482046274041D;
+ //
+ // tableCell9
+ //
+ this.tableCell9.ExpressionBindings.AddRange(new DevExpress.XtraReports.UI.ExpressionBinding[] {
+ new DevExpress.XtraReports.UI.ExpressionBinding("BeforePrint", "Text", "[Description]")});
+ this.tableCell9.Name = "tableCell9";
+ this.tableCell9.StyleName = "DetailData1";
+ this.tableCell9.Weight = 0.2344280066856971D;
+ //
+ // tableCell10
+ //
+ this.tableCell10.Controls.AddRange(new DevExpress.XtraReports.UI.XRControl[] {
+ this.pictureBox1});
+ this.tableCell10.Name = "tableCell10";
+ this.tableCell10.StyleName = "DetailData1";
+ this.tableCell10.Weight = 0.1609015596829928D;
+ //
+ // pictureBox1
+ //
+ this.pictureBox1.AnchorHorizontal = ((DevExpress.XtraReports.UI.HorizontalAnchorStyles)((DevExpress.XtraReports.UI.HorizontalAnchorStyles.Left | DevExpress.XtraReports.UI.HorizontalAnchorStyles.Right)));
+ this.pictureBox1.AnchorVertical = ((DevExpress.XtraReports.UI.VerticalAnchorStyles)((DevExpress.XtraReports.UI.VerticalAnchorStyles.Top | DevExpress.XtraReports.UI.VerticalAnchorStyles.Bottom)));
+ this.pictureBox1.ExpressionBindings.AddRange(new DevExpress.XtraReports.UI.ExpressionBinding[] {
+ new DevExpress.XtraReports.UI.ExpressionBinding("BeforePrint", "ImageSource", "[Picture]")});
+ this.pictureBox1.LocationFloat = new DevExpress.Utils.PointFloat(2.083333F, 0F);
+ this.pictureBox1.Name = "pictureBox1";
+ this.pictureBox1.SizeF = new System.Drawing.SizeF(102.5027F, 25F);
+ this.pictureBox1.Sizing = DevExpress.XtraPrinting.ImageSizeMode.ZoomImage;
+ //
+ // tableCell11
+ //
+ this.tableCell11.Controls.AddRange(new DevExpress.XtraReports.UI.XRControl[] {
+ this.pictureBox2});
+ this.tableCell11.Name = "tableCell11";
+ this.tableCell11.StyleName = "DetailData1";
+ this.tableCell11.Weight = 0.153162841796875D;
+ //
+ // pictureBox2
+ //
+ this.pictureBox2.AnchorHorizontal = ((DevExpress.XtraReports.UI.HorizontalAnchorStyles)((DevExpress.XtraReports.UI.HorizontalAnchorStyles.Left | DevExpress.XtraReports.UI.HorizontalAnchorStyles.Right)));
+ this.pictureBox2.AnchorVertical = ((DevExpress.XtraReports.UI.VerticalAnchorStyles)((DevExpress.XtraReports.UI.VerticalAnchorStyles.Top | DevExpress.XtraReports.UI.VerticalAnchorStyles.Bottom)));
+ this.pictureBox2.ExpressionBindings.AddRange(new DevExpress.XtraReports.UI.ExpressionBinding[] {
+ new DevExpress.XtraReports.UI.ExpressionBinding("BeforePrint", "ImageSource", "[Icon17]")});
+ this.pictureBox2.LocationFloat = new DevExpress.Utils.PointFloat(2.083333F, 0F);
+ this.pictureBox2.Name = "pictureBox2";
+ this.pictureBox2.SizeF = new System.Drawing.SizeF(97.47251F, 25F);
+ this.pictureBox2.Sizing = DevExpress.XtraPrinting.ImageSizeMode.ZoomImage;
+ //
+ // tableCell12
+ //
+ this.tableCell12.Controls.AddRange(new DevExpress.XtraReports.UI.XRControl[] {
+ this.pictureBox3});
+ this.tableCell12.Name = "tableCell12";
+ this.tableCell12.StyleName = "DetailData1";
+ this.tableCell12.Weight = 0.15316274789663462D;
+ //
+ // pictureBox3
+ //
+ this.pictureBox3.AnchorHorizontal = ((DevExpress.XtraReports.UI.HorizontalAnchorStyles)((DevExpress.XtraReports.UI.HorizontalAnchorStyles.Left | DevExpress.XtraReports.UI.HorizontalAnchorStyles.Right)));
+ this.pictureBox3.AnchorVertical = ((DevExpress.XtraReports.UI.VerticalAnchorStyles)((DevExpress.XtraReports.UI.VerticalAnchorStyles.Top | DevExpress.XtraReports.UI.VerticalAnchorStyles.Bottom)));
+ this.pictureBox3.ExpressionBindings.AddRange(new DevExpress.XtraReports.UI.ExpressionBinding[] {
+ new DevExpress.XtraReports.UI.ExpressionBinding("BeforePrint", "ImageSource", "[Icon25]")});
+ this.pictureBox3.LocationFloat = new DevExpress.Utils.PointFloat(2.083333F, 0F);
+ this.pictureBox3.Name = "pictureBox3";
+ this.pictureBox3.SizeF = new System.Drawing.SizeF(97.47245F, 25F);
+ this.pictureBox3.Sizing = DevExpress.XtraPrinting.ImageSizeMode.ZoomImage;
+ //
+ // GroupFooter1
+ //
+ this.GroupFooter1.Controls.AddRange(new DevExpress.XtraReports.UI.XRControl[] {
+ this.label2});
+ this.GroupFooter1.GroupUnion = DevExpress.XtraReports.UI.GroupFooterUnion.WithLastDetail;
+ this.GroupFooter1.HeightF = 6F;
+ this.GroupFooter1.Name = "GroupFooter1";
+ //
+ // label2
+ //
+ this.label2.Borders = DevExpress.XtraPrinting.BorderSide.None;
+ this.label2.LocationFloat = new DevExpress.Utils.PointFloat(0F, 0F);
+ this.label2.Name = "label2";
+ this.label2.SizeF = new System.Drawing.SizeF(650F, 2.08F);
+ this.label2.StyleName = "GroupFooterBackground3";
+ this.label2.StylePriority.UseBorders = false;
+ //
+ // sqlDataSource1
+ //
+ this.sqlDataSource1.ConnectionName = "NWindConnectionString";
+ this.sqlDataSource1.Name = "sqlDataSource1";
+ columnExpression1.ColumnName = "CategoryID";
+ table4.Name = "Categories";
+ columnExpression1.Table = table4;
+ column1.Expression = columnExpression1;
+ columnExpression2.ColumnName = "CategoryName";
+ columnExpression2.Table = table4;
+ column2.Expression = columnExpression2;
+ columnExpression3.ColumnName = "Description";
+ columnExpression3.Table = table4;
+ column3.Expression = columnExpression3;
+ columnExpression4.ColumnName = "Picture";
+ columnExpression4.Table = table4;
+ column4.Expression = columnExpression4;
+ columnExpression5.ColumnName = "Icon17";
+ columnExpression5.Table = table4;
+ column5.Expression = columnExpression5;
+ columnExpression6.ColumnName = "Icon25";
+ columnExpression6.Table = table4;
+ column6.Expression = columnExpression6;
+ selectQuery1.Columns.Add(column1);
+ selectQuery1.Columns.Add(column2);
+ selectQuery1.Columns.Add(column3);
+ selectQuery1.Columns.Add(column4);
+ selectQuery1.Columns.Add(column5);
+ selectQuery1.Columns.Add(column6);
+ selectQuery1.Name = "Categories";
+ selectQuery1.Tables.Add(table4);
+ this.sqlDataSource1.Queries.AddRange(new DevExpress.DataAccess.Sql.SqlQuery[] {
+ selectQuery1});
+ this.sqlDataSource1.ResultSchemaSerializable = resources.GetString("sqlDataSource1.ResultSchemaSerializable");
+ //
+ // Title
+ //
+ this.Title.BackColor = System.Drawing.Color.Transparent;
+ this.Title.BorderColor = System.Drawing.Color.Black;
+ this.Title.Borders = DevExpress.XtraPrinting.BorderSide.None;
+ this.Title.BorderWidth = 1F;
+ this.Title.Font = new DevExpress.Drawing.DXFont("Arial", 14.25F);
+ this.Title.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(70)))), ((int)(((byte)(80)))));
+ this.Title.Name = "Title";
+ this.Title.Padding = new DevExpress.XtraPrinting.PaddingInfo(6, 6, 0, 0, 100F);
+ //
+ // GroupCaption1
+ //
+ this.GroupCaption1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(181)))), ((int)(((byte)(211)))), ((int)(((byte)(142)))));
+ this.GroupCaption1.BorderColor = System.Drawing.Color.White;
+ this.GroupCaption1.Borders = DevExpress.XtraPrinting.BorderSide.Bottom;
+ this.GroupCaption1.BorderWidth = 2F;
+ this.GroupCaption1.Font = new DevExpress.Drawing.DXFont("Arial", 8.25F, DevExpress.Drawing.DXFontStyle.Bold);
+ this.GroupCaption1.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(228)))), ((int)(((byte)(228)))), ((int)(((byte)(228)))));
+ this.GroupCaption1.Name = "GroupCaption1";
+ this.GroupCaption1.Padding = new DevExpress.XtraPrinting.PaddingInfo(6, 2, 0, 0, 100F);
+ this.GroupCaption1.TextAlignment = DevExpress.XtraPrinting.TextAlignment.MiddleLeft;
+ //
+ // GroupData1
+ //
+ this.GroupData1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(181)))), ((int)(((byte)(211)))), ((int)(((byte)(142)))));
+ this.GroupData1.BorderColor = System.Drawing.Color.White;
+ this.GroupData1.Borders = DevExpress.XtraPrinting.BorderSide.Bottom;
+ this.GroupData1.BorderWidth = 2F;
+ this.GroupData1.Font = new DevExpress.Drawing.DXFont("Arial", 8.25F, DevExpress.Drawing.DXFontStyle.Bold);
+ this.GroupData1.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(70)))), ((int)(((byte)(80)))));
+ this.GroupData1.Name = "GroupData1";
+ this.GroupData1.Padding = new DevExpress.XtraPrinting.PaddingInfo(6, 2, 0, 0, 100F);
+ this.GroupData1.TextAlignment = DevExpress.XtraPrinting.TextAlignment.MiddleLeft;
+ //
+ // DetailCaption1
+ //
+ this.DetailCaption1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(181)))), ((int)(((byte)(211)))), ((int)(((byte)(142)))));
+ this.DetailCaption1.BorderColor = System.Drawing.Color.White;
+ this.DetailCaption1.Borders = DevExpress.XtraPrinting.BorderSide.Left;
+ this.DetailCaption1.BorderWidth = 2F;
+ this.DetailCaption1.Font = new DevExpress.Drawing.DXFont("Arial", 8.25F, DevExpress.Drawing.DXFontStyle.Bold);
+ this.DetailCaption1.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(70)))), ((int)(((byte)(80)))));
+ this.DetailCaption1.Name = "DetailCaption1";
+ this.DetailCaption1.Padding = new DevExpress.XtraPrinting.PaddingInfo(6, 6, 0, 0, 100F);
+ this.DetailCaption1.TextAlignment = DevExpress.XtraPrinting.TextAlignment.MiddleLeft;
+ //
+ // DetailData1
+ //
+ this.DetailData1.BorderColor = System.Drawing.Color.Transparent;
+ this.DetailData1.Borders = DevExpress.XtraPrinting.BorderSide.Left;
+ this.DetailData1.BorderWidth = 2F;
+ this.DetailData1.Font = new DevExpress.Drawing.DXFont("Arial", 8.25F);
+ this.DetailData1.ForeColor = System.Drawing.Color.Black;
+ this.DetailData1.Name = "DetailData1";
+ this.DetailData1.Padding = new DevExpress.XtraPrinting.PaddingInfo(6, 6, 0, 0, 100F);
+ this.DetailData1.TextAlignment = DevExpress.XtraPrinting.TextAlignment.MiddleLeft;
+ //
+ // GroupFooterBackground3
+ //
+ this.GroupFooterBackground3.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(109)))), ((int)(((byte)(117)))), ((int)(((byte)(129)))));
+ this.GroupFooterBackground3.BorderColor = System.Drawing.Color.White;
+ this.GroupFooterBackground3.Borders = DevExpress.XtraPrinting.BorderSide.Bottom;
+ this.GroupFooterBackground3.BorderWidth = 2F;
+ this.GroupFooterBackground3.Font = new DevExpress.Drawing.DXFont("Arial", 8.25F, DevExpress.Drawing.DXFontStyle.Bold);
+ this.GroupFooterBackground3.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(228)))), ((int)(((byte)(228)))), ((int)(((byte)(228)))));
+ this.GroupFooterBackground3.Name = "GroupFooterBackground3";
+ this.GroupFooterBackground3.Padding = new DevExpress.XtraPrinting.PaddingInfo(6, 2, 0, 0, 100F);
+ this.GroupFooterBackground3.TextAlignment = DevExpress.XtraPrinting.TextAlignment.MiddleLeft;
+ //
+ // DetailData3_Odd
+ //
+ this.DetailData3_Odd.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(243)))), ((int)(((byte)(245)))), ((int)(((byte)(248)))));
+ this.DetailData3_Odd.BorderColor = System.Drawing.Color.Transparent;
+ this.DetailData3_Odd.Borders = DevExpress.XtraPrinting.BorderSide.None;
+ this.DetailData3_Odd.BorderWidth = 1F;
+ this.DetailData3_Odd.Font = new DevExpress.Drawing.DXFont("Arial", 8.25F);
+ this.DetailData3_Odd.ForeColor = System.Drawing.Color.Black;
+ this.DetailData3_Odd.Name = "DetailData3_Odd";
+ this.DetailData3_Odd.Padding = new DevExpress.XtraPrinting.PaddingInfo(6, 6, 0, 0, 100F);
+ this.DetailData3_Odd.TextAlignment = DevExpress.XtraPrinting.TextAlignment.MiddleLeft;
+ //
+ // PageInfo
+ //
+ this.PageInfo.Font = new DevExpress.Drawing.DXFont("Arial", 8.25F, DevExpress.Drawing.DXFontStyle.Bold);
+ this.PageInfo.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(70)))), ((int)(((byte)(80)))));
+ this.PageInfo.Name = "PageInfo";
+ this.PageInfo.Padding = new DevExpress.XtraPrinting.PaddingInfo(6, 6, 0, 0, 100F);
+ //
+ // TestReport
+ //
+ this.Bands.AddRange(new DevExpress.XtraReports.UI.Band[] {
+ this.TopMargin,
+ this.BottomMargin,
+ this.ReportHeader,
+ this.GroupHeader1,
+ this.GroupHeader2,
+ this.Detail,
+ this.GroupFooter1});
+ this.ComponentStorage.AddRange(new System.ComponentModel.IComponent[] {
+ this.sqlDataSource1});
+ this.DataMember = "Categories";
+ this.DataSource = this.sqlDataSource1;
+ this.Font = new DevExpress.Drawing.DXFont("Arial", 9.75F);
+ this.StyleSheet.AddRange(new DevExpress.XtraReports.UI.XRControlStyle[] {
+ this.Title,
+ this.GroupCaption1,
+ this.GroupData1,
+ this.DetailCaption1,
+ this.DetailData1,
+ this.GroupFooterBackground3,
+ this.DetailData3_Odd,
+ this.PageInfo});
+ this.Version = "22.2";
+ ((System.ComponentModel.ISupportInitialize)(this.table1)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.table2)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.table3)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this)).EndInit();
+
+ }
+
+ #endregion
+
+ private DevExpress.XtraReports.UI.TopMarginBand TopMargin;
+ private DevExpress.XtraReports.UI.BottomMarginBand BottomMargin;
+ private DevExpress.XtraReports.UI.XRPageInfo pageInfo1;
+ private DevExpress.XtraReports.UI.XRPageInfo pageInfo2;
+ private DevExpress.XtraReports.UI.ReportHeaderBand ReportHeader;
+ private DevExpress.XtraReports.UI.XRLabel label1;
+ private DevExpress.XtraReports.UI.GroupHeaderBand GroupHeader1;
+ private DevExpress.XtraReports.UI.XRTable table1;
+ private DevExpress.XtraReports.UI.XRTableRow tableRow1;
+ private DevExpress.XtraReports.UI.XRTableCell tableCell1;
+ private DevExpress.XtraReports.UI.XRTableCell tableCell2;
+ private DevExpress.XtraReports.UI.GroupHeaderBand GroupHeader2;
+ private DevExpress.XtraReports.UI.XRTable table2;
+ private DevExpress.XtraReports.UI.XRTableRow tableRow2;
+ private DevExpress.XtraReports.UI.XRTableCell tableCell3;
+ private DevExpress.XtraReports.UI.XRTableCell tableCell4;
+ private DevExpress.XtraReports.UI.XRTableCell tableCell5;
+ private DevExpress.XtraReports.UI.XRTableCell tableCell6;
+ private DevExpress.XtraReports.UI.XRTableCell tableCell7;
+ private DevExpress.XtraReports.UI.DetailBand Detail;
+ private DevExpress.XtraReports.UI.XRTable table3;
+ private DevExpress.XtraReports.UI.XRTableRow tableRow3;
+ private DevExpress.XtraReports.UI.XRTableCell tableCell8;
+ private DevExpress.XtraReports.UI.XRTableCell tableCell9;
+ private DevExpress.XtraReports.UI.XRTableCell tableCell10;
+ private DevExpress.XtraReports.UI.XRPictureBox pictureBox1;
+ private DevExpress.XtraReports.UI.XRTableCell tableCell11;
+ private DevExpress.XtraReports.UI.XRPictureBox pictureBox2;
+ private DevExpress.XtraReports.UI.XRTableCell tableCell12;
+ private DevExpress.XtraReports.UI.XRPictureBox pictureBox3;
+ private DevExpress.XtraReports.UI.GroupFooterBand GroupFooter1;
+ private DevExpress.XtraReports.UI.XRLabel label2;
+ private DevExpress.DataAccess.Sql.SqlDataSource sqlDataSource1;
+ private DevExpress.XtraReports.UI.XRControlStyle Title;
+ private DevExpress.XtraReports.UI.XRControlStyle GroupCaption1;
+ private DevExpress.XtraReports.UI.XRControlStyle GroupData1;
+ private DevExpress.XtraReports.UI.XRControlStyle DetailCaption1;
+ private DevExpress.XtraReports.UI.XRControlStyle DetailData1;
+ private DevExpress.XtraReports.UI.XRControlStyle GroupFooterBackground3;
+ private DevExpress.XtraReports.UI.XRControlStyle DetailData3_Odd;
+ private DevExpress.XtraReports.UI.XRControlStyle PageInfo;
+ }
+}
diff --git a/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TestReport.cs b/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TestReport.cs
new file mode 100644
index 00000000..6278b7f7
--- /dev/null
+++ b/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TestReport.cs
@@ -0,0 +1,9 @@
+namespace Erp.Reports.PredefinedReports;
+
+public partial class TestReport : DevExpress.XtraReports.UI.XtraReport
+{
+ public TestReport()
+ {
+ InitializeComponent();
+ }
+}
diff --git a/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TestReport.resx b/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TestReport.resx
new file mode 100644
index 00000000..e36faffa
--- /dev/null
+++ b/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TestReport.resx
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ PERhdGFTZXQgTmFtZT0ic3FsRGF0YVNvdXJjZTEiPjxWaWV3IE5hbWU9IkNhdGVnb3JpZXMiPjxGaWVsZCBOYW1lPSJDYXRlZ29yeUlEIiBUeXBlPSJJbnQ2NCIgLz48RmllbGQgTmFtZT0iQ2F0ZWdvcnlOYW1lIiBUeXBlPSJTdHJpbmciIC8+PEZpZWxkIE5hbWU9IkRlc2NyaXB0aW9uIiBUeXBlPSJTdHJpbmciIC8+PEZpZWxkIE5hbWU9IlBpY3R1cmUiIFR5cGU9IkJ5dGVBcnJheSIgLz48RmllbGQgTmFtZT0iSWNvbjE3IiBUeXBlPSJCeXRlQXJyYXkiIC8+PEZpZWxkIE5hbWU9Ikljb24yNSIgVHlwZT0iQnl0ZUFycmF5IiAvPjwvVmlldz48L0RhdGFTZXQ+
+
+
\ No newline at end of file
diff --git a/api/src/Erp.Platform.HttpApi.Host/ReportServices/CustomDataSourceWizardJsonDataConnectionStorage.cs b/api/src/Erp.Platform.HttpApi.Host/ReportServices/CustomDataSourceWizardJsonDataConnectionStorage.cs
new file mode 100644
index 00000000..85223fe3
--- /dev/null
+++ b/api/src/Erp.Platform.HttpApi.Host/ReportServices/CustomDataSourceWizardJsonDataConnectionStorage.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using DevExpress.DataAccess.Json;
+using DevExpress.DataAccess.Web;
+using DevExpress.DataAccess.Wizard.Services;
+using Erp.Reports.HttpApi.Host.Data;
+
+namespace Erp.Platform.ReportServices;
+
+public class CustomDataSourceWizardJsonDataConnectionStorage : IDataSourceWizardJsonConnectionStorage
+{
+ protected LegacyReportDbContext DbContext { get; }
+
+ public CustomDataSourceWizardJsonDataConnectionStorage(LegacyReportDbContext dbContext)
+ {
+ DbContext = dbContext;
+ }
+
+ public List GetConnections()
+ {
+ return DbContext.JsonDataConnections.ToList();
+ }
+
+ bool IJsonConnectionStorageService.CanSaveConnection { get { return DbContext.JsonDataConnections != null; } }
+
+ bool IJsonConnectionStorageService.ContainsConnection(string connectionName)
+ {
+ return GetConnections().Any(x => x.Name == connectionName);
+ }
+
+ IEnumerable IJsonConnectionStorageService.GetConnections()
+ {
+ return GetConnections().Select(x => CreateJsonDataConnectionFromString(x));
+ }
+
+ JsonDataConnection IJsonDataConnectionProviderService.GetJsonDataConnection(string name)
+ {
+ var connection = GetConnections().FirstOrDefault(x => x.Name == name);
+ if (connection == null)
+ throw new InvalidOperationException();
+ return CreateJsonDataConnectionFromString(connection);
+ }
+
+ void IJsonConnectionStorageService.SaveConnection(string connectionName, JsonDataConnection dataConnection, bool saveCredentials)
+ {
+ var connections = GetConnections();
+ var connectionString = dataConnection.CreateConnectionString();
+ foreach (var connection in connections)
+ {
+ if (connection.Name == connectionName)
+ {
+ connection.ConnectionString = connectionString;
+ DbContext.SaveChanges();
+ return;
+ }
+ }
+ DbContext.JsonDataConnections.Add(new JsonDataConnectionDescription() { Name = connectionName, ConnectionString = connectionString });
+ DbContext.SaveChanges();
+ }
+
+ public static JsonDataConnection CreateJsonDataConnectionFromString(DataConnection dataConnection)
+ {
+ return new JsonDataConnection(dataConnection.ConnectionString) { StoreConnectionNameOnly = true, Name = dataConnection.Name };
+ }
+}
diff --git a/api/src/Erp.Platform.HttpApi.Host/ReportServices/CustomJsonDataConnectionProviderFactory.cs b/api/src/Erp.Platform.HttpApi.Host/ReportServices/CustomJsonDataConnectionProviderFactory.cs
new file mode 100644
index 00000000..ba035e98
--- /dev/null
+++ b/api/src/Erp.Platform.HttpApi.Host/ReportServices/CustomJsonDataConnectionProviderFactory.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using DevExpress.DataAccess.Json;
+using DevExpress.DataAccess.Web;
+using Erp.Reports.HttpApi.Host.Data;
+
+namespace Erp.Platform.ReportServices;
+
+public class CustomJsonDataConnectionProviderFactory : IJsonDataConnectionProviderFactory
+{
+ protected LegacyReportDbContext DbContext { get; }
+
+ public CustomJsonDataConnectionProviderFactory(LegacyReportDbContext dbContext)
+ {
+ DbContext = dbContext;
+ }
+
+ public IJsonDataConnectionProviderService Create()
+ {
+ return new WebDocumentViewerJsonDataConnectionProvider(DbContext.JsonDataConnections.ToList());
+ }
+}
+
+public class WebDocumentViewerJsonDataConnectionProvider : IJsonDataConnectionProviderService
+{
+ readonly IEnumerable jsonDataConnections;
+
+ public WebDocumentViewerJsonDataConnectionProvider(IEnumerable jsonDataConnections)
+ {
+ this.jsonDataConnections = jsonDataConnections;
+ }
+
+ public JsonDataConnection GetJsonDataConnection(string name)
+ {
+ var connection = jsonDataConnections.FirstOrDefault(x => x.Name == name);
+ if (connection == null)
+ throw new InvalidOperationException();
+ return CustomDataSourceWizardJsonDataConnectionStorage.CreateJsonDataConnectionFromString(connection);
+ }
+}
diff --git a/api/src/Erp.Platform.HttpApi.Host/ReportServices/CustomReportStorageWebExtension.cs b/api/src/Erp.Platform.HttpApi.Host/ReportServices/CustomReportStorageWebExtension.cs
new file mode 100644
index 00000000..7ee5a2b1
--- /dev/null
+++ b/api/src/Erp.Platform.HttpApi.Host/ReportServices/CustomReportStorageWebExtension.cs
@@ -0,0 +1,83 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using DevExpress.XtraReports.UI;
+using Erp.Reports.EntityFrameworkCore;
+using System;
+using Erp.Reports.PredefinedReports;
+
+namespace Erp.Platform.ReportServices;
+
+public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension
+{
+ protected ErpReportsDbContext DbContext { get; set; }
+
+ public CustomReportStorageWebExtension(ErpReportsDbContext dbContext)
+ {
+ this.DbContext = dbContext;
+ }
+
+ public override bool CanSetData(string url)
+ {
+ return true;
+ }
+
+ public override bool IsValidUrl(string url)
+ {
+ return true;
+ }
+
+ public override byte[] GetData(string url)
+ {
+ var reportData = DbContext.ReportDefinitions.FirstOrDefault(x => x.Name == url);
+ if (reportData != null)
+ return reportData.Content;
+
+ if (ReportsFactory.Reports.ContainsKey(url))
+ {
+ using var ms = new MemoryStream();
+ using XtraReport report = ReportsFactory.Reports[url]();
+ report.SaveLayoutToXml(ms);
+ return ms.ToArray();
+ }
+ throw new DevExpress.XtraReports.Web.ClientControls.FaultException($"Could not find report '{url}'.");
+ }
+
+ public override Dictionary GetUrls()
+ {
+ return DbContext.ReportDefinitions
+ .ToList()
+ .Select(x => x.Name)
+ .Union(ReportsFactory.Reports.Select(x => x.Key))
+ .ToDictionary(x => x);
+ }
+
+ public override void SetData(XtraReport report, string url)
+ {
+ using var stream = new MemoryStream();
+ report.SaveLayoutToXml(stream);
+
+ var reportData = DbContext.ReportDefinitions.FirstOrDefault(x => x.Name == url);
+ if (reportData == null)
+ {
+ var newReport = new Erp.Reports.ReportDefinitions.ReportDefinition(
+ Guid.NewGuid(),
+ url,
+ url,
+ stream.ToArray()
+ );
+ DbContext.ReportDefinitions.Add(newReport);
+ }
+ else
+ {
+ reportData.UpdateContent(stream.ToArray());
+ }
+ DbContext.SaveChanges();
+ }
+
+ public override string SetNewData(XtraReport report, string defaultUrl)
+ {
+ SetData(report, defaultUrl);
+ return defaultUrl;
+ }
+}
diff --git a/api/src/Erp.Platform.HttpApi.Host/ReportServices/CustomSqlDataConnectionProviderFactory.cs b/api/src/Erp.Platform.HttpApi.Host/ReportServices/CustomSqlDataConnectionProviderFactory.cs
new file mode 100644
index 00000000..257c5419
--- /dev/null
+++ b/api/src/Erp.Platform.HttpApi.Host/ReportServices/CustomSqlDataConnectionProviderFactory.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using DevExpress.DataAccess.ConnectionParameters;
+using DevExpress.DataAccess.Sql;
+using DevExpress.DataAccess.Web;
+using DevExpress.DataAccess.Wizard.Services;
+using Erp.Reports.HttpApi.Host.Data;
+
+namespace Erp.Platform.ReportServices;
+
+public class CustomSqlDataConnectionProviderFactory : IConnectionProviderFactory
+{
+ private readonly LegacyReportDbContext reportDbContext;
+
+ public CustomSqlDataConnectionProviderFactory(LegacyReportDbContext reportDbContext)
+ {
+ this.reportDbContext = reportDbContext;
+ }
+
+ public IConnectionProviderService Create()
+ {
+ return new CustomSqlConnectionProviderService(reportDbContext.SqlDataConnections.ToList());
+ }
+}
+
+public class CustomSqlConnectionProviderService : IConnectionProviderService
+{
+ readonly IEnumerable sqlDataConnections;
+
+ public CustomSqlConnectionProviderService(IEnumerable sqlDataConnections)
+ {
+ this.sqlDataConnections = sqlDataConnections;
+ }
+
+ public SqlDataConnection LoadConnection(string connectionName)
+ {
+ var sqlDataConnectionData = sqlDataConnections.FirstOrDefault(x => x.Name == connectionName);
+ if (sqlDataConnectionData == null)
+ throw new InvalidOperationException();
+
+ if (string.IsNullOrEmpty(sqlDataConnectionData.ConnectionString))
+ throw new KeyNotFoundException($"Connection string '{connectionName}' not found.");
+
+ var connectionParameters = new CustomStringConnectionParameters(sqlDataConnectionData.ConnectionString);
+ return new SqlDataConnection(connectionName, connectionParameters);
+ }
+}
diff --git a/api/src/Erp.Platform.HttpApi.Host/ReportServices/CustomSqlDataSourceWizardConnectionStringsProvider.cs b/api/src/Erp.Platform.HttpApi.Host/ReportServices/CustomSqlDataSourceWizardConnectionStringsProvider.cs
new file mode 100644
index 00000000..96a4d39d
--- /dev/null
+++ b/api/src/Erp.Platform.HttpApi.Host/ReportServices/CustomSqlDataSourceWizardConnectionStringsProvider.cs
@@ -0,0 +1,27 @@
+using System.Collections.Generic;
+using System.Linq;
+using DevExpress.DataAccess.ConnectionParameters;
+using DevExpress.DataAccess.Web;
+using Erp.Reports.HttpApi.Host.Data;
+
+namespace Erp.Platform.ReportServices;
+
+public class CustomSqlDataSourceWizardConnectionStringsProvider : IDataSourceWizardConnectionStringsProvider
+{
+ readonly LegacyReportDbContext reportDataContext;
+
+ public CustomSqlDataSourceWizardConnectionStringsProvider(LegacyReportDbContext reportDataContext)
+ {
+ this.reportDataContext = reportDataContext;
+ }
+
+ Dictionary IDataSourceWizardConnectionStringsProvider.GetConnectionDescriptions()
+ {
+ return reportDataContext.SqlDataConnections.ToDictionary(x => x.Name, x => x.DisplayName);
+ }
+
+ DataConnectionParametersBase IDataSourceWizardConnectionStringsProvider.GetDataConnectionParameters(string name)
+ {
+ return null;
+ }
+}
diff --git a/ui/package-lock.json b/ui/package-lock.json
index c8147f16..fb300f97 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -29,6 +29,7 @@
"axios": "^1.7.9",
"classnames": "^2.5.1",
"dayjs": "^1.11.13",
+ "devexpress-reporting-react": "25.1.7",
"devextreme": "25.1.7",
"devextreme-dist": "25.1.7",
"devextreme-react": "25.1.7",
@@ -1714,6 +1715,22 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@devexpress/analytics-core": {
+ "version": "25.1.7",
+ "resolved": "https://registry.npmjs.org/@devexpress/analytics-core/-/analytics-core-25.1.7.tgz",
+ "integrity": "sha512-3H98zZe4uylgiBdIi65z4TIJQa8owrpDVR6o6ACxjH0PtjCVgZr5MgExGEobYrjqK8GUCglUCFwsUDgRVTDlcA==",
+ "license": "SEE LICENSE IN README.md",
+ "peer": true,
+ "dependencies": {
+ "@types/jquery": "^3.1.1",
+ "ace-builds": "^1.4.13",
+ "jquery": "^3.1.1",
+ "knockout": "~3.5.0"
+ },
+ "peerDependencies": {
+ "devextreme": "25.1.7"
+ }
+ },
"node_modules/@devexpress/utils": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/@devexpress/utils/-/utils-1.4.8.tgz",
@@ -3552,6 +3569,16 @@
"@types/react": "*"
}
},
+ "node_modules/@types/jquery": {
+ "version": "3.5.33",
+ "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.33.tgz",
+ "integrity": "sha512-SeyVJXlCZpEki5F0ghuYe+L+PprQta6nRZqhONt9F13dWBtR/ftoaIbdRQ7cis7womE+X2LKhsDdDtkkDhJS6g==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@types/sizzle": "*"
+ }
+ },
"node_modules/@types/json-schema": {
"version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
@@ -3596,9 +3623,9 @@
"license": "MIT"
},
"node_modules/@types/prop-types": {
- "version": "15.7.15",
- "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
- "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
+ "version": "15.7.13",
+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz",
+ "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==",
"license": "MIT"
},
"node_modules/@types/raf": {
@@ -3622,7 +3649,6 @@
"version": "18.3.7",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz",
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
- "devOptional": true,
"license": "MIT",
"peerDependencies": {
"@types/react": "^18.0.0"
@@ -3692,6 +3718,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/sizzle": {
+ "version": "2.3.10",
+ "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.10.tgz",
+ "integrity": "sha512-TC0dmN0K8YcWEAEfiPi5gJP14eJe30TTGjkvek3iM/1NdHHsdCA/Td6GvNndMOo/iSnIsZ4HuuhrYPDAmbxzww==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/@types/trusted-types": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
@@ -4206,6 +4239,13 @@
"node": ">=6.5"
}
},
+ "node_modules/ace-builds": {
+ "version": "1.43.5",
+ "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.43.5.tgz",
+ "integrity": "sha512-iH5FLBKdB7SVn9GR37UgA/tpQS8OTWIxWAuq3Ofaw+Qbc69FfPXsXd9jeW7KRG2xKpKMqBDnu0tHBrCWY5QI7A==",
+ "license": "BSD-3-Clause",
+ "peer": true
+ },
"node_modules/acorn": {
"version": "8.15.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
@@ -5762,6 +5802,40 @@
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==",
"license": "0BSD"
},
+ "node_modules/devexpress-reporting": {
+ "version": "25.1.7",
+ "resolved": "https://registry.npmjs.org/devexpress-reporting/-/devexpress-reporting-25.1.7.tgz",
+ "integrity": "sha512-4Ffvj6bgzII63hAfq3u53w0VypDd4HRJHQnQv4yqWm5VyW+7V7ztLLeNQRerbyqjzdhfkN2qyXqFV+3YxZwoEg==",
+ "license": "SEE LICENSE IN README.md",
+ "peer": true,
+ "dependencies": {
+ "ace-builds": "^1.4.13",
+ "jquery": "^3.1.1",
+ "knockout": "~3.5.0"
+ },
+ "peerDependencies": {
+ "@devexpress/analytics-core": "25.1.7"
+ }
+ },
+ "node_modules/devexpress-reporting-react": {
+ "version": "25.1.7",
+ "resolved": "https://registry.npmjs.org/devexpress-reporting-react/-/devexpress-reporting-react-25.1.7.tgz",
+ "integrity": "sha512-2PbTbqsAFfZec+BgGSHqU/SBpyyXWps9qx+UD1eC09s7sIHdBvooGMwPI9Vb2+FUiqq1vcDKPxH1hLUqAJYZvg==",
+ "license": "SEE LICENSE IN README.md",
+ "dependencies": {
+ "prop-types": "^15.8.1"
+ },
+ "peerDependencies": {
+ "@devexpress/analytics-core": "25.1.7",
+ "@types/prop-types": "15.7.13",
+ "@types/react": "^18.0.0 || ^19.0.0",
+ "@types/react-dom": "^18.0.0 || ^19.0.0",
+ "devexpress-reporting": "25.1.7",
+ "devextreme-react": "25.1.7",
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/devextreme": {
"version": "25.1.7",
"resolved": "https://registry.npmjs.org/devextreme/-/devextreme-25.1.7.tgz",
@@ -8691,6 +8765,13 @@
"jiti": "bin/jiti.js"
}
},
+ "node_modules/jquery": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
+ "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/js-sha3": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
@@ -8914,6 +8995,13 @@
"json-buffer": "3.0.1"
}
},
+ "node_modules/knockout": {
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/knockout/-/knockout-3.5.1.tgz",
+ "integrity": "sha512-wRJ9I4az0QcsH7A4v4l0enUpkS++MBx0BnL/68KaLzJg7x1qmbjSlwEoCNol7KTYZ+pmtI7Eh2J0Nu6/2Z5J/Q==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/language-subtag-registry": {
"version": "0.3.23",
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
diff --git a/ui/package.json b/ui/package.json
index 653df566..44e9dc2a 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -40,6 +40,7 @@
"devextreme": "25.1.7",
"devextreme-dist": "25.1.7",
"devextreme-react": "25.1.7",
+ "devexpress-reporting-react": "25.1.7",
"easy-peasy": "^6.0.5",
"emoji-picker-react": "^4.14.1",
"exceljs": "^4.4.0",
diff --git a/ui/src/views/report/DevexpressReportViewer.tsx b/ui/src/views/report/DevexpressReportViewer.tsx
new file mode 100644
index 00000000..76beb61b
--- /dev/null
+++ b/ui/src/views/report/DevexpressReportViewer.tsx
@@ -0,0 +1,29 @@
+import React from 'react'
+import { Container } from '@/components/shared'
+import { Helmet } from 'react-helmet'
+import ReportViewer, { RequestOptions } from 'devexpress-reporting-react/dx-report-viewer'
+import { useLocalization } from '@/utils/hooks/useLocalization'
+import 'devextreme/dist/css/dx.light.css'
+import '@devexpress/analytics-core/dist/css/dx-analytics.common.css'
+import '@devexpress/analytics-core/dist/css/dx-analytics.light.css'
+import 'devexpress-reporting/dist/css/dx-webdocumentviewer.css'
+
+const DevexpressReportViewer: React.FC = () => {
+ const { translate } = useLocalization()
+
+ return (
+
+
+
+
+
+
+
+ )
+}
+
+export default DevexpressReportViewer