diff --git a/app/Http/Controllers/API/MemberBookingController.php b/app/Http/Controllers/API/MemberBookingController.php index cefa048..8466780 100644 --- a/app/Http/Controllers/API/MemberBookingController.php +++ b/app/Http/Controllers/API/MemberBookingController.php @@ -8,8 +8,8 @@ use App\Exceptions\BookingRuleViolationException; use App\Http\Controllers\Controller; use App\Models\Booking; use App\Models\CourseSchedule; -use App\Notifications\BookingCreatedNotification; use App\Notifications\BookingCancelledNotification; +use App\Notifications\BookingCreatedNotification; use Carbon\Carbon; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; @@ -23,7 +23,7 @@ class MemberBookingController extends Controller ->where('member_id', $request->user()->id) ->orderByDesc('created_at') ->get() - ->map(fn($b) => $this->formatBooking($b)); + ->map(fn ($b) => $this->formatBooking($b)); return response()->json(['status' => true, 'data' => $bookings]); } @@ -41,9 +41,9 @@ class MemberBookingController extends Controller public function store(Request $request) { $data = $request->validate([ - 'schedule_id' => 'required|integer|exists:course_schedules,id', + 'schedule_id' => 'required|integer|exists:course_schedules,id', 'participants' => 'required|integer|min:1', - 'notes' => 'nullable|string|max:500', + 'notes' => 'nullable|string|max:500', ]); $schedule = CourseSchedule::with('divingOffer.provider.providerProfile')->findOrFail($data['schedule_id']); @@ -51,7 +51,7 @@ class MemberBookingController extends Controller // Layer 1:快速失敗 // 可見性繞過防護:課程教練未通過審核時不可建立新預約(既有預約不受影響,見 provider-verification 規格) $offer = $schedule->divingOffer; - if ($offer->provider_id !== null && !($offer->provider?->providerProfile?->is_verified)) { + if ($offer->provider_id !== null && ! ($offer->provider?->providerProfile?->is_verified)) { // is_verified 為 accessor(= verification_status === approved) return response()->json(['status' => false, 'message' => '此課程目前不開放預約'], 422); } @@ -82,12 +82,12 @@ class MemberBookingController extends Controller } return Booking::create([ - 'schedule_id' => $schedule->id, - 'member_id' => $memberId, + 'schedule_id' => $schedule->id, + 'member_id' => $memberId, 'participants' => $data['participants'], - 'total_price' => $schedule->divingOffer->price * $data['participants'], - 'status' => BookingStatus::Pending, - 'notes' => $data['notes'] ?? null, + 'total_price' => $schedule->divingOffer->price * $data['participants'], + 'status' => BookingStatus::Pending, + 'notes' => $data['notes'] ?? null, ]); }); } catch (BookingRuleViolationException $e) { @@ -99,13 +99,13 @@ class MemberBookingController extends Controller $provider = $booking->schedule->divingOffer->provider; $provider->notify(new BookingCreatedNotification($booking)); } catch (\Throwable $e) { - Log::error('BookingCreatedNotification failed: ' . $e->getMessage()); + Log::error('BookingCreatedNotification failed: '.$e->getMessage()); } return response()->json([ - 'status' => true, + 'status' => true, 'message' => '預約已送出,等待教練確認', - 'data' => $this->formatBooking($booking->fresh(['schedule.divingOffer'])), + 'data' => $this->formatBooking($booking->fresh(['schedule.divingOffer'])), ], 201); } @@ -117,13 +117,13 @@ class MemberBookingController extends Controller } $canCancelFrom = [BookingStatus::Pending, BookingStatus::Confirmed]; - if (!in_array($booking->status, $canCancelFrom)) { + if (! in_array($booking->status, $canCancelFrom)) { return response()->json(['status' => false, 'message' => '此預約狀態無法取消'], 422); } // 24h 截止驗證 $schedule = $booking->schedule; - $courseStart = Carbon::parse($schedule->scheduled_date->toDateString() . ' ' . $schedule->start_time); + $courseStart = Carbon::parse($schedule->scheduled_date->toDateString().' '.$schedule->start_time); if (now()->diffInHours($courseStart, false) < 24) { return response()->json(['status' => false, 'message' => '距課程開始不足 24 小時,無法取消,請聯繫教練'], 422); } @@ -149,7 +149,7 @@ class MemberBookingController extends Controller $provider = $booking->schedule->divingOffer->provider; $provider->notify(new BookingCancelledNotification($booking, cancelledBy: 'member')); } catch (\Throwable $e) { - Log::error('BookingCancelledNotification(member) failed: ' . $e->getMessage()); + Log::error('BookingCancelledNotification(member) failed: '.$e->getMessage()); } return response()->json(['status' => true, 'message' => '預約已取消']); @@ -158,20 +158,21 @@ class MemberBookingController extends Controller private function formatBooking(Booking $b): array { $offer = $b->schedule?->divingOffer; + return [ - 'id' => $b->id, - 'offer_id' => $offer?->id, - 'offer_title' => $offer?->title, + 'id' => $b->id, + 'offer_id' => $offer?->id, + 'offer_title' => $offer?->title, 'offer_location' => $offer?->location, - 'offer_region' => $offer?->region, - 'offer_price' => $offer?->price, + 'offer_region' => $offer?->region, + 'offer_price' => $offer?->price, 'scheduled_date' => $b->schedule?->scheduled_date?->toDateString(), - 'start_time' => $b->schedule?->start_time, - 'participants' => $b->participants, - 'total_price' => $b->total_price, - 'status' => $b->status->value, - 'notes' => $b->notes, - 'created_at' => $b->created_at?->toISOString(), + 'start_time' => $b->schedule?->start_time, + 'participants' => $b->participants, + 'total_price' => $b->total_price, + 'status' => $b->status->value, + 'notes' => $b->notes, + 'created_at' => $b->created_at?->toISOString(), ]; } } diff --git a/app/Http/Controllers/API/ProviderBookingController.php b/app/Http/Controllers/API/ProviderBookingController.php index 4384204..4d5afc8 100644 --- a/app/Http/Controllers/API/ProviderBookingController.php +++ b/app/Http/Controllers/API/ProviderBookingController.php @@ -21,10 +21,10 @@ class ProviderBookingController extends Controller { $provider = $request->user(); $bookings = Booking::with(['member', 'schedule.divingOffer']) - ->whereHas('schedule', fn($q) => $q->where('provider_id', $provider->id)) + ->whereHas('schedule', fn ($q) => $q->where('provider_id', $provider->id)) ->orderByDesc('created_at') ->get() - ->map(fn($b) => $this->formatBooking($b)); + ->map(fn ($b) => $this->formatBooking($b)); return response()->json(['status' => true, 'data' => $bookings]); } @@ -34,7 +34,7 @@ class ProviderBookingController extends Controller $booking = Booking::with('schedule')->findOrFail($id); $this->authorizeProvider($request, $booking); - if (!$booking->canTransitionTo(BookingStatus::Confirmed)) { + if (! $booking->canTransitionTo(BookingStatus::Confirmed)) { return response()->json(['status' => false, 'message' => '當前狀態無法確認'], 422); } @@ -63,7 +63,7 @@ class ProviderBookingController extends Controller $booking->load('member'); $booking->member->notify(new BookingConfirmedNotification($booking)); } catch (\Throwable $e) { - Log::error('BookingConfirmedNotification failed: ' . $e->getMessage()); + Log::error('BookingConfirmedNotification failed: '.$e->getMessage()); } return response()->json(['status' => true, 'message' => '預約已確認', 'data' => $this->formatBooking($booking->fresh(['member', 'schedule.divingOffer']))]); @@ -74,7 +74,7 @@ class ProviderBookingController extends Controller $booking = Booking::with('schedule')->findOrFail($id); $this->authorizeProvider($request, $booking); - if (!$booking->canTransitionTo(BookingStatus::Rejected)) { + if (! $booking->canTransitionTo(BookingStatus::Rejected)) { return response()->json(['status' => false, 'message' => '當前狀態無法拒絕'], 422); } @@ -84,7 +84,7 @@ class ProviderBookingController extends Controller $booking->load('member'); $booking->member->notify(new BookingRejectedNotification($booking)); } catch (\Throwable $e) { - Log::error('BookingRejectedNotification failed: ' . $e->getMessage()); + Log::error('BookingRejectedNotification failed: '.$e->getMessage()); } return response()->json(['status' => true, 'message' => '預約已拒絕']); @@ -95,7 +95,7 @@ class ProviderBookingController extends Controller $booking = Booking::with('schedule')->findOrFail($id); $this->authorizeProvider($request, $booking); - if (!$booking->canTransitionTo(BookingStatus::ProviderCancelled)) { + if (! $booking->canTransitionTo(BookingStatus::ProviderCancelled)) { return response()->json(['status' => false, 'message' => '當前狀態無法取消'], 422); } @@ -115,7 +115,7 @@ class ProviderBookingController extends Controller $booking->load('member'); $booking->member->notify(new BookingCancelledNotification($booking, cancelledBy: 'provider')); } catch (\Throwable $e) { - Log::error('BookingCancelledNotification(provider) failed: ' . $e->getMessage()); + Log::error('BookingCancelledNotification(provider) failed: '.$e->getMessage()); } return response()->json(['status' => true, 'message' => '預約已取消']); @@ -126,7 +126,7 @@ class ProviderBookingController extends Controller $booking = Booking::with('schedule')->findOrFail($id); $this->authorizeProvider($request, $booking); - if (!$booking->canTransitionTo(BookingStatus::Completed)) { + if (! $booking->canTransitionTo(BookingStatus::Completed)) { return response()->json(['status' => false, 'message' => '只有已確認的預約才能標記完成'], 422); } @@ -136,7 +136,7 @@ class ProviderBookingController extends Controller $booking->load('member'); $booking->member->notify(new BookingCompletedNotification($booking)); } catch (\Throwable $e) { - Log::error('BookingCompletedNotification failed: ' . $e->getMessage()); + Log::error('BookingCompletedNotification failed: '.$e->getMessage()); } return response()->json(['status' => true, 'message' => '預約已標記為完成']); @@ -152,17 +152,17 @@ class ProviderBookingController extends Controller private function formatBooking(Booking $b): array { return [ - 'id' => $b->id, - 'member_name' => $b->member?->name, - 'member_email' => $b->member?->email, - 'offer_title' => $b->schedule?->divingOffer?->title, + 'id' => $b->id, + 'member_name' => $b->member?->name, + 'member_email' => $b->member?->email, + 'offer_title' => $b->schedule?->divingOffer?->title, 'scheduled_date' => $b->schedule?->scheduled_date?->toDateString(), - 'start_time' => $b->schedule?->start_time, - 'participants' => $b->participants, - 'total_price' => $b->total_price, - 'status' => $b->status->value, - 'notes' => $b->notes, - 'created_at' => $b->created_at?->toISOString(), + 'start_time' => $b->schedule?->start_time, + 'participants' => $b->participants, + 'total_price' => $b->total_price, + 'status' => $b->status->value, + 'notes' => $b->notes, + 'created_at' => $b->created_at?->toISOString(), ]; } }