|
@@ -3,7 +3,6 @@ package shop.alien.dining.service.impl;
|
|
|
import com.alibaba.fastjson2.JSON;
|
|
import com.alibaba.fastjson2.JSON;
|
|
|
import com.alibaba.fastjson2.JSONObject;
|
|
import com.alibaba.fastjson2.JSONObject;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
-import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
|
|
|
import lombok.RequiredArgsConstructor;
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
@@ -206,17 +205,17 @@ public class CartServiceImpl implements CartService {
|
|
|
// 商品已存在
|
|
// 商品已存在
|
|
|
Integer lockedQuantity = existingItem.getLockedQuantity();
|
|
Integer lockedQuantity = existingItem.getLockedQuantity();
|
|
|
if (lockedQuantity != null && lockedQuantity > 0) {
|
|
if (lockedQuantity != null && lockedQuantity > 0) {
|
|
|
- // 如果商品有锁定数量(已下单),将新数量叠加到当前数量和锁定数量上
|
|
|
|
|
|
|
+ // 如果商品有已下单数量,将新数量叠加到当前数量和已下单数量上
|
|
|
Integer newQuantity = existingItem.getQuantity() + dto.getQuantity();
|
|
Integer newQuantity = existingItem.getQuantity() + dto.getQuantity();
|
|
|
Integer newLockedQuantity = lockedQuantity + dto.getQuantity();
|
|
Integer newLockedQuantity = lockedQuantity + dto.getQuantity();
|
|
|
existingItem.setQuantity(newQuantity);
|
|
existingItem.setQuantity(newQuantity);
|
|
|
existingItem.setLockedQuantity(newLockedQuantity);
|
|
existingItem.setLockedQuantity(newLockedQuantity);
|
|
|
existingItem.setSubtotalAmount(existingItem.getUnitPrice()
|
|
existingItem.setSubtotalAmount(existingItem.getUnitPrice()
|
|
|
.multiply(BigDecimal.valueOf(newQuantity)));
|
|
.multiply(BigDecimal.valueOf(newQuantity)));
|
|
|
- log.info("商品已存在且有锁定数量,叠加数量, cuisineId={}, oldQuantity={}, newQuantity={}, oldLockedQuantity={}, newLockedQuantity={}",
|
|
|
|
|
|
|
+ log.info("商品已存在且有已下单数量,叠加数量, cuisineId={}, oldQuantity={}, newQuantity={}, oldOrderedQuantity={}, newOrderedQuantity={}",
|
|
|
dto.getCuisineId(), existingItem.getQuantity() - dto.getQuantity(), newQuantity, lockedQuantity, newLockedQuantity);
|
|
dto.getCuisineId(), existingItem.getQuantity() - dto.getQuantity(), newQuantity, lockedQuantity, newLockedQuantity);
|
|
|
} else {
|
|
} else {
|
|
|
- // 商品已存在但没有锁定数量,不允许重复添加
|
|
|
|
|
|
|
+ // 商品已存在但没有已下单数量,不允许重复添加
|
|
|
throw new RuntimeException("已添加过本商品");
|
|
throw new RuntimeException("已添加过本商品");
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
@@ -270,11 +269,11 @@ public class CartServiceImpl implements CartService {
|
|
|
.orElse(null);
|
|
.orElse(null);
|
|
|
|
|
|
|
|
if (item != null) {
|
|
if (item != null) {
|
|
|
- // 检查锁定数量:不允许将数量减少到小于锁定数量
|
|
|
|
|
|
|
+ // 检查已下单数量:不允许将数量减少到小于已下单数量
|
|
|
Integer lockedQuantity = item.getLockedQuantity();
|
|
Integer lockedQuantity = item.getLockedQuantity();
|
|
|
if (lockedQuantity != null && lockedQuantity > 0) {
|
|
if (lockedQuantity != null && lockedQuantity > 0) {
|
|
|
if (quantity < lockedQuantity) {
|
|
if (quantity < lockedQuantity) {
|
|
|
- throw new RuntimeException("商品数量不能少于锁定数量(" + lockedQuantity + "),该数量已下单");
|
|
|
|
|
|
|
+ throw new RuntimeException("商品数量不能少于已下单数量(" + lockedQuantity + "),该数量已下单");
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -304,7 +303,7 @@ public class CartServiceImpl implements CartService {
|
|
|
CartDTO cart = getCart(tableId);
|
|
CartDTO cart = getCart(tableId);
|
|
|
List<CartItemDTO> items = cart.getItems();
|
|
List<CartItemDTO> items = cart.getItems();
|
|
|
|
|
|
|
|
- // 检查是否有锁定数量,如果有则不允许删除
|
|
|
|
|
|
|
+ // 检查是否有已下单数量,如果有则不允许删除
|
|
|
CartItemDTO item = items.stream()
|
|
CartItemDTO item = items.stream()
|
|
|
.filter(i -> i.getCuisineId().equals(cuisineId))
|
|
.filter(i -> i.getCuisineId().equals(cuisineId))
|
|
|
.findFirst()
|
|
.findFirst()
|
|
@@ -313,7 +312,7 @@ public class CartServiceImpl implements CartService {
|
|
|
if (item != null) {
|
|
if (item != null) {
|
|
|
Integer lockedQuantity = item.getLockedQuantity();
|
|
Integer lockedQuantity = item.getLockedQuantity();
|
|
|
if (lockedQuantity != null && lockedQuantity > 0) {
|
|
if (lockedQuantity != null && lockedQuantity > 0) {
|
|
|
- throw new RuntimeException("商品已下单,锁定数量为 " + lockedQuantity + ",不允许删除");
|
|
|
|
|
|
|
+ throw new RuntimeException("商品已下单,已下单数量为 " + lockedQuantity + ",不允许删除");
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -335,30 +334,107 @@ public class CartServiceImpl implements CartService {
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public void clearCart(Integer tableId) {
|
|
public void clearCart(Integer tableId) {
|
|
|
- log.info("清空购物车, tableId={}", tableId);
|
|
|
|
|
- // 清空Redis
|
|
|
|
|
- String cartKey = CART_KEY_PREFIX + tableId;
|
|
|
|
|
- baseRedisService.delete(cartKey);
|
|
|
|
|
-
|
|
|
|
|
- // 清空数据库(逻辑删除)
|
|
|
|
|
- LambdaQueryWrapper<StoreCart> wrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
- wrapper.eq(StoreCart::getTableId, tableId);
|
|
|
|
|
- wrapper.eq(StoreCart::getDeleteFlag, 0);
|
|
|
|
|
- List<StoreCart> cartList = storeCartMapper.selectList(wrapper);
|
|
|
|
|
- if (cartList != null && !cartList.isEmpty()) {
|
|
|
|
|
- for (StoreCart cart : cartList) {
|
|
|
|
|
- cart.setDeleteFlag(1);
|
|
|
|
|
- cart.setUpdatedTime(new Date());
|
|
|
|
|
- storeCartMapper.updateById(cart);
|
|
|
|
|
|
|
+ log.info("清空购物车(保留已下单商品), tableId={}", tableId);
|
|
|
|
|
+
|
|
|
|
|
+ // 获取购物车
|
|
|
|
|
+ CartDTO cart = getCart(tableId);
|
|
|
|
|
+ List<CartItemDTO> items = cart.getItems();
|
|
|
|
|
+
|
|
|
|
|
+ if (items == null || items.isEmpty()) {
|
|
|
|
|
+ log.info("购物车为空,无需清空, tableId={}", tableId);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 分离已下单的商品和未下单的商品
|
|
|
|
|
+ List<CartItemDTO> orderedItems = new ArrayList<>(); // 已下单的商品(保留,数量恢复为已下单数量)
|
|
|
|
|
+ List<Integer> orderedCuisineIds = new ArrayList<>(); // 已下单的商品ID列表
|
|
|
|
|
+ List<CartItemDTO> unorderedItems = new ArrayList<>(); // 未下单的商品(删除)
|
|
|
|
|
+ boolean hasChanges = false; // 是否有变化(需要更新)
|
|
|
|
|
+
|
|
|
|
|
+ for (CartItemDTO item : items) {
|
|
|
|
|
+ Integer lockedQuantity = item.getLockedQuantity();
|
|
|
|
|
+ if (lockedQuantity != null && lockedQuantity > 0) {
|
|
|
|
|
+ // 有已下单数量,保留该商品,但将当前数量恢复为已下单数量
|
|
|
|
|
+ Integer currentQuantity = item.getQuantity();
|
|
|
|
|
+ if (currentQuantity != null && !currentQuantity.equals(lockedQuantity)) {
|
|
|
|
|
+ // 当前数量不等于已下单数量,需要恢复
|
|
|
|
|
+ item.setQuantity(lockedQuantity);
|
|
|
|
|
+ item.setSubtotalAmount(item.getUnitPrice().multiply(BigDecimal.valueOf(lockedQuantity)));
|
|
|
|
|
+ hasChanges = true;
|
|
|
|
|
+ log.info("恢复已下单商品数量, cuisineId={}, oldQuantity={}, orderedQuantity={}",
|
|
|
|
|
+ item.getCuisineId(), currentQuantity, lockedQuantity);
|
|
|
|
|
+ }
|
|
|
|
|
+ orderedItems.add(item);
|
|
|
|
|
+ orderedCuisineIds.add(item.getCuisineId());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 没有已下单数量,标记为删除
|
|
|
|
|
+ unorderedItems.add(item);
|
|
|
|
|
+ hasChanges = true;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // 更新桌号表的购物车统计
|
|
|
|
|
- StoreTable table = storeTableMapper.selectById(tableId);
|
|
|
|
|
- if (table != null) {
|
|
|
|
|
- table.setCartItemCount(0);
|
|
|
|
|
- table.setCartTotalAmount(BigDecimal.ZERO);
|
|
|
|
|
- storeTableMapper.updateById(table);
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 如果有变化(有未下单的商品需要删除,或者已下单商品数量需要恢复),进行更新
|
|
|
|
|
+ if (hasChanges) {
|
|
|
|
|
+ // 1. 更新购物车(删除未下单商品,已下单商品数量已恢复)
|
|
|
|
|
+ cart.setItems(orderedItems);
|
|
|
|
|
+ // 重新计算总金额和总数量(只计算保留的商品,数量已恢复为已下单数量)
|
|
|
|
|
+ BigDecimal totalAmount = orderedItems.stream()
|
|
|
|
|
+ .map(CartItemDTO::getSubtotalAmount)
|
|
|
|
|
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
|
|
+ Integer totalQuantity = orderedItems.stream()
|
|
|
|
|
+ .mapToInt(CartItemDTO::getQuantity)
|
|
|
|
|
+ .sum();
|
|
|
|
|
+ cart.setTotalAmount(totalAmount);
|
|
|
|
|
+ cart.setTotalQuantity(totalQuantity);
|
|
|
|
|
+
|
|
|
|
|
+ // 更新Redis(保留已下单的商品,数量已恢复)
|
|
|
|
|
+ if (orderedItems.isEmpty()) {
|
|
|
|
|
+ // 如果所有商品都未下单,清空Redis
|
|
|
|
|
+ String cartKey = CART_KEY_PREFIX + tableId;
|
|
|
|
|
+ baseRedisService.delete(cartKey);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 保存更新后的购物车到Redis(已下单商品数量已恢复为已下单数量)
|
|
|
|
|
+ saveCartToRedis(cart);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 从数据库中逻辑删除未下单的商品
|
|
|
|
|
+ if (!unorderedItems.isEmpty()) {
|
|
|
|
|
+ LambdaQueryWrapper<StoreCart> wrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ wrapper.eq(StoreCart::getTableId, tableId);
|
|
|
|
|
+ wrapper.eq(StoreCart::getDeleteFlag, 0);
|
|
|
|
|
+ if (!orderedCuisineIds.isEmpty()) {
|
|
|
|
|
+ // 排除已下单的商品ID
|
|
|
|
|
+ wrapper.notIn(StoreCart::getCuisineId, orderedCuisineIds);
|
|
|
|
|
+ }
|
|
|
|
|
+ List<StoreCart> cartListToDelete = storeCartMapper.selectList(wrapper);
|
|
|
|
|
+ if (cartListToDelete != null && !cartListToDelete.isEmpty()) {
|
|
|
|
|
+ List<Integer> cartIds = cartListToDelete.stream()
|
|
|
|
|
+ .map(StoreCart::getId)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+ // 使用 deleteBatchIds 进行逻辑删除(MyBatis-Plus 会自动处理 @TableLogic)
|
|
|
|
|
+ storeCartMapper.deleteBatchIds(cartIds);
|
|
|
|
|
+ log.info("删除未下单商品, tableId={}, count={}", tableId, cartIds.size());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 更新数据库中已下单商品的数量(恢复为已下单数量)
|
|
|
|
|
+ if (!orderedItems.isEmpty()) {
|
|
|
|
|
+ // 保存更新后的购物车到数据库(会更新已下单商品的数量)
|
|
|
|
|
+ saveCartToDatabase(cart);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 4. 更新桌号表的购物车统计
|
|
|
|
|
+ StoreTable table = storeTableMapper.selectById(tableId);
|
|
|
|
|
+ if (table != null) {
|
|
|
|
|
+ table.setCartItemCount(totalQuantity);
|
|
|
|
|
+ table.setCartTotalAmount(totalAmount);
|
|
|
|
|
+ storeTableMapper.updateById(table);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ log.info("清空购物车完成(保留已下单商品,数量恢复为已下单数量), tableId={}, 删除商品数={}, 保留商品数={}",
|
|
|
|
|
+ tableId, unorderedItems.size(), orderedItems.size());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ log.info("购物车无需更新, tableId={}", tableId);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -494,18 +570,18 @@ public class CartServiceImpl implements CartService {
|
|
|
String couponUsedKey = COUPON_USED_KEY_PREFIX + tableId;
|
|
String couponUsedKey = COUPON_USED_KEY_PREFIX + tableId;
|
|
|
baseRedisService.delete(couponUsedKey);
|
|
baseRedisService.delete(couponUsedKey);
|
|
|
|
|
|
|
|
- // 更新数据库(逻辑删除未下单的记录)
|
|
|
|
|
|
|
+ // 更新数据库(逻辑删除未下单的记录,使用 MyBatis-Plus 的 deleteBatchIds)
|
|
|
LambdaQueryWrapper<StoreCouponUsage> wrapper = new LambdaQueryWrapper<>();
|
|
LambdaQueryWrapper<StoreCouponUsage> wrapper = new LambdaQueryWrapper<>();
|
|
|
wrapper.eq(StoreCouponUsage::getTableId, tableId);
|
|
wrapper.eq(StoreCouponUsage::getTableId, tableId);
|
|
|
wrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
|
|
wrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
|
|
|
wrapper.eq(StoreCouponUsage::getUsageStatus, 0); // 只删除已标记使用但未下单的
|
|
wrapper.eq(StoreCouponUsage::getUsageStatus, 0); // 只删除已标记使用但未下单的
|
|
|
List<StoreCouponUsage> usageList = storeCouponUsageMapper.selectList(wrapper);
|
|
List<StoreCouponUsage> usageList = storeCouponUsageMapper.selectList(wrapper);
|
|
|
if (usageList != null && !usageList.isEmpty()) {
|
|
if (usageList != null && !usageList.isEmpty()) {
|
|
|
- for (StoreCouponUsage usage : usageList) {
|
|
|
|
|
- usage.setDeleteFlag(1);
|
|
|
|
|
- usage.setUpdatedTime(new Date());
|
|
|
|
|
- storeCouponUsageMapper.updateById(usage);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ List<Integer> usageIds = usageList.stream()
|
|
|
|
|
+ .map(StoreCouponUsage::getId)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+ // 使用 deleteBatchIds 进行逻辑删除(MyBatis-Plus 会自动处理 @TableLogic)
|
|
|
|
|
+ storeCouponUsageMapper.deleteBatchIds(usageIds);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 更新桌号表的优惠券ID
|
|
// 更新桌号表的优惠券ID
|
|
@@ -690,7 +766,7 @@ public class CartServiceImpl implements CartService {
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public CartDTO lockCartItems(Integer tableId) {
|
|
public CartDTO lockCartItems(Integer tableId) {
|
|
|
- log.info("锁定购物车商品数量, tableId={}", tableId);
|
|
|
|
|
|
|
+ log.info("锁定购物车商品数量(设置已下单数量), tableId={}", tableId);
|
|
|
|
|
|
|
|
// 获取购物车
|
|
// 获取购物车
|
|
|
CartDTO cart = getCart(tableId);
|
|
CartDTO cart = getCart(tableId);
|
|
@@ -701,7 +777,7 @@ public class CartServiceImpl implements CartService {
|
|
|
return cart;
|
|
return cart;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 遍历所有商品,将当前数量设置为锁定数量
|
|
|
|
|
|
|
+ // 遍历所有商品,将当前数量设置为已下单数量
|
|
|
boolean hasChanges = false;
|
|
boolean hasChanges = false;
|
|
|
for (CartItemDTO item : items) {
|
|
for (CartItemDTO item : items) {
|
|
|
Integer currentQuantity = item.getQuantity();
|
|
Integer currentQuantity = item.getQuantity();
|
|
@@ -709,16 +785,16 @@ public class CartServiceImpl implements CartService {
|
|
|
|
|
|
|
|
if (currentQuantity != null && currentQuantity > 0) {
|
|
if (currentQuantity != null && currentQuantity > 0) {
|
|
|
if (lockedQuantity == null || lockedQuantity == 0) {
|
|
if (lockedQuantity == null || lockedQuantity == 0) {
|
|
|
- // 如果还没有锁定数量,将当前数量设置为锁定数量
|
|
|
|
|
|
|
+ // 如果还没有已下单数量,将当前数量设置为已下单数量
|
|
|
item.setLockedQuantity(currentQuantity);
|
|
item.setLockedQuantity(currentQuantity);
|
|
|
hasChanges = true;
|
|
hasChanges = true;
|
|
|
- log.info("锁定商品数量, cuisineId={}, quantity={}", item.getCuisineId(), currentQuantity);
|
|
|
|
|
|
|
+ log.info("设置商品已下单数量, cuisineId={}, orderedQuantity={}", item.getCuisineId(), currentQuantity);
|
|
|
} else if (currentQuantity > lockedQuantity) {
|
|
} else if (currentQuantity > lockedQuantity) {
|
|
|
- // 如果已有锁定数量,且当前数量大于锁定数量(再次下单的情况),将新增数量累加到锁定数量
|
|
|
|
|
|
|
+ // 如果已有已下单数量,且当前数量大于已下单数量(再次下单的情况),将新增数量累加到已下单数量
|
|
|
Integer newLockedQuantity = lockedQuantity + (currentQuantity - lockedQuantity);
|
|
Integer newLockedQuantity = lockedQuantity + (currentQuantity - lockedQuantity);
|
|
|
item.setLockedQuantity(newLockedQuantity);
|
|
item.setLockedQuantity(newLockedQuantity);
|
|
|
hasChanges = true;
|
|
hasChanges = true;
|
|
|
- log.info("更新锁定商品数量, cuisineId={}, oldLockedQuantity={}, newLockedQuantity={}",
|
|
|
|
|
|
|
+ log.info("更新商品已下单数量, cuisineId={}, oldOrderedQuantity={}, newOrderedQuantity={}",
|
|
|
item.getCuisineId(), lockedQuantity, newLockedQuantity);
|
|
item.getCuisineId(), lockedQuantity, newLockedQuantity);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -768,13 +844,18 @@ public class CartServiceImpl implements CartService {
|
|
|
Date now = new Date();
|
|
Date now = new Date();
|
|
|
Integer userId = TokenUtil.getCurrentUserId();
|
|
Integer userId = TokenUtil.getCurrentUserId();
|
|
|
|
|
|
|
|
- // 1. 批量逻辑删除该桌号的所有购物车记录(使用批量更新,而不是循环单个更新)
|
|
|
|
|
- LambdaUpdateWrapper<StoreCart> deleteWrapper = new LambdaUpdateWrapper<>();
|
|
|
|
|
- deleteWrapper.eq(StoreCart::getTableId, cart.getTableId())
|
|
|
|
|
- .eq(StoreCart::getDeleteFlag, 0)
|
|
|
|
|
- .set(StoreCart::getDeleteFlag, 1)
|
|
|
|
|
- .set(StoreCart::getUpdatedTime, now);
|
|
|
|
|
- storeCartMapper.update(null, deleteWrapper);
|
|
|
|
|
|
|
+ // 1. 批量逻辑删除该桌号的所有购物车记录(使用 MyBatis-Plus 的 deleteBatchIds)
|
|
|
|
|
+ LambdaQueryWrapper<StoreCart> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ queryWrapper.eq(StoreCart::getTableId, cart.getTableId())
|
|
|
|
|
+ .eq(StoreCart::getDeleteFlag, 0);
|
|
|
|
|
+ List<StoreCart> existingCartList = storeCartMapper.selectList(queryWrapper);
|
|
|
|
|
+ if (existingCartList != null && !existingCartList.isEmpty()) {
|
|
|
|
|
+ List<Integer> cartIds = existingCartList.stream()
|
|
|
|
|
+ .map(StoreCart::getId)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+ // 使用 deleteBatchIds 进行逻辑删除(MyBatis-Plus 会自动处理 @TableLogic)
|
|
|
|
|
+ storeCartMapper.deleteBatchIds(cartIds);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
// 2. 批量插入新的购物车记录
|
|
// 2. 批量插入新的购物车记录
|
|
|
if (cart.getItems() != null && !cart.getItems().isEmpty()) {
|
|
if (cart.getItems() != null && !cart.getItems().isEmpty()) {
|