标准满减类型参考(o_promotion)
o_promotion 七种 type 与 rule_param 样例。流水线见 promotion-discount-checkout.md §5。
与实现冲突时以 PromotionHandlerService、PromotionService::discountPrice() 为准。
目录
- 1. 七种 type
- 2. rule_param 通用结构
- 3. 各 type 样例 JSON
- 4. 范围与多活动规则
- 5. 与 diy_offer / 券的关系
- 5.5 o_promotion 与 o_diy_offer 改价对比
- 6. 订单字段
- 7. 单测要点
- 8. 代码索引
1. 七种 type
| type | 常量 | 含义 | 计算入口 |
|---|---|---|---|
| 1 | PROMOTION_FULL_AMOUNT_MINUS_AMOUNT | 满额减元 | calGeneralDiscount |
| 2 | PROMOTION_FULL_NUM_MINUS_OFF | 满件打折 | calGeneralDiscount |
| 3 | PROMOTION_FULL_NUM_MINUS_AMOUNT | 满件减元 | calGeneralDiscount |
| 4 | PROMOTION_FULL_AMOUNT_MINUS_OFF | 满额打折 | calGeneralDiscount |
| 5 | PROMOTION_SINCE_COUNT_DISCOUNT | 第 X 件 Y 折 | calSinceDiscount |
| 6 | PROMOTION_FIXED_PRICE | 满件一口价 | calFixedPriceDiscount |
| 7 | PROMOTION_BUY_X_FREE_Y | 满 X 免 Y 件 | calBuyXFeeY |
PromotionModel部分常量旁注释与业务不一致,以 Service 分支为准。
2. rule_param 通用结构
Type 1–4 常见骨架:
{
"type": 1,
"allocation_limit": 0,
"rule": [
{ "ge": 100, "value": 10 },
{ "ge": 200, "value": 25 }
]
}| 字段 | 说明 |
|---|---|
type | 与活动 type 一致(1–7) |
allocation_limit | 999(ALLOCATION_LIMIT)= 上不封顶,按 floor(总额或件数/ge) 倍数计 |
rule[].ge | 门槛:满额类比 金额,满件类比 件数 |
rule[].value | type1/3:减 元;type2/4:折扣 百分比(如 20 表示 20% off) |
多档规则:取 满足条件的最大 ge 对应 value(非最优组合)。
3. 各 type 样例 JSON
Type 1 — 满额减元
满 100 减 10;满 200 减 25(取最高档):
{
"type": 1,
"allocation_limit": 0,
"rule": [{ "ge": 100, "value": 10 }, { "ge": 200, "value": 25 }]
}上不封顶示例(每满 100 减 10):
{
"type": 1,
"allocation_limit": 999,
"rule": [{ "ge": 100, "value": 10 }]
}Type 2 — 满件打折
满 3 件打 8 折(value=20 表示减 20%):
{
"type": 2,
"allocation_limit": 0,
"rule": [{ "ge": 3, "value": 20 }]
}Type 3 — 满件减元
满 2 件减 15 元:
{
"type": 3,
"allocation_limit": 0,
"rule": [{ "ge": 2, "value": 15 }]
}Type 4 — 满额打折
满 200 打 9 折(value=10):
{
"type": 4,
"allocation_limit": 0,
"rule": [{ "ge": 200, "value": 10 }]
}Type 5 — 第 X 件 Y 折
结构较复杂,含 top_promotion、promotion_xy_product_price_sort 等;见 PromotionHandlerService::calSinceDiscount。
示意(第 2 件 5 折):
{
"type": 5,
"top_promotion": 0,
"rule": [{ "ge": 2, "value": 50 }]
}Type 6 — 满件一口价
满 3 件共 99 元;见 calFixedPriceDiscount。
Type 7 — 满 X 免 Y 件
满 3 免 1(低价优先);见 calBuyXFeeY。
4. 范围与多活动规则
商品范围优先级(product_range_sort 升序):指定商品 < 专辑 < 全场。
getCartPromotion 三步:
- 剔除
mutexPromotionVariantUniqKey捆绑 SKU - 读缓存活动,构建
not_ranges(先到先得占用 SKU/专辑) - 按 type 调
cal*,discount=0 也返回(前端需过滤)
多活动:非取最优,先到先得 + discount 相加。
缓存:cartPromotion() / cartPromotionRange($id) TTL 7 天;活动 CRUD 时 expire。
5. 与 diy_offer / 券的关系
| 关系 | 说明 |
|---|---|
| vs bundlesale | 捆绑 SKU 整行 不参与 满减 |
| vs minmaxoffer | minmax 不挡满减;挡其它 diy_offer |
| vs 券 | 券在满减 之后;替换型券可 清零 满减(checkCouponUseWithPromotionStatus) |
| COD | 可能 未 走替换型券逻辑 → 双计风险 |
5.5 o_promotion 与 o_diy_offer 改价对比
⚡⚡⚡ o_promotion 不改 cart 行价,优惠额汇总后创单时分摊;o_diy_offer type=promotion 直接改 cart 行价。
| 体系 | 是否改 cart 行价 | 优惠额存在哪里 |
|---|---|---|
| o_promotion(满减 type1–7) | ❌ 否,行价不变 | cart.promotion_price(负值汇总)→ 创单 saveProducts 时分摊到 order_product.discount_price |
| o_diy_offer type=promotion(限时促销) | ✅ 是,直接改行 price/final_line_price | diy_offers.discount=0(InlinePrice);行 price 即已是折后价 |
o_promotion 典型流程:
购物车内行价(不变)
↓ getCartPromotion
cart.promotion_price +=满减优惠额(负值)
↓ 创单 saveProducts
OrderPriceService::calOrderProductDiscountPrice → 分摊到 order_product.discount_price
o_diy_offer type=promotion 典型流程:
购物车内行价(原价)
↓ calDiscount → changeCartPrice
行 price = 原价 × (1 - value/100) ← 直接改
或行 price = max(原价 - value, 0) ← reduction
或行 price = value ← definite_price
diy_offers.discount = 0
bundlesale / skubundlesale(AccruedDiscount):改行价 + diy_offers[].discount 记优惠额(负值)→ 进 cart.promotion_price 汇总。
gift(LineRebuild):不改行价,而是增删行,赠品行 final_price=0。
6. 订单字段
| 字段 | 来源 |
|---|---|
current_promotion_price | cart.promotion_price(含满减 + diy_offers.discount) |
o_order.promotion_id | 订单头 常为空/0;满减 ID 多在 order_product.promotion_id |
promotion_name | 行上汇总或订单头拼接 |
分摊:PromotionHandlerService::attachPromotionToCart → OrderPriceService 满减段。
7. 单测要点
| 场景 | 要点 |
|---|---|
| 多档 rule | 取 max(ge),非最优 |
| allocation_limit=999 | 倍数 floor |
| 两活动同 SKU | not_ranges 先到先得 |
| 捆绑 + 满减 | mutex 行不应进 promotion 计算 |
| discount=0 | getCartPromotion 仍返回,需过滤 |
| 替换型券 | promotion 清零、订单 current_promotion_price reconcile |
8. 代码索引
| 模块 | 路径 |
|---|---|
| 流水线 | common/services/PromotionHandlerService.php |
| 算法 | common/services/PromotionService.php — discountPrice |
| 挂载行 | PromotionHandlerService::attachPromotionToCart |
| Cart 入口 | CartService::getList 548–550 行 |