# ระบบกะงานหมุนเวียน (Work Shift Rotation System)

**วันที่จัดทำ:** 8 พฤษภาคม 2026  
**สถานะ:** Spec ฉบับรวม (ระบบเดิม + Database Design + Logic + Export Excel)  
**Scope:** Master Setup + Pattern + Export Excel เท่านั้น (ไม่รวม Calendar View / Override / วันหยุด)

---

## 1. ภาพรวมระบบเดิม (As-Is)

### 1.1 ระบบกะงานเดิม

ระบบเดิมมีแค่ **กะงานแบบตายตัว** (Fixed Shift) โดย:
- มีตาราง `ms_work_shift` เก็บข้อมูลกะ (ชื่อกะ + เวลาเริ่ม/สิ้นสุด)
- พนักงานแต่ละคนถูก map กับ `work_shift_id` ตัวเดียว
- ระบบแสดงกะของพนักงานจาก `work_shift_id` ตรงๆ ไม่มีการหมุน

### 1.2 ข้อจำกัดของระบบเดิม

- ไม่รองรับกะหมุนเวียน (Rotating Shift)
- ไม่สามารถแสดงได้ว่า "วันนี้พนักงานคนนี้ทำกะอะไรจริงๆ"
- ไม่รองรับการแบ่งกลุ่มพนักงานตามความสามารถในการทำกะ
- ไม่มีการ Export ตารางกะเป็น Excel

---

## 2. Requirement ใหม่: ระบบกะหมุนเวียน

### 2.1 การแบ่งกลุ่มพนักงาน (Work Group)

พนักงาน (ช่าง) ถูกแบ่งเป็น **6 กลุ่ม** ตามความสามารถ:

| กลุ่ม | ความสามารถ | ลักษณะการทำงาน |
|---|---|---|
| **C** | ทำได้แค่กะปกติ (จันทร์-ศุกร์) | กะปกติตลอด **ไม่หมุน** |
| **A** | ทำได้กะเช้า+บ่าย | หมุนสลับกับ B ทุกสัปดาห์ |
| **B** | ทำได้กะเช้า+บ่าย | หมุนสลับกับ A ทุกสัปดาห์ |
| **X** | ทำได้ทุกกะ (เช้า/บ่าย/ดึก) | หมุนสลับกับ Y, Z ทุกสัปดาห์ |
| **Y** | ทำได้ทุกกะ (เช้า/บ่าย/ดึก) | หมุนสลับกับ X, Z ทุกสัปดาห์ |
| **Z** | ทำได้ทุกกะ (เช้า/บ่าย/ดึก) | หมุนสลับกับ X, Y ทุกสัปดาห์ |

### 2.2 กะเวลา (Shift)

| shift_code | shift_name | start_time | end_time | หมายเหตุ |
|---|---|---|---|---|
| NORMAL | ปกติ | 08:00 | 17:00 | กลุ่ม C ทำงานปกติ จันทร์-ศุกร์ |
| MORNING | เช้า | 06:00 | 14:30 | 8.5 ชม. |
| AFTERNOON | บ่าย | 14:30 | 23:00 | 8.5 ชม. |
| NIGHT | ดึก | 23:00 | 06:00 | 7 ชม. ข้ามวัน |

### 2.3 ตารางการหมุน (Rotation Pattern) — รอบ 6 สัปดาห์

| สัปดาห์ | กะปกติ | กะเช้า | กะบ่าย | กะดึก |
|---|---|---|---|---|
| 1 | C | A + X | B + Y | Z |
| 2 | C | B + Y | A + Z | X |
| 3 | C | A + Z | B + X | Y |
| 4 | C | B + X | A + Y | Z |
| 5 | C | A + Y | B + Z | X |
| 6 | C | B + Z | A + X | Y |

**วิธีอ่าน:** สัปดาห์ที่ 1 → กลุ่ม A และกลุ่ม X ทำกะเช้า, กลุ่ม B และกลุ่ม Y ทำกะบ่าย, กลุ่ม Z ทำกะดึก  
หลังจบสัปดาห์ที่ 6 จะวนกลับไปเริ่มสัปดาห์ที่ 1 ใหม่

