hl-api-changelog/changelogs/2026-04/2026-04-21_mp-quote-early-bird.md
API Changelog Bot 5915b439b5 docs(mp-product): 小程序报价接口补早鸟优惠字段 (PR #1052)
MpQuoteResultVO 新增 5 个字段: earlyBirdDiscount / earlyBirdPlanId /
earlyBirdPlanName / finalBalanceAmount / finalGrandTotal

- 定金模式: 早鸟扣尾款 → finalBalanceAmount = balanceAmount - discount
- 全款模式: 早鸟扣全款 → finalGrandTotal = grandTotal - discount
- 未命中: earlyBirdDiscount=0, finalXxx=原值
2026-04-21 10:04:52 +08:00

5.9 KiB

小程序产品报价 - /mp/product/{id}/quote 接口补早鸟优惠字段

  • 日期: 2026-04-21
  • PR: #1052 (Closes #1047)
  • 类型: FEATURE响应 VO 新增字段,向前兼容)
  • 服务: hl-product-service-v2路由 /mp/product/**
  • 前端是否需要改动: 建议改动(展示早鸟优惠金额 + 最终应付金额给用户)

一、背景

之前的报价接口只返回「原价合计」与「原尾款/定金」,但订单创建时后端会自动扣早鸟优惠OrderCreateService.tryApplyEarlyBirdDiscount()),导致:

  • 小程序报价页显示 ¥10,510 尾款
  • 用户提交订单实付却是 ¥10,410(已扣 100 元早鸟)
  • 用户困惑 / 客服被投诉报价不准

本次修复让报价接口同步返回早鸟优惠信息,与订单实扣完全一致。


二、变更接口

# 方法 路径 变更类型
1 POST /mp/product/{id}/quote 响应 VO 新增 5 个字段;请求参数不变

三、响应 VO 新增字段(MpQuoteResultVO

字段 类型 含义 示例
earlyBirdDiscount BigDecimal 早鸟优惠金额(未命中为 0 100.00
earlyBirdPlanId Long (字符串) 命中的早鸟计划 ID未命中为 null "2046080027564318721"
earlyBirdPlanName String 命中的早鸟计划名称(展示用,未命中为 null "暑期早鸟"
finalBalanceAmount BigDecimal 定金模式下最终应付尾款 = balanceAmount - earlyBirdDiscount;全款模式为 null 10410.00
finalGrandTotal BigDecimal 最终应付总价 = grandTotal - earlyBirdDiscount 11410.00

其它字段不变grandTotal / balanceAmount / depositAmount 仍是「原始价」,仅新增的 finalXxx 是「扣优惠后最终应付」。


四、业务规则(与订单实扣对齐)

  • 早鸟优惠按下单日期生效(调用报价的当下,等于订单创建时的日期)
  • 定金模式 (DEPOSIT):定金原价收,早鸟优惠从尾款扣
    • finalBalanceAmount = balanceAmount - earlyBirdDiscount
    • finalGrandTotal = grandTotal - earlyBirdDiscount(整单一致)
  • 全款模式 (FULL):早鸟优惠从全款扣
    • finalBalanceAmount = null
    • finalGrandTotal = grandTotal - earlyBirdDiscount
  • 未命中 / 查询失败earlyBirdDiscount = 0earlyBirdPlanId = nullfinalXxx = 原值
  • 人数门槛:总人数(成人 + 儿童 + 小童 + 幼童)< 计划 minPeople → 不命中
  • 金额封顶:早鸟优惠 ≤ 对应金额池(定金模式下不超过尾款;全款模式下不超过总价),不会让尾款 / 全款为负

五、响应示例

定金模式 + 命中早鸟2 成人)

{
  "code": 200,
  "success": true,
  "data": {
    "adultUnitPrice": 5755.00,
    "totalAdultPrice": 11510.00,
    "grandTotal": 11510.00,
    "paymentType": "DEPOSIT",
    "depositAmount": 1000.00,
    "balanceAmount": 10510.00,

    "earlyBirdDiscount": 100.00,
    "earlyBirdPlanId": "2046080027564318721",
    "earlyBirdPlanName": "BUG20测试-2人",
    "finalBalanceAmount": 10410.00,
    "finalGrandTotal": 11410.00
  }
}

全款模式 + 命中早鸟

{
  "data": {
    "grandTotal": 8000.00,
    "paymentType": "FULL",
    "balanceAmount": null,

    "earlyBirdDiscount": 500.00,
    "earlyBirdPlanId": "1234567890",
    "earlyBirdPlanName": "全款早鸟",
    "finalBalanceAmount": null,
    "finalGrandTotal": 7500.00
  }
}

未命中早鸟

{
  "data": {
    "grandTotal": 5000.00,
    "balanceAmount": 4000.00,

    "earlyBirdDiscount": 0,
    "earlyBirdPlanId": null,
    "earlyBirdPlanName": null,
    "finalBalanceAmount": 4000.00,
    "finalGrandTotal": 5000.00
  }
}

六、前端使用建议

场景 A报价页展示早鸟优惠

{data.earlyBirdDiscount > 0 && (
  <View className="discount-row">
    <Text>早鸟优惠 {data.earlyBirdPlanName}</Text>
    <Text>-¥{data.earlyBirdDiscount}</Text>
  </View>
)}

场景 B定金模式下拆分展示

<View>订金(立付):¥{data.depositAmount}</View>

{data.earlyBirdDiscount > 0 ? (
  <>
    <View className="original">原尾款:<s>¥{data.balanceAmount}</s></View>
    <View className="final">最终尾款:<b>¥{data.finalBalanceAmount}</b></View>
  </>
) : (
  <View>尾款:¥{data.balanceAmount}</View>
)}

场景 C全款模式下拆分展示

{data.paymentType === 'FULL' && data.earlyBirdDiscount > 0 ? (
  <>
    <View>原价:<s>¥{data.grandTotal}</s></View>
    <View className="final">最终应付:<b>¥{data.finalGrandTotal}</b></View>
  </>
) : (
  <View>应付:¥{data.grandTotal}</View>
)}

⚠️ 注意

  • earlyBirdPlanId 是 Long,JSON 序列化为字符串防精度丢失(与项目其它 ID 字段一致)
  • 未命中早鸟时 finalBalanceAmount / finalGrandTotal 等于原值,可以无脑展示 finalXxx(无需判断)
  • earlyBirdDiscount 一定是 BigDecimal 形式的数字(0>0),不会是 null
  • 全款模式finalBalanceAmount 固定为 null(与 balanceAmount 语义保持一致)

七、不兼容变更

。仅响应 VO 新增字段,既有字段语义与取值完全不变。旧客户端(没更新适配的)继续按原逻辑渲染,只是看不到早鸟优惠而已。


八、回归验证

# 测试产品(班期内有早鸟"BUG20测试-2人"
curl -sk -X POST "https://api.test.1814.love:9443/mp/product/2044603865881333762/quote" \
  -H "Content-Type: application/json" \
  -d '{"departureDate":"2026-05-10","adultCount":2,"childCount":0,"tierSeq":1}' | jq .data

预期

  • earlyBirdDiscount: 100.00
  • earlyBirdPlanName: "BUG20测试-2人"
  • finalBalanceAmount = balanceAmount - 100
  • finalGrandTotal = grandTotal - 100