Giao diện
US-S04: Hủy chuyển nhượng (luồng 2) ​
Thuộc FS: 00-overview.md — SAPP-26297 Chuyển nhượng học viên (tool
sapp.011) Phần chung (tổng quan, roles, flow tổng, related features, NFR, Open Questions, References) xem ở Overview. File này chỉ chứa nội dung riêng của US.Cơ chế chạy bước, tự chấm, xác nhận GHI → US-S01. Câu SQL → US-S02 §4. "Kỳ vọng" là văn bản tool hiển thị theo guide QA — nghiệp vụ hủy do SAPP Ops cài.
| Field | Value |
|---|---|
| US ID | US-S04 |
| Role thực hiện | R1 - Người dùng tool — Assumption (OQ về G-01 → OQ-S-01) |
| Phase | As-built (đã triển khai @ e77c47a) |
| Priority | N/A — as-built |
| Status | Draft |
| NFR liên quan | NFR-S-01, NFR-S-02 — xem Overview §5 |
| OQ liên quan | OQ-S-01, OQ-S-12, OQ-S-14 — xem Overview §6 |
1. US Statement ​
text
As a Người dùng tool [Assumption — OQ-S-01]
I want chạy 9 case của luồng 2: đọc dữ liệu popup hủy, hủy chuyển nhượng A→B, chuyển nhượng lại,
và các trường hợp biên (hủy hai lần, lớp nhận / người nhận đã bị xoá, người nhận đã học, lớp đi kèm đã bị bảo lưu)
So that kiểm được AC10, AC12 của SAPP-26297 trên dev/staging
(nguồn phạm vi: tóm tắt luồng trên màn; mục tiêu nghiệp vụ rộng hơn là [Assumption] — OQ-S-18)2. Dependencies & Definition Of Ready ​
N/A — đã triển khai. Dependency runtime:
| # | Cần sẵn sàng | Ai cung cấp | Trạng thái |
|---|---|---|---|
| D1 | Tiền đề: case 1.A (US-S03) đã chạy, A→B đang chuyển nhượng | Tester | — |
3. Business Rules ​
| ID | Rule | Áp dụng ở | Đã cover bởi (AC) | Nguồn code (Mode B/C) |
|---|---|---|---|---|
| BR-01 | Bước hủy gửi lớp = L1 và học viên = người CHO (mặc định A) trên đường dẫn, không có body; bước đọc bản ghi dùng cùng cặp giá trị | M1 - bước hủy, đọc bản ghi | AC-M1.1 → AC-M1.5 | fe/src/ui/components/works/sapp/sapp-26297-flows.ts:405-434 |
| BR-02 | Case 2.A bước đọc bản ghi đạt khi HTTP 200 và có đủ: mã bản ghi, thời điểm chuyển nhượng, người thực hiện, người cho = A, người nhận = B, lớp nhận, tiến độ người nhận | M1 - case 2.A | AC-M1.1 | sapp-26297-flows.ts:879-896 |
| BR-03 | Case 2.A sau hủy đạt khi "Cập nhật thành công"; tại L1 A có lại nút chuyển nhượng và không còn nút hủy; tại L2 B không có nút hủy. Verify DB (A, B về NORMAL, bản ghi REVERTED không bị xoá) là câu SQL f2v tester đọc | M1 - case 2.A | AC-M1.1 | sapp-26297-flows.ts:897-922,482-491 |
| BR-04 | Case 2.B chuyển nhượng lại đạt khi "Cập nhật thành công"; ghi chú: vẫn 1 dòng lịch sử là đúng (bản ghi cũ được tái dùng) | M1 - case 2.B | AC-M1.2 | sapp-26297-flows.ts:924-933 |
| BR-05 | Hủy lần hai (2.1) đạt khi "Từ chối đúng" 400|100337 · exceptions.transfer_record_not_found | M1 - case 2.1 | AC-M1.3 | sapp-26297-flows.ts:935-942 |
| BR-06 | Đọc bản ghi khi không còn hiệu lực (2.2) hoặc với học viên = người nhận B (2.3) đạt khi HTTP 200 và data = null (không phải 404) | M1 - case 2.2, 2.3 | AC-M1.4 | sapp-26297-flows.ts:944-965 |
| BR-07 | Hủy vẫn thành công phía A khi lớp nhận L2 bị xoá mềm (2.4), B bị xoá khỏi L2 (2.5), B đã học tại L2 (2.6, kèm check tiến độ người nhận có giá trị), hoặc F1 của A đã bị bảo lưu (2.7) — dựng bằng SQL GHI, chấm "Cập nhật thành công" | M1 - case 2.4 → 2.7 | AC-M1.5 | sapp-26297-flows.ts:967-1027 |
4. Design ​
a. Mối liên hệ giữa các màn & User Flow ​
text
[Tab "2 · Hủy chuyển nhượng"] (tiền đề: 1.A đã chạy)
↓ 2.A
[đọc bản ghi (đọc)] → [hủy (GHI Ops)] → [SQL verify f2v] → [cờ nút L1, L2 (đọc)]
↓ 2.B
[chuyển nhượng lại (GHI Ops)] → [SQL verify f1v]
Trạng thái kỳ vọng phía Ops:
A@L1: TRANSFERED_TO --hủy--> NORMAL (status tính lại theo tiến độ); lớp đi kèm đã bị nghiệp vụ khác đổi thì GIỮ NGUYÊN
Lịch sử A→B: TRANSFERRED --hủy--> REVERTED --chuyển nhượng lại--> TRANSFERRED (tái dùng bản ghi, vẫn 1 dòng)b. Chi tiết từng màn ​
Màn M1 - Tab "2 · Hủy chuyển nhượng" ​
| Field | Value |
|---|---|
| Figma frame | N/A |
| Trigger vào màn | Bấm tab "2 · Hủy chuyển nhượng" |
| Mô tả ngắn | Tóm tắt: "AC10, AC12. Tiền đề: luồng 1 happy path đã chạy, A→B đang chuyển nhượng. Hủy KHÔNG phải revert sạch: lớp đã bị nghiệp vụ khác đổi trạng thái sẽ được bỏ qua có chủ đích." 9 case |
UI States ​
| State | Khi nào | Hiển thị | Figma frame |
|---|---|---|---|
| Default | Vào tab | Tóm tắt + 9 case đóng | N/A |
| Loading | Bước đang chạy | Theo US-S01 | N/A |
| Has data | Bước chạy xong | ✓/✗ + "x/y đạt"; case 2.7 có khung cảnh báo "Case dễ báo nhầm bug nhất…" | N/A |
| Empty | N/A | — | N/A |
| Error | Không gọi được Ops | Hộp đỏ 13042 | N/A |
| Disabled | Fixture thiếu L1 / A | Nút khoá "Chưa điền: …" | N/A |
Fields ​
| Field | Required | Type | Default | Format | Validation | Error Message | Visibility | Depends On |
|---|---|---|---|---|---|---|---|---|
class_id (đường dẫn) | Yes | Text | {class_id_l1} | id Ops | US-S01 BR-10 | "Chưa điền: …" | Bước hủy, đọc bản ghi | Fixture |
student_id (người CHO) | Yes | Text | {user_a} (2.3: {user_b}) | id Ops | US-S01 BR-10 | "Chưa điền: …" | Bước hủy, đọc bản ghi | Fixture |
| Field chuyển nhượng (2.B) | — | — | Như US-S03 | — | — | — | Bước chuyển nhượng | Fixture |
Actions ​
A1 - Chạy các bước của một case ​
| Item | Description |
|---|---|
| Trigger | Mở case, chạy từng bước (US-S01) |
| Behavior | Thao tác dùng: đọc bản ghi (đọc), hủy chuyển nhượng (GHI), chuyển nhượng (GHI, 2.B), danh sách học viên (đọc); SQL f1v, f2v, c24, c25, c26, c36. Ghi vào: Ops dev/staging và DB Ops dev/staging. Không có đường PROD |
| Success Result | Các check đạt theo bảng case |
Error cases:
| Case | Expected Handling |
|---|---|
| Ops từ chối ngoài kỳ vọng | Check ✗ + giá trị thực |
| Không gọi được Ops | Hộp đỏ 13042 |
Bảng case (9 case):
| Mã case | Tên | Bước | Kỳ vọng tool chấm |
|---|---|---|---|
| 2.A | Happy path: popup → hủy → verify | đọc bản ghi · hủy (GHI) · SQL f2v · học viên L1 · học viên L2 | BR-02, BR-03 |
| 2.B | Chuyển nhượng lại A→B sau khi hủy (AC12) | chuyển nhượng (GHI) · SQL f1v · hướng dẫn | Cập nhật thành công; vẫn 1 dòng lịch sử (đọc SQL) |
| 2.1 | Hủy hai lần liên tiếp | hủy · hủy | Lần 1 thành công; lần 2 400|100337 transfer_record_not_found |
| 2.2 | Đọc bản ghi khi không còn hiệu lực | đọc bản ghi | HTTP 200 + data = null |
| 2.3 | Đọc bản ghi với học viên = B | đọc bản ghi (student = B) | HTTP 200 + data = null |
| 2.4 | Lớp nhận L2 đã bị xoá | hướng dẫn · SQL c24 (GHI xoá mềm / khôi phục) · hủy | Cập nhật thành công |
| 2.5 | B đã bị xoá khỏi L2 | hướng dẫn · SQL c25 (GHI) · hủy | Cập nhật thành công |
| 2.6 | B đã học tại L2 | hướng dẫn · SQL c26 (GHI 1/10) · đọc bản ghi · hủy · SQL f2v | Tiến độ người nhận có giá trị · Cập nhật thành công · tiến độ B giữ (đọc SQL) |
| 2.7 | F1 của A bị bảo lưu sau chuyển nhượng | hướng dẫn · SQL c36 (GHI) · hủy · SQL f2v | Cập nhật thành công; F1 giữ RESERVED, chỉ L1 về NORMAL (đọc SQL) |
Acceptance Criteria của màn M1 ​
AC-M1.1 - Case 2.A happy path ​
gherkin
Given A→B đang chuyển nhượng (1.A đã chạy)
When người dùng chạy bước "Bước 1 — Dữ liệu popup hủy"
Then HTTP 200 và data.record_id, data.transferred_at, data.performed_by, data.transfer_to_class,
data.transfer_to_progress có giá trị; data.transfer_from.user_id = A; data.transfer_to.user_id = B
When người dùng chạy "Bước 2 — Hủy chuyển nhượng" và xác nhận GHI
Then HTTP 200, success = true, data.message = "Update successfully"
And tại L1: A can_transfer = true, can_revert_transfer = false
And tại L2: B can_revert_transfer = falseMaps to:
- Business Rule: BR-01, BR-02, BR-03
AC-M1.2 - Chuyển nhượng lại ​
gherkin
Given A→B đã bị hủy (2.A)
When người dùng chạy bước "Chuyển nhượng lại"
Then "Cập nhật thành công" đạt
And câu SQL đếm bản ghi A→B cho đúng 1 dòng (tester đọc)Maps to:
- Business Rule: BR-04
AC-M1.3 - Hủy hai lần ​
gherkin
Given A→B đang chuyển nhượng
When người dùng chạy "Hủy lần 1" rồi "Hủy lần 2"
Then lần 1 "Cập nhật thành công"
And lần 2 HTTP 400, error.code = "400|100337", error.message = "exceptions.transfer_record_not_found"Maps to:
- Business Rule: BR-05
AC-M1.4 - Không có bản ghi hiệu lực ​
gherkin
Scenario Outline: data null
Given <điều kiện>
When người dùng chạy bước đọc bản ghi với student_id = <học viên>
Then HTTP 200 và data = null
Examples:
| case | điều kiện | học viên |
| 2.2 | A→B đã bị hủy | A |
| 2.3 | A→B đang hiệu lực | B |Maps to:
- Business Rule: BR-06
AC-M1.5 - Hủy vẫn thành công trong tình huống biên ​
gherkin
Scenario Outline: hủy thành công phía A
Given A→B đang chuyển nhượng và đã chạy <dựng>
When người dùng chạy bước hủy
Then HTTP 200, success = true, data.message = "Update successfully"
Examples:
| case | dựng |
| 2.4 | SQL c24 câu 1: xoá mềm L2 (khôi phục bằng câu 2 sau khi test) |
| 2.5 | SQL c25 câu 1: xoá mềm B khỏi L2 (khôi phục bằng câu 2) |
| 2.6 | SQL c26: B tại L2 tiến độ 1/10; bước đọc bản ghi có data.transfer_to_progress |
| 2.7 | SQL c36: A tại F1 → RESERVED |Maps to:
- Business Rule: BR-07
Negative AC / Edge Cases của màn M1 ​
| ID | Tình huống | Hành vi mong đợi |
|---|---|---|
| EC-M1.1 | Chạy 2.x khi chưa có A→B hiệu lực | Ops trả từ chối (vd 100337); check ✗ — hướng dẫn tiền đề trong case yêu cầu chạy lại luồng 1 bước 2 |
| EC-M1.2 | Quên khôi phục L2 / B sau 2.4, 2.5 | Tool không tự khôi phục — câu khôi phục là câu 2 của panel, tester tự chạy |
| EC-M1.3 | 2.7 thấy F1 vẫn RESERVED | Đó là kỳ vọng (highlight: "BE bỏ qua F1 có chủ đích") — không phải lỗi |
| EC-M1.4 | Truyền student_id = người nhận khi hủy | Xem US-S07 case 3.19 |
5. Cross-feature AC ​
AC-X.1 - Phụ thuộc luồng 1 ​
gherkin
Given case 1.A (US-S03) chưa chạy trên môi trường đang chọn
When người dùng chạy case 2.A
Then bước đọc bản ghi trả data = null và các check field ✗Maps to:
- REL-07 (Affects - Hệ thống SAPP)