|
|
@@ -1,28 +1,40 @@
|
|
|
package com.fs.his.service.impl;
|
|
|
|
|
|
+import cn.hutool.json.JSONUtil;
|
|
|
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import com.fs.common.core.domain.R;
|
|
|
import com.fs.common.exception.CustomException;
|
|
|
-import com.fs.his.domain.FsIntegralCart;
|
|
|
-import com.fs.his.domain.FsIntegralGoods;
|
|
|
-import com.fs.his.domain.FsUser;
|
|
|
-import com.fs.his.mapper.FsIntegralCartMapper;
|
|
|
-import com.fs.his.mapper.FsIntegralGoodsMapper;
|
|
|
-import com.fs.his.mapper.FsUserMapper;
|
|
|
+import com.fs.common.exception.ServiceException;
|
|
|
+import com.fs.common.utils.StringUtils;
|
|
|
+import com.fs.common.utils.spring.SpringUtils;
|
|
|
+import com.fs.core.utils.OrderCodeUtils;
|
|
|
+import com.fs.his.domain.*;
|
|
|
+import com.fs.his.mapper.*;
|
|
|
+import com.fs.his.param.AddGoodsIntoCartParam;
|
|
|
+import com.fs.his.param.CreateOrderFromCartParm;
|
|
|
+import com.fs.his.param.GetFsIntegralCartDetailsParm;
|
|
|
+import com.fs.his.param.GetFsIntegralCartListParam;
|
|
|
import com.fs.his.service.IFsIntegralCartService;
|
|
|
-import com.fs.his.vo.FsIntegralCartVO;
|
|
|
+import com.fs.his.service.IFsUserIntegralLogsService;
|
|
|
+import com.fs.his.vo.*;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.lang3.ObjectUtils;
|
|
|
+import org.redisson.api.RLock;
|
|
|
+import org.redisson.api.RedissonClient;
|
|
|
+import org.springframework.beans.BeanUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.dao.DuplicateKeyException;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
import javax.validation.constraints.NotNull;
|
|
|
import java.time.LocalDateTime;
|
|
|
-import java.util.HashMap;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Map;
|
|
|
-import java.util.Objects;
|
|
|
+import java.util.*;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
@Slf4j
|
|
|
@Service
|
|
|
@@ -32,6 +44,14 @@ public class FsIntegralCartServiceImpl extends ServiceImpl<FsIntegralCartMapper,
|
|
|
private FsIntegralGoodsMapper goodsMapper;
|
|
|
@Resource
|
|
|
private FsUserMapper userMapper;
|
|
|
+ @Autowired
|
|
|
+ private FsUserAddressMapper fsUserAddressMapper;
|
|
|
+ @Autowired
|
|
|
+ private FsIntegralGoodsMapper fsIntegralGoodsMapper;
|
|
|
+ @Autowired
|
|
|
+ private FsIntegralOrderMapper fsIntegralOrderMapper;
|
|
|
+ @Autowired
|
|
|
+ IFsUserIntegralLogsService integralLogsService;
|
|
|
|
|
|
/**
|
|
|
* 添加或修改购物车
|
|
|
@@ -123,4 +143,197 @@ public class FsIntegralCartServiceImpl extends ServiceImpl<FsIntegralCartMapper,
|
|
|
params.put("ids", ids);
|
|
|
return baseMapper.getCartsByMap(params);
|
|
|
}
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<GetFsIntegralCartListVo> getFsIntegralCartList(GetFsIntegralCartListParam param, Long aLong) {
|
|
|
+ return baseMapper.getFsIntegralCartList(param, aLong, null);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取用户购物车详情页
|
|
|
+ *
|
|
|
+ * @param param
|
|
|
+ * @param userId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public GetFsIntegralCartDetailsVo getFsIntegralCartDetails(GetFsIntegralCartDetailsParm param, Long userId) {
|
|
|
+ List<GetFsIntegralCartListVo> cartListVoList = baseMapper.getFsIntegralCartList(new GetFsIntegralCartListParam(), userId, param.getCartId());
|
|
|
+ GetFsIntegralCartDetailsVo vos = new GetFsIntegralCartDetailsVo();
|
|
|
+ ArrayList<GetCartGoodsDetailsVo> goodsDetailsVos = new ArrayList<>();
|
|
|
+ for (GetFsIntegralCartListVo listVo : cartListVoList) {
|
|
|
+ GetCartGoodsDetailsVo cartListVo = new GetCartGoodsDetailsVo();
|
|
|
+ BeanUtils.copyProperties(listVo, cartListVo);
|
|
|
+ cartListVo.setGoodsIntegralTotal(listVo.getGoodsIntegral() * listVo.getQuantity());
|
|
|
+ goodsDetailsVos.add(cartListVo);
|
|
|
+ }
|
|
|
+ if (ObjectUtils.isNotEmpty(param.getAddressId())) {
|
|
|
+ FsUserAddress address = fsUserAddressMapper.selectFsUserAddressByAddressId(param.getAddressId());
|
|
|
+ vos.setUserName(address.getRealName());
|
|
|
+ vos.setUserAddress(address.getProvince() + address.getCity() + address.getDistrict() + address.getDetail());
|
|
|
+ vos.setUserPhone(address.getPhone());
|
|
|
+ vos.setAddressId(address.getAddressId());
|
|
|
+ }
|
|
|
+ vos.setUserId(cartListVoList.get(0).getUserId());
|
|
|
+ vos.setUserIntegral(cartListVoList.get(0).getUserIntegral());
|
|
|
+ vos.setGoodsIntegralTotal(goodsDetailsVos.stream().filter(n -> ObjectUtils.isNotEmpty(n.getGoodsIntegralTotal())).mapToLong(GetCartGoodsDetailsVo::getGoodsIntegralTotal).sum());
|
|
|
+ vos.setGoodsDetailsVoList(goodsDetailsVos);
|
|
|
+ return vos;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public Boolean addGoodsIntoCart(AddGoodsIntoCartParam param, Long userId) {
|
|
|
+ // 查询现有购物车项
|
|
|
+ FsIntegralCart existingCart = baseMapper.selectOne(Wrappers.<FsIntegralCart>lambdaQuery().eq(FsIntegralCart::getUserId, userId).eq(FsIntegralCart::getGoodsId, param.getGoodsId()));
|
|
|
+ int finalQuantity;
|
|
|
+ // 查询商品最新状态
|
|
|
+ FsIntegralGoods freshGoods = fsIntegralGoodsMapper.selectFsIntegralGoodsByGoodsId(param.getGoodsId());
|
|
|
+ if (freshGoods == null || freshGoods.getStatus() != 1) {
|
|
|
+ try {
|
|
|
+ int deleteCount = baseMapper.delete(Wrappers.<FsIntegralCart>lambdaQuery().eq(FsIntegralCart::getUserId, userId).eq(FsIntegralCart::getGoodsId, param.getGoodsId()));
|
|
|
+ log.info("清除下架商品,userId:{}, goodsId:{},清除数量:{}", userId, param.getGoodsId(), deleteCount);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("清除下架商品失败,userId:{}, goodsId:{}", userId, param.getGoodsId(), e);
|
|
|
+ }
|
|
|
+ throw new ServiceException(String.format("商品[名称:%d]不存在或已下架", freshGoods.getGoodsName()));
|
|
|
+ }
|
|
|
+ int maxAllowed = Math.min((int) freshGoods.getStock().longValue(), 99);
|
|
|
+ if (existingCart != null) {
|
|
|
+ // 先做校验
|
|
|
+ finalQuantity = existingCart.getCartNum() + param.getQuantity();
|
|
|
+ if (finalQuantity > maxAllowed) {
|
|
|
+ if (existingCart.getCartNum() >= maxAllowed) {
|
|
|
+ throw new ServiceException(String.format("商品已达最大购买数量%d件", maxAllowed));
|
|
|
+ }
|
|
|
+ int canAdd = maxAllowed - existingCart.getCartNum();
|
|
|
+ throw new ServiceException(String.format("最多还能购买%d件", canAdd));
|
|
|
+ }
|
|
|
+ int affectedRows = baseMapper.updateQuantityAtomically(userId, param.getGoodsId(), param.getQuantity(), maxAllowed);
|
|
|
+ if (affectedRows == 0) {
|
|
|
+ throw new ServiceException("添加失败,请重试");
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ } else {
|
|
|
+ // 新增购物车
|
|
|
+ if (param.getQuantity() > maxAllowed && param.getQuantity() > freshGoods.getStock()) {
|
|
|
+ throw new ServiceException(String.format("最多可购买%d件", freshGoods.getStock()));
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ FsIntegralCart newCart = FsIntegralCart.builder().userId(userId).goodsId(param.getGoodsId()).cartNum(param.getQuantity()).isSelected(param.getIsSelected()).build();
|
|
|
+ return this.save(newCart);
|
|
|
+ } catch (DuplicateKeyException e) {
|
|
|
+ log.info("购物车并发插入,转为更新,userId:{}, goodsId:{}", userId, param.getGoodsId());
|
|
|
+ int affectedRows = baseMapper.updateQuantityAtomically(userId, param.getGoodsId(), param.getQuantity(), maxAllowed);
|
|
|
+ return affectedRows > 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从购物车生成订单,兑换按钮(走的以前逻辑,没有重新设计)
|
|
|
+ *
|
|
|
+ * @param param
|
|
|
+ * @param userId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public R createOrderFromCart(CreateOrderFromCartParm param, Long userId) {
|
|
|
+ RedissonClient redissonClient = SpringUtils.getBean(RedissonClient.class);
|
|
|
+ String lockKey = "fsIntegralCartOrderCreate:" + userId;
|
|
|
+ RLock lock = redissonClient.getLock(lockKey);
|
|
|
+ try {
|
|
|
+ // 尝试获取锁,最多等待3秒,持有锁时间最多30秒
|
|
|
+ boolean isLocked = lock.tryLock(3, 10, TimeUnit.SECONDS);
|
|
|
+ if (!isLocked) {
|
|
|
+ return R.error("系统繁忙,请稍后再试");
|
|
|
+ }
|
|
|
+ FsUser user = userMapper.selectFsUserByUserId(userId);
|
|
|
+ FsUserAddress address = fsUserAddressMapper.selectFsUserAddressByAddressId(param.getAddressId());
|
|
|
+ List<FsIntegralGoodsVo> fsIntegralGoods = fsIntegralGoodsMapper.selectAllByGoodsIds(new HashSet<>(param.getGoodsId()));
|
|
|
+ List<FsIntegralCart> existingCart = baseMapper.selectList(Wrappers.<FsIntegralCart>lambdaQuery().eq(FsIntegralCart::getUserId, userId).in(FsIntegralCart::getGoodsId, param.getGoodsId()));
|
|
|
+ Map<Long, Integer> collect = existingCart.stream().collect(Collectors.groupingBy(FsIntegralCart::getGoodsId, Collectors.summingInt(FsIntegralCart::getCartNum)));
|
|
|
+ StringBuilder quantity = new StringBuilder();
|
|
|
+ for (FsIntegralGoodsVo fsIntegralGood : fsIntegralGoods) {
|
|
|
+ Integer integer = collect.get(fsIntegralGood.getGoodsId());
|
|
|
+ if (fsIntegralGood.getStock() < integer) {
|
|
|
+ throw new ServiceException(String.format("%d库存不足,兑换失败", fsIntegralGood.getGoodsName()));
|
|
|
+ }
|
|
|
+ if (fsIntegralGood.getStatus() != 1) {
|
|
|
+ this.remove(Wrappers.<FsIntegralCart>lambdaQuery().eq(FsIntegralCart::getUserId, userId).eq(FsIntegralCart::getGoodsId, fsIntegralGood.getGoodsId()));
|
|
|
+ log.info("清除下架商品,userId:{}, goodsId:{}", userId, fsIntegralGood.getGoodsId());
|
|
|
+ throw new ServiceException(String.format("商品[名称:%d]已下架,兑换失败", fsIntegralGood.getGoodsName()));
|
|
|
+ }
|
|
|
+ fsIntegralGood.setIntegralByNum(integer * fsIntegralGood.getIntegral());
|
|
|
+ fsIntegralGood.setQuantity(integer);
|
|
|
+ if (quantity.length() > 0) {
|
|
|
+ quantity.append(",");
|
|
|
+ }
|
|
|
+ quantity.append(ObjectUtils.isNotEmpty(integer) ? integer : "0");
|
|
|
+ }
|
|
|
+ // 商品总的积分
|
|
|
+ Long goodsIntegral = fsIntegralGoods.stream().filter(n -> ObjectUtils.isNotEmpty(n.getIntegralByNum())).mapToLong(FsIntegralGoodsVo::getIntegralByNum).sum();
|
|
|
+ if (user.getIntegral() < goodsIntegral) {
|
|
|
+ throw new ServiceException("用户积分不足,兑换失败");
|
|
|
+ }
|
|
|
+ String barCode = fsIntegralGoods.stream().map(FsIntegralGoodsVo::getBarCode).collect(Collectors.joining(","));
|
|
|
+ String Integral = fsIntegralGoods.stream().map(m -> m.getIntegral().toString()).collect(Collectors.joining(","));
|
|
|
+ String orderSn = OrderCodeUtils.getOrderSn();
|
|
|
+ if (StringUtils.isEmpty(orderSn)) {
|
|
|
+ throw new ServiceException("订单生成失败,请重试");
|
|
|
+ }
|
|
|
+ FsIntegralOrder order = new FsIntegralOrder();
|
|
|
+ order.setOrderCode(orderSn);
|
|
|
+ order.setUserId(user.getUserId());
|
|
|
+ order.setStatus(1);
|
|
|
+ order.setBarCodeCart(barCode);
|
|
|
+ order.setIntegral(goodsIntegral.toString());
|
|
|
+ order.setIntegralByCart(Integral);
|
|
|
+ order.setItemCartJson(ObjectUtils.isNotEmpty(fsIntegralGoods) ? JSONUtil.toJsonStr(fsIntegralGoods) : null);
|
|
|
+ order.setUserName(address.getRealName());
|
|
|
+ order.setUserAddress(address.getProvince() + address.getCity() + address.getDistrict() + address.getDetail());
|
|
|
+ order.setUserPhone(address.getPhone());
|
|
|
+ order.setCreateTime(new Date());
|
|
|
+ order.setQuantityCart(quantity.toString());
|
|
|
+ if (fsIntegralOrderMapper.insertFsIntegralOrder(order) > 0) {
|
|
|
+ //写入日志
|
|
|
+ FsUser userMap = new FsUser();
|
|
|
+ userMap.setUserId(user.getUserId());
|
|
|
+ // 可消费积分
|
|
|
+ long consumer = user.getIntegral() - user.getWithdrawIntegral();
|
|
|
+ if (consumer < goodsIntegral) {
|
|
|
+ // 扣除完可消费积分后,剩余的积分
|
|
|
+ long extra = goodsIntegral - consumer;
|
|
|
+ // 可提现积分扣除 剩余积分
|
|
|
+ Long withdrawIntegral = user.getWithdrawIntegral() - extra;
|
|
|
+ userMap.setIntegral(withdrawIntegral);
|
|
|
+ userMap.setWithdrawIntegral(withdrawIntegral);
|
|
|
+ } else {
|
|
|
+ userMap.setIntegral(user.getIntegral() - goodsIntegral);
|
|
|
+ }
|
|
|
+ userMapper.updateFsUser(userMap);
|
|
|
+ FsUserIntegralLogs logs = new FsUserIntegralLogs();
|
|
|
+ logs.setIntegral(-goodsIntegral);
|
|
|
+ logs.setUserId(order.getUserId());
|
|
|
+ logs.setBalance(userMap.getIntegral());
|
|
|
+ logs.setLogType(5);
|
|
|
+ logs.setBusinessId(order.getOrderId().toString());
|
|
|
+ logs.setCreateTime(new Date());
|
|
|
+ logs.setNickName(user.getNickName());
|
|
|
+ logs.setPhone(user.getPhone());
|
|
|
+ integralLogsService.insertFsUserIntegralLogs(logs);
|
|
|
+ //清空购物车对应商品
|
|
|
+ this.remove(Wrappers.<FsIntegralCart>lambdaQuery().eq(FsIntegralCart::getUserId, userId).in(FsIntegralCart::getGoodsId, param.getGoodsId()));
|
|
|
+ return R.ok("兑换成功").put("order", order);
|
|
|
+ } else {
|
|
|
+ return R.error("订单创建失败");
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ return R.error(e.getMessage());
|
|
|
+ } finally {
|
|
|
+ if (lock.isHeldByCurrentThread()) {
|
|
|
+ lock.unlock();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|