diff --git a/app/Http/Controllers/Sales/SalesManagerController.php b/app/Http/Controllers/Sales/SalesManagerController.php index 83887083..9833331b 100644 --- a/app/Http/Controllers/Sales/SalesManagerController.php +++ b/app/Http/Controllers/Sales/SalesManagerController.php @@ -3,7 +3,6 @@ namespace App\Http\Controllers\Sales; use App\Http\Controllers\Controller; -use App\Models\Role; use App\Models\Sales\SalesManagerDocument; use App\Models\User; use App\Services\Sales\SalesManagerService; @@ -12,7 +11,7 @@ use Illuminate\View\View; /** - * 영업 담당자/매니저 관리 컨트롤러 + * 영업파트너 관리 컨트롤러 */ class SalesManagerController extends Controller { @@ -35,10 +34,10 @@ public function index(Request $request): View|Response 'approval_status' => $request->get('approval_status'), ]; - $managers = $this->service->getSalesManagers($filters)->paginate(20); + $partners = $this->service->getSalesPartners($filters)->paginate(20); $stats = $this->service->getStats(); - return view('sales.managers.index', compact('managers', 'stats')); + return view('sales.managers.index', compact('partners', 'stats')); } /** @@ -46,20 +45,16 @@ public function index(Request $request): View|Response */ public function create(): View { - $tenantId = session('selected_tenant_id', 1); + // 영업 역할 목록 + $roles = $this->service->getSalesRoles(); - // 영업 관련 역할 목록 - $roles = Role::where('tenant_id', $tenantId) - ->whereIn('name', ['sales_operator', 'sales_admin', 'sales_manager']) - ->get(); - - // 상위 관리자 후보 - $parents = $this->service->getParentCandidates(); + // 추천인(유치자) 후보 + $recommenders = $this->service->getRecommenderCandidates(); // 문서 타입 목록 $documentTypes = SalesManagerDocument::DOCUMENT_TYPES; - return view('sales.managers.create', compact('roles', 'parents', 'documentTypes')); + return view('sales.managers.create', compact('roles', 'recommenders', 'documentTypes')); } /** @@ -77,7 +72,7 @@ public function store(Request $request) 'role_ids' => 'required|array|min:1', 'role_ids.*' => 'exists:roles,id', 'documents' => 'nullable|array', - 'documents.*.file' => 'nullable|file|max:10240', // 10MB + 'documents.*.file' => 'nullable|file|max:10240', 'documents.*.document_type' => 'nullable|string', 'documents.*.description' => 'nullable|string|max:500', ]); @@ -94,10 +89,10 @@ public function store(Request $request) } } - $this->service->createSalesManager($validated, $documents); + $this->service->createSalesPartner($validated, $documents); return redirect()->route('sales.managers.index') - ->with('success', '영업담당자 등록 신청이 완료되었습니다. 본사 승인 후 활성화됩니다.'); + ->with('success', '영업파트너 등록 신청이 완료되었습니다. 본사 승인 후 활성화됩니다.'); } /** @@ -105,10 +100,21 @@ public function store(Request $request) */ public function show(int $id): View { - $manager = User::with(['parent', 'children', 'userRoles.role', 'salesDocuments', 'approver']) + $partner = User::with(['parent', 'children', 'userRoles.role', 'salesDocuments', 'approver']) ->findOrFail($id); - return view('sales.managers.show', compact('manager')); + // 계층 레벨 + $level = $this->service->getPartnerLevel($partner); + + // 하위 파트너 + $children = User::where('parent_id', $partner->id) + ->with('userRoles.role') + ->get(); + + // 역할 위임 가능한 하위 파트너 + $delegationCandidates = $this->service->getDelegationCandidates($partner); + + return view('sales.managers.show', compact('partner', 'level', 'children', 'delegationCandidates')); } /** @@ -116,25 +122,22 @@ public function show(int $id): View */ public function edit(int $id): View { - $manager = User::with(['userRoles.role', 'salesDocuments'])->findOrFail($id); - $tenantId = session('selected_tenant_id', 1); + $partner = User::with(['userRoles.role', 'salesDocuments'])->findOrFail($id); - // 영업 관련 역할 목록 - $roles = Role::where('tenant_id', $tenantId) - ->whereIn('name', ['sales_operator', 'sales_admin', 'sales_manager']) - ->get(); + // 영업 역할 목록 + $roles = $this->service->getSalesRoles(); - // 상위 관리자 후보 - $parents = $this->service->getParentCandidates($id); + // 추천인(유치자) 후보 + $recommenders = $this->service->getRecommenderCandidates($id); // 현재 역할 ID 목록 - $currentRoleIds = $manager->userRoles->pluck('role_id')->toArray(); + $currentRoleIds = $partner->userRoles->pluck('role_id')->toArray(); // 문서 타입 목록 $documentTypes = SalesManagerDocument::DOCUMENT_TYPES; return view('sales.managers.edit', compact( - 'manager', 'roles', 'parents', 'currentRoleIds', 'documentTypes' + 'partner', 'roles', 'recommenders', 'currentRoleIds', 'documentTypes' )); } @@ -143,7 +146,7 @@ public function edit(int $id): View */ public function update(Request $request, int $id) { - $manager = User::findOrFail($id); + $partner = User::findOrFail($id); $validated = $request->validate([ 'name' => 'required|string|max:100', @@ -171,10 +174,10 @@ public function update(Request $request, int $id) } } - $this->service->updateSalesManager($manager, $validated, $documents); + $this->service->updateSalesPartner($partner, $validated, $documents); return redirect()->route('sales.managers.index') - ->with('success', '담당자 정보가 수정되었습니다.'); + ->with('success', '영업파트너 정보가 수정되었습니다.'); } /** @@ -182,11 +185,11 @@ public function update(Request $request, int $id) */ public function destroy(int $id) { - $manager = User::findOrFail($id); - $manager->update(['is_active' => false]); + $partner = User::findOrFail($id); + $partner->update(['is_active' => false]); return redirect()->route('sales.managers.index') - ->with('success', '담당자가 비활성화되었습니다.'); + ->with('success', '영업파트너가 비활성화되었습니다.'); } /** @@ -194,11 +197,11 @@ public function destroy(int $id) */ public function approve(int $id) { - $manager = User::findOrFail($id); - $this->service->approve($manager, auth()->id()); + $partner = User::findOrFail($id); + $this->service->approve($partner, auth()->id()); return redirect()->back() - ->with('success', '영업담당자가 승인되었습니다.'); + ->with('success', '영업파트너가 승인되었습니다.'); } /** @@ -210,11 +213,70 @@ public function reject(Request $request, int $id) 'rejection_reason' => 'required|string|max:1000', ]); - $manager = User::findOrFail($id); - $this->service->reject($manager, auth()->id(), $validated['rejection_reason']); + $partner = User::findOrFail($id); + $this->service->reject($partner, auth()->id(), $validated['rejection_reason']); return redirect()->back() - ->with('success', '영업담당자가 반려되었습니다.'); + ->with('success', '영업파트너가 반려되었습니다.'); + } + + /** + * 역할 위임 처리 + */ + public function delegateRole(Request $request, int $id) + { + $validated = $request->validate([ + 'to_user_id' => 'required|exists:users,id', + 'role_name' => 'required|string|in:manager,recruiter', + ]); + + $fromUser = User::findOrFail($id); + $toUser = User::findOrFail($validated['to_user_id']); + + try { + $this->service->delegateRole($fromUser, $toUser, $validated['role_name']); + + $roleLabel = $validated['role_name'] === 'manager' ? '매니저' : '유치담당'; + return redirect()->back() + ->with('success', "{$roleLabel} 역할이 {$toUser->name}님에게 위임되었습니다."); + } catch (\InvalidArgumentException $e) { + return redirect()->back() + ->with('error', $e->getMessage()); + } + } + + /** + * 역할 부여 + */ + public function assignRole(Request $request, int $id) + { + $validated = $request->validate([ + 'role_name' => 'required|string|in:sales,manager,recruiter', + ]); + + $partner = User::findOrFail($id); + $this->service->assignRole($partner, $validated['role_name']); + + $roleLabels = ['sales' => '영업', 'manager' => '매니저', 'recruiter' => '유치담당']; + return redirect()->back() + ->with('success', "{$roleLabels[$validated['role_name']]} 역할이 부여되었습니다."); + } + + /** + * 역할 제거 + */ + public function removeRole(Request $request, int $id) + { + $validated = $request->validate([ + 'role_name' => 'required|string|in:sales,manager,recruiter', + ]); + + $partner = User::findOrFail($id); + $this->service->removeRole($partner, $validated['role_name']); + + $roleLabels = ['sales' => '영업', 'manager' => '매니저', 'recruiter' => '유치담당']; + return redirect()->back() + ->with('success', "{$roleLabels[$validated['role_name']]} 역할이 제거되었습니다."); } /** diff --git a/app/Services/Sales/SalesManagerService.php b/app/Services/Sales/SalesManagerService.php index 3b960cfd..8ba09a9b 100644 --- a/app/Services/Sales/SalesManagerService.php +++ b/app/Services/Sales/SalesManagerService.php @@ -3,6 +3,7 @@ namespace App\Services\Sales; use App\Models\DepartmentUser; +use App\Models\Role; use App\Models\Sales\SalesManagerDocument; use App\Models\User; use App\Models\UserRole; @@ -15,9 +16,14 @@ class SalesManagerService { /** - * 영업담당자 생성 + * 영업파트너 역할 이름 목록 */ - public function createSalesManager(array $data, array $documents = []): User + public const SALES_ROLES = ['sales', 'manager', 'recruiter']; + + /** + * 영업파트너 생성 + */ + public function createSalesPartner(array $data, array $documents = []): User { return DB::transaction(function () use ($data, $documents) { $tenantId = session('selected_tenant_id', 1); @@ -30,7 +36,7 @@ public function createSalesManager(array $data, array $documents = []): User 'phone' => $data['phone'] ?? null, 'password' => Hash::make($data['password']), 'is_active' => false, // 승인 전까지 비활성 - 'parent_id' => $data['parent_id'] ?? null, + 'parent_id' => $data['parent_id'] ?? null, // 추천인(유치자) 'approval_status' => 'pending', // 승인 대기 상태 'must_change_password' => true, ]); @@ -47,12 +53,7 @@ public function createSalesManager(array $data, array $documents = []): User $this->syncRoles($user, $tenantId, $data['role_ids']); } - // 4. 부서 할당 - if (!empty($data['department_ids'])) { - $this->syncDepartments($user, $tenantId, $data['department_ids']); - } - - // 5. 첨부 서류 저장 + // 4. 첨부 서류 저장 if (!empty($documents)) { $this->uploadDocuments($user, $tenantId, $documents); } @@ -62,9 +63,9 @@ public function createSalesManager(array $data, array $documents = []): User } /** - * 영업담당자 수정 + * 영업파트너 수정 */ - public function updateSalesManager(User $user, array $data, array $documents = []): User + public function updateSalesPartner(User $user, array $data, array $documents = []): User { return DB::transaction(function () use ($user, $data, $documents) { $tenantId = session('selected_tenant_id', 1); @@ -89,12 +90,7 @@ public function updateSalesManager(User $user, array $data, array $documents = [ $this->syncRoles($user, $tenantId, $data['role_ids']); } - // 3. 부서 동기화 - if (isset($data['department_ids'])) { - $this->syncDepartments($user, $tenantId, $data['department_ids']); - } - - // 4. 새 첨부 서류 저장 + // 3. 새 첨부 서류 저장 if (!empty($documents)) { $this->uploadDocuments($user, $tenantId, $documents); } @@ -104,7 +100,7 @@ public function updateSalesManager(User $user, array $data, array $documents = [ } /** - * 영업담당자 승인 + * 영업파트너 승인 */ public function approve(User $user, int $approverId): User { @@ -120,7 +116,7 @@ public function approve(User $user, int $approverId): User } /** - * 영업담당자 반려 + * 영업파트너 반려 */ public function reject(User $user, int $approverId, string $reason): User { @@ -135,16 +131,119 @@ public function reject(User $user, int $approverId, string $reason): User return $user; } + /** + * 역할 위임 + * + * @param User $fromUser 역할을 넘기는 파트너 + * @param User $toUser 역할을 받는 파트너 + * @param string $roleName 위임할 역할 (manager, recruiter 등) + */ + public function delegateRole(User $fromUser, User $toUser, string $roleName): bool + { + $tenantId = session('selected_tenant_id', 1); + + return DB::transaction(function () use ($fromUser, $toUser, $roleName, $tenantId) { + // 역할 조회 + $role = Role::where('tenant_id', $tenantId) + ->where('name', $roleName) + ->first(); + + if (!$role) { + throw new \InvalidArgumentException("역할을 찾을 수 없습니다: {$roleName}"); + } + + // fromUser가 해당 역할을 가지고 있는지 확인 + $hasRole = UserRole::where('user_id', $fromUser->id) + ->where('tenant_id', $tenantId) + ->where('role_id', $role->id) + ->exists(); + + if (!$hasRole) { + throw new \InvalidArgumentException("{$fromUser->name}님이 {$roleName} 역할을 보유하고 있지 않습니다."); + } + + // fromUser에서 역할 제거 + UserRole::where('user_id', $fromUser->id) + ->where('tenant_id', $tenantId) + ->where('role_id', $role->id) + ->delete(); + + // toUser에게 역할 추가 (이미 있으면 무시) + UserRole::firstOrCreate([ + 'user_id' => $toUser->id, + 'tenant_id' => $tenantId, + 'role_id' => $role->id, + ], [ + 'assigned_at' => now(), + ]); + + return true; + }); + } + + /** + * 역할 부여 + */ + public function assignRole(User $user, string $roleName): bool + { + $tenantId = session('selected_tenant_id', 1); + + $role = Role::where('tenant_id', $tenantId) + ->where('name', $roleName) + ->first(); + + if (!$role) { + return false; + } + + UserRole::firstOrCreate([ + 'user_id' => $user->id, + 'tenant_id' => $tenantId, + 'role_id' => $role->id, + ], [ + 'assigned_at' => now(), + ]); + + return true; + } + + /** + * 역할 제거 + */ + public function removeRole(User $user, string $roleName): bool + { + $tenantId = session('selected_tenant_id', 1); + + $role = Role::where('tenant_id', $tenantId) + ->where('name', $roleName) + ->first(); + + if (!$role) { + return false; + } + + UserRole::where('user_id', $user->id) + ->where('tenant_id', $tenantId) + ->where('role_id', $role->id) + ->delete(); + + return true; + } + /** * 역할 동기화 */ public function syncRoles(User $user, int $tenantId, array $roleIds): void { - // 기존 역할 삭제 - UserRole::withTrashed() - ->where('user_id', $user->id) + // 영업 관련 역할만 삭제 (다른 역할은 유지) + $salesRoleIds = Role::where('tenant_id', $tenantId) + ->whereIn('name', self::SALES_ROLES) + ->pluck('id'); + + UserRole::where('user_id', $user->id) ->where('tenant_id', $tenantId) - ->forceDelete(); + ->whereIn('role_id', $salesRoleIds) + ->delete(); // 새 역할 추가 foreach ($roleIds as $roleId) { @@ -157,30 +256,6 @@ public function syncRoles(User $user, int $tenantId, array $roleIds): void } } - /** - * 부서 동기화 - */ - public function syncDepartments(User $user, int $tenantId, array $departmentIds): void - { - // 기존 부서 삭제 - DepartmentUser::withTrashed() - ->where('user_id', $user->id) - ->where('tenant_id', $tenantId) - ->forceDelete(); - - // 새 부서 추가 - foreach ($departmentIds as $index => $departmentId) { - DepartmentUser::create([ - 'user_id' => $user->id, - 'tenant_id' => $tenantId, - 'department_id' => $departmentId, - 'is_primary' => $index === 0, - 'joined_at' => now(), - 'created_by' => auth()->id(), - ]); - } - } - /** * 서류 업로드 */ @@ -199,7 +274,7 @@ public function uploadDocuments(User $user, int $tenantId, array $documents): ar // 파일 저장 $storedName = Str::uuid() . '.' . $file->getClientOriginalExtension(); - $filePath = "sales-managers/{$user->id}/{$storedName}"; + $filePath = "sales-partners/{$user->id}/{$storedName}"; Storage::disk('tenant')->put($filePath, file_get_contents($file)); @@ -241,18 +316,18 @@ public function deleteDocument(SalesManagerDocument $document): bool } /** - * 영업담당자 목록 조회 (역할 기반) + * 영업파트너 목록 조회 */ - public function getSalesManagers(array $filters = []) + public function getSalesPartners(array $filters = []) { $tenantId = session('selected_tenant_id', 1); - // 영업관련 역할을 가진 사용자 조회 + // 영업 관련 역할을 가진 사용자 조회 $query = User::query() ->whereHas('userRoles', function ($q) use ($tenantId) { $q->where('tenant_id', $tenantId) ->whereHas('role', function ($rq) { - $rq->whereIn('name', ['sales_operator', 'sales_admin', 'sales_manager']); + $rq->whereIn('name', self::SALES_ROLES); }); }) ->with(['parent', 'userRoles.role', 'salesDocuments']); @@ -288,9 +363,10 @@ public function getSalesManagers(array $filters = []) } /** - * 상위 관리자 목록 (운영자, 영업관리) + * 추천인(유치자) 후보 목록 + * 승인된 모든 영업파트너가 추천인이 될 수 있음 */ - public function getParentCandidates(?int $excludeId = null) + public function getRecommenderCandidates(?int $excludeId = null) { $tenantId = session('selected_tenant_id', 1); @@ -300,7 +376,7 @@ public function getParentCandidates(?int $excludeId = null) ->whereHas('userRoles', function ($q) use ($tenantId) { $q->where('tenant_id', $tenantId) ->whereHas('role', function ($rq) { - $rq->whereIn('name', ['sales_operator', 'sales_admin']); + $rq->whereIn('name', self::SALES_ROLES); }); }); @@ -311,6 +387,31 @@ public function getParentCandidates(?int $excludeId = null) return $query->orderBy('name')->get(); } + /** + * 역할 위임 가능한 하위 파트너 목록 + */ + public function getDelegationCandidates(User $user) + { + return User::query() + ->where('parent_id', $user->id) + ->where('is_active', true) + ->where('approval_status', 'approved') + ->orderBy('name') + ->get(); + } + + /** + * 영업 역할 목록 조회 + */ + public function getSalesRoles() + { + $tenantId = session('selected_tenant_id', 1); + + return Role::where('tenant_id', $tenantId) + ->whereIn('name', self::SALES_ROLES) + ->get(); + } + /** * 통계 조회 */ @@ -322,7 +423,7 @@ public function getStats(): array ->whereHas('userRoles', function ($q) use ($tenantId) { $q->where('tenant_id', $tenantId) ->whereHas('role', function ($rq) { - $rq->whereIn('name', ['sales_operator', 'sales_admin', 'sales_manager']); + $rq->whereIn('name', self::SALES_ROLES); }); }); @@ -330,15 +431,65 @@ public function getStats(): array 'total' => (clone $baseQuery)->count(), 'pending' => (clone $baseQuery)->where('approval_status', 'pending')->count(), 'approved' => (clone $baseQuery)->where('approval_status', 'approved')->count(), - 'operators' => (clone $baseQuery) - ->whereHas('userRoles.role', fn($q) => $q->where('name', 'sales_operator')) + 'sales' => (clone $baseQuery) + ->whereHas('userRoles.role', fn($q) => $q->where('name', 'sales')) ->count(), - 'sales_admins' => (clone $baseQuery) - ->whereHas('userRoles.role', fn($q) => $q->where('name', 'sales_admin')) + 'manager' => (clone $baseQuery) + ->whereHas('userRoles.role', fn($q) => $q->where('name', 'manager')) ->count(), - 'managers' => (clone $baseQuery) - ->whereHas('userRoles.role', fn($q) => $q->where('name', 'sales_manager')) + 'recruiter' => (clone $baseQuery) + ->whereHas('userRoles.role', fn($q) => $q->where('name', 'recruiter')) ->count(), ]; } + + /** + * 파트너의 계층 레벨 계산 + */ + public function getPartnerLevel(User $user): int + { + $level = 1; + $current = $user; + + while ($current->parent_id !== null) { + $level++; + $current = $current->parent; + + // 무한 루프 방지 + if ($level > 100) { + break; + } + } + + return $level; + } + + /** + * 하위 파트너 전체 목록 (재귀) + */ + public function getAllDescendants(User $user, int $maxDepth = 10): array + { + $descendants = []; + $this->collectDescendants($user, $descendants, 1, $maxDepth); + return $descendants; + } + + private function collectDescendants(User $user, array &$descendants, int $currentDepth, int $maxDepth): void + { + if ($currentDepth > $maxDepth) { + return; + } + + $children = User::where('parent_id', $user->id) + ->where('approval_status', 'approved') + ->get(); + + foreach ($children as $child) { + $descendants[] = [ + 'user' => $child, + 'level' => $currentDepth, + ]; + $this->collectDescendants($child, $descendants, $currentDepth + 1, $maxDepth); + } + } } diff --git a/database/seeders/SalesRoleSeeder.php b/database/seeders/SalesRoleSeeder.php index 3239eeed..3fc3e9a4 100644 --- a/database/seeders/SalesRoleSeeder.php +++ b/database/seeders/SalesRoleSeeder.php @@ -8,7 +8,10 @@ class SalesRoleSeeder extends Seeder { /** - * 영업관리 역할 시더 + * 영업파트너 역할 시더 + * + * 모든 영업 담당자는 "영업파트너"라는 동일한 직위 + * 역할은 수행하는 업무를 정의 */ public function run(): void { @@ -16,16 +19,16 @@ public function run(): void $roles = [ [ - 'name' => 'sales_operator', - 'description' => '영업 운영자 - 전체 영업 조직 관리', + 'name' => 'sales', + 'description' => '영업 - 가망고객 발굴, 상담, 계약 체결', ], [ - 'name' => 'sales_admin', - 'description' => '영업 관리자 - 하위 매니저 관리', + 'name' => 'manager', + 'description' => '매니저 - 하위 파트너 관리, 실적 취합, 승인 처리', ], [ - 'name' => 'sales_manager', - 'description' => '영업 매니저 - 가망고객 관리 및 영업 활동', + 'name' => 'recruiter', + 'description' => '유치담당 - 새로운 영업파트너 유치 활동', ], ]; @@ -42,6 +45,6 @@ public function run(): void ); } - $this->command->info('영업관리 역할이 생성되었습니다.'); + $this->command->info('영업파트너 역할이 생성되었습니다: sales, manager, recruiter'); } } diff --git a/resources/views/sales/managers/create.blade.php b/resources/views/sales/managers/create.blade.php index 168f33fd..be8bf6a2 100644 --- a/resources/views/sales/managers/create.blade.php +++ b/resources/views/sales/managers/create.blade.php @@ -102,17 +102,17 @@ class="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500">
- + -

영업 운영자, 영업 관리자만 상위 관리자로 지정 가능합니다.

+

이 파트너를 유치한 상위 영업파트너를 선택합니다.

diff --git a/resources/views/sales/managers/edit.blade.php b/resources/views/sales/managers/edit.blade.php index c1bf2682..32df3e4e 100644 --- a/resources/views/sales/managers/edit.blade.php +++ b/resources/views/sales/managers/edit.blade.php @@ -13,11 +13,11 @@ 목록으로

영업담당자 수정

-

{{ $manager->name }} ({{ $manager->email }})

+

{{ $partner->name }} ({{ $partner->email }})

-
+ @csrf @method('PUT') @@ -28,13 +28,13 @@
-
- @error('name')

{{ $message }}

@@ -43,7 +43,7 @@ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none foc
- @error('email')

{{ $message }}

@@ -52,7 +52,7 @@ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none foc
-
@@ -99,33 +99,34 @@ class="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500">
- + +

이 파트너를 유치한 상위 영업파트너를 선택합니다.

- @if($manager->salesDocuments->isNotEmpty()) + @if($partner->salesDocuments->isNotEmpty())

기존 첨부 서류

- @foreach($manager->salesDocuments as $document) + @foreach($partner->salesDocuments as $document)
{{ $document->document_type_label }} {{ $document->original_name }} {{ $document->formatted_size }}
- @csrf @method('DELETE') diff --git a/resources/views/sales/managers/index.blade.php b/resources/views/sales/managers/index.blade.php index 084f43af..d07c117b 100644 --- a/resources/views/sales/managers/index.blade.php +++ b/resources/views/sales/managers/index.blade.php @@ -1,26 +1,26 @@ @extends('layouts.app') -@section('title', '영업담당자 관리') +@section('title', '영업파트너 관리') @section('content')
-

영업담당자 관리

-

영업 담당자 및 매니저를 관리합니다

+

영업파트너 관리

+

영업파트너의 등록, 승인, 역할을 관리합니다

- 담당자 등록 + 파트너 등록
-
+
전체
{{ number_format($stats['total']) }}명
@@ -29,17 +29,21 @@ class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg transition
승인대기
{{ number_format($stats['pending']) }}명
-
-
운영자
-
{{ number_format($stats['operators']) }}명
+
+
승인완료
+
{{ number_format($stats['approved']) }}명
-
영업관리
-
{{ number_format($stats['sales_admins']) }}명
+
영업
+
{{ number_format($stats['sales']) }}명
+
+
+
매니저
+
{{ number_format($stats['manager']) }}명
-
매니저
-
{{ number_format($stats['managers']) }}명
+
유치담당
+
{{ number_format($stats['recruiter']) }}명
@@ -50,15 +54,15 @@ class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg transition
@@ -85,38 +89,38 @@ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none foc 아이디 역할 연락처 - 상위관리자 + 추천인(유치자) 상태 등록일 관리 - @forelse($managers as $manager) + @forelse($partners as $partner) -
{{ $manager->name }}
- @if($manager->email) -
{{ $manager->email }}
+
{{ $partner->name }}
+ @if($partner->email) +
{{ $partner->email }}
@endif - {{ $manager->user_id ?? '-' }} + {{ $partner->user_id ?? '-' }}
- @foreach($manager->userRoles as $userRole) + @foreach($partner->userRoles as $userRole) @php $roleColor = match($userRole->role->name ?? '') { - 'sales_operator' => 'bg-purple-100 text-purple-800', - 'sales_admin' => 'bg-blue-100 text-blue-800', - 'sales_manager' => 'bg-green-100 text-green-800', + 'sales' => 'bg-blue-100 text-blue-800', + 'manager' => 'bg-purple-100 text-purple-800', + 'recruiter' => 'bg-green-100 text-green-800', default => 'bg-gray-100 text-gray-800', }; $roleLabel = match($userRole->role->name ?? '') { - 'sales_operator' => '운영자', - 'sales_admin' => '영업관리', - 'sales_manager' => '매니저', + 'sales' => '영업', + 'manager' => '매니저', + 'recruiter' => '유치담당', default => $userRole->role->name ?? '-', }; @endphp @@ -127,30 +131,36 @@ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none foc
- {{ $manager->phone ?? '-' }} + {{ $partner->phone ?? '-' }} - {{ $manager->parent?->name ?? '-' }} + @if($partner->parent) + + {{ $partner->parent->name }} + + @else + 최상위 + @endif - - {{ $manager->approval_status_label }} + + {{ $partner->approval_status_label }} - {{ $manager->created_at->format('Y-m-d') }} + {{ $partner->created_at->format('Y-m-d') }} - 상세 - 수정 - @if($manager->isPendingApproval()) - 상세 + 수정 + @if($partner->isPendingApproval()) + @csrf @endif -
@csrf @method('DELETE') @@ -161,7 +171,7 @@ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none foc @empty - 등록된 담당자가 없습니다. + 등록된 파트너가 없습니다. @endforelse @@ -170,9 +180,9 @@ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none foc
- @if($managers->hasPages()) + @if($partners->hasPages())
- {{ $managers->withQueryString()->links() }} + {{ $partners->withQueryString()->links() }}
@endif
diff --git a/resources/views/sales/managers/show.blade.php b/resources/views/sales/managers/show.blade.php index 107f61ee..0956df2c 100644 --- a/resources/views/sales/managers/show.blade.php +++ b/resources/views/sales/managers/show.blade.php @@ -1,6 +1,6 @@ @extends('layouts.app') -@section('title', '영업담당자 상세') +@section('title', '영업파트너 상세') @section('content')
@@ -13,20 +13,21 @@ 목록으로 -

{{ $manager->name }}

+

{{ $partner->name }}

+

레벨 {{ $level }} 영업파트너

- @foreach($manager->userRoles as $userRole) + @foreach($partner->userRoles as $userRole) @php $roleColor = match($userRole->role->name ?? '') { - 'sales_operator' => 'bg-purple-100 text-purple-800', - 'sales_admin' => 'bg-blue-100 text-blue-800', - 'sales_manager' => 'bg-green-100 text-green-800', + 'sales' => 'bg-blue-100 text-blue-800', + 'manager' => 'bg-purple-100 text-purple-800', + 'recruiter' => 'bg-green-100 text-green-800', default => 'bg-gray-100 text-gray-800', }; $roleLabel = match($userRole->role->name ?? '') { - 'sales_operator' => '운영자', - 'sales_admin' => '영업관리', - 'sales_manager' => '매니저', + 'sales' => '영업', + 'manager' => '매니저', + 'recruiter' => '유치담당', default => $userRole->role->name ?? '-', }; @endphp @@ -34,19 +35,19 @@ {{ $roleLabel }} @endforeach - - {{ $manager->approval_status_label }} + + {{ $partner->approval_status_label }}
- 수정
- @if($manager->isPendingApproval()) + @if($partner->isPendingApproval())
@@ -54,9 +55,9 @@ class="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-lg transit

승인 대기 중

-

이 담당자는 승인 대기 중입니다. 첨부된 서류를 확인 후 승인 또는 반려해주세요.

+

이 파트너는 승인 대기 중입니다. 첨부된 서류를 확인 후 승인 또는 반려해주세요.

- + @csrf
+ + @if($partner->isApproved()) +
+

역할 관리

+ + +
+

현재 보유 역할

+
+ @php + $currentRoles = $partner->userRoles->pluck('role.name')->toArray(); + $roleLabels = ['sales' => '영업', 'manager' => '매니저', 'recruiter' => '유치담당']; + $roleColors = [ + 'sales' => 'bg-blue-100 text-blue-800 border-blue-200', + 'manager' => 'bg-purple-100 text-purple-800 border-purple-200', + 'recruiter' => 'bg-green-100 text-green-800 border-green-200', + ]; + @endphp + @forelse($currentRoles as $roleName) + @if(isset($roleLabels[$roleName])) +
+ {{ $roleLabels[$roleName] }} + + @csrf + + + +
+ @endif + @empty + 역할이 없습니다 + @endforelse +
+
+ + +
+

역할 부여

+
+ @foreach(['sales' => '영업', 'manager' => '매니저', 'recruiter' => '유치담당'] as $roleName => $label) + @if(!in_array($roleName, $currentRoles)) +
+ @csrf + + +
+ @endif + @endforeach +
+
+ + + @if((in_array('manager', $currentRoles) || in_array('recruiter', $currentRoles)) && $delegationCandidates->isNotEmpty()) +
+

역할 위임

+

보유 중인 역할을 하위 파트너에게 위임할 수 있습니다. 위임하면 해당 역할이 제거됩니다.

+ +
+ @csrf +
+
+ + +
+
+ + +
+
+ +
+
+ @endif +
+ @endif + - @if($manager->salesDocuments->isNotEmpty()) + @if($partner->salesDocuments->isNotEmpty())

첨부 서류

- @foreach($manager->salesDocuments as $document) + @foreach($partner->salesDocuments as $document)
@if($document->isImage())
@@ -181,7 +284,7 @@ class="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition te

{{ $document->description }}

@endif
@@ -191,10 +294,10 @@ class="text-sm text-blue-600 hover:underline">다운로드
@endif - - @if($manager->children->isNotEmpty()) + + @if($children->isNotEmpty())
-

하위 담당자

+

하위 파트너 (유치한 파트너)

@@ -206,7 +309,7 @@ class="text-sm text-blue-600 hover:underline">다운로드 - @foreach($manager->children as $child) + @foreach($children as $child)
@@ -217,15 +320,15 @@ class="text-sm text-blue-600 hover:underline">다운로드 @foreach($child->userRoles as $userRole) @php $roleColor = match($userRole->role->name ?? '') { - 'sales_operator' => 'bg-purple-100 text-purple-800', - 'sales_admin' => 'bg-blue-100 text-blue-800', - 'sales_manager' => 'bg-green-100 text-green-800', + 'sales' => 'bg-blue-100 text-blue-800', + 'manager' => 'bg-purple-100 text-purple-800', + 'recruiter' => 'bg-green-100 text-green-800', default => 'bg-gray-100 text-gray-800', }; $roleLabel = match($userRole->role->name ?? '') { - 'sales_operator' => '운영자', - 'sales_admin' => '영업관리', - 'sales_manager' => '매니저', + 'sales' => '영업', + 'manager' => '매니저', + 'recruiter' => '유치담당', default => $userRole->role->name ?? '-', }; @endphp @@ -254,7 +357,7 @@ class="text-sm text-blue-600 hover:underline">다운로드

반려 사유 입력

-
+ @csrf