huliguo
2025-04-03 de40c5a7d03ffe9bcdb2aabe82e03aef98e94eb8
订单部分
12个文件已修改
257 ■■■■ 已修改文件
ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/vo/ConfirmOrderVo.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/vo/Price.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/factory/GoodsShopClientFallbackFactory.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/feignClient/GoodsShopClient.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/SysConfigFallbackFactory.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/feignClient/SysConfigClient.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysConfigController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/OrderController.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/OrderServiceImpl.java 176 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/GoodsShopController.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/SeckillActivityInfoController.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/GoodsServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
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("获取积分兑换比例配置失败");
        }