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 联调延期
120 lines
4.1 KiB
Go
120 lines
4.1 KiB
Go
package iot_card
|
||
|
||
import (
|
||
"context"
|
||
"strconv"
|
||
|
||
cardapp "github.com/break/junhong_cmp_fiber/internal/application/cardobservation"
|
||
"github.com/break/junhong_cmp_fiber/internal/gateway"
|
||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||
"go.uber.org/zap"
|
||
)
|
||
|
||
// validateCardAccess 通过 ICCID 验证卡存在且当前用户有权限访问
|
||
// 利用 GORM 数据权限回调自动过滤,确保越权请求返回 404
|
||
func (s *Service) validateCardAccess(ctx context.Context, iccid string) error {
|
||
_, err := s.iotCardStore.GetByICCID(ctx, iccid)
|
||
if err != nil {
|
||
return errors.New(errors.CodeNotFound, "卡不存在或无权限访问")
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// GatewayQueryCardStatus 查询卡实时状态
|
||
func (s *Service) GatewayQueryCardStatus(ctx context.Context, iccid string) (*gateway.CardStatusResp, error) {
|
||
if err := s.validateCardAccess(ctx, iccid); err != nil {
|
||
return nil, err
|
||
}
|
||
return s.gatewayClient.QueryCardStatus(ctx, &gateway.CardStatusReq{
|
||
CardNo: iccid,
|
||
})
|
||
}
|
||
|
||
// GatewayQueryFlow 查询流量使用情况
|
||
func (s *Service) GatewayQueryFlow(ctx context.Context, iccid string) (*gateway.FlowUsageResp, error) {
|
||
if err := s.validateCardAccess(ctx, iccid); err != nil {
|
||
return nil, err
|
||
}
|
||
return s.gatewayClient.QueryFlow(ctx, &gateway.FlowQueryReq{
|
||
CardNo: iccid,
|
||
})
|
||
}
|
||
|
||
// GatewayQueryRealnameStatus 查询实名认证状态
|
||
func (s *Service) GatewayQueryRealnameStatus(ctx context.Context, iccid string) (*gateway.RealnameStatusResp, error) {
|
||
if err := s.validateCardAccess(ctx, iccid); err != nil {
|
||
return nil, err
|
||
}
|
||
return s.gatewayClient.QueryRealnameStatus(ctx, &gateway.CardStatusReq{
|
||
CardNo: iccid,
|
||
})
|
||
}
|
||
|
||
// GatewayGetRealnameLink 获取实名认证跳转链接
|
||
func (s *Service) GatewayGetRealnameLink(ctx context.Context, iccid string) (*gateway.RealnameLinkResp, error) {
|
||
card, err := s.iotCardStore.GetByICCID(ctx, iccid)
|
||
if err != nil {
|
||
return nil, errors.New(errors.CodeNotFound, "卡不存在或无权限访问")
|
||
}
|
||
response, err := s.gatewayClient.GetRealnameLink(ctx, &gateway.CardStatusReq{
|
||
CardNo: iccid,
|
||
})
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
s.dispatchAdminRealnameObservation(ctx, card)
|
||
return response, nil
|
||
}
|
||
|
||
func (s *Service) dispatchAdminRealnameObservation(ctx context.Context, card *model.IotCard) {
|
||
if s.observationSeries == nil || card == nil {
|
||
return
|
||
}
|
||
requestID := requestIDFromContext(ctx)
|
||
s.observationSeries.DispatchRealnameWithCapability(ctx, cardapp.RealnameCapabilitySeriesRequest{
|
||
CarrierID: card.CarrierID,
|
||
Request: cardapp.SeriesRequest{
|
||
Scene: constants.CardObservationSceneAdminRealnameLink,
|
||
ResourceType: constants.CardObservationResourceTypeCard,
|
||
ResourceID: strconv.FormatUint(uint64(card.ID), 10),
|
||
SyncType: constants.CardObservationSyncTypeRealname,
|
||
ExpectedValue: "verified", Source: constants.CardObservationSourceBusinessEvent,
|
||
RequestID: requestID, CorrelationID: requestID,
|
||
},
|
||
})
|
||
}
|
||
|
||
// GatewayStopCard 停止卡服务(通过 Gateway API)
|
||
func (s *Service) GatewayStopCard(ctx context.Context, iccid string) error {
|
||
if err := s.validateCardAccess(ctx, iccid); err != nil {
|
||
return err
|
||
}
|
||
s.logger.Info("调用网关停机(手动)", zap.String("iccid", iccid))
|
||
if err := s.gatewayClient.StopCard(ctx, &gateway.CardOperationReq{
|
||
CardNo: iccid,
|
||
}); err != nil {
|
||
s.logger.Error("网关停机失败(手动)", zap.String("iccid", iccid), zap.Error(err))
|
||
return err
|
||
}
|
||
s.logger.Info("网关停机成功(手动)", zap.String("iccid", iccid))
|
||
return nil
|
||
}
|
||
|
||
// GatewayStartCard 恢复卡服务(通过 Gateway API)
|
||
func (s *Service) GatewayStartCard(ctx context.Context, iccid string) error {
|
||
if err := s.validateCardAccess(ctx, iccid); err != nil {
|
||
return err
|
||
}
|
||
s.logger.Info("调用网关复机(手动)", zap.String("iccid", iccid))
|
||
if err := s.gatewayClient.StartCard(ctx, &gateway.CardOperationReq{
|
||
CardNo: iccid,
|
||
}); err != nil {
|
||
s.logger.Error("网关复机失败(手动)", zap.String("iccid", iccid), zap.Error(err))
|
||
return err
|
||
}
|
||
s.logger.Info("网关复机成功(手动)", zap.String("iccid", iccid))
|
||
return nil
|
||
}
|