From 7bc412d9a1ed28573aa480f787530aebe5200085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=B4=EA=B3=A4?= Date: Thu, 19 Feb 2026 09:53:13 +0900 Subject: [PATCH] =?UTF-8?q?feat:=ED=86=B5=ED=95=A9=20=EC=A0=95=EC=82=B0?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(5=EA=B0=9C=20=ED=83=AD=20=EA=B8=B0=EB=B0=98)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SettlementController 신규 생성 (통합 정산관리 메인 + 탭별 HTMX) - 5개 탭: 수당정산, 파트너별현황(NEW), 컨설팅비용, 고객사정산, 구독관리 - 수당정산 탭: 기존 영업수수료정산 이관 + 유치수당 컬럼/수당유형 필터 추가 - 파트너별 현황 탭: SalesPartner 수당 집계 + 필터/페이지네이션 - 컨설팅/고객사/구독 탭: React → Blade+Alpine.js 전환 (기존 API 재사용) - 통합 통계카드 (미지급수당/승인대기/이번달예정/누적지급) - 기존 4개 URL → 통합 페이지 리다이렉트 - SalesPartner 모델에 commissions 관계 추가 - SalesCommissionService에 commission_type 필터 + referrerPartner eager load 추가 Co-Authored-By: Claude Opus 4.6 --- .../Finance/SettlementController.php | 222 +++++++++++ app/Models/Sales/SalesPartner.php | 9 + app/Services/SalesCommissionService.php | 15 +- .../views/finance/settlement/index.blade.php | 372 ++++++++++++++++++ .../commission/detail-modal.blade.php | 183 +++++++++ .../partials/commission/filters.blade.php | 85 ++++ .../commission/payment-form.blade.php | 163 ++++++++ .../partials/commission/stats-cards.blade.php | 76 ++++ .../partials/commission/table.blade.php | 154 ++++++++ .../partials/consulting-tab.blade.php | 179 +++++++++ .../partials/customer-tab.blade.php | 183 +++++++++ .../partials/partner-summary.blade.php | 118 ++++++ .../partials/subscription-tab.blade.php | 202 ++++++++++ .../partials/summary-stats.blade.php | 66 ++++ routes/web.php | 39 +- 15 files changed, 2041 insertions(+), 25 deletions(-) create mode 100644 app/Http/Controllers/Finance/SettlementController.php create mode 100644 resources/views/finance/settlement/index.blade.php create mode 100644 resources/views/finance/settlement/partials/commission/detail-modal.blade.php create mode 100644 resources/views/finance/settlement/partials/commission/filters.blade.php create mode 100644 resources/views/finance/settlement/partials/commission/payment-form.blade.php create mode 100644 resources/views/finance/settlement/partials/commission/stats-cards.blade.php create mode 100644 resources/views/finance/settlement/partials/commission/table.blade.php create mode 100644 resources/views/finance/settlement/partials/consulting-tab.blade.php create mode 100644 resources/views/finance/settlement/partials/customer-tab.blade.php create mode 100644 resources/views/finance/settlement/partials/partner-summary.blade.php create mode 100644 resources/views/finance/settlement/partials/subscription-tab.blade.php create mode 100644 resources/views/finance/settlement/partials/summary-stats.blade.php diff --git a/app/Http/Controllers/Finance/SettlementController.php b/app/Http/Controllers/Finance/SettlementController.php new file mode 100644 index 00000000..7b6692c3 --- /dev/null +++ b/app/Http/Controllers/Finance/SettlementController.php @@ -0,0 +1,222 @@ +header('HX-Request') && !$request->header('HX-Boosted')) { + return response('', 200)->header('HX-Redirect', route('finance.settlement')); + } + + $initialTab = $request->input('tab', 'commission'); + + // 수당 정산 탭 데이터 (기본 탭이므로 즉시 로드) + $year = $request->input('year', now()->year); + $month = $request->input('month', now()->month); + + $filters = [ + 'scheduled_year' => $year, + 'scheduled_month' => $month, + 'status' => $request->input('status'), + 'payment_type' => $request->input('payment_type'), + 'partner_id' => $request->input('partner_id'), + 'commission_type' => $request->input('commission_type'), + 'search' => $request->input('search'), + ]; + + $commissions = $this->service->getCommissions($filters); + $stats = $this->service->getSettlementStats($year, $month); + + $partners = SalesPartner::with('user') + ->active() + ->orderBy('partner_code') + ->get(); + + $pendingTenants = $this->service->getPendingPaymentTenants(); + + // 통합 통계 (페이지 상단) + $summaryStats = $this->getSummaryStats(); + + return view('finance.settlement.index', compact( + 'initialTab', + 'commissions', + 'stats', + 'partners', + 'pendingTenants', + 'year', + 'month', + 'filters', + 'summaryStats' + )); + } + + /** + * 수당 통계카드 HTMX 갱신 + */ + public function commissionStats(Request $request): View + { + $year = $request->input('year', now()->year); + $month = $request->input('month', now()->month); + $stats = $this->service->getSettlementStats($year, $month); + + return view('finance.settlement.partials.commission.stats-cards', compact('stats', 'year', 'month')); + } + + /** + * 수당 테이블 HTMX 갱신 + */ + public function commissionTable(Request $request): View + { + $year = $request->input('year', now()->year); + $month = $request->input('month', now()->month); + + $filters = [ + 'scheduled_year' => $year, + 'scheduled_month' => $month, + 'status' => $request->input('status'), + 'payment_type' => $request->input('payment_type'), + 'partner_id' => $request->input('partner_id'), + 'commission_type' => $request->input('commission_type'), + 'search' => $request->input('search'), + ]; + + $commissions = $this->service->getCommissions($filters); + + return view('finance.settlement.partials.commission.table', compact('commissions')); + } + + /** + * 파트너별 현황 탭 + */ + public function partnerSummary(Request $request): View + { + $query = SalesPartner::with('user'); + + // 검색 + if ($search = $request->input('search')) { + $query->where(function ($q) use ($search) { + $q->where('partner_code', 'like', "%{$search}%") + ->orWhereHas('user', function ($uq) use ($search) { + $uq->where('name', 'like', "%{$search}%"); + }); + }); + } + + // 유형 필터 + if ($type = $request->input('type')) { + if ($type === 'individual') { + $query->where('partner_type', '!=', 'corporate'); + } elseif ($type === 'corporate') { + $query->where('partner_type', 'corporate'); + } + } + + // 상태 필터 + if ($request->input('status', 'active') === 'active') { + $query->active(); + } + + $partners = $query->orderBy('partner_code')->paginate(20); + + // 각 파트너별 수당 집계 + $partnerIds = $partners->pluck('id')->toArray(); + if (!empty($partnerIds)) { + $commissionStats = SalesCommission::selectRaw(' + partner_id, + SUM(CASE WHEN status = "paid" THEN partner_commission ELSE 0 END) as paid_total, + SUM(CASE WHEN status IN ("pending", "approved") THEN partner_commission ELSE 0 END) as unpaid_total, + COUNT(*) as total_count, + MAX(CASE WHEN status = "paid" THEN actual_payment_date ELSE NULL END) as last_paid_date + ') + ->whereIn('partner_id', $partnerIds) + ->groupBy('partner_id') + ->get() + ->keyBy('partner_id'); + } else { + $commissionStats = collect(); + } + + return view('finance.settlement.partials.partner-summary', compact('partners', 'commissionStats')); + } + + /** + * 컨설팅비용 탭 + */ + public function consultingTab(Request $request): View + { + return view('finance.settlement.partials.consulting-tab'); + } + + /** + * 고객사정산 탭 + */ + public function customerTab(Request $request): View + { + return view('finance.settlement.partials.customer-tab'); + } + + /** + * 구독관리 탭 + */ + public function subscriptionTab(Request $request): View + { + return view('finance.settlement.partials.subscription-tab'); + } + + /** + * 통합 통계 데이터 + */ + private function getSummaryStats(): array + { + $now = now(); + + // 미지급 수당 (pending + approved) + $unpaidAmount = SalesCommission::whereIn('status', [ + SalesCommission::STATUS_PENDING, + SalesCommission::STATUS_APPROVED, + ])->selectRaw('SUM(partner_commission + manager_commission + COALESCE(referrer_commission, 0)) as total') + ->value('total') ?? 0; + + // 승인 대기 건수 + $pendingCount = SalesCommission::where('status', SalesCommission::STATUS_PENDING)->count(); + + // 이번달 지급예정 + $thisMonthScheduled = SalesCommission::whereIn('status', [ + SalesCommission::STATUS_PENDING, + SalesCommission::STATUS_APPROVED, + ]) + ->whereYear('scheduled_payment_date', $now->year) + ->whereMonth('scheduled_payment_date', $now->month) + ->selectRaw('SUM(partner_commission + manager_commission + COALESCE(referrer_commission, 0)) as total') + ->value('total') ?? 0; + + // 누적 지급완료 + $totalPaid = SalesCommission::where('status', SalesCommission::STATUS_PAID) + ->selectRaw('SUM(partner_commission + manager_commission + COALESCE(referrer_commission, 0)) as total') + ->value('total') ?? 0; + + return [ + 'unpaid_amount' => $unpaidAmount, + 'pending_count' => $pendingCount, + 'this_month_scheduled' => $thisMonthScheduled, + 'total_paid' => $totalPaid, + ]; + } +} diff --git a/app/Models/Sales/SalesPartner.php b/app/Models/Sales/SalesPartner.php index 9d853e39..06334b42 100644 --- a/app/Models/Sales/SalesPartner.php +++ b/app/Models/Sales/SalesPartner.php @@ -2,6 +2,7 @@ namespace App\Models\Sales; +use App\Models\Sales\SalesCommission; use App\Models\User; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -86,6 +87,14 @@ public function tenantManagements(): HasMany return $this->hasMany(SalesTenantManagement::class, 'sales_partner_id'); } + /** + * 수수료 정산 내역 + */ + public function commissions(): HasMany + { + return $this->hasMany(SalesCommission::class, 'partner_id'); + } + /** * 이 단체를 유치한 영업파트너 */ diff --git a/app/Services/SalesCommissionService.php b/app/Services/SalesCommissionService.php index e01806d5..9502de54 100644 --- a/app/Services/SalesCommissionService.php +++ b/app/Services/SalesCommissionService.php @@ -32,7 +32,7 @@ class SalesCommissionService public function getCommissions(array $filters = [], int $perPage = 20): LengthAwarePaginator { $query = SalesCommission::query() - ->with(['tenant', 'partner.user', 'manager', 'management']); + ->with(['tenant', 'partner.user', 'manager', 'management', 'referrerPartner.user']); // 상태 필터 if (!empty($filters['status'])) { @@ -64,6 +64,19 @@ public function getCommissions(array $filters = [], int $perPage = 20): LengthAw $query->paymentDateBetween($filters['payment_start_date'], $filters['payment_end_date']); } + // 수당유형 필터 + if (!empty($filters['commission_type'])) { + $commissionType = $filters['commission_type']; + if ($commissionType === 'partner') { + $query->where('partner_commission', '>', 0); + } elseif ($commissionType === 'manager') { + $query->where('manager_commission', '>', 0); + } elseif ($commissionType === 'referrer') { + $query->whereNotNull('referrer_partner_id') + ->where('referrer_commission', '>', 0); + } + } + // 테넌트 검색 if (!empty($filters['search'])) { $search = $filters['search']; diff --git a/resources/views/finance/settlement/index.blade.php b/resources/views/finance/settlement/index.blade.php new file mode 100644 index 00000000..823362a6 --- /dev/null +++ b/resources/views/finance/settlement/index.blade.php @@ -0,0 +1,372 @@ +@extends('layouts.app') + +@section('title', '정산관리') + +@section('content') +
+ {{-- 페이지 헤더 --}} +
+
+

