- Auditable 트레이트 신규 생성 (bootAuditable 패턴) - creating: created_by/updated_by 자동 채우기 - updating: updated_by 자동 채우기 - deleting: deleted_by 채우기 + saveQuietly() - created/updated/deleted: audit_logs 자동 기록 - 기존 AuditLogger 패턴과 동일한 try/catch 조용한 실패 - 변경된 필드만 before/after 기록 (updated 이벤트) - auditExclude 프로퍼티로 모델별 제외 필드 설정 가능 - 제외 대상: Attendance, StockTransaction, TodayIssue 등 고빈도/시스템 모델 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
228 lines
5.9 KiB
PHP
228 lines
5.9 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use App\Traits\Auditable;
|
|
use App\Traits\BelongsToTenant;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
|
|
class NotificationSetting extends Model
|
|
{
|
|
use Auditable, BelongsToTenant;
|
|
|
|
protected $fillable = [
|
|
'tenant_id',
|
|
'user_id',
|
|
'notification_type',
|
|
'push_enabled',
|
|
'email_enabled',
|
|
'sms_enabled',
|
|
'in_app_enabled',
|
|
'kakao_enabled',
|
|
'settings',
|
|
];
|
|
|
|
protected $casts = [
|
|
'push_enabled' => 'boolean',
|
|
'email_enabled' => 'boolean',
|
|
'sms_enabled' => 'boolean',
|
|
'in_app_enabled' => 'boolean',
|
|
'kakao_enabled' => 'boolean',
|
|
'settings' => 'array',
|
|
];
|
|
|
|
/**
|
|
* 알림 유형 상수
|
|
*/
|
|
public const TYPE_APPROVAL = 'approval'; // 결재
|
|
|
|
public const TYPE_ORDER = 'order'; // 수주
|
|
|
|
public const TYPE_DEPOSIT = 'deposit'; // 입금
|
|
|
|
public const TYPE_WITHDRAWAL = 'withdrawal'; // 출금
|
|
|
|
public const TYPE_NOTICE = 'notice'; // 공지사항
|
|
|
|
public const TYPE_SYSTEM = 'system'; // 시스템
|
|
|
|
public const TYPE_MARKETING = 'marketing'; // 마케팅
|
|
|
|
public const TYPE_SECURITY = 'security'; // 보안 (로그인, 비밀번호 변경 등)
|
|
|
|
/**
|
|
* 알림 채널 상수
|
|
*/
|
|
public const CHANNEL_PUSH = 'push';
|
|
|
|
public const CHANNEL_EMAIL = 'email';
|
|
|
|
public const CHANNEL_SMS = 'sms';
|
|
|
|
public const CHANNEL_IN_APP = 'in_app';
|
|
|
|
public const CHANNEL_KAKAO = 'kakao';
|
|
|
|
/**
|
|
* 모든 알림 유형 반환
|
|
*/
|
|
public static function getAllTypes(): array
|
|
{
|
|
return [
|
|
self::TYPE_APPROVAL,
|
|
self::TYPE_ORDER,
|
|
self::TYPE_DEPOSIT,
|
|
self::TYPE_WITHDRAWAL,
|
|
self::TYPE_NOTICE,
|
|
self::TYPE_SYSTEM,
|
|
self::TYPE_MARKETING,
|
|
self::TYPE_SECURITY,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 모든 채널 반환
|
|
*/
|
|
public static function getAllChannels(): array
|
|
{
|
|
return [
|
|
self::CHANNEL_PUSH,
|
|
self::CHANNEL_EMAIL,
|
|
self::CHANNEL_SMS,
|
|
self::CHANNEL_IN_APP,
|
|
self::CHANNEL_KAKAO,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 알림 유형별 기본 설정 반환
|
|
*/
|
|
public static function getDefaultSettings(string $type): array
|
|
{
|
|
// 보안 관련 알림은 이메일 기본 활성화
|
|
if ($type === self::TYPE_SECURITY) {
|
|
return [
|
|
'push_enabled' => true,
|
|
'email_enabled' => true,
|
|
'sms_enabled' => false,
|
|
'in_app_enabled' => true,
|
|
'kakao_enabled' => false,
|
|
];
|
|
}
|
|
|
|
// 마케팅은 기본 비활성화
|
|
if ($type === self::TYPE_MARKETING) {
|
|
return [
|
|
'push_enabled' => false,
|
|
'email_enabled' => false,
|
|
'sms_enabled' => false,
|
|
'in_app_enabled' => false,
|
|
'kakao_enabled' => false,
|
|
];
|
|
}
|
|
|
|
// 기타 알림은 푸시, 인앱만 기본 활성화
|
|
return [
|
|
'push_enabled' => true,
|
|
'email_enabled' => false,
|
|
'sms_enabled' => false,
|
|
'in_app_enabled' => true,
|
|
'kakao_enabled' => false,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 알림 유형 레이블
|
|
*/
|
|
public static function getTypeLabels(): array
|
|
{
|
|
return [
|
|
self::TYPE_APPROVAL => '전자결재',
|
|
self::TYPE_ORDER => '수주',
|
|
self::TYPE_DEPOSIT => '입금',
|
|
self::TYPE_WITHDRAWAL => '출금',
|
|
self::TYPE_NOTICE => '공지사항',
|
|
self::TYPE_SYSTEM => '시스템',
|
|
self::TYPE_MARKETING => '마케팅',
|
|
self::TYPE_SECURITY => '보안',
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 채널 레이블
|
|
*/
|
|
public static function getChannelLabels(): array
|
|
{
|
|
return [
|
|
self::CHANNEL_PUSH => '푸시 알림',
|
|
self::CHANNEL_EMAIL => '이메일',
|
|
self::CHANNEL_SMS => 'SMS',
|
|
self::CHANNEL_IN_APP => '인앱 알림',
|
|
self::CHANNEL_KAKAO => '카카오 알림톡',
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 사용자 관계
|
|
*/
|
|
public function user(): BelongsTo
|
|
{
|
|
return $this->belongsTo(User::class);
|
|
}
|
|
|
|
/**
|
|
* 테넌트 관계
|
|
*/
|
|
public function tenant(): BelongsTo
|
|
{
|
|
return $this->belongsTo(Tenant::class);
|
|
}
|
|
|
|
/**
|
|
* Scope: 특정 사용자의 설정
|
|
*/
|
|
public function scopeForUser($query, int $userId)
|
|
{
|
|
return $query->where('user_id', $userId);
|
|
}
|
|
|
|
/**
|
|
* Scope: 특정 알림 유형
|
|
*/
|
|
public function scopeOfType($query, string $type)
|
|
{
|
|
return $query->where('notification_type', $type);
|
|
}
|
|
|
|
/**
|
|
* 특정 채널이 활성화되어 있는지 확인
|
|
*/
|
|
public function isChannelEnabled(string $channel): bool
|
|
{
|
|
return match ($channel) {
|
|
self::CHANNEL_PUSH => $this->push_enabled,
|
|
self::CHANNEL_EMAIL => $this->email_enabled,
|
|
self::CHANNEL_SMS => $this->sms_enabled,
|
|
self::CHANNEL_IN_APP => $this->in_app_enabled,
|
|
self::CHANNEL_KAKAO => $this->kakao_enabled,
|
|
default => false,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 채널 설정 업데이트
|
|
*/
|
|
public function setChannelEnabled(string $channel, bool $enabled): void
|
|
{
|
|
match ($channel) {
|
|
self::CHANNEL_PUSH => $this->push_enabled = $enabled,
|
|
self::CHANNEL_EMAIL => $this->email_enabled = $enabled,
|
|
self::CHANNEL_SMS => $this->sms_enabled = $enabled,
|
|
self::CHANNEL_IN_APP => $this->in_app_enabled = $enabled,
|
|
self::CHANNEL_KAKAO => $this->kakao_enabled = $enabled,
|
|
default => null,
|
|
};
|
|
}
|
|
}
|