314 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			314 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package product
 | ||
| 
 | ||
| import (
 | ||
| 	"context"
 | ||
| 
 | ||
| 	"github.com/shopspring/decimal"
 | ||
| 	"go.uber.org/zap"
 | ||
| 
 | ||
| 	"tyapi-server/internal/application/product/dto/commands"
 | ||
| 	appQueries "tyapi-server/internal/application/product/dto/queries"
 | ||
| 	"tyapi-server/internal/application/product/dto/responses"
 | ||
| 	"tyapi-server/internal/domains/product/entities"
 | ||
| 	repoQueries "tyapi-server/internal/domains/product/repositories/queries"
 | ||
| 	product_service "tyapi-server/internal/domains/product/services"
 | ||
| 	user_repositories "tyapi-server/internal/domains/user/repositories"
 | ||
| )
 | ||
| 
 | ||
| // SubscriptionApplicationServiceImpl 订阅应用服务实现
 | ||
| // 负责业务流程编排、事务管理、数据转换,不直接操作仓库
 | ||
| type SubscriptionApplicationServiceImpl struct {
 | ||
| 	productSubscriptionService *product_service.ProductSubscriptionService
 | ||
| 	userRepo                   user_repositories.UserRepository
 | ||
| 	logger                     *zap.Logger
 | ||
| }
 | ||
| 
 | ||
| // NewSubscriptionApplicationService 创建订阅应用服务
 | ||
