All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m15s
标记全部 13 个任务为已完成 Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
5.5 KiB
5.5 KiB
1. 修复购买时实名状态检查(order/service.go)
- 1.1 在
activateMainPackage的 REALNAME-02 决策块中,扩展卡信息查询:将tx.Select("card_category")改为tx.Select("card_category", "real_name_status"),并从结果读取currentlyRealnamed标志 - 1.2 在 REALNAME-02 决策块中,新增
device载体的实名状态检查:当carrierType == "device"时,通过 GORM 子查询统计绑定卡(bind_status=1)中real_name_status=1的数量,count > 0则currentlyRealnamed=true;注意:使用 GORM 查询时软删除过滤(deleted_at IS NULL)由 GORM 自动注入,不需要手动添加.Where("deleted_at IS NULL") - 1.3 修改
expiry_base != "from_purchase"分支的决策逻辑:若currentlyRealnamed=true则保持status=Active(不切换为 pending),记录 Info 日志"购买时载体已实名,直接激活套餐";若currentlyRealnamed=false则保持原有pending_realname_activation=true逻辑;边界情况:若 1.1 的卡查询失败(err != nil)或 1.2 的设备子查询出错,currentlyRealnamed应保守默认为false(走 pending 路径),不应阻断整个购买流程 - 1.4 运行
lsp_diagnostics确认internal/service/order/service.go无编译错误
2. 扩展 PollingRealnameHandler(polling_realname_handler.go)
- 2.1 在
PollingRealnameHandler结构体中新增字段deviceSimBindingStore *postgres.DeviceSimBindingStore - 2.2 更新
NewPollingRealnameHandler构造函数签名,在参数列表末尾新增deviceSimBindingStore *postgres.DeviceSimBindingStore,并在函数体中赋值到结构体字段 - 2.3 新增
triggerDeviceRealnameActivation(ctx context.Context, cardID uint)函数:调用h.deviceSimBindingStore.GetActiveBindingByCardID获取设备绑定;判断无绑定使用同包内已有的isNotFound(err)工具函数(定义于internal/task/polling_utils.go),命中则静默返回;若有绑定则提交carrier_type="device", carrier_id=binding.DeviceID的TaskTypePackageFirstActivationAsynq 任务(与卡级任务相同的 MaxRetry/Timeout/Queue 配置,参照triggerFirstRealnameActivation实现);任务提交失败记录 Warn 日志,日志字段需同时包含card_id和device_id以便关联排查,不中断流程 - 2.4 在
isFirstRealname分支中,在调用triggerFirstRealnameActivation之后追加调用triggerDeviceRealnameActivation(ctx, cardID) - 2.5 运行
lsp_diagnostics确认internal/task/polling_realname_handler.go无编译错误
3. 更新 Worker 构造调用(pkg/queue/handler.go)
- 3.1 在
registerPollingHandlers中,将task.NewPollingRealnameHandler(...)调用末尾追加参数h.workerResult.Stores.DeviceSimBinding - 3.2 运行
lsp_diagnostics确认pkg/queue/handler.go无编译错误
4. 整体编译验证与存量修复
-
4.1 执行
go build ./...确认整个项目编译通过,零错误零警告 -
4.2 通过 psql 或任意数据库客户端手动执行存量修复,分三步:
步骤 0 — 确认受影响范围(只读,先跑)
SELECT pu.id, pu.device_id, pu.iot_card_id, p.calendar_type, p.duration_months, p.duration_days, p.data_reset_cycle FROM tb_package_usage pu JOIN tb_package p ON p.id = pu.package_id WHERE pu.status = 0 AND pu.pending_realname_activation = true;预期:仅返回
id=1(device_id=2,natural_month,12 个月,monthly 重置)。若有其他记录,核实后再执行步骤 1。步骤 1 — 批量修复(写操作,建议在事务中执行)
BEGIN; UPDATE tb_package_usage pu SET status = 1, pending_realname_activation = false, activated_at = NOW(), expires_at = CASE p.calendar_type WHEN 'natural_month' THEN DATE_TRUNC('month', NOW()) + ((p.duration_months + 1)::text || ' months')::interval - INTERVAL '1 second' ELSE DATE_TRUNC('day', NOW()) + (p.duration_days::text || ' days')::interval + INTERVAL '86399 seconds' END, next_reset_at = CASE p.data_reset_cycle WHEN 'monthly' THEN CASE p.calendar_type WHEN 'natural_month' THEN DATE_TRUNC('month', NOW()) + INTERVAL '1 month' ELSE DATE_TRUNC('day', NOW()) + INTERVAL '30 days' END WHEN 'daily' THEN DATE_TRUNC('day', NOW()) + INTERVAL '1 day' WHEN 'yearly' THEN DATE_TRUNC('year', NOW() + INTERVAL '1 year') ELSE NULL END, updated_at = NOW() FROM tb_package p WHERE pu.package_id = p.id AND pu.status = 0 AND pu.pending_realname_activation = true AND pu.device_id > 0 AND pu.device_id IN ( SELECT DISTINCT dsb.device_id FROM tb_device_sim_binding dsb JOIN tb_iot_card ic ON ic.id = dsb.iot_card_id WHERE dsb.bind_status = 1 AND dsb.deleted_at IS NULL AND ic.real_name_status = 1 AND ic.deleted_at IS NULL ); -- 确认影响行数为预期值后再 COMMIT,否则 ROLLBACK COMMIT;步骤 2 — 验证结果
SELECT id, status, pending_realname_activation, activated_at, expires_at, next_reset_at FROM tb_package_usage WHERE id = 1;预期:
status=1,pending_realname_activation=false,expires_at为当月 +12 个月月末 23:59:59,next_reset_at为下月 1 日 00:00:00。