# 任务清单:add-refund-system > 退款功能从零建设,严格串行:数据模型 → Store → Service → Handler → 路由注册 → 文档。 > 审批通过后需自动执行资产处理和佣金回扣,涉及跨模块依赖。 ## 任务组 1:I-1 数据模型 - [x] 1.1 新建迁移文件 `migrations/000XXX_create_refund_request.up.sql`(编号接续现有最大值),创建 `tb_refund_request` 表,包含所有字段(参考 design.md 表设计,含 shop_id、processor_id、processed_at、reject_reason、remark、asset_reset 等) - [x] 1.2 新建对应 `.down.sql`:`DROP TABLE IF EXISTS tb_refund_request;` - [x] 1.3 新建 `internal/model/refund.go`,定义 `RefundRequest` GORM Model(使用 `gorm.Model` + `BaseModel` 嵌入),实现 `TableName()` 返回 `tb_refund_request`,所有字段显式指定 `gorm:"column:xxx"` 标签,注释使用中文 - [x] 1.4 在 `pkg/constants/` 中新增以下常量: - 退款状态:`RefundStatusPending=1, RefundStatusApproved=2, RefundStatusRejected=3, RefundStatusReturned=4` - 交易类型:`AgentTransactionTypeCommissionDeduct = "commission_deduct"`(在 `pkg/constants/wallet.go` 的代理钱包交易类型分组中新增) - 关联业务类型:`ReferenceTypeRefund = "refund"`(在 `pkg/constants/wallet.go` 的关联业务类型分组中新增) - [x] 1.5 新建 `internal/model/dto/refund_dto.go`,定义请求/响应 DTO:`CreateRefundRequest`、`RejectRefundRequest`、`ResubmitRefundRequest`、`ApproveRefundRequest`、`ReturnRefundRequest`、`RefundListRequest`、`RefundResponse`、`RefundListResponse`。所有 DTO 字段需含 `description` 标签 - [x] 1.6 执行迁移,通过 DBHub 确认表已创建 - [x] 1.7 验证:`go build ./...` 编译通过 ## 任务组 2:I-2 接口实现 - [x] 2.1 新建 `internal/store/postgres/refund_store.go`,实现 `Create`、`GetByID`、`List`(分页+筛选,含 `ApplyShopFilter` 数据权限过滤)、`Update` 方法 - [x] 2.2 新建 `internal/service/refund/service.go`,实现 7 个业务方法:`Create`、`List`、`GetByID`、`Approve`、`Reject`、`Return`、`Resubmit`。每个状态变更方法 MUST 使用条件更新 `WHERE status = expected` 保证幂等。`Create` 方法 MUST 检查同一订单不能重复退款(已存在 status IN (1,2,4) 的退款记录时拒绝) - [x] 2.3 退款单号生成:`generateRefundNo()` 格式 `RF` + 年月日时分秒 + 6位随机数,参考 `GenerateOrderNo` 实现 - [x] 2.4 `Create` 方法中从关联订单读取 `seller_shop_id`(或根据 buyer_type/buyer_id 确定)填入退款单的 `shop_id` 字段 - [x] 2.5 新建 `internal/handler/admin/refund.go`,实现 7 个 Handler 方法,遵循 Handler 只做参数解析+响应格式化的原则 - [x] 2.6 新建 `internal/routes/refund.go`,注册 `/api/admin/refunds` 路由组(参考 `routes/commission.go` 的 Register 模式),路由中间件限制仅平台用户可访问 - [x] 2.7 在 `internal/bootstrap/stores.go`、`services.go`、`handlers.go` 中注册 refund 模块: - Store: `RefundStore` - Service 依赖注入: `db`, `refundStore`, `orderStore`, `commissionRecordStore`, `agentWalletStore`, `agentWalletTransactionStore`, `stopResumeService`, `deviceService`, `packageActivationService`, `iotCardStore`, `deviceStore`, `assetWalletStore` - Handler: `RefundHandler` - [x] 2.8 在 `internal/routes/routes.go` 中调用 `registerRefundRoutes` - [x] 2.9 更新 `cmd/api/docs.go` 和 `cmd/gendocs/main.go`,注册退款 Handler - [x] 2.10 验证:`go build ./...` 编译通过 ## 任务组 3:I-3 佣金全额回扣 - [x] 3.1 在 `internal/service/refund/service.go` 中新增私有方法 `deductAllCommission(ctx, refundID)` - [x] 3.2 实现回扣逻辑:查退款单 → 查该订单所有已入账佣金记录(`WHERE order_id=? AND status=1`,使用 `CommissionStatusReleased` 常量)→ 对每条记录全额扣减对应代理的佣金钱包(`wallet_type="commission"`,使用 `GetCommissionWallet`)→ 使用乐观锁更新余额(`WHERE version=?`)→ 创建交易流水(`transaction_type="commission_deduct"`, `reference_type="refund"`, `reference_id=退款单ID`)→ 全部完成后标记 `commission_deducted=true` - [x] 3.3 在 `Approve()` 方法中,事务提交成功后通过 Goroutine 调用 `deductAllCommission` - [x] 3.4 回扣失败记录 Error 日志(含 refund_id 和 error),不影响审批结果 - [x] 3.5 验证:`go build ./...` 编译通过 ## 任务组 4:I-4 资产处理 - [x] 4.1 在 `internal/service/package/activation_service.go` 中新增公开方法 `InvalidateAllPackagesByAsset(ctx, assetType string, assetID uint) error`:查询 `status IN (0,1,2)` 的套餐使用记录(按 `iot_card_id` 或 `device_id` 查),批量更新为 `status=4`(已失效) - [x] 4.2 在 `internal/service/refund/service.go` 中新增私有方法 `handleAssetReset(ctx, refundID)`,包含: - a. 查退款单和关联订单,确定资产类型(单卡/设备)和资产ID - b. 调用 `InvalidateAllPackagesByAsset` 失效所有套餐 - c. 停机:单卡调 `stopResumeService.ManualStopCard(iccid)` / 设备调 `deviceService.StopDevice(deviceID)` - d. 世代重置(参照 `exchange/service.go` 第 278-305 行):`generation+1`、`asset_status=1`、清零累计充值字段、清理个人客户绑定、删除旧资产钱包并创建新空钱包 - e. 更新订单 `payment_status=4`(已退款) - f. 标记退款单 `asset_reset=true` - [x] 4.3 在 `Approve()` 方法中,事务提交成功后通过 Goroutine 调用 `handleAssetReset`(与佣金回扣独立执行) - [x] 4.4 资产处理失败记录 Error 日志(含 refund_id 和 error),`asset_reset` 保持 `false`,不影响审批结果 - [x] 4.5 验证:`go build ./...` 编译通过 ## 收尾验证 - [x] 5.1 执行 `go build ./...`,确认全量编译通过 - [x] 5.2 通过 DBHub 确认 `tb_refund_request` 表结构正确 - [x] 5.3 通过 `rg "refund" internal/bootstrap/` 确认模块已注册 - [x] 5.4 通过 `rg "commission_deduct" pkg/constants/` 确认新常量已添加 - [x] 5.5 通过 `rg "InvalidateAllPackagesByAsset" internal/service/package/` 确认新方法已添加