- 저장소 사용량 표시 추가 (테이블 + 모달) - 이메일/전화번호 컬럼 병합 (연락처) - 전화번호 하이픈 포맷 적용 - 생성일 yymmdd 형식 변경 및 ID 뒤로 이동 - 테이블 헤더 가운데 정렬 - 액션 컬럼을 관리(colspan)로 변경
257 lines
6.5 KiB
PHP
257 lines
6.5 KiB
PHP
<?php
|
|
|
|
namespace App\Models\Tenants;
|
|
|
|
use App\Models\User;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
|
|
|
class Tenant extends Model
|
|
{
|
|
use SoftDeletes;
|
|
|
|
protected $table = 'tenants';
|
|
|
|
protected $fillable = [
|
|
// 기본 정보
|
|
'company_name',
|
|
'code',
|
|
'email',
|
|
'phone',
|
|
// 회사 정보
|
|
'business_num',
|
|
'corp_reg_no',
|
|
'ceo_name',
|
|
'address',
|
|
'homepage',
|
|
'fax',
|
|
// 구독 정보
|
|
'tenant_st_code',
|
|
'tenant_type',
|
|
'template_id',
|
|
'billing_tp_code',
|
|
'max_users',
|
|
'trial_ends_at',
|
|
'expires_at',
|
|
'last_paid_at',
|
|
// 관리 메모
|
|
'admin_memo',
|
|
// 삭제 정보
|
|
'deleted_by',
|
|
];
|
|
|
|
protected $casts = [
|
|
'max_users' => 'integer',
|
|
'storage_limit' => 'integer',
|
|
'storage_used' => 'integer',
|
|
'trial_ends_at' => 'datetime',
|
|
'expires_at' => 'datetime',
|
|
'last_paid_at' => 'datetime',
|
|
'storage_warning_sent_at' => 'datetime',
|
|
'storage_grace_period_until' => 'datetime',
|
|
'created_at' => 'datetime',
|
|
'updated_at' => 'datetime',
|
|
'deleted_at' => 'datetime',
|
|
];
|
|
|
|
/**
|
|
* 활성 테넌트만 조회 (삭제되지 않은 모든 테넌트)
|
|
*/
|
|
public function scopeActive($query)
|
|
{
|
|
return $query->whereNull('deleted_at');
|
|
}
|
|
|
|
/**
|
|
* 관계: 사용자 (Many-to-Many via user_tenants)
|
|
*/
|
|
public function users(): BelongsToMany
|
|
{
|
|
return $this->belongsToMany(User::class, 'user_tenants');
|
|
}
|
|
|
|
/**
|
|
* 관계: 부서
|
|
*/
|
|
public function departments(): HasMany
|
|
{
|
|
return $this->hasMany(\App\Models\Tenants\Department::class, 'tenant_id');
|
|
}
|
|
|
|
/**
|
|
* 관계: 메뉴
|
|
*/
|
|
public function menus(): HasMany
|
|
{
|
|
return $this->hasMany(\App\Models\Commons\Menu::class, 'tenant_id');
|
|
}
|
|
|
|
/**
|
|
* 관계: 역할
|
|
*/
|
|
public function roles(): HasMany
|
|
{
|
|
return $this->hasMany(\App\Models\Permissions\Role::class, 'tenant_id');
|
|
}
|
|
|
|
/**
|
|
* 관계: 삭제한 사용자
|
|
*/
|
|
public function deletedByUser(): \Illuminate\Database\Eloquent\Relations\BelongsTo
|
|
{
|
|
return $this->belongsTo(User::class, 'deleted_by');
|
|
}
|
|
|
|
/**
|
|
* 상태 배지 색상 (Blade 뷰에서 사용)
|
|
*/
|
|
public function getStatusBadgeColorAttribute(): string
|
|
{
|
|
return match ($this->tenant_st_code) {
|
|
'active' => 'success',
|
|
'trial' => 'warning',
|
|
'suspended', 'expired' => 'error',
|
|
default => 'neutral',
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 상태 한글명 (Blade 뷰에서 사용)
|
|
*/
|
|
public function getStatusLabelAttribute(): string
|
|
{
|
|
return match ($this->tenant_st_code) {
|
|
'trial' => '트라이얼',
|
|
'active' => '활성',
|
|
'suspended' => '정지',
|
|
'expired' => '만료',
|
|
default => $this->tenant_st_code ?? '미설정',
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 결제 유형 한글명 (Blade 뷰에서 사용)
|
|
*/
|
|
public function getBillingTypeLabelAttribute(): ?string
|
|
{
|
|
if (! $this->billing_tp_code) {
|
|
return null;
|
|
}
|
|
|
|
return match ($this->billing_tp_code) {
|
|
'monthly' => '월간',
|
|
'yearly' => '연간',
|
|
'free' => '무료',
|
|
default => $this->billing_tp_code,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 저장소 사용률 (%) - Blade 뷰에서 사용
|
|
*/
|
|
public function getStorageUsagePercentAttribute(): float
|
|
{
|
|
$limit = $this->storage_limit ?? 10737418240; // 기본 10GB
|
|
if ($limit <= 0) {
|
|
return 0;
|
|
}
|
|
|
|
return round(($this->storage_used ?? 0) / $limit * 100, 1);
|
|
}
|
|
|
|
/**
|
|
* 저장소 사용량 포맷 (예: "2.5 GB / 10 GB")
|
|
*/
|
|
public function getStorageUsageFormattedAttribute(): string
|
|
{
|
|
$used = $this->formatBytes($this->storage_used ?? 0);
|
|
$limit = $this->formatBytes($this->storage_limit ?? 10737418240);
|
|
|
|
return "{$used} / {$limit}";
|
|
}
|
|
|
|
/**
|
|
* 저장소 사용량만 포맷 (예: "2.5 GB")
|
|
*/
|
|
public function getStorageUsedFormattedAttribute(): string
|
|
{
|
|
return $this->formatBytes($this->storage_used ?? 0);
|
|
}
|
|
|
|
/**
|
|
* 저장소 한도만 포맷 (예: "10 GB")
|
|
*/
|
|
public function getStorageLimitFormattedAttribute(): string
|
|
{
|
|
return $this->formatBytes($this->storage_limit ?? 10737418240);
|
|
}
|
|
|
|
/**
|
|
* 저장소 상태 배지 색상 (Blade 뷰에서 사용)
|
|
*/
|
|
public function getStorageBadgeColorAttribute(): string
|
|
{
|
|
$percent = $this->storage_usage_percent;
|
|
|
|
return match (true) {
|
|
$percent >= 90 => 'error',
|
|
$percent >= 70 => 'warning',
|
|
default => 'success',
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 바이트를 읽기 쉬운 형식으로 변환
|
|
*/
|
|
protected function formatBytes(int $bytes): string
|
|
{
|
|
if ($bytes <= 0) {
|
|
return '0 B';
|
|
}
|
|
|
|
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
$factor = floor(log($bytes, 1024));
|
|
$factor = min($factor, count($units) - 1);
|
|
|
|
return round($bytes / pow(1024, $factor), 1).' '.$units[$factor];
|
|
}
|
|
|
|
/**
|
|
* 전화번호 포맷 (하이픈 추가)
|
|
*/
|
|
public function getPhoneFormattedAttribute(): ?string
|
|
{
|
|
if (! $this->phone) {
|
|
return null;
|
|
}
|
|
|
|
// 숫자만 추출
|
|
$numbers = preg_replace('/[^0-9]/', '', $this->phone);
|
|
|
|
// 휴대폰 (010, 011, 016, 017, 018, 019)
|
|
if (preg_match('/^(01[0-9])(\d{3,4})(\d{4})$/', $numbers, $matches)) {
|
|
return $matches[1].'-'.$matches[2].'-'.$matches[3];
|
|
}
|
|
|
|
// 서울 (02)
|
|
if (preg_match('/^(02)(\d{3,4})(\d{4})$/', $numbers, $matches)) {
|
|
return $matches[1].'-'.$matches[2].'-'.$matches[3];
|
|
}
|
|
|
|
// 지역번호 (031, 032, ...)
|
|
if (preg_match('/^(0\d{2})(\d{3,4})(\d{4})$/', $numbers, $matches)) {
|
|
return $matches[1].'-'.$matches[2].'-'.$matches[3];
|
|
}
|
|
|
|
// 대표번호 (1588, 1544, ...)
|
|
if (preg_match('/^(1\d{3})(\d{4})$/', $numbers, $matches)) {
|
|
return $matches[1].'-'.$matches[2];
|
|
}
|
|
|
|
// 포맷 불가 시 원본 반환
|
|
return $this->phone;
|
|
}
|
|
}
|