Day 17 โ Logika Pengembalian Aset & Update Stok Otomatis โ
Fase: 2 โ Mini Project Asset Management | Minggu: 4 | Hari: Selasa
๐ฏ Tujuan Hari Ini โ
Peserta mengimplementasikan fitur pengembalian aset: saat tombol "Kembalikan" diklik, status pinjaman berubah menjadi dikembalikan dan stok aset bertambah kembali secara otomatis.
๐ Task Wajib โ
1. Rancang Alur Pengembalian โ
Sebelum coding, pahami alurnya:
User klik tombol "Kembalikan" di halaman detail/list pinjaman
โ
Kirim request POST ke route /loans/{id}/return
โ
Controller: cek apakah status masih 'dipinjam'
โ ya
Jalankan DB::transaction():
โโโ Update loans: status = 'dikembalikan', actual_return_date = hari ini
โโโ Increment asset stock sebesar quantity yang dikembalikan
โ
Redirect ke halaman list dengan pesan sukses2. Tambahkan Route Pengembalian (Custom Route) โ
Di routes/web.php, tambahkan di luar Route::resource:
php
// Custom route untuk aksi pengembalian
Route::post('loans/{loan}/return', [LoanController::class, 'returnAsset'])
->name('loans.return');3. Buat Method returnAsset() di LoanController โ
php
public function returnAsset(Loan $loan)
{
// Validasi: pastikan status masih 'dipinjam'
if ($loan->status !== 'dipinjam') {
return redirect()->route('loans.index')
->with('error', "Aset ini sudah dikembalikan sebelumnya!");
}
DB::transaction(function () use ($loan) {
// 1. Update record pinjaman
$loan->update([
'status' => 'dikembalikan',
'actual_return_date' => now()->toDateString(),
]);
// 2. Tambah kembali stok aset
$loan->asset->increment('stock', $loan->quantity);
});
return redirect()->route('loans.index')
->with('success', "Aset '{$loan->asset->name}' ({$loan->quantity} unit) berhasil dikembalikan. Stok diperbarui!");
}
public function show(Loan $loan)
{
$loan->load('asset.category');
return view('loans.show', compact('loan'));
}4. Buat Halaman Detail Pinjaman (loans/show.blade.php) โ
html
@extends('layouts.app')
@section('title', 'Detail Peminjaman')
@section('page-title', 'Detail Peminjaman')
@section('content')
<div style="margin-bottom:20px;">
<a href="{{ route('loans.index') }}" style="color:#666; text-decoration:none;">โ Kembali ke Daftar Pinjaman</a>
</div>
@include('partials.alert')
<div style="display:grid; grid-template-columns:2fr 1fr; gap:24px;">
<!-- Info Peminjaman -->
<div style="background:white; padding:30px; border-radius:10px; box-shadow:0 2px 8px rgba(0,0,0,0.07);">
<h2 style="margin-bottom:20px; color:#1a1a2e;">๐ Informasi Peminjaman</h2>
<table style="width:100%; border-collapse:collapse;">
<tr style="border-bottom:1px solid #f0f0f0;">
<td style="padding:12px 0; color:#666; width:40%;">Peminjam</td>
<td style="padding:12px 0; font-weight:bold;">{{ $loan->borrower_name }}</td>
</tr>
<tr style="border-bottom:1px solid #f0f0f0;">
<td style="padding:12px 0; color:#666;">Divisi</td>
<td style="padding:12px 0;">{{ $loan->borrower_department ?? '-' }}</td>
</tr>
<tr style="border-bottom:1px solid #f0f0f0;">
<td style="padding:12px 0; color:#666;">Aset</td>
<td style="padding:12px 0;">
<strong>{{ $loan->asset->name }}</strong>
<span style="font-family:monospace; color:#4f46e5;"> ({{ $loan->asset->code }})</span>
</td>
</tr>
<tr style="border-bottom:1px solid #f0f0f0;">
<td style="padding:12px 0; color:#666;">Kategori</td>
<td style="padding:12px 0;">{{ $loan->asset->category->name }}</td>
</tr>
<tr style="border-bottom:1px solid #f0f0f0;">
<td style="padding:12px 0; color:#666;">Jumlah Dipinjam</td>
<td style="padding:12px 0; font-weight:bold; font-size:18px; color:#1a1a2e;">{{ $loan->quantity }} unit</td>
</tr>
<tr style="border-bottom:1px solid #f0f0f0;">
<td style="padding:12px 0; color:#666;">Tanggal Pinjam</td>
<td style="padding:12px 0;">{{ $loan->borrow_date->format('d F Y') }}</td>
</tr>
<tr style="border-bottom:1px solid #f0f0f0;">
<td style="padding:12px 0; color:#666;">Rencana Kembali</td>
<td style="padding:12px 0;">
{{ $loan->expected_return_date->format('d F Y') }}
@if($loan->isTerlambat())
<span style="color:#dc3545; font-size:13px; margin-left:8px;">โ ๏ธ Terlambat!</span>
@endif
</td>
</tr>
@if($loan->actual_return_date)
<tr style="border-bottom:1px solid #f0f0f0;">
<td style="padding:12px 0; color:#666;">Tgl Aktual Kembali</td>
<td style="padding:12px 0; color:#28a745; font-weight:bold;">
โ
{{ $loan->actual_return_date->format('d F Y') }}
</td>
</tr>
@endif
<tr>
<td style="padding:12px 0; color:#666;">Catatan</td>
<td style="padding:12px 0; font-style:italic; color:#666;">{{ $loan->notes ?? '-' }}</td>
</tr>
</table>
</div>
<!-- Status & Aksi -->
<div>
<!-- Status Card -->
<div style="background:white; padding:24px; border-radius:10px; margin-bottom:16px; box-shadow:0 2px 8px rgba(0,0,0,0.07); text-align:center;">
<p style="color:#999; font-size:13px; margin-bottom:12px;">STATUS PEMINJAMAN</p>
@if($loan->status === 'dipinjam')
<div style="background:#fff3cd; color:#856404; padding:16px; border-radius:8px; font-size:18px; font-weight:bold;">
๐ Sedang Dipinjam
</div>
@else
<div style="background:#d4edda; color:#155724; padding:16px; border-radius:8px; font-size:18px; font-weight:bold;">
โ
Sudah Dikembalikan
</div>
@endif
</div>
<!-- Tombol Kembalikan -->
@if($loan->status === 'dipinjam')
<div style="background:white; padding:24px; border-radius:10px; box-shadow:0 2px 8px rgba(0,0,0,0.07);">
<h3 style="margin-bottom:12px; color:#1a1a2e;">Kembalikan Aset</h3>
<p style="color:#666; font-size:13px; margin-bottom:16px;">
Klik tombol di bawah untuk mengkonfirmasi pengembalian.
Stok aset akan bertambah <strong>{{ $loan->quantity }} unit</strong> secara otomatis.
</p>
<form action="{{ route('loans.return', $loan->id) }}" method="POST"
onsubmit="return confirm('Konfirmasi pengembalian {{ $loan->quantity }} unit dari {{ $loan->borrower_name }}?')">
@csrf
<button type="submit"
style="width:100%; background:#28a745; color:white; padding:14px; border:none; border-radius:8px; cursor:pointer; font-size:15px; font-weight:bold;">
โ
Konfirmasi Pengembalian
</button>
</form>
</div>
@endif
<!-- Info Stok Aset Saat Ini -->
<div style="background:#eef2ff; padding:20px; border-radius:10px; margin-top:16px;">
<p style="color:#4f46e5; font-size:13px; margin-bottom:6px; font-weight:bold;">STOK ASET SAAT INI</p>
<p style="font-size:28px; font-weight:bold; color:#1a1a2e;">{{ $loan->asset->stock }} unit</p>
<p style="color:#666; font-size:12px;">{{ $loan->asset->name }}</p>
</div>
</div>
</div>
@endsection5. Tambahkan Tombol Detail di Halaman List โ
Update loans/index.blade.php โ pastikan link "Detail" sudah mengarah ke loans.show:
html
<a href="{{ route('loans.show', $loan->id) }}" style="color:#0066cc; font-size:13px;">Detail</a>6. Uji Skenario Pengembalian โ
| # | Skenario | Expected |
|---|---|---|
| 1 | Buka detail pinjaman yang masih 'dipinjam' | Tampil tombol "Konfirmasi Pengembalian" |
| 2 | Klik konfirmasi kembalikan | Redirect ke list, pesan sukses muncul |
| 3 | Cek halaman /assets | Stok aset bertambah sesuai quantity |
| 4 | Buka kembali detail pinjaman yang sudah dikembalikan | Status berubah jadi "Sudah Dikembalikan", tombol hilang |
| 5 | Akses URL return langsung (sudah dikembalikan) | Muncul pesan error "sudah dikembalikan" |
๐ Laporan ke Mentor โ
๐ LAPORAN HARIAN โ Day 17
Nama : [Nama Lengkap]
Role : [Role Kamu]
โ
Yang saya kerjakan hari ini:
- [ ] Route POST loans/{loan}/return terdaftar
- [ ] Method returnAsset() di controller selesai
- [ ] Halaman loans/show.blade.php selesai
- [ ] Tombol "Konfirmasi Pengembalian" berfungsi
- [ ] Stok aset otomatis bertambah setelah pengembalian
- [ ] Semua skenario pengujian berhasil
๐ธ Screenshot Wajib:
1. Halaman detail pinjaman dengan status "Dipinjam" + tombol kembalikan
2. Halaman detail setelah dikembalikan (status berubah, tombol hilang)
3. Halaman /assets menunjukkan stok bertambah setelah pengembalian
๐งช QA Test:
| Skenario | PASS/FAIL |
|----------|-----------|
| Kembalikan aset โ stok bertambah | |
| Klik kembalikan 2x (sudah dikembalikan) | |
| Detail pinjaman tampil info lengkap | |
โ Kendala:
[Tulis jika ada]Catatan Mentor
Perkenalkan konsep idempotency secara sederhana: "Kenapa kita perlu cek if ($loan->status !== 'dipinjam') sebelum proses kembalikan?" Karena jika endpoint dipanggil dua kali (misal tombol diklik 2x), kita tidak mau stok bertambah 2 kali!