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

173 lines
6.5 KiB
PHP

<?php
namespace App\Http\Controllers\AdminRental;
use App\Http\Controllers\Controller;
use App\Models\Booking;
use App\Models\RentalCompany;
use App\Models\Review;
use App\Models\User;
use App\Services\PromoService;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;
class CustomerController extends Controller
{
public function index(Request $request): View|RedirectResponse
{
$rentalCompany = $this->getRentalCompany();
if (!$rentalCompany) {
return redirect()->route('admin-rental.dashboard')->with('error', 'Akun admin rental ini belum memiliki rental company.');
}
$this->authorize('viewAny', User::class);
$request->validate([
'search' => ['nullable', 'string', 'max:100'],
'loyal' => ['nullable', 'in:loyal,non_loyal'],
]);
$threshold = PromoService::LOYAL_COMPLETED_THRESHOLD;
$loyalCustomerIdSubQuery = Booking::query()
->select('customer_id')
->where('rental_company_id', $rentalCompany->id)
->where('booking_status', Booking::BOOKING_COMPLETED)
->groupBy('customer_id')
->havingRaw('COUNT(*) >= ?', [$threshold]);
$customers = User::query()
->whereHas('bookings', function (Builder $query) use ($rentalCompany): void {
$query->where('rental_company_id', $rentalCompany->id);
})
->withCount([
'bookings as booking_count' => function (Builder $query) use ($rentalCompany): void {
$query->where('rental_company_id', $rentalCompany->id);
},
'bookings as completed_booking_count' => function (Builder $query) use ($rentalCompany): void {
$query->where('rental_company_id', $rentalCompany->id)
->where('booking_status', Booking::BOOKING_COMPLETED);
},
])
->withSum([
'bookings as total_transaction_amount' => function (Builder $query) use ($rentalCompany): void {
$query->where('rental_company_id', $rentalCompany->id);
},
], 'total_amount')
->withMax([
'bookings as last_booking_at' => function (Builder $query) use ($rentalCompany): void {
$query->where('rental_company_id', $rentalCompany->id);
},
], 'created_at')
->withAvg([
'reviews as average_rating_given' => function (Builder $query) use ($rentalCompany): void {
$query->where('rental_company_id', $rentalCompany->id);
},
], 'rating')
->when($request->filled('search'), function (Builder $query) use ($request): void {
$search = $request->string('search')->toString();
$query->where(function (Builder $subQuery) use ($search): void {
$subQuery->where('name', 'like', '%' . $search . '%')
->orWhere('email', 'like', '%' . $search . '%');
});
})
->when($request->string('loyal')->toString() === 'loyal', function (Builder $query) use ($loyalCustomerIdSubQuery): void {
$query->whereIn('id', $loyalCustomerIdSubQuery);
})
->when($request->string('loyal')->toString() === 'non_loyal', function (Builder $query) use ($loyalCustomerIdSubQuery): void {
$query->whereNotIn('id', $loyalCustomerIdSubQuery);
})
->orderByDesc('last_booking_at')
->paginate(10)
->withQueryString();
$summary = [
'total_customers' => Booking::query()
->where('rental_company_id', $rentalCompany->id)
->distinct('customer_id')
->count('customer_id'),
'loyal_customers' => DB::query()->fromSub($loyalCustomerIdSubQuery, 'loyal_customers')->count(),
'completed_bookings' => Booking::query()
->where('rental_company_id', $rentalCompany->id)
->where('booking_status', Booking::BOOKING_COMPLETED)
->count(),
];
return view('admin-rental.customers.index', compact('customers', 'rentalCompany', 'summary', 'threshold'));
}
public function show(User $customer): View
{
$rentalCompany = $this->getRentalCompanyOrAbort();
$bookingsQuery = Booking::query()
->with(['vehicle', 'payment', 'review', 'promo'])
->where('rental_company_id', $rentalCompany->id)
->where('customer_id', $customer->id)
->latest('id');
if (!(clone $bookingsQuery)->exists()) {
abort(404);
}
$threshold = PromoService::LOYAL_COMPLETED_THRESHOLD;
$bookingCount = (clone $bookingsQuery)->count();
$completedCount = (clone $bookingsQuery)->where('booking_status', Booking::BOOKING_COMPLETED)->count();
$totalTransactionAmount = (float) ((clone $bookingsQuery)->sum('total_amount') ?? 0);
$lastBooking = (clone $bookingsQuery)->first();
$lastBookingDate = $lastBooking?->created_at;
$vehicles = (clone $bookingsQuery)
->with('vehicle')
->distinct('vehicle_id')
->get()
->pluck('vehicle')
->unique('id')
->sortBy('name');
$reviews = Review::query()
->with(['vehicle', 'booking'])
->where('rental_company_id', $rentalCompany->id)
->where('customer_id', $customer->id)
->latest('id')
->get();
$bookings = $bookingsQuery->paginate(8);
$isLoyal = $completedCount >= $threshold;
return view('admin-rental.customers.show', compact(
'customer',
'rentalCompany',
'bookings',
'bookingCount',
'completedCount',
'totalTransactionAmount',
'lastBookingDate',
'vehicles',
'reviews',
'threshold',
'isLoyal'
));
}
private function getRentalCompany(): ?RentalCompany
{
return Auth::user()?->rentalCompany;
}
private function getRentalCompanyOrAbort(): RentalCompany
{
$rentalCompany = $this->getRentalCompany();
if (!$rentalCompany) {
abort(404);
}
return $rentalCompany;
}
}