Add report pages with filtering and export to Excel/PDF
This commit is contained in:
24
app/Exports/ArrayReportExport.php
Normal file
24
app/Exports/ArrayReportExport.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exports;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Maatwebsite\Excel\Concerns\FromCollection;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
|
||||
class ArrayReportExport implements FromCollection, WithHeadings
|
||||
{
|
||||
public function __construct(private readonly array $headings, private readonly array $rows)
|
||||
{
|
||||
}
|
||||
|
||||
public function headings(): array
|
||||
{
|
||||
return $this->headings;
|
||||
}
|
||||
|
||||
public function collection(): Collection
|
||||
{
|
||||
return collect($this->rows);
|
||||
}
|
||||
}
|
||||
206
app/Http/Controllers/ReportController.php
Normal file
206
app/Http/Controllers/ReportController.php
Normal file
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Exports\ArrayReportExport;
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetAudit;
|
||||
use App\Models\AssetCategory;
|
||||
use App\Models\AssetClass;
|
||||
use App\Models\AssetDisposal;
|
||||
use App\Models\AssetLocation;
|
||||
use App\Models\AssetMovement;
|
||||
use App\Models\AssetStatus;
|
||||
use App\Models\AssetUser;
|
||||
use App\Models\Department;
|
||||
use App\Models\PersonInCharge;
|
||||
use App\Models\Warranty;
|
||||
use Illuminate\Http\Request;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Barryvdh\DomPDF\Facade\Pdf;
|
||||
|
||||
class ReportController extends Controller
|
||||
{
|
||||
public function assets(Request $request)
|
||||
{
|
||||
$filters = $request->only([
|
||||
'date_from','date_to','asset_status_id','asset_class_id','asset_category_id',
|
||||
'asset_location_id','department_id','asset_user_id','person_in_charge_id','warranty_id'
|
||||
]);
|
||||
|
||||
$query = Asset::with(['status','class','category','location','department','user','personInCharge','warranty'])
|
||||
->when($filters['date_from'] ?? null, fn($q,$v)=>$q->whereDate('created_at','>=',$v))
|
||||
->when($filters['date_to'] ?? null, fn($q,$v)=>$q->whereDate('created_at','<=',$v))
|
||||
->when($filters['asset_status_id'] ?? null, fn($q,$v)=>$q->where('asset_status_id',$v))
|
||||
->when($filters['asset_class_id'] ?? null, fn($q,$v)=>$q->where('asset_class_id',$v))
|
||||
->when($filters['asset_category_id'] ?? null, fn($q,$v)=>$q->where('asset_category_id',$v))
|
||||
->when($filters['asset_location_id'] ?? null, fn($q,$v)=>$q->where('asset_location_id',$v))
|
||||
->when($filters['department_id'] ?? null, fn($q,$v)=>$q->where('department_id',$v))
|
||||
->when($filters['asset_user_id'] ?? null, fn($q,$v)=>$q->where('asset_user_id',$v))
|
||||
->when($filters['person_in_charge_id'] ?? null, fn($q,$v)=>$q->where('person_in_charge_id',$v))
|
||||
->when($filters['warranty_id'] ?? null, fn($q,$v)=>$q->where('warranty_id',$v));
|
||||
|
||||
$assets = $query->paginate(20)->withQueryString();
|
||||
|
||||
if ($request->get('export') === 'excel') {
|
||||
$rows = $query->get()->map(fn($a)=>[
|
||||
$a->code,
|
||||
$a->name,
|
||||
$a->status?->name,
|
||||
$a->category?->name,
|
||||
$a->location?->name,
|
||||
$a->department?->name,
|
||||
$a->user?->name,
|
||||
$a->personInCharge?->name,
|
||||
$a->warranty?->name,
|
||||
$a->created_at?->format('d/m/Y'),
|
||||
])->toArray();
|
||||
return Excel::download(new ArrayReportExport([
|
||||
'Kode','Nama','Status','Kategori','Lokasi','Departemen','Pengguna','PIC','Garansi','Dibuat'
|
||||
], $rows), 'asset-report.xlsx');
|
||||
}
|
||||
|
||||
if ($request->get('export') === 'pdf') {
|
||||
$data = $query->get();
|
||||
$pdf = Pdf::loadView('reports.exports.assets', compact('data'));
|
||||
return $pdf->download('asset-report.pdf');
|
||||
}
|
||||
|
||||
return view('reports.assets', [
|
||||
'assets' => $assets,
|
||||
'filters' => $filters,
|
||||
'statuses' => AssetStatus::orderBy('name')->get(),
|
||||
'classes' => AssetClass::orderBy('name')->get(),
|
||||
'categories' => AssetCategory::orderBy('name')->get(),
|
||||
'locations' => AssetLocation::orderBy('name')->get(),
|
||||
'departments' => Department::orderBy('name')->get(),
|
||||
'users' => AssetUser::orderBy('name')->get(),
|
||||
'pics' => PersonInCharge::orderBy('name')->get(),
|
||||
'warranties' => Warranty::orderBy('name')->get(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function movements(Request $request)
|
||||
{
|
||||
$filters = $request->only(['date_from','date_to','asset_id','asset_location_id','department_id','asset_user_id']);
|
||||
$query = AssetMovement::with(['asset','toLocation','toDepartment','toUser','fromLocation','fromDepartment','fromUser'])
|
||||
->when($filters['date_from'] ?? null, fn($q,$v)=>$q->whereDate('performed_at','>=',$v))
|
||||
->when($filters['date_to'] ?? null, fn($q,$v)=>$q->whereDate('performed_at','<=',$v))
|
||||
->when($filters['asset_id'] ?? null, fn($q,$v)=>$q->where('asset_id',$v))
|
||||
->when($filters['asset_location_id'] ?? null, fn($q,$v)=>$q->where('to_location_id',$v))
|
||||
->when($filters['department_id'] ?? null, fn($q,$v)=>$q->where('to_department_id',$v))
|
||||
->when($filters['asset_user_id'] ?? null, fn($q,$v)=>$q->where('to_asset_user_id',$v));
|
||||
|
||||
$items = $query->paginate(20)->withQueryString();
|
||||
|
||||
if ($request->get('export') === 'excel') {
|
||||
$rows = $query->get()->map(fn($m)=>[
|
||||
$m->performed_at?->format('d/m/Y H:i'),
|
||||
$m->asset?->code,
|
||||
$m->fromLocation?->name,
|
||||
$m->toLocation?->name,
|
||||
$m->fromDepartment?->name,
|
||||
$m->toDepartment?->name,
|
||||
$m->fromUser?->name,
|
||||
$m->toUser?->name,
|
||||
$m->notes,
|
||||
])->toArray();
|
||||
return Excel::download(new ArrayReportExport([
|
||||
'Waktu','Aset','Dari Lokasi','Ke Lokasi','Dari Dept','Ke Dept','Dari User','Ke User','Catatan'
|
||||
], $rows), 'asset-movement-report.xlsx');
|
||||
}
|
||||
|
||||
if ($request->get('export') === 'pdf') {
|
||||
$data = $query->get();
|
||||
$pdf = Pdf::loadView('reports.exports.movements', compact('data'));
|
||||
return $pdf->download('asset-movement-report.pdf');
|
||||
}
|
||||
|
||||
return view('reports.movements', [
|
||||
'items' => $items,
|
||||
'filters' => $filters,
|
||||
'assets' => Asset::orderBy('code')->get(),
|
||||
'locations' => AssetLocation::orderBy('name')->get(),
|
||||
'departments' => Department::orderBy('name')->get(),
|
||||
'users' => AssetUser::orderBy('name')->get(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function disposals(Request $request)
|
||||
{
|
||||
$filters = $request->only(['date_from','date_to','asset_id','status']);
|
||||
$query = AssetDisposal::with('asset')
|
||||
->when($filters['date_from'] ?? null, fn($q,$v)=>$q->whereDate('disposed_at','>=',$v))
|
||||
->when($filters['date_to'] ?? null, fn($q,$v)=>$q->whereDate('disposed_at','<=',$v))
|
||||
->when($filters['asset_id'] ?? null, fn($q,$v)=>$q->where('asset_id',$v))
|
||||
->when($filters['status'] ?? null, function ($q, $v) {
|
||||
$v === 'reversed' ? $q->whereNotNull('reversed_at') : $q->whereNull('reversed_at');
|
||||
});
|
||||
|
||||
$items = $query->paginate(20)->withQueryString();
|
||||
|
||||
if ($request->get('export') === 'excel') {
|
||||
$rows = $query->get()->map(fn($d)=>[
|
||||
$d->disposed_at?->format('d/m/Y H:i'),
|
||||
$d->asset?->code,
|
||||
$d->reason,
|
||||
$d->notes,
|
||||
$d->reversed_at ? 'Reversed' : 'Active',
|
||||
])->toArray();
|
||||
return Excel::download(new ArrayReportExport([
|
||||
'Waktu','Aset','Alasan','Catatan','Status'
|
||||
], $rows), 'asset-disposal-report.xlsx');
|
||||
}
|
||||
|
||||
if ($request->get('export') === 'pdf') {
|
||||
$data = $query->get();
|
||||
$pdf = Pdf::loadView('reports.exports.disposals', compact('data'));
|
||||
return $pdf->download('asset-disposal-report.pdf');
|
||||
}
|
||||
|
||||
return view('reports.disposals', [
|
||||
'items' => $items,
|
||||
'filters' => $filters,
|
||||
'assets' => Asset::orderBy('code')->get(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function audits(Request $request)
|
||||
{
|
||||
$filters = $request->only(['date_from','date_to','asset_id','status','location_id']);
|
||||
$query = AssetAudit::with(['asset','location'])
|
||||
->when($filters['date_from'] ?? null, fn($q,$v)=>$q->whereDate('audited_at','>=',$v))
|
||||
->when($filters['date_to'] ?? null, fn($q,$v)=>$q->whereDate('audited_at','<=',$v))
|
||||
->when($filters['asset_id'] ?? null, fn($q,$v)=>$q->where('asset_id',$v))
|
||||
->when($filters['status'] ?? null, fn($q,$v)=>$q->where('status',$v))
|
||||
->when($filters['location_id'] ?? null, fn($q,$v)=>$q->where('location_id',$v));
|
||||
|
||||
$items = $query->paginate(20)->withQueryString();
|
||||
|
||||
if ($request->get('export') === 'excel') {
|
||||
$rows = $query->get()->map(fn($a)=>[
|
||||
$a->audited_at?->format('d/m/Y H:i'),
|
||||
$a->asset?->code,
|
||||
$a->status,
|
||||
$a->location?->name,
|
||||
$a->notes,
|
||||
])->toArray();
|
||||
return Excel::download(new ArrayReportExport([
|
||||
'Waktu','Aset','Status','Lokasi','Catatan'
|
||||
], $rows), 'asset-audit-report.xlsx');
|
||||
}
|
||||
|
||||
if ($request->get('export') === 'pdf') {
|
||||
$data = $query->get();
|
||||
$pdf = Pdf::loadView('reports.exports.audits', compact('data'));
|
||||
return $pdf->download('asset-audit-report.pdf');
|
||||
}
|
||||
|
||||
return view('reports.audits', [
|
||||
'items' => $items,
|
||||
'filters' => $filters,
|
||||
'assets' => Asset::orderBy('code')->get(),
|
||||
'locations' => AssetLocation::orderBy('name')->get(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,10 @@
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"barryvdh/laravel-dompdf": "^3.1",
|
||||
"laravel/framework": "^12.0",
|
||||
"laravel/tinker": "^2.10.1",
|
||||
"maatwebsite/excel": "^3.1",
|
||||
"simplesoftwareio/simple-qrcode": "^4.2",
|
||||
"spatie/laravel-permission": "^6.23"
|
||||
},
|
||||
|
||||
956
composer.lock
generated
956
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -161,6 +161,34 @@
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!-- Start::slide__category -->
|
||||
<li class="slide__category"><span class="category-name">Laporan</span></li>
|
||||
<!-- End::slide__category -->
|
||||
<li class="slide">
|
||||
<a href="{{ route('reports.assets') }}" class="side-menu__item {{ request()->routeIs('reports.assets') ? 'active' : '' }}">
|
||||
<i class="ri-bar-chart-2-line side-menu__icon"></i>
|
||||
<span class="side-menu__label">Laporan Aset</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="slide">
|
||||
<a href="{{ route('reports.movements') }}" class="side-menu__item {{ request()->routeIs('reports.movements') ? 'active' : '' }}">
|
||||
<i class="ri-route-line side-menu__icon"></i>
|
||||
<span class="side-menu__label">Laporan Movement</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="slide">
|
||||
<a href="{{ route('reports.disposals') }}" class="side-menu__item {{ request()->routeIs('reports.disposals') ? 'active' : '' }}">
|
||||
<i class="ri-delete-bin-2-line side-menu__icon"></i>
|
||||
<span class="side-menu__label">Laporan Disposal</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="slide">
|
||||
<a href="{{ route('reports.audits') }}" class="side-menu__item {{ request()->routeIs('reports.audits') ? 'active' : '' }}">
|
||||
<i class="ri-clipboard-line side-menu__icon"></i>
|
||||
<span class="side-menu__label">Laporan Audit</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!-- Start::slide__category -->
|
||||
<li class="slide__category"><span class="category-name">Web Apps</span></li>
|
||||
<!-- End::slide__category -->
|
||||
|
||||
39
resources/views/reports/assets.blade.php
Normal file
39
resources/views/reports/assets.blade.php
Normal file
@@ -0,0 +1,39 @@
|
||||
@php
|
||||
$filtersView = view('reports.partials.asset_filters', compact('filters','statuses','classes','categories','locations','departments','users','pics','warranties'));
|
||||
@endphp
|
||||
|
||||
@extends('reports.layout', ['title' => 'Laporan Aset', 'subtitle' => 'Filter by status, lokasi, PIC, pengguna, garansi', 'filtersView' => $filtersView])
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered text-nowrap align-middle mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Kode</th><th>Nama</th><th>Status</th><th>Kategori</th><th>Lokasi</th><th>Dept</th><th>User</th><th>PIC</th><th>Garansi</th><th>Dibuat</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($assets as $asset)
|
||||
<tr>
|
||||
<td>{{ $asset->code }}</td>
|
||||
<td>{{ $asset->name }}</td>
|
||||
<td>{{ $asset->status?->name }}</td>
|
||||
<td>{{ $asset->category?->name }}</td>
|
||||
<td>{{ $asset->location?->name }}</td>
|
||||
<td>{{ $asset->department?->name }}</td>
|
||||
<td>{{ $asset->user?->name }}</td>
|
||||
<td>{{ $asset->personInCharge?->name }}</td>
|
||||
<td>{{ $asset->warranty?->name }}</td>
|
||||
<td>{{ optional($asset->created_at)->format('d/m/Y') }}</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr><td colspan="10" class="text-center text-muted">Data tidak ditemukan.</td></tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
{{ $assets->links() }}
|
||||
</div>
|
||||
@endsection
|
||||
34
resources/views/reports/audits.blade.php
Normal file
34
resources/views/reports/audits.blade.php
Normal file
@@ -0,0 +1,34 @@
|
||||
@php
|
||||
$filtersView = view('reports.partials.audit_filters', compact('filters','assets','locations'));
|
||||
@endphp
|
||||
|
||||
@extends('reports.layout', ['title' => 'Laporan Audit', 'subtitle' => 'Filter per tanggal, status, lokasi', 'filtersView' => $filtersView])
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered text-nowrap align-middle mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Waktu</th><th>Aset</th><th>Status</th><th>Lokasi</th><th>Catatan</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($items as $item)
|
||||
<tr>
|
||||
<td>{{ optional($item->audited_at)->format('d/m/Y H:i') ?: '-' }}</td>
|
||||
<td>{{ $item->asset?->code }} - {{ $item->asset?->name }}</td>
|
||||
<td>{{ ucfirst($item->status) }}</td>
|
||||
<td>{{ $item->location?->name }}</td>
|
||||
<td>{{ $item->notes ?: '-' }}</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr><td colspan="5" class="text-center text-muted">Data tidak ditemukan.</td></tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
{{ $items->links() }}
|
||||
</div>
|
||||
@endsection
|
||||
34
resources/views/reports/disposals.blade.php
Normal file
34
resources/views/reports/disposals.blade.php
Normal file
@@ -0,0 +1,34 @@
|
||||
@php
|
||||
$filtersView = view('reports.partials.disposal_filters', compact('filters','assets'));
|
||||
@endphp
|
||||
|
||||
@extends('reports.layout', ['title' => 'Laporan Disposal', 'subtitle' => 'Filter per tanggal, status reverse', 'filtersView' => $filtersView])
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered text-nowrap align-middle mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Waktu</th><th>Aset</th><th>Alasan</th><th>Catatan</th><th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($items as $item)
|
||||
<tr>
|
||||
<td>{{ optional($item->disposed_at)->format('d/m/Y H:i') ?: '-' }}</td>
|
||||
<td>{{ $item->asset?->code }} - {{ $item->asset?->name }}</td>
|
||||
<td>{{ $item->reason ?: '-' }}</td>
|
||||
<td>{{ $item->notes ?: '-' }}</td>
|
||||
<td>{{ $item->reversed_at ? 'Reversed' : 'Active' }}</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr><td colspan="5" class="text-center text-muted">Data tidak ditemukan.</td></tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
{{ $items->links() }}
|
||||
</div>
|
||||
@endsection
|
||||
23
resources/views/reports/exports/assets.blade.php
Normal file
23
resources/views/reports/exports/assets.blade.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<table width="100%" cellspacing="0" cellpadding="4" border="1">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Kode</th><th>Nama</th><th>Status</th><th>Kategori</th><th>Lokasi</th><th>Dept</th><th>User</th><th>PIC</th><th>Garansi</th><th>Dibuat</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($data as $asset)
|
||||
<tr>
|
||||
<td>{{ $asset->code }}</td>
|
||||
<td>{{ $asset->name }}</td>
|
||||
<td>{{ $asset->status?->name }}</td>
|
||||
<td>{{ $asset->category?->name }}</td>
|
||||
<td>{{ $asset->location?->name }}</td>
|
||||
<td>{{ $asset->department?->name }}</td>
|
||||
<td>{{ $asset->user?->name }}</td>
|
||||
<td>{{ $asset->personInCharge?->name }}</td>
|
||||
<td>{{ $asset->warranty?->name }}</td>
|
||||
<td>{{ optional($asset->created_at)->format('d/m/Y') }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
18
resources/views/reports/exports/audits.blade.php
Normal file
18
resources/views/reports/exports/audits.blade.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<table width="100%" cellspacing="0" cellpadding="4" border="1">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Waktu</th><th>Aset</th><th>Status</th><th>Lokasi</th><th>Catatan</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($data as $a)
|
||||
<tr>
|
||||
<td>{{ optional($a->audited_at)->format('d/m/Y H:i') }}</td>
|
||||
<td>{{ $a->asset?->code }}</td>
|
||||
<td>{{ ucfirst($a->status) }}</td>
|
||||
<td>{{ $a->location?->name }}</td>
|
||||
<td>{{ $a->notes }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
18
resources/views/reports/exports/disposals.blade.php
Normal file
18
resources/views/reports/exports/disposals.blade.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<table width="100%" cellspacing="0" cellpadding="4" border="1">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Waktu</th><th>Aset</th><th>Alasan</th><th>Catatan</th><th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($data as $d)
|
||||
<tr>
|
||||
<td>{{ optional($d->disposed_at)->format('d/m/Y H:i') }}</td>
|
||||
<td>{{ $d->asset?->code }}</td>
|
||||
<td>{{ $d->reason }}</td>
|
||||
<td>{{ $d->notes }}</td>
|
||||
<td>{{ $d->reversed_at ? 'Reversed' : 'Active' }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
22
resources/views/reports/exports/movements.blade.php
Normal file
22
resources/views/reports/exports/movements.blade.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<table width="100%" cellspacing="0" cellpadding="4" border="1">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Waktu</th><th>Aset</th><th>Dari Lokasi</th><th>Ke Lokasi</th><th>Dari Dept</th><th>Ke Dept</th><th>Dari User</th><th>Ke User</th><th>Catatan</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($data as $m)
|
||||
<tr>
|
||||
<td>{{ optional($m->performed_at)->format('d/m/Y H:i') }}</td>
|
||||
<td>{{ $m->asset?->code }}</td>
|
||||
<td>{{ $m->fromLocation?->name }}</td>
|
||||
<td>{{ $m->toLocation?->name }}</td>
|
||||
<td>{{ $m->fromDepartment?->name }}</td>
|
||||
<td>{{ $m->toDepartment?->name }}</td>
|
||||
<td>{{ $m->fromUser?->name }}</td>
|
||||
<td>{{ $m->toUser?->name }}</td>
|
||||
<td>{{ $m->notes }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
34
resources/views/reports/layout.blade.php
Normal file
34
resources/views/reports/layout.blade.php
Normal file
@@ -0,0 +1,34 @@
|
||||
@extends('layouts.master')
|
||||
|
||||
@section('content')
|
||||
<div class="d-flex align-items-center justify-content-between mb-3 page-header-breadcrumb flex-wrap gap-2">
|
||||
<div>
|
||||
<h1 class="page-title fw-medium fs-20 mb-0">{{ $title }}</h1>
|
||||
@if(!empty($subtitle))
|
||||
<p class="text-muted mb-0">{{ $subtitle }}</p>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card custom-card">
|
||||
<div class="card-header">
|
||||
<div class="card-title mb-0">Filter</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{{ $filtersView }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card custom-card mt-3">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<div class="card-title mb-0">{{ $title }}</div>
|
||||
<div class="btn-list">
|
||||
<a href="{{ request()->fullUrlWithQuery(['export' => 'excel']) }}" class="btn btn-outline-primary btn-sm">Export Excel</a>
|
||||
<a href="{{ request()->fullUrlWithQuery(['export' => 'pdf']) }}" class="btn btn-outline-secondary btn-sm">Export PDF</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{{ $slot }}
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
34
resources/views/reports/movements.blade.php
Normal file
34
resources/views/reports/movements.blade.php
Normal file
@@ -0,0 +1,34 @@
|
||||
@php
|
||||
$filtersView = view('reports.partials.movement_filters', compact('filters','assets','locations','departments','users'));
|
||||
@endphp
|
||||
|
||||
@extends('reports.layout', ['title' => 'Laporan Movement', 'subtitle' => 'Filter per tanggal, lokasi, dept, user', 'filtersView' => $filtersView])
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered text-nowrap align-middle mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Waktu</th><th>Aset</th><th>Dari</th><th>Ke</th><th>Catatan</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($items as $item)
|
||||
<tr>
|
||||
<td>{{ optional($item->performed_at)->format('d/m/Y H:i') ?: '-' }}</td>
|
||||
<td>{{ $item->asset?->code }} - {{ $item->asset?->name }}</td>
|
||||
<td>{{ $item->fromLocation?->name ?: '-' }} / {{ $item->fromDepartment?->name ?: '-' }} / {{ $item->fromUser?->name ?: '-' }}</td>
|
||||
<td>{{ $item->toLocation?->name ?: '-' }} / {{ $item->toDepartment?->name ?: '-' }} / {{ $item->toUser?->name ?: '-' }}</td>
|
||||
<td>{{ $item->notes ?: '-' }}</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr><td colspan="5" class="text-center text-muted">Data tidak ditemukan.</td></tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
{{ $items->links() }}
|
||||
</div>
|
||||
@endsection
|
||||
86
resources/views/reports/partials/asset_filters.blade.php
Normal file
86
resources/views/reports/partials/asset_filters.blade.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<form method="GET" class="row g-2">
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Dari</label>
|
||||
<input type="date" name="date_from" class="form-control" value="{{ $filters['date_from'] ?? '' }}">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Sampai</label>
|
||||
<input type="date" name="date_to" class="form-control" value="{{ $filters['date_to'] ?? '' }}">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Status</label>
|
||||
<select name="asset_status_id" class="form-select">
|
||||
<option value="">Semua</option>
|
||||
@foreach($statuses as $item)
|
||||
<option value="{{ $item->id }}" @selected(($filters['asset_status_id'] ?? '') == $item->id)>{{ $item->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Kelas</label>
|
||||
<select name="asset_class_id" class="form-select">
|
||||
<option value="">Semua</option>
|
||||
@foreach($classes as $item)
|
||||
<option value="{{ $item->id }}" @selected(($filters['asset_class_id'] ?? '') == $item->id)>{{ $item->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Kategori</label>
|
||||
<select name="asset_category_id" class="form-select">
|
||||
<option value="">Semua</option>
|
||||
@foreach($categories as $item)
|
||||
<option value="{{ $item->id }}" @selected(($filters['asset_category_id'] ?? '') == $item->id)>{{ $item->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Lokasi</label>
|
||||
<select name="asset_location_id" class="form-select">
|
||||
<option value="">Semua</option>
|
||||
@foreach($locations as $item)
|
||||
<option value="{{ $item->id }}" @selected(($filters['asset_location_id'] ?? '') == $item->id)>{{ $item->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Departemen</label>
|
||||
<select name="department_id" class="form-select">
|
||||
<option value="">Semua</option>
|
||||
@foreach($departments as $item)
|
||||
<option value="{{ $item->id }}" @selected(($filters['department_id'] ?? '') == $item->id)>{{ $item->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Pengguna</label>
|
||||
<select name="asset_user_id" class="form-select">
|
||||
<option value="">Semua</option>
|
||||
@foreach($users as $item)
|
||||
<option value="{{ $item->id }}" @selected(($filters['asset_user_id'] ?? '') == $item->id)>{{ $item->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Person in Charge</label>
|
||||
<select name="person_in_charge_id" class="form-select">
|
||||
<option value="">Semua</option>
|
||||
@foreach($pics as $item)
|
||||
<option value="{{ $item->id }}" @selected(($filters['person_in_charge_id'] ?? '') == $item->id)>{{ $item->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Garansi</label>
|
||||
<select name="warranty_id" class="form-select">
|
||||
<option value="">Semua</option>
|
||||
@foreach($warranties as $item)
|
||||
<option value="{{ $item->id }}" @selected(($filters['warranty_id'] ?? '') == $item->id)>{{ $item->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-12 d-flex gap-2 mt-2">
|
||||
<button type="submit" class="btn btn-primary btn-wave">Terapkan</button>
|
||||
<a href="{{ route('reports.assets') }}" class="btn btn-outline-secondary">Reset</a>
|
||||
</div>
|
||||
</form>
|
||||
41
resources/views/reports/partials/audit_filters.blade.php
Normal file
41
resources/views/reports/partials/audit_filters.blade.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<form method="GET" class="row g-2">
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Dari</label>
|
||||
<input type="date" name="date_from" class="form-control" value="{{ $filters['date_from'] ?? '' }}">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Sampai</label>
|
||||
<input type="date" name="date_to" class="form-control" value="{{ $filters['date_to'] ?? '' }}">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Aset</label>
|
||||
<select name="asset_id" class="form-select">
|
||||
<option value="">Semua</option>
|
||||
@foreach($assets as $item)
|
||||
<option value="{{ $item->id }}" @selected(($filters['asset_id'] ?? '') == $item->id)>{{ $item->code }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Status</label>
|
||||
<select name="status" class="form-select">
|
||||
<option value="">Semua</option>
|
||||
<option value="matched" @selected(($filters['status'] ?? '') === 'matched')>Matched</option>
|
||||
<option value="missing" @selected(($filters['status'] ?? '') === 'missing')>Missing</option>
|
||||
<option value="damaged" @selected(($filters['status'] ?? '') === 'damaged')>Damaged</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Lokasi</label>
|
||||
<select name="location_id" class="form-select">
|
||||
<option value="">Semua</option>
|
||||
@foreach($locations as $item)
|
||||
<option value="{{ $item->id }}" @selected(($filters['location_id'] ?? '') == $item->id)>{{ $item->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-12 d-flex gap-2 mt-2">
|
||||
<button type="submit" class="btn btn-primary btn-wave">Terapkan</button>
|
||||
<a href="{{ route('reports.audits') }}" class="btn btn-outline-secondary">Reset</a>
|
||||
</div>
|
||||
</form>
|
||||
31
resources/views/reports/partials/disposal_filters.blade.php
Normal file
31
resources/views/reports/partials/disposal_filters.blade.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<form method="GET" class="row g-2">
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Dari</label>
|
||||
<input type="date" name="date_from" class="form-control" value="{{ $filters['date_from'] ?? '' }}">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Sampai</label>
|
||||
<input type="date" name="date_to" class="form-control" value="{{ $filters['date_to'] ?? '' }}">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Aset</label>
|
||||
<select name="asset_id" class="form-select">
|
||||
<option value="">Semua</option>
|
||||
@foreach($assets as $item)
|
||||
<option value="{{ $item->id }}" @selected(($filters['asset_id'] ?? '') == $item->id)>{{ $item->code }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Status</label>
|
||||
<select name="status" class="form-select">
|
||||
<option value="">Semua</option>
|
||||
<option value="active" @selected(($filters['status'] ?? '') === 'active')>Active</option>
|
||||
<option value="reversed" @selected(($filters['status'] ?? '') === 'reversed')>Reversed</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-12 d-flex gap-2 mt-2">
|
||||
<button type="submit" class="btn btn-primary btn-wave">Terapkan</button>
|
||||
<a href="{{ route('reports.disposals') }}" class="btn btn-outline-secondary">Reset</a>
|
||||
</div>
|
||||
</form>
|
||||
50
resources/views/reports/partials/movement_filters.blade.php
Normal file
50
resources/views/reports/partials/movement_filters.blade.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<form method="GET" class="row g-2">
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Dari</label>
|
||||
<input type="date" name="date_from" class="form-control" value="{{ $filters['date_from'] ?? '' }}">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Sampai</label>
|
||||
<input type="date" name="date_to" class="form-control" value="{{ $filters['date_to'] ?? '' }}">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Aset</label>
|
||||
<select name="asset_id" class="form-select">
|
||||
<option value="">Semua</option>
|
||||
@foreach($assets as $item)
|
||||
<option value="{{ $item->id }}" @selected(($filters['asset_id'] ?? '') == $item->id)>{{ $item->code }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Lokasi Tujuan</label>
|
||||
<select name="asset_location_id" class="form-select">
|
||||
<option value="">Semua</option>
|
||||
@foreach($locations as $item)
|
||||
<option value="{{ $item->id }}" @selected(($filters['asset_location_id'] ?? '') == $item->id)>{{ $item->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Dept Tujuan</label>
|
||||
<select name="department_id" class="form-select">
|
||||
<option value="">Semua</option>
|
||||
@foreach($departments as $item)
|
||||
<option value="{{ $item->id }}" @selected(($filters['department_id'] ?? '') == $item->id)>{{ $item->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">User Tujuan</label>
|
||||
<select name="asset_user_id" class="form-select">
|
||||
<option value="">Semua</option>
|
||||
@foreach($users as $item)
|
||||
<option value="{{ $item->id }}" @selected(($filters['asset_user_id'] ?? '') == $item->id)>{{ $item->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-12 d-flex gap-2 mt-2">
|
||||
<button type="submit" class="btn btn-primary btn-wave">Terapkan</button>
|
||||
<a href="{{ route('reports.movements') }}" class="btn btn-outline-secondary">Reset</a>
|
||||
</div>
|
||||
</form>
|
||||
@@ -20,6 +20,7 @@ use App\Http\Controllers\AssetController;
|
||||
use App\Http\Controllers\AssetTransactionController;
|
||||
use App\Http\Controllers\AssetAuditController;
|
||||
use App\Http\Controllers\AssetTransactionPageController;
|
||||
use App\Http\Controllers\ReportController;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
Route::get('/', function () {
|
||||
@@ -58,3 +59,7 @@ Route::post('assets/{asset}/audits', [AssetAuditController::class, 'store'])->na
|
||||
Route::get('asset-movements', [AssetTransactionPageController::class, 'movements'])->name('asset-movements.index');
|
||||
Route::get('asset-disposals', [AssetTransactionPageController::class, 'disposals'])->name('asset-disposals.index');
|
||||
Route::get('asset-audits', [AssetTransactionPageController::class, 'audits'])->name('asset-audits.index');
|
||||
Route::get('reports/assets', [ReportController::class, 'assets'])->name('reports.assets');
|
||||
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');
|
||||
|
||||
Reference in New Issue
Block a user