Giao diện
US-D13: Flow P2 — DTTH rời lớp, A rời / B nhận (story SAPP US-05 phase 2) ​
Thuộc FS: 00-overview.md — SAPP-26878 · Tạo dữ liệu test doanh thu (Ops → HubSpot → SAP) 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.
Mode B – As-built tại commit
e77c47a· nguồn Fact: inventory 26878 §3.3 (A-123). Khung stepper → US-D01 · lịch sử / log SAP → US-D02 · loại bước → US-D03.U01:x= bước x của luồng US-01 ở US-D09 §4a. Khối 8 bước học viên = như US-D12 BR-03.⚠ "US-05" ở đây là story phase 2 (chip id
us05-p2), khác "US-05 · Gia hạn / Bảo lưu" phase 1 (US-D05).
| Field | Value |
|---|---|
| US ID | US-D13 |
| Role thực hiện | Người dùng tool — Assumption (OQ về G-01 · inventory Q-05 — xem 00-overview §6) |
| Phase | Phase 2 của SAPP-26878 (DTTH) · chip US-05 · DTTH rời lớp (id us05-p2) |
| Priority | N/A — as-built, đã triển khai (backlog R2: không xếp Priority) |
| Status | Draft |
| NFR liên quan | NFR-P-01 (quyền, FS nền tảng) · NFR của 26878 — xem 00-overview §5 |
| OQ liên quan | OQ-D-07, OQ-D-06, OQ-D-13, OQ-D-15 — xem 00-overview §6 · DR-D-06 — xem 00-overview §6b |
1. US Statement ​
text
As a Người dùng tool (Assumption — OQ về G-01)
I want dựng một lớp có hai học viên, cho học viên A được ghi nhận vài buổi, rồi chuyển nhượng suất học
của A cho B trong cùng lớp và đọc kết quả
So that kiểm được rằng khi học viên rời lớp, phần doanh thu đã ghi cho họ bị đảo bằng một dòng sổ cái
mới mang số âm, ngay trong ngày, và cặp (Deal + môn) của người rời ngừng được xử lý- Nguồn "So that":
shared/runbooks/sapp/sapp-26878/phase-2/us-05/README.md:6("Học viên rời lớp thì phần doanh thu đã ghi cho họ bị đảo bằng một dòng sổ cái MỚI mang số âm"); chuyển nhượng không có lớp đích —shared/external/sapp/sapp-26878/README.md:184; hint luồngsapp-26878-flows.ts:4874. Tiêu chí nghiệm thu của tool:[Assumption](OQ-D-13).
2. Dependencies & Definition Of Ready ​
N/A — đã triển khai (Mode B). Dependency runtime như US-D09 §2. Thêm (hint): ngày khai giảng lớp phải trước hôm nay, trong [go-live, hôm qua] (dev từ 2026-09-14, staging từ 2026-09-17) (sapp-26878-flows.ts:4599,4881).
3. Business Rules ​
| ID | Rule | Áp dụng ở | Đã cover bởi (AC) | Nguồn code (Mode B/C) |
|---|---|---|---|---|
| BR-01 | Luồng có 30 bước chia hai hàng (A: 1–17, B: 18–30) theo thứ tự ở §4a; không có bước trả lại mã lớp | M1 | AC-M1.1 | fe/src/ui/components/works/sapp/sapp-26878-flows.ts:4876-4906 |
| BR-02 | Luồng có hai Deal: học viên A "người RỜI lớp", học viên B "người NHẬN suất", cùng bộ property Deal phase 2 của US-01, vai contact khác nhau; mỗi học viên đi qua khối 8 bước học viên | M1 - A9…A16, A18…A25 | AC-M1.2 | sapp-26878-flows.ts:4514-4530,4897-4900 |
| BR-03 | "Kéo hai buổi về quá khứ": người dùng nhập một ngày và hai id lịch; câu ghi cập nhật ngày bắt đầu và kết thúc của hai buổi đầu, các buổi còn lại giữ nguyên | M1 - A6 | AC-M1.3 | sapp-26878-flows.ts:4550-4605 |
| BR-04 | Sau khối 8 bước của A có một lượt quét (U01:16) để dựng nền ghi nhận cho A, trước khi B bắt đầu | M1 - A17 | AC-M1.1 | sapp-26878-flows.ts:4898-4899 |
| BR-05 | "Đọc học viên trong lớp" đọc danh sách học viên của lớp trên Ops và điền sẵn id người dùng của hai dòng đầu vào hai ô của bước chuyển nhượng (thứ tự không đảm bảo) | M1 - A26 | AC-M1.4 | sapp-26878-flows.ts:4615-4627 |
| BR-06 | "Chuyển nhượng suất học" gửi đúng hai trường người rời / người nhận (id người dùng), trong cùng lớp; cả hai bắt buộc | M1 - A27 | AC-M1.4 | sapp-26878-flows.ts:4635-4661 |
| BR-07 | Đọc kết quả lọc log SAP theo mã lớp, tự chạy 7 kiểm chứng (§M2), luôn coi là xong; panel SQL có 4 câu đọc và 2 câu ghi (đổi loại ghi danh để dựng nhãn "bảo lưu" / "chuyển đổi") | M2 | AC-M2.1 → AC-M2.8 | sapp-26878-flows.ts:4670-4802 |
| BR-08 | "Quét lại sau khi đảo" là một lượt quét thủ công; "Kiểm dừng xử lý" là bước đọc không có kiểm chứng tự động, lọc theo mã lớp, kèm 1 câu đọc và 1 câu ghi dựng lại ca (xóa dòng đảo → trả loại ghi danh về bình thường → xóa lượt chạy sự kiện rời lớp, theo đúng thứ tự trong một lệnh) | M1 - A29, M2 - A30 | AC-M1.5, AC-M2.9 | sapp-26878-flows.ts:4812-4858 |
| BR-09 | Mọi câu SQL ghi không tự chạy và phải qua hộp xác nhận | M1 - A6, M2 | AC-M1.3, AC-M2.9 | fe/src/ui/components/works/sapp/sapp-26878-step-sql.tsx:200-213 |
4. Design ​
a. Mối liên hệ giữa các màn & User Flow ​
text
[Chip "US-05 · DTTH rời lớp", portal Dev | Staging]
↓
[M1 · hàng A] U01:1 → U01:2 → U01:3 (sửa ngày khai giảng) → U01:5 → U01:4 → Kéo hai buổi về quá khứ
→ U01:6 → U01:7 → 8 bước học viên A → U01:16 (nền của A)
↓
[M1 · hàng B] 8 bước học viên B → Đọc học viên trong lớp → Chuyển nhượng suất học
↓
[M2] Đọc kết quả → (M1) Quét lại sau khi đảo → (M2) Kiểm dừng xử lýBảng bước (Fact: sapp-26878-flows.ts:4876-4906).
| # | Tên bước | Loại | Tái dùng | Ghi gì (hệ thống · môi trường) | Điều kiện chuyển (xong) |
|---|---|---|---|---|---|
| 1 | Kiểm tra kết nối Ops | ops + sql | U01:1 | Không ghi | Ping thành công |
| 2 | Đếm lớp của môn | ops | U01:2 | Không ghi | Gọi thành công |
| 3 | Tạo lớp | ops + sql | U01:3 (đổi hint started_at) | Ops dev/staging | Gọi thành công |
| 4 | Gán phòng học | ops | U01:5 | Ops | Gọi thành công |
| 5 | Tạo buổi học | ops | U01:4 | Ops | Gọi thành công |
| 6 | Kéo hai buổi về quá khứ | guide + sql | riêng | Ops DB: us05.backdate.2 cập nhật ngày 2 buổi | Bấm "Đã kéo ngày xong" |
| 7 | Mở lớp (PUBLIC) | ops | U01:6 | Ops | Gọi thành công |
| 8 | Thêm option mã lớp | option | U01:7 | HubSpot dev (staging: bỏ qua) | Đủ 3 property / bỏ qua |
| 9–16 | 8 bước học viên A (Tạo Deal … Hoàn thiện hồ sơ) | deal / classcode / ops / stage | tương đương U01:8 → U01:15, trên Deal A | HubSpot (⚠️ portal prod khi Staging) + Ops; Redis run history | Như U01:8 → U01:15 |
| 17 | Chạy lượt quét | scan | U01:16 | SAP service dev/staging | Gọi thành công |
| 18–25 | 8 bước học viên B | như 9–16 | tương đương U01:8 → U01:15, trên Deal B | Như 9–16 | Như 9–16 |
| 26 | Đọc học viên trong lớp | ops | riêng | Không ghi (đọc Ops) → bag class_user_0, class_user_1 | Gọi thành công |
| 27 | Chuyển nhượng suất học | ops | riêng | Ops: chuyển nhượng trong lớp (theo hint: bắn sự kiện rời lớp, bút toán âm chạy ngay) | Gọi thành công |
| 28 | Đọc kết quả | trace + sql | riêng | Không ghi, trừ câu SQL ⑤ ⑥ (Ops DB) nếu người dùng chạy | Luôn xong |
| 29 | Quét lại sau khi đảo | scan | riêng | SAP service | Gọi thành công |
| 30 | Kiểm dừng xử lý | trace + sql | riêng | Không ghi, trừ câu SQL ② (Ops DB) nếu chạy | Luôn xong |
⚠️ Ghi PROD — trên Staging, các bước Deal / Gán mã lớp / chuyển stage của hai học viên (9, 10, 12, 15, 16, 18, 19, 21, 24, 25) ghi HubSpot portal production.
Tình trạng nghiệm thu gần nhất (nguồn ngoài code, chưa kiểm chứng ở R3): runbook ghi ✅ 7/7 trên dev 2026-09-18, lớp F103.216 (shared/runbooks/sapp/sapp-26878/phase-2/us-05/README.md:3-4) và một lượt trọn vẹn trên staging 2026-09-22 (.../phase-2/staging/README.md §6g).
b. Chi tiết từng màn ​
Màn M1 - Chuỗi bước dựng dữ liệu và kích hoạt (bước 1–27, 29) ​
| Field | Value |
|---|---|
| Figma frame | N/A — as-built, không có Figma |
| Trigger vào màn | Chọn chip US-05 · DTTH rời lớp (inventory E-07) |
| Mô tả ngắn | Hai hàng "Học viên A · người RỜI lớp" / "Học viên B · người NHẬN suất". |
UI States ​
| State | Khi nào | Hiển thị | Figma frame |
|---|---|---|---|
| Default | Sitting mới | Hai hàng bước; bước 1 mở (→ US-D01) | N/A |
| Loading | Đang gọi hệ ngoài / SQL | Nút chạy ở trạng thái xử lý | N/A |
| Has data | Bước 26 xong | Response đầy đủ + hai id điền sẵn vào bước 27 | N/A |
| Empty | Staging, pool mã lớp rỗng | Như US-D09 EC-M1.2 | N/A |
| Error | Ops từ chối chuyển nhượng | Lỗi Ops (vd theo hint: học viên không ở trạng thái NORMAL) | N/A |
| Disabled | Bước khóa; bước 8 trên Staging | Như US-D09 | N/A |
Fields ​
Chỉ field riêng (Nguồn sapp-26878-flows.ts:4550-4661).
| Field | Required | Type | Default | Format | Validation | Error Message | Visibility | Depends On |
|---|---|---|---|---|---|---|---|---|
B3 · started_at | Yes | Datetime ISO | 00:00 hôm nay giờ VN | ISO | Hint: sửa về go-live; ngày rời lớp phải sau ngày khai giảng | — | Always | — |
| B6 · Ngày kéo về (quá khứ) | — | Date | — | YYYY-MM-DD | Hint: sau khai giảng, ≤ hôm nay, ≥ go-live | — | Always | — |
B6 · schedule_1, schedule_2 | — | Text | — (nhập tay từ câu ①) | id lịch | Hint: cột schedule_id | — | Always | Câu ① |
B27 · transfer_from (người RỜI) | Yes | Text | bag class_user_0 | id người dùng | BR-06 | Lỗi Ops | Always | Bước 26 |
B27 · transfer_to (người NHẬN) | Yes | Text | bag class_user_1 | id người dùng | BR-06 | Lỗi Ops | Always | Bước 26 |
Actions ​
A6 - Kéo hai buổi về quá khứ (bước 6) ​
| Item | Description |
|---|---|
| Trigger | Chạy câu ①, nhập ngày + 2 id, chạy câu ② (xác nhận), chạy câu ③, bấm "Đã kéo ngày xong" |
| Behavior | Ghi Ops DB dev/staging (BR-03, BR-09). Guide: kéo đúng hai buổi; kéo hết thì lớp bị chốt sổ và ca hỏng. |
| Success Result | Đúng hai buổi ở quá khứ, phần còn lại ở tương lai |
Error cases:
| Case | Expected Handling |
|---|---|
Nhập nhầm cột id | Theo ghi chú: không cập nhật dòng nào, không báo lỗi |
A26–A27 - Đọc học viên · Chuyển nhượng suất học (bước 26–27) ​
| Item | Description |
|---|---|
| Trigger | Bấm chạy bước 26; kiểm lại hai ô rồi bấm chạy bước 27 |
| Behavior | Bước 26 đọc học viên của lớp (BR-05). Bước 27 gọi chuyển nhượng trên Ops dev/staging (BR-06). Hint: phải đối chiếu tên/email trong "Phản hồi đầy đủ" để chắc ai là người rời — đặt ngược là đảo nhầm học viên, không có lỗi. |
| Success Result | Chuyển nhượng thành công; không có lượt quét nào cần bấm cho bút toán âm |
Error cases:
| Case | Expected Handling |
|---|---|
| Hai ô bị điền ngược thứ tự | Tool không phát hiện; bút toán âm rơi vào nhầm người |
Học viên không ở trạng thái NORMAL | Ops trả lỗi (hint sapp-26878-flows.ts:4622) |
A29 - Quét lại sau khi đảo (bước 29) ​
| Item | Description |
|---|---|
| Trigger | Bấm chạy |
| Behavior | Lượt quét thủ công (→ US-P05) để chứng minh cặp (Deal + môn) của người rời không sinh thêm dòng (BR-08). |
| Success Result | Lượt quét vào hàng đợi |
Error cases:
| Case | Expected Handling |
|---|---|
| Bấm ngay sau lượt trước | Theo hint: 429, đợi rồi bấm lại |
Acceptance Criteria của màn M1 ​
AC-M1.1 - Chuỗi 30 bước, hai hàng ​
gherkin
Given một sitting mới của luồng US-05 phase 2
When người dùng xem stepper
Then thấy hàng A (bước 1–17, kết thúc bằng "Chạy lượt quét") và hàng B (bước 18–30) theo §4a
And không có bước "Trả lại mã lớp"Maps to:
- Business Rule: BR-01, BR-04
AC-M1.2 - Hai Deal ​
gherkin
When đi hết khối học viên A và B
Then có hai Deal riêng (tên chứa "US-05 Rời lớp · Học viên A" và "… Học viên B")Maps to:
- Business Rule: BR-02
AC-M1.3 - Kéo hai buổi đầu ​
gherkin
Given đã nhập ngày và hai schedule_id
When chạy câu ② và xác nhận
Then ngày bắt đầu và kết thúc của đúng hai buổi đó đổi sang ngày đã chọnMaps to:
- Business Rule: BR-03, BR-09
AC-M1.4 - Chuyển nhượng trong cùng lớp ​
gherkin
Given bước 26 trả về danh sách học viên của lớp
When mở bước 27
Then transfer_from = user_id của dòng thứ nhất, transfer_to = user_id của dòng thứ hai, cả hai sửa được
When bấm chạy
Then Ops nhận yêu cầu chuyển nhượng chỉ gồm hai trường đó trên lớp của luồngMaps to:
- Business Rule: BR-05, BR-06
AC-M1.5 - Quét lại ​
gherkin
Given bước 28 đã đọc xong
When bấm chạy bước 29
Then một lượt quét thủ công được bắn; bước 30 mởMaps to:
- Business Rule: BR-08
Negative AC / Edge Cases của màn M1 ​
| ID | Tình huống | Hành vi mong đợi |
|---|---|---|
| EC-M1.1 | ⚠️ Observed — chạy luồng trên Staging | Luồng không có bước "Trả lại mã lớp" (chỉ US-01 có), trong khi runbook staging §0.1 và lượt §6g ghi mọi lượt đều trả mã. Mỗi lượt giữ vĩnh viễn một mã của pool staging; cạn pool → bước Tạo lớp của mọi luồng phase 2 bị chặn. OQ-D-07 · DR-D-06 — xem 00-overview §6 / §6b |
| EC-M1.2 | ⚠️ Observed (OQ-D-18) — guide bước 6 ghi "⚠ Chỉ làm trên dev" | Bước không bị khóa trên Staging; runbook §6g ghi đã chạy trên staging. Đề xuất OQ — điều phối viên cấp mã |
| EC-M1.3 | ⚠️ Observed — "Dùng deal có sẵn" cho Deal A hoặc B | Mọi bước còn lại thuộc deal đó bị đánh dấu xong — OQ-D-06 |
Màn M2 - Bước 28 "Đọc kết quả" và bước 30 "Kiểm dừng xử lý" ​
| Field | Value |
|---|---|
| Figma frame | N/A — as-built, không có Figma |
| Trigger vào màn | Mở bước 28 / bước 30 |
| Mô tả ngắn | Hai bước đọc cùng lọc theo mã lớp (→ US-P05); bước 28 có 7 kiểm chứng, bước 30 không có kiểm chứng tự động. |
UI States ​
| State | Khi nào | Hiển thị | Figma frame |
|---|---|---|---|
| Default | Mở bước | Hint + mã lớp + trace tự chạy + panel SQL (us05.trace / us05.stop) | N/A |
| Loading | Đang tra | Trace đang tải | N/A |
| Has data | Có trail | Bước 28: kết quả 7 kiểm chứng. Bước 30: chỉ trail | N/A |
| Empty | Chưa có dòng đảo | Kiểm chứng 1 fail kèm giải thích các lý do skipped | N/A |
| Error | Trace / SQL lỗi | → US-P05 / US-P09 | N/A |
| Disabled | N/A | N/A | N/A |
Fields ​
| Field | Required | Type | Default | Format | Validation | Error Message | Visibility | Depends On |
|---|---|---|---|---|---|---|---|---|
B28 · Mã sản phẩm SAP (item_code) | — | Text | — | — | chỉ cần cho câu ② | — | Always | Câu ① |
B28 / B30 · id bản ghi ghi danh (class_user_id) | — | Text | — | id | Hint: id bản ghi ghi danh, không phải id người dùng | — | Always | Câu ① |
Actions ​
A28 - Đọc kết quả (bước 28) ​
| Item | Description |
|---|---|
| Trigger | Mở bước (tự chạy); chạy tay SQL |
| Behavior | Trace theo mã lớp + 7 kiểm chứng (BR-07). SQL ①–④ chỉ đọc (sổ cái deal người rời, giờ lũy kế, lượt EVENT_LEAVE, dấu vết sự kiện rời lớp trong log). ⑤ ⑥ ghi Ops DB: đổi loại ghi danh sang RESERVED / MOVED_OUT để dựng hai nhãn lý do còn lại (sau đó người dùng tự gọi gửi lại dòng — ngoài bước này). |
| Success Result | Bước luôn xong |
Error cases:
| Case | Expected Handling |
|---|---|
| Không đọc được trường | Kiểm chứng = unknown |
A30 - Kiểm dừng xử lý (bước 30) ​
| Item | Description |
|---|---|
| Trigger | Mở bước (tự chạy); chạy tay SQL |
| Behavior | Trace theo mã lớp, không có kiểm chứng tự động — theo code, bước chứng minh một điều phủ định nên người dùng so tay (BR-08). SQL ① đọc 5 dòng sổ cái gần nhất của deal người rời; ② ghi Ops DB để dựng lại ca. |
| Success Result | Bước luôn xong |
Error cases:
| Case | Expected Handling |
|---|---|
| Trả loại ghi danh về bình thường mà chưa xóa dòng đảo (chạy tay ngoài câu ②) | Theo ghi chú: lượt quét sau gửi mail ERR-01 thật cho kế toán — câu ② gói đúng thứ tự để tránh việc này |
Acceptance Criteria của màn M2 ​
AC-M2.1 → AC-M2.7 = kiểm chứng tự chấm của bước 28 (sapp-26878-flows.ts:4670-4731).
AC-M2.1 - Có bút toán âm khi rời lớp ​
gherkin
When chạy kiểm chứng "Có bút toán âm khi rời lớp"
Then pass khi có ít nhất một dòng sổ cái mang entry_type = LEAVE_REVERSALMaps to:
- Business Rule: BR-07
AC-M2.2 - Payload mang recognition_type = LEAVE_REVERSAL ​
gherkin
When chạy kiểm chứng tương ứng
Then pass khi phần tử cuối của payload có recognition_type = LEAVE_REVERSALMaps to:
- Business Rule: BR-07
AC-M2.3 - Đảo gửi accumulated_hours ​
gherkin
When chạy kiểm chứng "Đảo gửi accumulated_hours"
Then pass khi phần tử cuối của payload CÓ accumulated_hoursMaps to:
- Business Rule: BR-07
AC-M2.4 - Đảo gửi standard_hours_remaining ​
gherkin
When chạy kiểm chứng "Đảo gửi standard_hours_remaining"
Then pass khi phần tử cuối của payload CÓ standard_hours_remainingMaps to:
- Business Rule: BR-07
AC-M2.5 - Đảo KHÔNG gửi lesson_hours ​
gherkin
When chạy kiểm chứng "Đảo KHÔNG gửi lesson_hours"
Then pass khi phần tử cuối của payload KHÔNG có lesson_hoursMaps to:
- Business Rule: BR-07
AC-M2.6 - document_date = u_lesson_date ​
gherkin
When chạy kiểm chứng "document_date = u_lesson_date"
Then pass khi ở phần tử cuối, hai trường ngày này bằng nhauMaps to:
- Business Rule: BR-07
AC-M2.7 - document_date = posting_date ​
gherkin
When chạy kiểm chứng "document_date = posting_date"
Then pass khi ở phần tử cuối, hai trường ngày này bằng nhauMaps to:
- Business Rule: BR-07
AC-M2.8 - Bước đọc không chặn ​
gherkin
Given một kiểm chứng fail hoặc unknown
Then bước 28 vẫn "xong" và bước 29 mởMaps to:
- Business Rule: BR-07
AC-M2.9 - Dựng lại ca rời lớp ​
gherkin
Given người dùng muốn chạy lại ca
When chạy câu ② của bước 30 và xác nhận
Then trong một lệnh: dòng LEAVE_REVERSAL của deal người rời bị xóa, loại ghi danh trở về NORMAL, các lượt EVENT_LEAVE bị xóa — theo đúng thứ tự đóMaps to:
- Business Rule: BR-08, BR-09
Negative AC / Edge Cases của màn M2 ​
| ID | Tình huống | Hành vi mong đợi |
|---|---|---|
| EC-M2.1 | Nhãn lý do trong remarks | Theo hint: phải so khớp toàn chuỗi bằng tay (Giảm trừ doanh thu thực hiện chuyển nhượng <Deal ID>_<Tên lớp>); không có kiểm chứng tự động |
| EC-M2.2 | Bước 30 — không có dòng mới | Người dùng tự so với ảnh chụp ở bước 28; tool không tự kết luận — OQ-D-15 |
| EC-M2.3 | ⚠️ Observed (OQ-D-19) — câu ② bước 30 xóa mọi lượt EVENT_LEAVE của môi trường | Hành vi hiện tại: câu xóa lượt chạy không lọc theo lớp (sapp-26878-flows.ts:4853) — trên môi trường dùng chung có thể xóa cả lượt của người khác. Đề xuất OQ "cố ý hay bug?" — điều phối viên cấp mã |
5. Cross-feature AC ​
AC-X.1 - Khối 8 bước học viên dùng chung với US-04 ​
gherkin
Given khối 8 bước học viên thay đổi
When mở luồng US-04
Then luồng đó dùng cùng khối bước (US-D12 bước 10–17 / 20–27)Maps to:
- Liên quan nội bộ FS 26878 (không có mã REL) (US-D09, US-D12)