onlyTrashed(); } elseif ($filters['trashed'] === 'with') { $query->withTrashed(); } } // 검색 필터 if (! empty($filters['search'])) { $search = $filters['search']; $query->where(function ($q) use ($search) { $q->where('bank_name', 'like', "%{$search}%") ->orWhere('account_number', 'like', "%{$search}%") ->orWhere('account_holder', 'like', "%{$search}%"); }); } // 은행 필터 if (! empty($filters['bank_name'])) { $query->where('bank_name', $filters['bank_name']); } // 예금종류 필터 if (! empty($filters['account_type'])) { $query->where('account_type', $filters['account_type']); } // 활성 상태 필터 (status 기반) if (isset($filters['status'])) { $query->where('status', $filters['status']); } return $query ->addSelect(['*']) ->addSelect([ 'latest_barobill_trans_date' => BarobillBankTransaction::select('trans_date') ->whereColumn('bank_account_num', DB::raw("REPLACE(bank_accounts.account_number, '-', '')")) ->orderByDesc('trans_date') ->orderByDesc('trans_time') ->limit(1), 'latest_barobill_trans_time' => BarobillBankTransaction::select('trans_time') ->whereColumn('bank_account_num', DB::raw("REPLACE(bank_accounts.account_number, '-', '')")) ->orderByDesc('trans_date') ->orderByDesc('trans_time') ->limit(1), ]) ->orderBy('sort_order') ->orderBy('bank_name') ->paginate($perPage); } /** * 모든 계좌 목록 (드롭다운용) */ public function getAllAccounts(): Collection { return BankAccount::active() ->ordered() ->get(['id', 'bank_name', 'account_number', 'account_type', 'balance']); } /** * 은행별 통계 */ public function getStatsByBank(): Collection { return BankAccount::active() ->select('bank_name') ->selectRaw('COUNT(*) as count') ->selectRaw('SUM(balance) as total_balance') ->groupBy('bank_name') ->orderBy('total_balance', 'desc') ->get(); } // ========================================================================= // 계좌 CRUD // ========================================================================= /** * 계좌 상세 조회 */ public function getAccountById(int $id, bool $withTrashed = false): ?BankAccount { $query = BankAccount::query(); if ($withTrashed) { $query->withTrashed(); } return $query->find($id); } /** * 계좌 생성 */ public function createAccount(array $data): BankAccount { $data['created_by'] = auth()->id(); $data['tenant_id'] = $data['tenant_id'] ?? session('selected_tenant_id') ?? auth()->user()?->tenant_id; return BankAccount::create($data); } /** * 계좌 수정 */ public function updateAccount(BankAccount $account, array $data): BankAccount { $data['updated_by'] = auth()->id(); $account->update($data); return $account->fresh(); } /** * 계좌 삭제 (Soft Delete) */ public function deleteAccount(BankAccount $account): bool { $account->deleted_by = auth()->id(); $account->save(); return $account->delete(); } /** * 계좌 복원 */ public function restoreAccount(BankAccount $account): bool { $account->deleted_by = null; return $account->restore(); } /** * 계좌 영구 삭제 */ public function forceDeleteAccount(BankAccount $account): bool { return $account->forceDelete(); } // ========================================================================= // 계좌 상태 토글 // ========================================================================= /** * 활성/비활성 토글 (status 기반) */ public function toggleActive(BankAccount $account): BankAccount { $newStatus = $account->status === 'active' ? 'inactive' : 'active'; $account->update([ 'status' => $newStatus, 'updated_by' => auth()->id(), ]); return $account->fresh(); } // ========================================================================= // 거래내역 관련 // ========================================================================= /** * 계좌의 거래내역 조회 */ public function getTransactions(int $accountId, array $filters = [], int $perPage = 20): LengthAwarePaginator { $query = BankTransaction::forAccount($accountId); // Soft Delete 필터 if (isset($filters['trashed'])) { if ($filters['trashed'] === 'only') { $query->onlyTrashed(); } elseif ($filters['trashed'] === 'with') { $query->withTrashed(); } } // 검색 필터 if (! empty($filters['search'])) { $search = $filters['search']; $query->where(function ($q) use ($search) { $q->where('description', 'like', "%{$search}%") ->orWhere('counterparty', 'like', "%{$search}%") ->orWhere('reference_number', 'like', "%{$search}%"); }); } // 거래유형 필터 if (! empty($filters['transaction_type'])) { $query->ofType($filters['transaction_type']); } // 날짜 범위 필터 if (! empty($filters['start_date']) && ! empty($filters['end_date'])) { $query->dateBetween($filters['start_date'], $filters['end_date']); } elseif (! empty($filters['start_date'])) { $query->where('transaction_date', '>=', $filters['start_date']); } elseif (! empty($filters['end_date'])) { $query->where('transaction_date', '<=', $filters['end_date']); } // 대사 상태 필터 if (isset($filters['is_reconciled'])) { $query->reconciled((bool) $filters['is_reconciled']); } return $query ->with('bankAccount:id,bank_name,account_number') ->latest() ->paginate($perPage); } /** * 거래내역 생성 */ public function createTransaction(array $data): BankTransaction { return DB::transaction(function () use ($data) { $account = BankAccount::findOrFail($data['bank_account_id']); // 거래 후 잔액 계산 $newBalance = match ($data['transaction_type']) { BankTransaction::TYPE_DEPOSIT => $account->balance + $data['amount'], BankTransaction::TYPE_WITHDRAWAL, BankTransaction::TYPE_TRANSFER => $account->balance - $data['amount'], default => $account->balance, }; $data['balance_after'] = $newBalance; $data['tenant_id'] = $account->tenant_id; $data['created_by'] = auth()->id(); $transaction = BankTransaction::create($data); // 계좌 잔액 업데이트 $account->updateBalance($newBalance); return $transaction; }); } /** * 거래내역 수정 */ public function updateTransaction(BankTransaction $transaction, array $data): BankTransaction { $data['updated_by'] = auth()->id(); $transaction->update($data); return $transaction->fresh(); } /** * 거래내역 삭제 */ public function deleteTransaction(BankTransaction $transaction): bool { $transaction->deleted_by = auth()->id(); $transaction->save(); return $transaction->delete(); } // ========================================================================= // 일괄 작업 // ========================================================================= /** * 일괄 삭제 */ public function bulkDelete(array $ids): int { return BankAccount::whereIn('id', $ids) ->update([ 'deleted_by' => auth()->id(), 'deleted_at' => now(), ]); } /** * 일괄 복원 */ public function bulkRestore(array $ids): int { return BankAccount::onlyTrashed() ->whereIn('id', $ids) ->update([ 'deleted_by' => null, 'deleted_at' => null, ]); } /** * 일괄 영구 삭제 */ public function bulkForceDelete(array $ids): int { return BankAccount::onlyTrashed() ->whereIn('id', $ids) ->forceDelete(); } // ========================================================================= // 요약 및 통계 // ========================================================================= /** * 전체 요약 통계 */ public function getSummary(): array { $accounts = BankAccount::active()->get(); return [ 'total_accounts' => $accounts->count(), 'total_balance' => $accounts->sum('balance'), 'formatted_total_balance' => number_format($accounts->sum('balance')).'원', 'by_bank' => $accounts->groupBy('bank_name')->map(fn ($group) => [ 'count' => $group->count(), 'total' => $group->sum('balance'), ]), ]; } }