diff --git a/sql/mysql/point.sql b/sql/mysql/point.sql
new file mode 100644
index 000000000..44123ea1b
--- /dev/null
+++ b/sql/mysql/point.sql
@@ -0,0 +1,6 @@
+ALTER TABLE trade_order ADD COLUMN use_point int NOT NULL DEFAULT 0 COMMENT '使用的积分' AFTER point_price;
+ALTER TABLE trade_order ADD COLUMN refund_point int NOT NULL DEFAULT 0 COMMENT '退还的使用积分' AFTER use_point;
+ALTER TABLE trade_order ADD COLUMN give_point int NOT NULL DEFAULT 0 COMMENT '赠送的积分' AFTER refund_point;
+
+ALTER TABLE trade_order_item ADD COLUMN use_point int NOT NULL DEFAULT 0 COMMENT '使用的积分' AFTER point_price;
+ALTER TABLE trade_order_item ADD COLUMN give_point int NOT NULL DEFAULT 0 COMMENT '赠送的积分' AFTER use_point;
diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java
index ab93431f4..b6b6b996d 100644
--- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java
+++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java
@@ -110,6 +110,11 @@ public class ProductSpuRespDTO {
// ========== 物流相关字段 =========
+ /**
+ * 赠送积分
+ */
+ private Integer giveIntegral;
+
/**
* 物流配置模板编号
*
diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionTypeEnum.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionTypeEnum.java
index 874651ea3..65af63406 100644
--- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionTypeEnum.java
+++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionTypeEnum.java
@@ -23,7 +23,8 @@ public enum PromotionTypeEnum implements IntArrayValuable {
REWARD_ACTIVITY(5, "满减送"),
MEMBER(6, "会员折扣"),
- COUPON(7, "优惠劵")
+ COUPON(7, "优惠劵"),
+ POINT(8, "积分")
;
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PromotionTypeEnum::getType).toArray();
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java
index bb68fc1ac..f7a03a52b 100644
--- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java
@@ -265,9 +265,13 @@ public class TradeOrderDO extends BaseDO {
* 对应 taobao 的 trade.point_fee 字段
*/
private Integer pointPrice;
-// /**
-// * 奖励的积分 TODO 疯狂:可以使用这个字段哈;
-// */
-// private Integer rewardPoint;
+ /**
+ * 赠送的积分
+ */
+ private Integer givePoint;
+ /**
+ * 退还的使用的积分
+ */
+ private Integer refundPoint;
}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java
index 27dd13f67..77b455344 100644
--- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java
@@ -143,6 +143,14 @@ public class TradeOrderItemDO extends BaseDO {
* 对应 taobao 的 trade.point_fee 字段
*/
private Integer pointPrice;
+ /**
+ * 使用的积分
+ */
+ private Integer usePoint;
+ /**
+ * 赠送的积分
+ */
+ private Integer givePoint;
// TODO @芋艿:如果商品 vip 折扣时,到底是新增一个 vipPrice 记录优惠记录,还是 vipDiscountPrice,记录 vip 的优惠;还是直接使用 vipPrice;
// 目前 crmeb 的选择,单独一个 vipPrice 记录优惠价格;感觉不一定合理,可以在看看有赞的;
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
index c4f1677e5..e2ff20c7c 100644
--- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
@@ -24,6 +24,7 @@ import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
+import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.promotion.api.bargain.BargainRecordApi;
import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
@@ -48,8 +49,8 @@ import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
import cn.iocoder.yudao.module.trade.enums.order.*;
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
import cn.iocoder.yudao.module.trade.framework.order.core.annotations.TradeOrderLog;
-import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageRecordService;
+import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
import cn.iocoder.yudao.module.trade.service.cart.CartService;
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
import cn.iocoder.yudao.module.trade.service.message.TradeMessageService;
@@ -105,6 +106,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
@Resource
private TradeMessageService tradeMessageService;
+ @Resource
+ private ProductSpuApi productSpuApi;
@Resource
private ProductSkuApi productSkuApi;
@Resource
@@ -240,8 +243,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
/**
* 订单创建前,执行前置逻辑
*
- * @param userId 用户编号
- * @param createReqVO 创建订单请求
+ * @param userId 用户编号
+ * @param createReqVO 创建订单请求
* @param calculateRespBO 订单价格计算结果
*/
private void beforeCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
@@ -260,12 +263,12 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
/**
* 订单创建后,执行后置逻辑
- *
+ *
* 例如说:优惠劵的扣减、积分的扣减、支付单的创建等等
*
* @param userId 用户编号
* @param createReqVO 创建订单请求
- * @param order 交易订单
+ * @param order 交易订单
* @param calculateRespBO 订单价格计算结果
*/
private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
@@ -283,12 +286,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
.setOrderId(order.getId()));
}
- // 3. 扣减积分
+ // 3. 扣减积分(抵扣)
// 不在前置扣减的原因,是因为积分扣减时,需要记录关联业务
- if (order.getUsePoint() != null && order.getUsePoint() > 0) {
- memberPointApi.reducePoint(userId, calculateRespBO.getUsePoint(),
- MemberPointBizTypeEnum.ORDER_USE.getType(), String.valueOf(order.getId()));
- }
+ reduceUserPoint(order.getUserId(), order.getUsePoint(), MemberPointBizTypeEnum.ORDER_USE, order.getId());
// 4. 删除购物车商品
Set cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId);
@@ -342,8 +342,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
// TODO 芋艿:OrderLog
- // 增加用户积分
- getSelf().addUserPointAsync(order.getUserId(), order.getPayPrice(), order.getId());
+ // 增加用户积分(赠送)
+ addUserPoint(order.getUserId(), order.getGivePoint(), MemberPointBizTypeEnum.ORDER_REWARD, order.getId());
// 增加用户经验
getSelf().addUserExperienceAsync(order.getUserId(), order.getPayPrice(), order.getId());
// 增加用户佣金
@@ -640,11 +640,12 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
return;
}
// 计算总的退款金额
- TradeOrderDO order = tradeOrderMapper.selectById(tradeOrderItemMapper.selectById(id).getOrderId());
+ TradeOrderItemDO orderItem = tradeOrderItemMapper.selectById(id);
+ TradeOrderDO order = tradeOrderMapper.selectById(orderItem.getOrderId());
Integer orderRefundPrice = order.getRefundPrice() + refundPrice;
if (isAllOrderItemAfterSaleSuccess(order.getId())) { // 如果都售后成功,则需要取消订单
tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId())
- .setRefundStatus(TradeOrderRefundStatusEnum.ALL.getStatus()).setRefundPrice(orderRefundPrice)
+ .setRefundStatus(TradeOrderRefundStatusEnum.ALL.getStatus()).setRefundPrice(orderRefundPrice).setRefundPoint(order.getRefundPoint() + orderItem.getUsePoint())
.setCancelType(TradeOrderCancelTypeEnum.AFTER_SALE_CLOSE.getType()).setCancelTime(LocalDateTime.now()));
// TODO 芋艿:记录订单日志
@@ -655,12 +656,17 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
.setRefundStatus(TradeOrderRefundStatusEnum.PART.getStatus()).setRefundPrice(orderRefundPrice));
}
- // 扣减用户积分
- getSelf().reduceUserPointAsync(order.getUserId(), orderRefundPrice, afterSaleId);
- // 扣减用户经验
- getSelf().reduceUserExperienceAsync(order.getUserId(), orderRefundPrice, afterSaleId);
- // 更新分佣记录为已失效
- getSelf().cancelBrokerageAsync(order.getUserId(), id);
+ // 售后成功后,执行数据回滚逻辑
+ if (Objects.equals(newAfterSaleStatus, TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus())) {
+ // 扣减用户积分(赠送的)
+ reduceUserPoint(order.getUserId(), orderItem.getGivePoint(), MemberPointBizTypeEnum.AFTER_SALE_DEDUCT_GIVE, afterSaleId);
+ // 增加用户积分(返还抵扣)
+ addUserPoint(order.getUserId(), orderItem.getUsePoint(), MemberPointBizTypeEnum.AFTER_SALE_REFUND_USED, afterSaleId);
+ // 扣减用户经验
+ getSelf().reduceUserExperienceAsync(order.getUserId(), orderRefundPrice, afterSaleId);
+ // 更新分佣记录为已失效
+ getSelf().cancelBrokerageAsync(order.getUserId(), id);
+ }
}
@Override
@@ -728,8 +734,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
// 3.回滚优惠券
couponApi.returnUsedCoupon(order.getCouponId());
- // 4.回滚积分:积分是支付成功后才增加的吧? 回复:每个项目不同,目前看下来,确认收货貌似更合适,我再看看其它项目的业务选择;
- // TODO @疯狂:有赞是可配置(支付 or 确认收货),我们按照支付好列;然后这里的退积分,指的是下单时的积分抵扣。
+ // 4.回滚积分(抵扣的)
+ addUserPoint(order.getUserId(), order.getUsePoint(), MemberPointBizTypeEnum.ORDER_CANCEL, order.getId());
// TODO 芋艿:OrderLog
@@ -760,18 +766,16 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
memberLevelApi.addExperience(userId, -refundPrice, bizType, String.valueOf(afterSaleId));
}
- @Async
- protected void addUserPointAsync(Long userId, Integer payPrice, Long orderId) {
- // TODO @疯狂:具体多少积分,需要分成 2 不分:1. 支付金额;2. 商品金额
- int bizType = MemberPointBizTypeEnum.ORDER_REWARD.getType();
- memberPointApi.addPoint(userId, payPrice, bizType, String.valueOf(orderId));
+ protected void addUserPoint(Long userId, Integer point, MemberPointBizTypeEnum bizType, Long bizId) {
+ if (point != null && point > 0) {
+ memberPointApi.addPoint(userId, point, bizType.getType(), String.valueOf(bizId));
+ }
}
- @Async
- protected void reduceUserPointAsync(Long userId, Integer refundPrice, Long afterSaleId) {
- // TODO @疯狂:退款时,按照金额比例,退还积分;https://help.youzan.com/displaylist/detail_4_4-1-49185
- int bizType = MemberPointBizTypeEnum.ORDER_CANCEL.getType();
- memberPointApi.addPoint(userId, -refundPrice, bizType, String.valueOf(afterSaleId));
+ protected void reduceUserPoint(Long userId, Integer point, MemberPointBizTypeEnum bizType, Long bizId) {
+ if (point != null && point > 0) {
+ memberPointApi.reducePoint(userId, point, bizType.getType(), String.valueOf(bizId));
+ }
}
@Async
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java
index e211374bf..a6982c177 100644
--- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java
@@ -41,7 +41,6 @@ public class TradePriceServiceImpl implements TradePriceService {
@Resource
private List priceCalculators;
- // TODO @疯狂:需要搞个 TradePriceCalculator,计算赠送积分;
@Override
public TradePriceCalculateRespBO calculatePrice(TradePriceCalculateReqBO calculateReqBO) {
// 1.1 获得商品 SKU 数组
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java
index 67019a49a..a908a93b9 100644
--- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java
@@ -29,7 +29,7 @@ public class TradePriceCalculateReqBO {
* 对应 CouponDO 的 id 编号
*/
private Long couponId;
- // TODO @疯狂:需要增加一个 PriceCalculator 实现积分扣减的计算;写回到 TradePriceCalculateRespBO 的 usePoint
+
/**
* 是否使用积分
*/
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java
index 1171cd8f2..786c478bc 100644
--- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java
@@ -53,6 +53,11 @@ public class TradePriceCalculateRespBO {
*/
private Integer usePoint;
+ /**
+ * 使用的积分
+ */
+ private Integer givePoint;
+
/**
* 订单价格
*/
@@ -158,6 +163,10 @@ public class TradePriceCalculateRespBO {
* 对应 taobao 的 trade.point_fee 字段
*/
private Integer pointPrice;
+ /**
+ * 使用的积分
+ */
+ private Integer usePoint;
/**
* 应付金额(总),单位:分
*
@@ -205,6 +214,11 @@ public class TradePriceCalculateRespBO {
*/
private List properties;
+ /**
+ * 使用的积分
+ */
+ private Integer givePoint;
+
}
/**
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointGiveCalculator.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointGiveCalculator.java
new file mode 100644
index 000000000..4fb2b2d7b
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointGiveCalculator.java
@@ -0,0 +1,62 @@
+package cn.iocoder.yudao.module.trade.service.price.calculator;
+
+import cn.hutool.core.util.BooleanUtil;
+import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
+import cn.iocoder.yudao.module.member.api.point.MemberPointApi;
+import cn.iocoder.yudao.module.member.api.point.dto.MemberPointConfigRespDTO;
+import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
+import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Optional;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
+
+/**
+ * 赠送积分的 {@link TradePriceCalculator} 实现类
+ *
+ * @author owen
+ */
+@Component
+@Order(TradePriceCalculator.ORDER_POINT_GIVE)
+@Slf4j
+public class TradePointGiveCalculator implements TradePriceCalculator {
+ @Resource
+ private MemberPointApi memberPointApi;
+
+ @Override
+ public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
+ // 1.1 校验积分功能是否开启
+ int givePointPerYuan = Optional.ofNullable(memberPointApi.getConfig())
+ .filter(config -> BooleanUtil.isTrue(config.getTradeDeductEnable()))
+ .map(MemberPointConfigRespDTO::getTradeGivePoint)
+ .orElse(0);
+ if (givePointPerYuan <= 0) {
+ return;
+ }
+ // 1.2 校验支付金额
+ if (result.getPrice().getPayPrice() <= 0) {
+ return;
+ }
+
+ // 2.1 计算赠送积分
+ int givePoint = MoneyUtils.calculateRatePriceFloor(result.getPrice().getPayPrice(), (double) givePointPerYuan);
+ // 2.2 计算分摊的赠送积分
+ List orderItems = filterList(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSelected);
+ List dividePoints = TradePriceCalculatorHelper.dividePrice(orderItems, givePoint);
+
+ // 3.2 更新 SKU 赠送积分
+ for (int i = 0; i < orderItems.size(); i++) {
+ TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i);
+ // 商品可能赠送了积分,所以这里要加上
+ orderItem.setGivePoint(orderItem.getGivePoint() + dividePoints.get(i));
+ TradePriceCalculatorHelper.recountPayPrice(orderItem);
+ }
+ // 3.3 更新订单赠送积分
+ TradePriceCalculatorHelper.recountAllGivePoint(result);
+ }
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculator.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculator.java
index 6bd479802..b2fd10572 100644
--- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculator.java
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculator.java
@@ -1,11 +1,25 @@
package cn.iocoder.yudao.module.trade.service.price.calculator;
+import cn.hutool.core.util.BooleanUtil;
+import cn.hutool.core.util.NumberUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.module.member.api.point.MemberPointApi;
+import cn.iocoder.yudao.module.member.api.point.dto.MemberPointConfigRespDTO;
+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.enums.common.PromotionTypeEnum;
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
+import javax.annotation.Resource;
+import java.math.RoundingMode;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
+
/**
* 使用积分的 {@link TradePriceCalculator} 实现类
*
@@ -15,15 +29,81 @@ import org.springframework.stereotype.Component;
@Order(TradePriceCalculator.ORDER_POINT_USE)
@Slf4j
public class TradePointUsePriceCalculator implements TradePriceCalculator {
+ @Resource
+ private MemberPointApi memberPointApi;
+ @Resource
+ private MemberUserApi memberUserApi;
@Override
public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
- // TODO 疯狂:待实现,嘿嘿;
- if (param.getPointStatus()) {
- result.setUsePoint(10);
- } else {
+ // 1.1 校验是否使用积分
+ if (!BooleanUtil.isTrue(param.getPointStatus())) {
result.setUsePoint(0);
+ return;
}
+ // 1.2 校验积分抵扣是否开启
+ MemberPointConfigRespDTO config = memberPointApi.getConfig();
+ if (!checkDeductPointEnable(config)) {
+ return;
+ }
+ // 1.3 校验用户积分余额
+ MemberUserRespDTO user = memberUserApi.getUser(param.getUserId());
+ if (user.getPoint() == null || user.getPoint() < 0) {
+ return;
+ }
+
+ // 2.1 计算积分优惠金额
+ int pointPrice = calculatePointPrice(config, user.getPoint(), result);
+ // 2.1 计算分摊的积分、抵扣金额
+ List orderItems = filterList(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSelected);
+ List dividePointPrices = TradePriceCalculatorHelper.dividePrice(orderItems, pointPrice);
+ List divideUsePoints = TradePriceCalculatorHelper.dividePrice(orderItems, result.getUsePoint());
+
+ // 3.1 记录优惠明细
+ TradePriceCalculatorHelper.addPromotion(result, orderItems,
+ param.getUserId(), "积分抵扣", PromotionTypeEnum.POINT.getType(),
+ StrUtil.format("积分抵扣:省 {} 元", TradePriceCalculatorHelper.formatPrice(pointPrice)),
+ dividePointPrices);
+ // 3.2 更新 SKU 优惠金额
+ for (int i = 0; i < orderItems.size(); i++) {
+ TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i);
+ orderItem.setPointPrice(dividePointPrices.get(i));
+ orderItem.setUsePoint(divideUsePoints.get(i));
+ TradePriceCalculatorHelper.recountPayPrice(orderItem);
+ }
+ TradePriceCalculatorHelper.recountAllPrice(result);
}
+ private boolean checkDeductPointEnable(MemberPointConfigRespDTO config) {
+ if (config == null) {
+ return false;
+ }
+ if (!BooleanUtil.isTrue(config.getTradeDeductEnable())) {
+ return false;
+ }
+
+ // 有没有配置:1 积分抵扣多少分
+ return config.getTradeDeductUnitPrice() != null && config.getTradeDeductUnitPrice() > 0;
+ }
+
+ private Integer calculatePointPrice(MemberPointConfigRespDTO config, Integer usePoint, TradePriceCalculateRespBO result) {
+ // 每个订单最多可以使用的积分数量
+ if (config.getTradeDeductMaxPrice() != null && config.getTradeDeductMaxPrice() > 0) {
+ usePoint = Math.min(usePoint, config.getTradeDeductMaxPrice());
+ }
+ // 积分优惠金额(分)
+ int pointPrice = usePoint * config.getTradeDeductUnitPrice();
+ // 0元购!!!:用户积分比较多时,积分可以抵扣的金额要大于支付金额, 这时需要根据支付金额反推使用多少积分
+ if (result.getPrice().getPayPrice() < pointPrice) {
+ pointPrice = result.getPrice().getPayPrice();
+ // 反推需要扣除的积分
+ usePoint = NumberUtil.toBigDecimal(pointPrice)
+ .divide(NumberUtil.toBigDecimal(config.getTradeDeductUnitPrice()), 0, RoundingMode.HALF_UP)
+ .intValue();
+ }
+ // 记录使用的积分
+ result.setUsePoint(usePoint);
+
+ return pointPrice;
+ }
}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java
index cddc1ea21..e5b18e88e 100644
--- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java
@@ -23,6 +23,10 @@ public interface TradePriceCalculator {
* 放在各种营销活动、优惠劵后面 TODO
*/
int ORDER_DELIVERY = 50;
+ /**
+ * 赠送积分,放最后
+ */
+ int ORDER_POINT_GIVE = 999;
void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result);
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java
index b8b9e0fb9..9a0a7e1d5 100644
--- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java
@@ -58,7 +58,8 @@ public class TradePriceCalculatorHelper {
.setWeight(sku.getWeight()).setVolume(sku.getVolume());
// spu 信息
orderItem.setSpuName(spu.getName()).setCategoryId(spu.getCategoryId())
- .setDeliveryTemplateId(spu.getDeliveryTemplateId());
+ .setDeliveryTemplateId(spu.getDeliveryTemplateId())
+ .setGivePoint(spu.getGiveIntegral()).setUsePoint(0);
if (orderItem.getPicUrl() == null) {
orderItem.setPicUrl(spu.getPicUrl());
}
@@ -67,6 +68,7 @@ public class TradePriceCalculatorHelper {
// 创建它的 Price 属性
result.setPrice(new TradePriceCalculateRespBO.Price());
recountAllPrice(result);
+ recountAllGivePoint(result);
return result;
}
@@ -111,13 +113,22 @@ public class TradePriceCalculatorHelper {
});
}
+ /**
+ * 基于订单项,重新计算赠送积分
+ *
+ * @param result 计算结果
+ */
+ public static void recountAllGivePoint(TradePriceCalculateRespBO result) {
+ result.setGivePoint(getSumValue(result.getItems(), item -> item.getSelected() ? item.getGivePoint() : 0, Integer::sum));
+ }
+
/**
* 重新计算单个订单项的支付金额
*
* @param orderItem 订单项
*/
public static void recountPayPrice(TradePriceCalculateRespBO.OrderItem orderItem) {
- orderItem.setPayPrice(orderItem.getPrice()* orderItem.getCount()
+ orderItem.setPayPrice(orderItem.getPrice() * orderItem.getCount()
- orderItem.getDiscountPrice()
+ orderItem.getDeliveryPrice()
- orderItem.getCouponPrice()
@@ -145,6 +156,12 @@ public class TradePriceCalculatorHelper {
if (orderItem.getPointPrice() == null) {
orderItem.setPointPrice(0);
}
+ if (orderItem.getUsePoint() == null) {
+ orderItem.setUsePoint(0);
+ }
+ if (orderItem.getGivePoint() == null) {
+ orderItem.setGivePoint(0);
+ }
recountPayPrice(orderItem);
});
}
@@ -169,7 +186,7 @@ public class TradePriceCalculatorHelper {
*/
public static Integer calculateTotalCount(List orderItems) {
return getSumValue(orderItems,
- orderItem -> orderItem.getSelected() ? orderItem.getCount() : 0, // 未选中的情况下,不计算数量
+ orderItem -> orderItem.getSelected() ? orderItem.getCount() : 0, // 未选中的情况下,不计算数量
Integer::sum);
}
@@ -177,7 +194,7 @@ public class TradePriceCalculatorHelper {
* 按照支付金额,返回每个订单项的分摊金额数组
*
* @param orderItems 订单项数组
- * @param price 金额
+ * @param price 金额
* @return 分摊金额数组,和传入的 orderItems 一一对应
*/
public static List dividePrice(List orderItems, Integer price) {
@@ -210,12 +227,12 @@ public class TradePriceCalculatorHelper {
/**
* 添加【匹配】单个 OrderItem 的营销明细
*
- * @param result 价格计算结果
+ * @param result 价格计算结果
* @param orderItem 单个订单商品 SKU
- * @param id 营销编号
- * @param name 营销名字
- * @param description 满足条件的提示
- * @param type 营销类型
+ * @param id 营销编号
+ * @param name 营销名字
+ * @param description 满足条件的提示
+ * @param type 营销类型
* @param discountPrice 单个订单商品 SKU 的优惠价格(总)
*/
public static void addPromotion(TradePriceCalculateRespBO result, TradePriceCalculateRespBO.OrderItem orderItem,
@@ -226,7 +243,7 @@ public class TradePriceCalculatorHelper {
/**
* 添加【匹配】多个 OrderItem 的营销明细
*
- * @param result 价格计算结果
+ * @param result 价格计算结果
* @param orderItems 多个订单商品 SKU
* @param id 营销编号
* @param name 营销名字
@@ -235,7 +252,7 @@ public class TradePriceCalculatorHelper {
* @param discountPrices 多个订单商品 SKU 的优惠价格(总),和 orderItems 一一对应
*/
public static void addPromotion(TradePriceCalculateRespBO result, List orderItems,
- Long id, String name, Integer type, String description, List discountPrices) {
+ Long id, String name, Integer type, String description, List discountPrices) {
// 创建营销明细 Item
List promotionItems = new ArrayList<>(discountPrices.size());
for (int i = 0; i < orderItems.size(); i++) {
@@ -255,12 +272,12 @@ public class TradePriceCalculatorHelper {
/**
* 添加【不匹配】多个 OrderItem 的营销明细
*
- * @param result 价格计算结果
- * @param orderItems 多个订单商品 SKU
- * @param id 营销编号
- * @param name 营销名字
- * @param description 满足条件的提示
- * @param type 营销类型
+ * @param result 价格计算结果
+ * @param orderItems 多个订单商品 SKU
+ * @param id 营销编号
+ * @param name 营销名字
+ * @param description 满足条件的提示
+ * @param type 营销类型
*/
public static void addNotMatchPromotion(TradePriceCalculateRespBO result, List orderItems,
Long id, String name, Integer type, String description) {
diff --git a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointApi.java b/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointApi.java
index 3eb749fb6..c6df95f7c 100644
--- a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointApi.java
+++ b/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointApi.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.member.api.point;
+import cn.iocoder.yudao.module.member.api.point.dto.MemberPointConfigRespDTO;
import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum;
import javax.validation.constraints.Min;
@@ -11,6 +12,13 @@ import javax.validation.constraints.Min;
*/
public interface MemberPointApi {
+ /**
+ * 获得积分配置
+ *
+ * @return 积分配置
+ */
+ MemberPointConfigRespDTO getConfig();
+
/**
* 增加用户积分
*
diff --git a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/point/dto/MemberPointConfigRespDTO.java b/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/point/dto/MemberPointConfigRespDTO.java
new file mode 100644
index 000000000..a9783352a
--- /dev/null
+++ b/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/point/dto/MemberPointConfigRespDTO.java
@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.member.api.point.dto;
+
+import lombok.Data;
+
+/**
+ * 用户信息 Response DTO
+ *
+ * @author 芋道源码
+ */
+@Data
+public class MemberPointConfigRespDTO {
+ /**
+ * 积分抵扣开关
+ */
+ private Boolean tradeDeductEnable;
+ /**
+ * 积分抵扣,单位:分
+ *
+ * 1 积分抵扣多少分
+ */
+ private Integer tradeDeductUnitPrice;
+ /**
+ * 积分抵扣最大值
+ */
+ private Integer tradeDeductMaxPrice;
+ /**
+ * 1 元赠送多少分
+ */
+ private Integer tradeGivePoint;
+}
diff --git a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/MemberUserRespDTO.java b/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/MemberUserRespDTO.java
index 10d96365f..0fa2c3e0b 100644
--- a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/MemberUserRespDTO.java
+++ b/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/MemberUserRespDTO.java
@@ -33,5 +33,8 @@ public class MemberUserRespDTO {
* 手机
*/
private String mobile;
-
+ /**
+ * 积分
+ */
+ private Integer point;
}
diff --git a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java b/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java
index 933f17168..c25de2461 100644
--- a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java
+++ b/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java
@@ -13,6 +13,7 @@ public interface ErrorCodeConstants {
ErrorCode USER_NOT_EXISTS = new ErrorCode(1004001000, "用户不存在");
ErrorCode USER_MOBILE_NOT_EXISTS = new ErrorCode(1004001001, "手机号未注册用户");
ErrorCode USER_MOBILE_USED = new ErrorCode(1004001002, "修改手机失败,该手机号({})已经被使用");
+ ErrorCode USER_POINT_NOT_ENOUGH = new ErrorCode(1004001003, "用户积分余额不足");
// ========== AUTH 模块 1004003000 ==========
ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1004003000, "登录失败,账号密码不正确");
diff --git a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/point/MemberPointBizTypeEnum.java b/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/point/MemberPointBizTypeEnum.java
index fe76cdb52..68e61cc9f 100644
--- a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/point/MemberPointBizTypeEnum.java
+++ b/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/point/MemberPointBizTypeEnum.java
@@ -18,8 +18,10 @@ public enum MemberPointBizTypeEnum implements IntArrayValuable {
SIGN(1, "签到", "签到获得 {} 积分", true),
ORDER_REWARD(10, "订单奖励", "下单获得 {} 积分", true),
- ORDER_CANCEL(11, "订单取消", "退单获得 {} 积分", false), // 退回积分
+ ORDER_CANCEL(11, "订单取消", "订单取消,退还 {} 积分", true), // 退回积分
ORDER_USE(12, "订单使用", "下单使用 {} 积分", false), // 扣减积分
+ AFTER_SALE_REFUND_USED(13, "订单退款", "订单退款,退还 {} 积分", true), // 退回积分
+ AFTER_SALE_DEDUCT_GIVE(14, "订单退款", "订单退款,扣除赠送的 {} 积分", false), // 扣减积分
;
/**
diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointApiImpl.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointApiImpl.java
index ee407eaf6..51239388a 100644
--- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointApiImpl.java
+++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointApiImpl.java
@@ -1,6 +1,10 @@
package cn.iocoder.yudao.module.member.api.point;
+import cn.hutool.core.lang.Assert;
+import cn.iocoder.yudao.module.member.api.point.dto.MemberPointConfigRespDTO;
+import cn.iocoder.yudao.module.member.convert.point.MemberPointConfigConvert;
import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum;
+import cn.iocoder.yudao.module.member.service.point.MemberPointConfigService;
import cn.iocoder.yudao.module.member.service.point.MemberPointRecordService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@@ -21,9 +25,17 @@ public class MemberPointApiImpl implements MemberPointApi {
@Resource
private MemberPointRecordService memberPointRecordService;
+ @Resource
+ private MemberPointConfigService memberPointConfigService;
+
+ @Override
+ public MemberPointConfigRespDTO getConfig() {
+ return MemberPointConfigConvert.INSTANCE.convert01(memberPointConfigService.getPointConfig());
+ }
@Override
public void addPoint(Long userId, Integer point, Integer bizType, String bizId) {
+ Assert.isTrue(point > 0);
MemberPointBizTypeEnum bizTypeEnum = MemberPointBizTypeEnum.getByType(bizType);
if (bizTypeEnum == null) {
throw exception(POINT_RECORD_BIZ_NOT_SUPPORT);
@@ -33,11 +45,12 @@ public class MemberPointApiImpl implements MemberPointApi {
@Override
public void reducePoint(Long userId, Integer point, Integer bizType, String bizId) {
+ Assert.isTrue(point > 0);
MemberPointBizTypeEnum bizTypeEnum = MemberPointBizTypeEnum.getByType(bizType);
if (bizTypeEnum == null) {
throw exception(POINT_RECORD_BIZ_NOT_SUPPORT);
}
- memberPointRecordService.createPointRecord(userId, point, bizTypeEnum, bizId);
+ memberPointRecordService.createPointRecord(userId, -point, bizTypeEnum, bizId);
}
}
diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/point/MemberPointConfigConvert.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/point/MemberPointConfigConvert.java
index e600378bb..c7f0e9881 100644
--- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/point/MemberPointConfigConvert.java
+++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/point/MemberPointConfigConvert.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.member.convert.point;
+import cn.iocoder.yudao.module.member.api.point.dto.MemberPointConfigRespDTO;
import cn.iocoder.yudao.module.member.controller.admin.point.vo.config.MemberPointConfigRespVO;
import cn.iocoder.yudao.module.member.controller.admin.point.vo.config.MemberPointConfigSaveReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointConfigDO;
@@ -20,4 +21,5 @@ public interface MemberPointConfigConvert {
MemberPointConfigDO convert(MemberPointConfigSaveReqVO bean);
+ MemberPointConfigRespDTO convert01(MemberPointConfigDO pointConfig);
}
diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MemberUserMapper.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MemberUserMapper.java
index 902057272..3f871020c 100644
--- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MemberUserMapper.java
+++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MemberUserMapper.java
@@ -1,12 +1,14 @@
package cn.iocoder.yudao.module.member.dal.mysql.user;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@@ -62,4 +64,33 @@ public interface MemberUserMapper extends BaseMapperX {
.apply("FIND_IN_SET({0}, tag_ids)", tagId));
}
+ /**
+ * 更新用户积分(增加)
+ *
+ * @param id 用户编号
+ * @param incrCount 增加积分(正数)
+ */
+ default void updatePointIncr(Long id, Integer incrCount) {
+ Assert.isTrue(incrCount > 0);
+ LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper()
+ .setSql(" point = point + " + incrCount)
+ .eq(MemberUserDO::getId, id);
+ update(null, lambdaUpdateWrapper);
+ }
+
+ /**
+ * 更新用户积分(减少)
+ *
+ * @param id 用户编号
+ * @param incrCount 增加积分(负数)
+ * @return 更新行数
+ */
+ default int updatePointDecr(Long id, Integer incrCount) {
+ Assert.isTrue(incrCount < 0);
+ LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper()
+ .setSql(" point = point + " + incrCount) // 负数,所以使用 + 号
+ .eq(MemberUserDO::getId, id);
+ return update(null, lambdaUpdateWrapper);
+ }
+
}
diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/point/MemberPointRecordServiceImpl.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/point/MemberPointRecordServiceImpl.java
index a28e94795..da67a9ec2 100644
--- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/point/MemberPointRecordServiceImpl.java
+++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/point/MemberPointRecordServiceImpl.java
@@ -5,7 +5,6 @@ import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.member.controller.admin.point.vo.recrod.MemberPointRecordPageReqVO;
-import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointConfigDO;
import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointRecordDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.dal.mysql.point.MemberPointRecordMapper;
@@ -14,6 +13,7 @@ import cn.iocoder.yudao.module.member.service.user.MemberUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
@@ -21,7 +21,9 @@ import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
+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.module.member.enums.ErrorCodeConstants.USER_POINT_NOT_ENOUGH;
/**
@@ -36,8 +38,6 @@ public class MemberPointRecordServiceImpl implements MemberPointRecordService {
@Resource
private MemberPointRecordMapper memberPointRecordMapper;
- @Resource
- private MemberPointConfigService memberPointConfigService;
@Resource
private MemberUserService memberUserService;
@@ -64,32 +64,28 @@ public class MemberPointRecordServiceImpl implements MemberPointRecordService {
}
@Override
+ @Transactional(rollbackFor = Exception.class)
public void createPointRecord(Long userId, Integer point, MemberPointBizTypeEnum bizType, String bizId) {
- MemberPointConfigDO pointConfig = memberPointConfigService.getPointConfig();
- if (pointConfig == null || pointConfig.getTradeGivePoint() == null) {
- log.error("[createPointRecord][增加积分失败:tradeGivePoint 未配置,userId({}) point({}) bizType({}) bizId({})]",
- userId, point, bizType.getType(), bizId);
- return;
- }
-
- // 1. 根据配置的比例,换算实际的积分
- point = point * pointConfig.getTradeGivePoint();
- if (!bizType.isAdd() && point > 0) {
- point = -point;
- }
-
- // 2. 增加积分记录
+ // 1. 校验用户积分余额
MemberUserDO user = memberUserService.getUser(userId);
Integer userPoint = ObjectUtil.defaultIfNull(user.getPoint(), 0);
- Integer totalPoint = userPoint + point; // 用户变动后的积分
+ int totalPoint = userPoint + point; // 用户变动后的积分
+ if (totalPoint < 0) {
+ throw exception(USER_POINT_NOT_ENOUGH);
+ }
+
+ // 2. 更新用户积分
+ boolean success = memberUserService.updateUserPoint(userId, point);
+ if (!success) {
+ throw exception(USER_POINT_NOT_ENOUGH);
+ }
+
+ // 3. 增加积分记录
MemberPointRecordDO record = new MemberPointRecordDO()
.setUserId(userId).setBizId(bizId).setBizType(bizType.getType())
.setTitle(bizType.getName()).setDescription(StrUtil.format(bizType.getDescription(), point))
.setPoint(point).setTotalPoint(totalPoint);
memberPointRecordMapper.insert(record);
-
- // 3. 更新用户积分
- memberUserService.updateUserPoint(userId, totalPoint);
}
}
diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserService.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserService.java
index f1a0a7265..50433a559 100644
--- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserService.java
+++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserService.java
@@ -164,6 +164,7 @@ public interface MemberUserService {
*
* @param userId 用户编号
* @param point 积分数量
+ * @return 更新结果
*/
- void updateUserPoint(Long userId, Integer point);
+ boolean updateUserPoint(Long userId, Integer point);
}
diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java
index 8381c73f1..3119c48db 100644
--- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java
+++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java
@@ -260,8 +260,13 @@ public class MemberUserServiceImpl implements MemberUserService {
}
@Override
- public void updateUserPoint(Long userId, Integer point) {
- memberUserMapper.updateById(new MemberUserDO().setId(userId).setPoint(point));
+ public boolean updateUserPoint(Long id, Integer point) {
+ if (point > 0) {
+ memberUserMapper.updatePointIncr(id, point);
+ } else if (point < 0) {
+ return memberUserMapper.updatePointDecr(id, point) > 0;
+ }
+ return true;
}
}