2026-02-08 15:16:35 +07:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
|
|
|
|
|
|
use Illuminate\Http\Request;
|
|
|
|
|
use App\Models\{Cat, Medicine, Food, Supply, Treatment, Matting, User, ActivityLog};
|
|
|
|
|
use App\Exports\UnifiedReportExport;
|
|
|
|
|
use Maatwebsite\Excel\Facades\Excel;
|
|
|
|
|
use Barryvdh\DomPDF\Facade\Pdf;
|
|
|
|
|
use Carbon\Carbon;
|
2026-02-08 18:45:10 +07:00
|
|
|
use Illuminate\Support\Facades\Gate;
|
2026-02-08 15:16:35 +07:00
|
|
|
|
|
|
|
|
class ReportController extends Controller
|
|
|
|
|
{
|
|
|
|
|
public function index(Request $request)
|
|
|
|
|
{
|
|
|
|
|
Gate::authorize('check-access', ['reports', 'read']);
|
|
|
|
|
|
|
|
|
|
$module = $request->get('module', 'cats');
|
|
|
|
|
$query = $this->initializeQuery($module);
|
|
|
|
|
|
|
|
|
|
$this->applyGlobalFilters($query, $request, $module);
|
|
|
|
|
$this->applyModuleFilters($query, $request, $module);
|
|
|
|
|
|
|
|
|
|
if ($request->filled('export')) {
|
|
|
|
|
$filteredData = $query->latest()->get();
|
|
|
|
|
return $this->processExport($filteredData, $module, $request->export);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$results = $query->latest()->paginate(15)->withQueryString();
|
|
|
|
|
$users = User::orderBy('name')->get(['id', 'name']);
|
|
|
|
|
|
|
|
|
|
return view('pages.reports.index', compact('results', 'module', 'users'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function initializeQuery($module)
|
|
|
|
|
{
|
|
|
|
|
return match ($module) {
|
|
|
|
|
'cats' => Cat::with(['pic']),
|
|
|
|
|
'medicine' => Medicine::query(),
|
|
|
|
|
'food' => Food::query(),
|
|
|
|
|
'supplies' => Supply::query(),
|
|
|
|
|
'treatment' => Treatment::with(['cat', 'pic']),
|
|
|
|
|
'vaccine', 'deworming', 'flea', 'grooming' => Cat::with(['pic']),
|
|
|
|
|
default => Cat::query(),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function applyGlobalFilters($query, $request, $module)
|
|
|
|
|
{
|
|
|
|
|
if ($request->filled('q')) {
|
|
|
|
|
$search = $request->q;
|
|
|
|
|
$query->where(function($q) use ($module, $search) {
|
|
|
|
|
$searchCol = $this->getSearchColumn($module);
|
|
|
|
|
$q->where($searchCol, 'like', "%{$search}%");
|
|
|
|
|
if ($module === 'treatment') {
|
|
|
|
|
$q->orWhereHas('cat', fn($query) => $query->where('nama_kucing', 'like', "%{$search}%"));
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($request->filled('pic_id')) {
|
|
|
|
|
$query->where('pic_id', $request->pic_id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($request->filled('start_date') && $request->filled('end_date')) {
|
|
|
|
|
$dateCol = $this->getDateColumn($module);
|
|
|
|
|
$query->whereBetween($dateCol, [
|
|
|
|
|
Carbon::parse($request->start_date)->startOfDay(),
|
|
|
|
|
Carbon::parse($request->end_date)->endOfDay()
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function applyModuleFilters($query, $request, $module)
|
|
|
|
|
{
|
|
|
|
|
$status = $request->status;
|
|
|
|
|
|
2026-02-08 18:45:10 +07:00
|
|
|
// TAMBAHAN: Logika Filter untuk Modul Cats (Sehat/Sakit)
|
|
|
|
|
// Ini yang membuat filter status di populasi kucing bekerja
|
|
|
|
|
if ($module === 'cats' && $request->filled('status')) {
|
|
|
|
|
match($status) {
|
|
|
|
|
'sakit' => $query->whereNotNull('riwayat_sakit_terakhir')->where('riwayat_sakit_terakhir', '!=', ''),
|
|
|
|
|
'sehat' => $query->where(function($q) {
|
|
|
|
|
$q->whereNull('riwayat_sakit_terakhir')
|
|
|
|
|
->orWhere('riwayat_sakit_terakhir', '');
|
|
|
|
|
}),
|
|
|
|
|
default => null
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-08 15:16:35 +07:00
|
|
|
// Modul Maintenance
|
|
|
|
|
if (in_array($module, ['vaccine', 'deworming', 'flea', 'grooming']) && $request->filled('status')) {
|
|
|
|
|
$dateCol = $this->getDateColumn($module);
|
|
|
|
|
match($status) {
|
|
|
|
|
'overdue' => $query->whereNotNull($dateCol)->where($dateCol, '<', now()->toDateString()),
|
|
|
|
|
'soon' => $query->whereNotNull($dateCol)->whereBetween($dateCol, [now()->toDateString(), now()->addDays(7)->toDateString()]),
|
|
|
|
|
'not_set' => $query->whereNull($dateCol),
|
|
|
|
|
default => null
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Modul Inventori
|
|
|
|
|
if (in_array($module, ['medicine', 'food', 'supplies']) && $request->filled('status')) {
|
|
|
|
|
match($status) {
|
|
|
|
|
'critical' => $query->where('qty', '<', 5),
|
|
|
|
|
'expired' => $query->whereNotNull('expired_date')->where('expired_date', '<', now()->toDateString()),
|
|
|
|
|
'safe' => $query->where('qty', '>=', 5),
|
|
|
|
|
default => null
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function getSearchColumn($module) {
|
|
|
|
|
return match($module) {
|
|
|
|
|
'cats', 'vaccine', 'deworming', 'flea', 'grooming' => 'nama_kucing',
|
|
|
|
|
'medicine' => 'nama_obat',
|
|
|
|
|
'food' => 'nama_makanan',
|
|
|
|
|
'supplies' => 'nama_perlengkapan',
|
|
|
|
|
default => 'id'
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function getDateColumn($module) {
|
|
|
|
|
return match($module) {
|
2026-02-08 18:45:10 +07:00
|
|
|
'cats' => 'tanggal_lahir',
|
2026-02-08 15:16:35 +07:00
|
|
|
'medicine', 'food', 'supplies' => 'expired_date',
|
|
|
|
|
'vaccine' => 'jadwal_vaksin',
|
|
|
|
|
'deworming' => 'jadwal_obat_cacing',
|
|
|
|
|
'flea' => 'jadwal_obat_kutu',
|
|
|
|
|
'grooming' => 'jadwal_grooming',
|
|
|
|
|
default => 'created_at'
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function processExport($data, $module, $format)
|
|
|
|
|
{
|
|
|
|
|
$fileName = "Report_{$module}_" . now()->format('Ymd_His');
|
|
|
|
|
if ($format === 'xlsx') {
|
|
|
|
|
return Excel::download(new UnifiedReportExport($data, $module), "{$fileName}.xlsx");
|
|
|
|
|
}
|
|
|
|
|
$pdf = Pdf::loadView('pages.reports.pdf_template', [
|
|
|
|
|
'data' => $data,
|
|
|
|
|
'module' => $module,
|
|
|
|
|
'title' => "Laporan " . ucfirst($module)
|
|
|
|
|
])->setPaper('a4', 'landscape');
|
|
|
|
|
return $pdf->download("{$fileName}.pdf");
|
|
|
|
|
}
|
|
|
|
|
}
|