# Pet Hotel 訂單流程架構

## 概述

本文檔說明 Pet Hotel 訂單系統的資料流程和架構設計，包含訂單項目多型設計、資料庫結構和類別繼承關係。

## 📊 資料庫架構

### 表結構關係圖

```mermaid
erDiagram
    orders_containers ||--o{ hotel_orders : "1對多"
    hotel_orders ||--o{ hotel_order_items : "1對多"
    hotels_rooms ||--o{ hotel_orders : "1對多"
    
    orders_containers {
        bigint id PK
        string displayId
        uuid merchant_id
        decimal total
        string status
    }
    
    hotel_orders {
        uuid id PK
        bigint container_id FK
        uuid product_id
        bigint room_id FK
        date check_in_date
        date check_out_date
        string status
        decimal price
        decimal total
    }
    
    hotel_order_items {
        bigint id PK
        uuid hotel_order_id FK
        string type
        string class_name
        json meta
        text note
    }
    
    hotels_rooms {
        bigint id PK
        uuid product_id
        bigint room_type_id FK
        string number
    }
```

## 🏗️ 類別繼承架構

### Single Table Inheritance (STI) 多型設計

```mermaid
classDiagram
    class HotelOrder {
        +uuid id
        +bigint container_id
        +uuid product_id
        +bigint room_id
        +date check_in_date
        +date check_out_date
        +string status
        +decimal price
        +decimal total
        +container() OrderContainer
        +room() HotelRoom
        +items() HotelOrderItem[]
    }
    
    class HotelOrderItem {
        <<abstract>>
        +bigint id
        +uuid hotel_order_id
        +string type
        +string class_name
        +json meta
        +text note
        +newFromBuilder() HotelOrderItem
        +newModelInstance() HotelOrderItem
        +hotelOrder() HotelOrder
    }
    
    class HotelOrderItemGuest {
        +getRoomIdAttribute() int
        +getDateAttribute() Carbon
        +getPetIdAttribute() array
        +getGuestNameAttribute() string
        +getRoomAttribute() HotelRoom
        +getPetsAttribute() Pet[]
    }
    
    class HotelOrderItemDiscount {
        +getDiscountTypeAttribute() string
        +getTitleAttribute() string
        +getDiscountAmountAttribute() decimal
        +getDiscountValueAttribute() decimal
        +getCouponIdAttribute() string
        +getLevelIdAttribute() string
    }
    
    class HotelOrderItemAddon {
        +getAddonPriceIdAttribute() uuid
        +getAddonPriceAttribute() decimal
        +getAddonQtyAttribute() int
        +getTitleAttribute() string
    }
    
    HotelOrder "1" --> "*" HotelOrderItem : has many
    HotelOrderItem <|-- HotelOrderItemGuest : extends
    HotelOrderItem <|-- HotelOrderItemDiscount : extends
    HotelOrderItem <|-- HotelOrderItemAddon : extends
```

## 🔄 資料流程

### 訂單建立流程

```mermaid
sequenceDiagram
    participant Controller
    participant Action
    participant HotelOrder
    participant HotelOrderItem
    participant HotelOrderItemGuest
    participant Database
    
    Controller->>Action: execute()
    Action->>HotelOrder: create()
    HotelOrder->>Database: INSERT hotel_orders
    Database-->>HotelOrder: UUID generated
    
    Action->>HotelOrderItemGuest: create()
    HotelOrderItemGuest->>HotelOrderItemGuest: boot() event
    Note over HotelOrderItemGuest: 設定 type='guest'<br/>class_name=self::class
    HotelOrderItemGuest->>Database: INSERT hotel_order_items
    Note over Database: meta 欄位儲存:<br/>{room_id, date, pet_id, guest_name}
    Database-->>HotelOrderItemGuest: 記錄建立
    
    Action->>HotelOrder: items() 關聯查詢
    HotelOrder->>Database: SELECT hotel_order_items
    Database-->>HotelOrder: 返回記錄
    HotelOrder->>HotelOrderItem: newFromBuilder()
    HotelOrderItem->>HotelOrderItem: 讀取 class_name
    HotelOrderItem->>HotelOrderItemGuest: 動態實例化
    HotelOrderItemGuest-->>HotelOrder: 返回正確類別實例
```

### 多型實例化流程