정산관리

+

통합 정산 현황

+
+
+ + + + + + 내보내기 + +
+
+ + {{-- 통합 통계 카드 --}} + @include('finance.settlement.partials.summary-stats', ['summaryStats' => $summaryStats]) + + {{-- 탭 네비게이션 --}} +
+ +
+ + {{-- 탭 1: 수당 정산 (즉시 렌더링) --}} +
+ {{-- 통계 카드 --}} +
+ @include('finance.settlement.partials.commission.stats-cards', ['stats' => $stats, 'year' => $year, 'month' => $month]) +
+ + {{-- 필터 --}} + @include('finance.settlement.partials.commission.filters', ['filters' => $filters, 'partners' => $partners, 'year' => $year, 'month' => $month]) + + {{-- 일괄 처리 버튼 --}} + + + {{-- 정산 테이블 --}} +
+ @include('finance.settlement.partials.commission.table', ['commissions' => $commissions]) +
+
+ + {{-- 탭 2: 파트너별 현황 (HTMX lazy load) --}} +
+
+
+ + + + + 로딩 중... +
+
+
+ + {{-- 탭 3: 컨설팅비용 (HTMX lazy load) --}} +
+
+
+ + + + + 로딩 중... +
+
+
+ + {{-- 탭 4: 고객사정산 (HTMX lazy load) --}} +
+
+
+ + + + + 로딩 중... +
+
+
+ + {{-- 탭 5: 구독관리 (HTMX lazy load) --}} +
+
+
+ + + + + 로딩 중... +
+
+
+
+ +{{-- 입금 등록 모달 --}} + + +{{-- 상세 모달 --}} + +@endsection + +@push('scripts') + +@endpush diff --git a/resources/views/finance/settlement/partials/commission/detail-modal.blade.php b/resources/views/finance/settlement/partials/commission/detail-modal.blade.php new file mode 100644 index 00000000..2a0dfcf7 --- /dev/null +++ b/resources/views/finance/settlement/partials/commission/detail-modal.blade.php @@ -0,0 +1,183 @@ +{{-- 정산 상세 모달 --}} +
+
+

