Skip to content

US-D09: Flow P2 — DTTH theo buổi (story SAPP US-01) ​

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-100 → A-117). Khung stepper → US-D01 · lịch sử run / log SAP → US-D02 · hành vi từng loại bước → US-D03. File này không mô tả lại ba phần đó.

⭐ US này là xương sống của phase 2. 16 bước đầu (bước 1–16) được 8 luồng phase 2 còn lại (US-D10 → US-D17) dùng lại nguyên vẹn; các file đó ghi U01:x = bước x trong bảng §4a của file này.

FieldValue
US IDUS-D09
Role thực hiệnNgười dùng tool — Assumption (OQ về G-01 · inventory Q-05 — xem 00-overview §6)
PhasePhase 2 của SAPP-26878 ("Doanh thu thực hiện" – DTTH) · chip US-01 · DTTH theo buổi (id us01)
PriorityN/A — as-built, đã triển khai (backlog R2: không xếp Priority)
StatusDraft
NFR liên quanNFR-P-01 (quyền, FS nền tảng) · NFR của 26878 — xem 00-overview §5
OQ liên quanOQ-D-05, OQ-D-06, OQ-D-11, OQ-D-13, OQ-D-14, OQ-D-15, OQ-D-02 — xem 00-overview §6 · DR-D-11, 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 trọn một lượt dữ liệu test "doanh thu thực hiện theo buổi" trên dev/staging bằng 18 bước
       có sẵn: tạo lớp mới trên Ops, sinh buổi học, tạo Deal HubSpot nối với lớp qua mã lớp, tạo đơn
       hàng + giao dịch trên Ops, kéo Deal qua hai mốc Won, chạy lượt quét rồi đọc sổ cái SAP
So that kiểm được rằng mỗi buổi đã diễn ra sinh một bút toán sang SAP và số dư tài khoản 3387 của học
        viên giảm dần qua từng buổi
  • Nguồn "So that": mục đích nghiệp vụ của DTTH lấy từ shared/runbooks/sapp/sapp-26878/README.md:3-4 ("Ghi nhận doanh thu theo buổi học … mỗi buổi đã diễn ra sinh một bút toán sang SAP, và số dư tài khoản 3387 của học viên giảm dần cho tới khi lớp kết thúc"). Việc tool phục vụ ai / nghiệm thu thế nào là [Assumption] (inventory Q-05, Q-13 — BA chưa cung cấp FS gốc của story US-01).

2. Dependencies & Definition Of Ready ​

N/A — đã triển khai (Mode B).

Dependency runtime (để luồng chạy được, Fact từ code):

#Cần sẵn sàngỞ đâuTham chiếu
D1Credential Ops của môi trường (dev/staging) trong env_systemsDB mind_keepUS-P04, hint bước 1 sapp-26878-flows.ts:2830
D2Danh mục phase 2 theo môi trường (môn, khóa, cơ sở, nhân sự, sản phẩm + giá, phòng học) — chỉ dev + staging; thiếu → 501BE constantinventory R-32, be/apps/api/src/sapp/sapp.controller.ts:640-657
D3Ops passthrough + auto-loginBE → Ops APIUS-P08
D4SQL runner theo statement idBE → Ops DBUS-P09
D5Thêm option property HubSpot (chỉ dev)BE → HubSpot devUS-P07
D6Manual scan + trace log SAPBE → SAP serviceUS-P05

3. Business Rules ​