```mermaid
flowchart TD
    A[查詢 hotel_order_items] --> B{讀取 class_name}
    B -->|HotelOrderItemGuest| C[實例化 HotelOrderItemGuest]
    B -->|HotelOrderItemDiscount| D[實例化 HotelOrderItemDiscount]
    B -->|HotelOrderItemAddon| E[實例化 HotelOrderItemAddon]
    B -->|其他或空值| F[實例化 HotelOrderItem]
    
    C --> G[從 meta 讀取 room_id, date, pet_id, guest_name]
    D --> H[從 meta 讀取 discount_type, title, discount_amount 等]
    E --> I[從 meta 讀取 addon_price_id, addon_price, addon_qty 等]
    
    G --> J[返回完整的預約項目物件]
    H --> K[返回完整的折扣項目物件]
    I --> L[返回完整的加購項目物件]
    F --> M[返回基礎項目物件]
```

## 🎨 Order Item 多型架構詳解

### 多型實例化機制

```mermaid
flowchart TB
    subgraph Database["資料庫 hotel_order_items"]
        DB1["id: 1<br/>type: 'guest'<br/>class_name: 'HotelOrderItemGuest'<br/>meta: {room_id, date, pet_id, guest_name}"]
        DB2["id: 2<br/>type: 'discount'<br/>class_name: 'HotelOrderItemDiscount'<br/>meta: {discount_type, title, discount_amount}"]
        DB3["id: 3<br/>type: 'addon'<br/>class_name: 'HotelOrderItemAddon'<br/>meta: {addon_price_id, addon_price, addon_qty}"]
    end
    
    subgraph BaseClass["HotelOrderItem (基礎類別)"]
        BC1["newFromBuilder()"]
        BC2["讀取 class_name 欄位"]
        BC3["驗證類別存在且為子類別"]
        BC4["動態實例化對應類別"]
    end
    
    subgraph SubClasses["子類別實例"]
        SC1["HotelOrderItemGuest<br/>- room_id<br/>- date<br/>- pet_id<br/>- guest_name"]
        SC2["HotelOrderItemDiscount<br/>- discount_type<br/>- title<br/>- discount_amount<br/>- discount_value"]
        SC3["HotelOrderItemAddon<br/>- addon_price_id<br/>- addon_price<br/>- addon_qty<br/>- title"]
    end
    
    DB1 --> BC1
    DB2 --> BC1
    DB3 --> BC1
    
    BC1 --> BC2
    BC2 --> BC3
    BC3 --> BC4
    
    BC4 -->|class_name = 'HotelOrderItemGuest'| SC1
    BC4 -->|class_name = 'HotelOrderItemDiscount'| SC2
    BC4 -->|class_name = 'HotelOrderItemAddon'| SC3
    
    SC1 -.->|Accessor| DB1
    SC2 -.->|Accessor| DB2
    SC3 -.->|Accessor| DB3
    
    style DB1 fill:#e1f5ff
    style DB2 fill:#fff4e1
    style DB3 fill:#e8f5e9
    style SC1 fill:#e1f5ff
    style SC2 fill:#fff4e1
    style SC3 fill:#e8f5e9
```

### Meta 欄位結構映射

```mermaid
graph LR
    subgraph GuestMeta["Guest 類型 meta 結構"]
        GM1["room_id: 123"]
        GM2["date: '2026-01-15'"]
        GM3["pet_id: [1,2,3]"]
        GM4["guest_name: '張三'"]
    end
    
    subgraph DiscountMeta["Discount 類型 meta 結構"]
        DM1["discount_type: 'fixed'"]
        DM2["title: '會員折扣'"]
        DM3["discount_amount: -500.00"]
        DM4["discount_value: null"]
        DM5["coupon_id: 'uuid'"]
        DM6["level_id: 'uuid'"]
    end
    
    subgraph AddonMeta["Addon 類型 meta 結構"]
        AM1["addon_price_id: 'uuid'"]
        AM2["addon_price: 300.00"]
        AM3["addon_qty: 2"]
        AM4["title: '加購服務'"]
    end
    
    subgraph Accessors["Accessor/Mutator"]
        A1["getRoomIdAttribute()"]
        A2["getDateAttribute()"]
        A3["getPetIdAttribute()"]
        A4["getGuestNameAttribute()"]
        A5["getDiscountTypeAttribute()"]
        A6["getDiscountAmountAttribute()"]
        A7["getAddonPriceAttribute()"]
        A8["getAddonQtyAttribute()"]
    end
    
    GM1 --> A1
    GM2 --> A2
    GM3 --> A3
    GM4 --> A4
    DM1 --> A5
    DM3 --> A6
    AM2 --> A7
    AM3 --> A8
    
    style GuestMeta fill:#e1f5ff
    style DiscountMeta fill:#fff4e1
    style AddonMeta fill:#e8f5e9
```