정산 상세

+ +
+
+ +@if ($commission) +
+
+
+

테넌트

+

{{ $commission->tenant->name ?? $commission->tenant->company_name ?? '-' }}

+
+
+

상태

+ @php + $statusColors = [ + 'pending' => 'bg-yellow-100 text-yellow-800', + 'approved' => 'bg-blue-100 text-blue-800', + 'paid' => 'bg-green-100 text-green-800', + 'cancelled' => 'bg-red-100 text-red-800', + ]; + @endphp + + {{ $commission->status_label }} + +
+
+

입금 구분

+ + {{ $commission->payment_type_label }} + +
+
+

입금일

+

{{ $commission->payment_date->format('Y-m-d') }}

+
+
+ +
+

금액 정보

+
+
+ 입금액 + {{ number_format($commission->payment_amount) }}원 +
+
+ 수당 기준액 (개발비 50%) + {{ number_format($commission->base_amount) }}원 +
+
+
+ +
+

수당 정보

+
+
+
+ 영업파트너 + {{ $commission->partner?->user?->name ?? '-' }} +
+
+ {{ $commission->partner_rate }}% + {{ number_format($commission->partner_commission) }}원 +
+
+
+
+ 매니저 + {{ $commission->manager?->name ?? '-' }} +
+
+ {{ $commission->manager_rate }}% + {{ number_format($commission->manager_commission) }}원 +
+
+ @if ($commission->referrer_partner_id) +
+
+ 유치파트너 + {{ $commission->referrerPartner?->user?->name ?? '-' }} +
+
+ {{ $commission->referrer_rate }}% + {{ number_format($commission->referrer_commission) }}원 +
+
+ @endif +
+ 총 수당 + {{ number_format($commission->total_commission) }}원 +
+
+
+ +
+
+

