Skip to content

Day 13 โ€” CRUD Master Data: Asset โ€‹

Fase: 2 โ€” Mini Project Asset Management | Minggu: 3 | Hari: Rabu


๐ŸŽฏ Tujuan Hari Ini โ€‹

Tim menyelesaikan modul CRUD Asset secara lengkap, termasuk dropdown kategori di form dan penampilan kode aset unik.


๐Ÿ“‹ Task Wajib โ€‹

1. Buat Model Asset โ€‹

bash
php artisan make:model Asset

Isi app/Models/Asset.php:

php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Asset extends Model
{
    protected $fillable = [
        'category_id', 'name', 'code', 'description', 'stock', 'condition'
    ];

    // Relasi: 1 aset milik 1 kategori
    public function category()
    {
        return $this->belongsTo(Category::class);
    }

    // Relasi: 1 aset punya banyak loan (akan dipakai di week 4)
    public function loans()
    {
        return $this->hasMany(Loan::class);
    }
}

2. Buat Controller โ€‹

bash
php artisan make:controller AssetController --resource

Isi AssetController.php:

php
<?php

namespace App\Http\Controllers;

use App\Models\Asset;
use App\Models\Category;
use Illuminate\Http\Request;

class AssetController extends Controller
{
    public function index()
    {
        $assets = Asset::with('category')->orderBy('name')->paginate(10);
        return view('assets.index', compact('assets'));
    }

    public function create()
    {
        $categories = Category::orderBy('name')->get();
        return view('assets.create', compact('categories'));
    }

    public function store(Request $request)
    {
        $request->validate([
            'category_id' => 'required|exists:categories,id',
            'name'        => 'required|min:2|max:150',
            'code'        => 'required|max:50|unique:assets,code',
            'description' => 'nullable|max:500',
            'stock'       => 'required|integer|min:0',
            'condition'   => 'required|in:baik,rusak,perbaikan',
        ]);

        Asset::create($request->only([
            'category_id', 'name', 'code', 'description', 'stock', 'condition'
        ]));

        return redirect()->route('assets.index')
            ->with('success', "Aset '{$request->name}' berhasil ditambahkan!");
    }

    public function show(Asset $asset)
    {
        $asset->load('category', 'loans');
        return view('assets.show', compact('asset'));
    }

    public function edit(Asset $asset)
    {
        $categories = Category::orderBy('name')->get();
        return view('assets.edit', compact('asset', 'categories'));
    }

    public function update(Request $request, Asset $asset)
    {
        $request->validate([
            'category_id' => 'required|exists:categories,id',
            'name'        => 'required|min:2|max:150',
            'code'        => "required|max:50|unique:assets,code,{$asset->id}",
            'description' => 'nullable|max:500',
            'stock'       => 'required|integer|min:0',
            'condition'   => 'required|in:baik,rusak,perbaikan',
        ]);

        $asset->update($request->only([
            'category_id', 'name', 'code', 'description', 'stock', 'condition'
        ]));

        return redirect()->route('assets.index')
            ->with('success', "Aset '{$asset->name}' berhasil diperbarui!");
    }

    public function destroy(Asset $asset)
    {
        $nama = $asset->name;
        $asset->delete();

        return redirect()->route('assets.index')
            ->with('success', "Aset '{$nama}' berhasil dihapus!");
    }
}

3. Daftarkan Route Asset โ€‹

Di routes/web.php:

php
use App\Http\Controllers\AssetController;

Route::resource('assets', AssetController::class);

4. Buat Views Asset โ€‹

resources/views/assets/index.blade.php:

html
@extends('layouts.app')
@section('title', 'Daftar Aset')

@section('content')
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:20px;">
    <div>
        <h1>๐Ÿ—‚๏ธ Daftar Aset</h1>
        <p style="color:#666;">Total: {{ $assets->total() }} aset</p>
    </div>
    <a href="{{ route('assets.create') }}" class="btn-primary">+ Tambah Aset</a>
</div>

@include('partials.alert')

