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

276 lines
11 KiB
PHP

<?php
require_once __DIR__ . '/../app/lib/auth.php';
require_once __DIR__ . '/../app/lib/db.php';
require_once __DIR__ . '/../app/lib/helpers.php';
require_once __DIR__ . '/../app/lib/loan_service.php';
check_auth();
$pdo = db();
$uid = user_id();
$error = '';
$msg = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
$mode = $_POST['mode'] ?? '';
if ($mode === 'delete') {
$loanId = (int)($_POST['loan_id'] ?? 0);
if ($loanId <= 0) {
throw new RuntimeException('대출 ID가 올바르지 않습니다.');
}
delete_loan_with_history($uid, $loanId);
$msg = '대출 및 관련 자동 생성 이력이 삭제되었습니다.';
}
if ($mode === 'reset_auto_history') {
$loanId = (int)($_POST['loan_id'] ?? 0);
if ($loanId <= 0) {
throw new RuntimeException('대출 ID가 올바르지 않습니다.');
}
reset_loan_auto_history_and_reapply($uid, $loanId, date('Y-m-d'));
$msg = '자동반영 이력을 초기화하고 오늘 기준으로 다시 반영했습니다.';
}
} catch (Throwable $e) {
$error = $e->getMessage();
}
}
$stmt = $pdo->prepare("
SELECT
l.*,
a.account_name,
a.institution_name,
(
SELECT COUNT(*)
FROM loan_schedules ls
WHERE ls.loan_id = l.id
AND ls.is_paid = 0
) AS unpaid_count,
(
SELECT COUNT(*)
FROM loan_schedules ls
WHERE ls.loan_id = l.id
AND ls.is_paid = 1
) AS paid_count,
(
SELECT COUNT(*)
FROM loan_schedules ls
WHERE ls.loan_id = l.id
) AS total_count,
(
SELECT MIN(ls.due_date)
FROM loan_schedules ls
WHERE ls.loan_id = l.id
AND ls.is_paid = 0
) AS next_due_date,
(
SELECT MAX(ls.due_date)
FROM loan_schedules ls
WHERE ls.loan_id = l.id
) AS maturity_due_date,
(
SELECT ls.scheduled_total
FROM loan_schedules ls
WHERE ls.loan_id = l.id
AND ls.is_paid = 0
ORDER BY ls.due_date ASC, ls.cycle_no ASC
LIMIT 1
) AS next_payment_amount,
(
SELECT ls.payment_phase
FROM loan_schedules ls
WHERE ls.loan_id = l.id
AND ls.is_paid = 0
ORDER BY ls.due_date ASC, ls.cycle_no ASC
LIMIT 1
) AS next_payment_phase,
(
SELECT COALESCE(SUM(ls.scheduled_total), 0)
FROM loan_schedules ls
WHERE ls.loan_id = l.id
AND ls.is_paid = 0
) AS remaining_total_amount
FROM loans l
LEFT JOIN accounts a ON a.id = l.account_id
WHERE l.user_id = ?
ORDER BY
CASE WHEN l.status = 'active' THEN 0 ELSE 1 END,
l.id DESC
");
$stmt->execute([$uid]);
$loans = $stmt->fetchAll();
require __DIR__ . '/../app/views/header.php';
?>
<div class="page-head">
<h2>대출 목록</h2>
<a href="/loan_create.php" class="btn btn-primary">대출 등록</a>
</div>
<?php if ($error): ?>
<div class="alert alert-danger"><?= h($error) ?></div>
<?php endif; ?>
<?php if ($msg): ?>
<div class="alert alert-success"><?= h($msg) ?></div>
<?php endif; ?>
<div class="row g-3">
<?php foreach ($loans as $loan): ?>
<?php
$summary = get_loan_remaining_summary((int)$loan['id']);
$paidCount = (int)($loan['paid_count'] ?? 0);
$totalCount = (int)($loan['total_count'] ?? 0);
$progress = $totalCount > 0 ? round(($paidCount / $totalCount) * 100, 1) : 0.0;
$phaseText = '-';
if (($loan['next_payment_phase'] ?? '') === 'grace') {
$phaseText = '거치 중';
} elseif (($loan['next_payment_phase'] ?? '') === 'repayment') {
$phaseText = '상환 중';
} elseif ($loan['status'] === 'closed') {
$phaseText = '종료';
}
?>
<div class="col-12 col-xxl-6">
<div class="card finance-card h-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-start gap-3 flex-wrap">
<div>
<div class="eyebrow">
<?= h($loan['lender_name'] ?: '-') ?>
<?php if (!empty($loan['account_name'])): ?>
· <?= h($loan['account_name']) ?>
<?php endif; ?>
</div>
<div class="card-title-lg"><?= h($loan['loan_name']) ?></div>
</div>
<div class="text-end">
<span class="badge <?= $loan['status'] === 'active' ? 'text-bg-warning' : 'text-bg-success' ?>">
<?= $loan['status'] === 'active' ? '진행중' : '종료' ?>
</span>
<div class="small text-secondary mt-2"><?= h($phaseText) ?></div>
</div>
</div>
<div class="row g-3 mt-2">
<div class="col-6 col-md-3">
<div class="stat-label">대출원금</div>
<div class="stat-value"><?= won($loan['principal_amount']) ?></div>
</div>
<div class="col-6 col-md-3">
<div class="stat-label">연이자율</div>
<div class="stat-value"><?= h((string)$loan['annual_interest_rate']) ?>%</div>
</div>
<div class="col-6 col-md-3">
<div class="stat-label">거치기간</div>
<div class="stat-value"><?= h((string)$loan['grace_period_months']) ?>개월</div>
</div>
<div class="col-6 col-md-3">
<div class="stat-label">상환기간</div>
<div class="stat-value"><?= h((string)$loan['repayment_months']) ?>개월</div>
</div>
<div class="col-6 col-md-3">
<div class="stat-label">남은 원금</div>
<div class="stat-value"><?= won($summary['remaining_principal']) ?></div>
</div>
<div class="col-6 col-md-3">
<div class="stat-label">남은 이자</div>
<div class="stat-value text-danger"><?= won($summary['remaining_interest']) ?></div>
</div>
<div class="col-6 col-md-3">
<div class="stat-label">남은 총액</div>
<div class="stat-value"><?= won($loan['remaining_total_amount'] ?? 0) ?></div>
</div>
<div class="col-6 col-md-3">
<div class="stat-label">다음 회차 금액</div>
<div class="stat-value"><?= won($loan['next_payment_amount'] ?? 0) ?></div>
</div>
<div class="col-6 col-md-3">
<div class="stat-label">다음 납부일</div>
<div class="stat-value"><?= h($loan['next_due_date'] ?: '-') ?></div>
</div>
<div class="col-6 col-md-3">
<div class="stat-label">만기일자</div>
<div class="stat-value"><?= h($loan['maturity_due_date'] ?: '-') ?></div>
</div>
<div class="col-6 col-md-3">
<div class="stat-label">남은 회차 수</div>
<div class="stat-value"><?= h((string)$loan['unpaid_count']) ?>회</div>
</div>
<div class="col-6 col-md-3">
<div class="stat-label">진행률</div>
<div class="stat-value"><?= number_format($progress, 1) ?>%</div>
</div>
</div>
<div class="mt-3">
<div class="finance-progress">
<div class="progress-bar" role="progressbar" style="width: <?= $progress ?>%"></div>
</div>
<div class="small text-secondary mt-2">
완료 <?= h((string)$paidCount) ?>회 / 전체 <?= h((string)$totalCount) ?>회
</div>
</div>
<div class="mt-3 d-flex flex-wrap gap-2">
<a href="/loan_detail.php?id=<?= $loan['id'] ?>" class="btn btn-sm btn-outline-primary">상세/스케줄</a>
<a href="/loan_edit.php?id=<?= $loan['id'] ?>" class="btn btn-sm btn-outline-secondary">수정</a>
<?php if ($loan['status'] === 'active'): ?>
<a href="/loan_prepay.php?id=<?= $loan['id'] ?>" class="btn btn-sm btn-outline-danger">중도상환</a>
<form method="post" class="d-inline">
<input type="hidden" name="mode" value="reset_auto_history">
<input type="hidden" name="loan_id" value="<?= $loan['id'] ?>">
<button class="btn btn-sm btn-outline-warning" onclick="return confirm('자동반영 이력과 자동 생성 거래를 삭제하고 오늘 기준으로 다시 반영합니다. 계속하시겠습니까?');">
자동반영 리셋 후 재적용
</button>
</form>
<?php endif; ?>
<form method="post" class="d-inline">
<input type="hidden" name="mode" value="delete">
<input type="hidden" name="loan_id" value="<?= $loan['id'] ?>">
<button class="btn btn-sm btn-outline-dark" onclick="return confirm('대출, 상환 스케줄, 대출 납부이력, 자동 생성 거래내역까지 삭제됩니다. 계속하시겠습니까?');">
삭제
</button>
</form>
</div>
</div>
</div>
</div>
<?php endforeach; ?>
<?php if (!$loans): ?>
<div class="col-12">
<div class="card finance-card">
<div class="card-body empty-state">
등록된 대출이 없습니다.
</div>
</div>
</div>
<?php endif; ?>
</div>
<?php require __DIR__ . '/../app/views/footer.php'; ?>