mirror of
				https://github.com/YunaiV/ruoyi-vue-pro.git
				synced 2025-10-31 02:28:03 +08:00 
			
		
		
		
	Merge branch 'develop' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into master-jdk17
This commit is contained in:
		| @ -0,0 +1,42 @@ | |||||||
|  | package cn.iocoder.yudao.module.promotion.api.point; | ||||||
|  |  | ||||||
|  | import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 积分商城活动 API 接口 | ||||||
|  |  * | ||||||
|  |  * @author HUIHUI | ||||||
|  |  */ | ||||||
|  | public interface PointActivityApi { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 【下单前】校验是否参与积分商城活动 | ||||||
|  |      * | ||||||
|  |      * 如果校验失败,则抛出业务异常 | ||||||
|  |      * | ||||||
|  |      * @param activityId 活动编号 | ||||||
|  |      * @param skuId      SKU 编号 | ||||||
|  |      * @param count      数量 | ||||||
|  |      * @return 积分商城商品信息 | ||||||
|  |      */ | ||||||
|  |     PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long skuId, Integer count); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 更新积分商城商品库存(减少) | ||||||
|  |      * | ||||||
|  |      * @param id    活动编号 | ||||||
|  |      * @param skuId sku 编号 | ||||||
|  |      * @param count 数量(正数) | ||||||
|  |      */ | ||||||
|  |     void updatePointStockDecr(Long id, Long skuId, Integer count); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 更新积分商城商品库存(增加) | ||||||
|  |      * | ||||||
|  |      * @param id    活动编号 | ||||||
|  |      * @param skuId sku 编号 | ||||||
|  |      * @param count 数量(正数) | ||||||
|  |      */ | ||||||
|  |     void updatePointStockIncr(Long id, Long skuId, Integer count); | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -0,0 +1,24 @@ | |||||||
|  | package cn.iocoder.yudao.module.promotion.api.point.dto; | ||||||
|  |  | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 校验参与积分商城 Response DTO | ||||||
|  |  */ | ||||||
|  | @Data | ||||||
|  | public class PointValidateJoinRespDTO { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 可兑换次数 | ||||||
|  |      */ | ||||||
|  |     private Integer count; | ||||||
|  |     /** | ||||||
|  |      * 所需兑换积分 | ||||||
|  |      */ | ||||||
|  |     private Integer point; | ||||||
|  |     /** | ||||||
|  |      * 所需兑换金额,单位:分 | ||||||
|  |      */ | ||||||
|  |     private Integer price; | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -50,6 +50,10 @@ public interface ErrorCodeConstants { | |||||||
|     ErrorCode POINT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_007_002, "积分商城活动已关闭,不能修改"); |     ErrorCode POINT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_007_002, "积分商城活动已关闭,不能修改"); | ||||||
|     ErrorCode POINT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1_013_007_003, "积分商城活动未关闭或未结束,不能删除"); |     ErrorCode POINT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1_013_007_003, "积分商城活动未关闭或未结束,不能删除"); | ||||||
|     ErrorCode POINT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_007_004, "积分商城活动已关闭,不能重复关闭"); |     ErrorCode POINT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_007_004, "积分商城活动已关闭,不能重复关闭"); | ||||||
|  |     ErrorCode POINT_ACTIVITY_JOIN_ACTIVITY_STATUS_CLOSED = new ErrorCode(1_013_007_005, "积分商品兑换失败,原因:积分商城活动已关闭"); | ||||||
|  |     ErrorCode POINT_ACTIVITY_JOIN_ACTIVITY_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_007_006, "积分商品兑换失败,原因:单次限购超出"); | ||||||
|  |     ErrorCode POINT_ACTIVITY_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS = new ErrorCode(1_013_007_007, "积分商品兑换失败,原因:商品不存在"); | ||||||
|  |     ErrorCode POINT_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1_013_007_008, "积分商品兑换失败,原因:积分商品库存不足"); | ||||||
|  |  | ||||||
|     // ========== 秒杀活动 1-013-008-000 ========== |     // ========== 秒杀活动 1-013-008-000 ========== | ||||||
|     ErrorCode SECKILL_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_008_000, "秒杀活动不存在"); |     ErrorCode SECKILL_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_008_000, "秒杀活动不存在"); | ||||||
|  | |||||||
| @ -0,0 +1,36 @@ | |||||||
|  | package cn.iocoder.yudao.module.promotion.api.point; | ||||||
|  |  | ||||||
|  | import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO; | ||||||
|  | import cn.iocoder.yudao.module.promotion.service.point.PointActivityService; | ||||||
|  | import jakarta.annotation.Resource; | ||||||
|  | import org.springframework.stereotype.Service; | ||||||
|  | import org.springframework.validation.annotation.Validated; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 积分商城活动 Api 接口实现类 | ||||||
|  |  * | ||||||
|  |  * @author HUIHUI | ||||||
|  |  */ | ||||||
|  | @Service | ||||||
|  | @Validated | ||||||
|  | public class PointActivityApiImpl implements PointActivityApi { | ||||||
|  |  | ||||||
|  |     @Resource | ||||||
|  |     private PointActivityService pointActivityService; | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long skuId, Integer count) { | ||||||
|  |         return pointActivityService.validateJoinPointActivity(activityId, skuId, count); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void updatePointStockDecr(Long id, Long skuId, Integer count) { | ||||||
|  |         pointActivityService.updatePointStockDecr(id, skuId, count); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void updatePointStockIncr(Long id, Long skuId, Integer count) { | ||||||
|  |         pointActivityService.updatePointStockIncr(id, skuId, count); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -76,8 +76,11 @@ public class AppPointActivityController { | |||||||
|  |  | ||||||
|         // 2. 拼接数据 |         // 2. 拼接数据 | ||||||
|         List<PointProductDO> products = pointActivityService.getPointProductListByActivityIds(Collections.singletonList(id)); |         List<PointProductDO> products = pointActivityService.getPointProductListByActivityIds(Collections.singletonList(id)); | ||||||
|         AppPointActivityDetailRespVO respVO = BeanUtils.toBean(activity, AppPointActivityDetailRespVO.class); |         PointProductDO minProduct = getMinObject(products, PointProductDO::getPoint); | ||||||
|         respVO.setProducts(BeanUtils.toBean(products, AppPointActivityDetailRespVO.Product.class)); |         assert minProduct != null; | ||||||
|  |         AppPointActivityDetailRespVO respVO = BeanUtils.toBean(activity, AppPointActivityDetailRespVO.class) | ||||||
|  |                 .setProducts(BeanUtils.toBean(products, AppPointActivityDetailRespVO.Product.class)) | ||||||
|  |                 .setPoint(minProduct.getPoint()).setPrice(minProduct.getPrice()); | ||||||
|         return success(respVO); |         return success(respVO); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | |||||||
| @ -30,6 +30,14 @@ public class AppPointActivityDetailRespVO { | |||||||
|     @Schema(description = "商品信息数组", requiredMode = Schema.RequiredMode.REQUIRED) |     @Schema(description = "商品信息数组", requiredMode = Schema.RequiredMode.REQUIRED) | ||||||
|     private List<Product> products; |     private List<Product> products; | ||||||
|  |  | ||||||
|  |     //======================= 显示所需兑换积分最少的 SKU 信息 ======================= | ||||||
|  |  | ||||||
|  |     @Schema(description = "兑换积分", requiredMode = Schema.RequiredMode.REQUIRED) | ||||||
|  |     private Integer point; | ||||||
|  |  | ||||||
|  |     @Schema(description = "兑换金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "15860") | ||||||
|  |     private Integer price; | ||||||
|  |  | ||||||
|     @Schema(description = "商品信息") |     @Schema(description = "商品信息") | ||||||
|     @Data |     @Data | ||||||
|     public static class Product { |     public static class Product { | ||||||
|  | |||||||
| @ -1,10 +1,12 @@ | |||||||
| package cn.iocoder.yudao.module.promotion.dal.mysql.point; | package cn.iocoder.yudao.module.promotion.dal.mysql.point; | ||||||
|  |  | ||||||
|  | import cn.hutool.core.lang.Assert; | ||||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||||
| import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||||||
| import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | ||||||
| import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO; | import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO; | ||||||
| import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointActivityDO; | import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointActivityDO; | ||||||
|  | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | ||||||
| import org.apache.ibatis.annotations.Mapper; | import org.apache.ibatis.annotations.Mapper; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @ -25,4 +27,33 @@ public interface PointActivityMapper extends BaseMapperX<PointActivityDO> { | |||||||
|                 .orderByDesc(PointActivityDO::getId)); |                 .orderByDesc(PointActivityDO::getId)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 更新活动库存(减少) | ||||||
|  |      * | ||||||
|  |      * @param id    活动编号 | ||||||
|  |      * @param count 扣减的库存数量(正数) | ||||||
|  |      * @return 影响的行数 | ||||||
|  |      */ | ||||||
|  |     default int updateStockDecr(Long id, int count) { | ||||||
|  |         Assert.isTrue(count > 0); | ||||||
|  |         return update(null, new LambdaUpdateWrapper<PointActivityDO>() | ||||||
|  |                 .eq(PointActivityDO::getId, id) | ||||||
|  |                 .ge(PointActivityDO::getStock, count) | ||||||
|  |                 .setSql("stock = stock - " + count)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 更新活动库存(增加) | ||||||
|  |      * | ||||||
|  |      * @param id    活动编号 | ||||||
|  |      * @param count 增加的库存数量(正数) | ||||||
|  |      * @return 影响的行数 | ||||||
|  |      */ | ||||||
|  |     default int updateStockIncr(Long id, int count) { | ||||||
|  |         Assert.isTrue(count > 0); | ||||||
|  |         return update(null, new LambdaUpdateWrapper<PointActivityDO>() | ||||||
|  |                 .eq(PointActivityDO::getId, id) | ||||||
|  |                 .setSql("stock = stock + " + count)); | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
| @ -1,5 +1,6 @@ | |||||||
| package cn.iocoder.yudao.module.promotion.dal.mysql.point; | package cn.iocoder.yudao.module.promotion.dal.mysql.point; | ||||||
|  |  | ||||||
|  | import cn.hutool.core.lang.Assert; | ||||||
| import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||||||
| import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointProductDO; | import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointProductDO; | ||||||
| import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | ||||||
| @ -29,4 +30,37 @@ public interface PointProductMapper extends BaseMapperX<PointProductDO> { | |||||||
|                 .eq(PointProductDO::getActivityId, pointProductDO.getActivityId())); |                 .eq(PointProductDO::getActivityId, pointProductDO.getActivityId())); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     default PointProductDO selectListByActivityIdAndSkuId(Long activityId, Long skuId) { | ||||||
|  |         return selectOne(PointProductDO::getActivityId, activityId, | ||||||
|  |                 PointProductDO::getSkuId, skuId); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 更新活动库存(减少) | ||||||
|  |      * | ||||||
|  |      * @param id    活动编号 | ||||||
|  |      * @param count 扣减的库存数量(减少库存) | ||||||
|  |      * @return 影响的行数 | ||||||
|  |      */ | ||||||
|  |     default int updateStockDecr(Long id, int count) { | ||||||
|  |         Assert.isTrue(count > 0); | ||||||
|  |         return update(null, new LambdaUpdateWrapper<PointProductDO>() | ||||||
|  |                 .eq(PointProductDO::getId, id) | ||||||
|  |                 .ge(PointProductDO::getStock, count) | ||||||
|  |                 .setSql("stock = stock - " + count)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 更新活动库存(增加) | ||||||
|  |      * | ||||||
|  |      * @param id    活动编号 | ||||||
|  |      * @param count 需要增加的库存(增加库存) | ||||||
|  |      * @return 影响的行数 | ||||||
|  |      */ | ||||||
|  |     default int updateStockIncr(Long id, int count) { | ||||||
|  |         Assert.isTrue(count > 0); | ||||||
|  |         return update(null, new LambdaUpdateWrapper<PointProductDO>() | ||||||
|  |                 .eq(PointProductDO::getId, id) | ||||||
|  |                 .setSql("stock = stock + " + count)); | ||||||
|  |     } | ||||||
| } | } | ||||||
| @ -1,6 +1,7 @@ | |||||||
| package cn.iocoder.yudao.module.promotion.service.point; | package cn.iocoder.yudao.module.promotion.service.point; | ||||||
|  |  | ||||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||||
|  | import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO; | ||||||
| import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO; | import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO; | ||||||
| import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivitySaveReqVO; | import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivitySaveReqVO; | ||||||
| import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointActivityDO; | import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointActivityDO; | ||||||
| @ -32,6 +33,24 @@ public interface PointActivityService { | |||||||
|      */ |      */ | ||||||
|     void updatePointActivity(@Valid PointActivitySaveReqVO updateReqVO); |     void updatePointActivity(@Valid PointActivitySaveReqVO updateReqVO); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 更新积分商城商品库存(减少) | ||||||
|  |      * | ||||||
|  |      * @param id    活动编号 | ||||||
|  |      * @param skuId sku 编号 | ||||||
|  |      * @param count 数量(正数) | ||||||
|  |      */ | ||||||
|  |     void updatePointStockDecr(Long id, Long skuId, Integer count); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 更新积分商城商品库存(增加) | ||||||
|  |      * | ||||||
|  |      * @param id    活动编号 | ||||||
|  |      * @param skuId sku 编号 | ||||||
|  |      * @param count 数量(正数) | ||||||
|  |      */ | ||||||
|  |     void updatePointStockIncr(Long id, Long skuId, Integer count); | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 关闭积分商城活动 |      * 关闭积分商城活动 | ||||||
|      * |      * | ||||||
| @ -78,4 +97,16 @@ public interface PointActivityService { | |||||||
|      */ |      */ | ||||||
|     List<PointProductDO> getPointProductListByActivityIds(Collection<Long> activityIds); |     List<PointProductDO> getPointProductListByActivityIds(Collection<Long> activityIds); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 【下单前】校验是否参与积分商城活动 | ||||||
|  |      * | ||||||
|  |      * 如果校验失败,则抛出业务异常 | ||||||
|  |      * | ||||||
|  |      * @param activityId 活动编号 | ||||||
|  |      * @param skuId      SKU 编号 | ||||||
|  |      * @param count      数量 | ||||||
|  |      * @return 积分商城商品信息 | ||||||
|  |      */ | ||||||
|  |     PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long skuId, Integer count); | ||||||
|  |  | ||||||
| } | } | ||||||
| @ -8,6 +8,7 @@ import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; | |||||||
| import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | ||||||
| import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; | import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; | ||||||
| import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; | import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; | ||||||
|  | import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO; | ||||||
| import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO; | import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO; | ||||||
| import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivitySaveReqVO; | import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivitySaveReqVO; | ||||||
| import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.product.PointProductSaveReqVO; | import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.product.PointProductSaveReqVO; | ||||||
| @ -102,6 +103,43 @@ public class PointActivityServiceImpl implements PointActivityService { | |||||||
|         updateSeckillProduct(updateObj, updateReqVO.getProducts()); |         updateSeckillProduct(updateObj, updateReqVO.getProducts()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     @Transactional(rollbackFor = Exception.class) | ||||||
|  |     public void updatePointStockDecr(Long id, Long skuId, Integer count) { | ||||||
|  |         // 1.1 校验活动库存是否充足 | ||||||
|  |         PointActivityDO activity = validatePointActivityExists(id); | ||||||
|  |         if (count > activity.getStock()) { | ||||||
|  |             throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL); | ||||||
|  |         } | ||||||
|  |         // 1.2 校验商品库存是否充足 | ||||||
|  |         PointProductDO product = pointProductMapper.selectListByActivityIdAndSkuId(id, skuId); | ||||||
|  |         if (product == null || count > product.getStock()) { | ||||||
|  |             throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // 2.1 更新活动商品库存 | ||||||
|  |         int updateCount = pointProductMapper.updateStockDecr(product.getId(), count); | ||||||
|  |         if (updateCount == 0) { | ||||||
|  |             throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // 2.2 更新活动库存 | ||||||
|  |         updateCount = pointActivityMapper.updateStockDecr(id, count); | ||||||
|  |         if (updateCount == 0) { | ||||||
|  |             throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     @Transactional(rollbackFor = Exception.class) | ||||||
|  |     public void updatePointStockIncr(Long id, Long skuId, Integer count) { | ||||||
|  |         PointProductDO product = pointProductMapper.selectListByActivityIdAndSkuId(id, skuId); | ||||||
|  |         // 更新活动商品库存 | ||||||
|  |         pointProductMapper.updateStockIncr(product.getId(), count); | ||||||
|  |         // 更新活动库存 | ||||||
|  |         pointActivityMapper.updateStockIncr(id, count); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     @Transactional(rollbackFor = Exception.class) |     @Transactional(rollbackFor = Exception.class) | ||||||
|     public void closePointActivity(Long id) { |     public void closePointActivity(Long id) { | ||||||
| @ -244,4 +282,28 @@ public class PointActivityServiceImpl implements PointActivityService { | |||||||
|         return pointProductMapper.selectListByActivityId(activityIds); |         return pointProductMapper.selectListByActivityId(activityIds); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long skuId, Integer count) { | ||||||
|  |         // 1. 校验积分商城活动是否存在 | ||||||
|  |         PointActivityDO activity = validatePointActivityExists(activityId); | ||||||
|  |         if (CommonStatusEnum.isDisable(activity.getStatus())) { | ||||||
|  |             throw exception(POINT_ACTIVITY_JOIN_ACTIVITY_STATUS_CLOSED); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // 2.1 校验积分商城商品是否存在 | ||||||
|  |         PointProductDO product = pointProductMapper.selectListByActivityIdAndSkuId(activityId, skuId); | ||||||
|  |         if (product == null) { | ||||||
|  |             throw exception(POINT_ACTIVITY_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS); | ||||||
|  |         } | ||||||
|  |         // 2.2 超过单次购买限制 | ||||||
|  |         if (count > product.getCount()) { | ||||||
|  |             throw exception(POINT_ACTIVITY_JOIN_ACTIVITY_SINGLE_LIMIT_COUNT_EXCEED); | ||||||
|  |         } | ||||||
|  |         // 2.2 校验库存是否充足 | ||||||
|  |         if (count > product.getStock()) { | ||||||
|  |             throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL); | ||||||
|  |         } | ||||||
|  |         return BeanUtils.toBean(product, PointValidateJoinRespDTO.class); | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
| @ -160,7 +160,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { | |||||||
|     public void updateSeckillStockDecr(Long id, Long skuId, Integer count) { |     public void updateSeckillStockDecr(Long id, Long skuId, Integer count) { | ||||||
|         // 1.1 校验活动库存是否充足 |         // 1.1 校验活动库存是否充足 | ||||||
|         SeckillActivityDO seckillActivity = validateSeckillActivityExists(id); |         SeckillActivityDO seckillActivity = validateSeckillActivityExists(id); | ||||||
|         if (count > seckillActivity.getTotalStock()) { |         if (count > seckillActivity.getStock()) { | ||||||
|             throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); |             throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); | ||||||
|         } |         } | ||||||
|         // 1.2 校验商品库存是否充足 |         // 1.2 校验商品库存是否充足 | ||||||
|  | |||||||
| @ -58,11 +58,12 @@ public interface ErrorCodeConstants { | |||||||
|  |  | ||||||
|     // ========== Price 相关 1-011-003-000 ============ |     // ========== Price 相关 1-011-003-000 ============ | ||||||
|     ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1_011_003_000, "支付价格计算异常,原因:价格小于等于 0"); |     ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1_011_003_000, "支付价格计算异常,原因:价格小于等于 0"); | ||||||
|     ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1_011_003_002, "计算快递运费异常,找不到对应的运费模板"); |     ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1_011_003_001, "计算快递运费异常,找不到对应的运费模板"); | ||||||
|     ErrorCode PRICE_CALCULATE_COUPON_NOT_MATCH_NORMAL_ORDER = new ErrorCode(1_011_003_004, "参与秒杀、拼团、砍价的营销商品,无法使用优惠劵"); |     ErrorCode PRICE_CALCULATE_COUPON_NOT_MATCH_NORMAL_ORDER = new ErrorCode(1_011_003_002, "参与秒杀、拼团、砍价的营销商品,无法使用优惠劵"); | ||||||
|     ErrorCode PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT = new ErrorCode(1_011_003_005, "参与秒杀的商品,超过了秒杀总限购数量"); |     ErrorCode PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT = new ErrorCode(1_011_003_003, "参与秒杀的商品,超过了秒杀总限购数量"); | ||||||
|     ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TYPE_ILLEGAL = new ErrorCode(1_011_003_006, "计算快递运费异常,配送方式不匹配"); |     ErrorCode PRICE_CALCULATE_POINT_TOTAL_LIMIT_COUNT = new ErrorCode(1_011_003_004, "参与积分活动的商品,超过了积分活动商品总限购数量"); | ||||||
|     ErrorCode PRICE_CALCULATE_COUPON_CAN_NOT_USE = new ErrorCode(1_011_003_007, "该优惠劵无法使用,原因:{}」"); |     ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TYPE_ILLEGAL = new ErrorCode(1_011_003_005, "计算快递运费异常,配送方式不匹配"); | ||||||
|  |     ErrorCode PRICE_CALCULATE_COUPON_CAN_NOT_USE = new ErrorCode(1_011_003_006, "该优惠劵无法使用,原因:{}」"); | ||||||
|  |  | ||||||
|     // ========== 物流 Express 模块 1-011-004-000 ========== |     // ========== 物流 Express 模块 1-011-004-000 ========== | ||||||
|     ErrorCode EXPRESS_NOT_EXISTS = new ErrorCode(1_011_004_000, "快递公司不存在"); |     ErrorCode EXPRESS_NOT_EXISTS = new ErrorCode(1_011_004_000, "快递公司不存在"); | ||||||
|  | |||||||
| @ -20,6 +20,7 @@ public enum TradeOrderTypeEnum implements IntArrayValuable { | |||||||
|     SECKILL(1, "秒杀订单"), |     SECKILL(1, "秒杀订单"), | ||||||
|     BARGAIN(2, "砍价订单"), |     BARGAIN(2, "砍价订单"), | ||||||
|     COMBINATION(3, "拼团订单"), |     COMBINATION(3, "拼团订单"), | ||||||
|  |     POINT(4, "积分商城"), | ||||||
|     ; |     ; | ||||||
|  |  | ||||||
|     public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderTypeEnum::getType).toArray(); |     public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderTypeEnum::getType).toArray(); | ||||||
| @ -54,4 +55,8 @@ public enum TradeOrderTypeEnum implements IntArrayValuable { | |||||||
|         return ObjectUtil.equal(type, COMBINATION.getType()); |         return ObjectUtil.equal(type, COMBINATION.getType()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public static boolean isPoint(Integer type) { | ||||||
|  |         return ObjectUtil.equal(type, POINT.getType()); | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -6,13 +6,13 @@ import cn.iocoder.yudao.framework.common.validation.Mobile; | |||||||
| import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; | import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; | ||||||
| import com.fasterxml.jackson.annotation.JsonIgnore; | import com.fasterxml.jackson.annotation.JsonIgnore; | ||||||
| import io.swagger.v3.oas.annotations.media.Schema; | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
| import lombok.Data; |  | ||||||
|  |  | ||||||
| import jakarta.validation.Valid; | import jakarta.validation.Valid; | ||||||
| import jakarta.validation.constraints.AssertTrue; | import jakarta.validation.constraints.AssertTrue; | ||||||
| import jakarta.validation.constraints.Min; | import jakarta.validation.constraints.Min; | ||||||
| import jakarta.validation.constraints.NotEmpty; | import jakarta.validation.constraints.NotEmpty; | ||||||
| import jakarta.validation.constraints.NotNull; | import jakarta.validation.constraints.NotNull; | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
| @Schema(description = "用户 App - 交易订单结算 Request VO") | @Schema(description = "用户 App - 交易订单结算 Request VO") | ||||||
| @ -62,6 +62,10 @@ public class AppTradeOrderSettlementReqVO { | |||||||
|     @Schema(description = "砍价记录编号", example = "123") |     @Schema(description = "砍价记录编号", example = "123") | ||||||
|     private Long bargainRecordId; |     private Long bargainRecordId; | ||||||
|  |  | ||||||
|  |     // ========== 积分商城活动相关字段 ========== | ||||||
|  |     @Schema(description = "积分商城活动编号", example = "123") | ||||||
|  |     private Long pointActivityId; | ||||||
|  |  | ||||||
|     @AssertTrue(message = "活动商品每次只能购买一种规格") |     @AssertTrue(message = "活动商品每次只能购买一种规格") | ||||||
|     @JsonIgnore |     @JsonIgnore | ||||||
|     public boolean isValidActivityItems() { |     public boolean isValidActivityItems() { | ||||||
|  | |||||||
| @ -219,7 +219,8 @@ public interface TradeOrderConvert { | |||||||
|                 .setSeckillActivityId(settlementReqVO.getSeckillActivityId()) |                 .setSeckillActivityId(settlementReqVO.getSeckillActivityId()) | ||||||
|                 .setBargainRecordId(settlementReqVO.getBargainRecordId()) |                 .setBargainRecordId(settlementReqVO.getBargainRecordId()) | ||||||
|                 .setCombinationActivityId(settlementReqVO.getCombinationActivityId()) |                 .setCombinationActivityId(settlementReqVO.getCombinationActivityId()) | ||||||
|                 .setCombinationHeadId(settlementReqVO.getCombinationHeadId()); |                 .setCombinationHeadId(settlementReqVO.getCombinationHeadId()) | ||||||
|  |                 .setPointActivityId(settlementReqVO.getPointActivityId()); | ||||||
|         // 商品项的构建 |         // 商品项的构建 | ||||||
|         Map<Long, CartDO> cartMap = convertMap(cartList, CartDO::getId); |         Map<Long, CartDO> cartMap = convertMap(cartList, CartDO::getId); | ||||||
|         for (AppTradeOrderSettlementReqVO.Item item : settlementReqVO.getItems()) { |         for (AppTradeOrderSettlementReqVO.Item item : settlementReqVO.getItems()) { | ||||||
|  | |||||||
| @ -353,4 +353,11 @@ public class TradeOrderDO extends BaseDO { | |||||||
|      */ |      */ | ||||||
|     private Long combinationRecordId; |     private Long combinationRecordId; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 积分商城活动的编号 | ||||||
|  |      * | ||||||
|  |      * 关联 PointActivityDO 的 id 字段 | ||||||
|  |      */ | ||||||
|  |     private Long pointActivityId; | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -245,7 +245,10 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 3. 生成预支付 |         // 3. 生成预支付 | ||||||
|  |         // 特殊情况:积分兑换时,可能支付金额为零 | ||||||
|  |         if (order.getPayPrice() > 0) { | ||||||
|             createPayOrder(order, orderItems); |             createPayOrder(order, orderItems); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         // 4. 插入订单日志 |         // 4. 插入订单日志 | ||||||
|         TradeOrderLogUtils.setOrderInfo(order.getId(), null, order.getStatus()); |         TradeOrderLogUtils.setOrderInfo(order.getId(), null, order.getStatus()); | ||||||
|  | |||||||
| @ -0,0 +1,71 @@ | |||||||
|  | package cn.iocoder.yudao.module.trade.service.order.handler; | ||||||
|  |  | ||||||
|  | import cn.hutool.core.collection.CollUtil; | ||||||
|  | import cn.hutool.core.lang.Assert; | ||||||
|  | import cn.iocoder.yudao.module.promotion.api.point.PointActivityApi; | ||||||
|  | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; | ||||||
|  | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; | ||||||
|  | import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; | ||||||
|  | import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; | ||||||
|  | import jakarta.annotation.Resource; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Objects; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 积分商城活动订单的 {@link TradeOrderHandler} 实现类 | ||||||
|  |  * | ||||||
|  |  * @author HUIHUI | ||||||
|  |  */ | ||||||
|  | @Component | ||||||
|  | public class TradePointOrderHandler implements TradeOrderHandler { | ||||||
|  |  | ||||||
|  |     @Resource | ||||||
|  |     private PointActivityApi pointActivityApi; | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void beforeOrderCreate(TradeOrderDO order, List<TradeOrderItemDO> orderItems) { | ||||||
|  |         if (!TradeOrderTypeEnum.isPoint(order.getType())) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         // 明确校验一下 | ||||||
|  |         Assert.isTrue(orderItems.size() == 1, "积分商城活动兑换商品兑换时,只允许选择一个商品"); | ||||||
|  |  | ||||||
|  |         // 扣减积分商城活动的库存 | ||||||
|  |         pointActivityApi.updatePointStockDecr(order.getPointActivityId(), | ||||||
|  |                 orderItems.get(0).getSkuId(), orderItems.get(0).getCount()); | ||||||
|  |  | ||||||
|  |         // 如果支付金额为 0,则直接设置为已支付 | ||||||
|  |         if (Objects.equals(order.getPayPrice(), 0)) { | ||||||
|  |             order.setPayStatus(true).setStatus(TradeOrderStatusEnum.UNDELIVERED.getStatus()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void afterCancelOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems) { | ||||||
|  |         if (!TradeOrderTypeEnum.isPoint(order.getType())) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         // 明确校验一下 | ||||||
|  |         Assert.isTrue(orderItems.size() == 1, "积分商城活动兑换商品兑换时,只允许选择一个商品"); | ||||||
|  |  | ||||||
|  |         // 售后的订单项,已经在 afterCancelOrderItem 回滚库存,所以这里不需要重复回滚 | ||||||
|  |         orderItems = filterOrderItemListByNoneAfterSale(orderItems); | ||||||
|  |         if (CollUtil.isEmpty(orderItems)) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         afterCancelOrderItem(order, orderItems.get(0)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void afterCancelOrderItem(TradeOrderDO order, TradeOrderItemDO orderItem) { | ||||||
|  |         if (!TradeOrderTypeEnum.isPoint(order.getType())) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         // 恢复积分商城活动的库存 | ||||||
|  |         pointActivityApi.updatePointStockIncr(order.getPointActivityId(), | ||||||
|  |                 orderItem.getSkuId(), orderItem.getCount()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -69,7 +69,8 @@ public class TradePriceServiceImpl implements TradePriceService { | |||||||
|                 .buildCalculateResp(calculateReqBO, spuList, skuList); |                 .buildCalculateResp(calculateReqBO, spuList, skuList); | ||||||
|         priceCalculators.forEach(calculator -> calculator.calculate(calculateReqBO, calculateRespBO)); |         priceCalculators.forEach(calculator -> calculator.calculate(calculateReqBO, calculateRespBO)); | ||||||
|         // 2.2  如果最终支付金额小于等于 0,则抛出业务异常 |         // 2.2  如果最终支付金额小于等于 0,则抛出业务异常 | ||||||
|         if (calculateRespBO.getPrice().getPayPrice() <= 0) { |         if (calculateReqBO.getPointActivityId() == null // 积分订单,允许支付金额为 0 | ||||||
|  |                 && calculateRespBO.getPrice().getPayPrice() <= 0) { | ||||||
|             log.error("[calculatePrice][价格计算不正确,请求 calculateReqDTO({}),结果 priceCalculate({})]", |             log.error("[calculatePrice][价格计算不正确,请求 calculateReqDTO({}),结果 priceCalculate({})]", | ||||||
|                     calculateReqBO, calculateRespBO); |                     calculateReqBO, calculateRespBO); | ||||||
|             throw exception(PRICE_CALCULATE_PAY_PRICE_ILLEGAL); |             throw exception(PRICE_CALCULATE_PAY_PRICE_ILLEGAL); | ||||||
|  | |||||||
| @ -1,11 +1,11 @@ | |||||||
| package cn.iocoder.yudao.module.trade.service.price.bo; | package cn.iocoder.yudao.module.trade.service.price.bo; | ||||||
|  |  | ||||||
| import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; | import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; | ||||||
| import lombok.Data; |  | ||||||
|  |  | ||||||
| import jakarta.validation.Valid; | import jakarta.validation.Valid; | ||||||
| import jakarta.validation.constraints.Min; | import jakarta.validation.constraints.Min; | ||||||
| import jakarta.validation.constraints.NotNull; | import jakarta.validation.constraints.NotNull; | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @ -84,6 +84,12 @@ public class TradePriceCalculateReqBO { | |||||||
|      */ |      */ | ||||||
|     private Long bargainRecordId; |     private Long bargainRecordId; | ||||||
|  |  | ||||||
|  |     // ========== 积分商城活动相关字段 ========== | ||||||
|  |     /** | ||||||
|  |      * 积分商城活动编号 | ||||||
|  |      */ | ||||||
|  |     private Long pointActivityId; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 商品 SKU |      * 商品 SKU | ||||||
|      */ |      */ | ||||||
|  | |||||||
| @ -0,0 +1,94 @@ | |||||||
|  | package cn.iocoder.yudao.module.trade.service.price.calculator; | ||||||
|  |  | ||||||
|  | import cn.hutool.core.lang.Assert; | ||||||
|  | import cn.hutool.core.util.ObjectUtil; | ||||||
|  | import cn.hutool.core.util.StrUtil; | ||||||
|  | import cn.iocoder.yudao.module.member.api.user.MemberUserApi; | ||||||
|  | import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; | ||||||
|  | import cn.iocoder.yudao.module.promotion.api.point.PointActivityApi; | ||||||
|  | import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO; | ||||||
|  | import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; | ||||||
|  | import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; | ||||||
|  | import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; | ||||||
|  | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | ||||||
|  | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | ||||||
|  | import jakarta.annotation.Resource; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import org.springframework.core.annotation.Order; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  |  | ||||||
|  | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||||
|  | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_POINT_TOTAL_LIMIT_COUNT; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 积分商城的 {@link TradePriceCalculator} 实现类 | ||||||
|  |  * | ||||||
|  |  * @author owen | ||||||
|  |  */ | ||||||
|  | @Component | ||||||
|  | @Order(TradePriceCalculator.ORDER_POINT_ACTIVITY) | ||||||
|  | @Slf4j | ||||||
|  | public class TradePointActivityPriceCalculator implements TradePriceCalculator { | ||||||
|  |  | ||||||
|  |     @Resource | ||||||
|  |     private PointActivityApi pointActivityApi; | ||||||
|  |     @Resource | ||||||
|  |     private MemberUserApi memberUserApi; | ||||||
|  |  | ||||||
|  |     @Resource | ||||||
|  |     private TradeOrderQueryService tradeOrderQueryService; | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { | ||||||
|  |         // 1.1 判断订单类型是否为积分商城活动 | ||||||
|  |         if (ObjectUtil.notEqual(result.getType(), TradeOrderTypeEnum.POINT.getType())) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         // 1.2 初始化积分 | ||||||
|  |         MemberUserRespDTO user = memberUserApi.getUser(param.getUserId()); | ||||||
|  |         result.setTotalPoint(user.getPoint()).setUsePoint(0); | ||||||
|  |  | ||||||
|  |         // 1.3 校验用户积分余额 | ||||||
|  |         if (user.getPoint() == null || user.getPoint() <= 0) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Assert.isTrue(param.getItems().size() == 1, "积分商城兑换商品时,只允许选择一个商品"); | ||||||
|  |         // 2. 校验是否可以参与积分商城活动 | ||||||
|  |         TradePriceCalculateRespBO.OrderItem orderItem = result.getItems().get(0); | ||||||
|  |         PointValidateJoinRespDTO activity = validateJoinSeckill( | ||||||
|  |                 param.getUserId(), param.getPointActivityId(), | ||||||
|  |                 orderItem.getSkuId(), orderItem.getCount()); | ||||||
|  |  | ||||||
|  |         // 3.1 记录优惠明细 | ||||||
|  |         int discountPrice = orderItem.getPayPrice(); // 情况一:单使用积分兑换 | ||||||
|  |         Assert.isTrue(activity.getPoint() >= 1, "积分商城商品兑换积分必须大于 1"); | ||||||
|  |         result.setUsePoint(activity.getPoint() * orderItem.getCount()); | ||||||
|  |         orderItem.setUsePoint(activity.getPoint() * orderItem.getCount()); | ||||||
|  |         if (activity.getPrice() != null && activity.getPrice() > 0) { // 情况二:积分 + 金额 | ||||||
|  |             discountPrice = orderItem.getPayPrice() - activity.getPrice() * orderItem.getCount(); | ||||||
|  |         } | ||||||
|  |         // 3.2 记录优惠明细 | ||||||
|  |         TradePriceCalculatorHelper.addPromotion(result, orderItem, | ||||||
|  |                 param.getPointActivityId(), "积分商城活动", PromotionTypeEnum.POINT.getType(), | ||||||
|  |                 StrUtil.format("积分商城活动:省 {} 元", TradePriceCalculatorHelper.formatPrice(discountPrice)), | ||||||
|  |                 discountPrice); | ||||||
|  |  | ||||||
|  |         // 3.3 更新 SKU 优惠金额 | ||||||
|  |         orderItem.setDiscountPrice(orderItem.getDiscountPrice() + discountPrice); | ||||||
|  |         TradePriceCalculatorHelper.recountPayPrice(orderItem); | ||||||
|  |         TradePriceCalculatorHelper.recountAllPrice(result); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private PointValidateJoinRespDTO validateJoinSeckill(Long userId, Long activityId, Long skuId, Integer count) { | ||||||
|  |         // 1. 校验是否可以参与积分商城活动 | ||||||
|  |         PointValidateJoinRespDTO pointValidateJoinRespDTO = pointActivityApi.validateJoinPointActivity(activityId, skuId, count); | ||||||
|  |         // 2. 校验总限购数量,目前只有 trade 有具体下单的数据,需要交给 trade 价格计算使用 | ||||||
|  |         int activityProductCount = tradeOrderQueryService.getSeckillProductCount(userId, activityId); | ||||||
|  |         if (activityProductCount + count > pointValidateJoinRespDTO.getCount()) { | ||||||
|  |             throw exception(PRICE_CALCULATE_POINT_TOTAL_LIMIT_COUNT); | ||||||
|  |         } | ||||||
|  |         return pointValidateJoinRespDTO; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -1,12 +1,14 @@ | |||||||
| package cn.iocoder.yudao.module.trade.service.price.calculator; | package cn.iocoder.yudao.module.trade.service.price.calculator; | ||||||
|  |  | ||||||
| import cn.hutool.core.util.BooleanUtil; | import cn.hutool.core.util.BooleanUtil; | ||||||
|  | import cn.hutool.core.util.ObjectUtil; | ||||||
| import cn.hutool.core.util.StrUtil; | import cn.hutool.core.util.StrUtil; | ||||||
| import cn.iocoder.yudao.module.member.api.config.MemberConfigApi; | import cn.iocoder.yudao.module.member.api.config.MemberConfigApi; | ||||||
| import cn.iocoder.yudao.module.member.api.config.dto.MemberConfigRespDTO; | import cn.iocoder.yudao.module.member.api.config.dto.MemberConfigRespDTO; | ||||||
| import cn.iocoder.yudao.module.member.api.user.MemberUserApi; | import cn.iocoder.yudao.module.member.api.user.MemberUserApi; | ||||||
| import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; | import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; | ||||||
| import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; | import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; | ||||||
|  | import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; | ||||||
| import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | ||||||
| import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | ||||||
| import jakarta.annotation.Resource; | import jakarta.annotation.Resource; | ||||||
| @ -37,6 +39,10 @@ public class TradePointUsePriceCalculator implements TradePriceCalculator { | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { |     public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { | ||||||
|  |         // 判断订单类型是否不为积分商城活动 | ||||||
|  |         if (ObjectUtil.equal(result.getType(), TradeOrderTypeEnum.POINT.getType())) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|         // 0. 初始化积分 |         // 0. 初始化积分 | ||||||
|         MemberUserRespDTO user = memberUserApi.getUser(param.getUserId()); |         MemberUserRespDTO user = memberUserApi.getUser(param.getUserId()); | ||||||
|         result.setTotalPoint(user.getPoint()).setUsePoint(0); |         result.setTotalPoint(user.getPoint()).setUsePoint(0); | ||||||
|  | |||||||
| @ -16,6 +16,7 @@ public interface TradePriceCalculator { | |||||||
|     int ORDER_SECKILL_ACTIVITY = 8; |     int ORDER_SECKILL_ACTIVITY = 8; | ||||||
|     int ORDER_BARGAIN_ACTIVITY = 8; |     int ORDER_BARGAIN_ACTIVITY = 8; | ||||||
|     int ORDER_COMBINATION_ACTIVITY = 8; |     int ORDER_COMBINATION_ACTIVITY = 8; | ||||||
|  |     int ORDER_POINT_ACTIVITY = 8; | ||||||
|  |  | ||||||
|     int ORDER_DISCOUNT_ACTIVITY = 10; |     int ORDER_DISCOUNT_ACTIVITY = 10; | ||||||
|     int ORDER_REWARD_ACTIVITY = 20; |     int ORDER_REWARD_ACTIVITY = 20; | ||||||
|  | |||||||
| @ -90,6 +90,9 @@ public class TradePriceCalculatorHelper { | |||||||
|         if (param.getBargainRecordId() != null) { |         if (param.getBargainRecordId() != null) { | ||||||
|             return TradeOrderTypeEnum.BARGAIN.getType(); |             return TradeOrderTypeEnum.BARGAIN.getType(); | ||||||
|         } |         } | ||||||
|  |         if (param.getPointActivityId() != null) { | ||||||
|  |             return TradeOrderTypeEnum.POINT.getType(); | ||||||
|  |         } | ||||||
|         return TradeOrderTypeEnum.NORMAL.getType(); |         return TradeOrderTypeEnum.NORMAL.getType(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | |||||||
| @ -8,11 +8,10 @@ import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; | |||||||
| import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; | import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; | ||||||
| import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | ||||||
| import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | ||||||
|  | import jakarta.annotation.Resource; | ||||||
| import org.springframework.core.annotation.Order; | import org.springframework.core.annotation.Order; | ||||||
| import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||||
|  |  | ||||||
| import jakarta.annotation.Resource; |  | ||||||
|  |  | ||||||
| import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||||
| import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT; | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT; | ||||||
|  |  | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV