Compare commits

..

33 commits
1.1.06 ... main

Author SHA1 Message Date
Sedat Öztürk
ab6a33c340 Wizard Problemleri Giderildi 2026-07-17 23:23:43 +03:00
Sedat ÖZTÜRK
319afbcb13 npx eslint src --quiet hatalar kontrol edildi 2026-07-17 12:47:00 +03:00
Sedat ÖZTÜRK
b87d7a94c8 EditingFormItemDto kaldırıldı. Yerine tüm sütunlar ColumnFormatDto eklendi 2026-07-17 11:59:51 +03:00
Sedat ÖZTÜRK
95b0b0ce89 Genel güncellemeler 2026-07-16 17:20:25 +03:00
Sedat ÖZTÜRK
24e92fcb82 Todo komponenti 2026-07-16 17:01:18 +03:00
Sedat ÖZTÜRK
412ad236cc CardView komponenti 2026-07-16 11:19:17 +03:00
Sedat ÖZTÜRK
d38e4f851a HostData düzenelemsi 2026-07-16 08:49:30 +03:00
Sedat Öztürk
6174253a40 Lisans bilgileri takip ekranı 2026-07-14 23:25:04 +03:00
Sedat ÖZTÜRK
248af7ca1a Licence 2026-07-14 17:54:50 +03:00
Sedat ÖZTÜRK
535ed6835f Check for Updates 2026-07-14 17:16:08 +03:00
Sedat ÖZTÜRK
4805e8c4d9 Check New Version eklendi 2026-07-14 16:43:05 +03:00
Sedat ÖZTÜRK
28ec641275 Update new version checking and Report Categories 2026-07-14 10:37:13 +03:00
Sedat Öztürk
1d05d24e41 Form içerisindeki Workflow custom butonlar 2026-07-13 20:29:53 +03:00
Sedat ÖZTÜRK
b53a4243ab AiBot Tenantlı ve MenuManager düzenlendi 2026-07-13 16:51:13 +03:00
Sedat ÖZTÜRK
50cb3eaf97 Forum güncellemeleri 2026-07-13 15:28:23 +03:00
Sedat ÖZTÜRK
0ff184fcdf Codex 5.6 Sol Genel Optimizasyon 2026-07-13 11:39:13 +03:00
Sedat Öztürk
e7be51a1be Codex 5.6 Sol Genel Optimizasyon 2026-07-11 23:35:32 +03:00
Sedat ÖZTÜRK
351eddfc0a Kullanılmayan değişkenler hata olarak görünmüyor.
"noUnusedLocals": false,
"noUnusedParameters": false,
2026-07-10 12:27:30 +03:00
Sedat ÖZTÜRK
7051a84b4b Optimizasyon güncellemeleri 2026-07-10 12:22:54 +03:00
Sedat ÖZTÜRK
d982a3ce42 Genel hata kontrolü ve düzenlemeler
npx tsc --noEmit --pretty false
dotnet build --no-restore --nologo --verbosity quiet
2026-07-10 11:18:20 +03:00
Sedat Öztürk
7f7c6fab36 localStorage kaldırıldı, herşey [EasyPeasyStore][0] taşındı 2026-07-09 20:55:07 +03:00
Sedat ÖZTÜRK
904f8ed447 Select komponenti dark mod 2026-07-08 16:32:55 +03:00
Sedat ÖZTÜRK
9cd49f3f66 bottom-end 2026-07-08 15:34:13 +03:00
Sedat ÖZTÜRK
f4d2be65e5 Workflow problemleri giderildi. 2026-07-08 14:53:23 +03:00
Sedat ÖZTÜRK
17e4716ee8 Grid Approval birden fazla kişi seçilebilir. 2026-07-08 10:29:45 +03:00
Sedat ÖZTÜRK
04e88fc969 bottom-end 2026-07-08 09:14:40 +03:00
Sedat Öztürk
3953498b8d Sales Order Mail Tasarımı 2026-07-08 00:13:31 +03:00
Sedat Öztürk
cda9aa6a72 District içerisine Postal Code eklendi. 2026-07-08 00:00:35 +03:00
Sedat Öztürk
c42a8d2bd1 Sales Order üzerinden Otomatik Tenant tanımlama 2026-07-07 22:14:26 +03:00
Sedat Öztürk
6dae9c4e94 IsNotAllowed_BranchLimit 2026-07-07 21:19:37 +03:00
Sedat ÖZTÜRK
4ae697600b SetMaxConcurrentUsers yapısı değiştirildi. 2026-07-07 17:51:33 +03:00
Sedat ÖZTÜRK
4fd22fe682 Sales Order güncellemeleri 2026-07-07 16:41:07 +03:00
Sedat Öztürk
5c9c99206c Yeni Müşteri ve Eski Müşteri Sipariş ayrımı 2026-07-07 00:53:45 +03:00
333 changed files with 24313 additions and 11282 deletions

View file

@ -107,9 +107,31 @@ public partial class LanguageTextCreateUpdateDtoToLanguageTextMapper : MapperBas
public partial class LanguageKeyToLanguageTextTranslatedDtoMapper : MapperBase<LanguageKey, LanguageTextTranslatedDto> public partial class LanguageKeyToLanguageTextTranslatedDtoMapper : MapperBase<LanguageKey, LanguageTextTranslatedDto>
{ {
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.Id))] [MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.Id))]
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.BaseCultureName))]
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.BaseValue))]
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.TargetCultureName))]
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.TargetValue))]
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.IsDeleted))]
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.DeleterId))]
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.DeletionTime))]
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.LastModificationTime))]
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.LastModifierId))]
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.CreationTime))]
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.CreatorId))]
public override partial LanguageTextTranslatedDto Map(LanguageKey source); public override partial LanguageTextTranslatedDto Map(LanguageKey source);
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.Id))] [MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.Id))]
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.BaseCultureName))]
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.BaseValue))]
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.TargetCultureName))]
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.TargetValue))]
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.IsDeleted))]
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.DeleterId))]
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.DeletionTime))]
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.LastModificationTime))]
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.LastModifierId))]
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.CreationTime))]
[MapperIgnoreTarget(nameof(LanguageTextTranslatedDto.CreatorId))]
public override partial void Map(LanguageKey source, LanguageTextTranslatedDto destination); public override partial void Map(LanguageKey source, LanguageTextTranslatedDto destination);
public override void BeforeMap(LanguageKey source) public override void BeforeMap(LanguageKey source)

View file

@ -153,6 +153,32 @@ public class NotificationAppService : ReadOnlyAppService<
return ObjectMapper.Map<Notification, NotificationDto>(item); return ObjectMapper.Map<Notification, NotificationDto>(item);
} }
public async Task<int> UpdateReadManyAsync(List<Guid> notificationIds, bool isRead)
{
if (notificationIds.Count == 0)
{
return 0;
}
var query = await repository.GetQueryableAsync();
return await query
.Where(a => a.UserId == CurrentUser.Id && notificationIds.Contains(a.Id) && a.IsRead != isRead)
.ExecuteUpdateAsync(setters => setters.SetProperty(a => a.IsRead, isRead));
}
public async Task<int> UpdateSentManyAsync(List<Guid> notificationIds, bool isSent)
{
if (notificationIds.Count == 0)
{
return 0;
}
var query = await repository.GetQueryableAsync();
return await query
.Where(a => a.UserId == CurrentUser.Id && notificationIds.Contains(a.Id) && a.IsSent != isSent)
.ExecuteUpdateAsync(setters => setters.SetProperty(a => a.IsSent, isSent));
}
[RemoteService(false)] [RemoteService(false)]
public override Task<NotificationDto> GetAsync(Guid id) => throw new NotImplementedException(); public override Task<NotificationDto> GetAsync(Guid id) => throw new NotImplementedException();
[RemoteService(false)] [RemoteService(false)]

View file

@ -5,6 +5,7 @@ using Sozsoft.Settings.Localization;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using Volo.Abp.Localization; using Volo.Abp.Localization;
using Volo.Abp.Settings; using Volo.Abp.Settings;
using Volo.Abp.Threading;
using SettingDefinition = Sozsoft.Settings.Entities.SettingDefinition; using SettingDefinition = Sozsoft.Settings.Entities.SettingDefinition;
namespace Sozsoft.Settings; namespace Sozsoft.Settings;
@ -22,8 +23,7 @@ public class SettingsDefinitionProvider : SettingDefinitionProvider
public override void Define(ISettingDefinitionContext context) public override void Define(ISettingDefinitionContext context)
{ {
repository.DisableTracking(); repository.DisableTracking();
var settingDefinitions = repository.GetListAsync().Result; var settingDefinitions = AsyncHelper.RunSync(() => repository.GetListAsync());
//var settingDefinitions = AsyncHelper.RunSync(() => repository.ToListAsync());
foreach (var item in settingDefinitions.OrderBy(a => a.Order)) foreach (var item in settingDefinitions.OrderBy(a => a.Order))
{ {

View file

@ -1,4 +1,5 @@
using System; using System;
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
namespace Sozsoft.Platform.DeveloperKit; namespace Sozsoft.Platform.DeveloperKit;
@ -6,6 +7,7 @@ namespace Sozsoft.Platform.DeveloperKit;
public class CustomComponentDto : FullAuditedEntityDto<Guid> public class CustomComponentDto : FullAuditedEntityDto<Guid>
{ {
public string Name { get; set; } = string.Empty; public string Name { get; set; } = string.Empty;
public string RoutePath { get; set; } = string.Empty;
public string Code { get; set; } = string.Empty; public string Code { get; set; } = string.Empty;
public string? Props { get; set; } public string? Props { get; set; }
public string? Description { get; set; } public string? Description { get; set; }
@ -16,6 +18,10 @@ public class CustomComponentDto : FullAuditedEntityDto<Guid>
public class CreateUpdateCustomComponentDto public class CreateUpdateCustomComponentDto
{ {
public string Name { get; set; } = string.Empty; public string Name { get; set; } = string.Empty;
[Required]
[StringLength(512)]
[RegularExpression(@"^/.*", ErrorMessage = "RoutePath must start with '/'.")]
public string RoutePath { get; set; } = string.Empty;
public string Code { get; set; } = string.Empty; public string Code { get; set; } = string.Empty;
public string? Props { get; set; } public string? Props { get; set; }
public string? Description { get; set; } public string? Description { get; set; }

View file

@ -93,6 +93,10 @@ public class ForumTopicDto : FullAuditedEntityDto<Guid>
public Guid CategoryId { get; set; } public Guid CategoryId { get; set; }
public Guid AuthorId { get; set; } public Guid AuthorId { get; set; }
public string AuthorName { get; set; } public string AuthorName { get; set; }
public string AuthorTitle { get; set; }
public string AuthorEmail { get; set; }
public string AuthorPhoneNumber { get; set; }
public string AuthorDepartment { get; set; }
public int ViewCount { get; set; } public int ViewCount { get; set; }
public int ReplyCount { get; set; } public int ReplyCount { get; set; }
public int LikeCount { get; set; } public int LikeCount { get; set; }
@ -155,6 +159,10 @@ public class ForumPostDto : FullAuditedEntityDto<Guid>
public string Content { get; set; } public string Content { get; set; }
public Guid AuthorId { get; set; } public Guid AuthorId { get; set; }
public string AuthorName { get; set; } public string AuthorName { get; set; }
public string AuthorTitle { get; set; }
public string AuthorEmail { get; set; }
public string AuthorPhoneNumber { get; set; }
public string AuthorDepartment { get; set; }
public int LikeCount { get; set; } public int LikeCount { get; set; }
public bool IsAcceptedAnswer { get; set; } public bool IsAcceptedAnswer { get; set; }

View file

@ -10,6 +10,11 @@ namespace Sozsoft.Platform.ListForms;
public class ColumnFormatDto : AuditedEntityDto<Guid> public class ColumnFormatDto : AuditedEntityDto<Guid>
{ {
private static readonly JsonSerializerOptions EditorOptionsSerializerOptions = new()
{
PropertyNameCaseInsensitive = true
};
public ColumnFormatDto() { } public ColumnFormatDto() { }
public string FieldName { get; set; } public string FieldName { get; set; }
@ -239,7 +244,42 @@ public class ColumnFormatDto : AuditedEntityDto<Guid>
} }
public string Alignment { get; set; } public string Alignment { get; set; }
public string Format { get; set; } public string Format { get; set; }
public string EditorOptions { get; set; }
public int? EditOrderNo { get; set; }
public int? EditGroupOrderNo { get; set; }
public string EditorType2 { get; set; }
public int? ColSpan { get; set; }
public string EditorOptions { get; set; }
public GridBoxOptionsDto GridBoxOptions =>
DeserializeEditorOptions<GridBoxOptionsDto>(PlatformConsts.EditorTypes.dxGridBox);
public TagBoxOptionsDto TagBoxOptions =>
DeserializeEditorOptions<TagBoxOptionsDto>(PlatformConsts.EditorTypes.dxTagBox);
public ImageUploadOptionsDto ImageUploadOptions =>
DeserializeEditorOptions<ImageUploadOptionsDto>(
PlatformConsts.EditorTypes.dxImageUpload,
PlatformConsts.EditorTypes.dxImageViewer);
public string EditorScript { get; set; }
private T DeserializeEditorOptions<T>(params string[] editorTypes) where T : class
{
if (!Array.Exists(
editorTypes,
editorType => string.Equals(EditorType2, editorType, StringComparison.OrdinalIgnoreCase)) ||
string.IsNullOrWhiteSpace(EditorOptions))
{
return null;
}
try
{
return JsonSerializer.Deserialize<T>(EditorOptions, EditorOptionsSerializerOptions);
}
catch (JsonException)
{
return null;
}
}
} }

View file

@ -0,0 +1,10 @@
using System;
namespace Sozsoft.Platform.ListForms.DynamicApi;
public class CreateTenantFromOrderInput
{
public Guid OrderId { get; set; }
public string Name { get; set; }
public string MenuGroup { get; set; }
}

View file

@ -28,6 +28,5 @@ public class CreateUpdateTenantInput
public string Email { get; set; } public string Email { get; set; }
public string Website { get; set; } public string Website { get; set; }
public string MenuGroup { get; set; } public string MenuGroup { get; set; }
public int MaxConcurrentUsers { get; set; }
} }

View file

@ -1,4 +1,4 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Sozsoft.Platform.ListForms.DynamicApi; namespace Sozsoft.Platform.ListForms.DynamicApi;
@ -12,5 +12,5 @@ public interface IListFormDynamicApiAppService
Task PostTenantInsertAsync(DynamicApiBaseInput<CreateUpdateTenantInput> input); Task PostTenantInsertAsync(DynamicApiBaseInput<CreateUpdateTenantInput> input);
Task PostTenantUpdateAsync(DynamicApiBaseInput<CreateUpdateTenantInput> input); Task PostTenantUpdateAsync(DynamicApiBaseInput<CreateUpdateTenantInput> input);
Task PostTenantDeleteAsync(DynamicApiBaseInput<string> input); Task PostTenantDeleteAsync(DynamicApiBaseInput<string> input);
Task<Guid> PostCreateTenantFromOrderAsync(DynamicApiBaseInput<CreateTenantFromOrderInput> input);
} }

View file

@ -16,35 +16,5 @@ public class EditingFormDto
public string Caption { get; set; } public string Caption { get; set; }
public int ColCount { get; set; } = 2; public int ColCount { get; set; } = 2;
public int ColSpan { get; set; } = 2; public int ColSpan { get; set; } = 2;
/// <summary> Type: Array<Simple Form Item | Group Form Item | Tabbed Form Item | Empty Form Item | Button Form Item>
/// Bu kisma suan sadece string olarak doldurulacak
/// items: ['FirstName', 'LastName',
/// { dataField: 'Notes', editorType: 'dxTextArea', colSpan: 2, editorOptions: { height: 100, }, }
/// ],
/// </summary>
//[TextArea]
//public string[] Items { get; set; }
public EditingFormItemDto[] Items { get; set; }
}
public class EditingFormItemDto
{
/// <summary>
/// DataField Accepted Values: 'dxAutocomplete' | 'dxCalendar' | 'dxCheckBox' | 'dxColorBox' | 'dxDateBox' | 'dxDateRangeBox' | 'dxDropDownBox' | 'dxHtmlEditor' | 'dxLookup' | 'dxNumberBox' | 'dxRadioGroup' | 'dxRangeSlider' | 'dxSelectBox' | 'dxSlider' | 'dxSwitch' | 'dxTagBox' | 'dxTextArea' | 'dxTextBox' | 'dxImageViewer' | 'dxImageUpload';
/// </summary>
[JsonPropertyName("order")]
public int Order { get; set; }
[JsonPropertyName("dataField")]
public string DataField { get; set; }
[JsonPropertyName("editorType2")]
public string EditorType2 { get; set; }
[JsonPropertyName("colSpan")]
public int ColSpan { get; set; }
[JsonPropertyName("editorOptions")]
public string EditorOptions { get; set; }
public GridBoxOptionsDto GridBoxOptions { get; set; }
public TagBoxOptionsDto TagBoxOptions { get; set; }
[JsonPropertyName("editorScript")]
public string EditorScript { get; set; }
} }

View file

@ -190,6 +190,19 @@ public class GridOptionsDto : AuditedEntityDto<Guid>
set { SchedulerOptionJson = JsonSerializer.Serialize(value); } set { SchedulerOptionJson = JsonSerializer.Serialize(value); }
} }
[JsonIgnore]
public string TodoOptionJson { get; set; }
public TodoOptionDto TodoOptionDto
{
get
{
if (!string.IsNullOrEmpty(TodoOptionJson))
return JsonSerializer.Deserialize<TodoOptionDto>(TodoOptionJson);
return new TodoOptionDto();
}
set { TodoOptionJson = JsonSerializer.Serialize(value); }
}
[JsonIgnore] [JsonIgnore]
public string PagerOptionJson { get; set; } public string PagerOptionJson { get; set; }
public GridPagerOptionDto PagerOptionDto public GridPagerOptionDto PagerOptionDto

View file

@ -0,0 +1,11 @@
namespace Sozsoft.Platform.ListForms;
public class ImageUploadOptionsDto
{
public string UploadUrl { get; set; }
public string Accept { get; set; }
public bool? Multiple { get; set; }
public long? MaxFileSize { get; set; }
public int? Width { get; set; }
public int? Height { get; set; }
}

View file

@ -3,11 +3,13 @@
public class LayoutDto public class LayoutDto
{ {
public bool Grid { get; set; } = true; public bool Grid { get; set; } = true;
public bool Card { get; set; } = true;
public bool Pivot { get; set; } = true; public bool Pivot { get; set; } = true;
public bool Chart { get; set; } = true; public bool Chart { get; set; } = true;
public bool Tree { get; set; } = true; public bool Tree { get; set; } = true;
public bool Gantt { get; set; } = true; public bool Gantt { get; set; } = true;
public bool Scheduler { get; set; } = true; public bool Scheduler { get; set; } = true;
public bool Todo { get; set; } = false;
public string DefaultLayout { get; set; } = "grid"; public string DefaultLayout { get; set; } = "grid";
} }

View file

@ -0,0 +1,20 @@
namespace Sozsoft.Platform.ListForms;
/// <summary>
/// Dinamik bir listeyi Todo/Kanban panosu olarak gostermek icin alan eslemeleri.
/// TitleExpr ve StatusExpr zorunlu, diger alanlar opsiyoneldir.
/// </summary>
public class TodoOptionDto
{
public string TitleExpr { get; set; }
public string StatusExpr { get; set; }
public string DescriptionExpr { get; set; }
public string DueDateExpr { get; set; }
public string TagExpr { get; set; }
public string AssigneeExpr { get; set; }
public string PriorityExpr { get; set; }
public string CompletedExpr { get; set; }
public string OrderExpr { get; set; }
public string StatusOrder { get; set; }
public bool AllowDragging { get; set; } = true;
}

View file

@ -5,10 +5,10 @@ namespace Sozsoft.Platform.ListForms;
public class WorkflowDto public class WorkflowDto
{ {
public string ApprovalUserFieldName { get; set; } public string ApprovalUserFieldName { get; set; }
public bool IsFilterUserName { get; set; }
public string ApprovalDateFieldName { get; set; } public string ApprovalDateFieldName { get; set; }
public string ApprovalStatusFieldName { get; set; } public string ApprovalStatusFieldName { get; set; }
public string ApprovalDescriptionFieldName { get; set; } public string ApprovalDescriptionFieldName { get; set; }
public bool ApprovalIsFilterUserName { get; set; }
public List<ListFormWorkflowCriteriaDto> Criteria { get; set; } = []; public List<ListFormWorkflowCriteriaDto> Criteria { get; set; } = [];
} }

View file

@ -49,6 +49,7 @@ public class ListFormEditTabs
public const string TreeForm = "tree"; public const string TreeForm = "tree";
public const string GanttForm = "gantt"; public const string GanttForm = "gantt";
public const string SchedulerForm = "scheduler"; public const string SchedulerForm = "scheduler";
public const string TodoForm = "todo";
public const string PagerForm = "pager"; public const string PagerForm = "pager";
public const string StateForm = "state"; public const string StateForm = "state";
public const string SubFormJsonRow = "subForm"; public const string SubFormJsonRow = "subForm";

View file

@ -22,11 +22,13 @@ public class ListFormWizardDto
public string DefaultLayout { get; set; } public string DefaultLayout { get; set; }
public bool Grid { get; set; } public bool Grid { get; set; }
public bool Card { get; set; }
public bool Pivot { get; set; } public bool Pivot { get; set; }
public bool Tree { get; set; } public bool Tree { get; set; }
public bool Chart { get; set; } public bool Chart { get; set; }
public bool Gantt { get; set; } public bool Gantt { get; set; }
public bool Scheduler { get; set; } public bool Scheduler { get; set; }
public bool Todo { get; set; }
public string LanguageTextMenuEn { get; set; } public string LanguageTextMenuEn { get; set; }
public string LanguageTextMenuTr { get; set; } public string LanguageTextMenuTr { get; set; }
@ -39,6 +41,7 @@ public class ListFormWizardDto
public string PermissionGroupName { get; set; } public string PermissionGroupName { get; set; }
public string MenuParentCode { get; set; } public string MenuParentCode { get; set; }
public string MenuParentShortName { get; set; }
public string MenuParentIcon { get; set; } public string MenuParentIcon { get; set; }
public string MenuIcon { get; set; } public string MenuIcon { get; set; }
public string DataSourceCode { get; set; } public string DataSourceCode { get; set; }
@ -68,9 +71,28 @@ public class ListFormWizardDto
public string SchedulerStartDateExpr { get; set; } public string SchedulerStartDateExpr { get; set; }
public string SchedulerEndDateExpr { get; set; } public string SchedulerEndDateExpr { get; set; }
// Todo options (required when DefaultLayout = "todo")
public string TodoTitleExpr { get; set; }
public string TodoStatusExpr { get; set; }
public string TodoDescriptionExpr { get; set; }
public string TodoDueDateExpr { get; set; }
public string TodoTagExpr { get; set; }
public string TodoAssigneeExpr { get; set; }
public string TodoPriorityExpr { get; set; }
public string TodoCompletedExpr { get; set; }
public string TodoOrderExpr { get; set; }
public string TodoStatusOrder { get; set; }
public bool TodoAllowDragging { get; set; } = true;
// Workflow options (required when DefaultLayout = "workflow")
public string ApprovalUserFieldName { get; set; }
public string ApprovalDateFieldName { get; set; }
public string ApprovalStatusFieldName { get; set; }
public string ApprovalDescriptionFieldName { get; set; }
public bool ApprovalIsFilterUserName { get; set; }
public List<ListFormWorkflowCriteriaDto> Criteria { get; set; } = [];
public List<WizardColumnGroupInputDto> Groups { get; set; } = new(); public List<WizardColumnGroupInputDto> Groups { get; set; } = new();
public List<SubFormDto> SubForms { get; set; } = new(); public List<SubFormDto> SubForms { get; set; } = new();
public List<WidgetEditDto> Widgets { get; set; } = new(); public List<WidgetEditDto> Widgets { get; set; } = new();
public WorkflowDto Workflow { get; set; } = new();
public List<ListFormWorkflowCriteriaDto> WorkflowCriteria { get; set; } = new();
} }

View file

@ -5,7 +5,7 @@ namespace Sozsoft.Platform.ListForms;
public class WizardColumnItemInputDto public class WizardColumnItemInputDto
{ {
public string DataField { get; set; } public string FieldName { get; set; }
public string CaptionName { get; set; } public string CaptionName { get; set; }
public string EditorType { get; set; } public string EditorType { get; set; }
public string EditorOptions { get; set; } public string EditorOptions { get; set; }

View file

@ -52,13 +52,13 @@ public static class LookupQueryValues
$"\"AbpTenants\".\"Name\" AS \"Name\" " + $"\"AbpTenants\".\"Name\" AS \"Name\" " +
$"FROM \"AbpTenants\"" + $"FROM \"AbpTenants\"" +
$") AS \"List\" " + $") AS \"List\" " +
$"ORDER BY \"Name\""; $"ORDER BY \"Name\"";
} }
else else
{ {
return $"SELECT * FROM (" + return $"SELECT * FROM (" +
$"SELECT NULL AS \"Key\", 'Host' AS \"Name\" " + // $"SELECT NULL AS \"Key\", 'Host' AS \"Name\" " +
$"UNION ALL " + // $"UNION ALL " +
$"SELECT " + $"SELECT " +
$"\"AbpTenants\".\"Id\" AS \"Key\", " + $"\"AbpTenants\".\"Id\" AS \"Key\", " +
$"\"AbpTenants\".\"Name\" AS \"Name\" " + $"\"AbpTenants\".\"Name\" AS \"Name\" " +
@ -118,14 +118,15 @@ public static class LookupQueryValues
public static string TownshipValues = public static string TownshipValues =
$"SELECT " + $"SELECT " +
$"\"Township\" AS \"Key\", " + $"\"Township\" AS \"Key\", " +
$"\"Township\" AS \"Name\" " + $"\"Township\" AS \"Name\", " +
$"\"PostalCode\" AS \"Group\" " +
$"FROM \"{FullNameTable(TableNameEnum.District)}\" " + $"FROM \"{FullNameTable(TableNameEnum.District)}\" " +
$"WHERE " + $"WHERE " +
$"(\"Country\" = @param0 OR @param0 IS NULL) " + $"(\"Country\" = @param0 OR @param0 IS NULL) " +
$"AND (\"City\" = @param1 OR @param1 IS NULL) " + $"AND (\"City\" = @param1 OR @param1 IS NULL) " +
$"AND (\"Name\" = @param2 OR @param2 IS NULL) " + $"AND (\"Name\" = @param2 OR @param2 IS NULL) " +
$"AND \"IsDeleted\" = 'false' " + $"AND \"IsDeleted\" = 'false' " +
$"GROUP BY \"Township\" " + $"GROUP BY \"Township\", \"PostalCode\" " +
$"ORDER BY \"Township\";"; $"ORDER BY \"Township\";";
public static string RoleValues = public static string RoleValues =
@ -178,11 +179,14 @@ public static class LookupQueryValues
public static string ProductValues = public static string ProductValues =
$"SELECT " + $"SELECT " +
$"\"Id\" AS \"Key\", " + $"\"{FullNameTable(TableNameEnum.Product)}\".\"Id\" AS \"Key\", " +
$"\"Name\" AS \"Name\" " + $"\"{FullNameTable(TableNameEnum.LanguageText)}\".\"Value\" AS \"Name\" " +
$"FROM \"{TableNameResolver.GetFullTableName(nameof(TableNameEnum.Product))}\" " + $"FROM \"{FullNameTable(TableNameEnum.Product)}\" " +
$"WHERE \"IsDeleted\" = 'false' " + $"LEFT OUTER JOIN \"{FullNameTable(TableNameEnum.LanguageText)}\" " +
$"ORDER BY \"Name\";"; $"ON \"{FullNameTable(TableNameEnum.Product)}\".\"Name\" = \"{FullNameTable(TableNameEnum.LanguageText)}\".\"Key\" " +
$"WHERE \"{FullNameTable(TableNameEnum.Product)}\".\"IsDeleted\" = 'false' " +
$"AND \"{FullNameTable(TableNameEnum.LanguageText)}\".\"CultureName\" = 'tr' " +
$"ORDER BY \"{FullNameTable(TableNameEnum.LanguageText)}\".\"Value\";";
public static string MenuCodeValues = public static string MenuCodeValues =
$"SELECT " + $"SELECT " +
@ -258,7 +262,7 @@ public static class LookupQueryValues
$"OR jp.\"ParentId\" IS NULL " + $"OR jp.\"ParentId\" IS NULL " +
$") " + $") " +
$"ORDER BY jp.\"Name\";"; $"ORDER BY jp.\"Name\";";
public static string SurveyQuestionValues = public static string SurveyQuestionValues =
$"SELECT " + $"SELECT " +
$"\"Id\" AS \"Key\", " + $"\"Id\" AS \"Key\", " +

View file

@ -9,6 +9,9 @@ public class CountryDto : AuditedEntityDto<string>
public string GroupName { get; set; } public string GroupName { get; set; }
public string Currency { get; set; } public string Currency { get; set; }
public int PhoneCode { get; set; } public int PhoneCode { get; set; }
public int? PhoneNumberMinLength { get; set; }
public int? PhoneNumberMaxLength { get; set; }
public string? PhoneNumberFormat { get; set; }
public string TaxLabel { get; set; } public string TaxLabel { get; set; }
public bool ZipRequired { get; set; } public bool ZipRequired { get; set; }
public bool StateRequired { get; set; } public bool StateRequired { get; set; }

View file

@ -9,4 +9,5 @@ public class DistrictDto : AuditedEntityDto<Guid>
public string City { get; set; } public string City { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string Township { get; set; } public string Township { get; set; }
public string PostalCode { get; set; }
} }

View file

@ -8,10 +8,17 @@ namespace Sozsoft.Platform.Public;
public class OrderDto : EntityDto<Guid> public class OrderDto : EntityDto<Guid>
{ {
public CustomTenantDto Tenant { get; set; } public CustomTenantDto Tenant { get; set; }
public List<OrderItemDto> Items { get; set; } public List<OrderItemDto> Items { get; set; }
public bool IsExisting { get; set; }
public string BillingCycle { get; set; }
public int Period { get; set; }
public DateTime? LicenseStartTime { get; set; }
public DateTime? LicenseEndTime { get; set; }
public decimal Subtotal { get; set; } public decimal Subtotal { get; set; }
public decimal VatTotal { get; set; }
public decimal Commission { get; set; } public decimal Commission { get; set; }
public decimal Total { get; set; } public decimal Total { get; set; }

View file

@ -8,6 +8,8 @@ public class OrderItemDto
public ProductDto Product { get; set; } public ProductDto Product { get; set; }
public string BillingCycle { get; set; } // monthly | yearly public string BillingCycle { get; set; } // monthly | yearly
public int Quantity { get; set; } public int Quantity { get; set; }
public decimal VatRate { get; set; }
public decimal VatAmount { get; set; }
public decimal TotalPrice { get; set; } public decimal TotalPrice { get; set; }
} }

View file

@ -13,6 +13,7 @@ public class ProductDto : EntityDto<Guid>
public int Order { get; set; } public int Order { get; set; }
public decimal? MonthlyPrice { get; set; } public decimal? MonthlyPrice { get; set; }
public decimal? YearlyPrice { get; set; } public decimal? YearlyPrice { get; set; }
public decimal VatRate { get; set; }
public bool IsQuantityBased { get; set; } public bool IsQuantityBased { get; set; }
public string ImageUrl { get; set; } public string ImageUrl { get; set; }
public string Unit => public string Unit =>

View file

@ -4,10 +4,8 @@ namespace Sozsoft.Platform.Tenants;
public class CustomTenantDto public class CustomTenantDto
{ {
public string Name { get; set; }
public bool IsActive { get; set; }
public Guid? Id { get; set; } public Guid? Id { get; set; }
public string Name { get; set; }
public string OrganizationName { get; set; } public string OrganizationName { get; set; }
public string Founder { get; set; } public string Founder { get; set; }
public long? VknTckn { get; set; } public long? VknTckn { get; set; }
@ -19,11 +17,12 @@ public class CustomTenantDto
public string Address1 { get; set; } public string Address1 { get; set; }
public string Address2 { get; set; } public string Address2 { get; set; }
public string PostalCode { get; set; } public string PostalCode { get; set; }
public string MobileNumber { get; set; }
public string PhoneNumber { get; set; } public string PhoneNumber { get; set; }
public string MobileNumber { get; set; }
public string FaxNumber { get; set; } public string FaxNumber { get; set; }
public string Email { get; set; } public string Email { get; set; }
public string Website { get; set; } public string Website { get; set; }
public string MenuGroup { get; set; } public string MenuGroup { get; set; }
public string Reference { get; set; }
} }

View file

@ -6,6 +6,7 @@ using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Linq; using System.Linq;
using System.Collections.Generic;
namespace Sozsoft.Platform.AiBots; namespace Sozsoft.Platform.AiBots;
@ -25,16 +26,31 @@ public class AiBotAppService : CrudAppService<
{ {
await CheckGetListPolicyAsync(); await CheckGetListPolicyAsync();
var query = await CreateFilteredQueryAsync(input);
if (CurrentTenant.IsAvailable && !string.IsNullOrWhiteSpace(CurrentTenant.Name)) if (CurrentTenant.IsAvailable && !string.IsNullOrWhiteSpace(CurrentTenant.Name))
{ {
var tenantName = CurrentTenant.Name; var tenantName = CurrentTenant.Name;
query = query.Where(aiBot => List<AiBot> tenantEntities;
string.IsNullOrWhiteSpace(aiBot.Tenants) ||
aiBot.Tenants.Contains($"\"{tenantName}\"")); using (CurrentTenant.Change(null))
{
var hostQuery = await CreateFilteredQueryAsync(input);
tenantEntities = await AsyncExecuter.ToListAsync(hostQuery);
}
var filteredQuery = tenantEntities
.Where(aiBot => IsAvailableForTenant(aiBot.Tenants, tenantName))
.AsQueryable();
var tenantTotalCount = filteredQuery.LongCount();
filteredQuery = ApplySorting(filteredQuery, input);
filteredQuery = ApplyPaging(filteredQuery, input);
var tenantDtos = await MapToGetListOutputDtosAsync(filteredQuery.ToList());
return new PagedResultDto<AiBotDto>(tenantTotalCount, tenantDtos);
} }
var query = await CreateFilteredQueryAsync(input);
var totalCount = await AsyncExecuter.CountAsync(query); var totalCount = await AsyncExecuter.CountAsync(query);
query = ApplySorting(query, input); query = ApplySorting(query, input);
query = ApplyPaging(query, input); query = ApplyPaging(query, input);
@ -44,5 +60,17 @@ public class AiBotAppService : CrudAppService<
return new PagedResultDto<AiBotDto>(totalCount, dtos); return new PagedResultDto<AiBotDto>(totalCount, dtos);
} }
private static bool IsAvailableForTenant(string tenants, string tenantName)
{
if (string.IsNullOrWhiteSpace(tenants))
{
return true;
}
return tenants
.Split('|', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.Any(name => string.Equals(name, tenantName, StringComparison.OrdinalIgnoreCase));
}
} }

View file

@ -100,13 +100,11 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
private string EncodePathAsId(string path) private string EncodePathAsId(string path)
{ {
// Path'deki '/' karakterlerini '|' ile değiştir URL-safe hale getirmek için
return path.Replace("/", "|"); return path.Replace("/", "|");
} }
private string DecodeIdAsPath(string id) private string DecodeIdAsPath(string id)
{ {
// ID'deki '|' karakterlerini '/' ile geri değiştir
return id.Replace("|", "/"); return id.Replace("|", "/");
} }

View file

@ -3,6 +3,9 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
using Sozsoft.Platform.Entities;
using Sozsoft.Platform.Extensions;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Authorization; using Volo.Abp.Authorization;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
@ -19,19 +22,24 @@ public class ForumAppService : PlatformAppService, IForumAppService
private readonly IRepository<ForumTopic, Guid> _topicRepository; private readonly IRepository<ForumTopic, Guid> _topicRepository;
private readonly IRepository<ForumPost, Guid> _postRepository; private readonly IRepository<ForumPost, Guid> _postRepository;
private readonly IIdentityUserRepository _identityUserRepository; private readonly IIdentityUserRepository _identityUserRepository;
private readonly IRepository<Department, Guid> _departmentRepository;
private readonly IRepository<JobPosition, Guid> _jobPositionRepository;
public ForumAppService( public ForumAppService(
IRepository<ForumCategory, Guid> categoryRepository, IRepository<ForumCategory, Guid> categoryRepository,
IRepository<ForumTopic, Guid> topicRepository, IRepository<ForumTopic, Guid> topicRepository,
IRepository<ForumPost, Guid> postRepository, IRepository<ForumPost, Guid> postRepository,
IIdentityUserRepository identityUserRepository) IIdentityUserRepository identityUserRepository,
IRepository<Department, Guid> departmentRepository,
IRepository<JobPosition, Guid> jobPositionRepository)
{ {
_categoryRepository = categoryRepository; _categoryRepository = categoryRepository;
_topicRepository = topicRepository; _topicRepository = topicRepository;
_postRepository = postRepository; _postRepository = postRepository;
_identityUserRepository = identityUserRepository; _identityUserRepository = identityUserRepository;
_departmentRepository = departmentRepository;
_jobPositionRepository = jobPositionRepository;
} }
// Search functionality // Search functionality
@ -48,7 +56,7 @@ public class ForumAppService : PlatformAppService, IForumAppService
if (string.IsNullOrWhiteSpace(input.Query)) if (string.IsNullOrWhiteSpace(input.Query))
return result; return result;
var query = input.Query.ToLower(); var query = input.Query.Trim();
// Search in categories // Search in categories
if (input.SearchInCategories) if (input.SearchInCategories)
@ -56,8 +64,8 @@ public class ForumAppService : PlatformAppService, IForumAppService
var categoryQuery = await _categoryRepository.GetQueryableAsync(); var categoryQuery = await _categoryRepository.GetQueryableAsync();
var categories = await AsyncExecuter.ToListAsync( var categories = await AsyncExecuter.ToListAsync(
categoryQuery.Where(c => c.IsActive && categoryQuery.Where(c => c.IsActive &&
(c.Name.ToLower().Contains(query) || (c.Name.Contains(query) ||
c.Description.ToLower().Contains(query))) c.Description.Contains(query)))
.Take(10) .Take(10)
); );
@ -70,9 +78,9 @@ public class ForumAppService : PlatformAppService, IForumAppService
var topicQuery = await _topicRepository.GetQueryableAsync(); var topicQuery = await _topicRepository.GetQueryableAsync();
var topics = await AsyncExecuter.ToListAsync( var topics = await AsyncExecuter.ToListAsync(
topicQuery.Where(t => topicQuery.Where(t =>
t.Title.ToLower().Contains(query) || t.Title.Contains(query) ||
t.Content.ToLower().Contains(query) || t.Content.Contains(query) ||
t.AuthorName.ToLower().Contains(query)) t.AuthorName.Contains(query))
.OrderByDescending(t => t.CreationTime) .OrderByDescending(t => t.CreationTime)
.Take(20) .Take(20)
); );
@ -86,8 +94,8 @@ public class ForumAppService : PlatformAppService, IForumAppService
var postQuery = await _postRepository.GetQueryableAsync(); var postQuery = await _postRepository.GetQueryableAsync();
var posts = await AsyncExecuter.ToListAsync( var posts = await AsyncExecuter.ToListAsync(
postQuery.Where(p => postQuery.Where(p =>
p.Content.ToLower().Contains(query) || p.Content.Contains(query) ||
p.AuthorName.ToLower().Contains(query)) p.AuthorName.Contains(query))
.OrderByDescending(p => p.CreationTime) .OrderByDescending(p => p.CreationTime)
.Take(30) .Take(30)
); );
@ -111,10 +119,10 @@ public class ForumAppService : PlatformAppService, IForumAppService
if (!string.IsNullOrWhiteSpace(input.Search)) if (!string.IsNullOrWhiteSpace(input.Search))
{ {
var search = input.Search.ToLower(); var search = input.Search.Trim();
queryable = queryable.Where(c => queryable = queryable.Where(c =>
c.Name.ToLower().Contains(search) || c.Name.Contains(search) ||
c.Description.ToLower().Contains(search)); c.Description.Contains(search));
} }
queryable = queryable.OrderBy(c => c.DisplayOrder); queryable = queryable.OrderBy(c => c.DisplayOrder);
@ -125,13 +133,34 @@ public class ForumAppService : PlatformAppService, IForumAppService
var maxResultCount = input.MaxResultCount > 0 ? input.MaxResultCount : 10; var maxResultCount = input.MaxResultCount > 0 ? input.MaxResultCount : 10;
var categories = await AsyncExecuter.ToListAsync( var categories = await AsyncExecuter.ToListAsync(
queryable.Skip(input.SkipCount).Take(input.MaxResultCount) queryable.Skip(skipCount).Take(maxResultCount)
); );
return new PagedResultDto<ForumCategoryDto>( var categoryDtos = ObjectMapper.Map<List<ForumCategory>, List<ForumCategoryDto>>(categories);
totalCount, var categoryIds = categories.Select(category => category.Id).ToList();
ObjectMapper.Map<List<ForumCategory>, List<ForumCategoryDto>>(categories) if (categoryIds.Count > 0)
); {
var topicQuery = await _topicRepository.GetQueryableAsync();
var postQuery = await _postRepository.GetQueryableAsync();
var topicCountItems = await AsyncExecuter.ToListAsync(
topicQuery.Where(topic => categoryIds.Contains(topic.CategoryId))
.GroupBy(topic => topic.CategoryId)
.Select(group => new { CategoryId = group.Key, Count = group.Count() }));
var topicCounts = topicCountItems.ToDictionary(item => item.CategoryId, item => item.Count);
var postCountItems = await AsyncExecuter.ToListAsync(
postQuery.Where(post => categoryIds.Contains(post.Topic.CategoryId))
.GroupBy(post => post.Topic.CategoryId)
.Select(group => new { CategoryId = group.Key, Count = group.Count() }));
var postCounts = postCountItems.ToDictionary(item => item.CategoryId, item => item.Count);
foreach (var category in categoryDtos)
{
category.TopicCount = topicCounts.GetValueOrDefault(category.Id);
category.PostCount = postCounts.GetValueOrDefault(category.Id);
}
}
return new PagedResultDto<ForumCategoryDto>(totalCount, categoryDtos);
} }
public async Task<ForumCategoryDto> GetCategoryAsync(Guid id) public async Task<ForumCategoryDto> GetCategoryAsync(Guid id)
@ -250,10 +279,10 @@ public class ForumAppService : PlatformAppService, IForumAppService
if (!string.IsNullOrWhiteSpace(input.Search)) if (!string.IsNullOrWhiteSpace(input.Search))
{ {
var search = input.Search.ToLower(); var search = input.Search.Trim();
queryable = queryable.Where(t => queryable = queryable.Where(t =>
t.Title.ToLower().Contains(search) || t.Title.Contains(search) ||
t.Content.ToLower().Contains(search)); t.Content.Contains(search));
} }
queryable = queryable.OrderByDescending(t => t.IsPinned) queryable = queryable.OrderByDescending(t => t.IsPinned)
@ -264,24 +293,50 @@ public class ForumAppService : PlatformAppService, IForumAppService
queryable.Skip(input.SkipCount).Take(input.MaxResultCount) queryable.Skip(input.SkipCount).Take(input.MaxResultCount)
); );
return new PagedResultDto<ForumTopicDto>( var topicDtos = ObjectMapper.Map<List<ForumTopic>, List<ForumTopicDto>>(topics);
totalCount, var topicIds = topics.Select(topic => topic.Id).ToList();
ObjectMapper.Map<List<ForumTopic>, List<ForumTopicDto>>(topics) if (topicIds.Count > 0)
); {
var postQuery = await _postRepository.GetQueryableAsync();
var replyCountItems = await AsyncExecuter.ToListAsync(
postQuery.Where(post => topicIds.Contains(post.TopicId))
.GroupBy(post => post.TopicId)
.Select(group => new { TopicId = group.Key, Count = group.Count() }));
var replyCounts = replyCountItems.ToDictionary(item => item.TopicId, item => item.Count);
foreach (var topic in topicDtos)
{
topic.ReplyCount = replyCounts.GetValueOrDefault(topic.Id);
}
}
return new PagedResultDto<ForumTopicDto>(totalCount, topicDtos);
} }
public async Task<ForumTopicDto> GetTopicAsync(Guid id) public async Task<ForumTopicDto> GetTopicAsync(Guid id)
{ {
var topic = await _topicRepository.GetAsync(id); var queryable = await _topicRepository.GetQueryableAsync();
var affectedRows = await queryable
.Where(t => t.Id == id)
.ExecuteUpdateAsync(setters =>
setters.SetProperty(t => t.ViewCount, t => t.ViewCount + 1)
);
// View count artırma işlemi arka planda yapılmalı (performans için) if (affectedRows == 0)
// Her okumada update yapmak performans sorununa neden olur
_ = Task.Run(async () =>
{ {
var t = await _topicRepository.GetAsync(id); throw new EntityNotFoundException(typeof(ForumTopic), id);
t.ViewCount++; }
await _topicRepository.UpdateAsync(t);
}); var topic = await AsyncExecuter.FirstOrDefaultAsync(
queryable
.AsNoTracking()
.Where(t => t.Id == id)
);
if (topic == null)
{
throw new EntityNotFoundException(typeof(ForumTopic), id);
}
return ObjectMapper.Map<ForumTopic, ForumTopicDto>(topic); return ObjectMapper.Map<ForumTopic, ForumTopicDto>(topic);
} }
@ -289,13 +344,32 @@ public class ForumAppService : PlatformAppService, IForumAppService
[UnitOfWork] [UnitOfWork]
public async Task<ForumTopicDto> CreateTopicAsync(CreateForumTopicDto input) public async Task<ForumTopicDto> CreateTopicAsync(CreateForumTopicDto input)
{ {
var author = await _identityUserRepository.FindAsync(CurrentUser.Id.Value)
?? throw new EntityNotFoundException(typeof(IdentityUser), CurrentUser.Id.Value);
var jobPositionId = author.GetJobPositionId();
var jobPosition = jobPositionId == Guid.Empty
? null
: await _jobPositionRepository.FindAsync(jobPositionId);
var departmentId = author.GetDepartmentId();
if (departmentId == Guid.Empty && jobPosition != null)
{
departmentId = jobPosition.DepartmentId;
}
var department = departmentId == Guid.Empty
? null
: await _departmentRepository.FindAsync(departmentId);
var topic = new ForumTopic( var topic = new ForumTopic(
GuidGenerator.Create(), GuidGenerator.Create(),
input.Title, input.Title,
input.Content, input.Content,
input.CategoryId, input.CategoryId,
CurrentUser.Id.Value, CurrentUser.Id.Value,
CurrentUser.Name, author.GetFullName(),
jobPosition?.Name ?? string.Empty,
author.Email ?? string.Empty,
author.PhoneNumber ?? string.Empty,
department?.Name ?? string.Empty,
input.TenantId input.TenantId
) )
{ {
@ -355,9 +429,6 @@ public class ForumAppService : PlatformAppService, IForumAppService
if (input.TopicId.HasValue) if (input.TopicId.HasValue)
{ {
queryable = queryable.Where(p => p.TopicId == input.TopicId.Value); queryable = queryable.Where(p => p.TopicId == input.TopicId.Value);
// Increment view count
var topic = await _topicRepository.GetAsync(input.TopicId.Value);
} }
if (input.IsAcceptedAnswer.HasValue) if (input.IsAcceptedAnswer.HasValue)
@ -367,8 +438,8 @@ public class ForumAppService : PlatformAppService, IForumAppService
if (!string.IsNullOrWhiteSpace(input.Search)) if (!string.IsNullOrWhiteSpace(input.Search))
{ {
var search = input.Search.ToLower(); var search = input.Search.Trim();
queryable = queryable.Where(p => p.Content.ToLower().Contains(search)); queryable = queryable.Where(p => p.Content.Contains(search));
} }
queryable = queryable.OrderBy(p => p.CreationTime); queryable = queryable.OrderBy(p => p.CreationTime);
@ -393,12 +464,31 @@ public class ForumAppService : PlatformAppService, IForumAppService
[UnitOfWork] [UnitOfWork]
public async Task<ForumPostDto> CreatePostAsync(CreateForumPostDto input) public async Task<ForumPostDto> CreatePostAsync(CreateForumPostDto input)
{ {
var author = await _identityUserRepository.FindAsync(CurrentUser.Id.Value)
?? throw new EntityNotFoundException(typeof(IdentityUser), CurrentUser.Id.Value);
var jobPositionId = author.GetJobPositionId();
var jobPosition = jobPositionId == Guid.Empty
? null
: await _jobPositionRepository.FindAsync(jobPositionId);
var departmentId = author.GetDepartmentId();
if (departmentId == Guid.Empty && jobPosition != null)
{
departmentId = jobPosition.DepartmentId;
}
var department = departmentId == Guid.Empty
? null
: await _departmentRepository.FindAsync(departmentId);
var post = new ForumPost( var post = new ForumPost(
GuidGenerator.Create(), GuidGenerator.Create(),
input.TopicId, input.TopicId,
input.Content, input.Content,
CurrentUser.Id.Value, CurrentUser.Id.Value,
CurrentUser.Name, author.GetFullName(),
jobPosition?.Name ?? string.Empty,
author.Email ?? string.Empty,
author.PhoneNumber ?? string.Empty,
department?.Name ?? string.Empty,
input.ParentPostId, input.ParentPostId,
input.TenantId input.TenantId
); );
@ -452,16 +542,15 @@ public class ForumAppService : PlatformAppService, IForumAppService
await _postRepository.DeleteAsync(id); await _postRepository.DeleteAsync(id);
topic.ReplyCount = Math.Max(0, topic.ReplyCount - 1); topic.ReplyCount = Math.Max(0, topic.ReplyCount - 1);
category.PostCount = Math.Max(0, category.PostCount ?? 0 - 1); category.PostCount = Math.Max(0, (category.PostCount ?? 0) - 1);
// 🔁 Last post değişti mi kontrol et // Last post değişti mi kontrol et
var latestPost = await _postRepository var postsQueryable = await _postRepository.GetQueryableAsync();
.GetQueryableAsync() var latestPost = await AsyncExecuter.FirstOrDefaultAsync(
.ContinueWith(q => q.Result postsQueryable
.Where(p => p.TopicId == topic.Id) .Where(p => p.TopicId == topic.Id)
.OrderByDescending(p => p.CreationTime) .OrderByDescending(p => p.CreationTime)
.FirstOrDefault() );
);
if (latestPost != null) if (latestPost != null)
{ {

View file

@ -1,4 +1,5 @@
using Sozsoft.Platform.Identity.Dto; using Sozsoft.Platform.Identity.Dto;
using Sozsoft.Platform.Extensions;
using Sozsoft.Platform.OrganizationUnits; using Sozsoft.Platform.OrganizationUnits;
using Sozsoft.Platform.Tenants; using Sozsoft.Platform.Tenants;
using Volo.Abp.Identity; using Volo.Abp.Identity;
@ -76,8 +77,44 @@ public partial class CreateUpdateOrganizationUnitDtoToOrganizationUnitMapper : M
[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)] [Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)]
public partial class TenantToCustomTenantDtoMapper : MapperBase<Tenant, CustomTenantDto> public partial class TenantToCustomTenantDtoMapper : MapperBase<Tenant, CustomTenantDto>
{ {
[MapperIgnoreTarget(nameof(CustomTenantDto.OrganizationName))]
[MapperIgnoreTarget(nameof(CustomTenantDto.Founder))]
[MapperIgnoreTarget(nameof(CustomTenantDto.VknTckn))]
[MapperIgnoreTarget(nameof(CustomTenantDto.TaxOffice))]
[MapperIgnoreTarget(nameof(CustomTenantDto.Country))]
[MapperIgnoreTarget(nameof(CustomTenantDto.City))]
[MapperIgnoreTarget(nameof(CustomTenantDto.District))]
[MapperIgnoreTarget(nameof(CustomTenantDto.Township))]
[MapperIgnoreTarget(nameof(CustomTenantDto.Address1))]
[MapperIgnoreTarget(nameof(CustomTenantDto.Address2))]
[MapperIgnoreTarget(nameof(CustomTenantDto.PostalCode))]
[MapperIgnoreTarget(nameof(CustomTenantDto.MobileNumber))]
[MapperIgnoreTarget(nameof(CustomTenantDto.PhoneNumber))]
[MapperIgnoreTarget(nameof(CustomTenantDto.FaxNumber))]
[MapperIgnoreTarget(nameof(CustomTenantDto.Email))]
[MapperIgnoreTarget(nameof(CustomTenantDto.Website))]
[MapperIgnoreTarget(nameof(CustomTenantDto.MenuGroup))]
[MapperIgnoreTarget(nameof(CustomTenantDto.Reference))]
public override partial CustomTenantDto Map(Tenant source); public override partial CustomTenantDto Map(Tenant source);
[MapperIgnoreTarget(nameof(CustomTenantDto.OrganizationName))]
[MapperIgnoreTarget(nameof(CustomTenantDto.Founder))]
[MapperIgnoreTarget(nameof(CustomTenantDto.VknTckn))]
[MapperIgnoreTarget(nameof(CustomTenantDto.TaxOffice))]
[MapperIgnoreTarget(nameof(CustomTenantDto.Country))]
[MapperIgnoreTarget(nameof(CustomTenantDto.City))]
[MapperIgnoreTarget(nameof(CustomTenantDto.District))]
[MapperIgnoreTarget(nameof(CustomTenantDto.Township))]
[MapperIgnoreTarget(nameof(CustomTenantDto.Address1))]
[MapperIgnoreTarget(nameof(CustomTenantDto.Address2))]
[MapperIgnoreTarget(nameof(CustomTenantDto.PostalCode))]
[MapperIgnoreTarget(nameof(CustomTenantDto.MobileNumber))]
[MapperIgnoreTarget(nameof(CustomTenantDto.PhoneNumber))]
[MapperIgnoreTarget(nameof(CustomTenantDto.FaxNumber))]
[MapperIgnoreTarget(nameof(CustomTenantDto.Email))]
[MapperIgnoreTarget(nameof(CustomTenantDto.Website))]
[MapperIgnoreTarget(nameof(CustomTenantDto.MenuGroup))]
[MapperIgnoreTarget(nameof(CustomTenantDto.Reference))]
public override partial void Map(Tenant source, CustomTenantDto destination); public override partial void Map(Tenant source, CustomTenantDto destination);
public override void BeforeMap(Tenant source) public override void BeforeMap(Tenant source)
@ -86,6 +123,23 @@ public partial class TenantToCustomTenantDtoMapper : MapperBase<Tenant, CustomTe
public override void AfterMap(Tenant source, CustomTenantDto destination) public override void AfterMap(Tenant source, CustomTenantDto destination)
{ {
destination.OrganizationName = source.GetOrganizationName();
destination.Founder = source.GetFounder();
destination.VknTckn = source.GetVknTckn();
destination.TaxOffice = source.GetTaxOffice();
destination.Country = source.GetCountry();
destination.City = source.GetCity();
destination.District = source.GetDistrict();
destination.Township = source.GetTownship();
destination.Address1 = source.GetAddress1();
destination.Address2 = source.GetAddress2();
destination.PostalCode = source.GetPostalCode();
destination.MobileNumber = source.GetMobileNumber();
destination.PhoneNumber = source.GetPhoneNumber();
destination.FaxNumber = source.GetFaxNumber();
destination.Email = source.GetEmail();
destination.Website = source.GetWebsite();
destination.MenuGroup = source.GetMenuGroup();
} }
} }

View file

@ -95,7 +95,8 @@ public class PlatformIdentityAppService : ApplicationService
//Branch //Branch
var queryBranch = await branchUsersRepository.GetQueryableAsync(); var queryBranch = await branchUsersRepository.GetQueryableAsync();
var branchUsers = queryBranch.Where(a => a.UserId == UserId).Select(r => r.BranchId).ToList(); var branchUsers = await AsyncExecuter.ToListAsync(
queryBranch.Where(a => a.UserId == UserId).Select(r => r.BranchId));
var branchList = await branchRepository.GetListAsync(a => a.TenantId == currentTenantId); var branchList = await branchRepository.GetListAsync(a => a.TenantId == currentTenantId);
var branches = branchList.Select(branch => new AssignedBranchViewModel var branches = branchList.Select(branch => new AssignedBranchViewModel
{ {
@ -129,7 +130,7 @@ public class PlatformIdentityAppService : ApplicationService
}).ToArray(); }).ToArray();
var departmentList = await departmentRepository.GetListAsync(); var departmentList = await departmentRepository.GetListAsync();
var departments = (await departmentRepository.GetListAsync()).Select(department => new AssignedDepartmentViewModel var departments = departmentList.Select(department => new AssignedDepartmentViewModel
{ {
Id = department.Id, Id = department.Id,
Name = department.Name, Name = department.Name,
@ -137,7 +138,7 @@ public class PlatformIdentityAppService : ApplicationService
}).ToArray(); }).ToArray();
var jobPositionList = await jobPositionRepository.GetListAsync(); var jobPositionList = await jobPositionRepository.GetListAsync();
var jobPositions = (await jobPositionRepository.GetListAsync()).Select(jobPosition => new AssignedJobPoisitionViewModel var jobPositions = jobPositionList.Select(jobPosition => new AssignedJobPoisitionViewModel
{ {
Id = jobPosition.Id, Id = jobPosition.Id,
Name = jobPosition.Name, Name = jobPosition.Name,

View file

@ -58,6 +58,10 @@ public static class PlatformSignInResultExtensions
{ {
return PlatformConsts.UserCannotSignInErrors.LoginNotAllowed_WorkHour; return PlatformConsts.UserCannotSignInErrors.LoginNotAllowed_WorkHour;
} }
if (resultP.IsNotAllowed_BranchLimit)
{
return PlatformConsts.UserCannotSignInErrors.LoginNotAllowed_BranchLimit;
}
if (resultP.IsNotAllowed_ConcurrentUserLimit) if (resultP.IsNotAllowed_ConcurrentUserLimit)
{ {
return PlatformConsts.UserCannotSignInErrors.LoginNotAllowed_ConcurrentUserLimit; return PlatformConsts.UserCannotSignInErrors.LoginNotAllowed_ConcurrentUserLimit;

View file

@ -25,6 +25,8 @@ namespace Sozsoft.Platform.Intranet;
[Authorize] [Authorize]
public class IntranetAppService : PlatformAppService, IIntranetAppService public class IntranetAppService : PlatformAppService, IIntranetAppService
{ {
private const int DashboardItemLimit = 50;
private Task<(Dictionary<Guid, string> DepartmentDict, Dictionary<Guid, JobPosition> JobPositionDict)>? _userLookupDictionariesTask;
private readonly ICurrentTenant _currentTenant; private readonly ICurrentTenant _currentTenant;
private readonly BlobManager _blobContainer; private readonly BlobManager _blobContainer;
private readonly IConfiguration _configuration; private readonly IConfiguration _configuration;
@ -32,6 +34,7 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
private readonly IRepository<Event, Guid> _eventRepository; private readonly IRepository<Event, Guid> _eventRepository;
private readonly IIdentityUserAppService _identityUserAppService; private readonly IIdentityUserAppService _identityUserAppService;
private readonly IIdentityUserRepository _identityUserRepository; private readonly IIdentityUserRepository _identityUserRepository;
private readonly IRepository<Volo.Abp.Identity.IdentityUser, Guid> _identityUserEntityRepository;
private readonly IRepository<Department, Guid> _departmentRepository; private readonly IRepository<Department, Guid> _departmentRepository;
private readonly IRepository<JobPosition, Guid> _jobPositionRepository; private readonly IRepository<JobPosition, Guid> _jobPositionRepository;
private readonly IRepository<Announcement, Guid> _announcementRepository; private readonly IRepository<Announcement, Guid> _announcementRepository;
@ -57,6 +60,7 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
IRepository<Event, Guid> eventRepository, IRepository<Event, Guid> eventRepository,
IIdentityUserAppService identityUserAppService, IIdentityUserAppService identityUserAppService,
IIdentityUserRepository identityUserRepository, IIdentityUserRepository identityUserRepository,
IRepository<Volo.Abp.Identity.IdentityUser, Guid> identityUserEntityRepository,
IRepository<Department, Guid> departmentRepository, IRepository<Department, Guid> departmentRepository,
IRepository<JobPosition, Guid> jobPositionRepository, IRepository<JobPosition, Guid> jobPositionRepository,
IRepository<Announcement, Guid> announcementRepository, IRepository<Announcement, Guid> announcementRepository,
@ -81,6 +85,7 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
_eventRepository = eventRepository; _eventRepository = eventRepository;
_identityUserAppService = identityUserAppService; _identityUserAppService = identityUserAppService;
_identityUserRepository = identityUserRepository; _identityUserRepository = identityUserRepository;
_identityUserEntityRepository = identityUserEntityRepository;
_departmentRepository = departmentRepository; _departmentRepository = departmentRepository;
_jobPositionRepository = jobPositionRepository; _jobPositionRepository = jobPositionRepository;
_announcementRepository = announcementRepository; _announcementRepository = announcementRepository;
@ -111,7 +116,12 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
}; };
} }
private async Task<(Dictionary<Guid, string> DepartmentDict, Dictionary<Guid, JobPosition> JobPositionDict)> GetUserLookupDictionariesAsync() private Task<(Dictionary<Guid, string> DepartmentDict, Dictionary<Guid, JobPosition> JobPositionDict)> GetUserLookupDictionariesAsync()
{
return _userLookupDictionariesTask ??= LoadUserLookupDictionariesAsync();
}
private async Task<(Dictionary<Guid, string> DepartmentDict, Dictionary<Guid, JobPosition> JobPositionDict)> LoadUserLookupDictionariesAsync()
{ {
var departments = await _departmentRepository.GetListAsync(); var departments = await _departmentRepository.GetListAsync();
var jobPositions = await _jobPositionRepository.GetListAsync(); var jobPositions = await _jobPositionRepository.GetListAsync();
@ -122,6 +132,17 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
); );
} }
private async Task<List<Volo.Abp.Identity.IdentityUser>> GetUsersByIdsAsync(IEnumerable<Guid> userIds)
{
var ids = userIds.Where(id => id != Guid.Empty).Distinct().ToList();
if (ids.Count == 0)
{
return [];
}
return await _identityUserEntityRepository.GetListAsync(user => ids.Contains(user.Id));
}
private UserInfoViewModel MapUserInfoViewModel( private UserInfoViewModel MapUserInfoViewModel(
Volo.Abp.Identity.IdentityUser user, Volo.Abp.Identity.IdentityUser user,
IReadOnlyDictionary<Guid, string> departmentDict, IReadOnlyDictionary<Guid, string> departmentDict,
@ -153,7 +174,10 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
.WithDetailsAsync(e => e.Category, e => e.Type); .WithDetailsAsync(e => e.Category, e => e.Type);
var events = await AsyncExecuter.ToListAsync( var events = await AsyncExecuter.ToListAsync(
queryable.Where(e => e.isPublished).OrderByDescending(e => e.CreationTime) queryable
.Where(e => e.isPublished)
.OrderByDescending(e => e.CreationTime)
.Take(DashboardItemLimit)
); );
if (events.Count == 0) if (events.Count == 0)
@ -170,7 +194,8 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
// Load all likes for these events // Load all likes for these events
var likesQueryable = await _eventLikeRepository.GetQueryableAsync(); var likesQueryable = await _eventLikeRepository.GetQueryableAsync();
var allLikes = await AsyncExecuter.ToListAsync( var allLikes = await AsyncExecuter.ToListAsync(
likesQueryable.Where(l => eventIds.Contains(l.EventId)) likesQueryable.Where(l =>
eventIds.Contains(l.EventId) && l.UserId == CurrentUser.Id)
); );
var likedEventIds = allLikes var likedEventIds = allLikes
.Where(l => l.UserId == CurrentUser.Id) .Where(l => l.UserId == CurrentUser.Id)
@ -192,9 +217,8 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
var (departmentDict, jobPositionDict) = await GetUserLookupDictionariesAsync(); var (departmentDict, jobPositionDict) = await GetUserLookupDictionariesAsync();
var fallbackUser = await GetDashboardFallbackUserAsync(departmentDict, jobPositionDict); var fallbackUser = await GetDashboardFallbackUserAsync(departmentDict, jobPositionDict);
var users = await _identityUserRepository.GetListAsync(); var users = await GetUsersByIdsAsync(userIds);
var userDict = users var userDict = users
.Where(u => userIds.Contains(u.Id))
.ToDictionary(u => u.Id, u => MapUserInfoViewModel(u, departmentDict, jobPositionDict)); .ToDictionary(u => u.Id, u => MapUserInfoViewModel(u, departmentDict, jobPositionDict));
var commentsByEvent = allComments.GroupBy(c => c.EventId) var commentsByEvent = allComments.GroupBy(c => c.EventId)
@ -264,9 +288,8 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
var userIds = comments.Select(c => c.UserId).Distinct().ToList(); var userIds = comments.Select(c => c.UserId).Distinct().ToList();
var (departmentDict, jobPositionDict) = await GetUserLookupDictionariesAsync(); var (departmentDict, jobPositionDict) = await GetUserLookupDictionariesAsync();
var users = await _identityUserRepository.GetListAsync(); var users = await GetUsersByIdsAsync(userIds);
var userDict = users var userDict = users
.Where(u => userIds.Contains(u.Id))
.ToDictionary(u => u.Id, u => MapUserInfoViewModel(u, departmentDict, jobPositionDict)); .ToDictionary(u => u.Id, u => MapUserInfoViewModel(u, departmentDict, jobPositionDict));
return comments.Select(c => new EventCommentDto return comments.Select(c => new EventCommentDto
@ -371,7 +394,11 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
private async Task<List<AnnouncementDto>> GetAnnouncementsAsync() private async Task<List<AnnouncementDto>> GetAnnouncementsAsync()
{ {
var announcements = await _announcementRepository.GetListAsync(); var announcementQueryable = await _announcementRepository.GetQueryableAsync();
var announcements = await AsyncExecuter.ToListAsync(
announcementQueryable
.OrderByDescending(announcement => announcement.CreationTime)
.Take(DashboardItemLimit));
var announcementDtos = new List<AnnouncementDto>(); var announcementDtos = new List<AnnouncementDto>();
if (announcements.Count == 0) if (announcements.Count == 0)
@ -386,7 +413,8 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
var likesQueryable = await _announcementLikeRepository.GetQueryableAsync(); var likesQueryable = await _announcementLikeRepository.GetQueryableAsync();
var allLikes = await AsyncExecuter.ToListAsync( var allLikes = await AsyncExecuter.ToListAsync(
likesQueryable.Where(l => announcementIds.Contains(l.AnnouncementId)) likesQueryable.Where(l =>
announcementIds.Contains(l.AnnouncementId) && l.UserId == CurrentUser.Id)
); );
var likedAnnouncementIds = allLikes var likedAnnouncementIds = allLikes
@ -403,9 +431,8 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
var (departmentDict, jobPositionDict) = await GetUserLookupDictionariesAsync(); var (departmentDict, jobPositionDict) = await GetUserLookupDictionariesAsync();
var fallbackUser = await GetDashboardFallbackUserAsync(departmentDict, jobPositionDict); var fallbackUser = await GetDashboardFallbackUserAsync(departmentDict, jobPositionDict);
var users = await _identityUserRepository.GetListAsync(); var users = await GetUsersByIdsAsync(userIds);
var userDict = users var userDict = users
.Where(u => userIds.Contains(u.Id))
.ToDictionary(u => u.Id, u => MapUserInfoViewModel(u, departmentDict, jobPositionDict)); .ToDictionary(u => u.Id, u => MapUserInfoViewModel(u, departmentDict, jobPositionDict));
var commentsByAnnouncement = allComments var commentsByAnnouncement = allComments
@ -454,9 +481,8 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
var userIds = comments.Select(c => c.UserId).Distinct().ToList(); var userIds = comments.Select(c => c.UserId).Distinct().ToList();
var (departmentDict, jobPositionDict) = await GetUserLookupDictionariesAsync(); var (departmentDict, jobPositionDict) = await GetUserLookupDictionariesAsync();
var users = await _identityUserRepository.GetListAsync(); var users = await GetUsersByIdsAsync(userIds);
var userDict = users var userDict = users
.Where(u => userIds.Contains(u.Id))
.ToDictionary(u => u.Id, u => MapUserInfoViewModel(u, departmentDict, jobPositionDict)); .ToDictionary(u => u.Id, u => MapUserInfoViewModel(u, departmentDict, jobPositionDict));
return comments.Select(c => new AnnouncementCommentDto return comments.Select(c => new AnnouncementCommentDto
@ -617,9 +643,8 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
{ {
var (departmentDict, jobPositionDict) = await GetUserLookupDictionariesAsync(); var (departmentDict, jobPositionDict) = await GetUserLookupDictionariesAsync();
var users = await _identityUserRepository.GetListAsync(); var users = await GetUsersByIdsAsync(userIds);
var userMap = users var userMap = users
.Where(u => userIds.Contains(u.Id))
.ToDictionary(u => u.Id, u => MapUserInfoViewModel(u, departmentDict, jobPositionDict)); .ToDictionary(u => u.Id, u => MapUserInfoViewModel(u, departmentDict, jobPositionDict));
foreach (var dto in dtos) foreach (var dto in dtos)
@ -947,9 +972,8 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
if (userIds.Count > 0) if (userIds.Count > 0)
{ {
var (departmentDict, jobPositionDict) = await GetUserLookupDictionariesAsync(); var (departmentDict, jobPositionDict) = await GetUserLookupDictionariesAsync();
var users = await _identityUserRepository.GetListAsync(); var users = await GetUsersByIdsAsync(userIds);
var userMap = users var userMap = users
.Where(u => userIds.Contains(u.Id))
.ToDictionary(u => u.Id, u => MapUserInfoViewModel(u, departmentDict, jobPositionDict)); .ToDictionary(u => u.Id, u => MapUserInfoViewModel(u, departmentDict, jobPositionDict));
if (dto.UserId.HasValue && userMap.TryGetValue(dto.UserId.Value, out var postUser)) if (dto.UserId.HasValue && userMap.TryGetValue(dto.UserId.Value, out var postUser))

View file

@ -47,26 +47,33 @@ public class ListFormFieldsAppService : CrudAppService<
protected override void MapToEntity(ColumnFormatEditDto updateInput, ListFormField entity) protected override void MapToEntity(ColumnFormatEditDto updateInput, ListFormField entity)
{ {
entity.CultureName = updateInput.CultureName;
entity.RoleId = updateInput.RoleId; entity.RoleId = updateInput.RoleId;
entity.ListFormCode = updateInput.ListFormCode; entity.ListFormCode = updateInput.ListFormCode;
entity.FieldName = updateInput.FieldName; entity.FieldName = updateInput.FieldName;
entity.CultureName = updateInput.CultureName;
entity.CaptionName = updateInput.CaptionName; entity.CaptionName = updateInput.CaptionName;
entity.PlaceHolder = updateInput.PlaceHolder; entity.PlaceHolder = updateInput.PlaceHolder;
entity.BandName = updateInput.BandName; entity.BandName = updateInput.BandName;
entity.IsActive = updateInput.IsActive; entity.IsActive = updateInput.IsActive;
entity.Visible = updateInput.Visible; entity.Visible = updateInput.Visible;
entity.AllowSearch = updateInput.AllowSearch; entity.AllowSearch = updateInput.AllowSearch;
entity.AllowEditing = updateInput.AllowEditing;
entity.AllowAdding = updateInput.AllowAdding;
entity.ListOrderNo = updateInput.ListOrderNo;
entity.SourceDbType = updateInput.SourceDbType; entity.SourceDbType = updateInput.SourceDbType;
entity.Alignment = updateInput.Alignment;
entity.Format = updateInput.Format;
entity.EditorOptions = updateInput.EditorOptions;
entity.EditorScript = updateInput.EditorScript;
entity.ListOrderNo = updateInput.ListOrderNo;
entity.Width = updateInput.Width; entity.Width = updateInput.Width;
entity.SortDirection = updateInput.SortDirection; entity.SortDirection = updateInput.SortDirection;
entity.SortIndex = updateInput.SortIndex; entity.SortIndex = updateInput.SortIndex;
entity.Format = updateInput.Format; entity.EditOrderNo = updateInput.EditOrderNo;
entity.Alignment = updateInput.Alignment; entity.EditGroupOrderNo = updateInput.EditGroupOrderNo;
entity.EditorOptions = updateInput.EditorOptions; entity.ColSpan = updateInput.ColSpan;
entity.EditorType2 = updateInput.EditorType2;
entity.AllowEditing = updateInput.AllowEditing;
entity.AllowAdding = updateInput.AllowAdding;
entity.PermissionJson = JsonSerializer.Serialize(updateInput.PermissionDto);
entity.LookupJson = JsonSerializer.Serialize(updateInput.LookupDto);
entity.ColumnCustomizationJson = JsonSerializer.Serialize(updateInput.ColumnCustomizationDto); entity.ColumnCustomizationJson = JsonSerializer.Serialize(updateInput.ColumnCustomizationDto);
entity.ColumnFilterJson = JsonSerializer.Serialize(updateInput.ColumnFilterDto); entity.ColumnFilterJson = JsonSerializer.Serialize(updateInput.ColumnFilterDto);
entity.ColumnHeaderJson = JsonSerializer.Serialize(updateInput.ColumnHeaderDto); entity.ColumnHeaderJson = JsonSerializer.Serialize(updateInput.ColumnHeaderDto);
@ -74,12 +81,10 @@ public class ListFormFieldsAppService : CrudAppService<
entity.GroupSummaryJson = updateInput.ColumnGroupSummaryDto.SummaryType.IsNullOrEmpty() ? "" : JsonSerializer.Serialize(updateInput.ColumnGroupSummaryDto); entity.GroupSummaryJson = updateInput.ColumnGroupSummaryDto.SummaryType.IsNullOrEmpty() ? "" : JsonSerializer.Serialize(updateInput.ColumnGroupSummaryDto);
entity.TotalSummaryJson = updateInput.ColumnTotalSummaryDto.SummaryType.IsNullOrEmpty() ? "" : JsonSerializer.Serialize(updateInput.ColumnTotalSummaryDto); entity.TotalSummaryJson = updateInput.ColumnTotalSummaryDto.SummaryType.IsNullOrEmpty() ? "" : JsonSerializer.Serialize(updateInput.ColumnTotalSummaryDto);
entity.JoinTableJson = JsonSerializer.Serialize(updateInput.ColumnJoinTableDto); entity.JoinTableJson = JsonSerializer.Serialize(updateInput.ColumnJoinTableDto);
entity.LookupJson = JsonSerializer.Serialize(updateInput.LookupDto);
entity.ColumnCssClass = updateInput.ColumnCssClass; entity.ColumnCssClass = updateInput.ColumnCssClass;
entity.ColumnCssValue = updateInput.ColumnCssValue; entity.ColumnCssValue = updateInput.ColumnCssValue;
entity.ValidationRuleJson = JsonSerializer.Serialize(updateInput.ValidationRuleDto); entity.ValidationRuleJson = JsonSerializer.Serialize(updateInput.ValidationRuleDto);
entity.ColumnStylingJson = JsonSerializer.Serialize(updateInput.ColumnStylingDto); entity.ColumnStylingJson = JsonSerializer.Serialize(updateInput.ColumnStylingDto);
entity.PermissionJson = JsonSerializer.Serialize(updateInput.PermissionDto);
entity.PivotSettingsJson = JsonSerializer.Serialize(updateInput.PivotSettingsDto); entity.PivotSettingsJson = JsonSerializer.Serialize(updateInput.PivotSettingsDto);
} }
@ -136,6 +141,9 @@ public class ListFormFieldsAppService : CrudAppService<
item.Alignment = input.Alignment; item.Alignment = input.Alignment;
item.Format = input.Format; item.Format = input.Format;
item.EditorOptions = input.EditorOptions; item.EditorOptions = input.EditorOptions;
item.IsActive = input.IsActive;
item.Visible = input.Visible;
item.AllowSearch = input.AllowSearch;
} }
else if (input.EditType == ListFormFieldEditTabs.PermissionsForm) else if (input.EditType == ListFormFieldEditTabs.PermissionsForm)
{ {
@ -152,6 +160,11 @@ public class ListFormFieldsAppService : CrudAppService<
item.AllowSearch = input.AllowSearch; item.AllowSearch = input.AllowSearch;
item.AllowEditing = input.AllowEditing; item.AllowEditing = input.AllowEditing;
item.AllowAdding = input.AllowAdding; item.AllowAdding = input.AllowAdding;
item.EditGroupOrderNo = input.EditGroupOrderNo;
item.EditOrderNo = input.EditOrderNo;
item.ColSpan = input.ColSpan;
item.EditorType2 = input.EditorType2;
item.EditorScript = input.EditorScript;
} }
else if (input.EditType == ListFormFieldEditTabs.CustomizationForm) else if (input.EditType == ListFormFieldEditTabs.CustomizationForm)
{ {
@ -257,6 +270,9 @@ public class ListFormFieldsAppService : CrudAppService<
field.CaptionName = sourceField.CaptionName; field.CaptionName = sourceField.CaptionName;
field.PlaceHolder = sourceField.PlaceHolder; field.PlaceHolder = sourceField.PlaceHolder;
field.SourceDbType = sourceField.SourceDbType; field.SourceDbType = sourceField.SourceDbType;
field.Alignment = sourceField.Alignment;
field.Format = sourceField.Format;
field.EditorOptions = sourceField.EditorOptions;
} }
if (input.CopiedFields.All || input.CopiedFields.Options) if (input.CopiedFields.All || input.CopiedFields.Options)
{ {
@ -269,35 +285,40 @@ public class ListFormFieldsAppService : CrudAppService<
field.AllowSearch = sourceField.AllowSearch; field.AllowSearch = sourceField.AllowSearch;
field.AllowEditing = sourceField.AllowEditing; field.AllowEditing = sourceField.AllowEditing;
field.AllowAdding = sourceField.AllowAdding; field.AllowAdding = sourceField.AllowAdding;
field.EditGroupOrderNo = sourceField.EditGroupOrderNo;
field.EditOrderNo = sourceField.EditOrderNo;
field.ColSpan = sourceField.ColSpan;
field.EditorType2 = sourceField.EditorType2;
field.EditorScript = sourceField.EditorScript;
} }
else if (input.CopiedFields.All || input.CopiedFields.Permission) if (input.CopiedFields.All || input.CopiedFields.Permission)
{ {
field.PermissionJson = sourceField.PermissionJson; field.PermissionJson = sourceField.PermissionJson;
} }
else if (input.CopiedFields.All || input.CopiedFields.Customization) if (input.CopiedFields.All || input.CopiedFields.Customization)
field.ColumnCustomizationJson = sourceField.ColumnCustomizationJson; field.ColumnCustomizationJson = sourceField.ColumnCustomizationJson;
else if (input.CopiedFields.All || input.CopiedFields.Filtering) if (input.CopiedFields.All || input.CopiedFields.Filtering)
field.ColumnFilterJson = sourceField.ColumnFilterJson; field.ColumnFilterJson = sourceField.ColumnFilterJson;
else if (input.CopiedFields.All || input.CopiedFields.Headering) if (input.CopiedFields.All || input.CopiedFields.Headering)
field.ColumnHeaderJson = sourceField.ColumnHeaderJson; field.ColumnHeaderJson = sourceField.ColumnHeaderJson;
else if (input.CopiedFields.All || input.CopiedFields.Grouping) if (input.CopiedFields.All || input.CopiedFields.Grouping)
field.GroupingJson = sourceField.GroupingJson; field.GroupingJson = sourceField.GroupingJson;
else if (input.CopiedFields.All || input.CopiedFields.GroupSummary) if (input.CopiedFields.All || input.CopiedFields.GroupSummary)
field.GroupSummaryJson = sourceField.GroupSummaryJson; field.GroupSummaryJson = sourceField.GroupSummaryJson;
else if (input.CopiedFields.All || input.CopiedFields.TotalSummary) if (input.CopiedFields.All || input.CopiedFields.TotalSummary)
field.TotalSummaryJson = sourceField.TotalSummaryJson; field.TotalSummaryJson = sourceField.TotalSummaryJson;
else if (input.CopiedFields.All || input.CopiedFields.JoinOptions) if (input.CopiedFields.All || input.CopiedFields.JoinOptions)
field.JoinTableJson = sourceField.JoinTableJson; field.JoinTableJson = sourceField.JoinTableJson;
else if (input.CopiedFields.All || input.CopiedFields.CssOptions) if (input.CopiedFields.All || input.CopiedFields.CssOptions)
{ {
field.ColumnCssClass = sourceField.ColumnCssClass; field.ColumnCssClass = sourceField.ColumnCssClass;
field.ColumnCssValue = sourceField.ColumnCssValue; field.ColumnCssValue = sourceField.ColumnCssValue;
} }
else if (input.CopiedFields.All || input.CopiedFields.ValidationRules) if (input.CopiedFields.All || input.CopiedFields.ValidationRules)
field.ValidationRuleJson = sourceField.ValidationRuleJson; field.ValidationRuleJson = sourceField.ValidationRuleJson;
else if (input.CopiedFields.All || input.CopiedFields.Formatting) if (input.CopiedFields.All || input.CopiedFields.Formatting)
field.ColumnStylingJson = sourceField.ColumnStylingJson; field.ColumnStylingJson = sourceField.ColumnStylingJson;
else if (input.CopiedFields.All || input.CopiedFields.PivotSetting) if (input.CopiedFields.All || input.CopiedFields.PivotSetting)
field.PivotSettingsJson = sourceField.PivotSettingsJson; field.PivotSettingsJson = sourceField.PivotSettingsJson;
await Repository.InsertAsync(field); await Repository.InsertAsync(field);

View file

@ -73,7 +73,7 @@ public class ListFormQueryPreviewAppService : PlatformAppService
var (_, _, dataSourceType) = await dynamicDataManager.GetAsync(listForm.IsTenant, listForm.DataSourceCode); var (_, _, dataSourceType) = await dynamicDataManager.GetAsync(listForm.IsTenant, listForm.DataSourceCode);
selectQueryManager.PrepareQueries(listForm, readableFields, dataSourceType, customizations); await selectQueryManager.PrepareQueriesAsync(listForm, readableFields, dataSourceType, customizations);
return selectQueryManager.SelectQuery; return selectQueryManager.SelectQuery;
} }

View file

@ -166,6 +166,10 @@ public class ListFormsAppService : CrudAppService<
{ {
item.SchedulerOptionJson = JsonSerializer.Serialize(input.SchedulerOptionDto); item.SchedulerOptionJson = JsonSerializer.Serialize(input.SchedulerOptionDto);
} }
else if (input.EditType == ListFormEditTabs.TodoForm)
{
item.TodoOptionJson = JsonSerializer.Serialize(input.TodoOptionDto);
}
else if (input.EditType == ListFormEditTabs.PagerForm) else if (input.EditType == ListFormEditTabs.PagerForm)
{ {
item.PageSize = input.PageSize; item.PageSize = input.PageSize;

View file

@ -55,12 +55,12 @@ public class ListFormDataAppService : PlatformAppService
var queryParameters = httpContext.Request.Query.ToDictionary(x => x.Key, x => x.Value); var queryParameters = httpContext.Request.Query.ToDictionary(x => x.Key, x => x.Value);
object filter = new object[] { input.Data[0], "=", input.Keys[0] }; object[] filter = [input.Data[0], "=", input.Keys[0]];
var selectRequest = new SelectRequestDto var selectRequest = new SelectRequestDto
{ {
ListFormCode = input.ListFormCode, ListFormCode = input.ListFormCode,
Filter = filter.ToString(), Filter = JsonSerializer.Serialize(filter),
Skip = 0, Skip = 0,
Take = 1, Take = 1,
RequireTotalCount = false, RequireTotalCount = false,

View file

@ -16,6 +16,8 @@ using Sozsoft.Platform.BlobStoring;
using Sozsoft.Platform.Identity; using Sozsoft.Platform.Identity;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Sozsoft.Platform.Entities;
using Volo.Abp.Domain.Repositories;
namespace Sozsoft.Platform.ListForms.DynamicApi; namespace Sozsoft.Platform.ListForms.DynamicApi;
@ -35,6 +37,7 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
private readonly IConfiguration configuration; private readonly IConfiguration configuration;
private readonly IHostEnvironment hostEnvironment; private readonly IHostEnvironment hostEnvironment;
private readonly IOptions<IdentityOptions> identityOptions; private readonly IOptions<IdentityOptions> identityOptions;
private readonly IRepository<Order, Guid> orderRepository;
public ListFormDynamicApiAppService( public ListFormDynamicApiAppService(
ITenantRepository tenantRepository, ITenantRepository tenantRepository,
@ -45,7 +48,8 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
BlobManager blobCdnManager, BlobManager blobCdnManager,
IConfiguration configuration, IConfiguration configuration,
IHostEnvironment hostEnvironment, IHostEnvironment hostEnvironment,
IOptions<IdentityOptions> identityOptions) IOptions<IdentityOptions> identityOptions,
IRepository<Order, Guid> orderRepository)
{ {
this.tenantRepository = tenantRepository; this.tenantRepository = tenantRepository;
this.tenantManager = tenantManager; this.tenantManager = tenantManager;
@ -56,6 +60,7 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
this.configuration = configuration; this.configuration = configuration;
this.hostEnvironment = hostEnvironment; this.hostEnvironment = hostEnvironment;
this.identityOptions = identityOptions; this.identityOptions = identityOptions;
this.orderRepository = orderRepository;
} }
private static Guid ParseGuid(string value) private static Guid ParseGuid(string value)
@ -233,30 +238,90 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
[Authorize(TenantManagementPermissions.Tenants.Create)] [Authorize(TenantManagementPermissions.Tenants.Create)]
public async Task PostTenantInsertAsync(DynamicApiBaseInput<CreateUpdateTenantInput> input) public async Task PostTenantInsertAsync(DynamicApiBaseInput<CreateUpdateTenantInput> input)
{ {
var tenant = await tenantManager.CreateAsync(input.Data.Name); await CreateTenantAsync(input.Data);
}
[Authorize(TenantManagementPermissions.Tenants.Create)]
public async Task<Guid> PostCreateTenantFromOrderAsync(DynamicApiBaseInput<CreateTenantFromOrderInput> input)
{
if (input.Data == null || input.Data.OrderId == Guid.Empty)
{
throw new UserFriendlyException(L["RecordNotFound"]);
}
if (input.Data.Name.IsNullOrWhiteSpace())
{
throw new UserFriendlyException("Tenant name is required.");
}
if (input.Data.MenuGroup.IsNullOrWhiteSpace())
{
throw new UserFriendlyException("Menu group is required.");
}
var order = await orderRepository.GetAsync(input.Data.OrderId)
?? throw new EntityNotFoundException(L["RecordNotFound"]);
if (order.TenantId.HasValue)
{
throw new UserFriendlyException("This order already has a tenant.");
}
var tenant = await CreateTenantAsync(new CreateUpdateTenantInput
{
Name = input.Data.Name,
IsActive = order.IsActive,
OrganizationName = order.OrganizationName,
Founder = order.Founder,
VknTckn = order.VknTckn ?? 0,
TaxOffice = order.TaxOffice,
Country = order.Country,
City = order.City,
District = order.District,
Township = order.Township,
Address1 = order.Address1,
Address2 = order.Address2,
PostalCode = order.PostalCode,
PhoneNumber = order.PhoneNumber,
MobileNumber = order.MobileNumber,
FaxNumber = order.FaxNumber,
Email = order.Email,
Website = order.Website,
MenuGroup = input.Data.MenuGroup,
});
order.TenantId = tenant.Id;
order.MenuGroup = input.Data.MenuGroup;
await orderRepository.UpdateAsync(order, autoSave: true);
return tenant.Id;
}
private async Task<Tenant> CreateTenantAsync(CreateUpdateTenantInput input)
{
var tenant = await tenantManager.CreateAsync(input.Name);
var entity = await tenantRepository.InsertAsync(tenant, autoSave: true); var entity = await tenantRepository.InsertAsync(tenant, autoSave: true);
entity.SetIsActive(input.Data.IsActive); entity.SetIsActive(input.IsActive);
entity.SetOrganizationName(input.Data.OrganizationName); entity.SetOrganizationName(input.OrganizationName);
entity.SetFounder(input.Data.Founder); entity.SetFounder(input.Founder);
entity.SetVknTckn(input.Data.VknTckn); entity.SetVknTckn(input.VknTckn);
entity.SetTaxOffice(input.Data.TaxOffice); entity.SetTaxOffice(input.TaxOffice);
entity.SetCountry(input.Data.Country); entity.SetCountry(input.Country);
entity.SetCity(input.Data.City); entity.SetCity(input.City);
entity.SetDistrict(input.Data.District); entity.SetDistrict(input.District);
entity.SetTownship(input.Data.Township); entity.SetTownship(input.Township);
entity.SetAddress1(input.Data.Address1); entity.SetAddress1(input.Address1);
entity.SetAddress2(input.Data.Address2); entity.SetAddress2(input.Address2);
entity.SetPostalCode(input.Data.PostalCode); entity.SetPostalCode(input.PostalCode);
entity.SetPhoneNumber(input.Data.PhoneNumber); entity.SetPhoneNumber(input.PhoneNumber);
entity.SetMobileNumber(input.Data.MobileNumber); entity.SetMobileNumber(input.MobileNumber);
entity.SetFaxNumber(input.Data.FaxNumber); entity.SetFaxNumber(input.FaxNumber);
entity.SetEmail(input.Data.Email); entity.SetEmail(input.Email);
entity.SetWebsite(input.Data.Website); entity.SetWebsite(input.Website);
entity.SetMenuGroup(input.Data.MenuGroup); entity.SetMenuGroup(input.MenuGroup);
entity.SetMaxConcurrentUsers(input.Data.MaxConcurrentUsers);
await tenantRepository.UpdateAsync(entity, autoSave: true); return await tenantRepository.UpdateAsync(entity, autoSave: true);
} }
[Authorize(TenantManagementPermissions.Tenants.Update)] [Authorize(TenantManagementPermissions.Tenants.Update)]
@ -290,7 +355,6 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
entity.SetEmail(input.Data.Email); entity.SetEmail(input.Data.Email);
entity.SetWebsite(input.Data.Website); entity.SetWebsite(input.Data.Website);
entity.SetMenuGroup(input.Data.MenuGroup); entity.SetMenuGroup(input.Data.MenuGroup);
entity.SetMaxConcurrentUsers(input.Data.MaxConcurrentUsers);
await tenantRepository.UpdateAsync(entity, autoSave: true); await tenantRepository.UpdateAsync(entity, autoSave: true);
} }

View file

@ -160,7 +160,7 @@ public class ListFormSelectAppService : PlatformAppService, IListFormSelectAppSe
var (dynamicDataRepository, connectionString, dataSourceType) = await dynamicDataManager.GetAsync(listForm.IsTenant, listForm.DataSourceCode); var (dynamicDataRepository, connectionString, dataSourceType) = await dynamicDataManager.GetAsync(listForm.IsTenant, listForm.DataSourceCode);
selectQueryManager.PrepareQueries(listForm, fields, dataSourceType, customizations, queryParams); await selectQueryManager.PrepareQueriesAsync(listForm, fields, dataSourceType, customizations, queryParams);
var param = selectQueryManager.SelectQueryParameters; var param = selectQueryManager.SelectQueryParameters;
if (!string.IsNullOrEmpty(queryParams.Group) && !string.IsNullOrEmpty(selectQueryManager.GroupQuery)) if (!string.IsNullOrEmpty(queryParams.Group) && !string.IsNullOrEmpty(selectQueryManager.GroupQuery))
@ -293,11 +293,6 @@ public class ListFormSelectAppService : PlatformAppService, IListFormSelectAppSe
//kullaniciya ait ListFormField verilerini al //kullaniciya ait ListFormField verilerini al
var fields = await listFormFieldManager.GetUserListFormFields(ListFormCode); var fields = await listFormFieldManager.GetUserListFormFields(ListFormCode);
// selectQueryManager.PrepareQueries(listForm, fields);
// fields = fields.Where(c => selectQueryManager.SelectFields.Any(sc => sc.FieldName == c.FieldName))
// .OrderBy(c => c.ListOrderNo)
// .ThenBy(c => c.CaptionName)
// .ToList();
fields = fields.OrderBy(c => c.ListOrderNo) fields = fields.OrderBy(c => c.ListOrderNo)
.ThenBy(c => c.CaptionName) .ThenBy(c => c.CaptionName)
.ToList(); .ToList();

View file

@ -180,11 +180,18 @@ public class ListFormWizardAppService(
Code = input.MenuParentCode, Code = input.MenuParentCode,
DisplayName = input.MenuParentCode, DisplayName = input.MenuParentCode,
IsDisabled = false, IsDisabled = false,
ShortName = input.MenuParentShortName?.Trim(),
Icon = menuParentIcon, Icon = menuParentIcon,
Order = maxRootOrder + 1, Order = maxRootOrder + 1,
}, autoSave: false); }, autoSave: false);
inserted.MenuCodes.Add(input.MenuParentCode); inserted.MenuCodes.Add(input.MenuParentCode);
} }
else if (string.IsNullOrWhiteSpace(menuParent.ShortName) &&
!string.IsNullOrWhiteSpace(input.MenuParentShortName))
{
menuParent.ShortName = input.MenuParentShortName.Trim();
await repoMenu.UpdateAsync(menuParent, autoSave: false);
}
//Menu //Menu
var maxChildOrder = menuQueryable.Where(a => a.ParentCode == menuParent.Code).Select(a => (int?)a.Order).Max() ?? 0; var maxChildOrder = menuQueryable.Where(a => a.ParentCode == menuParent.Code).Select(a => (int?)a.Order).Max() ?? 0;
@ -230,21 +237,9 @@ public class ListFormWizardAppService(
Caption = g.Caption, Caption = g.Caption,
ColCount = g.ColCount, ColCount = g.ColCount,
ColSpan = g.ColCount, ColSpan = g.ColCount,
ItemType = "group", ItemType = "group"
Items = g.Items
.Where(i => i.IncludeInEditingForm && i.DataField != input.KeyFieldName)
.Select((it, ii) => new EditingFormItemDto
{
Order = ii + 1,
DataField = it.DataField,
EditorType2 = it.EditorType,
ColSpan = it.ColSpan,
EditorOptions = string.IsNullOrWhiteSpace(it.EditorOptions) ? null : it.EditorOptions,
EditorScript = string.IsNullOrWhiteSpace(it.EditorScript) ? null : it.EditorScript,
})
.ToArray()
}) })
.Where(g => g.Items.Length > 0) .Where((_, index) => input.Groups[index].Items.Any(i => i.IncludeInEditingForm && i.FieldName != input.KeyFieldName))
.ToList(); .ToList();
//ListForm - varsa sil, yeniden ekle //ListForm - varsa sil, yeniden ekle
@ -269,9 +264,18 @@ public class ListFormWizardAppService(
var tableColumns = await GetTableColumnNamesAsync(input.DataSourceCode, input.SelectCommandType, input.SelectCommand); var tableColumns = await GetTableColumnNamesAsync(input.DataSourceCode, input.SelectCommandType, input.SelectCommand);
var isDeleted = tableColumns.Contains("IsDeleted"); var isDeleted = tableColumns.Contains("IsDeleted");
var isCreated = tableColumns.Contains("CreatorId"); var isCreated = tableColumns.Contains("CreatorId");
input.Workflow ??= new WorkflowDto(); input.Criteria ??= [];
input.Workflow.Criteria = input.WorkflowCriteria; EnsureUniqueWorkflowCriteriaTitles(input.Criteria);
EnsureUniqueWorkflowCriteriaTitles(input.WorkflowCriteria); NormalizeWorkflowCriteriaIds(listFormCode, input.Criteria);
var workflow = new WorkflowDto
{
ApprovalUserFieldName = input.ApprovalUserFieldName,
ApprovalIsFilterUserName = input.ApprovalIsFilterUserName,
ApprovalDateFieldName = input.ApprovalDateFieldName,
ApprovalStatusFieldName = input.ApprovalStatusFieldName,
ApprovalDescriptionFieldName = input.ApprovalDescriptionFieldName,
Criteria = input.Criteria,
};
await repoListForm.InsertAsync(new ListForm await repoListForm.InsertAsync(new ListForm
{ {
@ -279,8 +283,8 @@ public class ListFormWizardAppService(
PageSize = 10, PageSize = 10,
ExportJson = WizardConsts.DefaultExportJson, ExportJson = WizardConsts.DefaultExportJson,
IsSubForm = false, IsSubForm = false,
ShowNote = input.SubForms.Count > 0 || input.WorkflowCriteria.Count > 0, ShowNote = input.SubForms.Count > 0 || input.Criteria.Count > 0,
LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler), LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Card, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler, input.Todo),
CultureName = LanguageCodes.En, CultureName = LanguageCodes.En,
ListFormCode = input.ListFormCode, ListFormCode = input.ListFormCode,
Name = nameLangKey, Name = nameLangKey,
@ -300,18 +304,18 @@ public class ListFormWizardAppService(
HeaderFilterJson = WizardConsts.DefaultHeaderFilterJson(), HeaderFilterJson = WizardConsts.DefaultHeaderFilterJson(),
SearchPanelJson = WizardConsts.DefaultSearchPanelJson(), SearchPanelJson = WizardConsts.DefaultSearchPanelJson(),
GroupPanelJson = WizardConsts.DefaultGroupPanelJson(), GroupPanelJson = WizardConsts.DefaultGroupPanelJson(),
SelectionJson = WizardConsts.DefaultSelectionSingleJson(input.WorkflowCriteria.Count > 0 ? PlatformConsts.GridOptions.SelectionModeSingle : PlatformConsts.GridOptions.SelectionModeNone), SelectionJson = WizardConsts.DefaultSelectionSingleJson(input.Criteria.Count > 0 ? PlatformConsts.GridOptions.SelectionModeSingle : PlatformConsts.GridOptions.SelectionModeNone),
ColumnOptionJson = WizardConsts.DefaultColumnOptionJson(), ColumnOptionJson = WizardConsts.DefaultColumnOptionJson(),
PermissionJson = WizardConsts.DefaultPermissionJson(code), PermissionJson = WizardConsts.DefaultPermissionJson(code),
DeleteCommand = isDeleted ? WizardConsts.DefaultDeleteCommand(input.SelectCommand) : null, DeleteCommand = isDeleted ? WizardConsts.DefaultDeleteCommand(input.SelectCommand) : null,
DeleteFieldsDefaultValueJson = isDeleted ? WizardConsts.DefaultDeleteFieldsDefaultValueJson(input.KeyFieldDbSourceType) : WizardConsts.DefaultFieldsJsonOnlyId(input.KeyFieldDbSourceType), DeleteFieldsDefaultValueJson = isDeleted ? WizardConsts.DefaultDeleteFieldsDefaultValueJson(input.KeyFieldDbSourceType) : WizardConsts.DefaultDeleteFieldsJsonOnlyId(input.KeyFieldDbSourceType),
InsertFieldsDefaultValueJson = isCreated ? WizardConsts.DefaultInsertFieldsDefaultValueJson(input.KeyFieldDbSourceType) : WizardConsts.DefaultFieldsJsonOnlyId(input.KeyFieldDbSourceType), InsertFieldsDefaultValueJson = isCreated ? WizardConsts.DefaultInsertFieldsDefaultValueJson(input.KeyFieldDbSourceType) : WizardConsts.DefaultInsertFieldsJsonOnlyId(input.KeyFieldDbSourceType),
PagerOptionJson = WizardConsts.DefaultPagerOptionJson, PagerOptionJson = WizardConsts.DefaultPagerOptionJson,
EditingOptionJson = WizardConsts.DefaultEditingOptionJson(titleLangKey, 600, 500, input.AllowDeleting, input.AllowAdding, input.AllowUpdating, input.ConfirmDelete, false, input.AllowDetail), EditingOptionJson = WizardConsts.DefaultEditingOptionJson(titleLangKey, 600, 500, input.AllowDeleting, input.AllowAdding, input.AllowUpdating, input.ConfirmDelete, false, input.AllowDetail),
EditingFormJson = editingFormDtos.Count > 0 ? JsonSerializer.Serialize(editingFormDtos) : null, EditingFormJson = editingFormDtos.Count > 0 ? JsonSerializer.Serialize(editingFormDtos) : null,
SubFormsJson = input.SubForms.Count > 0 ? JsonSerializer.Serialize(input.SubForms) : null, SubFormsJson = input.SubForms.Count > 0 ? JsonSerializer.Serialize(input.SubForms) : null,
WidgetsJson = input.Widgets.Count > 0 ? JsonSerializer.Serialize(input.Widgets) : null, WidgetsJson = input.Widgets.Count > 0 ? JsonSerializer.Serialize(input.Widgets) : null,
WorkflowJson = HasWorkflow(input.Workflow, input.WorkflowCriteria) ? JsonSerializer.Serialize(input.Workflow) : null, WorkflowJson = HasWorkflow(workflow, input.Criteria) ? JsonSerializer.Serialize(workflow) : null,
TreeOptionJson = (input.Tree || input.DefaultLayout == "tree") && !string.IsNullOrEmpty(input.TreeParentIdExpr) TreeOptionJson = (input.Tree || input.DefaultLayout == "tree") && !string.IsNullOrEmpty(input.TreeParentIdExpr)
? JsonSerializer.Serialize(new TreeOptionDto ? JsonSerializer.Serialize(new TreeOptionDto
{ {
@ -340,25 +344,58 @@ public class ListFormWizardAppService(
EndDateExpr = input.SchedulerEndDateExpr, EndDateExpr = input.SchedulerEndDateExpr,
}) })
: null, : null,
TodoOptionJson = (input.Todo || input.DefaultLayout == "todo") &&
!string.IsNullOrEmpty(input.TodoTitleExpr) &&
!string.IsNullOrEmpty(input.TodoStatusExpr)
? JsonSerializer.Serialize(new TodoOptionDto
{
TitleExpr = input.TodoTitleExpr,
StatusExpr = input.TodoStatusExpr,
DescriptionExpr = input.TodoDescriptionExpr,
DueDateExpr = input.TodoDueDateExpr,
TagExpr = input.TodoTagExpr,
AssigneeExpr = input.TodoAssigneeExpr,
PriorityExpr = input.TodoPriorityExpr,
CompletedExpr = input.TodoCompletedExpr,
OrderExpr = input.TodoOrderExpr,
StatusOrder = input.TodoStatusOrder,
AllowDragging = input.TodoAllowDragging,
})
: null,
}, autoSave: true); }, autoSave: true);
// ListFormField - each item in each group becomes a visible field record // ListFormField - each item in each group becomes a visible field record
var fieldOrder = 0; var fieldOrder = 0;
var editGroupOrder = 0;
foreach (var group in input.Groups) foreach (var group in input.Groups)
{ {
editGroupOrder++;
var editOrder = 0;
foreach (var item in group.Items) foreach (var item in group.Items)
{ {
fieldOrder++; fieldOrder++;
if (item.IncludeInEditingForm && item.FieldName != input.KeyFieldName)
{
editOrder++;
}
await repoListFormField.InsertAsync(new ListFormField await repoListFormField.InsertAsync(new ListFormField
{ {
ListFormCode = input.ListFormCode, ListFormCode = input.ListFormCode,
FieldName = item.DataField, FieldName = item.FieldName,
CaptionName = item.CaptionName, CaptionName = item.CaptionName,
Visible = item.DataField != input.KeyFieldName, Visible = item.FieldName != input.KeyFieldName,
IsActive = true, IsActive = true,
AllowSearch = true, AllowSearch = true,
Width = 0, Width = 0,
ListOrderNo = fieldOrder, ListOrderNo = fieldOrder,
EditGroupOrderNo = item.IncludeInEditingForm ? editGroupOrder : null,
EditOrderNo = item.IncludeInEditingForm && item.FieldName != input.KeyFieldName
? editOrder
: null,
EditorType2 = item.EditorType,
ColSpan = item.ColSpan,
EditorOptions = string.IsNullOrWhiteSpace(item.EditorOptions) ? null : item.EditorOptions,
EditorScript = string.IsNullOrWhiteSpace(item.EditorScript) ? null : item.EditorScript,
SourceDbType = item.DbSourceType, SourceDbType = item.DbSourceType,
CultureName = PlatformConsts.DefaultLanguage, CultureName = PlatformConsts.DefaultLanguage,
PermissionJson = WizardConsts.DefaultFieldPermissionJson(code), PermissionJson = WizardConsts.DefaultFieldPermissionJson(code),
@ -372,7 +409,7 @@ public class ListFormWizardAppService(
} }
} }
foreach (var criteria in input.WorkflowCriteria) foreach (var criteria in input.Criteria)
{ {
if (string.IsNullOrWhiteSpace(criteria.Id)) if (string.IsNullOrWhiteSpace(criteria.Id))
{ {
@ -469,6 +506,55 @@ public class ListFormWizardAppService(
return string.IsNullOrWhiteSpace(kind) ? "Step" : kind.Trim(); return string.IsNullOrWhiteSpace(kind) ? "Step" : kind.Trim();
} }
private static void NormalizeWorkflowCriteriaIds(string listFormCode, List<ListFormWorkflowCriteriaDto> criteria)
{
if (string.IsNullOrWhiteSpace(listFormCode) || criteria == null || criteria.Count == 0)
{
return;
}
foreach (var item in criteria)
{
item.Id = NormalizeWorkflowCriteriaId(listFormCode, item.Id);
item.ListFormCode = listFormCode;
item.NextOnStart = NormalizeWorkflowTargetId(listFormCode, item.NextOnStart);
item.NextOnTrue = NormalizeWorkflowTargetId(listFormCode, item.NextOnTrue);
item.NextOnFalse = NormalizeWorkflowTargetId(listFormCode, item.NextOnFalse);
item.NextOnApprove = NormalizeWorkflowTargetId(listFormCode, item.NextOnApprove);
item.NextOnReject = NormalizeWorkflowTargetId(listFormCode, item.NextOnReject);
foreach (var outcome in item.CompareOutcomes ?? [])
{
outcome.TargetId = NormalizeWorkflowTargetId(listFormCode, outcome.TargetId);
}
}
}
private static string NormalizeWorkflowTargetId(string listFormCode, string id)
{
return string.IsNullOrWhiteSpace(id)
? string.Empty
: NormalizeWorkflowCriteriaId(listFormCode, id);
}
private static string NormalizeWorkflowCriteriaId(string listFormCode, string id)
{
var trimmed = id?.Trim();
if (string.IsNullOrWhiteSpace(trimmed))
{
return string.Empty;
}
if (trimmed.StartsWith($"{listFormCode}-", StringComparison.OrdinalIgnoreCase))
{
return trimmed;
}
return trimmed.StartsWith("N", StringComparison.OrdinalIgnoreCase)
? $"{listFormCode}-{trimmed}"
: trimmed;
}
/// <summary> /// <summary>
/// Wizard konfigürasyonunu JSON dosyası olarak kaydeder. /// Wizard konfigürasyonunu JSON dosyası olarak kaydeder.
/// Önce ContentRootPath'ten yukarı çıkarak Sozsoft.Platform.DbMigrator/Seeds/WizardData dizinini arar. /// Önce ContentRootPath'ten yukarı çıkarak Sozsoft.Platform.DbMigrator/Seeds/WizardData dizinini arar.

View file

@ -186,7 +186,7 @@ public class ListFormWorkflowAppService : PlatformAppService, IListFormWorkflowA
var code = input.ListFormCode; var code = input.ListFormCode;
var isNew = input.Id.IsNullOrWhiteSpace(); var isNew = input.Id.IsNullOrWhiteSpace();
var criteria = isNew var criteria = isNew
? new ListFormWorkflow(await GenerateNextCriteriaIdAsync()) ? new ListFormWorkflow(await GenerateNextCriteriaIdAsync(code))
: await criteriaRepository.GetAsync(input.Id); : await criteriaRepository.GetAsync(input.Id);
if (!isNew && criteria.ListFormCode != code) if (!isNew && criteria.ListFormCode != code)
@ -201,16 +201,16 @@ public class ListFormWorkflowAppService : PlatformAppService, IListFormWorkflowA
criteria.CompareOperator = NormalizeRequired(input.CompareOperator, ">"); criteria.CompareOperator = NormalizeRequired(input.CompareOperator, ">");
criteria.CompareValue = input.CompareValue; criteria.CompareValue = input.CompareValue;
criteria.Approver = input.Approver ?? string.Empty; criteria.Approver = input.Approver ?? string.Empty;
criteria.NextOnStart = input.NextOnStart ?? string.Empty; criteria.NextOnStart = NormalizeCriteriaTargetId(code, input.NextOnStart);
criteria.NextOnTrue = input.NextOnTrue ?? string.Empty; criteria.NextOnTrue = NormalizeCriteriaTargetId(code, input.NextOnTrue);
criteria.NextOnFalse = input.NextOnFalse ?? string.Empty; criteria.NextOnFalse = NormalizeCriteriaTargetId(code, input.NextOnFalse);
criteria.NextOnApprove = input.NextOnApprove ?? string.Empty; criteria.NextOnApprove = NormalizeCriteriaTargetId(code, input.NextOnApprove);
criteria.NextOnReject = input.NextOnReject ?? string.Empty; criteria.NextOnReject = NormalizeCriteriaTargetId(code, input.NextOnReject);
criteria.PositionX = input.PositionX <= 0 ? 32 : input.PositionX; criteria.PositionX = input.PositionX <= 0 ? 32 : input.PositionX;
criteria.PositionY = input.PositionY <= 0 ? 150 : input.PositionY; criteria.PositionY = input.PositionY <= 0 ? 150 : input.PositionY;
criteria.CompareOutcomesJson = SerializeCompareOutcomes(input.CompareOutcomes); var outcomes = NormalizeCompareOutcomeTargets(code, input.CompareOutcomes);
criteria.CompareOutcomesJson = SerializeCompareOutcomes(outcomes);
var outcomes = input.CompareOutcomes ?? [];
if (criteria.Kind == "Compare" && outcomes.Count > 0) if (criteria.Kind == "Compare" && outcomes.Count > 0)
{ {
criteria.NextOnTrue = outcomes.ElementAtOrDefault(0)?.TargetId ?? criteria.NextOnTrue; criteria.NextOnTrue = outcomes.ElementAtOrDefault(0)?.TargetId ?? criteria.NextOnTrue;
@ -357,6 +357,10 @@ public class ListFormWorkflowAppService : PlatformAppService, IListFormWorkflowA
{ {
throw new UserFriendlyException("Seçili kayıt bu onay adımında beklemiyor."); throw new UserFriendlyException("Seçili kayıt bu onay adımında beklemiyor.");
} }
if (!IsCurrentUserWorkflowApprover(context, current))
{
throw new UserFriendlyException("Bu kayıt için onay yetkiniz yok.");
}
var update = new Dictionary<string, object>(); var update = new Dictionary<string, object>();
if (!context.Workflow.ApprovalUserFieldName.IsNullOrWhiteSpace()) if (!context.Workflow.ApprovalUserFieldName.IsNullOrWhiteSpace())
@ -548,7 +552,7 @@ public class ListFormWorkflowAppService : PlatformAppService, IListFormWorkflowA
private async Task SendInformEmailAsync(WorkflowRunContext context, ListFormWorkflow node) private async Task SendInformEmailAsync(WorkflowRunContext context, ListFormWorkflow node)
{ {
var recipientEmail = await ResolveApproverEmailAsync(node.Approver); var recipientEmails = await ResolveApproverEmailsAsync(node.Approver);
var senderName = await settingProvider.GetOrNullAsync(SeedConsts.AbpSettings.Mailing.Default.DefaultFromDisplayName); var senderName = await settingProvider.GetOrNullAsync(SeedConsts.AbpSettings.Mailing.Default.DefaultFromDisplayName);
var senderEmail = await settingProvider.GetOrNullAsync(SeedConsts.AbpSettings.Mailing.Default.DefaultFromAddress); var senderEmail = await settingProvider.GetOrNullAsync(SeedConsts.AbpSettings.Mailing.Default.DefaultFromAddress);
KeyValuePair<string, string>? sender = null; KeyValuePair<string, string>? sender = null;
@ -557,22 +561,42 @@ public class ListFormWorkflowAppService : PlatformAppService, IListFormWorkflowA
sender = new KeyValuePair<string, string>(senderName, senderEmail); sender = new KeyValuePair<string, string>(senderName, senderEmail);
} }
var result = await erpEmailSender.SendEmailAsync( var body = BuildInformEmailBody(context, node, await BuildPreviousWorkflowNotesHtmlAsync(context));
recipientEmail, foreach (var recipientEmail in recipientEmails)
sender,
new { },
BuildInformEmailBody(context, node, await BuildPreviousWorkflowNotesHtmlAsync(context)),
$"Workflow Bilgilendirme: {node.Title}",
null,
true);
if (!result.Success)
{ {
throw new UserFriendlyException($"Bilgilendirme maili gonderilemedi: {result.ErrorMessage}"); var result = await erpEmailSender.SendEmailAsync(
recipientEmail,
sender,
new { },
body,
$"Workflow Bilgilendirme: {node.Title}",
null,
true);
if (!result.Success)
{
throw new UserFriendlyException($"Bilgilendirme maili gonderilemedi: {result.ErrorMessage}");
}
} }
} }
private async Task<List<string>> ResolveApproverEmailsAsync(string approver)
{
var emails = new List<string>();
foreach (var item in SplitWorkflowApprovers(approver))
{
emails.Add(await ResolveApproverEmailAsync(item));
}
if (emails.Count == 0)
{
throw new UserFriendlyException("Bilgilendirme dugumu icin approver tanimli degil.");
}
return emails;
}
private async Task<string> ResolveApproverEmailAsync(string approver) private async Task<string> ResolveApproverEmailAsync(string approver)
{ {
if (approver.IsNullOrWhiteSpace()) if (approver.IsNullOrWhiteSpace())
@ -594,6 +618,45 @@ public class ListFormWorkflowAppService : PlatformAppService, IListFormWorkflowA
return user.Email; return user.Email;
} }
private bool IsCurrentUserWorkflowApprover(WorkflowRunContext context, ListFormWorkflow current)
{
if (context.Workflow.ApprovalUserFieldName.IsNullOrWhiteSpace())
{
return true;
}
var approverValue = GetRowValue(context.Row, context.Workflow.ApprovalUserFieldName)?.ToString();
if (approverValue.IsNullOrWhiteSpace())
{
approverValue = current.Approver;
}
var approvers = SplitWorkflowApprovers(approverValue)
.ToHashSet(StringComparer.OrdinalIgnoreCase);
if (approvers.Count == 0)
{
return true;
}
return GetCurrentUserWorkflowIdentities().Any(approvers.Contains);
}
private IEnumerable<string> GetCurrentUserWorkflowIdentities()
{
return new[] { CurrentUser.UserName, CurrentUser.Email, CurrentUser.Name }
.Where(identity => !identity.IsNullOrWhiteSpace())
.Select(identity => identity.Trim());
}
private static IEnumerable<string> SplitWorkflowApprovers(string value)
{
return (value ?? string.Empty)
.Split(PlatformConsts.MultiValueDelimiter, StringSplitOptions.RemoveEmptyEntries)
.Select(item => item.Trim())
.Where(item => !item.IsNullOrWhiteSpace());
}
private async Task<string> BuildPreviousWorkflowNotesHtmlAsync(WorkflowRunContext context) private async Task<string> BuildPreviousWorkflowNotesHtmlAsync(WorkflowRunContext context)
{ {
var key = context.Keys?.FirstOrDefault()?.ToString(); var key = context.Keys?.FirstOrDefault()?.ToString();
@ -633,7 +696,7 @@ public class ListFormWorkflowAppService : PlatformAppService, IListFormWorkflowA
var keyText = string.Join(", ", context.Keys.Select(key => WebUtility.HtmlEncode(key?.ToString() ?? string.Empty))); var keyText = string.Join(", ", context.Keys.Select(key => WebUtility.HtmlEncode(key?.ToString() ?? string.Empty)));
var listFormCode = WebUtility.HtmlEncode(context.ListFormCode ?? string.Empty); var listFormCode = WebUtility.HtmlEncode(context.ListFormCode ?? string.Empty);
var nodeTitle = WebUtility.HtmlEncode(node.Title ?? string.Empty); var nodeTitle = WebUtility.HtmlEncode(node.Title ?? string.Empty);
var recipient = WebUtility.HtmlEncode(node.Approver ?? string.Empty); var recipient = WebUtility.HtmlEncode(FormatWorkflowApprovers(node.Approver));
var processRows = BuildWorkflowNoteContent(context.WorkflowNoteRows); var processRows = BuildWorkflowNoteContent(context.WorkflowNoteRows);
var previousNotesSection = previousWorkflowNotesHtml.IsNullOrWhiteSpace() var previousNotesSection = previousWorkflowNotesHtml.IsNullOrWhiteSpace()
? string.Empty ? string.Empty
@ -697,7 +760,7 @@ public class ListFormWorkflowAppService : PlatformAppService, IListFormWorkflowA
if (!node.Approver.IsNullOrWhiteSpace()) if (!node.Approver.IsNullOrWhiteSpace())
{ {
context.WorkflowNoteRows.Add((node.Kind == "Inform" ? "Inform: " : "Approver: ", node.Approver)); context.WorkflowNoteRows.Add((node.Kind == "Inform" ? "Inform: " : "Approver: ", FormatWorkflowApprovers(node.Approver)));
} }
} }
@ -790,7 +853,12 @@ public class ListFormWorkflowAppService : PlatformAppService, IListFormWorkflowA
{ {
return userName.IsNullOrWhiteSpace() return userName.IsNullOrWhiteSpace()
? localizer["ListForms.ListForm.Workflow.UndefinedUser"].Value ? localizer["ListForms.ListForm.Workflow.UndefinedUser"].Value
: userName; : FormatWorkflowApprovers(userName);
}
private static string FormatWorkflowApprovers(string value)
{
return string.Join(", ", SplitWorkflowApprovers(value));
} }
private async Task InsertWorkflowNoteAsync( private async Task InsertWorkflowNoteAsync(
@ -1039,7 +1107,7 @@ public class ListFormWorkflowAppService : PlatformAppService, IListFormWorkflowA
int positionY, int positionY,
string approver = "") string approver = "")
{ {
var criteria = new ListFormWorkflow(await GenerateNextCriteriaIdAsync()) var criteria = new ListFormWorkflow(await GenerateNextCriteriaIdAsync(listFormCode))
{ {
ListFormCode = listFormCode, ListFormCode = listFormCode,
Kind = kind, Kind = kind,
@ -1062,41 +1130,95 @@ public class ListFormWorkflowAppService : PlatformAppService, IListFormWorkflowA
return criteria; return criteria;
} }
private async Task<string> GenerateNextCriteriaIdAsync() private async Task<string> GenerateNextCriteriaIdAsync(string listFormCode)
{ {
var criteria = await criteriaRepository.GetListAsync(); var criteria = await criteriaRepository.GetListAsync(x => x.ListFormCode == listFormCode);
var maxNumber = criteria var maxNumber = criteria
.Select(x => TryParseCriteriaIdNumber(x.Id)) .Select(x => TryParseCriteriaIdNumber(listFormCode, x.Id))
.DefaultIfEmpty(0) .DefaultIfEmpty(0)
.Max(); .Max();
var nextNumber = maxNumber + 1; var nextNumber = maxNumber + 1;
var nextId = FormatCriteriaId(nextNumber); var nextId = FormatCriteriaId(listFormCode, nextNumber);
var existingIds = criteria.Select(x => x.Id).ToHashSet(); var existingIds = criteria.Select(x => x.Id).ToHashSet(StringComparer.OrdinalIgnoreCase);
while (existingIds.Contains(nextId)) while (existingIds.Contains(nextId))
{ {
nextNumber++; nextNumber++;
nextId = FormatCriteriaId(nextNumber); nextId = FormatCriteriaId(listFormCode, nextNumber);
} }
return nextId; return nextId;
} }
private static int TryParseCriteriaIdNumber(string id) private static int TryParseCriteriaIdNumber(string listFormCode, string id)
{ {
if (id.IsNullOrWhiteSpace() || var localId = GetLocalCriteriaId(listFormCode, id);
!id.StartsWith(CriteriaIdPrefix, StringComparison.OrdinalIgnoreCase)) if (localId.IsNullOrWhiteSpace() ||
!localId.StartsWith(CriteriaIdPrefix, StringComparison.OrdinalIgnoreCase))
{ {
return 0; return 0;
} }
return int.TryParse(id[CriteriaIdPrefix.Length..], out var number) ? number : 0; return int.TryParse(localId[CriteriaIdPrefix.Length..], out var number) ? number : 0;
} }
private static string FormatCriteriaId(int number) private static string FormatCriteriaId(string listFormCode, int number)
{ {
return $"{CriteriaIdPrefix}{number.ToString().PadLeft(CriteriaIdPadding, '0')}"; return $"{listFormCode}-{CriteriaIdPrefix}{number.ToString().PadLeft(CriteriaIdPadding, '0')}";
}
private static string NormalizeCriteriaTargetId(string listFormCode, string id)
{
return id.IsNullOrWhiteSpace()
? string.Empty
: NormalizeCriteriaId(listFormCode, id);
}
private static List<CompareOutcomeDto> NormalizeCompareOutcomeTargets(
string listFormCode,
List<CompareOutcomeDto> outcomes)
{
return (outcomes ?? [])
.Select(outcome => new CompareOutcomeDto
{
Label = outcome.Label,
TargetId = NormalizeCriteriaTargetId(listFormCode, outcome.TargetId),
Conditions = outcome.Conditions ?? []
})
.ToList();
}
private static string NormalizeCriteriaId(string listFormCode, string id)
{
var trimmed = id?.Trim();
if (trimmed.IsNullOrWhiteSpace())
{
return string.Empty;
}
if (trimmed.StartsWith($"{listFormCode}-", StringComparison.OrdinalIgnoreCase))
{
return trimmed;
}
return trimmed.StartsWith(CriteriaIdPrefix, StringComparison.OrdinalIgnoreCase)
? $"{listFormCode}-{trimmed}"
: trimmed;
}
private static string GetLocalCriteriaId(string listFormCode, string id)
{
var normalized = id?.Trim();
if (normalized.IsNullOrWhiteSpace())
{
return string.Empty;
}
var prefix = $"{listFormCode}-";
return normalized.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)
? normalized[prefix.Length..]
: normalized;
} }
private static bool ClearDeletedTarget(ListFormWorkflow criteria, string deletedId) private static bool ClearDeletedTarget(ListFormWorkflow criteria, string deletedId)

View file

@ -15,6 +15,8 @@ using Volo.Abp.PermissionManagement;
using Volo.Abp.TenantManagement; using Volo.Abp.TenantManagement;
using static Sozsoft.Platform.Data.Seeds.SeedConsts; using static Sozsoft.Platform.Data.Seeds.SeedConsts;
using Sozsoft.Languages; using Sozsoft.Languages;
using Sozsoft.Languages.Languages;
using Sozsoft.Platform.ListForms;
namespace Sozsoft.Platform.Menus; namespace Sozsoft.Platform.Menus;
@ -31,6 +33,7 @@ public class MenuAppService : CrudAppService<
private readonly ITenantRepository _tenantRepository; private readonly ITenantRepository _tenantRepository;
private readonly IPermissionDefinitionRecordRepository _permissionRepository; private readonly IPermissionDefinitionRecordRepository _permissionRepository;
private readonly LanguageTextAppService _languageTextAppService; private readonly LanguageTextAppService _languageTextAppService;
private readonly IRepository<MenuGroup, string> _menuGroupRepository;
public MenuAppService( public MenuAppService(
IRepository<Menu, Guid> menuRepository, IRepository<Menu, Guid> menuRepository,
@ -38,7 +41,8 @@ public class MenuAppService : CrudAppService<
IRepository<LanguageText, Guid> languageTextRepository, IRepository<LanguageText, Guid> languageTextRepository,
ITenantRepository tenantRepository, ITenantRepository tenantRepository,
IPermissionDefinitionRecordRepository permissionRepository, IPermissionDefinitionRecordRepository permissionRepository,
LanguageTextAppService languageTextAppService LanguageTextAppService languageTextAppService,
IRepository<MenuGroup, string> menuGroupRepository
) : base(menuRepository) ) : base(menuRepository)
{ {
_menuRepository = menuRepository; _menuRepository = menuRepository;
@ -47,6 +51,7 @@ public class MenuAppService : CrudAppService<
_tenantRepository = tenantRepository; _tenantRepository = tenantRepository;
_permissionRepository = permissionRepository; _permissionRepository = permissionRepository;
_languageTextAppService = languageTextAppService; _languageTextAppService = languageTextAppService;
_menuGroupRepository = menuGroupRepository;
CreatePolicyName = $"{AppCodes.Menus.Menu}.Create"; CreatePolicyName = $"{AppCodes.Menus.Menu}.Create";
UpdatePolicyName = $"{AppCodes.Menus.Menu}.Update"; UpdatePolicyName = $"{AppCodes.Menus.Menu}.Update";
@ -127,6 +132,30 @@ public class MenuAppService : CrudAppService<
.ToList(); .ToList();
entityDtos = await base.MapToGetListOutputDtosAsync(entities); entityDtos = await base.MapToGetListOutputDtosAsync(entities);
var languageKeys = entityDtos
.Select(item => string.IsNullOrWhiteSpace(item.DisplayName) ? item.Code : item.DisplayName)
.Where(key => !string.IsNullOrWhiteSpace(key))
.Distinct()
.ToList();
var languageTexts = await _repositoryText.GetListAsync(text =>
text.ResourceName == PlatformConsts.AppName &&
languageKeys.Contains(text.Key) &&
(text.CultureName == PlatformConsts.DefaultLanguage ||
text.CultureName == LanguageCodes.Tr));
foreach (var menu in entityDtos)
{
var languageKey = string.IsNullOrWhiteSpace(menu.DisplayName)
? menu.Code
: menu.DisplayName;
menu.MenuTextEn = languageTexts.FirstOrDefault(text =>
text.Key == languageKey &&
text.CultureName == PlatformConsts.DefaultLanguage)?.Value;
menu.MenuTextTr = languageTexts.FirstOrDefault(text =>
text.Key == languageKey &&
text.CultureName == LanguageCodes.Tr)?.Value;
}
} }
return new PagedResultDto<MenuDto>( return new PagedResultDto<MenuDto>(
@ -318,4 +347,18 @@ public class MenuAppService : CrudAppService<
return await base.CreateAsync(input); return await base.CreateAsync(input);
} }
public async Task<List<LookupDataDto>> GetMenuGroupsAsync()
{
var menuGroups = await _menuGroupRepository.GetListAsync();
return menuGroups
.OrderBy(menuGroup => menuGroup.Name)
.Select(menuGroup => new LookupDataDto
{
Key = menuGroup.Id,
Name = menuGroup.Name
})
.ToList();
}
} }

View file

@ -28,7 +28,7 @@ public class MessengerAppService : ApplicationService
private readonly IRepository<IdentityUser, Guid> _userRepository; private readonly IRepository<IdentityUser, Guid> _userRepository;
private readonly IRepository<MessengerConversation, Guid> _conversationRepository; private readonly IRepository<MessengerConversation, Guid> _conversationRepository;
private readonly IRepository<MessengerConversationMessage, Guid> _messageRepository; private readonly IRepository<MessengerConversationMessage, Guid> _messageRepository;
private readonly IIdentitySessionRepository _identitySessionRepository; private readonly IRepository<IdentitySession, Guid> _identitySessionRepository;
private readonly BlobManager _blobManager; private readonly BlobManager _blobManager;
private readonly IConfiguration _configuration; private readonly IConfiguration _configuration;
private readonly IHubContext<MessengerHub> _messengerHubContext; private readonly IHubContext<MessengerHub> _messengerHubContext;
@ -37,7 +37,7 @@ public class MessengerAppService : ApplicationService
IRepository<IdentityUser, Guid> userRepository, IRepository<IdentityUser, Guid> userRepository,
IRepository<MessengerConversation, Guid> conversationRepository, IRepository<MessengerConversation, Guid> conversationRepository,
IRepository<MessengerConversationMessage, Guid> messageRepository, IRepository<MessengerConversationMessage, Guid> messageRepository,
IIdentitySessionRepository identitySessionRepository, IRepository<IdentitySession, Guid> identitySessionRepository,
BlobManager blobManager, BlobManager blobManager,
IConfiguration configuration, IConfiguration configuration,
IHubContext<MessengerHub> messengerHubContext) IHubContext<MessengerHub> messengerHubContext)
@ -450,11 +450,14 @@ public class MessengerAppService : ApplicationService
return new HashSet<Guid>(); return new HashSet<Guid>();
} }
var sessions = await _identitySessionRepository.GetListAsync(); var sessionsQuery = await _identitySessionRepository.GetQueryableAsync();
return sessions var onlineUserIds = await AsyncExecuter.ToListAsync(
.Where(session => normalizedUserIds.Contains(session.UserId)) sessionsQuery
.Select(session => session.UserId) .Where(session => normalizedUserIds.Contains(session.UserId))
.ToHashSet(); .Select(session => session.UserId)
.Distinct());
return onlineUserIds.ToHashSet();
} }
private async Task<MessengerConversation?> FindConversationByParticipantKeyAsync(string participantKey) private async Task<MessengerConversation?> FindConversationByParticipantKeyAsync(string participantKey)

View file

@ -37,15 +37,15 @@ public class OrgChartAppService : PlatformAppService
var users = await _userRepository.GetListAsync(); var users = await _userRepository.GetListAsync();
var jobById = jobPositions.ToDictionary(x => x.Id); var jobById = jobPositions.ToDictionary(x => x.Id);
var positionsByDepartment = jobPositions
.GroupBy(position => position.DepartmentId)
.ToDictionary(group => group.Key, group => group.OrderBy(position => position.Name).ToList());
var usersByJobPosition = GroupUsersByJobPosition(users);
var topPositionByDepartment = new Dictionary<Guid, JobPosition>(); var topPositionByDepartment = new Dictionary<Guid, JobPosition>();
foreach (var department in departments) foreach (var department in departments)
{ {
var departmentPositions = jobPositions if (!positionsByDepartment.TryGetValue(department.Id, out var departmentPositions))
.Where(x => x.DepartmentId == department.Id)
.ToList();
if (!departmentPositions.Any())
{ {
continue; continue;
} }
@ -77,19 +77,9 @@ public class OrgChartAppService : PlatformAppService
ParentId = d.ParentId, ParentId = d.ParentId,
JobPositionId = topPosition?.Id, JobPositionId = topPosition?.Id,
JobPositionName = topPosition?.Name, JobPositionName = topPosition?.Name,
Users = users Users = topPosition != null && usersByJobPosition.TryGetValue(topPosition.Id, out var positionUsers)
.Where(u => ? positionUsers
topPosition != null && : [],
u.GetJobPositionId() == topPosition.Id)
.Select(u => new OrgChartUserDto
{
Id = u.Id,
FullName = u.GetFullName(),
Email = u.Email,
UserName = u.UserName,
PhoneNumber = u.PhoneNumber
})
.ToList(),
}; };
}).ToList(); }).ToList();
@ -104,6 +94,7 @@ public class OrgChartAppService : PlatformAppService
var users = await _userRepository.GetListAsync(); var users = await _userRepository.GetListAsync();
var deptDict = departments.ToDictionary(d => d.Id, d => d.Name); var deptDict = departments.ToDictionary(d => d.Id, d => d.Name);
var usersByJobPosition = GroupUsersByJobPosition(users);
var nodes = jobPositions.Select(jp => new OrgChartNodeDto var nodes = jobPositions.Select(jp => new OrgChartNodeDto
{ {
@ -114,19 +105,28 @@ public class OrgChartAppService : PlatformAppService
DepartmentName = deptDict.TryGetValue(jp.DepartmentId, out var name) ? name : null, DepartmentName = deptDict.TryGetValue(jp.DepartmentId, out var name) ? name : null,
JobPositionId = jp.Id, JobPositionId = jp.Id,
JobPositionName = jp.Name, JobPositionName = jp.Name,
Users = users Users = usersByJobPosition.TryGetValue(jp.Id, out var positionUsers)
.Where(u => u.GetJobPositionId() == jp.Id) ? positionUsers
.Select(u => new OrgChartUserDto : [],
{
Id = u.Id,
FullName = u.GetFullName(),
Email = u.Email,
UserName = u.UserName,
PhoneNumber = u.PhoneNumber
})
.ToList(),
}).ToList(); }).ToList();
return nodes; return nodes;
} }
private static Dictionary<Guid, List<OrgChartUserDto>> GroupUsersByJobPosition(
IEnumerable<IdentityUser> users)
{
return users
.GroupBy(user => user.GetJobPositionId())
.ToDictionary(
group => group.Key,
group => group.Select(user => new OrgChartUserDto
{
Id = user.Id,
FullName = user.GetFullName(),
Email = user.Email,
UserName = user.UserName,
PhoneNumber = user.PhoneNumber
}).ToList());
}
} }

View file

@ -8,8 +8,10 @@ using Sozsoft.Platform.Data.Seeds;
using Sozsoft.Sender.Mail; using Sozsoft.Sender.Mail;
using Volo.Abp.Settings; using Volo.Abp.Settings;
using Sozsoft.Platform.Demos; using Sozsoft.Platform.Demos;
using Microsoft.Extensions.Logging;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
using System.Linq; using System.Linq;
using System.Net;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using System.Text.Json; using System.Text.Json;
using Volo.Abp.Identity; using Volo.Abp.Identity;
@ -34,6 +36,8 @@ public class PublicAppService : PlatformAppService
private readonly IRepository<Home, Guid> _homeRepository; private readonly IRepository<Home, Guid> _homeRepository;
private readonly IRepository<Contact, Guid> _contactRepository; private readonly IRepository<Contact, Guid> _contactRepository;
private readonly IRepository<Country, string> _countryRepository; private readonly IRepository<Country, string> _countryRepository;
private readonly IRepository<City, Guid> _cityRepository;
private readonly IRepository<District, Guid> _districtRepository;
private readonly IIdentityUserRepository _identityUserRepository; private readonly IIdentityUserRepository _identityUserRepository;
private readonly IRepository<LanguageKey, Guid> _languageKeyRepository; private readonly IRepository<LanguageKey, Guid> _languageKeyRepository;
private readonly IRepository<LanguageText, Guid> _languageTextRepository; private readonly IRepository<LanguageText, Guid> _languageTextRepository;
@ -54,6 +58,8 @@ public class PublicAppService : PlatformAppService
IRepository<Home, Guid> homeRepository, IRepository<Home, Guid> homeRepository,
IRepository<Contact, Guid> contactRepository, IRepository<Contact, Guid> contactRepository,
IRepository<Country, string> countryRepository, IRepository<Country, string> countryRepository,
IRepository<City, Guid> cityRepository,
IRepository<District, Guid> districtRepository,
IIdentityUserRepository identityUserRepository, IIdentityUserRepository identityUserRepository,
IRepository<LanguageKey, Guid> languageKeyRepository, IRepository<LanguageKey, Guid> languageKeyRepository,
IRepository<LanguageText, Guid> languageTextRepository, IRepository<LanguageText, Guid> languageTextRepository,
@ -78,6 +84,8 @@ public class PublicAppService : PlatformAppService
_languageTextRepository = languageTextRepository; _languageTextRepository = languageTextRepository;
_languageTextAppService = languageTextAppService; _languageTextAppService = languageTextAppService;
_countryRepository = countryRepository; _countryRepository = countryRepository;
_cityRepository = cityRepository;
_districtRepository = districtRepository;
} }
public async Task<List<ServiceDto>> GetServicesListAsync() public async Task<List<ServiceDto>> GetServicesListAsync()
@ -457,51 +465,91 @@ public class PublicAppService : PlatformAppService
public async Task<OrderDto> CreateOrderAsync(OrderDto input) public async Task<OrderDto> CreateOrderAsync(OrderDto input)
{ {
var entity = new Order() var entity = new Order(GuidGenerator.Create())
{ {
Name = input.Tenant.Name, TenantId = input.Tenant.Id,
IsActive = input.Tenant.IsActive,
OrganizationName = input.Tenant.OrganizationName, OrganizationName = input.Tenant.OrganizationName,
Founder = input.Tenant.Founder, Founder = input.Tenant.Founder,
VknTckn = input.Tenant.VknTckn, VknTckn = input.Tenant.VknTckn,
TaxOffice = input.Tenant.TaxOffice, TaxOffice = input.Tenant.TaxOffice,
Address1 = input.Tenant.Address1, Address1 = input.Tenant.Address1,
Address2 = input.Tenant.Address2, Address2 = input.Tenant.Address2,
District = input.Tenant.District,
Country = input.Tenant.Country, Country = input.Tenant.Country,
City = input.Tenant.City, City = input.Tenant.City,
District = input.Tenant.District,
Township = input.Tenant.Township,
PostalCode = input.Tenant.PostalCode, PostalCode = input.Tenant.PostalCode,
MobileNumber = input.Tenant.MobileNumber, MobileNumber = NormalizePhoneNumber(input.Tenant.MobileNumber, input.Tenant.Country),
PhoneNumber = input.Tenant.PhoneNumber, PhoneNumber = NormalizePhoneNumber(input.Tenant.PhoneNumber, input.Tenant.Country),
FaxNumber = input.Tenant.FaxNumber, FaxNumber = NormalizePhoneNumber(input.Tenant.FaxNumber, input.Tenant.Country),
Email = input.Tenant.Email, Email = input.Tenant.Email,
Website = input.Tenant.Website, Website = input.Tenant.Website,
MenuGroup = input.Tenant.MenuGroup, MenuGroup = input.Tenant.MenuGroup,
BillingCycle = input.BillingCycle,
Period = input.Period,
LicenseStartTime = input.LicenseStartTime,
LicenseEndTime = input.LicenseEndTime,
Subtotal = input.Subtotal, Subtotal = input.Subtotal,
VatTotal = input.VatTotal,
Commission = input.Commission, Commission = input.Commission,
Total = input.Total, Total = input.Total,
PaymentMethodId = input.PaymentMethodId, PaymentMethodId = input.PaymentMethodId,
Installment = input.Installment, Installment = input.Installment,
PaymentDataJson = JsonSerializer.Serialize(input.PaymentData), PaymentDataJson = JsonSerializer.Serialize(input.PaymentData),
IsExisting = input.IsExisting,
}; };
decimal subtotal = 0;
decimal vatTotal = 0;
foreach (var item in input.Items) foreach (var item in input.Items)
{ {
var productId = item.ProductId != Guid.Empty ? item.ProductId : item.Product.Id;
var product = await _productRepository.FindAsync(productId);
if (product == null && !item.Product.Name.IsNullOrWhiteSpace())
{
product = await _productRepository.FirstOrDefaultAsync(x => x.Name == item.Product.Name);
}
if (product == null)
{
throw new EntityNotFoundException(typeof(Product), productId);
}
var vatRate = product.VatRate;
var price = GetOrderItemPrice(product, item.BillingCycle);
var grossTotal = Math.Round(item.TotalPrice, 2, MidpointRounding.AwayFromZero);
var netTotal = vatRate > 0
? Math.Round(grossTotal / (1 + vatRate), 2, MidpointRounding.AwayFromZero)
: grossTotal;
var vatAmount = Math.Round(grossTotal - netTotal, 2, MidpointRounding.AwayFromZero);
subtotal += netTotal;
vatTotal += vatAmount;
entity.Items.Add(new OrderItem entity.Items.Add(new OrderItem
{ {
OrderId = entity.Id, OrderId = entity.Id,
Order = entity, Order = entity,
ProductId = item.Product.Id, ProductId = product.Id,
ProductName = item.Product.Name, ProductName = product.Name,
BillingCycle = item.BillingCycle, BillingCycle = item.BillingCycle,
Period = input.Period,
Quantity = item.Quantity, Quantity = item.Quantity,
TotalPrice = item.TotalPrice Price = price,
VatRate = vatRate,
VatAmount = vatAmount,
TotalPrice = grossTotal
}); });
} }
entity.Subtotal = Math.Round(subtotal, 2, MidpointRounding.AwayFromZero);
entity.VatTotal = Math.Round(vatTotal, 2, MidpointRounding.AwayFromZero);
entity.Total = Math.Round(entity.Subtotal + entity.VatTotal + entity.Commission, 2, MidpointRounding.AwayFromZero);
await _orderRepository.InsertAsync(entity, autoSave: true); await _orderRepository.InsertAsync(entity, autoSave: true);
await SendOrderCreatedEmailsAsync(entity);
return new OrderDto return new OrderDto
{ {
@ -511,6 +559,318 @@ public class PublicAppService : PlatformAppService
}; };
} }
private static decimal GetOrderItemPrice(Product product, string billingCycle)
{
return string.Equals(billingCycle, "monthly", StringComparison.OrdinalIgnoreCase)
? product.MonthlyPrice ?? 0
: product.YearlyPrice ?? 0;
}
private async Task SendOrderCreatedEmailsAsync(Order order)
{
var recipients = new List<string>();
if (!order.Email.IsNullOrWhiteSpace())
{
recipients.Add(order.Email.Trim());
}
var notificationEmails = await _settingProvider.GetOrNullAsync("App.SiteManagement.General.NewTenantNotificationEmails");
if (!notificationEmails.IsNullOrWhiteSpace())
{
recipients.AddRange(notificationEmails
.Split(new[] { ',', ';', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries)
.Select(email => email.Trim())
.Where(email => !email.IsNullOrWhiteSpace()));
}
recipients = recipients
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
if (recipients.Count == 0)
{
return;
}
var senderName = await _settingProvider.GetOrNullAsync(SeedConsts.AbpSettings.Mailing.Default.DefaultFromDisplayName);
var senderEmail = await _settingProvider.GetOrNullAsync(SeedConsts.AbpSettings.Mailing.Default.DefaultFromAddress);
KeyValuePair<string, string>? sender = null;
if (!senderEmail.IsNullOrWhiteSpace())
{
sender = new KeyValuePair<string, string>(senderName ?? string.Empty, senderEmail);
}
var body = BuildOrderEmailBody(order);
var subject = $"{PlatformConsts.AppName} : Yeni Sipariş #{order.Id}";
foreach (var recipient in recipients)
{
try
{
await _emailSender.SendEmailAsync(
recipient,
sender,
new { },
body,
subject,
null,
true);
}
catch (Exception ex)
{
Logger.LogError(ex, "Order email could not be sent to {Recipient}", recipient);
}
}
}
private string BuildOrderEmailBody(Order order)
{
var itemRows = string.Join(string.Empty, order.Items.Select(item => $@"
<tr>
<td style=""padding:16px 14px;border-bottom:1px solid #e5e7eb;font-weight:700;color:#111827;line-height:20px;"">{Html(Translate(item.ProductName))}</td>
<td align=""right"" style=""padding:16px 14px;border-bottom:1px solid #e5e7eb;text-align:right;color:#374151;white-space:nowrap;line-height:20px;"">{FormatPrice(item.Price)}</td>
<td align=""right"" style=""padding:16px 14px;border-bottom:1px solid #e5e7eb;text-align:right;color:#374151;white-space:nowrap;line-height:20px;"">{item.Period}</td>
<td align=""right"" style=""padding:16px 14px;border-bottom:1px solid #e5e7eb;text-align:right;color:#374151;white-space:nowrap;line-height:20px;"">{item.Quantity}</td>
<td align=""right"" style=""padding:16px 14px;border-bottom:1px solid #e5e7eb;text-align:right;color:#374151;white-space:nowrap;line-height:20px;"">{BillingCycleLabel(item.BillingCycle)}</td>
<td align=""right"" style=""padding:16px 14px;border-bottom:1px solid #e5e7eb;text-align:right;color:#374151;white-space:nowrap;line-height:20px;"">%{item.VatRate * 100:0.##} / {FormatPrice(item.VatAmount)}</td>
<td align=""right"" style=""padding:16px 14px;border-bottom:1px solid #e5e7eb;text-align:right;font-weight:800;color:#111827;white-space:nowrap;line-height:20px;"">{FormatPrice(item.TotalPrice)}</td>
</tr>"));
return $@"
<!doctype html>
<html>
<head>
<meta http-equiv=""Content-Type"" content=""text/html; charset=utf-8"" />
<meta name=""viewport"" content=""width=device-width, initial-scale=1.0"" />
<meta name=""x-apple-disable-message-reformatting"" />
</head>
<body bgcolor=""#f3f4f6"" style=""margin:0;padding:0;background-color:#f3f4f6;font-family:Arial,Helvetica,sans-serif;color:#111827;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;"">
<div style=""display:none;font-size:1px;color:#f3f4f6;line-height:1px;max-height:0;max-width:0;opacity:0;overflow:hidden;"">
{Html(Translate("Public.order.success.title"))} #{order.Id}
</div>
<table role=""presentation"" width=""100%"" cellpadding=""0"" cellspacing=""0"" border=""0"" bgcolor=""#f3f4f6"" style=""width:100%;background-color:#f3f4f6;border-collapse:collapse;mso-table-lspace:0pt;mso-table-rspace:0pt;"">
<tr>
<td align=""center"" style=""padding:24px 12px;"">
<table role=""presentation"" width=""980"" cellpadding=""0"" cellspacing=""0"" border=""0"" align=""center"" bgcolor=""#ffffff"" style=""width:100%;max-width:980px;background-color:#ffffff;border:1px solid #e5e7eb;border-collapse:collapse;mso-table-lspace:0pt;mso-table-rspace:0pt;"">
<tr>
<td bgcolor=""#f9fafb"" style=""padding:24px;background-color:#f9fafb;border-bottom:1px solid #e5e7eb;"">
<table role=""presentation"" width=""100%"" cellpadding=""0"" cellspacing=""0"" border=""0"" style=""width:100%;border-collapse:collapse;mso-table-lspace:0pt;mso-table-rspace:0pt;"">
<tr>
<td style=""vertical-align:middle;"">
<table role=""presentation"" cellpadding=""0"" cellspacing=""0"" border=""0"" style=""border-collapse:collapse;mso-table-lspace:0pt;mso-table-rspace:0pt;"">
<tr>
<td style=""width:46px;vertical-align:middle;"">
<table role=""presentation"" width=""40"" height=""40"" cellpadding=""0"" cellspacing=""0"" border=""0"" bgcolor=""#22c55e"" style=""width:40px;height:40px;background-color:#22c55e;border-collapse:collapse;"">
<tr>
<td align=""center"" valign=""middle"" style=""font-size:22px;line-height:40px;font-weight:800;color:#ffffff;"">&#10003;</td>
</tr>
</table>
</td>
<td style=""vertical-align:middle;"">
<table role=""presentation"" cellpadding=""0"" cellspacing=""0"" border=""0"" style=""border-collapse:collapse;"">
<tr>
<td style=""font-size:22px;line-height:28px;font-weight:800;color:#111827;"">{Html(Translate("Public.order.success.title"))}</td>
</tr>
<tr>
<td style=""padding-top:6px;color:#4b5563;font-size:14px;line-height:20px;"">{Html(Translate("Public.order.success.number"))} <strong style=""color:#2563eb;"">#{order.Id}</strong></td>
</tr>
</table>
</td>
</tr>
</table>
</td>
<td align=""right"" style=""text-align:right;vertical-align:middle;color:#4b5563;"">
<table role=""presentation"" cellpadding=""0"" cellspacing=""0"" border=""0"" align=""right"" style=""border-collapse:collapse;"">
<tr>
<td align=""right"" style=""font-size:12px;line-height:16px;text-transform:uppercase;letter-spacing:.08em;color:#6b7280;"">Invoice</td>
</tr>
<tr>
<td align=""right"" style=""padding-top:4px;font-size:14px;line-height:20px;font-weight:700;color:#111827;"">{FormatDate(DateTime.Now)}</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td style=""padding:24px;"">
<table role=""presentation"" width=""100%"" cellpadding=""0"" cellspacing=""0"" border=""0"" style=""width:100%;border-collapse:separate;border-spacing:0;mso-table-lspace:0pt;mso-table-rspace:0pt;"">
<tr>
<td width=""50%"" style=""vertical-align:top;padding:0 10px 20px 0;"">
<table role=""presentation"" width=""100%"" cellpadding=""0"" cellspacing=""0"" border=""0"" bgcolor=""#ffffff"" style=""width:100%;background-color:#ffffff;border:1px solid #e5e7eb;border-collapse:collapse;mso-table-lspace:0pt;mso-table-rspace:0pt;"">
<tr>
<td style=""padding:18px;"">
<table role=""presentation"" width=""100%"" cellpadding=""0"" cellspacing=""0"" border=""0"" style=""width:100%;border-collapse:collapse;"">
<tr>
<td style=""font-size:18px;line-height:24px;font-weight:800;color:#111827;padding-bottom:14px;"">Customer Information</td>
</tr>
<tr>
<td style=""line-height:24px;color:#374151;font-size:14px;"">
<strong style=""color:#111827;"">{Html(order.OrganizationName)}</strong><br />
<a href=""mailto:{Html(order.Email)}"" style=""color:#2563eb;text-decoration:none;"">{Html(order.Email)}</a><br />
{Html(FormatPhoneNumber(order.PhoneNumber ?? order.MobileNumber))}<br />
{Html(order.Address1)}<br />
{Html(order.Township)} / {Html(order.District)} / {Html(order.City)} / {Html(order.Country)}
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
<td width=""50%"" style=""vertical-align:top;padding:0 0 20px 10px;"">
<table role=""presentation"" width=""100%"" cellpadding=""0"" cellspacing=""0"" border=""0"" bgcolor=""#ffffff"" style=""width:100%;background-color:#ffffff;border:1px solid #e5e7eb;border-collapse:collapse;mso-table-lspace:0pt;mso-table-rspace:0pt;"">
<tr>
<td style=""padding:18px;"">
<table role=""presentation"" width=""100%"" cellpadding=""0"" cellspacing=""0"" border=""0"" style=""width:100%;border-collapse:collapse;"">
<tr>
<td style=""font-size:18px;line-height:24px;font-weight:800;color:#111827;padding-bottom:14px;"">License Information</td>
</tr>
</table>
<table role=""presentation"" width=""100%"" cellpadding=""0"" cellspacing=""0"" border=""0"" style=""width:100%;border-collapse:collapse;font-size:14px;color:#374151;mso-table-lspace:0pt;mso-table-rspace:0pt;"">
<tr>
<td bgcolor=""#f9fafb"" style=""padding:8px;background-color:#f9fafb;color:#6b7280;line-height:20px;"">License Start Time</td>
<td bgcolor=""#f9fafb"" align=""right"" style=""padding:8px;background-color:#f9fafb;text-align:right;font-weight:700;color:#111827;line-height:20px;"">{FormatDate(order.LicenseStartTime)}</td>
</tr>
<tr>
<td style=""padding:8px;color:#6b7280;line-height:20px;"">License End Time</td>
<td align=""right"" style=""padding:8px;text-align:right;font-weight:700;color:#111827;line-height:20px;"">{FormatDate(order.LicenseEndTime)}</td>
</tr>
<tr>
<td bgcolor=""#f9fafb"" style=""padding:8px;background-color:#f9fafb;color:#6b7280;line-height:20px;"">Billing Cycle</td>
<td bgcolor=""#f9fafb"" align=""right"" style=""padding:8px;background-color:#f9fafb;text-align:right;font-weight:700;color:#111827;line-height:20px;"">{BillingCycleLabel(order.BillingCycle)}</td>
</tr>
<tr>
<td style=""padding:8px;color:#6b7280;line-height:20px;"">Period</td>
<td align=""right"" style=""padding:8px;text-align:right;font-weight:700;color:#111827;line-height:20px;"">{order.Period}</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
<table width=""100%"" cellpadding=""0"" cellspacing=""0"" border=""0"" style=""width:100%;border-collapse:collapse;border:1px solid #e5e7eb;mso-table-lspace:0pt;mso-table-rspace:0pt;"">
<thead>
<tr style=""background:#f9fafb;color:#6b7280;font-size:12px;text-transform:uppercase;letter-spacing:.06em;"">
<th bgcolor=""#f9fafb"" style=""padding:12px 14px;text-align:left;background-color:#f9fafb;line-height:16px;"">Product</th>
<th bgcolor=""#f9fafb"" align=""right"" style=""padding:12px 14px;text-align:right;background-color:#f9fafb;line-height:16px;"">Price</th>
<th bgcolor=""#f9fafb"" align=""right"" style=""padding:12px 14px;text-align:right;background-color:#f9fafb;line-height:16px;"">Period</th>
<th bgcolor=""#f9fafb"" align=""right"" style=""padding:12px 14px;text-align:right;background-color:#f9fafb;line-height:16px;"">Qty</th>
<th bgcolor=""#f9fafb"" align=""right"" style=""padding:12px 14px;text-align:right;background-color:#f9fafb;line-height:16px;"">Cycle</th>
<th bgcolor=""#f9fafb"" align=""right"" style=""padding:12px 14px;text-align:right;background-color:#f9fafb;line-height:16px;"">VAT</th>
<th bgcolor=""#f9fafb"" align=""right"" style=""padding:12px 14px;text-align:right;background-color:#f9fafb;line-height:16px;"">Amount</th>
</tr>
</thead>
<tbody>{itemRows}</tbody>
</table>
<table role=""presentation"" width=""100%"" cellpadding=""0"" cellspacing=""0"" border=""0"" style=""width:100%;border-collapse:collapse;margin-top:20px;mso-table-lspace:0pt;mso-table-rspace:0pt;"">
<tr>
<td style=""width:58%;"">&nbsp;</td>
<td style=""width:42%;vertical-align:top;"">
<table role=""presentation"" width=""100%"" cellpadding=""0"" cellspacing=""0"" border=""0"" style=""width:100%;border-collapse:collapse;color:#374151;font-size:14px;mso-table-lspace:0pt;mso-table-rspace:0pt;"">
<tr>
<td style=""padding:8px 0;text-align:left;line-height:20px;"">{Html(Translate("Public.payment.summary.subtotal"))}</td>
<td align=""right"" style=""padding:8px 0;text-align:right;font-weight:700;color:#111827;white-space:nowrap;line-height:20px;"">{FormatPrice(order.Subtotal)}</td>
</tr>
<tr>
<td style=""padding:8px 0;text-align:left;line-height:20px;"">{Html(Translate("Public.products.kdv"))}</td>
<td align=""right"" style=""padding:8px 0;text-align:right;font-weight:700;color:#111827;white-space:nowrap;line-height:20px;"">{FormatPrice(order.VatTotal)}</td>
</tr>
<tr>
<td style=""padding:8px 0;text-align:left;line-height:20px;"">{Html(Translate("Public.payment.installments.commission"))}</td>
<td align=""right"" style=""padding:8px 0;text-align:right;font-weight:700;color:#111827;white-space:nowrap;line-height:20px;"">{FormatPrice(order.Commission)}</td>
</tr>
<tr>
<td style=""padding:14px 0 0;border-top:1px solid #e5e7eb;text-align:left;font-size:18px;line-height:24px;font-weight:800;color:#111827;"">{Html(Translate("App.Listform.ListformField.Total"))}</td>
<td align=""right"" style=""padding:14px 0 0;border-top:1px solid #e5e7eb;text-align:right;font-size:18px;line-height:24px;font-weight:800;color:#2563eb;white-space:nowrap;"">{FormatPrice(order.Total)}</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>";
}
private string Translate(string key)
{
if (key.IsNullOrWhiteSpace())
{
return string.Empty;
}
var normalizedKey = key.StartsWith("::", StringComparison.Ordinal) ? key[2..] : key;
var text = L[normalizedKey];
return text.ResourceNotFound ? key : text.Value;
}
private static string BillingCycleLabel(string billingCycle)
{
return billingCycle == "monthly" ? "Aylık" : "Yıllık";
}
private static string NormalizePhoneNumber(string value, string country)
{
if (value.IsNullOrWhiteSpace())
{
return value;
}
var digits = new string(value.Where(char.IsDigit).ToArray());
if (country == "Türkiye" || digits.StartsWith("90"))
{
if (digits.StartsWith("90") && digits.Length > 10)
{
digits = digits[^10..];
}
if (digits.StartsWith("0") && digits.Length > 10)
{
digits = digits[^10..];
}
}
return digits;
}
private static string FormatPhoneNumber(string value)
{
var digits = NormalizePhoneNumber(value, string.Empty);
if (digits?.Length != 10)
{
return value;
}
return $"({digits[..3]}) {digits[3..6]}-{digits[6..]}";
}
private static string FormatDate(DateTime? value)
{
return value.HasValue ? value.Value.ToString("dd.MM.yyyy") : "-";
}
private static string FormatPrice(decimal value)
{
return string.Format(new System.Globalization.CultureInfo("tr-TR"), "{0:C2}", value);
}
private static string Html(string value)
{
return WebUtility.HtmlEncode(value ?? string.Empty);
}
public async Task<AboutDto> GetAboutAsync() public async Task<AboutDto> GetAboutAsync()
{ {
var entity = await _aboutRepository.FirstOrDefaultAsync() ?? throw new EntityNotFoundException(typeof(About)); var entity = await _aboutRepository.FirstOrDefaultAsync() ?? throw new EntityNotFoundException(typeof(About));
@ -526,9 +886,74 @@ public class PublicAppService : PlatformAppService
public async Task<List<CountryDto>> GetCountryAsync() public async Task<List<CountryDto>> GetCountryAsync()
{ {
var entities = await _countryRepository.GetListAsync() ?? throw new EntityNotFoundException(typeof(Country)); var queryable = await _countryRepository.GetQueryableAsync();
return ObjectMapper.Map<List<Country>, List<CountryDto>>(entities); return await AsyncExecuter.ToListAsync(
queryable
.OrderBy(country => country.Name)
.Select(country => new CountryDto
{
Id = country.Id,
Name = country.Name,
GroupName = country.GroupName,
Currency = country.Currency,
PhoneCode = country.PhoneCode,
PhoneNumberMinLength = country.PhoneNumberMinLength,
PhoneNumberMaxLength = country.PhoneNumberMaxLength,
PhoneNumberFormat = country.PhoneNumberFormat,
TaxLabel = country.TaxLabel,
ZipRequired = country.ZipRequired,
StateRequired = country.StateRequired,
Cities = new List<CityDto>()
}));
}
public async Task<List<CityDto>> GetCityAsync(string country)
{
if (string.IsNullOrWhiteSpace(country))
{
return [];
}
var queryable = await _cityRepository.GetQueryableAsync();
return await AsyncExecuter.ToListAsync(
queryable
.Where(city => city.Country == country)
.OrderBy(city => city.Name)
.Select(city => new CityDto
{
Id = city.Id,
Country = city.Country,
Name = city.Name,
PlateCode = city.PlateCode
}));
}
public async Task<List<DistrictDto>> GetDistrictAsync(string country, string city)
{
if (string.IsNullOrWhiteSpace(country) || string.IsNullOrWhiteSpace(city))
{
return [];
}
var queryable = await _districtRepository.GetQueryableAsync();
var entities = await AsyncExecuter.ToListAsync(
queryable
.Where(district => district.Country == country && district.City == city)
.OrderBy(district => district.Name));
return entities
.Select(district => new DistrictDto
{
Id = district.Id,
Country = district.Country,
City = district.City,
Name = district.Name,
Township = district.Township,
PostalCode = district.PostalCode
})
.ToList();
} }
public async Task SaveContactPageAsync(SaveContactPageInput input) public async Task SaveContactPageAsync(SaveContactPageInput input)

View file

@ -74,7 +74,7 @@ public class PlatformTenantAppService : TenantAppService, IPlatformTenantAppServ
} }
var dto = ObjectMapper.Map<Tenant, CustomTenantDto>(tenant); var dto = ObjectMapper.Map<Tenant, CustomTenantDto>(tenant);
dto.IsActive = tenant.GetIsActive(); dto.Name = tenant.Name;
dto.OrganizationName = tenant.GetOrganizationName(); dto.OrganizationName = tenant.GetOrganizationName();
dto.Founder = tenant.GetFounder(); dto.Founder = tenant.GetFounder();
dto.VknTckn = tenant.GetVknTckn(); dto.VknTckn = tenant.GetVknTckn();

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -40,6 +40,22 @@
"selectOptions": {}, "selectOptions": {},
"order": 2 "order": 2
}, },
{
"code": "App.SiteManagement.General.NewTenantNotificationEmails",
"nameKey": "App.SiteManagement.General.NewTenantNotificationEmails",
"descriptionKey": "App.SiteManagement.General.NewTenantNotificationEmails.Description",
"defaultValue": "destek@sozsoft.com",
"isVisibleToClients": false,
"providers": "T|G|D",
"isInherited": false,
"isEncrypted": false,
"mainGroupKey": "App.SiteManagement",
"subGroupKey": "App.SiteManagement.General",
"requiredPermissionName": "App.SiteManagement.General",
"dataType": "Text",
"selectOptions": {},
"order": 3
},
{ {
"code": "App.SiteManagement.Theme.Style", "code": "App.SiteManagement.Theme.Style",
"nameKey": "App.SiteManagement.Theme.Style", "nameKey": "App.SiteManagement.Theme.Style",

View file

@ -248,6 +248,9 @@ public class HostDataSeeder : IDataSeedContributor, ITransientDependency
groupName, groupName,
item.Currency, item.Currency,
item.PhoneCode, item.PhoneCode,
item.PhoneNumberMinLength,
item.PhoneNumberMaxLength,
item.PhoneNumberFormat,
item.TaxLabel item.TaxLabel
)); ));
@ -339,11 +342,11 @@ public class HostDataSeeder : IDataSeedContributor, ITransientDependency
// 1. Mevcut kayıtları çek (tek sorguda) // 1. Mevcut kayıtları çek (tek sorguda)
var existingDistricts = await dbCtx.Set<District>() var existingDistricts = await dbCtx.Set<District>()
.Select(d => new { d.Country, d.City, d.Name, d.Township }) .Select(d => new { d.Country, d.City, d.Name, d.Township, d.PostalCode })
.ToListAsync(); .ToListAsync();
var existingSet = existingDistricts var existingSet = existingDistricts
.Select(d => $"{d.Country}:{d.City}:{d.Name}:{d.Township}") .Select(d => $"{d.Country}:{d.City}:{d.Name}:{d.Township}:{d.PostalCode}")
.ToHashSet(); .ToHashSet();
var options = new JsonSerializerOptions var options = new JsonSerializerOptions
@ -359,7 +362,7 @@ public class HostDataSeeder : IDataSeedContributor, ITransientDependency
{ {
if (item == null) continue; if (item == null) continue;
var key = $"{item.Country}:{item.City}:{item.Name}:{item.Township}"; var key = $"{item.Country}:{item.City}:{item.Name}:{item.Township}:{item.PostalCode}";
if (existingSet.Contains(key)) continue; if (existingSet.Contains(key)) continue;
buffer.Add(new District( buffer.Add(new District(
@ -367,7 +370,8 @@ public class HostDataSeeder : IDataSeedContributor, ITransientDependency
item.Country, item.Country,
item.City, item.City,
item.Name, item.Name,
item.Township item.Township,
item.PostalCode
)); ));
if (buffer.Count >= 5000) // 3. Batch if (buffer.Count >= 5000) // 3. Batch

File diff suppressed because it is too large Load diff

View file

@ -67,11 +67,13 @@ public static class ListFormSeeder_DefaultJsons
public static string DefaultLayoutJson(string DefaultLayout = "grid") => JsonSerializer.Serialize(new LayoutDto() public static string DefaultLayoutJson(string DefaultLayout = "grid") => JsonSerializer.Serialize(new LayoutDto()
{ {
Grid = true, Grid = true,
Card = true,
Pivot = true, Pivot = true,
Chart = true, Chart = true,
Tree = true, Tree = true,
Gantt = true, Gantt = true,
Scheduler = true, Scheduler = true,
Todo = true,
DefaultLayout = DefaultLayout, DefaultLayout = DefaultLayout,
}); });
public static readonly string DefaultExportJson = JsonSerializer.Serialize(new ChartExportDto public static readonly string DefaultExportJson = JsonSerializer.Serialize(new ChartExportDto
@ -84,7 +86,7 @@ public static class ListFormSeeder_DefaultJsons
}); });
public static readonly string DefaultSelectionSingleJson = JsonSerializer.Serialize(new SelectionDto public static readonly string DefaultSelectionSingleJson = JsonSerializer.Serialize(new SelectionDto
{ {
Mode = GridOptions.SelectionModeNone, Mode = GridOptions.SelectionModeSingle,
AllowSelectAll = false AllowSelectAll = false
}); });
public static readonly string DefaultSelectionMultipleJson = JsonSerializer.Serialize(new SelectionDto public static readonly string DefaultSelectionMultipleJson = JsonSerializer.Serialize(new SelectionDto
@ -122,6 +124,14 @@ public static class ListFormSeeder_DefaultJsons
{ {
IsPivot = true IsPivot = true
}); });
public static string DefaultColumnTotalSummaryJson(string showInColumn, string summaryType = "sum") => JsonSerializer.Serialize(new ColumnTotalSummaryDto
{
SummaryType = summaryType,
DisplayFormat = "{0}",
ValueFormat = "#,##0.00",
ShowInColumn = showInColumn
});
public static string DefaultGroupingJson(int groupIndex) => JsonSerializer.Serialize(new ColumnGroupingDto public static string DefaultGroupingJson(int groupIndex) => JsonSerializer.Serialize(new ColumnGroupingDto
{ {
AllowGrouping = true, AllowGrouping = true,

View file

@ -1,13 +1,5 @@
{ {
"Routes": [ "Routes": [
{
"key": "roleListComponent",
"path": "/admin/RoleListComponent",
"componentType": "dynamic",
"componentPath": "RoleListComponent",
"routeType": "protected",
"authority": []
},
{ {
"key": "home", "key": "home",
"path": "/home", "path": "/home",
@ -509,31 +501,11 @@
"IsDisabled": false, "IsDisabled": false,
"ShortName": "Sas" "ShortName": "Sas"
}, },
{
"ParentCode": "App.Saas",
"Code": "AbpTenantManagement.Tenants",
"DisplayName": "AbpTenantManagement.Tenants",
"Order": 1,
"Url": "/admin/list/AbpTenantManagement.Tenants",
"Icon": "FcDepartment",
"RequiredPermissionName": "AbpTenantManagement.Tenants",
"IsDisabled": false
},
{
"ParentCode": "App.Saas",
"Code": "App.Branches",
"DisplayName": "App.Branches",
"Order": 2,
"Url": "/admin/list/App.Branches",
"Icon": "FcTreeStructure",
"RequiredPermissionName": "App.Branches",
"IsDisabled": false
},
{ {
"ParentCode": "App.Saas", "ParentCode": "App.Saas",
"Code": "App.Saas.Definitions", "Code": "App.Saas.Definitions",
"DisplayName": "App.Definitions", "DisplayName": "App.Definitions",
"Order": 3, "Order": 1,
"Url": null, "Url": null,
"Icon": "FcFilingCabinet", "Icon": "FcFilingCabinet",
"RequiredPermissionName": null, "RequiredPermissionName": null,
@ -649,6 +621,146 @@
"RequiredPermissionName": "App.Definitions.Sequence", "RequiredPermissionName": "App.Definitions.Sequence",
"IsDisabled": false "IsDisabled": false
}, },
{
"ParentCode": "App.Saas",
"Code": "App.Public",
"DisplayName": "App.Public",
"Order": 2,
"Url": null,
"Icon": "FcTemplate",
"RequiredPermissionName": null,
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.Home",
"DisplayName": "App.Home",
"Order": 0,
"Url": "/admin/public/home/designer",
"Icon": "FcHome",
"RequiredPermissionName": "App.Home",
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.About",
"DisplayName": "App.About",
"Order": 1,
"Url": "/admin/public/about/designer",
"Icon": "FcAbout",
"RequiredPermissionName": "App.About",
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.Services",
"DisplayName": "App.Services",
"Order": 2,
"Url": "/admin/public/services/designer",
"Icon": "FcServices",
"RequiredPermissionName": "App.Services",
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.Orders.Products",
"DisplayName": "App.Orders.Products",
"Order": 3,
"Url": "/admin/list/App.Orders.Products",
"Icon": "FcDiploma1",
"RequiredPermissionName": "App.Orders.Products",
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.Orders.PaymentMethods",
"DisplayName": "App.Orders.PaymentMethods",
"Order": 4,
"Url": "/admin/list/App.Orders.PaymentMethods",
"Icon": "FcFeedIn",
"RequiredPermissionName": "App.Orders.PaymentMethods",
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.Orders.InstallmentOptions",
"DisplayName": "App.Orders.InstallmentOptions",
"Order": 5,
"Url": "/admin/list/App.Orders.InstallmentOptions",
"Icon": "FcProcess",
"RequiredPermissionName": "App.Orders.InstallmentOptions",
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.Orders.SalesOrders",
"DisplayName": "App.Orders.SalesOrders",
"Order": 6,
"Url": "/admin/list/App.Orders.SalesOrders",
"Icon": "FcCollect",
"RequiredPermissionName": "App.Orders.SalesOrders",
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.BlogManagement.Category",
"DisplayName": "App.BlogManagement.Category",
"Order": 7,
"Url": "/admin/list/App.BlogManagement.Category",
"Icon": "FaCertificate",
"RequiredPermissionName": "App.BlogManagement.Category",
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.BlogManagement.Posts",
"DisplayName": "App.BlogManagement.Posts",
"Order": 8,
"Url": "/admin/list/App.BlogManagement.Posts",
"Icon": "FaWeixin",
"RequiredPermissionName": "App.BlogManagement.Posts",
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.Demos",
"DisplayName": "App.Demos",
"Order": 9,
"Url": "/admin/list/App.Demos",
"Icon": "FcMissedCall",
"RequiredPermissionName": "App.Demos",
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.Contact",
"DisplayName": "App.Contact",
"Order": 10,
"Url": "/admin/public/contact/designer",
"Icon": "FcContacts",
"RequiredPermissionName": "App.Contact",
"IsDisabled": false
},
{
"ParentCode": "App.Saas",
"Code": "AbpTenantManagement.Tenants",
"DisplayName": "AbpTenantManagement.Tenants",
"Order": 3,
"Url": "/admin/list/AbpTenantManagement.Tenants",
"Icon": "FcDepartment",
"RequiredPermissionName": "AbpTenantManagement.Tenants",
"IsDisabled": false
},
{
"ParentCode": "App.Saas",
"Code": "App.Branches",
"DisplayName": "App.Branches",
"Order": 4,
"Url": "/admin/list/App.Branches",
"Icon": "FcTreeStructure",
"RequiredPermissionName": "App.Branches",
"IsDisabled": false
},
{ {
"ParentCode": "App.Saas", "ParentCode": "App.Saas",
"Code": "App.SettingDefinitions", "Code": "App.SettingDefinitions",
@ -780,131 +892,11 @@
"RequiredPermissionName": "App.BackgroundWorkers.Jobs", "RequiredPermissionName": "App.BackgroundWorkers.Jobs",
"IsDisabled": false "IsDisabled": false
}, },
{
"ParentCode": "App.Saas",
"Code": "App.Public",
"DisplayName": "App.Public",
"Order": 12,
"Url": null,
"Icon": "FcTemplate",
"RequiredPermissionName": null,
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.Home",
"DisplayName": "App.Home",
"Order": 0,
"Url": "/admin/public/home/designer",
"Icon": "FcHome",
"RequiredPermissionName": "App.Home",
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.About",
"DisplayName": "App.About",
"Order": 1,
"Url": "/admin/public/about/designer",
"Icon": "FcAbout",
"RequiredPermissionName": "App.About",
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.Services",
"DisplayName": "App.Services",
"Order": 2,
"Url": "/admin/public/services/designer",
"Icon": "FcServices",
"RequiredPermissionName": "App.Services",
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.Orders.Products",
"DisplayName": "App.Orders.Products",
"Order": 3,
"Url": "/admin/list/App.Orders.Products",
"Icon": "FcDiploma1",
"RequiredPermissionName": "App.Orders.Products",
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.Orders.PaymentMethods",
"DisplayName": "App.Orders.PaymentMethods",
"Order": 4,
"Url": "/admin/list/App.Orders.PaymentMethods",
"Icon": "FcFeedIn",
"RequiredPermissionName": "App.Orders.PaymentMethods",
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.Orders.InstallmentOptions",
"DisplayName": "App.Orders.InstallmentOptions",
"Order": 5,
"Url": "/admin/list/App.Orders.InstallmentOptions",
"Icon": "FcProcess",
"RequiredPermissionName": "App.Orders.InstallmentOptions",
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.Orders.SalesOrders",
"DisplayName": "App.Orders.SalesOrders",
"Order": 6,
"Url": "/admin/list/App.Orders.SalesOrders",
"Icon": "FcCollect",
"RequiredPermissionName": "App.Orders.SalesOrders",
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.BlogManagement.Category",
"DisplayName": "App.BlogManagement.Category",
"Order": 7,
"Url": "/admin/list/App.BlogManagement.Category",
"Icon": "FaCertificate",
"RequiredPermissionName": "App.BlogManagement.Category",
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.BlogManagement.Posts",
"DisplayName": "App.BlogManagement.Posts",
"Order": 8,
"Url": "/admin/list/App.BlogManagement.Posts",
"Icon": "FaWeixin",
"RequiredPermissionName": "App.BlogManagement.Posts",
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.Demos",
"DisplayName": "App.Demos",
"Order": 9,
"Url": "/admin/list/App.Demos",
"Icon": "FcMissedCall",
"RequiredPermissionName": "App.Demos",
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.Contact",
"DisplayName": "App.Contact",
"Order": 10,
"Url": "/admin/public/contact/designer",
"Icon": "FcContacts",
"RequiredPermissionName": "App.Contact",
"IsDisabled": false
},
{ {
"ParentCode": "App.Saas", "ParentCode": "App.Saas",
"Code": "App.Menus", "Code": "App.Menus",
"DisplayName": "App.Menus", "DisplayName": "App.Menus",
"Order": 13, "Order": 12,
"Url": null, "Url": null,
"Icon": "FcParallelTasks", "Icon": "FcParallelTasks",
"RequiredPermissionName": null, "RequiredPermissionName": null,
@ -992,22 +984,22 @@
}, },
{ {
"ParentCode": "App.DeveloperKit", "ParentCode": "App.DeveloperKit",
"Code": "App.DeveloperKit.Components", "Code": "App.DeveloperKit.DynamicServices",
"DisplayName": "App.DeveloperKit.Components", "DisplayName": "App.DeveloperKit.DynamicServices",
"Order": 4, "Order": 4,
"Url": "/admin/developerkit/components", "Url": "/admin/developerkit/dynamic-services",
"Icon": "FcBiohazard", "Icon": "FcCommandLine",
"RequiredPermissionName": "App.DeveloperKit.Components", "RequiredPermissionName": "App.DeveloperKit.DynamicServices",
"IsDisabled": false "IsDisabled": false
}, },
{ {
"ParentCode": "App.DeveloperKit", "ParentCode": "App.DeveloperKit",
"Code": "App.DeveloperKit.DynamicServices", "Code": "App.DeveloperKit.Components",
"DisplayName": "App.DeveloperKit.DynamicServices", "DisplayName": "App.DeveloperKit.Components",
"Order": 5, "Order": 5,
"Url": "/admin/developerkit/dynamic-services", "Url": "/admin/developerkit/components",
"Icon": "FcCommandLine", "Icon": "FcBiohazard",
"RequiredPermissionName": "App.DeveloperKit.DynamicServices", "RequiredPermissionName": "App.DeveloperKit.Components",
"IsDisabled": false "IsDisabled": false
}, },
{ {
@ -1041,21 +1033,11 @@
"IsDisabled": false, "IsDisabled": false,
"ShortName": "Adm" "ShortName": "Adm"
}, },
{
"ParentCode": "App.Administration",
"Code": "App.Setting",
"DisplayName": "App.Setting",
"Order": 1,
"Url": "/admin/settings",
"Icon": "FcSettings",
"RequiredPermissionName": "App.Setting",
"IsDisabled": false
},
{ {
"ParentCode": "App.Administration", "ParentCode": "App.Administration",
"Code": "App.Administration.Definitions", "Code": "App.Administration.Definitions",
"DisplayName": "App.Definitions", "DisplayName": "App.Definitions",
"Order": 2, "Order": 1,
"Url": null, "Url": null,
"Icon": "FcFilingCabinet", "Icon": "FcFilingCabinet",
"RequiredPermissionName": null, "RequiredPermissionName": null,
@ -1101,11 +1083,31 @@
"RequiredPermissionName": "App.Definitions.OrgChart", "RequiredPermissionName": "App.Definitions.OrgChart",
"IsDisabled": false "IsDisabled": false
}, },
{
"ParentCode": "App.Administration",
"Code": "App.Licence",
"DisplayName": "App.Licence",
"Order": 2,
"Url": "/admin/form/App.Licence",
"Icon": "FcRules",
"RequiredPermissionName": "App.Licence",
"IsDisabled": false
},
{
"ParentCode": "App.Administration",
"Code": "App.Setting",
"DisplayName": "App.Setting",
"Order": 3,
"Url": "/admin/settings",
"Icon": "FcSettings",
"RequiredPermissionName": "App.Setting",
"IsDisabled": false
},
{ {
"ParentCode": "App.Administration", "ParentCode": "App.Administration",
"Code": "App.Administration.Intranet", "Code": "App.Administration.Intranet",
"DisplayName": "App.Intranet", "DisplayName": "App.Intranet",
"Order": 3, "Order": 4,
"Url": null, "Url": null,
"Icon": "FcConferenceCall", "Icon": "FcConferenceCall",
"RequiredPermissionName": null, "RequiredPermissionName": null,
@ -1175,7 +1177,7 @@
"ParentCode": "App.Administration", "ParentCode": "App.Administration",
"Code": "App.Administration.Restrictions", "Code": "App.Administration.Restrictions",
"DisplayName": "App.Restrictions", "DisplayName": "App.Restrictions",
"Order": 4, "Order": 5,
"Url": null, "Url": null,
"Icon": "FaLock", "Icon": "FaLock",
"RequiredPermissionName": null, "RequiredPermissionName": null,
@ -1205,7 +1207,7 @@
"ParentCode": "App.Administration", "ParentCode": "App.Administration",
"Code": "Abp.Identity", "Code": "Abp.Identity",
"DisplayName": "Abp.Identity", "DisplayName": "Abp.Identity",
"Order": 5, "Order": 6,
"Url": null, "Url": null,
"Icon": "FcConferenceCall", "Icon": "FcConferenceCall",
"RequiredPermissionName": null, "RequiredPermissionName": null,
@ -1295,7 +1297,7 @@
"ParentCode": "App.Administration", "ParentCode": "App.Administration",
"Code": "App.Reports.Management", "Code": "App.Reports.Management",
"DisplayName": "App.Reports.Management", "DisplayName": "App.Reports.Management",
"Order": 6, "Order": 7,
"Url": null, "Url": null,
"Icon": "FcDocument", "Icon": "FcDocument",
"RequiredPermissionName": null, "RequiredPermissionName": null,
@ -1325,7 +1327,7 @@
"ParentCode": "App.Administration", "ParentCode": "App.Administration",
"Code": "App.Videoroom.Dashboard", "Code": "App.Videoroom.Dashboard",
"DisplayName": "App.Videoroom.Dashboard", "DisplayName": "App.Videoroom.Dashboard",
"Order": 7, "Order": 8,
"Url": "/admin/videoroom/dashboard", "Url": "/admin/videoroom/dashboard",
"Icon": "FcVideoCall", "Icon": "FcVideoCall",
"RequiredPermissionName": "App.Videoroom.Dashboard", "RequiredPermissionName": "App.Videoroom.Dashboard",
@ -1335,7 +1337,7 @@
"ParentCode": "App.Administration", "ParentCode": "App.Administration",
"Code": "App.Files", "Code": "App.Files",
"DisplayName": "App.Files", "DisplayName": "App.Files",
"Order": 8, "Order": 9,
"Url": "/admin/files", "Url": "/admin/files",
"Icon": "FcFolder", "Icon": "FcFolder",
"RequiredPermissionName": "App.Files", "RequiredPermissionName": "App.Files",
@ -1345,7 +1347,7 @@
"ParentCode": "App.Administration", "ParentCode": "App.Administration",
"Code": "App.Forum", "Code": "App.Forum",
"DisplayName": "App.Forum", "DisplayName": "App.Forum",
"Order": 9, "Order": 10,
"Url": "/admin/forum", "Url": "/admin/forum",
"Icon": "FcLink", "Icon": "FcLink",
"RequiredPermissionName": "App.ForumManagement.Publish", "RequiredPermissionName": "App.ForumManagement.Publish",

View file

@ -4175,7 +4175,7 @@
"DisplayName": "App.Intranet.Survey", "DisplayName": "App.Intranet.Survey",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4184,7 +4184,7 @@
"DisplayName": "Create", "DisplayName": "Create",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4193,7 +4193,7 @@
"DisplayName": "Update", "DisplayName": "Update",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4202,7 +4202,7 @@
"DisplayName": "Delete", "DisplayName": "Delete",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4211,7 +4211,7 @@
"DisplayName": "Export", "DisplayName": "Export",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4220,7 +4220,7 @@
"DisplayName": "Import", "DisplayName": "Import",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4229,7 +4229,7 @@
"DisplayName": "Note", "DisplayName": "Note",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4238,7 +4238,7 @@
"DisplayName": "Widget", "DisplayName": "Widget",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4247,7 +4247,7 @@
"DisplayName": "App.Intranet.SurveyQuestion", "DisplayName": "App.Intranet.SurveyQuestion",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4256,7 +4256,7 @@
"DisplayName": "Create", "DisplayName": "Create",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4265,7 +4265,7 @@
"DisplayName": "Update", "DisplayName": "Update",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4274,7 +4274,7 @@
"DisplayName": "Delete", "DisplayName": "Delete",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4283,7 +4283,7 @@
"DisplayName": "Export", "DisplayName": "Export",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4292,7 +4292,7 @@
"DisplayName": "Import", "DisplayName": "Import",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4301,7 +4301,7 @@
"DisplayName": "Note", "DisplayName": "Note",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4310,7 +4310,7 @@
"DisplayName": "App.Intranet.SurveyQuestionOption", "DisplayName": "App.Intranet.SurveyQuestionOption",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4319,7 +4319,7 @@
"DisplayName": "Create", "DisplayName": "Create",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4328,7 +4328,7 @@
"DisplayName": "Update", "DisplayName": "Update",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4337,7 +4337,7 @@
"DisplayName": "Delete", "DisplayName": "Delete",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4346,7 +4346,7 @@
"DisplayName": "Export", "DisplayName": "Export",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4355,7 +4355,7 @@
"DisplayName": "Import", "DisplayName": "Import",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4364,7 +4364,7 @@
"DisplayName": "App.Intranet.SurveyResponse", "DisplayName": "App.Intranet.SurveyResponse",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4373,7 +4373,7 @@
"DisplayName": "Create", "DisplayName": "Create",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4382,7 +4382,7 @@
"DisplayName": "Update", "DisplayName": "Update",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4391,7 +4391,7 @@
"DisplayName": "Delete", "DisplayName": "Delete",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4400,7 +4400,7 @@
"DisplayName": "Export", "DisplayName": "Export",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4409,7 +4409,7 @@
"DisplayName": "Import", "DisplayName": "Import",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4418,7 +4418,7 @@
"DisplayName": "Note", "DisplayName": "Note",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4427,7 +4427,7 @@
"DisplayName": "App.Intranet.SurveyAnswer", "DisplayName": "App.Intranet.SurveyAnswer",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4436,7 +4436,7 @@
"DisplayName": "Create", "DisplayName": "Create",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4445,7 +4445,7 @@
"DisplayName": "Update", "DisplayName": "Update",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4454,7 +4454,7 @@
"DisplayName": "Delete", "DisplayName": "Delete",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4463,7 +4463,7 @@
"DisplayName": "Export", "DisplayName": "Export",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4472,7 +4472,7 @@
"DisplayName": "Import", "DisplayName": "Import",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4480,8 +4480,8 @@
"ParentName": null, "ParentName": null,
"DisplayName": "App.Videoroom", "DisplayName": "App.Videoroom",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 2, "MultiTenancySide": 3,
"MenuGroup": "Kurs" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4489,8 +4489,8 @@
"ParentName": "App.Videoroom", "ParentName": "App.Videoroom",
"DisplayName": "App.Videoroom.Dashboard", "DisplayName": "App.Videoroom.Dashboard",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 2, "MultiTenancySide": 3,
"MenuGroup": "Kurs" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4498,8 +4498,8 @@
"ParentName": "App.Videoroom", "ParentName": "App.Videoroom",
"DisplayName": "App.Videoroom.List", "DisplayName": "App.Videoroom.List",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 2, "MultiTenancySide": 3,
"MenuGroup": "Kurs" "MenuGroup": "Erp|Kurs"
}, },
{ {
"GroupName": "App.Administration", "GroupName": "App.Administration",
@ -4507,8 +4507,116 @@
"ParentName": "App.Videoroom", "ParentName": "App.Videoroom",
"DisplayName": "App.Videoroom.RoomDetail", "DisplayName": "App.Videoroom.RoomDetail",
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 2, "MultiTenancySide": 3,
"MenuGroup": "Kurs" "MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.Licence",
"ParentName": null,
"DisplayName": "App.Licence",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.Licence.Create",
"ParentName": "App.Licence",
"DisplayName": "Create",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.Licence.Update",
"ParentName": "App.Licence",
"DisplayName": "Update",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.Licence.Delete",
"ParentName": "App.Licence",
"DisplayName": "Delete",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.Licence.Export",
"ParentName": "App.Licence",
"DisplayName": "Export",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.Licence.Import",
"ParentName": "App.Licence",
"DisplayName": "Import",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.LicenceItem",
"ParentName": null,
"DisplayName": "App.LicenceItem",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.LicenceItem.Create",
"ParentName": "App.LicenceItem",
"DisplayName": "Create",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.LicenceItem.Update",
"ParentName": "App.LicenceItem",
"DisplayName": "Update",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.LicenceItem.Delete",
"ParentName": "App.LicenceItem",
"DisplayName": "Delete",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.LicenceItem.Export",
"ParentName": "App.LicenceItem",
"DisplayName": "Export",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.LicenceItem.Import",
"ParentName": "App.LicenceItem",
"DisplayName": "Import",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
} }
] ]
} }

View file

@ -0,0 +1,917 @@
CREATE OR REPLACE FUNCTION dbo."Sas_H_ListFormFieldsDictionaryJson"
(
p_definition_culture_name VARCHAR(10) DEFAULT 'en',
p_ui_culture_name VARCHAR(10) DEFAULT 'tr',
p_list_form_code VARCHAR(64) DEFAULT NULL,
p_only_base_definitions BOOLEAN DEFAULT TRUE,
p_resource_name VARCHAR(64) DEFAULT NULL
)
RETURNS JSONB
LANGUAGE plpgsql
AS $$
DECLARE
v_result JSONB;
BEGIN
WITH list_form_source AS
(
SELECT
l."Id",
l."ListFormCode",
l."CultureName",
l."Name",
lt_name."Value" AS name_value,
l."Title",
lt_title."Value" AS title_value,
l."Description",
lt_desc."Value" AS description_value,
l."TableName",
NULLIF(
BTRIM(l."SelectCommand"::TEXT),
''
) AS select_command_text,
l."KeyFieldName",
l."UserId",
l."RoleId"
FROM dbo."Sas_H_ListForm" l
/*
SQL Server OUTER APPLY TOP (1)
PostgreSQL LEFT JOIN LATERAL ... LIMIT 1
*/
LEFT JOIN LATERAL
(
SELECT lt."Value"
FROM dbo."Sas_H_LanguageText" lt
WHERE lt."CultureName" = p_ui_culture_name
AND lt."Key" = l."Name"
AND
(
p_resource_name IS NULL
OR lt."ResourceName" = p_resource_name
)
ORDER BY lt."ResourceName"
LIMIT 1
) lt_name ON TRUE
LEFT JOIN LATERAL
(
SELECT lt."Value"
FROM dbo."Sas_H_LanguageText" lt
WHERE lt."CultureName" = p_ui_culture_name
AND lt."Key" = l."Title"
AND
(
p_resource_name IS NULL
OR lt."ResourceName" = p_resource_name
)
ORDER BY lt."ResourceName"
LIMIT 1
) lt_title ON TRUE
LEFT JOIN LATERAL
(
SELECT lt."Value"
FROM dbo."Sas_H_LanguageText" lt
WHERE lt."CultureName" = p_ui_culture_name
AND lt."Key" = l."Description"
AND
(
p_resource_name IS NULL
OR lt."ResourceName" = p_resource_name
)
ORDER BY lt."ResourceName"
LIMIT 1
) lt_desc ON TRUE
WHERE
(
p_definition_culture_name IS NULL
OR l."CultureName" = p_definition_culture_name
)
AND
(
p_list_form_code IS NULL
OR l."ListFormCode" = p_list_form_code
)
AND
(
p_only_base_definitions = FALSE
OR
(
l."UserId" IS NULL
AND l."RoleId" IS NULL
)
)
),
list_forms_json AS
(
SELECT
jsonb_build_object
(
'listFormCode',
l."ListFormCode",
'displayName',
COALESCE(
l.name_value::TEXT,
l."Name",
''
),
'title',
COALESCE(
l.title_value::TEXT,
l."Title",
''
),
'description',
COALESCE(
l.description_value::TEXT,
l."Description",
''
),
'tableName',
COALESCE(
l."TableName",
''
),
'sqlSourceName',
COALESCE(
NULLIF(
l."TableName",
''
),
l.select_command_text,
''
),
'sourceKind',
CASE
WHEN COALESCE(
NULLIF(
l."TableName",
''
),
l.select_command_text
) IS NULL
THEN 'unknown'
WHEN UPPER(
BTRIM(
COALESCE(
NULLIF(
l."TableName",
''
),
l.select_command_text
)
)
) LIKE 'SELECT%'
THEN 'selectSql'
ELSE 'table'
END,
'keyFieldName',
COALESCE(
l."KeyFieldName",
''
),
'searchText',
CONCAT_WS(
' ',
l."ListFormCode",
l."TableName",
l.select_command_text,
COALESCE(
l.name_value::TEXT,
l."Name"
),
COALESCE(
l.title_value::TEXT,
l."Title"
),
COALESCE(
l.description_value::TEXT,
l."Description"
)
),
'fields',
COALESCE
(
(
SELECT
jsonb_agg
(
jsonb_build_object
(
'field',
f."FieldName",
'displayName',
COALESCE(
lt_cap."Value"::TEXT,
f."CaptionName",
''
),
'sqlDataType',
sc.sql_data_type,
'listOrderNo',
f."ListOrderNo",
'isVisible',
COALESCE(
f."Visible",
TRUE
),
'isBooleanColumn',
CASE
WHEN sc.sql_data_type = 'boolean'
THEN TRUE
WHEN f."FieldName" LIKE 'Is%'
THEN TRUE
WHEN f."FieldName" LIKE 'Has%'
THEN TRUE
WHEN f."FieldName" IN
(
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday'
)
THEN TRUE
WHEN f."FieldName" IN
(
'EmailConfirmed',
'TwoFactorEnabled',
'IsVerified',
'IsDefault',
'IsPublic',
'IsEnabled',
'IsPublished',
'IsPinned',
'IsAnonymous',
'IsFixed',
'IsCustomized',
'IsEncrypted',
'IsInherited',
'ZipRequired',
'StateRequired'
)
THEN TRUE
ELSE FALSE
END,
'lookupJsonText',
lj.lookup_json_text_decoded,
'lookupTableName',
COALESCE
(
CASE
WHEN lj.lookup_json IS NOT NULL
THEN COALESCE
(
lj.lookup_json ->> 'tableName',
lj.lookup_json ->> 'sqlTableName',
lj.lookup_json ->> 'lookupTableName',
lj.lookup_json #>> '{dataSource,tableName}',
lj.lookup_json #>> '{dataSource,sqlTableName}'
)
END,
lkp.parsed_lookup_table_name
),
'lookupValueColumn',
COALESCE
(
CASE
WHEN lj.lookup_json IS NOT NULL
THEN COALESCE
(
lj.lookup_json ->> 'valueExpr',
lj.lookup_json ->> 'valueField',
lj.lookup_json ->> 'valueColumn',
lj.lookup_json ->> 'keyField',
lj.lookup_json ->> 'keyFieldName'
)
END,
lkp.parsed_lookup_value_column
),
'lookupDisplayColumn',
COALESCE
(
CASE
WHEN lj.lookup_json IS NOT NULL
THEN COALESCE
(
lj.lookup_json ->> 'displayExpr',
lj.lookup_json ->> 'displayField',
lj.lookup_json ->> 'displayColumn',
lj.lookup_json ->> 'textField',
lj.lookup_json ->> 'textColumn',
lj.lookup_json ->> 'nameField',
lj.lookup_json ->> 'nameColumn'
)
END,
lkp.parsed_lookup_display_column
),
'lookupJoinMode',
CASE
WHEN lj.lookup_json_text_decoded IS NOT NULL
AND f."FieldName" NOT LIKE '%Id'
AND COALESCE(
lkp.parsed_lookup_value_column,
''
) IN
(
'Name',
'Code',
'Key',
'Value',
'key',
'value'
)
THEN 'direct-string'
WHEN lj.lookup_json_text_decoded IS NOT NULL
AND f."FieldName" NOT LIKE '%Id'
THEN 'direct-string'
WHEN lj.lookup_json_text_decoded IS NOT NULL
OR f."FieldName" LIKE '%Id'
THEN 'convert-nvarchar-safe'
ELSE NULL
END,
'lookupFallbackToSourceColumn',
CASE
WHEN
lj.lookup_json_text_decoded IS NOT NULL
AND f."FieldName" NOT LIKE '%Id'
THEN TRUE
ELSE FALSE
END,
'lookupSearchText',
CASE
WHEN lj.lookup_json_text_decoded IS NOT NULL
THEN CONCAT_WS
(
' ',
f."FieldName",
f."CaptionName",
lt_cap."Value"::TEXT,
lj.lookup_json_text_decoded
)
END,
'isActiveStatusColumn',
f."FieldName" IN
(
'IsActive',
'IsEnabled',
'IsPublished'
),
'isDeletedStatusColumn',
f."FieldName" IN
(
'IsDeleted',
'Deleted',
'IsRemoved'
),
'isSensitive',
CASE
WHEN f."FieldName" LIKE '%Password%'
OR f."FieldName" LIKE '%ConnectionString%'
OR f."FieldName" LIKE '%Token%'
OR f."FieldName" LIKE '%Secret%'
OR f."FieldName" LIKE '%ApiKey%'
OR f."FieldName" LIKE '%PrivateKey%'
THEN TRUE
ELSE FALSE
END,
'isDefaultSelectColumn',
CASE
WHEN
COALESCE(
f."Visible",
TRUE
) = TRUE
AND COALESCE(
f."IsActive",
TRUE
) = TRUE
AND f."FieldName" NOT LIKE '%Password%'
AND f."FieldName" NOT LIKE '%ConnectionString%'
AND f."FieldName" NOT LIKE '%Token%'
AND f."FieldName" NOT LIKE '%Secret%'
AND f."FieldName" NOT LIKE '%ApiKey%'
AND f."FieldName" NOT LIKE '%PrivateKey%'
AND f."FieldName" NOT IN
(
'Avatar',
'ExtraProperties'
)
THEN TRUE
ELSE FALSE
END
)
ORDER BY
COALESCE(
f."ListOrderNo",
999999
),
f."FieldName"
)
FROM dbo."Sas_H_ListFormField" f
/*
SQL Server:
sys.tables
sys.columns
TYPE_NAME()
PostgreSQL:
information_schema.columns
*/
LEFT JOIN LATERAL
(
SELECT
c.data_type AS sql_data_type
FROM information_schema.columns c
WHERE
c.table_schema = 'dbo'
AND c.table_name =
l."TableName"
AND c.column_name =
f."FieldName"
LIMIT 1
) sc ON TRUE
/*
LookupJson decode
*/
LEFT JOIN LATERAL
(
SELECT
NULLIF
(
BTRIM
(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
NULLIF(
BTRIM(
f."LookupJson"::TEXT
),
''
),
'\\u0022',
'"'
),
'\u0022',
'"'
),
'\\u0027',
''''
),
'\u0027',
''''
),
'&quot;',
'"'
)
),
''
) AS lookup_json_text_decoded
) lj_text ON TRUE
/*
PostgreSQL'de ISJSON yerine
güvenli JSON parse işlemi gerekiyor.
LookupJson kolonu zaten JSON/JSONB ise
doğrudan kullanılabilir.
*/
LEFT JOIN LATERAL
(
SELECT
lj_text.lookup_json_text_decoded,
CASE
WHEN
lj_text.lookup_json_text_decoded
~ '^\s*[\{\[]'
THEN
lj_text.lookup_json_text_decoded::JSONB
ELSE NULL
END AS lookup_json
) lj ON TRUE
/*
LookupQuery değerini al
*/
LEFT JOIN LATERAL
(
SELECT
CASE
WHEN lj.lookup_json IS NOT NULL
THEN
lj.lookup_json
->> 'LookupQuery'
END AS lookup_query_text
) lq ON TRUE
/*
LookupQuery temizleme
*/
LEFT JOIN LATERAL
(
SELECT
NULLIF
(
BTRIM
(
REGEXP_REPLACE
(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
COALESCE(
lq.lookup_query_text,
''
),
'"',
''
),
'[',
''
),
']',
''
),
'`',
''
),
'\s+',
' ',
'g'
)
),
''
) AS clean_lookup_query
) lqc ON TRUE
/*
SQL Server prosedürü LookupQuery içerisindeki
SELECT ... FROM ... ifadesini string işlemleri
ile parse ediyor.
PostgreSQL'de regexp_match daha temiz.
*/
LEFT JOIN LATERAL
(
SELECT
(
REGEXP_MATCH
(
lqc.clean_lookup_query,
'(?i)\bFROM\s+([a-zA-Z0-9_\."]+)'
)
)[1] AS parsed_table,
COALESCE
(
NULLIF(
lj.lookup_json
->> 'ValueExpr',
''
),
NULLIF(
lj.lookup_json
->> 'valueExpr',
''
),
NULLIF(
lj.lookup_json
->> 'valueField',
''
),
NULLIF(
lj.lookup_json
->> 'valueColumn',
''
),
NULLIF(
lj.lookup_json
->> 'keyField',
''
),
NULLIF(
lj.lookup_json
->> 'keyFieldName',
''
)
)
AS parsed_lookup_value_column,
COALESCE
(
NULLIF(
lj.lookup_json
->> 'DisplayExpr',
''
),
NULLIF(
lj.lookup_json
->> 'displayExpr',
''
),
NULLIF(
lj.lookup_json
->> 'displayField',
''
),
NULLIF(
lj.lookup_json
->> 'displayColumn',
''
),
NULLIF(
lj.lookup_json
->> 'textField',
''
),
NULLIF(
lj.lookup_json
->> 'textColumn',
''
),
NULLIF(
lj.lookup_json
->> 'nameField',
''
),
NULLIF(
lj.lookup_json
->> 'nameColumn',
''
)
)
AS parsed_lookup_display_column
) parsed ON TRUE
LEFT JOIN LATERAL
(
SELECT
NULLIF
(
REGEXP_REPLACE
(
COALESCE(
parsed.parsed_table,
''
),
'^(?i:dbo\.)',
''
),
''
)
AS parsed_lookup_table_name,
parsed.parsed_lookup_value_column,
parsed.parsed_lookup_display_column
) lkp ON TRUE
/*
Caption translation
*/
LEFT JOIN LATERAL
(
SELECT
lt."Value"
FROM dbo."Sas_H_LanguageText" lt
WHERE
lt."CultureName" =
p_ui_culture_name
AND lt."Key" =
f."CaptionName"
AND
(
p_resource_name IS NULL
OR lt."ResourceName" =
p_resource_name
)
ORDER BY
lt."ResourceName"
LIMIT 1
) lt_cap ON TRUE
WHERE
f."ListFormCode" =
l."ListFormCode"
AND f."CultureName" =
l."CultureName"
AND
(
p_definition_culture_name IS NULL
OR f."CultureName" =
p_definition_culture_name
)
AND
(
p_only_base_definitions = FALSE
OR
(
f."UserId" IS NULL
AND f."RoleId" IS NULL
)
)
),
'[]'::JSONB
)
)
AS form_json,
l."ListFormCode"
FROM list_form_source l
)
SELECT
jsonb_build_object
(
'listForms',
COALESCE
(
jsonb_agg
(
form_json
ORDER BY
"ListFormCode"
),
'[]'::JSONB
)
)
INTO v_result
FROM list_forms_json;
RETURN COALESCE
(
v_result,
jsonb_build_object
(
'listForms',
'[]'::JSONB
)
);
END;
$$;

View file

@ -0,0 +1,239 @@
CREATE OR REPLACE FUNCTION dbo."Sas_H_ListFormFieldsDictionaryJson_SaveDbTableColumns"
(
p_tenant_name VARCHAR(128) DEFAULT 'Sozsoft',
p_definition_culture_name VARCHAR(10) DEFAULT 'en',
p_ui_culture_name VARCHAR(10) DEFAULT 'tr',
p_list_form_code VARCHAR(64) DEFAULT NULL,
p_only_base_definitions BOOLEAN DEFAULT TRUE,
p_resource_name VARCHAR(64) DEFAULT NULL,
p_max_forms INTEGER DEFAULT 500,
p_deactivate_previous BOOLEAN DEFAULT TRUE,
p_note VARCHAR(4000) DEFAULT NULL
)
RETURNS TABLE
(
"TenantName" VARCHAR,
"DictionaryType" VARCHAR,
"DefinitionCultureName" VARCHAR,
"UiCultureName" VARCHAR,
"ListFormCode" VARCHAR,
"OnlyBaseDefinitions" BOOLEAN,
"ResourceName" VARCHAR,
"MaxForms" INTEGER,
"CacheKey" TEXT,
"FormCount" INTEGER,
"FieldCount" INTEGER,
"JsonLength" INTEGER,
"IsActive" BOOLEAN,
"RefreshedAt" TIMESTAMP,
"SourceProcedure" VARCHAR,
"Note" VARCHAR
)
LANGUAGE plpgsql
AS $$
DECLARE
v_json_data JSONB;
v_cache_key TEXT;
v_form_count INTEGER := 0;
v_field_count INTEGER := 0;
v_json_length INTEGER := 0;
BEGIN
/*
SQL Server:
EXEC dbo.Sas_H_ListFormFieldsDictionaryJson
PostgreSQL tarafında bunun JSON / JSONB döndüren bir FUNCTION
olduğu varsayılmıştır.
*/
SELECT dbo."Sas_H_ListFormFieldsDictionaryJson"
(
p_definition_culture_name,
p_ui_culture_name,
p_list_form_code,
p_only_base_definitions,
p_resource_name
)
INTO v_json_data;
/*
JSON boş kontrolü
*/
IF v_json_data IS NULL THEN
RAISE EXCEPTION
'JSON veri sözlüğü boş döndü. dbo.Sas_H_ListFormFieldsDictionaryJson çıktısını kontrol edin.'
USING ERRCODE = 'P0001';
END IF;
/*
CacheKey oluşturulması
*/
v_cache_key :=
'ListFormJson|'
|| COALESCE(p_tenant_name, '')
|| '|'
|| COALESCE(p_definition_culture_name, '')
|| '|'
|| COALESCE(p_ui_culture_name, '')
|| '|'
|| COALESCE(p_list_form_code, '')
|| '|'
|| CASE
WHEN COALESCE(p_only_base_definitions, TRUE)
THEN '1'
ELSE '0'
END
|| '|'
|| COALESCE(p_resource_name, '')
|| '|'
|| COALESCE(p_max_forms, 500)::TEXT;
/*
Form sayısı
JSON:
{
"listForms": [...]
}
*/
IF jsonb_typeof(v_json_data -> 'listForms') = 'array' THEN
v_form_count :=
jsonb_array_length(v_json_data -> 'listForms');
END IF;
/*
Toplam Field sayısı
Her listForms elemanının:
{
"fields": [...]
}
alanındaki kayıtlar sayılır.
*/
SELECT COUNT(*)::INTEGER
INTO v_field_count
FROM jsonb_array_elements(
COALESCE(
v_json_data -> 'listForms',
'[]'::JSONB
)
) AS lf
CROSS JOIN LATERAL jsonb_array_elements(
CASE
WHEN jsonb_typeof(lf -> 'fields') = 'array'
THEN lf -> 'fields'
ELSE '[]'::JSONB
END
) AS ff;
/*
JSON karakter uzunluğu
*/
v_json_length := LENGTH(v_json_data::TEXT);
/*
PostgreSQL function çağrısı kendi transaction'ı içerisinde
çalıştığı için SQL Server'daki BEGIN TRAN / COMMIT burada
ayrıca kullanılmaz.
*/
/*
Önceki aktif kaydı pasif yap
*/
IF p_deactivate_previous THEN
UPDATE dbo."Sas_H_DbTableColumn"
SET "IsActive" = FALSE
WHERE "DictionaryType" = 'ListFormJson'
AND "CacheKey" = v_cache_key
AND COALESCE("IsActive", FALSE) = TRUE;
END IF;
/*
Yeni JSON kaydını ekle
*/
INSERT INTO dbo."Sas_H_DbTableColumn"
(
"TenantName",
"DictionaryType",
"DefinitionCultureName",
"UiCultureName",
"ListFormCode",
"OnlyBaseDefinitions",
"ResourceName",
"MaxForms",
"CacheKey",
"JsonData",
"FormCount",
"FieldCount",
"JsonLength",
"IsActive",
"RefreshedAt",
"SourceProcedure",
"Note"
)
VALUES
(
COALESCE(p_tenant_name, 'Sozsoft'),
'ListFormJson',
COALESCE(p_definition_culture_name, 'en'),
COALESCE(p_ui_culture_name, 'tr'),
p_list_form_code,
COALESCE(p_only_base_definitions, TRUE),
p_resource_name,
COALESCE(p_max_forms, 500),
v_cache_key,
v_json_data,
v_form_count,
v_field_count,
v_json_length,
TRUE,
CURRENT_TIMESTAMP,
'dbo.Sas_H_ListFormFieldsDictionaryJson',
p_note
);
/*
Eklenen aktif kaydı döndür
*/
RETURN QUERY
SELECT
T."TenantName",
T."DictionaryType",
T."DefinitionCultureName",
T."UiCultureName",
T."ListFormCode",
T."OnlyBaseDefinitions",
T."ResourceName",
T."MaxForms",
T."CacheKey",
T."FormCount",
T."FieldCount",
T."JsonLength",
T."IsActive",
T."RefreshedAt",
T."SourceProcedure",
T."Note"
FROM dbo."Sas_H_DbTableColumn" T
WHERE T."DictionaryType" = 'ListFormJson'
AND T."CacheKey" = v_cache_key
AND T."IsActive" = TRUE
ORDER BY T."RefreshedAt" DESC
LIMIT 1;
END;
$$;

View file

@ -0,0 +1,22 @@
CREATE OR REPLACE VIEW dbo."Sas_H_OrderItem_ByTenantId"
AS
SELECT
oi."Id",
o."TenantId",
oi."ProductId",
oi."ProductName",
oi."BillingCycle",
oi."Period",
oi."Quantity",
oi."Price",
oi."VatRate",
oi."VatAmount",
oi."TotalPrice",
oi."OrderId",
o."IsActive"
FROM dbo."Sas_H_Order" o
INNER JOIN dbo."Sas_H_OrderItem" oi
ON o."Id" = oi."OrderId";

View file

@ -0,0 +1,8 @@
-- Create View
CREATE OR ALTER VIEW [dbo].[Sas_H_OrderItem_ByTenantId]
AS
SELECT dbo.Sas_H_OrderItem.Id, dbo.Sas_H_Order.TenantId, dbo.Sas_H_OrderItem.ProductId, dbo.Sas_H_OrderItem.ProductName, dbo.Sas_H_OrderItem.BillingCycle, dbo.Sas_H_OrderItem.Period, dbo.Sas_H_OrderItem.Quantity,
dbo.Sas_H_OrderItem.Price, dbo.Sas_H_OrderItem.VatRate, dbo.Sas_H_OrderItem.VatAmount, dbo.Sas_H_OrderItem.TotalPrice, dbo.Sas_H_OrderItem.OrderId, dbo.Sas_H_Order.IsActive
FROM dbo.Sas_H_Order INNER JOIN
dbo.Sas_H_OrderItem ON dbo.Sas_H_Order.Id = dbo.Sas_H_OrderItem.OrderId

View file

@ -0,0 +1,18 @@
IF OBJECT_ID(N'[dbo].[Pro_T_Approval]', 'U') IS NULL
BEGIN
CREATE TABLE [dbo].[Pro_T_Approval]
(
[Id] uniqueidentifier NOT NULL DEFAULT NEWID(),
[ApprovalUserName] nvarchar(256) NULL,
[ApprovalStatus] nvarchar(50) NULL,
[ApprovalDate] datetime NULL,
[ApprovalDescription] nvarchar(200) NULL,
[TenantId] uniqueidentifier NULL,
[Title] nvarchar(100) NULL,
CONSTRAINT [PK_Pro_T_Approval] PRIMARY KEY NONCLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO

View file

@ -0,0 +1,22 @@
IF OBJECT_ID(N'[dbo].[Pro_T_Todo]', 'U') IS NULL
BEGIN
CREATE TABLE [dbo].[Pro_T_Todo]
(
[Id] uniqueidentifier NOT NULL DEFAULT NEWID(),
[Title] nvarchar(300) NOT NULL,
[Status] nvarchar(50) NOT NULL DEFAULT N'Inbox',
[Description] nvarchar(MAX) NULL,
[DueDate] datetime2 NULL,
[Tags] nvarchar(500) NULL,
[Assignees] nvarchar(500) NULL,
[Priority] nvarchar(50) NULL,
[Completed] bit NOT NULL DEFAULT 0,
[SortOrder] int NOT NULL DEFAULT 0,
[TenantId] uniqueidentifier NULL,
CONSTRAINT [PK_Table] PRIMARY KEY NONCLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO

View file

@ -1,25 +0,0 @@
IF OBJECT_ID(N'[dbo].[Sal_T_Approval]', 'U') IS NULL
BEGIN
CREATE TABLE [dbo].[Sal_T_Approval]
(
[Id] uniqueidentifier NOT NULL DEFAULT NEWID(),
[CreationTime] datetime2 NOT NULL DEFAULT GETUTCDATE(),
[CreatorId] uniqueidentifier NULL,
[LastModificationTime] datetime2 NULL,
[LastModifierId] uniqueidentifier NULL,
[IsDeleted] bit NOT NULL DEFAULT 0,
[DeletionTime] datetime2 NULL,
[DeleterId] uniqueidentifier NULL,
[TenantId] uniqueidentifier NULL,
[ApprovalUserName] nvarchar(256) NULL,
[ApprovalStatus] nvarchar(50) NULL,
[ApprovalDate] datetime NULL,
[ApprovalDescription] nvarchar(200) NULL,
[Name] nvarchar(100) NULL,
CONSTRAINT [PK_Sal_T_Approval] PRIMARY KEY NONCLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO

View file

@ -13,27 +13,30 @@
"ConfirmDelete": true, "ConfirmDelete": true,
"DefaultLayout": "grid", "DefaultLayout": "grid",
"Grid": true, "Grid": true,
"Card": true,
"Pivot": true, "Pivot": true,
"Tree": true, "Tree": true,
"Chart": true, "Chart": true,
"Gantt": true, "Gantt": true,
"Scheduler": true, "Scheduler": true,
"Todo": false,
"LanguageTextMenuEn": "Approval", "LanguageTextMenuEn": "Approval",
"LanguageTextMenuTr": "Approval", "LanguageTextMenuTr": "Onaylama",
"LanguageTextTitleEn": "Approval", "LanguageTextTitleEn": "Approval",
"LanguageTextTitleTr": "Onaylama", "LanguageTextTitleTr": "Onaylama",
"LanguageTextDescEn": "Approval", "LanguageTextDescEn": "Approval",
"LanguageTextDescTr": "Onaylama", "LanguageTextDescTr": "Onaylama",
"LanguageTextMenuParentEn": "Sales", "LanguageTextMenuParentEn": "Project",
"LanguageTextMenuParentTr": "Sat\u0131\u015F", "LanguageTextMenuParentTr": "Project",
"PermissionGroupName": "App.Wizard.Sales", "PermissionGroupName": "App.Wizard.Project",
"MenuParentCode": "App.Wizard.Sales", "MenuParentCode": "App.Wizard.Project",
"MenuParentIcon": "FcAssistant", "MenuParentShortName": "Pro",
"MenuIcon": "FcAndroidOs", "MenuParentIcon": "FcVideoProjector",
"MenuIcon": "FcApproval",
"DataSourceCode": "Default", "DataSourceCode": "Default",
"DataSourceConnectionString": "", "DataSourceConnectionString": "",
"SelectCommandType": 1, "SelectCommandType": 1,
"SelectCommand": "Sal_T_Approval", "SelectCommand": "Pro_T_Approval",
"KeyFieldName": "Id", "KeyFieldName": "Id",
"KeyFieldDbSourceType": 9, "KeyFieldDbSourceType": 9,
"TreeKeyExpr": "", "TreeKeyExpr": "",
@ -49,13 +52,103 @@
"SchedulerTextExpr": "", "SchedulerTextExpr": "",
"SchedulerStartDateExpr": "", "SchedulerStartDateExpr": "",
"SchedulerEndDateExpr": "", "SchedulerEndDateExpr": "",
"TodoTitleExpr": "",
"TodoStatusExpr": "",
"TodoDescriptionExpr": "",
"TodoDueDateExpr": "",
"TodoTagExpr": "",
"TodoAssigneeExpr": "",
"TodoPriorityExpr": "",
"TodoCompletedExpr": "",
"TodoOrderExpr": "",
"TodoStatusOrder": "Backlog, Ready to Start, In Progress, Code Review, Testing, Staging",
"TodoAllowDragging": true,
"ApprovalUserFieldName": "ApprovalUserName",
"ApprovalDateFieldName": "ApprovalDate",
"ApprovalStatusFieldName": "ApprovalStatus",
"ApprovalDescriptionFieldName": "ApprovalDescription",
"ApprovalIsFilterUserName": false,
"Criteria": [
{
"ListFormCode": "App.Wizard.Approval",
"Kind": "Start",
"Title": "\u0130\u015F Ak\u0131\u015F\u0131 Ba\u015Flat1",
"CompareColumn": "Price",
"CompareOperator": "\u003E",
"CompareValue": 5000,
"Approver": "",
"NextOnStart": "App.Wizard.Approval-N002",
"NextOnTrue": "",
"NextOnFalse": "",
"NextOnApprove": "",
"NextOnReject": "",
"PositionX": 46,
"PositionY": 46,
"CompareOutcomes": [],
"Id": "App.Wizard.Approval-N001"
},
{
"ListFormCode": "App.Wizard.Approval",
"Kind": "Approval",
"Title": "Onay1",
"CompareColumn": "Price",
"CompareOperator": "\u003E",
"CompareValue": 5000,
"Approver": "system@sozsoft.com",
"NextOnStart": "",
"NextOnTrue": "",
"NextOnFalse": "",
"NextOnApprove": "App.Wizard.Approval-N003",
"NextOnReject": "App.Wizard.Approval-N004",
"PositionX": 337,
"PositionY": 39,
"CompareOutcomes": [],
"Id": "App.Wizard.Approval-N002"
},
{
"ListFormCode": "App.Wizard.Approval",
"Kind": "Inform",
"Title": "Bilgilendirme1",
"CompareColumn": "Price",
"CompareOperator": "\u003E",
"CompareValue": 5000,
"Approver": "system@sozsoft.com",
"NextOnStart": "App.Wizard.Approval-N004",
"NextOnTrue": "",
"NextOnFalse": "",
"NextOnApprove": "",
"NextOnReject": "",
"PositionX": 538,
"PositionY": 324,
"CompareOutcomes": [],
"Id": "App.Wizard.Approval-N003"
},
{
"ListFormCode": "App.Wizard.Approval",
"Kind": "End",
"Title": "\u0130\u015F Ak\u0131\u015F\u0131 Bitir1",
"CompareColumn": "Price",
"CompareOperator": "\u003E",
"CompareValue": 5000,
"Approver": "",
"NextOnStart": "",
"NextOnTrue": "",
"NextOnFalse": "",
"NextOnApprove": "",
"NextOnReject": "",
"PositionX": 852,
"PositionY": 26,
"CompareOutcomes": [],
"Id": "App.Wizard.Approval-N004"
}
],
"Groups": [ "Groups": [
{ {
"Caption": "", "Caption": "",
"ColCount": 1, "ColCount": 1,
"Items": [ "Items": [
{ {
"DataField": "Id", "FieldName": "Id",
"CaptionName": "App.Listform.ListformField.Id", "CaptionName": "App.Listform.ListformField.Id",
"EditorType": "dxTextBox", "EditorType": "dxTextBox",
"EditorOptions": "", "EditorOptions": "",
@ -72,24 +165,7 @@
"LookupQuery": "" "LookupQuery": ""
}, },
{ {
"DataField": "Name", "FieldName": "ApprovalUserName",
"CaptionName": "App.Listform.ListformField.Name",
"EditorType": "dxTextBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": true,
"IncludeInEditingForm": true,
"DbSourceType": 16,
"TurkishCaption": "Name",
"EnglishCaption": "Name",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
},
{
"DataField": "ApprovalUserName",
"CaptionName": "App.Listform.ListformField.ApprovalUserName", "CaptionName": "App.Listform.ListformField.ApprovalUserName",
"EditorType": "dxTextBox", "EditorType": "dxTextBox",
"EditorOptions": "", "EditorOptions": "",
@ -106,7 +182,7 @@
"LookupQuery": "" "LookupQuery": ""
}, },
{ {
"DataField": "ApprovalStatus", "FieldName": "ApprovalStatus",
"CaptionName": "App.Listform.ListformField.ApprovalStatus", "CaptionName": "App.Listform.ListformField.ApprovalStatus",
"EditorType": "dxTextBox", "EditorType": "dxTextBox",
"EditorOptions": "", "EditorOptions": "",
@ -123,7 +199,7 @@
"LookupQuery": "" "LookupQuery": ""
}, },
{ {
"DataField": "ApprovalDate", "FieldName": "ApprovalDate",
"CaptionName": "App.Listform.ListformField.ApprovalDate", "CaptionName": "App.Listform.ListformField.ApprovalDate",
"EditorType": "dxDateBox", "EditorType": "dxDateBox",
"EditorOptions": "", "EditorOptions": "",
@ -140,7 +216,7 @@
"LookupQuery": "" "LookupQuery": ""
}, },
{ {
"DataField": "ApprovalDescription", "FieldName": "ApprovalDescription",
"CaptionName": "App.Listform.ListformField.ApprovalDescription", "CaptionName": "App.Listform.ListformField.ApprovalDescription",
"EditorType": "dxTextBox", "EditorType": "dxTextBox",
"EditorOptions": "", "EditorOptions": "",
@ -155,219 +231,39 @@
"ValueExpr": "Key", "ValueExpr": "Key",
"DisplayExpr": "Name", "DisplayExpr": "Name",
"LookupQuery": "" "LookupQuery": ""
},
{
"FieldName": "Title",
"CaptionName": "App.Listform.ListformField.Title",
"EditorType": "dxTextBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": false,
"IncludeInEditingForm": true,
"DbSourceType": 16,
"TurkishCaption": "Title",
"EnglishCaption": "Title",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
} }
] ]
} }
], ],
"SubForms": [], "SubForms": [],
"Widgets": [], "Widgets": []
"Workflow": {
"ApprovalUserFieldName": "ApprovalUserName",
"IsFilterUserName": true,
"ApprovalDateFieldName": "ApprovalDate",
"ApprovalStatusFieldName": "ApprovalStatus",
"ApprovalDescriptionFieldName": "ApprovalDescription",
"Criteria": [
{
"ListFormCode": "App.Wizard.Approval",
"Kind": "Start",
"Title": "\u0130\u015F Ak\u0131\u015F\u0131 Ba\u015Flat1",
"CompareColumn": "Price",
"CompareOperator": "\u003E",
"CompareValue": 5000,
"Approver": "",
"NextOnStart": "N002",
"NextOnTrue": "",
"NextOnFalse": "",
"NextOnApprove": "",
"NextOnReject": "",
"PositionX": 34,
"PositionY": 104,
"CompareOutcomes": [],
"Id": "N001"
},
{
"ListFormCode": "App.Wizard.Approval",
"Kind": "Approval",
"Title": "Onay1",
"CompareColumn": "Price",
"CompareOperator": "\u003E",
"CompareValue": 5000,
"Approver": "admin@sozsoft.com",
"NextOnStart": "",
"NextOnTrue": "",
"NextOnFalse": "",
"NextOnApprove": "N003",
"NextOnReject": "N004",
"PositionX": 323,
"PositionY": 104,
"CompareOutcomes": [],
"Id": "N002"
},
{
"ListFormCode": "App.Wizard.Approval",
"Kind": "Approval",
"Title": "Onay2",
"CompareColumn": "Price",
"CompareOperator": "\u003E",
"CompareValue": 5000,
"Approver": "demo@sozsoft.com",
"NextOnStart": "",
"NextOnTrue": "",
"NextOnFalse": "",
"NextOnApprove": "N004",
"NextOnReject": "N004",
"PositionX": 586,
"PositionY": 104,
"CompareOutcomes": [],
"Id": "N003"
},
{
"ListFormCode": "App.Wizard.Approval",
"Kind": "Inform",
"Title": "Bilgilendirme1",
"CompareColumn": "Price",
"CompareOperator": "\u003E",
"CompareValue": 5000,
"Approver": "system@sozsoft.com",
"NextOnStart": "N005",
"NextOnTrue": "",
"NextOnFalse": "",
"NextOnApprove": "",
"NextOnReject": "",
"PositionX": 458,
"PositionY": 411,
"CompareOutcomes": [],
"Id": "N004"
},
{
"ListFormCode": "App.Wizard.Approval",
"Kind": "End",
"Title": "\u0130\u015F Ak\u0131\u015F\u0131 Bitir1",
"CompareColumn": "Price",
"CompareOperator": "\u003E",
"CompareValue": 5000,
"Approver": "",
"NextOnStart": "",
"NextOnTrue": "",
"NextOnFalse": "",
"NextOnApprove": "",
"NextOnReject": "",
"PositionX": 792,
"PositionY": 412,
"CompareOutcomes": [],
"Id": "N005"
}
]
},
"WorkflowCriteria": [
{
"ListFormCode": "App.Wizard.Approval",
"Kind": "Start",
"Title": "\u0130\u015F Ak\u0131\u015F\u0131 Ba\u015Flat1",
"CompareColumn": "Price",
"CompareOperator": "\u003E",
"CompareValue": 5000,
"Approver": "",
"NextOnStart": "N002",
"NextOnTrue": "",
"NextOnFalse": "",
"NextOnApprove": "",
"NextOnReject": "",
"PositionX": 34,
"PositionY": 104,
"CompareOutcomes": [],
"Id": "N001"
},
{
"ListFormCode": "App.Wizard.Approval",
"Kind": "Approval",
"Title": "Onay1",
"CompareColumn": "Price",
"CompareOperator": "\u003E",
"CompareValue": 5000,
"Approver": "admin@sozsoft.com",
"NextOnStart": "",
"NextOnTrue": "",
"NextOnFalse": "",
"NextOnApprove": "N003",
"NextOnReject": "N004",
"PositionX": 323,
"PositionY": 104,
"CompareOutcomes": [],
"Id": "N002"
},
{
"ListFormCode": "App.Wizard.Approval",
"Kind": "Approval",
"Title": "Onay2",
"CompareColumn": "Price",
"CompareOperator": "\u003E",
"CompareValue": 5000,
"Approver": "demo@sozsoft.com",
"NextOnStart": "",
"NextOnTrue": "",
"NextOnFalse": "",
"NextOnApprove": "N004",
"NextOnReject": "N004",
"PositionX": 586,
"PositionY": 104,
"CompareOutcomes": [],
"Id": "N003"
},
{
"ListFormCode": "App.Wizard.Approval",
"Kind": "Inform",
"Title": "Bilgilendirme1",
"CompareColumn": "Price",
"CompareOperator": "\u003E",
"CompareValue": 5000,
"Approver": "system@sozsoft.com",
"NextOnStart": "N005",
"NextOnTrue": "",
"NextOnFalse": "",
"NextOnApprove": "",
"NextOnReject": "",
"PositionX": 458,
"PositionY": 411,
"CompareOutcomes": [],
"Id": "N004"
},
{
"ListFormCode": "App.Wizard.Approval",
"Kind": "End",
"Title": "\u0130\u015F Ak\u0131\u015F\u0131 Bitir1",
"CompareColumn": "Price",
"CompareOperator": "\u003E",
"CompareValue": 5000,
"Approver": "",
"NextOnStart": "",
"NextOnTrue": "",
"NextOnFalse": "",
"NextOnApprove": "",
"NextOnReject": "",
"PositionX": 792,
"PositionY": 412,
"CompareOutcomes": [],
"Id": "N005"
}
]
}, },
"IsDeletedField": true, "IsDeletedField": false,
"IsCreatedField": true, "IsCreatedField": false,
"InsertedRecords": { "InsertedRecords": {
"LanguageKeys": [ "LanguageKeys": [
"App.Wizard.Approval", "App.Wizard.Approval",
"App.Wizard.Approval.Title", "App.Wizard.Approval.Title",
"App.Wizard.Approval.Desc", "App.Wizard.Approval.Desc"
"App.Listform.ListformField.ApprovalUserName",
"App.Listform.ListformField.ApprovalStatus",
"App.Listform.ListformField.ApprovalDate",
"App.Listform.ListformField.ApprovalDescription"
],
"PermissionGroupNames": [
"App.Wizard.Sales"
], ],
"PermissionGroupNames": [],
"PermissionNames": [ "PermissionNames": [
"App.Wizard.Approval", "App.Wizard.Approval",
"App.Wizard.Approval.Create", "App.Wizard.Approval.Create",

View file

@ -0,0 +1,281 @@
{
"Wizard": {
"WizardName": "Todo",
"ListFormCode": "App.Wizard.Todo",
"MenuCode": "App.Wizard.Todo",
"IsTenant": true,
"IsBranch": false,
"IsOrganizationUnit": false,
"AllowAdding": true,
"AllowUpdating": true,
"AllowDeleting": true,
"AllowDetail": false,
"ConfirmDelete": true,
"DefaultLayout": "todo",
"Grid": true,
"Card": true,
"Pivot": true,
"Tree": true,
"Chart": true,
"Gantt": true,
"Scheduler": true,
"Todo": true,
"LanguageTextMenuEn": "Todo",
"LanguageTextMenuTr": "\u0130\u015Fler",
"LanguageTextTitleEn": "Todo",
"LanguageTextTitleTr": "\u0130\u015Fler",
"LanguageTextDescEn": "Todo",
"LanguageTextDescTr": "\u0130\u015Fler",
"LanguageTextMenuParentEn": "Project",
"LanguageTextMenuParentTr": "Project",
"PermissionGroupName": "App.Wizard.Project",
"MenuParentCode": "App.Wizard.Project",
"MenuParentShortName": "Pro",
"MenuParentIcon": "FcVideoProjector",
"MenuIcon": "FcTodoList",
"DataSourceCode": "Default",
"DataSourceConnectionString": "",
"SelectCommandType": 1,
"SelectCommand": "Pro_T_Todo",
"KeyFieldName": "Id",
"KeyFieldDbSourceType": 9,
"TreeKeyExpr": "",
"TreeParentIdExpr": "",
"TreeAutoExpandAll": false,
"GanttKeyExpr": "",
"GanttParentIdExpr": "",
"GanttAutoExpandAll": false,
"GanttTitleExpr": "",
"GanttStartExpr": "",
"GanttEndExpr": "",
"GanttProgressExpr": "",
"SchedulerTextExpr": "",
"SchedulerStartDateExpr": "",
"SchedulerEndDateExpr": "",
"TodoTitleExpr": "Title",
"TodoStatusExpr": "Status",
"TodoDescriptionExpr": "Description",
"TodoDueDateExpr": "DueDate",
"TodoTagExpr": "Tags",
"TodoAssigneeExpr": "Assignees",
"TodoPriorityExpr": "Priority",
"TodoCompletedExpr": "Completed",
"TodoOrderExpr": "SortOrder",
"TodoStatusOrder": "Backlog, Ready to Start, In Progress, Code Review, Testing, Staging",
"TodoAllowDragging": true,
"ApprovalUserFieldName": "",
"ApprovalDateFieldName": "",
"ApprovalStatusFieldName": "",
"ApprovalDescriptionFieldName": "",
"ApprovalIsFilterUserName": false,
"Criteria": [],
"Groups": [
{
"Caption": "",
"ColCount": 1,
"Items": [
{
"FieldName": "Id",
"CaptionName": "App.Listform.ListformField.Id",
"EditorType": "dxTextBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": true,
"IncludeInEditingForm": true,
"DbSourceType": 9,
"TurkishCaption": "Id",
"EnglishCaption": "Id",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
},
{
"FieldName": "Title",
"CaptionName": "App.Listform.ListformField.Title",
"EditorType": "dxTextBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": true,
"IncludeInEditingForm": true,
"DbSourceType": 16,
"TurkishCaption": "Title",
"EnglishCaption": "Title",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
},
{
"FieldName": "Status",
"CaptionName": "App.Listform.ListformField.Status",
"EditorType": "dxTextBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": true,
"IncludeInEditingForm": false,
"DbSourceType": 16,
"TurkishCaption": "Status",
"EnglishCaption": "Status",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
},
{
"FieldName": "Description",
"CaptionName": "App.Listform.ListformField.Description",
"EditorType": "dxHtmlEditor",
"EditorOptions": "{\u0022mediaResizing\u0022:{\u0022enabled\u0022:true},\u0022imageUpload\u0022:{\u0022tabs\u0022:[\u0022file\u0022,\u0022url\u0022],\u0022fileUploadMode\u0022:\u0022base64\u0022},\u0022toolbar\u0022:{\u0022multiline\u0022:true,\u0022items\u0022:[{\u0022name\u0022:\u0022undo\u0022},{\u0022name\u0022:\u0022redo\u0022},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022size\u0022,\u0022acceptedValues\u0022:[\u00228pt\u0022,\u002210pt\u0022,\u002212pt\u0022,\u002214pt\u0022,\u002218pt\u0022,\u002224pt\u0022,\u002236pt\u0022],\u0022options\u0022:{\u0022inputAttr\u0022:{\u0022aria-label\u0022:\u0022Font size\u0022}}},{\u0022name\u0022:\u0022font\u0022,\u0022acceptedValues\u0022:[\u0022Arial\u0022,\u0022Courier New\u0022,\u0022Georgia\u0022,\u0022Impact\u0022,\u0022Lucida Console\u0022,\u0022Tahoma\u0022,\u0022Times New Roman\u0022,\u0022Verdana\u0022],\u0022options\u0022:{\u0022inputAttr\u0022:{\u0022aria-label\u0022:\u0022Font family\u0022}}},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022bold\u0022},{\u0022name\u0022:\u0022italic\u0022},{\u0022name\u0022:\u0022strike\u0022},{\u0022name\u0022:\u0022underline\u0022},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022alignLeft\u0022},{\u0022name\u0022:\u0022alignCenter\u0022},{\u0022name\u0022:\u0022alignRight\u0022},{\u0022name\u0022:\u0022alignJustify\u0022},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022orderedList\u0022},{\u0022name\u0022:\u0022bulletList\u0022},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022header\u0022,\u0022acceptedValues\u0022:[false,1,2,3,4,5]},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022color\u0022},{\u0022name\u0022:\u0022background\u0022},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022link\u0022},{\u0022name\u0022:\u0022image\u0022},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022clear\u0022},{\u0022name\u0022:\u0022codeBlock\u0022},{\u0022name\u0022:\u0022blockquote\u0022},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022insertTable\u0022},{\u0022name\u0022:\u0022deleteTable\u0022},{\u0022name\u0022:\u0022insertRowAbove\u0022},{\u0022name\u0022:\u0022insertRowBelow\u0022},{\u0022name\u0022:\u0022deleteRow\u0022},{\u0022name\u0022:\u0022insertColumnLeft\u0022},{\u0022name\u0022:\u0022insertColumnRight\u0022},{\u0022name\u0022:\u0022deleteColumn\u0022},{\u0022name\u0022:\u0022cellProperties\u0022},{\u0022name\u0022:\u0022tableProperties\u0022}]}}",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": false,
"IncludeInEditingForm": false,
"DbSourceType": 16,
"TurkishCaption": "Description",
"EnglishCaption": "Description",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
},
{
"FieldName": "DueDate",
"CaptionName": "App.Listform.ListformField.DueDate",
"EditorType": "dxDateBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": false,
"IncludeInEditingForm": false,
"DbSourceType": 6,
"TurkishCaption": "Due Date",
"EnglishCaption": "Due Date",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
},
{
"FieldName": "Tags",
"CaptionName": "App.Listform.ListformField.Tags",
"EditorType": "dxTextBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": false,
"IncludeInEditingForm": false,
"DbSourceType": 16,
"TurkishCaption": "Tags",
"EnglishCaption": "Tags",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
},
{
"FieldName": "Assignees",
"CaptionName": "App.Listform.ListformField.Assignees",
"EditorType": "dxTextBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": false,
"IncludeInEditingForm": false,
"DbSourceType": 16,
"TurkishCaption": "Assignees",
"EnglishCaption": "Assignees",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
},
{
"FieldName": "Priority",
"CaptionName": "App.Listform.ListformField.Priority",
"EditorType": "dxTextBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": false,
"IncludeInEditingForm": false,
"DbSourceType": 16,
"TurkishCaption": "Priority",
"EnglishCaption": "Priority",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
},
{
"FieldName": "Completed",
"CaptionName": "App.Listform.ListformField.Completed",
"EditorType": "dxCheckBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": true,
"IncludeInEditingForm": false,
"DbSourceType": 3,
"TurkishCaption": "Completed",
"EnglishCaption": "Completed",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
},
{
"FieldName": "SortOrder",
"CaptionName": "App.Listform.ListformField.SortOrder",
"EditorType": "dxNumberBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": true,
"IncludeInEditingForm": false,
"DbSourceType": 11,
"TurkishCaption": "Sort Order",
"EnglishCaption": "Sort Order",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
}
]
}
],
"SubForms": [],
"Widgets": []
},
"IsDeletedField": false,
"IsCreatedField": false,
"InsertedRecords": {
"LanguageKeys": [
"App.Wizard.Todo",
"App.Wizard.Todo.Title",
"App.Wizard.Todo.Desc",
"App.Listform.ListformField.Assignees",
"App.Listform.ListformField.Completed",
"App.Listform.ListformField.SortOrder"
],
"PermissionGroupNames": [
"App.Wizard.Project"
],
"PermissionNames": [
"App.Wizard.Todo",
"App.Wizard.Todo.Create",
"App.Wizard.Todo.Update",
"App.Wizard.Todo.Delete",
"App.Wizard.Todo.Export",
"App.Wizard.Todo.Import",
"App.Wizard.Todo.Note"
],
"MenuCodes": [
"App.Wizard.Todo"
],
"DataSourceCodes": []
}
}

View file

@ -107,6 +107,8 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
var fileName = Path.GetFileName(filePath); var fileName = Path.GetFileName(filePath);
await BackfillMenuParentShortNameAsync(seedFile.Wizard);
// Zaten seeded mi kontrol et (ListForm var mı?) // Zaten seeded mi kontrol et (ListForm var mı?)
if (await _repoListForm.AnyAsync(a => a.ListFormCode == seedFile.Wizard.ListFormCode)) if (await _repoListForm.AnyAsync(a => a.ListFormCode == seedFile.Wizard.ListFormCode))
{ {
@ -132,14 +134,17 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
var isCreated = seedFile.IsCreatedField; var isCreated = seedFile.IsCreatedField;
input.SubForms ??= new List<SubFormDto>(); input.SubForms ??= new List<SubFormDto>();
input.Widgets ??= new List<WidgetEditDto>(); input.Widgets ??= new List<WidgetEditDto>();
input.Workflow ??= new WorkflowDto(); input.Criteria ??= [];
input.WorkflowCriteria ??= new List<ListFormWorkflowCriteriaDto>(); EnsureUniqueWorkflowCriteriaTitles(input.Criteria);
if (input.WorkflowCriteria.Count == 0 && input.Workflow.Criteria?.Count > 0) var workflow = new WorkflowDto
{ {
input.WorkflowCriteria = input.Workflow.Criteria; ApprovalUserFieldName = input.ApprovalUserFieldName,
} ApprovalIsFilterUserName = input.ApprovalIsFilterUserName,
input.Workflow.Criteria = input.WorkflowCriteria; ApprovalDateFieldName = input.ApprovalDateFieldName,
EnsureUniqueWorkflowCriteriaTitles(input.WorkflowCriteria); ApprovalStatusFieldName = input.ApprovalStatusFieldName,
ApprovalDescriptionFieldName = input.ApprovalDescriptionFieldName,
Criteria = input.Criteria,
};
var wizardName = input.WizardName.Trim(); var wizardName = input.WizardName.Trim();
var code = string.IsNullOrWhiteSpace(input.MenuCode) var code = string.IsNullOrWhiteSpace(input.MenuCode)
@ -148,6 +153,7 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
var listFormCode = string.IsNullOrWhiteSpace(input.ListFormCode) var listFormCode = string.IsNullOrWhiteSpace(input.ListFormCode)
? code ? code
: input.ListFormCode.Trim(); : input.ListFormCode.Trim();
NormalizeWorkflowCriteriaIds(listFormCode, input.Criteria);
var titleLangKey = $"{listFormCode}.Title"; var titleLangKey = $"{listFormCode}.Title";
var nameLangKey = code; var nameLangKey = code;
var descLangKey = $"{listFormCode}.Desc"; var descLangKey = $"{listFormCode}.Desc";
@ -249,6 +255,7 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
Code = input.MenuParentCode, Code = input.MenuParentCode,
DisplayName = input.MenuParentCode, DisplayName = input.MenuParentCode,
IsDisabled = false, IsDisabled = false,
ShortName = input.MenuParentShortName,
Icon = menuParentIcon, Icon = menuParentIcon,
Order = maxRootOrder + 1, Order = maxRootOrder + 1,
}, autoSave: true); }, autoSave: true);
@ -298,21 +305,9 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
Caption = g.Caption, Caption = g.Caption,
ColCount = g.ColCount, ColCount = g.ColCount,
ColSpan = g.ColCount, ColSpan = g.ColCount,
ItemType = "group", ItemType = "group"
Items = g.Items
.Where(i => i.IncludeInEditingForm && i.DataField != input.KeyFieldName)
.Select((it, ii) => new EditingFormItemDto
{
Order = ii + 1,
DataField = it.DataField,
EditorType2 = it.EditorType,
ColSpan = it.ColSpan,
EditorOptions = string.IsNullOrWhiteSpace(it.EditorOptions) ? null : it.EditorOptions,
EditorScript = string.IsNullOrWhiteSpace(it.EditorScript) ? null : it.EditorScript,
})
.ToArray()
}) })
.Where(g => g.Items.Length > 0) .Where((_, index) => input.Groups[index].Items.Any(i => i.IncludeInEditingForm && i.FieldName != input.KeyFieldName))
.ToList(); .ToList();
// ListForm - varsa sil, yeniden ekle // ListForm - varsa sil, yeniden ekle
@ -337,8 +332,8 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
// EditingForm'da required olan alanları tespit et, ValidationRuleJson eklemek için // EditingForm'da required olan alanları tespit et, ValidationRuleJson eklemek için
var editingFormFieldNames = input.Groups var editingFormFieldNames = input.Groups
.SelectMany(g => g.Items) .SelectMany(g => g.Items)
.Where(i => i.IncludeInEditingForm && i.DataField != input.KeyFieldName) .Where(i => i.IncludeInEditingForm && i.FieldName != input.KeyFieldName)
.Select(i => new { FieldName = i.DataField, Isrequired = i.IsRequired }) .Select(i => new { FieldName = i.FieldName, Isrequired = i.IsRequired })
.ToList(); .ToList();
// Heigth ve Width hesaplama // Heigth ve Width hesaplama
@ -346,7 +341,7 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
.Select(g => .Select(g =>
{ {
var items = g.Items var items = g.Items
.Where(i => i.IncludeInEditingForm && i.DataField != input.KeyFieldName) .Where(i => i.IncludeInEditingForm && i.FieldName != input.KeyFieldName)
.ToList(); .ToList();
var columnCount = g.ColCount; var columnCount = g.ColCount;
@ -391,8 +386,8 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
PageSize = 10, PageSize = 10,
ExportJson = WizardConsts.DefaultExportJson, ExportJson = WizardConsts.DefaultExportJson,
IsSubForm = false, IsSubForm = false,
ShowNote = input.SubForms.Count > 0 || input.WorkflowCriteria.Count > 0, ShowNote = input.SubForms.Count > 0 || input.Criteria.Count > 0,
LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler), LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Card, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler, input.Todo),
CultureName = LanguageCodes.En, CultureName = LanguageCodes.En,
ListFormCode = input.ListFormCode, ListFormCode = input.ListFormCode,
Name = nameLangKey, Name = nameLangKey,
@ -412,41 +407,74 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
HeaderFilterJson = WizardConsts.DefaultHeaderFilterJson(), HeaderFilterJson = WizardConsts.DefaultHeaderFilterJson(),
SearchPanelJson = WizardConsts.DefaultSearchPanelJson(), SearchPanelJson = WizardConsts.DefaultSearchPanelJson(),
GroupPanelJson = WizardConsts.DefaultGroupPanelJson(), GroupPanelJson = WizardConsts.DefaultGroupPanelJson(),
SelectionJson = WizardConsts.DefaultSelectionSingleJson(input.WorkflowCriteria.Count > 0 ? GridOptions.SelectionModeSingle : GridOptions.SelectionModeNone), SelectionJson = WizardConsts.DefaultSelectionSingleJson(input.Criteria.Count > 0 ? GridOptions.SelectionModeSingle : GridOptions.SelectionModeNone),
ColumnOptionJson = WizardConsts.DefaultColumnOptionJson(), ColumnOptionJson = WizardConsts.DefaultColumnOptionJson(),
PermissionJson = WizardConsts.DefaultPermissionJson(code), PermissionJson = WizardConsts.DefaultPermissionJson(code),
DeleteCommand = isDeleted ? WizardConsts.DefaultDeleteCommand(input.SelectCommand) : null, DeleteCommand = isDeleted ? WizardConsts.DefaultDeleteCommand(input.SelectCommand) : null,
DeleteFieldsDefaultValueJson = isDeleted DeleteFieldsDefaultValueJson = isDeleted
? WizardConsts.DefaultDeleteFieldsDefaultValueJson(input.KeyFieldDbSourceType) ? WizardConsts.DefaultDeleteFieldsDefaultValueJson(input.KeyFieldDbSourceType)
: WizardConsts.DefaultFieldsJsonOnlyId(input.KeyFieldDbSourceType), : WizardConsts.DefaultDeleteFieldsJsonOnlyId(input.KeyFieldDbSourceType),
InsertFieldsDefaultValueJson = isCreated InsertFieldsDefaultValueJson = isCreated
? WizardConsts.DefaultInsertFieldsDefaultValueJson(input.KeyFieldDbSourceType) ? WizardConsts.DefaultInsertFieldsDefaultValueJson(input.KeyFieldDbSourceType)
: WizardConsts.DefaultFieldsJsonOnlyId(input.KeyFieldDbSourceType), : WizardConsts.DefaultInsertFieldsJsonOnlyId(input.KeyFieldDbSourceType),
PagerOptionJson = WizardConsts.DefaultPagerOptionJson, PagerOptionJson = WizardConsts.DefaultPagerOptionJson,
EditingOptionJson = WizardConsts.DefaultEditingOptionJson(titleLangKey, formWidth, formHeight, input.AllowDeleting, input.AllowAdding, input.AllowUpdating, input.ConfirmDelete, false, input.AllowDetail), EditingOptionJson = WizardConsts.DefaultEditingOptionJson(titleLangKey, formWidth, formHeight, input.AllowDeleting, input.AllowAdding, input.AllowUpdating, input.ConfirmDelete, false, input.AllowDetail),
EditingFormJson = editingFormDtos.Count > 0 ? JsonSerializer.Serialize(editingFormDtos) : null, EditingFormJson = editingFormDtos.Count > 0 ? JsonSerializer.Serialize(editingFormDtos) : null,
SubFormsJson = input.SubForms.Count > 0 ? JsonSerializer.Serialize(input.SubForms) : null, SubFormsJson = input.SubForms.Count > 0 ? JsonSerializer.Serialize(input.SubForms) : null,
WidgetsJson = input.Widgets.Count > 0 ? JsonSerializer.Serialize(input.Widgets) : null, WidgetsJson = input.Widgets.Count > 0 ? JsonSerializer.Serialize(input.Widgets) : null,
WorkflowJson = HasWorkflow(input.Workflow, input.WorkflowCriteria) ? JsonSerializer.Serialize(input.Workflow) : null, WorkflowJson = HasWorkflow(workflow, input.Criteria) ? JsonSerializer.Serialize(workflow) : null,
TodoOptionJson = (input.Todo || input.DefaultLayout == "todo") &&
!string.IsNullOrEmpty(input.TodoTitleExpr) &&
!string.IsNullOrEmpty(input.TodoStatusExpr)
? JsonSerializer.Serialize(new TodoOptionDto
{
TitleExpr = input.TodoTitleExpr,
StatusExpr = input.TodoStatusExpr,
DescriptionExpr = input.TodoDescriptionExpr,
DueDateExpr = input.TodoDueDateExpr,
TagExpr = input.TodoTagExpr,
AssigneeExpr = input.TodoAssigneeExpr,
PriorityExpr = input.TodoPriorityExpr,
CompletedExpr = input.TodoCompletedExpr,
OrderExpr = input.TodoOrderExpr,
StatusOrder = input.TodoStatusOrder,
AllowDragging = input.TodoAllowDragging,
})
: null,
}, autoSave: true); }, autoSave: true);
// ListFormFields // ListFormFields
var fieldOrder = 0; var fieldOrder = 0;
var editGroupOrder = 0;
foreach (var group in input.Groups) foreach (var group in input.Groups)
{ {
editGroupOrder++;
var editOrder = 0;
foreach (var item in group.Items) foreach (var item in group.Items)
{ {
fieldOrder++; fieldOrder++;
if (item.IncludeInEditingForm && item.FieldName != input.KeyFieldName)
{
editOrder++;
}
await _repoListFormField.InsertAsync(new ListFormField await _repoListFormField.InsertAsync(new ListFormField
{ {
ListFormCode = input.ListFormCode, ListFormCode = input.ListFormCode,
FieldName = item.DataField, FieldName = item.FieldName,
CaptionName = item.CaptionName, CaptionName = item.CaptionName,
Visible = item.DataField != input.KeyFieldName, Visible = item.FieldName != input.KeyFieldName,
IsActive = true, IsActive = true,
Width = 0, //Fit columns için hepsine sıfır veriyorum. Width = 0, //Fit columns için hepsine sıfır veriyorum.
AllowSearch = true, AllowSearch = true,
ListOrderNo = fieldOrder, ListOrderNo = fieldOrder,
EditGroupOrderNo = item.IncludeInEditingForm ? editGroupOrder : null,
EditOrderNo = item.IncludeInEditingForm && item.FieldName != input.KeyFieldName
? editOrder
: null,
EditorType2 = item.EditorType,
ColSpan = item.ColSpan,
EditorOptions = string.IsNullOrWhiteSpace(item.EditorOptions) ? null : item.EditorOptions,
EditorScript = string.IsNullOrWhiteSpace(item.EditorScript) ? null : item.EditorScript,
SourceDbType = item.DbSourceType, SourceDbType = item.DbSourceType,
CultureName = PlatformConsts.DefaultLanguage, CultureName = PlatformConsts.DefaultLanguage,
PermissionJson = WizardConsts.DefaultFieldPermissionJson(code), PermissionJson = WizardConsts.DefaultFieldPermissionJson(code),
@ -456,7 +484,7 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
LookupJson = !string.IsNullOrWhiteSpace(item.LookupQuery) LookupJson = !string.IsNullOrWhiteSpace(item.LookupQuery)
? WizardConsts.DefaultLookupJson(item.LookupDataSourceType, item.DisplayExpr, item.ValueExpr, item.LookupQuery) ? WizardConsts.DefaultLookupJson(item.LookupDataSourceType, item.DisplayExpr, item.ValueExpr, item.LookupQuery)
: null, : null,
ValidationRuleJson = editingFormFieldNames.Any(f => f.FieldName == item.DataField && f.Isrequired) ValidationRuleJson = editingFormFieldNames.Any(f => f.FieldName == item.FieldName && f.Isrequired)
? WizardConsts.DefaultValidationRuleRequiredJson ? WizardConsts.DefaultValidationRuleRequiredJson
: null : null
}, autoSave: true); }, autoSave: true);
@ -465,7 +493,7 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
} }
} }
foreach (var criteria in input.WorkflowCriteria) foreach (var criteria in input.Criteria)
{ {
if (string.IsNullOrWhiteSpace(criteria.Id)) if (string.IsNullOrWhiteSpace(criteria.Id))
{ {
@ -494,6 +522,24 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
} }
} }
private async Task BackfillMenuParentShortNameAsync(ListFormWizardDto input)
{
if (string.IsNullOrWhiteSpace(input.MenuParentCode) ||
string.IsNullOrWhiteSpace(input.MenuParentShortName))
return;
var menuParent = await _repoMenu.FirstOrDefaultAsync(a => a.Code == input.MenuParentCode);
if (menuParent == null || !string.IsNullOrWhiteSpace(menuParent.ShortName))
return;
menuParent.ShortName = input.MenuParentShortName.Trim();
await _repoMenu.UpdateAsync(menuParent, autoSave: true);
_logger.LogInformation(
"Menu parent '{MenuParentCode}' ShortName backfilled as '{ShortName}'.",
input.MenuParentCode,
menuParent.ShortName);
}
private static bool HasWorkflow(WorkflowDto workflow, List<ListFormWorkflowCriteriaDto> criteria) private static bool HasWorkflow(WorkflowDto workflow, List<ListFormWorkflowCriteriaDto> criteria)
{ {
return workflow != null && ( return workflow != null && (
@ -559,6 +605,55 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
return string.IsNullOrWhiteSpace(kind) ? "Step" : kind.Trim(); return string.IsNullOrWhiteSpace(kind) ? "Step" : kind.Trim();
} }
private static void NormalizeWorkflowCriteriaIds(string listFormCode, List<ListFormWorkflowCriteriaDto> criteria)
{
if (string.IsNullOrWhiteSpace(listFormCode) || criteria == null || criteria.Count == 0)
{
return;
}
foreach (var item in criteria)
{
item.Id = NormalizeWorkflowCriteriaId(listFormCode, item.Id);
item.ListFormCode = listFormCode;
item.NextOnStart = NormalizeWorkflowTargetId(listFormCode, item.NextOnStart);
item.NextOnTrue = NormalizeWorkflowTargetId(listFormCode, item.NextOnTrue);
item.NextOnFalse = NormalizeWorkflowTargetId(listFormCode, item.NextOnFalse);
item.NextOnApprove = NormalizeWorkflowTargetId(listFormCode, item.NextOnApprove);
item.NextOnReject = NormalizeWorkflowTargetId(listFormCode, item.NextOnReject);
foreach (var outcome in item.CompareOutcomes ?? [])
{
outcome.TargetId = NormalizeWorkflowTargetId(listFormCode, outcome.TargetId);
}
}
}
private static string NormalizeWorkflowTargetId(string listFormCode, string id)
{
return string.IsNullOrWhiteSpace(id)
? string.Empty
: NormalizeWorkflowCriteriaId(listFormCode, id);
}
private static string NormalizeWorkflowCriteriaId(string listFormCode, string id)
{
var trimmed = id?.Trim();
if (string.IsNullOrWhiteSpace(trimmed))
{
return string.Empty;
}
if (trimmed.StartsWith($"{listFormCode}-", StringComparison.OrdinalIgnoreCase))
{
return trimmed;
}
return trimmed.StartsWith("N", StringComparison.OrdinalIgnoreCase)
? $"{listFormCode}-{trimmed}"
: trimmed;
}
private async Task CreateLangKeyAsync(string key, string textEn, string textTr) private async Task CreateLangKeyAsync(string key, string textEn, string textTr)
{ {
if (string.IsNullOrWhiteSpace(key)) return; if (string.IsNullOrWhiteSpace(key)) return;

View file

@ -63,6 +63,7 @@ public enum TableNameEnum
InstallmentOption, InstallmentOption,
Order, Order,
OrderItem, OrderItem,
OrderItem_ByTenantId,
BlogCategory, BlogCategory,
BlogPost, BlogPost,
Demo, Demo,
@ -94,5 +95,5 @@ public enum TableNameEnum
VideoroomAttandance, VideoroomAttandance,
VideoroomChat, VideoroomChat,
Sequence, Sequence,
DbTableColumn DbTableColumn,
} }

View file

@ -36,6 +36,7 @@ public static class PlatformConsts
public static string CalcTotalHoursFromTimes = "(()=>{const toD=v=>!v?null:(v instanceof Date?v:new Date(v));const next={...formData,[e.dataField]:e.value};const s=toD(next.StartTime),t=toD(next.EndTime);let h=null;if(s&&t){h=(t-s)/36e5;if(h<0)h+=24;h=Math.round(h*10)/10;}setFormData({...next,TotalHours:h});})();"; public static string CalcTotalHoursFromTimes = "(()=>{const toD=v=>!v?null:(v instanceof Date?v:new Date(v));const next={...formData,[e.dataField]:e.value};const s=toD(next.StartTime),t=toD(next.EndTime);let h=null;if(s&&t){h=(t-s)/36e5;if(h<0)h+=24;h=Math.round(h*10)/10;}setFormData({...next,TotalHours:h});})();";
public static string MaterialOnChange = "(() => { const p=e.component.option('selectedItem')||{}; const q=Math.round((parseFloat(p.Quantity)||0)*100); const u=Math.round((parseFloat(p.UnitPrice)||0)*100); setFormData({ ...formData, Quantity:q/100, UnitPrice:u/100, UomId:p.UomId, TotalAmount:Math.round((q*u)/100)/100 }); })();"; public static string MaterialOnChange = "(() => { const p=e.component.option('selectedItem')||{}; const q=Math.round((parseFloat(p.Quantity)||0)*100); const u=Math.round((parseFloat(p.UnitPrice)||0)*100); setFormData({ ...formData, Quantity:q/100, UnitPrice:u/100, UomId:p.UomId, TotalAmount:Math.round((q*u)/100)/100 }); })();";
public static string CalcTotalAmount = "(() => { const n={...formData,[e.dataField]:e.value}; const q=Math.round((parseFloat(n.Quantity)||0)*100); const u=Math.round((parseFloat(n.UnitPrice)||0)*100); setFormData({ ...n, TotalAmount:Math.round((q*u)/100)/100 }); })();"; public static string CalcTotalAmount = "(() => { const n={...formData,[e.dataField]:e.value}; const q=Math.round((parseFloat(n.Quantity)||0)*100); const u=Math.round((parseFloat(n.UnitPrice)||0)*100); setFormData({ ...n, TotalAmount:Math.round((q*u)/100)/100 }); })();";
public static string SourceFieldItemWritetoDestination(string sourceField = "Township", string itemName = "Group", string destinationField = "PostalCode") => $"(async()=>{{const townshipField=\"{sourceField}\",groupField=\"{itemName}\",postalCodeField=\"{destinationField}\";const currentField=(typeof editor!=='undefined'&&editor?.dataField)||e?.dataField||townshipField;const next={{...formData,[currentField]:e?.value}};const isReady=e?.scriptEvent===\"contentReady\";const selectedItem=(()=>{{try{{return e?.component?.option?e.component.option(\"selectedItem\"):null;}}catch{{return null;}}}})();if(!isReady)next[postalCodeField]=selectedItem?selectedItem[groupField]:next[postalCodeField];if(!isReady&&typeof setFormData===\"function\")setFormData(next);}})();";
} }
public static class Prefix public static class Prefix
@ -70,7 +71,6 @@ public static class PlatformConsts
public const string Email = "Email"; public const string Email = "Email";
public const string Website = "Website"; public const string Website = "Website";
public const string MenuGroup = "MenuGroup"; public const string MenuGroup = "MenuGroup";
public const string MaxConcurrentUsers = "MaxConcurrentUsers";
} }
public static class Branches public static class Branches
@ -163,6 +163,7 @@ public static class PlatformConsts
public const string TenantIsPassive = GroupName + ".TenantIsPassive"; public const string TenantIsPassive = GroupName + ".TenantIsPassive";
public const string LoginNotAllowed_WorkHour = GroupName + ".LoginNotAllowed_WorkHour"; public const string LoginNotAllowed_WorkHour = GroupName + ".LoginNotAllowed_WorkHour";
public const string ConcurrentUserLimitError = GroupName + ".ConcurrentUserLimitError"; public const string ConcurrentUserLimitError = GroupName + ".ConcurrentUserLimitError";
public const string BranchLimitError = GroupName + ".BranchLimitError";
public const string CaptchaWrongCode = GroupName + ".CaptchaWrongCode"; public const string CaptchaWrongCode = GroupName + ".CaptchaWrongCode";
public const string TwoFactorWrongCode = GroupName + ".TwoFactorWrongCode"; public const string TwoFactorWrongCode = GroupName + ".TwoFactorWrongCode";
public const string SignOut = GroupName + ".SignOut"; public const string SignOut = GroupName + ".SignOut";
@ -549,6 +550,7 @@ public static class PlatformConsts
public static string LoginNotAllowed_TenantIsPassive { get; set; } = "UserCannotSignInTenantIsPassive"; public static string LoginNotAllowed_TenantIsPassive { get; set; } = "UserCannotSignInTenantIsPassive";
public static string LoginNotAllowed_TenantNotFound { get; set; } = "UserCannotSignInTenantNotFound"; public static string LoginNotAllowed_TenantNotFound { get; set; } = "UserCannotSignInTenantNotFound";
public static string LoginNotAllowed_WorkHour { get; set; } = "UserCannotSignInWorkHour"; public static string LoginNotAllowed_WorkHour { get; set; } = "UserCannotSignInWorkHour";
public static string LoginNotAllowed_BranchLimit { get; set; } = "UserCannotSignInBranchLimit";
public static string LoginNotAllowed_ConcurrentUserLimit { get; set; } = "UserCannotSignInConcurrentUserLimit"; public static string LoginNotAllowed_ConcurrentUserLimit { get; set; } = "UserCannotSignInConcurrentUserLimit";
} }
@ -756,6 +758,7 @@ public static class PlatformConsts
public const string dxDateBox = "dxDateBox"; public const string dxDateBox = "dxDateBox";
public const string dxDateRangeBox = "dxDateRangeBox"; public const string dxDateRangeBox = "dxDateRangeBox";
public const string dxDropDownBox = "dxDropDownBox"; public const string dxDropDownBox = "dxDropDownBox";
public const string dxGridBox = "dxGridBox";
public const string dxHtmlEditor = "dxHtmlEditor"; public const string dxHtmlEditor = "dxHtmlEditor";
public const string dxLookup = "dxHtmlEdidxLookuptor"; public const string dxLookup = "dxHtmlEdidxLookuptor";
public const string dxNumberBox = "dxNumberBox"; public const string dxNumberBox = "dxNumberBox";

View file

@ -116,7 +116,6 @@ public static class PlatformModuleExtensionConfigurator
tenantConfig.ConfigureTenant(entity => tenantConfig.ConfigureTenant(entity =>
{ {
entity.AddOrUpdateProperty<bool>("IsActive"); entity.AddOrUpdateProperty<bool>("IsActive");
entity.AddOrUpdateProperty<int?>("MaxConcurrentUsers");
}); });
}); });

View file

@ -59,6 +59,7 @@ public static class TableNameResolver
{ nameof(TableNameEnum.InstallmentOption), (TablePrefix.PlatformByName, MenuPrefix.Saas) }, { nameof(TableNameEnum.InstallmentOption), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
{ nameof(TableNameEnum.Order), (TablePrefix.PlatformByName, MenuPrefix.Saas) }, { nameof(TableNameEnum.Order), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
{ nameof(TableNameEnum.OrderItem), (TablePrefix.PlatformByName, MenuPrefix.Saas) }, { nameof(TableNameEnum.OrderItem), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
{ nameof(TableNameEnum.OrderItem_ByTenantId), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
{ nameof(TableNameEnum.BlogCategory), (TablePrefix.PlatformByName, MenuPrefix.Saas) }, { nameof(TableNameEnum.BlogCategory), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
{ nameof(TableNameEnum.BlogPost), (TablePrefix.PlatformByName, MenuPrefix.Saas) }, { nameof(TableNameEnum.BlogPost), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
{ nameof(TableNameEnum.Demo), (TablePrefix.PlatformByName, MenuPrefix.Saas) }, { nameof(TableNameEnum.Demo), (TablePrefix.PlatformByName, MenuPrefix.Saas) },

View file

@ -84,14 +84,16 @@ public static class WizardConsts
Margin = 10 Margin = 10
}); });
public static string DefaultLayoutJson(string DefaultLayout = "grid", bool Grid = true, bool Pivot = true, bool Chart = true, bool Tree = true, bool Gantt = true, bool Scheduler = true) => JsonSerializer.Serialize(new public static string DefaultLayoutJson(string DefaultLayout = "grid", bool Grid = true, bool Card = true, bool Pivot = true, bool Chart = true, bool Tree = true, bool Gantt = true, bool Scheduler = true, bool Todo = true) => JsonSerializer.Serialize(new
{ {
Grid = Grid, Grid = Grid,
Card = Card,
Pivot = Pivot, Pivot = Pivot,
Chart = Chart, Chart = Chart,
Tree = Tree, Tree = Tree,
Gantt = Gantt, Gantt = Gantt,
Scheduler = Scheduler, Scheduler = Scheduler,
Todo = Todo,
DefaultLayout = DefaultLayout, DefaultLayout = DefaultLayout,
}); });
@ -196,6 +198,14 @@ public static class WizardConsts
}); });
} }
public static string DefaultInsertFieldsJsonOnlyId(DbType dbType = DbType.Guid)
{
return JsonSerializer.Serialize(new[]
{
new { FieldName = "Id", FieldDbType = dbType, Value = "@NEWID", CustomValueType = FieldCustomValueTypeEnum.CustomKey }
});
}
public static string DefaultDeleteFieldsDefaultValueJson(DbType dbType = DbType.Guid) public static string DefaultDeleteFieldsDefaultValueJson(DbType dbType = DbType.Guid)
{ {
return JsonSerializer.Serialize(new[] return JsonSerializer.Serialize(new[]
@ -205,11 +215,11 @@ public static class WizardConsts
}); });
} }
public static string DefaultFieldsJsonOnlyId(DbType dbType = DbType.Guid) public static string DefaultDeleteFieldsJsonOnlyId(DbType dbType = DbType.Guid)
{ {
return JsonSerializer.Serialize(new[] return JsonSerializer.Serialize(new[]
{ {
new { FieldName = "Id", FieldDbType = dbType, Value = "@NEWID", CustomValueType = FieldCustomValueTypeEnum.CustomKey } new { FieldName = "Id", FieldDbType = dbType, Value = "@ID", CustomValueType = FieldCustomValueTypeEnum.CustomKey }
}); });
} }

View file

@ -416,6 +416,8 @@ public static class SeedConsts
public const string RecurringJobs = Default + ".RecurringJobs"; public const string RecurringJobs = Default + ".RecurringJobs";
public const string Jobs = Default + ".Jobs"; public const string Jobs = Default + ".Jobs";
} }
public const string Licence = Prefix.App + ".Licence";
public const string LicenceItem = Prefix.App + ".LicenceItem";
//Web Site //Web Site
public const string Home = Prefix.App + ".Home"; public const string Home = Prefix.App + ".Home";

View file

@ -9,6 +9,9 @@ public class Country : FullAuditedEntity<string>
public string GroupName { get; set; } public string GroupName { get; set; }
public string Currency { get; set; } public string Currency { get; set; }
public int PhoneCode { get; set; } public int PhoneCode { get; set; }
public int? PhoneNumberMinLength { get; set; }
public int? PhoneNumberMaxLength { get; set; }
public string? PhoneNumberFormat { get; set; }
public string TaxLabel { get; set; } public string TaxLabel { get; set; }
public bool ZipRequired { get; set; } public bool ZipRequired { get; set; }
public bool StateRequired { get; set; } public bool StateRequired { get; set; }
@ -23,6 +26,9 @@ public class Country : FullAuditedEntity<string>
string groupName, string groupName,
string currency, string currency,
int phoneCode, int phoneCode,
int? phoneNumberMinLength,
int? phoneNumberMaxLength,
string? phoneNumberFormat,
string taxLabel, string taxLabel,
bool zipRequired = false, bool zipRequired = false,
bool stateRequired = false) bool stateRequired = false)
@ -32,6 +38,9 @@ public class Country : FullAuditedEntity<string>
GroupName = groupName; GroupName = groupName;
Currency = currency; Currency = currency;
PhoneCode = phoneCode; PhoneCode = phoneCode;
PhoneNumberMinLength = phoneNumberMinLength;
PhoneNumberMaxLength = phoneNumberMaxLength;
PhoneNumberFormat = phoneNumberFormat;
TaxLabel = taxLabel; TaxLabel = taxLabel;
ZipRequired = zipRequired; ZipRequired = zipRequired;
StateRequired = stateRequired; StateRequired = stateRequired;

View file

@ -9,16 +9,18 @@ public class District : FullAuditedEntity<Guid>
public string City { get; set; } public string City { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string Township { get; set; } public string Township { get; set; }
public string PostalCode { get; set; }
protected District() { } protected District() { }
public District(Guid id, string country, string city, string name, string township) public District(Guid id, string country, string city, string name, string township, string postalCode)
: base(id) : base(id)
{ {
Country = country; Country = country;
City = city; City = city;
Name = name; Name = name;
Township = township; Township = township;
PostalCode = postalCode;
} }
} }

View file

@ -10,6 +10,10 @@ public class ForumPost : FullAuditedEntity<Guid>
public string Content { get; set; } public string Content { get; set; }
public Guid AuthorId { get; set; } public Guid AuthorId { get; set; }
public string AuthorName { get; set; } public string AuthorName { get; set; }
public string AuthorTitle { get; set; }
public string AuthorEmail { get; set; }
public string AuthorPhoneNumber { get; set; }
public string AuthorDepartment { get; set; }
public int? LikeCount { get; set; } public int? LikeCount { get; set; }
public bool? IsAcceptedAnswer { get; set; } = false; public bool? IsAcceptedAnswer { get; set; } = false;
public Guid? ParentPostId { get; set; } public Guid? ParentPostId { get; set; }
@ -21,12 +25,27 @@ public class ForumPost : FullAuditedEntity<Guid>
protected ForumPost() { } protected ForumPost() { }
public ForumPost(Guid id, Guid topicId, string content, Guid authorId, string authorName, Guid? parentPostId = null, Guid? tenantId = null) : base(id) public ForumPost(
Guid id,
Guid topicId,
string content,
Guid authorId,
string authorName,
string authorTitle,
string authorEmail,
string authorPhoneNumber,
string authorDepartment,
Guid? parentPostId = null,
Guid? tenantId = null) : base(id)
{ {
TopicId = topicId; TopicId = topicId;
Content = content; Content = content;
AuthorId = authorId; AuthorId = authorId;
AuthorName = authorName; AuthorName = authorName;
AuthorTitle = authorTitle;
AuthorEmail = authorEmail;
AuthorPhoneNumber = authorPhoneNumber;
AuthorDepartment = authorDepartment;
ParentPostId = parentPostId; ParentPostId = parentPostId;
LikeCount = 0; LikeCount = 0;
IsAcceptedAnswer = false; IsAcceptedAnswer = false;

View file

@ -12,6 +12,10 @@ public class ForumTopic : FullAuditedEntity<Guid>
public ForumCategory Category { get; set; } public ForumCategory Category { get; set; }
public Guid AuthorId { get; set; } public Guid AuthorId { get; set; }
public string AuthorName { get; set; } public string AuthorName { get; set; }
public string AuthorTitle { get; set; }
public string AuthorEmail { get; set; }
public string AuthorPhoneNumber { get; set; }
public string AuthorDepartment { get; set; }
public int ViewCount { get; set; } public int ViewCount { get; set; }
public int ReplyCount { get; set; } public int ReplyCount { get; set; }
public int LikeCount { get; set; } public int LikeCount { get; set; }
@ -28,13 +32,28 @@ public class ForumTopic : FullAuditedEntity<Guid>
protected ForumTopic() { } protected ForumTopic() { }
public ForumTopic(Guid id, string title, string content, Guid categoryId, Guid authorId, string authorName, Guid? tenantId = null) : base(id) public ForumTopic(
Guid id,
string title,
string content,
Guid categoryId,
Guid authorId,
string authorName,
string authorTitle,
string authorEmail,
string authorPhoneNumber,
string authorDepartment,
Guid? tenantId = null) : base(id)
{ {
Title = title; Title = title;
Content = content; Content = content;
CategoryId = categoryId; CategoryId = categoryId;
AuthorId = authorId; AuthorId = authorId;
AuthorName = authorName; AuthorName = authorName;
AuthorTitle = authorTitle;
AuthorEmail = authorEmail;
AuthorPhoneNumber = authorPhoneNumber;
AuthorDepartment = authorDepartment;
ViewCount = 0; ViewCount = 0;
ReplyCount = 0; ReplyCount = 0;
LikeCount = 0; LikeCount = 0;

View file

@ -9,15 +9,17 @@ public class CustomComponent : FullAuditedEntity<Guid>, IMultiTenant
public virtual Guid? TenantId { get; protected set; } public virtual Guid? TenantId { get; protected set; }
public string Name { get; set; } = string.Empty; public string Name { get; set; } = string.Empty;
public string RoutePath { get; set; } = string.Empty;
public string Code { get; set; } = string.Empty; public string Code { get; set; } = string.Empty;
public string? Props { get; set; } public string? Props { get; set; }
public string? Description { get; set; } public string? Description { get; set; }
public bool IsActive { get; set; } = true; public bool IsActive { get; set; } = true;
public string? Dependencies { get; set; } // JSON string of component names public string? Dependencies { get; set; } // JSON string of component names
public CustomComponent(string name, string code, string? props, string? description, bool isActive, string? dependencies) public CustomComponent(string name, string routePath, string code, string? props, string? description, bool isActive, string? dependencies)
{ {
Name = name; Name = name;
RoutePath = routePath;
Code = code; Code = code;
Props = props; Props = props;
Description = description; Description = description;

View file

@ -5,7 +5,7 @@ using Volo.Abp.MultiTenancy;
namespace Sozsoft.Platform.Entities namespace Sozsoft.Platform.Entities
{ {
public class ReportCategory : FullAuditedEntity<string>, IMultiTenant public class ReportCategory : FullAuditedEntity<Guid>, IMultiTenant
{ {
public Guid? TenantId { get; set; } public Guid? TenantId { get; set; }
@ -15,9 +15,12 @@ namespace Sozsoft.Platform.Entities
public ICollection<ReportTemplate> ReportTemplates { get; set; } public ICollection<ReportTemplate> ReportTemplates { get; set; }
public ReportCategory(string id) protected ReportCategory()
{
}
public ReportCategory(Guid id) : base(id)
{ {
Id = id;
} }
} }
} }

View file

@ -12,7 +12,7 @@ namespace Sozsoft.Platform.Entities
public string Description { get; set; } public string Description { get; set; }
public string HtmlContent { get; set; } public string HtmlContent { get; set; }
public string CategoryId { get; set; } public Guid CategoryId { get; set; }
public ReportCategory ReportCategory { get; set; } public ReportCategory ReportCategory { get; set; }
public string Status { get; set; } public string Status { get; set; }
@ -23,7 +23,7 @@ namespace Sozsoft.Platform.Entities
string name, string name,
string description, string description,
string htmlContent, string htmlContent,
string categoryId, Guid categoryId,
string status string status
) : base(id) ) : base(id)
{ {

View file

@ -6,19 +6,18 @@ namespace Sozsoft.Platform.Entities;
public class Order : FullAuditedEntity<Guid> public class Order : FullAuditedEntity<Guid>
{ {
public string Name { get; set; } public Guid? TenantId { get; set; }
public bool IsActive { get; set; }
public string OrganizationName { get; set; } public string OrganizationName { get; set; }
public string Founder { get; set; } public string Founder { get; set; }
public long? VknTckn { get; set; } public long? VknTckn { get; set; }
public string TaxOffice { get; set; } public string TaxOffice { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string District { get; set; }
public string Country { get; set; } public string Country { get; set; }
public string City { get; set; } public string City { get; set; }
public string District { get; set; }
public string Township { get; set; }
public string PostalCode { get; set; } public string PostalCode { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string MobileNumber { get; set; } public string MobileNumber { get; set; }
public string PhoneNumber { get; set; } public string PhoneNumber { get; set; }
public string FaxNumber { get; set; } public string FaxNumber { get; set; }
@ -26,19 +25,38 @@ public class Order : FullAuditedEntity<Guid>
public string Website { get; set; } public string Website { get; set; }
public string MenuGroup { get; set; } public string MenuGroup { get; set; }
public List<OrderItem> Items { get; set; } = new(); public bool IsExisting { get; set; }
public bool IsActive { get; set; }
public string BillingCycle { get; set; }
public int Period { get; set; }
public DateTime? LicenseStartTime { get; set; }
public DateTime? LicenseEndTime { get; set; }
public decimal Subtotal { get; set; } public decimal Subtotal { get; set; }
public decimal VatTotal { get; set; }
public decimal Commission { get; set; } public decimal Commission { get; set; }
public decimal Total { get; set; } public decimal Total { get; set; }
public Guid PaymentMethodId { get; set; } public Guid PaymentMethodId { get; set; }
public int? Installment { get; set; } public int? Installment { get; set; }
public string PaymentDataJson { get; set; } // JSON olarak saklanacak public string PaymentDataJson { get; set; } // JSON olarak saklanacak
public string ApprovalUserName { get; set; }
public string ApprovalStatus { get; set; }
public DateTime? ApprovalDate { get; set; }
public string ApprovalDescription { get; set; }
public List<OrderItem> Items { get; set; } = new();
public Order() public Order()
{ {
} }
public Order(Guid id)
: base(id)
{
}
} }
public class OrderItem : FullAuditedEntity<Guid> public class OrderItem : FullAuditedEntity<Guid>
@ -48,7 +66,11 @@ public class OrderItem : FullAuditedEntity<Guid>
public Guid ProductId { get; set; } public Guid ProductId { get; set; }
public string ProductName { get; set; } public string ProductName { get; set; }
public string BillingCycle { get; set; } public string BillingCycle { get; set; }
public int Period { get; set; }
public int Quantity { get; set; } public int Quantity { get; set; }
public decimal Price { get; set; }
public decimal VatRate { get; set; }
public decimal VatAmount { get; set; }
public decimal TotalPrice { get; set; } public decimal TotalPrice { get; set; }
public OrderItem() public OrderItem()

View file

@ -11,6 +11,7 @@ public class Product : FullAuditedEntity<Guid>
public int Order { get; set; } public int Order { get; set; }
public decimal? MonthlyPrice { get; set; } public decimal? MonthlyPrice { get; set; }
public decimal? YearlyPrice { get; set; } public decimal? YearlyPrice { get; set; }
public decimal VatRate { get; set; } = 0.20m;
public bool IsQuantityBased { get; set; } = false; public bool IsQuantityBased { get; set; } = false;
public string ImageUrl { get; set; } public string ImageUrl { get; set; }
} }

View file

@ -36,6 +36,7 @@ public class ListForm : Entity<Guid>
public string TreeOptionJson { get; set; } // Tree yapisi ile ilgili ayarlar public string TreeOptionJson { get; set; } // Tree yapisi ile ilgili ayarlar
public string GanttOptionJson { get; set; } // Gantt yapisi ile ilgili ayarlar public string GanttOptionJson { get; set; } // Gantt yapisi ile ilgili ayarlar
public string SchedulerOptionJson { get; set; } // Scheduler yapisi ile ilgili ayarlar public string SchedulerOptionJson { get; set; } // Scheduler yapisi ile ilgili ayarlar
public string TodoOptionJson { get; set; } // Todo board alan esleme ayarlari
public string FilterRowJson { get; set; } // Filtre ayarlari, Json olarak tutulur, donus sinifi FilterRowDto public string FilterRowJson { get; set; } // Filtre ayarlari, Json olarak tutulur, donus sinifi FilterRowDto
public string RowJson { get; set; } // Row ayarları, Json olarak tutulur, donus sinifi FilterRowDto public string RowJson { get; set; } // Row ayarları, Json olarak tutulur, donus sinifi FilterRowDto
public string HeaderFilterJson { get; set; } // Header filtreleme ayarlari, Json olarak tutulur public string HeaderFilterJson { get; set; } // Header filtreleme ayarlari, Json olarak tutulur

View file

@ -53,7 +53,13 @@ public class ListFormField : Entity<Guid>
public string Alignment { get; set; } = "left"; // Sütunun Sağa, sola veya ortalama gösterimi public string Alignment { get; set; } = "left"; // Sütunun Sağa, sola veya ortalama gösterimi
public string Format { get; set; } // Cell bazında sütunun formatlanması public string Format { get; set; } // Cell bazında sütunun formatlanması
public string EditorOptions { get; set; } //Sütunun ekstra özellikleri yönetilmesi
public int? EditOrderNo { get; set; }
public int? EditGroupOrderNo { get; set; }
public string EditorType2 { get; set; }
public int? ColSpan { get; set; }
public string EditorScript { get; set; } //Sütunun ekstra javascript ile yönetilmesi
public string EditorOptions { get; set; } //Sütunun ekstra özellikleri yönetilmesi
} }

View file

@ -20,9 +20,9 @@ public static class AbpPermissionsExtensions
// 🔹 Gereksiz boşlukları temizle // 🔹 Gereksiz boşlukları temizle
var cleaned = string.Join( var cleaned = string.Join(
'|', "|",
menuGroup menuGroup
.Split('|', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) .Split(PlatformConsts.MultiValueDelimiter, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.Distinct() .Distinct()
); );
@ -44,7 +44,7 @@ public static class AbpPermissionsExtensions
// 🔹 "Erp|Kurs" -> ["Erp", "Kurs"] // 🔹 "Erp|Kurs" -> ["Erp", "Kurs"]
return value return value
.Split('|', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) .Split(PlatformConsts.MultiValueDelimiter, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.Distinct() .Distinct()
.ToArray(); .ToArray();
} }

View file

@ -165,14 +165,5 @@ public static class AbpTenantExtensions
{ {
return tenant.GetProperty<string>(PlatformConsts.Tenants.MenuGroup); return tenant.GetProperty<string>(PlatformConsts.Tenants.MenuGroup);
} }
public static void SetMaxConcurrentUsers(this Tenant tenant, int? maxConcurrentUsers)
{
tenant.SetProperty(PlatformConsts.Tenants.MaxConcurrentUsers, maxConcurrentUsers.HasValue ? (object)maxConcurrentUsers.Value : null);
}
public static int? GetMaxConcurrentUsers(this Tenant tenant)
{
return tenant.GetProperty<int?>(PlatformConsts.Tenants.MaxConcurrentUsers);
}
} }

View file

@ -30,6 +30,8 @@ public class PlatformSignInResult : SignInResult
public bool IsNotAllowed_WorkHour { get; set; } public bool IsNotAllowed_WorkHour { get; set; }
public bool IsNotAllowed_BranchLimit { get; set; }
public bool IsNotAllowed_ConcurrentUserLimit { get; set; } public bool IsNotAllowed_ConcurrentUserLimit { get; set; }
public override string ToString() public override string ToString()
@ -42,6 +44,7 @@ public class PlatformSignInResult : SignInResult
ShouldChangePasswordPeriodic ? "ShouldChangePasswordPeriodic" : ShouldChangePasswordPeriodic ? "ShouldChangePasswordPeriodic" :
IsNotAllowed_TenantIsPassive ? "NotAllowed_TenantIsPassive" : IsNotAllowed_TenantIsPassive ? "NotAllowed_TenantIsPassive" :
IsNotAllowed_WorkHour ? "NotAllowed_WorkHour" : IsNotAllowed_WorkHour ? "NotAllowed_WorkHour" :
IsNotAllowed_BranchLimit ? "NotAllowed_BranchLimit" :
IsNotAllowed_ConcurrentUserLimit ? "NotAllowed_ConcurrentUserLimit" : IsNotAllowed_ConcurrentUserLimit ? "NotAllowed_ConcurrentUserLimit" :
base.ToString(); base.ToString();
} }

View file

@ -1,58 +0,0 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
using Volo.Abp.Domain.Values;
namespace Sozsoft.Platform.Queries;
// public class EditingForm : ValueObject
// {
// public int Order { get; set; }
// public string ItemType { get; set; }
// public string Caption { get; set; }
// public int ColCount { get; set; }
// public int ColSpan { get; set; }
// /// <summary> Type: Array<Simple Form Item | Group Form Item | Tabbed Form Item | Empty Form Item | Button Form Item>
// /// Bu kisma suan sadece string olarak doldurulacak
// /// items: ['FirstName', 'LastName',
// /// { dataField: 'Notes', editorType: 'dxTextArea', colSpan: 2, editorOptions: { height: 100, }, }
// /// ],
// /// </summary>
// //[TextArea]
// //public string[] Items { get; set; }
// public EditingFormItem[] Items { get; set; }
// protected override IEnumerable<object> GetAtomicValues()
// {
// yield return ItemType;
// yield return Caption;
// yield return ColCount;
// yield return ColSpan;
// yield return Items;
// }
// }
// public class EditingFormItem : ValueObject
// {
// [JsonPropertyName("order")]
// public int Order { get; set; }
// [JsonPropertyName("dataField")]
// public string DataField { get; set; }
// [JsonPropertyName("editorType2")]
// public string EditorType2 { get; set; }
// [JsonPropertyName("colSpan")]
// public int ColSpan { get; set; }
// [JsonPropertyName("editorOptions")]
// public string EditorOptions { get; set; }
// [JsonPropertyName("isRequired")]
// public bool IsRequired { get; set; }
// protected override IEnumerable<object> GetAtomicValues()
// {
// yield return DataField;
// yield return EditorType2;
// yield return ColSpan;
// yield return EditorOptions;
// yield return IsRequired;
// }
// }

View file

@ -52,7 +52,9 @@ public class QueryHelper
case DbType.String: case DbType.String:
case DbType.AnsiString: case DbType.AnsiString:
var strValues = values.Select(a => a?.ToString()).ToArray(); var strValues = values.Select(a => a?.ToString()).ToArray();
value = string.Join(PlatformConsts.MultiValueDelimiter, strValues); value = isArray
? string.Join(PlatformConsts.MultiValueDelimiter, strValues)
: strValues[0];
break; break;
case DbType.Date: case DbType.Date:
case DbType.DateTime: case DbType.DateTime:

View file

@ -170,7 +170,8 @@ public class QueryManager : PlatformDomainService, IQueryManager
// oncelik Command alanindadir, dolu ise silme islemi buradaki sorguya yonlendirilir // oncelik Command alanindadir, dolu ise silme islemi buradaki sorguya yonlendirilir
if (!string.IsNullOrEmpty(command)) if (!string.IsNullOrEmpty(command))
{ {
sql = NormalizeCollectionParameterCommand(command, parameters, dataSourceType); // sql = NormalizeCollectionParameterCommand(command, parameters, dataSourceType);
sql = command;
} }
else else
{ {
@ -188,12 +189,6 @@ public class QueryManager : PlatformDomainService, IQueryManager
} }
else if (op == OperationEnum.Update) else if (op == OperationEnum.Update)
{ {
var where = dataSourceType switch
{
DataSourceTypeEnum.Mssql => $"\"{listForm.KeyFieldName}\" IN @{listForm.KeyFieldName}",
DataSourceTypeEnum.Postgresql => $"\"{listForm.KeyFieldName}\" = ANY(@{listForm.KeyFieldName})",
_ => string.Empty,
};
var updateFields = parameters.Select(a => $"\"{a.Key}\" = @{a.Key}").ToList(); var updateFields = parameters.Select(a => $"\"{a.Key}\" = @{a.Key}").ToList();
var val = QueryHelper.GetFormattedValue(listForm.KeyFieldDbSourceType, keys); var val = QueryHelper.GetFormattedValue(listForm.KeyFieldDbSourceType, keys);
if (!parameters.ContainsKey(listForm.KeyFieldName)) if (!parameters.ContainsKey(listForm.KeyFieldName))
@ -202,6 +197,18 @@ public class QueryManager : PlatformDomainService, IQueryManager
listForm.KeyFieldName, listForm.KeyFieldName,
val.GetType().IsArray ? val : new object[] { val }); val.GetType().IsArray ? val : new object[] { val });
} }
var where = BuildWhereCondition(
listForm.KeyFieldName,
parameters[listForm.KeyFieldName],
dataSourceType);
if (parameters.TryGetValue("TenantId", out var tenantId)
&& !string.Equals(listForm.KeyFieldName, "TenantId", StringComparison.OrdinalIgnoreCase))
{
where += $" AND {BuildWhereCondition("TenantId", tenantId, dataSourceType)}";
}
sql = $"UPDATE \"{listForm.SelectCommand}\" SET {string.Join(',', updateFields)} WHERE {where}"; sql = $"UPDATE \"{listForm.SelectCommand}\" SET {string.Join(',', updateFields)} WHERE {where}";
} }
else if (op == OperationEnum.Delete) else if (op == OperationEnum.Delete)
@ -212,12 +219,7 @@ public class QueryManager : PlatformDomainService, IQueryManager
{ {
where = string.Join( where = string.Join(
" AND ", " AND ",
parameters.Select(a => dataSourceType switch parameters.Select(a => BuildWhereCondition(a.Key, a.Value, dataSourceType)).ToList());
{
DataSourceTypeEnum.Mssql => $"\"{a.Key}\" IN @{a.Key}",
DataSourceTypeEnum.Postgresql => $"\"{a.Key}\" = ANY(@{a.Key})",
_ => "1 = 0",
}).ToList());
} }
else else
{ {
@ -240,77 +242,101 @@ public class QueryManager : PlatformDomainService, IQueryManager
return sql; return sql;
} }
private static string NormalizeCollectionParameterCommand( private static bool IsCollectionValue(object value)
string command,
Dictionary<string, object> parameters,
DataSourceTypeEnum dataSourceType)
{
if (string.IsNullOrWhiteSpace(command) || parameters == null || parameters.Count == 0)
{
return command;
}
var sql = command;
foreach (var parameter in parameters)
{
if (!IsCollectionParameter(parameter.Value))
{
continue;
}
var escapedParameterName = Regex.Escape(parameter.Key);
sql = dataSourceType switch
{
DataSourceTypeEnum.Mssql => NormalizeMssqlCollectionParameter(sql, escapedParameterName, parameter.Key),
DataSourceTypeEnum.Postgresql => NormalizePostgresqlCollectionParameter(sql, escapedParameterName, parameter.Key),
_ => sql
};
}
return sql;
}
private static bool IsCollectionParameter(object value)
{ {
return value is System.Collections.IEnumerable return value is System.Collections.IEnumerable
&& value is not string && value is not string
&& value is not byte[]; && value is not byte[];
} }
private static string NormalizeMssqlCollectionParameter( private static string BuildWhereCondition(
string sql, string fieldName,
string escapedParameterName, object value,
string parameterName) DataSourceTypeEnum dataSourceType)
{ {
sql = Regex.Replace( return dataSourceType switch
sql, {
$@"IN\s*\(\s*@{escapedParameterName}\s*\)", DataSourceTypeEnum.Mssql when value is null or DBNull => $"\"{fieldName}\" IS NULL",
$"IN @{parameterName}", DataSourceTypeEnum.Postgresql when value is null or DBNull => $"\"{fieldName}\" IS NULL",
RegexOptions.IgnoreCase); DataSourceTypeEnum.Mssql when IsCollectionValue(value) => $"\"{fieldName}\" IN @{fieldName}",
DataSourceTypeEnum.Postgresql when IsCollectionValue(value) => $"\"{fieldName}\" = ANY(@{fieldName})",
return Regex.Replace( DataSourceTypeEnum.Mssql => $"\"{fieldName}\" = @{fieldName}",
sql, DataSourceTypeEnum.Postgresql => $"\"{fieldName}\" = @{fieldName}",
$@"(?<column>(""[^""]+""|\[[^\]]+\]|`[^`]+`|\w+))\s*=\s*@{escapedParameterName}\b", _ => "1 = 0",
match => $"{match.Groups["column"].Value} IN @{parameterName}", };
RegexOptions.IgnoreCase);
} }
private static string NormalizePostgresqlCollectionParameter( // private static string NormalizeCollectionParameterCommand(
string sql, // string command,
string escapedParameterName, // Dictionary<string, object> parameters,
string parameterName) // DataSourceTypeEnum dataSourceType)
{ // {
sql = Regex.Replace( // if (string.IsNullOrWhiteSpace(command) || parameters == null || parameters.Count == 0)
sql, // {
$@"IN\s*\(\s*@{escapedParameterName}\s*\)", // return command;
$"= ANY(@{parameterName})", // }
RegexOptions.IgnoreCase);
return Regex.Replace( // var sql = command;
sql, // foreach (var parameter in parameters)
$@"(?<column>(""[^""]+""|\[[^\]]+\]|`[^`]+`|\w+))\s*=\s*@{escapedParameterName}\b", // {
match => $"{match.Groups["column"].Value} = ANY(@{parameterName})", // if (!IsCollectionParameter(parameter.Value))
RegexOptions.IgnoreCase); // {
} // continue;
// }
// var escapedParameterName = Regex.Escape(parameter.Key);
// sql = dataSourceType switch
// {
// DataSourceTypeEnum.Mssql => NormalizeMssqlCollectionParameter(sql, escapedParameterName, parameter.Key),
// DataSourceTypeEnum.Postgresql => NormalizePostgresqlCollectionParameter(sql, escapedParameterName, parameter.Key),
// _ => sql
// };
// }
// return sql;
// }
// private static bool IsCollectionParameter(object value)
// {
// return value is System.Collections.IEnumerable
// && value is not string
// && value is not byte[];
// }
// private static string NormalizeMssqlCollectionParameter(
// string sql,
// string escapedParameterName,
// string parameterName)
// {
// sql = Regex.Replace(
// sql,
// $@"IN\s*\(\s*@{escapedParameterName}\s*\)",
// $"IN @{parameterName}",
// RegexOptions.IgnoreCase);
// return Regex.Replace(
// sql,
// $@"(?<column>(""[^""]+""|\[[^\]]+\]|`[^`]+`|\w+))\s*=\s*@{escapedParameterName}\b",
// match => $"{match.Groups["column"].Value} IN @{parameterName}",
// RegexOptions.IgnoreCase);
// }
// private static string NormalizePostgresqlCollectionParameter(
// string sql,
// string escapedParameterName,
// string parameterName)
// {
// sql = Regex.Replace(
// sql,
// $@"IN\s*\(\s*@{escapedParameterName}\s*\)",
// $"= ANY(@{parameterName})",
// RegexOptions.IgnoreCase);
// return Regex.Replace(
// sql,
// $@"(?<column>(""[^""]+""|\[[^\]]+\]|`[^`]+`|\w+))\s*=\s*@{escapedParameterName}\b",
// match => $"{match.Groups["column"].Value} = ANY(@{parameterName})",
// RegexOptions.IgnoreCase);
// }
} }

View file

@ -4,6 +4,7 @@ using System.Data;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Threading.Tasks;
using Sozsoft.Platform.Entities; using Sozsoft.Platform.Entities;
using Sozsoft.Platform.Enums; using Sozsoft.Platform.Enums;
using Sozsoft.Platform.Extensions; using Sozsoft.Platform.Extensions;
@ -32,11 +33,11 @@ public interface ISelectQueryManager
List<string> SummaryQueries { get; } List<string> SummaryQueries { get; }
public bool IsAppliedGridFilter { get; } public bool IsAppliedGridFilter { get; }
public bool IsAppliedServerFilter { get; } public bool IsAppliedServerFilter { get; }
void PrepareQueries(ListForm listform, Task PrepareQueriesAsync(ListForm listform,
List<ListFormField> listFormFields, List<ListFormField> listFormFields,
DataSourceTypeEnum dataSourceType, DataSourceTypeEnum dataSourceType,
List<ListFormCustomization> listFormCustomizations = null, List<ListFormCustomization> listFormCustomizations = null,
QueryParameters queryParams = null); QueryParameters queryParams = null);
} }
public class SelectField public class SelectField
@ -129,11 +130,11 @@ public class SelectQueryManager : PlatformDomainService, ISelectQueryManager
DefaultValueHelper = defaultValueHelper; DefaultValueHelper = defaultValueHelper;
} }
public void PrepareQueries(ListForm listform, public async Task PrepareQueriesAsync(ListForm listform,
List<ListFormField> listFormFields, List<ListFormField> listFormFields,
DataSourceTypeEnum dataSourceType, DataSourceTypeEnum dataSourceType,
List<ListFormCustomization> listFormCustomizations = null, List<ListFormCustomization> listFormCustomizations = null,
QueryParameters queryParams = null) QueryParameters queryParams = null)
{ {
ResetQueryState(); ResetQueryState();
@ -170,7 +171,7 @@ public class SelectQueryManager : PlatformDomainService, ISelectQueryManager
var joinParts = SelectFields.Where(c => !string.IsNullOrEmpty(c.JoinSql)).Select(c => c.JoinSql).Distinct(); var joinParts = SelectFields.Where(c => !string.IsNullOrEmpty(c.JoinSql)).Select(c => c.JoinSql).Distinct();
JoinParts.AddRange(joinParts); JoinParts.AddRange(joinParts);
List<string> whereFields = GetWhereFields(listform, listFormFields, queryParams); List<string> whereFields = await GetWhereFieldsAsync(listform, listFormFields, queryParams);
WhereParts.AddRange(whereFields); WhereParts.AddRange(whereFields);
List<string> sortFields = GetSortFields(listform, listFormFields, queryParams?.Sort); List<string> sortFields = GetSortFields(listform, listFormFields, queryParams?.Sort);
@ -343,7 +344,7 @@ public class SelectQueryManager : PlatformDomainService, ISelectQueryManager
} }
} }
private List<string> GetWhereFields(ListForm listform, List<ListFormField> listFormFields, QueryParameters queryParams = null) private async Task<List<string>> GetWhereFieldsAsync(ListForm listform, List<ListFormField> listFormFields, QueryParameters queryParams = null)
{ {
var whereParts = new List<string>(); var whereParts = new List<string>();
@ -436,7 +437,7 @@ public class SelectQueryManager : PlatformDomainService, ISelectQueryManager
whereParts.Add("AND"); whereParts.Add("AND");
} }
var ids = BranchUsersRepository.GetListAsync((a) => a.UserId == CurrentUser.Id.Value).Result; var ids = await BranchUsersRepository.GetListAsync((a) => a.UserId == CurrentUser.Id.Value);
if (ids.Count > 0) if (ids.Count > 0)
{ {
whereParts.Add($"\"BranchId\" IN ({string.Join(",", ids.Select(a => $"'{a.BranchId}'"))})"); whereParts.Add($"\"BranchId\" IN ({string.Join(",", ids.Select(a => $"'{a.BranchId}'"))})");
@ -454,7 +455,7 @@ public class SelectQueryManager : PlatformDomainService, ISelectQueryManager
whereParts.Add("AND"); whereParts.Add("AND");
} }
var ids = OuRepository.GetOrganizationUnitIdsWithChildren(CurrentUser.Id.Value).Result; var ids = await OuRepository.GetOrganizationUnitIdsWithChildren(CurrentUser.Id.Value);
if (ids.Count > 0) if (ids.Count > 0)
{ {
whereParts.Add($"\"OrganizationUnitId\" IN ({string.Join(",", ids.Select(a => $"'{a}'"))})"); whereParts.Add($"\"OrganizationUnitId\" IN ({string.Join(",", ids.Select(a => $"'{a}'"))})");
@ -468,7 +469,7 @@ public class SelectQueryManager : PlatformDomainService, ISelectQueryManager
if (listform.WorkflowJson.IsNullOrWhiteSpace() == false) if (listform.WorkflowJson.IsNullOrWhiteSpace() == false)
{ {
var workflow = JsonSerializer.Deserialize<Workflow>(listform.WorkflowJson); var workflow = JsonSerializer.Deserialize<Workflow>(listform.WorkflowJson);
if (workflow != null && workflow.IsFilterUserName) if (workflow != null && workflow.ApprovalIsFilterUserName)
{ {
if (whereParts.Any()) if (whereParts.Any())
{ {
@ -479,11 +480,7 @@ public class SelectQueryManager : PlatformDomainService, ISelectQueryManager
// hem de ApprovalUserFieldName alanı CurrentUserName'e eşit olan kayıtları getirmek istiyoruz, // hem de ApprovalUserFieldName alanı CurrentUserName'e eşit olan kayıtları getirmek istiyoruz,
// Boş olanları getirmemizin sebebi workflow start edebilmektir. // Boş olanları getirmemizin sebebi workflow start edebilmektir.
// İlk kayıt eklenince onaylayacak kişi atanmaz, böylece o kayıt onaysız olarak kalmaz ve workflow başlatılabilir olur. // İlk kayıt eklenince onaylayacak kişi atanmaz, böylece o kayıt onaysız olarak kalmaz ve workflow başlatılabilir olur.
whereParts.Add( whereParts.Add(GetWorkflowApproverFilter(workflow.ApprovalUserFieldName));
$"(\"{workflow.ApprovalUserFieldName}\" = '{CurrentUser.UserName}' " +
$"OR \"{workflow.ApprovalUserFieldName}\" IS NULL " +
$"OR \"{workflow.ApprovalUserFieldName}\" = '')"
);
} }
} }
@ -495,6 +492,38 @@ public class SelectQueryManager : PlatformDomainService, ISelectQueryManager
return whereParts; return whereParts;
} }
private string GetWorkflowApproverFilter(string approvalUserFieldName)
{
if (approvalUserFieldName.IsNullOrWhiteSpace())
{
return "1 = 1";
}
var field = $"\"{approvalUserFieldName}\"";
var identities = new[] { CurrentUser.UserName, CurrentUser.Email, CurrentUser.Name }
.Where(identity => !identity.IsNullOrWhiteSpace())
.Select(EscapeSqlLiteral)
.Distinct()
.ToList();
if (identities.Count == 0)
{
return $"({field} IS NULL OR {field} = '')";
}
var identityList = string.Join(",", identities.Select(identity => $"'{identity}'"));
var approverMatch = DataSourceType == DataSourceTypeEnum.Postgresql
? $"EXISTS (SELECT 1 FROM unnest(string_to_array(CAST({field} AS TEXT), '{PlatformConsts.MultiValueDelimiter}')) AS split(value) WHERE btrim(split.value) IN ({identityList}))"
: $"EXISTS (SELECT 1 FROM STRING_SPLIT(CAST({field} AS NVARCHAR(MAX)), N'{PlatformConsts.MultiValueDelimiter}') AS split WHERE LTRIM(RTRIM(split.value)) IN ({identityList}))";
return $"({approverMatch} OR {field} IS NULL OR {field} = '')";
}
private static string EscapeSqlLiteral(string value)
{
return (value ?? string.Empty).Replace("'", "''");
}
/// <summary> FieldName operator Id seklinde olan filtreleri ayirir /// <summary> FieldName operator Id seklinde olan filtreleri ayirir
/// </summary> /// </summary>
/// <param name="filter"></param> /// <param name="filter"></param>
@ -829,8 +858,7 @@ public class SelectQueryManager : PlatformDomainService, ISelectQueryManager
} }
else else
{ {
// Birden fazla → '|' ile birleştir argumentExpression = string.Join(PlatformConsts.MultiValueDelimiter, argumentFields.Select(f => $"[{f}]"));
argumentExpression = string.Join(" + '|' + ", argumentFields.Select(f => $"[{f}]"));
} }
// Select sütunlarını oluştur // Select sütunlarını oluştur

View file

@ -6,18 +6,18 @@ namespace Sozsoft.Platform.Queries;
public class Workflow : ValueObject public class Workflow : ValueObject
{ {
public string ApprovalUserFieldName { get; set; } public string ApprovalUserFieldName { get; set; }
public bool IsFilterUserName { get; set; }
public string ApprovalDateFieldName { get; set; } public string ApprovalDateFieldName { get; set; }
public string ApprovalStatusFieldName { get; set; } public string ApprovalStatusFieldName { get; set; }
public string ApprovalDescriptionFieldName { get; set; } public string ApprovalDescriptionFieldName { get; set; }
public bool ApprovalIsFilterUserName { get; set; }
protected override IEnumerable<object> GetAtomicValues() protected override IEnumerable<object> GetAtomicValues()
{ {
yield return ApprovalUserFieldName; yield return ApprovalUserFieldName;
yield return IsFilterUserName;
yield return ApprovalDateFieldName; yield return ApprovalDateFieldName;
yield return ApprovalStatusFieldName; yield return ApprovalStatusFieldName;
yield return ApprovalDescriptionFieldName; yield return ApprovalDescriptionFieldName;
yield return ApprovalIsFilterUserName;
} }
} }

View file

@ -378,6 +378,7 @@ public class PlatformDbContext :
b.Property(a => a.WorkflowJson).HasColumnType("text"); b.Property(a => a.WorkflowJson).HasColumnType("text");
b.Property(a => a.ExtraFilterJson).HasColumnType("text"); b.Property(a => a.ExtraFilterJson).HasColumnType("text");
b.Property(a => a.LayoutJson).HasColumnType("text"); b.Property(a => a.LayoutJson).HasColumnType("text");
b.Property(a => a.TodoOptionJson).HasColumnType("text");
b.Property(a => a.CommonJson).HasColumnType("text"); b.Property(a => a.CommonJson).HasColumnType("text");
b.Property(a => a.DataSourceJson).HasColumnType("text"); b.Property(a => a.DataSourceJson).HasColumnType("text");
b.Property(a => a.AdaptiveLayoutJson).HasColumnType("text"); b.Property(a => a.AdaptiveLayoutJson).HasColumnType("text");
@ -406,6 +407,7 @@ public class PlatformDbContext :
b.HasMany<ListFormField>().WithOne().HasForeignKey(x => x.ListFormCode).HasPrincipalKey(x => x.ListFormCode).IsRequired(); b.HasMany<ListFormField>().WithOne().HasForeignKey(x => x.ListFormCode).HasPrincipalKey(x => x.ListFormCode).IsRequired();
b.HasMany<ListFormCustomization>().WithOne().HasForeignKey(x => x.ListFormCode).HasPrincipalKey(x => x.ListFormCode).IsRequired(); b.HasMany<ListFormCustomization>().WithOne().HasForeignKey(x => x.ListFormCode).HasPrincipalKey(x => x.ListFormCode).IsRequired();
b.HasMany<ListFormImport>().WithOne().HasForeignKey(x => x.ListFormCode).HasPrincipalKey(x => x.ListFormCode).IsRequired(); b.HasMany<ListFormImport>().WithOne().HasForeignKey(x => x.ListFormCode).HasPrincipalKey(x => x.ListFormCode).IsRequired();
b.HasMany<ListFormWorkflow>().WithOne().HasForeignKey(x => x.ListFormCode).HasPrincipalKey(x => x.ListFormCode).IsRequired();
}); });
builder.Entity<ListFormField>(b => builder.Entity<ListFormField>(b =>
@ -453,6 +455,8 @@ public class PlatformDbContext :
b.Property(a => a.Alignment).HasMaxLength(20).HasDefaultValue("left"); b.Property(a => a.Alignment).HasMaxLength(20).HasDefaultValue("left");
b.Property(a => a.Format).HasMaxLength(128); b.Property(a => a.Format).HasMaxLength(128);
b.Property(a => a.EditorOptions).HasColumnType("text"); b.Property(a => a.EditorOptions).HasColumnType("text");
b.Property(a => a.EditorType2).HasMaxLength(64);
b.Property(a => a.EditorScript).HasColumnType("text");
b.HasIndex(x => new { x.ListFormCode, x.UserId, x.RoleId, x.CultureName, x.FieldName }).IsUnique().HasFilter(null); b.HasIndex(x => new { x.ListFormCode, x.UserId, x.RoleId, x.CultureName, x.FieldName }).IsUnique().HasFilter(null);
}); });
@ -498,7 +502,7 @@ public class PlatformDbContext :
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.ListFormWorkflow)), Prefix.DbSchema); b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.ListFormWorkflow)), Prefix.DbSchema);
b.ConfigureByConvention(); b.ConfigureByConvention();
b.Property(x => x.Id).HasMaxLength(50); b.Property(x => x.Id).HasMaxLength(128);
b.Property(x => x.ListFormCode).IsRequired().HasMaxLength(64); b.Property(x => x.ListFormCode).IsRequired().HasMaxLength(64);
b.Property(x => x.Kind).IsRequired().HasMaxLength(50); b.Property(x => x.Kind).IsRequired().HasMaxLength(50);
b.Property(x => x.Title).IsRequired().HasMaxLength(250); b.Property(x => x.Title).IsRequired().HasMaxLength(250);
@ -506,15 +510,14 @@ public class PlatformDbContext :
b.Property(x => x.CompareOperator).IsRequired().HasMaxLength(20); b.Property(x => x.CompareOperator).IsRequired().HasMaxLength(20);
b.Property(x => x.CompareValue).HasPrecision(18, 2); b.Property(x => x.CompareValue).HasPrecision(18, 2);
b.Property(x => x.Approver).IsRequired().HasMaxLength(250); b.Property(x => x.Approver).IsRequired().HasMaxLength(250);
b.Property(x => x.NextOnStart).IsRequired().HasMaxLength(50); b.Property(x => x.NextOnStart).IsRequired().HasMaxLength(128);
b.Property(x => x.NextOnTrue).IsRequired().HasMaxLength(50); b.Property(x => x.NextOnTrue).IsRequired().HasMaxLength(128);
b.Property(x => x.NextOnFalse).IsRequired().HasMaxLength(50); b.Property(x => x.NextOnFalse).IsRequired().HasMaxLength(128);
b.Property(x => x.NextOnApprove).IsRequired().HasMaxLength(50); b.Property(x => x.NextOnApprove).IsRequired().HasMaxLength(128);
b.Property(x => x.NextOnReject).IsRequired().HasMaxLength(50); b.Property(x => x.NextOnReject).IsRequired().HasMaxLength(128);
b.Property(x => x.PositionX).IsRequired(); b.Property(x => x.PositionX).IsRequired();
b.Property(x => x.PositionY).IsRequired(); b.Property(x => x.PositionY).IsRequired();
b.Property(x => x.CompareOutcomesJson).HasColumnType("text"); b.Property(x => x.CompareOutcomesJson).HasColumnType("text");
b.HasIndex(x => new { x.ListFormCode, x.Title }).IsUnique();
}); });
builder.Entity<Note>(b => builder.Entity<Note>(b =>
@ -573,6 +576,10 @@ public class PlatformDbContext :
b.Property(x => x.Title).IsRequired().HasMaxLength(256); b.Property(x => x.Title).IsRequired().HasMaxLength(256);
b.Property(x => x.Content).IsRequired(); b.Property(x => x.Content).IsRequired();
b.Property(x => x.AuthorName).HasMaxLength(128); b.Property(x => x.AuthorName).HasMaxLength(128);
b.Property(x => x.AuthorTitle).HasMaxLength(128);
b.Property(x => x.AuthorEmail).HasMaxLength(256);
b.Property(x => x.AuthorPhoneNumber).HasMaxLength(32);
b.Property(x => x.AuthorDepartment).HasMaxLength(128);
b.Property(x => x.LastPostUserName).HasMaxLength(128); b.Property(x => x.LastPostUserName).HasMaxLength(128);
b.HasMany(x => x.Posts) b.HasMany(x => x.Posts)
@ -588,6 +595,10 @@ public class PlatformDbContext :
b.Property(x => x.Content).IsRequired(); b.Property(x => x.Content).IsRequired();
b.Property(x => x.AuthorName).HasMaxLength(128); b.Property(x => x.AuthorName).HasMaxLength(128);
b.Property(x => x.AuthorTitle).HasMaxLength(128);
b.Property(x => x.AuthorEmail).HasMaxLength(256);
b.Property(x => x.AuthorPhoneNumber).HasMaxLength(32);
b.Property(x => x.AuthorDepartment).HasMaxLength(128);
b.HasOne(x => x.Topic) b.HasOne(x => x.Topic)
.WithMany(x => x.Posts) .WithMany(x => x.Posts)
@ -637,12 +648,14 @@ public class PlatformDbContext :
b.ConfigureByConvention(); b.ConfigureByConvention();
b.Property(x => x.Name).IsRequired().HasMaxLength(128); b.Property(x => x.Name).IsRequired().HasMaxLength(128);
b.Property(x => x.RoutePath).IsRequired().HasMaxLength(512);
b.Property(x => x.Code).IsRequired(); b.Property(x => x.Code).IsRequired();
b.Property(x => x.Props).HasMaxLength(1024); b.Property(x => x.Props).HasMaxLength(1024);
b.Property(x => x.Description).HasMaxLength(512); b.Property(x => x.Description).HasMaxLength(512);
b.Property(x => x.Dependencies).HasMaxLength(2048); b.Property(x => x.Dependencies).HasMaxLength(2048);
b.HasIndex(x => new { x.TenantId, x.Name }).IsUnique().HasFilter("[IsDeleted] = 0"); b.HasIndex(x => new { x.TenantId, x.Name }).IsUnique().HasFilter("[IsDeleted] = 0");
b.HasIndex(x => new { x.TenantId, x.RoutePath }).IsUnique().HasFilter("[IsDeleted] = 0");
}); });
builder.Entity<ReportCategory>(b => builder.Entity<ReportCategory>(b =>
@ -650,7 +663,6 @@ public class PlatformDbContext :
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.ReportCategory)), Prefix.DbSchema); b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.ReportCategory)), Prefix.DbSchema);
b.ConfigureByConvention(); b.ConfigureByConvention();
b.Property(x => x.Id).HasMaxLength(256);
b.Property(x => x.Name).IsRequired().HasMaxLength(256); b.Property(x => x.Name).IsRequired().HasMaxLength(256);
b.Property(x => x.Description).HasMaxLength(4096); // JSON string b.Property(x => x.Description).HasMaxLength(4096); // JSON string
b.Property(x => x.Icon).HasMaxLength(64); b.Property(x => x.Icon).HasMaxLength(64);
@ -664,7 +676,6 @@ public class PlatformDbContext :
b.ConfigureByConvention(); b.ConfigureByConvention();
b.Property(x => x.Name).IsRequired().HasMaxLength(256); b.Property(x => x.Name).IsRequired().HasMaxLength(256);
b.Property(x => x.CategoryId).HasMaxLength(256);
b.Property(x => x.Description).HasMaxLength(1024); b.Property(x => x.Description).HasMaxLength(1024);
b.Property(x => x.HtmlContent).IsRequired(); b.Property(x => x.HtmlContent).IsRequired();
b.Property(x => x.Status).HasMaxLength(20); b.Property(x => x.Status).HasMaxLength(20);
@ -747,6 +758,9 @@ public class PlatformDbContext :
b.Property(x => x.GroupName).HasMaxLength(128); b.Property(x => x.GroupName).HasMaxLength(128);
b.Property(x => x.TaxLabel).HasMaxLength(64); b.Property(x => x.TaxLabel).HasMaxLength(64);
b.Property(x => x.Currency).IsRequired().HasMaxLength(8); b.Property(x => x.Currency).IsRequired().HasMaxLength(8);
b.Property(x => x.PhoneNumberMinLength).HasDefaultValue(0);
b.Property(x => x.PhoneNumberMaxLength).HasDefaultValue(0);
b.Property(x => x.PhoneNumberFormat).HasMaxLength(64);
b.HasIndex(x => new { x.Name }).IsUnique().HasFilter("[IsDeleted] = 0"); b.HasIndex(x => new { x.Name }).IsUnique().HasFilter("[IsDeleted] = 0");
@ -977,6 +991,7 @@ public class PlatformDbContext :
b.Property(x => x.Category).IsRequired().HasMaxLength(64); b.Property(x => x.Category).IsRequired().HasMaxLength(64);
b.Property(x => x.MonthlyPrice).HasPrecision(18, 2); b.Property(x => x.MonthlyPrice).HasPrecision(18, 2);
b.Property(x => x.YearlyPrice).HasPrecision(18, 2); b.Property(x => x.YearlyPrice).HasPrecision(18, 2);
b.Property(x => x.VatRate).IsRequired().HasPrecision(5, 3).HasDefaultValue(0.20m);
b.Property(x => x.ImageUrl).HasMaxLength(512); b.Property(x => x.ImageUrl).HasMaxLength(512);
b.HasIndex(x => new { x.Name }).IsUnique().HasFilter("[IsDeleted] = 0"); b.HasIndex(x => new { x.Name }).IsUnique().HasFilter("[IsDeleted] = 0");
@ -1010,29 +1025,43 @@ public class PlatformDbContext :
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.Order)), Prefix.DbSchema); b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.Order)), Prefix.DbSchema);
b.ConfigureByConvention(); b.ConfigureByConvention();
b.Property(o => o.Name).HasMaxLength(64); var isActiveComputedColumnSql = _isPostgreSql
? "CASE WHEN \"LicenseEndTime\" IS NOT NULL AND CURRENT_DATE > \"LicenseEndTime\"::date THEN false ELSE true END"
: "CONVERT(bit, CASE WHEN [LicenseEndTime] IS NOT NULL AND CONVERT(date, GETDATE()) > CONVERT(date, [LicenseEndTime]) THEN 0 ELSE 1 END)";
b.Property(o => o.IsActive)
.HasComputedColumnSql(isActiveComputedColumnSql, stored: false);
b.Property(o => o.IsExisting).IsRequired().HasDefaultValue(false);
b.Property(o => o.OrganizationName).HasMaxLength(128); b.Property(o => o.OrganizationName).HasMaxLength(128);
b.Property(o => o.Founder).HasMaxLength(128); b.Property(o => o.Founder).HasMaxLength(128);
b.Property(o => o.TaxOffice).HasMaxLength(128); b.Property(o => o.TaxOffice).HasMaxLength(128);
b.Property(o => o.Address1).HasMaxLength(512);
b.Property(o => o.Address2).HasMaxLength(512);
b.Property(o => o.District).HasMaxLength(128);
b.Property(o => o.Country).HasMaxLength(128); b.Property(o => o.Country).HasMaxLength(128);
b.Property(o => o.City).HasMaxLength(128); b.Property(o => o.City).HasMaxLength(128);
b.Property(o => o.District).HasMaxLength(128);
b.Property(o => o.Township).HasMaxLength(128);
b.Property(o => o.PostalCode).HasMaxLength(16); b.Property(o => o.PostalCode).HasMaxLength(16);
b.Property(o => o.Address1).HasMaxLength(512);
b.Property(o => o.Address2).HasMaxLength(512);
b.Property(o => o.MobileNumber).HasMaxLength(20); b.Property(o => o.MobileNumber).HasMaxLength(20);
b.Property(o => o.PhoneNumber).HasMaxLength(20); b.Property(o => o.PhoneNumber).HasMaxLength(20);
b.Property(o => o.FaxNumber).HasMaxLength(20); b.Property(o => o.FaxNumber).HasMaxLength(20);
b.Property(o => o.Email).HasMaxLength(128); b.Property(o => o.Email).HasMaxLength(128);
b.Property(o => o.Website).HasMaxLength(128); b.Property(o => o.Website).HasMaxLength(128);
b.Property(o => o.MenuGroup).HasMaxLength(64); b.Property(o => o.MenuGroup).HasMaxLength(64);
b.Property(o => o.BillingCycle).HasMaxLength(32);
b.Property(o => o.Period).IsRequired().HasDefaultValue(1);
b.Property(o => o.Subtotal).IsRequired().HasPrecision(18, 2); b.Property(o => o.Subtotal).IsRequired().HasPrecision(18, 2);
b.Property(o => o.VatTotal).IsRequired().HasPrecision(18, 2);
b.Property(o => o.Commission).IsRequired().HasPrecision(18, 2); b.Property(o => o.Commission).IsRequired().HasPrecision(18, 2);
b.Property(o => o.Total).IsRequired().HasPrecision(18, 2); b.Property(o => o.Total).IsRequired().HasPrecision(18, 2);
b.Property(o => o.PaymentDataJson).HasMaxLength(4096); b.Property(o => o.PaymentDataJson).HasMaxLength(4096);
b.Property(o => o.ApprovalUserName).HasMaxLength(256);
b.Property(o => o.ApprovalStatus).HasMaxLength(64);
b.Property(o => o.ApprovalDescription).HasMaxLength(256);
b.HasMany(o => o.Items) b.HasMany(o => o.Items)
.WithOne(i => i.Order) .WithOne(i => i.Order)
.HasForeignKey(i => i.OrderId) .HasForeignKey(i => i.OrderId)
@ -1046,6 +1075,10 @@ public class PlatformDbContext :
b.Property(i => i.ProductName).IsRequired().HasMaxLength(128); b.Property(i => i.ProductName).IsRequired().HasMaxLength(128);
b.Property(i => i.BillingCycle).IsRequired().HasMaxLength(32); b.Property(i => i.BillingCycle).IsRequired().HasMaxLength(32);
b.Property(i => i.Period).IsRequired().HasDefaultValue(1);
b.Property(i => i.Price).IsRequired().HasPrecision(18, 2);
b.Property(i => i.VatRate).IsRequired().HasPrecision(5, 3);
b.Property(i => i.VatAmount).IsRequired().HasPrecision(18, 2);
b.Property(i => i.TotalPrice).IsRequired().HasPrecision(18, 2); b.Property(i => i.TotalPrice).IsRequired().HasPrecision(18, 2);
}); });

View file

@ -460,15 +460,6 @@ public static class PlatformEfCoreEntityExtensionMappings
} }
); );
ObjectExtensionManager.Instance
.MapEfCoreProperty<Tenant, int?>(
PlatformConsts.Tenants.MaxConcurrentUsers,
(entityBuilder, propertyBuilder) =>
{
propertyBuilder.HasDefaultValue(0);
}
);
ObjectExtensionManager.Instance ObjectExtensionManager.Instance
.MapEfCoreProperty<PermissionDefinitionRecord, string>( .MapEfCoreProperty<PermissionDefinitionRecord, string>(
PlatformConsts.Permissions.MenuGroup, PlatformConsts.Permissions.MenuGroup,

View file

@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
namespace Sozsoft.Platform.Migrations namespace Sozsoft.Platform.Migrations
{ {
[DbContext(typeof(PlatformDbContext))] [DbContext(typeof(PlatformDbContext))]
[Migration("20260625183130_Initial")] [Migration("20260717065637_Initial")]
partial class Initial partial class Initial
{ {
/// <inheritdoc /> /// <inheritdoc />
@ -1542,6 +1542,20 @@ namespace Sozsoft.Platform.Migrations
b.Property<int>("PhoneCode") b.Property<int>("PhoneCode")
.HasColumnType("int"); .HasColumnType("int");
b.Property<string>("PhoneNumberFormat")
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<int?>("PhoneNumberMaxLength")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasDefaultValue(0);
b.Property<int?>("PhoneNumberMinLength")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasDefaultValue(0);
b.Property<bool>("StateRequired") b.Property<bool>("StateRequired")
.HasColumnType("bit"); .HasColumnType("bit");
@ -1812,6 +1826,11 @@ namespace Sozsoft.Platform.Migrations
.HasMaxLength(1024) .HasMaxLength(1024)
.HasColumnType("nvarchar(1024)"); .HasColumnType("nvarchar(1024)");
b.Property<string>("RoutePath")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("nvarchar(512)");
b.Property<Guid?>("TenantId") b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier") .HasColumnType("uniqueidentifier")
.HasColumnName("TenantId"); .HasColumnName("TenantId");
@ -1822,6 +1841,10 @@ namespace Sozsoft.Platform.Migrations
.IsUnique() .IsUnique()
.HasFilter("[IsDeleted] = 0"); .HasFilter("[IsDeleted] = 0");
b.HasIndex("TenantId", "RoutePath")
.IsUnique()
.HasFilter("[IsDeleted] = 0");
b.ToTable("Sas_H_CustomComponent", (string)null); b.ToTable("Sas_H_CustomComponent", (string)null);
}); });
@ -2246,6 +2269,9 @@ namespace Sozsoft.Platform.Migrations
.HasMaxLength(128) .HasMaxLength(128)
.HasColumnType("nvarchar(128)"); .HasColumnType("nvarchar(128)");
b.Property<string>("PostalCode")
.HasColumnType("nvarchar(max)");
b.Property<string>("Township") b.Property<string>("Township")
.HasMaxLength(128) .HasMaxLength(128)
.HasColumnType("nvarchar(128)"); .HasColumnType("nvarchar(128)");
@ -3238,6 +3264,9 @@ namespace Sozsoft.Platform.Migrations
b.Property<string>("TitleJson") b.Property<string>("TitleJson")
.HasColumnType("text"); .HasColumnType("text");
b.Property<string>("TodoOptionJson")
.HasColumnType("text");
b.Property<string>("TooltipJson") b.Property<string>("TooltipJson")
.HasColumnType("text"); .HasColumnType("text");
@ -3386,6 +3415,9 @@ namespace Sozsoft.Platform.Migrations
.HasMaxLength(256) .HasMaxLength(256)
.HasColumnType("nvarchar(256)"); .HasColumnType("nvarchar(256)");
b.Property<int?>("ColSpan")
.HasColumnType("int");
b.Property<string>("ColumnCssClass") b.Property<string>("ColumnCssClass")
.HasMaxLength(128) .HasMaxLength(128)
.HasColumnType("nvarchar(128)"); .HasColumnType("nvarchar(128)");
@ -3411,9 +3443,22 @@ namespace Sozsoft.Platform.Migrations
.HasMaxLength(10) .HasMaxLength(10)
.HasColumnType("nvarchar(10)"); .HasColumnType("nvarchar(10)");
b.Property<int?>("EditGroupOrderNo")
.HasColumnType("int");
b.Property<int?>("EditOrderNo")
.HasColumnType("int");
b.Property<string>("EditorOptions") b.Property<string>("EditorOptions")
.HasColumnType("text"); .HasColumnType("text");
b.Property<string>("EditorScript")
.HasColumnType("text");
b.Property<string>("EditorType2")
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<string>("FieldName") b.Property<string>("FieldName")
.IsRequired() .IsRequired()
.HasMaxLength(128) .HasMaxLength(128)
@ -3635,8 +3680,8 @@ namespace Sozsoft.Platform.Migrations
modelBuilder.Entity("Sozsoft.Platform.Entities.ListFormWorkflow", b => modelBuilder.Entity("Sozsoft.Platform.Entities.ListFormWorkflow", b =>
{ {
b.Property<string>("Id") b.Property<string>("Id")
.HasMaxLength(50) .HasMaxLength(128)
.HasColumnType("nvarchar(50)"); .HasColumnType("nvarchar(128)");
b.Property<string>("Approver") b.Property<string>("Approver")
.IsRequired() .IsRequired()
@ -3672,28 +3717,28 @@ namespace Sozsoft.Platform.Migrations
b.Property<string>("NextOnApprove") b.Property<string>("NextOnApprove")
.IsRequired() .IsRequired()
.HasMaxLength(50) .HasMaxLength(128)
.HasColumnType("nvarchar(50)"); .HasColumnType("nvarchar(128)");
b.Property<string>("NextOnFalse") b.Property<string>("NextOnFalse")
.IsRequired() .IsRequired()
.HasMaxLength(50) .HasMaxLength(128)
.HasColumnType("nvarchar(50)"); .HasColumnType("nvarchar(128)");
b.Property<string>("NextOnReject") b.Property<string>("NextOnReject")
.IsRequired() .IsRequired()
.HasMaxLength(50) .HasMaxLength(128)
.HasColumnType("nvarchar(50)"); .HasColumnType("nvarchar(128)");
b.Property<string>("NextOnStart") b.Property<string>("NextOnStart")
.IsRequired() .IsRequired()
.HasMaxLength(50) .HasMaxLength(128)
.HasColumnType("nvarchar(50)"); .HasColumnType("nvarchar(128)");
b.Property<string>("NextOnTrue") b.Property<string>("NextOnTrue")
.IsRequired() .IsRequired()
.HasMaxLength(50) .HasMaxLength(128)
.HasColumnType("nvarchar(50)"); .HasColumnType("nvarchar(128)");
b.Property<int>("PositionX") b.Property<int>("PositionX")
.HasColumnType("int"); .HasColumnType("int");
@ -3708,8 +3753,7 @@ namespace Sozsoft.Platform.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("ListFormCode", "Title") b.HasIndex("ListFormCode");
.IsUnique();
b.ToTable("Sas_H_ListFormWorkflow", (string)null); b.ToTable("Sas_H_ListFormWorkflow", (string)null);
}); });
@ -4071,6 +4115,25 @@ namespace Sozsoft.Platform.Migrations
.HasMaxLength(512) .HasMaxLength(512)
.HasColumnType("nvarchar(512)"); .HasColumnType("nvarchar(512)");
b.Property<DateTime?>("ApprovalDate")
.HasColumnType("datetime2");
b.Property<string>("ApprovalDescription")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("ApprovalStatus")
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<string>("ApprovalUserName")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("BillingCycle")
.HasMaxLength(32)
.HasColumnType("nvarchar(32)");
b.Property<string>("City") b.Property<string>("City")
.HasMaxLength(128) .HasMaxLength(128)
.HasColumnType("nvarchar(128)"); .HasColumnType("nvarchar(128)");
@ -4119,7 +4182,9 @@ namespace Sozsoft.Platform.Migrations
.HasColumnType("int"); .HasColumnType("int");
b.Property<bool>("IsActive") b.Property<bool>("IsActive")
.HasColumnType("bit"); .ValueGeneratedOnAddOrUpdate()
.HasColumnType("bit")
.HasComputedColumnSql("CONVERT(bit, CASE WHEN [LicenseEndTime] IS NOT NULL AND CONVERT(date, GETDATE()) > CONVERT(date, [LicenseEndTime]) THEN 0 ELSE 1 END)", false);
b.Property<bool>("IsDeleted") b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
@ -4127,6 +4192,11 @@ namespace Sozsoft.Platform.Migrations
.HasDefaultValue(false) .HasDefaultValue(false)
.HasColumnName("IsDeleted"); .HasColumnName("IsDeleted");
b.Property<bool>("IsExisting")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false);
b.Property<DateTime?>("LastModificationTime") b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2") .HasColumnType("datetime2")
.HasColumnName("LastModificationTime"); .HasColumnName("LastModificationTime");
@ -4135,6 +4205,12 @@ namespace Sozsoft.Platform.Migrations
.HasColumnType("uniqueidentifier") .HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId"); .HasColumnName("LastModifierId");
b.Property<DateTime?>("LicenseEndTime")
.HasColumnType("datetime2");
b.Property<DateTime?>("LicenseStartTime")
.HasColumnType("datetime2");
b.Property<string>("MenuGroup") b.Property<string>("MenuGroup")
.HasMaxLength(64) .HasMaxLength(64)
.HasColumnType("nvarchar(64)"); .HasColumnType("nvarchar(64)");
@ -4143,10 +4219,6 @@ namespace Sozsoft.Platform.Migrations
.HasMaxLength(20) .HasMaxLength(20)
.HasColumnType("nvarchar(20)"); .HasColumnType("nvarchar(20)");
b.Property<string>("Name")
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<string>("OrganizationName") b.Property<string>("OrganizationName")
.HasMaxLength(128) .HasMaxLength(128)
.HasColumnType("nvarchar(128)"); .HasColumnType("nvarchar(128)");
@ -4158,6 +4230,11 @@ namespace Sozsoft.Platform.Migrations
b.Property<Guid>("PaymentMethodId") b.Property<Guid>("PaymentMethodId")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<int>("Period")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasDefaultValue(1);
b.Property<string>("PhoneNumber") b.Property<string>("PhoneNumber")
.HasMaxLength(20) .HasMaxLength(20)
.HasColumnType("nvarchar(20)"); .HasColumnType("nvarchar(20)");
@ -4174,10 +4251,21 @@ namespace Sozsoft.Platform.Migrations
.HasMaxLength(128) .HasMaxLength(128)
.HasColumnType("nvarchar(128)"); .HasColumnType("nvarchar(128)");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier");
b.Property<decimal>("Total") b.Property<decimal>("Total")
.HasPrecision(18, 2) .HasPrecision(18, 2)
.HasColumnType("decimal(18,2)"); .HasColumnType("decimal(18,2)");
b.Property<string>("Township")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<decimal>("VatTotal")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<long?>("VknTckn") b.Property<long?>("VknTckn")
.HasColumnType("bigint"); .HasColumnType("bigint");
@ -4233,6 +4321,15 @@ namespace Sozsoft.Platform.Migrations
b.Property<Guid>("OrderId") b.Property<Guid>("OrderId")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<int>("Period")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasDefaultValue(1);
b.Property<decimal>("Price")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<Guid>("ProductId") b.Property<Guid>("ProductId")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
@ -4248,6 +4345,14 @@ namespace Sozsoft.Platform.Migrations
.HasPrecision(18, 2) .HasPrecision(18, 2)
.HasColumnType("decimal(18,2)"); .HasColumnType("decimal(18,2)");
b.Property<decimal>("VatAmount")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<decimal>("VatRate")
.HasPrecision(5, 3)
.HasColumnType("decimal(5,3)");
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("OrderId"); b.HasIndex("OrderId");
@ -4375,6 +4480,12 @@ namespace Sozsoft.Platform.Migrations
b.Property<int>("Order") b.Property<int>("Order")
.HasColumnType("int"); .HasColumnType("int");
b.Property<decimal>("VatRate")
.ValueGeneratedOnAdd()
.HasPrecision(5, 3)
.HasColumnType("decimal(5,3)")
.HasDefaultValue(0.20m);
b.Property<decimal?>("YearlyPrice") b.Property<decimal?>("YearlyPrice")
.HasPrecision(18, 2) .HasPrecision(18, 2)
.HasColumnType("decimal(18,2)"); .HasColumnType("decimal(18,2)");
@ -4390,9 +4501,8 @@ namespace Sozsoft.Platform.Migrations
modelBuilder.Entity("Sozsoft.Platform.Entities.ReportCategory", b => modelBuilder.Entity("Sozsoft.Platform.Entities.ReportCategory", b =>
{ {
b.Property<string>("Id") b.Property<Guid>("Id")
.HasMaxLength(256) .HasColumnType("uniqueidentifier");
.HasColumnType("nvarchar(256)");
b.Property<DateTime>("CreationTime") b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2") .HasColumnType("datetime2")
@ -4455,9 +4565,8 @@ namespace Sozsoft.Platform.Migrations
b.Property<Guid>("Id") b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<string>("CategoryId") b.Property<Guid>("CategoryId")
.HasMaxLength(256) .HasColumnType("uniqueidentifier");
.HasColumnType("nvarchar(256)");
b.Property<DateTime>("CreationTime") b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2") .HasColumnType("datetime2")
@ -6211,6 +6320,14 @@ namespace Sozsoft.Platform.Migrations
b.Property<Guid>("Id") b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<string>("AuthorDepartment")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<string>("AuthorEmail")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<Guid>("AuthorId") b.Property<Guid>("AuthorId")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
@ -6218,6 +6335,14 @@ namespace Sozsoft.Platform.Migrations
.HasMaxLength(128) .HasMaxLength(128)
.HasColumnType("nvarchar(128)"); .HasColumnType("nvarchar(128)");
b.Property<string>("AuthorPhoneNumber")
.HasMaxLength(32)
.HasColumnType("nvarchar(32)");
b.Property<string>("AuthorTitle")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<string>("Content") b.Property<string>("Content")
.IsRequired() .IsRequired()
.HasColumnType("nvarchar(max)"); .HasColumnType("nvarchar(max)");
@ -6281,6 +6406,14 @@ namespace Sozsoft.Platform.Migrations
b.Property<Guid>("Id") b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<string>("AuthorDepartment")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<string>("AuthorEmail")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<Guid>("AuthorId") b.Property<Guid>("AuthorId")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
@ -6288,6 +6421,14 @@ namespace Sozsoft.Platform.Migrations
.HasMaxLength(128) .HasMaxLength(128)
.HasColumnType("nvarchar(128)"); .HasColumnType("nvarchar(128)");
b.Property<string>("AuthorPhoneNumber")
.HasMaxLength(32)
.HasColumnType("nvarchar(32)");
b.Property<string>("AuthorTitle")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<Guid>("CategoryId") b.Property<Guid>("CategoryId")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
@ -8368,11 +8509,6 @@ namespace Sozsoft.Platform.Migrations
.HasColumnType("uniqueidentifier") .HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId"); .HasColumnName("LastModifierId");
b.Property<int?>("MaxConcurrentUsers")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasDefaultValue(0);
b.Property<string>("MenuGroup") b.Property<string>("MenuGroup")
.HasMaxLength(64) .HasMaxLength(64)
.HasColumnType("nvarchar(64)"); .HasColumnType("nvarchar(64)");
@ -8664,6 +8800,16 @@ namespace Sozsoft.Platform.Migrations
.IsRequired(); .IsRequired();
}); });
modelBuilder.Entity("Sozsoft.Platform.Entities.ListFormWorkflow", b =>
{
b.HasOne("Sozsoft.Platform.Entities.ListForm", null)
.WithMany()
.HasForeignKey("ListFormCode")
.HasPrincipalKey("ListFormCode")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Sozsoft.Platform.Entities.MessengerConversationMessage", b => modelBuilder.Entity("Sozsoft.Platform.Entities.MessengerConversationMessage", b =>
{ {
b.HasOne("Sozsoft.Platform.Entities.MessengerConversation", "Conversation") b.HasOne("Sozsoft.Platform.Entities.MessengerConversation", "Conversation")
@ -8691,7 +8837,8 @@ namespace Sozsoft.Platform.Migrations
b.HasOne("Sozsoft.Platform.Entities.ReportCategory", "ReportCategory") b.HasOne("Sozsoft.Platform.Entities.ReportCategory", "ReportCategory")
.WithMany("ReportTemplates") .WithMany("ReportTemplates")
.HasForeignKey("CategoryId") .HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Restrict); .OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("ReportCategory"); b.Navigation("ReportCategory");
}); });

View file

@ -368,7 +368,6 @@ namespace Sozsoft.Platform.Migrations
FaxNumber = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true), FaxNumber = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true),
Founder = table.Column<string>(type: "nvarchar(max)", nullable: true), Founder = table.Column<string>(type: "nvarchar(max)", nullable: true),
IsActive = table.Column<bool>(type: "bit", nullable: false, defaultValue: true), IsActive = table.Column<bool>(type: "bit", nullable: false, defaultValue: true),
MaxConcurrentUsers = table.Column<int>(type: "int", nullable: true, defaultValue: 0),
MenuGroup = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true), MenuGroup = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true),
MobileNumber = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true), MobileNumber = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true),
OrganizationName = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true), OrganizationName = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true),
@ -651,7 +650,7 @@ namespace Sozsoft.Platform.Migrations
name: "Adm_T_ReportCategory", name: "Adm_T_ReportCategory",
columns: table => new columns: table => new
{ {
Id = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false), Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
Name = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false), Name = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
Description = table.Column<string>(type: "nvarchar(max)", maxLength: 4096, nullable: true), Description = table.Column<string>(type: "nvarchar(max)", maxLength: 4096, nullable: true),
@ -1129,6 +1128,7 @@ namespace Sozsoft.Platform.Migrations
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false), Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false), Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
RoutePath = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: false),
Code = table.Column<string>(type: "nvarchar(max)", nullable: false), Code = table.Column<string>(type: "nvarchar(max)", nullable: false),
Props = table.Column<string>(type: "nvarchar(1024)", maxLength: 1024, nullable: true), Props = table.Column<string>(type: "nvarchar(1024)", maxLength: 1024, nullable: true),
Description = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: true), Description = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: true),
@ -1392,6 +1392,7 @@ namespace Sozsoft.Platform.Migrations
TreeOptionJson = table.Column<string>(type: "nvarchar(max)", nullable: true), TreeOptionJson = table.Column<string>(type: "nvarchar(max)", nullable: true),
GanttOptionJson = table.Column<string>(type: "nvarchar(max)", nullable: true), GanttOptionJson = table.Column<string>(type: "nvarchar(max)", nullable: true),
SchedulerOptionJson = table.Column<string>(type: "nvarchar(max)", nullable: true), SchedulerOptionJson = table.Column<string>(type: "nvarchar(max)", nullable: true),
TodoOptionJson = table.Column<string>(type: "text", nullable: true),
FilterRowJson = table.Column<string>(type: "text", nullable: true), FilterRowJson = table.Column<string>(type: "text", nullable: true),
RowJson = table.Column<string>(type: "nvarchar(max)", nullable: true), RowJson = table.Column<string>(type: "nvarchar(max)", nullable: true),
HeaderFilterJson = table.Column<string>(type: "text", nullable: true), HeaderFilterJson = table.Column<string>(type: "text", nullable: true),
@ -1466,32 +1467,6 @@ namespace Sozsoft.Platform.Migrations
table.UniqueConstraint("AK_Sas_H_ListForm_ListFormCode", x => x.ListFormCode); table.UniqueConstraint("AK_Sas_H_ListForm_ListFormCode", x => x.ListFormCode);
}); });
migrationBuilder.CreateTable(
name: "Sas_H_ListFormWorkflow",
columns: table => new
{
Id = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
ListFormCode = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
Kind = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
Title = table.Column<string>(type: "nvarchar(250)", maxLength: 250, nullable: false),
CompareColumn = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
CompareOperator = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: false),
CompareValue = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
Approver = table.Column<string>(type: "nvarchar(250)", maxLength: 250, nullable: false),
NextOnStart = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
NextOnTrue = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
NextOnFalse = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
NextOnApprove = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
NextOnReject = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
PositionX = table.Column<int>(type: "int", nullable: false),
PositionY = table.Column<int>(type: "int", nullable: false),
CompareOutcomesJson = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Sas_H_ListFormWorkflow", x => x.Id);
});
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "Sas_H_LogEntry", name: "Sas_H_LogEntry",
columns: table => new columns: table => new
@ -1571,30 +1546,41 @@ namespace Sozsoft.Platform.Migrations
columns: table => new columns: table => new
{ {
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false), Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true), TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsActive = table.Column<bool>(type: "bit", nullable: false),
OrganizationName = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true), OrganizationName = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
Founder = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true), Founder = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
VknTckn = table.Column<long>(type: "bigint", nullable: true), VknTckn = table.Column<long>(type: "bigint", nullable: true),
TaxOffice = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true), TaxOffice = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
Address1 = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: true),
Address2 = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: true),
District = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
Country = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true), Country = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
City = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true), City = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
District = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
Township = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
PostalCode = table.Column<string>(type: "nvarchar(16)", maxLength: 16, nullable: true), PostalCode = table.Column<string>(type: "nvarchar(16)", maxLength: 16, nullable: true),
Address1 = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: true),
Address2 = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: true),
MobileNumber = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true), MobileNumber = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true),
PhoneNumber = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true), PhoneNumber = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true),
FaxNumber = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true), FaxNumber = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true),
Email = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true), Email = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
Website = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true), Website = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
MenuGroup = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true), MenuGroup = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true),
IsExisting = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
IsActive = table.Column<bool>(type: "bit", nullable: false, computedColumnSql: "CONVERT(bit, CASE WHEN [LicenseEndTime] IS NOT NULL AND CONVERT(date, GETDATE()) > CONVERT(date, [LicenseEndTime]) THEN 0 ELSE 1 END)", stored: false),
BillingCycle = table.Column<string>(type: "nvarchar(32)", maxLength: 32, nullable: true),
Period = table.Column<int>(type: "int", nullable: false, defaultValue: 1),
LicenseStartTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LicenseEndTime = table.Column<DateTime>(type: "datetime2", nullable: true),
Subtotal = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), Subtotal = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
VatTotal = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
Commission = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), Commission = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
Total = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), Total = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
PaymentMethodId = table.Column<Guid>(type: "uniqueidentifier", nullable: false), PaymentMethodId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Installment = table.Column<int>(type: "int", nullable: true), Installment = table.Column<int>(type: "int", nullable: true),
PaymentDataJson = table.Column<string>(type: "nvarchar(max)", maxLength: 4096, nullable: true), PaymentDataJson = table.Column<string>(type: "nvarchar(max)", maxLength: 4096, nullable: true),
ApprovalUserName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
ApprovalStatus = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true),
ApprovalDate = table.Column<DateTime>(type: "datetime2", nullable: true),
ApprovalDescription = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false), CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true), LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
@ -1640,6 +1626,7 @@ namespace Sozsoft.Platform.Migrations
Order = table.Column<int>(type: "int", nullable: false), Order = table.Column<int>(type: "int", nullable: false),
MonthlyPrice = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: true), MonthlyPrice = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: true),
YearlyPrice = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: true), YearlyPrice = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: true),
VatRate = table.Column<decimal>(type: "decimal(5,3)", precision: 5, scale: 3, nullable: false, defaultValue: 0.20m),
IsQuantityBased = table.Column<bool>(type: "bit", nullable: false), IsQuantityBased = table.Column<bool>(type: "bit", nullable: false),
ImageUrl = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: true), ImageUrl = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false), CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
@ -2273,7 +2260,7 @@ namespace Sozsoft.Platform.Migrations
Name = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false), Name = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
Description = table.Column<string>(type: "nvarchar(1024)", maxLength: 1024, nullable: true), Description = table.Column<string>(type: "nvarchar(1024)", maxLength: 1024, nullable: true),
HtmlContent = table.Column<string>(type: "nvarchar(max)", nullable: false), HtmlContent = table.Column<string>(type: "nvarchar(max)", nullable: false),
CategoryId = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true), CategoryId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Status = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true), Status = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false), CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
@ -2683,6 +2670,9 @@ namespace Sozsoft.Platform.Migrations
GroupName = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true), GroupName = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
Currency = table.Column<string>(type: "nvarchar(8)", maxLength: 8, nullable: false), Currency = table.Column<string>(type: "nvarchar(8)", maxLength: 8, nullable: false),
PhoneCode = table.Column<int>(type: "int", nullable: false), PhoneCode = table.Column<int>(type: "int", nullable: false),
PhoneNumberMinLength = table.Column<int>(type: "int", nullable: true, defaultValue: 0),
PhoneNumberMaxLength = table.Column<int>(type: "int", nullable: true, defaultValue: 0),
PhoneNumberFormat = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true),
TaxLabel = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true), TaxLabel = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true),
ZipRequired = table.Column<bool>(type: "bit", nullable: false), ZipRequired = table.Column<bool>(type: "bit", nullable: false),
StateRequired = table.Column<bool>(type: "bit", nullable: false), StateRequired = table.Column<bool>(type: "bit", nullable: false),
@ -2801,6 +2791,11 @@ namespace Sozsoft.Platform.Migrations
PivotSettingsJson = table.Column<string>(type: "text", nullable: true), PivotSettingsJson = table.Column<string>(type: "text", nullable: true),
Alignment = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true, defaultValue: "left"), Alignment = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true, defaultValue: "left"),
Format = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true), Format = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
EditOrderNo = table.Column<int>(type: "int", nullable: true),
EditGroupOrderNo = table.Column<int>(type: "int", nullable: true),
EditorType2 = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true),
ColSpan = table.Column<int>(type: "int", nullable: true),
EditorScript = table.Column<string>(type: "text", nullable: true),
EditorOptions = table.Column<string>(type: "text", nullable: true) EditorOptions = table.Column<string>(type: "text", nullable: true)
}, },
constraints: table => constraints: table =>
@ -2842,6 +2837,38 @@ namespace Sozsoft.Platform.Migrations
onDelete: ReferentialAction.Cascade); onDelete: ReferentialAction.Cascade);
}); });
migrationBuilder.CreateTable(
name: "Sas_H_ListFormWorkflow",
columns: table => new
{
Id = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
ListFormCode = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
Kind = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
Title = table.Column<string>(type: "nvarchar(250)", maxLength: 250, nullable: false),
CompareColumn = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
CompareOperator = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: false),
CompareValue = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
Approver = table.Column<string>(type: "nvarchar(250)", maxLength: 250, nullable: false),
NextOnStart = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
NextOnTrue = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
NextOnFalse = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
NextOnApprove = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
NextOnReject = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
PositionX = table.Column<int>(type: "int", nullable: false),
PositionY = table.Column<int>(type: "int", nullable: false),
CompareOutcomesJson = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Sas_H_ListFormWorkflow", x => x.Id);
table.ForeignKey(
name: "FK_Sas_H_ListFormWorkflow_Sas_H_ListForm_ListFormCode",
column: x => x.ListFormCode,
principalTable: "Sas_H_ListForm",
principalColumn: "ListFormCode",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "Sas_H_NotificationRule", name: "Sas_H_NotificationRule",
columns: table => new columns: table => new
@ -2882,7 +2909,11 @@ namespace Sozsoft.Platform.Migrations
ProductId = table.Column<Guid>(type: "uniqueidentifier", nullable: false), ProductId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
ProductName = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false), ProductName = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
BillingCycle = table.Column<string>(type: "nvarchar(32)", maxLength: 32, nullable: false), BillingCycle = table.Column<string>(type: "nvarchar(32)", maxLength: 32, nullable: false),
Period = table.Column<int>(type: "int", nullable: false, defaultValue: 1),
Quantity = table.Column<int>(type: "int", nullable: false), Quantity = table.Column<int>(type: "int", nullable: false),
Price = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
VatRate = table.Column<decimal>(type: "decimal(5,3)", precision: 5, scale: 3, nullable: false),
VatAmount = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
TotalPrice = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), TotalPrice = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false), CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
@ -2997,6 +3028,10 @@ namespace Sozsoft.Platform.Migrations
CategoryId = table.Column<Guid>(type: "uniqueidentifier", nullable: false), CategoryId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
AuthorId = table.Column<Guid>(type: "uniqueidentifier", nullable: false), AuthorId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
AuthorName = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true), AuthorName = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
AuthorTitle = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
AuthorEmail = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
AuthorPhoneNumber = table.Column<string>(type: "nvarchar(32)", maxLength: 32, nullable: true),
AuthorDepartment = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
ViewCount = table.Column<int>(type: "int", nullable: false), ViewCount = table.Column<int>(type: "int", nullable: false),
ReplyCount = table.Column<int>(type: "int", nullable: false), ReplyCount = table.Column<int>(type: "int", nullable: false),
LikeCount = table.Column<int>(type: "int", nullable: false), LikeCount = table.Column<int>(type: "int", nullable: false),
@ -3367,6 +3402,10 @@ namespace Sozsoft.Platform.Migrations
Content = table.Column<string>(type: "nvarchar(max)", nullable: false), Content = table.Column<string>(type: "nvarchar(max)", nullable: false),
AuthorId = table.Column<Guid>(type: "uniqueidentifier", nullable: false), AuthorId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
AuthorName = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true), AuthorName = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
AuthorTitle = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
AuthorEmail = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
AuthorPhoneNumber = table.Column<string>(type: "nvarchar(32)", maxLength: 32, nullable: true),
AuthorDepartment = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
LikeCount = table.Column<int>(type: "int", nullable: true), LikeCount = table.Column<int>(type: "int", nullable: true),
IsAcceptedAnswer = table.Column<bool>(type: "bit", nullable: true), IsAcceptedAnswer = table.Column<bool>(type: "bit", nullable: true),
ParentPostId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), ParentPostId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
@ -3405,6 +3444,7 @@ namespace Sozsoft.Platform.Migrations
City = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false), City = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false), Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
Township = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true), Township = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
PostalCode = table.Column<string>(type: "nvarchar(max)", nullable: true),
CityId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), CityId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false), CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
@ -3995,6 +4035,13 @@ namespace Sozsoft.Platform.Migrations
unique: true, unique: true,
filter: "[IsDeleted] = 0"); filter: "[IsDeleted] = 0");
migrationBuilder.CreateIndex(
name: "IX_Sas_H_CustomComponent_TenantId_RoutePath",
table: "Sas_H_CustomComponent",
columns: new[] { "TenantId", "RoutePath" },
unique: true,
filter: "[IsDeleted] = 0");
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_Sas_H_CustomEndpoint_TenantId_Name", name: "IX_Sas_H_CustomEndpoint_TenantId_Name",
table: "Sas_H_CustomEndpoint", table: "Sas_H_CustomEndpoint",
@ -4079,10 +4126,9 @@ namespace Sozsoft.Platform.Migrations
column: "ImportId"); column: "ImportId");
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_Sas_H_ListFormWorkflow_ListFormCode_Title", name: "IX_Sas_H_ListFormWorkflow_ListFormCode",
table: "Sas_H_ListFormWorkflow", table: "Sas_H_ListFormWorkflow",
columns: new[] { "ListFormCode", "Title" }, column: "ListFormCode");
unique: true);
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_Sas_H_Menu_Code", name: "IX_Sas_H_Menu_Code",

View file

@ -1539,6 +1539,20 @@ namespace Sozsoft.Platform.Migrations
b.Property<int>("PhoneCode") b.Property<int>("PhoneCode")
.HasColumnType("int"); .HasColumnType("int");
b.Property<string>("PhoneNumberFormat")
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<int?>("PhoneNumberMaxLength")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasDefaultValue(0);
b.Property<int?>("PhoneNumberMinLength")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasDefaultValue(0);
b.Property<bool>("StateRequired") b.Property<bool>("StateRequired")
.HasColumnType("bit"); .HasColumnType("bit");
@ -1809,6 +1823,11 @@ namespace Sozsoft.Platform.Migrations
.HasMaxLength(1024) .HasMaxLength(1024)
.HasColumnType("nvarchar(1024)"); .HasColumnType("nvarchar(1024)");
b.Property<string>("RoutePath")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("nvarchar(512)");
b.Property<Guid?>("TenantId") b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier") .HasColumnType("uniqueidentifier")
.HasColumnName("TenantId"); .HasColumnName("TenantId");
@ -1819,6 +1838,10 @@ namespace Sozsoft.Platform.Migrations
.IsUnique() .IsUnique()
.HasFilter("[IsDeleted] = 0"); .HasFilter("[IsDeleted] = 0");
b.HasIndex("TenantId", "RoutePath")
.IsUnique()
.HasFilter("[IsDeleted] = 0");
b.ToTable("Sas_H_CustomComponent", (string)null); b.ToTable("Sas_H_CustomComponent", (string)null);
}); });
@ -2243,6 +2266,9 @@ namespace Sozsoft.Platform.Migrations
.HasMaxLength(128) .HasMaxLength(128)
.HasColumnType("nvarchar(128)"); .HasColumnType("nvarchar(128)");
b.Property<string>("PostalCode")
.HasColumnType("nvarchar(max)");
b.Property<string>("Township") b.Property<string>("Township")
.HasMaxLength(128) .HasMaxLength(128)
.HasColumnType("nvarchar(128)"); .HasColumnType("nvarchar(128)");
@ -3235,6 +3261,9 @@ namespace Sozsoft.Platform.Migrations
b.Property<string>("TitleJson") b.Property<string>("TitleJson")
.HasColumnType("text"); .HasColumnType("text");
b.Property<string>("TodoOptionJson")
.HasColumnType("text");
b.Property<string>("TooltipJson") b.Property<string>("TooltipJson")
.HasColumnType("text"); .HasColumnType("text");
@ -3383,6 +3412,9 @@ namespace Sozsoft.Platform.Migrations
.HasMaxLength(256) .HasMaxLength(256)
.HasColumnType("nvarchar(256)"); .HasColumnType("nvarchar(256)");
b.Property<int?>("ColSpan")
.HasColumnType("int");
b.Property<string>("ColumnCssClass") b.Property<string>("ColumnCssClass")
.HasMaxLength(128) .HasMaxLength(128)
.HasColumnType("nvarchar(128)"); .HasColumnType("nvarchar(128)");
@ -3408,9 +3440,22 @@ namespace Sozsoft.Platform.Migrations
.HasMaxLength(10) .HasMaxLength(10)
.HasColumnType("nvarchar(10)"); .HasColumnType("nvarchar(10)");
b.Property<int?>("EditGroupOrderNo")
.HasColumnType("int");
b.Property<int?>("EditOrderNo")
.HasColumnType("int");
b.Property<string>("EditorOptions") b.Property<string>("EditorOptions")
.HasColumnType("text"); .HasColumnType("text");
b.Property<string>("EditorScript")
.HasColumnType("text");
b.Property<string>("EditorType2")
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<string>("FieldName") b.Property<string>("FieldName")
.IsRequired() .IsRequired()
.HasMaxLength(128) .HasMaxLength(128)
@ -3632,8 +3677,8 @@ namespace Sozsoft.Platform.Migrations
modelBuilder.Entity("Sozsoft.Platform.Entities.ListFormWorkflow", b => modelBuilder.Entity("Sozsoft.Platform.Entities.ListFormWorkflow", b =>
{ {
b.Property<string>("Id") b.Property<string>("Id")
.HasMaxLength(50) .HasMaxLength(128)
.HasColumnType("nvarchar(50)"); .HasColumnType("nvarchar(128)");
b.Property<string>("Approver") b.Property<string>("Approver")
.IsRequired() .IsRequired()
@ -3669,28 +3714,28 @@ namespace Sozsoft.Platform.Migrations
b.Property<string>("NextOnApprove") b.Property<string>("NextOnApprove")
.IsRequired() .IsRequired()
.HasMaxLength(50) .HasMaxLength(128)
.HasColumnType("nvarchar(50)"); .HasColumnType("nvarchar(128)");
b.Property<string>("NextOnFalse") b.Property<string>("NextOnFalse")
.IsRequired() .IsRequired()
.HasMaxLength(50) .HasMaxLength(128)
.HasColumnType("nvarchar(50)"); .HasColumnType("nvarchar(128)");
b.Property<string>("NextOnReject") b.Property<string>("NextOnReject")
.IsRequired() .IsRequired()
.HasMaxLength(50) .HasMaxLength(128)
.HasColumnType("nvarchar(50)"); .HasColumnType("nvarchar(128)");
b.Property<string>("NextOnStart") b.Property<string>("NextOnStart")
.IsRequired() .IsRequired()
.HasMaxLength(50) .HasMaxLength(128)
.HasColumnType("nvarchar(50)"); .HasColumnType("nvarchar(128)");
b.Property<string>("NextOnTrue") b.Property<string>("NextOnTrue")
.IsRequired() .IsRequired()
.HasMaxLength(50) .HasMaxLength(128)
.HasColumnType("nvarchar(50)"); .HasColumnType("nvarchar(128)");
b.Property<int>("PositionX") b.Property<int>("PositionX")
.HasColumnType("int"); .HasColumnType("int");
@ -3705,8 +3750,7 @@ namespace Sozsoft.Platform.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("ListFormCode", "Title") b.HasIndex("ListFormCode");
.IsUnique();
b.ToTable("Sas_H_ListFormWorkflow", (string)null); b.ToTable("Sas_H_ListFormWorkflow", (string)null);
}); });
@ -4068,6 +4112,25 @@ namespace Sozsoft.Platform.Migrations
.HasMaxLength(512) .HasMaxLength(512)
.HasColumnType("nvarchar(512)"); .HasColumnType("nvarchar(512)");
b.Property<DateTime?>("ApprovalDate")
.HasColumnType("datetime2");
b.Property<string>("ApprovalDescription")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("ApprovalStatus")
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<string>("ApprovalUserName")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("BillingCycle")
.HasMaxLength(32)
.HasColumnType("nvarchar(32)");
b.Property<string>("City") b.Property<string>("City")
.HasMaxLength(128) .HasMaxLength(128)
.HasColumnType("nvarchar(128)"); .HasColumnType("nvarchar(128)");
@ -4116,7 +4179,9 @@ namespace Sozsoft.Platform.Migrations
.HasColumnType("int"); .HasColumnType("int");
b.Property<bool>("IsActive") b.Property<bool>("IsActive")
.HasColumnType("bit"); .ValueGeneratedOnAddOrUpdate()
.HasColumnType("bit")
.HasComputedColumnSql("CONVERT(bit, CASE WHEN [LicenseEndTime] IS NOT NULL AND CONVERT(date, GETDATE()) > CONVERT(date, [LicenseEndTime]) THEN 0 ELSE 1 END)", false);
b.Property<bool>("IsDeleted") b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
@ -4124,6 +4189,11 @@ namespace Sozsoft.Platform.Migrations
.HasDefaultValue(false) .HasDefaultValue(false)
.HasColumnName("IsDeleted"); .HasColumnName("IsDeleted");
b.Property<bool>("IsExisting")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false);
b.Property<DateTime?>("LastModificationTime") b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2") .HasColumnType("datetime2")
.HasColumnName("LastModificationTime"); .HasColumnName("LastModificationTime");
@ -4132,6 +4202,12 @@ namespace Sozsoft.Platform.Migrations
.HasColumnType("uniqueidentifier") .HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId"); .HasColumnName("LastModifierId");
b.Property<DateTime?>("LicenseEndTime")
.HasColumnType("datetime2");
b.Property<DateTime?>("LicenseStartTime")
.HasColumnType("datetime2");
b.Property<string>("MenuGroup") b.Property<string>("MenuGroup")
.HasMaxLength(64) .HasMaxLength(64)
.HasColumnType("nvarchar(64)"); .HasColumnType("nvarchar(64)");
@ -4140,10 +4216,6 @@ namespace Sozsoft.Platform.Migrations
.HasMaxLength(20) .HasMaxLength(20)
.HasColumnType("nvarchar(20)"); .HasColumnType("nvarchar(20)");
b.Property<string>("Name")
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<string>("OrganizationName") b.Property<string>("OrganizationName")
.HasMaxLength(128) .HasMaxLength(128)
.HasColumnType("nvarchar(128)"); .HasColumnType("nvarchar(128)");
@ -4155,6 +4227,11 @@ namespace Sozsoft.Platform.Migrations
b.Property<Guid>("PaymentMethodId") b.Property<Guid>("PaymentMethodId")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<int>("Period")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasDefaultValue(1);
b.Property<string>("PhoneNumber") b.Property<string>("PhoneNumber")
.HasMaxLength(20) .HasMaxLength(20)
.HasColumnType("nvarchar(20)"); .HasColumnType("nvarchar(20)");
@ -4171,10 +4248,21 @@ namespace Sozsoft.Platform.Migrations
.HasMaxLength(128) .HasMaxLength(128)
.HasColumnType("nvarchar(128)"); .HasColumnType("nvarchar(128)");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier");
b.Property<decimal>("Total") b.Property<decimal>("Total")
.HasPrecision(18, 2) .HasPrecision(18, 2)
.HasColumnType("decimal(18,2)"); .HasColumnType("decimal(18,2)");
b.Property<string>("Township")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<decimal>("VatTotal")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<long?>("VknTckn") b.Property<long?>("VknTckn")
.HasColumnType("bigint"); .HasColumnType("bigint");
@ -4230,6 +4318,15 @@ namespace Sozsoft.Platform.Migrations
b.Property<Guid>("OrderId") b.Property<Guid>("OrderId")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<int>("Period")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasDefaultValue(1);
b.Property<decimal>("Price")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<Guid>("ProductId") b.Property<Guid>("ProductId")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
@ -4245,6 +4342,14 @@ namespace Sozsoft.Platform.Migrations
.HasPrecision(18, 2) .HasPrecision(18, 2)
.HasColumnType("decimal(18,2)"); .HasColumnType("decimal(18,2)");
b.Property<decimal>("VatAmount")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<decimal>("VatRate")
.HasPrecision(5, 3)
.HasColumnType("decimal(5,3)");
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("OrderId"); b.HasIndex("OrderId");
@ -4372,6 +4477,12 @@ namespace Sozsoft.Platform.Migrations
b.Property<int>("Order") b.Property<int>("Order")
.HasColumnType("int"); .HasColumnType("int");
b.Property<decimal>("VatRate")
.ValueGeneratedOnAdd()
.HasPrecision(5, 3)
.HasColumnType("decimal(5,3)")
.HasDefaultValue(0.20m);
b.Property<decimal?>("YearlyPrice") b.Property<decimal?>("YearlyPrice")
.HasPrecision(18, 2) .HasPrecision(18, 2)
.HasColumnType("decimal(18,2)"); .HasColumnType("decimal(18,2)");
@ -4387,9 +4498,8 @@ namespace Sozsoft.Platform.Migrations
modelBuilder.Entity("Sozsoft.Platform.Entities.ReportCategory", b => modelBuilder.Entity("Sozsoft.Platform.Entities.ReportCategory", b =>
{ {
b.Property<string>("Id") b.Property<Guid>("Id")
.HasMaxLength(256) .HasColumnType("uniqueidentifier");
.HasColumnType("nvarchar(256)");
b.Property<DateTime>("CreationTime") b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2") .HasColumnType("datetime2")
@ -4452,9 +4562,8 @@ namespace Sozsoft.Platform.Migrations
b.Property<Guid>("Id") b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<string>("CategoryId") b.Property<Guid>("CategoryId")
.HasMaxLength(256) .HasColumnType("uniqueidentifier");
.HasColumnType("nvarchar(256)");
b.Property<DateTime>("CreationTime") b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2") .HasColumnType("datetime2")
@ -6208,6 +6317,14 @@ namespace Sozsoft.Platform.Migrations
b.Property<Guid>("Id") b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<string>("AuthorDepartment")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<string>("AuthorEmail")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<Guid>("AuthorId") b.Property<Guid>("AuthorId")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
@ -6215,6 +6332,14 @@ namespace Sozsoft.Platform.Migrations
.HasMaxLength(128) .HasMaxLength(128)
.HasColumnType("nvarchar(128)"); .HasColumnType("nvarchar(128)");
b.Property<string>("AuthorPhoneNumber")
.HasMaxLength(32)
.HasColumnType("nvarchar(32)");
b.Property<string>("AuthorTitle")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<string>("Content") b.Property<string>("Content")
.IsRequired() .IsRequired()
.HasColumnType("nvarchar(max)"); .HasColumnType("nvarchar(max)");
@ -6278,6 +6403,14 @@ namespace Sozsoft.Platform.Migrations
b.Property<Guid>("Id") b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<string>("AuthorDepartment")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<string>("AuthorEmail")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<Guid>("AuthorId") b.Property<Guid>("AuthorId")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
@ -6285,6 +6418,14 @@ namespace Sozsoft.Platform.Migrations
.HasMaxLength(128) .HasMaxLength(128)
.HasColumnType("nvarchar(128)"); .HasColumnType("nvarchar(128)");
b.Property<string>("AuthorPhoneNumber")
.HasMaxLength(32)
.HasColumnType("nvarchar(32)");
b.Property<string>("AuthorTitle")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<Guid>("CategoryId") b.Property<Guid>("CategoryId")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
@ -8365,11 +8506,6 @@ namespace Sozsoft.Platform.Migrations
.HasColumnType("uniqueidentifier") .HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId"); .HasColumnName("LastModifierId");
b.Property<int?>("MaxConcurrentUsers")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasDefaultValue(0);
b.Property<string>("MenuGroup") b.Property<string>("MenuGroup")
.HasMaxLength(64) .HasMaxLength(64)
.HasColumnType("nvarchar(64)"); .HasColumnType("nvarchar(64)");
@ -8661,6 +8797,16 @@ namespace Sozsoft.Platform.Migrations
.IsRequired(); .IsRequired();
}); });
modelBuilder.Entity("Sozsoft.Platform.Entities.ListFormWorkflow", b =>
{
b.HasOne("Sozsoft.Platform.Entities.ListForm", null)
.WithMany()
.HasForeignKey("ListFormCode")
.HasPrincipalKey("ListFormCode")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Sozsoft.Platform.Entities.MessengerConversationMessage", b => modelBuilder.Entity("Sozsoft.Platform.Entities.MessengerConversationMessage", b =>
{ {
b.HasOne("Sozsoft.Platform.Entities.MessengerConversation", "Conversation") b.HasOne("Sozsoft.Platform.Entities.MessengerConversation", "Conversation")
@ -8688,7 +8834,8 @@ namespace Sozsoft.Platform.Migrations
b.HasOne("Sozsoft.Platform.Entities.ReportCategory", "ReportCategory") b.HasOne("Sozsoft.Platform.Entities.ReportCategory", "ReportCategory")
.WithMany("ReportTemplates") .WithMany("ReportTemplates")
.HasForeignKey("CategoryId") .HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Restrict); .OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("ReportCategory"); b.Navigation("ReportCategory");
}); });

View file

@ -349,7 +349,8 @@
"CustomComponents": [ "CustomComponents": [
{ {
"name": "DynamicEntityComponent", "name": "DynamicEntityComponent",
"code": "import React, { useEffect, useState } from \"react\";\nimport axios from \"axios\";\n\ninterface DynamicEntityComponentProps {\n title: string;\n}\n\nconst api = axios.create({\n baseURL: \"https://localhost:44344\",\n});\n\nconst DynamicEntityComponent: React.FC<DynamicEntityComponentProps> = ({ title }) => {\n const [data, setData] = useState<Array<{ id: string; name: string }>>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const fetchData = async () => {\n setLoading(true);\n setError(null);\n\n try {\n const res = await api.get(`/api/app/crudendpoint/${title}`);\n const raw = Array.isArray(res.data) ? res.data : res.data?.items ?? [];\n\n const filtered = raw.map((item: any) => ({\n id: item.Id ?? item.id,\n name: item.Name ?? item.name,\n }));\n\n setData(filtered);\n } catch (err: any) {\n setError(err.message || \"Failed to fetch data\");\n } finally {\n setLoading(false);\n }\n };\n\n if (title) fetchData();\n }, [title]);\n\n if (loading) return <div>Loading...</div>;\n if (error) return <div className=\"text-red-600 dark:text-red-400\">Error: {error}</div>;\n if (!data.length) return <div>No records found</div>;\n\n const headers = [\"id\", \"name\", \"actions\"];\n\n return (\n <div className=\"overflow-auto\">\n <table className=\"min-w-full bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700 shadow-sm rounded-lg\">\n <thead className=\"bg-slate-100 dark:bg-slate-800\">\n <tr>\n {headers.map((key) => (\n <th\n key={key}\n className=\"text-left px-4 py-2 border-b border-slate-200 dark:border-slate-700 text-sm font-medium text-slate-700 dark:text-slate-200\"\n >\n {key === \"actions\" ? \"Actions\" : key}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.map((item, rowIndex) => (\n <tr key={rowIndex} className=\"hover:bg-slate-50 dark:hover:bg-slate-800\">\n <td className=\"px-4 py-2 border-b border-slate-100 dark:border-slate-800 text-sm text-slate-800 dark:text-slate-100\">\n {item.id}\n </td>\n <td className=\"px-4 py-2 border-b border-slate-100 dark:border-slate-800 text-sm text-slate-800 dark:text-slate-100\">\n {item.name}\n </td>\n <td className=\"px-4 py-2 border-b border-slate-100 dark:border-slate-800\">\n <button\n type=\"button\"\n onClick={() => alert(item.name)}\n className=\"bg-blue-600 hover:bg-blue-700 dark:bg-blue-800 dark:hover:bg-blue-900 text-white text-sm px-3 py-1 rounded-lg shadow-sm transition\"\n >\n Show Name\n </button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n};\n\nexport default DynamicEntityComponent;", "routePath": "/admin/dynamic-entity",
"code": "import React, { useEffect, useState } from \"react\";\nimport axios from \"axios\";\n\ninterface DynamicEntityComponentProps {\n title: string;\n}\n\nconst api = axios.create({\n baseURL: \"https://localhost:44344\",\n});\n\nconst DynamicEntityComponent: React.FC<DynamicEntityComponentProps> = ({ title }) => {\n const [data, setData] = useState<Array<{ id: string; name: string }>>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const fetchData = async () => {\n setLoading(true);\n setError(null);\n\n try {\n const res = await api.get(`/api/app/crudendpoint/${title}`);\n const raw = Array.isArray(res.data) ? res.data : res.data?.items ?? [];\n\n const filtered = raw.map((item: any) => ({\n id: item.Id ?? item.id,\n name: item.Name ?? item.name,\n }));\n\n setData(filtered);\n } catch (err: any) {\n setError(err.message || \"Failed to fetch data\");\n } finally {\n setLoading(false);\n }\n };\n\n if (title) fetchData();\n }, [title]);\n\n if (loading) return <div>Loading...</div>;\n if (error) return <div className=\"text-red-600 dark:text-red-400\">Error: {error}</div>;\n if (!data.length) return <div>No records found</div>;\n\n const headers = [\"id\", \"name\", \"actions\"];\n\n return (\n <div className=\"overflow-auto\">\n <table className=\"min-w-full bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700 shadow-sm rounded-lg\">\n <thead className=\"bg-slate-100 dark:bg-slate-800\">\n <tr>\n {headers.map((key) => (\n <th\n key={key}\n className=\"text-left px-4 py-2 border-b border-slate-200 dark:border-slate-700 text-sm font-medium text-slate-700 dark:text-slate-200\"\n >\n {key === \"actions\" ? \"Actions\" : key}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.map((item, rowIndex) => (\n <tr key={item.id ?? rowIndex} className=\"hover:bg-slate-50 dark:hover:bg-slate-800\">\n <td className=\"px-4 py-2 border-b border-slate-100 dark:border-slate-800 text-sm text-slate-800 dark:text-slate-100\">\n {item.id}\n </td>\n <td className=\"px-4 py-2 border-b border-slate-100 dark:border-slate-800 text-sm text-slate-800 dark:text-slate-100\">\n {item.name}\n </td>\n <td className=\"px-4 py-2 border-b border-slate-100 dark:border-slate-800\">\n <Button\n type=\"button\"\n color=\"blue-500\"\n onClick={() => alert(item.name)}\n shape=\"round\"\n size=\"xs\"\n variant=\"solid\"\n id=\"c_mrix4c1a_qrybhk\"\n >\n Show Name\n </Button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n};\n\nexport default DynamicEntityComponent;",
"props": null, "props": null,
"description": null, "description": null,
"isActive": true, "isActive": true,
@ -357,13 +358,12 @@
}, },
{ {
"name": "RoleListComponent", "name": "RoleListComponent",
"routePath": "/admin/roles-list",
"code": "const RoleListComponent = ({\n title = \"AbpRoles\"\n}) => {\n return (\n <DynamicEntityComponent id=\"c_mdljvvmq_fno52v\" title={title} />\n );\n};\n\nexport default RoleListComponent;", "code": "const RoleListComponent = ({\n title = \"AbpRoles\"\n}) => {\n return (\n <DynamicEntityComponent id=\"c_mdljvvmq_fno52v\" title={title} />\n );\n};\n\nexport default RoleListComponent;",
"props": null, "props": null,
"description": null, "description": null,
"isActive": true, "isActive": true,
"dependencies": [ "dependencies": ["DynamicEntityComponent"]
"DynamicEntityComponent"
]
} }
], ],
"Abouts": [ "Abouts": [
@ -1805,9 +1805,7 @@
{ {
"postContent": "CI/CD pipeline güncellememiz tamamlandı! Deployment süremiz %40 azaldı. Otomasyonun gücü 💪", "postContent": "CI/CD pipeline güncellememiz tamamlandı! Deployment süremiz %40 azaldı. Otomasyonun gücü 💪",
"type": "video", "type": "video",
"urls": [ "urls": ["https://www.w3schools.com/html/mov_bbb.mp4"]
"https://www.w3schools.com/html/mov_bbb.mp4"
]
} }
], ],
"SocialPollOptions": [ "SocialPollOptions": [

View file

@ -354,6 +354,7 @@ public class InstallmentOptionSeedDto
public class CustomComponentSeedDto public class CustomComponentSeedDto
{ {
public string Name { get; set; } public string Name { get; set; }
public string RoutePath { get; set; }
public string Code { get; set; } public string Code { get; set; }
public string Props { get; set; } public string Props { get; set; }
public string Description { get; set; } public string Description { get; set; }
@ -490,7 +491,7 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
private readonly IRepository<GlobalSearch, int> _globalSearch; private readonly IRepository<GlobalSearch, int> _globalSearch;
private readonly IRepository<CustomEndpoint, Guid> _customEndpointRepository; private readonly IRepository<CustomEndpoint, Guid> _customEndpointRepository;
private readonly IRepository<CustomComponent, Guid> _customComponentRepository; private readonly IRepository<CustomComponent, Guid> _customComponentRepository;
private readonly IRepository<ReportCategory, string> _reportCategoriesRepository; private readonly IRepository<ReportCategory, Guid> _reportCategoriesRepository;
private readonly IRepository<ReportTemplate, Guid> _reportTemplatesRepository; private readonly IRepository<ReportTemplate, Guid> _reportTemplatesRepository;
private readonly IRepository<Home, Guid> _homeRepository; private readonly IRepository<Home, Guid> _homeRepository;
private readonly IRepository<About, Guid> _aboutRepository; private readonly IRepository<About, Guid> _aboutRepository;
@ -547,7 +548,7 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
IRepository<SkillLevel, string> skillLevelRepository, IRepository<SkillLevel, string> skillLevelRepository,
IRepository<CustomEndpoint, Guid> customEndpointRepository, IRepository<CustomEndpoint, Guid> customEndpointRepository,
IRepository<CustomComponent, Guid> customComponentRepository, IRepository<CustomComponent, Guid> customComponentRepository,
IRepository<ReportCategory, string> reportCategoriesRepository, IRepository<ReportCategory, Guid> reportCategoriesRepository,
IRepository<ReportTemplate, Guid> reportTemplatesRepository, IRepository<ReportTemplate, Guid> reportTemplatesRepository,
IRepository<Home, Guid> homeRepository, IRepository<Home, Guid> homeRepository,
IRepository<About, Guid> aboutRepository, IRepository<About, Guid> aboutRepository,
@ -851,6 +852,7 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
{ {
await _customComponentRepository.InsertAsync(new CustomComponent( await _customComponentRepository.InsertAsync(new CustomComponent(
item.Name, item.Name,
item.RoutePath,
item.Code, item.Code,
item.Props, item.Props,
item.Description, item.Description,
@ -865,7 +867,7 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
if (!exists) if (!exists)
{ {
await _reportCategoriesRepository.InsertAsync(new ReportCategory(item.Name) await _reportCategoriesRepository.InsertAsync(new ReportCategory(Guid.NewGuid())
{ {
Name = item.Name, Name = item.Name,
Description = item.Description, Description = item.Description,

View file

@ -64,6 +64,11 @@ public class PlatformLoginResult : AbpLoginResult
PResult = PlatformLoginResultType.NotAllowedWorkHour; PResult = PlatformLoginResultType.NotAllowedWorkHour;
Description = L[PlatformConsts.AbpIdentity.User.LoginNotAllowed_WorkHour]; Description = L[PlatformConsts.AbpIdentity.User.LoginNotAllowed_WorkHour];
} }
else if (resultP.IsNotAllowed_BranchLimit)
{
PResult = PlatformLoginResultType.BranchLimit;
Description = L[PlatformConsts.AbpIdentity.User.BranchLimitError];
}
else if (resultP.IsNotAllowed_ConcurrentUserLimit) else if (resultP.IsNotAllowed_ConcurrentUserLimit)
{ {
PResult = PlatformLoginResultType.ConcurrentUserLimit; PResult = PlatformLoginResultType.ConcurrentUserLimit;

View file

@ -16,6 +16,7 @@ public enum PlatformLoginResultType : byte
ShowCaptcha, ShowCaptcha,
TenantIsPassive, TenantIsPassive,
NotAllowedWorkHour, NotAllowedWorkHour,
BranchLimit,
ConcurrentUserLimit ConcurrentUserLimit
} }

View file

@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data.Common;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Sozsoft.Platform.Entities; using Sozsoft.Platform.Entities;
@ -8,6 +7,7 @@ using Sozsoft.Platform.Extensions;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
@ -31,6 +31,9 @@ public interface IPlatformSignInManager
public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager
{ {
private const string UserLicenseProductName = "Public.products.userLicense";
private const string BranchLicenseProductName = "Public.products.branchHosting";
private readonly IClock clock; private readonly IClock clock;
private readonly IRepository<IpRestriction, Guid> repositoryIp; private readonly IRepository<IpRestriction, Guid> repositoryIp;
private readonly IRepository<WorkHour, Guid> repositoryWorkHour; private readonly IRepository<WorkHour, Guid> repositoryWorkHour;
@ -39,6 +42,8 @@ public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager
private readonly IIdentitySessionRepository identitySessionRepository; private readonly IIdentitySessionRepository identitySessionRepository;
private readonly ICurrentTenant currentTenant; private readonly ICurrentTenant currentTenant;
private readonly IUnitOfWorkManager unitOfWorkManager; private readonly IUnitOfWorkManager unitOfWorkManager;
private readonly IRepository<Order, Guid> orderRepository;
private readonly IRepository<Branch, Guid> branchRepository;
public PlatformSignInManager( public PlatformSignInManager(
IdentityUserManager userManager, IdentityUserManager userManager,
@ -56,7 +61,9 @@ public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager
ITenantRepository tenantRepository, ITenantRepository tenantRepository,
IIdentitySessionRepository identitySessionRepository, IIdentitySessionRepository identitySessionRepository,
ICurrentTenant currentTenant, ICurrentTenant currentTenant,
IUnitOfWorkManager unitOfWorkManager IUnitOfWorkManager unitOfWorkManager,
IRepository<Order, Guid> orderRepository,
IRepository<Branch, Guid> branchRepository
) : base( ) : base(
userManager, userManager,
contextAccessor, contextAccessor,
@ -76,6 +83,8 @@ public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager
this.identitySessionRepository = identitySessionRepository; this.identitySessionRepository = identitySessionRepository;
this.currentTenant = currentTenant; this.currentTenant = currentTenant;
this.unitOfWorkManager = unitOfWorkManager; this.unitOfWorkManager = unitOfWorkManager;
this.orderRepository = orderRepository;
this.branchRepository = branchRepository;
} }
public async Task<bool> PreSignInCheckAsync(IdentityUser user) public async Task<bool> PreSignInCheckAsync(IdentityUser user)
@ -110,6 +119,10 @@ public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager
{ {
return new PlatformSignInResult() { IsNotAllowed_WorkHour = true }; return new PlatformSignInResult() { IsNotAllowed_WorkHour = true };
} }
if (!await CheckBranchLicenseLimitAsync(user))
{
return new PlatformSignInResult() { IsNotAllowed_BranchLimit = true };
}
if (!await CheckConcurrentLimitAsync(user)) if (!await CheckConcurrentLimitAsync(user))
{ {
return new PlatformSignInResult() { IsNotAllowed_ConcurrentUserLimit = true }; return new PlatformSignInResult() { IsNotAllowed_ConcurrentUserLimit = true };
@ -273,28 +286,20 @@ public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager
} }
/// <summary> /// <summary>
/// Tenant'a tanımlı MaxConcurrentUsers limitini aşmamak için login'i engeller. /// Tenant'a ait aktif Order'lardaki kullanıcı lisansı limitini aşmamak için login'i engeller.
/// AbpSessions tablosundaki aktif oturumları sayar (farklı UserId'lere göre distinct). /// AbpSessions tablosundaki aktif oturumları sayar (farklı UserId'lere göre distinct).
/// Kullanıcının kendisinin zaten oturumu varsa (refresh senaryosu) yeni concurrent user sayılmaz. /// Kullanıcının kendisinin zaten oturumu varsa (refresh senaryosu) yeni concurrent user sayılmaz.
/// </summary> /// </summary>
public async Task<bool> CheckConcurrentLimitAsync(IdentityUser user) public async Task<bool> CheckConcurrentLimitAsync(IdentityUser user)
{ {
// Eğer tenantId yoksa, kullanıcı tenant'a bağlı değil demektir.
// Bu durumda concurrent limit kontrolü yapılmaz.
if (!user.TenantId.HasValue) if (!user.TenantId.HasValue)
{ {
return true; return true;
} }
var tenant = await tenantRepository.FindAsync(user.TenantId.Value); var maxConcurrentUsers = await GetActiveUserLicenseQuantityAsync(user.TenantId.Value);
if (tenant == null)
{
return true;
}
var maxConcurrentUsers = tenant.GetMaxConcurrentUsers();
if (!maxConcurrentUsers.HasValue || maxConcurrentUsers.Value == 0)
{
return true;
}
// Tenant bağlamını explicit olarak set et — hem password hem refresh token akışlarında // Tenant bağlamını explicit olarak set et — hem password hem refresh token akışlarında
// doğru tenant izolasyonu için güvenli bir şekilde değiştirilir. // doğru tenant izolasyonu için güvenli bir şekilde değiştirilir.
@ -311,11 +316,11 @@ public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager
.Distinct() .Distinct()
.Count(); .Count();
if (otherActiveUserCount >= maxConcurrentUsers.Value) if (otherActiveUserCount >= maxConcurrentUsers)
{ {
Logger.LogWarning(PlatformEventIds.UserCannotSignInConcurrentUserLimit, Logger.LogWarning(PlatformEventIds.UserCannotSignInConcurrentUserLimit,
"Tenant {TenantId} concurrent user limit of {Limit} reached. Active users: {ActiveCount}.", "Tenant {TenantId} concurrent user limit of {Limit} reached. Active users: {ActiveCount}.",
user.TenantId, maxConcurrentUsers.Value, otherActiveUserCount); user.TenantId, maxConcurrentUsers, otherActiveUserCount);
return false; return false;
} }
@ -325,5 +330,60 @@ public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager
return true; return true;
} }
private async Task<bool> CheckBranchLicenseLimitAsync(IdentityUser user)
{
if (!user.TenantId.HasValue)
{
return true;
}
var tenantId = user.TenantId.Value;
var activeBranchCount = await GetActiveBranchCountAsync(tenantId);
var branchLicenseQuantity = await GetActiveBranchLicenseQuantityAsync(tenantId);
if (activeBranchCount > branchLicenseQuantity)
{
Logger.LogWarning(PlatformEventIds.UserCannotSignInConcurrentUserLimit,
"Tenant {TenantId} branch license quantity of {Limit} is lower than active branch count {ActiveCount}.",
tenantId, branchLicenseQuantity, activeBranchCount);
return false;
}
return true;
}
private async Task<int> GetActiveBranchCountAsync(Guid tenantId)
{
using (currentTenant.Change(tenantId))
{
return await branchRepository.CountAsync(branch => branch.TenantId == tenantId && branch.IsActive == true);
}
}
private async Task<int> GetActiveUserLicenseQuantityAsync(Guid tenantId)
{
return await GetActiveOrderItemQuantityAsync(tenantId, UserLicenseProductName);
}
private async Task<int> GetActiveBranchLicenseQuantityAsync(Guid tenantId)
{
return await GetActiveOrderItemQuantityAsync(tenantId, BranchLicenseProductName);
}
private async Task<int> GetActiveOrderItemQuantityAsync(Guid tenantId, string productName)
{
using (currentTenant.Change(null))
{
var orderQuery = await orderRepository.WithDetailsAsync(order => order.Items);
var activeOrders = await orderQuery
.Where(order => order.TenantId == tenantId && order.ApprovalStatus == "Approved" && order.IsActive)
.ToListAsync();
return activeOrders
.SelectMany(order => order.Items)
.Where(item => item.ProductName == productName)
.Sum(item => item.Quantity);
}
}
} }

Some files were not shown because too many files have changed in this diff Show more