diff --git a/api/src/Erp.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs b/api/src/Erp.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs index f82c622a..94e4ed4a 100644 --- a/api/src/Erp.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs +++ b/api/src/Erp.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs @@ -5999,7 +5999,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep Text ="View", UrlTarget="_blank", AuthName = listFormName, - Url=$"/admin/reports/@Id/view", + Url=$"/admin/reports/TemplateReport/view?name=@Id", IsVisible = true, }, new() { @@ -6007,7 +6007,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep Text ="Design", UrlTarget="_blank", AuthName = listFormName + ".Update", - Url=$"/admin/reports/@Id/design", + Url=$"/admin/reports/TemplateReport/design?name=@Id", IsVisible = true, }, }), diff --git a/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/ReportsFactory.cs b/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/ReportsFactory.cs deleted file mode 100644 index 50779f8c..00000000 --- a/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/ReportsFactory.cs +++ /dev/null @@ -1,13 +0,0 @@ -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/TemplateReport.Designer.cs similarity index 99% rename from api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TestReport.Designer.cs rename to api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TemplateReport.Designer.cs index 8363faff..dd03b155 100644 --- a/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TestReport.Designer.cs +++ b/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TemplateReport.Designer.cs @@ -1,6 +1,6 @@ namespace Erp.Reports.PredefinedReports { - partial class TestReport + partial class TemplateReport { /// /// Required designer variable. @@ -32,7 +32,7 @@ DevExpress.DataAccess.Sql.Table table1 = 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(); - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TestReport)); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TemplateReport)); this.TopMargin = new DevExpress.XtraReports.UI.TopMarginBand(); this.BottomMargin = new DevExpress.XtraReports.UI.BottomMarginBand(); this.pageInfo1 = new DevExpress.XtraReports.UI.XRPageInfo(); diff --git a/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TemplateReport.cs b/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TemplateReport.cs new file mode 100644 index 00000000..475339c5 --- /dev/null +++ b/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TemplateReport.cs @@ -0,0 +1,9 @@ +namespace Erp.Reports.PredefinedReports; + +public partial class TemplateReport : DevExpress.XtraReports.UI.XtraReport +{ + public TemplateReport() + { + InitializeComponent(); + } +} diff --git a/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TestReport.resx b/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TemplateReport.resx similarity index 100% rename from api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TestReport.resx rename to api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TemplateReport.resx diff --git a/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TestReport.cs b/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TestReport.cs deleted file mode 100644 index 6278b7f7..00000000 --- a/api/src/Erp.Platform.HttpApi.Host/PredefinedReports/TestReport.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Erp.Reports.PredefinedReports; - -public partial class TestReport : DevExpress.XtraReports.UI.XtraReport -{ - public TestReport() - { - InitializeComponent(); - } -} diff --git a/api/src/Erp.Platform.HttpApi.Host/ReportServices/CustomReportStorageWebExtension.cs b/api/src/Erp.Platform.HttpApi.Host/ReportServices/CustomReportStorageWebExtension.cs index 322c8532..879dbf7f 100644 --- a/api/src/Erp.Platform.HttpApi.Host/ReportServices/CustomReportStorageWebExtension.cs +++ b/api/src/Erp.Platform.HttpApi.Host/ReportServices/CustomReportStorageWebExtension.cs @@ -2,7 +2,7 @@ using System.IO; using System.Linq; using System; -using Erp.Reports.PredefinedReports; +using System.Reflection; namespace Erp.Platform.ReportServices; @@ -51,8 +51,10 @@ public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extens // Determines whether the URL passed to the current report storage is valid. // Implement your own logic to prohibit URLs that contain spaces or other specific characters. // Return **true** if no validation is required. - - return Path.GetFileName(url) == url; + + // Query string varsa sadece rapor adını kontrol et + string reportName = url.Contains("?") ? url.Split('?')[0] : url; + return Path.GetFileName(reportName) == reportName; } public override byte[] GetData(string url) @@ -63,18 +65,97 @@ public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extens // if the parameters are included in the report URL's query string. try { - if (Directory.EnumerateFiles(reportDirectory).Select(Path.GetFileNameWithoutExtension).Contains(url)) + // URL'den rapor adını ve parametreleri ayır + string reportName = url; + Dictionary parameters = new Dictionary(); + + if (url.Contains("?")) { - return File.ReadAllBytes(Path.Combine(reportDirectory, url + FileExtension)); - } - if (ReportsFactory.Reports.ContainsKey(url)) - { - using (MemoryStream ms = new MemoryStream()) + var parts = url.Split('?'); + reportName = parts[0]; + + // Query string parametrelerini parse et + var queryString = parts[1]; + var paramPairs = queryString.Split('&'); + foreach (var pair in paramPairs) { - ReportsFactory.Reports[url]().SaveLayoutToXml(ms); - return ms.ToArray(); + var keyValue = pair.Split('='); + if (keyValue.Length == 2) + { + parameters[keyValue[0]] = Uri.UnescapeDataString(keyValue[1]); + } } } + + // Önce Reports klasöründen yüklemeyi dene + if (Directory.EnumerateFiles(reportDirectory).Select(Path.GetFileNameWithoutExtension).Contains(reportName)) + { + var report = XtraReport.FromFile(Path.Combine(reportDirectory, reportName + FileExtension)); + + // SQL DataSource'daki filtreyi güncelle + if (parameters.Count > 0) + { + var sqlDataSource = report.ComponentStorage.OfType().FirstOrDefault(); + if (sqlDataSource != null && sqlDataSource.Queries.Count > 0) + { + var query = sqlDataSource.Queries[0] as DevExpress.DataAccess.Sql.SelectQuery; + if (query != null) + { + // FilterString'i oluştur - sadece kolon adını kullan + var filters = new List(); + foreach (var param in parameters) + { + // Capitalize first letter for column name matching (Name, Id, etc.) + var columnName = char.ToUpper(param.Key[0]) + param.Key.Substring(1); + filters.Add($"[{columnName}] = '{param.Value.Replace("'", "''")}'"); + } + query.FilterString = string.Join(" AND ", filters); + } + } + } + + using MemoryStream ms = new MemoryStream(); + report.SaveLayoutToXml(ms); + return ms.ToArray(); + } + + // Reports klasöründe yoksa PredefinedReports namespace'inden yükle + var reportType = Assembly.GetExecutingAssembly() + .GetTypes() + .FirstOrDefault(t => t.Namespace == "Erp.Reports.PredefinedReports" && + t.Name == reportName && + typeof(XtraReport).IsAssignableFrom(t)); + + if (reportType != null) + { + var report = (XtraReport)Activator.CreateInstance(reportType); + + // SQL DataSource'daki filtreyi güncelle + if (parameters.Count > 0) + { + var sqlDataSource = report.ComponentStorage.OfType().FirstOrDefault(); + if (sqlDataSource != null && sqlDataSource.Queries.Count > 0) + { + var query = sqlDataSource.Queries[0] as DevExpress.DataAccess.Sql.SelectQuery; + if (query != null) + { + // FilterString'i oluştur - sadece kolon adını kullan + var filters = new List(); + foreach (var param in parameters) + { + // Capitalize first letter for column name matching (Name, Id, etc.) + var columnName = char.ToUpper(param.Key[0]) + param.Key.Substring(1); + filters.Add($"[{columnName}] = '{param.Value.Replace("'", "''")}'"); + } + query.FilterString = string.Join(" AND ", filters); + } + } + } + + using MemoryStream ms = new MemoryStream(); + report.SaveLayoutToXml(ms); + return ms.ToArray(); + } } catch (Exception) { @@ -88,10 +169,18 @@ public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extens // Returns a dictionary that contains the report names (URLs) and display names. // The Report Designer uses this method to populate the Open Report and Save Report dialogs. - return Directory.GetFiles(reportDirectory, "*" + FileExtension) - .Select(Path.GetFileNameWithoutExtension) - .Union(ReportsFactory.Reports.Select(x => x.Key)) - .ToDictionary(x => x); + var reportsFromFiles = Directory.GetFiles(reportDirectory, "*" + FileExtension) + .Select(Path.GetFileNameWithoutExtension); + + var reportsFromCode = Assembly.GetExecutingAssembly() + .GetTypes() + .Where(t => t.Namespace == "Erp.Reports.PredefinedReports" && + typeof(XtraReport).IsAssignableFrom(t) && + !t.IsAbstract) + .Select(t => t.Name); + + return reportsFromFiles.Union(reportsFromCode) + .ToDictionary(x => x); } public override void SetData(XtraReport report, string url) diff --git a/api/src/Erp.Platform.HttpApi.Host/Reports/TestReport.repx b/api/src/Erp.Platform.HttpApi.Host/Reports/TestReport.repx deleted file mode 100644 index 386d757d..00000000 --- a/api/src/Erp.Platform.HttpApi.Host/Reports/TestReport.repx +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/ui/src/views/report/DevexpressReportViewer.tsx b/ui/src/views/report/DevexpressReportViewer.tsx index b7f8b465..670f75c5 100644 --- a/ui/src/views/report/DevexpressReportViewer.tsx +++ b/ui/src/views/report/DevexpressReportViewer.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { useMemo } from 'react' import { Container } from '@/components/shared' import { Helmet } from 'react-helmet' import ReportViewer, { RequestOptions } from 'devexpress-reporting-react/dx-report-viewer' @@ -7,11 +7,20 @@ 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' -import { useParams } from 'react-router-dom' +import { useParams, useLocation } from 'react-router-dom' const DevexpressReportViewer: React.FC = () => { const { translate } = useLocalization() const { id } = useParams<{ id: string }>() + const location = useLocation() + + // Query string parametrelerini reportUrl'e ekle + const reportUrlWithParams = useMemo(() => { + if (location.search) { + return `${id}${location.search}` + } + return id + }, [id, location.search]) if (!id) { return null @@ -25,7 +34,7 @@ const DevexpressReportViewer: React.FC = () => { defaultTitle="Erp Platform" > - +