Ver código fonte

【功能】完成下单确认页价格计算功能(只做了满减,还没做满送)

痴货 7 meses atrás
pai
commit
86b02b698a

+ 1 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java

@@ -46,6 +46,7 @@ public interface ErrorCodeConstants {
     ErrorCode REWARD_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1_013_006_003, "满减送活动未关闭,不能删除");
     ErrorCode REWARD_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_006_004, "满减送活动已关闭,不能重复关闭");
     ErrorCode REWARD_ACTIVITY_SCOPE_EXISTS = new ErrorCode(1_013_006_005, "与该时间段已存在的满减送活动商品范围冲突");
+    ErrorCode REWARD_ACTIVITY_TYPE_NOT_EXISTS = new ErrorCode(1_013_006_006, "满减送活动类型不存在");
 
     // ========== TODO 空着 1-013-007-000 ============
 

+ 2 - 1
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountProductMapper.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.promotion.dal.mysql.discount;
 
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import org.apache.ibatis.annotations.Mapper;
@@ -31,7 +32,7 @@ public interface DiscountProductMapper extends BaseMapperX<DiscountProductDO> {
     }
 
     // TODO @zhangshuai:逻辑里,尽量避免写 join 语句哈,你可以看看这个查询,有什么办法优化?目前的一个思路,是分 2 次查询,性能也是 ok 的
-    List<DiscountProductDO> getMatchDiscountProductList(@Param("skuIds") Collection<Long> skuIds);
+    List<DiscountProductRespDTO> getMatchDiscountProductList(@Param("skuIds") Collection<Long> skuIds);
 
     /**
      * 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号

+ 2 - 1
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityService.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.promotion.service.discount;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO;
 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO;
@@ -27,7 +28,7 @@ public interface DiscountActivityService {
      * @param skuIds SKU 编号数组
      * @return 匹配的限时折扣商品
      */
-    List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> skuIds);
+    List<DiscountProductRespDTO> getMatchDiscountProductList(Collection<Long> skuIds);
 
     /**
      * 创建限时折扣活动

+ 3 - 2
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImpl.java

@@ -6,6 +6,7 @@ import cn.hutool.core.map.MapUtil;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO;
 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO;
@@ -49,7 +50,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
     private DiscountProductMapper discountProductMapper;
 
     @Override
-    public List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> skuIds) {
+    public List<DiscountProductRespDTO> getMatchDiscountProductList(Collection<Long> skuIds) {
         return discountProductMapper.getMatchDiscountProductList(skuIds);
     }
 
@@ -130,7 +131,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
         List<DiscountProductDO> list = discountProductMapper.selectListByActivityId(id);
         // TODO @zhangshuai:一般简单的 stream 方法,建议是使用 CollectionUtils,例如说这里是 convertList 对把。
         List<Long> skuIds = list.stream().map(item -> item.getSkuId()).collect(Collectors.toList());
-        List<DiscountProductDO> matchDiscountProductList = getMatchDiscountProductList(skuIds);
+        List<DiscountProductRespDTO> matchDiscountProductList = getMatchDiscountProductList(skuIds);
         if (id != null) { // 排除自己这个活动
             matchDiscountProductList.removeIf(product -> id.equals(product.getActivityId()));
         }

+ 5 - 3
yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/discount/DiscountProductMapper.xml

@@ -3,8 +3,8 @@
 <mapper namespace="cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper">
 
 
-    <select id="getMatchDiscountProductList"   resultType="cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO">
-        SELECT pdp.*
+    <select id="getMatchDiscountProductList"   resultType="cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO">
+        SELECT pdp.*,pda.name as activity_name
         FROM promotion_discount_product pdp
         LEFT JOIN promotion_discount_activity pda
         ON pdp.activity_id = pda.id
@@ -17,8 +17,10 @@
             </if>
             AND pda.start_time &lt;= CURRENT_TIME AND pda.end_time &gt;= CURRENT_TIME
             AND pda.`status` = 0
-            AND pda.deleted != 1
+            AND pda.deleted =0
+            AND pdp.deleted = 0
         </where>
+        ORDER BY pdp.id DESC
     </select>
 
 </mapper>

+ 8 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementRespVO.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.trade.controller.app.order.vo;
 
 import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO;
+import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
 import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotNull;
 import lombok.AllArgsConstructor;
@@ -31,6 +32,13 @@ public class AppTradeOrderSettlementRespVO {
     @Schema(description = "总积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
     private Integer totalPoint;
 
+    /**
+     * 营销活动数组
+     *
+     * 只对应 {@link TradePriceCalculateRespBO.Price#items} 商品匹配的活动
+     */
+    private List<TradePriceCalculateRespBO.Promotion> promotions;
+
     @Schema(description = "购物项")
     @Data
     public static class Item {

+ 73 - 12
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDiscountActivityPriceCalculator.java

@@ -3,6 +3,10 @@ package cn.iocoder.yudao.module.trade.service.price.calculator;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.module.member.api.level.MemberLevelApi;
+import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO;
+import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
+import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
 import cn.iocoder.yudao.module.promotion.api.discount.DiscountActivityApi;
 import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO;
 import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum;
@@ -32,6 +36,10 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato
 
     @Resource
     private DiscountActivityApi discountActivityApi;
+    @Resource
+    private MemberLevelApi memberLevelApi;
+    @Resource
+    private MemberUserApi memberUserApi;
 
     @Override
     public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
@@ -39,6 +47,7 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato
         if (ObjectUtil.notEqual(result.getType(), TradeOrderTypeEnum.NORMAL.getType())) {
             return;
         }
+        //----------------------------------限时折扣计算-----------------------------------------
         // 获得 SKU 对应的限时折扣活动
         List<DiscountProductRespDTO> discountProducts = discountActivityApi.getMatchDiscountProductList(
                 convertSet(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSkuId));
@@ -47,27 +56,64 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato
         }
         Map<Long, DiscountProductRespDTO> discountProductMap = convertMap(discountProducts, DiscountProductRespDTO::getSkuId);
 
