Skip to content

PRD: Fare system & pricing

ModuleSản phẩm (CORE-05)PRD IDPRD-FAR-001
StatusShippedOwnerProduct squad
Date2026-06-03Versionv1.0
Packages@nx/pricing · @nx/commerce · @nx/sale · apps/clientURDFAR · VAR

TL;DR

Cho mỗi variant bán được một fare set hạng nhất - một container giá gồm giá mặc định cùng các override và discount theo khoảng ngày, theo tầng số lượng và theo ngữ cảnh - và một pricing engine theo snapshot resolve giá mà một dòng giỏ hàng phải trả tại thời điểm bán. Một CDC seam tự động provision fare set cho từng variant. Kết quả: giá POS phân tầng, xác định, thay cho một giá vô hướng duy nhất cho mỗi variant.

1. Bối cảnh & Vấn đề

Variant cần có giá, nhưng một giá vô hướng duy nhất là không đủ cho POS. Cùng một variant có thể mang một giá gốc cộng với các override và discount theo khoảng ngày, theo tầng số lượng và theo ngữ cảnh (channel, thời gian, thời lượng dịch vụ), và giá áp dụng phải resolve một cách xác định tại thời điểm bán. Hiện tại danh mục (commerce) có variant nhưng chưa có container giá hạng nhất, và chưa có engine để tính giá mà một dòng giỏ hàng thực sự phải trả - nếu không, logic giá sẽ rò rỉ vào mọi kênh bán và trôi dạt theo thời gian.

Phần tăng trưởng này xây phía giá của danh mục: một fare set liên kết một-một với mỗi variant, các fare bên trong (một fare mặc định cộng với các override/discount group có context rule), một pricing engine theo snapshot resolve fare áp dụng tại thời điểm bán, và một CDC seam để khi tạo hoặc cập nhật một product variant trong commerce sẽ tự động provision và làm giàu fare set của nó trong pricing.

2. Mục tiêu & Không làm

Mục tiêu

  • Fare-set CRUD: mỗi variant mang đúng một fare set với ít nhất một fare mặc định (URD-FAR-001…002).
  • Fare phân tầng: khoảng ngày hiệu lực, cửa sổ số lượng min/max, và các fare group phân cấp cha-con với context rule (channel, thời gian, số lượng, thời lượng dịch vụ) (URD-FAR-005…007).
  • Pricing engine theo snapshot: fare calculator + tax calculator + một pricing v2 endpoint resolve fare áp dụng tại thời điểm bán (override → discount → default) (URD-FAR-003…004).
  • CDC seam: tạo/cập nhật product variant trong commerce cascade sang pricing để tạo và làm giàu fare set của variant (gồm cả bundle / frequently-bought-together link).
  • Fare UI ở client: panel fare set, wizard giá mặc định, chỉnh sửa tier/group, và chọn rule (channel / thời gian / thời lượng dịch vụ) hiển thị trong màn chỉnh sửa sản phẩm.

Không làm (Non-Goals)

  • Tính toán discount khuyến mãi tại thời điểm pricing - chỉ có CRUD khuyến mãi; discount engine vẫn tắt (thuộc về Promotions).
  • Engine chuyển đổi đơn vị và một endpoint đọc "resolved price" độc lập cho variant (URD-VAR-011/012 - Planned).
  • Import danh mục hàng loạt qua CSV.

3. Success Metrics

Chỉ sốMục tiêu / tín hiệu
Độ phủ fare set100% variant mang đúng một fare set với ít nhất một fare mặc định
Tính xác định khi resolveCùng một dòng giỏ hàng + ngữ cảnh luôn resolve ra cùng một fare (override → discount → default)
Độ tin cậy của seamTạo/cập nhật variant luôn provision/làm giàu fare set; không variant nào thiếu fare set
Pricing tại thời điểm bánSale-order preview trả về giá cho mọi variant, gồm cả bundle FBT

4. Personas & Use Case

