Files
2026-06-07 00:33:58 +09:00

281 lines
10 KiB
PHP

<?php
require_once __DIR__ . '/../app/lib/auth.php';
require_once __DIR__ . '/../app/lib/db.php';
require_once __DIR__ . '/../app/lib/helpers.php';
check_auth();
$pdo = db();
$uid = user_id();
$ym = $_GET['ym'] ?? date('Y-m');
$q = trim($_GET['q'] ?? '');
$type = $_GET['type'] ?? '';
$accountId = (int)($_GET['account_id'] ?? 0);
$categoryId = (int)($_GET['category_id'] ?? 0);
$start = $ym . '-01';
$end = date('Y-m-t', strtotime($start));
$params = [$uid, $start, $end];
$where = [
"t.user_id = ?",
"t.transaction_date BETWEEN ? AND ?"
];
if ($q !== '') {
$where[] = "(t.merchant_name LIKE ? OR t.description LIKE ? OR c.name LIKE ? OR a.account_name LIKE ?)";
$like = '%' . $q . '%';
array_push($params, $like, $like, $like, $like);
}
if (in_array($type, ['income', 'expense', 'transfer', 'card_payment'], true)) {
$where[] = "t.transaction_type = ?";
$params[] = $type;
}
if ($accountId > 0) {
$where[] = "t.account_id = ?";
$params[] = $accountId;
}
if ($categoryId > 0) {
$where[] = "t.category_id = ?";
$params[] = $categoryId;
}
$sql = "
SELECT
t.*,
a.account_name,
a.account_type,
a.card_kind,
ra.account_name AS related_account_name,
c.name AS category_name
FROM transactions t
JOIN accounts a ON t.account_id = a.id
LEFT JOIN accounts ra ON t.related_account_id = ra.id
JOIN categories c ON t.category_id = c.id
WHERE " . implode(' AND ', $where) . "
ORDER BY t.transaction_date DESC, t.id DESC
";
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$list = $stmt->fetchAll();
$stmt = $pdo->prepare("SELECT id, account_name FROM accounts WHERE user_id = ? AND is_active = 1 ORDER BY id ASC");
$stmt->execute([$uid]);
$accounts = $stmt->fetchAll();
$stmt = $pdo->prepare("SELECT id, category_type, name FROM categories WHERE user_id = ? AND is_active = 1 ORDER BY category_type, sort_order, id");
$stmt->execute([$uid]);
$categories = $stmt->fetchAll();
/* 요약 */
$sumIncome = 0;
$sumExpense = 0;
$sumTransfer = 0;
$sumCardPay = 0;
foreach ($list as $row) {
$amt = (float)$row['amount'];
if ($row['transaction_type'] === 'income') $sumIncome += $amt;
elseif ($row['transaction_type'] === 'expense') $sumExpense += $amt;
elseif ($row['transaction_type'] === 'transfer') $sumTransfer += $amt;
elseif ($row['transaction_type'] === 'card_payment') $sumCardPay += $amt;
}
function tx_label(string $type): string
{
return match ($type) {
'income' => '수입',
'expense' => '지출',
'transfer' => '이체',
'card_payment' => '카드납부',
default => $type
};
}
require __DIR__ . '/../app/views/header.php';
?>
<div class="page-head">
<h2>거래내역</h2>
<a href="/transaction_create.php" class="btn btn-primary">거래등록</a>
</div>
<div class="card finance-card mb-4">
<div class="card-body">
<form method="get" class="row g-3">
<div class="col-md-2">
<label class="form-label">월</label>
<input type="month" name="ym" class="form-control" value="<?= h($ym) ?>">
</div>
<div class="col-md-3">
<label class="form-label">검색어</label>
<input type="text" name="q" class="form-control" value="<?= h($q) ?>" placeholder="사용처, 메모, 카테고리">
</div>
<div class="col-md-2">
<label class="form-label">유형</label>
<select name="type" class="form-select">
<option value="">전체</option>
<option value="income" <?= $type === 'income' ? 'selected' : '' ?>>수입</option>
<option value="expense" <?= $type === 'expense' ? 'selected' : '' ?>>지출</option>
<option value="transfer" <?= $type === 'transfer' ? 'selected' : '' ?>>이체</option>
<option value="card_payment" <?= $type === 'card_payment' ? 'selected' : '' ?>>카드납부</option>
</select>
</div>
<div class="col-md-2">
<label class="form-label">계좌</label>
<select name="account_id" class="form-select">
<option value="0">전체</option>
<?php foreach ($accounts as $account): ?>
<option value="<?= $account['id'] ?>" <?= $accountId === (int)$account['id'] ? 'selected' : '' ?>>
<?= h($account['account_name']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-3">
<label class="form-label">카테고리</label>
<select name="category_id" class="form-select">
<option value="0">전체</option>
<?php foreach ($categories as $category): ?>
<option value="<?= $category['id'] ?>" <?= $categoryId === (int)$category['id'] ? 'selected' : '' ?>>
[<?= h($category['category_type']) ?>] <?= h($category['name']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-12 d-flex gap-2">
<button class="btn btn-primary">조회</button>
<a href="/transactions.php" class="btn btn-outline-secondary">초기화</a>
</div>
</form>
</div>
</div>
<div class="row g-3 mb-4">
<div class="col-md-3">
<div class="card finance-card">
<div class="card-body">
<div class="stat-label">수입</div>
<div class="stat-value text-primary"><?= won($sumIncome) ?></div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card finance-card">
<div class="card-body">
<div class="stat-label">지출</div>
<div class="stat-value text-danger"><?= won($sumExpense) ?></div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card finance-card">
<div class="card-body">
<div class="stat-label">이체</div>
<div class="stat-value"><?= won($sumTransfer) ?></div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card finance-card">
<div class="card-body">
<div class="stat-label">카드납부</div>
<div class="stat-value"><?= won($sumCardPay) ?></div>
</div>
</div>
</div>
</div>
<div class="card finance-card">
<div class="card-body mobile-scroll">
<table class="table table-hover align-middle mb-0 transaction-list-table">
<thead>
<tr>
<th>날짜</th>
<th>유형</th>
<th>계좌</th>
<th>관련</th>
<th>카테고리</th>
<th>사용처</th>
<th class="text-end">금액</th>
<th>부가정보</th>
<th>메모</th>
<th>관리</th>
</tr>
</thead>
<tbody>
<?php foreach ($list as $row): ?>
<?php
$class = 'amount-transfer';
if ($row['transaction_type'] === 'income') $class = 'amount-income';
if ($row['transaction_type'] === 'expense') $class = 'amount-expense';
if ($row['transaction_type'] === 'card_payment') $class = 'amount-card';
$extra = [];
if (!empty($row['billing_year_month'])) {
$extra[] = '청구월 ' . $row['billing_year_month'];
}
if (!empty($row['is_installment']) && !empty($row['installment_months'])) {
$extra[] = $row['installment_months'] . '개월 할부';
}
if ($row['account_type'] === 'card' && $row['card_kind'] === 'check') {
$extra[] = '체크카드';
}
if ($row['account_type'] === 'card' && $row['card_kind'] === 'credit') {
$extra[] = '신용카드';
}
?>
<tr>
<td data-label="날짜"><?= h($row['transaction_date']) ?></td>
<td data-label="유형"><?= h(tx_label($row['transaction_type'])) ?></td>
<td data-label="계좌"><?= h($row['account_name']) ?></td>
<td data-label="관련"><?= h($row['related_account_name'] ?? '-') ?></td>
<td data-label="카테고리"><?= h($row['category_name']) ?></td>
<td data-label="사용처"><?= h($row['merchant_name'] ?: '-') ?></td>
<td data-label="금액" class="text-end <?= $class ?>"><?= won($row['amount']) ?></td>
<td data-label="부가정보"><?= h($extra ? implode(' / ', $extra) : '-') ?></td>
<td data-label="메모"><?= h($row['description'] ?: '-') ?></td>
<td data-label="관리" class="text-nowrap">
<a href="/transaction_create.php?copy_id=<?= $row['id'] ?>"
class="btn btn-sm btn-outline-secondary">복사</a>
<a href="/transaction_edit.php?id=<?= $row['id'] ?>" class="btn btn-sm btn-outline-primary">수정</a>
<form method="post" action="/transaction_delete.php" class="d-inline">
<input type="hidden" name="id" value="<?= (int)$row['id'] ?>">
<button class="btn btn-sm btn-outline-danger"
onclick="return confirm('삭제하시겠습니까?');">삭제</button>
</form>
</td>
</tr>
<?php endforeach; ?>
<?php if (!$list): ?>
<tr>
<td colspan="10" class="text-center text-secondary py-5">조회 결과가 없습니다.</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
<?php require __DIR__ . '/../app/views/footer.php'; ?>