Skip to content

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.

FieldValue
US IDUS-S04
Role thực hiệnR1 - Người dùng tool — Assumption (OQ về G-01 → OQ-S-01)
PhaseAs-built (đã triển khai @ e77c47a)
PriorityN/A — as-built
StatusDraft
NFR liên quanNFR-S-01, NFR-S-02 — xem Overview §5
OQ liên quanOQ-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àngAi cung cấpTrạng thái
D1Tiền đề: case 1.A (US-S03) đã chạy, A→B đang chuyển nhượngTester—

3. Business Rules ​

IDRuleÁp dụng ởĐã cover bởi (AC)Nguồn code (Mode B/C)
BR-01Bướ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 ghiAC-M1.1 → AC-M1.5fe/src/ui/components/works/sapp/sapp-26297-flows.ts:405-434
BR-02Case 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ậnM1 - case 2.AAC-M1.1sapp-26297-flows.ts:879-896
BR-03Case 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 đọcM1 - case 2.AAC-M1.1sapp-26297-flows.ts:897-922,482-491
BR-04Case 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.BAC-M1.2sapp-26297-flows.ts:924-933
BR-05Hủy lần hai (2.1) đạt khi "Từ chối đúng" 400|100337 · exceptions.transfer_record_not_foundM1 - case 2.1AC-M1.3sapp-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.3AC-M1.4sapp-26297-flows.ts:944-965
BR-07Hủ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.7AC-M1.5sapp-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" ​

FieldValue
Figma frameN/A
Trigger vào mànBấm tab "2 · Hủy chuyển nhượng"
Mô tả ngắnTó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 ​
StateKhi nàoHiển thịFigma frame
DefaultVào tabTóm tắt + 9 case đóngN/A
LoadingBước đang chạyTheo US-S01N/A
Has dataBướ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
EmptyN/A—N/A
ErrorKhông gọi được OpsHộp đỏ 13042N/A
DisabledFixture thiếu L1 / ANút khoá "Chưa điền: …"N/A
Fields ​
FieldRequiredTypeDefaultFormatValidationError MessageVisibilityDepends On
class_id (đường dẫn)YesText{class_id_l1}id OpsUS-S01 BR-10"Chưa điền: …"Bước hủy, đọc bản ghiFixture
student_id (người CHO)YesText{user_a} (2.3: {user_b})id OpsUS-S01 BR-10"Chưa điền: …"Bước hủy, đọc bản ghiFixture
Field chuyển nhượng (2.B)——Như US-S03———Bước chuyển nhượngFixture
Actions ​
A1 - Chạy các bước của một case ​
ItemDescription
TriggerMở case, chạy từng bước (US-S01)
BehaviorThao 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 ResultCác check đạt theo bảng case

Error cases:

CaseExpected Handling
Ops từ chối ngoài kỳ vọngCheck ✗ + giá trị thực
Không gọi được OpsHộp đỏ 13042

Bảng case (9 case):

Mã caseTênBướcKỳ vọng tool chấm
2.AHappy path: popup → hủy → verifyđọc bản ghi · hủy (GHI) · SQL f2v · học viên L1 · học viên L2BR-02, BR-03
2.BChuyển nhượng lại A→B sau khi hủy (AC12)chuyển nhượng (GHI) · SQL f1v · hướng dẫnCập nhật thành công; vẫn 1 dòng lịch sử (đọc SQL)
2.1Hủy hai lần liên tiếphủy · hủyLầ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 ghiHTTP 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.4Lớp nhận L2 đã bị xoáhướng dẫn · SQL c24 (GHI xoá mềm / khôi phục) · hủyCập nhật thành công
2.5B đã bị xoá khỏi L2hướng dẫn · SQL c25 (GHI) · hủyCập nhật thành công
2.6B đã học tại L2hướng dẫn · SQL c26 (GHI 1/10) · đọc bản ghi · hủy · SQL f2vTiến độ người nhận có giá trị · Cập nhật thành công · tiến độ B giữ (đọc SQL)
2.7F1 của A bị bảo lưu sau chuyển nhượnghướng dẫn · SQL c36 (GHI) · hủy · SQL f2vCậ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 = false

Maps 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 &ZeroWidthSpace;
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 &ZeroWidthSpace;
IDTình huốngHành vi mong đợi
EC-M1.1Chạy 2.x khi chưa có A→B hiệu lựcOps 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.2Quên khôi phục L2 / B sau 2.4, 2.5Tool 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.32.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.4Truyền student_id = người nhận khi hủyXem US-S07 case 3.19

5. Cross-feature AC &ZeroWidthSpace;

AC-X.1 - Phụ thuộc luồng 1 &ZeroWidthSpace;

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)