### 多型查詢流程

```mermaid
sequenceDiagram
    participant App as 應用程式
    participant HO as HotelOrder
    participant HOI as HotelOrderItem
    participant DB as 資料庫
    participant Guest as HotelOrderItemGuest
    participant Discount as HotelOrderItemDiscount
    participant Addon as HotelOrderItemAddon
    
    App->>HO: items() 關聯查詢
    HO->>DB: SELECT * FROM hotel_order_items<br/>WHERE hotel_order_id = ?
    DB-->>HO: 返回多筆記錄
    
    loop 每筆記錄
        HO->>HOI: newFromBuilder(attributes)
        HOI->>HOI: 讀取 class_name 欄位
        HOI->>HOI: class_exists() 檢查
        HOI->>HOI: is_subclass_of() 驗證
        
        alt class_name = 'HotelOrderItemGuest'
            HOI->>Guest: new HotelOrderItemGuest()
            Guest->>Guest: setRawAttributes(meta)
            Guest-->>HOI: 返回 Guest 實例
        else class_name = 'HotelOrderItemDiscount'
            HOI->>Discount: new HotelOrderItemDiscount()
            Discount->>Discount: setRawAttributes(meta)
            Discount-->>HOI: 返回 Discount 實例
        else class_name = 'HotelOrderItemAddon'
            HOI->>Addon: new HotelOrderItemAddon()
            Addon->>Addon: setRawAttributes(meta)
            Addon-->>HOI: 返回 Addon 實例
        else 其他情況
            HOI->>HOI: new HotelOrderItem()
            HOI-->>HOI: 返回基礎類別實例
        end
        
        HOI-->>HO: 返回正確類別的實例
    end
    
    HO-->>App: Collection<HotelOrderItem>
```

### 建立新項目時的類別選擇

```mermaid
flowchart TD
    Start[建立新項目] --> Choice{選擇建立方式}
    
    Choice -->|直接使用子類別| DirectCreate[HotelOrderItemGuest::create()]
    Choice -->|使用基礎類別| BaseCreate[HotelOrderItem::create()]
    
    DirectCreate --> GuestBoot[HotelOrderItemGuest::boot()]
    GuestBoot --> GuestCreating[creating 事件]
    GuestCreating --> SetType1["設定 type = 'guest'"]
    SetType1 --> SetClass1["設定 class_name = self::class"]
    SetClass1 --> Save1[儲存到資料庫]
    
    BaseCreate --> CheckType{檢查 type 欄位}
    CheckType -->|有指定 type| BaseBoot[HotelOrderItem::boot()]
    CheckType -->|無 type| Default[使用基礎類別]
    
    BaseBoot --> BaseCreating[creating 事件]
    BaseCreating --> SetClass2["設定 class_name = self::class"]
    SetClass2 --> Save2[儲存到資料庫]
    
    Default --> Save3[儲存到資料庫]
    
    Save1 --> End[完成]
    Save2 --> End
    Save3 --> End
    
    style DirectCreate fill:#e1f5ff
    style BaseCreate fill:#fff4e1
    style GuestBoot fill:#e1f5ff
    style BaseBoot fill:#fff4e1
```

### 類別擴展機制

