feat: 业务逻辑补全 — 佣金待审记录、C端订单重构、支付抽象、富友支付、卡设备状态联动
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled
F-1: 佣金链断裂时创建 status=99 零额待审记录,新增修正接口 POST /commission-records/:id/resolve F-4: C端订单查询从 Handler 迁移至 Service 层,移除 SkipPermissionCtx J-1: 富友支付 JSAPI/MiniApp 预下单实现,回调补全签名验证 J-2: 平台钱包代购支持(buyerType 为空时使用资产所属代理钱包) J-3: 套餐激活后自动更新卡/设备 status=3,最后套餐过期后更新 status=4 支付抽象: 引入 PaymentProvider 接口 + 微信/富友适配器,CreateOrder 支持多支付渠道 修复: 设备/IoT卡响应 DTO 移除 omitempty,空值字段返回 null 而非省略
This commit is contained in:
@@ -311,28 +311,8 @@ func (s *Service) GetRealtimeStatus(ctx context.Context, assetType string, id ui
|
||||
resp.DeviceProtectStatus = s.getDeviceProtectStatus(ctx, id)
|
||||
|
||||
// 实时查询 Gateway 设备状态(不缓存,per D-05)
|
||||
// Gateway 失败不阻断主流程,DeviceRealtime 返回 null(per D-06)
|
||||
if s.gatewayClient != nil {
|
||||
device, devErr := s.deviceStore.GetByID(ctx, id)
|
||||
if devErr == nil {
|
||||
// IMEI 优先,无则用 SN(与 Refresh 中 updateDeviceFromSyncInfo 保持一致)
|
||||
cardNo := device.IMEI
|
||||
if cardNo == "" {
|
||||
cardNo = device.SN
|
||||
}
|
||||
if cardNo != "" {
|
||||
if syncResp, syncErr := s.gatewayClient.SyncDeviceInfo(ctx, &gateway.SyncDeviceInfoReq{
|
||||
CardNo: cardNo,
|
||||
}); syncErr == nil {
|
||||
resp.DeviceRealtime = mapSyncRespToDeviceGatewayInfo(syncResp)
|
||||
} else {
|
||||
logger.GetAppLogger().Warn("GetRealtimeStatus: sync-info 调用失败,DeviceRealtime 返回 null",
|
||||
zap.Uint("device_id", id),
|
||||
zap.Error(syncErr))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Gateway 失败不阻断主流程,DeviceRealtime 始终非 nil,失败时仅填 GatewayMsg(per D-06)
|
||||
resp.DeviceRealtime = s.fetchDeviceGatewayInfo(ctx, id)
|
||||
|
||||
default:
|
||||
return nil, errors.New(errors.CodeInvalidParam, "不支持的资产类型,仅支持 card 或 device")
|
||||
@@ -341,6 +321,44 @@ func (s *Service) GetRealtimeStatus(ctx context.Context, assetType string, id ui
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// fetchDeviceGatewayInfo 查询设备 Gateway 实时状态,始终返回非 nil 对象
|
||||
// Gateway 成功时填充全量字段,失败时仅填充 GatewayMsg 供前端展示错误原因
|
||||
func (s *Service) fetchDeviceGatewayInfo(ctx context.Context, deviceID uint) *dto.DeviceGatewayInfo {
|
||||
if s.gatewayClient == nil {
|
||||
msg := "Gateway 客户端未配置"
|
||||
return &dto.DeviceGatewayInfo{GatewayMsg: &msg}
|
||||
}
|
||||
|
||||
device, err := s.deviceStore.GetByID(ctx, deviceID)
|
||||
if err != nil {
|
||||
msg := "查询设备信息失败: " + err.Error()
|
||||
return &dto.DeviceGatewayInfo{GatewayMsg: &msg}
|
||||
}
|
||||
|
||||
// IMEI 优先,无则用 SN(与 Refresh 中 updateDeviceFromSyncInfo 保持一致)
|
||||
cardNo := device.IMEI
|
||||
if cardNo == "" {
|
||||
cardNo = device.SN
|
||||
}
|
||||
if cardNo == "" {
|
||||
msg := "设备缺少 IMEI 和 SN,无法查询 Gateway 实时状态"
|
||||
return &dto.DeviceGatewayInfo{GatewayMsg: &msg}
|
||||
}
|
||||
|
||||
syncResp, syncErr := s.gatewayClient.SyncDeviceInfo(ctx, &gateway.SyncDeviceInfoReq{
|
||||
CardNo: cardNo,
|
||||
})
|
||||
if syncErr != nil {
|
||||
msg := syncErr.Error()
|
||||
logger.GetAppLogger().Warn("fetchDeviceGatewayInfo: sync-info 调用失败",
|
||||
zap.Uint("device_id", deviceID),
|
||||
zap.Error(syncErr))
|
||||
return &dto.DeviceGatewayInfo{GatewayMsg: &msg}
|
||||
}
|
||||
|
||||
return mapSyncRespToDeviceGatewayInfo(syncResp)
|
||||
}
|
||||
|
||||
// mapSyncRespToDeviceGatewayInfo 将 Gateway SyncDeviceInfoResp 映射为 B 端 DeviceGatewayInfo DTO
|
||||
// 使用指针字段,未赋值的字段保持 nil(omitempty)
|
||||
func mapSyncRespToDeviceGatewayInfo(r *gateway.SyncDeviceInfoResp) *dto.DeviceGatewayInfo {
|
||||
|
||||
Reference in New Issue
Block a user