'integer', 'is_active' => 'boolean', ]; /** * 기본 그룹 정의 (React 구조 기준) */ public const DEFAULT_GROUPS = [ [ 'code' => 'notice', 'name' => '공지 알림', 'sort_order' => 1, 'items' => [ ['notification_type' => 'notice', 'label' => '공지사항 알림', 'sort_order' => 1], ['notification_type' => 'event', 'label' => '이벤트 알림', 'sort_order' => 2], ], ], [ 'code' => 'schedule', 'name' => '일정 알림', 'sort_order' => 2, 'items' => [ ['notification_type' => 'vat_report', 'label' => '부가세 신고 알림', 'sort_order' => 1], ['notification_type' => 'income_tax_report', 'label' => '종합소득세 신고 알림', 'sort_order' => 2], ], ], [ 'code' => 'vendor', 'name' => '거래처 알림', 'sort_order' => 3, 'items' => [ ['notification_type' => 'new_vendor', 'label' => '신규 업체 등록 알림', 'sort_order' => 1], ['notification_type' => 'credit_rating', 'label' => '신용등급 등록 알림', 'sort_order' => 2], ], ], [ 'code' => 'attendance', 'name' => '근태 알림', 'sort_order' => 4, 'items' => [ ['notification_type' => 'annual_leave', 'label' => '연차 알림', 'sort_order' => 1], ['notification_type' => 'clock_in', 'label' => '출근 알림', 'sort_order' => 2], ['notification_type' => 'late', 'label' => '지각 알림', 'sort_order' => 3], ['notification_type' => 'absent', 'label' => '결근 알림', 'sort_order' => 4], ], ], [ 'code' => 'order', 'name' => '수주/발주 알림', 'sort_order' => 5, 'items' => [ ['notification_type' => 'sales_order', 'label' => '수주 등록 알림', 'sort_order' => 1], ['notification_type' => 'purchase_order', 'label' => '발주 알림', 'sort_order' => 2], ], ], [ 'code' => 'approval', 'name' => '전자결재 알림', 'sort_order' => 6, 'items' => [ ['notification_type' => 'approval_request', 'label' => '결재요청 알림', 'sort_order' => 1], ['notification_type' => 'draft_approved', 'label' => '기안 > 승인 알림', 'sort_order' => 2], ['notification_type' => 'draft_rejected', 'label' => '기안 > 반려 알림', 'sort_order' => 3], ['notification_type' => 'draft_completed', 'label' => '기안 > 완료 알림', 'sort_order' => 4], ], ], [ 'code' => 'production', 'name' => '생산 알림', 'sort_order' => 7, 'items' => [ ['notification_type' => 'safety_stock', 'label' => '안전재고 알림', 'sort_order' => 1], ['notification_type' => 'production_complete', 'label' => '생산완료 알림', 'sort_order' => 2], ], ], [ 'code' => 'collection', 'name' => '채권/지출 알림', 'sort_order' => 8, 'items' => [ ['notification_type' => 'bad_debt', 'label' => '추심이슈 알림', 'sort_order' => 1], ['notification_type' => 'expected_expense', 'label' => '지출 승인대기 알림', 'sort_order' => 2], ], ], ]; /** * snake_case → camelCase 변환 맵 */ public const CAMEL_CASE_MAP = [ 'vat_report' => 'vatReport', 'income_tax_report' => 'incomeTaxReport', 'new_vendor' => 'newVendor', 'credit_rating' => 'creditRating', 'annual_leave' => 'annualLeave', 'clock_in' => 'clockIn', 'sales_order' => 'salesOrder', 'purchase_order' => 'purchaseOrder', 'approval_request' => 'approvalRequest', 'draft_approved' => 'draftApproved', 'draft_rejected' => 'draftRejected', 'draft_completed' => 'draftCompleted', 'safety_stock' => 'safetyStock', 'production_complete' => 'productionComplete', 'bad_debt' => 'badDebt', 'expected_expense' => 'expectedExpense', ]; /** * 테넌트 관계 */ public function tenant(): BelongsTo { return $this->belongsTo(Tenant::class); } /** * 그룹 항목들 */ public function items(): HasMany { return $this->hasMany(NotificationSettingGroupItem::class, 'group_id')->orderBy('sort_order'); } /** * Scope: 활성화된 그룹만 */ public function scopeActive($query) { return $query->where('is_active', true); } /** * Scope: 정렬순 */ public function scopeOrdered($query) { return $query->orderBy('sort_order'); } /** * snake_case를 camelCase로 변환 */ public static function toCamelCase(string $snakeCase): string { return self::CAMEL_CASE_MAP[$snakeCase] ?? $snakeCase; } /** * camelCase를 snake_case로 변환 */ public static function toSnakeCase(string $camelCase): string { $flipped = array_flip(self::CAMEL_CASE_MAP); return $flipped[$camelCase] ?? $camelCase; } }