## Why 现有 `CardReplacementRecord` 模型仅支持简单换卡,无法满足完整换货需求:缺少收货地址、快递信息、设备换货、全量数据迁移等功能。客户端换货场景中,后台发起换货 → 客户端收到通知填写收货信息 → 后台发货+确认完成(含全量迁移)→ 旧资产可"转新"重新销售,是一个跨后台/客户端的完整业务闭环。 **前置依赖**:提案 0(`asset_status`/`generation` 字段已就位)、提案 1(客户端认证)。 ## What Changes ### 新增模型 - **ExchangeOrder(换货单)**:完整的换货生命周期模型,包含旧/新资产信息、收货地址、物流信息、迁移状态。状态机:`1-待填写信息 → 2-待发货 → 3-已发货待确认 → 4-已完成`,1 或 2 时可取消(→5) ### 删除旧模型 - **CardReplacementRecord**:表改名为 `tb_card_replacement_record_legacy`,代码引用替换为 ExchangeOrder ### 后台换货管理(模块 H,7 个接口) - **H1 发起换货** `POST /api/admin/exchanges`:验证资产无进行中换货单,创建 status=1 - **H2 换货列表** `GET /api/admin/exchanges`:支持状态筛选、资产标识符搜索、时间范围 - **H3 换货详情** `GET /api/admin/exchanges/:id` - **H4 发货** `POST /api/admin/exchanges/:id/ship`:填写物流信息+新资产标识符,验证 status=2、同类型资产、新资产 asset_status=1(在库) - **H5 确认完成** `POST /api/admin/exchanges/:id/complete`:验证 status=3,如 migrate_data=true 则执行全量迁移(11 张表事务内操作),旧资产 asset_status→3 - **H6 取消换货** `POST /api/admin/exchanges/:id/cancel`:验证 status IN (1,2),已发货不可取消 - **H7 旧资产转新** `POST /api/admin/exchanges/:id/renew`:旧资产 asset_status 从 3→1,generation+1,清除客户绑定和累计状态,创建新空钱包 ### 客户端换货(模块 G,2 个接口) - **G1 查询换货通知** `GET /api/c/v1/exchange/pending?identifier=xxx`:查是否有进行中的换货单 - **G2 填写收货信息** `POST /api/c/v1/exchange/:id/shipping-info`:验证 status=1,更新收货信息,status→2 ### 换货状态机 ``` 后台发起换货 │ ▼ ┌─────────────────────┐ │ 1-待填写信息 │ ←── ExchangeOrder 创建 │ (等待客户端填写) │ └──────────┬──────────┘ │ 客户端填写收货信息 [G2] │ ▼ ┌─────────────────────┐ │ 2-待发货 │ │ (等待后台填写物流) │ └──────────┬──────────┘ │ 后台发货 [H4] (填物流+新资产) │ ▼ ┌─────────────────────┐ │ 3-已发货待确认 │ │ (等待后台确认完成) │ └──────────┬──────────┘ │ 后台确认完成 [H5] (可选: 全量迁移) │ ▼ ┌─────────────────────┐ │ 4-已完成 │ └─────────────────────┘ 取消: status=1 或 2 时可取消 → 5-已取消 已发货(status=3)后不可取消 ``` ### 全量迁移流程(H5 确认完成时触发) ``` 确认完成 (migrate_data=true) │ ▼ 事务开始 │ ├── 1. 钱包余额转移 │ 旧 AssetWallet.Balance → 新 AssetWallet │ 生成迁移流水 AssetWalletTransaction │ ├── 2. 生效中套餐关联新资产 │ PackageUsage WHERE iot_card_id/device_id=旧 AND status IN (生效中) │ → UPDATE iot_card_id/device_id = 新 │ ├── 3. 累计充值/首充状态迁移 │ IotCard/Device 的 AccumulatedRecharge/FirstCommissionPaid │ 等字段复制到新资产 │ ├── 4. 标签复制 │ ResourceTag WHERE resource_type=? AND resource_id=旧 │ → 为新资产创建相同标签 │ ├── 5. 个人客户绑定更新 │ PersonalCustomerDevice WHERE virtual_no=旧虚拟号 │ → UPDATE virtual_no = 新虚拟号 │ ├── 6. 旧资产标记 │ 旧资产 asset_status → 3(已换货) │ └── 7. 记录迁移信息 ExchangeOrder: migration_completed=true, migration_balance=转移金额 │ ▼ 事务提交 │ ▼ ExchangeOrder status → 4(已完成) 注意: - 设备换设备时不迁移 DeviceSimBinding(卡绑定关系) - 新设备自带新的 SIM 卡,旧设备的卡绑定保持不变 - 保留不修改的表: tb_order, tb_commission, tb_data_usage_record, tb_asset_recharge_record(历史记录保留,通过 generation 隔离) ``` ### 转新流程(H7) ``` 旧资产 (asset_status=3 已换货) │ ▼ POST /api/admin/exchanges/:id/renew │ ├── 1. asset_status: 3 → 1(在库) ├── 2. generation: +1(进入新世代) ├── 3. 清除: 累计充值状态、首充触发状态 ├── 4. 清除: PersonalCustomerDevice 绑定 ├── 5. 创建新空钱包(新 wallet_id) └── 6. 不删除历史数据(通过 generation 隔离) │ ▼ 旧资产可重新销售给新客户 新客户查询时按当前 generation 过滤 看不到旧周期数据 ``` ## Capabilities ### New Capabilities - `exchange-order-model`:ExchangeOrder 模型定义、状态机、状态常量、换货单号生成规则 - `exchange-admin-management`:后台换货管理 CRUD(H1~H3)、发货(H4,含同类型资产校验+新资产在库校验)、确认完成(H5,含全量迁移事务)、取消(H6)、转新(H7,含 generation 自增+状态重置) - `exchange-data-migration`:全量迁移逻辑,11 张数据表的事务内操作规则,设备不迁移卡绑定的特殊规则 - `exchange-client-notification`:客户端换货通知查询(G1)、收货信息填写(G2) ### Modified Capabilities - `iot-card`:IotCard 新增换货相关行为——`asset_status=3` 标记、转新时 generation 自增+状态重置 - `device`:Device 同上 - `personal-customer`:PersonalCustomerDevice 绑定关系在换货迁移时更新虚拟号 - `card-replacement`:**REMOVED** — CardReplacementRecord 模型废弃,表改名为 legacy,代码引用替换为 ExchangeOrder ## Impact - **新增文件**:`internal/model/exchange_order.go`(模型);`internal/handler/admin/exchange.go`(后台 Handler);`internal/handler/app/client_exchange.go`(客户端 Handler);`internal/service/exchange/service.go`(Service,含迁移逻辑);`internal/store/postgres/exchange_order_store.go`(Store);DTO 文件;迁移文件;常量和错误码 - **修改文件**:`internal/model/card_replacement.go`(删除或标记废弃);`internal/store/postgres/iot_card_store.go`(移除 `is_replaced` 过滤改为查新表);`internal/model/system.go`(AutoMigrate 移除旧模型+注册新模型);`internal/routes/`(新增后台+客户端路由);`internal/bootstrap/`(注册新模块);`cmd/api/docs.go` + `cmd/gendocs/main.go`(文档生成器) - **新增 API 路由**:后台 `/api/admin/exchanges/` 下 7 个端点 + 客户端 `/api/c/v1/exchange/` 下 2 个端点 - **数据库变更**:新建 `tb_exchange_order` 表;旧表 `tb_card_replacement_record` 改名为 `tb_card_replacement_record_legacy` - **全量迁移涉及 11 张表**:`tb_asset_wallet`、`tb_asset_wallet_transaction`、`tb_asset_recharge_record`、`tb_package_usage`、`tb_package_usage_daily_record`、`tb_order`、`tb_commission`、`tb_data_usage_record`、`tb_resource_tag`、`tb_personal_customer_device`、`tb_iot_card`/`tb_device`