All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m8s
- client_order: 新增 getOrCreateWallet 兜底,钱包不存在时自动创建 - device_import: 设备导入事务内同步创建设备钱包 - iot_card_import: IoT卡批量导入后批量创建卡钱包 - queue/handler: 传递 AssetWalletStore 给两个导入 handler - migration 000098: 为存量IoT卡和设备补建资产钱包
6.1 KiB
6.1 KiB
任务清单:add-refund-system
退款功能从零建设,严格串行:数据模型 → Store → Service → Handler → 路由注册 → 文档。 审批通过后需自动执行资产处理和佣金回扣,涉及跨模块依赖。
任务组 1:I-1 数据模型
- 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 等) - 1.2 新建对应
.down.sql:DROP TABLE IF EXISTS tb_refund_request; - 1.3 新建
internal/model/refund.go,定义RefundRequestGORM Model(使用gorm.Model+BaseModel嵌入),实现TableName()返回tb_refund_request,所有字段显式指定gorm:"column:xxx"标签,注释使用中文 - 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的关联业务类型分组中新增)
- 退款状态:
- 1.5 新建
internal/model/dto/refund_dto.go,定义请求/响应 DTO:CreateRefundRequest、RejectRefundRequest、ResubmitRefundRequest、ApproveRefundRequest、ReturnRefundRequest、RefundListRequest、RefundResponse、RefundListResponse。所有 DTO 字段需含description标签 - 1.6 执行迁移,通过 DBHub 确认表已创建
- 1.7 验证:
go build ./...编译通过
任务组 2:I-2 接口实现
- 2.1 新建
internal/store/postgres/refund_store.go,实现Create、GetByID、List(分页+筛选,含ApplyShopFilter数据权限过滤)、Update方法 - 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) 的退款记录时拒绝) - 2.3 退款单号生成:
generateRefundNo()格式RF+ 年月日时分秒 + 6位随机数,参考GenerateOrderNo实现 - 2.4
Create方法中从关联订单读取seller_shop_id(或根据 buyer_type/buyer_id 确定)填入退款单的shop_id字段 - 2.5 新建
internal/handler/admin/refund.go,实现 7 个 Handler 方法,遵循 Handler 只做参数解析+响应格式化的原则 - 2.6 新建
internal/routes/refund.go,注册/api/admin/refunds路由组(参考routes/commission.go的 Register 模式),路由中间件限制仅平台用户可访问 - 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
- Store:
- 2.8 在
internal/routes/routes.go中调用registerRefundRoutes - 2.9 更新
cmd/api/docs.go和cmd/gendocs/main.go,注册退款 Handler - 2.10 验证:
go build ./...编译通过
任务组 3:I-3 佣金全额回扣
- 3.1 在
internal/service/refund/service.go中新增私有方法deductAllCommission(ctx, refundID) - 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 - 3.3 在
Approve()方法中,事务提交成功后通过 Goroutine 调用deductAllCommission - 3.4 回扣失败记录 Error 日志(含 refund_id 和 error),不影响审批结果
- 3.5 验证:
go build ./...编译通过
任务组 4:I-4 资产处理
- 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(已失效) - 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
- 4.3 在
Approve()方法中,事务提交成功后通过 Goroutine 调用handleAssetReset(与佣金回扣独立执行) - 4.4 资产处理失败记录 Error 日志(含 refund_id 和 error),
asset_reset保持false,不影响审批结果 - 4.5 验证:
go build ./...编译通过
收尾验证
- 5.1 执行
go build ./...,确认全量编译通过 - 5.2 通过 DBHub 确认
tb_refund_request表结构正确 - 5.3 通过
rg "refund" internal/bootstrap/确认模块已注册 - 5.4 通过
rg "commission_deduct" pkg/constants/确认新常量已添加 - 5.5 通过
rg "InvalidateAllPackagesByAsset" internal/service/package/确认新方法已添加