temp
This commit is contained in:
@@ -0,0 +1,354 @@
|
||||
package product
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
"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"
|
||||
"tyapi-server/internal/domains/product/repositories"
|
||||
repoQueries "tyapi-server/internal/domains/product/repositories/queries"
|
||||
"tyapi-server/internal/domains/product/services"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// SubscriptionApplicationServiceImpl 订阅应用服务实现
|
||||
type SubscriptionApplicationServiceImpl struct {
|
||||
subscriptionRepo repositories.SubscriptionRepository
|
||||
productRepo repositories.ProductRepository
|
||||
productService *services.ProductService
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewSubscriptionApplicationService 创建订阅应用服务
|
||||
func NewSubscriptionApplicationService(
|
||||
subscriptionRepo repositories.SubscriptionRepository,
|
||||
productRepo repositories.ProductRepository,
|
||||
productService *services.ProductService,
|
||||
logger *zap.Logger,
|
||||
) SubscriptionApplicationService {
|
||||
return &SubscriptionApplicationServiceImpl{
|
||||
subscriptionRepo: subscriptionRepo,
|
||||
productRepo: productRepo,
|
||||
productService: productService,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateSubscription 创建订阅
|
||||
func (s *SubscriptionApplicationServiceImpl) CreateSubscription(ctx context.Context, cmd *commands.CreateSubscriptionCommand) error {
|
||||
// 1. 参数验证
|
||||
if err := s.validateCreateSubscription(cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 2. 检查产品是否存在且可订阅
|
||||
canSubscribe, err := s.productService.CanUserSubscribeProduct(cmd.UserID, cmd.ProductID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !canSubscribe {
|
||||
return errors.New("产品不可订阅或用户已有活跃订阅")
|
||||
}
|
||||
|
||||
// 3. 检查产品是否存在
|
||||
_, err = s.productRepo.GetByID(ctx, cmd.ProductID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("产品不存在: %w", err)
|
||||
}
|
||||
|
||||
// 5. 创建订阅实体
|
||||
subscription := entities.Subscription{
|
||||
UserID: cmd.UserID,
|
||||
ProductID: cmd.ProductID,
|
||||
Status: entities.SubscriptionStatusActive,
|
||||
Price: cmd.Price,
|
||||
APIUsed: 0,
|
||||
}
|
||||
|
||||
// 6. 保存到仓储
|
||||
createdSubscription, err := s.subscriptionRepo.Create(ctx, subscription)
|
||||
if err != nil {
|
||||
s.logger.Error("创建订阅失败", zap.Error(err))
|
||||
return fmt.Errorf("创建订阅失败: %w", err)
|
||||
}
|
||||
|
||||
s.logger.Info("创建订阅成功", zap.String("id", createdSubscription.ID), zap.String("user_id", cmd.UserID), zap.String("product_id", cmd.ProductID))
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateSubscription 更新订阅
|
||||
func (s *SubscriptionApplicationServiceImpl) UpdateSubscription(ctx context.Context, cmd *commands.UpdateSubscriptionCommand) error {
|
||||
// 1. 获取现有订阅
|
||||
subscription, err := s.subscriptionRepo.GetByID(ctx, cmd.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("订阅不存在: %w", err)
|
||||
}
|
||||
|
||||
// 2. 更新字段
|
||||
if cmd.Price >= 0 {
|
||||
subscription.Price = cmd.Price
|
||||
}
|
||||
|
||||
// 3. 保存到仓储
|
||||
if err := s.subscriptionRepo.Update(ctx, subscription); err != nil {
|
||||
s.logger.Error("更新订阅失败", zap.Error(err))
|
||||
return fmt.Errorf("更新订阅失败: %w", err)
|
||||
}
|
||||
|
||||
s.logger.Info("更新订阅成功", zap.String("id", cmd.ID))
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSubscriptionByID 根据ID获取订阅
|
||||
func (s *SubscriptionApplicationServiceImpl) GetSubscriptionByID(ctx context.Context, query *appQueries.GetSubscriptionQuery) (*responses.SubscriptionInfoResponse, error) {
|
||||
subscription, err := s.subscriptionRepo.GetByID(ctx, query.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("订阅不存在: %w", err)
|
||||
}
|
||||
|
||||
// 转换为响应对象
|
||||
response := s.convertToSubscriptionInfoResponse(&subscription)
|
||||
|
||||
// 加载产品信息
|
||||
product, err := s.productRepo.GetByID(ctx, subscription.ProductID)
|
||||
if err == nil {
|
||||
response.Product = s.convertToProductSimpleResponse(&product)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// ListSubscriptions 获取订阅列表
|
||||
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,
|
||||
ProductID: query.ProductID,
|
||||
Status: query.Status,
|
||||
SortBy: query.SortBy,
|
||||
SortOrder: query.SortOrder,
|
||||
}
|
||||
|
||||
// 调用仓储
|
||||
subscriptions, total, err := s.subscriptionRepo.ListSubscriptions(ctx, repoQuery)
|
||||
if err != nil {
|
||||
s.logger.Error("获取订阅列表失败", zap.Error(err))
|
||||
return nil, fmt.Errorf("获取订阅列表失败: %w", err)
|
||||
}
|
||||
|
||||
// 转换为响应对象
|
||||
items := make([]responses.SubscriptionInfoResponse, len(subscriptions))
|
||||
for i, subscription := range subscriptions {
|
||||
items[i] = *s.convertToSubscriptionInfoResponse(subscription)
|
||||
}
|
||||
|
||||
return &responses.SubscriptionListResponse{
|
||||
Total: total,
|
||||
Page: query.Page,
|
||||
Size: query.PageSize,
|
||||
Items: items,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
// UpdateAPIUsage 更新API使用量
|
||||
func (s *SubscriptionApplicationServiceImpl) UpdateAPIUsage(ctx context.Context, cmd *commands.UpdateAPIUsageCommand) error {
|
||||
subscription, err := s.subscriptionRepo.GetByID(ctx, cmd.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("订阅不存在: %w", err)
|
||||
}
|
||||
|
||||
subscription.IncrementAPIUsage(cmd.APIUsed)
|
||||
|
||||
if err := s.subscriptionRepo.Update(ctx, subscription); err != nil {
|
||||
s.logger.Error("更新API使用量失败", zap.Error(err))
|
||||
return fmt.Errorf("更新API使用量失败: %w", err)
|
||||
}
|
||||
|
||||
s.logger.Info("更新API使用量成功", zap.String("id", cmd.ID), zap.Int64("api_used", cmd.APIUsed))
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResetAPIUsage 重置API使用量
|
||||
func (s *SubscriptionApplicationServiceImpl) ResetAPIUsage(ctx context.Context, cmd *commands.ResetAPIUsageCommand) error {
|
||||
subscription, err := s.subscriptionRepo.GetByID(ctx, cmd.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("订阅不存在: %w", err)
|
||||
}
|
||||
|
||||
subscription.ResetAPIUsage()
|
||||
|
||||
if err := s.subscriptionRepo.Update(ctx, subscription); err != nil {
|
||||
s.logger.Error("重置API使用量失败", zap.Error(err))
|
||||
return fmt.Errorf("重置API使用量失败: %w", err)
|
||||
}
|
||||
|
||||
s.logger.Info("重置API使用量成功", zap.String("id", cmd.ID))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
// GetUserSubscriptions 获取用户订阅
|
||||
func (s *SubscriptionApplicationServiceImpl) GetUserSubscriptions(ctx context.Context, query *appQueries.GetUserSubscriptionsQuery) ([]*responses.SubscriptionInfoResponse, error) {
|
||||
subscriptions, err := s.subscriptionRepo.FindByUserID(ctx, query.UserID)
|
||||
if err != nil {
|
||||
s.logger.Error("获取用户订阅失败", zap.Error(err))
|
||||
return nil, fmt.Errorf("获取用户订阅失败: %w", err)
|
||||
}
|
||||
|
||||
// 过滤状态
|
||||
if query.Status != nil {
|
||||
filtered := make([]*entities.Subscription, 0)
|
||||
for _, sub := range subscriptions {
|
||||
if sub.Status == *query.Status {
|
||||
filtered = append(filtered, sub)
|
||||
}
|
||||
}
|
||||
subscriptions = filtered
|
||||
}
|
||||
|
||||
// 转换为响应对象
|
||||
items := make([]*responses.SubscriptionInfoResponse, len(subscriptions))
|
||||
for i, subscription := range subscriptions {
|
||||
items[i] = s.convertToSubscriptionInfoResponse(subscription)
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
// GetProductSubscriptions 获取产品订阅
|
||||
func (s *SubscriptionApplicationServiceImpl) GetProductSubscriptions(ctx context.Context, query *appQueries.GetProductSubscriptionsQuery) ([]*responses.SubscriptionInfoResponse, error) {
|
||||
subscriptions, err := s.subscriptionRepo.FindByProductID(ctx, query.ProductID)
|
||||
if err != nil {
|
||||
s.logger.Error("获取产品订阅失败", zap.Error(err))
|
||||
return nil, fmt.Errorf("获取产品订阅失败: %w", err)
|
||||
}
|
||||
|
||||
// 过滤状态
|
||||
if query.Status != nil {
|
||||
filtered := make([]*entities.Subscription, 0)
|
||||
for _, sub := range subscriptions {
|
||||
if sub.Status == *query.Status {
|
||||
filtered = append(filtered, sub)
|
||||
}
|
||||
}
|
||||
subscriptions = filtered
|
||||
}
|
||||
|
||||
// 转换为响应对象
|
||||
items := make([]*responses.SubscriptionInfoResponse, len(subscriptions))
|
||||
for i, subscription := range subscriptions {
|
||||
items[i] = s.convertToSubscriptionInfoResponse(subscription)
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
// GetSubscriptionUsage 获取订阅使用情况
|
||||
func (s *SubscriptionApplicationServiceImpl) GetSubscriptionUsage(ctx context.Context, subscriptionID string) (*responses.SubscriptionUsageResponse, error) {
|
||||
subscription, err := s.subscriptionRepo.GetByID(ctx, subscriptionID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("订阅不存在: %w", err)
|
||||
}
|
||||
|
||||
return &responses.SubscriptionUsageResponse{
|
||||
ID: subscription.ID,
|
||||
ProductID: subscription.ProductID,
|
||||
APIUsed: subscription.APIUsed,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetSubscriptionStats 获取订阅统计
|
||||
func (s *SubscriptionApplicationServiceImpl) GetSubscriptionStats(ctx context.Context) (*responses.SubscriptionStatsResponse, error) {
|
||||
// 获取各种状态的订阅数量
|
||||
total, err := s.subscriptionRepo.CountActive(ctx)
|
||||
if err != nil {
|
||||
s.logger.Error("获取订阅统计失败", zap.Error(err))
|
||||
return nil, fmt.Errorf("获取订阅统计失败: %w", err)
|
||||
}
|
||||
|
||||
// TODO: 计算总收入,需要从订单系统获取
|
||||
totalRevenue := 0.0
|
||||
|
||||
return &responses.SubscriptionStatsResponse{
|
||||
TotalSubscriptions: total,
|
||||
TotalRevenue: totalRevenue,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 私有方法
|
||||
|
||||
func (s *SubscriptionApplicationServiceImpl) validateCreateSubscription(cmd *commands.CreateSubscriptionCommand) error {
|
||||
if cmd.UserID == "" {
|
||||
return errors.New("用户ID不能为空")
|
||||
}
|
||||
if cmd.ProductID == "" {
|
||||
return errors.New("产品ID不能为空")
|
||||
}
|
||||
if cmd.Price < 0 {
|
||||
return errors.New("订阅价格不能为负数")
|
||||
}
|
||||
if cmd.APILimit < 0 {
|
||||
return errors.New("API调用限制不能为负数")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SubscriptionApplicationServiceImpl) calculateEndDate(duration string) (*time.Time, error) {
|
||||
if duration == "" {
|
||||
return nil, nil // 永久订阅
|
||||
}
|
||||
|
||||
d, err := s.parseDuration(duration)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
endDate := time.Now().Add(d)
|
||||
return &endDate, nil
|
||||
}
|
||||
|
||||
func (s *SubscriptionApplicationServiceImpl) parseDuration(duration string) (time.Duration, error) {
|
||||
switch duration {
|
||||
case "7d":
|
||||
return 7 * 24 * time.Hour, nil
|
||||
case "30d":
|
||||
return 30 * 24 * time.Hour, nil
|
||||
case "90d":
|
||||
return 90 * 24 * time.Hour, nil
|
||||
case "365d":
|
||||
return 365 * 24 * time.Hour, nil
|
||||
default:
|
||||
return time.ParseDuration(duration)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SubscriptionApplicationServiceImpl) convertToSubscriptionInfoResponse(subscription *entities.Subscription) *responses.SubscriptionInfoResponse {
|
||||
return &responses.SubscriptionInfoResponse{
|
||||
ID: subscription.ID,
|
||||
UserID: subscription.UserID,
|
||||
ProductID: subscription.ProductID,
|
||||
Price: subscription.Price,
|
||||
APIUsed: subscription.APIUsed,
|
||||
CreatedAt: subscription.CreatedAt,
|
||||
UpdatedAt: subscription.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SubscriptionApplicationServiceImpl) convertToProductSimpleResponse(product *entities.Product) *responses.ProductSimpleResponse {
|
||||
return &responses.ProductSimpleResponse{
|
||||
ID: product.ID,
|
||||
Name: product.Name,
|
||||
Code: product.Code,
|
||||
Description: product.Description,
|
||||
Price: product.Price,
|
||||
IsPackage: product.IsPackage,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user