whereNumber('notificationChannel')->name('notification.webhooks.verify'); Route::post('/notification-webhooks/{notificationChannel}', [NotificationWebhookController::class, 'handle']) ->whereNumber('notificationChannel')->name('notification.webhooks.handle'); Route::post('/payment-webhooks/{accountUuid}', fn () => response()->json(['message' => 'Provider adapter belum dikonfigurasi.'], 501)) ->name('payment.webhooks.handle'); Route::middleware(['auth:sanctum', 'tenant.context'])->group(function () { Route::get('payment-gateway/providers', [PaymentGatewayController::class, 'providers']) ->middleware('menu.permission:payment-gateway-settings,view')->name('payment-gateway.providers'); Route::get('payment-gateway/settings', [PaymentGatewayController::class, 'settings']) ->middleware('menu.permission:payment-gateway-settings,view')->name('payment-gateway.settings.index'); Route::post('payment-gateway/accounts', [PaymentGatewayController::class, 'storeAccount']) ->middleware('menu.permission:payment-gateway-settings,create')->name('payment-gateway.accounts.store'); Route::put('payment-gateway/accounts/{account}', [PaymentGatewayController::class, 'updateAccount']) ->middleware('menu.permission:payment-gateway-settings,update')->whereNumber('account')->name('payment-gateway.accounts.update'); Route::put('payment-gateway/tenant-setting', [PaymentGatewayController::class, 'saveSetting']) ->middleware('menu.permission:payment-gateway-settings,update')->name('payment-gateway.tenant-setting.update'); Route::get('payment-gateway/transactions', [PaymentGatewayController::class, 'transactions']) ->middleware('menu.permission:payment-gateway-logs,view')->name('payment-gateway.transactions.index'); Route::get('wallets', [WalletController::class, 'index'])->name('wallets.index'); Route::get('wallets/{wallet}/ledger', [WalletController::class, 'ledger'])->whereNumber('wallet')->name('wallets.ledger'); Route::post('wallets/{wallet}/transfer', [WalletController::class, 'transfer'])->whereNumber('wallet')->name('wallets.transfer'); Route::post('wallets/{wallet}/withdraw', [WalletController::class, 'withdraw'])->whereNumber('wallet')->name('wallets.withdraw'); Route::get('notifications/events', [NotificationController::class, 'events'])->name('notifications.events'); Route::get('notifications/preferences', [NotificationController::class, 'preferences']) ->middleware('menu.permission:notifications-system,view')->name('notifications.preferences.index'); Route::put('notifications/preferences', [NotificationController::class, 'savePreferences']) ->middleware('menu.permission:notifications-system,update')->name('notifications.preferences.update'); Route::get('notifications/broadcasts', [NotificationController::class, 'broadcasts']) ->middleware('menu.permission:notifications-broadcasts,view')->name('notifications.broadcasts.index'); Route::post('notifications/broadcasts/preview', [NotificationController::class, 'previewBroadcast']) ->middleware('menu.permission:notifications-broadcasts,create')->name('notifications.broadcasts.preview'); Route::post('notifications/broadcasts', [NotificationController::class, 'storeBroadcast']) ->middleware('menu.permission:notifications-broadcasts,create')->name('notifications.broadcasts.store'); Route::get('notifications/broadcasts/{notificationBroadcast}', [NotificationController::class, 'showBroadcast']) ->middleware('menu.permission:notifications-broadcasts,view')->whereNumber('notificationBroadcast')->name('notifications.broadcasts.show'); Route::post('notifications/broadcasts/{notificationBroadcast}/approve', [NotificationController::class, 'approveBroadcast']) ->middleware('menu.permission:notifications-broadcasts,approve')->whereNumber('notificationBroadcast')->name('notifications.broadcasts.approve'); Route::get('me/notifications', [NotificationController::class, 'myNotifications'])->name('me.notifications.index'); Route::put('me/notifications/{uuid}/read', [NotificationController::class, 'markRead'])->name('me.notifications.read'); Route::get('customers/{customer}/notification-contacts', [NotificationController::class, 'contacts']) ->middleware('menu.permission:customers-active,view')->whereNumber('customer')->name('customers.notification-contacts.index'); Route::post('customers/{customer}/notification-contacts', [NotificationController::class, 'storeContact']) ->middleware('menu.permission:customers-active,update')->whereNumber('customer')->name('customers.notification-contacts.store'); Route::put('customers/{customer}/notification-contacts/{contact}', [NotificationController::class, 'updateContact']) ->middleware('menu.permission:customers-active,update')->whereNumber('customer')->whereNumber('contact')->name('customers.notification-contacts.update'); Route::delete('customers/{customer}/notification-contacts/{contact}', [NotificationController::class, 'destroyContact']) ->middleware('menu.permission:customers-active,update')->whereNumber('customer')->whereNumber('contact')->name('customers.notification-contacts.destroy'); foreach ([ 'system' => ['channel' => 'system', 'menu' => 'notifications-system'], 'whatsapp-official' => ['channel' => 'whatsapp_official', 'menu' => 'notifications-wa-official'], 'whatsapp-unofficial' => ['channel' => 'whatsapp_unofficial', 'menu' => 'notifications-wa-unofficial'], 'email' => ['channel' => 'email', 'menu' => 'notifications-email'], 'telegram' => ['channel' => 'telegram', 'menu' => 'notifications-telegram'], ] as $path => $notification) { Route::prefix("notifications/channels/{$path}") ->middleware("menu.resource:{$notification['menu']}") ->controller(NotificationController::class) ->group(function () use ($path, $notification) { Route::get('/settings', 'channels')->defaults('notification_channel', $notification['channel'])->name("notifications.{$path}.settings.index"); Route::post('/settings', 'storeChannel')->defaults('notification_channel', $notification['channel'])->name("notifications.{$path}.settings.store"); Route::put('/settings/{notificationChannel}', 'updateChannel')->defaults('notification_channel', $notification['channel'])->whereNumber('notificationChannel')->name("notifications.{$path}.settings.update"); Route::post('/settings/{notificationChannel}/test', 'testChannel')->defaults('notification_channel', $notification['channel'])->whereNumber('notificationChannel')->name("notifications.{$path}.settings.test"); Route::get('/templates', 'templates')->defaults('notification_channel', $notification['channel'])->name("notifications.{$path}.templates.index"); Route::post('/templates', 'storeTemplate')->defaults('notification_channel', $notification['channel'])->name("notifications.{$path}.templates.store"); Route::put('/templates/{notificationTemplate}', 'updateTemplate')->defaults('notification_channel', $notification['channel'])->whereNumber('notificationTemplate')->name("notifications.{$path}.templates.update"); Route::get('/logs', 'deliveries')->defaults('notification_channel', $notification['channel'])->name("notifications.{$path}.logs.index"); }); } Route::get('topology/options', [TopologyController::class, 'options']) ->name('topology.options'); Route::get('topology/map', [TopologyController::class, 'map']) ->middleware('menu.permission:topology-map,view') ->name('topology.map'); Route::post('topology/customer-connections', [TopologyController::class, 'connectCustomer']) ->middleware('menu.permission:topology-devices,update') ->name('topology.customer-connections.store'); Route::get('topology/customers/{customer}/path', [TopologyController::class, 'customerPath']) ->middleware('menu.permission:topology-network,view') ->whereNumber('customer')->name('topology.customers.path'); Route::get('topology/nodes/{node}/ports', [TopologyController::class, 'ports']) ->middleware('menu.permission:topology-devices,view') ->whereNumber('node')->name('topology.nodes.ports.index'); Route::post('topology/nodes/{node}/ports', [TopologyController::class, 'storePort']) ->defaults('topology_resource', 'port') ->middleware('menu.permission:topology-devices,create') ->whereNumber('node')->name('topology.nodes.ports.store'); Route::put('topology/ports/{port}', [TopologyController::class, 'updatePort']) ->defaults('topology_resource', 'port') ->middleware('menu.permission:topology-devices,update') ->whereNumber('port')->name('topology.ports.update'); Route::delete('topology/ports/{port}', [TopologyController::class, 'destroyPort']) ->middleware('menu.permission:topology-devices,delete') ->whereNumber('port')->name('topology.ports.destroy'); Route::get('topology/nodes/{node}/{direction}', [TopologyController::class, 'trace']) ->middleware('menu.permission:topology-network,view') ->whereNumber('node')->whereIn('direction', ['upstream', 'downstream']) ->name('topology.nodes.trace'); foreach ([ 'device-types' => ['resource' => 'device-type', 'menu' => 'topology-device-types'], 'nodes' => ['resource' => 'node', 'menu' => 'topology-devices'], 'links' => ['resource' => 'link', 'menu' => 'topology-links'], ] as $path => $topology) { Route::prefix("topology/{$path}") ->middleware("menu.resource:{$topology['menu']}") ->controller(TopologyController::class) ->group(function () use ($path, $topology) { Route::get('/', 'index')->defaults('topology_resource', $topology['resource'])->name("topology.{$path}.index"); Route::post('/', 'store')->defaults('topology_resource', $topology['resource'])->name("topology.{$path}.store"); Route::get('/{id}', 'show')->defaults('topology_resource', $topology['resource'])->whereNumber('id')->name("topology.{$path}.show"); Route::put('/{id}', 'update')->defaults('topology_resource', $topology['resource'])->whereNumber('id')->name("topology.{$path}.update"); Route::patch('/{id}', 'update')->defaults('topology_resource', $topology['resource'])->whereNumber('id')->name("topology.{$path}.patch"); Route::delete('/{id}', 'destroy')->defaults('topology_resource', $topology['resource'])->whereNumber('id')->name("topology.{$path}.destroy"); }); } Route::prefix('billing/profiles') ->middleware('menu.resource:billing-profiles') ->controller(BillingProfileController::class) ->group(function () { Route::get('/', 'index')->name('billing.profiles.index'); Route::post('/', 'store')->name('billing.profiles.store'); Route::get('/{id}', 'show')->name('billing.profiles.show')->whereNumber('id'); Route::put('/{id}', 'update')->name('billing.profiles.update')->whereNumber('id'); Route::patch('/{id}', 'update')->name('billing.profiles.patch')->whereNumber('id'); Route::delete('/{id}', 'destroy')->name('billing.profiles.destroy')->whereNumber('id'); }); foreach ([ 'running' => 'billing-running', 'overdue' => 'billing-overdue', 'paid' => 'billing-paid', ] as $scope => $menuSlug) { Route::prefix("billing/invoices/{$scope}") ->middleware("menu.resource:{$menuSlug}") ->controller(InvoiceController::class) ->group(function () use ($scope) { Route::get('/', 'index')->name("billing.invoices.{$scope}.index")->defaults('invoice_scope', $scope); Route::get('/{id}', 'show')->name("billing.invoices.{$scope}.show")->whereNumber('id')->defaults('invoice_scope', $scope); if ($scope !== 'paid') { Route::post('/{id}/pay', 'pay')->name("billing.invoices.{$scope}.pay")->whereNumber('id'); } }); } Route::get('billing/invoice-options', [InvoiceController::class, 'options']) ->name('billing.invoices.options') ->middleware('menu.permission:billing-running,view'); Route::post('billing/invoices', [InvoiceController::class, 'store']) ->name('billing.invoices.store') ->middleware('menu.permission:billing-running,create'); Route::put('billing/invoices/{id}', [InvoiceController::class, 'update']) ->name('billing.invoices.update')->whereNumber('id') ->middleware('menu.permission:billing-running,update'); Route::patch('billing/invoices/{id}', [InvoiceController::class, 'update']) ->name('billing.invoices.patch')->whereNumber('id') ->middleware('menu.permission:billing-running,update'); Route::post('billing/invoices/{id}/cancel', [InvoiceController::class, 'cancel']) ->name('billing.invoices.cancel')->whereNumber('id') ->middleware('menu.permission:billing-running,delete'); Route::get('customers/options', [CustomerController::class, 'options']) ->name('customers.options') ->middleware('menu.permission:customers-orders,view'); foreach ([ 'orders' => 'customers-orders', 'active' => 'customers-active', 'inactive' => 'customers-inactive', 'unmanaged' => 'customers-unmanaged', 'trash' => 'customers-trash', ] as $scope => $menuSlug) { Route::get("customers/{$scope}", [CustomerController::class, 'index']) ->name("customers.{$scope}.index") ->defaults('customer_scope', $scope) ->middleware("menu.permission:{$menuSlug},view"); Route::get("customers/{$scope}/{id}", [CustomerController::class, 'show']) ->name("customers.{$scope}.show") ->whereNumber('id') ->defaults('customer_scope', $scope) ->middleware("menu.permission:{$menuSlug},view"); } Route::post('customers', [CustomerController::class, 'store']) ->name('customers.store') ->middleware('menu.permission:customers-orders,create'); Route::put('customers/{id}', [CustomerController::class, 'update']) ->name('customers.update') ->whereNumber('id') ->middleware('menu.permission:customers-orders,update'); Route::patch('customers/{id}', [CustomerController::class, 'update']) ->name('customers.patch') ->whereNumber('id') ->middleware('menu.permission:customers-orders,update'); Route::post('customers/{id}/activate', [CustomerController::class, 'activate']) ->name('customers.activate') ->whereNumber('id') ->middleware('menu.permission:customers-orders,update'); Route::post('customers/{id}/deactivate', [CustomerController::class, 'deactivate']) ->name('customers.deactivate') ->whereNumber('id') ->middleware('menu.permission:customers-active,update'); Route::delete('customers/{id}', [CustomerController::class, 'destroy']) ->name('customers.destroy') ->whereNumber('id') ->middleware('menu.permission:customers-inactive,delete'); Route::post('customers/{id}/restore', [CustomerController::class, 'restore']) ->name('customers.restore') ->whereNumber('id') ->middleware('menu.permission:customers-trash,update'); Route::delete('customers/{id}/force', [CustomerController::class, 'forceDelete']) ->name('customers.force-delete') ->whereNumber('id') ->middleware('menu.permission:customers-trash,delete'); foreach ([ 'mikrotiks' => ['resource' => 'mikrotik', 'menu' => 'nas-mikrotik'], 'package-profiles' => ['resource' => 'package-profile', 'menu' => 'nas-package-profiles'], 'olts' => ['resource' => 'olt', 'menu' => 'nas-olt'], 'webfig-devices' => ['resource' => 'webfig', 'menu' => 'nas-webfig'], ] as $path => $nas) { Route::prefix("nas/{$path}") ->middleware("menu.resource:{$nas['menu']}") ->controller(NasResourceController::class) ->group(function () use ($nas, $path) { Route::get('/', 'index') ->name("nas.{$path}.index") ->defaults('nas_resource', $nas['resource']); Route::post('/', 'store') ->name("nas.{$path}.store") ->defaults('nas_resource', $nas['resource']); Route::get('/{id}', 'show') ->name("nas.{$path}.show") ->whereNumber('id') ->defaults('nas_resource', $nas['resource']); Route::put('/{id}', 'update') ->name("nas.{$path}.update") ->whereNumber('id') ->defaults('nas_resource', $nas['resource']); Route::patch('/{id}', 'update') ->name("nas.{$path}.patch") ->whereNumber('id') ->defaults('nas_resource', $nas['resource']); Route::delete('/{id}', 'destroy') ->name("nas.{$path}.destroy") ->whereNumber('id') ->defaults('nas_resource', $nas['resource']); }); } Route::apiResource('tickets', TicketController::class) ->middleware('menu.resource:ticketing-ticket'); Route::apiResource('ticket-types', TicketTypeController::class) ->middleware('menu.resource:ticketing-ticket-types'); Route::apiResource('ticket-incident-types', TicketIncidentTypeController::class) ->middleware('menu.resource:ticketing-ticket-incidents'); Route::prefix('tickets/{ticket}') ->controller(TicketWorkflowController::class) ->group(function () { Route::get('/workflow', 'history') ->middleware('menu.permission:ticketing-ticket,view'); Route::post('/assign', 'assign') ->middleware('menu.permission:ticketing-ticket,update'); Route::post('/reassign', 'reassign') ->middleware('menu.permission:ticketing-ticket,update'); Route::post('/approve', 'approve') ->middleware('menu.permission:ticketing-approval,approve'); Route::post('/reject', 'reject') ->middleware('menu.permission:ticketing-approval,approve'); Route::post('/start', 'start') ->middleware('menu.permission:ticketing-ticket,update'); Route::post('/pending', 'pending') ->middleware('menu.permission:ticketing-ticket,update'); Route::post('/resume', 'resume') ->middleware('menu.permission:ticketing-ticket,update'); Route::post('/resolve', 'resolve') ->middleware('menu.permission:ticketing-ticket,update'); Route::post('/close', 'close') ->middleware('menu.permission:ticketing-ticket,update'); Route::post('/cancel', 'cancel') ->middleware('menu.permission:ticketing-ticket,delete'); Route::post('/escalate', 'escalate') ->middleware('menu.permission:ticketing-ticket,update'); }); Route::prefix('materials') ->middleware('menu.resource:ticketing-material') ->controller(MaterialController::class) ->group(function () { Route::get('/', 'index'); Route::post('/assign', 'assign'); Route::post('/transfer', 'transfer'); Route::post('/return', 'return'); Route::get('/user/{user_id}', 'listByUser'); Route::get('/history/{barcode_id}', 'history'); }); Route::prefix('audit-logs') ->middleware('access.level:tenant_owner') ->controller(AuditLogController::class) ->group(function () { Route::get('/', 'index'); Route::get('/{id}', 'show'); }); Route::prefix('me') ->group(function () { Route::get('/menus', [MenuController::class, 'myMenus']); Route::get('/profile', [ProfileController::class, 'show']); Route::put('/profile', [ProfileController::class, 'update']); }); Route::prefix('files')->controller(StoredFileController::class)->group(function () { Route::get('/', 'index'); Route::post('/', 'store'); Route::get('/{storedFile}', 'show'); Route::get('/{storedFile}/temporary-url', 'temporaryUrl'); Route::delete('/{storedFile}', 'destroy'); }); Route::get('wilayah/alamat-lengkap', [WilayahController::class, 'alamatLengkap']) ->name('wilayah.alamat-lengkap'); Route::prefix('wilayah/options')->controller(WilayahController::class)->group(function () { Route::get('/provinsi', 'provinsiOptions')->name('wilayah.options.provinsi'); Route::get('/kabupaten/{provinsi}', 'kabupatenOptions')->name('wilayah.options.kabupaten'); Route::get('/kecamatan/{kabupaten}', 'kecamatanOptions')->name('wilayah.options.kecamatan'); Route::get('/desa/{kecamatan}', 'desaOptions')->name('wilayah.options.desa'); }); foreach ([ 'desa' => 'wilayah-desa', 'kecamatan' => 'wilayah-kecamatan', 'kabupaten' => 'wilayah-kabupaten', 'provinsi' => 'wilayah-provinsi', ] as $tingkat => $menuSlug) { $readRoutes = [ Route::get("wilayah/{$tingkat}", [WilayahController::class, 'index']) ->name("wilayah.{$tingkat}.index"), Route::get("wilayah/{$tingkat}/{wilayah}", [WilayahController::class, 'show']) ->name("wilayah.{$tingkat}.show") ->whereNumber('wilayah'), ]; $writeRoutes = [ Route::post("wilayah/{$tingkat}", [WilayahController::class, 'store']) ->name("wilayah.{$tingkat}.store"), Route::put("wilayah/{$tingkat}/{wilayah}", [WilayahController::class, 'update']) ->name("wilayah.{$tingkat}.update") ->whereNumber('wilayah'), Route::patch("wilayah/{$tingkat}/{wilayah}", [WilayahController::class, 'update']) ->name("wilayah.{$tingkat}.patch") ->whereNumber('wilayah'), Route::delete("wilayah/{$tingkat}/{wilayah}", [WilayahController::class, 'destroy']) ->name("wilayah.{$tingkat}.destroy") ->whereNumber('wilayah'), ]; foreach ($readRoutes as $wilayahRoute) { $wilayahRoute->defaults('tingkat', $tingkat); } foreach ($writeRoutes as $wilayahRoute) { $wilayahRoute->defaults('tingkat', $tingkat) ->middleware("menu.resource:{$menuSlug}"); } } Route::apiResource('menus', MenuListController::class) ->parameters(['menus' => 'menu_list']) ->middleware('access.level:master_admin'); Route::apiResource('menu-groups', MenuGroupController::class) ->middleware([ 'access.level:tenant_owner', 'menu.resource:users-group-menus', ]); Route::apiResource('tenants', TenantController::class) ->only(['index', 'show']) ->middleware('access.level:tenant_owner'); Route::apiResource('tenants', TenantController::class) ->except(['index', 'show']) ->middleware('access.level:master_admin'); Route::apiResource('users', UserController::class) ->middleware([ 'access.level:tenant_owner', 'menu.resource:users-user', ]); Route::prefix('menu-groups/{menu_group}') ->middleware([ 'access.level:tenant_owner', 'menu.permission:users-group-menus,update', ]) ->controller(MenuGroupController::class) ->group(function () { Route::get('/menus', 'menus'); Route::get('/available-menus', 'availableMenus'); Route::put('/menus', 'syncMenus'); }); Route::prefix('users/{user}') ->middleware([ 'access.level:tenant_owner', 'menu.permission:users-group-menus,update', ]) ->controller(MenuGroupController::class) ->group(function () { Route::get('/menu-groups', 'userAssignments'); Route::put('/menu-groups', 'syncUserAssignments'); }); });