IDRuleÁp dụng ởĐã cover bởi (AC)Nguồn code (Mode B/C)
BR-01Luồng chỉ chạy trên portal Dev và Staging; không mở trên ProdM1 - chọn portalAC-M1.1fe/src/ui/components/works/sapp/sapp-26878-tool.tsx:91-119
BR-02Luồng có đúng 18 bước theo thứ tự cố định ở §4a; một bước chỉ mở khi mọi bước trước đã xong (xong / bỏ qua)M1 - toàn chuỗiAC-M1.2fe/src/ui/components/works/sapp/sapp-26878-flows.ts:2796-3351; sapp-26878-tool.tsx:888-894
BR-03Số thứ tự lớp mới = số lớp loại STANDARD hiện có của môn đã chọn + 1, đếm tại thời điểm bấm bước 2M1 - A2 Đếm lớpAC-M1.3sapp-26878-flows.ts:2840-2860,2598
BR-04Trên Dev: mã lớp sinh theo mẫu {mã môn}03.{số thứ tự}, tên lớp theo mẫu [SAPP-26878] {mã môn} - {số thứ tự}M1 - A3 Tạo lớpAC-M1.3sapp-26878-flows.ts:2604-2605,2876-2891
BR-05Trên Staging: mã lớp chọn từ danh sách gồm những mã đã có option trên cả ba property mã lớp (Deal ×2, Contact ×1), đúng tiền tố môn, và chưa có lớp nào giữ (kể cả lớp đã xóa mềm). Danh sách rỗng → bước Tạo lớp bị chặn kèm lý doM1 - A3 Tạo lớpAC-M1.4, EC-M1.2be/apps/api/src/sapp/sapp.controller.ts:659-771; fe/src/ui/components/works/sapp/sapp-26878-step-ops.tsx:445-456,597-600,825-850
BR-06Lớp tạo với giá trị mặc định: trạng thái DRAFT, loại LESSON, hình thức BLENDED, thời lượng FIXED, khai giảng 00:00 hôm nay giờ VN, lịch tuần cố định = thứ của hôm nay 13:00–16:00 (UTC)M1 - A3 Tạo lớpAC-M1.3sapp-26878-flows.ts:2920-2971
BR-07Buổi học được sinh bằng bộ sinh lịch từ lịch tuần (không tạo tay từng buổi), mốc bắt đầu mặc định = hôm qua 15:00ZM1 - A4 Tạo buổi họcAC-M1.5sapp-26878-flows.ts:2994-3019
BR-08Gán phòng học gửi link_meeting rỗng (vẫn gửi khóa, không bỏ)M1 - A5 Gán phòngAC-M1.5sapp-26878-flows.ts:3039-3046; inventory R-24
BR-09Mở lớp chuyển trạng thái lớp sang PUBLIC (giá trị cố định, không sửa được)M1 - A6 Mở lớpAC-M1.5sapp-26878-flows.ts:3056-3066
BR-10Bước "Thêm option mã lớp" chỉ thực hiện được trên Dev; trên Staging người dùng phải bỏ qua bướcM1 - A7AC-M1.6fe/src/ui/components/works/sapp/sapp-26878-step-option.tsx:69-72,117; inventory R-19
BR-11Deal của mọi luồng phase 2 mang toàn bộ bộ property của Deal học phí thường phase 1 (US-03), cộng bắt buộc hai property mã lớp của Deal; hai ô mã lớp và mã lớp của Contact được điền sẵn từ bước Tạo lớpM1 - A8 Tạo DealAC-M1.7sapp-26878-flows.ts:2639-2651,2682-2686
BR-12Thiếu CCCD/Hộ chiếu, Họ tên học viên hoặc một property thuộc nhóm Business Partner (theo đối tượng mua hàng cá nhân / doanh nghiệp) → cảnh báo mềm, không chặn tạo DealM1 - A8 Tạo DealAC-M1.7sapp-26878-flows.ts:2662-2680,2687-2705; inventory R-06
BR-13Đơn hàng Ops tạo ra có số tiền 0 → báo lỗi, bước không được đánh dấu xongM1 - A10 Tạo đơn hàngEC-M1.4sapp-26878-step-ops.tsx:636-646; inventory R-22
BR-14Giao dịch lấy số tiền đúng bằng số tiền thật của đơn (không có mặc định); loại TUITION_PAYMENT, phương thức CASH, trạng thái AWAITING_CONFIRMATION, kiểu ONETIME, văn phòng NEU cố định; ngày thanh toán mặc định hôm nayM1 - A12 Tạo giao dịchAC-M1.8sapp-26878-flows.ts:3246-3292; inventory R-23
BR-15Deal đi qua hai mốc Won nối tiếp: Won - Hoàn tất thủ tục rồi Won - Hoàn thiện hồ sơ (stage gợi ý theo nhãn)M1 - A14, A15AC-M1.9sapp-26878-flows.ts:2748-2752,3308-3321
BR-16Bước Đọc kết quả lọc log SAP theo deal_id của lượt và tự chạy 2 kiểm chứng (§M2); bước này luôn coi là xongM2AC-M2.1, AC-M2.2, AC-M2.3sapp-26878-tool.tsx:883-884,1465-1501; sapp-26878-flows.ts:2715-2733,3331-3342
BR-17Kiểm chứng không đọc được trường cần kiểm → trạng thái "unknown", không phải "fail"M2AC-M2.3sapp-26878-flows.ts:382-384; fe/src/ui/components/works/sapp/sap-log-summary.tsx:401-409
BR-18"Trả lại mã lớp": câu đọc lớp tự chạy; câu ghi đổi mã lớp thành removed_{thời điểm}_{mã cũ} và đặt thời điểm xóa mềm trong cùng một lệnh, chỉ tác động lớp chưa bị xóa mềm; câu ghi phải qua hộp xác nhậnM1 - A18AC-M1.10sapp-26878-flows.ts:2519-2537,2767-2787; fe/src/ui/components/works/sapp/sapp-26878-step-sql.tsx:200-213; inventory R-26
BR-19Các luồng phase 2 khác dùng lại nguyên bước của luồng này theo tên bước; một bước bị đổi tên làm tool báo lỗi ngay thay vì lặng lẽ thiếu bướcToàn phase 2AC-X.1sapp-26878-flows.ts:3375-3418

