## Context

当前 `tb_order.total_amount` 在后台代购/钱包支付场景被覆盖为成本价，导致：
1. C 端订单列表/详情展示成本价（甚至 0 元）
2. `tb_package_usage.paid_amount` 快照的是成本价，资产套餐接口对所有后台账号一视同仁地暴露成本价

字段语义混乱的根源：`total_amount` 在 admin order service 中被 `buyerTotalCost` 覆盖，`retailTotalAmount` 计算出来后被丢弃。`actual_paid_amount` 本应是成本价，但 `total_amount` 也是成本价，两者语义重叠。

涉及模块：`internal/service/order`、`internal/service/client_order`、`internal/service/asset`、`internal/task`、`internal/model`、`internal/handler/admin`。

## Goals / Non-Goals

**Goals:**
- `Order.TotalAmount` 始终 = 零售价（客户面值），C 端和后台均可安全展示
- `Order.ActualPaidAmount` = 实际支付成本价，钱包扣款以此为准
- `OrderItem.UnitPrice` = 零售单价，新增 `CostPrice` 字段存成本单价
- `PackageUsage.RetailAmount` 快照零售价，`PaidAmount` 继续快照成本价
- 资产套餐接口按调用方账号类型过滤：非平台账号不返回 `paid_amount`

**Non-Goals:**
- 不修改 C 端下单流程（C 端本来就用零售价，无需改动）
- 不修改佣金计算逻辑（佣金基于 `SellerCostPrice`，不受此次影响）
- 不修改退款逻辑（退款金额基于 `ActualPaidAmount`，语义已正确）
- 不重命名 `PaidAmount` 字段（保持向后兼容）

## Decisions

### 决策 1：`TotalAmount` 始终存零售价，`ActualPaidAmount` 存成本价

**选择**：admin order service 中 `totalAmount` 始终赋值 `retailTotalAmount`，不再被 `buyerTotalCost` 覆盖；成本价只写入 `ActualPaidAmount`。

**理由**：`TotalAmount` 是订单的"面值"，对客户可见；`ActualPaidAmount` 是"实付"，是内部财务字段。两者语义本来就应该分离，当前代码是历史遗留的语义混用。

**钱包扣款影响**：`createOrderWithWalletPayment` 目前用 `order.TotalAmount` 扣款，改为用 `order.ActualPaidAmount`。这是正确的——代理扣的是成本价，不是零售价。

**替代方案**：新增独立的 `RetailAmount` 字段存零售价，`TotalAmount` 保持现状。被否决，因为 `TotalAmount` 的字段名本身就暗示"订单总金额"，应该是客户看到的面值，改语义比加字段更干净。

### 决策 2：`OrderItem` 新增 `CostPrice` 字段

**选择**：`tb_order_item` 新增 `cost_price BIGINT NOT NULL DEFAULT 0`，`UnitPrice` 改为存零售单价。

**理由**：详情页需要展示每个套餐的单价，C 端看零售价，后台平台账号可能需要看成本价做对账。两个字段各司其职，不互相覆盖。

**替代方案**：只在 order 级别存成本价（`SellerCostPrice` 已有），item 级别不存。被否决，因为多套餐订单时无法还原每个套餐的成本单价。

### 决策 3：`PackageUsage` 新增 `RetailAmount` 字段，`PaidAmount` 保持不变

**选择**：新增 `retail_amount BIGINT NULLABLE`，来源为 `order.TotalAmount`（零售价）；`PaidAmount` 继续来源于 `order.ActualPaidAmount`（成本价）。

**理由**：`PaidAmount` 已有存量数据和下游依赖，重命名风险高。新增字段向后兼容，存量数据通过迁移 SQL 回填。

### 决策 4：资产套餐接口按账号类型过滤，在 Service 层实现

**选择**：`GetPackages` / `GetCurrentPackage` 新增 `callerAccountType string` 参数，Service 层根据此参数决定是否填充 `PaidAmount`；Handler 层从 middleware 读取账号类型后传入。

**理由**：过滤逻辑是业务规则，属于 Service 层职责。Handler 层只负责提取调用方身份并传递，不做业务判断。

**账号类型判断规则**：`callerAccountType == "platform"` 时返回 `PaidAmount`，其他类型（`agent`、`enterprise`、`personal_customer`）不返回。

## Risks / Trade-offs

- **[风险] 钱包扣款金额变化**：改用 `ActualPaidAmount` 扣款后，代理自购场景扣款金额不变（成本价），但需确认所有扣款路径都已切换，避免遗漏。→ 迁移时逐一检查 `createOrderWithWalletPayment` 的所有调用点。

- **[风险] 存量订单数据不一致**：历史订单的 `TotalAmount` 已经是成本价，无法回填零售价（零售价快照未存储）。→ 接受此历史数据问题，仅对新订单生效；C 端展示历史订单时可能仍显示成本价，属于已知限制。

- **[风险] `PackageUsage.RetailAmount` 存量数据为 null**：历史套餐使用记录无零售价快照。→ 迁移 SQL 尝试从关联订单回填，但历史订单 `TotalAmount` 已是成本价，回填值不准确。接受此限制，存量数据 `RetailAmount` 保持 null，接口返回时 omitempty 处理。

- **[Trade-off] 赠送套餐（0 元）场景**：`TotalAmount` = 零售价，`ActualPaidAmount` = 0。C 端看到零售价，后台看到实付 0 元。这是期望行为（已与业务确认）。

## Migration Plan

1. 执行数据库迁移：`tb_order_item` 加 `cost_price`，`tb_package_usage` 加 `retail_amount`
2. 部署新代码（新订单开始写入正确的字段语义）
3. 存量数据回填（`retail_amount` 从关联订单 `total_amount` 回填，已知不准确，仅作参考）
4. 无需回滚策略：新增字段有默认值，旧代码不读新字段，可安全回滚

**回滚**：新字段有 `DEFAULT 0` / `NULLABLE`，回滚旧代码后新字段被忽略，不影响业务。