지급예정일

+

{{ $commission->scheduled_payment_date->format('Y-m-d') }}

+
+
+

실제지급일

+

{{ $commission->actual_payment_date?->format('Y-m-d') ?? '-' }}

+
+
+ + @if ($commission->approved_at) +
+
+

승인자

+

{{ $commission->approver?->name ?? '-' }}

+
+
+

승인일시

+

{{ $commission->approved_at->format('Y-m-d H:i') }}

+
+
+ @endif + + @if ($commission->bank_reference) +
+

이체 참조번호

+

{{ $commission->bank_reference }}

+
+ @endif + + @if ($commission->notes) +
+

메모

+

{{ $commission->notes }}

+
+ @endif + + @if ($commission->details->count() > 0) +
+

상품별 수당 내역

+
+ + + + + + + + + + + @foreach ($commission->details as $detail) + + + + + + + @endforeach + +
상품개발비파트너수당매니저수당
{{ $detail->contractProduct?->product?->name ?? '-' }}{{ number_format($detail->registration_fee) }}원{{ number_format($detail->partner_commission) }}원{{ number_format($detail->manager_commission) }}원
+
+
+ @endif + +
+ @if ($commission->status === 'pending') + + + @elseif ($commission->status === 'approved') + + @endif + +
+
+@else +
+ 정산 정보를 찾을 수 없습니다. +
+@endif diff --git a/resources/views/finance/settlement/partials/commission/filters.blade.php b/resources/views/finance/settlement/partials/commission/filters.blade.php new file mode 100644 index 00000000..ea7fb53b --- /dev/null +++ b/resources/views/finance/settlement/partials/commission/filters.blade.php @@ -0,0 +1,85 @@ +{{-- 수당 정산 필터 --}} +
+
+ +
+ {{-- 년도 --}} +
+ + +
+ + {{-- 월 --}} +
+ + +
+ + {{-- 상태 --}} +
+ + +
+ + {{-- 입금구분 --}} +
+ + +
+ + {{-- 영업파트너 --}} +
+ + +
+ + {{-- 수당유형 (NEW) --}} +
+ + +
+ + {{-- 버튼 --}} +
+ + + 초기화 + +
+
+
+
diff --git a/resources/views/finance/settlement/partials/commission/payment-form.blade.php b/resources/views/finance/settlement/partials/commission/payment-form.blade.php new file mode 100644 index 00000000..6bae4d18 --- /dev/null +++ b/resources/views/finance/settlement/partials/commission/payment-form.blade.php @@ -0,0 +1,163 @@ +{{-- 입금 등록 폼 --}} +
+ @csrf + +
+ + @if ($management) + +
+
{{ $management->tenant->name ?? $management->tenant->company_name }}
+
영업파트너: {{ $management->salesPartner?->user?->name ?? '-' }}
+
+ @else + + @endif +
+ + @if ($management) + @if ($management->contractProducts->count() > 0) +
+ +
+ + + + + + + + + @foreach ($management->contractProducts as $product) + + + + + @endforeach + + + + + + + +
상품명개발비
{{ $product->product?->name ?? '-' }}{{ number_format($product->registration_fee ?? 0) }}원
총 개발비 + {{ number_format($management->contractProducts->sum('registration_fee')) }}원 +
+
+
+ @endif + +
+
+
+ 계약금 +
+ {{ $management->deposit_status === 'paid' ? '입금완료' : '대기' }} + @if ($management->deposit_amount) + ({{ number_format($management->deposit_amount) }}원) + @endif +
+
+
+ 잔금 +
+ {{ $management->balance_status === 'paid' ? '입금완료' : '대기' }} + @if ($management->balance_amount) + ({{ number_format($management->balance_amount) }}원) + @endif +
+
+
+
+ @endif + +
+ +
+ + +
+
+ +
+ +
+ + +
+

