diff --git a/app/Http/Controllers/Api/V1/ExpectedExpenseController.php b/app/Http/Controllers/Api/V1/ExpectedExpenseController.php index 468ddf9..14e6c6c 100644 --- a/app/Http/Controllers/Api/V1/ExpectedExpenseController.php +++ b/app/Http/Controllers/Api/V1/ExpectedExpenseController.php @@ -124,4 +124,18 @@ public function summary(Request $request) return ApiResponse::success($summary, __('message.fetched')); } + + /** + * 대시보드 상세 조회 (CEO 대시보드 당월 예상 지출내역 모달용) + * + * @param Request $request transaction_type 쿼리 파라미터 (purchase, card, bill, null=전체) + */ + public function dashboardDetail(Request $request) + { + $transactionType = $request->query('transaction_type'); + + $data = $this->service->dashboardDetail($transactionType); + + return ApiResponse::success($data, __('message.fetched')); + } } diff --git a/app/Services/ExpectedExpenseService.php b/app/Services/ExpectedExpenseService.php index 75f90ab..6569fef 100644 --- a/app/Services/ExpectedExpenseService.php +++ b/app/Services/ExpectedExpenseService.php @@ -299,4 +299,116 @@ public function summary(array $params): array 'by_month' => $byMonth, ]; } + + /** + * 대시보드 상세 조회 (CEO 대시보드 당월 예상 지출내역 모달용) + * + * @param string|null $transactionType 거래유형 필터 (purchase, card, bill, null=전체) + * @return array{ + * summary: array{ + * total_amount: float, + * previous_month_amount: float, + * change_rate: float, + * remaining_balance: float, + * item_count: int + * }, + * items: array, + * footer_summary: array + * } + */ + public function dashboardDetail(?string $transactionType = null): array + { + $tenantId = $this->tenantId(); + $currentMonthStart = now()->startOfMonth()->toDateString(); + $currentMonthEnd = now()->endOfMonth()->toDateString(); + $previousMonthStart = now()->subMonth()->startOfMonth()->toDateString(); + $previousMonthEnd = now()->subMonth()->endOfMonth()->toDateString(); + + // 기본 쿼리 빌더 (transaction_type 필터 적용) + $baseQuery = function () use ($tenantId, $transactionType) { + $query = ExpectedExpense::query()->where('tenant_id', $tenantId); + if ($transactionType) { + $query->where('transaction_type', $transactionType); + } + + return $query; + }; + + // 1. 요약 정보 + $currentMonthTotal = $baseQuery() + ->whereBetween('expected_payment_date', [$currentMonthStart, $currentMonthEnd]) + ->sum('amount'); + + $currentMonthCount = $baseQuery() + ->whereBetween('expected_payment_date', [$currentMonthStart, $currentMonthEnd]) + ->count(); + + $previousMonthTotal = $baseQuery() + ->whereBetween('expected_payment_date', [$previousMonthStart, $previousMonthEnd]) + ->sum('amount'); + + $changeRate = $previousMonthTotal > 0 + ? round((($currentMonthTotal - $previousMonthTotal) / $previousMonthTotal) * 100, 1) + : ($currentMonthTotal > 0 ? 100 : 0); + + // 미지급 잔액 (pending 상태) - remaining_balance로 반환 + $pendingBalance = $baseQuery() + ->where('payment_status', 'pending') + ->sum('amount'); + + // 2. 지출예상 목록 (당월, 지급일 순) + $itemsQuery = ExpectedExpense::query() + ->select([ + 'expected_expenses.id', + 'expected_expenses.expected_payment_date', + 'expected_expenses.description', + 'expected_expenses.amount', + 'expected_expenses.client_id', + 'expected_expenses.client_name', + 'expected_expenses.account_code', + 'expected_expenses.payment_status', + 'expected_expenses.transaction_type', + ]) + ->leftJoin('clients', 'expected_expenses.client_id', '=', 'clients.id') + ->where('expected_expenses.tenant_id', $tenantId) + ->whereBetween('expected_expenses.expected_payment_date', [$currentMonthStart, $currentMonthEnd]); + + if ($transactionType) { + $itemsQuery->where('expected_expenses.transaction_type', $transactionType); + } + + $items = $itemsQuery + ->orderBy('expected_expenses.expected_payment_date', 'asc') + ->get() + ->map(function ($item) { + return [ + 'id' => $item->id, + 'payment_date' => $item->expected_payment_date?->format('Y-m-d'), + 'item_name' => $item->description ?? '', + 'amount' => (float) $item->amount, + 'vendor_name' => $item->client_name ?? '', + 'account_title' => $item->account_code ?? '', + 'status' => $item->payment_status, + 'transaction_type' => $item->transaction_type, + ]; + }) + ->toArray(); + + // 3. 푸터 합계 + $footerSummary = [ + 'total_amount' => (float) $currentMonthTotal, + 'item_count' => count($items), + ]; + + return [ + 'summary' => [ + 'total_amount' => (float) $currentMonthTotal, + 'previous_month_amount' => (float) $previousMonthTotal, + 'change_rate' => $changeRate, + 'remaining_balance' => (float) $pendingBalance, + ], + 'items' => $items, + 'footer_summary' => $footerSummary, + ]; + } }