| | |
| | | import com.ruoyi.common.core.domain.R; |
| | | import com.ruoyi.common.core.exception.ServiceException; |
| | | import com.ruoyi.common.core.utils.GeodesyUtil; |
| | | import com.ruoyi.common.core.utils.StringUtils; |
| | | import com.ruoyi.common.core.utils.bean.BeanUtils; |
| | | import com.ruoyi.common.core.web.page.PageInfo; |
| | | import com.ruoyi.common.security.service.TokenService; |
| | | import com.ruoyi.other.api.domain.Phone; |
| | | import com.ruoyi.other.api.domain.Shop; |
| | | import com.ruoyi.other.api.domain.ShopScore; |
| | | import com.ruoyi.other.mapper.PhoneMapper; |
| | | import com.ruoyi.other.mapper.ShopMapper; |
| | | import com.ruoyi.other.mapper.ShopScoreMapper; |
| | | import com.ruoyi.other.service.ShopScoreService; |
| | | import com.ruoyi.other.service.ShopService; |
| | | import com.ruoyi.other.vo.NearbyShopVO; |
| | | import com.ruoyi.other.vo.SaveWithdrawalAccount; |
| | | import com.ruoyi.other.vo.ShopDetailVO; |
| | | import com.ruoyi.order.feignClient.OrderClient; |
| | | import com.ruoyi.order.vo.Price; |
| | | import com.ruoyi.other.api.domain.*; |
| | | import com.ruoyi.other.dto.AddGoodsDTO; |
| | | import com.ruoyi.other.enums.GoodsStatus; |
| | | import com.ruoyi.other.mapper.*; |
| | | import com.ruoyi.other.service.*; |
| | | import com.ruoyi.other.vo.*; |
| | | import com.ruoyi.system.api.domain.SysConfig; |
| | | import com.ruoyi.system.api.domain.SysUser; |
| | | import com.ruoyi.system.api.feignClient.SysConfigClient; |
| | | import com.ruoyi.system.api.feignClient.SysUserClient; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.time.LocalDateTime; |
| | | import java.util.*; |
| | | import java.util.function.Function; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | |
| | | @Resource |
| | | private ShopMapper shopMapper; |
| | | @Resource |
| | | private GoodsService goodsService; |
| | | @Resource |
| | | private PhoneMapper phoneMapper; |
| | | @Resource |
| | | private ShopScoreService shopScoreService; |
| | |
| | | private SysUserClient sysUserClient; |
| | | @Resource |
| | | private ShopScoreMapper scoreMapper; |
| | | @Resource |
| | | private ShopBalanceStatementMapper shopBalanceStatementMapper; |
| | | @Resource |
| | | private OrderClient orderClient; |
| | | @Resource |
| | | private SeckillActivityInfoService seckillActivityInfoService; |
| | | @Resource |
| | | private GoodsSeckillService goodsSeckillService; |
| | | @Resource |
| | | private SysConfigClient sysConfigClient; |
| | | @Resource |
| | | private GoodsShopMapper goodsShopMapper; |
| | | @Resource |
| | | private GoodsShopService goodsShopService; |
| | | @Resource |
| | | private GoodsEvaluateMapper goodsEvaluateMapper; |
| | | |
| | | |
| | | /** |
| | |
| | | } |
| | | |
| | | // 计算距离 |
| | | if (shopDetailVO.getLongitude() != null && shopDetailVO.getLatitude() != null){ |
| | | if (shopDetailVO.getLongitude() != null && shopDetailVO.getLatitude() != null |
| | | && longitude != null && latitude != null) { |
| | | String shopLocation = String.format("%s,%s", shopDetailVO.getLongitude(), shopDetailVO.getLatitude()); |
| | | String userLocation = String.format("%s,%s", longitude.toString(), latitude.toString()); |
| | | Map<String, Double> distanceMap = GeodesyUtil.getDistance(userLocation, shopLocation); |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 门店余额统计 |
| | | * @param shopId |
| | | * @return |
| | | */ |
| | | @Override |
| | | public ShopBalanceVO getShopBalance(Integer shopId) { |
| | | Shop shop = shopMapper.selectById(shopId); |
| | | ShopBalanceVO shopBalanceVO = new ShopBalanceVO(); |
| | | shopBalanceVO.setBalance(shop.getBalance()); |
| | | shopBalanceVO.setCanWithdrawMoney(shop.getCanWithdrawMoney()); |
| | | shopBalanceVO.setWithdrawMoney(shop.getWithdrawMoney()); |
| | | shopBalanceVO.setWithdrawAuditMoney(shop.getWithdrawAuditMoney()); |
| | | //冻结金额 = 余额 - 可提现金额 |
| | | shopBalanceVO.setFreezeMoney(shop.getBalance().subtract(shop.getCanWithdrawMoney())); |
| | | return shopBalanceVO; |
| | | } |
| | | |
| | | /** |
| | | * 门店余额变更明细 |
| | | */ |
| | | @Override |
| | | public PageInfo<ShopBalanceStatementVO> getShopBalanceStatementList(Integer shopId, LocalDateTime startTime, LocalDateTime endTime, Integer type, Integer pageCurr, Integer pageSize) { |
| | | PageInfo<ShopBalanceStatementVO> pageInfo = new PageInfo<>(pageCurr, pageSize); |
| | | List<ShopBalanceStatementVO> ShopBalanceStatementList = shopBalanceStatementMapper.getShopBalanceStatementList(pageInfo, shopId, startTime, endTime, type); |
| | | |
| | | for (ShopBalanceStatementVO shopBalanceStatementVO : ShopBalanceStatementList) { |
| | | log.error(shopBalanceStatementVO.toString()); |
| | | BigDecimal historicalBalance = shopBalanceStatementVO.getHistoricalBalance(); |
| | | BigDecimal balance = shopBalanceStatementVO.getBalance(); |
| | | if (historicalBalance != null && balance != null) { |
| | | shopBalanceStatementVO.setFlag( |
| | | historicalBalance.compareTo(balance) > 0 ? 2 : 1 |
| | | ); |
| | | } |
| | | } |
| | | pageInfo.setRecords(ShopBalanceStatementList); |
| | | return pageInfo; |
| | | } |
| | | |
| | | /** |
| | | * 店铺内商品列表 门店后台 |
| | | */ |
| | | @Override |
| | | public List<GoodsVO> getGoodsListByShopId(PageInfo<GoodsVO> pageInfo, Integer shopId) { |
| | | //查询该门店商品 |
| | | List<GoodsVO> goods = shopMapper.selectListByShopId(pageInfo, shopId); |
| | | if(null == goods){ |
| | | return null; |
| | | } |
| | | // 根据id去重 |
| | | List<GoodsVO> distinctGoods = goods.stream() |
| | | .collect(Collectors.collectingAndThen( |
| | | Collectors.toMap(GoodsVO::getGoodsId, Function.identity(), (existing, replacement) -> existing), |
| | | map -> new ArrayList<>(map.values()) |
| | | )); |
| | | for (GoodsVO good : distinctGoods) { |
| | | //价格 |
| | | Price price = getPrice( good.getGoodsId()); |
| | | if(null != price){ |
| | | //秒杀活动 |
| | | good.setSellingPrice(price.getCash()); |
| | | good.setIntegral(price.getPoint()); |
| | | good.setStartTime(price.getStartTime()); |
| | | good.setEndTime(price.getEndTime()); |
| | | good.setPurchaseLimit(price.getPurchaseLimit()); |
| | | } |
| | | Integer data = orderClient.getGoodsSaleNum(good.getGoodsId(), 1).getData(); |
| | | good.setSaleNum(data); |
| | | } |
| | | return distinctGoods; |
| | | } |
| | | |
| | | @Override |
| | | public GoodsVO goodsDetail(Long goodsId) { |
| | | if (goodsId == null || goodsId <= 0) { |
| | | throw new NullPointerException("商品ID不能为空"); |
| | | } |
| | | |
| | | Goods goods = goodsService.getById(goodsId); |
| | | if(null == goods || goods.getDelFlag() == 1){ |
| | | throw new RuntimeException("商品不存在"); |
| | | } |
| | | |
| | | GoodsVO goodsVO = new GoodsVO(); |
| | | BeanUtils.copyBeanProp(goodsVO, goods); |
| | | goodsVO.setGoodsId(goods.getId()); |
| | | goodsVO.setGoodsName(goods.getName()); |
| | | |
| | | //商品活动前售价(编辑商品回显) |
| | | goodsVO.setEditPrice(goods.getSellingPrice()); |
| | | //限购数量(编辑商品回显) |
| | | goodsVO.setEditNum(goods.getPurchaseLimit()); |
| | | |
| | | //计算所需价格和积分 |
| | | Price price = getPrice( goods.getId()); |
| | | if(null != price){ |
| | | //在秒杀活动时间段内 |
| | | goodsVO.setSellingPrice(price.getCash()); |
| | | goodsVO.setIntegral(price.getPoint()); |
| | | goodsVO.setStartTime(price.getStartTime()); |
| | | goodsVO.setEndTime(price.getEndTime()); |
| | | } |
| | | //已售数量 |
| | | Integer data = orderClient.getGoodsSaleNum(goods.getId(), 1).getData(); |
| | | goodsVO.setSaleNum(data); |
| | | //一个商品对应一个门店 |
| | | //查找门店 |
| | | GoodsShop goodsShop = goodsShopMapper.selectOne(new LambdaQueryWrapper<GoodsShop>() |
| | | .eq(GoodsShop::getGoodsId, goodsId)); |
| | | Shop shop1 = shopMapper.selectById(goodsShop.getShopId()); |
| | | goodsVO.setShop(shop1); |
| | | //已售数量 |
| | | Integer integer = orderClient.getGoodsSaleNum(goods.getId(), 1).getData(); |
| | | goodsVO.setSaleNum(integer); |
| | | //分类id |
| | | goodsVO.setGoodsCategoryId(goods.getGoodsCategoryId()); |
| | | |
| | | //一个商品只有一个秒杀活动 |
| | | SeckillActivityInfo seckillActivityInfo = seckillActivityInfoService.getOne(new LambdaQueryWrapper<SeckillActivityInfo>() |
| | | .eq(SeckillActivityInfo::getGoodId, goodsId) |
| | | .eq(SeckillActivityInfo::getIsShelves,1) |
| | | .eq(SeckillActivityInfo::getDelFlag, 0)); |
| | | //商品是否开启秒杀活动 |
| | | goodsVO.setIsSkillActivity(0); |
| | | if (seckillActivityInfo != null) { |
| | | goodsVO.setIsSkillActivity(1); |
| | | //活动限购数量 |
| | | goodsVO.setEditActivityNum(seckillActivityInfo.getMaxNum()); |
| | | GoodsSeckill one = goodsSeckillService.getOne(new LambdaQueryWrapper<GoodsSeckill>().eq(GoodsSeckill::getSeckillActivityInfoId, seckillActivityInfo.getId())); |
| | | //有秒杀活动,查看秒杀价格 |
| | | goodsVO.setEditActivityPrice(one.getSellingPrice()); |
| | | } |
| | | |
| | | //商品评价 |
| | | GoodsEvaluate goodsEvaluateOne = goodsEvaluateMapper.getGoodsEvaluateOne(goods.getId()); |
| | | AppUser appUserById = appUserClient.getAppUserById(goodsEvaluateOne.getAppUserId()); |
| | | goodsEvaluateOne.setUserName(appUserById.getName()); |
| | | goodsEvaluateOne.setAvatar(appUserById.getAvatar()); |
| | | goodsVO.setGoodsEvaluate(goodsEvaluateOne); |
| | | return goodsVO; |
| | | |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 发布商品 门店后台-商品管理 |
| | | */ |
| | | @Override |
| | | public Integer addGoodsByShop(AddGoodsDTO addGoodsDTO) { |
| | | if(addGoodsDTO.getPurchaseLimit()==null){ |
| | | addGoodsDTO.setPurchaseLimit(-1); |
| | | } |
| | | Goods goods = new Goods(); |
| | | BeanUtils.copyProperties(addGoodsDTO, goods); |
| | | goods.setSaleNum(0);//销量 |
| | | goods.setStatus(GoodsStatus.DOWN.getCode());//下架状态 |
| | | goods.setIntegral(getPoint(addGoodsDTO.getSellingPrice()));//积分 |
| | | goods.setDelFlag(0); |
| | | goods.setCreateTime(LocalDateTime.now()); |
| | | goodsService.save(goods);//添加商品 |
| | | //保存商品门店关系 |
| | | GoodsShop goodsShop = new GoodsShop(); |
| | | goodsShop.setGoodsId(goods.getId()); |
| | | goodsShop.setShopId(addGoodsDTO.getShopId()); |
| | | Shop shop = shopMapper.selectById(addGoodsDTO.getShopId()); |
| | | if(shop==null){ |
| | | throw new ServiceException("门店不存在"); |
| | | } |
| | | goodsShop.setShopName(shop.getName()); |
| | | goodsShop.setOwnerName(shop.getShopManager()); |
| | | goodsShop.setPhone(shop.getPhone()); |
| | | goodsShop.setAddress(shop.getAddress()); |
| | | goodsShopService.save(goodsShop); |
| | | //判断是否参加秒杀活动 |
| | | if (addGoodsDTO.getIsActivity()==1){ |
| | | //秒杀活动 |
| | | SeckillActivityInfo seckillActivityInfo = new SeckillActivityInfo(); |
| | | seckillActivityInfo.setDelFlag(0); |
| | | seckillActivityInfo.setCreateTime(LocalDateTime.now()); |
| | | seckillActivityInfo.setGoodId(goods.getId()); |
| | | seckillActivityInfo.setMaxNum(addGoodsDTO.getMaxNum()); |
| | | seckillActivityInfo.setStartTime(addGoodsDTO.getStartTime()); |
| | | seckillActivityInfo.setEndTime(addGoodsDTO.getEndTime()); |
| | | seckillActivityInfo.setIsShelves(1);//默认上架 |
| | | seckillActivityInfoService.save(seckillActivityInfo); |
| | | //秒杀活动价格 |
| | | GoodsSeckill goodsSeckill = new GoodsSeckill(); |
| | | goodsSeckill.setSellingPrice(addGoodsDTO.getActivityPrice()); |
| | | goodsSeckill.setIntegral(getPoint(addGoodsDTO.getActivityPrice())); |
| | | goodsSeckill.setSeckillActivityInfoId(seckillActivityInfo.getId()); |
| | | goodsSeckillService.save(goodsSeckill); |
| | | } |
| | | return goods.getId(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 编辑商品 |
| | | * @param addGoodsDTO |
| | | * @return |
| | | */ |
| | | |
| | | @Override |
| | | public Integer editGoodsByShop(AddGoodsDTO addGoodsDTO) { |
| | | if(addGoodsDTO.getPurchaseLimit()==null){ |
| | | addGoodsDTO.setPurchaseLimit(-1); |
| | | } |
| | | //先修改商品 |
| | | Goods goods = new Goods(); |
| | | BeanUtils.copyProperties(addGoodsDTO, goods); |
| | | goods.setStatus(GoodsStatus.DOWN.getCode());//下架状态 |
| | | goods.setId(addGoodsDTO.getGoodId()); |
| | | goods.setIntegral(getPoint(addGoodsDTO.getSellingPrice()));//积分 |
| | | goods.setDelFlag(0); |
| | | goods.setCreateTime(LocalDateTime.now()); |
| | | goodsService.updateById(goods);//添加商品 |
| | | |
| | | |
| | | //门店关系不变 |
| | | |
| | | //判断是否参加秒杀活动 |
| | | if (addGoodsDTO.getIsActivity()==1){//参加 |
| | | //一个商品只有一个秒杀活动 |
| | | SeckillActivityInfo seckillActivityInfo = seckillActivityInfoService.getOne(new LambdaQueryWrapper<SeckillActivityInfo>() |
| | | .eq(SeckillActivityInfo::getGoodId, addGoodsDTO.getGoodId()) |
| | | .eq(SeckillActivityInfo::getDelFlag, 0)); |
| | | if (seckillActivityInfo != null) { |
| | | //删除原本活动 |
| | | goodsSeckillService.remove(new LambdaQueryWrapper<GoodsSeckill>().eq(GoodsSeckill::getSeckillActivityInfoId, seckillActivityInfo.getId())); |
| | | //删除主表 |
| | | seckillActivityInfoService.removeById(seckillActivityInfo.getId()); |
| | | } |
| | | //新增 |
| | | //秒杀活动 |
| | | SeckillActivityInfo seckillActivityInfo1 = new SeckillActivityInfo(); |
| | | seckillActivityInfo1.setDelFlag(0); |
| | | seckillActivityInfo1.setCreateTime(LocalDateTime.now()); |
| | | seckillActivityInfo1.setGoodId(goods.getId()); |
| | | seckillActivityInfo1.setMaxNum(addGoodsDTO.getMaxNum()); |
| | | seckillActivityInfo1.setStartTime(addGoodsDTO.getStartTime()); |
| | | seckillActivityInfo1.setEndTime(addGoodsDTO.getEndTime()); |
| | | seckillActivityInfo1.setIsShelves(1);//默认上架 |
| | | seckillActivityInfoService.save(seckillActivityInfo1); |
| | | //秒杀活动价格 |
| | | GoodsSeckill goodsSeckill = new GoodsSeckill(); |
| | | goodsSeckill.setSellingPrice(addGoodsDTO.getActivityPrice()); |
| | | goodsSeckill.setIntegral(getPoint(addGoodsDTO.getActivityPrice())); |
| | | goodsSeckill.setSeckillActivityInfoId(seckillActivityInfo1.getId()); |
| | | goodsSeckillService.save(goodsSeckill); |
| | | }else{ |
| | | //不参加秒杀活动,删除之前的活动 |
| | | //一个商品只有一个秒杀活动 |
| | | SeckillActivityInfo seckillActivityInfo = seckillActivityInfoService.getOne(new LambdaQueryWrapper<SeckillActivityInfo>() |
| | | .eq(SeckillActivityInfo::getGoodId, addGoodsDTO.getGoodId()) |
| | | .eq(SeckillActivityInfo::getDelFlag, 0)); |
| | | if (seckillActivityInfo != null) { |
| | | //删除原本活动 |
| | | goodsSeckillService.remove(new LambdaQueryWrapper<GoodsSeckill>().eq(GoodsSeckill::getSeckillActivityInfoId, seckillActivityInfo.getId())); |
| | | //删除主表 |
| | | seckillActivityInfoService.removeById(seckillActivityInfo.getId()); |
| | | } |
| | | } |
| | | return goods.getId(); |
| | | } |
| | | |
| | | @Override |
| | | public PageInfo<ShopBalanceListVO> getBalanceList(String name, Integer pageCurr, Integer pageSize) { |
| | | PageInfo<ShopBalanceListVO> pageInfo = new PageInfo<>(pageCurr, pageSize); |
| | | |
| | | List<ShopBalanceListVO> list = shopMapper.getBalanceList(pageInfo,name); |
| | | |
| | | |
| | | pageInfo.setRecords(list); |
| | | return pageInfo; |
| | | } |
| | | |
| | | /** |
| | | * 获取商品当前的价格,就是看当前商品是否在秒杀活动中 |
| | | */ |
| | | public Price getPrice( Integer goodsId){ |
| | | //判断是否有在秒杀活动时间中 |
| | | Price price = new Price(); |
| | | SeckillActivityInfo one = seckillActivityInfoService.getOne(new LambdaQueryWrapper<SeckillActivityInfo>().eq(SeckillActivityInfo::getGoodId, goodsId) |
| | | .eq(SeckillActivityInfo::getIsShelves, 1).eq(SeckillActivityInfo::getDelFlag, 0) |
| | | .last(" and now() between start_time and end_time order by create_time desc limit 0, 1")); |
| | | GoodsSeckill goodsSeckill = null;//秒杀配置 |
| | | if(null != one){ |
| | | //有秒杀活动,查看秒杀价格 |
| | | goodsSeckill = goodsSeckillService.getOne(new LambdaQueryWrapper<GoodsSeckill>().eq(GoodsSeckill::getSeckillActivityInfoId, one.getId())); |
| | | } |
| | | //没有秒杀活动或者添加的普通商品则使用秒杀活动价格 |
| | | if(null == goodsSeckill ){ |
| | | return null; |
| | | } |
| | | //秒杀活动价格 |
| | | price.setCash(goodsSeckill.getSellingPrice()); |
| | | //计算对应积分 |
| | | price.setPoint(getPoint(price.getCash())); |
| | | price.setStartTime(one.getStartTime()); |
| | | price.setEndTime(one.getEndTime()); |
| | | price.setPurchaseLimit(one.getMaxNum()); |
| | | return price; |
| | | } |
| | | |
| | | /** |
| | | * 获取现金对应积分 |
| | | */ |
| | | public Integer getPoint(BigDecimal cash){ |
| | | if (cash == null || cash.compareTo(BigDecimal.ZERO) < 0) { |
| | | throw new IllegalArgumentException("金额不能为null或负数"); |
| | | } |
| | | // 获取积分兑换比例配置 |
| | | R<SysConfig> info = sysConfigClient.getInfo(6L); |
| | | if (info == null || info.getData() == null) { |
| | | throw new RuntimeException("获取积分兑换比例配置失败"); |
| | | } |
| | | String configValue = info.getData().getConfigValue(); |
| | | if (StringUtils.isBlank(configValue)) { |
| | | throw new RuntimeException("积分兑换比例配置值为空"); |
| | | } |
| | | try { |
| | | // 使用BigDecimal处理比例,避免精度问题 |
| | | BigDecimal ratio = new BigDecimal(configValue.trim()); |
| | | if (ratio.compareTo(BigDecimal.ZERO) <= 0) { |
| | | throw new RuntimeException("积分兑换比例必须大于0"); |
| | | } |
| | | |
| | | // 计算积分并四舍五入取整 |
| | | return cash.multiply(ratio).intValue(); |
| | | |
| | | } catch (NumberFormatException e) { |
| | | throw new RuntimeException("积分兑换比例配置值格式错误", e); |
| | | } catch (ArithmeticException e) { |
| | | throw new RuntimeException("积分计算结果溢出", e); |
| | | } |
| | | |
| | | } |
| | | } |