총 개발비의 50%를 입금받습니다.

+
+ +
+ + +
+ + @if ($management && $management->salesPartner) + @php + $totalFee = $management->contractProducts->sum('registration_fee') ?: 0; + $baseAmount = $totalFee / 2; + $partnerRate = $management->salesPartner->commission_rate ?? 20; + $managerRate = $management->salesPartner->manager_commission_rate ?? 5; + $partnerCommission = $baseAmount * ($partnerRate / 100); + $managerCommission = $management->manager_user_id ? $baseAmount * ($managerRate / 100) : 0; + @endphp +
+

수당 미리보기

+
+
+ 기준액 (개발비의 50%) + {{ number_format($baseAmount) }}원 +
+
+ 영업파트너 수당 ({{ $partnerRate }}%) + {{ number_format($partnerCommission) }}원 +
+
+ 매니저 수당 ({{ $managerRate }}%) + {{ number_format($managerCommission) }}원 +
+
+ 총 수당 + {{ number_format($partnerCommission + $managerCommission) }}원 +
+
+
+ @endif + +
+ + +
+
diff --git a/resources/views/finance/settlement/partials/commission/stats-cards.blade.php b/resources/views/finance/settlement/partials/commission/stats-cards.blade.php new file mode 100644 index 00000000..bafe298f --- /dev/null +++ b/resources/views/finance/settlement/partials/commission/stats-cards.blade.php @@ -0,0 +1,76 @@ +{{-- 수당 유형별 통계 카드 --}} +
+ {{-- 지급 대기 --}} +
+
+
+

지급 대기

+

{{ number_format($stats['pending']['partner_total'] + $stats['pending']['manager_total']) }}원

+
+
+ + + +
+
+
+ {{ $stats['pending']['count'] }}건 + | + 파트너: {{ number_format($stats['pending']['partner_total']) }}원 + / + 매니저: {{ number_format($stats['pending']['manager_total']) }}원 +
+
+ + {{-- 승인 완료 --}} +
+
+
+

승인 완료

+

{{ number_format($stats['approved']['partner_total'] + $stats['approved']['manager_total']) }}원

+
+
+ + + +
+
+

{{ $stats['approved']['count'] }}건

