Skip to content

PRD: Bộ máy Fare & Tax Pricing

ModuleĐịnh giá (CORE-14)PRD IDPRD-FARE-001
StatusShippedOwnerPricing squad
Date2026-06-05Versionv1.0
Packages@nx/pricingURDFARE · TAX

TL;DR

Cung cấp cho merchant một bộ máy duy nhất để biến mọi biến thể sản phẩm thành số tiền: nó chọn fare thắng cho từng dòng (giá gốc, override, hoặc discount theo quy tắc), cộng thêm đúng các loại thuế (inclusive/exclusive, gộp, cấp dòng hàng vs cấp đơn hàng), và trả về một pricing snapshot bất biến duy nhất. Luồng bán hàng yêu cầu kết quả đó khi thanh toán thay vì tự cài đặt lại logic định giá, nhờ vậy mọi dòng hàng và đơn hàng đều được định giá nhất quán và có thể truy vết.

1. Context & Problem

Trước đây giá bị gắn cứng trên sản phẩm hoặc tính ngẫu hứng khi thanh toán, không có một nơi nhất quán cho thuế, giá theo quy tắc, hay một bảng phân rã có thể truy vết. Merchant cần một bộ máy duy nhất chọn đúng fare cho từng biến thể, tính thuế chính xác (inclusive/exclusive, gộp, cấp dòng hàng vs cấp đơn hàng), và trả về một kết quả định giá nhất quán. Luồng bán hàng phải yêu cầu kết quả đó khi thanh toán mà không tự cài đặt lại logic định giá - một yêu cầu bắt buộc để báo cáo giá vốn, thuế và biên lợi nhuận đáng tin cậy cho bài toán sổ sách HKD/SME mà KICKO hướng tới.

Bộ máy này xây việc chọn fare và tính thuế trên nền danh mục biến thể sản phẩm và scope theo từng merchant của commerce, đồng thời mở một endpoint mô phỏng để luồng bán hàng sử dụng.

2. Goals & Non-Goals

Goals

  • Chọn fare thắng cho từng biến thể: default, OVERRIDE (child hợp lệ đầu tiên), hoặc DISCOUNT (child hợp lệ rẻ nhất), kèm đánh giá quy tắc (attribute, operator, value; logic AND).
  • Tính thuế theo thứ tự ưu tiên với các chế độ percentage/fixed/combined, cách xử lý inclusive/exclusive, thuế gộp tax-on-tax, và phạm vi cấp dòng hàng vs cấp đơn hàng.
  • Mở một endpoint mô phỏng trả về một pricing snapshot bất biến - fare và thuế áp dụng theo từng dòng cộng với tổng đơn hàng.
  • Tự động seed một fare set + default fare khi một biến thể sản phẩm được tạo (CDC), để mọi biến thể đều có thể định giá ngay lập tức.
  • Áp dụng tax rate mặc định khi chưa cấu hình tax set nào.

Non-Goals

  • Áp dụng giảm giá khuyến mãi khi thanh toán - calculator chưa được nối trong increment này (thuộc về feature Promotions).
  • Định giá đa tiền tệ.
  • Lưu đơn hàng, phát hành hóa đơn, hay thay đổi tồn kho.

3. Success Metrics

MetricTarget / signal
Độ chính xác định giáGiá khi thanh toán khớp với fare + thuế đã cấu hình cho các giỏ hàng lấy mẫu; không sai lệch so với tính tay
Độ phủ fare100% biến thể sản phẩm có thể định giá ngay (tự seed fare set + default fare)
Tính toàn vẹn snapshotMỗi đơn hàng đã định giá tạo ra một v2 snapshot bất biến với bảng phân rã fare/thuế theo từng dòng
Độ chính xác số họcTính tiền khớp đến 4 chữ số thập phân xuyên suốt

4. Personas & Use Cases

PersonaMục tiêu trong feature này
Owner / ManagerĐặt giá gốc và giá có điều kiện theo từng biến thể, gắn thuế, kiểm soát cách chọn giá
CashierNhận kết quả định giá đúng và nhất quán khi thanh toán mà không phải cấu hình gì
SystemTự seed fare set + default fare khi một biến thể xuất hiện, để không có gì không định giá được

Core scenarios: owner đặt một base fare và các child fare tùy chọn theo quy tắc + thuế cho từng biến thể → khi thanh toán luồng bán hàng gọi endpoint mô phỏng → bộ máy chọn fare thắng cho từng dòng, tính thuế cấp dòng hàng và cấp đơn hàng theo thứ tự ưu tiên → trả về một pricing snapshot bất biến với tổng theo từng dòng và theo đơn hàng.

