diff --git a/api/src/Kurs.Platform.Application.Contracts/Reports/CreateReportTemplateDto.cs b/api/src/Kurs.Platform.Application.Contracts/Reports/CreateReportTemplateDto.cs index 451a09fc..3dad6e05 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 CategoryName { get; set; } + public Guid CategoryId { get; set; } public List Tags { get; set; } public List Parameters { get; set; } diff --git a/api/src/Kurs.Platform.Application.Contracts/Reports/GetReportsInput.cs b/api/src/Kurs.Platform.Application.Contracts/Reports/GetReportsInput.cs index adb82091..0aceb45b 100644 --- a/api/src/Kurs.Platform.Application.Contracts/Reports/GetReportsInput.cs +++ b/api/src/Kurs.Platform.Application.Contracts/Reports/GetReportsInput.cs @@ -6,7 +6,7 @@ namespace Kurs.Platform.Reports public class GetReportTemplatesInput : PagedAndSortedResultRequestDto { public string Filter { get; set; } - public string CategoryName { get; set; } + public Guid CategoryId { get; set; } } public class GetGeneratedReportsInput : PagedAndSortedResultRequestDto diff --git a/api/src/Kurs.Platform.Application.Contracts/Reports/IReportAppService.cs b/api/src/Kurs.Platform.Application.Contracts/Reports/IReportAppService.cs index 7e749324..26386e10 100644 --- a/api/src/Kurs.Platform.Application.Contracts/Reports/IReportAppService.cs +++ b/api/src/Kurs.Platform.Application.Contracts/Reports/IReportAppService.cs @@ -15,9 +15,9 @@ namespace Kurs.Platform.Reports Task DeleteTemplateAsync(Guid id); // Generated Report operations - Task> GetGeneratedReportsAsync(GetGeneratedReportsInput input); - Task GetGeneratedReportAsync(Guid id); - Task GenerateReportAsync(GenerateReportDto input); + Task> GetGeneratedReportsAsync(GetGeneratedReportsInput input); + Task GetGeneratedReportAsync(Guid id); + Task GenerateReportAsync(ReportGenerateDto input); Task DeleteGeneratedReportAsync(Guid id); // Bulk operations @@ -27,6 +27,6 @@ namespace Kurs.Platform.Reports public class ReportsDataDto { public PagedResultDto Templates { get; set; } - public PagedResultDto GeneratedReports { get; set; } + public PagedResultDto GeneratedReports { get; set; } } } diff --git a/api/src/Kurs.Platform.Application.Contracts/Reports/GenerateReportDto.cs b/api/src/Kurs.Platform.Application.Contracts/Reports/ReportGenerateDto.cs similarity index 82% rename from api/src/Kurs.Platform.Application.Contracts/Reports/GenerateReportDto.cs rename to api/src/Kurs.Platform.Application.Contracts/Reports/ReportGenerateDto.cs index d0c61dd1..9e816204 100644 --- a/api/src/Kurs.Platform.Application.Contracts/Reports/GenerateReportDto.cs +++ b/api/src/Kurs.Platform.Application.Contracts/Reports/ReportGenerateDto.cs @@ -4,14 +4,14 @@ using System.ComponentModel.DataAnnotations; namespace Kurs.Platform.Reports { - public class GenerateReportDto + public class ReportGenerateDto { [Required] public Guid TemplateId { get; set; } public Dictionary Parameters { get; set; } - public GenerateReportDto() + public ReportGenerateDto() { Parameters = []; } diff --git a/api/src/Kurs.Platform.Application.Contracts/Reports/GeneratedReportDto.cs b/api/src/Kurs.Platform.Application.Contracts/Reports/ReportGeneratedDto.cs similarity index 65% rename from api/src/Kurs.Platform.Application.Contracts/Reports/GeneratedReportDto.cs rename to api/src/Kurs.Platform.Application.Contracts/Reports/ReportGeneratedDto.cs index 0e256e75..328a5cba 100644 --- a/api/src/Kurs.Platform.Application.Contracts/Reports/GeneratedReportDto.cs +++ b/api/src/Kurs.Platform.Application.Contracts/Reports/ReportGeneratedDto.cs @@ -5,7 +5,7 @@ using Volo.Abp.Application.Dtos; namespace Kurs.Platform.Reports { - public class GeneratedReportDto : FullAuditedEntityDto + public class ReportGeneratedDto : FullAuditedEntityDto { public Guid? TemplateId { get; set; } @@ -15,13 +15,12 @@ namespace Kurs.Platform.Reports [Required] public string GeneratedContent { get; set; } public Dictionary Parameters { get; set; } - public DateTime GeneratedAt { get; set; } - public ReportTemplateDto Template { get; set; } - public GeneratedReportDto() + public ReportTemplateDto ReportTemplate { get; set; } + + public ReportGeneratedDto() { Parameters = []; - GeneratedAt = DateTime.UtcNow; } } } diff --git a/api/src/Kurs.Platform.Application.Contracts/Reports/ReportParameterDto.cs b/api/src/Kurs.Platform.Application.Contracts/Reports/ReportParameterDto.cs index cf353817..fc1a78bf 100644 --- a/api/src/Kurs.Platform.Application.Contracts/Reports/ReportParameterDto.cs +++ b/api/src/Kurs.Platform.Application.Contracts/Reports/ReportParameterDto.cs @@ -6,7 +6,7 @@ namespace Kurs.Platform.Reports public class ReportParameterDto { public Guid Id { get; set; } - public Guid ReportTemplateId { get; set; } + public Guid? TemplateId { get; set; } [Required] public string Name { get; set; } public string Placeholder { get; set; } diff --git a/api/src/Kurs.Platform.Application.Contracts/Reports/ReportTemplateDto.cs b/api/src/Kurs.Platform.Application.Contracts/Reports/ReportTemplateDto.cs index fce1a640..e71f5e27 100644 --- a/api/src/Kurs.Platform.Application.Contracts/Reports/ReportTemplateDto.cs +++ b/api/src/Kurs.Platform.Application.Contracts/Reports/ReportTemplateDto.cs @@ -13,8 +13,9 @@ namespace Kurs.Platform.Reports [Required] public string HtmlContent { get; set; } - public string CategoryName { get; set; } + public Guid CategoryId { get; set; } public List Tags { get; set; } + public List Parameters { get; set; } public ReportTemplateDto() diff --git a/api/src/Kurs.Platform.Application.Contracts/Reports/UpdateReportTemplateDto.cs b/api/src/Kurs.Platform.Application.Contracts/Reports/UpdateReportTemplateDto.cs index 84d62c59..1cef3165 100644 --- a/api/src/Kurs.Platform.Application.Contracts/Reports/UpdateReportTemplateDto.cs +++ b/api/src/Kurs.Platform.Application.Contracts/Reports/UpdateReportTemplateDto.cs @@ -2,37 +2,36 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -namespace Kurs.Platform.Reports +namespace Kurs.Platform.Reports; + +public class UpdateReportTemplateDto { - public class UpdateReportTemplateDto + [Required] + public string Name { get; set; } + public string Description { get; set; } + + [Required] + public string HtmlContent { get; set; } + public Guid CategoryId { get; set; } + public List Tags { get; set; } + public List Parameters { get; set; } + + public UpdateReportTemplateDto() { - [Required] - public string Name { get; set; } - public string Description { get; set; } - - [Required] - public string HtmlContent { get; set; } - public string CategoryName { get; set; } - public List Tags { get; set; } - public List Parameters { get; set; } - - public UpdateReportTemplateDto() - { - Tags = []; - Parameters = []; - } - } - - public class UpdateReportParameterDto - { - public Guid? Id { get; set; } - - [Required] - public string Name { get; set; } - public string Placeholder { get; set; } - public string Type { get; set; } - public string DefaultValue { get; set; } - public bool Required { get; set; } - public string Description { get; set; } + Tags = []; + Parameters = []; } } + +public class UpdateReportParameterDto +{ + public Guid? Id { get; set; } + + [Required] + public string Name { get; set; } + public string Placeholder { get; set; } + public string Type { get; set; } + public string DefaultValue { get; set; } + public bool Required { get; set; } + public string Description { get; set; } +} diff --git a/api/src/Kurs.Platform.Application/Reports/ReportAppService.cs b/api/src/Kurs.Platform.Application/Reports/ReportAppService.cs index 55f3d3f8..749e9971 100644 --- a/api/src/Kurs.Platform.Application/Reports/ReportAppService.cs +++ b/api/src/Kurs.Platform.Application/Reports/ReportAppService.cs @@ -51,14 +51,13 @@ public class ReportAppService : PlatformAppService, IReportAppService { query = query.Where(x => x.Name.Contains(input.Filter) || - x.Description.Contains(input.Filter) || - x.CategoryName.Contains(input.Filter) + x.Description.Contains(input.Filter) ); } - if (!string.IsNullOrWhiteSpace(input.CategoryName)) + if (input.CategoryId != Guid.Empty) { - query = query.Where(x => x.CategoryName == input.CategoryName); + query = query.Where(x => x.CategoryId == input.CategoryId); } // Toplam kayıt sayısı @@ -105,7 +104,7 @@ public class ReportAppService : PlatformAppService, IReportAppService input.Name, input.Description, input.HtmlContent, - input.CategoryName) + input.CategoryId) { Tags = JsonSerializer.Serialize(input.Tags) }; @@ -141,14 +140,14 @@ public class ReportAppService : PlatformAppService, IReportAppService template.Name = input.Name; template.Description = input.Description; template.HtmlContent = input.HtmlContent; - template.CategoryName = input.CategoryName; + template.CategoryId = input.CategoryId; template.Tags = JsonSerializer.Serialize(input.Tags ?? []); // Şablonu hemen persist et (audit alanları için de iyi olur) await _reportTemplateRepository.UpdateAsync(template, autoSave: true); // 2) Parametrelerde upsert + artıklarını sil - var existingParams = await _reportParameterRepository.GetListAsync(p => p.ReportTemplateId == id); + var existingParams = await _reportParameterRepository.GetListAsync(p => p.TemplateId == id); var existingById = existingParams.ToDictionary(p => p.Id, p => p); var inputParams = input.Parameters ?? new List(); @@ -231,13 +230,13 @@ public class ReportAppService : PlatformAppService, IReportAppService await _reportTemplateRepository.DeleteAsync(id); } - public async Task> GetGeneratedReportsAsync(GetGeneratedReportsInput input) + public async Task> GetGeneratedReportsAsync(GetGeneratedReportsInput input) { var query = await _generatedReportRepository.GetQueryableAsync(); // Okuma senaryosu: tracking gerekmiyor + Template'ı eager load edelim query = query.AsNoTracking() - .Include(x => x.Template); + .Include(x => x.ReportTemplate); // Filtre if (!string.IsNullOrWhiteSpace(input.Filter)) @@ -260,7 +259,7 @@ public class ReportAppService : PlatformAppService, IReportAppService if (!string.IsNullOrWhiteSpace(input.Sorting)) query = query.OrderBy(input.Sorting); // ör. "generatedAt DESC" veya "templateName" else - query = query.OrderByDescending(x => x.GeneratedAt); + query = query.OrderByDescending(x => x.CreationTime); // Sayfalama var reports = await AsyncExecuter.ToListAsync( @@ -270,17 +269,17 @@ public class ReportAppService : PlatformAppService, IReportAppService // DTO map var reportDtos = reports.Select(MapToGeneratedReportDto).ToList(); - return new PagedResultDto(totalCount, reportDtos); + return new PagedResultDto(totalCount, reportDtos); } - public async Task GetGeneratedReportAsync(Guid id) + public async Task GetGeneratedReportAsync(Guid id) { var report = await _generatedReportRepository.GetAsync(id); return MapToGeneratedReportDto(report); } - public async Task GenerateReportAsync(GenerateReportDto input) + public async Task GenerateReportAsync(ReportGenerateDto input) { var template = await _reportTemplateRepository.GetAsync(input.TemplateId); if (template == null) @@ -336,7 +335,7 @@ public class ReportAppService : PlatformAppService, IReportAppService Name = template.Name, Description = template.Description, HtmlContent = template.HtmlContent, - CategoryName = template.CategoryName, + CategoryId = template.CategoryId, CreationTime = template.CreationTime, LastModificationTime = template.LastModificationTime, CreatorId = template.CreatorId, @@ -359,7 +358,7 @@ public class ReportAppService : PlatformAppService, IReportAppService dto.Parameters = template.Parameters?.Select(p => new ReportParameterDto { Id = p.Id, - ReportTemplateId = p.ReportTemplateId, + TemplateId = p.TemplateId, Name = p.Name, Placeholder = p.Placeholder, Type = p.Type, @@ -371,15 +370,14 @@ public class ReportAppService : PlatformAppService, IReportAppService return dto; } - private GeneratedReportDto MapToGeneratedReportDto(ReportGenerated report) + private ReportGeneratedDto MapToGeneratedReportDto(ReportGenerated report) { - var dto = new GeneratedReportDto + var dto = new ReportGeneratedDto { Id = report.Id, TemplateId = report.TemplateId, TemplateName = report.TemplateName, GeneratedContent = report.GeneratedContent, - GeneratedAt = report.GeneratedAt, CreationTime = report.CreationTime, LastModificationTime = report.LastModificationTime, CreatorId = report.CreatorId, @@ -399,9 +397,9 @@ public class ReportAppService : PlatformAppService, IReportAppService } // Template mapping - if (report.Template != null) + if (report.ReportTemplate != null) { - dto.Template = MapToReportTemplateDto(report.Template); + dto.ReportTemplate = MapToReportTemplateDto(report.ReportTemplate); } return dto; diff --git a/api/src/Kurs.Platform.Application/Reports/ReportAutoMapperProfile.cs b/api/src/Kurs.Platform.Application/Reports/ReportAutoMapperProfile.cs index b008e9ee..0b5f515b 100644 --- a/api/src/Kurs.Platform.Application/Reports/ReportAutoMapperProfile.cs +++ b/api/src/Kurs.Platform.Application/Reports/ReportAutoMapperProfile.cs @@ -26,23 +26,22 @@ namespace Kurs.Platform.Reports CreateMap() .ForMember(dest => dest.Id, opt => opt.Ignore()) - .ForMember(dest => dest.ReportTemplateId, opt => opt.Ignore()); + .ForMember(dest => dest.TemplateId, opt => opt.Ignore()); CreateMap() - .ForMember(dest => dest.ReportTemplateId, opt => opt.Ignore()); + .ForMember(dest => dest.TemplateId, opt => opt.Ignore()); - CreateMap() + CreateMap() .ForMember(dest => dest.Parameters, opt => opt.MapFrom(src => ConvertParametersFromJson(src.Parameters))) - .ForMember(dest => dest.Template, opt => opt.MapFrom(src => src.Template)); + .ForMember(dest => dest.ReportTemplate, opt => opt.MapFrom(src => src.ReportTemplate)); - CreateMap() + CreateMap() .ForMember(dest => dest.Parameters, opt => opt.MapFrom(src => ConvertParametersToJson(src.Parameters))) .ForMember(dest => dest.Id, opt => opt.Ignore()) .ForMember(dest => dest.TemplateId, opt => opt.MapFrom(src => src.TemplateId)) .ForMember(dest => dest.TemplateName, opt => opt.Ignore()) - .ForMember(dest => dest.GeneratedContent, opt => opt.Ignore()) - .ForMember(dest => dest.GeneratedAt, opt => opt.Ignore()); + .ForMember(dest => dest.GeneratedContent, opt => opt.Ignore()); CreateMap(); diff --git a/api/src/Kurs.Platform.DbMigrator/Seeds/PlatformListFormsSeeder.cs b/api/src/Kurs.Platform.DbMigrator/Seeds/PlatformListFormsSeeder.cs index 6033cddb..15a3f988 100644 --- a/api/src/Kurs.Platform.DbMigrator/Seeds/PlatformListFormsSeeder.cs +++ b/api/src/Kurs.Platform.DbMigrator/Seeds/PlatformListFormsSeeder.cs @@ -24348,7 +24348,7 @@ public class PlatformListFormsSeeder : IDataSeedContributor, ITransientDependenc new() { Order = 1, - ColCount = 2, + ColCount = 1, ColSpan = 2, ItemType = "group", Items = @@ -24641,7 +24641,7 @@ public class PlatformListFormsSeeder : IDataSeedContributor, ITransientDependenc new EditingFormItemDto { Order = 2, DataField = "BranchId", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxSelectBox, EditorOptions=showClearButton }, new EditingFormItemDto { Order = 3, DataField = "ClassTypeId", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxSelectBox, EditorOptions=showClearButton }, new EditingFormItemDto { Order = 4, DataField = "Name", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxTextBox }, - new EditingFormItemDto { Order = 5, DataField = "LevelType", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxTextBox }, + new EditingFormItemDto { Order = 5, DataField = "LevelType", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxSelectBox }, new EditingFormItemDto { Order = 6, DataField = "LessonCount", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxNumberBox }, new EditingFormItemDto { Order = 7, DataField = "LessonDuration", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxNumberBox }, new EditingFormItemDto { Order = 8, DataField = "MonthlyPaymentRate", ColSpan = 1, EditorType2 = EditorTypes.dxNumberBox }, @@ -24805,6 +24805,19 @@ public class PlatformListFormsSeeder : IDataSeedContributor, ITransientDependenc Visible = true, IsActive = true, IsDeleted = false, + ValidationRuleJson = JsonSerializer.Serialize(new ValidationRuleDto[] + { + new ValidationRuleDto() { Type = Enum.GetName(UiColumnValidationRuleTypeEnum.required) } + }), + LookupJson = JsonSerializer.Serialize(new LookupDto { + DataSourceType = UiLookupDataSourceTypeEnum.StaticData, + DisplayExpr = "name", + ValueExpr = "key", + LookupQuery = JsonSerializer.Serialize(new LookupDataDto[] { + new () { Key="Seviye",Name="Seviye" }, + new () { Key="Sınav Eğitimi",Name="Sınav Eğitimi" }, + }), + }), PermissionJson = JsonSerializer.Serialize(new ListFormFieldPermissionDto { C = AppCodes.Definitions.Level + ".Create", @@ -25014,7 +25027,7 @@ public class PlatformListFormsSeeder : IDataSeedContributor, ITransientDependenc new() { Order = 1, - ColCount = 2, + ColCount = 1, ColSpan = 2, ItemType = "group", Items = diff --git a/api/src/Kurs.Platform.DbMigrator/Seeds/TenantData.json b/api/src/Kurs.Platform.DbMigrator/Seeds/TenantData.json index 7f7fb63a..e351415d 100644 --- a/api/src/Kurs.Platform.DbMigrator/Seeds/TenantData.json +++ b/api/src/Kurs.Platform.DbMigrator/Seeds/TenantData.json @@ -2639,6 +2639,12 @@ "en": "Category", "tr": "Kategori" }, + { + "resourceName": "Platform", + "key": "App.Reports.TemplateEditor.Placeholder.SelectCategory", + "en": "Select Category", + "tr": "Kategori Seç" + }, { "resourceName": "Platform", "key": "App.Reports.TemplateEditor.Label.Tags", diff --git a/api/src/Kurs.Platform.Domain/Entities/Tenant/Report/ReportGenerated.cs b/api/src/Kurs.Platform.Domain/Entities/Tenant/Report/ReportGenerated.cs index 94890500..f323f84b 100644 --- a/api/src/Kurs.Platform.Domain/Entities/Tenant/Report/ReportGenerated.cs +++ b/api/src/Kurs.Platform.Domain/Entities/Tenant/Report/ReportGenerated.cs @@ -12,18 +12,17 @@ namespace Kurs.Platform.Entities public string TemplateName { get; set; } public string GeneratedContent { get; set; } public string Parameters { get; set; } - public DateTime GeneratedAt { get; set; } - public virtual ReportTemplate Template { get; set; } + public virtual ReportTemplate ReportTemplate { get; set; } public ReportGenerated() { - GeneratedAt = DateTime.UtcNow; + } public ReportGenerated( Guid id, - Guid? templateId, + Guid templateId, string templateName, string generatedContent, string parameters @@ -33,7 +32,6 @@ namespace Kurs.Platform.Entities TemplateName = templateName; GeneratedContent = generatedContent; Parameters = parameters; - GeneratedAt = DateTime.UtcNow; } } } diff --git a/api/src/Kurs.Platform.Domain/Entities/Tenant/Report/ReportParameter.cs b/api/src/Kurs.Platform.Domain/Entities/Tenant/Report/ReportParameter.cs index 5461e2ef..756eb2cf 100644 --- a/api/src/Kurs.Platform.Domain/Entities/Tenant/Report/ReportParameter.cs +++ b/api/src/Kurs.Platform.Domain/Entities/Tenant/Report/ReportParameter.cs @@ -8,7 +8,7 @@ namespace Kurs.Platform.Entities { public Guid? TenantId { get; set; } - public Guid ReportTemplateId { get; set; } + public Guid? TemplateId { get; set; } public string Name { get; set; } public string Placeholder { get; set; } public string Type { get; set; } @@ -24,14 +24,14 @@ namespace Kurs.Platform.Entities public ReportParameter( Guid id, - Guid reportTemplateId, + Guid templateId, string name, string placeholder, string type, bool required = false ) : base(id) { - ReportTemplateId = reportTemplateId; + TemplateId = templateId; Name = name; Placeholder = placeholder; Type = type; diff --git a/api/src/Kurs.Platform.Domain/Entities/Tenant/Report/ReportTemplate.cs b/api/src/Kurs.Platform.Domain/Entities/Tenant/Report/ReportTemplate.cs index d8a5de06..effa1760 100644 --- a/api/src/Kurs.Platform.Domain/Entities/Tenant/Report/ReportTemplate.cs +++ b/api/src/Kurs.Platform.Domain/Entities/Tenant/Report/ReportTemplate.cs @@ -12,15 +12,18 @@ namespace Kurs.Platform.Entities public string Name { get; set; } public string Description { get; set; } public string HtmlContent { get; set; } - public string CategoryName { get; set; } + public Guid CategoryId { get; set; } public string Tags { get; set; } public ReportCategory ReportCategory { get; set; } + public ICollection Parameters { get; set; } + public ICollection Generated { get; set; } public ReportTemplate() { Parameters = []; + Generated = []; } public ReportTemplate( @@ -28,14 +31,15 @@ namespace Kurs.Platform.Entities string name, string description, string htmlContent, - string categoryName = "Genel" + Guid categoryId ) : base(id) { Name = name; Description = description; HtmlContent = htmlContent; - CategoryName = categoryName; - Parameters = new List(); + CategoryId = categoryId; + Parameters = []; + Generated = []; } } } diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs b/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs index 6ad23bc9..0136c8d8 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs @@ -667,13 +667,11 @@ public class PlatformDbContext : b.Property(x => x.Description).HasMaxLength(4000); // JSON string b.Property(x => x.Icon).HasMaxLength(64); - b.HasIndex(x => x.Name).IsUnique(); - b.HasMany(x => x.ReportTemplates) .WithOne(x => x.ReportCategory) - .HasForeignKey(x => x.CategoryName) - .HasPrincipalKey(c => c.Name) - .OnDelete(DeleteBehavior.SetNull); + .HasForeignKey(x => x.CategoryId) + .HasPrincipalKey(c => c.Id) + .OnDelete(DeleteBehavior.Cascade); }); builder.Entity(b => @@ -684,12 +682,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.CategoryName).HasMaxLength(256); b.Property(x => x.Tags).HasMaxLength(2000); b.HasMany(t => t.Parameters) .WithOne(p => p.ReportTemplate) - .HasForeignKey(p => p.ReportTemplateId) + .HasForeignKey(p => p.TemplateId) + .OnDelete(DeleteBehavior.Cascade); + + b.HasMany(t => t.Generated) + .WithOne(p => p.ReportTemplate) + .HasForeignKey(p => p.TemplateId) .OnDelete(DeleteBehavior.Cascade); }); @@ -698,7 +700,7 @@ public class PlatformDbContext : b.ToTable(Prefix.DbTableDefault + nameof(ReportParameter), Prefix.DbSchema); b.ConfigureByConvention(); - b.Property(x => x.ReportTemplateId).IsRequired(); + b.Property(x => x.TemplateId).IsRequired(); b.Property(x => x.Name).IsRequired().HasMaxLength(100); b.Property(x => x.Placeholder).HasMaxLength(200); b.Property(x => x.Type).IsRequired(); @@ -716,13 +718,6 @@ public class PlatformDbContext : b.Property(x => x.TemplateName).IsRequired().HasMaxLength(256); b.Property(x => x.GeneratedContent).IsRequired(); b.Property(x => x.Parameters).HasMaxLength(4000); // JSON string - b.Property(x => x.GeneratedAt).IsRequired(); - - b.HasOne(x => x.Template) - .WithMany() - .HasForeignKey(x => x.TemplateId) - .OnDelete(DeleteBehavior.SetNull) - .IsRequired(false); }); //Administration diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251008085215_Initial.Designer.cs b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251008104142_Initial.Designer.cs similarity index 99% rename from api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251008085215_Initial.Designer.cs rename to api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251008104142_Initial.Designer.cs index ebae6d07..d6af052a 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251008085215_Initial.Designer.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251008104142_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace Kurs.Platform.Migrations { [DbContext(typeof(PlatformDbContext))] - [Migration("20251008085215_Initial")] + [Migration("20251008104142_Initial")] partial class Initial { /// @@ -5183,9 +5183,6 @@ namespace Kurs.Platform.Migrations b.HasKey("Id"); - b.HasIndex("Name") - .IsUnique(); - b.ToTable("PReportCategory", (string)null); }); @@ -5210,9 +5207,6 @@ namespace Kurs.Platform.Migrations .HasColumnType("datetime2") .HasColumnName("DeletionTime"); - b.Property("GeneratedAt") - .HasColumnType("datetime2"); - b.Property("GeneratedContent") .IsRequired() .HasColumnType("nvarchar(max)"); @@ -5306,12 +5300,12 @@ namespace Kurs.Platform.Migrations .HasMaxLength(200) .HasColumnType("nvarchar(200)"); - b.Property("ReportTemplateId") - .HasColumnType("uniqueidentifier"); - b.Property("Required") .HasColumnType("bit"); + b.Property("TemplateId") + .HasColumnType("uniqueidentifier"); + b.Property("TenantId") .HasColumnType("uniqueidentifier") .HasColumnName("TenantId"); @@ -5322,7 +5316,7 @@ namespace Kurs.Platform.Migrations b.HasKey("Id"); - b.HasIndex("ReportTemplateId"); + b.HasIndex("TemplateId"); b.ToTable("PReportParameter", (string)null); }); @@ -5332,9 +5326,8 @@ namespace Kurs.Platform.Migrations b.Property("Id") .HasColumnType("uniqueidentifier"); - b.Property("CategoryName") - .HasMaxLength(256) - .HasColumnType("nvarchar(256)"); + b.Property("CategoryId") + .HasColumnType("uniqueidentifier"); b.Property("CreationTime") .HasColumnType("datetime2") @@ -5389,7 +5382,7 @@ namespace Kurs.Platform.Migrations b.HasKey("Id"); - b.HasIndex("CategoryName"); + b.HasIndex("CategoryId"); b.ToTable("PReportTemplate", (string)null); }); @@ -8832,19 +8825,19 @@ namespace Kurs.Platform.Migrations modelBuilder.Entity("Kurs.Platform.Entities.ReportGenerated", b => { - b.HasOne("Kurs.Platform.Entities.ReportTemplate", "Template") - .WithMany() + b.HasOne("Kurs.Platform.Entities.ReportTemplate", "ReportTemplate") + .WithMany("Generated") .HasForeignKey("TemplateId") - .OnDelete(DeleteBehavior.SetNull); + .OnDelete(DeleteBehavior.Cascade); - b.Navigation("Template"); + b.Navigation("ReportTemplate"); }); modelBuilder.Entity("Kurs.Platform.Entities.ReportParameter", b => { b.HasOne("Kurs.Platform.Entities.ReportTemplate", "ReportTemplate") .WithMany("Parameters") - .HasForeignKey("ReportTemplateId") + .HasForeignKey("TemplateId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); @@ -8855,9 +8848,9 @@ namespace Kurs.Platform.Migrations { b.HasOne("Kurs.Platform.Entities.ReportCategory", "ReportCategory") .WithMany("ReportTemplates") - .HasForeignKey("CategoryName") - .HasPrincipalKey("Name") - .OnDelete(DeleteBehavior.SetNull); + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); b.Navigation("ReportCategory"); }); @@ -9167,6 +9160,8 @@ namespace Kurs.Platform.Migrations modelBuilder.Entity("Kurs.Platform.Entities.ReportTemplate", b => { + b.Navigation("Generated"); + b.Navigation("Parameters"); }); diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251008085215_Initial.cs b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251008104142_Initial.cs similarity index 99% rename from api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251008085215_Initial.cs rename to api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251008104142_Initial.cs index 8d83e09e..07a010d7 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251008085215_Initial.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251008104142_Initial.cs @@ -1727,7 +1727,6 @@ namespace Kurs.Platform.Migrations constraints: table => { table.PrimaryKey("PK_PReportCategory", x => x.Id); - table.UniqueConstraint("AK_PReportCategory_Name", x => x.Name); }); migrationBuilder.CreateTable( @@ -3052,7 +3051,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), - CategoryName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + CategoryId = table.Column(type: "uniqueidentifier", nullable: false), Tags = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: true), CreationTime = table.Column(type: "datetime2", nullable: false), CreatorId = table.Column(type: "uniqueidentifier", nullable: true), @@ -3066,11 +3065,11 @@ namespace Kurs.Platform.Migrations { table.PrimaryKey("PK_PReportTemplate", x => x.Id); table.ForeignKey( - name: "FK_PReportTemplate_PReportCategory_CategoryName", - column: x => x.CategoryName, + name: "FK_PReportTemplate_PReportCategory_CategoryId", + column: x => x.CategoryId, principalTable: "PReportCategory", - principalColumn: "Name", - onDelete: ReferentialAction.SetNull); + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( @@ -3398,7 +3397,6 @@ namespace Kurs.Platform.Migrations TemplateName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), GeneratedContent = table.Column(type: "nvarchar(max)", nullable: false), Parameters = table.Column(type: "nvarchar(4000)", maxLength: 4000, nullable: true), - GeneratedAt = table.Column(type: "datetime2", nullable: false), CreationTime = table.Column(type: "datetime2", nullable: false), CreatorId = table.Column(type: "uniqueidentifier", nullable: true), LastModificationTime = table.Column(type: "datetime2", nullable: true), @@ -3415,7 +3413,7 @@ namespace Kurs.Platform.Migrations column: x => x.TemplateId, principalTable: "PReportTemplate", principalColumn: "Id", - onDelete: ReferentialAction.SetNull); + onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( @@ -3424,7 +3422,7 @@ namespace Kurs.Platform.Migrations { Id = table.Column(type: "uniqueidentifier", nullable: false), TenantId = table.Column(type: "uniqueidentifier", nullable: true), - ReportTemplateId = table.Column(type: "uniqueidentifier", nullable: false), + TemplateId = 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: "nvarchar(max)", nullable: false), @@ -3443,8 +3441,8 @@ namespace Kurs.Platform.Migrations { table.PrimaryKey("PK_PReportParameter", x => x.Id); table.ForeignKey( - name: "FK_PReportParameter_PReportTemplate_ReportTemplateId", - column: x => x.ReportTemplateId, + name: "FK_PReportParameter_PReportTemplate_TemplateId", + column: x => x.TemplateId, principalTable: "PReportTemplate", principalColumn: "Id", onDelete: ReferentialAction.Cascade); @@ -3993,26 +3991,20 @@ namespace Kurs.Platform.Migrations table: "PNotification", column: "NotificationRuleId"); - migrationBuilder.CreateIndex( - name: "IX_PReportCategory_Name", - table: "PReportCategory", - column: "Name", - unique: true); - migrationBuilder.CreateIndex( name: "IX_PReportGenerated_TemplateId", table: "PReportGenerated", column: "TemplateId"); migrationBuilder.CreateIndex( - name: "IX_PReportParameter_ReportTemplateId", + name: "IX_PReportParameter_TemplateId", table: "PReportParameter", - column: "ReportTemplateId"); + column: "TemplateId"); migrationBuilder.CreateIndex( - name: "IX_PReportTemplate_CategoryName", + name: "IX_PReportTemplate_CategoryId", table: "PReportTemplate", - column: "CategoryName"); + column: "CategoryId"); migrationBuilder.CreateIndex( name: "IX_PRoute_Key", diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs index d9013d5c..e566032c 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs @@ -5180,9 +5180,6 @@ namespace Kurs.Platform.Migrations b.HasKey("Id"); - b.HasIndex("Name") - .IsUnique(); - b.ToTable("PReportCategory", (string)null); }); @@ -5207,9 +5204,6 @@ namespace Kurs.Platform.Migrations .HasColumnType("datetime2") .HasColumnName("DeletionTime"); - b.Property("GeneratedAt") - .HasColumnType("datetime2"); - b.Property("GeneratedContent") .IsRequired() .HasColumnType("nvarchar(max)"); @@ -5303,12 +5297,12 @@ namespace Kurs.Platform.Migrations .HasMaxLength(200) .HasColumnType("nvarchar(200)"); - b.Property("ReportTemplateId") - .HasColumnType("uniqueidentifier"); - b.Property("Required") .HasColumnType("bit"); + b.Property("TemplateId") + .HasColumnType("uniqueidentifier"); + b.Property("TenantId") .HasColumnType("uniqueidentifier") .HasColumnName("TenantId"); @@ -5319,7 +5313,7 @@ namespace Kurs.Platform.Migrations b.HasKey("Id"); - b.HasIndex("ReportTemplateId"); + b.HasIndex("TemplateId"); b.ToTable("PReportParameter", (string)null); }); @@ -5329,9 +5323,8 @@ namespace Kurs.Platform.Migrations b.Property("Id") .HasColumnType("uniqueidentifier"); - b.Property("CategoryName") - .HasMaxLength(256) - .HasColumnType("nvarchar(256)"); + b.Property("CategoryId") + .HasColumnType("uniqueidentifier"); b.Property("CreationTime") .HasColumnType("datetime2") @@ -5386,7 +5379,7 @@ namespace Kurs.Platform.Migrations b.HasKey("Id"); - b.HasIndex("CategoryName"); + b.HasIndex("CategoryId"); b.ToTable("PReportTemplate", (string)null); }); @@ -8829,19 +8822,19 @@ namespace Kurs.Platform.Migrations modelBuilder.Entity("Kurs.Platform.Entities.ReportGenerated", b => { - b.HasOne("Kurs.Platform.Entities.ReportTemplate", "Template") - .WithMany() + b.HasOne("Kurs.Platform.Entities.ReportTemplate", "ReportTemplate") + .WithMany("Generated") .HasForeignKey("TemplateId") - .OnDelete(DeleteBehavior.SetNull); + .OnDelete(DeleteBehavior.Cascade); - b.Navigation("Template"); + b.Navigation("ReportTemplate"); }); modelBuilder.Entity("Kurs.Platform.Entities.ReportParameter", b => { b.HasOne("Kurs.Platform.Entities.ReportTemplate", "ReportTemplate") .WithMany("Parameters") - .HasForeignKey("ReportTemplateId") + .HasForeignKey("TemplateId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); @@ -8852,9 +8845,9 @@ namespace Kurs.Platform.Migrations { b.HasOne("Kurs.Platform.Entities.ReportCategory", "ReportCategory") .WithMany("ReportTemplates") - .HasForeignKey("CategoryName") - .HasPrincipalKey("Name") - .OnDelete(DeleteBehavior.SetNull); + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); b.Navigation("ReportCategory"); }); @@ -9164,6 +9157,8 @@ namespace Kurs.Platform.Migrations modelBuilder.Entity("Kurs.Platform.Entities.ReportTemplate", b => { + b.Navigation("Generated"); + b.Navigation("Parameters"); }); diff --git a/ui/src/components/reports/Dashboard.tsx b/ui/src/components/reports/Dashboard.tsx index 9ca86f98..b773a1a8 100644 --- a/ui/src/components/reports/Dashboard.tsx +++ b/ui/src/components/reports/Dashboard.tsx @@ -57,7 +57,7 @@ export const Dashboard: React.FC = () => { // Filter by category (if not "tumu-category") if (selectedCategory && selectedCategory.id !== 'tumu-category') { - filtered = filtered.filter((template) => template.categoryName === selectedCategory.name) + filtered = filtered.filter((template) => template.categoryId === selectedCategory.id) } // Filter by search query @@ -167,7 +167,7 @@ export const Dashboard: React.FC = () => { {category.id !== 'tumu-category' && ( - ({templates.filter((t) => t.categoryName === category.name).length}) + ({templates.filter((t) => t.categoryId === category.id).length}) )} {category.id === 'tumu-category' && ( @@ -283,6 +283,7 @@ export const Dashboard: React.FC = () => { { setGeneratingTemplate(null) }} template={generatingTemplate} + categories={categories} onGenerate={handleReportGeneration} /> diff --git a/ui/src/components/reports/ReportGenerator.tsx b/ui/src/components/reports/ReportGenerator.tsx index 2903aa0a..4376c940 100644 --- a/ui/src/components/reports/ReportGenerator.tsx +++ b/ui/src/components/reports/ReportGenerator.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react' import { Button, Input, Dialog } from '../ui' import { FaFileAlt } from 'react-icons/fa' -import { ReportTemplateDto } from '@/proxy/reports/models' +import { ReportCategoryDto, ReportTemplateDto } from '@/proxy/reports/models' import { useLocalization } from '@/utils/hooks/useLocalization' import { ROUTES_ENUM } from '@/routes/route.constant' @@ -9,6 +9,7 @@ interface ReportGeneratorProps { isOpen: boolean onClose: () => void template: ReportTemplateDto | null + categories: ReportCategoryDto[] onGenerate: (templateId: string, parameters: Record) => Promise // Rapor ID'si döndürmek için (async) } @@ -16,6 +17,7 @@ export const ReportGenerator: React.FC = ({ isOpen, onClose, template, + categories, onGenerate, }) => { const [parameterValues, setParameterValues] = useState>({}) @@ -80,7 +82,7 @@ export const ReportGenerator: React.FC = ({

