全局审计完成
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m31s

This commit is contained in:
2026-08-07 11:02:52 +08:00
parent 88cc5e96ec
commit c64f3d8b80
94 changed files with 8641 additions and 6714 deletions

View File

@@ -11,10 +11,10 @@ import (
"time"
"github.com/break/junhong_cmp_fiber/internal/gateway"
infraAudit "github.com/break/junhong_cmp_fiber/internal/infrastructure/audit"
"github.com/break/junhong_cmp_fiber/internal/model"
"github.com/break/junhong_cmp_fiber/internal/model/dto"
packageexpiry "github.com/break/junhong_cmp_fiber/internal/query/packageexpiry"
assetAuditSvc "github.com/break/junhong_cmp_fiber/internal/service/asset_audit"
"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"
@@ -52,7 +52,7 @@ type Service struct {
iotCardService IotCardRefresher
gatewayClient *gateway.Client
assetIdentifierStore *postgres.AssetIdentifierStore
assetAuditService assetAuditSvc.OperationLogger
auditWriter *infraAudit.Writer
packageExpiryQuery PackageExpiryResolver
}
@@ -78,7 +78,6 @@ func New(
orderStore *postgres.OrderStore,
orderItemStore *postgres.OrderItemStore,
exchangeOrderStore *postgres.ExchangeOrderStore,
assetAuditService assetAuditSvc.OperationLogger,
) *Service {
return &Service{
db: db,
@@ -96,11 +95,15 @@ func New(
iotCardService: iotCardService,
gatewayClient: gatewayClient,
assetIdentifierStore: assetIdentifierStore,
assetAuditService: assetAuditService,
packageExpiryQuery: packageexpiry.NewQuery(db),
}
}
// SetAccessAudit 注入资产人工调整的统一审计 Writer。
func (s *Service) SetAccessAudit(writer *infraAudit.Writer) {
s.auditWriter = writer
}
// Resolve 通过任意标识符解析资产
// 主路径:查注册表(精确匹配 ICCID 或 VirtualNo
// Fallback原有跨表 OR 查询(处理 IMEI/SN/MSISDN 等非注册标识符)
@@ -912,35 +915,26 @@ func (s *Service) UpdatePackageExpiresAt(ctx context.Context, assetType string,
}
beforeData := packageUsageExpiresAtAuditData(before)
rows, err := s.packageUsageStore.UpdateExpiresAtForCarrier(ctx, packageUsageID, carrierType, assetID, expiresAt)
var updated *model.PackageUsage
err = s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
store := postgres.NewPackageUsageStore(tx, nil)
rows, updateErr := store.UpdateExpiresAtForCarrier(ctx, packageUsageID, carrierType, assetID, expiresAt)
if updateErr != nil {
return errors.Wrap(errors.CodeDatabaseError, updateErr, "修改套餐过期时间失败")
}
if rows == 0 {
return errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
}
updated, updateErr = store.GetByIDForCarrier(ctx, packageUsageID, carrierType, assetID)
if updateErr != nil {
return errors.Wrap(errors.CodeDatabaseError, updateErr, "查询套餐使用记录失败")
}
return s.appendPackageAdjustmentAudit(ctx, tx, constants.AuditActionPackageUsageExpiresAtUpdated, "修改资产套餐过期时间", constants.AuditResultSuccess, updated, assetType, assetID, assetIdentifier, beforeData, packageUsageExpiresAtAuditData(updated), nil)
})
if err != nil {
appErr := errors.Wrap(errors.CodeDatabaseError, err, "修改套餐过期时间失败")
s.logPackageAdjustmentAudit(ctx, constants.AssetAuditOpAssetPackageExpiresAt, "修改资产套餐过期时间失败", constants.AssetAuditResultFailed, assetType, assetID, assetIdentifier, beforeData, map[string]any{
"package_usage_id": packageUsageID,
"expires_at": expiresAt,
}, appErr)
return nil, appErr
s.recordPackageAdjustmentFailure(ctx, constants.AuditActionPackageUsageExpiresAtUpdated, "修改资产套餐过期时间失败", before, assetType, assetID, assetIdentifier, beforeData, map[string]any{"package_usage_id": packageUsageID, "expires_at": expiresAt}, err)
return nil, err
}
if rows == 0 {
appErr := errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
s.logPackageAdjustmentAudit(ctx, constants.AssetAuditOpAssetPackageExpiresAt, "修改资产套餐过期时间失败", constants.AssetAuditResultFailed, assetType, assetID, assetIdentifier, beforeData, map[string]any{
"package_usage_id": packageUsageID,
"expires_at": expiresAt,
}, appErr)
return nil, appErr
}
updated, err := s.packageUsageStore.GetByIDForCarrier(ctx, packageUsageID, carrierType, assetID)
if err != nil {
appErr := errors.Wrap(errors.CodeDatabaseError, err, "查询套餐使用记录失败")
s.logPackageAdjustmentAudit(ctx, constants.AssetAuditOpAssetPackageExpiresAt, "修改资产套餐过期时间失败", constants.AssetAuditResultFailed, assetType, assetID, assetIdentifier, beforeData, map[string]any{
"package_usage_id": packageUsageID,
"expires_at": expiresAt,
}, appErr)
return nil, appErr
}
s.logPackageAdjustmentAudit(ctx, constants.AssetAuditOpAssetPackageExpiresAt, "修改资产套餐过期时间", constants.AssetAuditResultSuccess, assetType, assetID, assetIdentifier, beforeData, packageUsageExpiresAtAuditData(updated), nil)
return s.buildAssetPackageResponse(ctx, updated, constants.OwnerTypePlatform), nil
}
@@ -962,35 +956,26 @@ func (s *Service) UpdatePackageUsage(ctx context.Context, assetType string, asse
beforeData := packageUsageTrafficAuditData(before)
nextStatus := statusForManualDataUsage(before, dataUsageMB)
rows, err := s.packageUsageStore.UpdateDataUsageForCarrier(ctx, packageUsageID, carrierType, assetID, dataUsageMB, nextStatus)
var updated *model.PackageUsage
err = s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
store := postgres.NewPackageUsageStore(tx, nil)
rows, updateErr := store.UpdateDataUsageForCarrier(ctx, packageUsageID, carrierType, assetID, dataUsageMB, nextStatus)
if updateErr != nil {
return errors.Wrap(errors.CodeDatabaseError, updateErr, "修改套餐已用量失败")
}
if rows == 0 {
return errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
}
updated, updateErr = store.GetByIDForCarrier(ctx, packageUsageID, carrierType, assetID)
if updateErr != nil {
return errors.Wrap(errors.CodeDatabaseError, updateErr, "查询套餐使用记录失败")
}
return s.appendPackageAdjustmentAudit(ctx, tx, constants.AuditActionPackageUsageTrafficAdjusted, "修改资产套餐已用量", constants.AuditResultSuccess, updated, assetType, assetID, assetIdentifier, beforeData, packageUsageTrafficAuditData(updated), nil)
})
if err != nil {
appErr := errors.Wrap(errors.CodeDatabaseError, err, "修改套餐已用量失败")
s.logPackageAdjustmentAudit(ctx, constants.AssetAuditOpAssetPackageUsage, "修改资产套餐已用量失败", constants.AssetAuditResultFailed, assetType, assetID, assetIdentifier, beforeData, map[string]any{
"package_usage_id": packageUsageID,
"data_usage_mb": dataUsageMB,
}, appErr)
return nil, appErr
s.recordPackageAdjustmentFailure(ctx, constants.AuditActionPackageUsageTrafficAdjusted, "修改资产套餐已用量失败", before, assetType, assetID, assetIdentifier, beforeData, map[string]any{"package_usage_id": packageUsageID, "data_usage_mb": dataUsageMB}, err)
return nil, err
}
if rows == 0 {
appErr := errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
s.logPackageAdjustmentAudit(ctx, constants.AssetAuditOpAssetPackageUsage, "修改资产套餐已用量失败", constants.AssetAuditResultFailed, assetType, assetID, assetIdentifier, beforeData, map[string]any{
"package_usage_id": packageUsageID,
"data_usage_mb": dataUsageMB,
}, appErr)
return nil, appErr
}
updated, err := s.packageUsageStore.GetByIDForCarrier(ctx, packageUsageID, carrierType, assetID)
if err != nil {
appErr := errors.Wrap(errors.CodeDatabaseError, err, "查询套餐使用记录失败")
s.logPackageAdjustmentAudit(ctx, constants.AssetAuditOpAssetPackageUsage, "修改资产套餐已用量失败", constants.AssetAuditResultFailed, assetType, assetID, assetIdentifier, beforeData, map[string]any{
"package_usage_id": packageUsageID,
"data_usage_mb": dataUsageMB,
}, appErr)
return nil, appErr
}
s.logPackageAdjustmentAudit(ctx, constants.AssetAuditOpAssetPackageUsage, "修改资产套餐已用量", constants.AssetAuditResultSuccess, assetType, assetID, assetIdentifier, beforeData, packageUsageTrafficAuditData(updated), nil)
return s.buildAssetPackageResponse(ctx, updated, constants.OwnerTypePlatform), nil
}
@@ -1210,31 +1195,6 @@ func packageUsageTrafficAuditData(usage *model.PackageUsage) map[string]any {
}
}
func (s *Service) logPackageAdjustmentAudit(ctx context.Context, operationType, operationDesc, resultStatus, assetType string, assetID uint, assetIdentifier string, beforeData, afterData map[string]any, err error) {
if s == nil || s.assetAuditService == nil {
return
}
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(err)
wrappedBefore, wrappedAfter := assetAuditSvc.WrapOperationContent(beforeData, afterData, map[string]any{
"asset_type": assetAuditSvc.NormalizeAssetType(assetType),
"asset_id": assetID,
"asset_identifier": assetIdentifier,
})
s.assetAuditService.LogOperation(ctx, assetAuditSvc.BuildLog(ctx, assetAuditSvc.BuildLogParams{
Operator: assetAuditSvc.OperatorFromContext(ctx),
AssetType: assetType,
AssetID: assetID,
AssetIdentifier: assetIdentifier,
OperationType: operationType,
OperationDesc: operationDesc,
BeforeData: wrappedBefore,
AfterData: wrappedAfter,
ResultStatus: resultStatus,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
}))
}
// tracePreviousGenerations 通过换货链逆向追溯前代资产的订单最多追溯10代
func (s *Service) tracePreviousGenerations(ctx context.Context, assetType string, assetID uint) ([]*dto.PreviousGenerationOrders, bool) {
const maxDepth = 10