5. User Stories

  • Là một owner, tôi muốn đặt giá gốc cho từng biến thể và các giá child có điều kiện theo quy tắc, để đúng giá được áp dụng tự động.
  • Là một owner, tôi muốn chọn xem child fare khớp đầu tiên thắng (OVERRIDE) hay child hợp lệ rẻ nhất thắng (DISCOUNT), để tôi kiểm soát chiến lược giá của mình.
  • Là một owner, tôi muốn gắn thuế percentage/fixed/gộp ở cấp dòng hàng hoặc cấp đơn hàng, inclusive hoặc exclusive, để tổng phản ánh đúng cách xử lý thuế.
  • Là một cashier, tôi muốn việc thanh toán trả về một kết quả định giá nhất quán cho giỏ hàng, để tôi không phải nhập lại hay tính lại giá.
  • Là một cashier, tôi muốn một bảng phân rã có thể truy vết cho mọi fare và thuế đã áp dụng, để một mức giá bị tranh chấp có thể được giải thích.
  • system, tôi muốn một fare set + default fare được tạo tự động khi một biến thể xuất hiện, để mọi biến thể đều có thể định giá ngay.

6. Functional Requirements

#RequirementURD ref
FR-1Mỗi biến thể sản phẩm có đúng một fare set được kích hoạt; owner có thể đặt một default (base) fareURD-FARE-001 · URD-FARE-003
FR-2Tự seed một fare set + default fare khi một biến thể sản phẩm được tạo (CDC)URD-FARE-002
FR-3Parent fare mang chiến lược OVERRIDE hoặc DISCOUNT; child fare mang giá có điều kiện và quy tắc (logic AND)URD-FARE-004..006
FR-4OVERRIDE chọn child hợp lệ đầu tiên; DISCOUNT chọn child hợp lệ rẻ nhất; default fare là phương án dự phòngURD-FARE-007..009
FR-5Owner có thể tạo tax type và một tax set, thêm thuế qua aggregate updateURD-TAX-001..002
FR-6Một thuế có thể là percentage, fixed, hoặc combined; thuế áp dụng theo thứ tự ưu tiên tăng dầnURD-TAX-003..004
FR-7Một thuế có thể exclusive (cộng thêm lên trên) hoặc inclusive (tính ngược ra); thuế gộp tính trên tổng đang chạyURD-TAX-005..006
FR-8Thuế cấp dòng hàng áp theo từng dòng; thuế cấp đơn hàng áp cho các tax set ở scope merchantURD-TAX-008
FR-9Áp dụng tax rate mặc định khi chưa cấu hình tax set nàoURD-TAX-009
FR-10Endpoint mô phỏng trả về một v2 pricing snapshot bất biến (fare + thuế áp dụng theo từng dòng, cộng với tổng đơn hàng); v1 trả về một kết quả phẳngURD-CON-004
FR-11Giá trị tiền dùng độ chính xác 4 chữ số thập phân xuyên suốt tính toánURD-CON-003

Toàn văn requirement và tiêu chí nghiệm thu nằm trong Pricing URD. PRD này tham chiếu chúng thay vì lặp lại.

7. Non-Functional Requirements

AreaRequirement
Data integrityMột v2 pricing snapshot đã tính là bất biến sau khi tạo ra; bảng phân rã không bị sửa về sau
Tenancy & authzMọi fare, thuế, và bản ghi đều được scope theo từng merchant (merchant header) và dùng soft-delete; endpoint yêu cầu xác thực
PrecisionTính tiền dùng float(value, 4); thuế inclusive không bao giờ làm tăng tổng
Performance / scaleMô phỏng định giá cả giỏ hàng trong một lần gọi; v1 và v2 dùng chung logic fare/thuế lõi nên các sửa lỗi áp cho cả hai
ConsistencyĐúng một fare set được kích hoạt cho mỗi biến thể; việc tự seed giữ cho mọi biến thể đều định giá được
i18nNhãn hiển thị cho người dùng là song ngữ ({ en, vi })

8. UX & Flows

Các màn hình cấu hình (fare, fare set, thuế, tax set) nằm trong back office hướng tới owner; kết quả định giá được luồng bán hàng dùng không giao diện khi thanh toán. Cả /simulation (v1, phẳng) và /simulation-v2 (snapshot) đều đang chạy, với v2 là chuẩn.

9. Data & Domain

