收口七月卡状态回调与系列授权兼容契约
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled
完成运营商实名回调、业务事件观测序列与受控配置装配,同时恢复 UR43 已交付的 packages[].remove 字段及旧响应兼容,统一更新 OpenSpec、OpenAPI 和交付文档。 Constraint: 七月测试环境里程碑不新增或运行自动化测试 Rejected: 以必填 operation_type 替换 packages[].remove | 会破坏已交付前端契约 Confidence: high Scope-risk: broad Directive: 后续修改系列套餐管理接口必须保持 packages[].remove 和 ShopSeriesGrantResponse 兼容 Tested: go run ./cmd/gendocs;go build -buildvcs=false ./...;openspec validate complete-july-iteration-test-release --strict;git diff --check Not-tested: 按本 Change 约定未运行 go test,真实运营商与 Gateway 联调延期
This commit is contained in:
@@ -4,9 +4,11 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
cardObservationApp "github.com/break/junhong_cmp_fiber/internal/application/cardobservation"
|
||||
domainwallet "github.com/break/junhong_cmp_fiber/internal/domain/wallet"
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
"github.com/break/junhong_cmp_fiber/internal/model/dto"
|
||||
@@ -38,6 +40,12 @@ type Service struct {
|
||||
agentWalletStore *postgres.AgentWalletStore
|
||||
deviceSimBindingStore *postgres.DeviceSimBindingStore
|
||||
deviceStore *postgres.DeviceStore
|
||||
observationSeries cardObservationApp.BestEffortSeriesDispatcher
|
||||
}
|
||||
|
||||
// SetObservationSeriesDispatcher 注入 OpenAPI 读取后的后台观测序列端口。
|
||||
func (s *Service) SetObservationSeriesDispatcher(dispatcher cardObservationApp.BestEffortSeriesDispatcher) {
|
||||
s.observationSeries = dispatcher
|
||||
}
|
||||
|
||||
// New 创建代理开放接口业务编排服务
|
||||
@@ -83,7 +91,11 @@ func (s *Service) GetCardTraffic(ctx context.Context, req *dto.AgentOpenAPICardQ
|
||||
if cardErr == nil {
|
||||
// 独立卡:直接查卡维度流量
|
||||
if card.IsStandalone {
|
||||
return s.buildCardTrafficResponse(ctx, req.CardNo, "iot_card", card.ID, "")
|
||||
resp, err := s.buildCardTrafficResponse(ctx, req.CardNo, "iot_card", card.ID, "")
|
||||
if err == nil {
|
||||
s.dispatchCardObservation(ctx, constants.CardObservationSceneOpenCardTraffic, card.ID, constants.CardObservationSyncTypeTraffic)
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
// 已绑定设备的卡:反查设备后查设备维度流量
|
||||
binding, err := s.deviceSimBindingStore.GetActiveBindingByCardID(ctx, card.ID)
|
||||
@@ -94,7 +106,11 @@ func (s *Service) GetCardTraffic(ctx context.Context, req *dto.AgentOpenAPICardQ
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.CodeInternalError, err, "查询绑定设备信息失败")
|
||||
}
|
||||
return s.buildCardTrafficResponse(ctx, req.CardNo, "device", device.ID, device.VirtualNo)
|
||||
resp, buildErr := s.buildCardTrafficResponse(ctx, req.CardNo, "device", device.ID, device.VirtualNo)
|
||||
if buildErr == nil {
|
||||
s.dispatchCardObservation(ctx, constants.CardObservationSceneOpenCardTraffic, card.ID, constants.CardObservationSyncTypeTraffic)
|
||||
}
|
||||
return resp, buildErr
|
||||
}
|
||||
|
||||
// 兜底:尝试解析为设备标识(支持 IMEI/虚拟号)
|
||||
@@ -103,7 +119,11 @@ func (s *Service) GetCardTraffic(ctx context.Context, req *dto.AgentOpenAPICardQ
|
||||
// 两种解析都失败,返回原始卡解析错误(语义更贴近入参)
|
||||
return nil, cardErr
|
||||
}
|
||||
return s.buildCardTrafficResponse(ctx, req.CardNo, "device", device.ID, device.VirtualNo)
|
||||
resp, buildErr := s.buildCardTrafficResponse(ctx, req.CardNo, "device", device.ID, device.VirtualNo)
|
||||
if buildErr == nil {
|
||||
s.dispatchDeviceCardObservations(ctx, constants.CardObservationSceneOpenCardTraffic, device.ID, constants.CardObservationSyncTypeTraffic)
|
||||
}
|
||||
return resp, buildErr
|
||||
}
|
||||
|
||||
// buildCardTrafficResponse 统一构造卡流量响应,支持卡和设备两种载体维度
|
||||
@@ -167,14 +187,16 @@ func (s *Service) GetCardStatus(ctx context.Context, req *dto.AgentOpenAPICardQu
|
||||
stopReason = ""
|
||||
}
|
||||
|
||||
return &dto.AgentOpenAPICardStatusResponse{
|
||||
resp := &dto.AgentOpenAPICardStatusResponse{
|
||||
CardNo: req.CardNo,
|
||||
CardStatus: cardStatus,
|
||||
CardStatusName: constants.AgentOpenAPICardStatusName(cardStatus),
|
||||
GatewayExtend: card.GatewayExtend,
|
||||
StopReason: stopReason,
|
||||
StopReasonName: constants.AgentOpenAPIStopReasonName(stopReason),
|
||||
}, nil
|
||||
}
|
||||
s.dispatchCardObservation(ctx, constants.CardObservationSceneOpenCardNetwork, card.ID, constants.CardObservationSyncTypeNetwork)
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetRealnameStatus 查询开放接口单卡实名状态
|
||||
@@ -184,10 +206,12 @@ func (s *Service) GetRealnameStatus(ctx context.Context, req *dto.AgentOpenAPICa
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.AgentOpenAPIRealnameStatusResponse{
|
||||
resp := &dto.AgentOpenAPIRealnameStatusResponse{
|
||||
CardNo: req.CardNo,
|
||||
IsRealnamed: card.RealNameStatus == constants.RealNameStatusVerified,
|
||||
}, nil
|
||||
}
|
||||
s.dispatchCardObservation(ctx, constants.CardObservationSceneOpenCardRealname, card.ID, constants.CardObservationSyncTypeRealname)
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// ResumeCard 调用上游复机机卡分离停机卡
|
||||
@@ -396,6 +420,41 @@ func (s *Service) CreateWalletPackageOrders(ctx context.Context, req *dto.AgentO
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *Service) dispatchDeviceCardObservations(ctx context.Context, scene string, deviceID uint, syncType string) {
|
||||
if s.observationSeries == nil || deviceID == 0 {
|
||||
return
|
||||
}
|
||||
requestID := ""
|
||||
if value := middleware.GetRequestIDFromContext(ctx); value != nil {
|
||||
requestID = *value
|
||||
}
|
||||
s.observationSeries.DispatchDeviceCards(ctx, cardObservationApp.DeviceCardsSeriesRequest{
|
||||
DeviceID: deviceID,
|
||||
Request: cardObservationApp.SeriesRequest{
|
||||
Scene: scene, ResourceType: constants.CardObservationResourceTypeDevice,
|
||||
ResourceID: strconv.FormatUint(uint64(deviceID), 10), SyncType: syncType,
|
||||
Source: constants.CardObservationSourceBusinessEvent,
|
||||
RequestID: requestID, CorrelationID: requestID,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Service) dispatchCardObservation(ctx context.Context, scene string, cardID uint, syncType string) {
|
||||
if s.observationSeries == nil || cardID == 0 {
|
||||
return
|
||||
}
|
||||
requestID := ""
|
||||
if value := middleware.GetRequestIDFromContext(ctx); value != nil {
|
||||
requestID = *value
|
||||
}
|
||||
s.observationSeries.Dispatch(ctx, cardObservationApp.SeriesRequest{
|
||||
Scene: scene, ResourceType: constants.CardObservationResourceTypeCard,
|
||||
ResourceID: strconv.FormatUint(uint64(cardID), 10), SyncType: syncType,
|
||||
Source: constants.CardObservationSourceBusinessEvent,
|
||||
RequestID: requestID, CorrelationID: requestID,
|
||||
})
|
||||
}
|
||||
|
||||
// resolveOpenAPIDevice 将开放接口设备标识解析为当前代理可见的设备
|
||||
// 设备不存在或不属于代理管辖店铺时统一返回 CodeForbidden,避免信息泄露
|
||||
func (s *Service) resolveOpenAPIDevice(ctx context.Context, deviceNo string) (*model.Device, error) {
|
||||
@@ -473,6 +532,7 @@ func (s *Service) GetDeviceTraffic(ctx context.Context, req *dto.AgentOpenAPIDev
|
||||
resp.PendingPackages = append(resp.PendingPackages, s.buildTrafficItem(usage, packageMap, seriesMap, false))
|
||||
}
|
||||
|
||||
s.dispatchDeviceCardObservations(ctx, constants.CardObservationSceneOpenDeviceTraffic, device.ID, constants.CardObservationSyncTypeTraffic)
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user