From 5f8189abe9225e4223c9eb5ef9bc5c63ec49bbcd Mon Sep 17 00:00:00 2001 From: Arya Dwi Putra Date: Mon, 1 Dec 2025 12:50:47 +0700 Subject: [PATCH] Add asset maintenance tracking with CRUD page and menu --- .../AssetMaintenanceController.php | 61 ++++++++ app/Models/Asset.php | 5 + app/Models/AssetMaintenance.php | 32 ++++ ...000000_create_asset_maintenances_table.php | 28 ++++ resources/views/assets/maintenances.blade.php | 143 ++++++++++++++++++ .../partials/maintenance_form.blade.php | 45 ++++++ .../layouts/components/main-sidebar.blade.php | 6 + routes/web.php | 2 + 8 files changed, 322 insertions(+) create mode 100644 app/Http/Controllers/AssetMaintenanceController.php create mode 100644 app/Models/AssetMaintenance.php create mode 100644 database/migrations/2025_12_07_000000_create_asset_maintenances_table.php create mode 100644 resources/views/assets/maintenances.blade.php create mode 100644 resources/views/assets/partials/maintenance_form.blade.php diff --git a/app/Http/Controllers/AssetMaintenanceController.php b/app/Http/Controllers/AssetMaintenanceController.php new file mode 100644 index 0000000..14db406 --- /dev/null +++ b/app/Http/Controllers/AssetMaintenanceController.php @@ -0,0 +1,61 @@ +latest()->paginate(20); + $assets = Asset::orderBy('code')->get(); + + return view('assets.maintenances', compact('maintenances', 'assets')); + } + + public function store(Request $request): RedirectResponse + { + $data = $request->validate([ + 'asset_id' => ['required', 'uuid', 'exists:assets,id'], + 'performed_at' => ['nullable', 'date'], + 'description' => ['required', 'string', 'max:255'], + 'vendor' => ['nullable', 'string', 'max:255'], + 'cost' => ['nullable', 'numeric', 'min:0'], + 'status' => ['required', 'string'], + 'notes' => ['nullable', 'string'], + ]); + + AssetMaintenance::create($data); + + return back()->with('success', 'Data perawatan berhasil dicatat.'); + } + + public function update(Request $request, AssetMaintenance $asset_maintenance): RedirectResponse + { + $data = $request->validate([ + 'asset_id' => ['required', 'uuid', 'exists:assets,id'], + 'performed_at' => ['nullable', 'date'], + 'description' => ['required', 'string', 'max:255'], + 'vendor' => ['nullable', 'string', 'max:255'], + 'cost' => ['nullable', 'numeric', 'min:0'], + 'status' => ['required', 'string'], + 'notes' => ['nullable', 'string'], + ]); + + $asset_maintenance->update($data); + + return back()->with('success', 'Data perawatan berhasil diperbarui.'); + } + + public function destroy(AssetMaintenance $asset_maintenance): RedirectResponse + { + $asset_maintenance->delete(); + + return back()->with('success', 'Data perawatan dihapus.'); + } +} diff --git a/app/Models/Asset.php b/app/Models/Asset.php index 348203b..097fc5e 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -102,4 +102,9 @@ class Asset extends Model { return $this->hasMany(AssetAudit::class); } + + public function maintenances() + { + return $this->hasMany(AssetMaintenance::class); + } } diff --git a/app/Models/AssetMaintenance.php b/app/Models/AssetMaintenance.php new file mode 100644 index 0000000..41a901d --- /dev/null +++ b/app/Models/AssetMaintenance.php @@ -0,0 +1,32 @@ + 'datetime', + 'cost' => 'decimal:2', + ]; + + public function asset() + { + return $this->belongsTo(Asset::class); + } +} diff --git a/database/migrations/2025_12_07_000000_create_asset_maintenances_table.php b/database/migrations/2025_12_07_000000_create_asset_maintenances_table.php new file mode 100644 index 0000000..2017cea --- /dev/null +++ b/database/migrations/2025_12_07_000000_create_asset_maintenances_table.php @@ -0,0 +1,28 @@ +uuid('id')->primary(); + $table->foreignUuid('asset_id')->constrained('assets')->cascadeOnDelete(); + $table->timestamp('performed_at')->nullable(); + $table->string('description'); + $table->string('vendor')->nullable(); + $table->decimal('cost', 15, 2)->nullable(); + $table->string('status')->default('completed'); // planned, in_progress, completed + $table->text('notes')->nullable(); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('asset_maintenances'); + } +}; diff --git a/resources/views/assets/maintenances.blade.php b/resources/views/assets/maintenances.blade.php new file mode 100644 index 0000000..9c4242e --- /dev/null +++ b/resources/views/assets/maintenances.blade.php @@ -0,0 +1,143 @@ +@extends('layouts.master') + +@section('content') +
+
+

