command->info(''); $this->command->info('📋 결재 데이터 생성...'); // 해당 테넌트의 사용자 ID 가져오기 $users = DB::table('user_tenants') ->where('tenant_id', $tenantId) ->pluck('user_id') ->toArray(); if (count($users) < 3) { $this->command->error('최소 3명의 사용자가 필요합니다.'); return; } $mainUser = $users[0]; // 기안자 겸 참조 대상 $approver1 = $users[1] ?? $users[0]; $approver2 = $users[2] ?? $users[0]; // 1. 결재 양식 생성 $this->command->info('결재 양식 생성 중...'); $forms = $this->createApprovalForms($tenantId, $mainUser, $now); // 2. 결재 문서 생성 $this->command->info('결재 문서 생성 중...'); $this->createApprovals($tenantId, $forms, $mainUser, $approver1, $approver2, $now); $this->command->info('✅ 결재 테스트 데이터 생성 완료!'); $this->command->info(' - 기안함: 15건'); $this->command->info(' - 결재함: 15건'); $this->command->info(' - 참조함: 10건'); } private function createApprovalForms(int $tenantId, int $userId, Carbon $now): array { $forms = [ [ 'tenant_id' => $tenantId, 'name' => '품의서', 'code' => 'proposal', 'category' => '일반', 'template' => json_encode([ 'fields' => [ ['name' => 'title', 'type' => 'text', 'label' => '제목', 'required' => true], ['name' => 'vendor', 'type' => 'text', 'label' => '거래처', 'required' => false], ['name' => 'description', 'type' => 'textarea', 'label' => '내용', 'required' => true], ['name' => 'reason', 'type' => 'textarea', 'label' => '사유', 'required' => true], ['name' => 'estimatedCost', 'type' => 'number', 'label' => '예상비용', 'required' => false], ] ]), 'is_active' => true, 'created_by' => $userId, 'created_at' => $now, 'updated_at' => $now, ], [ 'tenant_id' => $tenantId, 'name' => '지출결의서', 'code' => 'expenseReport', 'category' => '경비', 'template' => json_encode([ 'fields' => [ ['name' => 'requestDate', 'type' => 'date', 'label' => '신청일', 'required' => true], ['name' => 'paymentDate', 'type' => 'date', 'label' => '지급일', 'required' => true], ['name' => 'items', 'type' => 'array', 'label' => '지출항목', 'required' => true], ['name' => 'totalAmount', 'type' => 'number', 'label' => '총액', 'required' => true], ] ]), 'is_active' => true, 'created_by' => $userId, 'created_at' => $now, 'updated_at' => $now, ], [ 'tenant_id' => $tenantId, 'name' => '비용견적서', 'code' => 'expenseEstimate', 'category' => '경비', 'template' => json_encode([ 'fields' => [ ['name' => 'items', 'type' => 'array', 'label' => '비용항목', 'required' => true], ['name' => 'totalExpense', 'type' => 'number', 'label' => '총지출', 'required' => true], ['name' => 'accountBalance', 'type' => 'number', 'label' => '계좌잔액', 'required' => true], ] ]), 'is_active' => true, 'created_by' => $userId, 'created_at' => $now, 'updated_at' => $now, ], ]; $formIds = []; foreach ($forms as $form) { // 기존 양식 확인 $existing = DB::table('approval_forms') ->where('tenant_id', $tenantId) ->where('code', $form['code']) ->first(); if ($existing) { $formIds[$form['code']] = $existing->id; } else { $formIds[$form['code']] = DB::table('approval_forms')->insertGetId($form); } } return $formIds; } private function createApprovals( int $tenantId, array $forms, int $mainUser, int $approver1, int $approver2, Carbon $now ): void { $proposalTitles = [ '신규 장비 구매 품의', '사무용품 구매 요청', '소프트웨어 라이선스 갱신', '출장 경비 지원 요청', '교육 프로그램 신청', '복지시설 개선 제안', '마케팅 예산 증액 품의', '시스템 업그레이드 제안', '인력 충원 요청', '사무실 이전 품의', '연구개발 예산 신청', '고객 세미나 개최 품의', '협력업체 계약 갱신', '보안 시스템 도입 품의', '업무 차량 구매 요청', ]; $expenseItems = [ '교통비', '식비', '숙박비', '소모품비', '통신비', '유류비', '접대비', '회의비' ]; $vendors = [ '삼성전자', 'LG전자', 'SK하이닉스', '현대자동차', '네이버', '카카오', '쿠팡', '배달의민족', '토스', '당근마켓' ]; $docNumber = 1; // 기안함용 문서 15건 (mainUser가 기안자) for ($i = 0; $i < 15; $i++) { $status = $i < 5 ? 'draft' : 'pending'; $formCode = ['proposal', 'expenseReport', 'expenseEstimate'][$i % 3]; $formId = $forms[$formCode]; $content = $this->generateContent($formCode, $proposalTitles[$i], $vendors, $expenseItems); $approvalId = DB::table('approvals')->insertGetId([ 'tenant_id' => $tenantId, 'document_number' => sprintf('DOC-%s-%04d', $now->format('Ymd'), $docNumber++), 'form_id' => $formId, 'title' => $proposalTitles[$i], 'content' => json_encode($content), 'status' => $status, 'drafter_id' => $mainUser, 'drafted_at' => $status === 'pending' ? $now->copy()->subDays(rand(1, 10)) : null, 'current_step' => $status === 'pending' ? 1 : 0, 'created_by' => $mainUser, 'created_at' => $now->copy()->subDays(rand(1, 15)), 'updated_at' => $now, ]); // 결재선 추가 (pending 상태인 경우) if ($status === 'pending') { // 결재자 1 (approver1이 결재 대기) DB::table('approval_steps')->insert([ 'approval_id' => $approvalId, 'step_order' => 1, 'step_type' => 'approval', 'approver_id' => $approver1, 'status' => 'pending', 'created_at' => $now, 'updated_at' => $now, ]); // 결재자 2 DB::table('approval_steps')->insert([ 'approval_id' => $approvalId, 'step_order' => 2, 'step_type' => 'approval', 'approver_id' => $approver2, 'status' => 'pending', 'created_at' => $now, 'updated_at' => $now, ]); // 참조 (mainUser에게 참조) if ($i < 10) { DB::table('approval_steps')->insert([ 'approval_id' => $approvalId, 'step_order' => 3, 'step_type' => 'reference', 'approver_id' => $mainUser, 'status' => 'pending', 'is_read' => false, 'created_at' => $now, 'updated_at' => $now, ]); } } } // 결재함용 추가 문서 (approver1/approver2가 기안, mainUser가 결재자) for ($i = 0; $i < 5; $i++) { $formCode = ['proposal', 'expenseReport'][$i % 2]; $formId = $forms[$formCode]; $drafter = $i < 3 ? $approver1 : $approver2; $title = '추가 결재 요청 문서 ' . ($i + 1); $content = $this->generateContent($formCode, $title, $vendors, $expenseItems); $approvalId = DB::table('approvals')->insertGetId([ 'tenant_id' => $tenantId, 'document_number' => sprintf('DOC-%s-%04d', $now->format('Ymd'), $docNumber++), 'form_id' => $formId, 'title' => $title, 'content' => json_encode($content), 'status' => 'pending', 'drafter_id' => $drafter, 'drafted_at' => $now->copy()->subDays(rand(1, 5)), 'current_step' => 1, 'created_by' => $drafter, 'created_at' => $now->copy()->subDays(rand(1, 10)), 'updated_at' => $now, ]); // mainUser가 결재자 DB::table('approval_steps')->insert([ 'approval_id' => $approvalId, 'step_order' => 1, 'step_type' => 'approval', 'approver_id' => $mainUser, 'status' => 'pending', 'created_at' => $now, 'updated_at' => $now, ]); } } private function generateContent(string $formCode, string $title, array $vendors, array $expenseItems): array { switch ($formCode) { case 'proposal': return [ 'title' => $title, 'vendor' => $vendors[array_rand($vendors)], 'vendorPaymentDate' => Carbon::now()->addDays(rand(7, 30))->format('Y-m-d'), 'description' => $title . '에 대한 상세 설명입니다. 업무 효율성 향상과 비용 절감을 위해 필요합니다.', 'reason' => '업무 효율성 향상 및 경쟁력 강화를 위해 필수적으로 진행해야 합니다.', 'estimatedCost' => rand(100, 5000) * 10000, ]; case 'expenseReport': $items = []; $total = 0; for ($j = 0; $j < rand(2, 5); $j++) { $amount = rand(10, 200) * 1000; $total += $amount; $items[] = [ 'id' => (string) ($j + 1), 'description' => $expenseItems[array_rand($expenseItems)], 'amount' => $amount, 'note' => '업무 관련 지출', ]; } return [ 'requestDate' => Carbon::now()->subDays(rand(1, 7))->format('Y-m-d'), 'paymentDate' => Carbon::now()->addDays(rand(1, 14))->format('Y-m-d'), 'items' => $items, 'cardId' => 'CARD-' . rand(1000, 9999), 'totalAmount' => $total, ]; case 'expenseEstimate': $items = []; $total = 0; for ($j = 0; $j < rand(3, 8); $j++) { $amount = rand(50, 500) * 10000; $total += $amount; $items[] = [ 'id' => (string) ($j + 1), 'expectedPaymentDate' => Carbon::now()->addDays(rand(1, 60))->format('Y-m-d'), 'category' => $expenseItems[array_rand($expenseItems)], 'amount' => $amount, 'vendor' => $vendors[array_rand($vendors)], 'memo' => '예정 지출', 'checked' => false, ]; } return [ 'items' => $items, 'totalExpense' => $total, 'accountBalance' => rand(5000, 20000) * 10000, 'finalDifference' => rand(5000, 20000) * 10000 - $total, ]; default: return []; } } }