各结账形态可用优惠对照

本文说明 五种结账形态 下四套优惠体系(o_diy_offer / o_promotion / o_coupon / o_order_diy_offer是否可用计算先后顺序如何写入订单。体系细节见 promotion-discount-checkout.md

与实现冲突时以代码为准。

目录


1. 四套体系速记

体系Cart 字段Order 字段作用阶段
diy_offer(购物车插件)o_diy_offerdiy_offers[]、行 diy_offer_idcurrent_promotion_price(与满减合计)、order_product.diy_offer_id加购~结账计价
promotion(标准满减)o_promotionpromotion[]promotion_price 一部分promotion_id/namecurrent_promotion_price购物车~结账计价
coupon(优惠券)o_couponcoupon_pricecoupon_codecoupon_id/codecurrent_coupon_price购物车预存~创单绑定
order_diy_offer(订单级)o_order_diy_offerdiy_offer_price(易混名)current_offer_price仅在线三种,物流/complete 步

易混cart.diy_offers[]cart.diy_offer_price(后者是 order_diy_offer 汇总)。


2. 总对照表(五种形态)

形态diy_offerpromotioncouponorder_diy_offer计价 Serviceo_order 计价
标准 standardCartService::getList创单后 ✅
单页 one_pagegetList + CheckoutOnePageService::getCart 补算创单后 ✅
渐进式 single_pageCartService::getList创单后 ✅
COD 带 token✅(有坑)CodCartService::getCartList❌ 仅内存
COD 单页✅(有坑)CodCartService(临时 DTO)

图例:

  • = 支持且与在线主链一致(或文档化差异见 §9)
  • = 不支持写入 o_order_diy_offer / current_offer_price(COD 表也无等价表)
  • coupon(有坑) = COD checkCouponUseWithPromotionStatus,替换型券可能与满减双计

3. 在线三种:统一计算顺序

主链:CartService::getList()(523–758 行)。

flowchart TD
    A[cartDataComposition 行价] --> B[defaultDiyOffer minmaxoffer]
    B --> C{has_minmaxoffer?}
    C -->|否| D[cartDiyOffers: promotion/bundlesale/skubundlesale]
    C -->|否| E[cartDiyOffers: gift]
    C -->|是| F[getCartPromotion o_promotion]
    D --> E --> F
    F --> G["promotion_price = Σ满减 + Σdiy_offers.discount"]
    G --> H[calPreCouponPrice 预券]
    H --> I[checkCouponUseWithPromotionStatus]
    I --> J{已有 order?}
    J -->|是| K[验券/税/运费 reconcile]
    K --> L[saveProducts 行 discount]
    K --> M[OrderDiyOfferService.updateDiyOfferInfo]
    J -->|否| N[仅内存 total]
    L --> O[total_price 汇总]
    M --> O
    N --> O
顺序步骤影响字段
1cartDataCompositionprice/final_price;过期限时促销清 diy_offer_id
2minmaxoffer可能 has_minmaxoffer=true跳过后续 diy_offer 类型
3cartDiyOffers(非 minmax)diy_offers[]、可能直接改行价
4getCartPromotionpromotion[]minmax 时仍执行
5汇总promotion_price(负值)
6calPreCouponPricecoupon_price(读 Cache 预券)
7checkCouponUseWithPromotionStatus替换型券可能 清零 promotion_price
8有订单时 reconcile写回 o_order.current_*saveProducts 刷新行
9updateDiyOfferInfodiy_offer_pricecurrent_offer_price + o_order_diy_offer
10汇总 total_price见 promotion-discount-checkout §2.2 公式

单页额外步骤CheckoutOnePageService::getCart):在 getList 之后按请求再算 券/税/运费/险/小费/支付费(744–767 行),不改变 1–7 的商品优惠顺序。


4. COD 两种:计算顺序与差异

CodCartService::getCartList()(20–61 行):

