tenantId(); // 입금 쿼리 (payment_method = 'transfer') $depositsQuery = DB::table('deposits') ->leftJoin('bank_accounts', 'deposits.bank_account_id', '=', 'bank_accounts.id') ->leftJoin('clients', 'deposits.client_id', '=', 'clients.id') ->where('deposits.tenant_id', $tenantId) ->where('deposits.payment_method', 'transfer') ->whereNull('deposits.deleted_at') ->select([ 'deposits.id', DB::raw("'deposit' as type"), 'deposits.deposit_date as transaction_date', 'bank_accounts.id as bank_account_id', 'bank_accounts.bank_name', 'bank_accounts.account_name', 'deposits.description as note', 'deposits.client_id as vendor_id', DB::raw('COALESCE(clients.name, deposits.client_name) as vendor_name'), 'deposits.client_name as depositor_name', 'deposits.amount as deposit_amount', DB::raw('0 as withdrawal_amount'), 'deposits.account_code as transaction_type', DB::raw("CONCAT('deposit-', deposits.id) as source_id"), 'deposits.created_at', 'deposits.updated_at', ]); // 출금 쿼리 (payment_method = 'transfer') $withdrawalsQuery = DB::table('withdrawals') ->leftJoin('bank_accounts', 'withdrawals.bank_account_id', '=', 'bank_accounts.id') ->leftJoin('clients', 'withdrawals.client_id', '=', 'clients.id') ->where('withdrawals.tenant_id', $tenantId) ->where('withdrawals.payment_method', 'transfer') ->whereNull('withdrawals.deleted_at') ->select([ 'withdrawals.id', DB::raw("'withdrawal' as type"), 'withdrawals.withdrawal_date as transaction_date', 'bank_accounts.id as bank_account_id', 'bank_accounts.bank_name', 'bank_accounts.account_name', 'withdrawals.description as note', 'withdrawals.client_id as vendor_id', DB::raw('COALESCE(clients.name, withdrawals.client_name) as vendor_name'), 'withdrawals.client_name as depositor_name', DB::raw('0 as deposit_amount'), 'withdrawals.amount as withdrawal_amount', 'withdrawals.account_code as transaction_type', DB::raw("CONCAT('withdrawal-', withdrawals.id) as source_id"), 'withdrawals.created_at', 'withdrawals.updated_at', ]); // 필터 적용: 날짜 범위 if ($startDate) { $depositsQuery->whereDate('deposits.deposit_date', '>=', $startDate); $withdrawalsQuery->whereDate('withdrawals.withdrawal_date', '>=', $startDate); } if ($endDate) { $depositsQuery->whereDate('deposits.deposit_date', '<=', $endDate); $withdrawalsQuery->whereDate('withdrawals.withdrawal_date', '<=', $endDate); } // 필터 적용: 계좌 if ($bankAccountId) { $depositsQuery->where('deposits.bank_account_id', $bankAccountId); $withdrawalsQuery->where('withdrawals.bank_account_id', $bankAccountId); } // 필터 적용: 입출금유형 (account_code) if ($transactionType) { if ($transactionType === 'unset') { $depositsQuery->whereNull('deposits.account_code'); $withdrawalsQuery->whereNull('withdrawals.account_code'); } else { $depositsQuery->where('deposits.account_code', $transactionType); $withdrawalsQuery->where('withdrawals.account_code', $transactionType); } } // 필터 적용: 검색어 if ($search) { $depositsQuery->where(function ($q) use ($search) { $q->where('bank_accounts.bank_name', 'like', "%{$search}%") ->orWhere('bank_accounts.account_name', 'like', "%{$search}%") ->orWhere('deposits.client_name', 'like', "%{$search}%") ->orWhere('clients.name', 'like', "%{$search}%") ->orWhere('deposits.description', 'like', "%{$search}%"); }); $withdrawalsQuery->where(function ($q) use ($search) { $q->where('bank_accounts.bank_name', 'like', "%{$search}%") ->orWhere('bank_accounts.account_name', 'like', "%{$search}%") ->orWhere('withdrawals.client_name', 'like', "%{$search}%") ->orWhere('clients.name', 'like', "%{$search}%") ->orWhere('withdrawals.description', 'like', "%{$search}%"); }); } // UNION $unionQuery = $depositsQuery->union($withdrawalsQuery); // 정렬 컬럼 매핑 $sortColumn = match ($sortBy) { 'transaction_date' => 'transaction_date', 'deposit_amount', 'withdrawal_amount', 'amount' => DB::raw('(deposit_amount + withdrawal_amount)'), default => 'transaction_date', }; // 전체 조회하여 정렬 및 잔액 계산 $allItems = DB::query() ->fromSub($unionQuery, 'transactions') ->orderBy($sortColumn, $sortDir) ->get(); // 잔액 계산 (날짜순 정렬 기준) $balance = 0; $itemsWithBalance = $allItems->map(function ($item) use (&$balance) { $balance += $item->deposit_amount - $item->withdrawal_amount; $item->balance = $balance; return $item; }); // 수동 페이지네이션 $total = $itemsWithBalance->count(); $offset = ($page - 1) * $perPage; $paginatedItems = $itemsWithBalance->slice($offset, $perPage)->values(); return new LengthAwarePaginator( $paginatedItems, $total, $perPage, $page, ['path' => request()->url()] ); } /** * 입출금 요약 통계 */ public function summary(array $params): array { $startDate = $params['start_date'] ?? null; $endDate = $params['end_date'] ?? null; $tenantId = $this->tenantId(); // 입금 합계 (계좌이체) $depositQuery = Deposit::where('tenant_id', $tenantId) ->where('payment_method', 'transfer'); if ($startDate) { $depositQuery->whereDate('deposit_date', '>=', $startDate); } if ($endDate) { $depositQuery->whereDate('deposit_date', '<=', $endDate); } $totalDeposit = $depositQuery->sum('amount'); $depositUnsetCount = (clone $depositQuery)->whereNull('account_code')->count(); // 출금 합계 (계좌이체) $withdrawalQuery = Withdrawal::where('tenant_id', $tenantId) ->where('payment_method', 'transfer'); if ($startDate) { $withdrawalQuery->whereDate('withdrawal_date', '>=', $startDate); } if ($endDate) { $withdrawalQuery->whereDate('withdrawal_date', '<=', $endDate); } $totalWithdrawal = $withdrawalQuery->sum('amount'); $withdrawalUnsetCount = (clone $withdrawalQuery)->whereNull('account_code')->count(); return [ 'total_deposit' => (float) $totalDeposit, 'total_withdrawal' => (float) $totalWithdrawal, 'deposit_unset_count' => (int) $depositUnsetCount, 'withdrawal_unset_count' => (int) $withdrawalUnsetCount, ]; } /** * 계좌 목록 조회 (필터용) */ public function getAccountOptions(): array { $tenantId = $this->tenantId(); return BankAccount::where('tenant_id', $tenantId) ->where('status', 'active') ->orderBy('bank_name') ->orderBy('account_name') ->get() ->map(fn ($acc) => [ 'id' => $acc->id, 'label' => "{$acc->bank_name}|{$acc->account_name}", ]) ->toArray(); } }