From c42a8d2bd163b39c0fc01fa6a7cbf3d4e77b1108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96zt=C3=BCrk?= Date: Tue, 7 Jul 2026 22:14:26 +0300 Subject: [PATCH] =?UTF-8?q?Sales=20Order=20=C3=BCzerinden=20Otomatik=20Ten?= =?UTF-8?q?ant=20tan=C4=B1mlama?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DynamicApi/CreateTenantFromOrderInput.cs | 10 + .../IListFormDynamicApiAppService.cs | 4 +- .../ListForms/ListFormDynamicApiAppService.cs | 107 ++++++-- .../Menu/MenuAppService.cs | 20 +- .../Seeds/LanguagesData.json | 12 + .../Seeds/ListFormSeeder_Saas.cs | 27 +- .../Seeds/MenusData.json | 244 +++++++++--------- ui/src/services/menu.service.ts | 23 +- ui/src/services/tenant.service.ts | 17 +- .../CreateTenantFromOrderDialog.tsx | 170 ++++++++++++ .../DialogContext/DialogShowComponent.tsx | 9 + 11 files changed, 489 insertions(+), 154 deletions(-) create mode 100644 api/src/Sozsoft.Platform.Application.Contracts/ListForms/DynamicApi/CreateTenantFromOrderInput.cs create mode 100644 ui/src/views/admin/tenant-management/CreateTenantFromOrderDialog.tsx diff --git a/api/src/Sozsoft.Platform.Application.Contracts/ListForms/DynamicApi/CreateTenantFromOrderInput.cs b/api/src/Sozsoft.Platform.Application.Contracts/ListForms/DynamicApi/CreateTenantFromOrderInput.cs new file mode 100644 index 0000000..ff05b79 --- /dev/null +++ b/api/src/Sozsoft.Platform.Application.Contracts/ListForms/DynamicApi/CreateTenantFromOrderInput.cs @@ -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; } +} diff --git a/api/src/Sozsoft.Platform.Application.Contracts/ListForms/DynamicApi/IListFormDynamicApiAppService.cs b/api/src/Sozsoft.Platform.Application.Contracts/ListForms/DynamicApi/IListFormDynamicApiAppService.cs index 6849438..8c4860a 100644 --- a/api/src/Sozsoft.Platform.Application.Contracts/ListForms/DynamicApi/IListFormDynamicApiAppService.cs +++ b/api/src/Sozsoft.Platform.Application.Contracts/ListForms/DynamicApi/IListFormDynamicApiAppService.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading.Tasks; namespace Sozsoft.Platform.ListForms.DynamicApi; @@ -12,5 +12,5 @@ public interface IListFormDynamicApiAppService Task PostTenantInsertAsync(DynamicApiBaseInput input); Task PostTenantUpdateAsync(DynamicApiBaseInput input); Task PostTenantDeleteAsync(DynamicApiBaseInput input); + Task PostCreateTenantFromOrderAsync(DynamicApiBaseInput input); } - diff --git a/api/src/Sozsoft.Platform.Application/ListForms/ListFormDynamicApiAppService.cs b/api/src/Sozsoft.Platform.Application/ListForms/ListFormDynamicApiAppService.cs index 4428079..b92eb25 100644 --- a/api/src/Sozsoft.Platform.Application/ListForms/ListFormDynamicApiAppService.cs +++ b/api/src/Sozsoft.Platform.Application/ListForms/ListFormDynamicApiAppService.cs @@ -16,6 +16,8 @@ using Sozsoft.Platform.BlobStoring; using Sozsoft.Platform.Identity; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; +using Sozsoft.Platform.Entities; +using Volo.Abp.Domain.Repositories; namespace Sozsoft.Platform.ListForms.DynamicApi; @@ -35,6 +37,7 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic private readonly IConfiguration configuration; private readonly IHostEnvironment hostEnvironment; private readonly IOptions identityOptions; + private readonly IRepository orderRepository; public ListFormDynamicApiAppService( ITenantRepository tenantRepository, @@ -45,7 +48,8 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic BlobManager blobCdnManager, IConfiguration configuration, IHostEnvironment hostEnvironment, - IOptions identityOptions) + IOptions identityOptions, + IRepository orderRepository) { this.tenantRepository = tenantRepository; this.tenantManager = tenantManager; @@ -56,6 +60,7 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic this.configuration = configuration; this.hostEnvironment = hostEnvironment; this.identityOptions = identityOptions; + this.orderRepository = orderRepository; } private static Guid ParseGuid(string value) @@ -233,29 +238,89 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic [Authorize(TenantManagementPermissions.Tenants.Create)] public async Task PostTenantInsertAsync(DynamicApiBaseInput input) { - var tenant = await tenantManager.CreateAsync(input.Data.Name); + await CreateTenantAsync(input.Data); + } + + [Authorize(TenantManagementPermissions.Tenants.Create)] + public async Task PostCreateTenantFromOrderAsync(DynamicApiBaseInput 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, + 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 CreateTenantAsync(CreateUpdateTenantInput input) + { + var tenant = await tenantManager.CreateAsync(input.Name); var entity = await tenantRepository.InsertAsync(tenant, autoSave: true); - entity.SetIsActive(input.Data.IsActive); - entity.SetOrganizationName(input.Data.OrganizationName); - entity.SetFounder(input.Data.Founder); - entity.SetVknTckn(input.Data.VknTckn); - entity.SetTaxOffice(input.Data.TaxOffice); - entity.SetCountry(input.Data.Country); - entity.SetCity(input.Data.City); - entity.SetDistrict(input.Data.District); - entity.SetTownship(input.Data.Township); - entity.SetAddress1(input.Data.Address1); - entity.SetAddress2(input.Data.Address2); - entity.SetPostalCode(input.Data.PostalCode); - entity.SetPhoneNumber(input.Data.PhoneNumber); - entity.SetMobileNumber(input.Data.MobileNumber); - entity.SetFaxNumber(input.Data.FaxNumber); - entity.SetEmail(input.Data.Email); - entity.SetWebsite(input.Data.Website); - entity.SetMenuGroup(input.Data.MenuGroup); + entity.SetIsActive(input.IsActive); + entity.SetOrganizationName(input.OrganizationName); + entity.SetFounder(input.Founder); + entity.SetVknTckn(input.VknTckn); + entity.SetTaxOffice(input.TaxOffice); + entity.SetCountry(input.Country); + entity.SetCity(input.City); + entity.SetDistrict(input.District); + entity.SetTownship(input.Township); + entity.SetAddress1(input.Address1); + entity.SetAddress2(input.Address2); + entity.SetPostalCode(input.PostalCode); + entity.SetPhoneNumber(input.PhoneNumber); + entity.SetMobileNumber(input.MobileNumber); + entity.SetFaxNumber(input.FaxNumber); + entity.SetEmail(input.Email); + entity.SetWebsite(input.Website); + entity.SetMenuGroup(input.MenuGroup); - await tenantRepository.UpdateAsync(entity, autoSave: true); + return await tenantRepository.UpdateAsync(entity, autoSave: true); } [Authorize(TenantManagementPermissions.Tenants.Update)] diff --git a/api/src/Sozsoft.Platform.Application/Menu/MenuAppService.cs b/api/src/Sozsoft.Platform.Application/Menu/MenuAppService.cs index 1c297d9..133d189 100644 --- a/api/src/Sozsoft.Platform.Application/Menu/MenuAppService.cs +++ b/api/src/Sozsoft.Platform.Application/Menu/MenuAppService.cs @@ -15,6 +15,7 @@ using Volo.Abp.PermissionManagement; using Volo.Abp.TenantManagement; using static Sozsoft.Platform.Data.Seeds.SeedConsts; using Sozsoft.Languages; +using Sozsoft.Platform.ListForms; namespace Sozsoft.Platform.Menus; @@ -31,6 +32,7 @@ public class MenuAppService : CrudAppService< private readonly ITenantRepository _tenantRepository; private readonly IPermissionDefinitionRecordRepository _permissionRepository; private readonly LanguageTextAppService _languageTextAppService; + private readonly IRepository _menuGroupRepository; public MenuAppService( IRepository menuRepository, @@ -38,7 +40,8 @@ public class MenuAppService : CrudAppService< IRepository languageTextRepository, ITenantRepository tenantRepository, IPermissionDefinitionRecordRepository permissionRepository, - LanguageTextAppService languageTextAppService + LanguageTextAppService languageTextAppService, + IRepository menuGroupRepository ) : base(menuRepository) { _menuRepository = menuRepository; @@ -47,6 +50,7 @@ public class MenuAppService : CrudAppService< _tenantRepository = tenantRepository; _permissionRepository = permissionRepository; _languageTextAppService = languageTextAppService; + _menuGroupRepository = menuGroupRepository; CreatePolicyName = $"{AppCodes.Menus.Menu}.Create"; UpdatePolicyName = $"{AppCodes.Menus.Menu}.Update"; @@ -318,4 +322,18 @@ public class MenuAppService : CrudAppService< return await base.CreateAsync(input); } + + public async Task> GetMenuGroupsAsync() + { + var menuGroups = await _menuGroupRepository.GetListAsync(); + + return menuGroups + .OrderBy(menuGroup => menuGroup.Name) + .Select(menuGroup => new LookupDataDto + { + Key = menuGroup.Id, + Name = menuGroup.Name + }) + .ToList(); + } } diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json b/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json index c72d995..73eef34 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json @@ -3654,6 +3654,12 @@ "en": "The maximum number of simultaneous users has been reached.", "tr": "Eş zamanlı kullanıcı limiti dolmuştur." }, + { + "resourceName": "Platform", + "key": "Abp.Identity.BranchLimitError", + "en": "The maximum number of active branches has been reached.", + "tr": "Aktif şube limiti dolmuştur." + }, { "resourceName": "Platform", "key": "Abp.Identity.IpRestrictionError", @@ -19931,6 +19937,12 @@ "key": "MessengerWidget.MessageDeleteFailed", "en": "Message could not be deleted", "tr": "Mesaj silinemedi" + }, + { + "resourceName": "Platform", + "key": "App.Tenant.Create", + "en": "Tenant Create", + "tr": "Tenant Oluştur" } ] } diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs index 9b0a58b..907fdb4 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs @@ -93,7 +93,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency EditingOptionJson = DefaultEditingOptionJson(TenantManagementPermissions.Tenants.Default, 950, 750, true, true, true, true, false, true), EditingFormJson = JsonSerializer.Serialize(new List() { - new() { Order=1, ColCount=3, ColSpan=1, ItemType="group", Items = + new() { Order=1, ColCount=4, ColSpan=1, ItemType="group", Items = [ new EditingFormItemDto { Order=1, DataField = "Name", ColSpan=1, EditorType2=EditorTypes.dxTextBox }, new EditingFormItemDto { Order=2, DataField = "OrganizationName", ColSpan=1, EditorType2=EditorTypes.dxTextBox }, @@ -104,20 +104,20 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency new EditingFormItemDto { Order=7, DataField = "PhoneNumber", ColSpan=1, EditorType2=EditorTypes.dxTextBox, EditorOptions=EditorOptionValues.PhoneEditorOptions }, new EditingFormItemDto { Order=8, DataField = "FaxNumber", ColSpan=1, EditorType2=EditorTypes.dxTextBox, EditorOptions=EditorOptionValues.PhoneEditorOptions }, new EditingFormItemDto { Order=9, DataField = "MenuGroup", ColSpan=1, EditorType2=EditorTypes.dxSelectBox, EditorOptions=EditorOptionValues.ShowClearButton }, + new EditingFormItemDto { Order=10, DataField = "Email", ColSpan=1, EditorType2=EditorTypes.dxTextBox }, + new EditingFormItemDto { Order=11, DataField = "Website", ColSpan=1, EditorType2=EditorTypes.dxTextBox }, + new EditingFormItemDto { Order=12, DataField = "IsActive", ColSpan=1, EditorType2=EditorTypes.dxCheckBox }, ] }, - new() { Order=2, ColCount=3, ColSpan=1, ItemType="group", Items = + new() { Order=2, ColCount=4, ColSpan=1, ItemType="group", Items = [ new EditingFormItemDto { Order=1, DataField = "Country", ColSpan=1, EditorType2=EditorTypes.dxSelectBox, EditorOptions=EditorOptionValues.ShowClearButton }, new EditingFormItemDto { Order=2, DataField = "City", ColSpan=1, EditorType2=EditorTypes.dxSelectBox, EditorOptions=EditorOptionValues.ShowClearButton }, new EditingFormItemDto { Order=3, DataField = "District", ColSpan=1, EditorType2=EditorTypes.dxSelectBox, EditorOptions=EditorOptionValues.ShowClearButton }, new EditingFormItemDto { Order=4, DataField = "Township", ColSpan=1, EditorType2=EditorTypes.dxSelectBox, EditorOptions=EditorOptionValues.ShowClearButton }, new EditingFormItemDto { Order=5, DataField = "PostalCode", ColSpan=1, EditorType2=EditorTypes.dxTextBox, EditorOptions=EditorOptionValues.ShowClearButton }, - new EditingFormItemDto { Order=6, DataField = "Email", ColSpan=1, EditorType2=EditorTypes.dxTextBox }, - new EditingFormItemDto { Order=7, DataField = "Website", ColSpan=1, EditorType2=EditorTypes.dxTextBox }, - new EditingFormItemDto { Order=8, DataField = "IsActive", ColSpan=1, EditorType2=EditorTypes.dxCheckBox }, - new EditingFormItemDto { Order=9, DataField = "Address1", ColSpan=3, EditorType2=EditorTypes.dxTextArea }, - new EditingFormItemDto { Order=10, DataField = "Address2", ColSpan=3, EditorType2=EditorTypes.dxTextArea }, + new EditingFormItemDto { Order=6, DataField = "Address1", ColSpan=3, EditorType2=EditorTypes.dxTextArea }, + new EditingFormItemDto { Order=7, DataField = "Address2", ColSpan=4, EditorType2=EditorTypes.dxTextArea }, ] } }), @@ -6963,6 +6963,19 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(), PagerOptionJson = DefaultPagerOptionJson, EditingOptionJson = DefaultEditingOptionJson(listFormName, 1200, 700, true, true, true, true, false, true), + CommandColumnJson = JsonSerializer.Serialize(new CommandColumnDto[] { + new() { + Hint = "Tenant", + Text = "Tenant", + AuthName = TenantManagementPermissions.Tenants.Create, + DialogName = "CreateTenantFromOrderDialog", + DialogParameters = JsonSerializer.Serialize(new { + orderId = "@Id" + }), + IsVisible = true, + VisibleExpression = "(e) => !e.row?.data?.TenantId", + }, + }), EditingFormJson = JsonSerializer.Serialize(new List { new() { Order=1, ColCount=4, ColSpan=1, ItemType="group", Items = diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/MenusData.json b/api/src/Sozsoft.Platform.DbMigrator/Seeds/MenusData.json index 54b06a2..86f3d66 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/MenusData.json +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/MenusData.json @@ -509,6 +509,128 @@ "IsDisabled": false, "ShortName": "Sas" }, + { + "ParentCode": "App.Saas", + "Code": "App.Public", + "DisplayName": "App.Public", + "Order": 0, + "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", @@ -780,131 +902,11 @@ "RequiredPermissionName": "App.BackgroundWorkers.Jobs", "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", "Code": "App.Menus", "DisplayName": "App.Menus", - "Order": 13, + "Order": 12, "Url": null, "Icon": "FcParallelTasks", "RequiredPermissionName": null, diff --git a/ui/src/services/menu.service.ts b/ui/src/services/menu.service.ts index 40294b7..d0a22aa 100644 --- a/ui/src/services/menu.service.ts +++ b/ui/src/services/menu.service.ts @@ -1,6 +1,12 @@ import { PagedAndSortedResultRequestDto, PagedResultDto } from '@/proxy/abp' import { MenuDto } from '@/proxy/menus/models' -import apiService, { Config } from '@/services/api.service' +import apiService from '@/services/api.service' + +export type MenuGroupLookupDto = { + key: string + name: string + group?: string +} export class MenuService { apiName = 'Default' @@ -85,6 +91,15 @@ export class MenuService { }, { apiName: this.apiName }, ) + + getMenuGroups = () => + apiService.fetchData( + { + method: 'GET', + url: '/api/app/menu/menu-groups', + }, + { apiName: this.apiName }, + ) } export const getMenus = async (skipCount = 0, maxResultCount = 1000, sorting = 'order') => { @@ -96,3 +111,9 @@ export const getMenus = async (skipCount = 0, maxResultCount = 1000, sorting = ' maxResultCount, }) } + +export const getMenuGroups = async () => { + const menuService = new MenuService() + + return await menuService.getMenuGroups() +} diff --git a/ui/src/services/tenant.service.ts b/ui/src/services/tenant.service.ts index e8d8eca..00854b2 100644 --- a/ui/src/services/tenant.service.ts +++ b/ui/src/services/tenant.service.ts @@ -3,6 +3,12 @@ import { SeedTenantDataInput } from '../proxy/admin/tenant/models' import { CustomTenantDto, TenantDto } from '../proxy/config/models' import apiService from './api.service' +export type CreateTenantFromOrderInput = { + orderId: string + name: string + menuGroup: string +} + export const getTenants = (skipCount = 0, maxResultCount = 10) => apiService.fetchData>({ method: 'GET', @@ -53,4 +59,13 @@ export const postSeedTenantData = (data: SeedTenantDataInput) => data, }) - \ No newline at end of file +export const createTenantFromOrder = (data: CreateTenantFromOrderInput) => + apiService.fetchData({ + method: 'POST', + url: '/api/app/list-form-dynamic-api/create-tenant-from-order', + data: { + data, + keys: [data.orderId], + listFormCode: 'App.Orders.SalesOrders', + }, + }) diff --git a/ui/src/views/admin/tenant-management/CreateTenantFromOrderDialog.tsx b/ui/src/views/admin/tenant-management/CreateTenantFromOrderDialog.tsx new file mode 100644 index 0000000..87c4f89 --- /dev/null +++ b/ui/src/views/admin/tenant-management/CreateTenantFromOrderDialog.tsx @@ -0,0 +1,170 @@ +import { + Button, + Dialog, + FormContainer, + FormItem, + Input, + Notification, + Select, + toast, +} from '@/components/ui' +import { getMenuGroups } from '@/services/menu.service' +import { createTenantFromOrder } from '@/services/tenant.service' +import { SelectBoxOption } from '@/types/shared' +import { useLocalization } from '@/utils/hooks/useLocalization' +import { Field, FieldProps, Form, Formik, FormikHelpers } from 'formik' +import { useEffect, useState } from 'react' +import * as Yup from 'yup' + +type CreateTenantFromOrderValues = { + name: string + menuGroup: string +} + +type CreateTenantFromOrderDialogProps = { + open: boolean + onDialogClose: () => void + orderId: string +} + +const schema = Yup.object().shape({ + name: Yup.string().trim().required(), + menuGroup: Yup.string().trim().required(), +}) + +const CreateTenantFromOrderDialog = ({ + open, + onDialogClose, + orderId, +}: CreateTenantFromOrderDialogProps) => { + const { translate } = useLocalization() + const [menuGroupOptions, setMenuGroupOptions] = useState([]) + const [isMenuGroupsLoading, setIsMenuGroupsLoading] = useState(false) + + useEffect(() => { + if (!open) { + return + } + + const fetchMenuGroups = async () => { + setIsMenuGroupsLoading(true) + + try { + const response = await getMenuGroups() + const items = response?.data ?? [] + + setMenuGroupOptions( + items.map((item: any) => ({ + value: String(item.key ?? item.Key ?? ''), + label: String(item.name ?? item.Name ?? ''), + })), + ) + } catch { + setMenuGroupOptions([]) + } finally { + setIsMenuGroupsLoading(false) + } + } + + fetchMenuGroups() + }, [open]) + + const handleSubmit = async ( + values: CreateTenantFromOrderValues, + { setSubmitting }: FormikHelpers, + ) => { + setSubmitting(true) + + try { + await createTenantFromOrder({ + orderId, + name: values.name.trim(), + menuGroup: values.menuGroup.trim(), + }) + + toast.push( + + {translate('::App.Platform.SaveSuccess') || 'Tenant kaydedildi'} + , + { placement: 'top-end' }, + ) + + onDialogClose() + } catch (error) { + const message = + (error as any)?.response?.data?.error?.message ?? + (error as any)?.response?.data?.message ?? + (error as any)?.message ?? + 'Islem basarisiz' + + toast.push( + + {message} + , + { placement: 'top-end' }, + ) + } finally { + setSubmitting(false) + } + } + + return ( + +
{translate('::App.Tenant.Create')}
+ + + initialValues={{ + name: '', + menuGroup: 'Erp', + }} + validationSchema={schema} + onSubmit={handleSubmit} + > + {({ errors, touched, isSubmitting }) => ( +
+ + + + {({ field, form }: FieldProps) => ( +