Files
tyapi-server/internal/application/product/product_application_service_impl.go
2025-07-28 01:46:39 +08:00

426 lines
14 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 product
import (
"context"
"fmt"
"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"
product_service "tyapi-server/internal/domains/product/services"
"tyapi-server/internal/shared/interfaces"
)
// ProductApplicationServiceImpl 产品应用服务实现
// 负责业务流程编排、事务管理、数据转换,不直接操作仓库
type ProductApplicationServiceImpl struct {
productManagementService *product_service.ProductManagementService
productSubscriptionService *product_service.ProductSubscriptionService
productApiConfigAppService ProductApiConfigApplicationService
logger *zap.Logger
}
// NewProductApplicationService 创建产品应用服务
func NewProductApplicationService(
productManagementService *product_service.ProductManagementService,
productSubscriptionService *product_service.ProductSubscriptionService,
productApiConfigAppService ProductApiConfigApplicationService,
logger *zap.Logger,
) ProductApplicationService {
return &ProductApplicationServiceImpl{
productManagementService: productManagementService,
productSubscriptionService: productSubscriptionService,
productApiConfigAppService: productApiConfigAppService,
logger: logger,
}
}
// CreateProduct 创建产品
// 业务流程1. 构建产品实体 2. 创建产品
func (s *ProductApplicationServiceImpl) CreateProduct(ctx context.Context, cmd *commands.CreateProductCommand) error {
// 1. 构建产品实体
product := &entities.Product{
Name: cmd.Name,
Code: cmd.Code,
Description: cmd.Description,
Content: cmd.Content,
CategoryID: cmd.CategoryID,
Price: decimal.NewFromFloat(cmd.Price),
IsEnabled: cmd.IsEnabled,
IsVisible: cmd.IsVisible,
IsPackage: cmd.IsPackage,
SEOTitle: cmd.SEOTitle,
SEODescription: cmd.SEODescription,
SEOKeywords: cmd.SEOKeywords,
}
// 2. 创建产品
_, err := s.productManagementService.CreateProduct(ctx, product)
return err
}
// UpdateProduct 更新产品
// 业务流程1. 获取现有产品 2. 更新产品信息 3. 保存产品
func (s *ProductApplicationServiceImpl) UpdateProduct(ctx context.Context, cmd *commands.UpdateProductCommand) error {
// 1. 获取现有产品
existingProduct, err := s.productManagementService.GetProductByID(ctx, cmd.ID)
if err != nil {
return err
}
// 2. 更新产品信息
existingProduct.Name = cmd.Name
existingProduct.Code = cmd.Code
existingProduct.Description = cmd.Description
existingProduct.Content = cmd.Content
existingProduct.CategoryID = cmd.CategoryID
existingProduct.Price = decimal.NewFromFloat(cmd.Price)
existingProduct.IsEnabled = cmd.IsEnabled
existingProduct.IsVisible = cmd.IsVisible
existingProduct.IsPackage = cmd.IsPackage
existingProduct.SEOTitle = cmd.SEOTitle
existingProduct.SEODescription = cmd.SEODescription
existingProduct.SEOKeywords = cmd.SEOKeywords
// 3. 保存产品
return s.productManagementService.UpdateProduct(ctx, existingProduct)
}
// DeleteProduct 删除产品
// 业务流程1. 删除产品
func (s *ProductApplicationServiceImpl) DeleteProduct(ctx context.Context, cmd *commands.DeleteProductCommand) error {
return s.productManagementService.DeleteProduct(ctx, cmd.ID)
}
// ListProducts 获取产品列表
// 业务流程1. 获取产品列表 2. 构建响应数据
func (s *ProductApplicationServiceImpl) ListProducts(ctx context.Context, filters map[string]interface{}, options interfaces.ListOptions) (*responses.ProductListResponse, error) {
// 调用领域服务获取产品列表
products, total, err := s.productManagementService.ListProducts(ctx, filters, options)
if err != nil {
return nil, err
}
// 转换为响应对象
items := make([]responses.ProductInfoResponse, len(products))
for i := range products {
items[i] = *s.convertToProductInfoResponse(products[i])
}
return &responses.ProductListResponse{
Total: total,
Page: options.Page,
Size: options.PageSize,
Items: items,
}, nil
}
// GetProductsByIDs 根据ID列表获取产品
// 业务流程1. 获取产品列表 2. 构建响应数据
func (s *ProductApplicationServiceImpl) GetProductsByIDs(ctx context.Context, query *appQueries.GetProductsByIDsQuery) ([]*responses.ProductInfoResponse, error) {
// 这里需要扩展领域服务来支持批量获取
// 暂时返回空列表
return []*responses.ProductInfoResponse{}, nil
}
// GetSubscribableProducts 获取可订阅产品列表
// 业务流程1. 获取启用产品 2. 过滤可订阅产品 3. 构建响应数据
func (s *ProductApplicationServiceImpl) GetSubscribableProducts(ctx context.Context, query *appQueries.GetSubscribableProductsQuery) ([]*responses.ProductInfoResponse, error) {
products, err := s.productManagementService.GetEnabledProducts(ctx)
if err != nil {
return nil, err
}
// 过滤可订阅的产品
var subscribableProducts []*entities.Product
for _, product := range products {
if product.CanBeSubscribed() {
subscribableProducts = append(subscribableProducts, product)
}
}
// 转换为响应对象
items := make([]*responses.ProductInfoResponse, len(subscribableProducts))
for i := range subscribableProducts {
items[i] = s.convertToProductInfoResponse(subscribableProducts[i])
}
return items, nil
}
// GetProductByID 根据ID获取产品
// 业务流程1. 获取产品信息 2. 构建响应数据
func (s *ProductApplicationServiceImpl) GetProductByID(ctx context.Context, query *appQueries.GetProductQuery) (*responses.ProductInfoResponse, error) {
product, err := s.productManagementService.GetProductWithCategory(ctx, query.ID)
if err != nil {
return nil, err
}
return s.convertToProductInfoResponse(product), nil
}
// GetProductStats 获取产品统计信息
// 业务流程1. 获取产品统计 2. 构建响应数据
func (s *ProductApplicationServiceImpl) GetProductStats(ctx context.Context) (*responses.ProductStatsResponse, error) {
stats, err := s.productSubscriptionService.GetProductStats(ctx)
if err != nil {
return nil, err
}
return &responses.ProductStatsResponse{
TotalProducts: stats["total"],
EnabledProducts: stats["enabled"],
VisibleProducts: stats["visible"],
PackageProducts: 0, // 需要单独统计
}, nil
}
// AddPackageItem 添加组合包子产品
func (s *ProductApplicationServiceImpl) AddPackageItem(ctx context.Context, packageID string, cmd *commands.AddPackageItemCommand) error {
// 验证组合包是否存在
packageProduct, err := s.productManagementService.GetProductByID(ctx, packageID)
if err != nil {
return err
}
if !packageProduct.IsPackage {
return fmt.Errorf("产品不是组合包")
}
// 验证子产品是否存在且不是组合包
subProduct, err := s.productManagementService.GetProductByID(ctx, cmd.ProductID)
if err != nil {
return err
}
if subProduct.IsPackage {
return fmt.Errorf("不能将组合包作为子产品")
}
// 检查是否已经存在
existingItems, err := s.productManagementService.GetPackageItems(ctx, packageID)
if err == nil {
for _, item := range existingItems {
if item.ProductID == cmd.ProductID {
return fmt.Errorf("该产品已在组合包中")
}
}
}
// 获取当前最大排序号
maxSortOrder := 0
if existingItems != nil {
for _, item := range existingItems {
if item.SortOrder > maxSortOrder {
maxSortOrder = item.SortOrder
}
}
}
// 创建组合包项目
packageItem := &entities.ProductPackageItem{
PackageID: packageID,
ProductID: cmd.ProductID,
SortOrder: maxSortOrder + 1,
}
return s.productManagementService.CreatePackageItem(ctx, packageItem)
}
// UpdatePackageItem 更新组合包子产品
func (s *ProductApplicationServiceImpl) UpdatePackageItem(ctx context.Context, packageID, itemID string, cmd *commands.UpdatePackageItemCommand) error {
// 验证组合包项目是否存在
packageItem, err := s.productManagementService.GetPackageItemByID(ctx, itemID)
if err != nil {
return err
}
if packageItem.PackageID != packageID {
return fmt.Errorf("组合包项目不属于指定组合包")
}
// 更新项目
packageItem.SortOrder = cmd.SortOrder
return s.productManagementService.UpdatePackageItem(ctx, packageItem)
}
// RemovePackageItem 移除组合包子产品
func (s *ProductApplicationServiceImpl) RemovePackageItem(ctx context.Context, packageID, itemID string) error {
// 验证组合包项目是否存在
packageItem, err := s.productManagementService.GetPackageItemByID(ctx, itemID)
if err != nil {
return err
}
if packageItem.PackageID != packageID {
return fmt.Errorf("组合包项目不属于指定组合包")
}
return s.productManagementService.DeletePackageItem(ctx, itemID)
}
// ReorderPackageItems 重新排序组合包子产品
func (s *ProductApplicationServiceImpl) ReorderPackageItems(ctx context.Context, packageID string, cmd *commands.ReorderPackageItemsCommand) error {
// 验证所有项目是否属于该组合包
for i, itemID := range cmd.ItemIDs {
packageItem, err := s.productManagementService.GetPackageItemByID(ctx, itemID)
if err != nil {
return err
}
if packageItem.PackageID != packageID {
return fmt.Errorf("组合包项目不属于指定组合包")
}
// 更新排序
packageItem.SortOrder = i + 1
if err := s.productManagementService.UpdatePackageItem(ctx, packageItem); err != nil {
return err
}
}
return nil
}
// UpdatePackageItems 批量更新组合包子产品
func (s *ProductApplicationServiceImpl) UpdatePackageItems(ctx context.Context, packageID string, cmd *commands.UpdatePackageItemsCommand) error {
// 验证组合包是否存在
packageProduct, err := s.productManagementService.GetProductByID(ctx, packageID)
if err != nil {
return err
}
if !packageProduct.IsPackage {
return fmt.Errorf("产品不是组合包")
}
// 验证所有子产品是否存在且不是组合包
for _, item := range cmd.Items {
subProduct, err := s.productManagementService.GetProductByID(ctx, item.ProductID)
if err != nil {
return err
}
if subProduct.IsPackage {
return fmt.Errorf("不能将组合包作为子产品")
}
}
// 使用事务进行批量更新
return s.productManagementService.UpdatePackageItemsBatch(ctx, packageID, cmd.Items)
}
// GetAvailableProducts 获取可选子产品列表
func (s *ProductApplicationServiceImpl) GetAvailableProducts(ctx context.Context, query *appQueries.GetAvailableProductsQuery) (*responses.ProductListResponse, error) {
// 构建筛选条件
filters := make(map[string]interface{})
filters["is_package"] = false // 只获取非组合包产品
filters["is_enabled"] = true // 只获取启用产品
if query.Keyword != "" {
filters["keyword"] = query.Keyword
}
if query.CategoryID != "" {
filters["category_id"] = query.CategoryID
}
// 设置分页选项
options := interfaces.ListOptions{
Page: query.Page,
PageSize: query.PageSize,
Sort: "created_at",
Order: "desc",
}
// 获取产品列表
products, total, err := s.productManagementService.ListProducts(ctx, filters, options)
if err != nil {
return nil, err
}
// 转换为响应对象
items := make([]responses.ProductInfoResponse, len(products))
for i := range products {
items[i] = *s.convertToProductInfoResponse(products[i])
}
return &responses.ProductListResponse{
Total: total,
Page: options.Page,
Size: options.PageSize,
Items: items,
}, nil
}
// convertToProductInfoResponse 转换为产品信息响应
func (s *ProductApplicationServiceImpl) convertToProductInfoResponse(product *entities.Product) *responses.ProductInfoResponse {
response := &responses.ProductInfoResponse{
ID: product.ID,
Name: product.Name,
Code: product.Code,
Description: product.Description,
Content: product.Content,
CategoryID: product.CategoryID,
Price: product.Price.InexactFloat64(),
IsEnabled: product.IsEnabled,
IsVisible: product.IsVisible,
IsPackage: product.IsPackage,
SEOTitle: product.SEOTitle,
SEODescription: product.SEODescription,
SEOKeywords: product.SEOKeywords,
CreatedAt: product.CreatedAt,
UpdatedAt: product.UpdatedAt,
}
// 添加分类信息
if product.Category != nil {
response.Category = s.convertToCategoryInfoResponse(product.Category)
}
// 转换组合包项目信息
if product.IsPackage && len(product.PackageItems) > 0 {
response.PackageItems = make([]*responses.PackageItemResponse, len(product.PackageItems))
for i, item := range product.PackageItems {
response.PackageItems[i] = &responses.PackageItemResponse{
ID: item.ID,
ProductID: item.ProductID,
ProductCode: item.Product.Code,
ProductName: item.Product.Name,
SortOrder: item.SortOrder,
Price: item.Product.Price.InexactFloat64(),
}
}
}
return response
}
// convertToCategoryInfoResponse 转换为分类信息响应
func (s *ProductApplicationServiceImpl) convertToCategoryInfoResponse(category *entities.ProductCategory) *responses.CategoryInfoResponse {
return &responses.CategoryInfoResponse{
ID: category.ID,
Name: category.Name,
Description: category.Description,
IsEnabled: category.IsEnabled,
CreatedAt: category.CreatedAt,
UpdatedAt: category.UpdatedAt,
}
}
// GetProductApiConfig 获取产品API配置
func (s *ProductApplicationServiceImpl) GetProductApiConfig(ctx context.Context, productID string) (*responses.ProductApiConfigResponse, error) {
return s.productApiConfigAppService.GetProductApiConfig(ctx, productID)
}
// CreateProductApiConfig 创建产品API配置
func (s *ProductApplicationServiceImpl) CreateProductApiConfig(ctx context.Context, productID string, config *responses.ProductApiConfigResponse) error {
return s.productApiConfigAppService.CreateProductApiConfig(ctx, productID, config)
}
// UpdateProductApiConfig 更新产品API配置
func (s *ProductApplicationServiceImpl) UpdateProductApiConfig(ctx context.Context, configID string, config *responses.ProductApiConfigResponse) error {
return s.productApiConfigAppService.UpdateProductApiConfig(ctx, configID, config)
}
// DeleteProductApiConfig 删除产品API配置
func (s *ProductApplicationServiceImpl) DeleteProductApiConfig(ctx context.Context, configID string) error {
return s.productApiConfigAppService.DeleteProductApiConfig(ctx, configID)
}