Không phải BR (⚠️ Observed, xem EC): trùng mã lớp khi có người tạo lớp xen giữa bước 2 và 3 (inventory Q-11 / R-21); "Dùng deal có sẵn" tự đánh dấu xong mọi bước còn lại (inventory Q-06 / R-04); BE có route prod cho thao tác ghi Ops (inventory Q-02 / R-33).

4. Design ​

a. Mối liên hệ giữa các màn & User Flow ​

Toàn bộ luồng chạy trong một màn stepper (khung ở US-D01): M1 = 17 bước dựng dữ liệu + bước trả mã, M2 = bước 17 "Đọc kết quả".

text
[Chip "US-01 · DTTH theo buổi", portal Dev | Staging]
  ↓
[M1] 1 Ping Ops → 2 Đếm lớp → 3 Tạo lớp → 4 Tạo buổi → 5 Gán phòng → 6 Mở lớp PUBLIC
  → 7 Thêm option (dev) / bỏ qua (staging) → 8 Tạo Deal → 9 Gán mã lớp → 10 Tạo đơn
  → 11 Soạn thảo hợp đồng → 12 Tạo giao dịch → 13 Xác nhận giao dịch → 14 Won - Hoàn tất thủ tục
  → 15 Won - Hoàn thiện hồ sơ → 16 Chạy lượt quét
  ↓
[M2] 17 Đọc kết quả (luôn "xong")
  ↓
[M1] 18 Trả lại mã lớp (staging) / bỏ qua (dev)

Bảng bước (Fact: sapp-26878-flows.ts:2796-3351; loại bước → US-D03). Cột "Tái dùng" ở file này luôn là "gốc" — các US-D10…D17 dẫn ngược về đây.

#Tên bướcLoạiTái dùngGhi gì (hệ thống · môi trường)Điều kiện chuyển (xong)
1Kiểm tra kết nối Opsops + sqlgốc (A-100)Không ghi. Đọc Ops API; SQL p2.ping.1/2 đọc Ops DB (bảng có thật, có cột xóa mềm, schema)Gọi ping thành công
2Đếm lớp của mônopsgốc (A-101)Không ghi. Đọc danh sách lớp Ops (môn, STANDARD) → bag subject_code, class_total, class_seqGọi thành công
3Tạo lớpops + sqlgốc (A-102)Ops (dev/staging): lớp mới DRAFT. SQL p2.takencodes chỉ đọc → bag course_id, class_id, class_codeGọi thành công
4Tạo buổi họcopsgốc (A-103)Ops: sinh buổi từ lịch tuầnGọi thành công
5Gán phòng họcopsgốc (A-104)Ops: phòng của lớpGọi thành công
6Mở lớp (PUBLIC)opsgốc (A-105)Ops: DRAFT → PUBLICGọi thành công
7Thêm option mã lớpoptiongốc (A-106)HubSpot dev: định nghĩa 3 property enumerationĐủ 3 property (dev) · staging: bỏ qua
8Tạo Dealdealgốc (A-107)HubSpot deal + contact — dev portal, hoặc portal prod khi Staging. Redis run historyCó deal trong lượt
9Gán mã lớpclasscodegốc (A-108)HubSpot deal (2 property) + contact (1 property)Gọi thành công
10Tạo đơn hàngopsgốc (A-109)Ops: đơn hàng gắn deal_id → bag order_id, order_amountGọi thành công và số tiền ≠ 0
11Soạn thảo hợp đồngstagegốc (A-110)HubSpot dealstageChuyển stage thành công
12Tạo giao dịchopsgốc (A-111)Ops: giao dịch chờ xác nhận → bag transaction_idGọi thành công
13Xác nhận giao dịchopsgốc (A-112)Ops → SAP (theo hint: sinh số dư 3387)Gọi thành công
14Kéo sang Wonstagegốc (A-113)HubSpot dealstage = Won - Hoàn tất thủ tục (theo hint: bắn event hóa đơn)Chuyển stage thành công
15Hoàn thiện hồ sơstagegốc (A-114)HubSpot dealstage = Won - Hoàn thiện hồ sơ (theo hint: action tự thêm học viên vào lớp)Chuyển stage thành công
16Chạy lượt quétscangốc (A-115)SAP service (dev/staging): bắn một lượt quét thủ côngGọi thành công
17Đọc kết quảtraceriêng của US-01 (A-116)Không ghi (chỉ đọc log SAP theo deal_id)Luôn xong
18Trả lại mã lớp (staging)guide + sqlriêng của US-01 (A-117)Ops DB (staging): đổi mã lớp + đặt xóa mềmBấm "Đã trả lại mã lớp" (ack) · dev: bỏ qua

