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 的错误描述
129 lines
5.6 KiB
Markdown
129 lines
5.6 KiB
Markdown
# 客户端接口数据模型基础准备 - 功能总结
|
||
|
||
## 概述
|
||
|
||
本提案作为客户端接口系列的前置基础,完成三类工作:BUG 修复、基础字段准备、旧接口清理。
|
||
|
||
## 一、BUG 修复
|
||
|
||
### BUG-1:代理零售价修复
|
||
|
||
**问题**:`ShopPackageAllocation` 缺少 `retail_price` 字段,所有渠道统一使用 `Package.SuggestedRetailPrice`,代理无法设定自己的零售价。
|
||
|
||
**修复内容**:
|
||
|
||
- `ShopPackageAllocation` 新增 `retail_price` 字段(迁移中存量数据批量回填为 `SuggestedRetailPrice`)
|
||
- `GetPurchasePrice()` 改为按渠道取价:代理渠道返回 `allocation.RetailPrice`,平台渠道返回 `SuggestedRetailPrice`
|
||
- `validatePackages()` 价格累加同步修正,代理渠道额外校验 `RetailPrice >= CostPrice`
|
||
- 分配创建(`shop_package_batch_allocation`、`shop_series_grant`)时自动设置 `RetailPrice = SuggestedRetailPrice`
|
||
- 新增 cost_price 分配锁定:存在下级分配记录时禁止修改 `cost_price`
|
||
- `BatchUpdatePricing` 接口仅支持成本价批量调整(保留 cost_price 锁定规则)
|
||
- 新增独立接口 `PATCH /api/admin/packages/:id/retail-price`,代理可修改自己的套餐零售价
|
||
- `PackageResponse` 新增 `retail_price` 字段,利润计算修正为 `RetailPrice - CostPrice`
|
||
|
||
**涉及文件**:
|
||
- `internal/model/shop_package_allocation.go`
|
||
- `internal/model/dto/shop_package_batch_pricing_dto.go`
|
||
- `internal/model/dto/package_dto.go`
|
||
- `internal/service/purchase_validation/service.go`
|
||
- `internal/service/shop_package_batch_allocation/service.go`
|
||
- `internal/service/shop_series_grant/service.go`
|
||
- `internal/service/shop_package_batch_pricing/service.go`
|
||
- `internal/service/package/service.go`
|
||
|
||
### BUG-2:一次性佣金触发条件修复
|
||
|
||
**问题**:后台所有订单(包括代理自购)都可能触发一次性佣金。
|
||
|
||
**修复内容**:
|
||
|
||
- `Order` 新增 `source` 字段(`admin`/`client`),默认 `admin`
|
||
- 佣金触发条件从 `!order.IsPurchaseOnBehalf` 改为 `!order.IsPurchaseOnBehalf && order.Source == "client"`
|
||
- `CreateAdminOrder()` 设置 `Source: constants.OrderSourceAdmin`
|
||
|
||
**涉及文件**:
|
||
- `internal/model/order.go`
|
||
- `internal/service/commission_calculation/service.go`(两个方法)
|
||
- `internal/service/order/service.go`
|
||
|
||
### BUG-4:充值回调事务一致性修复
|
||
|
||
**问题**:`HandlePaymentCallback` 中 `UpdateStatusWithOptimisticLock` 和 `UpdatePaymentInfo` 使用 `s.db` 而非事务内 `tx`。
|
||
|
||
**修复内容**:
|
||
|
||
- `AssetRechargeStore` 新增 `UpdateStatusWithOptimisticLockDB` 和 `UpdatePaymentInfoWithDB` 方法(支持传入 `tx`)
|
||
- 原方法保留(委托调用新方法),确保向后兼容
|
||
- `HandlePaymentCallback` 改用事务内 `tx` 调用
|
||
|
||
**涉及文件**:
|
||
- `internal/store/postgres/asset_recharge_store.go`
|
||
- `internal/service/recharge/service.go`
|
||
|
||
## 二、基础字段准备
|
||
|
||
### 新增常量文件
|
||
|
||
| 文件 | 内容 |
|
||
|------|------|
|
||
| `pkg/constants/asset_status.go` | 资产业务状态(在库/已销售/已换货/已停用) |
|
||
| `pkg/constants/order_source.go` | 订单来源(admin/client) |
|
||
| `pkg/constants/operator_type.go` | 操作人类型(admin_user/personal_customer) |
|
||
| `pkg/constants/realname_link.go` | 实名链接类型(none/template/gateway) |
|
||
|
||
### 模型字段变更
|
||
|
||
| 模型 | 新增字段 | 说明 |
|
||
|------|---------|------|
|
||
| `IotCard` | `asset_status`, `generation` | 业务生命周期状态、资产世代编号 |
|
||
| `Device` | `asset_status`, `generation` | 同上 |
|
||
| `Order` | `source`, `generation` | 订单来源、资产世代快照 |
|
||
| `PackageUsage` | `generation` | 资产世代快照 |
|
||
| `AssetRechargeRecord` | `operator_type`, `generation`, `linked_package_ids`, `linked_order_type`, `linked_carrier_type`, `linked_carrier_id` | 操作人类型、世代、强充关联字段 |
|
||
| `Carrier` | `realname_link_type`, `realname_link_template` | 实名链接配置 |
|
||
| `ShopPackageAllocation` | `retail_price` | 代理零售价 |
|
||
| `PersonalCustomer` | `wx_open_id` 索引变更 | 唯一索引改为普通索引 |
|
||
|
||
### Carrier 管理 DTO 更新
|
||
|
||
- `CarrierCreateRequest`、`CarrierUpdateRequest` 新增 `realname_link_type` 和 `realname_link_template` 字段
|
||
- `CarrierResponse` 新增对应展示字段
|
||
- Carrier Service 的 Create/Update 方法同步处理,Update 时 `template` 类型强制校验模板非空
|
||
|
||
### 资产手动停用
|
||
|
||
- 新增 `PATCH /api/admin/iot-cards/:id/deactivate` 和 `PATCH /api/admin/devices/:id/deactivate`
|
||
- 仅 `asset_status` 为 1(在库)或 2(已销售)时允许停用
|
||
- 使用条件更新确保幂等
|
||
|
||
## 三、旧接口清理
|
||
|
||
### H5 接口删除
|
||
|
||
- 删除 `internal/handler/h5/` 全部文件(5 个)
|
||
- 删除 `internal/routes/h5*.go`(3 个文件)
|
||
- 清理 `routes.go`、`order.go`、`recharge.go` 中的 H5 路由注册
|
||
- 清理 `bootstrap/` 中 H5 Handler 构造和字段
|
||
- 清理 `middlewares.go` 中 H5 认证中间件
|
||
- 清理 `pkg/openapi/handlers.go` 中 H5 文档生成引用
|
||
- 清理 `cmd/api/main.go` 中 H5 限流挂载
|
||
|
||
### 个人客户旧登录方法删除
|
||
|
||
- 删除 `internal/handler/app/personal_customer.go` 中 Login、SendCode、WechatOAuthLogin、BindWechat 方法
|
||
- 清理对应路由注册
|
||
- 保留 UpdateProfile 和 GetProfile
|
||
|
||
## 四、数据库迁移
|
||
|
||
- 迁移编号:000082
|
||
- 涉及 7 张表、15+ 个字段变更
|
||
- 包含存量 `retail_price` 批量回填
|
||
- 包含 `wx_open_id` 索引从唯一改为普通
|
||
- 所有字段使用 `NOT NULL DEFAULT` 确保存量兼容
|
||
|
||
## 五、后台订单 generation 快照
|
||
|
||
- `CreateAdminOrder()` 创建订单时从资产(IotCard/Device)获取当前 `Generation` 值写入订单
|
||
- 不再依赖数据库默认值 1
|