Skip to content

PRD: Điểm thưởng khi đặt hàng

ModuleBán hàngPRD IDPRD-PNT-001
Trạng tháiSẵn sàng devFEATPNT
EpicPlaneBANA-1559
Ngày2026-03-23Phiên bảnv1.0
Gói@nx/saleURDPNT
SurfaceBackend
Phụ tráchPhát Nguyễn

TL;DR

Đơn có gắn khách hàng thanh toán đủ → khách tự động tích điểm thưởng tính từ tổng đơn theo tỷ lệ quy đổi của merchant. Mỗi đơn chỉ cộng điểm đúng một lần, ghi vào sổ chỉ-đọc và cập nhật số dư ngay - thu ngân không cần thao tác thêm.

1. Context & Problem

Đơn hàng đã có thể gắn với khách hàng (URD-ORD-014) và đạt trạng thái cuối COMPLETED khi thanh toán đủ (URD-ORD-011), nhưng không có gì được tích lũy trên mối quan hệ đó - không có cách nào để tưởng thưởng việc mua lại. Những merchant muốn một cơ chế loyalty đơn giản kiểu "chi tiêu X, nhận một điểm" buộc phải theo dõi ngoài hệ thống hoặc bỏ qua, điều này không khả thi với các merchant bán lẻ và F&B quy mô HKD/SME mà BANA hướng tới.

Tính năng này lấp khoảng trống đó: đơn có gắn khách hàng và thanh toán đủ tự động cộng điểm qua luồng thanh toán thành công - một bản ghi sổ bất biến, idempotent theo từng đơn, kèm số dư cập nhật đồng thời.

2. Goals & Non-Goals

Goals

  • Cộng điểm cho khách hàng khi đơn được thanh toán đủ và có khách hàng gắn kèm, móc vào cả luồng thanh toán thành công của đơn hàng lẫn của từng check.
  • Tính điểm từ tổng đơn theo tỷ lệ quy đổi của từng merchant, làm tròn xuống thành điểm nguyên.
  • Đảm bảo việc cộng điểm idempotent cho mỗi đơn - phát lại cùng một đơn đã hoàn tất không cộng thêm gì.
  • Theo dõi một số dư điểm theo từng khách hàng từng merchant, được tăng cùng với bản ghi sổ trong một lần ghi nguyên tử duy nhất.
  • Ghi nhận mỗi lần cộng điểm thành một bản ghi sổ điểm (earn) chỉ-đọc mang theo đơn, số điểm và tỷ lệ quy đổi.

Non-Goals

  • Tiêu / dùng điểm - chỉ có loại bản ghi earn trong đợt này.
  • Hoàn lại / đảo điểm khi refund / trả hàng (luồng refund bản thân nó là Non-Goal của module).
  • Hạng, hết hạn, hệ số nhân, khuyến mãi, hay điểm thưởng theo chiến dịch.
  • Một UI hướng khách hàng cho số dư hoặc sổ điểm.

3. Success Metrics

MetricMục tiêu / tín hiệu
Độ phủĐơn có gắn khách hàng và thanh toán đủ tạo ra một lần cộng điểm (khi đã cấu hình tỷ lệ quy đổi)
IdempotencyKhông có lần cộng trùng - tối đa một bản ghi sổ cho mỗi đơn
Tính toàn vẹn số dưSố dư khách hàng luôn bằng tổng các bản ghi sổ earn của khách đó
Mức áp dụngSố merchant cấu hình tỷ lệ quy đổi và tích lũy điểm

4. Personas & Use Cases

PersonaMục tiêu trong tính năng này
Khách hàngTự động tích điểm trên mỗi lần mua hoàn tất
Thu ngânThu tiền như bình thường; điểm tự cộng mà không cần thao tác thêm
Chủ merchantVận hành một chương trình loyalty kiểu tích điểm đơn giản, phạm vi theo từng merchant

Kịch bản chính: thu ngân gắn khách hàng → thu thanh toán đủ (đơn hoặc check cuối) → hệ thống tính điểm (làm tròn xuống), ghi một bản ghi earn và cộng số dư - idempotent, kể cả khi sự kiện bị phát lại.