| func NewSubscriptionApplicationService(
 | ||
| 	productSubscriptionService *product_service.ProductSubscriptionService,
 | ||
| 	userRepo user_repositories.UserRepository,
 | ||
| 	logger *zap.Logger,
 | ||
| ) SubscriptionApplicationService {
 | ||
| 	return &SubscriptionApplicationServiceImpl{
 | ||
| 		productSubscriptionService: productSubscriptionService,
 | ||
| 		userRepo:                   userRepo,
 | ||
| 		logger:                     logger,
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| // UpdateSubscriptionPrice 更新订阅价格
 | ||
| // 业务流程:1. 获取订阅 2. 更新价格 3. 保存订阅
 | ||
| func (s *SubscriptionApplicationServiceImpl) UpdateSubscriptionPrice(ctx context.Context, cmd *commands.UpdateSubscriptionPriceCommand) error {
 | ||
| 	return s.productSubscriptionService.UpdateSubscriptionPrice(ctx, cmd.ID, cmd.Price)
 | ||
| }
 | ||
| 
 | ||
| // BatchUpdateSubscriptionPrices 一键改价
 | ||
| // 业务流程:1. 获取用户所有订阅 2. 根据范围筛选 3. 批量更新价格
 | ||
| func (s *SubscriptionApplicationServiceImpl) BatchUpdateSubscriptionPrices(ctx context.Context, cmd *commands.BatchUpdateSubscriptionPricesCommand) error {
 | ||
| 	subscriptions, _, err := s.productSubscriptionService.ListSubscriptions(ctx, &repoQueries.ListSubscriptionsQuery{
 | ||
| 		UserID:   cmd.UserID,
 | ||
| 		Page:     1,
 | ||
| 		PageSize: 1000,
 | ||
| 	})
 | ||
| 	if err != nil {
 | ||
| 		return err
 | ||
| 	}
 | ||
| 
 | ||
| 	// 根据范围筛选订阅
 | ||
| 	var targetSubscriptions []*entities.Subscription
 | ||
| 	for _, sub := range subscriptions {
 | ||
| 		if cmd.Scope == "all" {
 | ||
| 			// 所有订阅都修改
 | ||
| 			targetSubscriptions = append(targetSubscriptions, sub)
 | ||
| 		} else if cmd.Scope == "undiscounted" {
 | ||
| 			// 只修改未打折的订阅(价格等于产品原价)
 | ||
| 			if sub.Product != nil && sub.Price.Equal(sub.Product.Price) {
 | ||
| 				targetSubscriptions = append(targetSubscriptions, sub)
 | ||
| 			}
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	// 批量更新价格
 | ||
| 	for _, sub := range targetSubscriptions {
 | ||
| 		if sub.Product != nil {
 | ||
| 			// 计算折扣后的价格
 | ||
| 			discountRatio := cmd.Discount / 10
 | ||
| 			newPrice := sub.Product.Price.Mul(decimal.NewFromFloat(discountRatio))
 | ||
| 			// 四舍五入到2位小数
 | ||
| 			newPrice = newPrice.Round(2)
 | ||
| 
 | ||
| 			err := s.productSubscriptionService.UpdateSubscriptionPrice(ctx, sub.ID, newPrice.InexactFloat64())
 | ||
| 			if err != nil {
 | ||
| 				s.logger.Error("批量更新订阅价格失败",
 | ||
| 					zap.String("subscription_id", sub.ID),
 | ||
| 					zap.Error(err))
 | ||
| 				// 继续处理其他订阅,不中断整个流程
 | ||
| 			}
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // CreateSubscription 创建订阅
 | ||
| // 业务流程:1. 创建订阅
 | ||
| func (s *SubscriptionApplicationServiceImpl) CreateSubscription(ctx context.Context, cmd *commands.CreateSubscriptionCommand) error {
 | ||
| 	_, err := s.productSubscriptionService.CreateSubscription(ctx, cmd.UserID, cmd.ProductID)
 | ||
| 	return err
 | ||
| }
 | ||
| 
 | ||
| // GetSubscriptionByID 根据ID获取订阅
 | ||
| // 业务流程:1. 获取订阅信息 2. 构建响应数据
 | ||
| func (s *SubscriptionApplicationServiceImpl) GetSubscriptionByID(ctx context.Context, query *appQueries.GetSubscriptionQuery) (*responses.SubscriptionInfoResponse, error) {
 | ||
| 	subscription, err := s.productSubscriptionService.GetSubscriptionByID(ctx, query.ID)
 | ||
| 	if err != nil {
 | ||
| 		return nil, err
 | ||
| 	}
 | ||
| 
 | ||
| 	return s.convertToSubscriptionInfoResponse(subscription), nil
 | ||
| }
 | ||
| 
 | ||
| // ListSubscriptions 获取订阅列表(管理员用)
 | ||
| // 业务流程:1. 获取订阅列表 2. 构建响应数据
 | ||
| func (s *SubscriptionApplicationServiceImpl) ListSubscriptions(ctx context.Context, query *appQueries.ListSubscriptionsQuery) (*responses.SubscriptionListResponse, error) {
 | ||
| 	repoQuery := &repoQueries.ListSubscriptionsQuery{
 | ||
| 		Page:        query.Page,
 | ||
| 		PageSize:    query.PageSize,
 | ||
| 		UserID:      query.UserID, // 管理员可以按用户筛选
 | ||
| 		Keyword:     query.Keyword,
 | ||
| 		SortBy:      query.SortBy,
 | ||
| 		SortOrder:   query.SortOrder,
 | ||
| 		CompanyName: query.CompanyName,
 | ||
| 		ProductName: query.ProductName,
 | ||
| 		StartTime:   query.StartTime,
 | ||
| 		EndTime:     query.EndTime,
 | ||
| 	}
 | ||
| 	subscriptions, total, err := s.productSubscriptionService.ListSubscriptions(ctx, repoQuery)
 | ||
| 	if err != nil {
 | ||
| 		return nil, err
 | ||
| 	}
 | ||
| 	items := make([]responses.SubscriptionInfoResponse, len(subscriptions))
 | ||
| 	for i := range subscriptions {
 | ||
| 		resp := s.convertToSubscriptionInfoResponse(subscriptions[i])
 | ||
| 		if resp != nil {
 | ||
| 			items[i] = *resp // 解引用指针
 | ||
| 		}
 | ||
| 	}
 | ||
| 	return &responses.SubscriptionListResponse{
 | ||
| 		Total: total,
 | ||
| 		Page:  query.Page,
 | ||
| 		Size:  query.PageSize,
 | ||
| 		Items: items,
 | ||
| 	}, nil
 | ||
| }
 | ||
| 
 | ||
| // ListMySubscriptions 获取我的订阅列表(用户用)
 | ||
| // 业务流程:1. 获取用户订阅列表 2. 构建响应数据
 | ||
| func (s *SubscriptionApplicationServiceImpl) ListMySubscriptions(ctx context.Context, userID string, query *appQueries.ListSubscriptionsQuery) (*responses.SubscriptionListResponse, error) {
 | ||
| 	repoQuery := &repoQueries.ListSubscriptionsQuery{
 | ||
| 		Page:        query.Page,
 | ||
| 		PageSize:    query.PageSize,
 | ||
| 		UserID:      userID, // 强制设置为当前用户ID
 | ||
| 		Keyword:     query.Keyword,
 | ||
| 		SortBy:      query.SortBy,
 | ||
| 		SortOrder:   query.SortOrder,
 | ||
| 		CompanyName: query.CompanyName,
 | ||
| 		ProductName: query.ProductName,
 | ||
| 		StartTime:   query.StartTime,
 | ||
| 		EndTime:     query.EndTime,
 | ||
| 	}
 | ||
| 	subscriptions, total, err := s.productSubscriptionService.ListSubscriptions(ctx, repoQuery)
 | ||
| 	if err != nil {
 | ||
| 		return nil, err
 | ||
| 	}
 | ||
| 	items := make([]responses.SubscriptionInfoResponse, len(subscriptions))
 | ||
| 	for i := range subscriptions {
 | ||
| 		resp := s.convertToSubscriptionInfoResponse(subscriptions[i])
 | ||
| 		if resp != nil {
 | ||
| 			items[i] = *resp // 解引用指针
 | ||
| 		}
 | ||
| 	}
 | ||
| 	return &responses.SubscriptionListResponse{
 | ||
| 		Total: total,
 | ||
| 		Page:  query.Page,
 | ||
| 		Size:  query.PageSize,
 | ||
| 		Items: items,
 | ||
| 	}, nil
 | ||
| }
 | ||
| 
 | ||
| // GetUserSubscriptions 获取用户订阅
 | ||
| // 业务流程:1. 获取用户订阅 2. 构建响应数据
 | ||
| func (s *SubscriptionApplicationServiceImpl) GetUserSubscriptions(ctx context.Context, query *appQueries.GetUserSubscriptionsQuery) ([]*responses.SubscriptionInfoResponse, error) {
 | ||
| 	subscriptions, err := s.productSubscriptionService.GetUserSubscriptions(ctx, query.UserID)
 | ||
| 	if err != nil {
 | ||
| 		return nil, err
 | ||
| 	}
 | ||
| 
 | ||
| 	// 转换为响应对象
 | ||
| 	items := make([]*responses.SubscriptionInfoResponse, len(subscriptions))
 | ||
| 	for i := range subscriptions {
 | ||
| 		items[i] = s.convertToSubscriptionInfoResponse(subscriptions[i])
 | ||
| 	}
 | ||
| 
 | ||
| 	return items, nil
 | ||
| }
 | ||
| 
 | ||
| // GetProductSubscriptions 获取产品订阅
 | ||
| // 业务流程:1. 获取产品订阅 2. 构建响应数据
 | ||
| func (s *SubscriptionApplicationServiceImpl) GetProductSubscriptions(ctx context.Context, query *appQueries.GetProductSubscriptionsQuery) ([]*responses.SubscriptionInfoResponse, error) {
 | ||
| 	// 这里需要扩展领域服务来支持按产品查询订阅
 | ||
| 	// 暂时返回空列表
 | ||
| 	return []*responses.SubscriptionInfoResponse{}, nil
 | ||
| }
 | ||
| 
 | ||
| // GetSubscriptionUsage 获取订阅使用情况
 | ||
| // 业务流程:1. 获取订阅使用情况 2. 构建响应数据
 | ||
| func (s *SubscriptionApplicationServiceImpl) GetSubscriptionUsage(ctx context.Context, subscriptionID string) (*responses.SubscriptionUsageResponse, error) {
 | ||
| 	subscription, err := s.productSubscriptionService.GetSubscriptionByID(ctx, subscriptionID)
 | ||
| 	if err != nil {
 | ||
| 		return nil, err
 | ||
| 	}
 | ||
| 
 | ||
| 	return &responses.SubscriptionUsageResponse{
 | ||
| 		ID:        subscription.ID,
 | ||
| 		ProductID: subscription.ProductID,
 | ||
| 		APIUsed:   subscription.APIUsed,
 | ||
| 	}, nil
 | ||
| }
 | ||
| 
 | ||
| // GetSubscriptionStats 获取订阅统计信息
 | ||
| // 业务流程:1. 获取订阅统计 2. 构建响应数据
 | ||
| func (s *SubscriptionApplicationServiceImpl) GetSubscriptionStats(ctx context.Context) (*responses.SubscriptionStatsResponse, error) {
 | ||
| 	stats, err := s.productSubscriptionService.GetSubscriptionStats(ctx)
 | ||
| 	if err != nil {
 | ||
| 		return nil, err
 | ||
| 	}
 | ||
| 
 | ||
| 	return &responses.SubscriptionStatsResponse{
 | ||
| 		TotalSubscriptions: stats["total_subscriptions"].(int64),
 | ||
| 		TotalRevenue:       stats["total_revenue"].(float64),
 | ||
| 	}, nil
 | ||
| }
 | ||
| 
 | ||
| // GetMySubscriptionStats 获取我的订阅统计信息
 | ||
| // 业务流程:1. 获取用户订阅统计 2. 构建响应数据
 | ||
| func (s *SubscriptionApplicationServiceImpl) GetMySubscriptionStats(ctx context.Context, userID string) (*responses.SubscriptionStatsResponse, error) {
 | ||
| 	stats, err := s.productSubscriptionService.GetUserSubscriptionStats(ctx, userID)
 | ||
| 	if err != nil {
 | ||
| 		return nil, err
 | ||
| 	}
 | ||
| 
 | ||
| 	return &responses.SubscriptionStatsResponse{
 | ||
| 		TotalSubscriptions: stats["total_subscriptions"].(int64),
 | ||
| 		TotalRevenue:       stats["total_revenue"].(float64),
 | ||
| 	}, nil
 | ||
| }
 | ||
| 
 | ||
| // convertToSubscriptionInfoResponse 转换为订阅信息响应
 | ||
| func (s *SubscriptionApplicationServiceImpl) convertToSubscriptionInfoResponse(subscription *entities.Subscription) *responses.SubscriptionInfoResponse {
 | ||
| 	// 查询用户信息
 | ||
| 	var userInfo *responses.UserSimpleResponse
 | ||
| 	if subscription.UserID != "" {
 | ||
| 		user, err := s.userRepo.GetByIDWithEnterpriseInfo(context.Background(), subscription.UserID)
 | ||
| 		if err == nil {
 | ||
| 			companyName := "未知公司"
 | ||
| 			if user.EnterpriseInfo != nil {
 | ||
| 				companyName = user.EnterpriseInfo.CompanyName
 | ||
| 			}
 | ||
| 			userInfo = &responses.UserSimpleResponse{
 | ||
| 				ID:          user.ID,
 | ||
| 				CompanyName: companyName,
 | ||
| 				Phone:       user.Phone,
 | ||
| 			}
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	var productResponse *responses.ProductSimpleResponse
 | ||
| 	if subscription.Product != nil {
 | ||
| 		productResponse = s.convertToProductSimpleResponse(subscription.Product)
 | ||
| 	}
 | ||
| 
 | ||
| 	return &responses.SubscriptionInfoResponse{
 | ||
| 		ID:        subscription.ID,
 | ||
| 		UserID:    subscription.UserID,
 | ||
| 		ProductID: subscription.ProductID,
 | ||
| 		Price:     subscription.Price.InexactFloat64(),
 | ||
| 		User:      userInfo,
 | ||
| 		Product:   productResponse,
 | ||
| 		APIUsed:   subscription.APIUsed,
 | ||
| 		CreatedAt: subscription.CreatedAt,
 | ||
| 		UpdatedAt: subscription.UpdatedAt,
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| // convertToProductSimpleResponse 转换为产品简单信息响应
 | ||
| func (s *SubscriptionApplicationServiceImpl) convertToProductSimpleResponse(product *entities.Product) *responses.ProductSimpleResponse {
 | ||
| 	var categoryResponse *responses.CategorySimpleResponse
 | ||
| 	if product.Category != nil {
 | ||
| 		categoryResponse = s.convertToCategorySimpleResponse(product.Category)
 | ||
| 	}
 | ||
| 
 | ||
| 	return &responses.ProductSimpleResponse{
 | ||
| 		ID:          product.ID,
 | ||
| 		OldID:       product.OldID,
 | ||
| 		Name:        product.Name,
 | ||
| 		Code:        product.Code,
 | ||
| 		Description: product.Description,
 | ||
| 		Price:       product.Price.InexactFloat64(),
 | ||
| 		Category:    categoryResponse,
 | ||
| 		IsPackage:   product.IsPackage,
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| // convertToCategorySimpleResponse 转换为分类简单信息响应
 | ||
| func (s *SubscriptionApplicationServiceImpl) convertToCategorySimpleResponse(category *entities.ProductCategory) *responses.CategorySimpleResponse {
 | ||
| 	if category == nil {
 | ||
| 		return nil
 | ||
| 	}
 | ||
| 
 | ||
| 	return &responses.CategorySimpleResponse{
 | ||
| 		ID:   category.ID,
 | ||
| 		Name: category.Name,
 | ||
| 	}
 | ||
| }
 |