104 lines
3.0 KiB
PHP
104 lines
3.0 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace App\Console\Commands;
|
||
|
|
|
||
|
|
use App\Models\Tenants\Tenant;
|
||
|
|
use Illuminate\Console\Command;
|
||
|
|
use Illuminate\Support\Facades\DB;
|
||
|
|
use Illuminate\Support\Facades\Log;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 데모 테넌트 비활성 알림 커맨드
|
||
|
|
*
|
||
|
|
* - 7일 이상 활동 없는 데모 테넌트 탐지
|
||
|
|
* - 파트너에게 후속 조치 알림 로그
|
||
|
|
*
|
||
|
|
* 기존 코드 영향 없음: DEMO 테넌트만 대상
|
||
|
|
*
|
||
|
|
* @see docs/features/sales/demo-tenant-policy.md
|
||
|
|
*/
|
||
|
|
class CheckDemoInactiveCommand extends Command
|
||
|
|
{
|
||
|
|
protected $signature = 'demo:check-inactive
|
||
|
|
{--days=7 : 비활성 기준 일수}';
|
||
|
|
|
||
|
|
protected $description = '데모 테넌트 비활성 알림 (활동 없는 테넌트 탐지)';
|
||
|
|
|
||
|
|
public function handle(): int
|
||
|
|
{
|
||
|
|
$thresholdDays = (int) $this->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;
|
||
|
|
}
|
||
|
|
}
|