对应spec.md FR-028~FR-036与plan.md本次变更;本文是Claude Code实施契约,接口/字段当前尚未上线。所有金额为与现有订单一致的新台币元,整数元口径,禁止擅自乘100。
promotionPricingVersion=2显式接入;不接入036批次、商家自配送、闪送、自取或堂食。POST /app/userPromotionCalc/calculate的body和finalAmount含义保持,不能偷偷让finalAmount包含/扣除配送费。新配送上下文只能由服务端应用层构造。沿用/system/shPromotionActivity的POST/PUT和既有GET/结束/删除接口,不重新拆参数。登录token在Header;新增业务参数全部在body。
创建示例:
{
"storeId": 1,
"type": 5,
"name": "原价满100免配送费",
"startTime": "2026-10-19",
"endTime": "2026-10-31",
"rules": [{ "threshold": 100 }]
}
修改在同body增加id,仅允许有效状态未开始的活动;详情同样返回type=5和threshold。规则只能一条且threshold为正整数元,不填写reduceAmount、productId、discountRate。日期按本地整天含首尾日;人工结束优先,状态展示与算价必须一致;同店同类型日期不能重叠。普通商家与夜市场景均验证真实门店管理归属。
POST /app/userPromotionCalc/deliveryQuote,Header token,明确FoodDeliveryPromotionQuoteRequest DTO。
{
"storeId": 1,
"orderType": 0,
"addressId": 8,
"delryTime": null,
"items": [{ "productId": 10, "quantity": 2, "specValueIds": [] }],
"couponId": null,
"forcePath": null
}
yyyy-MM-dd HH:mm-HH:mm预约格式;实际配送模式按预约时段判定,活动资格按报价/创建时日期。以下为AjaxResult.data内关键字段示例(原价100、配送费30、预算20,普通商品优惠实减0):
{
"pricingVersion": 2,
"originalAmount": 100,
"finalAmount": 100,
"deliveryFee": 30,
"deliveryDiscountAmount": 30,
"customerDeliveryFee": 0,
"payableAmount": 100,
"freeDeliveryActivityId": 51,
"freeDeliveryThreshold": 100,
"discountBudget": 20,
"remainingDiscountBudget": 0,
"appliedCouponId": null,
"details": [
{
"type": "promotion",
"subType": 5,
"name": "原价满100免配送费",
"refId": 51,
"reduce": 30,
"originalAmount": 100,
"deliveryFee": 30,
"customerDeliveryFee": 0,
"threshold": 100
}
]
}
| 字段 | Java类型 | 定义 |
|---|---|---|
| pricingVersion | Integer | 新完整配送报价固定2;旧接口可不返回 |
| originalAmount / finalAmount | BigDecimal | O商品原价 / G优惠后商品金额,保留旧含义 |
| deliveryFee | BigDecimal | R原配送费,也是骑手毛配送费基数 |
| deliveryDiscountAmount | BigDecimal | F本活动免运减免;不再从G扣 |
| customerDeliveryFee | BigDecimal | D客户实际支付配送费 |
| payableAmount | BigDecimal | A=G+D,客户整单应付 |
| freeDeliveryActivityId / freeDeliveryThreshold | Long / BigDecimal | 命中活动ID/原价门槛;未命中可为null |
| discountBudget / remainingDiscountBudget | BigDecimal | 总预算B / 全部受限优惠分配后剩余预算;开关关闭用null表示无限,不能用0表示 |
| couponId / appliedCouponId | Long / Long | 原字段保留用户选择意图;新增字段仅实际生效且实减>0时返回,核销以appliedCouponId为准 |
PromotionDetail的originalAmount/deliveryFee/customerDeliveryFee/threshold为type=5快照扩展字段;其他旧明细可为null。活动未命中时不返回虚假type=5优惠记录;R=0时优惠额为0,不核销券。路径A/B保持原字段,新增完整报价默认选应用预算后的A最小路径;forcePath保留手选。
免运命中时免配送费券usable=false,理由为本地化“本单已享受满额免运”;不消费该券。预算耗尽的其他券预估实减0、不可用;选择这些券也不生成appliedCouponId。既有无免运场景的旧配送券偏差不借本次扩展全局改写。
继续使用UserOrderController现有POST /system/userOrder/createOrder,不创建第二套订单生命周期。新单在items[0]增加promotionPricingVersion: 2,cartItems提供productId/quantity/specValueIds;父/子type都必须0且只有一家门店。沿用已有shdzId作为addressId。
promotion.freeDelivery.quoteChanged,事务回滚。不要由前端把原freight改为0。promotion_pricing_version=2、merchant_delivery_subsidy=F、customer_delivery_fee=D;freight继续R、amount继续A。type=5活动明细写已有pos_order_promotion并固化门槛与金额,不占商品减免汇总。仅新增可选响应,不要求App本轮渲染;金额由后端快照/支付方式派生,不新存现金确认状态。
| 场景(G100/R30/F30/D0/A100) | merchantPayToRider | riderPayToMerchant | customerCollectAmount |
|---|---|---|---|
| 在线已付 | 30 | 0 | 0 |
| 到付 | 0 | 70 | 100 |
| 到付G20/R30/F30/D0/A20 | 10 | 0 | 20 |
返回的交款字段均为BigDecimal且非负,不能只给一个无方向的负数。字段作为PosOrder新增的@TableField(exist=false)派生属性/getter从快照计算,保留现有返回PosOrder的查询路径;legacy订单可不返回这些新字段,禁止为三个派生数值新增数据库列。到付依现有collectPayment/payType语义判断;支付切换后的查询即时反映新方向。骑手净收入仍按R减原佣金/税,不把毛运费说成到手金额。现金交付和现有钱包账单不是两次支付。
发票按既有不含客户配送费口径取A−D,免运示例为100;退款最多退渠道实际支付A,不另外退F。新流程商家商品分成基数为G,不重复从餐费减去免运。
门槛100、预算比例20%,无半价例外,商品优惠/券按既有可用规则:
| O | R | 商品受限优惠 | F | D | G | A | 说明 |
|---|---|---|---|---|---|---|---|
| 100 | 30 | 0 | 30 | 0 | 100 | 100 | 免运可超预算 |
| 100 | 20 | 0 | 20 | 0 | 100 | 100 | 预算刚好用完 |
| 100 | 10 | 10 | 10 | 0 | 90 | 90 | 其他优惠最多剩10 |
| 99 | 30 | 0 | 0 | 30 | 99 | 129 | 原价未达标 |
| 100 | 30 | 30(预算关闭) | 30 | 0 | 70 | 70 | 优惠后不足门槛仍免运 |
| 100 | 30 | 半价25(豁免) | 30 | 0 | 75 | 75 | 保留原半价例外 |
新增本地化key至少包含promotion.freeDelivery.invalidThreshold、invalidRules、forbiddenStore、overlap、invalidAddress、invalidProduct、invalidSpec、unsupportedOrder、freightUnavailable、alreadyApplied、quoteChanged、invalidSnapshot(后三段同前缀)。沿用AjaxResult业务错误机制,不硬编码中文。
本轮验收覆盖商家PC及后端新接口;App用户端、商家App、骑手App的渲染与新报价接入未实施,不得在交付中标记已完成。将来App只需按本契约对接,不重新讨论门槛与预算规则。