From 53cd04f6fac9cc5a939edf098c1fe420e53c8f39 Mon Sep 17 00:00:00 2001 From: pro Date: Mon, 26 Jan 2026 12:43:49 +0900 Subject: [PATCH] =?UTF-8?q?feat:=EC=98=81=EC=97=85=EA=B4=80=EB=A6=AC=20?= =?UTF-8?q?=EB=A7=88=EC=9D=B4=EA=B7=B8=EB=A0=88=EC=9D=B4=EC=85=98=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MNG에서 이동: - sales_managers 테이블 - sales_prospects 테이블 - sales_prospect_products 테이블 - sales_prospect_scenarios 테이블 - sales_prospect_consultations 테이블 - sales_records 테이블 Co-Authored-By: Claude Opus 4.5 --- ..._26_010000_create_sales_managers_table.php | 41 ++++++++++++++++++ ...26_010100_create_sales_prospects_table.php | 42 ++++++++++++++++++ ...0_create_sales_prospect_products_table.php | 43 +++++++++++++++++++ ..._create_sales_prospect_scenarios_table.php | 35 +++++++++++++++ ...ate_sales_prospect_consultations_table.php | 40 +++++++++++++++++ ...1_26_010500_create_sales_records_table.php | 41 ++++++++++++++++++ 6 files changed, 242 insertions(+) create mode 100644 database/migrations/2026_01_26_010000_create_sales_managers_table.php create mode 100644 database/migrations/2026_01_26_010100_create_sales_prospects_table.php create mode 100644 database/migrations/2026_01_26_010200_create_sales_prospect_products_table.php create mode 100644 database/migrations/2026_01_26_010300_create_sales_prospect_scenarios_table.php create mode 100644 database/migrations/2026_01_26_010400_create_sales_prospect_consultations_table.php create mode 100644 database/migrations/2026_01_26_010500_create_sales_records_table.php diff --git a/database/migrations/2026_01_26_010000_create_sales_managers_table.php b/database/migrations/2026_01_26_010000_create_sales_managers_table.php new file mode 100644 index 0000000..ea1d55b --- /dev/null +++ b/database/migrations/2026_01_26_010000_create_sales_managers_table.php @@ -0,0 +1,41 @@ +id(); + $table->string('member_id', 50)->unique()->comment('로그인 ID'); + $table->string('password', 255)->comment('비밀번호'); + $table->string('name', 100)->comment('성명'); + $table->string('phone', 20)->nullable()->comment('전화번호'); + $table->string('email', 100)->nullable()->comment('이메일'); + $table->foreignId('parent_id')->nullable()->comment('상위 관리자 ID'); + $table->enum('role', ['operator', 'sales_admin', 'manager'])->default('manager')->comment('역할'); + $table->text('remarks')->nullable()->comment('비고'); + $table->boolean('is_active')->default(true)->comment('활성화 여부'); + $table->timestamps(); + $table->softDeletes(); + + $table->index('parent_id'); + $table->index('role'); + $table->index('is_active'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('sales_managers'); + } +}; diff --git a/database/migrations/2026_01_26_010100_create_sales_prospects_table.php b/database/migrations/2026_01_26_010100_create_sales_prospects_table.php new file mode 100644 index 0000000..b5afc86 --- /dev/null +++ b/database/migrations/2026_01_26_010100_create_sales_prospects_table.php @@ -0,0 +1,42 @@ +id(); + $table->foreignId('manager_id')->constrained('sales_managers')->cascadeOnDelete()->comment('영업한 영업파트너 ID'); + $table->foreignId('sales_manager_id')->nullable()->constrained('sales_managers')->nullOnDelete()->comment('매칭된 매니저 ID'); + $table->string('company_name', 200)->comment('업체명'); + $table->string('representative', 100)->nullable()->comment('대표자명'); + $table->string('business_no', 20)->nullable()->comment('사업자번호'); + $table->string('contact_phone', 20)->nullable()->comment('연락처'); + $table->string('email', 100)->nullable()->comment('이메일'); + $table->string('address', 500)->nullable()->comment('주소'); + $table->enum('status', ['lead', 'prospect', 'negotiation', 'contracted', 'lost'])->default('lead')->comment('상태'); + $table->timestamps(); + $table->softDeletes(); + + $table->index('manager_id'); + $table->index('sales_manager_id'); + $table->index('status'); + $table->index('business_no'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('sales_prospects'); + } +}; diff --git a/database/migrations/2026_01_26_010200_create_sales_prospect_products_table.php b/database/migrations/2026_01_26_010200_create_sales_prospect_products_table.php new file mode 100644 index 0000000..3a67f33 --- /dev/null +++ b/database/migrations/2026_01_26_010200_create_sales_prospect_products_table.php @@ -0,0 +1,43 @@ +id(); + $table->foreignId('prospect_id')->constrained('sales_prospects')->cascadeOnDelete(); + $table->string('product_name', 200)->comment('상품명'); + $table->decimal('contract_amount', 15, 2)->default(0)->comment('계약금액'); + $table->decimal('subscription_fee', 15, 2)->default(0)->comment('구독료'); + $table->decimal('commission_rate', 5, 2)->default(20)->comment('수수료율'); + $table->decimal('commission_amount', 15, 2)->default(0)->comment('수수료'); + $table->date('contract_date')->nullable()->comment('계약일'); + $table->boolean('join_approved')->default(false)->comment('가입 승인 여부'); + $table->boolean('payment_approved')->default(false)->comment('결제 승인 여부'); + $table->decimal('payout_rate', 5, 2)->default(0)->comment('지급율'); + $table->decimal('payout_amount', 15, 2)->default(0)->comment('지급금액'); + $table->json('sub_models')->nullable()->comment('선택모델 목록'); + $table->timestamps(); + $table->softDeletes(); + + $table->index('prospect_id'); + $table->index('contract_date'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('sales_prospect_products'); + } +}; diff --git a/database/migrations/2026_01_26_010300_create_sales_prospect_scenarios_table.php b/database/migrations/2026_01_26_010300_create_sales_prospect_scenarios_table.php new file mode 100644 index 0000000..ee8fdab --- /dev/null +++ b/database/migrations/2026_01_26_010300_create_sales_prospect_scenarios_table.php @@ -0,0 +1,35 @@ +id(); + $table->foreignId('prospect_id')->constrained('sales_prospects')->cascadeOnDelete(); + $table->enum('scenario_type', ['sales', 'manager'])->default('manager')->comment('시나리오 유형'); + $table->unsignedInteger('step_id')->comment('단계 ID'); + $table->unsignedInteger('checkpoint_index')->comment('체크포인트 인덱스'); + $table->boolean('is_checked')->default(false)->comment('체크 여부'); + $table->timestamps(); + + $table->unique(['prospect_id', 'scenario_type', 'step_id', 'checkpoint_index'], 'unique_prospect_scenario_step'); + $table->index('prospect_id'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('sales_prospect_scenarios'); + } +}; diff --git a/database/migrations/2026_01_26_010400_create_sales_prospect_consultations_table.php b/database/migrations/2026_01_26_010400_create_sales_prospect_consultations_table.php new file mode 100644 index 0000000..8f7763b --- /dev/null +++ b/database/migrations/2026_01_26_010400_create_sales_prospect_consultations_table.php @@ -0,0 +1,40 @@ +id(); + $table->foreignId('prospect_id')->constrained('sales_prospects')->cascadeOnDelete(); + $table->foreignId('manager_id')->constrained('sales_managers')->cascadeOnDelete(); + $table->enum('scenario_type', ['sales', 'manager'])->default('manager')->comment('시나리오 유형'); + $table->unsignedInteger('step_id')->nullable()->comment('단계 ID'); + $table->text('log_text')->comment('상담 내용'); + $table->string('audio_file_path', 500)->nullable()->comment('음성 파일 경로'); + $table->json('attachment_paths')->nullable()->comment('첨부파일 경로 목록'); + $table->enum('consultation_type', ['text', 'audio', 'file'])->default('text')->comment('상담 유형'); + $table->timestamps(); + $table->softDeletes(); + + $table->index('prospect_id'); + $table->index('manager_id'); + $table->index('scenario_type'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('sales_prospect_consultations'); + } +}; diff --git a/database/migrations/2026_01_26_010500_create_sales_records_table.php b/database/migrations/2026_01_26_010500_create_sales_records_table.php new file mode 100644 index 0000000..f30d133 --- /dev/null +++ b/database/migrations/2026_01_26_010500_create_sales_records_table.php @@ -0,0 +1,41 @@ +id(); + $table->foreignId('manager_id')->constrained('sales_managers')->cascadeOnDelete()->comment('담당자 ID'); + $table->foreignId('prospect_id')->nullable()->constrained('sales_prospects')->nullOnDelete()->comment('가망고객 ID'); + $table->date('record_date')->comment('실적 일자'); + $table->string('record_type', 50)->comment('실적 유형'); + $table->decimal('amount', 15, 2)->default(0)->comment('실적 금액'); + $table->decimal('commission', 15, 2)->default(0)->comment('수수료'); + $table->text('description')->nullable()->comment('설명'); + $table->enum('status', ['pending', 'approved', 'rejected', 'paid'])->default('pending')->comment('상태'); + $table->timestamps(); + $table->softDeletes(); + + $table->index('manager_id'); + $table->index('prospect_id'); + $table->index('record_date'); + $table->index('status'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('sales_records'); + } +};