+
+ + {{-- 지급 완료 --}} +
+
+
+

지급 완료

+

{{ number_format($stats['paid']['partner_total'] + $stats['paid']['manager_total']) }}원

+
+
+ + + +
+
+

{{ $stats['paid']['count'] }}건

+
+ + {{-- 해당 월 총 수당 --}} +
+
+
+

{{ $year }}년 {{ $month }}월 총 수당

+

{{ number_format($stats['total']['partner_commission'] + $stats['total']['manager_commission']) }}원

+
+
+ + + +
+
+
+ 파트너: {{ number_format($stats['total']['partner_commission']) }}원 + | + 매니저: {{ number_format($stats['total']['manager_commission']) }}원 +
+
+
diff --git a/resources/views/finance/settlement/partials/commission/table.blade.php b/resources/views/finance/settlement/partials/commission/table.blade.php new file mode 100644 index 00000000..4b7505d7 --- /dev/null +++ b/resources/views/finance/settlement/partials/commission/table.blade.php @@ -0,0 +1,154 @@ +{{-- 수당 정산 테이블 --}} +
+
+ + + + + + + + + + + + + + + + + + + + + @forelse ($commissions as $commission) + + + + + + + + + + + + + + + + + @empty + + + + @endforelse + +
+ + 테넌트입금구분입금액입금일영업파트너파트너수당매니저매니저수당유치파트너유치수당지급예정일상태액션
+ @if (in_array($commission->status, ['pending', 'approved'])) + + @endif + +
{{ $commission->tenant->name ?? $commission->tenant->company_name ?? '-' }}
+
ID: {{ $commission->tenant_id }}
+
+ + {{ $commission->payment_type_label }} + + + {{ number_format($commission->payment_amount) }} + + {{ $commission->payment_date->format('Y-m-d') }} + +
{{ $commission->partner?->user?->name ?? '-' }}
+
{{ $commission->partner_rate }}%
+
+ {{ number_format($commission->partner_commission) }} + +
{{ $commission->manager?->name ?? '-' }}
+
{{ $commission->manager_rate }}%
+
+ {{ number_format($commission->manager_commission) }} + + @if ($commission->referrer_partner_id) +
{{ $commission->referrerPartner?->user?->name ?? '-' }}
+
{{ $commission->referrer_rate }}%
+ @else + - + @endif +
+ @if ($commission->referrer_commission > 0) + {{ number_format($commission->referrer_commission) }} + @else + - + @endif + + {{ $commission->scheduled_payment_date->format('Y-m-d') }} + + @php + $statusColors = [ + 'pending' => 'bg-yellow-100 text-yellow-800', + 'approved' => 'bg-blue-100 text-blue-800', + 'paid' => 'bg-green-100 text-green-800', + 'cancelled' => 'bg-red-100 text-red-800', + ]; + @endphp + + {{ $commission->status_label }} + + +
+ + @if ($commission->status === 'pending') + + + @elseif ($commission->status === 'approved') + + @endif +
+
+ 등록된 정산 내역이 없습니다. +
+
+ + @if ($commissions->hasPages()) +
+ {{ $commissions->links() }} +
+ @endif +
diff --git a/resources/views/finance/settlement/partials/consulting-tab.blade.php b/resources/views/finance/settlement/partials/consulting-tab.blade.php new file mode 100644 index 00000000..1936eab9 --- /dev/null +++ b/resources/views/finance/settlement/partials/consulting-tab.blade.php @@ -0,0 +1,179 @@ +{{-- 컨설팅비용 탭 (Blade + Alpine.js) --}} +
+ {{-- 통계 카드 --}} +
+
+

총 시간

+

0시간

+
+
+

총 수수료

+

0원

+
+
+

지급완료

+

0원

+
+
+

지급예정

+

0원

+
+
+ + {{-- 필터 + 등록 버튼 --}} +
+
+
+ + +
+
+ + +
+ +
+
+ + {{-- 테이블 --}} +
+
+ + + + + + + + + + + + + + + + + + +
날짜컨설턴트고객사서비스시간금액상태관리
+
+
+ + {{-- 모달 --}} +
+
+
+

+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ + +
+
+
+
+ + diff --git a/resources/views/finance/settlement/partials/customer-tab.blade.php b/resources/views/finance/settlement/partials/customer-tab.blade.php new file mode 100644 index 00000000..5ed446ae --- /dev/null +++ b/resources/views/finance/settlement/partials/customer-tab.blade.php @@ -0,0 +1,183 @@ +{{-- 고객사정산 탭 (Blade + Alpine.js) --}} +
+ {{-- 통계 카드 --}} +
+
+

