完成
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled

This commit is contained in:
2026-06-23 11:05:58 +09:00
parent 5c2ef97c24
commit c0b9604515
9 changed files with 380 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
Status: done
## Parent
`.scratch/iot-risk-import-voucher-remark/PRD.md`
## What to build
新增两个 gateway_extend 常量(`GatewayCardExtendRiskStop = "风险停机"``GatewayCardExtendCancelled = "已销户"`),然后在后台复机入口(`ManualStartCard`)和 Open API 复机入口(`ResumeCard`)中增加前置拦截:
- 仅对 `is_standalone = true` 的独立卡生效
- 读取 DB 中已落库的 `gateway_extend` 字段(不实时查网关)
- 若命中 `"风险停机"``"已销户"`,立即返回业务错误,不再继续调用网关
- 错误提示需明确说明被拒绝的原因(如"该卡已被运营商风险停机,不允许复机"
无 Schema 变更,不需要 Migration。
## Acceptance criteria
- [ ] `pkg/constants/iot.go` 新增 `GatewayCardExtendRiskStop``GatewayCardExtendCancelled` 两个常量
- [ ] 后台 `ManualStartCard` 在调用网关前检查独立卡 `gateway_extend`,命中风险值时返回业务错误
- [ ] Open API `ResumeCard` 在调用网关前检查独立卡 `gateway_extend`,命中风险值时返回业务错误
- [ ] 已绑定设备的卡(`is_standalone = false`)不受此限制,复机正常进行
- [ ] 返回的错误信息能区分"风险停机"和"已销户"两种情况
## Blocked by
None - can start immediately

View File

@@ -0,0 +1,28 @@
Status: done
## Parent
`.scratch/iot-risk-import-voucher-remark/PRD.md`
## What to build
`PollingCardStatusHandler` 中,当轮询查询网关后将新的 `gateway_extend` 写入 DB若新值命中风险常量`GatewayCardExtendRiskStop``GatewayCardExtendCancelled`)且该卡 `is_standalone = true`,则:
1. 调用现有的 `UpdatePollingStatus(false)``enable_polling` 写为 `false`
2. 跳过末尾的 `requeueCard`,终止该卡的轮询循环
检查时机:在 `UpdateFields` 写入 `gateway_extend` 成功之后,`requeueCard` 调用之前。
不需要 Schema 变更,不需要 Migration。
## Acceptance criteria
- [ ] 轮询处理器在写入 `gateway_extend` 后检查风险状态
- [ ] 独立卡(`is_standalone=true`)命中风险值时调用 `UpdatePollingStatus(false)``tb_iot_card.enable_polling` 被置为 `false`
- [ ] 该卡不再入队(不调用 `requeueCard`),轮询循环终止
- [ ] 已绑定设备的卡(`is_standalone=false`)命中风险值时不触发此逻辑,轮询正常继续
- [ ] 可通过 PostgreSQL MCP 验证:风险状态卡处理后 `enable_polling = false`
## Blocked by
- `issues/01-risk-resume-block.md`(依赖 `GatewayCardExtendRiskStop``GatewayCardExtendCancelled` 常量)

View File