⚠️ Ghi PROD — trên portal Staging, các bước 8, 9, 11, 14, 15 ghi vào HubSpot portal production (pipeline [UAT-TEST]), vì Staging dùng credential portal prod (inventory §6 "Tích hợp ngoài — HubSpot"; sapp-26878-tool.tsx:85-90). Các bước Ops/SQL/scan ghi Ops/SAP staging, không phải prod.

Tình trạng nghiệm thu gần nhất (nguồn ngoài code, chưa kiểm chứng lại ở R3): runbook ghi US-01 dựng data ✅ và khẳng định nghiệp vụ ✅ 2/2 trên dev 2026-09-18 (shared/runbooks/sapp/sapp-26878/phase-2/README.md bảng "Trạng thái lần đo cuối"); một lượt trọn vẹn trên staging 2026-09-21 (shared/runbooks/sapp/sapp-26878/phase-2/staging/README.md §6c).

b. Chi tiết từng màn ​

Màn M1 - Chuỗi bước dựng dữ liệu (bước 1–16, 18) ​

FieldValue
Figma frameN/A — as-built, không có Figma
Trigger vào mànChọn chip US-01 · DTTH theo buổi ở nhóm "Phase 2 · doanh thu thực hiện" (inventory E-07)
Mô tả ngắnStepper 18 bước; mỗi bước hiển thị hint, form (điền sẵn từ "bag" id của lượt), panel SQL nếu có, nút chạy / bỏ qua.
UI States ​
StateKhi nàoHiển thịFigma frame
DefaultVừa mở chip (sitting mới)Bước 1 mở, bước 2–18 khóa (khung → US-D01)N/A
LoadingĐang gọi Ops / HubSpot / SAP của một bướcNút chạy của bước ở trạng thái đang xử lýN/A
Has dataBước chạy xongResponse + các id vừa thu vào bag; sau 1,2 s tự sang bước kế (US-D01)N/A
EmptyStaging, danh sách mã lớp còn trống rỗngÔ code không có lựa chọn, thông báo đỏ "⛔ Không còn mã lớp nào dùng được…"N/A
ErrorHệ ngoài trả lỗi / đơn 0đThông báo lỗi của bước; bước không được đánh dấu xongN/A
DisabledBước bị khóa; bước 7 trên Staging; nút chạy bước 3 khi pool rỗngBước khóa hiện lý do khi bấm; bước 7 không chạy được ở StagingN/A
Fields ​

Chỉ liệt kê field riêng của luồng ở các bước ops (field của bước deal → US-D03 / US-D04). Nguồn: sapp-26878-flows.ts:2842-3292.

FieldRequiredTypeDefaultFormatValidationError MessageVisibilityDepends On
B2 · subject_idYesDropdown (danh mục môn)—id Ops—Lỗi của OpsAlwaysDanh mục môi trường (D2)
B2 · categoryYesTextSTANDARD———Readonly—
B3 · nameYesTextmẫu [SAPP-26878] {subject_code} - {class_seq}—BR-04Lỗi của OpsAlwaysB2
B3 · codeYesText (dev) / Dropdown (staging)Dev: mẫu {subject_code}03.{class_seq}; Staging: mục đầu của pool—BR-04, BR-05; Ops ràng buộc duy nhấtPool rỗng: thông báo chặn (EC-M1.2); trùng: lỗi 422 của OpsAlwaysB2, môi trường
B3 · course_id, facility_id, class_owner_id, cx_admin_idYesDropdown (danh mục)—id Ops—Lỗi của OpsAlwaysD2
B3 · status / type / instruction_mode / duration_typeNoTextDRAFT / LESSON / BLENDED / FIXED—BR-06—Always—
B3 · started_at, opening_atYesDatetime ISO00:00 hôm nay giờ VNISOHint: ≥ go-live (dev 2026-09-14, staging 2026-09-17)—Always—
B3 · capacityNoDropdown 20/30/40/5020số——Always—
B3 · class_standard_schedules—JSONthứ hôm nay, 13:00–16:00JSONBR-06—Hidden—
B4 · class_idYesTexttừ bag———AlwaysB3
B4 · started_atYesDatetime ISOhôm qua 15:00ZISOBR-07Lỗi của OpsAlways—
B5 · room_idYesDropdown (phòng học)—id—Lỗi của OpsAlwaysD2
B5 · link_meeting—Textrỗng—BR-08—Readonly—
B6 · id / statusYesTextbag class_id / PUBLIC—BR-09—status ReadonlyB3
B10 · deal_id, thông tin học viên, sản phẩm, giáYes (deal_id)Text / Dropdowntừ bag / danh mục sản phẩm (giá theo sản phẩm)—BR-13"Đơn hàng tạo ra có số tiền bằng 0"AlwaysB8
B12 · amountYesNumberbag order_amount—BR-14Lỗi của OpsAlwaysB10
B12 · type / payment_method / status / payment_type / payment_office—TextTUITION_PAYMENT / CASH / AWAITING_CONFIRMATION / ONETIME / NEU—BR-14—Readonly—
B12 · pay_dateYesDatehôm nayYYYY-MM-DD——Always—
Actions ​