5. User Stories

  • Là một khách hàng, tôi muốn tích điểm khi đơn của tôi được thanh toán đủ, để các lần mua lại tạo nên số dư mà sau này tôi có thể được tưởng thưởng.
  • Là một thu ngân, tôi muốn điểm tự động cộng khi thanh toán, để tôi không phải nhớ một bước loyalty thủ công.
  • Là một chủ merchant, tôi muốn đặt một tỷ lệ quy đổi cho từng merchant, để tôi kiểm soát mức chi tiêu đổi được một điểm.
  • Là một chủ merchant, tôi muốn một đơn nhất định chỉ cộng điểm một lần, để một sự kiện thanh toán bị phát lại không thể thổi phồng số dư.
  • Là một chủ merchant, tôi muốn một sổ chỉ-đọc các lần cộng điểm, để mọi điểm trong số dư khách hàng đều truy ngược được về một đơn.

6. Functional Requirements

#Yêu cầuURD ref
FR-1Cộng điểm cho khách hàng khi đơn trở thành thanh toán đủ và có khách hàng gắn kèm, kích hoạt từ cả luồng thanh toán thành công của đơn hàng lẫn của từng checkURD-PNT-001
FR-2Tính điểm bằng tổng đơn chia cho tỷ lệ quy đổi, làm tròn xuống thành điểm nguyên; bỏ qua khi kết quả ≤ 0URD-PNT-001
FR-3Đọc thiết lập tỷ lệ quy đổi điểm của từng merchant; bỏ qua khi không có thiết lập hoặc tỷ lệ không dương; mặc định 1000URD-PNT-001
FR-4Việc cộng điểm idempotent cho mỗi đơn - dừng sớm nếu đơn đã có lần cộng điểmURD-PNT-002
FR-5Ghi nhận lần cộng điểm thành một bản ghi sổ điểm (earn) mang theo đơn, số điểm và tỷ lệ quy đổiURD-PNT-001
FR-6Tăng số dư điểm của khách hàng và ghi bản ghi sổ cùng nhau trong một lần ghi nguyên tử duy nhất; rollback khi lỗiURD-PNT-003
FR-7Phơi bày sổ ở chế độ chỉ-đọc (liệt kê, lấy theo id, lấy một, đếm), giới hạn trong merchant của chính người dùng; lần cộng điểm không bao giờ được ghi bởi clientURD-PNT-001..003

Toàn văn yêu cầu và tiêu chí chấp nhận nằm trong Orders URD. PRD này tham chiếu chúng thay vì lặp lại.

7. Non-Functional Requirements

Lĩnh vựcYêu cầu
Toàn vẹn dữ liệuBản ghi sổ và lần tăng số dư được ghi cùng nhau trong một lần ghi nguyên tử - không có thay đổi số dư mà thiếu bản ghi sổ tương ứng, và ngược lại
IdempotencyTối đa một lần cộng cho mỗi đơn bất kể sự kiện thanh toán thành công kích hoạt bao nhiêu lần
Tính bất biếnSổ chỉ được ghi qua luồng thanh toán thành công và là chỉ-đọc đối với client; các bản ghi không bị client chỉnh sửa
Tenancy & authzMọi thao tác giới hạn trong merchant của chính người dùng; đọc sổ được gác bởi permission đọc sổ điểm
Độ chính xácTổng đơn đọc với độ chính xác 4 chữ số thập phân; điểm là số nguyên
i18nNhãn/trạng thái hướng người dùng song ngữ (tiếng Anh & tiếng Việt)

8. UX & Flows

Luồng cộng điểm không có UI riêng - nó chạy ngầm theo sự kiện thanh toán thành công. Sổ chỉ-đọc và số dư theo từng khách hàng được các màn hình Orders/Khách hàng ở front end dùng đến.

9. Data & Domain