Perawatan Aset

+

Catat dan pantau riwayat perawatan/maintenance aset.

+
+ +
+ +
+
+
Data Perawatan
+
+
+ @if(session('success')) + + @endif + + @if($errors->any()) +
+
    + @foreach($errors->all() as $error) +
  • {{ $error }}
  • + @endforeach +
+
+ @endif + +
+ + + + + + + + + + + + + + + @forelse($maintenances as $item) + + + + + + + + + + + @empty + + @endforelse + +
AsetTanggalDeskripsiVendorBiayaStatusCatatanAksi
{{ $item->asset?->code }} - {{ $item->asset?->name }}{{ optional($item->performed_at)->format('d/m/Y') ?: '-' }}{{ $item->description }}{{ $item->vendor ?: '-' }}{{ $item->cost ? number_format($item->cost, 2, ',', '.') : '-' }}{{ $item->status }}{{ $item->notes ?: '-' }} + +
+ @csrf + @method('DELETE') + +
+
Belum ada data perawatan.
+
+
{{ $maintenances->links() }}
+
+
+ + {{-- Modal create --}} + + + {{-- Modal edit --}} + +@endsection + +@section('scripts') + +@endsection diff --git a/resources/views/assets/partials/maintenance_form.blade.php b/resources/views/assets/partials/maintenance_form.blade.php new file mode 100644 index 0000000..d276cab --- /dev/null +++ b/resources/views/assets/partials/maintenance_form.blade.php @@ -0,0 +1,45 @@ + + diff --git a/resources/views/layouts/components/main-sidebar.blade.php b/resources/views/layouts/components/main-sidebar.blade.php index d0862d4..ea6b2a9 100644 --- a/resources/views/layouts/components/main-sidebar.blade.php +++ b/resources/views/layouts/components/main-sidebar.blade.php @@ -188,6 +188,12 @@ Laporan Audit +
  • + + + Perawatan Aset + +
  • Web Apps
  • diff --git a/routes/web.php b/routes/web.php index 55da7e0..47e11e6 100644 --- a/routes/web.php +++ b/routes/web.php @@ -21,6 +21,7 @@ use App\Http\Controllers\AssetTransactionController; use App\Http\Controllers\AssetAuditController; use App\Http\Controllers\AssetTransactionPageController; use App\Http\Controllers\ReportController; +use App\Http\Controllers\AssetMaintenanceController; use App\Http\Controllers\Controller; Route::get('/', function () { @@ -63,3 +64,4 @@ Route::get('reports/assets', [ReportController::class, 'assets'])->name('reports Route::get('reports/movements', [ReportController::class, 'movements'])->name('reports.movements'); Route::get('reports/disposals', [ReportController::class, 'disposals'])->name('reports.disposals'); Route::get('reports/audits', [ReportController::class, 'audits'])->name('reports.audits'); +Route::resource('asset-maintenances', AssetMaintenanceController::class)->only(['index','store','update','destroy']);