From 3fccc2381b9dc9a19b9e21b14c04b6ebf9aa92ea Mon Sep 17 00:00:00 2001 From: API Changelog Bot Date: Tue, 12 May 2026 10:18:28 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BA=A7=E5=93=81=20V2=20=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E4=B8=A4=E9=A1=B9=E4=BF=AE=E5=A4=8D(=E9=87=8C?= =?UTF-8?q?=E7=A8=8B=E8=A2=AB=E8=A6=86=E7=9B=96=20+=20=E5=84=BF=E7=AB=A5?= =?UTF-8?q?=E5=94=AE=E4=BB=B7=3D0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #2067 (commit d30bd995): - #2064 行程编排日里程手动改后保存被高德自动计算覆盖 - #2066 价格日历批量设置允许儿童售价等于 0(儿童免费) 测试服 admin token round-trip 4 case 全过(2026-05-12 10:14-10:15)。 Co-Authored-By: Claude Opus 4.7 (1M context) --- ...2-mileage-override-and-child-price-zero.md | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 changelogs/2026-05/12_fix_admin_product-v2-mileage-override-and-child-price-zero.md diff --git a/changelogs/2026-05/12_fix_admin_product-v2-mileage-override-and-child-price-zero.md b/changelogs/2026-05/12_fix_admin_product-v2-mileage-override-and-child-price-zero.md new file mode 100644 index 0000000..64ec75c --- /dev/null +++ b/changelogs/2026-05/12_fix_admin_product-v2-mileage-override-and-child-price-zero.md @@ -0,0 +1,100 @@ +# 后端 fix 通知 — 产品 V2 编辑两项修复(里程被覆盖 + 儿童售价=0) + +**日期**: 2026-05-12 +**类型**: 后端修复 (PR #2067, merge commit `d30bd995`) +**模块**: 产品 V2 编辑 → 行程编排 / 价格日历批量 +**通知**: @mmg +**前端是否需改动**: **可选**(后端兼容现有前端行为, 修复后即生效; 若要支持"取消手动锁回到自动计算"则需小调整, 见下) +**严重性**: P1(行程里程) + P2(儿童售价=0) + +--- + +## 修复 1: 行程编排「当日里程」手动改后保存被高德覆盖 (Closes #2064) + +### 现象 +产品 V2 编辑页 → 第 2 步「行程编排」→ DAY N → 修改「里程」输入框为某个值(如 180 km)→ 保存 → 刷新页面 → 里程又变回了高德自动计算的数字。 + +### 根因 +后端有 `mileageManualOverride` 开关字段标记是否人工覆盖。前端编辑 `dailyMileage` 时只传数值未带 override=true, 后端 MP `updateById` NOT_NULL 策略跳过 null 字段, DB 中 override 保持 0, 事务提交后 `ItineraryAutoCalculator` 调高德 API 重新覆盖用户输入。 + +### 修复 +后端 `ProductItineraryService.convertDay` 兜底: 当前端传了 `dailyMileage` 但未显式传 `mileageManualOverride` 时, 自动视为手动覆盖(置为 TRUE), 阻断 autocalc 覆盖。 + +### 前端 mmg 完全无需改动 +前端继续按当前逻辑只提交 `dailyMileage` 即可, 后端兜底已覆盖。 + +### 如果要支持「重置回自动计算」(可选, 不是必做) +若想加一个"刷新/重置"按钮让用户撤销手动锁、回到高德自动值, 需: +1. 该天 SaveReqVO 显式传 `dailyMileage: null` **且** `mileageManualOverride: false` +2. 保存后等 1-2 秒, 后端 autocalc 会重算并填入 + +截图里看到里程字段旁有圆形刷新图标和 × 按钮, 如果这两个图标已绑此语义, 检查一下提交时是否真的清空 dailyMileage + 显式 override=false。 + +--- + +## 修复 2: 价格日历批量设置允许儿童售价 = 0 (Closes #2066) + +### 现象 +价格日历批量设置中, 儿童售价填 `0` 报「儿童售价必须大于0」无法保存。业务上 `0` 表示儿童免费应允许。 + +### 修复 +后端 4 处放宽: +1. `PriceCalendarBatchReqVO.childSellPrice` `@DecimalMin` 0.01 → 0.00, 文案改"儿童售价不能为负数" +2. `ProductPricingService` 第一道校验拆分: null → 原 REQUIRED 错误码; <0 → 新错误码 `PRICE_CHILD_SELL_PRICE_NEGATIVE` (410112) +3. `ProductPricingService` 固定订金模式: `childSellPrice=0` 时跳过"必须>订金"校验 +4. `ProductBasicService` 反向校验对称处理: 调订金时若现存价格日历/班期 `childPrice=0` 视为免费跳过, 避免"正向能设 0、反向改订金又被卡" + +成人售价校验维持 `>0` 不变, 不允许成人售价 0。 + +### 前端 mmg 行为变化 +- 儿童售价输入框: 现在允许填 `0`(免费) +- 儿童售价 = 负数: 仍报错, 文案变成「儿童售价不能为负数」(原"必须大于0") +- 成人售价: 维持 `>0`, 不可填 0 + +如果前端有"儿童售价 ≥ 0.01"的本地校验, **请放宽到 ≥ 0**(允许 0.00, 不允许负数)。 + +--- + +## ✅ 测试服真测(2026-05-12 10:04 部署, 10:14-10:15 真测) + +测试服 admin token (test_admin) 经网关 `api.test.1814.love:9443` 真测, 用产品 `2053662735618506754`: + +### Case 1: BUG #2064 修复验证 + +| 步骤 | 操作 | 结果 | +|------|------|------| +| baseline | DAY 2 (dayId=2053662735677227011) `daily_mileage=140.0` `override=1` | — | +| 改动 | PUT `/admin/product/item/{id}/itinerary` DAY 2 `dailyMileage=888.0`, **不传 override** | HTTP 200, code=200, msg="行程保存成功" | +| 等 8s | autocalc 在 10:14:11 跑完 `自动计算每日里程完成, 天数=7` | — | +| 验证 | SQL `daily_mileage=888.0` `mileage_manual_override=1` | ✅ 888 未被高德覆盖 | + +### Case 2: BUG #2066 修复验证 + +| 步骤 | 操作 | 结果 | +|------|------|------| +| 改动 | POST `/admin/product/item/{id}/price-calendar/batch`, `childSellPrice=0, adultSellPrice=1999, date=2026-12-15, tier=1, NORMAL` | HTTP 200, code=200, msg="价格日历设置成功" | +| 验证 | SQL `child_sell_price=0.00, adult_sell_price=1999.00, price_type=NORMAL` | ✅ child=0 落库 | + +### Case 3: 边界 — 儿童售价 = -1 仍拦 + +- POST 同上 `childSellPrice=-1` → HTTP 200, **code=400** msg="**儿童售价不能为负数**" success=false ✅ + +### Case 4: 旁证 — autocalc 在 override=false 时正常生效 + +- DAY 3 显式传 `mileageManualOverride=false` 且不传 `dailyMileage` → 8s 后 SQL `daily_mileage=0.0 override=0`, 日志 10:15:36 `自动计算每日里程完成` — autocalc 正常生效(该天集散坐标相同高德返 0km, 是预期结果) + +--- + +## 影响面 / 兼容性 + +- 接口签名零变化 — 任何前端代码不改也能直接用 +- 已部署: 测试服 product-v2 双实例(8083 + 8183) 已是含修复的版本 +- 历史已被高德覆盖的天: 下次用户手动改并保存即可锁住, 无需脏数据修复 +- 已有 `mileage_manual_override=1` 的天不受影响 +- 历史已有 `childSellPrice` 数据不受影响, 仅前向允许 0 入库 + +## 关联 + +- PR: https://git.1814.love:8443/wx/HL/pulls/2067 +- Issue #2064: https://git.1814.love:8443/wx/HL/issues/2064 +- Issue #2066: https://git.1814.love:8443/wx/HL/issues/2066