**หลักการสำคัญ:** ในฐานข้อมูล **ไม่เก็บ AX, BY, AZ เป็น string รวม** แต่แยกเป็นราย group (A และ X เป็น 2 rows) แล้ว aggregate ตอนแสดงผล

---

## 3. Database Design

### 3.1 ตาราง ms_shift — Master กะเวลา

```sql
CREATE TABLE public.ms_shift (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    shift_code varchar(20) NOT NULL,
    shift_name varchar(100) NOT NULL,
    start_ts time NULL,
    end_ts time NULL,
    seq int4 DEFAULT 0,
    is_active bool DEFAULT true NOT NULL,
    is_deleted bool DEFAULT false NOT NULL,
    created_date timestamptz DEFAULT now() NOT NULL,
    updated_date timestamptz DEFAULT now() NOT NULL,
    CONSTRAINT ms_shift_pk PRIMARY KEY (id)
);
```

### 3.2 ตาราง ms_work_group — Master กลุ่มพนักงาน

```sql
CREATE TABLE public.ms_work_group (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    group_code varchar(10) NOT NULL,
    group_name varchar(100) NOT NULL,
    is_active bool DEFAULT true NOT NULL,
    is_deleted bool DEFAULT false NOT NULL,
    created_date timestamptz DEFAULT now() NOT NULL,
    updated_date timestamptz DEFAULT now() NOT NULL,
    CONSTRAINT ms_work_group_pk PRIMARY KEY (id)
);
```

### 3.3 ตาราง ms_employee — เพิ่ม work_group_id

```sql
ALTER TABLE public.ms_employee ADD COLUMN work_group_id uuid;
ALTER TABLE public.ms_employee ADD CONSTRAINT fk_employee_group 
    FOREIGN KEY (work_group_id) REFERENCES public.ms_work_group(id);
```

### 3.4 ตาราง ms_shift_pattern — Pattern หลัก

```sql
CREATE TABLE public.ms_shift_pattern (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    pattern_code varchar(50) NOT NULL,
    pattern_name varchar(200) NOT NULL,
    cycle_days int4 NOT NULL,              -- จำนวนวันของ pattern ทั้งหมด (42)
    anchor_date date NOT NULL,             -- วันเริ่มรอบจริง
    is_active bool DEFAULT true NOT NULL,
    is_deleted bool DEFAULT false NOT NULL,
    created_date timestamptz DEFAULT now() NOT NULL,
    updated_date timestamptz DEFAULT now() NOT NULL,
    CONSTRAINT ms_shift_pattern_pk PRIMARY KEY (id)
);
```

### 3.5 ตาราง ms_shift_pattern_week_detail — รายละเอียด Pattern รายสัปดาห์

```sql
CREATE TABLE public.ms_shift_pattern_week_detail (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    pattern_id uuid NOT NULL,
    week_no int4 NOT NULL,
    shift_id uuid NOT NULL,
    work_group_id uuid NOT NULL,
    is_active bool DEFAULT true NOT NULL,
    is_deleted bool DEFAULT false NOT NULL,
    created_date timestamptz DEFAULT now() NOT NULL,
    updated_date timestamptz DEFAULT now() NOT NULL,
    CONSTRAINT ms_shift_pattern_week_detail_pk PRIMARY KEY (id),
    CONSTRAINT fk_week_detail_pattern FOREIGN KEY (pattern_id) REFERENCES public.ms_shift_pattern(id),
    CONSTRAINT fk_week_detail_shift FOREIGN KEY (shift_id) REFERENCES public.ms_shift(id),
    CONSTRAINT fk_week_detail_group FOREIGN KEY (work_group_id) REFERENCES public.ms_work_group(id)
);
```

**ตัวอย่างข้อมูล Week 1:**

| week_no | shift | group |
|---|---|---|
| 1 | NORMAL | C |
| 1 | MORNING | A |
| 1 | MORNING | X |
| 1 | AFTERNOON | B |
| 1 | AFTERNOON | Y |
| 1 | NIGHT | Z |

---

## 4. Logic การคำนวณรอบหมุน