{template.description}

- {template.categoryName} + {categories.find((c) => c.id === template.categoryId)?.name} {template.tags.map((tag) => ( diff --git a/ui/src/components/reports/ReportViewer.tsx b/ui/src/components/reports/ReportViewer.tsx index 58183741..976aa18c 100644 --- a/ui/src/components/reports/ReportViewer.tsx +++ b/ui/src/components/reports/ReportViewer.tsx @@ -23,7 +23,7 @@ export const ReportViewer: React.FC = () => { const [isLoading, setIsLoading] = useState(true) const [error, setError] = useState(null) const { translate } = useLocalization() - const { getReportById, getTemplateById } = useReports() + const { getReportById, getTemplateById, categories } = useReports() // İçeriği sayfalara bölen fonksiyon const splitContentIntoPages = (content: string) => { @@ -254,7 +254,7 @@ export const ReportViewer: React.FC = () => { } pdf.save( - `${report!.templateName}_${new Date(report!.generatedAt).toLocaleDateString('tr-TR')}.pdf`, + `${report!.templateName}_${new Date(report!.creationTime).toLocaleDateString('tr-TR')}.pdf`, ) } catch (error) { console.error('PDF oluşturma hatası:', error) @@ -274,7 +274,7 @@ export const ReportViewer: React.FC = () => {
- {new Date(report.generatedAt).toLocaleDateString('tr-TR', { + {new Date(report.creationTime).toLocaleDateString('tr-TR', { year: 'numeric', month: 'long', day: 'numeric', @@ -285,7 +285,7 @@ export const ReportViewer: React.FC = () => { {template && ( - {template.categoryName} + {categories.find((c) => c.id === template.categoryId)?.name} )}
diff --git a/ui/src/components/reports/TemplateCard.tsx b/ui/src/components/reports/TemplateCard.tsx index 8924e12c..5eb54358 100644 --- a/ui/src/components/reports/TemplateCard.tsx +++ b/ui/src/components/reports/TemplateCard.tsx @@ -1,11 +1,12 @@ import React from 'react' import { Button } from '../ui/Button' -import { FaFileAlt, FaEdit, FaTrash, FaPlay } from 'react-icons/fa'; -import { ReportTemplateDto } from '@/proxy/reports/models' -import { useLocalization } from '@/utils/hooks/useLocalization'; +import { FaFileAlt, FaEdit, FaTrash, FaPlay } from 'react-icons/fa' +import { ReportCategoryDto, ReportTemplateDto } from '@/proxy/reports/models' +import { useLocalization } from '@/utils/hooks/useLocalization' interface TemplateCardProps { template: ReportTemplateDto + categories: ReportCategoryDto[] onEdit: (template: ReportTemplateDto) => void onDelete: (id: string) => void onGenerate: (template: ReportTemplateDto) => void @@ -13,6 +14,7 @@ interface TemplateCardProps { export const TemplateCard: React.FC = ({ template, + categories, onEdit, onDelete, onGenerate, @@ -31,14 +33,16 @@ export const TemplateCard: React.FC = ({
- {template.parameters.length} + + {template.parameters.length} +
{/* Tags section with proper wrapping */}
- {template.categoryName} + {categories.find((c) => c.id === template.categoryId)?.name} {template.tags.slice(0, 2).map((tag) => ( = ({ {/* Footer with date and actions */}
-

{new Date(template.lastModificationTime || template.creationTime).toLocaleString('tr-TR', { - day: '2-digit', - month: '2-digit', - year: 'numeric', - hour: '2-digit', - minute: '2-digit' - })}

+

+ {new Date(template.lastModificationTime || template.creationTime).toLocaleString( + 'tr-TR', + { + day: '2-digit', + month: '2-digit', + year: 'numeric', + hour: '2-digit', + minute: '2-digit', + }, + )} +

diff --git a/ui/src/components/reports/TemplateEditor.tsx b/ui/src/components/reports/TemplateEditor.tsx index 1b57a2f7..0b8dc138 100644 --- a/ui/src/components/reports/TemplateEditor.tsx +++ b/ui/src/components/reports/TemplateEditor.tsx @@ -25,7 +25,7 @@ export const TemplateEditor: React.FC = ({ name: '', description: '', htmlContent: '', - categoryName: 'Genel Raporlar', + categoryId: '', tags: [] as string[], parameters: [] as ReportParameterDto[], }) @@ -34,13 +34,23 @@ export const TemplateEditor: React.FC = ({ const [tagInput, setTagInput] = useState('') const [isSaving, setIsSaving] = useState(false) + // Debug kategorileri + useEffect(() => { + console.log('Categories received:', categories) + }, [categories]) + + // Debug form data değişimini takip et + useEffect(() => { + console.log('FormData changed:', formData) + }, [formData]) + useEffect(() => { if (template) { setFormData({ name: template.name, description: template.description || '', htmlContent: template.htmlContent, - categoryName: template.categoryName!, + categoryId: template.categoryId!, tags: template.tags, parameters: template.parameters, }) @@ -49,7 +59,7 @@ export const TemplateEditor: React.FC = ({ name: '', description: '', htmlContent: '', - categoryName: 'Genel Raporlar', + categoryId: '', tags: [], parameters: [], }) @@ -74,7 +84,7 @@ export const TemplateEditor: React.FC = ({ // Yeni parametre oluştur return { id: crypto.randomUUID(), - reportTemplateId: template?.id || '', + templateId: template?.id || '', name: paramName, placeholder: `@@${paramName}`, type: 'text', @@ -99,6 +109,9 @@ export const TemplateEditor: React.FC = ({ return } + console.log('FormData before save:', formData) + console.log('Categories available:', categories) + setIsSaving(true) try { await onSave(formData as unknown as ReportTemplateDto) @@ -213,17 +226,21 @@ export const TemplateEditor: React.FC = ({ {translate('::App.Reports.TemplateEditor.Label.Category')}