Giao diện
US-D17: Flow P2 — DTTH đồng bộ ngược (story SAPP US-09 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-127). 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. Dựng callback đã ký (dịch vụ dùng chung) → US-P06.⏳ Đã triển khai — chưa chạy được end-to-end. Bộ ký callback dựng body mà webhook SAP từ chối (400, 7 điểm lệch), chờ SAPP — đo trên staging 2026-09-22 (
shared/external/sapp/sapp-26878/README.md:222,224-244;shared/runbooks/sapp/sapp-26878/phase-2/staging/README.md§6i "🔴 Callback TỰ DỰNG bị chặn"). Các bước của chip vẫn bấm được; hai ca bắt buộc cần callback tự dựng thì chưa dựng được. Xem OQ-D-08.
| Field | Value |
|---|---|
| US ID | US-D17 |
| 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-09 · DTTH đồng bộ ngược (id us09-p2) |
| Priority | N/A — as-built, đã triển khai (backlog R2: không xếp Priority) |
| Status | Draft · Đã triển khai — chưa chạy được end-to-end (⏳ chờ SAPP: body /sign-callback bị webhook từ chối) |
| 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-08, OQ-D-07, OQ-D-06, OQ-D-13, OQ-D-15 — xem 00-overview §6 · DR-D-10, 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 có một dòng sổ cái đang chờ kết quả SAP, tự dựng callback SAP đã ký rồi bắn vào webhook, đọc
kết quả và dựng các ca còn lại (thiếu trường, ngưỡng cảnh báo đối soát)
So that kiểm được rằng kết quả SAP trả về được ghi đúng vào sổ cái, và dòng đã có bút toán trên SAP
luôn được đánh dấu đã post (kể cả khi thiếu trường) để không bị gửi lại sinh bút toán trùng- Nguồn "So that":
shared/runbooks/sapp/sapp-26878/phase-2/us-09/README.md:8-10("Luồng duy nhất nói về dữ liệu đi về: SAP trả kết quả, LMS ghi vào sổ cái … Đường dự phòng là vòng đối soát hỏi lại bằngGET; quá 8 lần thì gửi email và ngừng hỏi"); hint luồngsapp-26878-flows.ts:6214. Tiêu chí nghiệm thu và phạm vi "đã nghiệm thu" của US này:[Assumption](inventory Q-08, Q-13).
2. Dependencies & Definition Of Ready ​
N/A — đã triển khai (Mode B). Dependency runtime như US-D09 §2, thêm:
| # | Cần sẵn sàng | Ở đâu | Tình trạng |
|---|---|---|---|
| D1 | Credential ký callback (clientId / secret) trong env_systems | DB mind_keep → US-P04 | Fact từ hint (sapp-26878-flows.ts:6008) |
| D2 | Route dựng callback đã ký (dev/staging, không có prod) | BE → SAP service → US-P06 | Đã có (inventory E-26) |
| D3 | Bộ ký phía SAPP dựng body khớp DTO webhook | Hệ ngoài (SAPP) | ⏳ Chờ SAPP — shared/external/sapp/sapp-26878/README.md:222 |
| D4 | Công cụ chạy curl ngoài tool | Máy người dùng | Người dùng tự chuẩn bị |
3. Business Rules ​
| ID | Rule | Áp dụng ở | Đã cover bởi (AC) | Nguồn code (Mode B/C) |
|---|---|---|---|---|
| BR-01 | Luồng có 21 bước: U01:1 → U01:16 rồi 5 bước riêng 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:6216-6250 |
| BR-02 | "Đọc sổ cái và tracking" là bước đọc không có kiểm chứng tự động, lọc theo deal_id | M2 - A17 | AC-M2.1 | sapp-26878-flows.ts:5958-5967 |
| BR-03 | "Dựng callback đã ký": câu SQL đọc tự chạy và điền sẵn event_id + id dòng sổ cái (dòng đầu theo ngày buổi) vào hai ô bắt buộc; các ô còn lại có mặc định (trạng thái SUCCEEDED, vai POSITIVE, số chứng từ, khóa chứng từ, số tiền, số dư 3387); bấm lặp được | M1 - A18 | AC-M1.2 | sapp-26878-flows.ts:5981-6069 |
| BR-04 | Để trống ô số dư 3387 là cách dựng ca "thiếu trường" (ERR-05) | M1 - A18 | AC-M1.3 | sapp-26878-flows.ts:6062-6066 |
| BR-05 | "Bắn callback" là bước hướng dẫn: người dùng tự chạy lệnh curl đã ký ngoài tool (hiệu lực khoảng 300 giây, dùng được một lần); xong khi bấm "Đã bắn callback" | M1 - A19 | AC-M1.4 | sapp-26878-flows.ts:6072-6086 |
| BR-06 | "Đọc kết quả" lọc theo deal_id, tự chạy 1 kiểm chứng, luôn coi là xong | M2 - A20 | AC-M2.2, AC-M2.3 | sapp-26878-flows.ts:6094-6115 |
| BR-07 | "Dựng các ca còn lại" là bước hướng dẫn (8 ca), xong khi bấm xác nhận; panel SQL 3 câu đọc + 2 câu ghi (đặt bộ đếm đối soát đúng ngưỡng 8; đưa dòng sổ cái và bản ghi tracking về trạng thái ban đầu) | M1 - A21 | AC-M1.5 | sapp-26878-flows.ts:6132-6200 |
| BR-08 | Câu SQL ghi không tự chạy và phải qua hộp xác nhận | M1 - A21 | AC-M1.5 | 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-09 · DTTH đồng bộ ngược", portal Dev | Staging]
↓
[M1] U01:1 → … → U01:16 (để có một dòng sổ cái đang SENT)
↓
[M2] Đọc sổ cái và tracking
↓
[M1] Dựng callback đã ký → Bắn callback (curl NGOÀI tool) ⏳ webhook trả 400 với body tự dựng
↓
[M2] Đọc kết quả
↓
[M1] Dựng các ca còn lạiBảng bước (Fact: sapp-26878-flows.ts:6216-6250).
| # | 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–16 | Kiểm tra kết nối Ops … Chạy lượt quét | như US-D09 | U01:1 → U01:16 (đúng thứ tự) | Như US-D09 §4a bước 1–16 (⚠️ HubSpot portal prod khi Staging) | Như US-D09 |
| 17 | Đọc sổ cái và tracking | trace | riêng | Không ghi | Luôn xong |
| 18 | Dựng callback đã ký | ops + sql | riêng | Không ghi dữ liệu nghiệp vụ: gọi route ký (SAP service dev/staging) trả lệnh curl đã ký. SQL us09.sign.1 chỉ đọc → bag entry_id, event_id | Gọi thành công |
| 19 | Bắn callback | guide | riêng | Tool không ghi. Người dùng chạy curl → webhook SAP của môi trường (ghi sổ cái nếu webhook nhận) | Bấm "Đã bắn callback" |
| 20 | Đọc kết quả | trace | riêng | Không ghi | Luôn xong |
| 21 | Dựng các ca còn lại | guide + sql | riêng | Ops DB: us09.cases.2, .3 (chỉ khi người dùng chạy) | Bấm "Đã đọc các ca còn lại" |
⚠️ Ghi PROD — trên Staging, bước 8, 9, 11, 14, 15 ghi HubSpot portal production (như US-D09 §4a).
Tình trạng nghiệm thu gần nhất (nguồn ngoài code, chưa kiểm chứng ở R3): dev 2026-09-18 🟡 "chạy được một nửa" — phần đối soát ✅, phần bắn callback tự dựng 🔴 (shared/runbooks/sapp/sapp-26878/phase-2/us-09/README.md:3-5); staging 2026-09-22 — callback thật từ SAP ghi đúng sổ cái, callback tự dựng bị webhook trả 400; hai ca bắt buộc (ERR-05, FAILED không kèm artifact) chưa dựng được (.../phase-2/staging/README.md §6i).
b. Chi tiết từng màn ​
Màn M1 - Chuỗi bước dựng dữ liệu và callback (bước 1–16, 18, 19, 21) ​
| Field | Value |
|---|---|
| Figma frame | N/A — as-built, không có Figma |
| Trigger vào màn | Chọn chip US-09 · DTTH đồng bộ ngược (inventory E-07) |
| Mô tả ngắn | Dựng như US-01 để có dòng sổ cái đang chờ, rồi dựng + bắn callback SAP giả lập. |
UI States ​
| State | Khi nào | Hiển thị | Figma frame |
|---|---|---|---|
| Default | Sitting mới | Bước 1 mở (→ US-D01) | N/A |
| Loading | Đang gọi route ký / SQL | Nút chạy ở trạng thái xử lý | N/A |
| Has data | Bước 18 xong | "Phản hồi đầy đủ" chứa lệnh curl đã ký | N/A |
| Empty | Câu us09.sign.1 không có event_id | Ghi chú: lượt quét chưa gửi dòng này — quay lại bước 16 | N/A |
| Error | Route ký lỗi | Lỗi của bước (→ US-P06) | N/A |
| Disabled | Bước khóa; bước 7 trên Staging | Như US-D09 | N/A |
Fields ​
Nguồn sapp-26878-flows.ts:6009-6067.
| Field | Required | Type | Default | Format | Validation | Error Message | Visibility | Depends On |
|---|---|---|---|---|---|---|---|---|
B18 · event_id | Yes | Text | bag event_id | — | — | — | Always | us09.sign.1 |
B18 · external_reference (id dòng sổ cái) | Yes | Text | bag entry_id | id | Hint: sai → webhook vẫn 200 mà không ghi | — | Always | us09.sign.1 |
B18 · status | No | Dropdown SUCCEEDED / FAILED | SUCCEEDED | — | — | — | Always | — |
B18 · role | No | Dropdown POSITIVE / REVERSAL | POSITIVE | — | — | — | Always | — |
B18 · doc_num | No | Text | 12345 | — | — | — | Always | — |
B18 · trans_id | No | Text | 67890 | — | — | — | Always | — |
B18 · recognized_amount | No | Text | 1000000.00 | — | — | — | Always | — |
B18 · baseline_3387 | No | Text | 7000000.00 | — | BR-04 | — | Always | — |
B21 · id dòng sổ cái / event_id của dòng | — | Text | — (nhập tay từ câu ①) | — | — | — | Always | Câu ① |
Actions ​
A18 - Dựng callback đã ký (bước 18) ​
| Item | Description |
|---|---|
| Trigger | Mở bước (SQL tự chạy), kiểm các ô, bấm chạy (lặp được) |
| Behavior | Gọi route ký của tool (→ US-P06); bí mật đọc ở BE, không qua trình duyệt (BR-03, BR-04). |
| Success Result | Nhận lệnh curl đã ký trong "Phản hồi đầy đủ" |
Error cases:
| Case | Expected Handling |
|---|---|
| Lệnh đã hết hạn / đã dùng | Bấm lại bước để lấy lệnh mới (hint) |
A19 - Bắn callback (bước 19) ​
| Item | Description |
|---|---|
| Trigger | Chép lệnh curl từ bước 18, chạy ngoài tool, bấm "Đã bắn callback" |
| Behavior | Tool không gọi gì (BR-05). |
| Success Result | Theo guide: nhận 200 — nhưng 200 không có nghĩa sổ cái đã đổi |
Error cases:
| Case | Expected Handling |
|---|---|
| 401 | Guide: chữ ký sai, ngoài cửa sổ thời gian, hoặc nonce đã dùng |
| ⏳ 400 từ webhook với body tự dựng | Hành vi đo được ngoài tool (EC-M1.1) — tool không phát hiện, người dùng đọc ở bước 20 |
A21 - Dựng các ca còn lại (bước 21) ​
| Item | Description |
|---|---|
| Trigger | Đọc checklist; chạy câu SQL tùy ca (câu ghi cần xác nhận); bấm "Đã đọc các ca còn lại" |
| Behavior | 8 ca: thiếu trường vẫn đánh dấu đã post; Deal ID lệch; thất bại một phần; ngưỡng cảnh báo gửi đúng một lần; thiếu trường không xóa giá trị cũ; callback trùng; đảo đến sau khi đã SUCCESS; bút toán giá trị 0 (BR-07). Câu ② ③ ghi Ops DB dev/staging (BR-08). |
| Success Result | Bước xong khi xác nhận |
Error cases:
| Case | Expected Handling |
|---|---|
| Ca ngưỡng cảnh báo | Guide: không bấm được gì, chờ ≤ 15 phút cho vòng đối soát (dịch vụ không có ingress) |
Acceptance Criteria của màn M1 ​
AC-M1.1 - Chuỗi 21 bước ​
gherkin
Given một sitting mới của luồng US-09 phase 2
When người dùng xem stepper
Then bước 1–16 trùng US-01, bước 17–21 lần lượt "Đọc sổ cái và tracking", "Dựng callback đã ký", "Bắn callback", "Đọc kết quả", "Dựng các ca còn lại"
And không có bước "Trả lại mã lớp"Maps to:
- Business Rule: BR-01
AC-M1.2 - Điền sẵn khóa callback ​
gherkin
Given lượt quét đã gửi dòng sổ cái của lớp
When mở bước 18
Then câu SQL ① tự chạy, ô event_id và external_reference được điền từ dòng đầu theo ngày buổi
And bấm chạy trả về lệnh curl đã kýMaps to:
- Business Rule: BR-03
AC-M1.3 - Dựng ca thiếu trường ​
gherkin
Given bước 18 đang mở
When xóa ô baseline_3387 rồi bấm chạy
Then yêu cầu ký được gửi không kèm số dư 3387Maps to:
- Business Rule: BR-04
AC-M1.4 - Bắn callback ngoài tool ​
gherkin
When mở bước 19
Then tool chỉ hiện hướng dẫn chạy curl, không gọi API nào; bước xong khi bấm "Đã bắn callback"Maps to:
- Business Rule: BR-05
AC-M1.5 - Dựng các ca còn lại ​
gherkin
When mở bước 21
Then thấy checklist 8 ca và panel 5 câu SQL (câu ② ③ là câu ghi, cần xác nhận)
When chạy câu ② và xác nhận
Then bản ghi tracking của event_id đã nhập có bộ đếm = 8, chưa cảnh báo, trạng thái PROCESSINGMaps to:
- Business Rule: BR-07, BR-08
Negative AC / Edge Cases của màn M1 ​
| ID | Tình huống | Hành vi mong đợi |
|---|---|---|
| EC-M1.1 | ⏳ Callback tự dựng bị webhook từ chối (đo trên staging 2026-09-22, ngoài code) | Hành vi hiện tại: bộ ký trả lệnh curl hợp lệ, callback tới được webhook nhưng bị trả 400 vì body thiếu 5 trường (request_id, dry_run, created_at, updated_at, steps) và doc_num / trans_id là chuỗi thay vì số nguyên. Không đi vòng được từ phía tool. Hệ quả: ca ERR-05 và ca FAILED không kèm artifact chưa dựng được. ⏳ Chờ SAPP — OQ-D-08 — xem 00-overview §6 |
| EC-M1.2 | ⚠️ Observed — comment trong code ghi thao tác ký "pinned to dev" | Luồng đã chạy được trên staging (integration #40BE) — DR-D-10 — xem 00-overview §6b |
| EC-M1.3 | ⚠️ 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 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.4 | Vòng đối soát định kỳ (đường dự phòng) | Guide: tool chưa nối được đường này |
| EC-M1.5 | ⚠️ Observed — "Dùng deal có sẵn" ở bước 8 | Như US-D09 EC-M1.3 — OQ-D-06 |
Màn M2 - Bước 17 "Đọc sổ cái và tracking" và bước 20 "Đọc kết quả" ​
| Field | Value |
|---|---|
| Figma frame | N/A — as-built, không có Figma |
| Trigger vào màn | Mở bước 17 / 20 |
| Mô tả ngắn | Hai bước đọc lọc theo deal_id (→ US-P05); bước 17 không có kiểm chứng, bước 20 có 1. |
UI States ​
| State | Khi nào | Hiển thị | Figma frame |
|---|---|---|---|
| Default | Mở bước | Hint + mã lớp + trace tự chạy | N/A |
| Loading | Đang tra | Trace đang tải | N/A |
| Has data | Có trail | Bước 20: kết quả kiểm chứng "Dòng đã chốt kết quả" | N/A |
| Empty | Callback chưa tới / bị từ chối | Dòng vẫn SENT; kiểm chứng fail kèm ba nghi can | N/A |
| Error | Trace lỗi | → US-P05 | N/A |
| Disabled | N/A | N/A | N/A |
Fields ​
N/A — bước chỉ đọc.
Actions ​
A17 / A20 - Đọc sổ cái và tracking / Đọc kết quả ​
| Item | Description |
|---|---|
| Trigger | Mở bước (tự chạy) |
| Behavior | Bước 17: trace, không kiểm chứng (BR-02). Bước 20: trace + 1 kiểm chứng (BR-06). Không ghi. |
| Success Result | Bước luôn xong |
Error cases:
| Case | Expected Handling |
|---|---|
| Không đọc được trường | Kiểm chứng = unknown |
Acceptance Criteria của màn M2 ​
AC-M2.2 = kiểm chứng tự chấm duy nhất của bước 20 (sapp-26878-flows.ts:6094-6103).
AC-M2.1 - Đọc sổ cái không chấm ​
gherkin
When mở bước 17
Then trace tự chạy theo deal_id, không có kiểm chứng tự độngMaps to:
- Business Rule: BR-02
AC-M2.2 - Dòng đã chốt kết quả ​
gherkin
Given callback đã được webhook nhận và xử lý
When bước 20 chạy kiểm chứng "Dòng đã chốt kết quả"
Then pass khi có ít nhất một dòng sổ cái của lượt ở status = SUCCESS
And fail kèm ba nghi can (sai id dòng; Deal ID lệch → ERR-01; callback thiếu trường → SENT + ERR-05, khi đó fail là đúng kỳ vọng của ca đó) khi còn SENTMaps to:
- Business Rule: BR-06
AC-M2.3 - Bước đọc không chặn ​
gherkin
Given kiểm chứng fail hoặc unknown
Then bước 20 vẫn "xong" và bước 21 mởMaps to:
- Business Rule: BR-06
Negative AC / Edge Cases của màn M2 ​
| ID | Tình huống | Hành vi mong đợi |
|---|---|---|
| EC-M2.1 | ⏳ Callback tự dựng bị 400 (EC-M1.1) | Bước 20 thấy dòng vẫn SENT, kiểm chứng fail — không phân biệt được với ca "thiếu trường" chỉ qua kiểm chứng; người dùng phải đọc log (có WEBHOOK_RECEIVED nhưng không có WEBHOOK_VERIFIED, theo runbook §6i) |
| EC-M2.2 | Ca thiếu trường chạy được (sau khi SAPP sửa) | Theo hint: dòng SENT + ERR-05, mốc đã post có giá trị — kiểm chứng duy nhất fail là đúng kỳ vọng; không có kiểm chứng tự động cho mốc đã post — OQ-D-15 |
5. Cross-feature AC ​
AC-X.1 - Dùng lại bước US-01 ​
gherkin
Given bước U01:1–16 thay đổi ở US-01
When mở luồng US-09 phase 2
Then luồng dùng đúng định nghĩa mớiMaps to:
- Liên quan nội bộ FS 26878 (không có mã REL) (US-D09)
AC-X.2 - Dòng thiếu trường không được gửi lại ở US-08 ​
gherkin
Given dòng sổ cái ở SENT + ERR-05 với mốc đã post (ca AC-M2.4 của story)
When sang luồng US-08 phase 2 và gửi lại dòng đó
Then theo guide, dòng bị chặn và đếm ở skipped.ALREADY_POSTEDMaps to:
- Liên quan nội bộ FS 26878 (không có mã REL) (US-D16). ⏳ Chưa dựng được vì EC-M1.1.