### 4.1 คำนวณ week_no จากวันที่

```
week_no = floor(((work_date - anchor_date) % cycle_days) / 7) + 1
```

เมื่อ `cycle_days = 42` จะได้ week_no วิ่ง 1-6

### 4.2 ดึง pattern ของวันที่ที่ต้องการ

```sql
SELECT 
    d.week_no,
    s.shift_code,
    s.shift_name,
    s.seq,
    STRING_AGG(g.group_code, '' ORDER BY g.group_code) AS display_text
FROM ms_shift_pattern_week_detail d
JOIN ms_shift s ON s.id = d.shift_id
JOIN ms_work_group g ON g.id = d.work_group_id
WHERE d.pattern_id = :pattern_id
  AND d.week_no = :calculated_week_no
  AND d.is_active = true
  AND d.is_deleted = false
GROUP BY d.week_no, s.shift_code, s.shift_name, s.seq
ORDER BY s.seq;
```

---

## 5. Relationship Diagram

```
ms_shift 1 ──── * ms_shift_pattern_week_detail
ms_work_group 1 ──── * ms_shift_pattern_week_detail
ms_shift_pattern 1 ──── * ms_shift_pattern_week_detail

ms_work_group 1 ──── * ms_employee
```

---

## 6. Export Excel (ตารางกะเป็นสีๆ เหมือน EGM ของลูกค้า)

### 6.1 ภาพรวม

ฟีเจอร์ Export ตารางกะจากระบบเป็นไฟล์ Excel (.xlsx) โดยรูปแบบอ้างอิงจากไฟล์ `EGM_ตารางกะ ธ.ค.2025-มี.ค.2027.xlsx` ของลูกค้า

### 6.2 แหล่งข้อมูลสำหรับ Export

ข้อมูลที่ใช้ generate Excel มาจาก:

| ตาราง | ข้อมูลที่ดึง |
|---|---|
| `ms_shift_pattern` | anchor_date, cycle_days → คำนวณ week_no |
| `ms_shift_pattern_week_detail` | week_no, shift_id, work_group_id → pattern แต่ละสัปดาห์ |
| `ms_shift` | shift_code, shift_name, seq → ชื่อกะ + ลำดับ |
| `ms_work_group` | group_code → ชื่อกลุ่ม |

### 6.3 รูปแบบ Excel (อ้างอิงจากไฟล์ EGM — Sheet 103ki)

**Layout:** แต่ละเดือนใช้ 5 คอลัมน์ เรียงแนวนอน

```
│ Col 1-5 = เดือนที่ 1 │ Col 6-10 = เดือนที่ 2 │ Col 11-15 = เดือนที่ 3 │ ...
```

**โครงสร้างแต่ละกลุ่ม 5 คอลัมน์:**

| คอลัมน์ | เนื้อหา |
|---|---|
| 1 (วันที่) | เลขวันที่ (1, 2, 3, ..., 31) |
| 2 (ปกติ) | กลุ่มที่ทำกะปกติ (C) |
| 3 (เช้า) | กลุ่มที่ทำกะเช้า (เช่น BX, AY) |
| 4 (บ่าย) | กลุ่มที่ทำกะบ่าย (เช่น AY, BZ) |
| 5 (ดึก) | กลุ่มที่ทำกะดึก (เช่น Z, X, Y) |

**Header (Row 1):**

| Row | เนื้อหา |
|---|---|
| 1 | "ตารางกะการทำงานของพนักงาน บริษัท ไทยฮอนด้า จำกัด" (merge cells ทั้งแถว, พื้นน้ำเงินเข้ม, ตัวอักษรขาว Bold) |

**Data (Row 2+):** ตารางปฏิทินเลย — แต่ละเดือนใช้ 5 คอลัมน์เรียงแนวนอน

### 6.4 ตัวอย่างข้อมูลใน Cell

| วันที่ | ปกติ | เช้า | บ่าย | ดึก |
|---|---|---|---|---|
| 1 | C | BX | AY | Z |
| 2 | C | BX | AY | Z |
| 3 | C | BX | AY | Z |
| 4 | C | BX | AY | Z |
| 5 | C | AY | BZ | X |
| 6 | C | AY | BZ | X |
| 7 | C | AY | BZ | X |

