diff --git a/app/Http/Controllers/Finance/FinanceDashboardController.php b/app/Http/Controllers/Finance/FinanceDashboardController.php new file mode 100644 index 00000000..8eb2b34d --- /dev/null +++ b/app/Http/Controllers/Finance/FinanceDashboardController.php @@ -0,0 +1,64 @@ +bankAccountService->getSummary(); + + // 자금 일정 요약 + $scheduleSummary = $this->fundScheduleService->getSummary(); + + // 이번 달 자금 일정 요약 + $monthlySummary = $this->fundScheduleService->getMonthlySummary( + now()->year, + now()->month + ); + + // 향후 7일 자금 일정 + $upcomingSchedules = $this->fundScheduleService->getUpcomingSchedules(7); + + // 최근 거래내역 (10건) + $recentTransactions = BankTransaction::with('bankAccount:id,bank_name,account_number') + ->latest('transaction_date') + ->limit(10) + ->get(); + + // 계좌별 잔액 + $accountBalances = BankAccount::active() + ->ordered() + ->get(['id', 'bank_name', 'account_number', 'account_name', 'balance', 'account_type']); + + // 은행별 통계 + $bankStats = $this->bankAccountService->getStatsByBank(); + + return view('finance.dashboard', compact( + 'accountSummary', + 'scheduleSummary', + 'monthlySummary', + 'upcomingSchedules', + 'recentTransactions', + 'accountBalances', + 'bankStats' + )); + } +} diff --git a/resources/views/finance/dashboard.blade.php b/resources/views/finance/dashboard.blade.php new file mode 100644 index 00000000..067e0328 --- /dev/null +++ b/resources/views/finance/dashboard.blade.php @@ -0,0 +1,302 @@ +@extends('layouts.app') + +@section('title', '재무 대시보드') + +@section('content') +
+ {{-- 페이지 헤더 --}} +
+
+

재무 대시보드

+

{{ now()->format('Y년 n월 j일') }} 현재

+
+ +
+ + {{-- 요약 카드 --}} +
+ {{-- 총 잔액 --}} +
+
+
+

총 잔액

+

{{ number_format($accountSummary['total_balance']) }}원

+

{{ $accountSummary['total_accounts'] }}개 계좌

+
+
+ + + +
+
+
+ + {{-- 예정 수입 --}} +
+
+
+

예정 수입

+

+{{ number_format($scheduleSummary['pending_income']) }}원

+

이번 달 예정

+
+
+ + + +
+
+
+ + {{-- 예정 지출 --}} +
+
+
+

예정 지출

+

-{{ number_format($scheduleSummary['pending_expense']) }}원

+

이번 달 예정

+
+
+ + + +
+
+
+ + {{-- 7일내 일정 --}} +
+
+
+

7일내 일정

+

{{ $scheduleSummary['upcoming_7days'] }}건

+

처리 필요

+
+
+ + + +
+
+
+
+ + {{-- 이번 달 요약 --}} +
+

{{ now()->format('n월') }} 자금 일정 요약

+
+
+

수입

+

+{{ number_format($monthlySummary['income']['total']) }}원

+

+ 완료: {{ number_format($monthlySummary['income']['completed']) }}원 / + 예정: {{ number_format($monthlySummary['income']['pending']) }}원 +

+
+
+

지출

+

-{{ number_format($monthlySummary['expense']['total']) }}원

+

+ 완료: {{ number_format($monthlySummary['expense']['completed']) }}원 / + 예정: {{ number_format($monthlySummary['expense']['pending']) }}원 +

+
+
+

순수익

+

+ {{ $monthlySummary['net'] >= 0 ? '+' : '' }}{{ number_format($monthlySummary['net']) }}원 +

+

총 {{ $monthlySummary['total_count'] }}건 일정

+
+
+
+ +
+ {{-- 계좌별 잔액 --}} +
+
+

계좌별 잔액

+ + 전체보기 + +
+
+ @forelse($accountBalances as $account) +
+
+
+ {{ mb_substr($account->bank_name, 0, 2) }} +
+
+

+ {{ $account->account_name ?: $account->bank_name }} +

+

{{ $account->account_number }}

+
+
+
+

{{ number_format($account->balance) }}원

+

{{ $account->account_type }}

+
+
+ @empty +
+ 등록된 계좌가 없습니다. +
+ @endforelse +
+
+ + {{-- 향후 7일 자금 일정 --}} +
+
+

향후 7일 자금 일정

+ + 전체보기 + +
+
+ @forelse($upcomingSchedules as $schedule) +
+
+
+ @if($schedule->schedule_type === 'income') + + + + @else + + + + @endif +
+
+

{{ $schedule->title }}

+

+ {{ $schedule->scheduled_date->format('m/d') }} + @if($schedule->counterparty) + - {{ $schedule->counterparty }} + @endif +

+
+
+
+

+ {{ $schedule->schedule_type === 'income' ? '+' : '-' }}{{ number_format($schedule->amount) }}원 +