Hành vi chung của từng loại bước (gọi API nào, bag, bỏ qua) → US-D03. Dưới đây chỉ ghi phần riêng của luồng.

A1 - Kiểm tra kết nối Ops (bước 1) ​
ItemDescription
TriggerMở bước 1 (SQL tự chạy) và bấm chạy ping
BehaviorGọi thao tác ping Ops qua passthrough (US-P08); SQL p2.ping.1 tự chạy, p2.ping.2 chạy tay (US-P09). Không ghi.
Success ResultPing thành công → bước xong

Error cases:

CaseExpected Handling
Credential Ops chưa cấu hìnhLỗi của bước; hint chỉ ra env_systems (sapp-26878-flows.ts:2830)
A2 / A3 - Đếm lớp · Tạo lớp (bước 2–3) ​
ItemDescription
TriggerChọn môn, bấm chạy bước 2; sang bước 3 kiểm/chọn mã lớp, bấm chạy
BehaviorBước 2 đọc tổng số lớp STANDARD của môn → số thứ tự (BR-03). Bước 3 tạo lớp trên Ops dev/staging (BR-04/05/06); panel SQL p2.takencodes (chỉ đọc, tự chạy) liệt kê mã đã dùng để giải thích danh sách chọn.
Success ResultBag có class_id, class_code, course_id

Error cases:

CaseExpected Handling
Pool mã staging rỗngChặn chạy, thông báo đỏ (EC-M1.2)
Mã trùng (có người tạo lớp xen giữa)Ops trả 422; hint khuyên bấm lại bước 2 (EC-M1.1)
A4–A6 - Tạo buổi học · Gán phòng · Mở lớp (bước 4–6) ​
ItemDescription
TriggerBấm chạy từng bước
BehaviorGhi Ops dev/staging: sinh buổi từ lịch tuần (BR-07), gán phòng (BR-08), chuyển lớp PUBLIC (BR-09). class_id lấy từ bag.
Success ResultTừng bước xong

Error cases:

CaseExpected Handling
Ops từ chối (vd lịch không khớp thứ, phòng trùng)Lỗi của Ops hiện ở bước; bước không xong
A7 - Thêm option mã lớp (bước 7) ​
ItemDescription
TriggerBấm chạy (Dev) · "Bỏ qua bước này" (Staging)
BehaviorDev: thêm class_code vào option của 3 property (US-P07). Staging: không chạy được (BR-10) — mã đã có option sẵn vì được chọn từ pool.
Success ResultĐủ 3 property / bước đánh dấu bỏ qua

Error cases:

CaseExpected Handling
Staging bấm chạyKhông thực hiện được (BR-10); dùng "Bỏ qua bước này"
A8–A9 - Tạo Deal · Gán mã lớp (bước 8–9) ​
ItemDescription
TriggerĐiền form Deal, bấm tạo; bấm chạy bước 9
BehaviorTạo Deal + Contact trên HubSpot theo spec Deal phase 2 (BR-11, BR-12) — chi tiết form → US-D03 / US-D04. Bước 9 ghi mã lớp lên 2 property Deal + 1 property Contact, không ghi nếu đã đúng (inventory R-16). Tạo Deal ghi một run vào lịch sử → US-D02. ⚠️ Ghi PROD khi Staging (HubSpot portal prod).
Success ResultBag có deal_id, contact_*

Error cases:

CaseExpected Handling
Property ngoài whitelist / thiếu bắt buộcChặn ở form hoặc BE trả 400 13027 (→ US-D03)
A10–A13 - Tạo đơn · Soạn thảo hợp đồng · Tạo giao dịch · Xác nhận giao dịch (bước 10–13) ​
ItemDescription
TriggerBấm chạy từng bước
BehaviorBước 10 tạo đơn trên Ops với deal_id + thông tin học viên từ bag, sản phẩm từ danh mục (giá theo sản phẩm) (BR-13). Bước 11 chuyển stage HubSpot. Bước 12 tạo giao dịch trong đơn, số tiền = số tiền đơn (BR-14). Bước 13 xác nhận giao dịch trên Ops — theo hint, đây là bước gọi SAP và sinh số dư 3387 (sapp-26878-flows.ts:3303).
Success ResultBag có order_id, order_amount, transaction_id

