PRD: Seam điểm thưởng khách hàng (tích điểm)
| Module | Khách hàng | PRD ID | PRD-PNT-001 |
| Trạng thái | Sẵn sàng dev | FEAT | PNT |
| Epic | — | Plane | BANA-1537 |
| Ngày | 2026-06-15 | Phiên bản | v1.0 |
| Gói | @nx/sale | URD | PNT |
| Surface | Backend | ||
| Phụ trách | Phát Nguyễn | ||
TL;DR
Thanh toán một đơn có khách hàng gắn kèm là khách đó được tích điểm - trong cùng một giao dịch nguyên tử vừa ghi một mục sổ cái bất biến vừa cộng số dư điểm lũy kế. Điểm bằng tổng đơn hàng chia cho tỷ lệ quy đổi theo merchant (hệ số chi-tiêu-trên-điểm), làm tròn xuống số nguyên; lần tặng idempotent theo đơn nên một sự kiện thanh toán gửi lại không bao giờ cộng kép. Chỉ tích điểm - quy đổi (tiêu điểm) được cố ý loại khỏi phạm vi và chưa xây dựng.
1. Bối cảnh & Vấn đề
Module Khách hàng đã lưu hồ sơ (CUS) và gắn khách hàng vào đơn khi thanh toán; module Sale đã đưa đơn tới trạng thái đã-thanh-toán-đầy-đủ. Cái còn thiếu là seam nối hai bên: không gì biến một lần thanh toán hoàn tất thành giá trị thưởng cho người mua.
Thiếu nó, merchant không thể tưởng thưởng khách quay lại: không tích điểm tự động, không có số dư theo từng khách để đọc, không có bản ghi truy được lý do số dư thay đổi. Một đường tích điểm cẩu thả còn dễ cộng kép khi sự kiện thanh toán gửi lại, hoặc tích điểm với tỷ lệ chưa cấu hình hay bằng không. Bước tăng này bổ sung seam tích điểm trên nền các khối hồ sơ và thanh toán sẵn có: mỗi đơn đã thanh toán một lần tặng - tính một lần, ghi một lần.
2. Mục tiêu & Loại trừ
Mục tiêu
- Tích điểm tự động khi đơn hoàn tất thanh toán và có khách hàng gắn kèm (URD-PNT-001).
- Tính điểm tặng từ tổng đơn hàng và một tỷ lệ quy đổi theo merchant (chi-tiêu-trên-điểm), làm tròn xuống số nguyên (URD-PNT-002).
- Theo dõi số dư điểm lũy kế theo từng khách, cộng nguyên tử (URD-PNT-003).
- Idempotent theo đơn - tặng tối đa một lần kể cả khi sự kiện thanh toán gửi lại (URD-PNT-004).
- Không tặng gì khi không có khách hàng gắn kèm, tỷ lệ chưa đặt, hoặc tỷ lệ / điểm tính được không dương (URD-PNT-005).
- Ghi mỗi lần tặng như một mục sổ cái bất biến liên kết khách hàng, đơn, merchant, số điểm, và tỷ lệ đã áp (URD-PNT-006).
- Cung cấp sổ cái chỉ-đọc, theo phạm vi merchant để duyệt lịch sử điểm của khách (URD-PNT-007).
Loại trừ
- Quy đổi điểm (tiêu điểm) - tiêu điểm cho một đơn. Chưa xây dựng; sổ cái chỉ ghi mục tích điểm và số dư chỉ luôn tăng. Ghi nhận như một mục nằm ngoài phạm vi (URD - Loại trừ).
- Hạng thành viên (Đồng / Bạc / Vàng) và hệ số tích theo hạng.
- Điều chỉnh điểm thủ công hay quyền ghi sổ cái từ bên ngoài - mục được ghi chỉ bởi seam tích điểm.
- Hết hạn điểm đã tích, và sao kê / thông báo điểm cho khách hàng.
3. Thước đo thành công
| Thước đo | Mục tiêu / tín hiệu |
|---|---|
| Phủ tích điểm | Mỗi đơn đã thanh toán đầy đủ có khách hàng gắn kèm và tỷ lệ đã cấu hình tạo đúng một lần tặng |
| Không cộng kép | Một sự kiện thanh toán gửi lại không bao giờ thêm lần tặng thứ hai cho cùng đơn |
| Toàn vẹn số dư | Số dư của một khách bằng tổng số điểm các mục sổ cái của họ |
| Đầy đủ kiểm tra | Không có lần cộng số dư nào mà thiếu một mục sổ cái bất biến tương ứng |
| Mặc định an toàn | Đơn không có khách, không có tỷ lệ, hay tỷ lệ không dương thì không tặng gì - không phải lỗi |
4. Persona & Tình huống
| Persona | Mục tiêu trong tính năng này |
|---|---|
| Chủ / Quản lý | Cấu hình tỷ lệ quy đổi; đọc số dư và lịch sử điểm của một khách |
| Thu ngân | Gắn khách khi thanh toán để giao dịch tích điểm cho họ lúc thanh toán |
| Khách hàng | Tích lũy số dư điểm từ mua sắm, kiểm tra được từng mục |
Tình huống cốt lõi: thu ngân gắn khách vào đơn rồi nhận thanh toán. Khi đơn thành đã-thanh-toán-đầy-đủ, seam đọc tỷ lệ quy đổi của merchant, tính điểm từ tổng đơn, ghi một mục sổ cái và cộng số dư của khách - tất cả trong một giao dịch nguyên tử. Một sự kiện thanh toán gửi lại sẽ thấy đơn đã tích điểm và không làm gì.
5. Câu chuyện người dùng
- Là chủ, tôi muốn khách tự động tích điểm khi đơn của họ được thanh toán, để thưởng không cần bước thủ công.
- Là chủ, tôi đặt một tỷ lệ quy đổi duy nhất theo merchant, để việc tích điểm nhất quán trên mọi giao dịch.
- Là chủ, tôi muốn mỗi lần tặng được ghi như một mục bất biến, để tôi luôn giải thích được một số dư.
- Là chủ, tôi muốn một sự kiện thanh toán gửi lại không bao giờ cộng kép, để số dư đáng tin cậy.
- Là thu ngân, tôi gắn khách khi thanh toán và không làm gì khác, để điểm tự theo giao dịch.
- Là chủ, tôi duyệt lịch sử điểm của một khách trong một danh sách chỉ-đọc, để kiểm tra số dư của họ tăng thế nào.
6. Yêu cầu chức năng
| # | Yêu cầu | URD ref |
|---|---|---|
| FR-1 | Khi một đơn hoàn tất thanh toán và có khách hàng gắn kèm, tích điểm cho khách đó | URD-PNT-001 |
| FR-2 | Tính điểm tặng = ⌊tổng đơn ÷ tỷ lệ quy đổi theo merchant⌋ - tỷ lệ là chi-tiêu-trên-điểm | URD-PNT-002 |
| FR-3 | Duy trì số dư điểm lũy kế theo từng khách, cộng theo mỗi lần tặng | URD-PNT-003 |
| FR-4 | Tặng tối đa một lần cho mỗi đơn; sự kiện thanh toán gửi lại là no-op (idempotent theo đơn) | URD-PNT-004 |
| FR-5 | Không tặng gì khi không có khách, tỷ lệ chưa đặt, hoặc tỷ lệ / điểm tính được ≤ 0 | URD-PNT-005 |
| FR-6 | Ghi mỗi lần tặng như một mục sổ cái bất biến: loại, điểm, tỷ lệ đã áp, liên kết khách / đơn / merchant | URD-PNT-006 |
| FR-7 | Mục sổ cái và lần cộng số dư được ghi trong một giao dịch nguyên tử | URD-PNT-003 · URD-PNT-006 |
| FR-8 | Cung cấp sổ cái chỉ-đọc, theo phạm vi merchant để duyệt lịch sử điểm của một khách | URD-PNT-007 |
Toàn văn yêu cầu và tiêu chí chấp nhận nằm trong URD Khách hàng - PNT. PRD này tham chiếu chúng thay vì lặp lại.
7. Yêu cầu phi chức năng
| Lĩnh vực | Yêu cầu |
|---|---|
| Idempotency | Tối đa một lần tặng cho mỗi đơn; seam kiểm tra mục đã tồn tại trước khi cộng |
| Nguyên tử | Mục sổ cái + lần cộng số dư commit cùng nhau; lỗi một phần thì rollback toàn bộ |
| Toàn vẹn dữ liệu | Không có lần cộng số dư nào thiếu một mục sổ cái bất biến tương ứng; mục chỉ-thêm |
| Phạm vi & phân quyền | Việc đọc sổ cái được giới hạn trong merchant của người dùng và kiểm soát bằng quyền đọc lịch sử điểm |
| Độ chính xác | Tổng đơn và tỷ lệ dùng độ chính xác 4 chữ số thập phân; điểm làm tròn xuống số nguyên |
| Bền bỉ | Thiếu khách, thiếu tỷ lệ, hay tỷ lệ / kết quả điểm không dương là no-op an toàn, không phải lỗi |
| i18n | Nhãn hiển thị cho người dùng song ngữ (tiếng Anh / tiếng Việt) |
8. UX & Luồng
Đường tích điểm không có UI - nó chạy khi thanh toán hoàn tất. Hai bề mặt duy nhất hướng chủ là thiết lập tỷ lệ quy đổi theo merchant và sổ cái điểm chỉ-đọc của một khách.
9. Dữ liệu & Miền nghiệp vụ
| Khái niệm | Vai trò trong seam |
|---|---|
| Mục sổ cái điểm | Một mục tích điểm bất biến cho mỗi lần tặng - điểm, tỷ lệ quy đổi đã áp, liên kết khách / đơn / merchant. Một mục mỗi đơn |
| Khách hàng | Mang số dư điểm lũy kế, cộng nguyên tử theo mỗi lần tặng |
| Cấu hình merchant | Giữ tỷ lệ quy đổi điểm theo merchant đọc lúc tặng |
| Sale order | Đơn đã thanh toán có tổng tiền dẫn dắt lần tặng |
Chỉ mang tính khái niệm - mô hình dữ liệu và bất biến đầy đủ nằm trong tài liệu nhà phát triển Sale - Customer Points. Liên kết là tham chiếu logic; toàn vẹn được thực thi bởi logic tích điểm, không bằng ràng buộc cơ sở dữ liệu.
10. Phụ thuộc & Giả định
Phụ thuộc vào
- Hồ sơ khách hàng (CUS) - lần tặng cộng cho khách gắn vào đơn.
- Hoàn tất thanh toán đơn (Đơn hàng) - seam kích hoạt khi đơn thành đã thanh toán đầy đủ.
- Cấu hình theo merchant - tỷ lệ quy đổi đọc từ thiết lập quy đổi điểm của merchant; một mặc định hợp lý áp dụng khi thiết lập tồn tại nhưng không có giá trị rõ ràng.
- Dữ liệu lõi dùng chung - sổ cái điểm, số dư khách, đơn, và cấu hình.
Giả định
- Một khách được gắn vào đơn khi thanh toán; nếu không seam không tặng gì.
- Merchant đã cấu hình một tỷ lệ quy đổi dương; tỷ lệ chưa đặt hay không dương thì không tặng.
- Seam thanh toán có thể gửi lại sự kiện hoàn tất, nên đường tích điểm phải idempotent.
11. Rủi ro & Câu hỏi mở
| Rủi ro / câu hỏi | Giảm thiểu / trạng thái |
|---|---|
| Sự kiện thanh toán gửi lại cộng kép | Lần tặng idempotent theo đơn - mục đã tồn tại sẽ ngắt mạch seam |
| Mục sổ cái và số dư lệch nhau khi lỗi một phần | Cả hai ghi trong một giao dịch nguyên tử; lỗi một phần rollback toàn bộ |
| Merchant chưa cấu hình tỷ lệ | No-op an toàn - không tặng, không lỗi; có log để theo dõi |
| Tỷ lệ bằng không hoặc âm | No-op an toàn - chặn trước mọi lần ghi |
| Đơn nhỏ tích không điểm | Đúng kỳ vọng - điểm làm tròn xuống; tổng dưới một điểm không tặng gì |
| Khách kỳ vọng tiêu điểm | Ngoài phạm vi - quy đổi (tiêu điểm) được cố ý loại khỏi bước này |
12. Kế hoạch phát hành & Tiêu chí ra mắt
| Khía cạnh | Kế hoạch |
|---|---|
| Phase | P2 - PNT trong danh mục tính năng URD |
| Triển khai | Mọi merchant; không feature flag. Tích điểm hoạt động khi merchant đặt một tỷ lệ quy đổi |
| Di trú | Không - seam chạy trên đường hoàn tất thanh toán sẵn có; số dư đã có |
| Tiêu chí ra mắt | Một đơn đã thanh toán đầy đủ có khách và tỷ lệ đã cấu hình tích ⌊tổng ÷ tỷ lệ⌋ điểm; lần tặng ghi một mục sổ cái bất biến và cộng số dư nguyên tử; sự kiện gửi lại không tặng gì; không khách / không tỷ lệ / tỷ lệ không dương không tặng gì |
| Giám sát | Số lần tặng theo merchant, kiểm tra số-dư-so-sổ-cái, lý do no-op (không khách, không tỷ lệ, không dương), số lần bỏ qua idempotent |
13. FAQ
Điểm được tính thế nào? Lấy tổng đơn hàng chia cho tỷ lệ quy đổi, làm tròn xuống số nguyên. Tỷ lệ là hệ số chi-tiêu-trên-điểm - bao nhiêu giá trị đơn bằng một điểm - nên tỷ lệ 1000 tích một điểm cho mỗi 1000 tổng đơn.
Nếu sự kiện thanh toán gửi lại thì sao? Không gì được cộng hai lần. Seam kiểm tra đơn đã tích điểm chưa, nếu rồi thì không làm gì.
Nếu merchant chưa đặt tỷ lệ? Không tặng điểm - một no-op an toàn, không phải lỗi. Tương tự khi không có khách gắn kèm hoặc tỷ lệ không dương.
Khách có thể tiêu điểm không? Chưa. Bước này chỉ phát hành tích điểm; quy đổi (tiêu điểm) được cố ý loại khỏi phạm vi - sổ cái chỉ ghi mục tích điểm và số dư chỉ tăng.
Mọi thay đổi số dư có kiểm tra được không? Có - mỗi lần tặng ghi một mục sổ cái bất biến (điểm, tỷ lệ đã áp, khách / đơn / merchant) trong cùng giao dịch với lần cộng số dư, và sổ cái duyệt được chỉ-đọc theo merchant.
Nhân viên có sửa được sổ cái không? Không - mục được ghi chỉ bởi seam tích điểm. Sổ cái là chỉ-đọc và giới hạn trong merchant của người dùng.
Tham chiếu
- URD: Khách hàng - PNT
- PRD liên quan: Hồ sơ khách hàng · KH doanh nghiệp & nhóm
- Module: Khách hàng - URD
- Nhà phát triển: @nx/sale - Customer Points · @nx/core