```mermaid
graph TB
    subgraph Existing["現有類別"]
        E1["HotelOrderItem<br/>(基礎類別)"]
        E2["HotelOrderItemGuest"]
        E3["HotelOrderItemDiscount"]
        E4["HotelOrderItemAddon"]
    end
    
    subgraph NewClass["新增類別範例"]
        N1["HotelOrderItemCustom<br/>(新類別)"]
        N2["extends HotelOrderItem"]
        N3["boot() 設定<br/>type = 'custom'<br/>class_name = self::class"]
        N4["定義專屬的<br/>Accessor/Mutator"]
    end
    
    subgraph Auto["自動機制"]
        A1["newFromBuilder()<br/>自動識別 class_name"]
        A2["動態實例化<br/>對應類別"]
        A3["無需修改<br/>基礎類別"]
    end
    
    E1 --> E2
    E1 --> E3
    E1 --> E4
    E1 --> N1
    
    N1 --> N2
    N2 --> N3
    N3 --> N4
    
    N1 --> A1
    A1 --> A2
    A2 --> A3
    
    style E1 fill:#f0f0f0
    style N1 fill:#e8f5e9
    style A3 fill:#fff4e1
```

## 📋 資料結構說明

### hotel_order_items 表結構

| 欄位 | 類型 | 說明 |
|------|------|------|
| id | bigint | 主鍵 |
| hotel_order_id | uuid | 住宿訂單ID（外鍵） |
| type | string | 項目類型：guest, discount, addon |
| class_name | string | 完整類別命名空間 |
| meta | json | 類型特定資料（JSON格式） |
| note | text | 備註 |

### meta 欄位結構（依類型不同）

#### Guest 類型 (HotelOrderItemGuest)
```json
{
  "room_id": 123,
  "date": "2026-01-15",
  "pet_id": [1, 2, 3],
  "guest_name": "張三"
}
```

#### Discount 類型 (HotelOrderItemDiscount)
```json
{
  "discount_type": "fixed",
  "title": "會員折扣",
  "discount_amount": -500.00,
  "discount_value": null,
  "coupon_id": "coupon-uuid",
  "level_id": "level-uuid"
}
```

#### Addon 類型 (HotelOrderItemAddon)
```json
{
  "addon_price_id": "price-uuid",
  "addon_price": 300.00,
  "addon_qty": 2,
  "title": "加購服務"
}
```

## 🎯 設計特點

### 1. Single Table Inheritance (STI)
- 所有類型的訂單項目共用同一張表
- 透過 `class_name` 欄位動態實例化對應的類別
- 類型特定資料統一儲存在 `meta` JSON 欄位

### 2. 動態類別載入
- 不需要維護 `typeMap` 靜態陣列
- 新增類型時只需建立新的子類別
- 類別資訊直接記錄在資料庫中

### 3. Accessor/Mutator 模式
- 子類別透過 accessor/mutator 存取 `meta` 中的資料
- 使用方式與一般屬性相同
- 自動處理資料轉換（如日期轉 Carbon）

### 4. 擴展性
- 新增類型時不需要修改基礎類別
- 只需建立新的子類別並設定 `class_name`
- 系統會自動識別並使用新類型

## 📝 使用範例

### 建立預約項目
```php
$guestItem = HotelOrderItemGuest::create([
    'hotel_order_id' => $orderId,
    'room_id' => $roomId,        // 自動儲存到 meta['room_id']
    'date' => '2026-01-15',      // 自動儲存到 meta['date']
    'pet_id' => [1, 2, 3],       // 自動儲存到 meta['pet_id']
    'guest_name' => '張三',       // 自動儲存到 meta['guest_name']
]);
// class_name 會自動設定為 HotelOrderItemGuest::class
```

### 查詢並自動實例化
```php
$items = HotelOrder::find($orderId)->items;
// $items[0] 會根據 class_name 自動實例化為對應的類別
// 例如：HotelOrderItemGuest, HotelOrderItemDiscount, HotelOrderItemAddon
```

### 存取 meta 資料
```php
$guestItem = HotelOrderItemGuest::find($id);
echo $guestItem->room_id;      // 從 meta['room_id'] 讀取
echo $guestItem->date;         // 從 meta['date'] 讀取，自動轉為 Carbon
$room = $guestItem->room;      // 取得房間物件
$pets = $guestItem->pets;      // 取得寵物集合
```

## 🔍 查詢優化

### 索引設計
- `hotel_order_id`: 快速查詢訂單的所有項目
- `type`: 依類型篩選項目
- `class_name`: 依類別名稱查詢

### 注意事項
- `meta` 欄位為 JSON 類型，無法直接在資料庫層面建立索引
- 如需依 `meta` 中的欄位查詢，建議在應用層面處理
- 或使用 MySQL 5.7+ 的 JSON 函數建立虛擬欄位索引

