Files
junhong_cmp_fiber/internal/service/iot_card/gateway_service.go
break 5c4d17e9fc
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 联调延期
2026-07-24 19:59:24 +08:00

120 lines
4.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
}