# Module `payroll` — Lương giáo viên

> ⛔ **ĐÃ THAY THẾ (08/7):** không scaffold module này — dùng **hrm built-in (feature timesheet-dat + payroll)** (`core/hrm-builtin-2026-07-08.md`). Trang giữ làm spec nghiệp vụ tham chiếu. Xem [quan hệ module](../quan-he-module-2026-07-07.md).

> 07/7/2026 · Giai đoạn: **v1.5** · WS đào tạo · Bản HTML: [payroll.html](payroll.html) · Sơ đồ tổng thể: [../so-do-ws-module-feature-2026-07-06.md](../so-do-ws-module-feature-2026-07-06.md)
> Trạng thái: Chưa có trong code — scaffold ở v1.5.

## 1. Vai trò
Chấm công GV theo **giờ dạy thực tế từ dữ liệu DAT / phiên chip** — không khai tay; tính lương theo giờ hoặc khoán khóa.

## 2. Feature / BO / Action

| Feature | BO chính | Action |
|---|---|---|
| `timesheet` | Bảng công từ giờ dạy DAT/chip | view·edit·**generate** |
| `salary` | Bảng lương (giờ / khoán) | view·export·**generate**·**approve** |

## 3. Dữ liệu chính

| BO | Trường chính |
|---|---|
| **Bảng công** | Kỳ × GV · Σ giờ dạy thực hành (phiên DAT hợp lệ theo `ma_gv`) · giờ lý thuyết (lms) · điều chỉnh tay (có lý do + người duyệt) |
| **Bảng lương** | Kỳ × GV · đơn giá giờ / khoán khóa · phụ cấp · khấu trừ · thực lãnh · trạng thái (nháp → duyệt → **đã khóa**) |

## 4. Quy tắc nghiệp vụ
1. Nguồn giờ duy nhất = **phiên DAT hợp lệ** + buổi lms — không nhập tay số giờ
2. Điều chỉnh tay phải có lý do + người duyệt (audit)
3. Kỳ lương đã khóa không sửa — sai thì điều chỉnh kỳ sau
4. GV xem được bảng công/lương **của chính mình** (data scope)

## 5. Liên kết chéo
- **dat** — phiên hợp lệ theo GV
- **lms** — giờ dạy lý thuyết
- **teacher / hr** — hồ sơ, hợp đồng, đơn giá
- **finance** — chi lương vào sổ

## 6. Câu hỏi mở
- Công thức lương thực tế của Vĩnh An (giờ/khoán/hỗn hợp)?
- Kỳ lương theo tháng hay theo khóa?

## 7. Ma trận phân quyền (→ manifest & seed role)

### 7.1 Khai báo `permissions[]` trong `manifest.json`

```json
[
  {
    "group": "main",
    "feature": "timesheet",
    "label": "Bảng công",
    "actions": [
      "view",
      "edit",
      "generate"
    ]
  },
  {
    "group": "main",
    "feature": "salary",
    "label": "Bảng lương",
    "actions": [
      "view",
      "export",
      "generate",
      "approve"
    ]
  }
]
```

> ⚠️ Action đặc thù (`generate`) cần bổ sung vào validator manifest — xem [plan data-scope P1](../giai-doan-1-mvp/plan-data-scope-2026-07-06.md).

### 7.2 Ma trận vai trò × feature (seed `rt_role`)

| Feature | `QTHT` | `GIAM_DOC` | `KE_TOAN` | `NHAN_SU` | `GIAO_VIEN` |
|---|:--:|:--:|:--:|:--:|:--:|
| `timesheet` | R | R | W | R | R² |
| `salary` | R | R·A | W | R | R² |

> **R** xem · **W** tạo/sửa · **A** duyệt · **—** không có quyền · ¹ dữ liệu **phân công** · ² **của chính mình** · ³ **theo trạng thái** hồ sơ. Vai trò không liệt kê = không có quyền. Permission key đầy đủ: `payroll.main.<feature>.<action>`.
> Đặc thù: +generate bảng công/lương (KE_TOAN)

### 7.3 Quyền mức record (row-level)

**(a) Manifest — bổ sung `fields` + `scopeVars` vào các feature bị scope** *(mở rộng schema theo [plan data-scope P1](../giai-doan-1-mvp/plan-data-scope-2026-07-06.md) — manifest chỉ khai "cái gì scope được", KHÔNG chứa rule)*:

```json
[
  {
    "group": "main",
    "feature": "timesheet",
    "fields": [
      "giao_vien_id"
    ],
    "scopeVars": [
      "current_giao_vien_id"
    ]
  },
  {
    "group": "main",
    "feature": "salary",
    "fields": [
      "giao_vien_id"
    ],
    "scopeVars": [
      "current_giao_vien_id"
    ]
  }
]
```

**(b) Điều kiện record theo vai trò:**

| Vai trò | Feature (action) | Điều kiện record |
|---|---|---|
| `GIAO_VIEN` | timesheet, salary (view) | giao_vien_id = ctx.current_giao_vien_id (bảng công/lương của mình) |

**(c) Seed `rt_role.grants` (kind `rule` — nhiều rule cùng resource+action = OR):**

```json
[
  {
    "kind": "rule",
    "module": "payroll",
    "feature": "timesheet",
    "actions": [
      "view"
    ],
    "predicate": {
      "op": "cmp",
      "field": "giao_vien_id",
      "cmp": "=",
      "value": {
        "ctx": "current_giao_vien_id"
      }
    }
  },
  {
    "kind": "rule",
    "module": "payroll",
    "feature": "salary",
    "actions": [
      "view"
    ],
    "predicate": {
      "op": "cmp",
      "field": "giao_vien_id",
      "cmp": "=",
      "value": {
        "ctx": "current_giao_vien_id"
      }
    }
  }
]
```

> Biến ngữ cảnh: `current_user_id` — engine có sẵn · `current_giao_vien_id`/`current_ma_gv` — module teacher tra từ user đăng nhập (ctxVars, plan P3) · `current_nguoi_lxid`/`current_ma_dk_list` — module student tra (1 người nhiều lượt đăng ký) · `current_assigned_*` — danh sách phụ trách/được phân công.