<div style="background:white; border-radius:10px; overflow:hidden; box-shadow:0 2px 8px rgba(0,0,0,0.07);">
    <table style="width:100%; border-collapse:collapse;">
        <thead>
            <tr style="background:#1a1a2e; color:white;">
                <th style="padding:14px 16px; text-align:left;">Kode</th>
                <th style="padding:14px 16px; text-align:left;">Nama Aset</th>
                <th style="padding:14px 16px; text-align:left;">Kategori</th>
                <th style="padding:14px 16px; text-align:center;">Stock</th>
                <th style="padding:14px 16px; text-align:center;">Kondisi</th>
                <th style="padding:14px 16px; text-align:center;">Aksi</th>
            </tr>
        </thead>
        <tbody>
            @forelse($assets as $asset)
            <tr style="border-bottom:1px solid #f0f0f0;">
                <td style="padding:14px 16px; font-family:monospace; font-weight:bold; color:#4f46e5;">
                    {{ $asset->code }}
                </td>
                <td style="padding:14px 16px;">{{ $asset->name }}</td>
                <td style="padding:14px 16px; color:#666;">{{ $asset->category->name }}</td>
                <td style="padding:14px 16px; text-align:center;">
                    <span style="font-weight:bold; color:{{ $asset->stock > 0 ? '#155724' : '#721c24' }};">
                        {{ $asset->stock }}
                    </span>
                </td>
                <td style="padding:14px 16px; text-align:center;">
                    @php
                        $condColor = ['baik' => '#d4edda', 'rusak' => '#f8d7da', 'perbaikan' => '#fff3cd'];
                        $condText = ['baik' => '#155724', 'rusak' => '#721c24', 'perbaikan' => '#856404'];
                    @endphp
                    <span style="background:{{ $condColor[$asset->condition] }}; color:{{ $condText[$asset->condition] }};
                                 padding:4px 10px; border-radius:20px; font-size:12px;">
                        {{ ucfirst($asset->condition) }}
                    </span>
                </td>
                <td style="padding:14px 16px; text-align:center;">
                    <a href="{{ route('assets.show', $asset->id) }}" style="color:#6c757d; margin:0 4px;">Detail</a>
                    <a href="{{ route('assets.edit', $asset->id) }}" style="color:#0066cc; margin:0 4px;">Edit</a>
                    <form action="{{ route('assets.destroy', $asset->id) }}" method="POST" style="display:inline;"
                          onsubmit="return confirm('Hapus aset {{ $asset->name }}?')">
                        @csrf @method('DELETE')
                        <button type="submit" style="border:none; background:none; color:#dc3545; cursor:pointer;">Hapus</button>
                    </form>
                </td>
            </tr>
            @empty
            <tr>
                <td colspan="6" style="text-align:center; padding:40px; color:#999;">
                    Belum ada aset. <a href="{{ route('assets.create') }}">Tambahkan sekarang.</a>
                </td>
            </tr>
            @endforelse
        </tbody>
    </table>
</div>

<div style="margin-top:20px;">
    {{ $assets->links() }}
</div>
@endsection

resources/views/assets/create.blade.php โ€” pastikan dropdown kategori mengambil dari variabel $categories:

html
<select name="category_id" ...>
    <option value="">-- Pilih Kategori --</option>
    @foreach($categories as $cat)
        <option value="{{ $cat->id }}" {{ old('category_id') == $cat->id ? 'selected' : '' }}>
            {{ $cat->name }}
        </option>
    @endforeach
</select>

5. Tambahkan Data Aset Dummy via Seeder โ€‹

bash
php artisan make:seeder AssetSeeder
php
use App\Models\Asset;
use App\Models\Category;

public function run(): void
{
    $elektronik = Category::where('name', 'Elektronik')->first();
    $furniture  = Category::where('name', 'Furniture')->first();

    Asset::insert([
        ['category_id' => $elektronik->id, 'name' => 'Laptop Dell Inspiron', 'code' => 'EL-001', 'stock' => 5, 'condition' => 'baik', 'created_at' => now(), 'updated_at' => now()],
        ['category_id' => $elektronik->id, 'name' => 'Proyektor Epson', 'code' => 'EL-002', 'stock' => 2, 'condition' => 'baik', 'created_at' => now(), 'updated_at' => now()],
        ['category_id' => $furniture->id,  'name' => 'Meja Rapat', 'code' => 'FU-001', 'stock' => 8, 'condition' => 'baik', 'created_at' => now(), 'updated_at' => now()],
    ]);
}
bash
php artisan db:seed --class=AssetSeeder

๐Ÿ“ Laporan ke Mentor โ€‹

๐Ÿ“Œ LAPORAN HARIAN โ€” Day 13
Nama     : [Nama Lengkap]
Role     : [Role Kamu]

โœ… Yang saya kerjakan hari ini:
- [ ] Model Asset dengan relasi belongsTo Category selesai
- [ ] AssetController lengkap dengan validasi
- [ ] Halaman index dengan pagination berjalan
- [ ] Form create dengan dropdown kategori dari DB
- [ ] Seeder untuk data dummy aset berhasil dijalankan

๐Ÿ“ธ Screenshot Wajib:
1. Halaman /assets dengan tabel data aset + kondisi berwarna
2. Form tambah aset dengan dropdown kategori yang terisi
3. Pagination (jika ada > 10 data)

๐Ÿงช QA Test Result:
| Test Case | Pass/Fail |
|-----------|-----------|
| Tambah aset tanpa kategori | |
| Tambah aset dengan kode duplikat | |
| Edit aset: ganti kategori | |
| Hapus aset | |

โ“ Kendala:
[Tulis jika ada]

Catatan Mentor

Ingatkan peserta tentang validasi exists:categories,id di field category_id. Ini memastikan user tidak bisa manipulasi ID kategori dengan cara inject ID yang tidak ada di database (keamanan dasar).

Program Magang SMK RPL โ€” Rekayasa Perangkat Lunak