- DemoTenantController: 목록/상세/생성/리셋/연장/전환/통계 API - DemoTenantStoreRequest: 고객 체험 테넌트 생성 검증 - DemoTenantService: API용 메서드 추가 (index/show/reset/extend/convert/stats) - CheckDemoExpiredCommand: 만료 임박(7일) 알림 + 만료 테넌트 비활성 처리 - 라우트 등록 (api/v1/demo-tenants, 7개 엔드포인트) - 스케줄러 등록 (04:20 demo:check-expired) - i18n 메시지 추가 (message.demo_tenant.*, error.demo_tenant.*)
93 lines
3.2 KiB
PHP
93 lines
3.2 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\Tenants\Tenant;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
/**
|
|
* 데모 테넌트 만료 체크 및 알림 커맨드
|
|
*
|
|
* - 만료 임박 (7일 이내): 파트너에게 알림 로그
|
|
* - 만료된 테넌트: 비활성 상태로 전환
|
|
*
|
|
* 기존 코드 영향 없음: DEMO_TRIAL 테넌트만 대상
|
|
*
|
|
* @see docs/features/sales/demo-tenant-policy.md
|
|
*/
|
|
class CheckDemoExpiredCommand extends Command
|
|
{
|
|
protected $signature = 'demo:check-expired
|
|
{--dry-run : 실제 변경 없이 대상만 표시}';
|
|
|
|
protected $description = '데모 체험 테넌트 만료 체크 및 비활성 처리';
|
|
|
|
public function handle(): int
|
|
{
|
|
// 1. 만료 임박 테넌트 (7일 이내)
|
|
$expiringSoon = Tenant::withoutGlobalScopes()
|
|
->where('tenant_type', Tenant::TYPE_DEMO_TRIAL)
|
|
->where('tenant_st_code', '!=', 'expired')
|
|
->whereNotNull('demo_expires_at')
|
|
->where('demo_expires_at', '>', now())
|
|
->where('demo_expires_at', '<=', now()->addDays(7))
|
|
->get();
|
|
|
|
if ($expiringSoon->isNotEmpty()) {
|
|
$this->info("만료 임박 테넌트: {$expiringSoon->count()}건");
|
|
foreach ($expiringSoon as $tenant) {
|
|
$daysLeft = (int) now()->diffInDays($tenant->demo_expires_at, false);
|
|
$this->line(" - [{$tenant->id}] {$tenant->company_name} (D-{$daysLeft})");
|
|
|
|
Log::info('데모 체험 만료 임박', [
|
|
'tenant_id' => $tenant->id,
|
|
'company_name' => $tenant->company_name,
|
|
'expires_at' => $tenant->demo_expires_at->toDateString(),
|
|
'days_left' => $daysLeft,
|
|
'partner_id' => $tenant->demo_source_partner_id,
|
|
]);
|
|
}
|
|
}
|
|
|
|
// 2. 이미 만료된 테넌트 → 상태 변경
|
|
$expired = Tenant::withoutGlobalScopes()
|
|
->where('tenant_type', Tenant::TYPE_DEMO_TRIAL)
|
|
->where('tenant_st_code', '!=', 'expired')
|
|
->whereNotNull('demo_expires_at')
|
|
->where('demo_expires_at', '<', now())
|
|
->get();
|
|
|
|
if ($expired->isEmpty()) {
|
|
$this->info('만료 처리 대상 없음');
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
$this->info("만료 처리 대상: {$expired->count()}건");
|
|
|
|
foreach ($expired as $tenant) {
|
|
$this->line(" - [{$tenant->id}] {$tenant->company_name} (만료: {$tenant->demo_expires_at->toDateString()})");
|
|
|
|
if (! $this->option('dry-run')) {
|
|
$tenant->forceFill(['tenant_st_code' => 'expired']);
|
|
$tenant->save();
|
|
|
|
Log::info('데모 체험 만료 처리', [
|
|
'tenant_id' => $tenant->id,
|
|
'company_name' => $tenant->company_name,
|
|
'partner_id' => $tenant->demo_source_partner_id,
|
|
]);
|
|
}
|
|
}
|
|
|
|
if ($this->option('dry-run')) {
|
|
$this->warn('(dry-run 모드 — 실제 변경 없음)');
|
|
} else {
|
|
$this->info(" {$expired->count()}건 만료 처리 완료");
|
|
}
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
}
|