-        // 处理每个 SKU 的限时折扣
+
+
+        //----------------------------------会员计算-----------------------------------------
+
+        // 获得用户的会员等级
+        MemberUserRespDTO user = memberUserApi.getUser(param.getUserId());
+        if (user.getLevelId() == null || user.getLevelId() <= 0) {
+            return;
+        }
+        MemberLevelRespDTO level = memberLevelApi.getMemberLevel(user.getLevelId());
+        if (level == null || level.getDiscountPercent() == null) {
+            return;
+        }
+
+        // 2. 计算每个 SKU 的优惠金额
         result.getItems().forEach(orderItem -> {
-            // 1. 获取该 SKU 的优惠信息
+
+            //----------------------------------限时折扣计算-----------------------------------------
+
+            // 2.1  计算限时折扣优惠信息
             DiscountProductRespDTO discountProduct = discountProductMap.get(orderItem.getSkuId());
             if (discountProduct == null) {
                 return;
             }
-            // 2. 计算优惠金额
+            // 2.2 计算优惠金额
             Integer newPayPrice = calculatePayPrice(discountProduct, orderItem);
             Integer newDiscountPrice = orderItem.getPayPrice() - newPayPrice;
 
-            // 3.1 记录优惠明细
+
+            //----------------------------------会员计算-----------------------------------------
+
+            // 2.3 计算会员优惠金额
+            Integer vipPrice = calculateVipPrice(orderItem.getPayPrice(), level.getDiscountPercent());
+            if (vipPrice <= 0) {
+                return;
+            }
+
+            // 2.4 记录优惠明细
             if (orderItem.getSelected()) {
-                // 注意,只有在选中的情况下,才会记录到优惠明细。否则仅仅是更新 SKU 优惠金额,用于展示
-                TradePriceCalculatorHelper.addPromotion(result, orderItem,
-                        discountProduct.getActivityId(), discountProduct.getActivityName(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType(),
-                        StrUtil.format("限时折扣:省 {} 元", formatPrice(newDiscountPrice)),
-                        newDiscountPrice);
+                if(newDiscountPrice > vipPrice){
+                    // 注意,只有在选中的情况下,才会记录到优惠明细。否则仅仅是更新 SKU 优惠金额,用于展示
+                    TradePriceCalculatorHelper.addPromotion(result, orderItem,
+                            discountProduct.getActivityId(), discountProduct.getActivityName(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType(),
+                            StrUtil.format("限时折扣:省 {} 元", formatPrice(newDiscountPrice)),
+                            newDiscountPrice);
+                    // 2.5 更新 SKU 优惠金额
+                    orderItem.setDiscountPrice(orderItem.getDiscountPrice() + newDiscountPrice);
+                }else{
+                    // 注意,只有在选中的情况下,才会记录到优惠明细。否则仅仅是更新 SKU 优惠金额,用于展示
+                    TradePriceCalculatorHelper.addPromotion(result, orderItem,
+                            level.getId(), level.getName(), PromotionTypeEnum.MEMBER_LEVEL.getType(),
+                            String.format("会员等级折扣:省 %s 元", formatPrice(vipPrice)),
+                            vipPrice);
+                    // 2.5 更新 SKU 的优惠金额
+                    orderItem.setVipPrice(vipPrice);
+                }
             }
-            // 3.2 更新 SKU 优惠金额
-            orderItem.setDiscountPrice(orderItem.getDiscountPrice() + newDiscountPrice);
+
             TradePriceCalculatorHelper.recountPayPrice(orderItem);
         });
         TradePriceCalculatorHelper.recountAllPrice(result);
@@ -77,7 +123,7 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato
                                       TradePriceCalculateRespBO.OrderItem orderItem) {
         Integer price = orderItem.getPayPrice();
         if (PromotionDiscountTypeEnum.PRICE.getType().equals(discountProduct.getDiscountType())) { // 减价
-            price -= discountProduct.getDiscountPrice() * orderItem.getCount();
+            price -= discountProduct.getDiscountPrice() * 100 * orderItem.getCount();
         } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(discountProduct.getDiscountType())) { // 打折
             price = price * discountProduct.getDiscountPercent() / 100;
         } else {
@@ -86,4 +132,19 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato
         return price;
     }
 
+    /**
+     * 计算会员 VIP 优惠价格
+     *
+     * @param price 原价
+     * @param discountPercent 折扣
+     * @return 优惠价格
+     */
+    public Integer calculateVipPrice(Integer price, Integer discountPercent) {
+        if (discountPercent == null) {
+            return 0;
+        }
+        Integer newPrice = price * discountPercent / 100;
+        return price - newPrice;
+    }
+
 }

