36 lines
3.6 KiB
PHP
36 lines
3.6 KiB
PHP
<?php
|
|
namespace App\Http\Controllers;
|
|
use App\Models\LodgeBooking;
|
|
use App\Models\LodgePhoto;
|
|
use Carbon\CarbonImmutable;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Str;
|
|
use Illuminate\Validation\ValidationException;
|
|
class LodgeController extends Controller {
|
|
private function nightlyRate(): int { return max(1,(int)config('lodge.nightly_rate_pence',17500)); }
|
|
public function home() { return view('lodge.home',['rate'=>$this->nightlyRate()/100,'uploadedPhotos'=>LodgePhoto::latest()->get()]); }
|
|
public function availability(Request $request) {
|
|
$v=$request->validate(['check_in'=>'required|date|after_or_equal:today','check_out'=>'required|date|after:check_in','guests'=>'required|integer|min:1|max:'.config('lodge.max_guests',6)]);
|
|
$start=CarbonImmutable::parse($v['check_in']);$end=CarbonImmutable::parse($v['check_out']);$nights=$start->diffInDays($end);
|
|
if($nights>30) throw ValidationException::withMessages(['check_out'=>'Maximum stay is 30 nights.']);
|
|
$available=!LodgeBooking::whereIn('status',['pending','confirmed'])->where('check_in','<',$v['check_out'])->where('check_out','>',$v['check_in'])->exists();
|
|
return view('lodge.availability',compact('v','available','nights')+['total'=>$nights*$this->nightlyRate()/100]);
|
|
}
|
|
public function book(Request $request) {
|
|
$v=$request->validate(['check_in'=>'required|date|after_or_equal:today','check_out'=>'required|date|after:check_in','guests'=>'required|integer|min:1|max:'.config('lodge.max_guests',6),'guest_name'=>'required|string|max:120','guest_email'=>'required|email|max:255','guest_phone'=>'nullable|string|max:40','notes'=>'nullable|string|max:2000']);
|
|
$nights=CarbonImmutable::parse($v['check_in'])->diffInDays(CarbonImmutable::parse($v['check_out']));
|
|
if($nights>30) throw ValidationException::withMessages(['check_out'=>'Maximum stay is 30 nights.']);
|
|
// Serialized booking creation protects against concurrent requests on supported database engines.
|
|
$booking=DB::transaction(function()use($v,$nights){
|
|
DB::table('lodge_booking_locks')->where('id',1)->lockForUpdate()->first();
|
|
if(LodgeBooking::whereIn('status',['pending','confirmed'])->where('check_in','<',$v['check_out'])->where('check_out','>',$v['check_in'])->exists()) throw ValidationException::withMessages(['check_in'=>'These dates have just been booked. Please choose different dates.']);
|
|
return LodgeBooking::create($v+['reference'=>'CR31-'.strtoupper(Str::random(9)),'nights'=>$nights,'total_pence'=>$nights*$this->nightlyRate(),'status'=>'pending']);
|
|
},3);
|
|
return redirect()->route('lodge.confirmation',['reference'=>$booking->reference]);
|
|
}
|
|
public function confirmation(string $reference) { $booking=LodgeBooking::where('reference',$reference)->firstOrFail();return view('lodge.confirmation',compact('booking')); }
|
|
public function admin(Request $request) { abort_unless($request->user()?->email===config('lodge.admin_email') && filled(config('lodge.admin_email')),403);return view('lodge.admin',['bookings'=>LodgeBooking::latest()->paginate(30),'photos'=>LodgePhoto::latest()->get()]); }
|
|
public function update(Request $request,LodgeBooking $booking) {abort_unless($request->user()?->email===config('lodge.admin_email') && filled(config('lodge.admin_email')),403);$v=$request->validate(['status'=>'required|in:pending,confirmed,cancelled']);if($v['status']!=='cancelled' && LodgeBooking::whereKeyNot($booking->id)->whereIn('status',['pending','confirmed'])->where('check_in','<',$booking->check_out)->where('check_out','>',$booking->check_in)->exists()) throw ValidationException::withMessages(['status'=>'Date conflict.']);$booking->update($v);return back()->with('success','Booking updated.'); }
|
|
}
|