Commit 052328c5fafca745051e5f6c9378f47ee21c44df
1 parent
dc46dff6
积分:完善积分获得、退还、使用 相关逻辑
Showing
24 changed files
with
381 additions
and
85 deletions
sql/mysql/point.sql
0 → 100644
| 1 | +ALTER TABLE trade_order ADD COLUMN use_point int NOT NULL DEFAULT 0 COMMENT '使用的积分' AFTER point_price; | ||
| 2 | +ALTER TABLE trade_order ADD COLUMN refund_point int NOT NULL DEFAULT 0 COMMENT '退还的使用积分' AFTER use_point; | ||
| 3 | +ALTER TABLE trade_order ADD COLUMN give_point int NOT NULL DEFAULT 0 COMMENT '赠送的积分' AFTER refund_point; | ||
| 4 | + | ||
| 5 | +ALTER TABLE trade_order_item ADD COLUMN use_point int NOT NULL DEFAULT 0 COMMENT '使用的积分' AFTER point_price; | ||
| 6 | +ALTER TABLE trade_order_item ADD COLUMN give_point int NOT NULL DEFAULT 0 COMMENT '赠送的积分' AFTER use_point; |
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java
| @@ -111,6 +111,11 @@ public class ProductSpuRespDTO { | @@ -111,6 +111,11 @@ public class ProductSpuRespDTO { | ||
| 111 | // ========== 物流相关字段 ========= | 111 | // ========== 物流相关字段 ========= |
| 112 | 112 | ||
| 113 | /** | 113 | /** |
| 114 | + * 赠送积分 | ||
| 115 | + */ | ||
| 116 | + private Integer giveIntegral; | ||
| 117 | + | ||
| 118 | + /** | ||
| 114 | * 物流配置模板编号 | 119 | * 物流配置模板编号 |
| 115 | * | 120 | * |
| 116 | * 对应 TradeDeliveryExpressTemplateDO 的 id 编号 | 121 | * 对应 TradeDeliveryExpressTemplateDO 的 id 编号 |
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 { | @@ -23,7 +23,8 @@ public enum PromotionTypeEnum implements IntArrayValuable { | ||
| 23 | REWARD_ACTIVITY(5, "满减送"), | 23 | REWARD_ACTIVITY(5, "满减送"), |
| 24 | 24 | ||
| 25 | MEMBER(6, "会员折扣"), | 25 | MEMBER(6, "会员折扣"), |
| 26 | - COUPON(7, "优惠劵") | 26 | + COUPON(7, "优惠劵"), |
| 27 | + POINT(8, "积分") | ||
| 27 | ; | 28 | ; |
| 28 | 29 | ||
| 29 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PromotionTypeEnum::getType).toArray(); | 30 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PromotionTypeEnum::getType).toArray(); |
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 { | @@ -265,9 +265,13 @@ public class TradeOrderDO extends BaseDO { | ||
| 265 | * 对应 taobao 的 trade.point_fee 字段 | 265 | * 对应 taobao 的 trade.point_fee 字段 |
| 266 | */ | 266 | */ |
| 267 | private Integer pointPrice; | 267 | private Integer pointPrice; |
| 268 | -// /** | ||
| 269 | -// * 奖励的积分 TODO 疯狂:可以使用这个字段哈; | ||
| 270 | -// */ | ||
| 271 | -// private Integer rewardPoint; | 268 | + /** |
| 269 | + * 赠送的积分 | ||
| 270 | + */ | ||
| 271 | + private Integer givePoint; | ||
| 272 | + /** | ||
| 273 | + * 退还的使用的积分 | ||
| 274 | + */ | ||
| 275 | + private Integer refundPoint; | ||
| 272 | 276 | ||
| 273 | } | 277 | } |
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 { | @@ -143,6 +143,14 @@ public class TradeOrderItemDO extends BaseDO { | ||
| 143 | * 对应 taobao 的 trade.point_fee 字段 | 143 | * 对应 taobao 的 trade.point_fee 字段 |
| 144 | */ | 144 | */ |
| 145 | private Integer pointPrice; | 145 | private Integer pointPrice; |
| 146 | + /** | ||
| 147 | + * 使用的积分 | ||
| 148 | + */ | ||
| 149 | + private Integer usePoint; | ||
| 150 | + /** | ||
| 151 | + * 赠送的积分 | ||
| 152 | + */ | ||
| 153 | + private Integer givePoint; | ||
| 146 | // TODO @芋艿:如果商品 vip 折扣时,到底是新增一个 vipPrice 记录优惠记录,还是 vipDiscountPrice,记录 vip 的优惠;还是直接使用 vipPrice; | 154 | // TODO @芋艿:如果商品 vip 折扣时,到底是新增一个 vipPrice 记录优惠记录,还是 vipDiscountPrice,记录 vip 的优惠;还是直接使用 vipPrice; |
| 147 | // 目前 crmeb 的选择,单独一个 vipPrice 记录优惠价格;感觉不一定合理,可以在看看有赞的; | 155 | // 目前 crmeb 的选择,单独一个 vipPrice 记录优惠价格;感觉不一定合理,可以在看看有赞的; |
| 148 | 156 |
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; | @@ -24,6 +24,7 @@ import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; | ||
| 24 | import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi; | 24 | import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi; |
| 25 | import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO; | 25 | import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO; |
| 26 | import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; | 26 | import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; |
| 27 | +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; | ||
| 27 | import cn.iocoder.yudao.module.promotion.api.bargain.BargainRecordApi; | 28 | import cn.iocoder.yudao.module.promotion.api.bargain.BargainRecordApi; |
| 28 | import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi; | 29 | import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi; |
| 29 | import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi; | 30 | import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi; |
| @@ -48,8 +49,8 @@ import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; | @@ -48,8 +49,8 @@ import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; | ||
| 48 | import cn.iocoder.yudao.module.trade.enums.order.*; | 49 | import cn.iocoder.yudao.module.trade.enums.order.*; |
| 49 | import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; | 50 | import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; |
| 50 | import cn.iocoder.yudao.module.trade.framework.order.core.annotations.TradeOrderLog; | 51 | import cn.iocoder.yudao.module.trade.framework.order.core.annotations.TradeOrderLog; |
| 51 | -import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO; | ||
| 52 | import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageRecordService; | 52 | import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageRecordService; |
| 53 | +import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO; | ||
| 53 | import cn.iocoder.yudao.module.trade.service.cart.CartService; | 54 | import cn.iocoder.yudao.module.trade.service.cart.CartService; |
| 54 | import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; | 55 | import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; |
| 55 | import cn.iocoder.yudao.module.trade.service.message.TradeMessageService; | 56 | import cn.iocoder.yudao.module.trade.service.message.TradeMessageService; |
| @@ -106,6 +107,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -106,6 +107,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 106 | private TradeMessageService tradeMessageService; | 107 | private TradeMessageService tradeMessageService; |
| 107 | 108 | ||
| 108 | @Resource | 109 | @Resource |
| 110 | + private ProductSpuApi productSpuApi; | ||
| 111 | + @Resource | ||
| 109 | private ProductSkuApi productSkuApi; | 112 | private ProductSkuApi productSkuApi; |
| 110 | @Resource | 113 | @Resource |
| 111 | private PayOrderApi payOrderApi; | 114 | private PayOrderApi payOrderApi; |
| @@ -240,8 +243,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -240,8 +243,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 240 | /** | 243 | /** |
| 241 | * 订单创建前,执行前置逻辑 | 244 | * 订单创建前,执行前置逻辑 |
| 242 | * | 245 | * |
| 243 | - * @param userId 用户编号 | ||
| 244 | - * @param createReqVO 创建订单请求 | 246 | + * @param userId 用户编号 |
| 247 | + * @param createReqVO 创建订单请求 | ||
| 245 | * @param calculateRespBO 订单价格计算结果 | 248 | * @param calculateRespBO 订单价格计算结果 |
| 246 | */ | 249 | */ |
| 247 | private void beforeCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO, | 250 | private void beforeCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO, |
| @@ -260,12 +263,12 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -260,12 +263,12 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 260 | 263 | ||
| 261 | /** | 264 | /** |
| 262 | * 订单创建后,执行后置逻辑 | 265 | * 订单创建后,执行后置逻辑 |
| 263 | - * | 266 | + * <p> |
| 264 | * 例如说:优惠劵的扣减、积分的扣减、支付单的创建等等 | 267 | * 例如说:优惠劵的扣减、积分的扣减、支付单的创建等等 |
| 265 | * | 268 | * |
| 266 | * @param userId 用户编号 | 269 | * @param userId 用户编号 |
| 267 | * @param createReqVO 创建订单请求 | 270 | * @param createReqVO 创建订单请求 |
| 268 | - * @param order 交易订单 | 271 | + * @param order 交易订单 |
| 269 | * @param calculateRespBO 订单价格计算结果 | 272 | * @param calculateRespBO 订单价格计算结果 |
| 270 | */ | 273 | */ |
| 271 | private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO, | 274 | private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO, |
| @@ -283,12 +286,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -283,12 +286,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 283 | .setOrderId(order.getId())); | 286 | .setOrderId(order.getId())); |
| 284 | } | 287 | } |
| 285 | 288 | ||
| 286 | - // 3. 扣减积分 | 289 | + // 3. 扣减积分(抵扣) |
| 287 | // 不在前置扣减的原因,是因为积分扣减时,需要记录关联业务 | 290 | // 不在前置扣减的原因,是因为积分扣减时,需要记录关联业务 |
| 288 | - if (order.getUsePoint() != null && order.getUsePoint() > 0) { | ||
| 289 | - memberPointApi.reducePoint(userId, calculateRespBO.getUsePoint(), | ||
| 290 | - MemberPointBizTypeEnum.ORDER_USE.getType(), String.valueOf(order.getId())); | ||
| 291 | - } | 291 | + reduceUserPoint(order.getUserId(), order.getUsePoint(), MemberPointBizTypeEnum.ORDER_USE, order.getId()); |
| 292 | 292 | ||
| 293 | // 4. 删除购物车商品 | 293 | // 4. 删除购物车商品 |
| 294 | Set<Long> cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId); | 294 | Set<Long> cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId); |
| @@ -342,8 +342,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -342,8 +342,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 342 | 342 | ||
| 343 | // TODO 芋艿:OrderLog | 343 | // TODO 芋艿:OrderLog |
| 344 | 344 | ||
| 345 | - // 增加用户积分 | ||
| 346 | - getSelf().addUserPointAsync(order.getUserId(), order.getPayPrice(), order.getId()); | 345 | + // 增加用户积分(赠送) |
| 346 | + addUserPoint(order.getUserId(), order.getGivePoint(), MemberPointBizTypeEnum.ORDER_REWARD, order.getId()); | ||
| 347 | // 增加用户经验 | 347 | // 增加用户经验 |
| 348 | getSelf().addUserExperienceAsync(order.getUserId(), order.getPayPrice(), order.getId()); | 348 | getSelf().addUserExperienceAsync(order.getUserId(), order.getPayPrice(), order.getId()); |
| 349 | // 增加用户佣金 | 349 | // 增加用户佣金 |
| @@ -640,11 +640,12 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -640,11 +640,12 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 640 | return; | 640 | return; |
| 641 | } | 641 | } |
| 642 | // 计算总的退款金额 | 642 | // 计算总的退款金额 |
| 643 | - TradeOrderDO order = tradeOrderMapper.selectById(tradeOrderItemMapper.selectById(id).getOrderId()); | 643 | + TradeOrderItemDO orderItem = tradeOrderItemMapper.selectById(id); |
| 644 | + TradeOrderDO order = tradeOrderMapper.selectById(orderItem.getOrderId()); | ||
| 644 | Integer orderRefundPrice = order.getRefundPrice() + refundPrice; | 645 | Integer orderRefundPrice = order.getRefundPrice() + refundPrice; |
| 645 | if (isAllOrderItemAfterSaleSuccess(order.getId())) { // 如果都售后成功,则需要取消订单 | 646 | if (isAllOrderItemAfterSaleSuccess(order.getId())) { // 如果都售后成功,则需要取消订单 |
| 646 | tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()) | 647 | tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()) |
| 647 | - .setRefundStatus(TradeOrderRefundStatusEnum.ALL.getStatus()).setRefundPrice(orderRefundPrice) | 648 | + .setRefundStatus(TradeOrderRefundStatusEnum.ALL.getStatus()).setRefundPrice(orderRefundPrice).setRefundPoint(order.getRefundPoint() + orderItem.getUsePoint()) |
| 648 | .setCancelType(TradeOrderCancelTypeEnum.AFTER_SALE_CLOSE.getType()).setCancelTime(LocalDateTime.now())); | 649 | .setCancelType(TradeOrderCancelTypeEnum.AFTER_SALE_CLOSE.getType()).setCancelTime(LocalDateTime.now())); |
| 649 | 650 | ||
| 650 | // TODO 芋艿:记录订单日志 | 651 | // TODO 芋艿:记录订单日志 |
| @@ -655,12 +656,17 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -655,12 +656,17 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 655 | .setRefundStatus(TradeOrderRefundStatusEnum.PART.getStatus()).setRefundPrice(orderRefundPrice)); | 656 | .setRefundStatus(TradeOrderRefundStatusEnum.PART.getStatus()).setRefundPrice(orderRefundPrice)); |
| 656 | } | 657 | } |
| 657 | 658 | ||
| 658 | - // 扣减用户积分 | ||
| 659 | - getSelf().reduceUserPointAsync(order.getUserId(), orderRefundPrice, afterSaleId); | ||
| 660 | - // 扣减用户经验 | ||
| 661 | - getSelf().reduceUserExperienceAsync(order.getUserId(), orderRefundPrice, afterSaleId); | ||
| 662 | - // 更新分佣记录为已失效 | ||
| 663 | - getSelf().cancelBrokerageAsync(order.getUserId(), id); | 659 | + // 售后成功后,执行数据回滚逻辑 |
| 660 | + if (Objects.equals(newAfterSaleStatus, TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus())) { | ||
| 661 | + // 扣减用户积分(赠送的) | ||
| 662 | + reduceUserPoint(order.getUserId(), orderItem.getGivePoint(), MemberPointBizTypeEnum.AFTER_SALE_DEDUCT_GIVE, afterSaleId); | ||
| 663 | + // 增加用户积分(返还抵扣) | ||
| 664 | + addUserPoint(order.getUserId(), orderItem.getUsePoint(), MemberPointBizTypeEnum.AFTER_SALE_REFUND_USED, afterSaleId); | ||
| 665 | + // 扣减用户经验 | ||
| 666 | + getSelf().reduceUserExperienceAsync(order.getUserId(), orderRefundPrice, afterSaleId); | ||
| 667 | + // 更新分佣记录为已失效 | ||
| 668 | + getSelf().cancelBrokerageAsync(order.getUserId(), id); | ||
| 669 | + } | ||
| 664 | } | 670 | } |
| 665 | 671 | ||
| 666 | @Override | 672 | @Override |
| @@ -728,8 +734,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -728,8 +734,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 728 | // 3.回滚优惠券 | 734 | // 3.回滚优惠券 |
| 729 | couponApi.returnUsedCoupon(order.getCouponId()); | 735 | couponApi.returnUsedCoupon(order.getCouponId()); |
| 730 | 736 | ||
| 731 | - // 4.回滚积分:积分是支付成功后才增加的吧? 回复:每个项目不同,目前看下来,确认收货貌似更合适,我再看看其它项目的业务选择; | ||
| 732 | - // TODO @疯狂:有赞是可配置(支付 or 确认收货),我们按照支付好列;然后这里的退积分,指的是下单时的积分抵扣。 | 737 | + // 4.回滚积分(抵扣的) |
| 738 | + addUserPoint(order.getUserId(), order.getUsePoint(), MemberPointBizTypeEnum.ORDER_CANCEL, order.getId()); | ||
| 733 | 739 | ||
| 734 | // TODO 芋艿:OrderLog | 740 | // TODO 芋艿:OrderLog |
| 735 | 741 | ||
| @@ -760,18 +766,16 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -760,18 +766,16 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 760 | memberLevelApi.addExperience(userId, -refundPrice, bizType, String.valueOf(afterSaleId)); | 766 | memberLevelApi.addExperience(userId, -refundPrice, bizType, String.valueOf(afterSaleId)); |
| 761 | } | 767 | } |
| 762 | 768 | ||
| 763 | - @Async | ||
| 764 | - protected void addUserPointAsync(Long userId, Integer payPrice, Long orderId) { | ||
| 765 | - // TODO @疯狂:具体多少积分,需要分成 2 不分:1. 支付金额;2. 商品金额 | ||
| 766 | - int bizType = MemberPointBizTypeEnum.ORDER_REWARD.getType(); | ||
| 767 | - memberPointApi.addPoint(userId, payPrice, bizType, String.valueOf(orderId)); | 769 | + protected void addUserPoint(Long userId, Integer point, MemberPointBizTypeEnum bizType, Long bizId) { |
| 770 | + if (point != null && point > 0) { | ||
| 771 | + memberPointApi.addPoint(userId, point, bizType.getType(), String.valueOf(bizId)); | ||
| 772 | + } | ||
| 768 | } | 773 | } |
| 769 | 774 | ||
| 770 | - @Async | ||
| 771 | - protected void reduceUserPointAsync(Long userId, Integer refundPrice, Long afterSaleId) { | ||
| 772 | - // TODO @疯狂:退款时,按照金额比例,退还积分;https://help.youzan.com/displaylist/detail_4_4-1-49185 | ||
| 773 | - int bizType = MemberPointBizTypeEnum.ORDER_CANCEL.getType(); | ||
| 774 | - memberPointApi.addPoint(userId, -refundPrice, bizType, String.valueOf(afterSaleId)); | 775 | + protected void reduceUserPoint(Long userId, Integer point, MemberPointBizTypeEnum bizType, Long bizId) { |
| 776 | + if (point != null && point > 0) { | ||
| 777 | + memberPointApi.reducePoint(userId, point, bizType.getType(), String.valueOf(bizId)); | ||
| 778 | + } | ||
| 775 | } | 779 | } |
| 776 | 780 | ||
| 777 | @Async | 781 | @Async |
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 { | @@ -41,7 +41,6 @@ public class TradePriceServiceImpl implements TradePriceService { | ||
| 41 | @Resource | 41 | @Resource |
| 42 | private List<TradePriceCalculator> priceCalculators; | 42 | private List<TradePriceCalculator> priceCalculators; |
| 43 | 43 | ||
| 44 | - // TODO @疯狂:需要搞个 TradePriceCalculator,计算赠送积分; | ||
| 45 | @Override | 44 | @Override |
| 46 | public TradePriceCalculateRespBO calculatePrice(TradePriceCalculateReqBO calculateReqBO) { | 45 | public TradePriceCalculateRespBO calculatePrice(TradePriceCalculateReqBO calculateReqBO) { |
| 47 | // 1.1 获得商品 SKU 数组 | 46 | // 1.1 获得商品 SKU 数组 |
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 { | @@ -29,7 +29,7 @@ public class TradePriceCalculateReqBO { | ||
| 29 | * 对应 CouponDO 的 id 编号 | 29 | * 对应 CouponDO 的 id 编号 |
| 30 | */ | 30 | */ |
| 31 | private Long couponId; | 31 | private Long couponId; |
| 32 | - // TODO @疯狂:需要增加一个 PriceCalculator 实现积分扣减的计算;写回到 TradePriceCalculateRespBO 的 usePoint | 32 | + |
| 33 | /** | 33 | /** |
| 34 | * 是否使用积分 | 34 | * 是否使用积分 |
| 35 | */ | 35 | */ |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java
| @@ -54,6 +54,11 @@ public class TradePriceCalculateRespBO { | @@ -54,6 +54,11 @@ public class TradePriceCalculateRespBO { | ||
| 54 | private Integer usePoint; | 54 | private Integer usePoint; |
| 55 | 55 | ||
| 56 | /** | 56 | /** |
| 57 | + * 使用的积分 | ||
| 58 | + */ | ||
| 59 | + private Integer givePoint; | ||
| 60 | + | ||
| 61 | + /** | ||
| 57 | * 订单价格 | 62 | * 订单价格 |
| 58 | */ | 63 | */ |
| 59 | @Data | 64 | @Data |
| @@ -159,6 +164,10 @@ public class TradePriceCalculateRespBO { | @@ -159,6 +164,10 @@ public class TradePriceCalculateRespBO { | ||
| 159 | */ | 164 | */ |
| 160 | private Integer pointPrice; | 165 | private Integer pointPrice; |
| 161 | /** | 166 | /** |
| 167 | + * 使用的积分 | ||
| 168 | + */ | ||
| 169 | + private Integer usePoint; | ||
| 170 | + /** | ||
| 162 | * 应付金额(总),单位:分 | 171 | * 应付金额(总),单位:分 |
| 163 | * | 172 | * |
| 164 | * = {@link #price} * {@link #count} | 173 | * = {@link #price} * {@link #count} |
| @@ -205,6 +214,11 @@ public class TradePriceCalculateRespBO { | @@ -205,6 +214,11 @@ public class TradePriceCalculateRespBO { | ||
| 205 | */ | 214 | */ |
| 206 | private List<ProductPropertyValueDetailRespDTO> properties; | 215 | private List<ProductPropertyValueDetailRespDTO> properties; |
| 207 | 216 | ||
| 217 | + /** | ||
| 218 | + * 使用的积分 | ||
| 219 | + */ | ||
| 220 | + private Integer givePoint; | ||
| 221 | + | ||
| 208 | } | 222 | } |
| 209 | 223 | ||
| 210 | /** | 224 | /** |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointGiveCalculator.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.price.calculator; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.util.BooleanUtil; | ||
| 4 | +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; | ||
| 5 | +import cn.iocoder.yudao.module.member.api.point.MemberPointApi; | ||
| 6 | +import cn.iocoder.yudao.module.member.api.point.dto.MemberPointConfigRespDTO; | ||
| 7 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | ||
| 8 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | ||
| 9 | +import lombok.extern.slf4j.Slf4j; | ||
| 10 | +import org.springframework.core.annotation.Order; | ||
| 11 | +import org.springframework.stereotype.Component; | ||
| 12 | + | ||
| 13 | +import javax.annotation.Resource; | ||
| 14 | +import java.util.List; | ||
| 15 | +import java.util.Optional; | ||
| 16 | + | ||
| 17 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; | ||
| 18 | + | ||
| 19 | +/** | ||
| 20 | + * 赠送积分的 {@link TradePriceCalculator} 实现类 | ||
| 21 | + * | ||
| 22 | + * @author owen | ||
| 23 | + */ | ||
| 24 | +@Component | ||
| 25 | +@Order(TradePriceCalculator.ORDER_POINT_GIVE) | ||
| 26 | +@Slf4j | ||
| 27 | +public class TradePointGiveCalculator implements TradePriceCalculator { | ||
| 28 | + @Resource | ||
| 29 | + private MemberPointApi memberPointApi; | ||
| 30 | + | ||
| 31 | + @Override | ||
| 32 | + public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { | ||
| 33 | + // 1.1 校验积分功能是否开启 | ||
| 34 | + int givePointPerYuan = Optional.ofNullable(memberPointApi.getConfig()) | ||
| 35 | + .filter(config -> BooleanUtil.isTrue(config.getTradeDeductEnable())) | ||
| 36 | + .map(MemberPointConfigRespDTO::getTradeGivePoint) | ||
| 37 | + .orElse(0); | ||
| 38 | + if (givePointPerYuan <= 0) { | ||
| 39 | + return; | ||
| 40 | + } | ||
| 41 | + // 1.2 校验支付金额 | ||
| 42 | + if (result.getPrice().getPayPrice() <= 0) { | ||
| 43 | + return; | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + // 2.1 计算赠送积分 | ||
| 47 | + int givePoint = MoneyUtils.calculateRatePriceFloor(result.getPrice().getPayPrice(), (double) givePointPerYuan); | ||
| 48 | + // 2.2 计算分摊的赠送积分 | ||
| 49 | + List<TradePriceCalculateRespBO.OrderItem> orderItems = filterList(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSelected); | ||
| 50 | + List<Integer> dividePoints = TradePriceCalculatorHelper.dividePrice(orderItems, givePoint); | ||
| 51 | + | ||
| 52 | + // 3.2 更新 SKU 赠送积分 | ||
| 53 | + for (int i = 0; i < orderItems.size(); i++) { | ||
| 54 | + TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i); | ||
| 55 | + // 商品可能赠送了积分,所以这里要加上 | ||
| 56 | + orderItem.setGivePoint(orderItem.getGivePoint() + dividePoints.get(i)); | ||
| 57 | + TradePriceCalculatorHelper.recountPayPrice(orderItem); | ||
| 58 | + } | ||
| 59 | + // 3.3 更新订单赠送积分 | ||
| 60 | + TradePriceCalculatorHelper.recountAllGivePoint(result); | ||
| 61 | + } | ||
| 62 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculator.java
| 1 | package cn.iocoder.yudao.module.trade.service.price.calculator; | 1 | package cn.iocoder.yudao.module.trade.service.price.calculator; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.util.BooleanUtil; | ||
| 4 | +import cn.hutool.core.util.NumberUtil; | ||
| 5 | +import cn.hutool.core.util.StrUtil; | ||
| 6 | +import cn.iocoder.yudao.module.member.api.point.MemberPointApi; | ||
| 7 | +import cn.iocoder.yudao.module.member.api.point.dto.MemberPointConfigRespDTO; | ||
| 8 | +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; | ||
| 9 | +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; | ||
| 10 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; | ||
| 3 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | 11 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; |
| 4 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | 12 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; |
| 5 | import lombok.extern.slf4j.Slf4j; | 13 | import lombok.extern.slf4j.Slf4j; |
| 6 | import org.springframework.core.annotation.Order; | 14 | import org.springframework.core.annotation.Order; |
| 7 | import org.springframework.stereotype.Component; | 15 | import org.springframework.stereotype.Component; |
| 8 | 16 | ||
| 17 | +import javax.annotation.Resource; | ||
| 18 | +import java.math.RoundingMode; | ||
| 19 | +import java.util.List; | ||
| 20 | + | ||
| 21 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; | ||
| 22 | + | ||
| 9 | /** | 23 | /** |
| 10 | * 使用积分的 {@link TradePriceCalculator} 实现类 | 24 | * 使用积分的 {@link TradePriceCalculator} 实现类 |
| 11 | * | 25 | * |
| @@ -15,15 +29,81 @@ import org.springframework.stereotype.Component; | @@ -15,15 +29,81 @@ import org.springframework.stereotype.Component; | ||
| 15 | @Order(TradePriceCalculator.ORDER_POINT_USE) | 29 | @Order(TradePriceCalculator.ORDER_POINT_USE) |
| 16 | @Slf4j | 30 | @Slf4j |
| 17 | public class TradePointUsePriceCalculator implements TradePriceCalculator { | 31 | public class TradePointUsePriceCalculator implements TradePriceCalculator { |
| 32 | + @Resource | ||
| 33 | + private MemberPointApi memberPointApi; | ||
| 34 | + @Resource | ||
| 35 | + private MemberUserApi memberUserApi; | ||
| 18 | 36 | ||
| 19 | @Override | 37 | @Override |
| 20 | public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { | 38 | public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { |
| 21 | - // TODO 疯狂:待实现,嘿嘿; | ||
| 22 | - if (param.getPointStatus()) { | ||
| 23 | - result.setUsePoint(10); | ||
| 24 | - } else { | 39 | + // 1.1 校验是否使用积分 |
| 40 | + if (!BooleanUtil.isTrue(param.getPointStatus())) { | ||
| 25 | result.setUsePoint(0); | 41 | result.setUsePoint(0); |
| 42 | + return; | ||
| 43 | + } | ||
| 44 | + // 1.2 校验积分抵扣是否开启 | ||
| 45 | + MemberPointConfigRespDTO config = memberPointApi.getConfig(); | ||
| 46 | + if (!checkDeductPointEnable(config)) { | ||
| 47 | + return; | ||
| 48 | + } | ||
| 49 | + // 1.3 校验用户积分余额 | ||
| 50 | + MemberUserRespDTO user = memberUserApi.getUser(param.getUserId()); | ||
| 51 | + if (user.getPoint() == null || user.getPoint() < 0) { | ||
| 52 | + return; | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + // 2.1 计算积分优惠金额 | ||
| 56 | + int pointPrice = calculatePointPrice(config, user.getPoint(), result); | ||
| 57 | + // 2.1 计算分摊的积分、抵扣金额 | ||
| 58 | + List<TradePriceCalculateRespBO.OrderItem> orderItems = filterList(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSelected); | ||
| 59 | + List<Integer> dividePointPrices = TradePriceCalculatorHelper.dividePrice(orderItems, pointPrice); | ||
| 60 | + List<Integer> divideUsePoints = TradePriceCalculatorHelper.dividePrice(orderItems, result.getUsePoint()); | ||
| 61 | + | ||
| 62 | + // 3.1 记录优惠明细 | ||
| 63 | + TradePriceCalculatorHelper.addPromotion(result, orderItems, | ||
| 64 | + param.getUserId(), "积分抵扣", PromotionTypeEnum.POINT.getType(), | ||
| 65 | + StrUtil.format("积分抵扣:省 {} 元", TradePriceCalculatorHelper.formatPrice(pointPrice)), | ||
| 66 | + dividePointPrices); | ||
| 67 | + // 3.2 更新 SKU 优惠金额 | ||
| 68 | + for (int i = 0; i < orderItems.size(); i++) { | ||
| 69 | + TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i); | ||
| 70 | + orderItem.setPointPrice(dividePointPrices.get(i)); | ||
| 71 | + orderItem.setUsePoint(divideUsePoints.get(i)); | ||
| 72 | + TradePriceCalculatorHelper.recountPayPrice(orderItem); | ||
| 73 | + } | ||
| 74 | + TradePriceCalculatorHelper.recountAllPrice(result); | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + private boolean checkDeductPointEnable(MemberPointConfigRespDTO config) { | ||
| 78 | + if (config == null) { | ||
| 79 | + return false; | ||
| 26 | } | 80 | } |
| 81 | + if (!BooleanUtil.isTrue(config.getTradeDeductEnable())) { | ||
| 82 | + return false; | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + // 有没有配置:1 积分抵扣多少分 | ||
| 86 | + return config.getTradeDeductUnitPrice() != null && config.getTradeDeductUnitPrice() > 0; | ||
| 27 | } | 87 | } |
| 28 | 88 | ||
| 89 | + private Integer calculatePointPrice(MemberPointConfigRespDTO config, Integer usePoint, TradePriceCalculateRespBO result) { | ||
| 90 | + // 每个订单最多可以使用的积分数量 | ||
| 91 | + if (config.getTradeDeductMaxPrice() != null && config.getTradeDeductMaxPrice() > 0) { | ||
| 92 | + usePoint = Math.min(usePoint, config.getTradeDeductMaxPrice()); | ||
| 93 | + } | ||
| 94 | + // 积分优惠金额(分) | ||
| 95 | + int pointPrice = usePoint * config.getTradeDeductUnitPrice(); | ||
| 96 | + // 0元购!!!:用户积分比较多时,积分可以抵扣的金额要大于支付金额, 这时需要根据支付金额反推使用多少积分 | ||
| 97 | + if (result.getPrice().getPayPrice() < pointPrice) { | ||
| 98 | + pointPrice = result.getPrice().getPayPrice(); | ||
| 99 | + // 反推需要扣除的积分 | ||
| 100 | + usePoint = NumberUtil.toBigDecimal(pointPrice) | ||
| 101 | + .divide(NumberUtil.toBigDecimal(config.getTradeDeductUnitPrice()), 0, RoundingMode.HALF_UP) | ||
| 102 | + .intValue(); | ||
| 103 | + } | ||
| 104 | + // 记录使用的积分 | ||
| 105 | + result.setUsePoint(usePoint); | ||
| 106 | + | ||
| 107 | + return pointPrice; | ||
| 108 | + } | ||
| 29 | } | 109 | } |
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 { | @@ -23,6 +23,10 @@ public interface TradePriceCalculator { | ||
| 23 | * 放在各种营销活动、优惠劵后面 TODO | 23 | * 放在各种营销活动、优惠劵后面 TODO |
| 24 | */ | 24 | */ |
| 25 | int ORDER_DELIVERY = 50; | 25 | int ORDER_DELIVERY = 50; |
| 26 | + /** | ||
| 27 | + * 赠送积分,放最后 | ||
| 28 | + */ | ||
| 29 | + int ORDER_POINT_GIVE = 999; | ||
| 26 | 30 | ||
| 27 | void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result); | 31 | void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result); |
| 28 | 32 |
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 { | @@ -58,7 +58,8 @@ public class TradePriceCalculatorHelper { | ||
| 58 | .setWeight(sku.getWeight()).setVolume(sku.getVolume()); | 58 | .setWeight(sku.getWeight()).setVolume(sku.getVolume()); |
| 59 | // spu 信息 | 59 | // spu 信息 |
| 60 | orderItem.setSpuName(spu.getName()).setCategoryId(spu.getCategoryId()) | 60 | orderItem.setSpuName(spu.getName()).setCategoryId(spu.getCategoryId()) |
| 61 | - .setDeliveryTemplateId(spu.getDeliveryTemplateId()); | 61 | + .setDeliveryTemplateId(spu.getDeliveryTemplateId()) |
| 62 | + .setGivePoint(spu.getGiveIntegral()).setUsePoint(0); | ||
| 62 | if (orderItem.getPicUrl() == null) { | 63 | if (orderItem.getPicUrl() == null) { |
| 63 | orderItem.setPicUrl(spu.getPicUrl()); | 64 | orderItem.setPicUrl(spu.getPicUrl()); |
| 64 | } | 65 | } |
| @@ -67,6 +68,7 @@ public class TradePriceCalculatorHelper { | @@ -67,6 +68,7 @@ public class TradePriceCalculatorHelper { | ||
| 67 | // 创建它的 Price 属性 | 68 | // 创建它的 Price 属性 |
| 68 | result.setPrice(new TradePriceCalculateRespBO.Price()); | 69 | result.setPrice(new TradePriceCalculateRespBO.Price()); |
| 69 | recountAllPrice(result); | 70 | recountAllPrice(result); |
| 71 | + recountAllGivePoint(result); | ||
| 70 | return result; | 72 | return result; |
| 71 | } | 73 | } |
| 72 | 74 | ||
| @@ -112,12 +114,21 @@ public class TradePriceCalculatorHelper { | @@ -112,12 +114,21 @@ public class TradePriceCalculatorHelper { | ||
| 112 | } | 114 | } |
| 113 | 115 | ||
| 114 | /** | 116 | /** |
| 117 | + * 基于订单项,重新计算赠送积分 | ||
| 118 | + * | ||
| 119 | + * @param result 计算结果 | ||
| 120 | + */ | ||
| 121 | + public static void recountAllGivePoint(TradePriceCalculateRespBO result) { | ||
| 122 | + result.setGivePoint(getSumValue(result.getItems(), item -> item.getSelected() ? item.getGivePoint() : 0, Integer::sum)); | ||
| 123 | + } | ||
| 124 | + | ||
| 125 | + /** | ||
| 115 | * 重新计算单个订单项的支付金额 | 126 | * 重新计算单个订单项的支付金额 |
| 116 | * | 127 | * |
| 117 | * @param orderItem 订单项 | 128 | * @param orderItem 订单项 |
| 118 | */ | 129 | */ |
| 119 | public static void recountPayPrice(TradePriceCalculateRespBO.OrderItem orderItem) { | 130 | public static void recountPayPrice(TradePriceCalculateRespBO.OrderItem orderItem) { |
| 120 | - orderItem.setPayPrice(orderItem.getPrice()* orderItem.getCount() | 131 | + orderItem.setPayPrice(orderItem.getPrice() * orderItem.getCount() |
| 121 | - orderItem.getDiscountPrice() | 132 | - orderItem.getDiscountPrice() |
| 122 | + orderItem.getDeliveryPrice() | 133 | + orderItem.getDeliveryPrice() |
| 123 | - orderItem.getCouponPrice() | 134 | - orderItem.getCouponPrice() |
| @@ -145,6 +156,12 @@ public class TradePriceCalculatorHelper { | @@ -145,6 +156,12 @@ public class TradePriceCalculatorHelper { | ||
| 145 | if (orderItem.getPointPrice() == null) { | 156 | if (orderItem.getPointPrice() == null) { |
| 146 | orderItem.setPointPrice(0); | 157 | orderItem.setPointPrice(0); |
| 147 | } | 158 | } |
| 159 | + if (orderItem.getUsePoint() == null) { | ||
| 160 | + orderItem.setUsePoint(0); | ||
| 161 | + } | ||
| 162 | + if (orderItem.getGivePoint() == null) { | ||
| 163 | + orderItem.setGivePoint(0); | ||
| 164 | + } | ||
| 148 | recountPayPrice(orderItem); | 165 | recountPayPrice(orderItem); |
| 149 | }); | 166 | }); |
| 150 | } | 167 | } |
| @@ -169,7 +186,7 @@ public class TradePriceCalculatorHelper { | @@ -169,7 +186,7 @@ public class TradePriceCalculatorHelper { | ||
| 169 | */ | 186 | */ |
| 170 | public static Integer calculateTotalCount(List<TradePriceCalculateRespBO.OrderItem> orderItems) { | 187 | public static Integer calculateTotalCount(List<TradePriceCalculateRespBO.OrderItem> orderItems) { |
| 171 | return getSumValue(orderItems, | 188 | return getSumValue(orderItems, |
| 172 | - orderItem -> orderItem.getSelected() ? orderItem.getCount() : 0, // 未选中的情况下,不计算数量 | 189 | + orderItem -> orderItem.getSelected() ? orderItem.getCount() : 0, // 未选中的情况下,不计算数量 |
| 173 | Integer::sum); | 190 | Integer::sum); |
| 174 | } | 191 | } |
| 175 | 192 | ||
| @@ -177,7 +194,7 @@ public class TradePriceCalculatorHelper { | @@ -177,7 +194,7 @@ public class TradePriceCalculatorHelper { | ||
| 177 | * 按照支付金额,返回每个订单项的分摊金额数组 | 194 | * 按照支付金额,返回每个订单项的分摊金额数组 |
| 178 | * | 195 | * |
| 179 | * @param orderItems 订单项数组 | 196 | * @param orderItems 订单项数组 |
| 180 | - * @param price 金额 | 197 | + * @param price 金额 |
| 181 | * @return 分摊金额数组,和传入的 orderItems 一一对应 | 198 | * @return 分摊金额数组,和传入的 orderItems 一一对应 |
| 182 | */ | 199 | */ |
| 183 | public static List<Integer> dividePrice(List<TradePriceCalculateRespBO.OrderItem> orderItems, Integer price) { | 200 | public static List<Integer> dividePrice(List<TradePriceCalculateRespBO.OrderItem> orderItems, Integer price) { |
| @@ -210,12 +227,12 @@ public class TradePriceCalculatorHelper { | @@ -210,12 +227,12 @@ public class TradePriceCalculatorHelper { | ||
| 210 | /** | 227 | /** |
| 211 | * 添加【匹配】单个 OrderItem 的营销明细 | 228 | * 添加【匹配】单个 OrderItem 的营销明细 |
| 212 | * | 229 | * |
| 213 | - * @param result 价格计算结果 | 230 | + * @param result 价格计算结果 |
| 214 | * @param orderItem 单个订单商品 SKU | 231 | * @param orderItem 单个订单商品 SKU |
| 215 | - * @param id 营销编号 | ||
| 216 | - * @param name 营销名字 | ||
| 217 | - * @param description 满足条件的提示 | ||
| 218 | - * @param type 营销类型 | 232 | + * @param id 营销编号 |
| 233 | + * @param name 营销名字 | ||
| 234 | + * @param description 满足条件的提示 | ||
| 235 | + * @param type 营销类型 | ||
| 219 | * @param discountPrice 单个订单商品 SKU 的优惠价格(总) | 236 | * @param discountPrice 单个订单商品 SKU 的优惠价格(总) |
| 220 | */ | 237 | */ |
| 221 | public static void addPromotion(TradePriceCalculateRespBO result, TradePriceCalculateRespBO.OrderItem orderItem, | 238 | public static void addPromotion(TradePriceCalculateRespBO result, TradePriceCalculateRespBO.OrderItem orderItem, |
| @@ -226,7 +243,7 @@ public class TradePriceCalculatorHelper { | @@ -226,7 +243,7 @@ public class TradePriceCalculatorHelper { | ||
| 226 | /** | 243 | /** |
| 227 | * 添加【匹配】多个 OrderItem 的营销明细 | 244 | * 添加【匹配】多个 OrderItem 的营销明细 |
| 228 | * | 245 | * |
| 229 | - * @param result 价格计算结果 | 246 | + * @param result 价格计算结果 |
| 230 | * @param orderItems 多个订单商品 SKU | 247 | * @param orderItems 多个订单商品 SKU |
| 231 | * @param id 营销编号 | 248 | * @param id 营销编号 |
| 232 | * @param name 营销名字 | 249 | * @param name 营销名字 |
| @@ -235,7 +252,7 @@ public class TradePriceCalculatorHelper { | @@ -235,7 +252,7 @@ public class TradePriceCalculatorHelper { | ||
| 235 | * @param discountPrices 多个订单商品 SKU 的优惠价格(总),和 orderItems 一一对应 | 252 | * @param discountPrices 多个订单商品 SKU 的优惠价格(总),和 orderItems 一一对应 |
| 236 | */ | 253 | */ |
| 237 | public static void addPromotion(TradePriceCalculateRespBO result, List<TradePriceCalculateRespBO.OrderItem> orderItems, | 254 | public static void addPromotion(TradePriceCalculateRespBO result, List<TradePriceCalculateRespBO.OrderItem> orderItems, |
| 238 | - Long id, String name, Integer type, String description, List<Integer> discountPrices) { | 255 | + Long id, String name, Integer type, String description, List<Integer> discountPrices) { |
| 239 | // 创建营销明细 Item | 256 | // 创建营销明细 Item |
| 240 | List<TradePriceCalculateRespBO.PromotionItem> promotionItems = new ArrayList<>(discountPrices.size()); | 257 | List<TradePriceCalculateRespBO.PromotionItem> promotionItems = new ArrayList<>(discountPrices.size()); |
| 241 | for (int i = 0; i < orderItems.size(); i++) { | 258 | for (int i = 0; i < orderItems.size(); i++) { |
| @@ -255,12 +272,12 @@ public class TradePriceCalculatorHelper { | @@ -255,12 +272,12 @@ public class TradePriceCalculatorHelper { | ||
| 255 | /** | 272 | /** |
| 256 | * 添加【不匹配】多个 OrderItem 的营销明细 | 273 | * 添加【不匹配】多个 OrderItem 的营销明细 |
| 257 | * | 274 | * |
| 258 | - * @param result 价格计算结果 | ||
| 259 | - * @param orderItems 多个订单商品 SKU | ||
| 260 | - * @param id 营销编号 | ||
| 261 | - * @param name 营销名字 | ||
| 262 | - * @param description 满足条件的提示 | ||
| 263 | - * @param type 营销类型 | 275 | + * @param result 价格计算结果 |
| 276 | + * @param orderItems 多个订单商品 SKU | ||
| 277 | + * @param id 营销编号 | ||
| 278 | + * @param name 营销名字 | ||
| 279 | + * @param description 满足条件的提示 | ||
| 280 | + * @param type 营销类型 | ||
| 264 | */ | 281 | */ |
| 265 | public static void addNotMatchPromotion(TradePriceCalculateRespBO result, List<TradePriceCalculateRespBO.OrderItem> orderItems, | 282 | public static void addNotMatchPromotion(TradePriceCalculateRespBO result, List<TradePriceCalculateRespBO.OrderItem> orderItems, |
| 266 | Long id, String name, Integer type, String description) { | 283 | Long id, String name, Integer type, String description) { |
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointApi.java
| 1 | package cn.iocoder.yudao.module.member.api.point; | 1 | package cn.iocoder.yudao.module.member.api.point; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.module.member.api.point.dto.MemberPointConfigRespDTO; | ||
| 3 | import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum; | 4 | import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum; |
| 4 | 5 | ||
| 5 | import javax.validation.constraints.Min; | 6 | import javax.validation.constraints.Min; |
| @@ -12,6 +13,13 @@ import javax.validation.constraints.Min; | @@ -12,6 +13,13 @@ import javax.validation.constraints.Min; | ||
| 12 | public interface MemberPointApi { | 13 | public interface MemberPointApi { |
| 13 | 14 | ||
| 14 | /** | 15 | /** |
| 16 | + * 获得积分配置 | ||
| 17 | + * | ||
| 18 | + * @return 积分配置 | ||
| 19 | + */ | ||
| 20 | + MemberPointConfigRespDTO getConfig(); | ||
| 21 | + | ||
| 22 | + /** | ||
| 15 | * 增加用户积分 | 23 | * 增加用户积分 |
| 16 | * | 24 | * |
| 17 | * @param userId 用户编号 | 25 | * @param userId 用户编号 |
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/point/dto/MemberPointConfigRespDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.member.api.point.dto; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * 用户信息 Response DTO | ||
| 7 | + * | ||
| 8 | + * @author 芋道源码 | ||
| 9 | + */ | ||
| 10 | +@Data | ||
| 11 | +public class MemberPointConfigRespDTO { | ||
| 12 | + /** | ||
| 13 | + * 积分抵扣开关 | ||
| 14 | + */ | ||
| 15 | + private Boolean tradeDeductEnable; | ||
| 16 | + /** | ||
| 17 | + * 积分抵扣,单位:分 | ||
| 18 | + * <p> | ||
| 19 | + * 1 积分抵扣多少分 | ||
| 20 | + */ | ||
| 21 | + private Integer tradeDeductUnitPrice; | ||
| 22 | + /** | ||
| 23 | + * 积分抵扣最大值 | ||
| 24 | + */ | ||
| 25 | + private Integer tradeDeductMaxPrice; | ||
| 26 | + /** | ||
| 27 | + * 1 元赠送多少分 | ||
| 28 | + */ | ||
| 29 | + private Integer tradeGivePoint; | ||
| 30 | +} |
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/MemberUserRespDTO.java
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 { | @@ -13,6 +13,7 @@ public interface ErrorCodeConstants { | ||
| 13 | ErrorCode USER_NOT_EXISTS = new ErrorCode(1004001000, "用户不存在"); | 13 | ErrorCode USER_NOT_EXISTS = new ErrorCode(1004001000, "用户不存在"); |
| 14 | ErrorCode USER_MOBILE_NOT_EXISTS = new ErrorCode(1004001001, "手机号未注册用户"); | 14 | ErrorCode USER_MOBILE_NOT_EXISTS = new ErrorCode(1004001001, "手机号未注册用户"); |
| 15 | ErrorCode USER_MOBILE_USED = new ErrorCode(1004001002, "修改手机失败,该手机号({})已经被使用"); | 15 | ErrorCode USER_MOBILE_USED = new ErrorCode(1004001002, "修改手机失败,该手机号({})已经被使用"); |
| 16 | + ErrorCode USER_POINT_NOT_ENOUGH = new ErrorCode(1004001003, "用户积分余额不足"); | ||
| 16 | 17 | ||
| 17 | // ========== AUTH 模块 1004003000 ========== | 18 | // ========== AUTH 模块 1004003000 ========== |
| 18 | ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1004003000, "登录失败,账号密码不正确"); | 19 | ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1004003000, "登录失败,账号密码不正确"); |
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 { | @@ -18,8 +18,10 @@ public enum MemberPointBizTypeEnum implements IntArrayValuable { | ||
| 18 | 18 | ||
| 19 | SIGN(1, "签到", "签到获得 {} 积分", true), | 19 | SIGN(1, "签到", "签到获得 {} 积分", true), |
| 20 | ORDER_REWARD(10, "订单奖励", "下单获得 {} 积分", true), | 20 | ORDER_REWARD(10, "订单奖励", "下单获得 {} 积分", true), |
| 21 | - ORDER_CANCEL(11, "订单取消", "退单获得 {} 积分", false), // 退回积分 | 21 | + ORDER_CANCEL(11, "订单取消", "订单取消,退还 {} 积分", true), // 退回积分 |
| 22 | ORDER_USE(12, "订单使用", "下单使用 {} 积分", false), // 扣减积分 | 22 | ORDER_USE(12, "订单使用", "下单使用 {} 积分", false), // 扣减积分 |
| 23 | + AFTER_SALE_REFUND_USED(13, "订单退款", "订单退款,退还 {} 积分", true), // 退回积分 | ||
| 24 | + AFTER_SALE_DEDUCT_GIVE(14, "订单退款", "订单退款,扣除赠送的 {} 积分", false), // 扣减积分 | ||
| 23 | ; | 25 | ; |
| 24 | 26 | ||
| 25 | /** | 27 | /** |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointApiImpl.java
| 1 | package cn.iocoder.yudao.module.member.api.point; | 1 | package cn.iocoder.yudao.module.member.api.point; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.lang.Assert; | ||
| 4 | +import cn.iocoder.yudao.module.member.api.point.dto.MemberPointConfigRespDTO; | ||
| 5 | +import cn.iocoder.yudao.module.member.convert.point.MemberPointConfigConvert; | ||
| 3 | import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum; | 6 | import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum; |
| 7 | +import cn.iocoder.yudao.module.member.service.point.MemberPointConfigService; | ||
| 4 | import cn.iocoder.yudao.module.member.service.point.MemberPointRecordService; | 8 | import cn.iocoder.yudao.module.member.service.point.MemberPointRecordService; |
| 5 | import org.springframework.stereotype.Service; | 9 | import org.springframework.stereotype.Service; |
| 6 | import org.springframework.validation.annotation.Validated; | 10 | import org.springframework.validation.annotation.Validated; |
| @@ -21,9 +25,17 @@ public class MemberPointApiImpl implements MemberPointApi { | @@ -21,9 +25,17 @@ public class MemberPointApiImpl implements MemberPointApi { | ||
| 21 | 25 | ||
| 22 | @Resource | 26 | @Resource |
| 23 | private MemberPointRecordService memberPointRecordService; | 27 | private MemberPointRecordService memberPointRecordService; |
| 28 | + @Resource | ||
| 29 | + private MemberPointConfigService memberPointConfigService; | ||
| 30 | + | ||
| 31 | + @Override | ||
| 32 | + public MemberPointConfigRespDTO getConfig() { | ||
| 33 | + return MemberPointConfigConvert.INSTANCE.convert01(memberPointConfigService.getPointConfig()); | ||
| 34 | + } | ||
| 24 | 35 | ||
| 25 | @Override | 36 | @Override |
| 26 | public void addPoint(Long userId, Integer point, Integer bizType, String bizId) { | 37 | public void addPoint(Long userId, Integer point, Integer bizType, String bizId) { |
| 38 | + Assert.isTrue(point > 0); | ||
| 27 | MemberPointBizTypeEnum bizTypeEnum = MemberPointBizTypeEnum.getByType(bizType); | 39 | MemberPointBizTypeEnum bizTypeEnum = MemberPointBizTypeEnum.getByType(bizType); |
| 28 | if (bizTypeEnum == null) { | 40 | if (bizTypeEnum == null) { |
| 29 | throw exception(POINT_RECORD_BIZ_NOT_SUPPORT); | 41 | throw exception(POINT_RECORD_BIZ_NOT_SUPPORT); |
| @@ -33,11 +45,12 @@ public class MemberPointApiImpl implements MemberPointApi { | @@ -33,11 +45,12 @@ public class MemberPointApiImpl implements MemberPointApi { | ||
| 33 | 45 | ||
| 34 | @Override | 46 | @Override |
| 35 | public void reducePoint(Long userId, Integer point, Integer bizType, String bizId) { | 47 | public void reducePoint(Long userId, Integer point, Integer bizType, String bizId) { |
| 48 | + Assert.isTrue(point > 0); | ||
| 36 | MemberPointBizTypeEnum bizTypeEnum = MemberPointBizTypeEnum.getByType(bizType); | 49 | MemberPointBizTypeEnum bizTypeEnum = MemberPointBizTypeEnum.getByType(bizType); |
| 37 | if (bizTypeEnum == null) { | 50 | if (bizTypeEnum == null) { |
| 38 | throw exception(POINT_RECORD_BIZ_NOT_SUPPORT); | 51 | throw exception(POINT_RECORD_BIZ_NOT_SUPPORT); |
| 39 | } | 52 | } |
| 40 | - memberPointRecordService.createPointRecord(userId, point, bizTypeEnum, bizId); | 53 | + memberPointRecordService.createPointRecord(userId, -point, bizTypeEnum, bizId); |
| 41 | } | 54 | } |
| 42 | 55 | ||
| 43 | } | 56 | } |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/point/MemberPointConfigConvert.java
| 1 | package cn.iocoder.yudao.module.member.convert.point; | 1 | package cn.iocoder.yudao.module.member.convert.point; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.module.member.api.point.dto.MemberPointConfigRespDTO; | ||
| 3 | import cn.iocoder.yudao.module.member.controller.admin.point.vo.config.MemberPointConfigRespVO; | 4 | import cn.iocoder.yudao.module.member.controller.admin.point.vo.config.MemberPointConfigRespVO; |
| 4 | import cn.iocoder.yudao.module.member.controller.admin.point.vo.config.MemberPointConfigSaveReqVO; | 5 | import cn.iocoder.yudao.module.member.controller.admin.point.vo.config.MemberPointConfigSaveReqVO; |
| 5 | import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointConfigDO; | 6 | import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointConfigDO; |
| @@ -20,4 +21,5 @@ public interface MemberPointConfigConvert { | @@ -20,4 +21,5 @@ public interface MemberPointConfigConvert { | ||
| 20 | 21 | ||
| 21 | MemberPointConfigDO convert(MemberPointConfigSaveReqVO bean); | 22 | MemberPointConfigDO convert(MemberPointConfigSaveReqVO bean); |
| 22 | 23 | ||
| 24 | + MemberPointConfigRespDTO convert01(MemberPointConfigDO pointConfig); | ||
| 23 | } | 25 | } |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MemberUserMapper.java
| 1 | package cn.iocoder.yudao.module.member.dal.mysql.user; | 1 | package cn.iocoder.yudao.module.member.dal.mysql.user; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | +import cn.hutool.core.lang.Assert; | ||
| 4 | import cn.hutool.core.util.StrUtil; | 5 | import cn.hutool.core.util.StrUtil; |
| 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | 7 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 7 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | 8 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 8 | import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO; | 9 | import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO; |
| 9 | import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; | 10 | import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; |
| 11 | +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | ||
| 10 | import org.apache.ibatis.annotations.Mapper; | 12 | import org.apache.ibatis.annotations.Mapper; |
| 11 | 13 | ||
| 12 | import java.util.List; | 14 | import java.util.List; |
| @@ -62,4 +64,33 @@ public interface MemberUserMapper extends BaseMapperX<MemberUserDO> { | @@ -62,4 +64,33 @@ public interface MemberUserMapper extends BaseMapperX<MemberUserDO> { | ||
| 62 | .apply("FIND_IN_SET({0}, tag_ids)", tagId)); | 64 | .apply("FIND_IN_SET({0}, tag_ids)", tagId)); |
| 63 | } | 65 | } |
| 64 | 66 | ||
| 67 | + /** | ||
| 68 | + * 更新用户积分(增加) | ||
| 69 | + * | ||
| 70 | + * @param id 用户编号 | ||
| 71 | + * @param incrCount 增加积分(正数) | ||
| 72 | + */ | ||
| 73 | + default void updatePointIncr(Long id, Integer incrCount) { | ||
| 74 | + Assert.isTrue(incrCount > 0); | ||
| 75 | + LambdaUpdateWrapper<MemberUserDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<MemberUserDO>() | ||
| 76 | + .setSql(" point = point + " + incrCount) | ||
| 77 | + .eq(MemberUserDO::getId, id); | ||
| 78 | + update(null, lambdaUpdateWrapper); | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + /** | ||
| 82 | + * 更新用户积分(减少) | ||
| 83 | + * | ||
| 84 | + * @param id 用户编号 | ||
| 85 | + * @param incrCount 增加积分(负数) | ||
| 86 | + * @return 更新行数 | ||
| 87 | + */ | ||
| 88 | + default int updatePointDecr(Long id, Integer incrCount) { | ||
| 89 | + Assert.isTrue(incrCount < 0); | ||
| 90 | + LambdaUpdateWrapper<MemberUserDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<MemberUserDO>() | ||
| 91 | + .setSql(" point = point + " + incrCount) // 负数,所以使用 + 号 | ||
| 92 | + .eq(MemberUserDO::getId, id); | ||
| 93 | + return update(null, lambdaUpdateWrapper); | ||
| 94 | + } | ||
| 95 | + | ||
| 65 | } | 96 | } |
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; | @@ -5,7 +5,6 @@ import cn.hutool.core.util.StrUtil; | ||
| 5 | import cn.iocoder.yudao.framework.common.pojo.PageParam; | 5 | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | import cn.iocoder.yudao.module.member.controller.admin.point.vo.recrod.MemberPointRecordPageReqVO; | 7 | import cn.iocoder.yudao.module.member.controller.admin.point.vo.recrod.MemberPointRecordPageReqVO; |
| 8 | -import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointConfigDO; | ||
| 9 | import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointRecordDO; | 8 | import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointRecordDO; |
| 10 | import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; | 9 | import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; |
| 11 | import cn.iocoder.yudao.module.member.dal.mysql.point.MemberPointRecordMapper; | 10 | import cn.iocoder.yudao.module.member.dal.mysql.point.MemberPointRecordMapper; |
| @@ -14,6 +13,7 @@ import cn.iocoder.yudao.module.member.service.user.MemberUserService; | @@ -14,6 +13,7 @@ import cn.iocoder.yudao.module.member.service.user.MemberUserService; | ||
| 14 | import lombok.extern.slf4j.Slf4j; | 13 | import lombok.extern.slf4j.Slf4j; |
| 15 | import org.apache.commons.lang3.StringUtils; | 14 | import org.apache.commons.lang3.StringUtils; |
| 16 | import org.springframework.stereotype.Service; | 15 | import org.springframework.stereotype.Service; |
| 16 | +import org.springframework.transaction.annotation.Transactional; | ||
| 17 | import org.springframework.util.CollectionUtils; | 17 | import org.springframework.util.CollectionUtils; |
| 18 | import org.springframework.validation.annotation.Validated; | 18 | import org.springframework.validation.annotation.Validated; |
| 19 | 19 | ||
| @@ -21,7 +21,9 @@ import javax.annotation.Resource; | @@ -21,7 +21,9 @@ import javax.annotation.Resource; | ||
| 21 | import java.util.List; | 21 | import java.util.List; |
| 22 | import java.util.Set; | 22 | import java.util.Set; |
| 23 | 23 | ||
| 24 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 24 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | 25 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| 26 | +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.USER_POINT_NOT_ENOUGH; | ||
| 25 | 27 | ||
| 26 | 28 | ||
| 27 | /** | 29 | /** |
| @@ -36,8 +38,6 @@ public class MemberPointRecordServiceImpl implements MemberPointRecordService { | @@ -36,8 +38,6 @@ public class MemberPointRecordServiceImpl implements MemberPointRecordService { | ||
| 36 | 38 | ||
| 37 | @Resource | 39 | @Resource |
| 38 | private MemberPointRecordMapper memberPointRecordMapper; | 40 | private MemberPointRecordMapper memberPointRecordMapper; |
| 39 | - @Resource | ||
| 40 | - private MemberPointConfigService memberPointConfigService; | ||
| 41 | 41 | ||
| 42 | @Resource | 42 | @Resource |
| 43 | private MemberUserService memberUserService; | 43 | private MemberUserService memberUserService; |
| @@ -64,32 +64,28 @@ public class MemberPointRecordServiceImpl implements MemberPointRecordService { | @@ -64,32 +64,28 @@ public class MemberPointRecordServiceImpl implements MemberPointRecordService { | ||
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | @Override | 66 | @Override |
| 67 | + @Transactional(rollbackFor = Exception.class) | ||
| 67 | public void createPointRecord(Long userId, Integer point, MemberPointBizTypeEnum bizType, String bizId) { | 68 | public void createPointRecord(Long userId, Integer point, MemberPointBizTypeEnum bizType, String bizId) { |
| 68 | - MemberPointConfigDO pointConfig = memberPointConfigService.getPointConfig(); | ||
| 69 | - if (pointConfig == null || pointConfig.getTradeGivePoint() == null) { | ||
| 70 | - log.error("[createPointRecord][增加积分失败:tradeGivePoint 未配置,userId({}) point({}) bizType({}) bizId({})]", | ||
| 71 | - userId, point, bizType.getType(), bizId); | ||
| 72 | - return; | 69 | + // 1. 校验用户积分余额 |
| 70 | + MemberUserDO user = memberUserService.getUser(userId); | ||
| 71 | + Integer userPoint = ObjectUtil.defaultIfNull(user.getPoint(), 0); | ||
| 72 | + int totalPoint = userPoint + point; // 用户变动后的积分 | ||
| 73 | + if (totalPoint < 0) { | ||
| 74 | + throw exception(USER_POINT_NOT_ENOUGH); | ||
| 73 | } | 75 | } |
| 74 | 76 | ||
| 75 | - // 1. 根据配置的比例,换算实际的积分 | ||
| 76 | - point = point * pointConfig.getTradeGivePoint(); | ||
| 77 | - if (!bizType.isAdd() && point > 0) { | ||
| 78 | - point = -point; | 77 | + // 2. 更新用户积分 |
| 78 | + boolean success = memberUserService.updateUserPoint(userId, point); | ||
| 79 | + if (!success) { | ||
| 80 | + throw exception(USER_POINT_NOT_ENOUGH); | ||
| 79 | } | 81 | } |
| 80 | 82 | ||
| 81 | - // 2. 增加积分记录 | ||
| 82 | - MemberUserDO user = memberUserService.getUser(userId); | ||
| 83 | - Integer userPoint = ObjectUtil.defaultIfNull(user.getPoint(), 0); | ||
| 84 | - Integer totalPoint = userPoint + point; // 用户变动后的积分 | 83 | + // 3. 增加积分记录 |
| 85 | MemberPointRecordDO record = new MemberPointRecordDO() | 84 | MemberPointRecordDO record = new MemberPointRecordDO() |
| 86 | .setUserId(userId).setBizId(bizId).setBizType(bizType.getType()) | 85 | .setUserId(userId).setBizId(bizId).setBizType(bizType.getType()) |
| 87 | .setTitle(bizType.getName()).setDescription(StrUtil.format(bizType.getDescription(), point)) | 86 | .setTitle(bizType.getName()).setDescription(StrUtil.format(bizType.getDescription(), point)) |
| 88 | .setPoint(point).setTotalPoint(totalPoint); | 87 | .setPoint(point).setTotalPoint(totalPoint); |
| 89 | memberPointRecordMapper.insert(record); | 88 | memberPointRecordMapper.insert(record); |
| 90 | - | ||
| 91 | - // 3. 更新用户积分 | ||
| 92 | - memberUserService.updateUserPoint(userId, totalPoint); | ||
| 93 | } | 89 | } |
| 94 | 90 | ||
| 95 | } | 91 | } |
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 { | @@ -164,6 +164,7 @@ public interface MemberUserService { | ||
| 164 | * | 164 | * |
| 165 | * @param userId 用户编号 | 165 | * @param userId 用户编号 |
| 166 | * @param point 积分数量 | 166 | * @param point 积分数量 |
| 167 | + * @return 更新结果 | ||
| 167 | */ | 168 | */ |
| 168 | - void updateUserPoint(Long userId, Integer point); | 169 | + boolean updateUserPoint(Long userId, Integer point); |
| 169 | } | 170 | } |
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 { | @@ -260,8 +260,13 @@ public class MemberUserServiceImpl implements MemberUserService { | ||
| 260 | } | 260 | } |
| 261 | 261 | ||
| 262 | @Override | 262 | @Override |
| 263 | - public void updateUserPoint(Long userId, Integer point) { | ||
| 264 | - memberUserMapper.updateById(new MemberUserDO().setId(userId).setPoint(point)); | 263 | + public boolean updateUserPoint(Long id, Integer point) { |
| 264 | + if (point > 0) { | ||
| 265 | + memberUserMapper.updatePointIncr(id, point); | ||
| 266 | + } else if (point < 0) { | ||
| 267 | + return memberUserMapper.updatePointDecr(id, point) > 0; | ||
| 268 | + } | ||
| 269 | + return true; | ||
| 265 | } | 270 | } |
| 266 | 271 | ||
| 267 | } | 272 | } |