869 lines
23 KiB
Go
869 lines
23 KiB
Go
package service
|
||
|
||
import (
|
||
"dianshang/internal/model"
|
||
"dianshang/internal/repository"
|
||
"dianshang/pkg/utils"
|
||
"errors"
|
||
"fmt"
|
||
"strconv"
|
||
"time"
|
||
)
|
||
|
||
// ProductService 产品服务
|
||
type ProductService struct {
|
||
productRepo *repository.ProductRepository
|
||
userRepo *repository.UserRepository
|
||
}
|
||
|
||
// NewProductService 创建产品服务
|
||
func NewProductService(productRepo *repository.ProductRepository, userRepo *repository.UserRepository) *ProductService {
|
||
return &ProductService{
|
||
productRepo: productRepo,
|
||
userRepo: userRepo,
|
||
}
|
||
}
|
||
|
||
// GetProductList 获取产品列表(前端用户)
|
||
func (s *ProductService) GetProductList(page, pageSize int, categoryID uint, keyword string, minPrice, maxPrice float64, sort, sortType string) ([]model.Product, *utils.Pagination, error) {
|
||
if page <= 0 {
|
||
page = 1
|
||
}
|
||
if pageSize <= 0 || pageSize > 100 {
|
||
pageSize = 20
|
||
}
|
||
|
||
offset := (page - 1) * pageSize
|
||
conditions := make(map[string]interface{})
|
||
|
||
if categoryID > 0 {
|
||
conditions["category_id"] = categoryID
|
||
}
|
||
if keyword != "" {
|
||
conditions["keyword"] = keyword
|
||
}
|
||
if minPrice > 0 {
|
||
conditions["min_price"] = minPrice
|
||
}
|
||
if maxPrice > 0 {
|
||
conditions["max_price"] = maxPrice
|
||
}
|
||
if sort != "" {
|
||
conditions["sort"] = sort
|
||
}
|
||
if sortType != "" {
|
||
conditions["sort_type"] = sortType
|
||
}
|
||
|
||
products, total, err := s.productRepo.GetList(offset, pageSize, conditions)
|
||
if err != nil {
|
||
return nil, nil, err
|
||
}
|
||
|
||
pagination := utils.NewPagination(page, pageSize)
|
||
pagination.Total = total
|
||
return products, pagination, nil
|
||
}
|
||
|
||
// GetProductListForAdmin 获取产品列表(管理系统)
|
||
func (s *ProductService) GetProductListForAdmin(page, pageSize int, categoryID uint, keyword string, minPrice, maxPrice float64, sort, sortType, status, isHot, isNew, isRecommend string) ([]model.Product, *utils.Pagination, error) {
|
||
if page <= 0 {
|
||
page = 1
|
||
}
|
||
if pageSize <= 0 || pageSize > 100 {
|
||
pageSize = 20
|
||
}
|
||
|
||
offset := (page - 1) * pageSize
|
||
conditions := make(map[string]interface{})
|
||
|
||
if categoryID > 0 {
|
||
conditions["category_id"] = categoryID
|
||
}
|
||
if keyword != "" {
|
||
conditions["keyword"] = keyword
|
||
}
|
||
if minPrice > 0 {
|
||
conditions["min_price"] = minPrice
|
||
}
|
||
if maxPrice > 0 {
|
||
conditions["max_price"] = maxPrice
|
||
}
|
||
if sort != "" {
|
||
conditions["sort"] = sort
|
||
}
|
||
if sortType != "" {
|
||
conditions["sort_type"] = sortType
|
||
}
|
||
// 添加状态条件,支持获取所有状态的商品
|
||
if status != "" {
|
||
conditions["status"] = status
|
||
}
|
||
// 添加热门、新品、推荐筛选条件
|
||
if isHot != "" {
|
||
conditions["is_hot"] = isHot
|
||
}
|
||
if isNew != "" {
|
||
conditions["is_new"] = isNew
|
||
}
|
||
if isRecommend != "" {
|
||
conditions["is_recommend"] = isRecommend
|
||
}
|
||
|
||
products, total, err := s.productRepo.GetList(offset, pageSize, conditions)
|
||
if err != nil {
|
||
return nil, nil, err
|
||
}
|
||
|
||
pagination := utils.NewPagination(page, pageSize)
|
||
pagination.Total = total
|
||
return products, pagination, nil
|
||
}
|
||
|
||
// GetProductDetail 获取产品详情
|
||
func (s *ProductService) GetProductDetail(id uint) (*model.Product, error) {
|
||
return s.productRepo.GetByID(id)
|
||
}
|
||
|
||
// CreateProduct 创建产品
|
||
func (s *ProductService) CreateProduct(product *model.Product) error {
|
||
// 验证分类是否存在
|
||
if product.CategoryID > 0 {
|
||
_, err := s.productRepo.GetCategoryByID(product.CategoryID)
|
||
if err != nil {
|
||
return errors.New("分类不存在")
|
||
}
|
||
}
|
||
|
||
return s.productRepo.Create(product)
|
||
}
|
||
|
||
// UpdateProduct 更新产品
|
||
func (s *ProductService) UpdateProduct(id uint, updates map[string]interface{}) error {
|
||
// 检查产品是否存在
|
||
_, err := s.productRepo.GetByID(id)
|
||
if err != nil {
|
||
return errors.New("产品不存在")
|
||
}
|
||
|
||
// 如果更新分类,验证分类是否存在
|
||
if categoryID, ok := updates["category_id"]; ok {
|
||
var catID uint
|
||
switch v := categoryID.(type) {
|
||
case uint:
|
||
catID = v
|
||
case float64:
|
||
catID = uint(v)
|
||
case int:
|
||
catID = uint(v)
|
||
default:
|
||
return errors.New("分类ID格式错误")
|
||
}
|
||
|
||
if catID > 0 {
|
||
_, err := s.productRepo.GetCategoryByID(catID)
|
||
if err != nil {
|
||
return errors.New("分类不存在")
|
||
}
|
||
}
|
||
}
|
||
|
||
// 处理 detail_images 字段 - 确保正确转换为 JSONSlice 类型
|
||
if detailImages, ok := updates["detail_images"]; ok {
|
||
switch v := detailImages.(type) {
|
||
case []interface{}:
|
||
// 将 []interface{} 转换为 []string
|
||
var stringSlice []string
|
||
for _, item := range v {
|
||
if str, ok := item.(string); ok {
|
||
stringSlice = append(stringSlice, str)
|
||
}
|
||
}
|
||
updates["detail_images"] = model.JSONSlice(stringSlice)
|
||
case []string:
|
||
updates["detail_images"] = model.JSONSlice(v)
|
||
}
|
||
}
|
||
|
||
// 处理 images 字段 - 确保正确转换为 JSONSlice 类型
|
||
if images, ok := updates["images"]; ok {
|
||
switch v := images.(type) {
|
||
case []interface{}:
|
||
// 将 []interface{} 转换为 []string
|
||
var stringSlice []string
|
||
for _, item := range v {
|
||
if str, ok := item.(string); ok {
|
||
stringSlice = append(stringSlice, str)
|
||
}
|
||
}
|
||
updates["images"] = model.JSONSlice(stringSlice)
|
||
case []string:
|
||
updates["images"] = model.JSONSlice(v)
|
||
}
|
||
}
|
||
|
||
// 处理SKU数据
|
||
var skusData []interface{}
|
||
if skus, ok := updates["skus"]; ok {
|
||
skusData, _ = skus.([]interface{})
|
||
// 从updates中移除skus,避免直接更新到Product表
|
||
delete(updates, "skus")
|
||
}
|
||
|
||
// 更新商品基本信息
|
||
if err := s.productRepo.Update(id, updates); err != nil {
|
||
return err
|
||
}
|
||
|
||
// 处理SKU数据
|
||
if len(skusData) > 0 {
|
||
if err := s.handleProductSKUs(id, skusData); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// handleProductSKUs 处理商品SKU数据
|
||
func (s *ProductService) handleProductSKUs(productID uint, skusData []interface{}) error {
|
||
// 获取当前商品的所有现有SKU
|
||
existingSKUs, err := s.productRepo.GetProductSKUs(productID)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// 收集前端发送的SKU ID列表
|
||
var submittedSKUIDs []uint
|
||
|
||
// 处理前端发送的SKU数据
|
||
for _, skuData := range skusData {
|
||
skuMap, ok := skuData.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
|
||
// 创建SKU对象
|
||
sku := &model.ProductSKU{
|
||
ProductID: productID,
|
||
}
|
||
|
||
// 处理SKU字段
|
||
if skuCode, ok := skuMap["sku_code"].(string); ok {
|
||
sku.SKUCode = skuCode
|
||
}
|
||
|
||
if price, ok := skuMap["price"].(float64); ok {
|
||
sku.Price = price
|
||
}
|
||
|
||
if stock, ok := skuMap["stock"]; ok {
|
||
switch v := stock.(type) {
|
||
case float64:
|
||
sku.Stock = int(v)
|
||
case int:
|
||
sku.Stock = v
|
||
case string:
|
||
if stockInt, err := strconv.Atoi(v); err == nil {
|
||
sku.Stock = stockInt
|
||
}
|
||
}
|
||
}
|
||
|
||
// 处理spec_values
|
||
if specValues, ok := skuMap["spec_values"]; ok {
|
||
if specMap, ok := specValues.(map[string]interface{}); ok {
|
||
sku.SpecValues = model.JSONMap(specMap)
|
||
}
|
||
}
|
||
|
||
// 处理image字段
|
||
if image, ok := skuMap["image"].(string); ok {
|
||
sku.Image = image
|
||
}
|
||
|
||
// 检查是否是更新还是创建
|
||
var isUpdate bool
|
||
var skuIDValue uint
|
||
|
||
if skuID, ok := skuMap["id"]; ok && skuID != nil {
|
||
switch v := skuID.(type) {
|
||
case float64:
|
||
if v > 0 {
|
||
isUpdate = true
|
||
skuIDValue = uint(v)
|
||
submittedSKUIDs = append(submittedSKUIDs, skuIDValue)
|
||
}
|
||
case int:
|
||
if v > 0 {
|
||
isUpdate = true
|
||
skuIDValue = uint(v)
|
||
submittedSKUIDs = append(submittedSKUIDs, skuIDValue)
|
||
}
|
||
}
|
||
}
|
||
|
||
if isUpdate {
|
||
// 更新现有SKU
|
||
updates := make(map[string]interface{})
|
||
if sku.SKUCode != "" {
|
||
updates["sku_code"] = sku.SKUCode
|
||
}
|
||
updates["price"] = sku.Price
|
||
updates["stock"] = sku.Stock
|
||
// 直接传递JSONMap类型,让GORM处理序列化
|
||
updates["spec_values"] = sku.SpecValues
|
||
// 添加image字段的更新
|
||
if sku.Image != "" {
|
||
updates["image"] = sku.Image
|
||
}
|
||
|
||
if err := s.productRepo.UpdateSKU(skuIDValue, updates); err != nil {
|
||
return err
|
||
}
|
||
} else {
|
||
// 创建新SKU - 确保不设置ID字段
|
||
sku.ID = 0 // 明确设置为0,让数据库自动生成
|
||
if sku.SKUCode == "" {
|
||
// 生成默认SKU代码
|
||
sku.SKUCode = fmt.Sprintf("SKU-%d-%d", productID, time.Now().Unix())
|
||
}
|
||
if err := s.productRepo.CreateSKU(sku); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
}
|
||
|
||
// 删除不在前端提交列表中的现有SKU
|
||
for _, existingSKU := range existingSKUs {
|
||
shouldDelete := true
|
||
for _, submittedID := range submittedSKUIDs {
|
||
if existingSKU.ID == submittedID {
|
||
shouldDelete = false
|
||
break
|
||
}
|
||
}
|
||
|
||
if shouldDelete {
|
||
if err := s.productRepo.DeleteSKU(existingSKU.ID); err != nil {
|
||
return fmt.Errorf("删除SKU失败 - SKU ID: %d, 错误: %v", existingSKU.ID, err)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 处理完所有SKU后,同步商品库存
|
||
if err := s.productRepo.SyncProductStockFromSKUs(productID); err != nil {
|
||
// 记录错误但不阻止操作
|
||
fmt.Printf("同步商品库存失败 - 商品ID: %d, 错误: %v\n", productID, err)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// DeleteProduct 删除产品
|
||
func (s *ProductService) DeleteProduct(id uint) error {
|
||
// 检查产品是否存在
|
||
_, err := s.productRepo.GetByID(id)
|
||
if err != nil {
|
||
return errors.New("产品不存在")
|
||
}
|
||
|
||
return s.productRepo.Delete(id)
|
||
}
|
||
|
||
// GetCategories 获取分类列表
|
||
func (s *ProductService) GetCategories() ([]model.Category, error) {
|
||
return s.productRepo.GetCategories()
|
||
}
|
||
|
||
// CreateCategory 创建分类
|
||
func (s *ProductService) CreateCategory(category *model.Category) error {
|
||
return s.productRepo.CreateCategory(category)
|
||
}
|
||
|
||
// UpdateCategory 更新分类
|
||
func (s *ProductService) UpdateCategory(id uint, updates map[string]interface{}) error {
|
||
// 检查分类是否存在
|
||
_, err := s.productRepo.GetCategoryByID(id)
|
||
if err != nil {
|
||
return errors.New("分类不存在")
|
||
}
|
||
|
||
return s.productRepo.UpdateCategory(id, updates)
|
||
}
|
||
|
||
// DeleteCategory 删除分类
|
||
func (s *ProductService) DeleteCategory(id uint) error {
|
||
// 检查分类是否存在
|
||
_, err := s.productRepo.GetCategoryByID(id)
|
||
if err != nil {
|
||
return errors.New("分类不存在")
|
||
}
|
||
|
||
// 检查分类下是否有商品
|
||
productCount, err := s.productRepo.CountProductsByCategory(id)
|
||
if err != nil {
|
||
return errors.New("检查分类商品数量失败")
|
||
}
|
||
|
||
if productCount > 0 {
|
||
return errors.New("该分类下还有商品,无法删除")
|
||
}
|
||
|
||
// 检查是否有子分类
|
||
var childCategories []model.Category
|
||
err = s.productRepo.GetDB().Where("parent_id = ?", id).Find(&childCategories).Error
|
||
if err != nil {
|
||
return errors.New("检查子分类失败")
|
||
}
|
||
|
||
if len(childCategories) > 0 {
|
||
return errors.New("该分类下还有子分类,请先删除子分类")
|
||
}
|
||
|
||
return s.productRepo.DeleteCategory(id)
|
||
}
|
||
|
||
// GetProductReviews 获取产品评价列表
|
||
func (s *ProductService) GetProductReviews(productID uint, page, pageSize int) ([]model.ProductReview, *utils.Pagination, error) {
|
||
if page <= 0 {
|
||
page = 1
|
||
}
|
||
if pageSize <= 0 || pageSize > 100 {
|
||
pageSize = 20
|
||
}
|
||
|
||
offset := (page - 1) * pageSize
|
||
reviews, total, err := s.productRepo.GetReviews(productID, offset, pageSize)
|
||
if err != nil {
|
||
return nil, nil, err
|
||
}
|
||
|
||
pagination := utils.NewPagination(page, pageSize)
|
||
pagination.Total = total
|
||
return reviews, pagination, nil
|
||
}
|
||
|
||
// CreateReview 创建评价
|
||
func (s *ProductService) CreateReview(userID uint, review *model.ProductReview) error {
|
||
// 检查用户是否存在
|
||
_, err := s.userRepo.GetByID(userID)
|
||
if err != nil {
|
||
return errors.New("用户不存在")
|
||
}
|
||
|
||
// 检查产品是否存在
|
||
_, err = s.productRepo.GetByID(review.ProductID)
|
||
if err != nil {
|
||
return errors.New("产品不存在")
|
||
}
|
||
|
||
// 检查是否已经评价过
|
||
if review.OrderID != nil {
|
||
existingReview, _ := s.productRepo.GetReviewByOrderID(userID, *review.OrderID)
|
||
if existingReview != nil {
|
||
return errors.New("已经评价过该商品")
|
||
}
|
||
}
|
||
|
||
review.UserID = userID
|
||
return s.productRepo.CreateReview(review)
|
||
}
|
||
|
||
// GetHotProducts 获取热门产品
|
||
func (s *ProductService) GetHotProducts(limit int) ([]model.Product, error) {
|
||
if limit <= 0 || limit > 50 {
|
||
limit = 10
|
||
}
|
||
return s.productRepo.GetHotProducts(limit)
|
||
}
|
||
|
||
// GetRecommendProducts 获取推荐产品
|
||
func (s *ProductService) GetRecommendProducts(limit int) ([]model.Product, error) {
|
||
if limit <= 0 || limit > 50 {
|
||
limit = 10
|
||
}
|
||
return s.productRepo.GetRecommendProducts(limit)
|
||
}
|
||
|
||
// SearchProducts 搜索产品(支持价格与排序)
|
||
func (s *ProductService) SearchProducts(keyword string, page, pageSize int, minPrice, maxPrice float64, sort, sortType string) ([]model.Product, *utils.Pagination, error) {
|
||
if keyword == "" {
|
||
return []model.Product{}, utils.NewPagination(page, pageSize), nil
|
||
}
|
||
|
||
return s.GetProductList(page, pageSize, 0, keyword, minPrice, maxPrice, sort, sortType)
|
||
}
|
||
|
||
// UpdateStock 更新库存
|
||
func (s *ProductService) UpdateStock(id uint, quantity int) error {
|
||
// 检查产品是否存在
|
||
product, err := s.productRepo.GetByID(id)
|
||
if err != nil {
|
||
return errors.New("产品不存在")
|
||
}
|
||
|
||
// 检查库存是否足够(减库存时)
|
||
if quantity < 0 && product.Stock < -quantity {
|
||
return errors.New("库存不足")
|
||
}
|
||
|
||
return s.productRepo.UpdateStock(id, quantity)
|
||
}
|
||
|
||
// GetProductSKUs 获取产品SKU列表
|
||
func (s *ProductService) GetProductSKUs(productID uint) ([]model.ProductSKU, error) {
|
||
return s.productRepo.GetProductSKUs(productID)
|
||
}
|
||
|
||
// GetSKUByID 根据SKU ID获取SKU详情
|
||
func (s *ProductService) GetSKUByID(skuID uint) (*model.ProductSKU, error) {
|
||
return s.productRepo.GetSKUByID(skuID)
|
||
}
|
||
|
||
// GetProductTags 获取产品标签列表
|
||
func (s *ProductService) GetProductTags() ([]model.ProductTag, error) {
|
||
return s.productRepo.GetProductTags()
|
||
}
|
||
|
||
// GetStores 获取店铺列表
|
||
func (s *ProductService) GetStores() ([]model.Store, error) {
|
||
return s.productRepo.GetStores()
|
||
}
|
||
|
||
// GetStoreByID 根据ID获取店铺信息
|
||
func (s *ProductService) GetStoreByID(id uint) (*model.Store, error) {
|
||
return s.productRepo.GetStoreByID(id)
|
||
}
|
||
|
||
// GetProductReviewCount 获取产品评价统计
|
||
func (s *ProductService) GetProductReviewCount(productID uint) (map[string]interface{}, error) {
|
||
// 检查产品是否存在
|
||
_, err := s.productRepo.GetByID(productID)
|
||
if err != nil {
|
||
return nil, errors.New("产品不存在")
|
||
}
|
||
|
||
return s.productRepo.GetReviewCount(productID)
|
||
}
|
||
|
||
// GetProductStatistics 获取产品统计
|
||
func (s *ProductService) GetProductStatistics() (map[string]interface{}, error) {
|
||
// 使用ProductRepository的GetProductStatistics方法
|
||
return s.productRepo.GetProductStatistics()
|
||
}
|
||
|
||
// GetProductSalesRanking 获取产品销售排行
|
||
func (s *ProductService) GetProductSalesRanking(startDate, endDate, limit string) ([]map[string]interface{}, error) {
|
||
// 简化实现,返回基础排行数据
|
||
var results []map[string]interface{}
|
||
|
||
// 这里应该根据订单数据统计产品销量,暂时返回模拟数据
|
||
products, _, err := s.productRepo.GetList(0, 10, map[string]interface{}{"status": 1})
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
for i, product := range products {
|
||
if i >= 10 { // 限制返回数量
|
||
break
|
||
}
|
||
results = append(results, map[string]interface{}{
|
||
"product_id": product.ID,
|
||
"product_name": product.Name,
|
||
"sales_count": 100 - i*5, // 模拟销量数据
|
||
"sales_amount": float64(1000 - i*50),
|
||
})
|
||
}
|
||
|
||
return results, nil
|
||
}
|
||
|
||
// GetCategorySalesRanking 获取分类销售排行
|
||
func (s *ProductService) GetCategorySalesRanking(startDate, endDate, limit string) ([]map[string]interface{}, error) {
|
||
// 解析limit参数
|
||
limitInt := 10 // 默认值
|
||
if limit != "" {
|
||
if parsedLimit, err := strconv.Atoi(limit); err == nil && parsedLimit > 0 {
|
||
limitInt = parsedLimit
|
||
}
|
||
}
|
||
|
||
// 如果没有提供日期范围,使用最近30天
|
||
if startDate == "" || endDate == "" {
|
||
now := time.Now()
|
||
endDate = now.Format("2006-01-02")
|
||
startDate = now.AddDate(0, 0, -30).Format("2006-01-02")
|
||
}
|
||
|
||
// 使用真实的数据库查询
|
||
return s.productRepo.GetCategorySalesStatistics(startDate, endDate, limitInt)
|
||
}
|
||
|
||
// BatchUpdateProductStatus 批量更新商品状态
|
||
func (s *ProductService) BatchUpdateProductStatus(ids []uint, status int) error {
|
||
if len(ids) == 0 {
|
||
return errors.New("商品ID列表不能为空")
|
||
}
|
||
|
||
return s.productRepo.BatchUpdateStatus(ids, status)
|
||
}
|
||
|
||
// BatchUpdateProductPrice 批量更新商品价格
|
||
func (s *ProductService) BatchUpdateProductPrice(updates []map[string]interface{}) error {
|
||
if len(updates) == 0 {
|
||
return errors.New("更新数据不能为空")
|
||
}
|
||
|
||
return s.productRepo.BatchUpdatePrice(updates)
|
||
}
|
||
|
||
// BatchDeleteProducts 批量删除商品
|
||
func (s *ProductService) BatchDeleteProducts(ids []uint) error {
|
||
if len(ids) == 0 {
|
||
return errors.New("商品ID列表不能为空")
|
||
}
|
||
|
||
return s.productRepo.BatchDelete(ids)
|
||
}
|
||
|
||
// CreateProductSKU 创建商品SKU
|
||
func (s *ProductService) CreateProductSKU(sku *model.ProductSKU) error {
|
||
// 验证商品是否存在
|
||
_, err := s.productRepo.GetByID(sku.ProductID)
|
||
if err != nil {
|
||
return errors.New("商品不存在")
|
||
}
|
||
|
||
return s.productRepo.CreateSKU(sku)
|
||
}
|
||
|
||
// UpdateProductSKU 更新商品SKU
|
||
func (s *ProductService) UpdateProductSKU(id uint, updates map[string]interface{}) error {
|
||
// 检查SKU是否存在
|
||
_, err := s.productRepo.GetSKUByID(id)
|
||
if err != nil {
|
||
return errors.New("SKU不存在")
|
||
}
|
||
|
||
return s.productRepo.UpdateSKU(id, updates)
|
||
}
|
||
|
||
// DeleteProductSKU 删除商品SKU
|
||
func (s *ProductService) DeleteProductSKU(id uint) error {
|
||
// 检查SKU是否存在(包括已软删除的)
|
||
var sku model.ProductSKU
|
||
err := s.productRepo.GetDB().Where("id = ?", id).First(&sku).Error
|
||
if err != nil {
|
||
return errors.New("SKU不存在")
|
||
}
|
||
|
||
// 如果SKU已经被软删除,直接返回成功
|
||
if sku.Status == 0 {
|
||
fmt.Printf("SKU ID %d 已经被软删除,无需重复操作\n", id)
|
||
return nil
|
||
}
|
||
|
||
// 检查SKU是否被订单引用
|
||
var count int64
|
||
err = s.productRepo.GetDB().Table("order_items").Where("sk_uid = ?", id).Count(&count).Error
|
||
if err != nil {
|
||
return fmt.Errorf("检查SKU引用关系失败: %v", err)
|
||
}
|
||
|
||
if count > 0 {
|
||
// 如果被订单引用,执行软删除
|
||
err = s.productRepo.DeleteSKU(id)
|
||
if err != nil {
|
||
return fmt.Errorf("删除SKU失败: %v", err)
|
||
}
|
||
// 软删除成功,记录日志但不返回错误
|
||
fmt.Printf("SKU ID %d 已被 %d 个订单引用,已执行软删除(设置为不可用状态)\n", id, count)
|
||
return nil
|
||
}
|
||
|
||
// 如果没有被引用,执行硬删除
|
||
err = s.productRepo.DeleteSKU(id)
|
||
if err != nil {
|
||
return fmt.Errorf("删除SKU失败: %v", err)
|
||
}
|
||
|
||
// 同步更新商品库存
|
||
if err := s.productRepo.SyncProductStockFromSKUs(sku.ProductID); err != nil {
|
||
// 记录错误但不阻止删除操作
|
||
fmt.Printf("同步商品库存失败 - 商品ID: %d, 错误: %v\n", sku.ProductID, err)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// GetProductImages 获取商品图片列表
|
||
func (s *ProductService) GetProductImages(productID uint) ([]model.ProductImage, error) {
|
||
return s.productRepo.GetProductImages(productID)
|
||
}
|
||
|
||
// CreateProductImage 创建商品图片
|
||
func (s *ProductService) CreateProductImage(image *model.ProductImage) error {
|
||
// 验证商品是否存在
|
||
_, err := s.productRepo.GetByID(image.ProductID)
|
||
if err != nil {
|
||
return errors.New("商品不存在")
|
||
}
|
||
|
||
return s.productRepo.CreateProductImage(image)
|
||
}
|
||
|
||
// UpdateProductImageSort 更新商品图片排序
|
||
func (s *ProductService) UpdateProductImageSort(id uint, sort int) error {
|
||
return s.productRepo.UpdateProductImageSort(id, sort)
|
||
}
|
||
|
||
// DeleteProductImage 删除商品图片
|
||
func (s *ProductService) DeleteProductImage(id uint) error {
|
||
return s.productRepo.DeleteProductImage(id)
|
||
}
|
||
|
||
// CreateProductSpec 创建商品规格
|
||
func (s *ProductService) CreateProductSpec(spec *model.ProductSpec) error {
|
||
// 验证商品是否存在
|
||
_, err := s.productRepo.GetByID(spec.ProductID)
|
||
if err != nil {
|
||
return errors.New("商品不存在")
|
||
}
|
||
|
||
return s.productRepo.CreateProductSpec(spec)
|
||
}
|
||
|
||
// UpdateProductSpec 更新商品规格
|
||
func (s *ProductService) UpdateProductSpec(id uint, updates map[string]interface{}) error {
|
||
return s.productRepo.UpdateProductSpec(id, updates)
|
||
}
|
||
|
||
// DeleteProductSpec 删除商品规格
|
||
func (s *ProductService) DeleteProductSpec(id uint) error {
|
||
return s.productRepo.DeleteProductSpec(id)
|
||
}
|
||
|
||
// GetProductSpecs 获取商品规格列表
|
||
func (s *ProductService) GetProductSpecs(productID uint) ([]model.ProductSpec, error) {
|
||
return s.productRepo.GetProductSpecs(productID)
|
||
}
|
||
|
||
// CreateProductTag 创建商品标签
|
||
func (s *ProductService) CreateProductTag(tag *model.ProductTag) error {
|
||
return s.productRepo.CreateProductTag(tag)
|
||
}
|
||
|
||
// UpdateProductTag 更新商品标签
|
||
func (s *ProductService) UpdateProductTag(id uint, updates map[string]interface{}) error {
|
||
return s.productRepo.UpdateProductTag(id, updates)
|
||
}
|
||
|
||
// DeleteProductTag 删除商品标签
|
||
func (s *ProductService) DeleteProductTag(id uint) error {
|
||
return s.productRepo.DeleteProductTag(id)
|
||
}
|
||
|
||
// AssignTagsToProduct 为商品分配标签
|
||
func (s *ProductService) AssignTagsToProduct(productID uint, tagIDs []uint) error {
|
||
// 验证商品是否存在
|
||
_, err := s.productRepo.GetByID(productID)
|
||
if err != nil {
|
||
return errors.New("商品不存在")
|
||
}
|
||
|
||
return s.productRepo.AssignTagsToProduct(productID, tagIDs)
|
||
}
|
||
|
||
// GetLowStockProducts 获取低库存商品
|
||
func (s *ProductService) GetLowStockProducts(threshold int) ([]model.Product, error) {
|
||
if threshold <= 0 {
|
||
threshold = 10 // 默认阈值
|
||
}
|
||
|
||
return s.productRepo.GetLowStockProducts(threshold)
|
||
}
|
||
|
||
// GetInventoryStatistics 获取库存统计
|
||
func (s *ProductService) GetInventoryStatistics() (map[string]interface{}, error) {
|
||
return s.productRepo.GetInventoryStatistics()
|
||
}
|
||
|
||
// ExportProducts 导出商品数据
|
||
func (s *ProductService) ExportProducts(conditions map[string]interface{}) ([]model.Product, error) {
|
||
return s.productRepo.GetProductsForExport(conditions)
|
||
}
|
||
|
||
// ImportProducts 导入商品数据
|
||
func (s *ProductService) ImportProducts(products []model.Product) (map[string]interface{}, error) {
|
||
successCount := 0
|
||
failCount := 0
|
||
var errors []string
|
||
|
||
for _, product := range products {
|
||
// 验证商品数据
|
||
if product.Name == "" {
|
||
errors = append(errors, "商品名称不能为空")
|
||
failCount++
|
||
continue
|
||
}
|
||
|
||
if product.Price <= 0 {
|
||
errors = append(errors, "商品价格必须大于0")
|
||
failCount++
|
||
continue
|
||
}
|
||
|
||
// 创建商品
|
||
err := s.productRepo.Create(&product)
|
||
if err != nil {
|
||
errors = append(errors, err.Error())
|
||
failCount++
|
||
} else {
|
||
successCount++
|
||
}
|
||
}
|
||
|
||
return map[string]interface{}{
|
||
"success_count": successCount,
|
||
"fail_count": failCount,
|
||
"errors": errors,
|
||
}, nil
|
||
}
|
||
|
||
// SyncProductStock 同步商品库存(根据SKU库存计算)
|
||
func (s *ProductService) SyncProductStock(productID uint) error {
|
||
return s.productRepo.SyncProductStockFromSKUs(productID)
|
||
}
|
||
|
||
// SyncAllProductsStock 同步所有商品库存
|
||
func (s *ProductService) SyncAllProductsStock() error {
|
||
// 获取所有有SKU的商品
|
||
products, _, err := s.productRepo.GetList(0, 0, map[string]interface{}{})
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
var syncErrors []string
|
||
for _, product := range products {
|
||
// 检查商品是否有SKU
|
||
skus, err := s.productRepo.GetProductSKUs(product.ID)
|
||
if err != nil {
|
||
continue
|
||
}
|
||
|
||
if len(skus) > 0 {
|
||
// 如果有SKU,同步库存
|
||
err = s.productRepo.SyncProductStockFromSKUs(product.ID)
|
||
if err != nil {
|
||
syncErrors = append(syncErrors, fmt.Sprintf("商品ID %d 同步失败: %v", product.ID, err))
|
||
}
|
||
}
|
||
}
|
||
|
||
if len(syncErrors) > 0 {
|
||
return fmt.Errorf("部分商品同步失败: %v", syncErrors)
|
||
}
|
||
|
||
return nil
|
||
} |