ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/vo/ConfirmOrderVo.java
@@ -19,7 +19,7 @@ private Integer goodId; @ApiModelProperty("商品名称") private Integer goodName; private String goodName; @ApiModelProperty("商品封面图") @@ -28,9 +28,12 @@ @ApiModelProperty("售价现金") private BigDecimal cash; @ApiModelProperty("划线价格") private String originalPrice; private BigDecimal originalPrice; @ApiModelProperty("购买数量") private Integer number; @ApiModelProperty("限购数量") private Integer purchaseLimitNum; @ApiModelProperty("核销门店") private String shopName; @@ -54,5 +57,10 @@ @ApiModelProperty("支付方式(1=现金,2=积分,3=混合)") private Integer paymentType; @ApiModelProperty("是否超出限购数量") private Boolean IsPurchaseLimit; @ApiModelProperty("结束时间戳") private Long endTimeStamp; } ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/vo/Price.java
@@ -20,9 +20,13 @@ */ private LocalDateTime startTime; /** * 获取开始时间 * 获取结束时间 */ private LocalDateTime endTime; /** * 获取结束时间戳 */ private Long endTimeStamp; /** * 现金支付 ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/factory/GoodsShopClientFallbackFactory.java
@@ -19,7 +19,7 @@ public GoodsShopClient create(Throwable cause) { return new GoodsShopClient() { @Override public R<GoodsShop> getGoodsShop(GoodsShop goodsShop) { public R<GoodsShop> getGoodsShop(Integer goodsId) { return R.fail("获取商品门店关系数据失败:" + cause.getMessage()); } ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/feignClient/GoodsShopClient.java
@@ -6,6 +6,8 @@ import com.ruoyi.other.api.factory.GoodsShopClientFallbackFactory; import com.ruoyi.other.api.vo.GetGoodsShopByGoodsIds; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -17,20 +19,18 @@ */ @FeignClient(contextId = "GoodsShopClient", value = ServiceNameConstants.OTHER_SERVICE, fallbackFactory = GoodsShopClientFallbackFactory.class) public interface GoodsShopClient { /** * 获取商品门店关系数据 * @param goodsShop * @return */ @PostMapping("/goods-shop/getGoodsShop") R<GoodsShop> getGoodsShop(@RequestBody GoodsShop goodsShop); /** * 根据商品id集合和门店id查询数据 * @param goodsIds * @return */ @PostMapping("/goods-shop/getGoodsShopByGoodsIds") @GetMapping("/goods-shop/getGoodsShopByGoodsIds") R<List<GoodsShop>> getGoodsShopByGoodsIds(@RequestBody GetGoodsShopByGoodsIds goodsIds); /** * 根据id获取门店信息 */ @GetMapping ("/goods-shop/getGoodsShop/{goodsId}") R<GoodsShop> getGoodsShop(@PathVariable("goodsId") Integer goodsId); } ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/SysConfigFallbackFactory.java
@@ -17,7 +17,7 @@ public SysConfigClient create(Throwable cause) { return new SysConfigClient(){ @Override public R<SysConfig> getInfo(String configId) { public R<SysConfig> getInfo(Long configId) { System.out.println(cause.getMessage()); return R.fail("获取系统配置失败:" + cause.getMessage()); } ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/feignClient/SysConfigClient.java
@@ -16,6 +16,6 @@ @FeignClient(contextId = "SysConfigClient", value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = SysConfigFallbackFactory.class) public interface SysConfigClient { @GetMapping(value = "config/{configId}") R<SysConfig> getInfo(@PathVariable("configId") String configId); R<SysConfig> getInfo(@PathVariable("configId") Long configId); } ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysConfigController.java
@@ -50,7 +50,7 @@ * 根据参数编号获取详细信息 */ @GetMapping(value = "/{configId}") public R getInfo(@PathVariable Long configId) { public R getInfo(@PathVariable("configId") Long configId) { return R.ok(configService.selectConfigById(configId)); } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/OrderController.java
@@ -72,9 +72,9 @@ @ResponseBody @PostMapping("/confirmOrder") @GetMapping("/confirmOrder") @ApiOperation(value = "确定订单", tags = {"商城-订单-小程序"}) public R<ConfirmOrderVo> confirmOrder(@ApiParam("商品id") Integer goodId,@ApiParam("支付类型")Integer type) { public R<ConfirmOrderVo> confirmOrder(@ApiParam("商品id") Integer goodId,@ApiParam("支付类型(1-现金,2-积分)")Integer type) { ConfirmOrderVo confirmOrderVo = orderService.confirmOrder(goodId,type); return R.ok(confirmOrderVo); } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/OrderServiceImpl.java
@@ -27,6 +27,7 @@ import com.ruoyi.order.mapper.OrderMapper; import com.ruoyi.order.model.Order; import com.ruoyi.order.model.OrderGood; import com.ruoyi.order.service.OrderGoodService; import com.ruoyi.order.service.OrderService; import com.ruoyi.order.util.ExpressDeliveryUtil; import com.ruoyi.order.util.payment.PaymentUtil; @@ -37,7 +38,10 @@ import com.ruoyi.order.vo.*; import com.ruoyi.other.api.domain.*; import com.ruoyi.other.api.feignClient.*; import com.ruoyi.other.api.vo.GetSeckillActivityInfo; 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 com.ruoyi.system.api.model.LoginUser; import lombok.SneakyThrows; @@ -98,6 +102,14 @@ @Resource private GoodsClient goodsClient; @Resource private SeckillActivityInfoClient seckillActivityInfoClient; @Resource private SysConfigClient sysConfigClient; @Resource private GoodsShopClient goodsShopClient; @Resource private OrderGoodService orderGoodService; @Resource private RedisTemplate redisTemplate; @@ -622,16 +634,172 @@ //用户信息 Long userid = tokenService.getLoginUserApplet().getUserid(); AppUser appUser = appUserClient.getAppUserById(userid); //商品信息 //获取商品信息 Goods good = goodsClient.getGoodsById(goodId).getData(); if (null == good) { if (null == good||good.getDelFlag()==1||good.getStatus()==0) { //商品不存在 throw new ServiceException("商品不存在"); } //店铺信息 //查询店铺信息 //计算价格信息 GoodsShop shop = goodsShopClient.getGoodsShop(goodId).getData(); System.out.println(shop); if (null == shop){ //门店不存在 throw new ServiceException("该商品门店不存在"); } //插入基础信息 confirmOrderVo.setGoodId(goodId); confirmOrderVo.setGoodName(good.getName()); confirmOrderVo.setHomePicture(good.getHomePagePicture()); confirmOrderVo.setNumber(1); confirmOrderVo.setShopId(shop.getShopId()); confirmOrderVo.setShopName(shop.getShopName()); confirmOrderVo.setPurchaseLimitNum(good.getPurchaseLimit()); confirmOrderVo.setOriginalPrice(good.getOriginalPrice()); //todo 实时计算用户可用积分 confirmOrderVo.setResidualPoint(appUser.getAvailablePoint()); //插入价格 confirmOrderVo.setCash(good.getSellingPrice()); confirmOrderVo.setPoint(good.getIntegral()); //计算活动价格信息 Price price = getPrice(goodId, 1); if (null != price) { confirmOrderVo.setCash(price.getCash()); confirmOrderVo.setOrderPoint(price.getPoint()); confirmOrderVo.setEndTimeStamp(price.getEndTimeStamp()); } //判断是否是积分支付 if (type == 1) {//现金 confirmOrderVo.setOrderMoney(confirmOrderVo.getCash()); //计算积分抵扣的金额 将积分转为金额,去掉小数 BigDecimal deduction=getCashByPoint(confirmOrderVo.getResidualPoint()); confirmOrderVo.setDeduction(deduction); }else {//积分 confirmOrderVo.setOrderPoint(good.getIntegral()); } //限购检查 //判断当前数量是否已经超出限购数量(需要计算已经购买的数量) if(null == good.getPurchaseLimit() || -1 == good.getPurchaseLimit()){ confirmOrderVo.setIsPurchaseLimit(false); confirmOrderVo.setPurchaseLimitNum(-1); }else{ //todo 查当前用户的订单 List<Order> orders = this.list(new LambdaQueryWrapper<Order>().eq(Order::getAppUserId, appUser.getId()).eq(Order::getDelFlag, 0).in(Order::getOrderStatus, Arrays.asList(4, 8))); List<Long> orderIds = orders.stream().map(Order::getId).collect(Collectors.toList()); int sum = 0; if(!orderIds.isEmpty()){ //关于该商品的订单 List<OrderGood> orderGoodList = orderGoodService.list(new LambdaQueryWrapper<OrderGood>().in(OrderGood::getOrderId, orderIds) .eq(OrderGood::getGoodsId, good.getId()).eq(OrderGood::getDelFlag, 0)); sum = orderGoodList.stream().mapToInt(OrderGood::getNum).sum(); } confirmOrderVo.setIsPurchaseLimit((1 + sum) > good.getPurchaseLimit()); confirmOrderVo.setPurchaseLimitNum(good.getPurchaseLimit() - sum); } return confirmOrderVo; } /** * 根据商品的价格配置体系获取商品当前的价格 * @param goodsId * @param type 1普通商品,2秒杀商品 * @return */ public Price getPrice( Integer goodsId, Integer type){ //判断是否有在秒杀活动时间中 Price price = new Price(); GetSeckillActivityInfo getSeckillActivityInfo = new GetSeckillActivityInfo(); getSeckillActivityInfo.setGoodsId(goodsId); GoodsSeckill goodsSeckill = seckillActivityInfoClient.getSeckillActivityInfo(getSeckillActivityInfo).getData(); //没有秒杀活动或者添加的普通商品则使用秒杀活动价格 if(null == goodsSeckill || type == 1){ return null; } //秒杀活动价格 price.setCash(goodsSeckill.getSellingPrice()); //计算对应积分 price.setPoint(getPoint(price.getCash())); price.setEndTimeStamp(goodsSeckill.getEndTime()); 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); } } /** * 获取积分对应金额 */ public BigDecimal getCashByPoint(Integer point){ // 参数校验 if (point == null || point < 0) { throw new IllegalArgumentException("积分值不能为null或负数"); } // 特殊情况:0积分直接返回0金额 if (point == 0) { return BigDecimal.ZERO.setScale(2); } // 获取积分兑换比例配置 R<SysConfig> info = sysConfigClient.getInfo(6L); if (info == null || info.getData() == null) { throw new RuntimeException("获取积分兑换比例配置失败"); } String configValue = info.getData().getConfigValue(); // 示例:"100" 表示 100积分=1元 if (StringUtils.isBlank(configValue)) { throw new RuntimeException("积分兑换比例配置值为空"); } try { // 解析兑换比例(转换为BigDecimal保证精度) BigDecimal exchangeRate = new BigDecimal(configValue.trim()); if (exchangeRate.compareTo(BigDecimal.ZERO) <= 0) { throw new RuntimeException("积分兑换比例必须为正数"); } // 高精度计算(积分/比例) return new BigDecimal(point) .divide(exchangeRate, 2, RoundingMode.HALF_UP); } catch (NumberFormatException e) { throw new RuntimeException("积分兑换比例配置值格式错误,应为数字", e); } catch (ArithmeticException e) { throw new RuntimeException("积分计算错误", e); } } } ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/GoodsShopController.java
@@ -8,9 +8,11 @@ import com.ruoyi.common.core.web.page.TableDataInfo; import com.ruoyi.other.api.domain.Goods; import com.ruoyi.other.api.domain.GoodsShop; import com.ruoyi.other.api.domain.Shop; import com.ruoyi.other.api.vo.GetGoodsShopByGoodsIds; import com.ruoyi.other.service.GoodsService; import com.ruoyi.other.service.GoodsShopService; import com.ruoyi.other.service.ShopService; import com.ruoyi.other.vo.ShopGoodsList; import com.ruoyi.other.vo.ShopGoodsListVo; import io.swagger.annotations.ApiOperation; @@ -33,6 +35,8 @@ @Resource private GoodsShopService goodsShopService; @Resource private ShopService shopService; @Resource private GoodsService goodsService; @@ -40,14 +44,18 @@ /** * 获取商品门店关系数据 * @param goodsShop * @return */ @ResponseBody @PostMapping("/getGoodsShop") public R<GoodsShop> getGoodsShop(@RequestBody GoodsShop goodsShop){ GoodsShop one = goodsShopService.getOne(new LambdaQueryWrapper<GoodsShop>().eq(GoodsShop::getGoodsId, goodsShop.getGoodsId()) .eq(GoodsShop::getShopId, goodsShop.getShopId())); @GetMapping("/getGoodsShop/{goodsId}") public R<GoodsShop> getGoodsShop(@PathVariable("goodsId") Integer goodsId) { GoodsShop one = goodsShopService.getOne(new LambdaQueryWrapper<GoodsShop>().eq(GoodsShop::getGoodsId,goodsId)); Shop shop = shopService.getOne(new LambdaQueryWrapper<Shop>().eq(Shop::getId, one.getShopId())); if (shop == null || shop.getStatus() ==2 || shop.getDelFlag()==1) { return R.ok(); } one.setShopName(shop.getName()); one.setPhone(shop.getPhone()); one.setAddress(shop.getAddress()); return R.ok(one); } ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/SeckillActivityInfoController.java
@@ -83,16 +83,19 @@ /** * 根据商品id和会员等级获取对应的秒杀活动 * 根据商品id获取对应的秒杀活动 */ @PostMapping("/getSeckillActivityInfo") public R<GoodsSeckill> getSeckillActivityInfo(@RequestBody GetSeckillActivityInfo info){ SeckillActivityInfo one = seckillActivityInfoService.getOne(new LambdaQueryWrapper<SeckillActivityInfo>().eq(SeckillActivityInfo::getGoodId, info.getGoodsId()) .eq(SeckillActivityInfo::getDelFlag, 0).eq(SeckillActivityInfo::getIsShelves, 1).last(" and now() between start_time and end_time order by create_time limit 0,1")); SeckillActivityInfo one = seckillActivityInfoService.getOne(new LambdaQueryWrapper<SeckillActivityInfo>() .eq(SeckillActivityInfo::getGoodId, info.getGoodsId()) .eq(SeckillActivityInfo::getDelFlag, 0) .eq(SeckillActivityInfo::getIsShelves, 1) .last(" and now() between start_time and end_time order by create_time limit 0,1")); if(null == one){ return R.ok(); } GoodsSeckill goodsSeckill = goodsSeckillService.getOne(new LambdaQueryWrapper<GoodsSeckill>().eq(GoodsSeckill::getSeckillActivityInfoId, one.getId()).eq(GoodsSeckill::getVip, info.getVip())); GoodsSeckill goodsSeckill = goodsSeckillService.getOne(new LambdaQueryWrapper<GoodsSeckill>().eq(GoodsSeckill::getSeckillActivityInfoId, one.getId())); if(null != goodsSeckill){ LocalDateTime endTime = one.getEndTime(); // 转时间戳 ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/GoodsServiceImpl.java
@@ -366,7 +366,7 @@ throw new IllegalArgumentException("金额不能为null或负数"); } // 获取积分兑换比例配置 R<SysConfig> info = sysConfigClient.getInfo("6"); R<SysConfig> info = sysConfigClient.getInfo(6L); if (info == null || info.getData() == null) { throw new RuntimeException("获取积分兑换比例配置失败"); }