From c6e13b921673061ef86fe33dfed201248e697c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96ZT=C3=9CRK?= <76204082+iamsedatozturk@users.noreply.github.com> Date: Fri, 15 Aug 2025 16:01:24 +0300 Subject: [PATCH] Report Category Entity ve Seeder --- .../Reports/CreateReportTemplateDto.cs | 2 +- .../Reports/ReportCategoryDto.cs | 14 ++ .../Reports/ReportTemplateDto.cs | 6 +- .../Reports/UpdateReportTemplateDto.cs | 2 +- .../Reports/ReportAppService.cs | 10 +- .../Reports/ReportAutoMapperProfile.cs | 3 + .../Seeds/ListFormsSeeder.cs | 185 ++++++++++++++++++ .../Seeds/PlatformDataSeeder.cs | 20 +- .../Seeds/SeederData.json | 20 ++ .../Seeds/SeederDto.cs | 9 + .../PlatformConsts.cs | 1 + .../Kurs.Platform.Domain/Data/SeedConsts.cs | 6 + .../Entities/ReportCategory.cs | 33 ++++ .../Entities/ReportTemplate.cs | 9 +- .../EntityFrameworkCore/PlatformDbContext.cs | 42 +++- ....cs => 20250815123946_Reports.Designer.cs} | 99 +++++++++- ...1_Reports.cs => 20250815123946_Reports.cs} | 48 ++++- .../PlatformDbContextModelSnapshot.cs | 97 ++++++++- ui/src/components/reports/Dashboard.tsx | 5 +- ui/src/proxy/reports/models.ts | 6 +- 20 files changed, 574 insertions(+), 43 deletions(-) create mode 100644 api/src/Kurs.Platform.Application.Contracts/Reports/ReportCategoryDto.cs create mode 100644 api/src/Kurs.Platform.Domain/Entities/ReportCategory.cs rename api/src/Kurs.Platform.EntityFrameworkCore/Migrations/{20250815115111_Reports.Designer.cs => 20250815123946_Reports.Designer.cs} (98%) rename api/src/Kurs.Platform.EntityFrameworkCore/Migrations/{20250815115111_Reports.cs => 20250815123946_Reports.cs} (72%) diff --git a/api/src/Kurs.Platform.Application.Contracts/Reports/CreateReportTemplateDto.cs b/api/src/Kurs.Platform.Application.Contracts/Reports/CreateReportTemplateDto.cs index 350a46a4..451a09fc 100644 --- a/api/src/Kurs.Platform.Application.Contracts/Reports/CreateReportTemplateDto.cs +++ b/api/src/Kurs.Platform.Application.Contracts/Reports/CreateReportTemplateDto.cs @@ -12,7 +12,7 @@ namespace Kurs.Platform.Reports [Required] public string HtmlContent { get; set; } - public string Category { get; set; } + public string CategoryName { get; set; } public List Tags { get; set; } public List Parameters { get; set; } diff --git a/api/src/Kurs.Platform.Application.Contracts/Reports/ReportCategoryDto.cs b/api/src/Kurs.Platform.Application.Contracts/Reports/ReportCategoryDto.cs new file mode 100644 index 00000000..1f6e13f9 --- /dev/null +++ b/api/src/Kurs.Platform.Application.Contracts/Reports/ReportCategoryDto.cs @@ -0,0 +1,14 @@ +using System; +using Volo.Abp.Application.Dtos; + +namespace Kurs.Platform.Reports +{ + public class ReportCategoryDto : FullAuditedEntityDto + { + public string Name { get; set; } + public string Description { get; set; } + public string Icon { get; set; } + + public int TemplateCount { get; init; } + } +} diff --git a/api/src/Kurs.Platform.Application.Contracts/Reports/ReportTemplateDto.cs b/api/src/Kurs.Platform.Application.Contracts/Reports/ReportTemplateDto.cs index d298831c..fce1a640 100644 --- a/api/src/Kurs.Platform.Application.Contracts/Reports/ReportTemplateDto.cs +++ b/api/src/Kurs.Platform.Application.Contracts/Reports/ReportTemplateDto.cs @@ -13,14 +13,14 @@ namespace Kurs.Platform.Reports [Required] public string HtmlContent { get; set; } - public string Category { get; set; } + public string CategoryName { get; set; } public List Tags { get; set; } public List Parameters { get; set; } public ReportTemplateDto() { - Tags = new List(); - Parameters = new List(); + Tags = []; + Parameters = []; } } } diff --git a/api/src/Kurs.Platform.Application.Contracts/Reports/UpdateReportTemplateDto.cs b/api/src/Kurs.Platform.Application.Contracts/Reports/UpdateReportTemplateDto.cs index 064acc60..84d62c59 100644 --- a/api/src/Kurs.Platform.Application.Contracts/Reports/UpdateReportTemplateDto.cs +++ b/api/src/Kurs.Platform.Application.Contracts/Reports/UpdateReportTemplateDto.cs @@ -12,7 +12,7 @@ namespace Kurs.Platform.Reports [Required] public string HtmlContent { get; set; } - public string Category { get; set; } + public string CategoryName { get; set; } public List Tags { get; set; } public List Parameters { get; set; } diff --git a/api/src/Kurs.Platform.Application/Reports/ReportAppService.cs b/api/src/Kurs.Platform.Application/Reports/ReportAppService.cs index 8768a1ce..a101e339 100644 --- a/api/src/Kurs.Platform.Application/Reports/ReportAppService.cs +++ b/api/src/Kurs.Platform.Application/Reports/ReportAppService.cs @@ -40,13 +40,13 @@ public class ReportAppService : PlatformAppService, IReportAppService query = query.Where(x => x.Name.Contains(input.Filter) || x.Description.Contains(input.Filter) || - x.Category.Contains(input.Filter) + x.CategoryName.Contains(input.Filter) ); } if (!string.IsNullOrWhiteSpace(input.Category)) { - query = query.Where(x => x.Category == input.Category); + query = query.Where(x => x.CategoryName == input.Category); } // Toplam kayıt sayısı @@ -85,7 +85,7 @@ public class ReportAppService : PlatformAppService, IReportAppService input.Name, input.Description, input.HtmlContent, - input.Category ?? "Genel") + input.CategoryName) { Tags = JsonSerializer.Serialize(input.Tags) }; @@ -120,7 +120,7 @@ public class ReportAppService : PlatformAppService, IReportAppService template.Name = input.Name; template.Description = input.Description; template.HtmlContent = input.HtmlContent; - template.Category = input.Category ?? "Genel"; + template.CategoryName = input.CategoryName; template.Tags = JsonSerializer.Serialize(input.Tags); await _reportTemplateRepository.UpdateAsync(template); @@ -262,7 +262,7 @@ public class ReportAppService : PlatformAppService, IReportAppService Name = template.Name, Description = template.Description, HtmlContent = template.HtmlContent, - Category = template.Category, + CategoryName = template.CategoryName, CreationTime = template.CreationTime, LastModificationTime = template.LastModificationTime, CreatorId = template.CreatorId, diff --git a/api/src/Kurs.Platform.Application/Reports/ReportAutoMapperProfile.cs b/api/src/Kurs.Platform.Application/Reports/ReportAutoMapperProfile.cs index 7ef5df88..b008e9ee 100644 --- a/api/src/Kurs.Platform.Application/Reports/ReportAutoMapperProfile.cs +++ b/api/src/Kurs.Platform.Application/Reports/ReportAutoMapperProfile.cs @@ -43,6 +43,9 @@ namespace Kurs.Platform.Reports .ForMember(dest => dest.TemplateName, opt => opt.Ignore()) .ForMember(dest => dest.GeneratedContent, opt => opt.Ignore()) .ForMember(dest => dest.GeneratedAt, opt => opt.Ignore()); + + + CreateMap(); } private static List ConvertTagsFromJson(string tags) diff --git a/api/src/Kurs.Platform.DbMigrator/Seeds/ListFormsSeeder.cs b/api/src/Kurs.Platform.DbMigrator/Seeds/ListFormsSeeder.cs index e3ca95ea..33314964 100644 --- a/api/src/Kurs.Platform.DbMigrator/Seeds/ListFormsSeeder.cs +++ b/api/src/Kurs.Platform.DbMigrator/Seeds/ListFormsSeeder.cs @@ -13089,6 +13089,191 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency } #endregion + #region Report Categories + if (!await _listFormRepository.AnyAsync(a => a.ListFormCode == ListFormCodes.Lists.ReportCategory)) + { + var listFormReportCatory = await _listFormRepository.InsertAsync( + new ListForm + { + CultureName = LanguageCodes.En, + ListFormCode = ListFormCodes.Lists.ReportCategory, + Name = AppCodes.Reports.Categories, + Title = AppCodes.Reports.Categories, + DataSourceCode = SeedConsts.DataSources.DefaultCode, + IsTenant = false, + IsBranch = false, + IsOrganizationUnit = false, + Description = AppCodes.Reports.Categories, + SelectCommandType = SelectCommandTypeEnum.Table, + SelectCommand = SelectCommandByTableName("ReportCategory"), + KeyFieldName = "Id", + KeyFieldDbSourceType = DbType.Int32, + SortMode = GridOptions.SortModeSingle, + FilterRowJson = JsonSerializer.Serialize(new GridFilterRowDto { Visible = true }), + HeaderFilterJson = JsonSerializer.Serialize(new { Visible = true }), + SearchPanelJson = JsonSerializer.Serialize(new { Visible = true }), + GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), + SelectionJson = JsonSerializer.Serialize(new SelectionDto + { + Mode = GridOptions.SelectionModeSingle, + AllowSelectAll = false + }), + ColumnOptionJson = JsonSerializer.Serialize(new + { + ColumnFixingEnabled = true, + }), + PermissionJson = JsonSerializer.Serialize(new PermissionCrudDto + { + C = AppCodes.Reports.Default + ".Create", + R = AppCodes.Reports.Default, + U = AppCodes.Reports.Default + ".Update", + D = AppCodes.Reports.Default + ".Delete", + E = AppCodes.Reports.Default + ".Export", + I = AppCodes.Reports.Default + ".Import" + }), + PagerOptionJson = JsonSerializer.Serialize(new GridPagerOptionDto + { + Visible = true, + AllowedPageSizes = "10,20,50,100", + ShowPageSizeSelector = true, + ShowNavigationButtons = true, + ShowInfo = false, + InfoText = "Page {0} of {1} ({2} items)", + DisplayMode = GridColumnOptions.PagerDisplayModeAdaptive, + ScrollingMode = GridColumnOptions.ScrollingModeStandard, + LoadPanelEnabled = "auto", + LoadPanelText = "Loading..." + }), + EditingOptionJson = JsonSerializer.Serialize(new GridEditingDto + { + Popup = new GridEditingPopupDto + { + Title = "Report Category Form", + Width = 500, + Height = 300 + }, + AllowDeleting = true, + AllowAdding = true, + AllowUpdating = true, + SendOnlyChangedFormValuesUpdate = false + }), + EditingFormJson = JsonSerializer.Serialize(new List + { + new() + { + Order = 1, + ColCount = 1, + ColSpan = 2, + ItemType = "group", + Items = + [ + new EditingFormItemDto { Order = 1, DataField = "Id", ColSpan = 2, IsRequired = true, EditorType2 = EditorTypes.dxTextBox }, + new EditingFormItemDto { Order = 2, DataField = "Name", ColSpan = 2, IsRequired = true, EditorType2 = EditorTypes.dxTextBox }, + new EditingFormItemDto { Order = 3, DataField = "Description", ColSpan = 2, IsRequired = false, EditorType2 = EditorTypes.dxTextArea }, + new EditingFormItemDto { Order = 4, DataField = "Icon", ColSpan = 2, IsRequired = false, EditorType2 = EditorTypes.dxTextBox }, + ] + } + }) + }); + + #region Report Categories Fields + await _listFormFieldRepository.InsertManyAsync([ + new() + { + ListFormCode = listFormReportCatory.ListFormCode, + CultureName = LanguageCodes.En, + SourceDbType = DbType.Guid, + FieldName = "Id", + Width = 100, + ListOrderNo = 1, + Visible = true, + IsActive = true, + IsDeleted = false, + ValidationRuleJson = JsonSerializer.Serialize(new[] + { + new ValidationRuleDto { Type = "required" } + }), + PermissionJson = JsonSerializer.Serialize(new ListFormFieldPermissionDto + { + C = AppCodes.Reports.Default + ".Create", + R = AppCodes.Reports.Default, + U = AppCodes.Reports.Default + ".Update", + E = true, + Deny = false + }) + }, + new() + { + ListFormCode = listFormReportCatory.ListFormCode, + CultureName = LanguageCodes.En, + SourceDbType = DbType.String, + FieldName = "Name", + Width = 300, + ListOrderNo = 2, + Visible = true, + IsActive = true, + IsDeleted = false, + AllowSearch = true, + ValidationRuleJson = JsonSerializer.Serialize(new[] + { + new ValidationRuleDto { Type = "required" } + }), + PermissionJson = JsonSerializer.Serialize(new ListFormFieldPermissionDto + { + C = AppCodes.Reports.Default + ".Create", + R = AppCodes.Reports.Default, + U = AppCodes.Reports.Default + ".Update", + E = true, + Deny = false + }) + }, + new() + { + ListFormCode = listFormReportCatory.ListFormCode, + CultureName = LanguageCodes.En, + SourceDbType = DbType.String, + FieldName = "Description", + Width = 100, + ListOrderNo = 3, + Visible = true, + IsActive = true, + IsDeleted = false, + AllowSearch = true, + PermissionJson = JsonSerializer.Serialize(new ListFormFieldPermissionDto + { + C = AppCodes.Reports.Default + ".Create", + R = AppCodes.Reports.Default, + U = AppCodes.Reports.Default + ".Update", + E = true, + Deny = false + }) + }, + new() + { + ListFormCode = listFormReportCatory.ListFormCode, + CultureName = LanguageCodes.En, + SourceDbType = DbType.String, + FieldName = "Icon", + Width = 100, + ListOrderNo = 4, + Visible = true, + IsActive = true, + IsDeleted = false, + AllowSearch = true, + PermissionJson = JsonSerializer.Serialize(new ListFormFieldPermissionDto + { + C = AppCodes.Reports.Default + ".Create", + R = AppCodes.Reports.Default, + U = AppCodes.Reports.Default + ".Update", + E = true, + Deny = false + }) + }, + ]); + #endregion + } + #endregion + #endregion } } diff --git a/api/src/Kurs.Platform.DbMigrator/Seeds/PlatformDataSeeder.cs b/api/src/Kurs.Platform.DbMigrator/Seeds/PlatformDataSeeder.cs index 8ed8539a..213d8867 100644 --- a/api/src/Kurs.Platform.DbMigrator/Seeds/PlatformDataSeeder.cs +++ b/api/src/Kurs.Platform.DbMigrator/Seeds/PlatformDataSeeder.cs @@ -60,7 +60,7 @@ public class PlatformDataSeeder : IDataSeedContributor, ITransientDependency private readonly IRepository _paymentMethodRepository; private readonly IRepository _installmentOptionRepository; private readonly IRepository _customComponentRepository; - + private readonly IRepository _reportCategoriesRepository; public PlatformDataSeeder( IRepository languages, @@ -96,7 +96,8 @@ public class PlatformDataSeeder : IDataSeedContributor, ITransientDependency IRepository ProductRepository, IRepository PaymentMethodRepository, IRepository InstallmentOptionRepository, - IRepository CustomComponentRepository + IRepository CustomComponentRepository, + IRepository ReportCategoriesRepository ) { _languages = languages; @@ -133,6 +134,7 @@ public class PlatformDataSeeder : IDataSeedContributor, ITransientDependency _paymentMethodRepository = PaymentMethodRepository; _installmentOptionRepository = InstallmentOptionRepository; _customComponentRepository = CustomComponentRepository; + _reportCategoriesRepository = ReportCategoriesRepository; } private static IConfigurationRoot BuildConfiguration() @@ -750,6 +752,20 @@ public class PlatformDataSeeder : IDataSeedContributor, ITransientDependency JsonSerializer.Serialize(item.Dependencies))); } } + + foreach (var item in items.ReportCategories) + { + var exists = await _reportCategoriesRepository.AnyAsync(x => x.Name == item.Name); + + if (!exists) + { + await _reportCategoriesRepository.InsertAsync(new ReportCategory( + item.Id, + item.Name, + item.Description, + item.Icon)); + } + } } } diff --git a/api/src/Kurs.Platform.DbMigrator/Seeds/SeederData.json b/api/src/Kurs.Platform.DbMigrator/Seeds/SeederData.json index a1aacff9..74ce1870 100644 --- a/api/src/Kurs.Platform.DbMigrator/Seeds/SeederData.json +++ b/api/src/Kurs.Platform.DbMigrator/Seeds/SeederData.json @@ -25914,5 +25914,25 @@ "isActive": true, "dependencies": ["AxiosListComponent"] } + ], + "ReportCategories": [ + { + "id": "5f4d6c1f-b1e0-4f91-854c-1d59c25e7191", + "name": "Genel Raporlar", + "description": "Genel Şirket içi raporlar", + "icon": "📊" + }, + { + "id": "5f4d6c1f-b1e0-4f91-854c-1d59c25e7192", + "name": "Taahhütnameler", + "description": "Kursiyeler ile ilgili taahhütname raporları", + "icon": "✍️" + }, + { + "id": "5f4d6c1f-b1e0-4f91-854c-1d59c25e7193", + "name": "Sözleşmeler", + "description": "Tedarikçiler ile ilgili sözleşme raporları", + "icon": "📜" + } ] } diff --git a/api/src/Kurs.Platform.DbMigrator/Seeds/SeederDto.cs b/api/src/Kurs.Platform.DbMigrator/Seeds/SeederDto.cs index e0221d4e..fd8f169f 100644 --- a/api/src/Kurs.Platform.DbMigrator/Seeds/SeederDto.cs +++ b/api/src/Kurs.Platform.DbMigrator/Seeds/SeederDto.cs @@ -43,6 +43,7 @@ public class SeederDto public List PaymentMethods { get; set; } public List InstallmentOptions { get; set; } public List CustomComponents { get; set; } + public List ReportCategories { get; set; } } public class ChartsSeedDto @@ -309,3 +310,11 @@ public class CustomComponentSeedDto public bool IsActive { get; set; } public List Dependencies { get; set; } = new(); } + +public class ReportCategorySeedDto +{ + public Guid Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string Icon { get; set; } +} diff --git a/api/src/Kurs.Platform.Domain.Shared/PlatformConsts.cs b/api/src/Kurs.Platform.Domain.Shared/PlatformConsts.cs index b1e277bb..de792fb2 100644 --- a/api/src/Kurs.Platform.Domain.Shared/PlatformConsts.cs +++ b/api/src/Kurs.Platform.Domain.Shared/PlatformConsts.cs @@ -366,6 +366,7 @@ public static class PlatformConsts public const string PaymentMethod = "list-paymentmethod"; public const string InstallmentOption = "list-installmentoption"; public const string PurchaseOrder = "list-purchaseorder"; + public const string ReportCategory = "list-reportcategory"; public const string ListformField = "list-listformfield"; } diff --git a/api/src/Kurs.Platform.Domain/Data/SeedConsts.cs b/api/src/Kurs.Platform.Domain/Data/SeedConsts.cs index ed55aa85..9fda7c95 100644 --- a/api/src/Kurs.Platform.Domain/Data/SeedConsts.cs +++ b/api/src/Kurs.Platform.Domain/Data/SeedConsts.cs @@ -394,6 +394,12 @@ public static class SeedConsts public const string InstallmentOptions = Default + ".InstallmentOptions"; public const string PurchaseOrders = Default + ".PurchaseOrders"; } + + public static class Reports + { + public const string Default = Prefix.App + ".Reports"; + public const string Categories = Default + ".Categories"; + } } public static class DataSources diff --git a/api/src/Kurs.Platform.Domain/Entities/ReportCategory.cs b/api/src/Kurs.Platform.Domain/Entities/ReportCategory.cs new file mode 100644 index 00000000..0aa719b2 --- /dev/null +++ b/api/src/Kurs.Platform.Domain/Entities/ReportCategory.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Domain.Entities.Auditing; + +namespace Kurs.Platform.Entities +{ + public class ReportCategory : FullAuditedAggregateRoot + { + [Required] + public string Name { get; set; } + public string Description { get; set; } + public string Icon { get; set; } + + public ICollection ReportTemplates { get; set; } + + public ReportCategory() + { + } + + public ReportCategory( + Guid id, + string name, + string description, + string icon = null + ) : base(id) + { + Name = name; + Description = description; + Icon = icon; + } + } +} diff --git a/api/src/Kurs.Platform.Domain/Entities/ReportTemplate.cs b/api/src/Kurs.Platform.Domain/Entities/ReportTemplate.cs index 1edbd5b6..20ca07af 100644 --- a/api/src/Kurs.Platform.Domain/Entities/ReportTemplate.cs +++ b/api/src/Kurs.Platform.Domain/Entities/ReportTemplate.cs @@ -13,10 +13,11 @@ namespace Kurs.Platform.Entities [Required] public string HtmlContent { get; set; } - public string Category { get; set; } + public string CategoryName { get; set; } public string Tags { get; set; } // JSON string array - public virtual ICollection Parameters { get; set; } + public ReportCategory ReportCategory { get; set; } + public ICollection Parameters { get; set; } public ReportTemplate() { @@ -28,13 +29,13 @@ namespace Kurs.Platform.Entities string name, string description, string htmlContent, - string category = "Genel" + string categoryName = "Genel" ) : base(id) { Name = name; Description = description; HtmlContent = htmlContent; - Category = category; + CategoryName = categoryName; Parameters = new List(); } } diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs b/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs index 91279b39..5234acc5 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs @@ -81,13 +81,14 @@ public class PlatformDbContext : public DbSet Orders { get; set; } public DbSet OrderItems { get; set; } + public DbSet ListFormImports { get; set; } + public DbSet ListFormImportExecutes { get; set; } + // Reports Entities public DbSet ReportTemplates { get; set; } public DbSet ReportParameters { get; set; } - public DbSet GeneratedReports { get; set; } - - public DbSet ListFormImports { get; set; } - public DbSet ListFormImportExecutes { get; set; } + public DbSet ReportGenerated { get; set; } + public DbSet ReportCategories { get; set; } #region Entities from the modules @@ -692,6 +693,26 @@ public class PlatformDbContext : }); // Reports Configuration + // Reports Configuration + builder.Entity(b => + { + b.ToTable(PlatformConsts.DbTablePrefix + nameof(ReportCategory), PlatformConsts.DbSchema); + b.ConfigureByConvention(); + + b.Property(x => x.Name).IsRequired().HasMaxLength(256); + b.Property(x => x.Description).HasMaxLength(4000); // JSON string + b.Property(x => x.Icon).HasMaxLength(64); + + // Primary key dışında Name de ilişki anahtarı olarak kullanılacaksa + b.HasIndex(x => x.Name).IsUnique(); + + b.HasMany(x => x.ReportTemplates) // Bir kategori birden çok template içerir + .WithOne(x => x.ReportCategory) // Template'in bir kategorisi vardır + .HasForeignKey(x => x.CategoryName) // Template tarafındaki FK property + .HasPrincipalKey(c => c.Name) // Category tarafındaki anahtar + .OnDelete(DeleteBehavior.SetNull); // Silindiğinde null bırak + }); + builder.Entity(b => { b.ToTable(PlatformConsts.DbTablePrefix + nameof(ReportTemplate), PlatformConsts.DbSchema); @@ -700,13 +721,16 @@ public class PlatformDbContext : b.Property(x => x.Name).IsRequired().HasMaxLength(256); b.Property(x => x.Description).HasMaxLength(1000); b.Property(x => x.HtmlContent).IsRequired(); - b.Property(x => x.Category).HasMaxLength(100); + b.Property(x => x.CategoryName).HasMaxLength(100); b.Property(x => x.Tags).HasMaxLength(2000); - b.HasMany(t => t.Parameters) // navigation üzerinden - .WithOne(p => p.ReportTemplate) // karşı navigation - .HasForeignKey(p => p.ReportTemplateId) // scalar FK property - .OnDelete(DeleteBehavior.Cascade); + // Burada CategoryName FK olacak + b.Property(x => x.CategoryName).HasMaxLength(256); + + b.HasMany(t => t.Parameters) + .WithOne(p => p.ReportTemplate) + .HasForeignKey(p => p.ReportTemplateId) + .OnDelete(DeleteBehavior.Cascade); }); builder.Entity(b => diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250815115111_Reports.Designer.cs b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250815123946_Reports.Designer.cs similarity index 98% rename from api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250815115111_Reports.Designer.cs rename to api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250815123946_Reports.Designer.cs index a70aeddb..e0f04b12 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250815115111_Reports.Designer.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250815123946_Reports.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace Kurs.Platform.Migrations { [DbContext(typeof(PlatformDbContext))] - [Migration("20250815115111_Reports")] + [Migration("20250815123946_Reports")] partial class Reports { /// @@ -2886,6 +2886,74 @@ namespace Kurs.Platform.Migrations b.ToTable("PProduct", (string)null); }); + modelBuilder.Entity("Kurs.Platform.Entities.ReportCategory", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + 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("Description") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Icon") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + 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") + .IsUnique(); + + b.ToTable("PReportCategory", (string)null); + }); + modelBuilder.Entity("Kurs.Platform.Entities.ReportGenerated", b => { b.Property("Id") @@ -3017,8 +3085,9 @@ namespace Kurs.Platform.Migrations b.Property("Required") .HasColumnType("bit"); - b.Property("Type") - .HasColumnType("int"); + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); @@ -3032,9 +3101,9 @@ namespace Kurs.Platform.Migrations b.Property("Id") .HasColumnType("uniqueidentifier"); - b.Property("Category") - .HasMaxLength(100) - .HasColumnType("nvarchar(100)"); + b.Property("CategoryName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); b.Property("ConcurrencyStamp") .IsConcurrencyToken() @@ -3097,6 +3166,8 @@ namespace Kurs.Platform.Migrations b.HasKey("Id"); + b.HasIndex("CategoryName"); + b.ToTable("PReportTemplate", (string)null); }); @@ -6000,6 +6071,17 @@ namespace Kurs.Platform.Migrations b.Navigation("ReportTemplate"); }); + modelBuilder.Entity("Kurs.Platform.Entities.ReportTemplate", b => + { + b.HasOne("Kurs.Platform.Entities.ReportCategory", "ReportCategory") + .WithMany("ReportTemplates") + .HasForeignKey("CategoryName") + .HasPrincipalKey("Name") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("ReportCategory"); + }); + modelBuilder.Entity("Kurs.Platform.Entities.Uom", b => { b.HasOne("Kurs.Platform.Entities.UomCategory", "UomCategory") @@ -6227,6 +6309,11 @@ namespace Kurs.Platform.Migrations b.Navigation("Fields"); }); + modelBuilder.Entity("Kurs.Platform.Entities.ReportCategory", b => + { + b.Navigation("ReportTemplates"); + }); + modelBuilder.Entity("Kurs.Platform.Entities.ReportTemplate", b => { b.Navigation("Parameters"); diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250815115111_Reports.cs b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250815123946_Reports.cs similarity index 72% rename from api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250815115111_Reports.cs rename to api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250815123946_Reports.cs index 802eb7a4..9c34d125 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250815115111_Reports.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250815123946_Reports.cs @@ -11,6 +11,30 @@ namespace Kurs.Platform.Migrations /// protected override void Up(MigrationBuilder migrationBuilder) { + migrationBuilder.CreateTable( + name: "PReportCategory", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + Description = table.Column(type: "nvarchar(4000)", maxLength: 4000, nullable: true), + Icon = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: false), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, 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_PReportCategory", x => x.Id); + table.UniqueConstraint("AK_PReportCategory_Name", x => x.Name); + }); + migrationBuilder.CreateTable( name: "PReportTemplate", columns: table => new @@ -19,7 +43,7 @@ namespace Kurs.Platform.Migrations Name = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), HtmlContent = table.Column(type: "nvarchar(max)", nullable: false), - Category = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: true), + CategoryName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), Tags = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: true), ExtraProperties = table.Column(type: "nvarchar(max)", nullable: false), ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: false), @@ -34,6 +58,12 @@ namespace Kurs.Platform.Migrations constraints: table => { table.PrimaryKey("PK_PReportTemplate", x => x.Id); + table.ForeignKey( + name: "FK_PReportTemplate_PReportCategory_CategoryName", + column: x => x.CategoryName, + principalTable: "PReportCategory", + principalColumn: "Name", + onDelete: ReferentialAction.SetNull); }); migrationBuilder.CreateTable( @@ -75,7 +105,7 @@ namespace Kurs.Platform.Migrations ReportTemplateId = table.Column(type: "uniqueidentifier", nullable: false), Name = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false), Placeholder = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: true), - Type = table.Column(type: "int", nullable: false), + Type = table.Column(type: "nvarchar(max)", nullable: false), DefaultValue = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: true), Required = table.Column(type: "bit", nullable: false), Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), @@ -98,6 +128,12 @@ namespace Kurs.Platform.Migrations onDelete: ReferentialAction.Cascade); }); + migrationBuilder.CreateIndex( + name: "IX_PReportCategory_Name", + table: "PReportCategory", + column: "Name", + unique: true); + migrationBuilder.CreateIndex( name: "IX_PReportGenerated_TemplateId", table: "PReportGenerated", @@ -107,6 +143,11 @@ namespace Kurs.Platform.Migrations name: "IX_PReportParameter_ReportTemplateId", table: "PReportParameter", column: "ReportTemplateId"); + + migrationBuilder.CreateIndex( + name: "IX_PReportTemplate_CategoryName", + table: "PReportTemplate", + column: "CategoryName"); } /// @@ -120,6 +161,9 @@ namespace Kurs.Platform.Migrations migrationBuilder.DropTable( name: "PReportTemplate"); + + migrationBuilder.DropTable( + name: "PReportCategory"); } } } diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs index f89a72c5..403d52c6 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs @@ -2883,6 +2883,74 @@ namespace Kurs.Platform.Migrations b.ToTable("PProduct", (string)null); }); + modelBuilder.Entity("Kurs.Platform.Entities.ReportCategory", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + 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("Description") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Icon") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + 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") + .IsUnique(); + + b.ToTable("PReportCategory", (string)null); + }); + modelBuilder.Entity("Kurs.Platform.Entities.ReportGenerated", b => { b.Property("Id") @@ -3014,8 +3082,9 @@ namespace Kurs.Platform.Migrations b.Property("Required") .HasColumnType("bit"); - b.Property("Type") - .HasColumnType("int"); + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); @@ -3029,9 +3098,9 @@ namespace Kurs.Platform.Migrations b.Property("Id") .HasColumnType("uniqueidentifier"); - b.Property("Category") - .HasMaxLength(100) - .HasColumnType("nvarchar(100)"); + b.Property("CategoryName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); b.Property("ConcurrencyStamp") .IsConcurrencyToken() @@ -3094,6 +3163,8 @@ namespace Kurs.Platform.Migrations b.HasKey("Id"); + b.HasIndex("CategoryName"); + b.ToTable("PReportTemplate", (string)null); }); @@ -5997,6 +6068,17 @@ namespace Kurs.Platform.Migrations b.Navigation("ReportTemplate"); }); + modelBuilder.Entity("Kurs.Platform.Entities.ReportTemplate", b => + { + b.HasOne("Kurs.Platform.Entities.ReportCategory", "ReportCategory") + .WithMany("ReportTemplates") + .HasForeignKey("CategoryName") + .HasPrincipalKey("Name") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("ReportCategory"); + }); + modelBuilder.Entity("Kurs.Platform.Entities.Uom", b => { b.HasOne("Kurs.Platform.Entities.UomCategory", "UomCategory") @@ -6224,6 +6306,11 @@ namespace Kurs.Platform.Migrations b.Navigation("Fields"); }); + modelBuilder.Entity("Kurs.Platform.Entities.ReportCategory", b => + { + b.Navigation("ReportTemplates"); + }); + modelBuilder.Entity("Kurs.Platform.Entities.ReportTemplate", b => { b.Navigation("Parameters"); diff --git a/ui/src/components/reports/Dashboard.tsx b/ui/src/components/reports/Dashboard.tsx index 5b8af763..2a717517 100644 --- a/ui/src/components/reports/Dashboard.tsx +++ b/ui/src/components/reports/Dashboard.tsx @@ -20,7 +20,7 @@ export const Dashboard: React.FC = () => { const [selectedCategory, setSelectedCategory] = useState('Tümü') const categories = useMemo(() => { - const cats = ['Tümü', ...new Set(templates.map((t) => t.category))] + const cats = ['Tümü', ...new Set(templates.map((t) => t.categoryName))] return cats }, [templates]) @@ -31,7 +31,8 @@ export const Dashboard: React.FC = () => { template.description?.toLowerCase().includes(searchQuery.toLowerCase()) || template.tags.some((tag: any) => tag.toLowerCase().includes(searchQuery.toLowerCase())) - const matchesCategory = selectedCategory === 'Tümü' || template.category === selectedCategory + const matchesCategory = + selectedCategory === 'Tümü' || template.categoryName === selectedCategory return matchesSearch && matchesCategory }) diff --git a/ui/src/proxy/reports/models.ts b/ui/src/proxy/reports/models.ts index 7403aeb4..7cf87368 100644 --- a/ui/src/proxy/reports/models.ts +++ b/ui/src/proxy/reports/models.ts @@ -16,7 +16,7 @@ export interface ReportTemplateDto { name: string description?: string htmlContent: string - category?: string + categoryName?: string tags: string[] parameters: ReportParameterDto[] @@ -62,7 +62,7 @@ export interface CreateReportTemplateDto { name: string description?: string htmlContent: string - category?: string + categoryName?: string tags?: string[] parameters: CreateReportParameterDto[] } @@ -71,7 +71,7 @@ export interface UpdateReportTemplateDto { name: string description?: string htmlContent: string - category?: string + categoryName?: string tags?: string[] parameters: UpdateReportParameterDto[] }