Explorar o código

积分分摊计算v1

lhm %!s(int64=3) %!d(string=hai) anos
pai
achega
d592150433

+ 9 - 0
kmall-admin/src/main/java/com/kmall/admin/dao/vip/Mall2PointsRulesDao.java

@@ -4,6 +4,7 @@ import com.kmall.admin.dto.Mall2RulesDto;
 import com.kmall.admin.entity.vip.Mall2PointsRulesEntity;
 import com.kmall.manager.dao.BaseDao;
 
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
 
@@ -18,4 +19,12 @@ public interface Mall2PointsRulesDao extends BaseDao<Mall2PointsRulesEntity> {
 
 
     Integer queryRulesDetilId(Long mkaId);
+
+    /**
+     * 查询当前时间的积分规则
+     *
+     * @param nowTime 当前时间
+     * @return 积分生成规则
+     */
+    List<Mall2PointsRulesEntity> queryListByTime(Date nowTime);
 }

+ 1 - 1
kmall-admin/src/main/java/com/kmall/admin/entity/vip/Mall2PointsRulesEntity.java

@@ -20,7 +20,7 @@ public class Mall2PointsRulesEntity implements Serializable {
      */
     private Integer mprId;
     /**
-     * 积分类型 :0.门店 ,1.商品类别,2.门店商品'
+     * 积分类型 :0.门店 ,1.商品类别,2.门店商品',数字越大,优先级越高
      */
     private Integer pointsType;
     /**

+ 32 - 0
kmall-admin/src/main/java/com/kmall/admin/haikong/constant/Constants.java

@@ -102,4 +102,36 @@ public class Constants {
         }
     }
 
+    /**
+     * 参与了限时特价的商品是否参与积分抵扣
+     */
+    public enum PromotionActivityRejectEnum {
+        /**
+         * 允许参加积分抵扣
+         */
+        ALLOW("0", "不互斥"),
+        /**
+         * 不允许参加积分抵扣
+         */
+        REJECT("1", "互斥"),
+        ;
+
+        private final String code;
+
+        private final String desc;
+
+        PromotionActivityRejectEnum(String code, String desc) {
+            this.code = code;
+            this.desc = desc;
+        }
+
+        public String getCode() {
+            return code;
+        }
+
+        public String getDesc() {
+            return desc;
+        }
+    }
+
 }

+ 2 - 0
kmall-admin/src/main/java/com/kmall/admin/haikong/task/MemberOrderSyncResendTask.java

@@ -20,6 +20,7 @@ import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 import java.util.Objects;
 
