feat:가망고객에 매니저 지정 기능 추가 및 수당 구조 변경
- 영업 진행중(가망고객)에도 매니저 드롭다운 추가 - 가망고객용 assign-manager API 라우트 추가 - 매니저 수당: 5% → 1개월 구독료 (고정 금액) - 역할별 수당 표시에서 관리자 "1개월 구독료" 라벨 추가 - 유치 파트너 현황 예상 수당도 구독료 기준으로 변경 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -127,7 +127,8 @@ private function getDashboardData(Request $request): array
|
||||
],
|
||||
[
|
||||
'name' => '관리자',
|
||||
'rate' => 5,
|
||||
'rate' => null, // 1개월 구독료 (퍼센트가 아닌 고정 금액)
|
||||
'rate_label' => '1개월 구독료',
|
||||
'amount' => $managerCommissionTotal,
|
||||
'paid' => $managerCommissionPaid,
|
||||
'pending' => $managerCommissionPending,
|
||||
@@ -166,11 +167,10 @@ private function getDashboardData(Request $request): array
|
||||
->where('hq_status', SalesTenantManagement::HQ_STATUS_HANDOVER)
|
||||
->get();
|
||||
$managedHandoverManagementIds = $managedHandoverManagements->pluck('id')->toArray();
|
||||
$managedHandoverTotalRegFee = SalesContractProduct::whereIn('management_id', $managedHandoverManagementIds)
|
||||
->sum('registration_fee');
|
||||
|
||||
// 매니저 수당: 가입비 × 50% × 5% = 가입비 × 2.5%
|
||||
$handoverManagerCommission = (int)($managedHandoverTotalRegFee * 0.025);
|
||||
// 매니저 수당: 1개월 구독료 (퍼센트가 아닌 고정 금액)
|
||||
$handoverManagerCommission = (int)SalesContractProduct::whereIn('management_id', $managedHandoverManagementIds)
|
||||
->sum('subscription_fee');
|
||||
|
||||
// 기존 수당에 인계 완료 수당 추가
|
||||
$partnerCommissionTotal += $handoverPartnerCommission;
|
||||
@@ -318,6 +318,51 @@ public function assignManager(int $tenantId, Request $request): JsonResponse
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 가망고객에 매니저 지정
|
||||
*/
|
||||
public function assignProspectManager(int $prospectId, Request $request): JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
'manager_id' => 'required|integer',
|
||||
]);
|
||||
|
||||
$prospect = TenantProspect::findOrFail($prospectId);
|
||||
$managerId = $request->input('manager_id');
|
||||
|
||||
// 가망고객 영업 관리 정보 조회 또는 생성
|
||||
$management = SalesTenantManagement::findOrCreateByProspect($prospectId);
|
||||
|
||||
if ($managerId === 0) {
|
||||
// 본인으로 설정 (현재 로그인 사용자)
|
||||
$manager = auth()->user();
|
||||
$management->update([
|
||||
'manager_user_id' => $manager->id,
|
||||
]);
|
||||
} else {
|
||||
// 특정 매니저 지정
|
||||
$manager = User::find($managerId);
|
||||
if (!$manager) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => '매니저를 찾을 수 없습니다.',
|
||||
], 404);
|
||||
}
|
||||
|
||||
$management->update([
|
||||
'manager_user_id' => $manager->id,
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'manager' => [
|
||||
'id' => $manager->id,
|
||||
'name' => $manager->name,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 테넌트 리스트 부분 새로고침 (HTMX)
|
||||
*/
|
||||
@@ -441,10 +486,9 @@ private function calculatePartnerSummaryStats(array $partnerIds, int $currentUse
|
||||
// 하위 파트너들이 등록한 총 영업권(명함) 수
|
||||
$totalProspects = TenantProspect::whereIn('registered_by', $partnerIds)->count();
|
||||
|
||||
// 예상 수당 계산을 위해 먼저 가입비 정보 조회
|
||||
// 예상 수당 계산을 위해 먼저 가입비/구독료 정보 조회
|
||||
$prospectIds = TenantProspect::whereIn('registered_by', $partnerIds)->pluck('id')->toArray();
|
||||
$managementIds = SalesTenantManagement::whereIn('tenant_prospect_id', $prospectIds)->pluck('id')->toArray();
|
||||
$totalRegistrationFee = SalesContractProduct::whereIn('management_id', $managementIds)->sum('registration_fee');
|
||||
|
||||
// 하위 파트너들의 계약 건수 (가입비가 설정된 건수)
|
||||
$contractedManagementCount = SalesContractProduct::whereIn('management_id', $managementIds)
|
||||
@@ -453,13 +497,16 @@ private function calculatePartnerSummaryStats(array $partnerIds, int $currentUse
|
||||
->count('management_id');
|
||||
$totalConversions = $contractedManagementCount;
|
||||
|
||||
// 매니저 예상 수당: 1개월 구독료 (퍼센트가 아닌 고정 금액)
|
||||
$totalSubscriptionFee = SalesContractProduct::whereIn('management_id', $managementIds)->sum('subscription_fee');
|
||||
|
||||
// 확정 수당 (SalesCommission에서)
|
||||
$confirmedCommission = SalesCommission::where('manager_user_id', $currentUserId)
|
||||
->whereHas('partner', function ($query) use ($partnerIds) {
|
||||
$query->whereIn('user_id', $partnerIds);
|
||||
})
|
||||
->sum('manager_commission');
|
||||
$expectedFromFee = (int)($totalRegistrationFee * 0.05);
|
||||
$expectedFromFee = (int)$totalSubscriptionFee; // 1개월 구독료
|
||||
|
||||
// 최종 예상 수당 (확정 + 예상 중 큰 값)
|
||||
$expectedCommission = max($confirmedCommission, $expectedFromFee);
|
||||
@@ -504,11 +551,12 @@ private function getPartnerActivitiesDetail($recruitedPartners, int $currentUser
|
||||
->sum('manager_commission');
|
||||
}
|
||||
|
||||
// 예상 수당 계산: 파트너가 등록한 가망고객의 가입비 × 5%
|
||||
// 예상 수당 계산: 파트너가 등록한 가망고객의 1개월 구독료
|
||||
$prospectIds = TenantProspect::where('registered_by', $partner->id)->pluck('id')->toArray();
|
||||
$managementIds = SalesTenantManagement::whereIn('tenant_prospect_id', $prospectIds)->pluck('id')->toArray();
|
||||
$totalRegistrationFee = SalesContractProduct::whereIn('management_id', $managementIds)->sum('registration_fee');
|
||||
$expectedCommission = (int)($totalRegistrationFee * 0.05); // 5% 매니저 수당
|
||||
$totalSubscriptionFee = SalesContractProduct::whereIn('management_id', $managementIds)->sum('subscription_fee');
|
||||
$expectedCommission = (int)$totalSubscriptionFee; // 1개월 구독료
|
||||
|
||||
// 최종 매니저 수당 (확정 + 예상 중 큰 값, 또는 합산)
|
||||
$managerCommission = max($confirmedCommission, $expectedCommission);
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
@elseif($role['color'] === 'blue') text-blue-600
|
||||
@else text-gray-600
|
||||
@endif">{{ $role['rate'] }}%</span>
|
||||
@elseif(!empty($role['rate_label']))
|
||||
<span class="px-2 py-0.5 text-xs font-medium bg-blue-100 text-blue-700 rounded">{{ $role['rate_label'] }}</span>
|
||||
@else
|
||||
<span class="px-2 py-0.5 text-xs font-medium bg-red-100 text-red-700 rounded">별도</span>
|
||||
@endif
|
||||
|
||||
@@ -1,18 +1,31 @@
|
||||
{{-- 매니저 드롭다운 컴포넌트 --}}
|
||||
{{-- 매니저 드롭다운 컴포넌트 (테넌트 또는 가망고객용) --}}
|
||||
@once
|
||||
<style>[x-cloak] { display: none !important; }</style>
|
||||
@endonce
|
||||
@php
|
||||
$management = $managements[$tenant->id] ?? null;
|
||||
// 테넌트 또는 가망고객에 따라 다르게 처리
|
||||
$isProspect = isset($prospect);
|
||||
$entityId = $isProspect ? $prospect->id : $tenant->id;
|
||||
|
||||
if ($isProspect) {
|
||||
$management = $prospectManagement ?? \App\Models\Sales\SalesTenantManagement::findOrCreateByProspect($prospect->id);
|
||||
} else {
|
||||
$management = $managements[$tenant->id] ?? null;
|
||||
}
|
||||
|
||||
$assignedManager = $management?->manager;
|
||||
$isSelf = !$assignedManager || $assignedManager->id === auth()->id();
|
||||
$managerName = $assignedManager?->name ?? '본인';
|
||||
$managersJson = $allManagers->map(fn($m) => ['id' => $m->id, 'name' => $m->name, 'email' => $m->email])->values()->toJson();
|
||||
$currentManagerJson = json_encode($assignedManager ? ['id' => $assignedManager->id, 'name' => $assignedManager->name, 'is_self' => $isSelf] : null);
|
||||
|
||||
// API 엔드포인트 결정
|
||||
$apiEndpoint = $isProspect ? '/sales/prospects/' : '/sales/tenants/';
|
||||
@endphp
|
||||
|
||||
<div x-data="{
|
||||
tenantId: {{ $tenant->id }},
|
||||
entityId: {{ $entityId }},
|
||||
isProspect: {{ $isProspect ? 'true' : 'false' }},
|
||||
isOpen: false,
|
||||
managers: {{ $managersJson }},
|
||||
currentManager: {{ $currentManagerJson }},
|
||||
@@ -23,7 +36,8 @@
|
||||
this.isOpen = false;
|
||||
},
|
||||
selectManager(managerId, managerName) {
|
||||
fetch('/sales/tenants/' + this.tenantId + '/assign-manager', {
|
||||
const endpoint = this.isProspect ? '/sales/prospects/' : '/sales/tenants/';
|
||||
fetch(endpoint + this.entityId + '/assign-manager', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
$isProspectHqEnabled = $prospectProgress['sales']['percentage'] >= 100 && $prospectProgress['manager']['percentage'] >= 100;
|
||||
@endphp
|
||||
<div class="prospect-row flex items-center gap-4 px-4 py-3 hover:bg-orange-50 transition-colors" data-prospect-id="{{ $prospect->id }}">
|
||||
<!-- 업체명 및 정보 + 영업/매니저 버튼 -->
|
||||
<!-- 업체명 및 정보 + 매니저 드롭다운 + 영업/매니저 버튼 -->
|
||||
<div class="flex items-center gap-3 flex-shrink-0">
|
||||
<div class="min-w-0">
|
||||
<div class="flex items-center gap-2">
|
||||
@@ -111,6 +111,10 @@
|
||||
<span>{{ $prospect->business_number ?? '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{{-- 매니저 드롭다운 --}}
|
||||
<div class="flex-shrink-0">
|
||||
@include('sales.dashboard.partials.manager-dropdown', ['prospect' => $prospect, 'prospectManagement' => $prospectManagement])
|
||||
</div>
|
||||
{{-- 영업/매니저 진행 버튼 --}}
|
||||
<div class="flex-shrink-0 flex items-center gap-1">
|
||||
<button
|
||||
|
||||
@@ -967,6 +967,7 @@
|
||||
|
||||
// 매니저 지정 변경
|
||||
Route::post('/tenants/{tenant}/assign-manager', [\App\Http\Controllers\Sales\SalesDashboardController::class, 'assignManager'])->name('tenants.assign-manager');
|
||||
Route::post('/prospects/{prospect}/assign-manager', [\App\Http\Controllers\Sales\SalesDashboardController::class, 'assignProspectManager'])->name('prospects.assign-manager');
|
||||
|
||||
// 매니저 목록 조회 (드롭다운용)
|
||||
Route::get('/managers/list', [\App\Http\Controllers\Sales\SalesDashboardController::class, 'getManagers'])->name('managers.list');
|
||||
|
||||
Reference in New Issue
Block a user