tenantId(); $date = Carbon::parse($params['date'] ?? now()->toDateString()); $previousDate = $date->copy()->subDay(); // 전일 잔액 계산 (기준일 전일까지의 모든 입출금 합계) $previousBalance = $this->calculateBalanceUntilDate($tenantId, $previousDate); // 당일 입금 합계 $dailyDeposit = Deposit::query() ->where('tenant_id', $tenantId) ->whereDate('deposit_date', $date) ->sum('amount'); // 당일 출금 합계 $dailyWithdrawal = Withdrawal::query() ->where('tenant_id', $tenantId) ->whereDate('withdrawal_date', $date) ->sum('amount'); // 당일 잔액 $currentBalance = $previousBalance + $dailyDeposit - $dailyWithdrawal; // 상세 내역 (입출금 통합) $details = $this->getDailyDetails($tenantId, $date); return [ 'date' => $date->toDateString(), 'previous_balance' => (float) $previousBalance, 'daily_deposit' => (float) $dailyDeposit, 'daily_withdrawal' => (float) $dailyWithdrawal, 'current_balance' => (float) $currentBalance, 'details' => $details, ]; } /** * 지출 예상 내역서 조회 * * @param array $params [year_month: YYYY-MM 형식] */ public function expenseEstimate(array $params): array { $tenantId = $this->tenantId(); $yearMonth = $params['year_month'] ?? now()->format('Y-m'); [$year, $month] = explode('-', $yearMonth); $startDate = Carbon::createFromDate($year, $month, 1)->startOfMonth(); $endDate = $startDate->copy()->endOfMonth(); // 미결제 매입 내역 조회 (지출 예상) $items = Purchase::query() ->where('tenant_id', $tenantId) ->whereIn('status', ['draft', 'confirmed']) ->whereNull('withdrawal_id') ->whereBetween('purchase_date', [$startDate, $endDate]) ->with(['client:id,name']) ->orderBy('purchase_date') ->get() ->map(function ($purchase) { return [ 'id' => $purchase->id, 'expected_date' => $purchase->purchase_date->toDateString(), 'item_name' => $purchase->description ?? __('message.report.purchase'), 'amount' => (float) $purchase->total_amount, 'client_name' => $purchase->client?->name ?? '', 'account_name' => '', ]; }); // 예상 지출 합계 $totalEstimate = $items->sum('amount'); // 계좌 잔액 (대표 계좌 기준, 없으면 모든 계좌 합산) $accountBalance = $this->getAccountBalance($tenantId); // 예상 잔액 $expectedBalance = $accountBalance - $totalEstimate; // 월별 합계 $monthlySummary = $this->getMonthlySummary($tenantId, $startDate); return [ 'year_month' => $yearMonth, 'total_estimate' => (float) $totalEstimate, 'account_balance' => (float) $accountBalance, 'expected_balance' => (float) $expectedBalance, 'items' => $items->values()->toArray(), 'monthly_summary' => $monthlySummary, ]; } /** * 특정 날짜까지의 잔액 계산 */ private function calculateBalanceUntilDate(int $tenantId, Carbon $date): float { $totalDeposits = Deposit::query() ->where('tenant_id', $tenantId) ->whereDate('deposit_date', '<=', $date) ->sum('amount'); $totalWithdrawals = Withdrawal::query() ->where('tenant_id', $tenantId) ->whereDate('withdrawal_date', '<=', $date) ->sum('amount'); return (float) ($totalDeposits - $totalWithdrawals); } /** * 일일 상세 내역 조회 (입출금 통합) */ private function getDailyDetails(int $tenantId, Carbon $date): array { // 입금 내역 $deposits = Deposit::query() ->where('tenant_id', $tenantId) ->whereDate('deposit_date', $date) ->with(['client:id,name']) ->get() ->map(function ($deposit) { return [ 'type' => 'deposit', 'type_label' => __('message.report.deposit'), 'client_name' => $deposit->client?->name ?? $deposit->client_name ?? '', 'account_code' => $deposit->account_code ?? '', 'deposit_amount' => (float) $deposit->amount, 'withdrawal_amount' => 0, 'description' => $deposit->description ?? '', 'payment_method' => $deposit->payment_method, ]; }); // 출금 내역 $withdrawals = Withdrawal::query() ->where('tenant_id', $tenantId) ->whereDate('withdrawal_date', $date) ->with(['client:id,name']) ->get() ->map(function ($withdrawal) { return [ 'type' => 'withdrawal', 'type_label' => __('message.report.withdrawal'), 'client_name' => $withdrawal->client?->name ?? $withdrawal->client_name ?? '', 'account_code' => $withdrawal->account_code ?? '', 'deposit_amount' => 0, 'withdrawal_amount' => (float) $withdrawal->amount, 'description' => $withdrawal->description ?? '', 'payment_method' => $withdrawal->payment_method, ]; }); return $deposits->concat($withdrawals)->values()->toArray(); } /** * 계좌 잔액 조회 * 입출금 내역 기반으로 계산 */ private function getAccountBalance(int $tenantId): float { return $this->calculateBalanceUntilDate($tenantId, Carbon::now()); } /** * 월별 지출 예상 합계 */ private function getMonthlySummary(int $tenantId, Carbon $baseDate): array { $summary = []; // 기준월부터 3개월간 집계 for ($i = 0; $i < 3; $i++) { $targetDate = $baseDate->copy()->addMonths($i); $startOfMonth = $targetDate->copy()->startOfMonth(); $endOfMonth = $targetDate->copy()->endOfMonth(); $total = Purchase::query() ->where('tenant_id', $tenantId) ->whereIn('status', ['draft', 'confirmed']) ->whereNull('withdrawal_id') ->whereBetween('purchase_date', [$startOfMonth, $endOfMonth]) ->sum('total_amount'); $summary[] = [ 'month' => $targetDate->format('Y/m'), 'total' => (float) $total, ]; } // 전체 합계 $grandTotal = collect($summary)->sum('total'); // 계좌 잔액 $accountBalance = $this->getAccountBalance($tenantId); return [ 'by_month' => $summary, 'total_expense' => $grandTotal, 'account_balance' => $accountBalance, 'final_difference' => $accountBalance - $grandTotal, ]; } }