Files
sam-manage/app/Http/Controllers/Sales/SalesScenarioController.php
pro 2f381b2285 feat:레거시 영업관리 시스템 MNG 마이그레이션
- 영업/매니저 시나리오 모달 구현 (6단계 체크리스트)
- 상담 기록 기능 (텍스트, 음성, 첨부파일)
- 음성 녹음 + Speech-to-Text 변환
- 첨부파일 Drag & Drop 업로드
- 매니저 지정 드롭다운

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 21:45:11 +09:00

213 lines
6.7 KiB
PHP

<?php
namespace App\Http\Controllers\Sales;
use App\Http\Controllers\Controller;
use App\Models\Tenants\Tenant;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\View\View;
/**
* 영업 시나리오 관리 컨트롤러
*
* 영업 진행 및 매니저 상담 프로세스의 시나리오 모달과 체크리스트를 관리합니다.
*/
class SalesScenarioController extends Controller
{
/**
* 영업 시나리오 모달 뷰
*/
public function salesScenario(int $tenantId, Request $request): View|Response
{
$tenant = Tenant::findOrFail($tenantId);
$steps = config('sales_scenario.sales_steps');
$currentStep = (int) $request->input('step', 1);
$icons = config('sales_scenario.icons');
// 체크리스트 진행 상태 조회
$progress = $this->getChecklistProgress($tenantId, 'sales');
// HTMX 요청이면 단계 콘텐츠만 반환
if ($request->header('HX-Request') && $request->has('step')) {
return view('sales.modals.scenario-step', [
'tenant' => $tenant,
'steps' => $steps,
'currentStep' => $currentStep,
'step' => collect($steps)->firstWhere('id', $currentStep),
'progress' => $progress,
'scenarioType' => 'sales',
'icons' => $icons,
]);
}
return view('sales.modals.scenario-modal', [
'tenant' => $tenant,
'steps' => $steps,
'currentStep' => $currentStep,
'progress' => $progress,
'scenarioType' => 'sales',
'icons' => $icons,
]);
}
/**
* 매니저 시나리오 모달 뷰
*/
public function managerScenario(int $tenantId, Request $request): View|Response
{
$tenant = Tenant::findOrFail($tenantId);
$steps = config('sales_scenario.manager_steps');
$currentStep = (int) $request->input('step', 1);
$icons = config('sales_scenario.icons');
// 체크리스트 진행 상태 조회
$progress = $this->getChecklistProgress($tenantId, 'manager');
// HTMX 요청이면 단계 콘텐츠만 반환
if ($request->header('HX-Request') && $request->has('step')) {
return view('sales.modals.scenario-step', [
'tenant' => $tenant,
'steps' => $steps,
'currentStep' => $currentStep,
'step' => collect($steps)->firstWhere('id', $currentStep),
'progress' => $progress,
'scenarioType' => 'manager',
'icons' => $icons,
]);
}
return view('sales.modals.scenario-modal', [
'tenant' => $tenant,
'steps' => $steps,
'currentStep' => $currentStep,
'progress' => $progress,
'scenarioType' => 'manager',
'icons' => $icons,
]);
}
/**
* 체크리스트 항목 토글 (HTMX)
*/
public function toggleChecklist(Request $request): Response
{
$request->validate([
'tenant_id' => 'required|integer|exists:tenants,id',
'scenario_type' => 'required|in:sales,manager',
'step_id' => 'required|integer',
'checkpoint_id' => 'required|string',
'checked' => 'required|boolean',
]);
$tenantId = $request->input('tenant_id');
$scenarioType = $request->input('scenario_type');
$stepId = $request->input('step_id');
$checkpointId = $request->input('checkpoint_id');
$checked = $request->boolean('checked');
// 캐시 키 생성
$cacheKey = "scenario_checklist:{$tenantId}:{$scenarioType}";
// 현재 체크리스트 상태 조회
$checklist = cache()->get($cacheKey, []);
// 체크리스트 상태 업데이트
$key = "{$stepId}_{$checkpointId}";
if ($checked) {
$checklist[$key] = [
'checked_at' => now()->toDateTimeString(),
'checked_by' => auth()->id(),
];
} else {
unset($checklist[$key]);
}
// 캐시에 저장 (30일 유지)
cache()->put($cacheKey, $checklist, now()->addDays(30));
// 진행률 계산
$progress = $this->calculateProgress($tenantId, $scenarioType);
return response()->json([
'success' => true,
'progress' => $progress,
'checked' => $checked,
]);
}
/**
* 진행률 조회
*/
public function getProgress(int $tenantId, string $type): Response
{
$progress = $this->calculateProgress($tenantId, $type);
return response()->json([
'success' => true,
'progress' => $progress,
]);
}
/**
* 체크리스트 진행 상태 조회
*/
private function getChecklistProgress(int $tenantId, string $scenarioType): array
{
$cacheKey = "scenario_checklist:{$tenantId}:{$scenarioType}";
return cache()->get($cacheKey, []);
}
/**
* 진행률 계산
*/
private function calculateProgress(int $tenantId, string $scenarioType): array
{
$steps = config("sales_scenario.{$scenarioType}_steps");
$checklist = $this->getChecklistProgress($tenantId, $scenarioType);
$totalCheckpoints = 0;
$completedCheckpoints = 0;
$stepProgress = [];
foreach ($steps as $step) {
$stepCompleted = 0;
$stepTotal = count($step['checkpoints']);
$totalCheckpoints += $stepTotal;
foreach ($step['checkpoints'] as $checkpoint) {
$key = "{$step['id']}_{$checkpoint['id']}";
if (isset($checklist[$key])) {
$completedCheckpoints++;
$stepCompleted++;
}
}
$stepProgress[$step['id']] = [
'total' => $stepTotal,
'completed' => $stepCompleted,
'percentage' => $stepTotal > 0 ? round(($stepCompleted / $stepTotal) * 100) : 0,
];
}
return [
'total' => $totalCheckpoints,
'completed' => $completedCheckpoints,
'percentage' => $totalCheckpoints > 0 ? round(($completedCheckpoints / $totalCheckpoints) * 100) : 0,
'steps' => $stepProgress,
];
}
/**
* 특정 단계의 체크포인트 체크 여부 확인
*/
public function isCheckpointChecked(int $tenantId, string $scenarioType, int $stepId, string $checkpointId): bool
{
$checklist = $this->getChecklistProgress($tenantId, $scenarioType);
$key = "{$stepId}_{$checkpointId}";
return isset($checklist[$key]);
}
}