총 매출

+

0원

+
+
+

정산금액

+

0원

+
+
+

정산완료

+

0원

+
+
+

수수료 합계

+

0원

+
+
+ + {{-- 필터 + 등록 버튼 --}} +
+
+
+ + +
+
+ + +
+ +
+
+ + {{-- 테이블 --}} +
+
+ + + + + + + + + + + + + + + + + + +
정산월고객사매출액수수료비용정산금액상태관리
+
+
+ + {{-- 모달 --}} +
+
+
+

+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+ 정산금액 (매출 - 수수료 - 비용) + +
+
+
+
+
+
+
+
+ + +
+
+
+
+ + diff --git a/resources/views/finance/settlement/partials/partner-summary.blade.php b/resources/views/finance/settlement/partials/partner-summary.blade.php new file mode 100644 index 00000000..78c11865 --- /dev/null +++ b/resources/views/finance/settlement/partials/partner-summary.blade.php @@ -0,0 +1,118 @@ +{{-- 파트너별 현황 탭 --}} +
+ {{-- 필터 --}} +
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+ + {{-- 테이블 --}} +
+
+ + + + + + + + + + + + + + + + @forelse ($partners as $partner) + @php + $stats = $commissionStats[$partner->id] ?? null; + $paidTotal = $stats->paid_total ?? 0; + $unpaidTotal = $stats->unpaid_total ?? 0; + $totalCount = $stats->total_count ?? $partner->total_contracts ?? 0; + $lastPaidDate = $stats->last_paid_date ?? null; + @endphp + + + + + + + + + + + + @empty + + + + @endforelse + +
파트너명유형수당률계약건수누적 수당미지급지급완료최근 지급일액션
+
{{ $partner->user?->name ?? '-' }}
+
{{ $partner->partner_code }}
+
+ @if ($partner->partner_type === 'corporate') + 단체 + @else + 개인 + @endif + + {{ $partner->commission_rate }}% + + {{ number_format($totalCount) }} + + {{ number_format($paidTotal + $unpaidTotal) }}원 + + {{ number_format($unpaidTotal) }}원 + + {{ number_format($paidTotal) }}원 + + {{ $lastPaidDate ? \Carbon\Carbon::parse($lastPaidDate)->format('Y-m-d') : '-' }} + + + 상세보기 + +
+ 등록된 파트너가 없습니다. +
+
+ + @if ($partners->hasPages()) +
+ {{ $partners->links() }} +
+ @endif +
+
diff --git a/resources/views/finance/settlement/partials/subscription-tab.blade.php b/resources/views/finance/settlement/partials/subscription-tab.blade.php new file mode 100644 index 00000000..b3e28409 --- /dev/null +++ b/resources/views/finance/settlement/partials/subscription-tab.blade.php @@ -0,0 +1,202 @@ +{{-- 구독관리 탭 (Blade + Alpine.js) --}} +
+ {{-- 통계 카드 --}} +
+
+

활성 구독

+

0개

+
+
+

월 반복 수익(MRR)

+

0원

+
+
+

연 반복 수익(ARR)

+

0원

+
+
+

총 사용자

+

0명

+
+
+ + {{-- 필터 + 등록 버튼 --}} +
+
+
+ + +
+
+ + +
+
+ + +
+ +
+
+ + {{-- 테이블 --}} +
+
+ + + + + + + + + + + + + + + + + + +
고객사플랜월 요금결제주기다음 결제사용자상태관리
+
+
+ + {{-- 모달 --}} +
+
+
+

+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ + +
+
+
+
+ + diff --git a/resources/views/finance/settlement/partials/summary-stats.blade.php b/resources/views/finance/settlement/partials/summary-stats.blade.php new file mode 100644 index 00000000..bb00e2b3 --- /dev/null +++ b/resources/views/finance/settlement/partials/summary-stats.blade.php @@ -0,0 +1,66 @@ +{{-- 통합 통계 카드 (탭 위) --}} +
+ {{-- 미지급 수당 --}} +
+
+
+

미지급 수당

+

{{ number_format($summaryStats['unpaid_amount']) }}원

+
+
+ + + +
+
+

대기 + 승인 상태