+ + {{ $schedule->status === 'pending' ? '대기' : ($schedule->status === 'completed' ? '완료' : '취소') }} + +
+
+ @empty +
+ 7일내 예정된 일정이 없습니다. +
+ @endforelse +
+
+
+ + {{-- 최근 거래내역 --}} +
+
+

최근 거래내역

+ + 전체보기 + +
+
+ + + + + + + + + + + + + @forelse($recentTransactions as $tx) + + + + + + + + + @empty + + + + @endforelse + +
날짜계좌유형적요금액잔액
+ {{ $tx->transaction_date->format('m/d') }} + + {{ $tx->bankAccount?->bank_name ?? '-' }} + + @php + $typeColors = [ + 'deposit' => 'bg-green-100 text-green-700', + 'withdrawal' => 'bg-red-100 text-red-700', + 'transfer' => 'bg-blue-100 text-blue-700', + ]; + $typeLabels = [ + 'deposit' => '입금', + 'withdrawal' => '출금', + 'transfer' => '이체', + ]; + @endphp + + {{ $typeLabels[$tx->transaction_type] ?? $tx->transaction_type }} + + + {{ Str::limit($tx->description, 20) }} + + {{ $tx->transaction_type === 'deposit' ? '+' : '-' }}{{ number_format($tx->amount) }}원 + + {{ number_format($tx->balance_after) }}원 +
+ 거래내역이 없습니다. +
+
+
+ + {{-- 은행별 분포 --}} + @if($bankStats->count() > 0) +
+

은행별 분포

+
+ @foreach($bankStats as $bank) +
+

{{ $bank->bank_name }}

+

{{ number_format($bank->total_balance) }}원

+

{{ $bank->count }}개 계좌

