# Mục 1.4.8 — Nhập cấu trúc hồ sơ từ file Excel (UC??)

> ⚠️ **Mã UC chưa được chốt** (2026-08-14). Đã biết: 1.4.1 = UC22, 1.4.2 = UC23, 1.4.6 = UC25;
> 1.4.4, 1.4.5, 1.4.7 và 1.4.8 chưa có xác nhận của QA. Tạm ghi `UC??` trong tên test và dùng prefix
> dữ liệu `AT-1.4.8-<mã case>-<ts>`. Khi QA chốt: sửa tên test + prefix ở
> [`1.4.8.setup.ts`](./1.4.8.setup.ts) và bảng danh sách case bên dưới.

> 📌 **PHẠM VI FILE NÀY — CHỈ TIỀN ĐIỀU KIỆN CHUNG CỦA CẢ BỘ CASE.**
>
> Được ghi ở đây: nguyên văn tiền điều kiện QA, cách đọc nó, bảng "vai → cách script dựng dữ liệu",
> dữ liệu mà setup tạo ra, danh sách case của mục.
>
> **KHÔNG** ghi ở đây: thao tác/kỳ vọng của từng case, cách assert, giả định khi viết case, điểm cần
> QA/DEV chốt, bảng hàm dùng chung. Những thứ đó là **logic của case** → mô tả trong khối comment đầu
> file `1.4.8.<mã case>.spec.ts` của chính case đó (hàm dùng chung thì tự mô tả bằng JSDoc trong
> [`1.4.8.steps.ts`](./1.4.8.steps.ts) / `KHO-TAI-LIEU.functions.ts`).

> **Đọc file này trước khi viết bất kỳ case nào của mục 1.4.8.**
>
> Tài liệu màn hình: `src/screen-instructions/KHO-TAI-LIEU.md` (+ mục **4.4** — toolbar & menu
> `btn-more` của tab Cấu trúc hồ sơ, nơi có mục `mni-nhap-tu-excel`).
> Quy ước đặt tên & cấu trúc: `CLAUDE.md`. Fixture/TIMEOUT/PW: `tests/README.md`.

---

## 1. Tiền điều kiện chung của mục 1.4.8

Chưa có bản **nguyên văn QA** cho toàn mục — hiện chỉ có phần thao tác của từng case do người dùng
gửi. Bản dưới đây suy ra từ mục 1.4.2 / 1.4.7 (cùng màn, cùng nhóm vai, cùng đối tượng là thư mục /
tài liệu trong Cấu trúc hồ sơ); **thay bằng nguyên văn khi QA gửi**:

- Thủ thư / ITAdmin / Người dùng được phân quyền **tạo mới bộ hồ sơ**: BHS ở trạng thái
  **"Khai báo"** hoặc **"Đang hoạt động"**.
- Người dùng / Nhóm được phân quyền **Owner / Tạo mới** của Bộ hồ sơ: BHS **"Đang hoạt động"**.

Cách đọc tiền điều kiện: xem `CLAUDE.md` mục "Đọc tiền điều kiện của testcase QA" — vai QA ghi là
có quyền thì **mặc định làm được** tới bước Mong muốn; quyền **cấp lớn bao trùm cấp nhỏ**.

### 🚨 Ràng buộc bắt buộc khi dựng dữ liệu

1. **BHS dùng để nhập excel phải rỗng**: có sẵn thư mục/tài liệu thì không tách được item nào do
   thao tác nhập excel sinh ra → mỗi case tự tạo BHS mới (`dungBoHoSoNhapExcel`).
2. **Vai không phải người tạo BHS chỉ mở được BHS ở trạng thái "Hoạt động"**
   (`KHO-TAI-LIEU.PHAN-QUYEN-THEO-VAI.md` mục 1) → case nào để vai khác nhập excel thì phải
   `chuyenHoatDong` trước.
3. **`recordUrl` của BHS phải lưu ngay sau khi tạo** (`KHO-TAI-LIEU.md` mục 9.3) — `createBoHoSo`
   đã trả về sẵn, luôn mở lại BHS bằng biến này.
4. **File Excel mẫu để ở `src/template-files/`** (khác `src/sample-files/` — chỗ đó là file mềm để
   upload vào tab "Tài liệu số"); lấy đường dẫn bằng `templateFile(TEMPLATE_FILE.*)`.

### 🚨 Chưa khảo sát: modal "Nhập excel"

Bộ case này viết theo yêu cầu **"chỉ viết script, không chạy MCP khảo sát"** (2026-08-14). Trong
luồng nhập excel, phần **đã khảo sát** chỉ gồm: `btn-more` của bảng Cấu trúc hồ sơ và mục menu
`mni-nhap-tu-excel` (`KHO-TAI-LIEU.md` mục 4.4). **Toàn bộ modal "Nhập excel"** (ô chọn file, bảng
xem trước, nút "Tiếp theo" / "Cập nhật", modal xác nhận có nút "Tiếp tục", nội dung toast) **chưa có testId khảo sát** — hàm
`nhapCauTrucTuExcel` tạm bám `input[type="file"]` + **nhãn nút**.

→ Chạy thật mà hỏng: khảo sát bằng `/khao-sat-man-hinh`, thay bằng testId thật rồi bổ sung mô tả
modal vào tài liệu màn hình. **Đừng** vá bằng selector đoán thêm.

### ✅ Đã kiểm chứng trên DOM thật (trace lần chạy 2026-08-14 10:49, sitdev)