PersonaMục tiêu trong tính năng này
OwnerĐặt giá gốc và các override/discount phân tầng cho từng variant; kiểm soát giá thay đổi theo channel, thời gian, số lượng
Cashier / EmployeeĐược áp đúng giá một cách tự động tại điểm bán
Sale channel (hệ thống)Resolve giá mà một dòng giỏ hàng phải trả theo ngữ cảnh bán

Kịch bản chính: owner định nghĩa giá mặc định và các tier của variant trong màn chỉnh sửa sản phẩm → fare set được provision/làm giàu qua CDC seam → tại thời điểm bán pricing engine resolve fare áp dụng cho dòng giỏ hàng theo ngữ cảnh → sale order preview và tính theo giá đã resolve.

5. User Stories

  • Là một owner, tôi muốn mỗi variant mang một fare set với giá mặc định, để không có gì bị bán mà không có giá.
  • Là một owner, tôi muốn thêm các fare theo khoảng ngày và theo tầng số lượng, để giá thay đổi cho khung khuyến mãi và mua số lượng lớn.
  • Là một owner, tôi muốn các fare group có context rule (channel, thời gian, thời lượng dịch vụ), để cùng một variant có giá khác nhau theo channel hoặc thời gian.
  • Là một cashier, tôi muốn giá đúng được resolve tự động khi thêm variant vào giỏ, để không bao giờ phải nhập giá thủ công.
  • Là một sale channel, tôi muốn một endpoint pricing preview nhận ngữ cảnh bán, để một dòng order hiển thị giá nó thực sự phải trả (gồm cả bundle FBT).
  • Là một owner, tôi muốn việc tạo hoặc cập nhật variant tự động provision fare set của nó, để pricing không bao giờ trễ so với danh mục.

6. Functional Requirements

#Yêu cầuURD ref
FR-1Mỗi variant có đúng một fare set; một fare set chứa ít nhất một fare mặc địnhURD-FAR-001..002
FR-2Số tiền fare phải bằng 0 hoặc dươngURD-FAR-003
FR-3Tại thời điểm bán, engine resolve fare áp dụng: override → discount → defaultURD-FAR-004
FR-4Fare hỗ trợ khoảng ngày hiệu lực và cửa sổ số lượng min/maxURD-FAR-005..006
FR-5Fare hỗ trợ group phân cấp cha-con (OVERRIDE / DISCOUNT) với context rule (channel, thời gian, số lượng, thời lượng dịch vụ)URD-FAR-007
FR-6Pricing engine theo snapshot: fare calculator + tax calculator + pricing v2 endpoint tính giá dòng từ một pricing snapshotURD-FAR-004
FR-7Sale-order pricing preview nhận pricing context (serviceTime, channel) và tính giá FBT qua orderProductVariantIdsURD-FAR-004
FR-8CDC seam: tạo/cập nhật variant trong commerce provision và làm giàu fare set (gồm bundle / FBT link)URD-VAR-003/004

Nội dung yêu cầu đầy đủ và tiêu chí chấp nhận nằm trong URD Sản phẩm. PRD này tham chiếu, không lặp lại.

7. Non-Functional Requirements

Khía cạnhYêu cầu
Toàn vẹn dữ liệuMỗi variant luôn mang đúng một fare set với ít nhất một fare; số tiền fare bằng 0 hoặc dương
Tính xác địnhResolve fare là xác định cho một dòng + ngữ cảnh cho trước (override → discount → default; cửa sổ ngày/số lượng lọc ứng viên trước)
Tenancy & authzMọi thao tác theo phạm vi merchant (x-merchant-id); kiểm soát bằng permission của product/pricing
Độ chính xácPhép tính tiền/số lượng dùng float(value, 4)
Tính nhất quánProvision variant + fare set là một phần của variant aggregate một thao tác duy nhất; CDC seam đồng bộ fare set theo trạng thái variant
i18nNhãn fare ở phần hiển thị là song ngữ ({ en, vi })

8. UX & Luồng