+
+ @endforeach +
+
+ @endif +
+@endsection diff --git a/routes/web.php b/routes/web.php index e2193022..93928315 100644 --- a/routes/web.php +++ b/routes/web.php @@ -461,6 +461,10 @@ return response()->file(public_path('재무관리.html')); }); +Route::get('/일일자금일보', function () { + return response()->file(public_path('일일자금일보.html')); +}); + /* |-------------------------------------------------------------------------- | Finance Routes (재무 관리) @@ -468,7 +472,7 @@ */ Route::middleware('auth')->prefix('finance')->name('finance.')->group(function () { // 대시보드 - Route::get('/dashboard', fn() => view('finance.placeholder', ['title' => '재무 대시보드']))->name('dashboard'); + Route::get('/dashboard', [\App\Http\Controllers\Finance\FinanceDashboardController::class, 'index'])->name('dashboard'); // 계좌관리 (실제 구현) Route::prefix('accounts')->name('accounts.')->group(function () { @@ -478,8 +482,13 @@ Route::get('/{id}/edit', [\App\Http\Controllers\Finance\BankAccountController::class, 'edit'])->name('edit'); }); - // 자금관리 (계좌거래내역은 accounts로 리다이렉트) - Route::get('/account-transactions', fn() => redirect()->route('finance.accounts.index'))->name('account-transactions'); + // 계좌거래내역 + Route::get('/account-transactions', function () { + if (request()->header('HX-Request')) { + return response('', 200)->header('HX-Redirect', route('finance.account-transactions')); + } + return view('finance.account-transactions'); + })->name('account-transactions'); // 자금계획일정 (실제 구현) Route::prefix('fund-schedules')->name('fund-schedules.')->group(function () { @@ -491,39 +500,135 @@ // 기존 fund-schedule URL 리다이렉트 (호환성) Route::get('/fund-schedule', fn() => redirect()->route('finance.fund-schedules.index'))->name('fund-schedule'); - Route::get('/daily-fund', fn() => view('finance.placeholder', ['title' => '일일자금일보']))->name('daily-fund'); + Route::get('/daily-fund', function () { + // HTMX 요청이면 전체 페이지로 리다이렉트 (React 스크립트 로딩을 위해) + if (request()->header('HX-Request')) { + return response('', 200)->header('HX-Redirect', route('finance.daily-fund')); + } + return view('finance.daily-fund'); + })->name('daily-fund'); // 카드관리 - Route::get('/corporate-cards', fn() => view('finance.placeholder', ['title' => '법인카드 등록/조회']))->name('corporate-cards'); - Route::get('/card-transactions', fn() => view('finance.placeholder', ['title' => '법인카드 거래내역']))->name('card-transactions'); + Route::get('/corporate-cards', function () { + if (request()->header('HX-Request')) { + return response('', 200)->header('HX-Redirect', route('finance.corporate-cards')); + } + return view('finance.corporate-cards'); + })->name('corporate-cards'); + Route::get('/card-transactions', function () { + if (request()->header('HX-Request')) { + return response('', 200)->header('HX-Redirect', route('finance.card-transactions')); + } + return view('finance.card-transactions'); + })->name('card-transactions'); // 수입/지출 - Route::get('/income', fn() => view('finance.placeholder', ['title' => '수입관리']))->name('income'); - Route::get('/expense', fn() => view('finance.placeholder', ['title' => '지출관리']))->name('expense'); + Route::get('/income', function () { + if (request()->header('HX-Request')) { + return response('', 200)->header('HX-Redirect', route('finance.income')); + } + return view('finance.income'); + })->name('income'); + Route::get('/expense', function () { + if (request()->header('HX-Request')) { + return response('', 200)->header('HX-Redirect', route('finance.expense')); + } + return view('finance.expense'); + })->name('expense'); // 매출/매입 - Route::get('/sales', fn() => view('finance.placeholder', ['title' => '매출관리']))->name('sales'); - Route::get('/purchase', fn() => view('finance.placeholder', ['title' => '매입관리']))->name('purchase'); + Route::get('/sales', function () { + if (request()->header('HX-Request')) { + return response('', 200)->header('HX-Redirect', route('finance.sales')); + } + return view('finance.sales'); + })->name('sales'); + Route::get('/purchase', function () { + if (request()->header('HX-Request')) { + return response('', 200)->header('HX-Redirect', route('finance.purchase')); + } + return view('finance.purchase'); + })->name('purchase'); // 정산관리 - Route::get('/sales-commission', fn() => view('finance.placeholder', ['title' => '영업수수료']))->name('sales-commission'); - Route::get('/consulting-fee', fn() => view('finance.placeholder', ['title' => '상담수수료']))->name('consulting-fee'); - Route::get('/customer-settlement', fn() => view('finance.placeholder', ['title' => '고객사별 정산']))->name('customer-settlement'); - Route::get('/subscription', fn() => view('finance.placeholder', ['title' => '구독관리']))->name('subscription'); + Route::get('/sales-commission', function () { + if (request()->header('HX-Request')) { + return response('', 200)->header('HX-Redirect', route('finance.sales-commission')); + } + return view('finance.sales-commission'); + })->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'); + 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('/subscription', function () { + if (request()->header('HX-Request')) { + return response('', 200)->header('HX-Redirect', route('finance.subscription')); + } + return view('finance.subscription'); + })->name('subscription'); // 차량관리 - Route::get('/corporate-vehicles', fn() => view('finance.placeholder', ['title' => '법인차량 등록']))->name('corporate-vehicles'); - Route::get('/vehicle-maintenance', fn() => view('finance.placeholder', ['title' => '차량 유지비']))->name('vehicle-maintenance'); + Route::get('/corporate-vehicles', function () { + if (request()->header('HX-Request')) { + return response('', 200)->header('HX-Redirect', route('finance.corporate-vehicles')); + } + return view('finance.corporate-vehicles'); + })->name('corporate-vehicles'); + Route::get('/vehicle-maintenance', function () { + if (request()->header('HX-Request')) { + return response('', 200)->header('HX-Redirect', route('finance.vehicle-maintenance')); + } + return view('finance.vehicle-maintenance'); + })->name('vehicle-maintenance'); // 거래처관리 - Route::get('/customers', fn() => view('finance.placeholder', ['title' => '고객사 관리']))->name('customers'); - Route::get('/partners', fn() => view('finance.placeholder', ['title' => '일반 거래처']))->name('partners'); + Route::get('/customers', function () { + if (request()->header('HX-Request')) { + return response('', 200)->header('HX-Redirect', route('finance.customers')); + } + return view('finance.customers'); + })->name('customers'); + Route::get('/partners', function () { + if (request()->header('HX-Request')) { + return response('', 200)->header('HX-Redirect', route('finance.partners')); + } + return view('finance.partners'); + })->name('partners'); // 채권/채무 - Route::get('/receivables', fn() => view('finance.placeholder', ['title' => '미수금']))->name('receivables'); - Route::get('/payables', fn() => view('finance.placeholder', ['title' => '미지급금']))->name('payables'); + Route::get('/receivables', function () { + if (request()->header('HX-Request')) { + return response('', 200)->header('HX-Redirect', route('finance.receivables')); + } + return view('finance.receivables'); + })->name('receivables'); + Route::get('/payables', function () { + if (request()->header('HX-Request')) { + return response('', 200)->header('HX-Redirect', route('finance.payables')); + } + return view('finance.payables'); + })->name('payables'); // 기타 - Route::get('/refunds', fn() => view('finance.placeholder', ['title' => '환불/해지']))->name('refunds'); - Route::get('/vat', fn() => view('finance.placeholder', ['title' => '부가세']))->name('vat'); + Route::get('/refunds', function () { + if (request()->header('HX-Request')) { + return response('', 200)->header('HX-Redirect', route('finance.refunds')); + } + return view('finance.refunds'); + })->name('refunds'); + Route::get('/vat', function () { + if (request()->header('HX-Request')) { + return response('', 200)->header('HX-Redirect', route('finance.vat')); + } + return view('finance.vat'); + })->name('vat'); });