success(NotificationEvent::where('enabled', true)->orderBy('category')->orderBy('name')->get(), 'Daftar event notifikasi berhasil diambil'); } public function channels(Request $request) { return $this->success($this->service->channels($this->channel($request), $request->user(), $this->tenantId($request)), 'Konfigurasi channel berhasil diambil'); } public function storeChannel(StoreNotificationChannelRequest $request) { abort_unless($request->validated('channel') === $this->channel($request), 422); return $this->created($this->service->saveChannel($request->validated(), $request->user(), $this->tenantId($request)), 'Konfigurasi channel berhasil dibuat'); } public function updateChannel(StoreNotificationChannelRequest $request, NotificationChannel $notificationChannel) { $this->authorizeTenant($request, $notificationChannel->tenant_id); abort_unless($notificationChannel->channel === $this->channel($request), 404); return $this->updated($this->service->saveChannel($request->validated(), $request->user(), $this->tenantId($request), $notificationChannel), 'Konfigurasi channel berhasil diperbarui'); } public function testChannel(Request $request, NotificationChannel $notificationChannel) { $this->authorizeTenant($request, $notificationChannel->tenant_id); abort_unless($notificationChannel->channel === $this->channel($request), 404); return $this->success($this->service->testChannel($notificationChannel), 'Pengujian channel selesai'); } public function templates(Request $request) { return $this->success($this->service->templates($this->channel($request), $request->user(), $this->tenantId($request)), 'Daftar template berhasil diambil'); } public function storeTemplate(StoreNotificationTemplateRequest $request) { abort_unless($request->validated('channel') === $this->channel($request), 422); return $this->created($this->service->saveTemplate($request->validated(), $request->user(), $this->tenantId($request)), 'Template berhasil dibuat'); } public function updateTemplate(StoreNotificationTemplateRequest $request, NotificationTemplate $notificationTemplate) { if ($notificationTemplate->tenant_id) { $this->authorizeTenant($request, $notificationTemplate->tenant_id); } abort_unless($notificationTemplate->channel === $this->channel($request), 404); return $this->updated($this->service->saveTemplate($request->validated(), $request->user(), $this->tenantId($request), $notificationTemplate), 'Template berhasil diperbarui'); } public function preferences(Request $request) { $tenantId = $request->user()->isMasterAdmin() && $request->integer('tenant_id') ? $request->integer('tenant_id') : $this->tenantId($request); return $this->success($this->service->preferences($request->user(), $tenantId), 'Preference notifikasi berhasil diambil'); } public function savePreferences(SaveNotificationPreferencesRequest $request) { $this->service->savePreferences($request->validated('preferences'), $request->user(), $this->tenantId($request)); return $this->updated(null, 'Preference notifikasi berhasil disimpan'); } public function deliveries(IndexNotificationRequest $request) { return $this->successPaginated( $this->service->deliveries($this->channel($request), $request->validated(), $request->user(), $this->tenantId($request)), NotificationDeliveryResource::class, 'Log pesan berhasil diambil', ); } public function broadcasts(IndexNotificationRequest $request) { return $this->success($this->service->broadcasts($request->validated(), $request->user(), $this->tenantId($request)), 'Daftar pesan siaran berhasil diambil'); } public function previewBroadcast(StoreNotificationBroadcastRequest $request) { return $this->success($this->service->previewBroadcast($request->validated(), $request->user(), $this->tenantId($request)), 'Preview penerima berhasil dihitung'); } public function storeBroadcast(StoreNotificationBroadcastRequest $request) { return $this->created($this->service->createBroadcast($request->validated(), $request->user(), $this->tenantId($request)), 'Pesan siaran masuk antrean'); } public function showBroadcast(Request $request, NotificationBroadcast $notificationBroadcast) { $this->authorizeTenant($request, $notificationBroadcast->tenant_id); return $this->success($notificationBroadcast->load(['template', 'channelConfig', 'recipients.customer:id,customer_code,name']), 'Detail siaran berhasil diambil'); } public function approveBroadcast(Request $request, NotificationBroadcast $notificationBroadcast) { $this->authorizeTenant($request, $notificationBroadcast->tenant_id); return $this->updated($this->service->approveBroadcast($notificationBroadcast, $request->user()), 'Pesan siaran berhasil disetujui'); } public function myNotifications(IndexNotificationRequest $request) { return $this->success($this->service->userNotifications($request->user(), $request->validated()), 'Notifikasi aplikasi berhasil diambil'); } public function markRead(Request $request, string $uuid) { $notification = $request->user()->userNotifications()->where('uuid', $uuid)->firstOrFail(); $notification->update(['read_at' => now()]); return $this->updated($notification, 'Notifikasi ditandai sudah dibaca'); } public function contacts(Request $request, Customer $customer) { $this->authorizeTenant($request, $customer->tenant_id); return $this->success($customer->contacts()->orderBy('type')->orderByDesc('is_primary')->get(), 'Kontak notifikasi berhasil diambil'); } public function storeContact(StoreCustomerContactRequest $request, Customer $customer) { $this->authorizeTenant($request, $customer->tenant_id); return $this->created($this->service->saveContact($customer, $request->validated()), 'Kontak notifikasi berhasil dibuat'); } public function updateContact(StoreCustomerContactRequest $request, Customer $customer, CustomerContact $contact) { $this->authorizeTenant($request, $customer->tenant_id); return $this->updated($this->service->saveContact($customer, $request->validated(), $contact), 'Kontak notifikasi berhasil diperbarui'); } public function destroyContact(Request $request, Customer $customer, CustomerContact $contact) { $this->authorizeTenant($request, $customer->tenant_id); abort_unless((int) $contact->customer_id === (int) $customer->id, 404); $contact->delete(); return $this->deleted('Kontak notifikasi berhasil dihapus'); } private function channel(Request $request): string { return $request->route()->defaults['notification_channel']; } private function tenantId(Request $request): ?int { return $request->attributes->get('tenant_id'); } private function authorizeTenant(Request $request, int $tenantId): void { abort_unless($request->user()->isMasterAdmin() || $tenantId === $this->tenantId($request), 403); } }