Files
a620906209 975b56ca54 feat:實作預約系統 — 時段管理、預約生命週期與前端整合
後端:
- 新增 course_schedules / bookings migration(含索引)
- BookingStatus / ScheduleStatus PHP BackedEnum
- CourseSchedule / Booking Model(七狀態機 VALID_TRANSITIONS)
- ScheduleController、ProviderBookingController、MemberBookingController
- 雙層名額驗證(API 層快速失敗 + DB lockForUpdate 防超賣)
- 24h 取消截止、pending 不佔位設計
- ExpirePendingBookings(每小時)/ CompleteFinishedBookings(每日)Scheduler
- Docker cron 配置、CACHE_STORE 改為 file 修正 502

前端:
- 課程詳情頁加入時段選擇與預約流程
- 我的預約頁(展開式卡片、狀態說明、連結課程詳情)
- Coach 時段管理(上午/下午時間選擇器、新課程引導)
- Coach 預約管理(依課程分組、待確認徽章)
- Navbar 新增「我的預約」與「時段/預約管理」入口
- 密碼格式提示與即時比對

OpenSpec:
- booking-system change 歸檔至 archive/2026-05-12-booking-system
- 新增 specs/course-scheduling 與 specs/booking-lifecycle 主規格

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-05-12 00:24:51 +08:00

52 lines
1.3 KiB
PHP

<?php
namespace App\Models;
use App\Enums\BookingStatus;
use Illuminate\Database\Eloquent\Model;
class Booking extends Model
{
protected $fillable = [
'schedule_id',
'member_id',
'participants',
'total_price',
'status',
'notes',
];
protected $casts = [
'participants' => 'integer',
'total_price' => 'integer',
'status' => BookingStatus::class,
];
const VALID_TRANSITIONS = [
'pending' => ['confirmed', 'rejected', 'expired', 'member_cancelled'],
'confirmed' => ['completed', 'member_cancelled', 'provider_cancelled'],
'completed' => [],
'rejected' => [],
'expired' => [],
'member_cancelled' => [],
'provider_cancelled' => [],
];
public function canTransitionTo(BookingStatus $newStatus): bool
{
$current = $this->status->value;
$allowed = self::VALID_TRANSITIONS[$current] ?? [];
return in_array($newStatus->value, $allowed);
}
public function schedule()
{
return $this->belongsTo(CourseSchedule::class, 'schedule_id');
}
public function member()
{
return $this->belongsTo(User::class, 'member_id');
}
}