Error cases:

CaseExpected Handling
Đơn 0đEC-M1.4
Số tiền giao dịch lệch đơnOps từ chối (hint sapp-26878-flows.ts:3259)
A14–A16 - Kéo Won · Hoàn thiện hồ sơ · Chạy lượt quét (bước 14–16) ​
ItemDescription
TriggerBấm chuyển stage (bước 14, 15); bấm chạy lượt quét (bước 16)
BehaviorHai mốc Won nối tiếp (BR-15). Lượt quét thủ công → US-P05; chỉ dev/staging (inventory R-25). ⚠️ Ghi PROD (HubSpot) khi Staging cho bước 14, 15.
Success ResultLượt quét được đưa vào hàng đợi (xử lý bất đồng bộ)

Error cases:

CaseExpected Handling
Bấm quét dồnHint ghi SAP service chặn nhịp 1000 ms (429) — nêu ở US-D12/D13
A18 - Trả lại mã lớp (bước 18, staging) ​
ItemDescription
TriggerMở bước (câu ① tự chạy), bấm "Chạy" câu ②, xác nhận, rồi "Đã trả lại mã lớp"
BehaviorCâu ② ghi Ops DB staging qua SQL runner (BR-18). Dev: bỏ qua bước. Guide ghi rõ: không hoàn tác được bằng tool; bút toán đã ghi không mất (sổ cái khóa theo class_id).
Success ResultrowCount = 1; mã quay lại danh sách chọn ở bước 3 của lượt sau

Error cases:

CaseExpected Handling
Lớp đã trả trước đórowCount = 0 — guide ghi "không phải lỗi"
Acceptance Criteria của màn M1 ​
AC-M1.1 - Chỉ Dev / Staging ​
gherkin
Given người dùng đang ở portal Prod
When chọn chip "US-01 · DTTH theo buổi"
Then tool tự chuyển sang portal được phép và hiện thông báo; luồng không chạy trên Prod

Maps to:

  • Business Rule: BR-01
AC-M1.2 - Thứ tự 18 bước ​
gherkin
Given một sitting mới của luồng US-01
When người dùng xem stepper
Then thấy đúng 18 bước theo thứ tự §4a, chỉ bước 1 mở
And bấm vào bước N (N > bước chưa xong đầu tiên) thì hiện lý do bị khóa

Maps to:

  • Business Rule: BR-02
AC-M1.3 - Sinh mã lớp trên Dev ​
gherkin
Given portal Dev, môn có 215 lớp STANDARD, mã môn "F1"
When chạy bước 2 rồi mở bước 3
Then ô code điền sẵn "F103.216", ô name điền sẵn "[SAPP-26878] F1 - 216"
And lớp được tạo với DRAFT, LESSON, BLENDED, FIXED, khai giảng 00:00 hôm nay giờ VN

Maps to:

  • Business Rule: BR-03, BR-04, BR-06
AC-M1.4 - Chọn mã lớp từ pool trên Staging ​
gherkin
Given portal Staging và pool có ít nhất một mã hợp lệ
When mở bước 3
Then ô code là danh sách chọn chỉ gồm mã có option trên cả 3 property, đúng tiền tố môn, chưa có lớp nào giữ

Maps to:

  • Business Rule: BR-05
AC-M1.5 - Chuẩn bị lớp trước khi tạo Deal ​
gherkin
Given bước 3 đã tạo lớp
When chạy lần lượt bước 4, 5, 6
Then Ops có buổi học sinh từ lịch tuần, lớp có phòng, và lớp ở trạng thái PUBLIC

Maps to:

  • Business Rule: BR-07, BR-08, BR-09
AC-M1.6 - Option mã lớp chỉ Dev ​
gherkin
Given portal Staging
When tới bước 7 "Thêm option mã lớp"
Then bước không chạy được; người dùng dùng "Bỏ qua bước này" để đi tiếp

Maps to:

  • Business Rule: BR-10
AC-M1.7 - Deal mang mã lớp ​
gherkin
Given bag có class_code từ bước 3
When mở bước 8 "Tạo Deal"
Then hai property mã lớp của Deal và mã lớp của Contact đã điền sẵn class_code, và hai property Deal là bắt buộc
And nếu để trống CCCD/Họ tên hoặc nhóm Business Partner thì chỉ hiện cảnh báo, vẫn tạo được Deal