### 6.5 สีพื้นหลัง — แยกตามสัปดาห์ในรอบหมุน (W1-W6)

สีใช้แยกตาม **สัปดาห์ในรอบหมุน** เพื่อให้เห็นชัดว่าวันไหนอยู่ในรอบเดียวกัน ทุก cell ในสัปดาห์เดียวกันจะใช้สีเดียวกันทั้งแถว

| สัปดาห์ | สีพื้นหลัง | Hex (ประมาณ) | ลักษณะ |
|---|---|---|---|
| W1 | ฟ้าอ่อน | #BDD7EE | ฟ้าพาสเทล |
| W2 | เขียวอ่อน | #C6EFCE | เขียวมิ้นท์ |
| W3 | เหลืองอ่อน | #FFFF99 | เหลืองพาสเทล |
| W4 | ม่วงอ่อน | #E2BFEE | ม่วงลาเวนเดอร์ |
| W5 | ชมพูอ่อน | #FFC7CE | ชมพูพาสเทล |
| W6 | ส้มอ่อน | #FFD966 | ส้มพาสเทล |

**หลักการ:** สีสลับทุก 7 วัน ทำให้แยกรอบหมุนได้ง่ายด้วยตา

> หมายเหตุ: สี Hex เป็นค่าประมาณ — ให้ Dev ดูจากไฟล์ EGM ต้นฉบับเป็นหลัก

### 6.6 Logic การ Generate Excel

```
1. ดึง ms_shift_pattern (anchor_date, cycle_days)
2. ดึง ms_shift_pattern_week_detail ทั้งหมดของ pattern นั้น
3. Aggregate group_code ตาม week_no + shift
4. สำหรับแต่ละวันใน date range ที่ต้องการ:
   a. คำนวณ week_no = floor(((วันนั้น - anchor_date) % cycle_days) / 7) + 1
   b. ดึง display_text ของ week_no นั้น (NORMAL, MORNING, AFTERNOON, NIGHT)
   c. เขียนลง cell พร้อมสีพื้นหลังตาม week_no
5. Save เป็นไฟล์ .xlsx
```

### 6.7 Date Range ของ Export

**Default:** export ตั้งแต่ anchor_date ไปจนจบปี (ของ anchor_date) แล้วบวกเพิ่มอีก 3 เดือน

```
start_date = anchor_date
end_date = สิ้นเดือนที่ 3 ของปีถัดไป (จากปีของ anchor_date)
```

**สูตร:**
```
anchor_year = ปีของ anchor_date
end_date = 31 มีนาคม ของ (anchor_year + 1)
```

**ตัวอย่าง:**
- anchor_date = 1 ธ.ค. 2025 → ปีของ anchor = 2025 → จบปี 2025 = 31 ธ.ค. 2025 → บวก 3 เดือน → **export ถึง 31 มี.ค. 2026**
- anchor_date = 1 มิ.ย. 2026 → ปีของ anchor = 2026 → จบปี 2026 = 31 ธ.ค. 2026 → บวก 3 เดือน → **export ถึง 31 มี.ค. 2027**

**เหตุผล:** แสดงกะงานที่เหลือของปีที่เป็น anchor date + ล่วงหน้าอีก 3 เดือนของปีถัดไป เพื่อวางแผนได้สะดวก

### 6.8 Export Options (UI)

| Option | Type | ค่าเริ่มต้น |
|---|---|---|
| Pattern | Dropdown | pattern ที่ active |
| วันเริ่มต้น | Date picker | anchor_date |
| วันสิ้นสุด | Date picker | 31 มี.ค. ของปีถัดจาก anchor_year |
| Production Line | Text | (ว่าง) |

### 6.9 API สำหรับ Export

```
POST /api/shift-pattern/export
Content-Type: application/json

{
  "pattern_id": "uuid",
  "start_date": "2025-12-01",
  "end_date": "2027-03-31",
  "production_line": "102KI"
}

Response:
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Content-Disposition: attachment; filename="ตารางกะ_102KI_ธค2568-มีค2570.xlsx"
```

