diff --git a/app/Http/Controllers/Finance/SettlementController.php b/app/Http/Controllers/Finance/SettlementController.php index 7b6692c3..3d79c6da 100644 --- a/app/Http/Controllers/Finance/SettlementController.php +++ b/app/Http/Controllers/Finance/SettlementController.php @@ -180,6 +180,143 @@ public function subscriptionTab(Request $request): View return view('finance.settlement.partials.subscription-tab'); } + /** + * 수당 지급 탭 (파트너별 그룹핑) + */ + public function paymentTab(Request $request): View + { + // approved 상태 수당을 partner_id 기준 GROUP BY + $partnerPayments = SalesCommission::where('status', SalesCommission::STATUS_APPROVED) + ->selectRaw(' + partner_id, + GROUP_CONCAT(id) as commission_ids, + COUNT(*) as count, + SUM(partner_commission) as partner_total, + SUM(manager_commission) as manager_total, + SUM(COALESCE(referrer_commission, 0)) as referrer_total + ') + ->groupBy('partner_id') + ->get(); + + // 파트너 정보 eager load + $partners = SalesPartner::with('user') + ->whereIn('id', $partnerPayments->pluck('partner_id')) + ->get() + ->keyBy('id'); + + // 통계 카드 데이터 + $now = now(); + $paymentStats = [ + 'waiting_count' => $partnerPayments->sum('count'), + 'waiting_amount' => $partnerPayments->sum(fn ($p) => $p->partner_total + $p->manager_total + $p->referrer_total), + 'this_month_paid_count' => SalesCommission::where('status', SalesCommission::STATUS_PAID) + ->whereYear('actual_payment_date', $now->year) + ->whereMonth('actual_payment_date', $now->month) + ->count(), + 'this_month_paid_amount' => SalesCommission::where('status', SalesCommission::STATUS_PAID) + ->whereYear('actual_payment_date', $now->year) + ->whereMonth('actual_payment_date', $now->month) + ->selectRaw('SUM(partner_commission + manager_commission + COALESCE(referrer_commission, 0)) as total') + ->value('total') ?? 0, + 'partner_total' => $partnerPayments->sum('partner_total'), + 'manager_referrer_total' => $partnerPayments->sum('manager_total') + $partnerPayments->sum('referrer_total'), + ]; + + return view('finance.settlement.partials.payment-tab', compact('partnerPayments', 'partners', 'paymentStats')); + } + + /** + * 파트너별 수당 건 상세 (HTMX partial) + */ + public function paymentPartnerDetail(int $partnerId): View + { + $commissions = SalesCommission::where('status', SalesCommission::STATUS_APPROVED) + ->where('partner_id', $partnerId) + ->with(['management.tenant', 'manager']) + ->orderBy('scheduled_payment_date') + ->get(); + + return view('finance.settlement.partials.payment-partner-detail', compact('commissions', 'partnerId')); + } + + /** + * 수당지급현황통계 페이지 + */ + public function paymentStats(Request $request): View|Response + { + if ($request->header('HX-Request') && !$request->header('HX-Boosted')) { + return response('', 200)->header('HX-Redirect', route('finance.settlement.payment-stats')); + } + + $year = (int) $request->input('year', now()->year); + + // 통계 카드 + $totalPaidAmount = SalesCommission::where('status', SalesCommission::STATUS_PAID) + ->whereYear('actual_payment_date', $year) + ->selectRaw('SUM(partner_commission + manager_commission + COALESCE(referrer_commission, 0)) as total') + ->value('total') ?? 0; + + $totalPaidCount = SalesCommission::where('status', SalesCommission::STATUS_PAID) + ->whereYear('actual_payment_date', $year) + ->count(); + + $activePartners = SalesCommission::where('status', SalesCommission::STATUS_PAID) + ->whereYear('actual_payment_date', $year) + ->distinct('partner_id') + ->count('partner_id'); + + $avgCommission = $totalPaidCount > 0 ? round($totalPaidAmount / $totalPaidCount) : 0; + + $statsCards = [ + 'total_paid_amount' => $totalPaidAmount, + 'total_paid_count' => $totalPaidCount, + 'active_partners' => $activePartners, + 'avg_commission' => $avgCommission, + ]; + + // 차트 1 & 4: 월별 지급 추이 (해당 연도) + $monthlyTrend = SalesCommission::where('status', SalesCommission::STATUS_PAID) + ->whereYear('actual_payment_date', $year) + ->selectRaw(" + DATE_FORMAT(actual_payment_date, '%Y-%m') as month, + SUM(partner_commission) as partner_total, + SUM(manager_commission) as manager_total, + SUM(COALESCE(referrer_commission, 0)) as referrer_total, + COUNT(*) as count + ") + ->groupByRaw("DATE_FORMAT(actual_payment_date, '%Y-%m')") + ->orderBy('month') + ->get(); + + // 차트 2: 수당 유형별 비율 + $typeRatio = SalesCommission::where('status', SalesCommission::STATUS_PAID) + ->whereYear('actual_payment_date', $year) + ->selectRaw(" + SUM(partner_commission) as partner_total, + SUM(manager_commission) as manager_total, + SUM(COALESCE(referrer_commission, 0)) as referrer_total + ") + ->first(); + + // 차트 3: 파트너별 수당 Top 10 + $topPartners = SalesCommission::where('status', SalesCommission::STATUS_PAID) + ->whereYear('actual_payment_date', $year) + ->selectRaw('partner_id, SUM(partner_commission + manager_commission + COALESCE(referrer_commission, 0)) as total') + ->groupBy('partner_id') + ->orderByDesc('total') + ->limit(10) + ->get(); + + $topPartnerNames = SalesPartner::with('user') + ->whereIn('id', $topPartners->pluck('partner_id')) + ->get() + ->keyBy('id'); + + return view('finance.settlement.payment-stats', compact( + 'year', 'statsCards', 'monthlyTrend', 'typeRatio', 'topPartners', 'topPartnerNames' + )); + } + /** * 통합 통계 데이터 */ diff --git a/resources/views/finance/settlement/index.blade.php b/resources/views/finance/settlement/index.blade.php index 6adcd13f..e04b4e96 100644 --- a/resources/views/finance/settlement/index.blade.php +++ b/resources/views/finance/settlement/index.blade.php @@ -42,6 +42,15 @@ class="inline-flex items-center gap-2 px-4 py-2 bg-gray-600 hover:bg-gray-700 te class="border-b-2 py-3 px-4 text-sm font-medium whitespace-nowrap transition-colors"> 수당 정산 + + + + + + + 지급현황통계 + + + + {{-- 파트너별 지급 대기 테이블 --}} +
+
+ + + + + + + + + + + + + + + + + @forelse ($partnerPayments as $pp) + @php + $partner = $partners->get($pp->partner_id); + $totalAmount = $pp->partner_total + $pp->manager_total + $pp->referrer_total; + @endphp + @if ($partner) + + + + + + + + + + + + + {{-- 확장 영역: 파트너별 상세 건 목록 --}} + + + + @endif + @empty + + + + @endforelse + +
+ + 파트너유형계좌정보건수파트너수당매니저수당유치수당총액액션
+ + + + + @if ($partner->partner_type === 'corporate') + 단체 + @else + 개인 + @endif + + @if ($partner->bank_name && $partner->account_number) + {{ $partner->bank_name }} {{ $partner->account_number }} +
{{ $partner->account_holder }}
+ @else + 계좌 미등록 + @endif +
{{ $pp->count }}건{{ number_format($pp->partner_total) }}원{{ number_format($pp->manager_total) }}원{{ number_format($pp->referrer_total) }}원{{ number_format($totalAmount) }}원 + +
+
+
+ + + +

지급 대기 건이 없습니다

+

모든 승인된 수당이 지급 처리되었습니다.

+
+
+
+ + +{{-- 지급완료 모달 --}} + + + diff --git a/resources/views/finance/settlement/payment-stats.blade.php b/resources/views/finance/settlement/payment-stats.blade.php new file mode 100644 index 00000000..5ebb04ad --- /dev/null +++ b/resources/views/finance/settlement/payment-stats.blade.php @@ -0,0 +1,349 @@ +@extends('layouts.app') + +@section('title', '수당지급현황통계') + +@section('content') +
+ {{-- 페이지 헤더 --}} +
+
+

수당지급현황통계

+

{{ $year }}년 수당 지급 현황 종합 통계

+
+
+ + + + + 정산관리 + +
+ + +
+
+
+ + {{-- 통계 카드 --}} +
+
+
+
+

총 지급액

+

{{ number_format($statsCards['total_paid_amount']) }}원

+
+
+ + + +
+
+

{{ $year }}년 지급 합계

+
+ +
+
+
+

총 지급 건수

+

{{ number_format($statsCards['total_paid_count']) }}건

+
+
+ + + +
+
+

{{ $year }}년 총 건수

+
+ +
+
+
+

지급 파트너 수

+

{{ $statsCards['active_partners'] }}명

+
+
+ + + +
+
+

{{ $year }}년 지급 대상

+
+ +
+
+
+

건당 평균 수당

+

{{ number_format($statsCards['avg_commission']) }}원

+
+
+ + + +
+
+

전체 평균

+
+
+ + {{-- 차트 영역 --}} +
+ {{-- 차트 1: 월별 지급 추이 (Stacked Bar) --}} +
+

월별 지급 추이

+
+ +
+
+ + {{-- 차트 2: 수당 유형별 비율 (Doughnut) --}} +
+

수당 유형별 비율

+
+ +
+
+ + {{-- 차트 3: 파트너별 수당 Top 10 (Horizontal Bar) --}} +
+

파트너별 수당 Top 10

+
+ +
+
+ + {{-- 차트 4: 월별 지급 건수 추이 (Line) --}} +
+

월별 지급 건수 추이

+
+ +
+
+
+ + {{-- 월별 지급 요약 테이블 --}} +
+
+

월별 지급 요약

+
+
+ + + + + + + + + + + + + @php $grandPartner = 0; $grandManager = 0; $grandReferrer = 0; $grandTotal = 0; $grandCount = 0; @endphp + @forelse ($monthlyTrend->reverse() as $row) + @php + $rowTotal = $row->partner_total + $row->manager_total + $row->referrer_total; + $grandPartner += $row->partner_total; + $grandManager += $row->manager_total; + $grandReferrer += $row->referrer_total; + $grandTotal += $rowTotal; + $grandCount += $row->count; + @endphp + + + + + + + + + @empty + + + + @endforelse + @if ($monthlyTrend->isNotEmpty()) + + + + + + + + + @endif + +
파트너수당매니저수당유치수당합계건수
{{ \Carbon\Carbon::parse($row->month . '-01')->format('n월') }}{{ number_format($row->partner_total) }}원{{ number_format($row->manager_total) }}원{{ number_format($row->referrer_total) }}원{{ number_format($rowTotal) }}원{{ $row->count }}건
{{ $year }}년 지급 데이터가 없습니다.
합계{{ number_format($grandPartner) }}원{{ number_format($grandManager) }}원{{ number_format($grandReferrer) }}원{{ number_format($grandTotal) }}원{{ $grandCount }}건
+
+
+
+@endsection + +@push('scripts') + + +@endpush diff --git a/routes/web.php b/routes/web.php index 0e40b364..df06d3b7 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1002,6 +1002,9 @@ Route::get('/settlement/consulting', [\App\Http\Controllers\Finance\SettlementController::class, 'consultingTab'])->name('settlement.consulting'); Route::get('/settlement/customer', [\App\Http\Controllers\Finance\SettlementController::class, 'customerTab'])->name('settlement.customer'); Route::get('/settlement/subscription', [\App\Http\Controllers\Finance\SettlementController::class, 'subscriptionTab'])->name('settlement.subscription'); + Route::get('/settlement/payment', [\App\Http\Controllers\Finance\SettlementController::class, 'paymentTab'])->name('settlement.payment'); + Route::get('/settlement/payment-partner-detail/{partnerId}', [\App\Http\Controllers\Finance\SettlementController::class, 'paymentPartnerDetail'])->name('settlement.payment-partner-detail'); + Route::get('/settlement/payment-stats', [\App\Http\Controllers\Finance\SettlementController::class, 'paymentStats'])->name('settlement.payment-stats'); // 영업수수료정산 (실제 구현 - CRUD API는 그대로 유지) Route::prefix('sales-commissions')->name('sales-commissions.')->group(function () {