where('tenant_id', $tenantId); })->count(); if ($existing > 0) { $this->command->info(' ⚠ payments: 이미 '.$existing.'건 존재 (스킵)'); return; } // 1. 요금제 생성 (없으면) $plans = $this->createPlans($userId); // 2. 구독 생성 $subscription = $this->createSubscription($tenantId, $plans['standard']->id, $userId); // 3. 결제 내역 생성 $paymentCount = $this->createPayments($subscription, $userId); $this->command->info(' ✓ plans: '.count($plans).'건 생성'); $this->command->info(' ✓ subscriptions: 1건 생성'); $this->command->info(' ✓ payments: '.$paymentCount.'건 생성'); } /** * 요금제 생성 */ private function createPlans(int $userId): array { $plansData = [ 'free' => [ 'name' => '무료 체험', 'code' => 'FREE', 'description' => '14일 무료 체험', 'price' => 0, 'billing_cycle' => Plan::BILLING_MONTHLY, 'features' => ['basic_features', 'limited_users'], 'is_active' => true, ], 'starter' => [ 'name' => '스타터', 'code' => 'STARTER', 'description' => '소규모 팀을 위한 기본 플랜', 'price' => 29000, 'billing_cycle' => Plan::BILLING_MONTHLY, 'features' => ['basic_features', 'email_support', 'up_to_5_users'], 'is_active' => true, ], 'standard' => [ 'name' => '스탠다드', 'code' => 'STANDARD', 'description' => '성장하는 팀을 위한 표준 플랜', 'price' => 79000, 'billing_cycle' => Plan::BILLING_MONTHLY, 'features' => ['all_features', 'priority_support', 'up_to_20_users', 'api_access'], 'is_active' => true, ], 'professional' => [ 'name' => '프로페셔널', 'code' => 'PRO', 'description' => '전문가 팀을 위한 고급 플랜', 'price' => 149000, 'billing_cycle' => Plan::BILLING_MONTHLY, 'features' => ['all_features', 'dedicated_support', 'unlimited_users', 'api_access', 'custom_integrations'], 'is_active' => true, ], 'enterprise' => [ 'name' => '엔터프라이즈', 'code' => 'ENTERPRISE', 'description' => '대기업 맞춤형 플랜', 'price' => 499000, 'billing_cycle' => Plan::BILLING_MONTHLY, 'features' => ['all_features', 'dedicated_support', 'unlimited_users', 'api_access', 'custom_integrations', 'sla', 'on_premise'], 'is_active' => true, ], 'yearly_standard' => [ 'name' => '스탠다드 (연간)', 'code' => 'STANDARD_YEARLY', 'description' => '연간 결제 시 20% 할인', 'price' => 758400, // 79000 * 12 * 0.8 'billing_cycle' => Plan::BILLING_YEARLY, 'features' => ['all_features', 'priority_support', 'up_to_20_users', 'api_access'], 'is_active' => true, ], ]; $plans = []; foreach ($plansData as $key => $data) { $plans[$key] = Plan::firstOrCreate( ['code' => $data['code']], array_merge($data, ['created_by' => $userId]) ); } return $plans; } /** * 구독 생성 */ private function createSubscription(int $tenantId, int $planId, int $userId): Subscription { // 기존 활성 구독이 있으면 반환 $existing = Subscription::where('tenant_id', $tenantId) ->where('status', Subscription::STATUS_ACTIVE) ->first(); if ($existing) { return $existing; } // 새 구독 생성 (12개월 전부터 시작) return Subscription::create([ 'tenant_id' => $tenantId, 'plan_id' => $planId, 'started_at' => now()->subMonths(12)->startOfMonth(), 'ended_at' => now()->addMonths(1)->endOfMonth(), 'status' => Subscription::STATUS_ACTIVE, 'created_by' => $userId, ]); } /** * 결제 내역 생성 */ private function createPayments(Subscription $subscription, int $userId): int { // 이미 결제 내역이 있으면 스킵 if ($subscription->payments()->count() > 0) { return 0; } $plan = $subscription->plan; $paymentMethods = [ Payment::METHOD_CARD, Payment::METHOD_CARD, Payment::METHOD_CARD, // 카드 60% Payment::METHOD_BANK, Payment::METHOD_BANK, // 계좌이체 30% Payment::METHOD_VIRTUAL, // 가상계좌 10% ]; $statuses = [ Payment::STATUS_COMPLETED, Payment::STATUS_COMPLETED, Payment::STATUS_COMPLETED, Payment::STATUS_COMPLETED, Payment::STATUS_COMPLETED, Payment::STATUS_COMPLETED, Payment::STATUS_COMPLETED, Payment::STATUS_COMPLETED, // 완료 80% Payment::STATUS_CANCELLED, // 취소 10% Payment::STATUS_REFUNDED, // 환불 10% ]; $count = 0; // 12개월치 결제 내역 생성 for ($i = 12; $i >= 0; $i--) { $paymentDate = now()->subMonths($i)->startOfMonth(); // 이번 달은 대기 상태로 $status = $i === 0 ? Payment::STATUS_PENDING : $statuses[array_rand($statuses)]; // 금액 변동 (할인, 프로모션 등) $baseAmount = $plan->price; $amount = match (true) { $i >= 10 => $baseAmount * 0.5, // 첫 3개월 50% 할인 $i >= 6 => $baseAmount * 0.8, // 다음 4개월 20% 할인 default => $baseAmount, // 이후 정가 }; // 취소/환불은 금액 0 if (in_array($status, [Payment::STATUS_CANCELLED, Payment::STATUS_REFUNDED])) { $amount = $baseAmount; } $paidAt = $status === Payment::STATUS_COMPLETED ? $paymentDate->copy()->addDays(rand(1, 5)) : null; $transactionId = $status === Payment::STATUS_COMPLETED ? 'TXN'.$paymentDate->format('Ymd').str_pad(rand(1, 9999), 4, '0', STR_PAD_LEFT) : null; $memo = match ($status) { Payment::STATUS_CANCELLED => '고객 요청에 의한 취소', Payment::STATUS_REFUNDED => '서비스 불만족으로 인한 환불', Payment::STATUS_PENDING => '결제 대기 중', default => null, }; Payment::create([ 'subscription_id' => $subscription->id, 'amount' => $amount, 'payment_method' => $paymentMethods[array_rand($paymentMethods)], 'transaction_id' => $transactionId, 'paid_at' => $paidAt, 'status' => $status, 'memo' => $memo, 'created_by' => $userId, 'created_at' => $paymentDate, ]); $count++; } return $count; } }