format('Y-m-d'); // 입금 (deposits) $depositStats = DB::connection('mysql') ->table('deposits') ->where('tenant_id', $tenantId) ->where('deposit_date', $dateStr) ->whereNull('deleted_at') ->selectRaw('COUNT(*) as cnt, COALESCE(SUM(amount), 0) as total') ->first(); // 출금 (withdrawals) $withdrawalStats = DB::connection('mysql') ->table('withdrawals') ->where('tenant_id', $tenantId) ->where('withdrawal_date', $dateStr) ->whereNull('deleted_at') ->selectRaw('COUNT(*) as cnt, COALESCE(SUM(amount), 0) as total') ->first(); // 매입 (purchases) $purchaseStats = DB::connection('mysql') ->table('purchases') ->where('tenant_id', $tenantId) ->where('purchase_date', $dateStr) ->whereNull('deleted_at') ->selectRaw(' COUNT(*) as cnt, COALESCE(SUM(supply_amount), 0) as supply_total, COALESCE(SUM(tax_amount), 0) as tax_total ') ->first(); // 어음 발행 (bills - issued on this date) $billIssuedStats = DB::connection('mysql') ->table('bills') ->where('tenant_id', $tenantId) ->where('issue_date', $dateStr) ->whereNull('deleted_at') ->selectRaw('COUNT(*) as cnt, COALESCE(SUM(amount), 0) as total') ->first(); // 어음 만기 (bills - matured on this date) $billMaturedStats = DB::connection('mysql') ->table('bills') ->where('tenant_id', $tenantId) ->where('maturity_date', $dateStr) ->whereNull('deleted_at') ->selectRaw('COUNT(*) as cnt, COALESCE(SUM(amount), 0) as total') ->first(); // 카드 거래 (withdrawals with card_id) $cardStats = DB::connection('mysql') ->table('withdrawals') ->where('tenant_id', $tenantId) ->where('withdrawal_date', $dateStr) ->whereNotNull('card_id') ->whereNull('deleted_at') ->selectRaw('COUNT(*) as cnt, COALESCE(SUM(amount), 0) as total') ->first(); // 은행 잔액 합계 (bank_transactions - 계좌별 최신 잔액) $bankBalance = DB::connection('mysql') ->query() ->fromSub(function ($query) use ($tenantId, $dateStr) { $query->from('bank_transactions') ->where('tenant_id', $tenantId) ->where('transaction_date', '<=', $dateStr) ->whereNull('deleted_at') ->selectRaw('bank_account_id, balance_after as latest_balance, ROW_NUMBER() OVER(PARTITION BY bank_account_id ORDER BY transaction_date DESC, id DESC) as rn'); }, 'sub') ->where('rn', 1) ->selectRaw('COALESCE(SUM(latest_balance), 0) as total_balance') ->first(); $depositAmount = $depositStats->total ?? 0; $withdrawalAmount = $withdrawalStats->total ?? 0; StatFinanceDaily::updateOrCreate( ['tenant_id' => $tenantId, 'stat_date' => $dateStr], [ 'deposit_count' => $depositStats->cnt ?? 0, 'deposit_amount' => $depositAmount, 'withdrawal_count' => $withdrawalStats->cnt ?? 0, 'withdrawal_amount' => $withdrawalAmount, 'net_cashflow' => $depositAmount - $withdrawalAmount, 'purchase_count' => $purchaseStats->cnt ?? 0, 'purchase_amount' => $purchaseStats->supply_total ?? 0, 'purchase_tax_amount' => $purchaseStats->tax_total ?? 0, 'receivable_balance' => 0, // Phase 3에서 미수금 로직 추가 'payable_balance' => 0, 'overdue_receivable' => 0, 'bill_issued_count' => $billIssuedStats->cnt ?? 0, 'bill_issued_amount' => $billIssuedStats->total ?? 0, 'bill_matured_count' => $billMaturedStats->cnt ?? 0, 'bill_matured_amount' => $billMaturedStats->total ?? 0, 'card_transaction_count' => $cardStats->cnt ?? 0, 'card_transaction_amount' => $cardStats->total ?? 0, 'bank_balance_total' => $bankBalance->total_balance ?? 0, ] ); return 1; } public function aggregateMonthly(int $tenantId, int $year, int $month): int { $dailySum = StatFinanceDaily::where('tenant_id', $tenantId) ->whereYear('stat_date', $year) ->whereMonth('stat_date', $month) ->selectRaw(' SUM(deposit_amount) as deposit_total, SUM(withdrawal_amount) as withdrawal_total, SUM(net_cashflow) as net_cashflow, SUM(purchase_amount) as purchase_total, SUM(card_transaction_amount) as card_total ') ->first(); // 월말 데이터 (해당 월의 마지막 일간 레코드) $lastDay = StatFinanceDaily::where('tenant_id', $tenantId) ->whereYear('stat_date', $year) ->whereMonth('stat_date', $month) ->orderByDesc('stat_date') ->first(); // 전월 대비 현금흐름 변화 $prevMonth = StatFinanceMonthly::where('tenant_id', $tenantId) ->where(function ($q) use ($year, $month) { $prev = Carbon::create($year, $month, 1)->subMonth(); $q->where('stat_year', $prev->year)->where('stat_month', $prev->month); }) ->first(); $netCashflow = $dailySum->net_cashflow ?? 0; $momChange = null; if ($prevMonth && $prevMonth->net_cashflow != 0) { $momChange = (($netCashflow - $prevMonth->net_cashflow) / abs($prevMonth->net_cashflow)) * 100; } StatFinanceMonthly::updateOrCreate( ['tenant_id' => $tenantId, 'stat_year' => $year, 'stat_month' => $month], [ 'deposit_total' => $dailySum->deposit_total ?? 0, 'withdrawal_total' => $dailySum->withdrawal_total ?? 0, 'net_cashflow' => $netCashflow, 'purchase_total' => $dailySum->purchase_total ?? 0, 'card_total' => $dailySum->card_total ?? 0, 'receivable_end' => $lastDay->receivable_balance ?? 0, 'payable_end' => $lastDay->payable_balance ?? 0, 'bank_balance_end' => $lastDay->bank_balance_total ?? 0, 'mom_cashflow_change' => $momChange, ] ); return 1; } }