661 lines
16 KiB
Go
661 lines
16 KiB
Go
package service
|
||
|
||
import (
|
||
"dianshang/internal/model"
|
||
"dianshang/internal/repository"
|
||
"errors"
|
||
"fmt"
|
||
"time"
|
||
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
// CartService 购物车服务
|
||
type CartService struct {
|
||
orderRepo *repository.OrderRepository
|
||
productRepo *repository.ProductRepository
|
||
userRepo *repository.UserRepository
|
||
}
|
||
|
||
// NewCartService 创建购物车服务
|
||
func NewCartService(orderRepo *repository.OrderRepository, productRepo *repository.ProductRepository, userRepo *repository.UserRepository) *CartService {
|
||
return &CartService{
|
||
orderRepo: orderRepo,
|
||
productRepo: productRepo,
|
||
userRepo: userRepo,
|
||
}
|
||
}
|
||
|
||
// GetCart 获取购物车
|
||
func (s *CartService) GetCart(userID uint) ([]model.Cart, error) {
|
||
// 检查用户是否存在
|
||
_, err := s.userRepo.GetByID(userID)
|
||
if err != nil {
|
||
return nil, errors.New("用户不存在")
|
||
}
|
||
|
||
return s.orderRepo.GetCart(userID)
|
||
}
|
||
|
||
// AddToCart 添加到购物车
|
||
func (s *CartService) AddToCart(userID, productID uint, skuID uint, quantity int) error {
|
||
// 检查用户是否存在
|
||
_, err := s.userRepo.GetByID(userID)
|
||
if err != nil {
|
||
return errors.New("用户不存在")
|
||
}
|
||
|
||
// 检查产品是否存在
|
||
product, err := s.productRepo.GetByID(productID)
|
||
if err != nil {
|
||
return errors.New("产品不存在")
|
||
}
|
||
|
||
// 检查产品状态
|
||
if product.Status != 1 {
|
||
return errors.New("产品已下架")
|
||
}
|
||
|
||
// 检查库存
|
||
if product.Stock < quantity {
|
||
return errors.New("库存不足")
|
||
}
|
||
|
||
// 检查购物车中是否已存在该商品(包括SKU)
|
||
existingCart, err := s.orderRepo.GetCartItemBySKU(userID, productID, skuID)
|
||
if err == nil && existingCart != nil {
|
||
// 已存在,更新数量
|
||
newQuantity := existingCart.Quantity + quantity
|
||
if product.Stock < newQuantity {
|
||
return errors.New("库存不足")
|
||
}
|
||
return s.orderRepo.UpdateCartItem(existingCart.ID, newQuantity)
|
||
}
|
||
|
||
// 如果不是记录不存在的错误,返回错误
|
||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||
return err
|
||
}
|
||
|
||
// 不存在,添加新项
|
||
var skuPtr *uint
|
||
if skuID != 0 {
|
||
skuPtr = &skuID
|
||
}
|
||
cart := &model.Cart{
|
||
UserID: userID,
|
||
ProductID: productID,
|
||
SKUID: skuPtr,
|
||
Quantity: quantity,
|
||
Selected: true,
|
||
CreatedAt: time.Now(),
|
||
UpdatedAt: time.Now(),
|
||
}
|
||
|
||
return s.orderRepo.AddToCart(cart)
|
||
}
|
||
|
||
// UpdateCartItem 更新购物车项
|
||
func (s *CartService) UpdateCartItem(userID, productID uint, quantity int) error {
|
||
// 检查用户是否存在
|
||
_, err := s.userRepo.GetByID(userID)
|
||
if err != nil {
|
||
return errors.New("用户不存在")
|
||
}
|
||
|
||
// 获取该用户该产品的所有购物车项
|
||
cartItems, err := s.orderRepo.GetCart(userID)
|
||
if err != nil {
|
||
return errors.New("获取购物车失败")
|
||
}
|
||
|
||
// 查找匹配的购物车项
|
||
var targetCartItem *model.Cart
|
||
for _, item := range cartItems {
|
||
if item.ProductID == productID {
|
||
targetCartItem = &item
|
||
break
|
||
}
|
||
}
|
||
|
||
if targetCartItem == nil {
|
||
return errors.New("购物车项不存在")
|
||
}
|
||
|
||
if quantity == 0 {
|
||
// 数量为0,删除该项
|
||
return s.orderRepo.RemoveFromCart(userID, productID)
|
||
}
|
||
|
||
// 检查产品库存
|
||
product, err := s.productRepo.GetByID(productID)
|
||
if err != nil {
|
||
return errors.New("产品不存在")
|
||
}
|
||
|
||
if product.Stock < quantity {
|
||
return errors.New("库存不足")
|
||
}
|
||
|
||
return s.orderRepo.UpdateCartItem(targetCartItem.ID, quantity)
|
||
}
|
||
|
||
// UpdateCartItemBySKU 基于SKU更新购物车项
|
||
func (s *CartService) UpdateCartItemBySKU(userID, productID, skuID uint, quantity int) error {
|
||
// 检查用户是否存在
|
||
_, err := s.userRepo.GetByID(userID)
|
||
if err != nil {
|
||
return errors.New("用户不存在")
|
||
}
|
||
|
||
// 使用SKU查找购物车项
|
||
cartItem, err := s.orderRepo.GetCartItemBySKU(userID, productID, skuID)
|
||
if err != nil {
|
||
return errors.New("购物车项不存在")
|
||
}
|
||
|
||
if quantity == 0 {
|
||
// 数量为0,删除该项
|
||
return s.orderRepo.RemoveFromCartBySKU(userID, productID, skuID)
|
||
}
|
||
|
||
// 检查产品库存
|
||
product, err := s.productRepo.GetByID(productID)
|
||
if err != nil {
|
||
return errors.New("产品不存在")
|
||
}
|
||
|
||
if product.Stock < quantity {
|
||
return errors.New("库存不足")
|
||
}
|
||
|
||
return s.orderRepo.UpdateCartItem(cartItem.ID, quantity)
|
||
}
|
||
|
||
// RemoveFromCart 从购物车移除
|
||
func (s *CartService) RemoveFromCart(userID, productID uint) error {
|
||
// 检查用户是否存在
|
||
_, err := s.userRepo.GetByID(userID)
|
||
if err != nil {
|
||
return errors.New("用户不存在")
|
||
}
|
||
|
||
// 获取该用户该产品的所有购物车项
|
||
cartItems, err := s.orderRepo.GetCart(userID)
|
||
if err != nil {
|
||
return errors.New("获取购物车失败")
|
||
}
|
||
|
||
// 查找匹配的购物车项
|
||
var found bool
|
||
for _, item := range cartItems {
|
||
if item.ProductID == productID {
|
||
found = true
|
||
break
|
||
}
|
||
}
|
||
|
||
if !found {
|
||
return errors.New("购物车项不存在")
|
||
}
|
||
|
||
return s.orderRepo.RemoveFromCart(userID, productID)
|
||
}
|
||
|
||
// RemoveFromCartBySKU 基于SKU从购物车移除
|
||
func (s *CartService) RemoveFromCartBySKU(userID, productID, skuID uint) error {
|
||
// 检查用户是否存在
|
||
_, err := s.userRepo.GetByID(userID)
|
||
if err != nil {
|
||
return errors.New("用户不存在")
|
||
}
|
||
|
||
// 使用SKU查找购物车项
|
||
_, err = s.orderRepo.GetCartItemBySKU(userID, productID, skuID)
|
||
if err != nil {
|
||
return errors.New("购物车项不存在")
|
||
}
|
||
|
||
return s.orderRepo.RemoveFromCartBySKU(userID, productID, skuID)
|
||
}
|
||
|
||
// ClearCart 清空购物车
|
||
func (s *CartService) ClearCart(userID uint) error {
|
||
// 检查用户是否存在
|
||
_, err := s.userRepo.GetByID(userID)
|
||
if err != nil {
|
||
return errors.New("用户不存在")
|
||
}
|
||
|
||
return s.orderRepo.ClearCart(userID)
|
||
}
|
||
|
||
// GetCartCount 获取购物车商品数量
|
||
func (s *CartService) GetCartCount(userID uint) (int, error) {
|
||
cart, err := s.GetCart(userID)
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
|
||
var count int
|
||
for _, item := range cart {
|
||
count += int(item.Quantity)
|
||
}
|
||
|
||
return count, nil
|
||
}
|
||
|
||
// GetCartTotal 获取购物车总金额
|
||
func (s *CartService) GetCartTotal(userID uint) (float64, error) {
|
||
cart, err := s.GetCart(userID)
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
|
||
var total float64
|
||
for _, item := range cart {
|
||
if item.Product.ID != 0 {
|
||
// 将价格从分转换为元
|
||
total += (float64(item.Product.Price) / 100) * float64(item.Quantity)
|
||
}
|
||
}
|
||
|
||
return total, nil
|
||
}
|
||
|
||
// SelectCartItem 选择/取消选择购物车项
|
||
func (s *CartService) SelectCartItem(userID, cartID uint, selected bool) error {
|
||
// 检查用户是否存在
|
||
_, err := s.userRepo.GetByID(userID)
|
||
if err != nil {
|
||
return errors.New("用户不存在")
|
||
}
|
||
|
||
return s.orderRepo.SelectCartItem(userID, cartID, selected)
|
||
}
|
||
|
||
// SelectAllCartItems 全选/取消全选购物车
|
||
func (s *CartService) SelectAllCartItems(userID uint, selected bool) error {
|
||
// 检查用户是否存在
|
||
_, err := s.userRepo.GetByID(userID)
|
||
if err != nil {
|
||
return errors.New("用户不存在")
|
||
}
|
||
|
||
return s.orderRepo.SelectAllCartItems(userID, selected)
|
||
}
|
||
|
||
// BatchAddToCart 批量添加到购物车
|
||
func (s *CartService) BatchAddToCart(userID uint, items []struct {
|
||
ProductID uint `json:"product_id"`
|
||
SKUID uint `json:"sku_id"`
|
||
Quantity int `json:"quantity"`
|
||
}) error {
|
||
// 检查用户是否存在
|
||
_, err := s.userRepo.GetByID(userID)
|
||
if err != nil {
|
||
return errors.New("用户不存在")
|
||
}
|
||
|
||
// 验证所有商品
|
||
for _, item := range items {
|
||
product, err := s.productRepo.GetByID(item.ProductID)
|
||
if err != nil {
|
||
return errors.New("商品不存在: " + err.Error())
|
||
}
|
||
|
||
if product.Status != 1 {
|
||
return errors.New("商品已下架")
|
||
}
|
||
|
||
if product.Stock < item.Quantity {
|
||
return errors.New("商品库存不足")
|
||
}
|
||
}
|
||
|
||
// 批量添加
|
||
for _, item := range items {
|
||
err := s.AddToCart(userID, item.ProductID, item.SKUID, item.Quantity)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// BatchRemoveFromCart 批量从购物车移除
|
||
func (s *CartService) BatchRemoveFromCart(userID uint, cartIDs []uint) error {
|
||
// 检查用户是否存在
|
||
_, err := s.userRepo.GetByID(userID)
|
||
if err != nil {
|
||
return errors.New("用户不存在")
|
||
}
|
||
|
||
return s.orderRepo.BatchRemoveFromCart(userID, cartIDs)
|
||
}
|
||
|
||
// BatchUpdateCartItems 批量更新购物车项
|
||
func (s *CartService) BatchUpdateCartItems(userID uint, updates []struct {
|
||
CartID uint `json:"cart_id"`
|
||
Quantity int `json:"quantity"`
|
||
}) error {
|
||
// 检查用户是否存在
|
||
_, err := s.userRepo.GetByID(userID)
|
||
if err != nil {
|
||
return errors.New("用户不存在")
|
||
}
|
||
|
||
// 获取购物车项并验证
|
||
for _, update := range updates {
|
||
cartItem, err := s.orderRepo.GetCartItem(userID, update.CartID)
|
||
if err != nil {
|
||
return errors.New("购物车项不存在")
|
||
}
|
||
|
||
// 检查库存
|
||
product, err := s.productRepo.GetByID(cartItem.ProductID)
|
||
if err != nil {
|
||
return errors.New("商品不存在")
|
||
}
|
||
|
||
if product.Stock < update.Quantity {
|
||
return errors.New("商品库存不足")
|
||
}
|
||
|
||
// 更新数量
|
||
if update.Quantity == 0 {
|
||
err = s.orderRepo.RemoveCartItem(update.CartID)
|
||
} else {
|
||
err = s.orderRepo.UpdateCartItem(update.CartID, update.Quantity)
|
||
}
|
||
|
||
if err != nil {
|
||
return err
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// GetCartWithDetails 获取购物车详细信息(包含商品详情)
|
||
func (s *CartService) GetCartWithDetails(userID uint) (map[string]interface{}, error) {
|
||
// 检查用户是否存在
|
||
_, err := s.userRepo.GetByID(userID)
|
||
if err != nil {
|
||
return nil, errors.New("用户不存在")
|
||
}
|
||
|
||
cart, err := s.orderRepo.GetCart(userID)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
var validItems []model.Cart
|
||
var invalidItems []model.Cart
|
||
var totalAmount float64
|
||
var totalQuantity int
|
||
var selectedAmount float64
|
||
var selectedQuantity int
|
||
|
||
for _, item := range cart {
|
||
// 检查商品是否有效
|
||
product, err := s.productRepo.GetByID(item.ProductID)
|
||
if err != nil || product.Status != 1 {
|
||
invalidItems = append(invalidItems, item)
|
||
continue
|
||
}
|
||
|
||
// 检查库存
|
||
if product.Stock < item.Quantity {
|
||
item.Product = *product
|
||
invalidItems = append(invalidItems, item)
|
||
continue
|
||
}
|
||
|
||
// 计算价格
|
||
item.Product = *product
|
||
itemPrice := float64(product.Price) / 100 * float64(item.Quantity)
|
||
totalAmount += itemPrice
|
||
totalQuantity += item.Quantity
|
||
|
||
if item.Selected {
|
||
selectedAmount += itemPrice
|
||
selectedQuantity += item.Quantity
|
||
}
|
||
|
||
validItems = append(validItems, item)
|
||
}
|
||
|
||
return map[string]interface{}{
|
||
"valid_items": validItems,
|
||
"invalid_items": invalidItems,
|
||
"total_amount": totalAmount,
|
||
"total_quantity": totalQuantity,
|
||
"selected_amount": selectedAmount,
|
||
"selected_quantity": selectedQuantity,
|
||
"valid_count": len(validItems),
|
||
"invalid_count": len(invalidItems),
|
||
}, nil
|
||
}
|
||
|
||
// ValidateCartItems 验证购物车商品有效性
|
||
func (s *CartService) ValidateCartItems(userID uint) (map[string]interface{}, error) {
|
||
// 检查用户是否存在
|
||
_, err := s.userRepo.GetByID(userID)
|
||
if err != nil {
|
||
return nil, errors.New("用户不存在")
|
||
}
|
||
|
||
cart, err := s.orderRepo.GetCart(userID)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
var validItems []uint
|
||
var invalidItems []struct {
|
||
CartID uint `json:"cart_id"`
|
||
Reason string `json:"reason"`
|
||
}
|
||
|
||
for _, item := range cart {
|
||
// 检查商品是否存在
|
||
product, err := s.productRepo.GetByID(item.ProductID)
|
||
if err != nil {
|
||
invalidItems = append(invalidItems, struct {
|
||
CartID uint `json:"cart_id"`
|
||
Reason string `json:"reason"`
|
||
}{
|
||
CartID: item.ID,
|
||
Reason: "商品不存在",
|
||
})
|
||
continue
|
||
}
|
||
|
||
// 检查商品状态
|
||
if product.Status != 1 {
|
||
invalidItems = append(invalidItems, struct {
|
||
CartID uint `json:"cart_id"`
|
||
Reason string `json:"reason"`
|
||
}{
|
||
CartID: item.ID,
|
||
Reason: "商品已下架",
|
||
})
|
||
continue
|
||
}
|
||
|
||
// 检查库存
|
||
if product.Stock < item.Quantity {
|
||
invalidItems = append(invalidItems, struct {
|
||
CartID uint `json:"cart_id"`
|
||
Reason string `json:"reason"`
|
||
}{
|
||
CartID: item.ID,
|
||
Reason: "库存不足",
|
||
})
|
||
continue
|
||
}
|
||
|
||
validItems = append(validItems, item.ID)
|
||
}
|
||
|
||
return map[string]interface{}{
|
||
"valid_items": validItems,
|
||
"invalid_items": invalidItems,
|
||
"valid_count": len(validItems),
|
||
"invalid_count": len(invalidItems),
|
||
}, nil
|
||
}
|
||
|
||
// CleanInvalidCartItems 清理无效的购物车项
|
||
func (s *CartService) CleanInvalidCartItems(userID uint) error {
|
||
// 检查用户是否存在
|
||
_, err := s.userRepo.GetByID(userID)
|
||
if err != nil {
|
||
return errors.New("用户不存在")
|
||
}
|
||
|
||
validation, err := s.ValidateCartItems(userID)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
invalidItems := validation["invalid_items"].([]struct {
|
||
CartID uint `json:"cart_id"`
|
||
Reason string `json:"reason"`
|
||
})
|
||
|
||
if len(invalidItems) == 0 {
|
||
return nil
|
||
}
|
||
|
||
var cartIDs []uint
|
||
for _, item := range invalidItems {
|
||
cartIDs = append(cartIDs, item.CartID)
|
||
}
|
||
|
||
return s.orderRepo.BatchRemoveFromCart(userID, cartIDs)
|
||
}
|
||
|
||
// GetCartSummary 获取购物车摘要信息
|
||
func (s *CartService) GetCartSummary(userID uint) (map[string]interface{}, error) {
|
||
// 检查用户是否存在
|
||
_, err := s.userRepo.GetByID(userID)
|
||
if err != nil {
|
||
return nil, errors.New("用户不存在")
|
||
}
|
||
|
||
details, err := s.GetCartWithDetails(userID)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return map[string]interface{}{
|
||
"total_items": details["valid_count"].(int) + details["invalid_count"].(int),
|
||
"valid_items": details["valid_count"],
|
||
"invalid_items": details["invalid_count"],
|
||
"total_amount": details["total_amount"],
|
||
"selected_amount": details["selected_amount"],
|
||
"total_quantity": details["total_quantity"],
|
||
"selected_quantity": details["selected_quantity"],
|
||
}, nil
|
||
}
|
||
|
||
// MergeCart 合并购物车(用于登录后合并游客购物车)
|
||
func (s *CartService) MergeCart(userID uint, guestCartItems []struct {
|
||
ProductID uint `json:"product_id"`
|
||
SKUID uint `json:"sku_id"`
|
||
Quantity int `json:"quantity"`
|
||
}) error {
|
||
// 检查用户是否存在
|
||
_, err := s.userRepo.GetByID(userID)
|
||
if err != nil {
|
||
return errors.New("用户不存在")
|
||
}
|
||
|
||
// 获取用户现有购物车
|
||
existingCart, err := s.orderRepo.GetCart(userID)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// 创建现有购物车的映射
|
||
existingMap := make(map[string]*model.Cart)
|
||
for i, item := range existingCart {
|
||
key := fmt.Sprintf("%d_%d", item.ProductID, item.SKUID)
|
||
if item.SKUID == nil {
|
||
key = fmt.Sprintf("%d_0", item.ProductID)
|
||
}
|
||
existingMap[key] = &existingCart[i]
|
||
}
|
||
|
||
// 合并游客购物车项
|
||
for _, guestItem := range guestCartItems {
|
||
key := fmt.Sprintf("%d_%d", guestItem.ProductID, guestItem.SKUID)
|
||
if guestItem.SKUID == 0 {
|
||
key = fmt.Sprintf("%d_0", guestItem.ProductID)
|
||
}
|
||
|
||
if existingItem, exists := existingMap[key]; exists {
|
||
// 已存在,更新数量
|
||
newQuantity := existingItem.Quantity + guestItem.Quantity
|
||
err = s.orderRepo.UpdateCartItem(existingItem.ID, newQuantity)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
} else {
|
||
// 不存在,添加新项
|
||
err = s.AddToCart(userID, guestItem.ProductID, guestItem.SKUID, guestItem.Quantity)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// GetSelectedCartItems 获取选中的购物车项
|
||
func (s *CartService) GetSelectedCartItems(userID uint) ([]model.Cart, error) {
|
||
// 检查用户是否存在
|
||
_, err := s.userRepo.GetByID(userID)
|
||
if err != nil {
|
||
return nil, errors.New("用户不存在")
|
||
}
|
||
|
||
return s.orderRepo.GetSelectedCartItems(userID)
|
||
}
|
||
|
||
// CalculateCartDiscount 计算购物车优惠(预留接口)
|
||
func (s *CartService) CalculateCartDiscount(userID uint, couponID uint) (map[string]interface{}, error) {
|
||
// 检查用户是否存在
|
||
_, err := s.userRepo.GetByID(userID)
|
||
if err != nil {
|
||
return nil, errors.New("用户不存在")
|
||
}
|
||
|
||
selectedItems, err := s.GetSelectedCartItems(userID)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
var originalAmount float64
|
||
for _, item := range selectedItems {
|
||
product, err := s.productRepo.GetByID(item.ProductID)
|
||
if err != nil {
|
||
continue
|
||
}
|
||
originalAmount += float64(product.Price) / 100 * float64(item.Quantity)
|
||
}
|
||
|
||
// 这里可以添加优惠券计算逻辑
|
||
discountAmount := 0.0
|
||
finalAmount := originalAmount - discountAmount
|
||
|
||
return map[string]interface{}{
|
||
"original_amount": originalAmount,
|
||
"discount_amount": discountAmount,
|
||
"final_amount": finalAmount,
|
||
"coupon_id": couponID,
|
||
}, nil
|
||
} |