### 6.10 การจัดรูปแบบ Excel

- **Font:** ขนาด 10-11, Tahoma หรือ TH Sarabun New
- **Header:** Bold, พื้นเทาอ่อน
- **Alignment:** Center ทุก cell
- **Border:** เส้นบางรอบทุก cell
- **Column width:** auto-fit (~5-8 ต่อคอลัมน์)

---

## 7. สรุป Table ทั้งหมดที่ใช้

| Table | ประเภท | หน้าที่ |
|---|---|---|
| `ms_shift` | Master | เก็บ master กะเวลา (NORMAL, MORNING, AFTERNOON, NIGHT) |
| `ms_work_group` | Master | เก็บ master กลุ่ม A/B/C/X/Y/Z |
| `ms_employee` | Master | เก็บพนักงาน + ผูกกับ work_group_id |
| `ms_shift_pattern` | Master | เก็บหัว pattern (cycle_days, anchor_date) |
| `ms_shift_pattern_week_detail` | Master | เก็บรายละเอียด pattern รายสัปดาห์ แยก group เป็นราย row |

---

## 8. สรุปสิ่งที่ Dev ต้องทำ

### 8.1 Database

| # | งาน | รายละเอียด |
|---|---|---|
| 1 | สร้างตาราง ms_shift | Master กะเวลา (NORMAL, MORNING, AFTERNOON, NIGHT) |
| 2 | สร้างตาราง ms_work_group | Master กลุ่ม (A, B, C, X, Y, Z) |
| 3 | แก้ตาราง ms_employee | เพิ่ม work_group_id |
| 4 | สร้างตาราง ms_shift_pattern | Pattern หลัก (cycle_days, anchor_date) |
| 5 | สร้างตาราง ms_shift_pattern_week_detail | รายละเอียด pattern รายสัปดาห์ |
| 6 | Insert master data | กะเวลา + กลุ่ม + pattern 6 สัปดาห์ |

### 8.2 Backend / API

| # | งาน | รายละเอียด |
|---|---|---|
| 7 | Logic คำนวณ week_no | จาก anchor_date + cycle_days |
| 8 | API POST /shift-pattern/export | Export Excel |
| 9 | CRUD API สำหรับ ms_shift | จัดการ master กะเวลา |
| 10 | CRUD API สำหรับ ms_work_group | จัดการ master กลุ่ม |
| 11 | CRUD API สำหรับ ms_shift_pattern + detail | จัดการ pattern |

### 8.3 Frontend / UI

| # | งาน | รายละเอียด |
|---|---|---|
| 12 | หน้า Work Shift Setup | CRUD กะเวลา |
| 13 | หน้า Work Group Setup | CRUD กลุ่มพนักงาน |
| 14 | หน้า Shift Pattern Setup | Header + Detail grid (week_no × shift × group) |
| 15 | แก้หน้า Employee | เพิ่ม dropdown เลือก Work Group |
| 16 | Export Excel | ปุ่ม export + dialog เลือก options + generate .xlsx |

---

## 9. Key Decisions

| หัวข้อ | Decision |
|---|---|
| Pattern storage | เก็บรายสัปดาห์ (ไม่ใช่รายวัน) เพราะ 1 สัปดาห์ pattern เหมือนกันทุกวัน |
| Group storage | แยกเป็นราย row (ไม่เก็บ AX, BY เป็น string รวม) |
| Export สี | แยกสีตามสัปดาห์ในรอบหมุน (W1-W6 คนละสี) |
| Export format | อ้างอิง layout จากไฟล์ EGM ลูกค้า (เดือนเรียงแนวนอน) |
| Display aggregation | aggregate group เป็น AX/BY/AZ ตอนแสดงผลและ export |
| rotation_cycle_days | ตัดออก ใช้แค่ cycle_days ตัวเดียว |

---

## 10. แหล่งอ้างอิง

- ไฟล์ Excel ลูกค้า: `EGM_ตารางกะ ธ.ค.2025-มี.ค.2027.xlsx`
- ไฟล์รูป: `shift rotation.png`
- ไฟล์ Logic: `shift_rotation_logic_summary.md`