EntityVai trò
Bản ghi sổ điểmBản ghi sổ bất biến (loại earn) - đơn, số điểm, tỷ lệ quy đổi, scope theo khách hàng & merchant
Số dư điểm khách hàngSố dư đang chạy theo từng khách hàng từng merchant, được tăng một thao tác duy nhất với mỗi lần cộng điểm
Thiết lập tỷ lệ quy đổi điểmThiết lập tỷ lệ quy đổi của từng merchant; mặc định 1000
OrderNguồn của tổng đơn và liên kết khách hàng dẫn dắt việc cộng điểm

Chỉ ở mức khái niệm - toàn bộ schema và bất biến nằm trong sale domain model.

10. Dependencies & Assumptions

Phụ thuộc vào

  • Vòng đời Sale Order (URD-ORD-011) - lần cộng điểm kích hoạt tại bước chuyển sang thanh toán đủ.
  • Liên kết khách hàng (URD-ORD-014) - chỉ đơn có gắn khách hàng mới tích điểm.
  • Tách hoá đơn (check splitting) (URD-CHK) - thanh toán thành công của sale-check là luồng kích hoạt thứ hai.
  • Thiết lập tỷ lệ quy đổi điểm - cung cấp tỷ lệ quy đổi của từng merchant.

Giả định

  • Đơn mang một tổng đã chốt tại thời điểm thanh toán thành công.
  • Một merchant muốn tích điểm sẽ cấu hình tỷ lệ quy đổi; nếu thiếu, lần cộng điểm bị bỏ qua (mặc định 1000 chỉ áp dụng khi thiết lập tồn tại nhưng không có giá trị).

11. Risks & Open Questions

Rủi ro / câu hỏiGiảm thiểu / trạng thái
Cộng trùng do sự kiện thanh toán bị phát lạiDừng sớm idempotency theo khóa đơn hàng
Sổ và số dư có thể lệch khi lỗi cục bộCả hai được ghi cùng nhau trong một lần ghi nguyên tử; rollback khi lỗi
Refund / trả hàng sau khi đã cộng điểmNgoài phạm vi - chưa có đảo điểm; refund là Non-Goal của module
Chưa có luồng redemptionChấp nhận trong đợt này; chỉ có earn, redemption là đợt tương lai
Merchant chưa cấu hình tỷ lệ thì không tích được điểmTheo thiết kế - bỏ qua khi thiếu config hoặc tỷ lệ không dương

12. Release Plan & Launch Criteria

Khía cạnhKế hoạch
PhaseP2 - xem URD feature catalog
RolloutMọi merchant; không feature flag (vô hiệu cho đến khi merchant đặt tỷ lệ quy đổi)
MigrationBản ghi sổ điểm mới và số dư điểm khách hàng
Tiêu chí ra mắtThanh toán đủ trên đơn có gắn khách hàng cộng đúng số điểm đã làm tròn; phát lại không cộng thêm; số dư bằng tổng sổ; đọc scope theo merchant và chỉ-đọc
Giám sátLượng cộng điểm theo từng merchant, tỷ lệ bỏ qua do idempotency, kiểm tra nhất quán số-dư-vs-sổ

13. FAQ

Điểm được cộng chính xác khi nào? Khi một đơn có gắn khách hàng trở thành thanh toán đủ - qua luồng thanh toán thành công của đơn hàng hoặc của từng check.

Một đơn tích được bao nhiêu điểm? Tổng đơn chia cho tỷ lệ quy đổi, làm tròn xuống thành điểm nguyên, trong đó tỷ lệ quy đổi là thiết lập của merchant (mặc định 1000). Phần dư dưới một điểm bị bỏ.

Nếu merchant chưa cấu hình tỷ lệ thì sao? Không cộng điểm - lần cộng bị bỏ qua khi thiếu config hoặc tỷ lệ không dương.

Sự kiện thanh toán phát lại có cộng điểm gấp đôi không? Không - việc cộng điểm idempotent cho mỗi đơn; lần thử thứ hai cho cùng một đơn bị dừng sớm.

Khách hàng có thể tiêu hoặc đổi điểm không? Không trong đợt này - chỉ có loại bản ghi earn. Redemption, hạng và hết hạn là việc tương lai.

Client có thể ghi vào sổ không? Không - sổ là chỉ-đọc; lần cộng điểm chỉ được ghi bởi luồng thanh toán thành công.

References

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.