refactor:영업파트너 고객관리 테이블 정리 + 정산관리에 수당지급일 관리 이동
- 고객관리 테이블: 1차수당/2차수당/매니저수당/협업지원금/등록일 열 제거, 계약일 열 추가 (16열→12열) - 정산관리 수당정산 테이블: 수당지급일/매니저지급일/협업지원금 인라인 편집 컬럼 추가 - SalesCommissionController에 updateCommissionDate 메서드 추가 - 불필요한 JS 함수 제거 (saveReferrerCommission, checkHandoverStatus) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -253,6 +253,29 @@ public function cancel(int $id): JsonResponse
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 수당지급일/협업지원금 인라인 수정
|
||||
*/
|
||||
public function updateCommissionDate(int $id, Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'field' => 'required|in:first_partner_paid_at,second_partner_paid_at,manager_paid_at,referrer_commission',
|
||||
'value' => 'nullable',
|
||||
]);
|
||||
|
||||
$commission = SalesCommission::findOrFail($id);
|
||||
|
||||
// 수당지급일은 인계 상태일 때만 변경 가능
|
||||
$paidFields = ['first_partner_paid_at', 'second_partner_paid_at', 'manager_paid_at'];
|
||||
if (in_array($validated['field'], $paidFields) && $commission->management?->hq_status !== 'handover') {
|
||||
return response()->json(['success' => false, 'message' => '인계 상태일 때만 수당지급일 설정 가능'], 422);
|
||||
}
|
||||
|
||||
$commission->update([$validated['field'] => $validated['value'] ?: null]);
|
||||
|
||||
return response()->json(['success' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 정산 테이블 부분 새로고침 (HTMX)
|
||||
*/
|
||||
|
||||
@@ -191,6 +191,7 @@ private function getIndexData(Request $request): array
|
||||
$prospect->hq_status = $management?->hq_status ?? 'pending';
|
||||
$prospect->hq_status_label = $management?->hq_status_label ?? '대기';
|
||||
$prospect->manager_user = $management?->manager;
|
||||
$prospect->contracted_at = $management?->contracted_at;
|
||||
|
||||
$prospect->commission = $this->loadMergedCommission($management);
|
||||
|
||||
@@ -237,6 +238,7 @@ private function getIndexData(Request $request): array
|
||||
$prospect->hq_status = $management?->hq_status ?? 'pending';
|
||||
$prospect->hq_status_label = $management?->hq_status_label ?? '대기';
|
||||
$prospect->manager_user = $management?->manager;
|
||||
$prospect->contracted_at = $management?->contracted_at;
|
||||
|
||||
// 수당 정보 (management가 있는 경우)
|
||||
$prospect->commission = $this->loadMergedCommission($management);
|
||||
|
||||
@@ -362,6 +362,28 @@ function cancelCommission(id) {
|
||||
});
|
||||
}
|
||||
|
||||
function saveSettlementDate(commissionId, field, value) {
|
||||
fetch(`{{ url('finance/sales-commissions') }}/${commissionId}/update-date`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ field: field, value: value })
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (!data.success) {
|
||||
alert(data.message || '저장에 실패했습니다.');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('저장 중 오류가 발생했습니다.');
|
||||
});
|
||||
}
|
||||
|
||||
function onTenantSelect(managementId) {
|
||||
if (!managementId) return;
|
||||
htmx.ajax('GET', '{{ route("finance.sales-commissions.payment-form") }}?management_id=' + managementId, {
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">유치파트너</th>
|
||||
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">유치수당</th>
|
||||
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">지급예정일</th>
|
||||
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">수당지급일</th>
|
||||
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">매니저지급일</th>
|
||||
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">협업지원금</th>
|
||||
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">상태</th>
|
||||
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">액션</th>
|
||||
</tr>
|
||||
@@ -179,6 +182,41 @@ class="commission-checkbox rounded border-gray-300 text-emerald-600 focus:ring-e
|
||||
<td class="px-4 py-3 text-center text-sm text-gray-500">
|
||||
{{ $commission->scheduled_payment_date->format('Y-m-d') }}
|
||||
</td>
|
||||
{{-- 수당지급일 (deposit→first_partner_paid_at, balance→second_partner_paid_at) --}}
|
||||
@php
|
||||
$paidField = $commission->payment_type === 'deposit' ? 'first_partner_paid_at' : 'second_partner_paid_at';
|
||||
$paidValue = $commission->$paidField?->format('Y-m-d');
|
||||
@endphp
|
||||
<td class="px-1 py-2 whitespace-nowrap text-center">
|
||||
<input type="date"
|
||||
class="w-28 h-7 text-xs px-1 border border-gray-300 rounded cursor-pointer hover:border-blue-400 focus:outline-none focus:border-blue-500 {{ $paidValue ? 'text-blue-600 font-medium bg-blue-50 border-blue-400' : 'text-gray-500 bg-gray-50' }}"
|
||||
value="{{ $paidValue }}"
|
||||
onchange="saveSettlementDate({{ $commission->id }}, '{{ $paidField }}', this.value)">
|
||||
</td>
|
||||
{{-- 매니저지급일 --}}
|
||||
<td class="px-1 py-2 whitespace-nowrap text-center">
|
||||
@if($isGroup)
|
||||
<span class="text-xs text-gray-400">-</span>
|
||||
@else
|
||||
<input type="date"
|
||||
class="w-28 h-7 text-xs px-1 border border-gray-300 rounded cursor-pointer hover:border-purple-400 focus:outline-none focus:border-purple-500 {{ $commission->manager_paid_at ? 'text-purple-600 font-medium bg-purple-50 border-purple-400' : 'text-gray-500 bg-gray-50' }}"
|
||||
value="{{ $commission->manager_paid_at?->format('Y-m-d') }}"
|
||||
onchange="saveSettlementDate({{ $commission->id }}, 'manager_paid_at', this.value)">
|
||||
@endif
|
||||
</td>
|
||||
{{-- 협업지원금 --}}
|
||||
<td class="px-1 py-2 whitespace-nowrap text-center">
|
||||
@if(!$isGroup)
|
||||
<input type="number"
|
||||
class="w-20 h-7 text-xs px-1 border border-gray-300 rounded cursor-pointer hover:border-orange-400 focus:outline-none focus:border-orange-500 {{ ($commission->referrer_commission ?? 0) > 0 ? 'text-orange-600 font-medium bg-orange-50 border-orange-400' : 'text-gray-500 bg-gray-50' }}"
|
||||
value="{{ ($commission->referrer_commission ?? 0) > 0 ? intval($commission->referrer_commission) : '' }}"
|
||||
placeholder="0"
|
||||
min="0"
|
||||
onchange="saveSettlementDate({{ $commission->id }}, 'referrer_commission', this.value)">
|
||||
@else
|
||||
<span class="text-xs text-gray-400">-</span>
|
||||
@endif
|
||||
</td>
|
||||
<td class="px-4 py-3 text-center">
|
||||
@php
|
||||
$statusColors = [
|
||||
@@ -235,7 +273,7 @@ class="p-1 text-green-400 hover:text-green-600"
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="15" class="px-4 py-8 text-center text-gray-500">
|
||||
<td colspan="18" class="px-4 py-8 text-center text-gray-500">
|
||||
등록된 정산 내역이 없습니다.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -336,57 +336,7 @@ function confirmDelete() {
|
||||
});
|
||||
}
|
||||
|
||||
// 협업지원금 저장
|
||||
function saveReferrerCommission(prospectId, amount) {
|
||||
const input = document.querySelector(`input[data-prospect-id="${prospectId}"][data-field="referrer_commission"]`);
|
||||
const numAmount = parseInt(amount) || 0;
|
||||
|
||||
fetch(`/sales/admin-prospects/${prospectId}/referrer-commission`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ amount: numAmount })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
if (result.success && input) {
|
||||
if (numAmount > 0) {
|
||||
input.value = result.amount;
|
||||
input.className = input.className.replace(/text-gray-500 bg-gray-50/g, '').replace(/text-orange-600 font-medium bg-orange-50 border-orange-400/g, '');
|
||||
input.classList.add('text-orange-600', 'font-medium', 'bg-orange-50', 'border-orange-400');
|
||||
} else {
|
||||
input.value = '';
|
||||
input.className = input.className.replace(/text-orange-600 font-medium bg-orange-50 border-orange-400/g, '');
|
||||
input.classList.add('text-gray-500', 'bg-gray-50');
|
||||
}
|
||||
} else if (!result.success) {
|
||||
alert(result.message || '협업지원금 저장에 실패했습니다.');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('협업지원금 저장 중 오류가 발생했습니다.');
|
||||
});
|
||||
}
|
||||
|
||||
// 인계 상태 체크 (수당지급 필드만)
|
||||
const commissionPaidFields = ['first_partner_paid_at', 'second_partner_paid_at', 'manager_paid_at'];
|
||||
|
||||
function checkHandoverStatus(prospectId, field) {
|
||||
if (!commissionPaidFields.includes(field)) return true;
|
||||
|
||||
const hqSelect = document.querySelector(`select[data-hq-status="${prospectId}"]`);
|
||||
if (hqSelect && hqSelect.value !== 'handover') {
|
||||
alert('개발상태가 인계일 때만 수당이 지급됩니다.');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 수당 날짜 저장 (date input에서 호출)
|
||||
// 납입 날짜 저장 (date input에서 호출)
|
||||
function saveCommissionDate(prospectId, field, date) {
|
||||
const input = document.querySelector(`input[data-prospect-id="${prospectId}"][data-field="${field}"]`);
|
||||
|
||||
@@ -396,12 +346,6 @@ function saveCommissionDate(prospectId, field, date) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 수당지급일 입력 시 인계 상태 체크
|
||||
if (!checkHandoverStatus(prospectId, field)) {
|
||||
input.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/sales/admin-prospects/${prospectId}/commission-date`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@@ -474,22 +418,9 @@ function updateInputStyle(input, field, hasValue) {
|
||||
input.className = 'commission-date-input w-24 text-xs px-1 py-1 border border-gray-200 rounded text-center focus:outline-none focus:ring-1';
|
||||
|
||||
if (hasValue) {
|
||||
if (field === 'first_payment_at' || field === 'second_payment_at') {
|
||||
input.className += ' text-emerald-600 font-medium bg-emerald-50 focus:ring-emerald-500 focus:border-emerald-500';
|
||||
} else if (field === 'first_partner_paid_at' || field === 'second_partner_paid_at') {
|
||||
input.className += ' text-blue-600 font-medium bg-blue-50 focus:ring-blue-500 focus:border-blue-500';
|
||||
} else if (field === 'manager_paid_at') {
|
||||
input.className += ' text-purple-600 font-medium bg-purple-50 focus:ring-purple-500 focus:border-purple-500';
|
||||
}
|
||||
input.className += ' text-emerald-600 font-medium bg-emerald-50 focus:ring-emerald-500 focus:border-emerald-500';
|
||||
} else {
|
||||
input.className += ' text-gray-400 bg-white';
|
||||
if (field === 'first_payment_at' || field === 'second_payment_at') {
|
||||
input.className += ' focus:ring-emerald-500 focus:border-emerald-500';
|
||||
} else if (field === 'first_partner_paid_at' || field === 'second_partner_paid_at') {
|
||||
input.className += ' focus:ring-blue-500 focus:border-blue-500';
|
||||
} else if (field === 'manager_paid_at') {
|
||||
input.className += ' focus:ring-purple-500 focus:border-purple-500';
|
||||
}
|
||||
input.className += ' text-gray-400 bg-white focus:ring-emerald-500 focus:border-emerald-500';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -89,15 +89,11 @@ class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none foc
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">담당 매니저</th>
|
||||
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">영업 진행률</th>
|
||||
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">매니저 진행률</th>
|
||||
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">계약일</th>
|
||||
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">1차 납입</th>
|
||||
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">1차 수당</th>
|
||||
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">2차 납입</th>
|
||||
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">2차 수당</th>
|
||||
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">매니저 수당</th>
|
||||
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">협업지원금</th>
|
||||
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">개발 상태</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">상태</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">등록일</th>
|
||||
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">관리</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -150,6 +146,10 @@ class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none foc
|
||||
$isCorporate = ($prospect->partner_type ?? 'individual') === 'corporate';
|
||||
$disabledClass = $commissionDisabled ? 'opacity-40 cursor-not-allowed bg-gray-100' : '';
|
||||
@endphp
|
||||
{{-- 계약일 --}}
|
||||
<td class="px-4 py-3 whitespace-nowrap text-center text-sm text-gray-500">
|
||||
{{ $prospect->contracted_at ? \Carbon\Carbon::parse($prospect->contracted_at)->format('Y-m-d') : '-' }}
|
||||
</td>
|
||||
{{-- 1차 납입완료 --}}
|
||||
<td class="px-1 py-2 whitespace-nowrap text-center">
|
||||
<input type="date"
|
||||
@@ -160,16 +160,6 @@ class="w-28 h-7 text-xs px-1 border-2 border-gray-300 rounded {{ $commissionDisa
|
||||
{{ $commissionDisabled ? 'disabled' : '' }}
|
||||
onchange="saveCommissionDate({{ $prospect->id }}, 'first_payment_at', this.value)">
|
||||
</td>
|
||||
{{-- 1차 파트너 수당지급 --}}
|
||||
<td class="px-1 py-2 whitespace-nowrap text-center">
|
||||
<input type="date"
|
||||
class="w-28 h-7 text-xs px-1 border-2 border-gray-300 rounded {{ $commissionDisabled ? $disabledClass : 'cursor-pointer hover:border-blue-400' }} focus:outline-none focus:border-blue-500 {{ !$commissionDisabled && $prospect->commission?->first_partner_paid_at ? 'text-blue-600 font-medium bg-blue-50 border-blue-400' : (!$commissionDisabled ? 'text-gray-500 bg-gray-50' : '') }}"
|
||||
value="{{ $prospect->commission?->first_partner_paid_at?->format('Y-m-d') }}"
|
||||
data-prospect-id="{{ $prospect->id }}"
|
||||
data-field="first_partner_paid_at"
|
||||
{{ $commissionDisabled ? 'disabled' : '' }}
|
||||
onchange="saveCommissionDate({{ $prospect->id }}, 'first_partner_paid_at', this.value)">
|
||||
</td>
|
||||
{{-- 2차 납입완료 --}}
|
||||
<td class="px-1 py-2 whitespace-nowrap text-center">
|
||||
<input type="date"
|
||||
@@ -180,47 +170,6 @@ class="w-28 h-7 text-xs px-1 border-2 border-gray-300 rounded {{ $commissionDisa
|
||||
{{ $commissionDisabled ? 'disabled' : '' }}
|
||||
onchange="saveCommissionDate({{ $prospect->id }}, 'second_payment_at', this.value)">
|
||||
</td>
|
||||
{{-- 2차 파트너 수당지급 --}}
|
||||
<td class="px-1 py-2 whitespace-nowrap text-center">
|
||||
<input type="date"
|
||||
class="w-28 h-7 text-xs px-1 border-2 border-gray-300 rounded {{ $commissionDisabled ? $disabledClass : 'cursor-pointer hover:border-blue-400' }} focus:outline-none focus:border-blue-500 {{ !$commissionDisabled && $prospect->commission?->second_partner_paid_at ? 'text-blue-600 font-medium bg-blue-50 border-blue-400' : (!$commissionDisabled ? 'text-gray-500 bg-gray-50' : '') }}"
|
||||
value="{{ $prospect->commission?->second_partner_paid_at?->format('Y-m-d') }}"
|
||||
data-prospect-id="{{ $prospect->id }}"
|
||||
data-field="second_partner_paid_at"
|
||||
{{ $commissionDisabled ? 'disabled' : '' }}
|
||||
onchange="saveCommissionDate({{ $prospect->id }}, 'second_partner_paid_at', this.value)">
|
||||
</td>
|
||||
{{-- 매니저 수당지급 --}}
|
||||
{{-- 매니저 수당지급 (단체는 해당없음) --}}
|
||||
<td class="px-1 py-2 whitespace-nowrap text-center">
|
||||
@if($isCorporate)
|
||||
<span class="text-xs text-gray-400">-</span>
|
||||
@else
|
||||
<input type="date"
|
||||
class="w-28 h-7 text-xs px-1 border-2 border-gray-300 rounded {{ $commissionDisabled ? $disabledClass : 'cursor-pointer hover:border-purple-400' }} focus:outline-none focus:border-purple-500 {{ !$commissionDisabled && $prospect->commission?->manager_paid_at ? 'text-purple-600 font-medium bg-purple-50 border-purple-400' : (!$commissionDisabled ? 'text-gray-500 bg-gray-50' : '') }}"
|
||||
value="{{ $prospect->commission?->manager_paid_at?->format('Y-m-d') }}"
|
||||
data-prospect-id="{{ $prospect->id }}"
|
||||
data-field="manager_paid_at"
|
||||
{{ $commissionDisabled ? 'disabled' : '' }}
|
||||
onchange="saveCommissionDate({{ $prospect->id }}, 'manager_paid_at', this.value)">
|
||||
@endif
|
||||
</td>
|
||||
{{-- 협업지원금 --}}
|
||||
<td class="px-1 py-2 whitespace-nowrap text-center">
|
||||
@if(($prospect->partner_type ?? 'individual') !== 'corporate')
|
||||
<input type="number"
|
||||
class="w-20 h-7 text-xs px-1 border-2 border-gray-300 rounded {{ $commissionDisabled ? $disabledClass : 'cursor-pointer hover:border-orange-400' }} focus:outline-none focus:border-orange-500 {{ !$commissionDisabled && ($prospect->commission?->referrer_commission ?? 0) > 0 ? 'text-orange-600 font-medium bg-orange-50 border-orange-400' : (!$commissionDisabled ? 'text-gray-500 bg-gray-50' : '') }}"
|
||||
value="{{ ($prospect->commission?->referrer_commission ?? 0) > 0 ? intval($prospect->commission->referrer_commission) : '' }}"
|
||||
placeholder="0"
|
||||
min="0"
|
||||
data-prospect-id="{{ $prospect->id }}"
|
||||
data-field="referrer_commission"
|
||||
{{ $commissionDisabled ? 'disabled' : '' }}
|
||||
onchange="saveReferrerCommission({{ $prospect->id }}, this.value)">
|
||||
@else
|
||||
<span class="text-xs text-gray-400">-</span>
|
||||
@endif
|
||||
</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap text-center">
|
||||
<select
|
||||
data-hq-status="{{ $prospect->id }}"
|
||||
@@ -250,9 +199,6 @@ class="px-2 py-1 text-xs font-medium rounded-full cursor-pointer hover:opacity-8
|
||||
</span>
|
||||
@endif
|
||||
</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-500">
|
||||
{{ $prospect->created_at->format('Y-m-d') }}
|
||||
</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap text-right text-sm font-medium">
|
||||
<div class="flex items-center justify-end gap-2">
|
||||
<button type="button" onclick="openDetailModal({{ $prospect->id }})" class="text-blue-600 hover:text-blue-900">상세</button>
|
||||
@@ -271,7 +217,7 @@ class="text-red-500 hover:text-red-700"
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="16" class="px-6 py-12 text-center text-gray-500">
|
||||
<td colspan="12" class="px-6 py-12 text-center text-gray-500">
|
||||
등록된 고객이 없습니다.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -1025,6 +1025,7 @@
|
||||
Route::post('/{id}/approve', [\App\Http\Controllers\Finance\SalesCommissionController::class, 'approve'])->name('approve');
|
||||
Route::post('/{id}/mark-paid', [\App\Http\Controllers\Finance\SalesCommissionController::class, 'markPaid'])->name('mark-paid');
|
||||
Route::post('/{id}/cancel', [\App\Http\Controllers\Finance\SalesCommissionController::class, 'cancel'])->name('cancel');
|
||||
Route::put('/{id}/update-date', [\App\Http\Controllers\Finance\SalesCommissionController::class, 'updateCommissionDate'])->name('update-date');
|
||||
});
|
||||
|
||||
// 기존 URL 리다이렉트 → 통합 정산관리
|
||||
|
||||
Reference in New Issue
Block a user