Files
junhong_cmp_fiber/internal/service/package/customer_view_service.go
huang 353621d923
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m33s
移除所有测试代码和测试要求
**变更说明**:
- 删除所有 *_test.go 文件(单元测试、集成测试、验收测试、流程测试)
- 删除整个 tests/ 目录
- 更新 CLAUDE.md:用"测试禁令"章节替换所有测试要求
- 删除测试生成 Skill (openspec-generate-acceptance-tests)
- 删除测试生成命令 (opsx:gen-tests)
- 更新 tasks.md:删除所有测试相关任务

**新规范**:
-  禁止编写任何形式的自动化测试
-  禁止创建 *_test.go 文件
-  禁止在任务中包含测试相关工作
-  仅当用户明确要求时才编写测试

**原因**:
业务系统的正确性通过人工验证和生产环境监控保证,测试代码维护成本高于价值。

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-11 17:13:42 +08:00

148 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 packagepkg
import (
"context"
"github.com/break/junhong_cmp_fiber/internal/model"
"github.com/break/junhong_cmp_fiber/internal/model/dto"
"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/redis/go-redis/v9"
"go.uber.org/zap"
"gorm.io/gorm"
)
type CustomerViewService struct {
db *gorm.DB
redis *redis.Client
packageUsageStore *postgres.PackageUsageStore
logger *zap.Logger
}
func NewCustomerViewService(
db *gorm.DB,
redis *redis.Client,
packageUsageStore *postgres.PackageUsageStore,
logger *zap.Logger,
) *CustomerViewService {
return &CustomerViewService{
db: db,
redis: redis,
packageUsageStore: packageUsageStore,
logger: logger,
}
}
// GetMyUsage 任务 12.2-12.5: 获取客户套餐使用情况
// 根据载体ID和类型查询生效中的套餐计算总流量使用情况
func (s *CustomerViewService) GetMyUsage(ctx context.Context, carrierType string, carrierID uint) (*dto.PackageUsageCustomerViewResponse, error) {
// 任务 12.3: 查询生效套餐status IN (1,2)
var packages []*model.PackageUsage
query := s.db.WithContext(ctx).
Where("status IN ?", []int{constants.PackageUsageStatusActive, constants.PackageUsageStatusDepleted})
if carrierType == "iot_card" {
query = query.Where("iot_card_id = ?", carrierID)
} else if carrierType == "device" {
query = query.Where("device_id = ?", carrierID)
} else {
return nil, errors.New(errors.CodeInvalidParam, "无效的载体类型")
}
// 按优先级排序:主套餐在前,加油包在后
if err := query.Order("CASE WHEN master_usage_id IS NULL THEN 0 ELSE 1 END, priority ASC").
Find(&packages).Error; err != nil {
return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询套餐使用记录失败")
}
if len(packages) == 0 {
return nil, errors.New(errors.CodeNotFound, "未找到套餐使用记录")
}
// 任务 12.4: 区分主套餐和加油包,计算总流量
var mainPackage *dto.PackageUsageItemResponse
var addonPackages []dto.PackageUsageItemResponse
var totalUsedMB int64
var totalLimitMB int64
for _, pkg := range packages {
// 查询套餐信息
var packageInfo model.Package
if err := s.db.First(&packageInfo, pkg.PackageID).Error; err != nil {
s.logger.Warn("查询套餐信息失败",
zap.Uint("package_id", pkg.PackageID),
zap.Error(err))
continue
}
// 格式化状态文本
statusText := getStatusText(pkg.Status)
// 格式化时间
activatedAtStr := ""
if pkg.ActivatedAt.Year() > 1 {
activatedAtStr = pkg.ActivatedAt.Format("2006-01-02 15:04:05")
}
expiresAtStr := ""
if pkg.ExpiresAt.Year() > 1 {
expiresAtStr = pkg.ExpiresAt.Format("2006-01-02 15:04:05")
}
item := dto.PackageUsageItemResponse{
PackageUsageID: pkg.ID,
PackageID: pkg.PackageID,
PackageName: packageInfo.PackageName,
UsedMB: pkg.DataUsageMB,
TotalMB: pkg.DataLimitMB,
Status: pkg.Status,
StatusText: statusText,
ActivatedAt: activatedAtStr,
ExpiresAt: expiresAtStr,
Priority: pkg.Priority,
}
// 累计总流量
totalUsedMB += pkg.DataUsageMB
totalLimitMB += pkg.DataLimitMB
// 区分主套餐和加油包
if pkg.MasterUsageID == nil {
mainPackage = &item
} else {
addonPackages = append(addonPackages, item)
}
}
// 任务 12.5: 组装响应 DTO
response := &dto.PackageUsageCustomerViewResponse{
MainPackage: mainPackage,
AddonPackages: addonPackages,
Total: dto.PackageUsageTotalInfo{
UsedMB: totalUsedMB,
TotalMB: totalLimitMB,
},
}
return response, nil
}
// getStatusText 获取状态文本
func getStatusText(status int) string {
switch status {
case constants.PackageUsageStatusPending:
return "待生效"
case constants.PackageUsageStatusActive:
return "生效中"
case constants.PackageUsageStatusDepleted:
return "已用完"
case constants.PackageUsageStatusExpired:
return "已过期"
case constants.PackageUsageStatusInvalidated:
return "已失效"
default:
return "未知"
}
}