顺序在线 CartServiceCOD
行价组装cartDataCompositioncodCartDataComposition
minmaxoffer
diy_offer 批次promotion/bundlesale/skubundlesale 然后 gift(两轮)同一轮 promotion/bundlesale/skubundales/gift
满减getCartPromotion
promotion_price
预券CouponHandlerService::calPreCouponPriceCodCouponService::calPreCouponPrice
替换型券清满减checkCouponUseWithPromotionStatus❌ 未调用
order_diy_offerupdateDiyOfferInfo
写 MySQL 订单getList reconcilesaveOrder 一次o_cod_order

COD 订单字段:current_promotion_pricecurrent_coupon_pricecurrent_offer_price(offer 来自 cart 级 diy 折扣, o_order_diy_offer 表)。


5. 各形态:用券入口与落库时机

形态用券 API / 时机绑定订单刷新行价
标准GET /coupon/use/{token};创单 savePreCoupono_order.coupon_*saveProducts(getList reconcile)
单页complete/presavetrans_info.coupon_codecalCartCouponPricesavePreCouponsaveOrderProducts
渐进式POST .../use-couponsavePreCoupon同标准同标准
COD tokenPOST .../use-coupon → Cache;saveOrder 读 DTOo_cod_order.coupon_*CodOrderProductService 创单时
COD 单页请求 trans_info.coupon_code / 预券 Cacheo_cod_order创单时

购物车阶段(未创单):POST /coupons 或 COD use-coupon 仅写 预券 Cache,不落订单。


6. 各形态:order_diy_offer

形态是否支持写入 API / 参数典型 type
标准shipping_method POST → offer_from_name积分、Seel、deliveryprotec
单页complete / preCompletetrans_info.offer_from_name同上
渐进式shipping-method POST → offer_from_name同上
COD积分/Seel 不可用
COD 单页同上

写入 Service:OrderDiyOfferHandleService::saveDiyOffer → 表 o_order_diy_offer;汇总进 o_order.current_offer_price


7. 订单 / 行字段影响一览

7.1 订单头(在线 o_order / COD o_cod_order

优惠来源主要写入字段何时持久化
diy_offer + promotioncurrent_promotion_pricepromotion_id(满减时)创单初值;getList reconcile;complete/saveProducts
couponcoupon_idcoupon_codecurrent_coupon_pricesavePreCoupon / useCoupon / reconcile
order_diy_offercurrent_offer_priceshipping/complete 步 saveDiyOffer;getList updateDiyOfferInfo
汇总current_subtotal_pricetotal_pricecurrent_* 全套各 POST 步 + renew

7.2 订单行 o_order_product / o_cod_order_product

来源字段
行活动diy_offer_id
分摊后单价discount_priceOrderPriceService::calOrderProductDiscountPrice
属性o_order_product_property

分摊在 OrderService::saveProducts(在线)或 COD 创单 时执行。


8. 行级 discount_price 分摊顺序

OrderPriceService::calOrderProductDiscountPrice()(在线,saveProducts 内):

顺序扣减来源
1基线 = final_price(变体+属性)
2diy_offer 行 discount
3优惠券(按适用商品比例)
4满减 promotion(按 product_list)

时机OrderService::saveProducts(创单)时执行 calOrderProductDiscountPrice,逐层递减计算每行 discount_price。cart 阶段不出现在 discount_price 字段。

注意:cart 阶段 promotion_price 先汇总满减+diy_offers;行分摊顺序为 diy → 券 → 满减(与汇总顺序不同层)。


9. 已知差异与排障

现象原因
COD 替换型券仍带满减未调 checkCouponUseWithPromotionStatus
单页 price 与 complete 不一致complete 前未传齐 shipping/coupon/offer_from_name
积分未扣COD 不支持;在线查对应步是否传 offer_from_name
diy_offer_price 为 0 但有积分混淆 diy_offers[]order_diy_offer
改 cart 后 order 价不变未触发 getList reconcile(需 has_contact_information 或 order 存在)

10. 分形态详细链路

各形态文档内 § 可用优惠 为本表在该形态下的具体 API 与步骤;完整流程见:

购物车 Redis / 加购逻辑见 shopping-cart.md


体系细则:promotion-discount-checkout.md · FAQ:faq.md