168 lines
4.7 KiB
PHP
168 lines
4.7 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace App\Services\Demo;
|
||
|
|
|
||
|
|
use App\Models\Tenants\Tenant;
|
||
|
|
use App\Services\Service;
|
||
|
|
use Illuminate\Support\Facades\Log;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 데모 테넌트 생성/관리 서비스
|
||
|
|
*
|
||
|
|
* 기존 코드 영향 없음: 데모 전용 로직만 포함
|
||
|
|
*
|
||
|
|
* @see docs/features/sales/demo-tenant-policy.md
|
||
|
|
*/
|
||
|
|
class DemoTenantService extends Service
|
||
|
|
{
|
||
|
|
/**
|
||
|
|
* 기본 데모 수량 제한
|
||
|
|
*/
|
||
|
|
private const DEFAULT_DEMO_LIMITS = [
|
||
|
|
'max_items' => 100,
|
||
|
|
'max_orders' => 50,
|
||
|
|
'max_productions' => 30,
|
||
|
|
'max_users' => 5,
|
||
|
|
'max_storage_gb' => 1,
|
||
|
|
'max_ai_tokens' => 100000,
|
||
|
|
];
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 사용 가능한 프리셋 목록
|
||
|
|
*/
|
||
|
|
private const AVAILABLE_PRESETS = [
|
||
|
|
'manufacturing', // 제조업 기본
|
||
|
|
// 향후 추가 예정:
|
||
|
|
// 'blinds', // 블라인드/스크린
|
||
|
|
// 'construction', // 시공/건설
|
||
|
|
// 'distribution', // 유통/도소매
|
||
|
|
];
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 파트너 데모 테넌트 생성 (Tier 2)
|
||
|
|
* 파트너 승인 시 호출
|
||
|
|
*/
|
||
|
|
public function createPartnerDemo(int $partnerId, string $preset = 'manufacturing'): Tenant
|
||
|
|
{
|
||
|
|
$tenant = new Tenant;
|
||
|
|
$tenant->forceFill([
|
||
|
|
'company_name' => '파트너데모_'.$partnerId,
|
||
|
|
'code' => 'DEMO_P_'.$partnerId,
|
||
|
|
'email' => 'demo-partner-'.$partnerId.'@codebridge-x.com',
|
||
|
|
'tenant_st_code' => 'active',
|
||
|
|
'tenant_type' => Tenant::TYPE_DEMO_PARTNER,
|
||
|
|
'demo_source_partner_id' => $partnerId,
|
||
|
|
'options' => [
|
||
|
|
Tenant::OPTION_DEMO_PRESET => $preset,
|
||
|
|
Tenant::OPTION_DEMO_LIMITS => self::DEFAULT_DEMO_LIMITS,
|
||
|
|
],
|
||
|
|
]);
|
||
|
|
$tenant->save();
|
||
|
|
|
||
|
|
Log::info('파트너 데모 테넌트 생성', [
|
||
|
|
'tenant_id' => $tenant->id,
|
||
|
|
'partner_id' => $partnerId,
|
||
|
|
'preset' => $preset,
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $tenant;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 고객 체험 테넌트 생성 (Tier 3)
|
||
|
|
* 파트너가 요청 → 본사 승인 후 호출
|
||
|
|
*/
|
||
|
|
public function createTrialDemo(
|
||
|
|
int $partnerId,
|
||
|
|
string $companyName,
|
||
|
|
string $email,
|
||
|
|
int $durationDays = 30,
|
||
|
|
string $preset = 'manufacturing'
|
||
|
|
): Tenant {
|
||
|
|
$tenant = new Tenant;
|
||
|
|
$tenant->forceFill([
|
||
|
|
'company_name' => $companyName,
|
||
|
|
'code' => 'DEMO_T_'.strtoupper(substr(md5(uniqid()), 0, 8)),
|
||
|
|
'email' => $email,
|
||
|
|
'tenant_st_code' => 'trial',
|
||
|
|
'tenant_type' => Tenant::TYPE_DEMO_TRIAL,
|
||
|
|
'demo_expires_at' => now()->addDays($durationDays),
|
||
|
|
'demo_source_partner_id' => $partnerId,
|
||
|
|
'options' => [
|
||
|
|
Tenant::OPTION_DEMO_PRESET => $preset,
|
||
|
|
Tenant::OPTION_DEMO_LIMITS => self::DEFAULT_DEMO_LIMITS,
|
||
|
|
],
|
||
|
|
]);
|
||
|
|
$tenant->save();
|
||
|
|
|
||
|
|
Log::info('고객 체험 테넌트 생성', [
|
||
|
|
'tenant_id' => $tenant->id,
|
||
|
|
'partner_id' => $partnerId,
|
||
|
|
'company_name' => $companyName,
|
||
|
|
'expires_at' => $tenant->demo_expires_at->toDateString(),
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $tenant;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 체험 기간 연장 (최대 1회, 30일)
|
||
|
|
*/
|
||
|
|
public function extendTrial(Tenant $tenant, int $days = 30): bool
|
||
|
|
{
|
||
|
|
if (! $tenant->isDemoTrial()) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 이미 연장한 이력이 있는지 체크 (options에 기록)
|
||
|
|
if ($tenant->getOption('demo_extended', false)) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
$newExpiry = ($tenant->demo_expires_at ?? now())->addDays($days);
|
||
|
|
$tenant->forceFill(['demo_expires_at' => $newExpiry]);
|
||
|
|
$tenant->setOption('demo_extended', true);
|
||
|
|
$tenant->save();
|
||
|
|
|
||
|
|
Log::info('고객 체험 기간 연장', [
|
||
|
|
'tenant_id' => $tenant->id,
|
||
|
|
'new_expires_at' => $newExpiry->toDateString(),
|
||
|
|
]);
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 데모 → 정식 전환
|
||
|
|
*/
|
||
|
|
public function convertToProduction(Tenant $tenant): void
|
||
|
|
{
|
||
|
|
$tenant->convertToProduction();
|
||
|
|
|
||
|
|
Log::info('데모 → 정식 테넌트 전환', [
|
||
|
|
'tenant_id' => $tenant->id,
|
||
|
|
'company_name' => $tenant->company_name,
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 사용 가능한 프리셋 목록
|
||
|
|
*/
|
||
|
|
public function getAvailablePresets(): array
|
||
|
|
{
|
||
|
|
return self::AVAILABLE_PRESETS;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 만료된 체험 테넌트 조회
|
||
|
|
*/
|
||
|
|
public function getExpiredTrials(): \Illuminate\Database\Eloquent\Collection
|
||
|
|
{
|
||
|
|
return Tenant::withoutGlobalScopes()
|
||
|
|
->where('tenant_type', Tenant::TYPE_DEMO_TRIAL)
|
||
|
|
->whereNotNull('demo_expires_at')
|
||
|
|
->where('demo_expires_at', '<', now())
|
||
|
|
->get();
|
||
|
|
}
|
||
|
|
}
|