All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m12s
1. 修正 retail_price 架构:
- 删除 batch-pricing 接口的 pricing_target 字段和 retail_price 分支
(上级只能改下级成本价,不能改零售价)
- 新增 PATCH /api/admin/packages/:id/retail-price 接口
(代理自己改自己的零售价,校验 retail_price >= cost_price)
2. 清理旧微信 YAML 配置(已全部迁移到数据库 tb_wechat_config):
- 删除 config.yaml 中 wechat.official_account 配置节
- 删除 NewOfficialAccountApp() 旧工厂函数
- 清理 personal_customer service 中的死代码(旧登录/绑定微信方法)
- 清理 docker-compose.prod.yml 中旧微信环境变量和证书挂载注释
3. 归档四个已完成提案到 openspec/changes/archive/
4. 新增前端接口变更说明文档(docs/前端接口变更说明.md)
5. 修正归档提案和 specs 中关于 pricing_target 的错误描述
68 lines
8.2 KiB
Markdown
68 lines
8.2 KiB
Markdown
## Why
|
||
|
||
系统存在 4 个影响资金安全和业务正确性的 BUG,且即将启动客户端(C 端)接口体系开发。本提案作为客户端接口系列提案的**前置基础**,解决三类问题:
|
||
|
||
1. **资金/业务 BUG 修复**:代理零售价缺失导致价格计算错误(BUG-1)、后台订单误触发一次性佣金(BUG-2)、充值回调事务半提交风险(BUG-4)
|
||
2. **基础字段准备**:为客户端接口和换货系统新增必要的模型字段(`asset_status`、`generation`、`source`、`operator_type`、`realname_link_type`)
|
||
3. **旧接口清理**:删除基于 B 端认证体系的旧 H5 接口和旧个人客户登录接口,为新的 `/api/c/v1` 体系腾出空间
|
||
|
||
## What Changes
|
||
|
||
### BUG 修复
|
||
|
||
- **BUG-1 代理零售价修复**:`ShopPackageAllocation` 新增 `retail_price` 字段;`GetPurchasePrice()` 改为代理渠道查 `allocation.retail_price`、平台渠道用 `Package.SuggestedRetailPrice`;`validatePackages()` 内部价格累加同步修正;新增 cost_price 分配锁定规则(存在下级分配时禁止修改 cost_price);`BatchUpdatePricing` 接口仅支持成本价批量调整;新增独立接口 `PATCH /api/admin/packages/:id/retail-price` 供代理修改自己的零售价;**代理套餐列表(`PackageResponse`)新增 `retail_price` 字段**,代理可查看自己的零售价;**利润计算修正**为 `RetailPrice - CostPrice`(代理实际利润 = 零售价 - 成本价,而非建议售价 - 成本价)
|
||
- **BUG-2 一次性佣金触发修复**:`Order` 新增 `source` 字段(`admin`/`client`);佣金触发条件从 `!order.IsPurchaseOnBehalf` 改为 `!order.IsPurchaseOnBehalf && order.Source == "client"`,确保只有客户端个人客户购买才触发
|
||
- **BUG-4 充值回调事务修复**:`HandlePaymentCallback` 中 `UpdateStatusWithOptimisticLock` 和 `UpdatePaymentInfo` 从 `s.db.WithContext(ctx)` 改为事务内 `tx`,确保充值单状态变更和钱包入账原子完成
|
||
|
||
### 新增模型字段
|
||
|
||
- **`IotCard`/`Device` 新增 `asset_status`**:业务生命周期状态(1-在库 2-已销售 3-已换货 4-已停用),与运营商 `network_status` 独立
|
||
- **`IotCard`/`Device` 新增 `generation`**:资产世代编号,换货转新时 +1,客户端按当前 generation 过滤历史数据
|
||
- **`Order`/`PackageUsage`/`AssetRechargeRecord` 新增 `generation`**:创建时快照资产当前 generation,客户端查询按此字段过滤
|
||
- **`AssetRechargeRecord` 新增 `operator_type`**:区分操作人类型(`admin_user`/`personal_customer`),配合 `user_id` 区分不同 ID 体系
|
||
- **`AssetRechargeRecord` 新增强充关联字段**:`linked_package_ids`、`linked_order_type`、`linked_carrier_type`、`linked_carrier_id`,支持强充两阶段处理
|
||
- **`Carrier` 新增实名链接配置**:`realname_link_type`(none/template/gateway)、`realname_link_template`(支持 `{iccid}`/`{msisdn}`/`{virtual_no}` 占位符)。**同步更新 Carrier admin DTO**(`CarrierCreateRequest`/`CarrierUpdateRequest`)包含这两个字段,使后台管理员可通过 API 配置运营商实名链接方式
|
||
- **`PersonalCustomer` 索引变更**:`wx_open_id` 从唯一索引改为普通索引(支持后续多 OpenID 方案)
|
||
|
||
### 旧接口删除
|
||
|
||
- **删除全部旧 H5 接口**:`internal/handler/h5/` 下所有文件(auth、order、recharge、package_usage、enterprise_device)、`internal/routes/h5*.go` 路由注册
|
||
- **删除旧个人客户登录接口**:`internal/handler/app/personal_customer.go` 中的 Login、SendCode、WechatOAuthLogin、BindWechat、Profile 方法
|
||
- **同步清理**:bootstrap 中 H5 Handler 注册、docs.go/gendocs 中引用
|
||
|
||
## Capabilities
|
||
|
||
### New Capabilities
|
||
|
||
- `asset-lifecycle-status`:资产业务生命周期状态管理。IotCard/Device 新增 `asset_status` 字段(在库→已销售→已换货→已停用),定义状态流转规则,与运营商 `network_status` 完全独立
|
||
- `asset-generation`:资产世代机制。IotCard/Device 的 `generation` 字段,关联表(Order/PackageUsage/AssetRechargeRecord)的 generation 写时快照规则,客户端按世代过滤、后台不过滤的查询规则
|
||
- `carrier-realname-config`:运营商实名链接配置。Carrier 模型新增 `realname_link_type`/`realname_link_template` 字段,支持 none/template/gateway 三种模式,URL 模板占位符替换。**Carrier admin DTO 同步更新**,后台可通过现有运营商管理接口配置实名链接
|
||
- `agent-retail-price`:代理零售价管理。ShopPackageAllocation 新增 `retail_price` 字段,支持代理设定面向终端客户的零售价,约束 `retail_price >= cost_price`,cost_price 分配锁定规则。新增独立接口 `PATCH /api/admin/packages/:id/retail-price` 供代理修改自己的零售价;**代理套餐列表展示 retail_price**;**利润计算修正**为 `RetailPrice - CostPrice`
|
||
- `asset-manual-deactivation`:资产手动停用。新增后台接口 `PATCH /api/admin/iot-cards/:id/deactivate` 和 `PATCH /api/admin/devices/:id/deactivate`,将 `asset_status` 设为 4(已停用),仅 `asset_status=1`(在库)或 `asset_status=2`(已销售)时可操作
|
||
- `h5-legacy-cleanup`:旧 H5 接口和旧登录接口的完整删除,包括 handler、route、bootstrap 注册、文档生成器引用的清理
|
||
|
||
### Modified Capabilities
|
||
|
||
- `package-purchase-validation`:`GetPurchasePrice()` 价格来源改为按渠道区分(代理→retail_price,平台→SuggestedRetailPrice);`validatePackages()` 价格累加逻辑同步修正
|
||
- `package-list`:代理查询套餐列表时,`PackageResponse` 新增 `retail_price` 字段;`ProfitMargin` 计算从 `SuggestedRetailPrice - CostPrice` 改为 `RetailPrice - CostPrice`
|
||
- `batch-pricing`:`BatchUpdatePricing` 接口仅支持 `cost_price` 批量调整;保留 `cost_price` 锁定校验(存在下级分配时不可修改)
|
||
- `one-time-commission-trigger`:触发条件增加 `order.Source == "client"` 判断,确保仅客户端个人客户购买才触发
|
||
- `wallet-recharge`:`HandlePaymentCallback` 事务一致性修复,Store 方法支持传入事务 `tx`
|
||
- `iot-order`:Order 模型新增 `source`(订单来源)和 `generation`(世代)字段;`CreateAdminOrder()` 创建订单时从资产快照当前 `generation` 写入订单(而非依赖默认值 1)
|
||
- `iot-card`:IotCard 模型新增 `asset_status` 和 `generation` 字段
|
||
- `device`:Device 模型新增 `asset_status` 和 `generation` 字段
|
||
- `personal-customer`:`wx_open_id` 索引从唯一改为普通索引
|
||
- `asset-recharge-adaptation`:AssetRechargeRecord 新增 `operator_type`、`generation`、强充关联字段
|
||
|
||
## Impact
|
||
|
||
- **模型文件**:`shop_package_allocation.go`、`carrier.go`、`order.go`、`iot_card.go`、`device.go`、`package_usage.go`、`asset_recharge_record.go`、`personal_customer.go`
|
||
- **Service 文件**:`purchase_validation/service.go`(价格计算)、`commission_calculation/service.go`(佣金触发)、`recharge/service.go`(回调事务)、`shop_package_batch_pricing/service.go`(仅成本价批量调价 + cost_price 锁定)、`shop_series_grant/service.go`(cost_price 锁定)、`order/service.go`(source 设置 + generation 快照)、`package/service.go`(新增代理改零售价接口逻辑 + 利润计算修正 + PackageResponse 新增 retail_price)
|
||
- **Handler/DTO 文件**:`shop_package_batch_pricing.go` Handler(仅保留成本价批量调价)、`shop_package_batch_pricing_dto.go`(移除 `pricing_target` 字段)、`package.go` Handler(新增 `PATCH /packages/:id/retail-price`)、`package_dto.go`(`PackageResponse` 新增 `retail_price` + 新增更新零售价请求 DTO)、`carrier_dto.go`(新增实名链接字段)
|
||
- **Store 文件**:`asset_recharge_store.go`(支持事务传入)
|
||
- **删除文件**:`internal/handler/h5/` 全部(5 个文件)、`internal/routes/h5*.go`(3 个文件)、`internal/handler/app/personal_customer.go` 中旧方法
|
||
- **数据库迁移**:7 张表共 15+ 个字段变更,1 个索引变更
|
||
- **文档生成器**:`cmd/api/docs.go`、`cmd/gendocs/main.go` 移除 H5 Handler 引用
|
||
- **Bootstrap**:移除 H5 Handler 注册
|
||
- **性能**:所有变更为字段新增/修复,无查询性能影响;新增字段均带 DEFAULT 值,迁移可在线执行
|