Màn hình chính (trong apps/client): panel fare set, wizard giá mặc định, chỉnh sửa tier/group, và chọn rule (channel / thời gian / thời lượng dịch vụ), hiển thị trong màn chỉnh sửa sản phẩm.

9. Dữ liệu & Domain

EntityVai trò
FareSetContainer giá liên kết một-một với một variant; chứa các fare của variant
FareMột mục giá - default, override, hoặc discount; mang số tiền, khoảng ngày, cửa sổ số lượng
Fare groupPhân cấp cha-con (OVERRIDE / DISCOUNT) với context rule (channel, thời gian, số lượng, thời lượng dịch vụ)
Pricing snapshotĐầu vào bất biến cho calculator để resolve fare áp dụng tại thời điểm bán

Chỉ mang tính khái niệm - schema đầy đủ và bất biến nằm trong mô hình domain pricing fares.

10. Phụ thuộc & Giả định

Phụ thuộc

  • Variants (URD-VAR) - một fare set được provision cho mỗi variant qua aggregate create/update.
  • CDC seam Commerce → Pricing (@nx/commerce@nx/pricing) - Kafka CDC của product variant kích hoạt provision fare set.
  • Sale orders (@nx/sale) - tiêu thụ endpoint pricing preview với ngữ cảnh bán.

Giả định

  • Mỗi variant tồn tại trong commerce trước khi fare set của nó được làm giàu (CDC seam sắp xếp thứ tự này).
  • Sale channel cung cấp pricing context (serviceTime, channel) và orderProductVariantIds cho pricing FBT.

11. Rủi ro & Câu hỏi mở

Rủi ro / câu hỏiGiảm thiểu / trạng thái
Fare set có thể trễ so với variant vừa tạo/cập nhậtCDC seam provision/làm giàu fare set ở mọi thay đổi variant
Resolve nhập nhằng khi nhiều fare cùng đủ điều kiệnCố định thứ tự ưu tiên override → discount → default; cửa sổ ngày/số lượng lọc ứng viên trước
Discount khuyến mãi chưa áp tại thời điểm pricingNgoài phạm vi phần này; discount engine tắt, chỉ có CRUD khuyến mãi
Chưa có endpoint đọc resolved-price độc lập cho variantPlanned (URD-VAR-011); hiện pricing được lộ qua sale-order preview

12. Release Plan & Launch Criteria

Khía cạnhKế hoạch
PhaseP2 - xem feature catalog của URD
RolloutToàn bộ merchant; không feature flag
MigrationKhông (fare set được provision cho mỗi variant qua CDC seam)
Launch criteriaTạo/cập nhật variant provision một fare set; engine resolve override → discount → default; sale-order preview tính giá dòng (gồm FBT); số tiền fare bằng 0 hoặc dương
MonitoringKiểm tra variant-thiếu-fare-set, kết quả resolve fare, tỷ lệ lỗi pricing-preview

13. FAQ

Giá áp dụng được chọn thế nào? Engine lọc các fare theo khoảng ngày và cửa sổ số lượng trước, rồi resolve theo thứ tự ưu tiên: một override group thắng; nếu không thì discount đủ điều kiện thấp nhất; nếu không nữa thì fare mặc định (giá gốc).

Một variant có thể tồn tại mà không có fare set không? Không - mỗi variant mang đúng một fare set với ít nhất một fare mặc định, được provision qua CDC seam.

Khuyến mãi có được áp tại thời điểm pricing không? Chưa - CRUD khuyến mãi đã có, nhưng discount calculation engine đang tắt, nên discount khuyến mãi không được áp tự động.

Pricing chạy ở đâu tại thời điểm bán? Sale order gọi endpoint pricing preview với pricing context (serviceTime, channel); bundle FBT được tính giá qua orderProductVariantIds.

OVERRIDE và DISCOUNT fare group khác nhau thế nào? OVERRIDE group thay thế hẳn giá; DISCOUNT group giảm giá. Cả hai đều có thể mang rule channel / thời gian / số lượng / thời lượng dịch vụ.

Tài liệu liên quan

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