prepare("
SELECT
i.*,
a.account_name,
a.institution_name,
t.transaction_date,
t.merchant_name,
t.description,
COALESCE(SUM(CASE WHEN s.is_billed = 0 THEN s.principal_amount ELSE 0 END), 0) AS remaining_principal,
COALESCE(SUM(CASE WHEN s.is_billed = 0 THEN s.interest_amount ELSE 0 END), 0) AS remaining_interest,
COALESCE(SUM(CASE WHEN s.is_billed = 0 THEN s.total_amount ELSE 0 END), 0) AS remaining_total,
COALESCE(SUM(CASE WHEN s.is_billed = 1 THEN s.total_amount ELSE 0 END), 0) AS billed_total,
COALESCE(MIN(CASE WHEN s.is_billed = 0 THEN s.cycle_no ELSE NULL END), 0) AS next_cycle
FROM installments i
JOIN accounts a ON a.id = i.account_id
JOIN transactions t ON t.id = i.transaction_id
LEFT JOIN installment_schedules s ON s.installment_id = i.id
WHERE i.id = ?
AND i.user_id = ?
GROUP BY
i.id, i.user_id, i.transaction_id, i.account_id,
i.principal_amount, i.interest_total, i.total_billed_amount,
i.installment_months, i.annual_interest_rate, i.start_year_month,
i.interest_type, i.current_cycle, i.is_completed,
i.prepaid_principal_amount, i.prepaid_interest_amount,
i.created_at, i.updated_at,
a.account_name, a.institution_name,
t.transaction_date, t.merchant_name, t.description
");
$stmt->execute([$installmentId, $uid]);
$installment = $stmt->fetch();
if (!$installment) {
require __DIR__ . '/../app/views/header.php';
?>
할부 정보를 찾을 수 없습니다.
이미 초기화되었거나 삭제된 할부 내역일 수 있습니다.
prepare("
SELECT *
FROM accounts
WHERE user_id = ?
AND is_active = 1
AND account_type IN ('bank','cash','other')
ORDER BY FIELD(account_type, 'bank', 'cash', 'other'), id ASC
");
$stmt->execute([$uid]);
$paymentAccounts = $stmt->fetchAll();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
$paymentAccountId = (int)($_POST['payment_account_id'] ?? 0);
$prepayDate = $_POST['prepay_date'] ?? date('Y-m-d');
$prepayPrincipal = (float)str_replace(',', '', (string)($_POST['prepay_principal_amount'] ?? 0));
$prepayInterest = (float)str_replace(',', '', (string)($_POST['prepay_interest_amount'] ?? 0));
$description = trim($_POST['description'] ?? '') ?: null;
$targetScheduleId = !empty($_POST['target_schedule_id'])
? (int)$_POST['target_schedule_id']
: null;
if ($paymentAccountId <= 0) {
throw new RuntimeException('결제 계좌를 선택하세요.');
}
prepay_installment(
$uid,
$installmentId,
$paymentAccountId,
$prepayDate,
$prepayPrincipal,
$prepayInterest,
$description,
$targetScheduleId
);
$msg = '선결제/중도상환이 처리되었습니다.';
$stmt = $pdo->prepare("
SELECT
i.*,
a.account_name,
a.institution_name,
t.transaction_date,
t.merchant_name,
t.description,
COALESCE(SUM(CASE WHEN s.is_billed = 0 THEN s.principal_amount ELSE 0 END), 0) AS remaining_principal,
COALESCE(SUM(CASE WHEN s.is_billed = 0 THEN s.interest_amount ELSE 0 END), 0) AS remaining_interest,
COALESCE(SUM(CASE WHEN s.is_billed = 0 THEN s.total_amount ELSE 0 END), 0) AS remaining_total,
COALESCE(SUM(CASE WHEN s.is_billed = 1 THEN s.total_amount ELSE 0 END), 0) AS billed_total,
COALESCE(MIN(CASE WHEN s.is_billed = 0 THEN s.cycle_no ELSE NULL END), 0) AS next_cycle
FROM installments i
JOIN accounts a ON a.id = i.account_id
JOIN transactions t ON t.id = i.transaction_id
LEFT JOIN installment_schedules s ON s.installment_id = i.id
WHERE i.id = ?
AND i.user_id = ?
GROUP BY
i.id, i.user_id, i.transaction_id, i.account_id,
i.principal_amount, i.interest_total, i.total_billed_amount,
i.installment_months, i.annual_interest_rate, i.start_year_month,
i.interest_type, i.current_cycle, i.is_completed,
i.prepaid_principal_amount, i.prepaid_interest_amount,
i.created_at, i.updated_at,
a.account_name, a.institution_name,
t.transaction_date, t.merchant_name, t.description
");
$stmt->execute([$installmentId, $uid]);
$installment = $stmt->fetch();
} catch (Throwable $e) {
$error = $e->getMessage();
}
}
$stmt = $pdo->prepare("
SELECT *
FROM installment_schedules
WHERE installment_id = ?
ORDER BY cycle_no ASC
");
$stmt->execute([$installmentId]);
$schedules = $stmt->fetchAll();
$stmt = $pdo->prepare("
SELECT *
FROM installment_prepayments
WHERE installment_id = ?
AND user_id = ?
ORDER BY prepay_date DESC, id DESC
");
$stmt->execute([$installmentId, $uid]);
$prepayments = $stmt->fetchAll();
$remainingPrincipal = (float)($installment['remaining_principal'] ?? 0);
$remainingInterest = (float)($installment['remaining_interest'] ?? 0);
$remainingTotal = (float)($installment['remaining_total'] ?? 0);
$totalBilled = (float)($installment['total_billed_amount'] ?? 0);
$billedTotal = (float)($installment['billed_total'] ?? 0);
$progress = $totalBilled > 0 ? (($totalBilled - $remainingTotal) / $totalBilled) * 100 : 0;
$progress = max(0, min(100, $progress));
$barWidth = $progress > 0 ? max($progress, 2) : 0;
require __DIR__ . '/../app/views/header.php';
?>
= h($error) ?>
= h($msg) ?>
= h($installment['institution_name']) ?> / = h($installment['account_name']) ?>
= h($installment['merchant_name'] ?: '사용처 없음') ?>
= $remainingTotal > 0 ? '진행중' : '완료' ?>
결제일 = ymd($installment['transaction_date']) ?>
· 시작 청구월 = h($installment['start_year_month']) ?>
· = intvalf($installment['installment_months']) ?>개월
= h($installment['description']) ?>
남은 원금
= won($remainingPrincipal) ?>
남은 이자
= won($remainingInterest) ?>
남은 총액
= won($remainingTotal) ?>
연이자율
= numf($installment['annual_interest_rate'], 2) ?>%
총 청구금액
= won($totalBilled) ?>
청구완료 금액
= won($billedTotal) ?>
진행률 = percentf($progress) ?>
0): ?>
· 다음 = intvalf($installment['next_cycle']) ?>회차