@@ -53,6 +54,7 @@ public class MemberOrderSyncResendTask {
             MemberOrderInfoSyncDTO memberOrderInfoSyncDTO = new MemberOrderInfoSyncDTO();
             BeanUtils.copyProperties(haiKongMemberOrderSyncResendEntity, memberOrderInfoSyncDTO);
             String body = JacksonUtil.toJson(memberOrderInfoSyncDTO);
+            haiKongMemberOrderSyncResendEntity.setLastResendTime(new Date());
             log.info("【重发】请求会员消费订单同步接口!请求体:{}", body);
             try {
                 String responseJson = haiKongMemberTemplate.changeMemberScore(body);

+ 4 - 2
kmall-admin/src/main/java/com/kmall/admin/haikong/task/MemberScoreChangeResendTask.java

@@ -19,6 +19,7 @@ import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 import java.util.Objects;
 
@@ -52,12 +53,13 @@ public class MemberScoreChangeResendTask {
             MemberScoreChangeDTO memberScoreChangeDTO = new MemberScoreChangeDTO();
             BeanUtils.copyProperties(haiKongMemberScoreChangeRecordEntity, memberScoreChangeDTO);
             String body = JacksonUtil.toJson(memberScoreChangeDTO);
+            haiKongMemberScoreChangeRecordEntity.setModifyTime(new Date());
             log.info("【重发】请求会员系统积分变动接口!请求体:{}", body);
             try {
                 String responseJson = haiKongMemberTemplate.changeMemberScore(body);
-                Response<MemberScoreChangeResponseDTO> response = JacksonUtil.fromListJson(responseJson, new TypeReference<Response<MemberScoreChangeResponseDTO>>() {});
+                Response<String> response = JacksonUtil.fromListJson(responseJson, new TypeReference<Response<String>>() {});
                 if (Objects.nonNull(response) && response.getSuccess()) {
-                    MemberScoreChangeResponseDTO responseData = response.getData();
+                    MemberScoreChangeResponseDTO responseData = JacksonUtil.fromStringJson(response.getData(), MemberScoreChangeResponseDTO.class);
                     haiKongMemberScoreChangeRecordEntity.setStatementId(responseData.getStatementId());
                     haiKongMemberScoreChangeRecordEntity.setResendStatus(HaiKongMemberOrderResendStatusEnum.RESEND_SUCCESS.getStatus());
                     successList.add(haiKongMemberScoreChangeRecordEntity);

+ 61 - 7
kmall-admin/src/main/java/com/kmall/admin/service/impl/OrderServiceImpl.java

@@ -3039,6 +3039,9 @@ public class OrderServiceImpl implements OrderService {
         memberOrderInfoSyncDTO.setOrderAmount(order.getActual_price());
         memberOrderInfoSyncDTO.setOrderScore(deductionScore);
         BeanUtils.copyProperties(memberOrderInfoSyncDTO, haiKongMemberOrderSyncResendEntity);
+        Date date = new Date();
+        haiKongMemberOrderSyncResendEntity.setCreateTime(date);
+        haiKongMemberOrderSyncResendEntity.setLastResendTime(date);
         try {
             String body = JacksonUtil.toJson(memberOrderInfoSyncDTO);
             LOGGER.info("请求会员系统同步消费订单接口!请求体:{}", body);
@@ -3078,6 +3081,9 @@ public class OrderServiceImpl implements OrderService {
         memberScoreChangeDTO.setOutBizNo(order.getOrder_sn());
         memberScoreChangeDTO.setScore(score);
         BeanUtils.copyProperties(memberScoreChangeDTO, haiKongMemberScoreChangeRecordEntity);
+        Date date = new Date();
+        haiKongMemberScoreChangeRecordEntity.setCreateTime(date);
+        haiKongMemberScoreChangeRecordEntity.setModifyTime(date);
         try {
             String body = JacksonUtil.toJson(memberScoreChangeDTO);
             LOGGER.info("请求会员系统积分变动接口!请求体:{}", body);
@@ -3988,7 +3994,7 @@ public class OrderServiceImpl implements OrderService {
         /*
          * 活动相关规则:
          * 1. 优先优惠券再去计算积分
-         * 2. 满赠的赠品商品在推送定时时零售价为0
+         * 2. 满赠的赠品商品在推送订单时零售价为0
          * 3. 任何活动都优先于积分计算
          * 4. 活动之间具有互斥性
          */
@@ -4011,6 +4017,9 @@ public class OrderServiceImpl implements OrderService {
         List<Integer> categoryIdList = goodsEntities.stream().map(GoodsEntity::getCategoryId).collect(Collectors.toList());
         // 活动互斥标识
         AtomicBoolean activityFlag = new AtomicBoolean(true);
+        // 限时特价活动标识
+        AtomicBoolean promotionActivityFlag = new AtomicBoolean(false);
+        List<String> promotionSkuList = new ArrayList<>();
         // 判断活动类型并排序,再确定购物栏中商品是否满足活动条件
         mkActivitiesEntityList.stream().sorted().forEach(mkActivitiesEntity -> {
             String mkaStoreId = mkActivitiesEntity.getMkaStoreId();
@@ -4034,6 +4043,11 @@ public class OrderServiceImpl implements OrderService {
                     String entityGoodsSn = mkActivitiesPromotionEntity.getSku();
                     BigDecimal activityPrice = mkActivitiesPromotionEntity.getActivityPrice();
                     String shopSn = mkActivitiesPromotionEntity.getShopSn();
+                    String rejectScore = mkActivitiesPromotionEntity.getRejectScore();
+                    // 如果与积分抵扣互斥的,记录sku
+                    if (!org.springframework.util.StringUtils.isEmpty(rejectScore) && Constants.PromotionActivityRejectEnum.REJECT.getCode().equals(rejectScore)) {
+                        promotionSkuList.add(entityGoodsSn);
+                    }
                     goodsEntities.forEach(goodsEntity -> {
                         String sku = goodsEntity.getSku();
                         String prodBarcode = goodsEntity.getProdBarcode();
@@ -4049,6 +4063,7 @@ public class OrderServiceImpl implements OrderService {
                             goodsDetailsDto.setDiscountedPrice(retailPrice.subtract(activityPrice));
                             goodsDetailsDtos.add(goodsDetailsDto);
                             activityFlag.set(false);
+                            promotionActivityFlag.set(true);
                         }
                     });
                 });
@@ -4279,7 +4294,7 @@ public class OrderServiceImpl implements OrderService {
                 Integer score = memberInfoDTO.getScore();
                 if (Objects.nonNull(score) && score > 0) {
                     // 有积分
-                    afterDiscountPrice = calculatePreferentialPrice(orderTotalPrice, score, storeId, memberCode, calculateOrderDiscountPriceResponseVO);
+                    afterDiscountPrice = calculatePreferentialPrice(orderTotalPrice, score, storeId, memberCode, calculateOrderDiscountPriceResponseVO, goodsDetailsDtos, promotionActivityFlag, promotionSkuList);
                     LOGGER.info("会员【{}】,当前积分:{},积分抵扣后的订单金额:{},积分抵扣前的订单金额:{}", memberCode, score, afterDiscountPrice, orderTotalPrice);
                     calculateOrderDiscountPriceResponseVO.setOrderTotalPrice(afterDiscountPrice);
                     calculateOrderDiscountPriceResponseVO.setGoodsDetailsDtos(goodsDetailsDtos);
@@ -4308,13 +4323,17 @@ public class OrderServiceImpl implements OrderService {
 
     /**
      * 计算积分抵扣后的订单总金额
-     * @param orderTotalPrice   订单商品详情
+     * @param orderTotalPrice   订单商品总价
      * @param score             积分
      * @param storeId           门店id
      * @param memberCode        会员码
+     * @param goodsDetailsDtos  订单商品详情
+     * @param calculateOrderDiscountPriceResponseVO 响应数据
+     * @param promotionActivityFlag 是否参与了积分抵扣活动
+     * @param promotionSkuList  参与了积分抵扣活动的sku集合
      * @return                  积分抵扣后的订单总金额
      */
-    private BigDecimal calculatePreferentialPrice(BigDecimal orderTotalPrice, Integer score, String storeId, String memberCode, CalculateOrderDiscountPriceResponseVO calculateOrderDiscountPriceResponseVO) {
+    private BigDecimal calculatePreferentialPrice(BigDecimal orderTotalPrice, Integer score, String storeId, String memberCode, CalculateOrderDiscountPriceResponseVO calculateOrderDiscountPriceResponseVO, List<GoodsDetailsDto> goodsDetailsDtos, AtomicBoolean promotionActivityFlag, List<String> promotionSkuList) {
         // 1. 判断是否有积分,是否需要计算积分抵扣后的价格
         AtomicBoolean isCalculateScorePrice = new AtomicBoolean(false);
         if (Objects.nonNull(score) && score > 0) {
@@ -4329,6 +4348,10 @@ public class OrderServiceImpl implements OrderService {
                 LOGGER.warn("用户【{}】的积分数量为:{},最低需要30积分才能抵扣!", memberCode, score);
                 return orderTotalPrice;
             } else {
+                // 积分取整
+                int scoreInteger = score % scoreLimit == 0 ? score : score - (score % scoreLimit);
+                // 积分的50%
+                int scoreIntegerHalf = scoreInteger * scoreLimit / 100;
                 // 3-2. 计算出积分能抵扣的价格
                 int scoreMayDeductionPrice = (int) (score / scoreLimit);
                 BigDecimal scoreMayDeductionPriceDecimal = new BigDecimal(scoreMayDeductionPrice);
@@ -4337,17 +4360,48 @@ public class OrderServiceImpl implements OrderService {
                     // 积分能抵扣的金额大于订单总额的50%,按50%抵扣
                     scoreMayDeductionPriceDecimal = halfPrice;
                 }
+                // 参与了积分抵扣活动,不互斥的情况下
+                if (promotionActivityFlag.get() && !CollectionUtils.isEmpty(promotionSkuList)) {
+                    BigDecimal shareScore = BigDecimal.ZERO;
+                    BigDecimal scoreIntegerDecimal = BigDecimal.valueOf(scoreInteger);
+                    BigDecimal scoreLimitDecimal = BigDecimal.valueOf(scoreLimit);
+                    BigDecimal goodsDetailScoreDeductionPrice = BigDecimal.ZERO;
+                    for (int i = 0; i < goodsDetailsDtos.size(); i++) {
+                        GoodsDetailsDto goodsDetailsDto = goodsDetailsDtos.get(i);
+                        // 抵扣积分分摊
+                        int index = goodsDetailsDtos.size() - 1;
+                        if (promotionSkuList.contains(goodsDetailsDto.getSku()) && i < index) {
+                            // 计算抵扣
+                            // 商品总价
+                            BigDecimal actualPaymentAmount = goodsDetailsDto.getActualPaymentAmount();
+                            BigDecimal scoreIntegerHalfDecimal = BigDecimal.valueOf(scoreIntegerHalf);
+                            // 分摊积分
+                            shareScore = shareScore.add(actualPaymentAmount.divide(scoreIntegerDecimal.multiply(scoreIntegerHalfDecimal), 2, BigDecimal.ROUND_HALF_UP));
+                            // 保留两位小数,四舍五入
+                            BigDecimal discountedPrice = shareScore.divide(scoreLimitDecimal, 2, BigDecimal.ROUND_HALF_UP);
+                            goodsDetailScoreDeductionPrice = goodsDetailScoreDeductionPrice.add(discountedPrice);
+                            goodsDetailsDto.setDiscountedPrice(discountedPrice);
+                        }
+                        if (i == index) {
+                            BigDecimal discountedPrice = scoreIntegerDecimal.subtract(shareScore).divide(scoreLimitDecimal, 2, BigDecimal.ROUND_HALF_UP);
+                            goodsDetailScoreDeductionPrice = goodsDetailScoreDeductionPrice.add(discountedPrice);
+                            goodsDetailsDto.setDiscountedPrice(discountedPrice);
+                        }
+                    }
+                    scoreMayDeductionPriceDecimal = goodsDetailScoreDeductionPrice;
+                }
+
                 orderTotalPrice = orderTotalPrice.subtract(scoreMayDeductionPriceDecimal);
-                int afterScore = score - scoreMayDeductionPriceDecimal.multiply(new BigDecimal(scoreLimit)).intValue();
+                int afterScore = score - scoreIntegerHalf;
                 calculateOrderDiscountPriceResponseVO.setAfterScore(afterScore);
                 calculateOrderDiscountPriceResponseVO.setScoreLimit(scoreLimit);
-                calculateOrderDiscountPriceResponseVO.setDeductionScore(score - afterScore);
+                calculateOrderDiscountPriceResponseVO.setDeductionScore(scoreIntegerHalf);
                 calculateOrderDiscountPriceResponseVO.setOrderTotalPrice(orderTotalPrice);
                 calculateOrderDiscountPriceResponseVO.setScoreDeductionPrice(scoreMayDeductionPriceDecimal);
                 LOGGER.info("会员【{}】,当前积分:{},抵扣订单金额后剩余积分:{}", memberCode, score, afterScore);
             }
         } else {
-            LOGGER.info("会员【{}】的积分为0,不参加积分抵扣!", memberCode);
+            LOGGER.info("会员【{}】的积分小于积分抵扣最低值,不参加积分抵扣!", memberCode);
         }
         return orderTotalPrice;
     }

+ 12 - 0
kmall-admin/src/main/java/com/kmall/admin/service/impl/vip/Mall2PointsRulesServiceImpl.java

@@ -9,6 +9,7 @@ import com.kmall.common.utils.Query;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -179,4 +180,15 @@ public class Mall2PointsRulesServiceImpl implements Mall2PointsRulesService {
                 break;
         }
     }
+
+    /**
+     * 查询当前时间的积分规则
+     *
+     * @param nowTime 当前时间
+     * @return 积分生成规则
+     */
+    @Override
+    public List<Mall2PointsRulesEntity> queryListByTime(Date nowTime) {
+        return mall2PointsRulesDao.queryListByTime(nowTime);
+    }
 }

+ 8 - 0
kmall-admin/src/main/java/com/kmall/admin/service/vip/Mall2PointsRulesService.java

@@ -5,6 +5,7 @@ import com.kmall.admin.entity.vip.Mall2DetilEntity;
 import com.kmall.admin.entity.vip.Mall2PointsRulesEntity;
 import com.kmall.common.utils.Query;
 
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
 
@@ -84,4 +85,11 @@ public interface Mall2PointsRulesService {
 
 
     void deleteDetil(Integer[] mprIds,Long typeId);
+
+    /**
+     * 查询当前时间的积分规则
+     * @param nowTime 当前时间
+     * @return        积分生成规则
+     */
+    List<Mall2PointsRulesEntity> queryListByTime(Date nowTime);
 }

+ 1 - 1
kmall-admin/src/main/resources/mybatis/mapper/StoreMngChangeDao.xml

@@ -152,7 +152,7 @@
 			`moder_sn`,
 			`mod_time`,
 			`tstm`,
-			order_sn))
+			order_sn)
 		values(
 			#{storeChangeNum},
 			#{storeOriginalNum},

+ 18 - 0
kmall-admin/src/main/resources/mybatis/mapper/vip/Mall2PointsRulesDao.xml

@@ -141,6 +141,24 @@
        select points_type from mall2_points_rules where mpr_id=#{mkaId}
 	</select>
 
+    <select id="queryListByTime" resultType="com.kmall.admin.entity.vip.Mall2PointsRulesEntity">
+		select
+    		`mpr_id`,
+    		`points_type`,
+			 points_rules_money as pointsRulesMoney,
+			 points_rules_num as pointsRulesNum,
+    		`points_begin_time`,
+    		`points_end_time`,
+		     points_proportion as pointsProportion,
+    		`is_valid`,
+    		`creater_sn`,
+    		`create_time`,
+    		`moder_sn`,
+    		`mod_time`,
+    		`tstm`
+    	from mall2_points_rules
+    	where points_begin_time &lt;= #{nowTime} and points_end_time &gt;= #{nowTime}
+	</select>
 
 
 </mapper>