EntityVai trò
FareSetBộ chứa tất cả fare cho một biến thể sản phẩm; đúng một bộ được kích hoạt cho mỗi biến thể
FareMột bản ghi giá - default (base), hoặc parent/child tạo thành một nhóm chọn
RuleMột điều kiện (attribute, operator, value) trên một child fare; tất cả quy tắc phải qua (AND)
TaxSetBộ chứa thuế cho một biến thể (cấp dòng hàng) hoặc một merchant (cấp đơn hàng)
TaxMột khoản percentage/fixed/combined với priority, cửa sổ thời gian, các cờ inclusive/exclusive/gộp
TaxTypeMột danh mục (vd VAT) - toàn hệ thống hoặc scope theo merchant
Pricing snapshotKết quả v2 bất biến - fare và thuế áp dụng theo từng dòng, cộng với tổng đơn hàng

Chỉ ở mức khái niệm - schema và bất biến đầy đủ nằm trong pricing domain model.

10. Dependencies & Assumptions

Phụ thuộc vào

  • Product (biến thể) - fare, tax set, và giá vốn đều khóa theo biến thể sản phẩm; CDC của biến thể kích hoạt việc tự seed.
  • Commerce / Merchant - fare, thuế, và bản ghi đều được scope theo từng merchant.
  • Luồng CDC biến thể sản phẩm - yếu tố kích hoạt việc tự seed một fare set + default fare.

Giả định

  • Mỗi biến thể sản phẩm phát một CDC event khi tạo để fare set của nó có thể được seed.
  • Tồn tại một tax rate mặc định của merchant để áp dụng khi chưa cấu hình tax set nào.
  • Luồng bán hàng gọi endpoint mô phỏng khi thanh toán thay vì tự tính giá.

11. Risks & Open Questions

Risk / questionMitigation / status
Thứ tự giảm giá khuyến mãi so với thuế cấp đơn hàng trong pipeline v2Mở: xác định calculator giảm giá chạy trước hay sau thuế cấp đơn hàng khi nó được nối
Hai phiên bản mô phỏng đang chạy (v1 + v2) có thể trôi lệchv1 và v2 dùng chung logic fare/thuế lõi; sửa lỗi áp cho cả hai. Mở: ngừng v1 khi mọi consumer chuyển sang v2
Thiếu cấu hình thuế sẽ khiến một dòng không bị tính thuếÁp dụng tax rate mặc định khi chưa cấu hình tax set nào (FR-9)
Biến thể được tạo mà không có fare sẽ không định giá đượcTự seed một fare set + default fare khi biến thể CDC (FR-2)

12. Release Plan & Launch Criteria

AspectPlan
PhaseP1 (Fares + Taxes) - xem URD feature catalog
RolloutMọi merchant; không feature flag. Cả /simulation (v1) và /simulation-v2 đang chạy, v2 là chuẩn
MigrationKhông (entity mới; fare set tự seed từ CDC biến thể sản phẩm)
Launch criteriaGiá khi thanh toán khớp với fare + thuế đã cấu hình cho các giỏ hàng lấy mẫu; v2 snapshot tạo ra cho mỗi đơn; toán thuế inclusive/exclusive/gộp đã kiểm chứng
MonitoringTỉ lệ sai lệch định giá so với tính tay, độ phủ seed fare theo từng merchant, lỗi tạo snapshot

13. FAQ

Bộ máy chọn fare thắng như thế nào? Nó đánh giá các child fare theo quy tắc của chúng. Với một parent OVERRIDE, child hợp lệ đầu tiên thắng; với một parent DISCOUNT, child hợp lệ rẻ nhất thắng; nếu không child nào hợp lệ, default fare được dùng.

Điều gì xảy ra nếu một biến thể không cấu hình thuế? Một tax rate mặc định được áp dụng để dòng hàng không bao giờ bị bỏ sót thuế.

Thuế inclusive vs exclusive - khác nhau ở đâu? Thuế exclusive được cộng thêm lên trên giá; thuế inclusive được tính ngược ra khỏi giá, nên một thuế inclusive không bao giờ làm tăng tổng.

Khác biệt giữa mô phỏng v1 và v2 là gì? v1 (/simulation) trả về một kết quả định giá phẳng; v2 (/simulation-v2) trả về một snapshot bất biến với bảng phân rã fare và thuế áp dụng theo từng dòng cộng với tổng đơn hàng. v2 là chuẩn.

Bộ máy này có áp khuyến mãi khi thanh toán không? Chưa - entity khuyến mãi và CRUD đã có, nhưng calculator giảm giá chưa được nối vào pipeline định giá trong increment này.

References

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