@@ -0,0 +1,30 @@
Status: done
## Parent
`.scratch/iot-risk-import-voucher-remark/PRD.md`
## What to build
在现有两个导入任务表中新增操作人快照字段,并在列表接口返回:
- `tb_iot_card_import_task` 新增 `creator_name varchar(100)` 字段
- `tb_device_import_task` 新增 `creator_name varchar(100)` 字段
- 创建任务时从当前登录用户快照姓名写入(不可为 null旧数据留空字符串
- IoT 卡导入任务列表响应 DTO 新增 `creator_name` 字段
- 设备导入任务列表响应 DTO 新增 `creator_name` 字段
历史数据不回填,旧记录 `creator_name` 为空字符串。
## Acceptance criteria
- [ ] Migration 为两个现有任务表各添加 `creator_name varchar(100) not null default ''` 字段
- [ ] IoT 卡导入任务创建时写入当前用户姓名快照
- [ ] 设备导入任务创建时写入当前用户姓名快照
- [ ] IoT 卡导入任务列表接口返回 `creator_name` 字段
- [ ] 设备导入任务列表接口返回 `creator_name` 字段
- [ ] 旧记录 `creator_name` 为空字符串,不报错
## Blocked by
None - can start immediately

View File

@@ -0,0 +1,43 @@
Status: done
## Parent
`.scratch/iot-risk-import-voucher-remark/PRD.md`
## What to build
新增"批量失效订单套餐"导入任务,完整实现 Model → Store → Service → Handler → Route → Worker 全链路,参照现有 IoT 卡导入任务的结构。
**数据模型**(新建 `tb_order_package_invalidate_task`
- 参照 `tb_iot_card_import_task` 的基础字段(任务编号、状态、计数、失败/跳过明细、文件存储 key、时间戳等
- 额外字段:`creator_name varchar(100)``remark text``voucher_keys jsonb`(存储 `[]string`最多5个元素
**上传接口**(创建任务):
- 接受 CSV 文件(单列 `order_no`
- 额外参数:`remark`(字符串,可选)和 `voucher_keys``[]string`最多5个可选
- 写入 `creator_name` 快照
**Worker 处理逻辑**
- 逐行读取 `order_no`
-`order_no` 查询 `tb_order` 获取 `order_id`;找不到则记为失败,继续处理
- 查询 `tb_package_usage WHERE order_id = ? AND status NOT IN (3, 4)`,批量更新 `status = 4`(已失效)
- 订单存在但套餐全部已是终态status 3 或 4记为成功
- 不触发退款,不调用网关,不直接停机
**列表/详情接口**:参照现有导入任务接口结构。
## Acceptance criteria
- [ ] Migration 创建 `tb_order_package_invalidate_task` 表,包含所有必要字段
- [ ] 创建任务接口:接受 CSV + remark + voucher_keys最多5个写入 creator_name 快照
- [ ] Worker 按行处理:`order_no` 不存在 → 失败并记录原因,继续下一行
- [ ] Worker 按行处理:订单存在且有可失效套餐 → 批量更新 `status=4` → 记为成功
- [ ] Worker 按行处理:订单存在但套餐全为终态 → 记为成功
- [ ] 处理过程中不调用退款接口、不操作网关
- [ ] 列表接口返回 `creator_name``remark`、任务状态和计数
- [ ] 详情接口返回失败明细(含 order_no 和原因)
- [ ] 已在路由和文档生成器中注册
## Blocked by
None - can start immediately

View File

@@ -0,0 +1,36 @@
Status: done
## Parent
`.scratch/iot-risk-import-voucher-remark/PRD.md`
## What to build
一次 Migration 完成三个现有表的凭证字段类型变更,并同时新增代理预充值备注字段:
**字段类型变更**varchar(500) → jsonb
- `tb_order.payment_voucher_key`
- `tb_refund.refund_voucher_key`
- `tb_agent_recharge_record.payment_voucher_key`
**数据转换规则**(在同一 Migration 的 USING 子句中完成):
- 非空旧值 `"some_key"``["some_key"]`
- 空字符串 `""``[]`
- NULL → `[]`
**新增字段**
- `tb_agent_recharge_record.remark text`(可为空,默认 null
生产环境由运营手动执行Migration 文件需包含完整的 UP 和 DOWN 语句。
## Acceptance criteria
- [ ] Migration UP三个凭证字段成功从 varchar 转为 jsonb历史单值数据转换为单元素数组
- [ ] Migration UP空字符串/NULL 转换为空数组 `[]`
- [ ] Migration UP`tb_agent_recharge_record` 新增 `remark text` 字段
- [ ] Migration DOWN可回滚jsonb → varchar取数组第一个元素remark 字段删除)
- [ ] 迁移后可用 PostgreSQL MCP 验证数据格式正确
## Blocked by
None - can start immediately

View File

@@ -0,0 +1,27 @@
Status: done
## Parent
`.scratch/iot-risk-import-voucher-remark/PRD.md`
## What to build
将后台创建订单接口的凭证字段从单个字符串改为最多5个字符串的列表
- `CreateAdminOrderRequest.payment_voucher_key``string``[]string`validate 限制 `max=5`,每项 `max=500`
- `OrderResponse.payment_voucher_key`(以及所有订单相关响应 DTO`string``[]string`
- Order Model 的 `PaymentVoucherKey` 字段类型改为适配 jsonb 的 `pq.StringArray` 或自定义 JSON 类型
- Order Service 中读写 `payment_voucher_key` 的逻辑同步更新
Schema 变更已由 `issues/05-voucher-multi-migration.md` 完成。
## Acceptance criteria
- [ ] 后台创建订单接口接受 `payment_voucher_key []string`0-5个元素offline 支付时至少需要1个
- [ ] 订单列表/详情接口返回 `payment_voucher_key []string`
- [ ] 传入超过5个凭证 key 时返回参数校验错误
- [ ] 现有无凭证的订单wallet 支付)返回空数组,不报错
## Blocked by
- `issues/05-voucher-multi-migration.md`

View File

@@ -0,0 +1,29 @@
Status: done
## Parent
`.scratch/iot-risk-import-voucher-remark/PRD.md`
## What to build
将退款申请接口的凭证字段从单个字符串改为最多5个字符串的列表
- `CreateRefundRequest.refund_voucher_key``string``[]string`validate 限制 `max=5`,每项 `max=500`required至少1个
- `ResubmitRefundRequest.refund_voucher_key``*string``*[]string`(重新提交时可选替换)
- `RefundResponse.refund_voucher_key`(以及所有退款相关响应 DTO`string``[]string`
- Refund Model 的 `RefundVoucherKey` 字段类型改为适配 jsonb 的类型
- Refund Service 中读写 `refund_voucher_key` 的逻辑同步更新
Schema 变更已由 `issues/05-voucher-multi-migration.md` 完成。
## Acceptance criteria
- [ ] 创建退款申请接口接受 `refund_voucher_key []string`1-5个元素必填
- [ ] 重新提交退款接口的 `refund_voucher_key` 可选,传入时替换全部凭证
- [ ] 退款列表/详情接口返回 `refund_voucher_key []string`
- [ ] 传入超过5个凭证 key 时返回参数校验错误
- [ ] 传入空数组时返回参数校验错误至少需要1个
## Blocked by
- `issues/05-voucher-multi-migration.md`

View File

@@ -0,0 +1,35 @@
Status: done
## Parent
`.scratch/iot-risk-import-voucher-remark/PRD.md`
## What to build
同时完成代理预充值的凭证多图改造和备注字段接入:
**凭证多图**
- `CreateAgentRechargeRequest.payment_voucher_key``string``[]string`validate 限制 `max=5`,每项 `max=500`offline 支付时至少1个微信支付时忽略
- `AgentRechargeResponse.payment_voucher_key``string``[]string`
- `AgentRechargeRecord.PaymentVoucherKey` Model 字段类型改为适配 jsonb 的类型
**备注字段**
- `CreateAgentRechargeRequest` 新增 `remark string`可选建议不超过1000字符
- `AgentRechargeResponse` 新增 `remark string`(列表和详情接口均返回)
- `AgentRechargeRecord.Remark` 在创建时写入,后续不可修改
AgentRecharge Service 中读写相关字段的逻辑同步更新。
Schema 变更payment_voucher_key 类型 + remark 字段)已由 `issues/05-voucher-multi-migration.md` 完成。
## Acceptance criteria
- [ ] 创建代理预充值接口接受 `payment_voucher_key []string`offline 时至少1个和可选 `remark`
- [ ] 代理预充值列表/详情接口返回 `payment_voucher_key []string``remark`
- [ ] 传入超过5个凭证 key 时返回参数校验错误
- [ ] 不新增 remark 修改接口,创建后备注字段只读
- [ ] 微信支付创建预充值时可不传凭证(与现有逻辑一致)
## Blocked by
- `issues/05-voucher-multi-migration.md`