337 lines
15 KiB
PHP
337 lines
15 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/lending_app.php';
|
|
|
|
lending_ensure_schema();
|
|
|
|
$loanId = isset($_GET['id']) ? (int) $_GET['id'] : 0;
|
|
$loan = $loanId > 0 ? fetch_loan($loanId) : null;
|
|
$returnValues = default_return_form();
|
|
$returnErrors = [];
|
|
|
|
if ($loan && $_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$action = trim((string) ($_POST['action'] ?? ''));
|
|
|
|
if ($action === 'mark_reminder_sent') {
|
|
if ($loan['is_returned']) {
|
|
set_flash('secondary', 'Pinjaman sudah selesai sehingga reminder tidak diperlukan.');
|
|
} else {
|
|
mark_reminder_sent($loanId);
|
|
set_flash('success', 'Waktu reminder terakhir sudah dicatat.');
|
|
}
|
|
header('Location: loan.php?id=' . $loanId);
|
|
exit;
|
|
}
|
|
|
|
if ($action === 'record_return') {
|
|
if ($loan['is_returned']) {
|
|
set_flash('secondary', 'Pengembalian sudah pernah dicatat sebelumnya.');
|
|
header('Location: loan.php?id=' . $loanId);
|
|
exit;
|
|
}
|
|
|
|
[$returnValues, $returnErrors] = validate_return_input($_POST, $loan);
|
|
if ($returnErrors === []) {
|
|
record_return($loanId, $returnValues);
|
|
set_flash('success', 'Pengembalian berhasil dicatat dan riwayat telah diperbarui.');
|
|
header('Location: loan.php?id=' . $loanId);
|
|
exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
$loan = $loanId > 0 ? fetch_loan($loanId) : null;
|
|
$flashes = pull_flashes();
|
|
$cssVersion = asset_version('assets/css/custom.css');
|
|
$jsVersion = asset_version('assets/js/main.js');
|
|
|
|
if (!$loan):
|
|
http_response_code(404);
|
|
?>
|
|
<!doctype html>
|
|
<html lang="id">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<?= render_head_meta('Pinjaman tidak ditemukan', 'Detail pinjaman tidak tersedia atau sudah dihapus dari sistem.') ?>
|
|
<meta name="robots" content="noindex, nofollow" />
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
|
|
<link rel="stylesheet" href="assets/css/custom.css?v=<?= e($cssVersion) ?>" />
|
|
</head>
|
|
<body class="app-body">
|
|
<main class="py-5">
|
|
<div class="container app-container">
|
|
<section class="section-card not-found-card text-center">
|
|
<span class="eyebrow">404</span>
|
|
<h1 class="hero-title mt-2">Pinjaman tidak ditemukan</h1>
|
|
<p class="hero-copy mb-4">Periksa kembali tautan detail pinjaman atau kembali ke dashboard untuk membuka transaksi lain.</p>
|
|
<a href="index.php" class="btn btn-primary btn-app">Kembali ke dashboard</a>
|
|
</section>
|
|
</div>
|
|
</main>
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" defer></script>
|
|
<script src="assets/js/main.js?v=<?= e($jsVersion) ?>" defer></script>
|
|
</body>
|
|
</html>
|
|
<?php
|
|
return;
|
|
endif;
|
|
?>
|
|
<!doctype html>
|
|
<html lang="id">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<?= render_head_meta('Detail ' . $loan['reference'], 'Lihat detail transaksi peminjaman, copy pengingat, dan catat pengembalian barang.') ?>
|
|
<meta name="robots" content="index, follow" />
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
|
|
<link rel="stylesheet" href="assets/css/custom.css?v=<?= e($cssVersion) ?>" />
|
|
</head>
|
|
<body class="app-body">
|
|
<div class="toast-container position-fixed top-0 end-0 p-3">
|
|
<div id="appToast" class="toast border-0 shadow-sm" role="status" aria-live="polite" aria-atomic="true">
|
|
<div class="toast-body"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<nav class="navbar navbar-expand-lg app-navbar sticky-top">
|
|
<div class="container app-container">
|
|
<a class="navbar-brand" href="index.php">
|
|
<span class="brand-mark">LP</span>
|
|
<span>
|
|
<strong><?= e(project_name()) ?></strong>
|
|
<small class="d-block text-muted">Loan detail</small>
|
|
</span>
|
|
</a>
|
|
<div class="d-flex align-items-center gap-2 ms-auto">
|
|
<a href="index.php#loan-board" class="btn btn-sm btn-outline-secondary btn-app">Kembali ke board</a>
|
|
<?php if (!$loan['is_returned']): ?>
|
|
<button type="button" class="btn btn-sm btn-primary btn-app copy-trigger" data-copy-text="<?= e($loan['reminder_message']) ?>" data-copy-success="Teks reminder <?= e($loan['reference']) ?> disalin.">Salin reminder</button>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<main class="py-4 py-lg-5">
|
|
<div class="container app-container d-grid gap-4">
|
|
<?php foreach ($flashes as $flash): ?>
|
|
<div class="alert alert-<?= e($flash['type'] === 'success' ? 'success' : 'secondary') ?> alert-dismissible fade show app-alert auto-dismiss-alert" role="alert">
|
|
<?= e($flash['message'] ?? '') ?>
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
|
|
<section class="section-card hero-card">
|
|
<div class="d-flex flex-column flex-lg-row justify-content-between align-items-start gap-4">
|
|
<div>
|
|
<span class="eyebrow">Detail transaksi</span>
|
|
<h1 class="hero-title mt-2 mb-2"><?= e($loan['reference']) ?> — <?= e($loan['item_name']) ?></h1>
|
|
<p class="hero-copy mb-3">Pinjaman atas nama <?= e($loan['borrower_name']) ?> dengan qty <?= e((string) $loan['quantity']) ?>. Gunakan halaman ini untuk reminder dan penutupan transaksi.</p>
|
|
<div class="d-flex flex-wrap gap-2">
|
|
<span class="status-badge <?= e($loan['status_badge_class']) ?>"><?= e($loan['status_label']) ?></span>
|
|
<span class="status-badge badge-status-neutral"><?= e($loan['due_note']) ?></span>
|
|
</div>
|
|
</div>
|
|
<div class="hero-summary-list loan-detail-summary">
|
|
<div>
|
|
<span class="summary-label">Jatuh tempo</span>
|
|
<strong><?= e($loan['due_at_label']) ?></strong>
|
|
</div>
|
|
<div>
|
|
<span class="summary-label">Reminder terakhir</span>
|
|
<strong><?= e($loan['last_reminder_at_label'] ?: 'Belum ada') ?></strong>
|
|
</div>
|
|
<div>
|
|
<span class="summary-label">Status pengembalian</span>
|
|
<strong><?= e($loan['is_returned'] ? $loan['returned_at_label'] : 'Belum kembali') ?></strong>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="row g-4 align-items-start">
|
|
<div class="col-xl-7 d-grid gap-4">
|
|
<div class="section-card">
|
|
<div class="section-header">
|
|
<div>
|
|
<h2>Ringkasan pinjaman</h2>
|
|
<p>Data inti transaksi untuk follow-up dan audit internal.</p>
|
|
</div>
|
|
<a href="index.php#new-loan" class="btn btn-sm btn-outline-secondary btn-app">Transaksi baru</a>
|
|
</div>
|
|
|
|
<dl class="detail-grid mb-0">
|
|
<div>
|
|
<dt>Peminjam</dt>
|
|
<dd><?= e($loan['borrower_name']) ?></dd>
|
|
</div>
|
|
<div>
|
|
<dt>Kontak</dt>
|
|
<dd><?= e($loan['borrower_contact'] ?: 'Belum diisi') ?></dd>
|
|
</div>
|
|
<div>
|
|
<dt>Divisi</dt>
|
|
<dd><?= e($loan['department'] ?: 'Tanpa divisi') ?></dd>
|
|
</div>
|
|
<div>
|
|
<dt>Kode barang</dt>
|
|
<dd><?= e($loan['item_code'] ?: 'Tanpa kode') ?></dd>
|
|
</div>
|
|
<div>
|
|
<dt>Tanggal pinjam</dt>
|
|
<dd><?= e($loan['loaned_at_label']) ?></dd>
|
|
</div>
|
|
<div>
|
|
<dt>Jatuh tempo</dt>
|
|
<dd><?= e($loan['due_at_label']) ?></dd>
|
|
</div>
|
|
<div>
|
|
<dt>Jumlah</dt>
|
|
<dd><?= e((string) $loan['quantity']) ?></dd>
|
|
</div>
|
|
<div>
|
|
<dt>Catatan awal</dt>
|
|
<dd><?= e($loan['notes'] ?: 'Tidak ada catatan tambahan') ?></dd>
|
|
</div>
|
|
</dl>
|
|
</div>
|
|
|
|
<div class="section-card">
|
|
<div class="section-header">
|
|
<div>
|
|
<h2>Template reminder</h2>
|
|
<p>Salin pesan untuk WhatsApp, email, atau chat internal.</p>
|
|
</div>
|
|
<?php if (!$loan['is_returned']): ?>
|
|
<form method="post">
|
|
<input type="hidden" name="action" value="mark_reminder_sent" />
|
|
<button type="submit" class="btn btn-sm btn-outline-secondary btn-app">Catat reminder terkirim</button>
|
|
</form>
|
|
<?php endif; ?>
|
|
</div>
|
|
<div class="message-preview"><?= e($loan['reminder_message']) ?></div>
|
|
<div class="d-flex flex-wrap gap-2 pt-3">
|
|
<button type="button" class="btn btn-outline-secondary btn-app copy-trigger" data-copy-text="<?= e($loan['reminder_message']) ?>" data-copy-success="Pesan reminder disalin.">Salin teks reminder</button>
|
|
<a href="index.php#loan-board" class="btn btn-primary btn-app">Kembali ke daftar</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-xl-5 d-grid gap-4">
|
|
<?php if (!$loan['is_returned']): ?>
|
|
<div class="section-card" id="return-form">
|
|
<div class="section-header">
|
|
<div>
|
|
<h2>Proses pengembalian</h2>
|
|
<p>Catat kapan barang kembali dan bagaimana kondisinya.</p>
|
|
</div>
|
|
<span class="section-chip">Close transaction</span>
|
|
</div>
|
|
|
|
<form method="post" novalidate class="row g-3">
|
|
<input type="hidden" name="action" value="record_return" />
|
|
|
|
<div class="col-12">
|
|
<label class="form-label" for="returned_at">Waktu kembali</label>
|
|
<input type="datetime-local" class="form-control <?= isset($returnErrors['returned_at']) ? 'is-invalid' : '' ?>" id="returned_at" name="returned_at" value="<?= e($returnValues['returned_at']) ?>" />
|
|
<?php if (isset($returnErrors['returned_at'])): ?><div class="invalid-feedback"><?= e($returnErrors['returned_at']) ?></div><?php endif; ?>
|
|
</div>
|
|
|
|
<div class="col-12">
|
|
<label class="form-label" for="return_condition">Kondisi barang saat kembali</label>
|
|
<select class="form-select <?= isset($returnErrors['return_condition']) ? 'is-invalid' : '' ?>" id="return_condition" name="return_condition">
|
|
<?php foreach (['baik' => 'Baik', 'catatan' => 'Ada catatan', 'rusak' => 'Rusak'] as $optionValue => $optionLabel): ?>
|
|
<option value="<?= e($optionValue) ?>" <?= $returnValues['return_condition'] === $optionValue ? 'selected' : '' ?>><?= e($optionLabel) ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
<?php if (isset($returnErrors['return_condition'])): ?><div class="invalid-feedback"><?= e($returnErrors['return_condition']) ?></div><?php endif; ?>
|
|
</div>
|
|
|
|
<div class="col-12">
|
|
<label class="form-label" for="return_notes">Catatan pengembalian</label>
|
|
<textarea class="form-control <?= isset($returnErrors['return_notes']) ? 'is-invalid' : '' ?>" id="return_notes" name="return_notes" rows="4" placeholder="Misalnya charger lengkap, tas hilang, atau ada kerusakan ringan."><?= e($returnValues['return_notes']) ?></textarea>
|
|
<?php if (isset($returnErrors['return_notes'])): ?><div class="invalid-feedback"><?= e($returnErrors['return_notes']) ?></div><?php endif; ?>
|
|
</div>
|
|
|
|
<div class="col-12 d-flex justify-content-between align-items-center gap-3 pt-1">
|
|
<p class="form-helper mb-0">Status board akan berubah otomatis setelah pengembalian disimpan.</p>
|
|
<button type="submit" class="btn btn-primary btn-app">Catat pengembalian</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="section-card">
|
|
<div class="section-header">
|
|
<div>
|
|
<h2>Pengembalian tercatat</h2>
|
|
<p>Transaksi ini sudah ditutup dan tersimpan di riwayat.</p>
|
|
</div>
|
|
<span class="section-chip">Closed</span>
|
|
</div>
|
|
<dl class="detail-grid mb-0">
|
|
<div>
|
|
<dt>Waktu kembali</dt>
|
|
<dd><?= e($loan['returned_at_label']) ?></dd>
|
|
</div>
|
|
<div>
|
|
<dt>Kondisi barang</dt>
|
|
<dd><?= e($loan['return_condition_label']) ?></dd>
|
|
</div>
|
|
<div>
|
|
<dt>Ketepatan</dt>
|
|
<dd><?= e($loan['due_note']) ?></dd>
|
|
</div>
|
|
<div>
|
|
<dt>Catatan akhir</dt>
|
|
<dd><?= e($loan['return_notes'] ?: 'Tidak ada catatan tambahan') ?></dd>
|
|
</div>
|
|
</dl>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="section-card">
|
|
<div class="section-header">
|
|
<div>
|
|
<h2>Riwayat aktivitas</h2>
|
|
<p>Titik audit sederhana untuk staff dan admin.</p>
|
|
</div>
|
|
</div>
|
|
<ul class="timeline-list mb-0">
|
|
<li>
|
|
<strong>Transaksi dibuat</strong>
|
|
<span><?= e(format_date_id($loan['created_at'], true)) ?></span>
|
|
</li>
|
|
<li>
|
|
<strong>Reminder terakhir</strong>
|
|
<span><?= e($loan['last_reminder_at_label'] ?: 'Belum dicatat') ?></span>
|
|
</li>
|
|
<li>
|
|
<strong>Status saat ini</strong>
|
|
<span><?= e($loan['status_label'] . ' · ' . $loan['due_note']) ?></span>
|
|
</li>
|
|
<?php if ($loan['is_returned']): ?>
|
|
<li>
|
|
<strong>Pengembalian selesai</strong>
|
|
<span><?= e($loan['returned_at_label']) ?></span>
|
|
</li>
|
|
<?php endif; ?>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</main>
|
|
|
|
<footer class="app-footer">
|
|
<div class="container app-container d-flex flex-column flex-sm-row justify-content-between gap-2">
|
|
<span><?= e($loan['reference']) ?> · <?= e($loan['item_name']) ?></span>
|
|
<span><a href="healthz.php">/healthz</a> tersedia untuk monitoring.</span>
|
|
</div>
|
|
</footer>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" defer></script>
|
|
<script src="assets/js/main.js?v=<?= e($jsVersion) ?>" defer></script>
|
|
</body>
|
|
</html>
|