## MODIFIED Requirements ### Requirement: 套餐使用记录新增零售价快照字段 系统 SHALL 在 `tb_package_usage` 中新增 `retail_amount BIGINT NULLABLE` 字段,在创建 `PackageUsage` 记录时快照套餐零售价。 **字段规范**: - 数据库字段:`retail_amount BIGINT NULLABLE` - Go 字段:`RetailAmount *int64`(单位:分) - 赋值来源:`order.TotalAmount`(零售价),直接赋值,不转换 - 为 null 的情况:无订单关联的企业分配套餐(`order_id = 0`) **现有 `PaidAmount` 字段保持不变**:继续快照 `order.ActualPaidAmount`(成本价)。 **覆盖范围(所有 PackageUsage 写入点)**: - `internal/service/order/service.go` `activateMainPackage()` - `internal/service/order/service.go` `activateAddonPackage()` - `internal/task/auto_purchase.go` `activateMainPackage()` - `internal/task/auto_purchase.go` `activateAddonPackage()` **存量数据回填**:通过迁移 SQL 从关联订单回填,已知历史订单 `total_amount` 可能为成本价(历史数据问题),回填值仅作参考,接受不准确。 #### Scenario: 代理钱包支付套餐激活时快照零售价和成本价 - **WHEN** 代理以钱包支付购买套餐,零售价 9900 分,成本价 7000 分 - **THEN** 激活生成的 `PackageUsage.retail_amount = 9900`,`PackageUsage.paid_amount = 7000` #### Scenario: 平台代购套餐激活时快照零售价和成本价 - **WHEN** 平台代购套餐,零售价 9900 分,成本价 7000 分 - **THEN** 激活生成的 `PackageUsage.retail_amount = 9900`,`PackageUsage.paid_amount = 7000` #### Scenario: 赠送套餐激活时 paid_amount 为 0,retail_amount 为零售价 - **WHEN** 平台赠送套餐,零售价 9900 分,实付 0 元 - **THEN** `PackageUsage.retail_amount = 9900`,`PackageUsage.paid_amount = 0` #### Scenario: 无订单关联的套餐 retail_amount 为 null - **WHEN** 企业分配套餐(无订单),`order_id = 0` - **THEN** `PackageUsage.retail_amount = nil`,接口响应中 `retail_amount` 字段缺省(omitempty) --- ### Requirement: 资产套餐接口按调用方角色过滤成本价 系统 SHALL 在 `/api/admin/assets/{identifier}/packages` 和 `/api/admin/assets/{identifier}/current-package` 接口中,根据调用方账号类型决定是否返回 `paid_amount`(成本价)字段。 **过滤规则**: - 调用方账号类型为 `platform`:返回 `paid_amount` 和 `retail_amount` 两个字段 - 调用方账号类型为其他(`agent`、`enterprise`、`personal_customer`):`paid_amount` 不返回(null/omitempty),仅返回 `retail_amount` **实现方式**:`GetPackages` / `GetCurrentPackage` 新增 `callerAccountType string` 参数,Service 层根据此参数决定是否填充 `PaidAmount`;Handler 层从 middleware 读取账号类型后传入。 **`AssetPackageResponse` DTO 新增字段**: - `retail_amount *int64`:零售价(分),来源 `PackageUsage.RetailAmount`,omitempty #### Scenario: 平台账号查询资产套餐返回两种价格 - **WHEN** 平台账号调用 `/api/admin/assets/{identifier}/packages`,套餐零售价 9900 分,成本价 7000 分 - **THEN** 响应中 `retail_amount = 9900`,`paid_amount = 7000`,两个字段均返回 #### Scenario: 代理账号查询资产套餐只返回零售价 - **WHEN** 代理账号调用 `/api/admin/assets/{identifier}/packages`,套餐零售价 9900 分,成本价 7000 分 - **THEN** 响应中 `retail_amount = 9900`,`paid_amount` 字段不返回(null) #### Scenario: 平台账号查询当前生效套餐返回两种价格 - **WHEN** 平台账号调用 `/api/admin/assets/{identifier}/current-package` - **THEN** 响应中 `retail_amount` 和 `paid_amount` 均有值 #### Scenario: 代理账号查询当前生效套餐只返回零售价 - **WHEN** 代理账号调用 `/api/admin/assets/{identifier}/current-package` - **THEN** 响应中 `retail_amount` 有值,`paid_amount` 不返回 #### Scenario: 套餐无零售价快照时 retail_amount 为 null - **WHEN** 历史套餐使用记录 `retail_amount` 为 null(存量数据) - **THEN** 响应中 `retail_amount` 字段缺省(omitempty),不返回