| Điểm                     | Kết quả đo được                                                                                                                                                                                                                                                                                                                        |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Modal sau nút "Cập nhật" | Có thật, phải bấm **"Tiếp tục"**; không bấm thì luồng dừng và **không có toast**                                                                                                                                                                                                                                                       |
| Toast kết quả            | `.ant-message-notice` > `.ant-message-custom-content.ant-message-success` > `span` = **`"Tạo mới thành công!"`**; toast AntD tự tắt sau **~3 s** (mặc định `.ant-message`, **chưa đo trực tiếp**) — đúng bằng `TIMEOUT.CONTROL_LOADING` mà bản cũ chờ cứng sau click → phải `rinhToast` **trước** khi bấm "Cập nhật", không assert sau |
| Bộ đếm ở header tab      | **KHÔNG có** `Thư mục: n` / `Tài liệu: m` trên build này (khác `KHO-TAI-LIEU.md` mục 4.4)                                                                                                                                                                                                                                              |
| Cây trong bảng Cấu trúc  | **Không** expand sẵn hết: chỉ hiện `A`, `A.1`, `A.2`, `A.3` → phải `moRongToanBoCayCauTruc` trước khi đọc dòng                                                                                                                                                                                                                         |

---

## 2. Bảng vai → cách script dựng dữ liệu

Dựng qua `dungBoHoSoNhapExcel()` trong [`1.4.8.setup.ts`](./1.4.8.setup.ts); mỗi test **tự dựng BHS
riêng** để chạy song song được.

| Vai QA nêu                    | Fixture     | Cách dựng                                                                                              | Trạng thái BHS |
| ----------------------------- | ----------- | ------------------------------------------------------------------------------------------------------ | -------------- |
| Thủ thư                       | `librarian` | Chính nó gọi `dungBoHoSoNhapExcel` → tự tạo BHS nên là **Owner**                                       | `Khai báo`     |
| ITAdmin                       | `admin`     | Như trên                                                                                               | `Khai báo`     |
| Người dùng được **Owner** BHS | `ecm05`     | người tạo dựng + `quyenBoHoSo: { permTestId: DOC_PERM.OWNER, account: "ecm05" }`, rồi `chuyenHoatDong` | `Hoạt động`    |
| **Nhóm** được Owner / Tạo mới | `ecm06`     | như trên với `account: GROUP.ECM06` (`AUTO_GROUP_ECM06`, thành viên `ecm06`), thao tác bằng `ecm06`    | `Hoạt động`    |

### Dữ liệu `dungBoHoSoNhapExcel` tạo ra

```
BHS  AT-1.4.8-<maCase>-<ts>        (Owner = người gọi; + quyenBoHoSo nếu có) — RỖNG, chưa có TM/TL
```

### File Excel mẫu — `src/template-files/`

| Hằng                        | File              | Nội dung                                                                    |
| --------------------------- | ----------------- | --------------------------------------------------------------------------- |
| `TEMPLATE_FILE.CAU_TRUC_3A` | `template3A.xlsx` | `Sheet1`, dòng 4–23 là dữ liệu: **9 thư mục + 11 tài liệu** (cây 4 cấp `A`) |

> ⚠️ **Điểm cần chốt về `template3A.xlsx`** (2026-08-14): người dùng cho biết file này _"chỉ có thư
> mục, không có tài liệu/file"_, nhưng đọc file thì cột `type` **có 11 dòng `Tài liệu`** — `A.1.1`,
> `A.1.2.1`, `A.1.2.2`, `A.1.3.1`, `A.1.3.2`, `A.2.1`, `A.2.2.1`, `A.2.2.2`, `A.2.3.1`, `A.2.3.2`,
> `A.3.1` (đều có Số hiệu; riêng `A.3.1` **thiếu "Loại tài liệu"** — cột này file ghi là bắt buộc).
> → Hoặc app bỏ qua các dòng tài liệu khi nhập, hoặc case cần dùng template khác.
> Trong lúc chưa chốt: case **chỉ assert cứng phần thư mục**, số tài liệu khớp được **chỉ ghi log**.

Cấu trúc 3 dòng đầu của template (không phải dữ liệu): dòng 1 = tên cột kỹ thuật (`code`, `title`,
`type`…), dòng 2 = nhãn tiếng Việt, dòng 3 = hướng dẫn nhập. Đọc file bằng `docCauTrucTuTemplate`
([`1.4.8.steps.ts`](./1.4.8.steps.ts)) — sửa file không phải sửa code.

> 🚨 **File mẫu có thể chứa dòng lỗi cố ý** (phục vụ các case kiểm tra lỗi) → app bỏ qua một số dòng
> vẫn là hành vi đúng. Vì vậy **không case nào của mục được assert "bảng khớp đủ mọi dòng của file"**;
> số item đọc từ file chỉ dùng để **ghi log**.

---

## 3. Danh sách case của mục 1.4.8

| Mã  | UC   | Nội dung testcase                                                            | File                                       | Trạng thái                                                                                                                                                                                                                           |
| --- | ---- | ---------------------------------------------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 664 | UC?? | Kiểm tra nút **Cập nhật thành công khi toàn bộ dữ liệu hợp lệ** (nhập excel) | [`1.4.8.664.spec.ts`](./1.4.8.664.spec.ts) | 2 test (Thủ thư + Admin). Viết 2026-08-14. Chạy sitdev 2026-08-14: qua hết thao tác, toast `"Tạo mới thành công!"` **có**, fail do 2 assert của script sai với DOM thật (bộ đếm header + cây chưa expand) → **đã sửa, cần chạy lại** |

> Viết case mới → thêm 1 dòng vào bảng này (chỉ **nội dung testcase + file + trạng thái chạy**,
> không mô tả cách làm / kỳ vọng).
