diff --git a/sql/mysql/ruoyi-vue-pro.sql b/sql/mysql/ruoyi-vue-pro.sql index 443be2c2c..ef0da9f0a 100644 --- a/sql/mysql/ruoyi-vue-pro.sql +++ b/sql/mysql/ruoyi-vue-pro.sql @@ -1188,8 +1188,8 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1166, 2, '折扣', '2', 'promotion_discount_type', 0, 'primary', '', '优惠类型 - 折扣', '1', '2022-11-01 12:46:51', '1', '2022-11-01 12:50:08', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1167, 1, '固定日期', '1', 'promotion_coupon_template_validity_type', 0, 'default', '', '优惠劵模板的有限期类型 - 固定日期', '1', '2022-11-02 00:07:34', '1', '2022-11-04 00:07:49', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1168, 2, '领取之后', '2', 'promotion_coupon_template_validity_type', 0, 'default', '', '优惠劵模板的有限期类型 - 领取之后', '1', '2022-11-02 00:07:54', '1', '2022-11-04 00:07:52', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1169, 1, '通用卷', '1', 'promotion_product_scope', 0, 'default', '', '营销的商品范围 - 全部商品参与', '1', '2022-11-02 00:28:22', '1', '2023-09-01 23:42:49', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1170, 2, '商品卷', '2', 'promotion_product_scope', 0, 'default', '', '营销的商品范围 - 指定商品参与', '1', '2022-11-02 00:28:34', '1', '2023-09-01 23:42:54', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1169, 1, '通用券', '1', 'promotion_product_scope', 0, 'default', '', '营销的商品范围 - 全部商品参与', '1', '2022-11-02 00:28:22', '1', '2023-09-01 23:42:49', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1170, 2, '商品券', '2', 'promotion_product_scope', 0, 'default', '', '营销的商品范围 - 指定商品参与', '1', '2022-11-02 00:28:34', '1', '2023-09-01 23:42:54', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1171, 1, '已领取', '1', 'promotion_coupon_status', 0, 'primary', '', '优惠劵的状态 - 已领取', '1', '2022-11-04 00:15:08', '1', '2022-11-04 19:16:04', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1172, 2, '已使用', '2', 'promotion_coupon_status', 0, 'success', '', '优惠劵的状态 - 已使用', '1', '2022-11-04 00:15:21', '1', '2022-11-04 19:16:08', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1173, 3, '已过期', '3', 'promotion_coupon_status', 0, 'info', '', '优惠劵的状态 - 已过期', '1', '2022-11-04 00:15:43', '1', '2022-11-04 19:16:12', b'0'); @@ -1284,7 +1284,7 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1355, 5, '抽奖奖励', '5', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1356, 1, '快递发货', '1', 'trade_delivery_type', 0, '', '', '', '1', '2023-08-23 00:04:55', '1', '2023-08-23 00:04:55', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1357, 2, '用户自提', '2', 'trade_delivery_type', 0, '', '', '', '1', '2023-08-23 00:05:05', '1', '2023-08-23 00:05:05', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1358, 3, '品类卷', '3', 'promotion_product_scope', 0, 'default', '', '', '1', '2023-09-01 23:43:07', '1', '2023-09-01 23:43:07', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1358, 3, '品类券', '3', 'promotion_product_scope', 0, 'default', '', '', '1', '2023-09-01 23:43:07', '1', '2023-09-01 23:43:07', b'0'); COMMIT; -- ---------------------------- diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/dto/RewardActivityMatchRespDTO.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/dto/RewardActivityMatchRespDTO.java index 19f46a49a..6ae71a1d9 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/dto/RewardActivityMatchRespDTO.java +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/dto/RewardActivityMatchRespDTO.java @@ -68,7 +68,7 @@ public class RewardActivityMatchRespDTO { */ private List couponIds; /** - * 赠送的优惠卷数量的数组 + * 赠送的优惠券数量的数组 */ private List couponCounts; diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionProductScopeEnum.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionProductScopeEnum.java index 6ae9f9f46..882dc4aee 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionProductScopeEnum.java +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionProductScopeEnum.java @@ -15,9 +15,9 @@ import java.util.Arrays; @AllArgsConstructor public enum PromotionProductScopeEnum implements IntArrayValuable { - ALL(1, "通用卷"), // 全部商品 - SPU(2, "商品卷"), // 指定商品 - CATEGORY(3, "品类卷"), // 指定商品 + ALL(1, "通用券"), // 全部商品 + SPU(2, "商品券"), // 指定商品 + CATEGORY(3, "品类券"), // 指定品类 ; public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PromotionProductScopeEnum::getScope).toArray(); diff --git a/yudao-module-mall/yudao-module-promotion-biz/pom.xml b/yudao-module-mall/yudao-module-promotion-biz/pom.xml index 44d0e8967..c9a544c06 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/pom.xml +++ b/yudao-module-mall/yudao-module-promotion-biz/pom.xml @@ -45,6 +45,10 @@ cn.iocoder.boot yudao-spring-boot-starter-biz-operatelog + + cn.iocoder.boot + yudao-spring-boot-starter-biz-tenant + cn.iocoder.boot yudao-spring-boot-starter-biz-weixin diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponPageReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponPageReqVO.java index 11d61a518..75aa2f74b 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponPageReqVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponPageReqVO.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon; import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; @@ -8,6 +10,7 @@ import lombok.ToString; import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; +import java.util.Collection; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; @@ -21,6 +24,7 @@ public class CouponPageReqVO extends PageParam { private Long templateId; @Schema(description = "优惠码状态", example = "1") + @InEnum(value = CouponStatusEnum.class, message = "优惠劵状态,必须是 {value}") private Integer status; @Schema(description = "创建时间") @@ -30,4 +34,7 @@ public class CouponPageReqVO extends PageParam { @Schema(description = "用户昵称", example = "芋艿") private String nickname; + @Schema(description = "用户编号", example = "1") + private Collection userIds; + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplatePageReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplatePageReqVO.java index abc7134e1..551d076ea 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplatePageReqVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplatePageReqVO.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -33,8 +34,14 @@ public class CouponTemplatePageReqVO extends PageParam { @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] createTime; - @Schema(description = "可以领取的类型", example = "[1,2, 3]") + @Schema(description = "可以领取的类型", example = "[1, 2, 3]") @InEnum(value = CouponTakeTypeEnum.class, message = "可以领取的类型,必须是 {value}") private List canTakeTypes; + @Schema(description = "商品范围", example = "1") + @InEnum(value = PromotionProductScopeEnum.class, message = "商品范围,必须是 {value}") + private Integer productScope; + + @Schema(description = "商品范围编号", example = "1") + private Long productScopeValue; } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityBaseVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityBaseVO.java index 3cb3109f3..030a31a5d 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityBaseVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityBaseVO.java @@ -84,7 +84,7 @@ public class RewardActivityBaseVO { @Schema(description = "赠送的优惠劵编号的数组", example = "1,2,3") private List couponIds; - @Schema(description = "赠送的优惠卷数量的数组", example = "1,2,3") + @Schema(description = "赠送的优惠券数量的数组", example = "1,2,3") private List couponCounts; @AssertTrue(message = "优惠劵和数量必须一一对应") diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponController.java index 8a9b82bbb..f6b92eaae 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponController.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponController.java @@ -1,24 +1,27 @@ package cn.iocoder.yudao.module.promotion.controller.app.coupon; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; -import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponMatchReqVO; -import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponMatchRespVO; -import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponPageReqVO; -import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponRespVO; -import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.template.AppCouponTemplatePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.*; +import cn.iocoder.yudao.module.promotion.convert.coupon.CouponConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; +import cn.iocoder.yudao.module.promotion.service.coupon.CouponTemplateService; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; -import java.time.LocalDateTime; -import java.util.ArrayList; +import javax.validation.Valid; +import java.util.Collections; import java.util.List; -import java.util.Random; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; @@ -31,73 +34,40 @@ public class AppCouponController { @Resource private CouponService couponService; + @Resource + private CouponTemplateService couponTemplateService; - // TODO 芋艿:待实现 @PostMapping("/take") @Operation(summary = "领取优惠劵") - public CommonResult takeCoupon(@RequestBody AppCouponTemplatePageReqVO pageReqVO) { - return success(1L); + @Parameter(name = "templateId", description = "优惠券模板编号", required = true, example = "1024") + public CommonResult takeCoupon(@Valid @RequestBody AppCouponTakeReqVO reqVO) { + Long userId = getLoginUserId(); + // 领取 + couponService.takeCoupon(reqVO.getTemplateId(), CollUtil.newHashSet(userId), CouponTakeTypeEnum.USER); + // 检查是否可以继续领取 + CouponTemplateDO couponTemplate = couponTemplateService.getCouponTemplate(reqVO.getTemplateId()); + boolean canTakeAgain = true; + if (couponTemplate.getTakeLimitCount() != null && couponTemplate.getTakeLimitCount() > 0) { + Integer takeCount = MapUtil.getInt(couponService.getTakeCountMapByTemplateIds( + Collections.singleton(reqVO.getTemplateId()), userId), reqVO.getTemplateId(), 0); + canTakeAgain = takeCount < couponTemplate.getTakeLimitCount(); + } + return success(canTakeAgain); } - // TODO 芋艿:待实现 @GetMapping("/match-list") @Operation(summary = "获得匹配指定商品的优惠劵列表") public CommonResult> getMatchCouponList(AppCouponMatchReqVO matchReqVO) { - List list = new ArrayList<>(); - Random random = new Random(); - for (int i = 0; i < 10; i++) { - AppCouponMatchRespVO vo = new AppCouponMatchRespVO(); - vo.setId(i + 1L); - vo.setName("优惠劵" + (i + 1)); - vo.setUsePrice(random.nextInt(100) * 100); - vo.setValidStartTime(LocalDateTime.now().plusDays(random.nextInt(10))); - vo.setValidEndTime(LocalDateTime.now().plusDays(random.nextInt(20) + 10)); - vo.setDiscountType(random.nextInt(2) + 1); - if (vo.getDiscountType() == 1) { - vo.setDiscountPercent(null); - vo.setDiscountPrice(random.nextInt(50) * 100); - vo.setDiscountLimitPrice(null); - } else { - vo.setDiscountPercent(random.nextInt(90) + 10); - vo.setDiscountPrice(null); - vo.setDiscountLimitPrice(random.nextInt(200) * 100); - } - vo.setMatch(random.nextBoolean()); - if (!vo.getMatch()) { - vo.setDescription("不符合条件噢"); - } - list.add(vo); - } - return success(list); + // todo: 优惠金额倒序 + return success(CouponConvert.INSTANCE.convertList(couponService.getMatchCouponList(getLoginUserId(), matchReqVO))); } - // TODO 芋艿:待实现 @GetMapping("/page") @Operation(summary = "优惠劵列表", description = "我的优惠劵") public CommonResult> takeCoupon(AppCouponPageReqVO pageReqVO) { - List list = new ArrayList<>(); - Random random = new Random(); - for (int i = 0; i < 10; i++) { - AppCouponRespVO vo = new AppCouponRespVO(); - vo.setId(i + 1L); - vo.setName("优惠劵" + (i + 1)); - vo.setStatus(pageReqVO.getStatus()); - vo.setUsePrice(random.nextInt(100) * 100); - vo.setValidStartTime(LocalDateTime.now().plusDays(random.nextInt(10))); - vo.setValidEndTime(LocalDateTime.now().plusDays(random.nextInt(20) + 10)); - vo.setDiscountType(random.nextInt(2) + 1); - if (vo.getDiscountType() == 1) { - vo.setDiscountPercent(null); - vo.setDiscountPrice(random.nextInt(50) * 100); - vo.setDiscountLimitPrice(null); - } else { - vo.setDiscountPercent(random.nextInt(90) + 10); - vo.setDiscountPrice(null); - vo.setDiscountLimitPrice(random.nextInt(200) * 100); - } - list.add(vo); - } - return success(new PageResult<>(list, 20L)); + PageResult pageResult = couponService.getCouponPage( + CouponConvert.INSTANCE.convert(pageReqVO, Collections.singleton(getLoginUserId()))); + return success(CouponConvert.INSTANCE.convertAppPage(pageResult)); } @GetMapping(value = "/get-unused-count") diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponTemplateController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponTemplateController.java index c4d81de2c..be2c53559 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponTemplateController.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponTemplateController.java @@ -1,27 +1,31 @@ package cn.iocoder.yudao.module.promotion.controller.app.coupon; +import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.template.AppCouponTemplatePageReqVO; import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.template.AppCouponTemplateRespVO; +import cn.iocoder.yudao.module.promotion.convert.coupon.CouponTemplateConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; +import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; import cn.iocoder.yudao.module.promotion.service.coupon.CouponTemplateService; import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; +import java.util.*; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; @Tag(name = "用户 App - 优惠劵模板") @RestController @@ -31,84 +35,45 @@ public class AppCouponTemplateController { @Resource private CouponTemplateService couponTemplateService; + @Resource + private CouponService couponService; - // TODO 芋艿:待实现 - @GetMapping("/list") - @Operation(summary = "获得优惠劵模版列表") - @Parameters({ - @Parameter(name = "spuId", description = "商品 SPU 编号"), // 目前主要给商品详情使用 - @Parameter(name = "useType", description = "使用类型"), - @Parameter(name = "count", description = "数量", required = true) - }) - public CommonResult> getCouponTemplateList(@RequestParam(value = "spuId", required = false) Long spuId, - @RequestParam(value = "useType", required = false) Integer useType, - @RequestParam(value = "count", required = false, defaultValue = "10") Integer count) { - List list = new ArrayList<>(); - Random random = new Random(); - for (int i = 0; i < 10; i++) { - AppCouponTemplateRespVO vo = new AppCouponTemplateRespVO(); - vo.setId(i + 1L); - vo.setName("优惠劵" + (i + 1)); - vo.setTakeLimitCount(random.nextInt(10) + 1); - vo.setUsePrice(random.nextInt(100) * 100); - vo.setValidityType(random.nextInt(2) + 1); - if (vo.getValidityType() == 1) { - vo.setValidStartTime(LocalDateTime.now().plusDays(random.nextInt(10))); - vo.setValidEndTime(LocalDateTime.now().plusDays(random.nextInt(20) + 10)); - } else { - vo.setFixedStartTerm(random.nextInt(10)); - vo.setFixedEndTerm(random.nextInt(10) + vo.getFixedStartTerm() + 1); - } - vo.setDiscountType(random.nextInt(2) + 1); - if (vo.getDiscountType() == 1) { - vo.setDiscountPercent(null); - vo.setDiscountPrice(random.nextInt(50) * 100); - vo.setDiscountLimitPrice(null); - } else { - vo.setDiscountPercent(random.nextInt(90) + 10); - vo.setDiscountPrice(null); - vo.setDiscountLimitPrice(random.nextInt(200) * 100); - } - vo.setTakeStatus(random.nextBoolean()); - list.add(vo); - } - return success(list); - } + @Resource + private ProductSpuApi productSpuApi; - // TODO 芋艿:待实现;和 getCouponTemplateList 类似 @GetMapping("/page") @Operation(summary = "获得优惠劵模版分页") public CommonResult> getCouponTemplatePage(AppCouponTemplatePageReqVO pageReqVO) { - List list = new ArrayList<>(); - Random random = new Random(); - for (int i = 0; i < 10; i++) { - AppCouponTemplateRespVO vo = new AppCouponTemplateRespVO(); - vo.setId(i + 1L); - vo.setName("优惠劵" + (i + 1)); - vo.setTakeLimitCount(random.nextInt(10) + 1); - vo.setUsePrice(random.nextInt(100) * 100); - vo.setValidityType(random.nextInt(2) + 1); - if (vo.getValidityType() == 1) { - vo.setValidStartTime(LocalDateTime.now().plusDays(random.nextInt(10))); - vo.setValidEndTime(LocalDateTime.now().plusDays(random.nextInt(20) + 10)); - } else { - vo.setFixedStartTerm(random.nextInt(10)); - vo.setFixedEndTerm(random.nextInt(10) + vo.getFixedStartTerm() + 1); - } - vo.setDiscountType(random.nextInt(2) + 1); - if (vo.getDiscountType() == 1) { - vo.setDiscountPercent(null); - vo.setDiscountPrice(random.nextInt(50) * 100); - vo.setDiscountLimitPrice(null); - } else { - vo.setDiscountPercent(random.nextInt(90) + 10); - vo.setDiscountPrice(null); - vo.setDiscountLimitPrice(random.nextInt(200) * 100); - } - vo.setTakeStatus(random.nextBoolean()); - list.add(vo); + // 1.1 处理查询条件:商品范围编号 + Long productScopeValue = getaProductScopeValue(pageReqVO); + // 1.2 处理查询条件:领取方式=直接领取 + List canTakeTypes = Collections.singletonList(CouponTakeTypeEnum.USER.getValue()); + // 2. 分页查询 + PageResult pageResult = couponTemplateService.getCouponTemplatePage( + CouponTemplateConvert.INSTANCE.convert(pageReqVO, canTakeTypes, pageReqVO.getProductScope(), productScopeValue)); + // 3.1 领取数量 + Map couponTakeCountMap = new HashMap<>(0); + Long userId = getLoginUserId(); + if (userId != null) { + List templateIds = convertList(pageResult.getList(), CouponTemplateDO::getId, + t -> ObjUtil.notEqual(t.getTakeLimitCount(), -1)); // 只查有设置“每人限领个数”的 + couponTakeCountMap = couponService.getTakeCountMapByTemplateIds(templateIds, userId); } - return success(new PageResult<>(list, 20L)); + // 3.2 拼接返回 + return success(CouponTemplateConvert.INSTANCE.convertAppPage(pageResult, couponTakeCountMap)); + } + + private Long getaProductScopeValue(AppCouponTemplatePageReqVO pageReqVO) { + Long productScopeValue = pageReqVO.getSpuId(); + if (pageReqVO.getProductScope() == null || Objects.equals(pageReqVO.getProductScope(), PromotionProductScopeEnum.ALL.getScope())) { + // 通用券:清除商品范围 + productScopeValue = null; + } else if (Objects.equals(pageReqVO.getProductScope(), PromotionProductScopeEnum.CATEGORY.getScope()) && pageReqVO.getSpuId() != null) { + // 品类券:查询商品的品类 + productScopeValue = Optional.ofNullable(productSpuApi.getSpu(pageReqVO.getSpuId())) + .map(ProductSpuRespDTO::getCategoryId).orElse(null); + } + return productScopeValue; } } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponMatchReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponMatchReqVO.java index 633644ea3..9d36e3a4e 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponMatchReqVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponMatchReqVO.java @@ -15,15 +15,15 @@ public class AppCouponMatchReqVO { @NotNull(message = "商品金额不能为空") private Integer price; - @Schema(description = "商品 SPU 编号的数组", required = true, example = "[1, 2]") + @Schema(description = "商品 SPU 编号的数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2]") @NotEmpty(message = "商品 SPU 编号不能为空") private List spuIds; - @Schema(description = "商品 SKU 编号的数组", required = true, example = "[1, 2]") + @Schema(description = "商品 SKU 编号的数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2]") @NotEmpty(message = "商品 SKU 编号不能为空") private List skuIds; - @Schema(description = "分类编号的数组", required = true, example = "[10, 20]") + @Schema(description = "分类编号的数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[10, 20]") @NotEmpty(message = "分类编号不能为空") private List categoryIds; diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponPageReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponPageReqVO.java index 5bd057f37..0c423959b 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponPageReqVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponPageReqVO.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon; import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; @@ -13,6 +15,7 @@ import lombok.ToString; public class AppCouponPageReqVO extends PageParam { @Schema(description = "优惠劵状态", example = "1") + @InEnum(value = CouponStatusEnum.class, message = "优惠劵状态,必须是 {value}") private Integer status; } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/template/AppCouponTemplatePageReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/template/AppCouponTemplatePageReqVO.java index 6eda32167..48f2dc904 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/template/AppCouponTemplatePageReqVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/template/AppCouponTemplatePageReqVO.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.template; import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; @@ -12,8 +14,10 @@ import lombok.ToString; @ToString(callSuper = true) public class AppCouponTemplatePageReqVO extends PageParam { - @Schema(description = "使用类型", example = "1") - // TODO 芋艿:这里要限制下枚举的使用 - private Integer useType; + @Schema(description = "商品范围", example = "1") + @InEnum(value = PromotionProductScopeEnum.class, message = "商品范围,必须是 {value}") + private Integer productScope; + @Schema(description = "商品标号", example = "1") + private Long spuId; } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponConvert.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponConvert.java index 364095a4d..3fc42dbe2 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponConvert.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponConvert.java @@ -3,6 +3,10 @@ package cn.iocoder.yudao.module.promotion.convert.coupon; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponRespDTO; import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageItemRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponMatchRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponRespVO; import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum; @@ -11,6 +15,8 @@ import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; /** * 优惠劵 Convert @@ -49,4 +55,10 @@ public interface CouponConvert { } return couponDO; } + + CouponPageReqVO convert(AppCouponPageReqVO pageReqVO, Collection userIds); + + PageResult convertAppPage(PageResult pageResult); + + List convertList(List list); } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponTemplateConvert.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponTemplateConvert.java index 22d78f46f..1c5c9b31f 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponTemplateConvert.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponTemplateConvert.java @@ -1,13 +1,20 @@ package cn.iocoder.yudao.module.promotion.convert.coupon; +import cn.hutool.core.map.MapUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplatePageReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateRespVO; import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateUpdateReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.template.AppCouponTemplatePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.template.AppCouponTemplateRespVO; import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; +import java.util.List; +import java.util.Map; + /** * 优惠劵模板 Convert * @@ -26,4 +33,25 @@ public interface CouponTemplateConvert { PageResult convertPage(PageResult page); + CouponTemplatePageReqVO convert(AppCouponTemplatePageReqVO pageReqVO, List canTakeTypes, Integer productScope, Long productScopeValue); + + PageResult convertAppPage(PageResult pageResult); + + default PageResult convertAppPage(PageResult pageResult, Map couponTakeCountMap) { + PageResult result = convertAppPage(pageResult); + if (MapUtil.isEmpty(couponTakeCountMap)) { + return result; + } + + for (AppCouponTemplateRespVO vo : result.getList()) { + // 每人领取数量无限制 + if (vo.getTakeLimitCount() == -1) { + vo.setTakeStatus(false); + continue; + } + // 检查已领取数量是否超过限领数量 + vo.setTakeStatus(MapUtil.getInt(couponTakeCountMap, vo.getId(), 0) >= vo.getTakeLimitCount()); + } + return result; + } } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/reward/RewardActivityDO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/reward/RewardActivityDO.java index 9d417d75f..a066d2f26 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/reward/RewardActivityDO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/reward/RewardActivityDO.java @@ -110,7 +110,7 @@ public class RewardActivityDO extends BaseDO { */ private List couponIds; /** - * 赠送的优惠卷数量的数组 + * 赠送的优惠券数量的数组 */ private List couponCounts; diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java index ddf90691c..dc909b4c6 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java @@ -1,15 +1,23 @@ package cn.iocoder.yudao.module.promotion.dal.mysql.coupon; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO; import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import cn.iocoder.yudao.module.promotion.service.coupon.bo.CouponTakeCountBO; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.github.yulichang.toolkit.MPJWrappers; import org.apache.ibatis.annotations.Mapper; +import java.time.LocalDateTime; import java.util.Collection; import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; /** * 优惠劵 Mapper @@ -19,11 +27,11 @@ import java.util.List; @Mapper public interface CouponMapper extends BaseMapperX { - default PageResult selectPage(CouponPageReqVO reqVO, Collection userIds) { + default PageResult selectPage(CouponPageReqVO reqVO) { return selectPage(reqVO, new LambdaQueryWrapperX() .eqIfPresent(CouponDO::getTemplateId, reqVO.getTemplateId()) .eqIfPresent(CouponDO::getStatus, reqVO.getStatus()) - .inIfPresent(CouponDO::getUserId, userIds) + .inIfPresent(CouponDO::getUserId, reqVO.getUserIds()) .betweenIfPresent(CouponDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(CouponDO::getId)); } @@ -62,4 +70,36 @@ public interface CouponMapper extends BaseMapperX { ); } + default List selectCountByUserIdAndTemplateIdIn(Long userId, Collection templateIds) { + return BeanUtil.copyToList(selectMaps(MPJWrappers.lambdaJoin(CouponDO.class) + .select(CouponDO::getTemplateId) + .selectCount(CouponDO::getId, CouponTakeCountBO::getCount) + .eq(CouponDO::getUserId, userId) + .in(CouponDO::getTemplateId, templateIds) + .groupBy(CouponDO::getTemplateId)), CouponTakeCountBO.class); + } + + default List selectListByUserIdAndStatusAndUsePriceLeAndProductScope( + Long userId, Integer status, Integer usePrice, List spuIds, List categoryIds) { + + Function, String> productScopeValuesFindInSetFunc = ids -> ids.stream() + .map(id -> StrUtil.format("FIND_IN_SET({}, product_scope_values) ", id)) + .collect(Collectors.joining(" OR ")); + return selectList(new LambdaQueryWrapperX() + .eq(CouponDO::getUserId, userId) + .eq(CouponDO::getStatus, status) + .le(CouponDO::getUsePrice, usePrice) + .and(w -> w.eq(CouponDO::getProductScope, PromotionProductScopeEnum.ALL.getScope()) + .or(ww -> ww.eq(CouponDO::getProductScope, PromotionProductScopeEnum.SPU.getScope()) + .apply(productScopeValuesFindInSetFunc.apply(spuIds))) + .or(ww -> ww.eq(CouponDO::getProductScope, PromotionProductScopeEnum.CATEGORY.getScope()) + .apply(productScopeValuesFindInSetFunc.apply(categoryIds))))); + } + + default List selectListByStatusAndValidEndTimeLe(Integer status, LocalDateTime validEndTime) { + return selectList(new LambdaQueryWrapperX() + .eq(CouponDO::getStatus, status) + .le(CouponDO::getValidEndTime, validEndTime) + ); + } } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java index c95513e18..3c575c4d4 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java @@ -39,6 +39,9 @@ public interface CouponTemplateMapper extends BaseMapperX { .eqIfPresent(CouponTemplateDO::getStatus, reqVO.getStatus()) .eqIfPresent(CouponTemplateDO::getDiscountType, reqVO.getDiscountType()) .betweenIfPresent(CouponTemplateDO::getCreateTime, reqVO.getCreateTime()) + .eqIfPresent(CouponTemplateDO::getProductScope, reqVO.getProductScope()) + .and(reqVO.getProductScopeValue() != null, w -> w.apply("FIND_IN_SET({0}, product_scope_values)", + reqVO.getProductScopeValue())) .and(canTakeConsumer != null, canTakeConsumer) .orderByDesc(CouponTemplateDO::getId)); } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/job/CouponExpireJob.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/job/CouponExpireJob.java new file mode 100644 index 000000000..0526d1a72 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/job/CouponExpireJob.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.promotion.job; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 优惠券过期 Job + * + * @author owen + */ +@Component +@TenantJob +public class CouponExpireJob implements JobHandler { + + @Resource + private CouponService couponService; + + @Override + public String execute(String param) { + int count = couponService.expireCoupon(); + return StrUtil.format("过期优惠券 {} 个", count); + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java index cf22fe2b3..a85ac31a9 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java @@ -3,12 +3,18 @@ package cn.iocoder.yudao.module.promotion.service.coupon; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponMatchReqVO; import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; +import cn.iocoder.yudao.module.promotion.service.coupon.bo.CouponTakeCountBO; +import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Set; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + /** * 优惠劵 Service 接口 * @@ -18,11 +24,11 @@ public interface CouponService { /** * 校验优惠劵,包括状态、有限期 - * + *

* 1. 如果校验通过,则返回优惠劵信息 * 2. 如果校验不通过,则直接抛出业务异常 * - * @param id 优惠劵编号 + * @param id 优惠劵编号 * @param userId 用户编号 * @return 优惠劵信息 */ @@ -31,9 +37,8 @@ public interface CouponService { /** * 校验优惠劵,包括状态、有限期 * - * @see #validCoupon(Long, Long) 逻辑相同,只是入参不同 - * * @param coupon 优惠劵 + * @see #validCoupon(Long, Long) 逻辑相同,只是入参不同 */ void validCoupon(CouponDO coupon); @@ -124,4 +129,39 @@ public interface CouponService { takeCoupon(templateId, CollUtil.newHashSet(userId), CouponTakeTypeEnum.REGISTER); } + /** + * 统计会员领取优惠券的数量 + * + * @param templateIds 优惠券模板编号列表 + * @param userId 用户编号 + * @return 领取优惠券的数量 + */ + default Map getTakeCountMapByTemplateIds(Collection templateIds, Long userId) { + return convertMap(getTakeCountListByTemplateIds(templateIds, userId), CouponTakeCountBO::getTemplateId, CouponTakeCountBO::getCount); + } + + /** + * 统计会员领取优惠券的数量 + * + * @param templateIds 优惠券模板编号列表 + * @param userId 用户编号 + * @return 领取优惠券的数量 + */ + List getTakeCountListByTemplateIds(Collection templateIds, Long userId); + + /** + * 获取用户匹配的优惠券列表 + * + * @param userId 用户编号 + * @param matchReqVO 匹配参数 + * @return 优惠券列表 + */ + List getMatchCouponList(Long userId, AppCouponMatchReqVO matchReqVO); + + /** + * 过期优惠券 + * + * @return 过期数量 + */ + int expireCoupon(); } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java index f4b56260c..be2370c1a 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java @@ -2,15 +2,18 @@ package cn.iocoder.yudao.module.promotion.service.coupon; import cn.hutool.core.collection.CollStreamUtil; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; 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.controller.admin.coupon.vo.coupon.CouponPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponMatchReqVO; import cn.iocoder.yudao.module.promotion.convert.coupon.CouponConvert; import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; @@ -18,12 +21,15 @@ import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponMapper; import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum; import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum; +import cn.iocoder.yudao.module.promotion.service.coupon.bo.CouponTakeCountBO; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import java.time.LocalDateTime; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; @@ -39,6 +45,7 @@ import static java.util.Arrays.asList; * * @author 芋道源码 */ +@Slf4j @Service @Validated public class CouponServiceImpl implements CouponService { @@ -77,16 +84,16 @@ public class CouponServiceImpl implements CouponService { @Override public PageResult getCouponPage(CouponPageReqVO pageReqVO) { // 获得用户编号 - Set userIds = null; if (StrUtil.isNotEmpty(pageReqVO.getNickname())) { - userIds = CollectionUtils.convertSet(memberUserApi.getUserListByNickname(pageReqVO.getNickname()), + Set userIds = CollectionUtils.convertSet(memberUserApi.getUserListByNickname(pageReqVO.getNickname()), MemberUserRespDTO::getId); if (CollUtil.isEmpty(userIds)) { return PageResult.empty(); } + pageReqVO.setUserIds(userIds); } // 分页查询 - return couponMapper.selectPage(pageReqVO, userIds); + return couponMapper.selectPage(pageReqVO); } @Override @@ -175,6 +182,57 @@ public class CouponServiceImpl implements CouponService { couponTemplateService.updateCouponTemplateTakeCount(templateId, userIds.size()); } + @Override + public List getTakeCountListByTemplateIds(Collection templateIds, Long userId) { + if (CollUtil.isEmpty(templateIds)) { + return ListUtil.empty(); + } + return couponMapper.selectCountByUserIdAndTemplateIdIn(userId, templateIds); + } + + @Override + public List getMatchCouponList(Long userId, AppCouponMatchReqVO matchReqVO) { + return couponMapper.selectListByUserIdAndStatusAndUsePriceLeAndProductScope(userId, CouponStatusEnum.UNUSED.getStatus(), + matchReqVO.getPrice(), matchReqVO.getSpuIds(), matchReqVO.getCategoryIds()); + } + + @Override + public int expireCoupon() { + // 1. 查询待过期的优惠券 + List list = couponMapper.selectListByStatusAndValidEndTimeLe( + CouponStatusEnum.UNUSED.getStatus(), LocalDateTime.now()); + if (CollUtil.isEmpty(list)) { + return 0; + } + + // 2. 遍历执行 + int count = 0; + for (CouponDO coupon : list) { + try { + boolean success = getSelf().expireCoupon(coupon); + if (success) { + count++; + } + } catch (Exception e) { + log.error("[expireCoupon][coupon({}) 更新为已过期失败]", coupon.getId(), e); + } + } + return count; + } + + private boolean expireCoupon(CouponDO coupon) { + // 更新记录状态 + CouponDO updateObj = new CouponDO().setStatus(CouponStatusEnum.EXPIRE.getStatus()); + int updateRows = couponMapper.updateByIdAndStatus(coupon.getId(), CouponStatusEnum.UNUSED.getStatus(), updateObj); + if (updateRows == 0) { + log.error("[expireCoupon][coupon({}) 更新为已过期失败]", coupon.getId()); + return false; + } + + log.info("[expireCoupon][coupon({}) 更新为已过期成功]", coupon.getId()); + return true; + } + /** * 校验优惠券是否可以领取 * @@ -211,7 +269,7 @@ public class CouponServiceImpl implements CouponService { /** * 过滤掉达到领取上线的用户 * - * @param userIds 用户编号数组 + * @param userIds 用户编号数组 * @param couponTemplate 优惠劵模版 */ private void removeTakeLimitUser(Set userIds, CouponTemplateDO couponTemplate) { @@ -228,4 +286,12 @@ public class CouponServiceImpl implements CouponService { userIds.removeIf(userId -> MapUtil.getInt(userTakeCountMap, userId, 0) >= couponTemplate.getTakeLimitCount()); } + /** + * 获得自身的代理对象,解决 AOP 生效问题 + * + * @return 自己 + */ + private CouponServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/bo/CouponTakeCountBO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/bo/CouponTakeCountBO.java new file mode 100644 index 000000000..18928067d --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/bo/CouponTakeCountBO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.promotion.service.coupon.bo; + +import lombok.Data; + +/** + * 优惠券领取数量 BO + * + * @author owen + */ +@Data +public class CouponTakeCountBO { + /** + * 优惠劵模板编号 + */ + private Long templateId; + /** + * 领取数量 + */ + private Integer count; +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageUserController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageUserController.java index 8d27dd3b4..71832fd8b 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageUserController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageUserController.java @@ -10,10 +10,10 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO; import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum; import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum; -import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageWithdrawService; -import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO; import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageRecordService; import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageUserService; +import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageWithdrawService; +import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO; import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserWithdrawSummaryBO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -92,20 +92,17 @@ public class BrokerageUserController { Set userIds = convertSet(pageResult.getList(), BrokerageUserDO::getId); // 查询用户信息 Map userMap = memberUserApi.getUserMap(userIds); - // TODO @疯狂:看看下面两个 getBrokerageUserCountByBindUserId、getWithdrawSummaryByUserId 有没可能一次性出结果,不然 n 次有点太花性能了; // 合计分佣订单 - Map userOrderSummaryMap = convertMap(userIds, - userId -> userId, - userId -> brokerageRecordService.getUserBrokerageSummaryByUserId(userId, - BrokerageRecordBizTypeEnum.ORDER.getType(), BrokerageRecordStatusEnum.SETTLEMENT.getStatus())); + Map userOrderSummaryMap = brokerageRecordService.getUserBrokerageSummaryMapByUserId( + userIds, BrokerageRecordBizTypeEnum.ORDER.getType(), BrokerageRecordStatusEnum.SETTLEMENT.getStatus()); + // TODO @芋艿:看看下面 getBrokerageUserCountByBindUserId 有没可能一次性出结果,不然 n 次有点太花性能了; // 合计推广用户数量 Map brokerageUserCountMap = convertMap(userIds, userId -> userId, userId -> brokerageUserService.getBrokerageUserCountByBindUserId(userId, null)); // 合计提现 - Map withdrawMap = convertMap(userIds, - userId -> userId, - userId -> brokerageWithdrawService.getWithdrawSummaryByUserId(userId, BrokerageWithdrawStatusEnum.AUDIT_SUCCESS)); + Map withdrawMap = brokerageWithdrawService.getWithdrawSummaryMapByUserId(userIds, + BrokerageWithdrawStatusEnum.AUDIT_SUCCESS); // 拼接返回 return success(BrokerageUserConvert.INSTANCE.convertPage(pageResult, userMap, brokerageUserCountMap, userOrderSummaryMap, withdrawMap)); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageUserController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageUserController.java index da78f9dff..f7b7276ab 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageUserController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageUserController.java @@ -27,6 +27,7 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.validation.Valid; import java.time.LocalDateTime; +import java.util.Collections; import java.util.Map; import java.util.Optional; @@ -76,23 +77,25 @@ public class AppBrokerageUserController { @Operation(summary = "获得个人分销统计") @PreAuthenticated public CommonResult getBrokerageUserSummary() { - Long userId = getLoginUserId(); - // TODO @疯狂:后面这种,要不也改成 convert;感觉 controller 这样更容易看到整体;核心其实是 86、8/87、9/90、9/91 这阶段 - // 统计 yesterdayPrice、withdrawPrice、firstBrokerageUserCount、secondBrokerageUserCount 字段 + // 查询当前登录用户信息 + BrokerageUserDO brokerageUser = brokerageUserService.getBrokerageUser(getLoginUserId()); + // 统计用户昨日的佣金 LocalDateTime yesterday = LocalDateTime.now().minusDays(1); LocalDateTime beginTime = LocalDateTimeUtil.beginOfDay(yesterday); LocalDateTime endTime = LocalDateTimeUtil.endOfDay(yesterday); - AppBrokerageUserMySummaryRespVO respVO = new AppBrokerageUserMySummaryRespVO() - .setYesterdayPrice(brokerageRecordService.getSummaryPriceByUserId(userId, BrokerageRecordBizTypeEnum.ORDER.getType(), beginTime, endTime)) - .setWithdrawPrice(Optional.ofNullable(brokerageWithdrawService.getWithdrawSummaryByUserId(userId, BrokerageWithdrawStatusEnum.AUDIT_SUCCESS)) - .map(UserWithdrawSummaryBO::getPrice).orElse(0)) - .setBrokeragePrice(0).setFrozenPrice(0) - .setFirstBrokerageUserCount(brokerageUserService.getBrokerageUserCountByBindUserId(userId, 1)) - .setSecondBrokerageUserCount(brokerageUserService.getBrokerageUserCountByBindUserId(userId, 2)); - // 设置 brokeragePrice、frozenPrice 字段 - Optional.ofNullable(brokerageUserService.getBrokerageUser(userId)) - .ifPresent(user -> respVO.setBrokeragePrice(user.getBrokeragePrice()).setFrozenPrice(user.getFrozenPrice())); - return success(respVO); + Integer yesterdayPrice = brokerageRecordService.getSummaryPriceByUserId(brokerageUser.getId(), + BrokerageRecordBizTypeEnum.ORDER.getType(), beginTime, endTime); + // 统计用户提现的佣金 + Integer withdrawPrice = brokerageWithdrawService.getWithdrawSummaryByUserId(Collections.singleton(brokerageUser.getId()), + BrokerageWithdrawStatusEnum.AUDIT_SUCCESS).stream() + .findFirst().map(UserWithdrawSummaryBO::getPrice).orElse(0); + // 统计分销用户数量(一级) + Long firstBrokerageUserCount = brokerageUserService.getBrokerageUserCountByBindUserId(brokerageUser.getId(), 1); + // 统计分销用户数量(二级) + Long secondBrokerageUserCount = brokerageUserService.getBrokerageUserCountByBindUserId(brokerageUser.getId(), 2); + + // 拼接返回 + return success(BrokerageUserConvert.INSTANCE.convert(yesterdayPrice, withdrawPrice, firstBrokerageUserCount, secondBrokerageUserCount, brokerageUser)); } @GetMapping("/rank-page-by-user-count") diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementRespVO.java index 4b5d98a37..494b9bfa5 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementRespVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementRespVO.java @@ -37,6 +37,8 @@ public class AppTradeOrderSettlementRespVO { // ========== SPU 信息 ========== + @Schema(description = "品类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Long categoryId; @Schema(description = "SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") private Long spuId; @Schema(description = "SPU 名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "Apple iPhone 12") diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/BrokerageUserConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/BrokerageUserConvert.java index 6a578032d..086ef0aa1 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/BrokerageUserConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/BrokerageUserConvert.java @@ -1,9 +1,11 @@ package cn.iocoder.yudao.module.trade.convert.brokerage; import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user.BrokerageUserRespVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserMySummaryRespVO; import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserRankByUserCountRespVO; import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO; import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO; @@ -71,4 +73,18 @@ public interface BrokerageUserConvert { void copyTo(MemberUserRespDTO from, @MappingTarget AppBrokerageUserRankByUserCountRespVO to); + default AppBrokerageUserMySummaryRespVO convert(Integer yesterdayPrice, Integer withdrawPrice, + Long firstBrokerageUserCount, Long secondBrokerageUserCount, + BrokerageUserDO brokerageUser) { + AppBrokerageUserMySummaryRespVO respVO = new AppBrokerageUserMySummaryRespVO() + .setYesterdayPrice(ObjUtil.defaultIfNull(yesterdayPrice, 0)) + .setWithdrawPrice(ObjUtil.defaultIfNull(withdrawPrice, 0)) + .setBrokeragePrice(0).setFrozenPrice(0) + .setFirstBrokerageUserCount(ObjUtil.defaultIfNull(firstBrokerageUserCount, 0L)) + .setSecondBrokerageUserCount(ObjUtil.defaultIfNull(secondBrokerageUserCount, 0L)); + // 设置 brokeragePrice、frozenPrice 字段 + Optional.ofNullable(brokerageUser) + .ifPresent(user -> respVO.setBrokeragePrice(user.getBrokeragePrice()).setFrozenPrice(user.getFrozenPrice())); + return respVO; + } } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageRecordMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageRecordMapper.java index eb55a8c4c..b4b606b5a 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageRecordMapper.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageRecordMapper.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.trade.dal.mysql.brokerage; +import cn.hutool.core.bean.BeanUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; @@ -9,12 +10,15 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageRecordDO; import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; +import com.github.yulichang.toolkit.MPJWrappers; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import java.time.LocalDateTime; +import java.util.Collection; import java.util.List; +import java.util.Map; /** * 佣金记录 Mapper @@ -52,11 +56,27 @@ public interface BrokerageRecordMapper extends BaseMapperX { BrokerageRecordDO::getUserId, userId); } - @Select("SELECT COUNT(1), SUM(price) FROM trade_brokerage_record " + - "WHERE user_id = #{userId} AND biz_type = #{bizType} AND status = #{status} AND deleted = FALSE") - UserBrokerageSummaryBO selectCountAndSumPriceByUserIdAndBizTypeAndStatus(@Param("userId") Long userId, - @Param("bizType") Integer bizType, - @Param("status") Integer status); + default List selectCountAndSumPriceByUserIdInAndBizTypeAndStatus(Collection userIds, + Integer bizType, + Integer status) { + List> list = selectMaps(MPJWrappers.lambdaJoin(BrokerageRecordDO.class) + .select(BrokerageRecordDO::getUserId) + .selectCount(BrokerageRecordDO::getId, UserBrokerageSummaryBO::getCount) + .selectSum(BrokerageRecordDO::getPrice) + .in(BrokerageRecordDO::getUserId, userIds) + .eq(BrokerageRecordDO::getBizId, bizType) + .eq(BrokerageRecordDO::getStatus, status) + .groupBy(BrokerageRecordDO::getUserId)); + return BeanUtil.copyToList(list, UserBrokerageSummaryBO.class); +// return selectJoinList(UserBrokerageSummaryBO.class, MPJWrappers.lambdaJoin(BrokerageRecordDO.class) +// .select(BrokerageRecordDO::getUserId) +// .selectCount(BrokerageRecordDO::getId, UserBrokerageSummaryBO::getCount) +// .selectSum(BrokerageRecordDO::getPrice) +// .in(BrokerageRecordDO::getUserId, userIds) +// .eq(BrokerageRecordDO::getBizId, bizType) +// .eq(BrokerageRecordDO::getStatus, status) +// .groupBy(BrokerageRecordDO::getUserId)); + } @Select("SELECT SUM(price) FROM trade_brokerage_record " + "WHERE user_id = #{userId} AND biz_type = #{bizType} " + diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageWithdrawMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageWithdrawMapper.java index f8ca4c5b7..4bbf427e9 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageWithdrawMapper.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageWithdrawMapper.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.trade.dal.mysql.brokerage; +import cn.hutool.core.bean.BeanUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; @@ -7,9 +8,12 @@ import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw.Brok import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageWithdrawDO; import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserWithdrawSummaryBO; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.github.yulichang.wrapper.MPJLambdaWrapper; import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.apache.ibatis.annotations.Select; + +import java.util.Collection; +import java.util.List; +import java.util.Map; /** * 佣金提现 Mapper @@ -37,9 +41,23 @@ public interface BrokerageWithdrawMapper extends BaseMapperX selectCountAndSumPriceByUserIdAndStatus(Collection userIds, Integer status) { + List> list = selectMaps(new MPJLambdaWrapper() + .select(BrokerageWithdrawDO::getUserId) + .selectCount(BrokerageWithdrawDO::getId, UserWithdrawSummaryBO::getCount) + .selectSum(BrokerageWithdrawDO::getPrice) + .in(BrokerageWithdrawDO::getUserId, userIds) + .eq(BrokerageWithdrawDO::getStatus, status) + .groupBy(BrokerageWithdrawDO::getUserId)); + return BeanUtil.copyToList(list, UserWithdrawSummaryBO.class); + // selectJoinList有BUG,会与租户插件冲突:解析SQL时,发生异常 https://gitee.com/best_handsome/mybatis-plus-join/issues/I84GYW +// return selectJoinList(UserWithdrawSummaryBO.class, new MPJLambdaWrapper() +// .select(BrokerageWithdrawDO::getUserId) +// .selectCount(BrokerageWithdrawDO::getId, UserWithdrawSummaryBO::getCount) +// .selectSum(BrokerageWithdrawDO::getPrice) +// .in(BrokerageWithdrawDO::getUserId, userIds) +// .eq(BrokerageWithdrawDO::getStatus, status) +// .groupBy(BrokerageWithdrawDO::getUserId)); + } } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java index 80acf9b99..a41b73ec3 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java @@ -85,7 +85,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa @Override public TradeAfterSaleDO getAfterSale(Long userId, Long id) { - return tradeAfterSaleMapper.selectByIdAndUserId(id, userId); + return tradeAfterSaleMapper.selectByIdAndUserId(id, userId); } @Override @@ -167,9 +167,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa tradeAfterSaleMapper.insert(afterSale); // 更新交易订单项的售后状态 - tradeOrderUpdateService.updateOrderItemAfterSaleStatus(orderItem.getId(), - TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(), TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), - afterSale.getId(), null); + tradeOrderUpdateService.updateOrderItemWhenAfterSaleCreate(orderItem.getId(), afterSale.getId()); // 记录售后日志 createAfterSaleLog(orderItem.getUserId(), UserTypeEnum.MEMBER.getValue(), @@ -219,8 +217,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa // TODO 发送售后消息 // 更新交易订单项的售后状态为【未申请】 - tradeOrderUpdateService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(), - TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); + tradeOrderUpdateService.updateOrderItemWhenAfterSaleCancel(afterSale.getOrderItemId()); } /** @@ -313,8 +310,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa // TODO 发送售后消息 // 更新交易订单项的售后状态为【未申请】 - tradeOrderUpdateService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(), - TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); + tradeOrderUpdateService.updateOrderItemWhenAfterSaleCancel(afterSale.getOrderItemId()); } /** @@ -360,9 +356,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa // TODO 发送售后消息 // 更新交易订单项的售后状态为【已完成】 - tradeOrderUpdateService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(), - TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus(), - null, afterSale.getRefundPrice()); + tradeOrderUpdateService.updateOrderItemWhenAfterSaleSuccess(afterSale.getOrderItemId(), afterSale.getRefundPrice()); } private void createPayRefund(String userIp, TradeAfterSaleDO afterSale) { @@ -403,8 +397,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa // TODO 发送售后消息 // 更新交易订单项的售后状态为【未申请】 - tradeOrderUpdateService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(), - TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); + tradeOrderUpdateService.updateOrderItemWhenAfterSaleCancel(afterSale.getOrderItemId()); } @Override diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordService.java index 875c29cfd..a059c712d 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordService.java @@ -12,7 +12,11 @@ import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO import javax.validation.Valid; import java.time.LocalDateTime; +import java.util.Collection; import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; /** * 佣金记录 Service 接口 @@ -76,12 +80,24 @@ public interface BrokerageRecordService { /** * 汇总用户佣金 * - * @param userId 用户编号 + * @param userIds 用户编号 * @param bizType 业务类型 * @param status 佣金状态 * @return 用户佣金汇总 */ - UserBrokerageSummaryBO getUserBrokerageSummaryByUserId(Long userId, Integer bizType, Integer status); + List getUserBrokerageSummaryByUserId(Collection userIds, Integer bizType, Integer status); + + /** + * 汇总用户佣金 + * + * @param userIds 用户编号 + * @param bizType 业务类型 + * @param status 佣金状态 + * @return 用户佣金汇总 + */ + default Map getUserBrokerageSummaryMapByUserId(Collection userIds, Integer bizType, Integer status) { + return convertMap(getUserBrokerageSummaryByUserId(userIds, bizType, status), UserBrokerageSummaryBO::getUserId); + } /** * 获得用户佣金合计 diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java index 7630ce4c5..1c83c9ec6 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java @@ -36,10 +36,7 @@ import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Optional; +import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue; @@ -235,9 +232,8 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { } @Override - public UserBrokerageSummaryBO getUserBrokerageSummaryByUserId(Long userId, Integer bizType, Integer status) { - UserBrokerageSummaryBO summaryBO = brokerageRecordMapper.selectCountAndSumPriceByUserIdAndBizTypeAndStatus(userId, bizType, status); - return summaryBO != null ? summaryBO : new UserBrokerageSummaryBO(0, 0); + public List getUserBrokerageSummaryByUserId(Collection userIds, Integer bizType, Integer status) { + return brokerageRecordMapper.selectCountAndSumPriceByUserIdInAndBizTypeAndStatus(userIds, bizType, status); } @Override @@ -338,7 +334,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { if (BooleanUtil.isTrue(spu.getSubCommissionType())) { fixedMinPrice = getMinValue(skuList, ProductSkuRespDTO::getFirstBrokeragePrice); fixedMaxPrice = getMaxValue(skuList, ProductSkuRespDTO::getFirstBrokeragePrice); - // 3.2 全局分佣模式(根据商品价格比例计算) + // 3.2 全局分佣模式(根据商品价格比例计算) } else { spuMinPrice = getMinValue(skuList, ProductSkuRespDTO::getPrice); spuMaxPrice = getMaxValue(skuList, ProductSkuRespDTO::getPrice); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserService.java index 8fc8c1960..861e3d8c4 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserService.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.trade.service.brokerage; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user.BrokerageUserPageReqVO; import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryPageReqVO; import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryRespVO; @@ -111,21 +110,7 @@ public interface BrokerageUserService { * @param registerTime 用户注册时间 * @return 是否绑定 */ - default boolean bindBrokerageUser(@NotNull Long userId, @NotNull Long bindUserId, @NotNull LocalDateTime registerTime) { - // 注册时间在30秒内的,都算新用户 - boolean isNewUser = LocalDateTimeUtils.afterNow(registerTime.minusSeconds(30)); - return bindBrokerageUser(userId, bindUserId, isNewUser); - } - - /** - * 【会员】绑定推广员 - * - * @param userId 用户编号 - * @param bindUserId 推广员编号 - * @param isNewUser 是否为新用户 - * @return 是否绑定 - */ - boolean bindBrokerageUser(Long userId, Long bindUserId, Boolean isNewUser); + boolean bindBrokerageUser(@NotNull Long userId, @NotNull Long bindUserId, @NotNull LocalDateTime registerTime); /** * 获取用户是否有分销资格 diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserServiceImpl.java index 8672f3069..71b33d36c 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserServiceImpl.java @@ -5,6 +5,7 @@ import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.BooleanUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user.BrokerageUserPageReqVO; import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryPageReqVO; @@ -154,7 +155,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { } @Override - public boolean bindBrokerageUser(Long userId, Long bindUserId, Boolean isNewUser) { + public boolean bindBrokerageUser(Long userId, Long bindUserId, LocalDateTime registerTime) { // 1. 获得分销用户 boolean isNewBrokerageUser = false; BrokerageUserDO brokerageUser = brokerageUserMapper.selectById(userId); @@ -164,7 +165,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { } // 2.1 校验是否能绑定用户 - boolean validated = isUserCanBind(brokerageUser, isNewUser); + boolean validated = isUserCanBind(brokerageUser, registerTime); if (!validated) { return false; } @@ -222,7 +223,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { return new PageResult<>(pageResult.getRecords(), pageResult.getTotal()); } - private boolean isUserCanBind(BrokerageUserDO user, Boolean isNewUser) { + private boolean isUserCanBind(BrokerageUserDO user, LocalDateTime registerTime) { // 校验分销功能是否启用 TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig(); if (tradeConfig == null || !BooleanUtil.isTrue(tradeConfig.getBrokerageEnabled())) { @@ -236,8 +237,9 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { // 校验分销关系绑定模式 if (BrokerageBindModeEnum.REGISTER.getMode().equals(tradeConfig.getBrokerageBindMode())) { - // TODO @疯狂:是不是把 isNewUser 挪到这里好点呀? - if (!BooleanUtil.isTrue(isNewUser)) { + // 判断是否为新用户:注册时间在30秒内的,都算新用户 + boolean isNotNewUser = LocalDateTimeUtils.beforeNow(registerTime.plusSeconds(30)); + if (isNotNewUser) { throw exception(BROKERAGE_BIND_MODE_REGISTER); // 只有在注册时可以绑定 } } else if (BrokerageBindModeEnum.ANYTIME.getMode().equals(tradeConfig.getBrokerageBindMode())) { diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawService.java index 2d7ba622b..696b266f3 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawService.java @@ -7,6 +7,13 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageWithdrawD import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum; import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserWithdrawSummaryBO; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + /** * 佣金提现 Service 接口 * @@ -51,10 +58,20 @@ public interface BrokerageWithdrawService { /** * 汇总用户提现 * - * @param userId 用户编号 - * @param status 提现状态 + * @param userIds 用户编号 + * @param status 提现状态 * @return 用户提现汇总 */ - UserWithdrawSummaryBO getWithdrawSummaryByUserId(Long userId, BrokerageWithdrawStatusEnum status); + List getWithdrawSummaryByUserId(Collection userIds, BrokerageWithdrawStatusEnum status); + /** + * 汇总用户提现 + * + * @param userIds 用户编号 + * @param status 提现状态 + * @return 用户提现汇总 + */ + default Map getWithdrawSummaryMapByUserId(Set userIds, BrokerageWithdrawStatusEnum status) { + return convertMap(getWithdrawSummaryByUserId(userIds, status), UserWithdrawSummaryBO::getUserId); + } } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImpl.java index 102e65529..61dcf2817 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImpl.java @@ -26,6 +26,8 @@ import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Validator; import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; @@ -142,9 +144,8 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { } @Override - public UserWithdrawSummaryBO getWithdrawSummaryByUserId(Long userId, BrokerageWithdrawStatusEnum status) { - UserWithdrawSummaryBO summaryBO = brokerageWithdrawMapper.selectCountAndSumPriceByUserIdAndStatus(userId, status.getStatus()); - return summaryBO != null ? summaryBO : new UserWithdrawSummaryBO(0, 0); + public List getWithdrawSummaryByUserId(Collection userIds, BrokerageWithdrawStatusEnum status) { + return brokerageWithdrawMapper.selectCountAndSumPriceByUserIdAndStatus(userIds, status.getStatus()); } /** diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/UserBrokerageSummaryBO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/UserBrokerageSummaryBO.java index 4504290be..872378e47 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/UserBrokerageSummaryBO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/UserBrokerageSummaryBO.java @@ -13,7 +13,10 @@ import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor public class UserBrokerageSummaryBO { - + /** + * 用户编号 + */ + private Long userId; /** * 佣金数量 */ diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/UserWithdrawSummaryBO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/UserWithdrawSummaryBO.java index cbfc79302..0061185fa 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/UserWithdrawSummaryBO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/UserWithdrawSummaryBO.java @@ -14,6 +14,11 @@ import lombok.NoArgsConstructor; @AllArgsConstructor public class UserWithdrawSummaryBO { + /** + * 用户编号 + */ + private Long userId; + /** * 提现次数 */ diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java index db2780770..e9959715d 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java @@ -1,15 +1,17 @@ package cn.iocoder.yudao.module.trade.service.order; -import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdateAddressReqVO; -import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdatePriceReqVO; import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO; import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdateAddressReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdatePriceReqVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementReqVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementRespVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import javax.validation.constraints.NotNull; + /** * 交易订单【写】Service 接口 * @@ -116,27 +118,28 @@ public interface TradeOrderUpdateService { // =================== Order Item =================== /** - * 更新交易订单项的售后状态 + * 当售后申请后,更新交易订单项的售后状态 * - * @param id 交易订单项编号 - * @param oldAfterSaleStatus 当前售后状态;如果不符,更新后会抛出异常 - * @param newAfterSaleStatus 目标售后状态 + * @param id 交易订单项编号 + * @param afterSaleId 售后单编号 */ - default void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus) { - updateOrderItemAfterSaleStatus(id, oldAfterSaleStatus, newAfterSaleStatus, null, null); - } + void updateOrderItemWhenAfterSaleCreate(@NotNull Long id, @NotNull Long afterSaleId); + /** - * 更新交易订单项的售后状态 + * 当售后完成后,更新交易订单项的售后状态 * - * @param id 交易订单项编号 - * @param oldAfterSaleStatus 当前售后状态;如果不符,更新后会抛出异常 - * @param newAfterSaleStatus 目标售后状态 - * @param afterSaleId 售后单编号;当订单项发起售后时,必须传递该字段 - * @param refundPrice 退款金额;当订单项退款成功时,必须传递该值 + * @param id 交易订单项编号 + * @param refundPrice 退款金额 */ - void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus, - Long afterSaleId, Integer refundPrice); + void updateOrderItemWhenAfterSaleSuccess(@NotNull Long id, @NotNull Integer refundPrice); + + /** + * 当售后取消(用户取消、管理员驳回、管理员拒绝收货)后,更新交易订单项的售后状态 + * + * @param id 交易订单项编号 + */ + void updateOrderItemWhenAfterSaleCancel(@NotNull Long id); /** * 【会员】创建订单项的评论 diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java index 52ef9e655..101b7b346 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java @@ -74,10 +74,7 @@ import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Set; +import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; @@ -363,7 +360,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { /** * 校验交易订单满足被支付的条件 - * + *

* 1. 交易订单未支付 * 2. 支付单已支付 * @@ -416,7 +413,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @Override @Transactional(rollbackFor = Exception.class) - @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_CANCEL) + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_DELIVERY) public void deliveryOrder(TradeOrderDeliveryReqVO deliveryReqVO) { // 1.1 校验并获得交易订单(可发货) TradeOrderDO order = validateOrderDeliverable(deliveryReqVO.getId()); @@ -455,7 +452,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { /** * 校验交易订单满足被发货的条件 - * + *

* 1. 交易订单未发货 * * @param id 交易订单编号 @@ -521,7 +518,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { for (TradeOrderDO order : orders) { try { getSelf().receiveOrderBySystem(order); - count ++; + count++; } catch (Throwable e) { log.error("[receiveOrderBySystem][order({}) 自动收货订单异常]", order.getId(), e); } @@ -559,7 +556,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { /** * 校验交易订单满足可售货的条件 - * + *

* 1. 交易订单待收货 * * @param userId 用户编号 @@ -612,7 +609,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { for (TradeOrderDO order : orders) { try { getSelf().cancelOrderBySystem(order); - count ++; + count++; } catch (Throwable e) { log.error("[cancelOrderBySystem][order({}) 过期订单异常]", order.getId(), e); } @@ -634,7 +631,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { /** * 取消订单的核心实现 * - * @param order 订单 + * @param order 订单 * @param cancelType 取消类型 */ private void cancelOrder0(TradeOrderDO order, TradeOrderCancelTypeEnum cancelType) { @@ -754,66 +751,79 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { // =================== Order Item =================== - // TODO 疯狂:帮我重构下: - // 1. updateOrderItemAfterSaleStatus 拆分成三个方法:发起;同意;拒绝。原因是,职责更清晰,操作日志也更容易记录; - @Override - @Transactional(rollbackFor = Exception.class) - public void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus, - Long afterSaleId, Integer refundPrice) { - // 如果退款成功,则 refundPrice 非空 - if (Objects.equals(newAfterSaleStatus, TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus()) - && refundPrice == null) { - throw new IllegalArgumentException(StrUtil.format("id({}) 退款成功,退款金额不能为空", id)); - } - // 如果退款发起,则 afterSaleId 非空 - if (Objects.equals(newAfterSaleStatus, TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus()) - && afterSaleId == null) { + public void updateOrderItemWhenAfterSaleCreate(Long id, Long afterSaleId) { + if (afterSaleId == null) { throw new IllegalArgumentException(StrUtil.format("id({}) 退款发起,售后单编号不能为空", id)); } + // 更新订单项 + updateOrderItemAfterSaleStatus(id, TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(), + TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), afterSaleId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateOrderItemWhenAfterSaleSuccess(Long id, Integer refundPrice) { + if (refundPrice == null) { + throw new IllegalArgumentException(StrUtil.format("id({}) 退款成功,退款金额不能为空", id)); + } + + // 1. 更新订单项 + updateOrderItemAfterSaleStatus(id, TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), + TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus(), null); + + // 2. 计算总的退款金额、退回积分 + TradeOrderItemDO orderItem = tradeOrderItemMapper.selectById(id); + TradeOrderDO order = tradeOrderMapper.selectById(orderItem.getOrderId()); + Integer orderRefundPrice = order.getRefundPrice() + refundPrice; + Integer orderRefundPoint = order.getRefundPoint() + orderItem.getUsePoint(); + if (isAllOrderItemAfterSaleSuccess(order.getId())) { // 如果都售后成功,则需要取消订单 + cancelOrderByAfterSale(order, orderRefundPrice, orderRefundPoint); + } else { // 如果部分售后,则更新退款金额 + tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()) + .setRefundStatus(TradeOrderRefundStatusEnum.PART.getStatus()) + .setRefundPrice(orderRefundPrice).setRefundPoint(orderRefundPoint)); + } + + // TODO 芋艿:这块扣减规则,需要在考虑下 + // 3.1 回滚数据:增加 SKU 库存 + productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(Collections.singletonList(orderItem))); + // 3.2 回滚数据:扣减用户积分(赠送的) + reduceUserPoint(order.getUserId(), orderItem.getGivePoint(), MemberPointBizTypeEnum.AFTER_SALE_DEDUCT_GIVE, orderItem.getAfterSaleId()); + // 3.3 回滚数据:增加用户积分(返还抵扣) + addUserPoint(order.getUserId(), orderItem.getUsePoint(), MemberPointBizTypeEnum.AFTER_SALE_REFUND_USED, orderItem.getAfterSaleId()); + // 3.4 回滚数据:扣减用户经验 + getSelf().reduceUserExperienceAsync(order.getUserId(), orderRefundPrice, orderItem.getAfterSaleId()); + // 3.5 回滚数据:更新分佣记录为已失效 + getSelf().cancelBrokerageAsync(order.getUserId(), id); + } + + @Override + public void updateOrderItemWhenAfterSaleCancel(Long id) { + // 更新订单项 + updateOrderItemAfterSaleStatus(id, TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), + TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(), null); + } + + private void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus, + Long afterSaleId) { // 更新订单项 int updateCount = tradeOrderItemMapper.updateAfterSaleStatus(id, oldAfterSaleStatus, newAfterSaleStatus, afterSaleId); if (updateCount <= 0) { throw exception(ORDER_ITEM_UPDATE_AFTER_SALE_STATUS_FAIL); } + } - // 如果有退款金额,则需要更新订单 - if (refundPrice == null) { - return; - } - // 计算总的退款金额 - TradeOrderItemDO orderItem = tradeOrderItemMapper.selectById(id); - TradeOrderDO order = tradeOrderMapper.selectById(orderItem.getOrderId()); - Integer orderRefundPrice = order.getRefundPrice() + refundPrice; - // TODO @疯狂:809 到 817 改成:cancelOrderByAfterSale:相当于全部售后成功后,就是要取消胆子; - if (isAllOrderItemAfterSaleSuccess(order.getId())) { // 如果都售后成功,则需要取消订单 - tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()) - .setRefundStatus(TradeOrderRefundStatusEnum.ALL.getStatus()).setRefundPrice(orderRefundPrice).setRefundPoint(order.getRefundPoint() + orderItem.getUsePoint()) - .setCancelType(TradeOrderCancelTypeEnum.AFTER_SALE_CLOSE.getType()).setCancelTime(LocalDateTime.now())); - - // TODO 芋艿:记录订单日志 - - // TODO 芋艿:要不要退优惠劵 - - } else { // 如果部分售后,则更新退款金额 - tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()) - .setRefundStatus(TradeOrderRefundStatusEnum.PART.getStatus()).setRefundPrice(orderRefundPrice)); - } - - // TODO 芋艿:这块扣减规则,需要在考虑下 - // 售后成功后,执行数据回滚逻辑 - if (Objects.equals(newAfterSaleStatus, TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus())) { - // TODO @疯狂:这里库存也要扣减下; - // 扣减用户积分(赠送的) - reduceUserPoint(order.getUserId(), orderItem.getGivePoint(), MemberPointBizTypeEnum.AFTER_SALE_DEDUCT_GIVE, afterSaleId); - // 增加用户积分(返还抵扣) - addUserPoint(order.getUserId(), orderItem.getUsePoint(), MemberPointBizTypeEnum.AFTER_SALE_REFUND_USED, afterSaleId); - // 扣减用户经验 - getSelf().reduceUserExperienceAsync(order.getUserId(), orderRefundPrice, afterSaleId); - // 更新分佣记录为已失效 - getSelf().cancelBrokerageAsync(order.getUserId(), id); - } + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_CANCEL) + private void cancelOrderByAfterSale(TradeOrderDO order, Integer orderRefundPrice, Integer refundPoint) { + // 1. 更新订单 + tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()) + .setRefundStatus(TradeOrderRefundStatusEnum.ALL.getStatus()) + .setRefundPrice(orderRefundPrice).setRefundPoint(refundPoint) + .setCancelType(TradeOrderCancelTypeEnum.AFTER_SALE_CLOSE.getType()).setCancelTime(LocalDateTime.now())); + // 2. 退还优惠券 + couponApi.returnUsedCoupon(order.getCouponId()); } @@ -879,7 +889,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { for (TradeOrderDO order : orders) { try { getSelf().createOrderItemCommentBySystemBySystem(order); - count ++; + count++; } catch (Throwable e) { log.error("[createOrderItemCommentBySystem][order({}) 过期订单异常]", order.getId(), e); } @@ -923,7 +933,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { /** * 创建订单项的评论的核心实现 * - * @param orderItem 订单项 + * @param orderItem 订单项 * @param createReqVO 评论内容 * @return 评论编号 */ @@ -979,14 +989,14 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { /** * 创建分销记录 - * + *

* 目前是支付成功后,就会创建分销记录。 - * + *

* 业内还有两种做法,可以根据自己的业务调整: - * 1. 确认收货后,才创建分销记录 - * 2. 支付 or 下单成功时,创建分销记录(冻结),确认收货解冻或者 n 天后解冻 + * 1. 确认收货后,才创建分销记录 + * 2. 支付 or 下单成功时,创建分销记录(冻结),确认收货解冻或者 n 天后解冻 * - * @param userId 用户编号 + * @param userId 用户编号 * @param orderId 订单编号 */ @Async diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointGiveCalculator.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointGiveCalculator.java index ea9faaec9..d93d04582 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointGiveCalculator.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointGiveCalculator.java @@ -56,7 +56,6 @@ public class TradePointGiveCalculator implements TradePriceCalculator { TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i); // 商品可能赠送了积分,所以这里要加上 orderItem.setGivePoint(orderItem.getGivePoint() + dividePoints.get(i)); - TradePriceCalculatorHelper.recountPayPrice(orderItem); // TODO @疯狂:这个应该不用调用哇?不影响支付金额 } // 3.3 更新订单赠送积分 TradePriceCalculatorHelper.recountAllGivePoint(result); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculator.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculator.java index 8436eaa2d..bcb43a11c 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculator.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculator.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.trade.service.price.calculator; import cn.hutool.core.util.BooleanUtil; -import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.module.member.api.point.MemberPointApi; import cn.iocoder.yudao.module.member.api.point.dto.MemberPointConfigRespDTO; @@ -15,10 +14,11 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import javax.annotation.Resource; -import java.math.RoundingMode; import java.util.List; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_PAY_PRICE_ILLEGAL; // TODO @疯狂:搞个单测,嘿嘿; /** @@ -45,7 +45,7 @@ public class TradePointUsePriceCalculator implements TradePriceCalculator { } // 1.2 校验积分抵扣是否开启 MemberPointConfigRespDTO config = memberPointApi.getConfig(); - if (!checkDeductPointEnable(config)) { + if (!isDeductPointEnable(config)) { return; } // 1.3 校验用户积分余额 @@ -55,7 +55,6 @@ public class TradePointUsePriceCalculator implements TradePriceCalculator { } // 2.1 计算积分优惠金额 - // TODO @疯狂:如果计算出来,优惠金额为 0,那是不是不用执行后续逻辑哈 int pointPrice = calculatePointPrice(config, user.getPoint(), result); // 2.2 计算分摊的积分、抵扣金额 List orderItems = filterList(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSelected); @@ -77,18 +76,10 @@ public class TradePointUsePriceCalculator implements TradePriceCalculator { TradePriceCalculatorHelper.recountAllPrice(result); } - // TODO @疯狂:这个最好是 is 开头;因为 check 或者 validator,更多失败,会抛出异常; - private boolean checkDeductPointEnable(MemberPointConfigRespDTO config) { - // TODO @疯狂:这个要不直接写成 return config != null && config .... 多行这样一个形式; - if (config == null) { - return false; - } - if (!BooleanUtil.isTrue(config.getTradeDeductEnable())) { - return false; - } - - // 有没有配置:1 积分抵扣多少分 - return config.getTradeDeductUnitPrice() != null && config.getTradeDeductUnitPrice() > 0; + private boolean isDeductPointEnable(MemberPointConfigRespDTO config) { + return config != null && + !BooleanUtil.isTrue(config.getTradeDeductEnable()) && // 积分功能是否启用 + config.getTradeDeductUnitPrice() != null && config.getTradeDeductUnitPrice() > 0; // 有没有配置:1 积分抵扣多少分 } private Integer calculatePointPrice(MemberPointConfigRespDTO config, Integer usePoint, TradePriceCalculateRespBO result) { @@ -98,14 +89,18 @@ public class TradePointUsePriceCalculator implements TradePriceCalculator { } // 积分优惠金额(分) int pointPrice = usePoint * config.getTradeDeductUnitPrice(); - // 0 元购!!!:用户积分比较多时,积分可以抵扣的金额要大于支付金额,这时需要根据支付金额反推使用多少积分 - if (result.getPrice().getPayPrice() < pointPrice) { - pointPrice = result.getPrice().getPayPrice(); - // 反推需要扣除的积分 - usePoint = NumberUtil.toBigDecimal(pointPrice) - .divide(NumberUtil.toBigDecimal(config.getTradeDeductUnitPrice()), 0, RoundingMode.HALF_UP) - .intValue(); + if (result.getPrice().getPayPrice() <= pointPrice) { + // 禁止0元购 + throw exception(PRICE_CALCULATE_PAY_PRICE_ILLEGAL); } +// // 允许0 元购!!!:用户积分比较多时,积分可以抵扣的金额要大于支付金额,这时需要根据支付金额反推使用多少积分 +// if (result.getPrice().getPayPrice() < pointPrice) { +// pointPrice = result.getPrice().getPayPrice(); +// // 反推需要扣除的积分 +// usePoint = NumberUtil.toBigDecimal(pointPrice) +// .divide(NumberUtil.toBigDecimal(config.getTradeDeductUnitPrice()), 0, RoundingMode.HALF_UP) +// .intValue(); +// } // 记录使用的积分 result.setUsePoint(usePoint); return pointPrice;