+
+ + {{-- 승인 대기 --}} +
+
+
+

승인 대기

+

{{ $summaryStats['pending_count'] }}건

+
+
+ + + +
+
+

승인 처리 필요

+
+ + {{-- 이번달 지급예정 --}} +
+
+
+

이번달 지급예정

+

{{ number_format($summaryStats['this_month_scheduled']) }}원

+
+
+ + + +
+
+

{{ now()->format('Y년 n월') }} 예정

+
+ + {{-- 누적 지급완료 --}} +
+
+
+

누적 지급완료

+

{{ number_format($summaryStats['total_paid']) }}원

+
+
+ + + +
+
+

전체 기간 합계

+
+
diff --git a/routes/web.php b/routes/web.php index 3d22e1d8..0e40b364 100644 --- a/routes/web.php +++ b/routes/web.php @@ -994,7 +994,16 @@ Route::delete('/{id}', [\App\Http\Controllers\Finance\PurchaseController::class, 'destroy'])->name('destroy'); }); - // 영업수수료정산 (실제 구현) + // 통합 정산관리 + Route::get('/settlement', [\App\Http\Controllers\Finance\SettlementController::class, 'index'])->name('settlement'); + Route::get('/settlement/commission-stats', [\App\Http\Controllers\Finance\SettlementController::class, 'commissionStats'])->name('settlement.commission-stats'); + Route::get('/settlement/commission-table', [\App\Http\Controllers\Finance\SettlementController::class, 'commissionTable'])->name('settlement.commission-table'); + Route::get('/settlement/partner-summary', [\App\Http\Controllers\Finance\SettlementController::class, 'partnerSummary'])->name('settlement.partner-summary'); + 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'); + + // 영업수수료정산 (실제 구현 - CRUD API는 그대로 유지) Route::prefix('sales-commissions')->name('sales-commissions.')->group(function () { Route::get('/', [\App\Http\Controllers\Finance\SalesCommissionController::class, 'index'])->name('index'); Route::get('/export', [\App\Http\Controllers\Finance\SalesCommissionController::class, 'export'])->name('export'); @@ -1011,15 +1020,9 @@ Route::post('/{id}/cancel', [\App\Http\Controllers\Finance\SalesCommissionController::class, 'cancel'])->name('cancel'); }); - // 기존 sales-commission URL 리다이렉트 (호환성) - Route::get('/sales-commission', fn () => redirect()->route('finance.sales-commissions.index'))->name('sales-commission'); - Route::get('/consulting-fee', function () { - if (request()->header('HX-Request')) { - return response('', 200)->header('HX-Redirect', route('finance.consulting-fee')); - } - - return view('finance.consulting-fee'); - })->name('consulting-fee'); + // 기존 URL 리다이렉트 → 통합 정산관리 + Route::get('/sales-commission', fn () => redirect()->route('finance.settlement'))->name('sales-commission'); + Route::get('/consulting-fee', fn () => redirect()->route('finance.settlement', ['tab' => 'consulting']))->name('consulting-fee'); // 상담수수료 API Route::prefix('consulting-fees')->name('consulting-fees.')->group(function () { @@ -1029,13 +1032,7 @@ Route::delete('/{id}', [\App\Http\Controllers\Finance\ConsultingFeeController::class, 'destroy'])->name('destroy'); }); - Route::get('/customer-settlement', function () { - if (request()->header('HX-Request')) { - return response('', 200)->header('HX-Redirect', route('finance.customer-settlement')); - } - - return view('finance.customer-settlement'); - })->name('customer-settlement'); + Route::get('/customer-settlement', fn () => redirect()->route('finance.settlement', ['tab' => 'customer']))->name('customer-settlement'); // 고객사별 정산 API Route::prefix('customer-settlements')->name('customer-settlements.')->group(function () { @@ -1045,13 +1042,7 @@ Route::delete('/{id}', [\App\Http\Controllers\Finance\CustomerSettlementController::class, 'destroy'])->name('destroy'); }); - Route::get('/subscription', function () { - if (request()->header('HX-Request')) { - return response('', 200)->header('HX-Redirect', route('finance.subscription')); - } - - return view('finance.subscription'); - })->name('subscription'); + Route::get('/subscription', fn () => redirect()->route('finance.settlement', ['tab' => 'subscription']))->name('subscription'); // 구독 관리 API Route::prefix('subscriptions')->name('subscriptions.')->group(function () {