Maps to:

  • Business Rule: BR-11, BR-12
AC-M1.8 - Giao dịch theo số tiền đơn ​
gherkin
Given bước 10 trả về đơn có số tiền X > 0
When mở bước 12
Then ô amount = X, các ô type/payment_method/status/payment_type/payment_office chỉ đọc với giá trị cố định

Maps to:

  • Business Rule: BR-14
AC-M1.9 - Hai mốc Won ​
gherkin
Given Deal ở stage "Soạn thảo hợp đồng" và giao dịch đã xác nhận
When mở bước 14 rồi bước 15
Then stage gợi ý lần lượt là "Won - Hoàn tất thủ tục" và "Won - Hoàn thiện hồ sơ"

Maps to:

  • Business Rule: BR-15
AC-M1.10 - Trả lại mã lớp ​
gherkin
Given portal Staging, đã xong bước 17, lớp chưa bị xóa mềm
When chạy câu ② của bước 18 và xác nhận hộp thoại
Then mã lớp đổi thành "removed_<thời điểm>_<mã cũ>" và lớp bị xóa mềm; rowCount = 1
And ở lượt sau, mã cũ xuất hiện lại trong danh sách chọn của bước 3

Maps to:

  • Business Rule: BR-18
Negative AC / Edge Cases của màn M1 &ZeroWidthSpace;
IDTình huốngHành vi mong đợi
EC-M1.1⚠️ Observed — có người tạo lớp của cùng môn xen giữa bước 2 và bước 3Hành vi hiện tại: mã lớp dựng từ số đếm cũ bị trùng, Ops trả 422; hint khuyên bấm lại bước 2. Không có cơ chế chống trùng — OQ-D-11 — xem 00-overview §6
EC-M1.2Staging, pool mã lớp rỗngChặn chạy bước 3. Nếu không có mã nào có option trên đủ 3 property → báo "vấn đề cấu hình"; nếu mọi mã đã có lớp → hướng dẫn chạy bước "Trả lại mã lớp" của một luồng đã nghiệm thu (sapp-26878-step-ops.tsx:825-850)
EC-M1.3⚠️ Observed — bước 8 chọn "Dùng deal có sẵn" (nhập deal id)Hành vi hiện tại: không kiểm deal tồn tại / do tool tạo; mọi bước không phải deal của luồng (vì luồng chỉ có 1 deal: gồm cả tạo lớp, đơn, giao dịch, quét) bị đánh dấu "xong · bỏ qua" — OQ-D-06 — xem 00-overview §6
EC-M1.4Đơn hàng Ops ra số tiền 0Báo "Đơn hàng tạo ra có số tiền bằng 0", bước không xong (BR-13)
EC-M1.5Bỏ qua bước 13 (xác nhận giao dịch)Luồng vẫn đi tiếp; theo hint, mọi bút toán sẽ ra 0đ (AC-X.1 của story) — không có chặn trong tool
EC-M1.6Bỏ qua bước 15 (Hoàn thiện hồ sơ)Luồng vẫn đi tiếp; theo hint, lớp không có học viên và lượt quét không sinh bút toán — không có chặn trong tool
EC-M1.7⚠️ Observed — hint bước 3 và bước 10 nói Deal ở "bước 5"Deal thật ở bước 8 — DR-D-11 — xem 00-overview §6b
EC-M1.8Chạy câu ghi SQL (bước 18)Luôn qua hộp xác nhận, không tự chạy (BR-18). Id câu SQL FE ↔ BE không được kiểm đối chiếu tự động — OQ-D-14
EC-M1.9⚠️ Observed — route ghi Ops có bản prod ở BETool không mở luồng trên Prod (BR-01) nhưng chặn chỉ nằm ở giao diện — OQ-D-02 — xem 00-overview §6

Màn M2 - Bước 17 "Đọc kết quả" &ZeroWidthSpace;

FieldValue
Figma frameN/A — as-built, không có Figma
Trigger vào mànBước 16 xong (hoặc bỏ qua) → mở bước 17
Mô tả ngắnTra trail log SAP theo deal_id của lượt (→ US-P05), hiện mã lớp để copy, và tự chạy các kiểm chứng của story.
UI States &ZeroWidthSpace;
StateKhi nàoHiển thịFigma frame
DefaultMở bướcHint + mã lớp (copy được) + khung trace tự chạy với bộ lọc deal_idN/A
LoadingĐang tra logTrace đang tảiN/A
Has dataCó trailLog SAP + kết quả từng kiểm chứng (pass / fail / unknown); fail kèm câu giải thíchN/A
EmptyChưa có log (quét bất đồng bộ)Trace rỗng; hint khuyên đọc counters của lượt quét và đọc lại sau một nhịpN/A
ErrorAPI trace lỗiLỗi của trace (→ US-P05)N/A
DisabledN/A — bước không có trạng thái khóa riêngN/AN/A
Fields &ZeroWidthSpace;

