option('days'); $demos = Tenant::withoutGlobalScopes() ->whereIn('tenant_type', Tenant::DEMO_TYPES) ->where('tenant_st_code', '!=', 'expired') ->get(); if ($demos->isEmpty()) { $this->info('활성 데모 테넌트 없음'); return self::SUCCESS; } $inactiveCount = 0; foreach ($demos as $tenant) { $lastActivity = $this->getLastActivity($tenant->id); if (! $lastActivity) { continue; } $daysSince = (int) now()->diffInDays($lastActivity); if ($daysSince < $thresholdDays) { continue; } $inactiveCount++; $this->line(" - [{$tenant->id}] {$tenant->company_name} ({$daysSince}일 비활성)"); Log::warning('데모 테넌트 비활성 알림', [ 'tenant_id' => $tenant->id, 'company_name' => $tenant->company_name, 'tenant_type' => $tenant->tenant_type, 'days_inactive' => $daysSince, 'last_activity' => $lastActivity->toDateString(), 'partner_id' => $tenant->demo_source_partner_id, ]); } if ($inactiveCount === 0) { $this->info("비활성 테넌트 없음 (기준: {$thresholdDays}일)"); } else { $this->info("비활성 테넌트: {$inactiveCount}건 (기준: {$thresholdDays}일)"); } return self::SUCCESS; } private function getLastActivity(int $tenantId): ?\Carbon\Carbon { $tables = ['orders', 'quotes', 'items', 'clients']; $latest = null; foreach ($tables as $table) { if (! \Schema::hasTable($table) || ! \Schema::hasColumn($table, 'tenant_id')) { continue; } $date = DB::table($table) ->where('tenant_id', $tenantId) ->max('updated_at'); if ($date) { $parsed = \Carbon\Carbon::parse($date); if (! $latest || $parsed->gt($latest)) { $latest = $parsed; } } } return $latest; } }