+ 41 - 36
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeMemberLevelPriceCalculator.java

@@ -30,44 +30,49 @@ public class TradeMemberLevelPriceCalculator implements TradePriceCalculator {
     @Resource
     private MemberUserApi memberUserApi;
 
+    /**
+     * 会员计算迁移到限时优惠计算里
+     * @param param
+     * @param result
+     */
     @Override
     public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
-        // 0. 只有【普通】订单,才计算该优惠
-        if (ObjectUtil.notEqual(result.getType(), TradeOrderTypeEnum.NORMAL.getType())) {
-            return;
-        }
-        // 1. 获得用户的会员等级
-        MemberUserRespDTO user = memberUserApi.getUser(param.getUserId());
-        if (user.getLevelId() == null || user.getLevelId() <= 0) {
-            return;
-        }
-        MemberLevelRespDTO level = memberLevelApi.getMemberLevel(user.getLevelId());
-        if (level == null || level.getDiscountPercent() == null) {
-            return;
-        }
-
-        // 2. 计算每个 SKU 的优惠金额
-        result.getItems().forEach(orderItem -> {
-            // 2.1 计算优惠金额
-            Integer vipPrice = calculateVipPrice(orderItem.getPayPrice(), level.getDiscountPercent());
-            if (vipPrice <= 0) {
-                return;
-            }
-
-            // 2.2 记录优惠明细
-            if (orderItem.getSelected()) {
-                // 注意,只有在选中的情况下,才会记录到优惠明细。否则仅仅是更新 SKU 优惠金额,用于展示
-                TradePriceCalculatorHelper.addPromotion(result, orderItem,
-                        level.getId(), level.getName(), PromotionTypeEnum.MEMBER_LEVEL.getType(),
-                        String.format("会员等级折扣:省 %s 元", formatPrice(vipPrice)),
-                        vipPrice);
-            }
-
-            // 2.3 更新 SKU 的优惠金额
-            orderItem.setVipPrice(vipPrice);
-            TradePriceCalculatorHelper.recountPayPrice(orderItem);
-        });
-        TradePriceCalculatorHelper.recountAllPrice(result);
+//        // 0. 只有【普通】订单,才计算该优惠
+//        if (ObjectUtil.notEqual(result.getType(), TradeOrderTypeEnum.NORMAL.getType())) {
+//            return;
+//        }
+//        // 1. 获得用户的会员等级
+//        MemberUserRespDTO user = memberUserApi.getUser(param.getUserId());
+//        if (user.getLevelId() == null || user.getLevelId() <= 0) {
+//            return;
+//        }
+//        MemberLevelRespDTO level = memberLevelApi.getMemberLevel(user.getLevelId());
+//        if (level == null || level.getDiscountPercent() == null) {
+//            return;
+//        }
+//
+//        // 2. 计算每个 SKU 的优惠金额
+//        result.getItems().forEach(orderItem -> {
+//            // 2.1 计算优惠金额
+//            Integer vipPrice = calculateVipPrice(orderItem.getPayPrice(), level.getDiscountPercent());
+//            if (vipPrice <= 0) {
+//                return;
+//            }
+//
+//            // 2.2 记录优惠明细
+//            if (orderItem.getSelected()) {
+//                // 注意,只有在选中的情况下,才会记录到优惠明细。否则仅仅是更新 SKU 优惠金额,用于展示
+//                TradePriceCalculatorHelper.addPromotion(result, orderItem,
+//                        level.getId(), level.getName(), PromotionTypeEnum.MEMBER_LEVEL.getType(),
+//                        String.format("会员等级折扣:省 %s 元", formatPrice(vipPrice)),
+//                        vipPrice);
+//            }
+//
+//            // 2.3 更新 SKU 的优惠金额
+//            orderItem.setVipPrice(vipPrice);
+//            TradePriceCalculatorHelper.recountPayPrice(orderItem);
+//        });
+//        TradePriceCalculatorHelper.recountAllPrice(result);
     }
 
     /**

+ 13 - 13
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculator.java

@@ -23,8 +23,10 @@ import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
+import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.REWARD_ACTIVITY_TYPE_NOT_EXISTS;
 import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice;
 
 // TODO @puhui999:相关的单测,建议改一改
@@ -53,9 +55,10 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator
         if (CollUtil.isEmpty(rewardActivities)) {
             return;
         }
-
-        // 处理每个满减送活动
-        rewardActivities.forEach(rewardActivity -> calculate(param, result, rewardActivity));
+        // 处理最新的满减送活动
+        if(!rewardActivities.isEmpty()){
+            calculate(param, result, rewardActivities.get(0));
+        }
     }
 
     private void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result,
@@ -120,27 +123,24 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator
     /**
      * 获得满减送的订单项(商品)列表
      *
-     * @param result         计算结果
+     * @param result 计算结果
      * @param rewardActivity 满减送活动
      * @return 订单项(商品)列表
      */
     private List<TradePriceCalculateRespBO.OrderItem> filterMatchActivityOrderItems(TradePriceCalculateRespBO result,
                                                                                     RewardActivityMatchRespDTO rewardActivity) {
-        // 情况一:全部商品都可以参与
-        if (PromotionProductScopeEnum.isAll(rewardActivity.getProductScope())) {
+        Integer productScope = rewardActivity.getProductScope();
+        if(PromotionProductScopeEnum.isAll(productScope)){
             return result.getItems();
-        }
-        // 情况二:指定商品参与
-        if (PromotionProductScopeEnum.isSpu(rewardActivity.getProductScope())) {
+        }else if (PromotionProductScopeEnum.isSpu(productScope)) {
             return filterList(result.getItems(),
                     orderItem -> CollUtil.contains(rewardActivity.getProductScopeValues(), orderItem.getSpuId()));
-        }
-        // 情况三:指定商品类型参与
-        if (PromotionProductScopeEnum.isCategory(rewardActivity.getProductScope())) {
+        }else if (PromotionProductScopeEnum.isCategory(productScope)) {
             return filterList(result.getItems(),
                     orderItem -> CollUtil.contains(rewardActivity.getProductScopeValues(), orderItem.getCategoryId()));
+        }else{
+            throw exception(REWARD_ACTIVITY_TYPE_NOT_EXISTS);
         }
-        return List.of();
     }
 
     /**