MIF_E31232103/app/Http/Controllers/AdminRental/ReportController.php

304 lines
12 KiB
PHP

<?php
namespace App\Http\Controllers\AdminRental;
use App\Http\Controllers\Controller;
use App\Models\Booking;
use App\Models\User;
use App\Models\Vehicle;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\View\View;
class ReportController extends Controller
{
private float $commissionRate = 10.0; // 10% commission
/**
* Dashboard ringkas laporan rental
*/
public function index(Request $request): View
{
$rentalId = Auth::user()->rentalCompany->id;
$dateFilter = $this->getDateFilter($request);
// Total Booking untuk rental ini
$totalBookings = $this->getBaseBookingsQuery($rentalId, $dateFilter)->count();
// Total Payment Verified
$totalPaymentsVerified = $this->getBaseBookingsQuery($rentalId, $dateFilter)
->where('payment_status', Booking::PAYMENT_VERIFIED)
->count();
// Total Revenue (dari payment verified)
$totalRevenue = (float) ($this->getBaseBookingsQuery($rentalId, $dateFilter)
->where('payment_status', Booking::PAYMENT_VERIFIED)
->sum('total_amount') ?? 0);
// Total Commission (10% dari revenue)
$totalCommission = round($totalRevenue * ($this->commissionRate / 100), 2);
// Total Vehicles (milik rental)
$totalVehicles = Vehicle::where('rental_company_id', $rentalId)->count();
// Total Active Customers (yang pernah booking ke rental ini)
$totalActiveCustomers = User::query()
->where('role', 'customer')
->whereHas('bookings', fn($q) => $q->where('rental_company_id', $rentalId))
->count();
return view('admin-rental.reports.index', compact(
'totalBookings',
'totalPaymentsVerified',
'totalRevenue',
'totalCommission',
'totalVehicles',
'totalActiveCustomers'
));
}
/**
* Laporan Booking Rental
*/
public function bookings(Request $request): View
{
$request->validate([
'start_date' => ['nullable', 'date'],
'end_date' => ['nullable', 'date', 'after_or_equal:start_date'],
'booking_status' => ['nullable', 'in:waiting_payment,waiting_verification,confirmed,ongoing,completed,cancelled'],
]);
$rentalId = Auth::user()->rentalCompany->id;
$dateFilter = $this->getDateFilter($request);
$baseQuery = Booking::query()
->where('rental_company_id', $rentalId)
->with(['customer', 'vehicle', 'payment'])
->when($dateFilter['start'], fn($q) => $q->where('created_at', '>=', $dateFilter['start']))
->when($dateFilter['end'], fn($q) => $q->where('created_at', '<=', $dateFilter['end']))
->when($request->filled('booking_status'), fn($q) => $q->where('booking_status', $request->string('booking_status')));
// Summary statistics
$summary = [
'total_bookings' => (clone $baseQuery)->count(),
'total_completed' => (clone $baseQuery)->where('booking_status', Booking::BOOKING_COMPLETED)->count(),
'total_cancelled' => (clone $baseQuery)->where('booking_status', Booking::BOOKING_CANCELLED)->count(),
'total_ongoing' => (clone $baseQuery)->where('booking_status', Booking::BOOKING_ONGOING)->count(),
];
$bookings = (clone $baseQuery)
->latest('id')
->paginate(15)
->withQueryString();
$bookingStatuses = Booking::statusOptions();
return view('admin-rental.reports.bookings', compact(
'bookings',
'summary',
'bookingStatuses'
));
}
/**
* Laporan Pembayaran Rental
*/
public function payments(Request $request): View
{
$request->validate([
'start_date' => ['nullable', 'date'],
'end_date' => ['nullable', 'date', 'after_or_equal:start_date'],
'payment_status' => ['nullable', 'in:unpaid,uploaded,verified,rejected'],
]);
$rentalId = Auth::user()->rentalCompany->id;
$dateFilter = $this->getDateFilter($request);
$baseQuery = Booking::query()
->where('rental_company_id', $rentalId)
->with(['customer', 'vehicle', 'payment'])
->whereHas('payment')
->when($dateFilter['start'], fn($q) => $q->where('created_at', '>=', $dateFilter['start']))
->when($dateFilter['end'], fn($q) => $q->where('created_at', '<=', $dateFilter['end']))
->when($request->filled('payment_status'), fn($q) => $q->where('payment_status', $request->string('payment_status')));
// Summary statistics
$summary = [
'total_payments_verified' => (clone $baseQuery)->where('payment_status', Booking::PAYMENT_VERIFIED)->count(),
'total_payments_uploaded' => (clone $baseQuery)->where('payment_status', Booking::PAYMENT_UPLOADED)->count(),
'total_payments_rejected' => (clone $baseQuery)->where('payment_status', Booking::PAYMENT_REJECTED)->count(),
'total_nominal_verified' => (float) ((clone $baseQuery)->where('payment_status', Booking::PAYMENT_VERIFIED)->sum('total_amount') ?? 0),
];
$bookings = (clone $baseQuery)
->latest('id')
->paginate(15)
->withQueryString();
$paymentStatuses = Booking::paymentStatusOptions();
return view('admin-rental.reports.payments', compact(
'bookings',
'summary',
'paymentStatuses'
));
}
/**
* Laporan Kendaraan Terlaris Rental
*/
public function topVehicles(Request $request): View
{
$request->validate([
'start_date' => ['nullable', 'date'],
'end_date' => ['nullable', 'date', 'after_or_equal:start_date'],
'limit' => ['nullable', 'integer', 'min:5', 'max:100'],
]);
$limit = $request->integer('limit', 20);
$rentalId = Auth::user()->rentalCompany->id;
$dateFilter = $this->getDateFilter($request);
// Kendaraan terlaris berdasarkan jumlah booking dengan payment verified
$topVehicles = Vehicle::query()
->where('rental_company_id', $rentalId)
->withCount([
'bookings as verified_booking_count' => function (Builder $query) use ($dateFilter): void {
$query->where('payment_status', Booking::PAYMENT_VERIFIED)
->when($dateFilter['start'], fn($q) => $q->where('created_at', '>=', $dateFilter['start']))
->when($dateFilter['end'], fn($q) => $q->where('created_at', '<=', $dateFilter['end']));
},
])
->withSum([
'bookings as total_revenue' => function (Builder $query) use ($dateFilter): void {
$query->where('payment_status', Booking::PAYMENT_VERIFIED)
->when($dateFilter['start'], fn($q) => $q->where('created_at', '>=', $dateFilter['start']))
->when($dateFilter['end'], fn($q) => $q->where('created_at', '<=', $dateFilter['end']));
},
], 'total_amount')
->having('verified_booking_count', '>', 0)
->orderByDesc('verified_booking_count')
->limit($limit)
->get();
return view('admin-rental.reports.top-vehicles', compact('topVehicles'));
}
/**
* Laporan Customer Aktif Rental
*/
public function activeCustomers(Request $request): View
{
$request->validate([
'start_date' => ['nullable', 'date'],
'end_date' => ['nullable', 'date', 'after_or_equal:start_date'],
'limit' => ['nullable', 'integer', 'min:5', 'max:100'],
]);
$limit = $request->integer('limit', 20);
$rentalId = Auth::user()->rentalCompany->id;
$dateFilter = $this->getDateFilter($request);
// Customer aktif berdasarkan completed bookings
$activeCustomers = User::query()
->where('role', 'customer')
->withCount([
'bookings as total_booking_count' => function (Builder $query) use ($rentalId, $dateFilter): void {
$query->where('rental_company_id', $rentalId)
->when($dateFilter['start'], fn($q) => $q->where('created_at', '>=', $dateFilter['start']))
->when($dateFilter['end'], fn($q) => $q->where('created_at', '<=', $dateFilter['end']));
},
'bookings as completed_booking_count' => function (Builder $query) use ($rentalId, $dateFilter): void {
$query->where('rental_company_id', $rentalId)
->where('booking_status', Booking::BOOKING_COMPLETED)
->when($dateFilter['start'], fn($q) => $q->where('created_at', '>=', $dateFilter['start']))
->when($dateFilter['end'], fn($q) => $q->where('created_at', '<=', $dateFilter['end']));
},
])
->withMax([
'bookings as last_booking_date' => function (Builder $query) use ($rentalId, $dateFilter): void {
$query->where('rental_company_id', $rentalId)
->when($dateFilter['start'], fn($q) => $q->where('created_at', '>=', $dateFilter['start']))
->when($dateFilter['end'], fn($q) => $q->where('created_at', '<=', $dateFilter['end']));
},
], 'created_at')
->withSum([
'bookings as total_transaction' => function (Builder $query) use ($rentalId, $dateFilter): void {
$query->where('rental_company_id', $rentalId)
->where('payment_status', Booking::PAYMENT_VERIFIED)
->when($dateFilter['start'], fn($q) => $q->where('created_at', '>=', $dateFilter['start']))
->when($dateFilter['end'], fn($q) => $q->where('created_at', '<=', $dateFilter['end']));
},
], 'total_amount')
->having('completed_booking_count', '>', 0)
->orderByDesc('completed_booking_count')
->limit($limit)
->get();
// Check loyal threshold (3 completed bookings)
$loyalThreshold = 3;
return view('admin-rental.reports.active-customers', compact('activeCustomers', 'loyalThreshold'));
}
/**
* Laporan Pendapatan Rental
*/
public function revenue(Request $request): View
{
$request->validate([
'start_date' => ['nullable', 'date'],
'end_date' => ['nullable', 'date', 'after_or_equal:start_date'],
]);
$rentalId = Auth::user()->rentalCompany->id;
$dateFilter = $this->getDateFilter($request);
// Revenue untuk rental ini
$baseQuery = Booking::query()
->where('rental_company_id', $rentalId)
->where('payment_status', Booking::PAYMENT_VERIFIED)
->when($dateFilter['start'], fn($q) => $q->where('created_at', '>=', $dateFilter['start']))
->when($dateFilter['end'], fn($q) => $q->where('created_at', '<=', $dateFilter['end']));
$verifiedBookingCount = (clone $baseQuery)->count();
$grossRevenue = (float) ((clone $baseQuery)->sum('total_amount') ?? 0);
$commission = round($grossRevenue * ($this->commissionRate / 100), 2);
$netRevenue = round($grossRevenue - $commission, 2);
$rentalCompany = Auth::user()->rentalCompany;
return view('admin-rental.reports.revenue', compact(
'rentalCompany',
'verifiedBookingCount',
'grossRevenue',
'commission',
'netRevenue'
));
}
/**
* Helper: Get date filter array
*/
private function getDateFilter(Request $request): array
{
return [
'start' => $request->filled('start_date') ? $request->date('start_date')->startOfDay() : null,
'end' => $request->filled('end_date') ? $request->date('end_date')->endOfDay() : null,
];
}
/**
* Helper: Get base bookings query with filters
*/
private function getBaseBookingsQuery(int $rentalId, array $dateFilter): Builder
{
return Booking::query()
->where('rental_company_id', $rentalId)
->when($dateFilter['start'], fn($q) => $q->where('created_at', '>=', $dateFilter['start']))
->when($dateFilter['end'], fn($q) => $q->where('created_at', '<=', $dateFilter['end']));
}
}