开放接口,修复上游同步不对的问题
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m55s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m55s
This commit is contained in:
489
internal/service/agent_open_api/service.go
Normal file
489
internal/service/agent_open_api/service.go
Normal file
@@ -0,0 +1,489 @@
|
||||
package agent_open_api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
"github.com/break/junhong_cmp_fiber/internal/model/dto"
|
||||
assetSvc "github.com/break/junhong_cmp_fiber/internal/service/asset"
|
||||
orderSvc "github.com/break/junhong_cmp_fiber/internal/service/order"
|
||||
packageSvc "github.com/break/junhong_cmp_fiber/internal/service/package"
|
||||
shopCommissionSvc "github.com/break/junhong_cmp_fiber/internal/service/shop_commission"
|
||||
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/middleware"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Service 代理开放接口业务编排服务
|
||||
type Service struct {
|
||||
assetService *assetSvc.Service
|
||||
packageService *packageSvc.Service
|
||||
orderService *orderSvc.Service
|
||||
shopCommissionService *shopCommissionSvc.Service
|
||||
iotCardStore *postgres.IotCardStore
|
||||
packageUsageStore *postgres.PackageUsageStore
|
||||
packageStore *postgres.PackageStore
|
||||
packageSeriesStore *postgres.PackageSeriesStore
|
||||
agentWalletStore *postgres.AgentWalletStore
|
||||
}
|
||||
|
||||
// New 创建代理开放接口业务编排服务
|
||||
func New(
|
||||
assetService *assetSvc.Service,
|
||||
packageService *packageSvc.Service,
|
||||
orderService *orderSvc.Service,
|
||||
shopCommissionService *shopCommissionSvc.Service,
|
||||
iotCardStore *postgres.IotCardStore,
|
||||
packageUsageStore *postgres.PackageUsageStore,
|
||||
packageStore *postgres.PackageStore,
|
||||
packageSeriesStore *postgres.PackageSeriesStore,
|
||||
agentWalletStore *postgres.AgentWalletStore,
|
||||
) *Service {
|
||||
return &Service{
|
||||
assetService: assetService,
|
||||
packageService: packageService,
|
||||
orderService: orderService,
|
||||
shopCommissionService: shopCommissionService,
|
||||
iotCardStore: iotCardStore,
|
||||
packageUsageStore: packageUsageStore,
|
||||
packageStore: packageStore,
|
||||
packageSeriesStore: packageSeriesStore,
|
||||
agentWalletStore: agentWalletStore,
|
||||
}
|
||||
}
|
||||
|
||||
// GetCardTraffic 查询开放接口单卡流量
|
||||
func (s *Service) GetCardTraffic(ctx context.Context, req *dto.AgentOpenAPICardQueryRequest) (*dto.AgentOpenAPICardTrafficResponse, error) {
|
||||
card, err := s.resolveOpenAPICard(ctx, req.CardNo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
activeStatus := constants.PackageUsageStatusActive
|
||||
pendingStatus := constants.PackageUsageStatusPending
|
||||
activeUsages, err := s.packageUsageStore.ListByCarrier(ctx, "iot_card", card.ID, &activeStatus)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.CodeInternalError, err, "查询生效套餐失败")
|
||||
}
|
||||
pendingUsages, err := s.packageUsageStore.ListByCarrier(ctx, "iot_card", card.ID, &pendingStatus)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.CodeInternalError, err, "查询待生效套餐失败")
|
||||
}
|
||||
|
||||
packageMap, seriesMap, err := s.loadUsagePackageContext(ctx, append(activeUsages, pendingUsages...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp := &dto.AgentOpenAPICardTrafficResponse{
|
||||
CardNo: req.CardNo,
|
||||
ActivePackages: make([]dto.AgentOpenAPIPackageTrafficItem, 0, len(activeUsages)),
|
||||
PendingPackages: make([]dto.AgentOpenAPIPackageTrafficItem, 0, len(pendingUsages)),
|
||||
}
|
||||
for _, usage := range activeUsages {
|
||||
item := s.buildTrafficItem(usage, packageMap, seriesMap, true)
|
||||
resp.ActivePackages = append(resp.ActivePackages, item)
|
||||
resp.ActiveTotalFlowMB += item.TotalFlowMB
|
||||
resp.ActiveUsedFlowMB += item.UsedFlowMB
|
||||
resp.ActiveRemainingFlowMB += item.RemainingFlowMB
|
||||
if item.ExpiresAt != nil && (resp.ActiveExpiresAt == nil || item.ExpiresAt.After(*resp.ActiveExpiresAt)) {
|
||||
resp.ActiveExpiresAt = item.ExpiresAt
|
||||
}
|
||||
}
|
||||
for _, usage := range pendingUsages {
|
||||
resp.PendingPackages = append(resp.PendingPackages, s.buildTrafficItem(usage, packageMap, seriesMap, false))
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetCardStatus 查询开放接口单卡状态
|
||||
func (s *Service) GetCardStatus(ctx context.Context, req *dto.AgentOpenAPICardQueryRequest) (*dto.AgentOpenAPICardStatusResponse, error) {
|
||||
card, err := s.resolveOpenAPICard(ctx, req.CardNo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cardStatus := constants.AgentOpenAPICardStatusStopped
|
||||
stopReason := card.StopReason
|
||||
if card.NetworkStatus == constants.NetworkStatusOnline {
|
||||
cardStatus = constants.AgentOpenAPICardStatusNormal
|
||||
stopReason = ""
|
||||
}
|
||||
|
||||
return &dto.AgentOpenAPICardStatusResponse{
|
||||
CardNo: req.CardNo,
|
||||
CardStatus: cardStatus,
|
||||
CardStatusName: constants.AgentOpenAPICardStatusName(cardStatus),
|
||||
StopReason: stopReason,
|
||||
StopReasonName: constants.AgentOpenAPIStopReasonName(stopReason),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetRealnameStatus 查询开放接口单卡实名状态
|
||||
func (s *Service) GetRealnameStatus(ctx context.Context, req *dto.AgentOpenAPICardQueryRequest) (*dto.AgentOpenAPIRealnameStatusResponse, error) {
|
||||
card, err := s.resolveOpenAPICard(ctx, req.CardNo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.AgentOpenAPIRealnameStatusResponse{
|
||||
CardNo: req.CardNo,
|
||||
IsRealnamed: card.RealNameStatus == constants.RealNameStatusVerified,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ListPackages 查询开放接口代理可购买套餐列表
|
||||
func (s *Service) ListPackages(ctx context.Context, req *dto.AgentOpenAPIPackageListRequest) ([]*dto.AgentOpenAPIPackageItem, int64, int, int, error) {
|
||||
status := constants.StatusEnabled
|
||||
shelfStatus := constants.ShelfStatusOn
|
||||
packageReq := &dto.PackageListRequest{
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
PackageName: req.PackageName,
|
||||
SeriesID: req.SeriesID,
|
||||
Status: &status,
|
||||
ShelfStatus: &shelfStatus,
|
||||
PackageType: req.PackageType,
|
||||
}
|
||||
packages, total, err := s.packageService.List(ctx, packageReq)
|
||||
if err != nil {
|
||||
return nil, 0, 0, 0, err
|
||||
}
|
||||
|
||||
items := make([]*dto.AgentOpenAPIPackageItem, 0, len(packages))
|
||||
for _, pkg := range packages {
|
||||
items = append(items, &dto.AgentOpenAPIPackageItem{
|
||||
PackageID: pkg.ID,
|
||||
PackageCode: pkg.PackageCode,
|
||||
PackageName: pkg.PackageName,
|
||||
SeriesName: stringValue(pkg.SeriesName),
|
||||
PackageType: pkg.PackageType,
|
||||
PackageTypeName: constants.AgentOpenAPIPackageTypeName(pkg.PackageType),
|
||||
CostPrice: pkg.CostPrice,
|
||||
RetailPrice: int64Value(pkg.EffectiveRetailPrice),
|
||||
TotalFlowMB: pkg.RealDataMB,
|
||||
ValidDays: packageValidDays(pkg.DurationDays, pkg.DurationMonths),
|
||||
})
|
||||
}
|
||||
|
||||
page, pageSize := normalizePage(req.Page, req.PageSize)
|
||||
return items, total, page, pageSize, nil
|
||||
}
|
||||
|
||||
// GetWalletBalance 查询开放接口预充值主钱包余额
|
||||
func (s *Service) GetWalletBalance(ctx context.Context) (*dto.AgentOpenAPIWalletBalanceResponse, error) {
|
||||
shopID := middleware.GetShopIDFromContext(ctx)
|
||||
if shopID == 0 {
|
||||
return nil, errors.New(errors.CodeUnauthorized)
|
||||
}
|
||||
|
||||
wallet, err := s.agentWalletStore.GetMainWallet(ctx, shopID)
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return &dto.AgentOpenAPIWalletBalanceResponse{
|
||||
Balance: 0,
|
||||
FrozenBalance: 0,
|
||||
AvailableBalance: 0,
|
||||
Currency: constants.AgentOpenAPIWalletCurrencyCNY,
|
||||
}, nil
|
||||
}
|
||||
return nil, errors.Wrap(errors.CodeInternalError, err, "查询主钱包余额失败")
|
||||
}
|
||||
|
||||
return &dto.AgentOpenAPIWalletBalanceResponse{
|
||||
Balance: wallet.Balance,
|
||||
FrozenBalance: wallet.FrozenBalance,
|
||||
AvailableBalance: wallet.GetAvailableBalance(),
|
||||
Currency: walletCurrency(wallet.Currency),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ListWalletTransactions 查询开放接口预充值主钱包流水
|
||||
func (s *Service) ListWalletTransactions(ctx context.Context, req *dto.AgentOpenAPIWalletTransactionListRequest) (*dto.MainWalletTransactionListResponse, error) {
|
||||
shopID := middleware.GetShopIDFromContext(ctx)
|
||||
if shopID == 0 {
|
||||
return nil, errors.New(errors.CodeUnauthorized)
|
||||
}
|
||||
|
||||
return s.shopCommissionService.ListMainWalletTransactions(ctx, shopID, &dto.MainWalletTransactionListRequest{
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
TransactionType: req.TransactionType,
|
||||
StartDate: req.StartDate,
|
||||
EndDate: req.EndDate,
|
||||
})
|
||||
}
|
||||
|
||||
// CreateWalletPackageOrders 使用代理预充值钱包按卡购买套餐
|
||||
func (s *Service) CreateWalletPackageOrders(ctx context.Context, req *dto.AgentOpenAPIWalletPackageOrderRequest) (*dto.AgentOpenAPIWalletPackageOrderResponse, error) {
|
||||
shopID := middleware.GetShopIDFromContext(ctx)
|
||||
if shopID == 0 {
|
||||
return nil, errors.New(errors.CodeUnauthorized)
|
||||
}
|
||||
|
||||
pkg, err := s.packageStore.GetByCode(ctx, strings.TrimSpace(req.PackageCode))
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, errors.New(errors.CodeNotFound, "套餐不存在")
|
||||
}
|
||||
return nil, errors.Wrap(errors.CodeInternalError, err, "查询套餐失败")
|
||||
}
|
||||
|
||||
resp := &dto.AgentOpenAPIWalletPackageOrderResponse{
|
||||
BatchNo: generateAgentOpenAPIBatchNo(),
|
||||
PackageCode: pkg.PackageCode,
|
||||
Orders: []dto.AgentOpenAPIWalletPackageOrderItem{},
|
||||
FailedCards: []dto.AgentOpenAPIWalletPackageOrderFailure{},
|
||||
}
|
||||
|
||||
for _, rawCardNo := range req.CardNos {
|
||||
cardNo := strings.TrimSpace(rawCardNo)
|
||||
if cardNo == "" {
|
||||
resp.FailedCards = append(resp.FailedCards, buildFailedCard(rawCardNo, errors.New(errors.CodeInvalidParam, "卡标识不能为空")))
|
||||
continue
|
||||
}
|
||||
card, err := s.resolveOpenAPICard(ctx, cardNo)
|
||||
if err != nil {
|
||||
resp.FailedCards = append(resp.FailedCards, buildFailedCard(cardNo, err))
|
||||
continue
|
||||
}
|
||||
|
||||
orderResp, err := s.orderService.CreateAdminOrder(ctx, &dto.CreateAdminOrderRequest{
|
||||
Identifier: card.ICCID,
|
||||
PackageIDs: []uint{pkg.ID},
|
||||
PaymentMethod: model.PaymentMethodWallet,
|
||||
}, model.BuyerTypeAgent, shopID)
|
||||
if err != nil {
|
||||
resp.FailedCards = append(resp.FailedCards, buildFailedCard(cardNo, err))
|
||||
continue
|
||||
}
|
||||
|
||||
resp.Orders = append(resp.Orders, dto.AgentOpenAPIWalletPackageOrderItem{
|
||||
CardNo: cardNo,
|
||||
OrderNo: orderResp.OrderNo,
|
||||
})
|
||||
}
|
||||
|
||||
resp.SuccessCount = len(resp.Orders)
|
||||
resp.FailedCount = len(resp.FailedCards)
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// resolveOpenAPICard 将开放接口卡标识解析为当前代理可见的 IoT 卡
|
||||
func (s *Service) resolveOpenAPICard(ctx context.Context, cardNo string) (*model.IotCard, error) {
|
||||
identifier := strings.TrimSpace(cardNo)
|
||||
if identifier == "" {
|
||||
return nil, errors.New(errors.CodeInvalidParam)
|
||||
}
|
||||
if s.assetService == nil || s.iotCardStore == nil {
|
||||
return nil, errors.New(errors.CodeInternalError, "开放接口资产解析依赖未配置")
|
||||
}
|
||||
|
||||
resolved, err := s.assetService.Resolve(ctx, identifier)
|
||||
if err != nil {
|
||||
if appErr, ok := err.(*errors.AppError); ok && appErr.Code == errors.CodeNotFound {
|
||||
return s.resolveOpenAPICardByIdentifier(ctx, identifier)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if resolved.AssetType != "card" {
|
||||
return nil, errors.New(errors.CodeInvalidParam, "开放接口只支持单卡标识")
|
||||
}
|
||||
|
||||
card, err := s.iotCardStore.GetByID(ctx, resolved.AssetID)
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
|
||||
}
|
||||
return nil, errors.Wrap(errors.CodeInternalError, err, "查询卡信息失败")
|
||||
}
|
||||
return card, nil
|
||||
}
|
||||
|
||||
// resolveOpenAPICardByIdentifier 兜底支持 ICCID 双列、虚拟号和 MSISDN 精确解析
|
||||
func (s *Service) resolveOpenAPICardByIdentifier(ctx context.Context, identifier string) (*model.IotCard, error) {
|
||||
card, err := s.iotCardStore.GetByIdentifier(ctx, identifier)
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
|
||||
}
|
||||
return nil, errors.Wrap(errors.CodeInternalError, err, "查询卡信息失败")
|
||||
}
|
||||
return card, nil
|
||||
}
|
||||
|
||||
// loadUsagePackageContext 批量加载套餐和系列信息,避免单卡流量响应出现 N+1 查询
|
||||
func (s *Service) loadUsagePackageContext(ctx context.Context, usages []*model.PackageUsage) (map[uint]*model.Package, map[uint]string, error) {
|
||||
packageIDs := make([]uint, 0)
|
||||
packageIDSeen := make(map[uint]struct{})
|
||||
for _, usage := range usages {
|
||||
if usage.PackageID == 0 {
|
||||
continue
|
||||
}
|
||||
if _, ok := packageIDSeen[usage.PackageID]; !ok {
|
||||
packageIDSeen[usage.PackageID] = struct{}{}
|
||||
packageIDs = append(packageIDs, usage.PackageID)
|
||||
}
|
||||
}
|
||||
|
||||
packages, err := s.packageStore.GetByIDsUnscoped(ctx, packageIDs)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(errors.CodeInternalError, err, "批量查询套餐失败")
|
||||
}
|
||||
packageMap := make(map[uint]*model.Package, len(packages))
|
||||
seriesIDSeen := make(map[uint]struct{})
|
||||
seriesIDs := make([]uint, 0)
|
||||
for _, pkg := range packages {
|
||||
packageMap[pkg.ID] = pkg
|
||||
if pkg.SeriesID > 0 {
|
||||
if _, ok := seriesIDSeen[pkg.SeriesID]; !ok {
|
||||
seriesIDSeen[pkg.SeriesID] = struct{}{}
|
||||
seriesIDs = append(seriesIDs, pkg.SeriesID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
seriesList, err := s.packageSeriesStore.GetByIDs(ctx, seriesIDs)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(errors.CodeInternalError, err, "批量查询套餐系列失败")
|
||||
}
|
||||
seriesMap := make(map[uint]string, len(seriesList))
|
||||
for _, series := range seriesList {
|
||||
seriesMap[series.ID] = series.SeriesName
|
||||
}
|
||||
|
||||
return packageMap, seriesMap, nil
|
||||
}
|
||||
|
||||
// buildTrafficItem 按开放接口口径构造套餐流量项,主动隐藏虚流量内部字段
|
||||
func (s *Service) buildTrafficItem(usage *model.PackageUsage, packageMap map[uint]*model.Package, seriesMap map[uint]string, active bool) dto.AgentOpenAPIPackageTrafficItem {
|
||||
pkg := packageMap[usage.PackageID]
|
||||
packageCode := ""
|
||||
packageName := usage.PackageName
|
||||
packageType := ""
|
||||
validDays := 0
|
||||
seriesName := ""
|
||||
if pkg != nil {
|
||||
packageCode = pkg.PackageCode
|
||||
if packageName == "" {
|
||||
packageName = pkg.PackageName
|
||||
}
|
||||
packageType = pkg.PackageType
|
||||
validDays = packageValidDays(nil, pkg.DurationMonths)
|
||||
if pkg.DurationDays > 0 {
|
||||
validDays = pkg.DurationDays
|
||||
}
|
||||
seriesName = seriesMap[pkg.SeriesID]
|
||||
}
|
||||
|
||||
usedFlow := int64(0)
|
||||
remainingFlow := int64(0)
|
||||
if active {
|
||||
usedFlow = visibleUsedFlowMB(usage)
|
||||
remainingFlow = usage.DataLimitMB - usedFlow
|
||||
if remainingFlow < 0 {
|
||||
remainingFlow = 0
|
||||
}
|
||||
}
|
||||
|
||||
return dto.AgentOpenAPIPackageTrafficItem{
|
||||
PackageCode: packageCode,
|
||||
PackageName: packageName,
|
||||
SeriesName: seriesName,
|
||||
PackageType: packageType,
|
||||
PackageTypeName: constants.AgentOpenAPIPackageTypeName(packageType),
|
||||
TotalFlowMB: usage.DataLimitMB,
|
||||
UsedFlowMB: usedFlow,
|
||||
RemainingFlowMB: remainingFlow,
|
||||
StartAt: usage.ActivatedAt,
|
||||
ExpiresAt: usage.ExpiresAt,
|
||||
ValidDays: validDays,
|
||||
Priority: usage.Priority,
|
||||
}
|
||||
}
|
||||
|
||||
// visibleUsedFlowMB 计算对代理展示的已用流量,并限制不超过真实总量
|
||||
func visibleUsedFlowMB(usage *model.PackageUsage) int64 {
|
||||
ratio := usage.DisplayGainRatioSnapshot
|
||||
if ratio <= 0 {
|
||||
ratio = 1
|
||||
}
|
||||
used := int64(float64(usage.DataUsageMB) * ratio)
|
||||
if used > usage.DataLimitMB {
|
||||
return usage.DataLimitMB
|
||||
}
|
||||
if used < 0 {
|
||||
return 0
|
||||
}
|
||||
return used
|
||||
}
|
||||
|
||||
// packageValidDays 将套餐有效期统一折算为开放接口展示天数
|
||||
func packageValidDays(durationDays *int, durationMonths int) int {
|
||||
if durationDays != nil && *durationDays > 0 {
|
||||
return *durationDays
|
||||
}
|
||||
if durationMonths > 0 {
|
||||
return durationMonths * 30
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func normalizePage(page, pageSize int) (int, int) {
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize < 1 {
|
||||
pageSize = constants.DefaultPageSize
|
||||
}
|
||||
if pageSize > constants.MaxPageSize {
|
||||
pageSize = constants.MaxPageSize
|
||||
}
|
||||
return page, pageSize
|
||||
}
|
||||
|
||||
func stringValue(value *string) string {
|
||||
if value == nil {
|
||||
return ""
|
||||
}
|
||||
return *value
|
||||
}
|
||||
|
||||
func int64Value(value *int64) int64 {
|
||||
if value == nil {
|
||||
return 0
|
||||
}
|
||||
return *value
|
||||
}
|
||||
|
||||
func walletCurrency(currency string) string {
|
||||
if currency == "" {
|
||||
return constants.AgentOpenAPIWalletCurrencyCNY
|
||||
}
|
||||
return currency
|
||||
}
|
||||
|
||||
func buildFailedCard(cardNo string, err error) dto.AgentOpenAPIWalletPackageOrderFailure {
|
||||
code := errors.CodeInternalError
|
||||
message := errors.GetMessage(code, "zh-CN")
|
||||
if appErr, ok := err.(*errors.AppError); ok {
|
||||
code = appErr.Code
|
||||
message = appErr.Message
|
||||
}
|
||||
return dto.AgentOpenAPIWalletPackageOrderFailure{
|
||||
CardNo: cardNo,
|
||||
Code: code,
|
||||
Message: message,
|
||||
}
|
||||
}
|
||||
|
||||
func generateAgentOpenAPIBatchNo() string {
|
||||
return fmt.Sprintf("%s%s%06d", constants.AgentOpenAPIBatchNoPrefix, time.Now().Format("20060102150405"), rand.Intn(1000000))
|
||||
}
|
||||
@@ -1241,8 +1241,15 @@ func (s *Service) RefreshCardDataFromGateway(ctx context.Context, iccid string)
|
||||
if err != nil {
|
||||
s.logger.Warn("刷新卡数据:查询网络状态失败", zap.String("iccid", iccid), zap.Error(err))
|
||||
} else {
|
||||
networkStatus := parseNetworkStatus(statusResp.CardStatus)
|
||||
updates["network_status"] = networkStatus
|
||||
networkStatus, ok := gateway.ParseCardNetworkStatus(statusResp.CardStatus, statusResp.Extend)
|
||||
if !ok {
|
||||
s.logger.Warn("刷新卡数据:未知 Gateway 卡状态",
|
||||
zap.String("iccid", iccid),
|
||||
zap.String("card_status", statusResp.CardStatus),
|
||||
zap.String("extend", statusResp.Extend))
|
||||
} else {
|
||||
updates["network_status"] = networkStatus
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 查询实名状态
|
||||
@@ -1267,7 +1274,7 @@ func (s *Service) RefreshCardDataFromGateway(ctx context.Context, iccid string)
|
||||
if err != nil {
|
||||
s.logger.Warn("刷新卡数据:查询流量失败", zap.String("iccid", iccid), zap.Error(err))
|
||||
} else {
|
||||
flowIncrementMB = s.calculateRefreshFlowUpdates(card, flowResp.Used, syncTime, updates)
|
||||
flowIncrementMB = s.calculateRefreshFlowUpdates(card, float64(flowResp.Used), syncTime, updates)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1385,15 +1392,6 @@ func isRefreshResetWindow(now time.Time, resetDay int) bool {
|
||||
return today == prevDay
|
||||
}
|
||||
|
||||
// parseNetworkStatus 将网关返回的卡状态字符串转换为 network_status 数值
|
||||
// 停机→0,其他(准备/正常)→1
|
||||
func parseNetworkStatus(cardStatus string) int {
|
||||
if cardStatus == "停机" {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
// parseGatewayRealnameStatus 将网关返回的实名状态布尔值转换为 real_name_status 数值
|
||||
// true=已实名(1),false=未实名(0)
|
||||
func parseGatewayRealnameStatus(realStatus bool) int {
|
||||
|
||||
@@ -2064,6 +2064,12 @@ func (s *Service) resolveAssetByIdentifier(ctx context.Context, identifier strin
|
||||
}
|
||||
}
|
||||
}
|
||||
if card, cardErr := s.iotCardStore.GetByIdentifier(ctx, identifier); cardErr == nil && card != nil {
|
||||
return card, nil, nil
|
||||
}
|
||||
if device, deviceErr := s.deviceStore.GetByIdentifier(ctx, identifier); deviceErr == nil && device != nil {
|
||||
return nil, device, nil
|
||||
}
|
||||
return nil, nil, errors.New(errors.CodeNotFound, "未找到对应资产,请使用 ICCID 或虚拟号")
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user