# Phân Hệ Quản Lý Phúc Khảo (Web Exam Regrading)
## 02. Quy Tắc Nghiệp Vụ & Logic Chi Tiết (Business Logic & Rules)

---

### 1. Phân Định Lượt Chấm Phúc Khảo (`assign_type = 2`)

Toàn bộ các truy vấn và nghiệp vụ trong phân hệ **Quản lý phúc khảo** (`web_exam_regrading`) được lọc chặt chẽ theo cờ:

$$\text{WHERE } tah.assign\_type = 2$$

Đồng thời, để tránh trùng lặp dòng khi một bài thi có nhiều lượt gán phúc khảo lịch sử, hệ thống áp dụng kỹ thuật **lấy bản ghi phân công mới nhất**:

```sql
WHERE tah.id = (
    SELECT MAX(tah2.id) 
    FROM teacher_assigned_histories as tah2 
    WHERE tah2.student_score_id = ss.id 
      AND tah2.assign_type = 2
)
```

---

### 2. Logic Reset Điểm Khi Kích Hoạt Phúc Khảo (Unbiased Re-grading)

Quy trình phúc khảo được thiết kế nhằm đảm bảo **tính khách quan và công bằng tuyệt đối**:
- **Điểm trước Phúc khảo (`scoreBeforePk`)**: Là snapshot điểm số do Giáo viên chấm lần 1 (`assign_type = 1`) hoàn thành trước đó. Điểm này được lưu trữ để phục vụ đối soát, so sánh chênh lệch.
- **Cơ chế Reset về điểm gốc**: Khi bài thi được chuyển sang trạng thái phúc khảo để QA chấm, điểm bài thi trên giao diện chấm của QA sẽ **trở về điểm gốc ban đầu (Raw Score / Baseline)** chứ không kế thừa điểm số mà GV1 đã chấm (Tránh việc QA bị định kiến hoặc ảnh hưởng bởi đánh giá của giáo viên trước).
- **Điểm sau Phúc khảo (`scoreAfterPk`)**: Là kết quả đánh giá độc lập cuối cùng của cán bộ QA (`assign_type = 2`).

---

### 3. Logic Trích Xuất & So Sánh Điểm Trước vs Sau Phúc Khảo

Hệ thống truy vấn tập trung lịch sử từ `StudentScoreGradingHistory` và bóc tách qua `IclScoreService::parseEmsSnapshot`:

```mermaid
flowchart LR
    GradingHist[(StudentScoreGradingHistory)] --> Filter1[assign_type = 1 -> Lấy bản ghi cuối]
    GradingHist --> Filter2[assign_type = 2 -> Lấy bản ghi cuối]
    
    Filter1 --> Parse1[IclScoreService::parseEmsSnapshot]
    Filter2 --> Parse2[IclScoreService::parseEmsSnapshot]
    
    Parse1 --> ScoreBefore["scoreBeforePk (Điểm GV1)"]
    Parse2 --> ScoreAfter["scoreAfterPk (Điểm QA)"]
```

- **`scoreBeforePk`**:
  ```php
  $beforeRecord = $scoreLogs->where('assign_type', 1)->last();
  $item->scoreBeforePk = $iclScoreService->parseEmsSnapshot($beforeRecord);
  ```
- **`scoreAfterPk`**:
  ```php
  $afterRecord = $scoreLogs->where('assign_type', 2)->last();
  $item->scoreAfterPk = $iclScoreService->parseEmsSnapshot($afterRecord);
  ```

---

### 4. Logic Bóc Tách Báo Cáo Gian Lận Cho Hội Đồng Phúc Khảo

Trong quá trình phúc khảo, nếu bài thi bị gắn cờ `cheating_status = 1`, hệ thống tự động bóc tách chi tiết vi phạm từ `data_rescored` của từng giáo viên/kỹ năng để QA có đầy đủ chứng cứ:

1. **Kỹ năng Writing**: Bóc tách mảng `cheating_reports` (lấy `question_id`, `task_number`, `type`, `reason`).
2. **Kỹ năng Speaking**: Bóc tách object `cheating_report` (lấy `type`, `reason`).
3. **Cờ tổng hợp (`has_cheating`)**:
   $$item.\text{has\_cheating} = (item.\text{cheating\_status} == 1) \lor (\text{count}(item.\text{cheating\_reports}) > 0)$$

---

### 5. Logic Chốt Điểm Chính Thức & Đồng Bộ Sang Zeus

1. Khi QA hoàn thành bài chấm phúc khảo và bấm **Lưu kết quả**:
   - Hệ thống tính toán lại điểm Overall Band Score của bài thi theo thuật toán làm tròn chuẩn IELTS.
   - Cập nhật `student_score`:
     - Điểm kỹ năng mới được ghi nhận vào `student_score`.
     - `score_processing_status = 1` (Hoàn tất).
     - `manual_grading_status = 1` (Đã hoàn thành phúc khảo).
2. Tự động kích hoạt `IclScoreService::syncScoreToIcl` để cập nhật điểm chính thức sau phúc khảo sang hệ thống Zeus / ICL.
