订单相关以及佣金相关修复
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m57s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m57s
This commit is contained in:
@@ -1123,7 +1123,7 @@ components:
|
||||
DtoAssetResolveResponse:
|
||||
properties:
|
||||
activated_at:
|
||||
description: 激活时间
|
||||
description: 激活时间(未来准备移除,请勿依赖)
|
||||
format: date-time
|
||||
nullable: true
|
||||
type: string
|
||||
@@ -3440,6 +3440,12 @@ components:
|
||||
network_status:
|
||||
description: 网络状态:0停机 1开机(asset_type=card时有效)
|
||||
type: integer
|
||||
real_name_status:
|
||||
description: 实名状态 (0:未实名, 1:已实名)
|
||||
type: integer
|
||||
real_name_status_name:
|
||||
description: 实名状态名称(中文)
|
||||
type: string
|
||||
realname_policy:
|
||||
description: 实名认证策略 (none:无需实名, before_order:先实名后充值/购买, after_order:先充值/购买后实名)
|
||||
type: string
|
||||
@@ -5449,11 +5455,17 @@ components:
|
||||
commission_config_version:
|
||||
description: 佣金配置版本
|
||||
type: integer
|
||||
commission_result:
|
||||
description: 佣金业务结果 (0:未知, 1:有佣金, 2:无佣金, 3:链路异常)
|
||||
type: integer
|
||||
commission_result_name:
|
||||
description: 佣金业务结果名称(中文)
|
||||
type: string
|
||||
commission_status:
|
||||
description: 佣金状态 (1:待计算, 2:已计算)
|
||||
description: 佣金流程状态 (1:待计算, 2:已完成, 3:待人工处理)
|
||||
type: integer
|
||||
commission_status_name:
|
||||
description: 佣金状态名称(中文)
|
||||
description: 佣金流程状态名称(中文)
|
||||
type: string
|
||||
created_at:
|
||||
description: 创建时间
|
||||
@@ -5494,15 +5506,15 @@ components:
|
||||
nullable: true
|
||||
type: array
|
||||
operator_id:
|
||||
description: 操作者ID
|
||||
description: 操作者账号ID(真实发起操作的账号/主体ID)
|
||||
minimum: 0
|
||||
nullable: true
|
||||
type: integer
|
||||
operator_name:
|
||||
description: 操作者名称
|
||||
description: 操作者名称(按账号语义展示)
|
||||
type: string
|
||||
operator_type:
|
||||
description: 操作者类型 (platform:平台, agent:代理)
|
||||
description: 操作者账号类型 (platform:平台, agent:代理, enterprise:企业, personal_customer:个人客户)
|
||||
type: string
|
||||
order_no:
|
||||
description: 订单号
|
||||
@@ -5533,6 +5545,14 @@ components:
|
||||
purchase_role:
|
||||
description: 订单角色 (self_purchase:自己购买, purchased_by_parent:上级代理购买, purchased_by_platform:平台代购, purchase_for_subordinate:给下级购买)
|
||||
type: string
|
||||
seller_shop_id:
|
||||
description: 销售店铺ID(业务归属字段)
|
||||
minimum: 0
|
||||
nullable: true
|
||||
type: integer
|
||||
seller_shop_name:
|
||||
description: 销售店铺名称(业务归属展示)
|
||||
type: string
|
||||
total_amount:
|
||||
description: 订单总金额(分)
|
||||
type: integer
|
||||
@@ -6741,11 +6761,17 @@ components:
|
||||
type: object
|
||||
DtoSetSwitchModeRequest:
|
||||
properties:
|
||||
iot_card_id:
|
||||
description: 目标卡资产ID(必须是系统内状态正常且已实名的卡)
|
||||
minimum: 1
|
||||
type: integer
|
||||
switch_mode:
|
||||
description: 切卡模式 (0:自动切卡, 1:手动切卡)
|
||||
nullable: true
|
||||
type: integer
|
||||
required:
|
||||
- switch_mode
|
||||
- iot_card_id
|
||||
type: object
|
||||
DtoSetWiFiRequest:
|
||||
properties:
|
||||
@@ -13385,7 +13411,7 @@ paths:
|
||||
- 设备管理
|
||||
/api/admin/devices/by-identifier/{identifier}/switch-mode:
|
||||
post:
|
||||
description: 通过虚拟号/IMEI/SN 设置设备切卡模式(0:自动切卡, 1:手动切卡)。设备必须已配置 IMEI。
|
||||
description: 通过虚拟号/IMEI/SN 设置设备切卡模式(0:自动切卡, 1:手动切卡)。设备必须已配置 IMEI,且必须指定一张系统内状态正常并已实名的目标卡资产ID。
|
||||
parameters:
|
||||
- description: 设备标识符(支持虚拟号/IMEI/SN)
|
||||
in: path
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
| `virtual_used_mb` | float64 | 当前主套餐展示已用量 MB |
|
||||
| `reduction_pct` | float64 | 展示增幅比例,公式为 `(real_total_mb / virtual_total_mb) - 1` |
|
||||
| `device_protect_status` | string | 保护期状态:`none` / `stop` / `start`(仅 device) |
|
||||
| `activated_at` | time | 激活时间 |
|
||||
| `activated_at` | time | 激活时间(未来准备移除,请勿依赖) |
|
||||
| `created_at` | time | 创建时间 |
|
||||
| `updated_at` | time | 更新时间 |
|
||||
| **绑定关系(card 时)** | | |
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
## 订单操作者与佣金语义兼容映射清单
|
||||
|
||||
### 1. 历史字段现状
|
||||
|
||||
- `tb_order.operator_id`:历史上混用了“真实操作者账号 ID”和“代理店铺 ID”两种语义。
|
||||
- `tb_order.operator_type`:历史上仅承载 `platform/agent`,且与 `operator_id` 的 ID 体系并不稳定一致。
|
||||
- `tb_order.creator`:后台订单通常可回溯真实账号,但旧响应逻辑没有统一优先使用该字段补齐平台操作者展示。
|
||||
- `tb_order.commission_status`:历史上仅有 `1=待计算`、`2=已计算`,无法表达“无佣金”和“链路异常待人工处理”。
|
||||
|
||||
### 2. 新增权威字段
|
||||
|
||||
- `operator_account_id`:真实操作者账号/主体 ID。
|
||||
- `operator_account_type`:真实操作者类型,使用 `platform/agent/enterprise/personal_customer` 语义。
|
||||
- `operator_account_name`:真实操作者名称快照。
|
||||
- `commission_result`:佣金业务结果,使用 `0=未知 1=有佣金 2=无佣金 3=链路异常`。
|
||||
|
||||
### 3. 写路径兼容策略
|
||||
|
||||
- 新订单统一写入 `operator_account_*` 权威字段。
|
||||
- 保留写入 legacy `operator_id/operator_type`,但仅作为兼容读取兜底,不再作为新语义权威来源。
|
||||
- `seller_shop_id` 继续作为差价佣金链路起点,不再从 `operator_id/operator_type` 推导佣金归属。
|
||||
|
||||
### 4. 读路径兼容策略
|
||||
|
||||
- 响应层优先读取 `operator_account_*`。
|
||||
- 若新字段为空:
|
||||
- 优先尝试 `creator` 回填后台账号名称。
|
||||
- 对客户端个人客户订单,回填个人客户昵称。
|
||||
- 对历史代理订单,若 `operator_id/operator_type` 仍承载店铺语义,则回退展示店铺名称,但不回写新字段。
|
||||
- `commission_result` 为空时,按历史订单状态与佣金记录兜底推断,不直接篡改旧列值。
|
||||
|
||||
### 5. 高风险兼容点
|
||||
|
||||
- `internal/store/postgres/order_store.go` 中旧逻辑把 `operator_id IN subordinateShopIDs` 作为代理权限过滤条件;当 `operator_id` 不再表示店铺 ID 后,该条件必须迁移到 `seller_shop_id`,历史订单仅保留兜底分支。
|
||||
- `internal/service/order/service.go` 当前 `operator_name` 仅在 `operator_type=agent` 时按店铺名称回填,会导致平台旧订单长期空白。
|
||||
- `internal/service/commission_calculation/service.go` 当前仅把订单写成“已计算”,无法区分“有佣金 / 无佣金 / 链路异常”。
|
||||
|
||||
### 6. 本次实现范围内的迁移原则
|
||||
|
||||
- 只做增量字段迁移,不删除旧列。
|
||||
- 不在本次 migration 中批量强制回填历史订单,只在运行时兼容读取并为后续人工校验提供依据。
|
||||
@@ -0,0 +1,78 @@
|
||||
## 订单操作者与产业链佣金语义修复功能总结
|
||||
|
||||
### 1. 变更目标
|
||||
|
||||
本次变更围绕两个历史语义问题展开:
|
||||
|
||||
1. 订单 `operator_id/operator_type` 混用了“真实操作者账号”和“代理店铺 ID”,导致平台订单无法稳定显示真实操作者。
|
||||
2. 订单 `commission_status` 只区分“待计算/已计算”,无法表达“有佣金 / 无佣金 / 链路异常待人工处理”的真实业务结果。
|
||||
|
||||
### 2. 已完成的核心改动
|
||||
|
||||
#### 2.1 订单操作者改为账号语义
|
||||
|
||||
- 新增权威字段:
|
||||
- `operator_account_id`
|
||||
- `operator_account_type`
|
||||
- `operator_account_name`
|
||||
- 后台订单创建、H5 代理订单创建、客户端个人客户订单、自动购包订单都会写入真实操作者快照。
|
||||
- 旧 `operator_id/operator_type` 保留为历史兼容字段,不再作为新语义权威来源。
|
||||
|
||||
#### 2.2 订单响应分离“操作者账号”和“业务店铺”
|
||||
|
||||
- `operator_id/operator_type/operator_name` 现在按真实操作者账号语义返回。
|
||||
- 新增 `seller_shop_id/seller_shop_name`,用于表达业务归属店铺展示。
|
||||
- 历史订单优先使用新字段;若缺失,则按 `creator`、个人客户昵称、旧店铺型 `operator_id` 顺序兜底,避免平台旧订单出现空白操作者名称。
|
||||
|
||||
#### 2.3 订单佣金状态拆成“流程状态 + 业务结果”
|
||||
|
||||
- `commission_status` 现在表示流程状态:
|
||||
- `1=待计算`
|
||||
- `2=已完成`
|
||||
- `3=待人工处理`
|
||||
- 新增 `commission_result` 表示业务结果:
|
||||
- `0=未知`
|
||||
- `1=有佣金`
|
||||
- `2=无佣金`
|
||||
- `3=链路异常`
|
||||
|
||||
#### 2.4 差价佣金任务结果显式落单
|
||||
|
||||
- 佣金 worker 结束后会显式写回订单:
|
||||
- `已完成 + 有佣金`
|
||||
- `已完成 + 无佣金`
|
||||
- `待人工处理 + 链路异常`
|
||||
- 0 佣金订单不再长期停留在“待计算”。
|
||||
|
||||
#### 2.5 入队与幂等语义修复
|
||||
|
||||
- 钱包支付创建订单后,所有仍处于 `待计算` 的适用订单都会入队佣金任务,不再只覆盖特定购买角色。
|
||||
- 重复支付回调、重复钱包支付不会重复入队。
|
||||
- worker 对 `已完成/待人工处理` 订单直接跳过,避免重复补偿处理。
|
||||
|
||||
### 3. 兼容策略
|
||||
|
||||
- migration 仅新增字段,不删除旧列。
|
||||
- 历史订单读取时:
|
||||
- 优先使用 `operator_account_*`
|
||||
- 其次使用 `creator` 回填账号名
|
||||
- 对旧代理订单保留店铺名兜底展示
|
||||
- 历史订单的 `commission_result` 若未回填,则在响应层按佣金记录只读推断。
|
||||
|
||||
### 4. 受影响文件
|
||||
|
||||
- `internal/model/order.go`
|
||||
- `internal/model/dto/order_dto.go`
|
||||
- `internal/service/order/service.go`
|
||||
- `internal/service/client_order/service.go`
|
||||
- `internal/service/commission_calculation/service.go`
|
||||
- `internal/store/postgres/order_store.go`
|
||||
- `internal/task/auto_purchase.go`
|
||||
- `pkg/constants/iot.go`
|
||||
- `migrations/000140_add_order_operator_snapshot_and_commission_result.*.sql`
|
||||
|
||||
### 5. 风险提示
|
||||
|
||||
- 历史订单若 `creator` 无法映射到账号,仍会退回旧店铺型操作者展示,仅保证“可读”而不强行伪造账号 ID。
|
||||
- `commission_result=0` 仅作为历史兼容态存在;新计算链路应尽量落为明确业务结果。
|
||||
- 本次不重构一次性佣金规则本身,只保证其异常待审记录能纳入订单最终流程结果判断。
|
||||
@@ -0,0 +1,39 @@
|
||||
## 手工验收清单
|
||||
|
||||
### 一、平台订单操作者展示
|
||||
|
||||
- [ ] 创建或查询一条历史平台订单,确认响应中的 `operator_name` 不再为空。
|
||||
- [ ] 确认该订单的 `operator_type=platform`,且操作者名称优先来自 `creator` 对应后台账号。
|
||||
- [ ] 确认 `seller_shop_name` 与 `operator_name` 语义分离,不再混用店铺名代替平台账号名。
|
||||
|
||||
### 二、多级代理链差价佣金
|
||||
|
||||
- [ ] 准备一条 `seller_shop_id` 存在完整父级链的订单。
|
||||
- [ ] 执行佣金任务后,确认各级代理按父级链逐级生成差价佣金记录。
|
||||
- [ ] 确认订单 `commission_status=2`、`commission_result=1`。
|
||||
- [ ] 确认相关代理钱包流水与佣金记录金额一致。
|
||||
|
||||
### 三、无佣金完成态
|
||||
|
||||
- [ ] 准备一条顶级代理订单或无正差价订单。
|
||||
- [ ] 执行佣金任务后,确认不产生正金额佣金记录。
|
||||
- [ ] 确认订单不会继续停留在待计算,而是落为 `commission_status=2`、`commission_result=2`。
|
||||
|
||||
### 四、链路异常待人工处理
|
||||
|
||||
- [ ] 准备一条上级链断裂、系列配置缺失或套餐分配缺失的订单。
|
||||
- [ ] 执行佣金任务后,确认生成 `status=99` 的待人工修正佣金记录。
|
||||
- [ ] 确认备注中包含链路断点信息。
|
||||
- [ ] 确认订单落为 `commission_status=3`、`commission_result=3`。
|
||||
|
||||
### 五、入队与幂等
|
||||
|
||||
- [ ] 钱包支付创建订单后,确认差价佣金任务会自动入队。
|
||||
- [ ] 重复触发支付回调或重复调用钱包支付时,确认不会重复入队。
|
||||
- [ ] 对已经完成或待人工处理的订单重复执行佣金任务,确认 worker 会直接跳过。
|
||||
|
||||
### 六、历史兼容读取
|
||||
|
||||
- [ ] 抽查至少一条历史平台订单,确认 `creator` 能兜底回填操作者名称。
|
||||
- [ ] 抽查至少一条历史代理订单,确认新字段为空时仍可读出兼容操作者展示。
|
||||
- [ ] 确认历史订单不会把旧 `operator_id` 误当成新的账号 ID 再写回数据库。
|
||||
@@ -756,7 +756,7 @@ GET /api/admin/assets/resolve/:identifier
|
||||
| `series_name` | string | 套餐系列名称 |
|
||||
| `first_commission_paid` | bool | 一次性佣金是否已发放 |
|
||||
| `accumulated_recharge` | int64 | 累计充值金额(分) |
|
||||
| `activated_at` | string | 激活时间 |
|
||||
| `activated_at` | string | 激活时间(未来准备移除,请勿依赖) |
|
||||
| `created_at` | string | 创建时间 |
|
||||
| `updated_at` | string | 更新时间 |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user