N/A — bước chỉ đọc; bộ lọc deal_id lấy tự động từ bag.

Actions &ZeroWidthSpace;
A17 - Đọc kết quả &ZeroWidthSpace;
ItemDescription
TriggerMở bước 17 (tự chạy)
BehaviorTra log SAP theo deal_id, chạy 2 kiểm chứng (BR-16, BR-17). Không ghi.
Success ResultBước luôn "xong" dù kiểm chứng pass hay fail

Error cases:

CaseExpected Handling
Không đọc được trường cần kiểmKiểm chứng = unknown (BR-17)
Acceptance Criteria của màn M2 &ZeroWidthSpace;

AC = các kiểm chứng tự chấm của bước (sapp-26878-flows.ts:2715-2733).

AC-M2.1 - Số dư giảm dần qua từng buổi &ZeroWidthSpace;
gherkin
Given lượt quét đã gửi các buổi của lớp sang SAP
When bước "Đọc kết quả" chạy kiểm chứng "Số dư giảm dần qua từng buổi"
Then pass khi trường standard_hours_remaining trong các payload gửi SAP giảm dần theo thứ tự (vd 15.00 → 12.00 → 9.00)
And fail kèm giải thích "một buổi bị ghi lại hoặc thứ tự thời gian sai" khi không giảm

Maps to:

  • Business Rule: BR-16
AC-M2.2 - Mẫu số tính theo cả môn &ZeroWidthSpace;
gherkin
Given các payload gửi SAP của lượt
When chạy kiểm chứng "Mẫu số tính theo cả môn, không theo từng buổi"
Then pass khi standard_hours_remaining KHÔNG luôn bằng lesson_hours ở mọi buổi
And fail kèm "⛔ … mẫu số đang tính sai phạm vi … Báo dev" khi bằng nhau ở mọi buổi

Maps to:

  • Business Rule: BR-16
AC-M2.3 - Bước đọc không chặn &ZeroWidthSpace;
gherkin
Given một hoặc cả hai kiểm chứng fail hoặc unknown
When người dùng xem stepper
Then bước 17 vẫn được coi là xong và bước 18 mở

Maps to:

  • Business Rule: BR-16, BR-17
Negative AC / Edge Cases của màn M2 &ZeroWidthSpace;
IDTình huốngHành vi mong đợi
EC-M2.1Kiểm chứng fail nhưng người dùng vẫn đi tiếpHành vi hiện tại: không có gate "phải xanh"; nghiệm thu dựa vào người đọc — OQ-D-15 — xem 00-overview §6
EC-M2.2Dòng sổ cái SUCCESS không có số chứng từTheo hint: bút toán giá trị 0, đúng thiết kế (EC-M2.7 của story) — tool không phân biệt riêng
EC-M2.3Chạy bước 18 trước khi đọc kết quảTheo guide: sau khi trả mã không tra lớp theo mã được nữa; đọc theo deal_id vẫn được. Tool không chặn thứ tự ngoài gate chung (BR-02)

5. Cross-feature AC &ZeroWidthSpace;

AC-X.1 - Các luồng phase 2 dùng lại bước của US-01 &ZeroWidthSpace;

gherkin
Given một thay đổi ở bước 1–16 của US-01 (hint, field, mặc định)
When mở bất kỳ luồng phase 2 nào dùng lại bước đó (US-D10 … US-D17)
Then luồng đó chạy đúng bước đã đổi (cùng một định nghĩa), trừ các field được ghi đè riêng ở luồng đó
And nếu một bước của US-01 bị đổi tên, tool báo lỗi thay vì lặng lẽ thiếu bước

Maps to:

  • Business Rule: BR-19
  • Liên quan nội bộ FS 26878 (không có mã REL) (liên quan nội bộ FS: US-D10 → US-D17; khung US-D01/US-D03)

AC-X.2 - Lịch sử run của phase 2 &ZeroWidthSpace;

gherkin
Given bước 8 tạo Deal thành công
When tool ghi run history
Then run được ghi vào bucket "us01" của môi trường (→ US-D02)

Maps to:

  • Liên quan nội bộ FS 26878 (không có mã REL) (US-D02). ⚠️ Observed: bucket phase 2 không có trong enum BE / API doc — OQ-D-03, DR-D-02; nút "Lịch sử" ở luồng phase 2 nghi crash — OQ-D-04 — xem US-D02